Commit 6d79125b authored by Carsten Otte's avatar Carsten Otte Committed by Linus Torvalds

[PATCH] xip: ext2: execute in place

These are the ext2 related parts.  Ext2 now uses the xip_* file operations
along with the get_xip_page aop when mounted with -o xip.
Signed-off-by: default avatarCarsten Otte <cotte@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent ceffc078
...@@ -50,6 +50,23 @@ config EXT2_FS_SECURITY ...@@ -50,6 +50,23 @@ config EXT2_FS_SECURITY
If you are not using a security module that requires using If you are not using a security module that requires using
extended attributes for file security labels, say N. extended attributes for file security labels, say N.
config EXT2_FS_XIP
bool "Ext2 execute in place support"
depends on EXT2_FS
help
Execute in place can be used on memory-backed block devices. If you
enable this option, you can select to mount block devices which are
capable of this feature without using the page cache.
If you do not use a block device that is capable of using this,
or if unsure, say N.
config FS_XIP
# execute in place
bool
depends on EXT2_FS_XIP
default y
config EXT3_FS config EXT3_FS
tristate "Ext3 journalling file system support" tristate "Ext3 journalling file system support"
help help
......
...@@ -10,3 +10,4 @@ ext2-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ ...@@ -10,3 +10,4 @@ ext2-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
ext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.o ext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.o
ext2-$(CONFIG_EXT2_FS_SECURITY) += xattr_security.o ext2-$(CONFIG_EXT2_FS_SECURITY) += xattr_security.o
ext2-$(CONFIG_EXT2_FS_XIP) += xip.o
...@@ -147,9 +147,11 @@ extern struct file_operations ext2_dir_operations; ...@@ -147,9 +147,11 @@ extern struct file_operations ext2_dir_operations;
/* file.c */ /* file.c */
extern struct inode_operations ext2_file_inode_operations; extern struct inode_operations ext2_file_inode_operations;
extern struct file_operations ext2_file_operations; extern struct file_operations ext2_file_operations;
extern struct file_operations ext2_xip_file_operations;
/* inode.c */ /* inode.c */
extern struct address_space_operations ext2_aops; extern struct address_space_operations ext2_aops;
extern struct address_space_operations ext2_aops_xip;
extern struct address_space_operations ext2_nobh_aops; extern struct address_space_operations ext2_nobh_aops;
/* namei.c */ /* namei.c */
......
...@@ -55,6 +55,24 @@ struct file_operations ext2_file_operations = { ...@@ -55,6 +55,24 @@ struct file_operations ext2_file_operations = {
.sendfile = generic_file_sendfile, .sendfile = generic_file_sendfile,
}; };
#ifdef CONFIG_EXT2_FS_XIP
struct file_operations ext2_xip_file_operations = {
.llseek = generic_file_llseek,
.read = do_sync_read,
.write = do_sync_write,
.aio_read = xip_file_aio_read,
.aio_write = xip_file_aio_write,
.ioctl = ext2_ioctl,
.mmap = xip_file_mmap,
.open = generic_file_open,
.release = ext2_release_file,
.fsync = ext2_sync_file,
.readv = xip_file_readv,
.writev = xip_file_writev,
.sendfile = xip_file_sendfile,
};
#endif
struct inode_operations ext2_file_inode_operations = { struct inode_operations ext2_file_inode_operations = {
.truncate = ext2_truncate, .truncate = ext2_truncate,
#ifdef CONFIG_EXT2_FS_XATTR #ifdef CONFIG_EXT2_FS_XATTR
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/mpage.h> #include <linux/mpage.h>
#include "ext2.h" #include "ext2.h"
#include "acl.h" #include "acl.h"
#include "xip.h"
MODULE_AUTHOR("Remy Card and others"); MODULE_AUTHOR("Remy Card and others");
MODULE_DESCRIPTION("Second Extended Filesystem"); MODULE_DESCRIPTION("Second Extended Filesystem");
...@@ -594,6 +595,16 @@ int ext2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_ ...@@ -594,6 +595,16 @@ int ext2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_
if (err) if (err)
goto cleanup; goto cleanup;
if (ext2_use_xip(inode->i_sb)) {
/*
* we need to clear the block
*/
err = ext2_clear_xip_target (inode,
le32_to_cpu(chain[depth-1].key));
if (err)
goto cleanup;
}
if (ext2_splice_branch(inode, iblock, chain, partial, left) < 0) if (ext2_splice_branch(inode, iblock, chain, partial, left) < 0)
goto changed; goto changed;
...@@ -691,6 +702,11 @@ struct address_space_operations ext2_aops = { ...@@ -691,6 +702,11 @@ struct address_space_operations ext2_aops = {
.writepages = ext2_writepages, .writepages = ext2_writepages,
}; };
struct address_space_operations ext2_aops_xip = {
.bmap = ext2_bmap,
.get_xip_page = ext2_get_xip_page,
};
struct address_space_operations ext2_nobh_aops = { struct address_space_operations ext2_nobh_aops = {
.readpage = ext2_readpage, .readpage = ext2_readpage,
.readpages = ext2_readpages, .readpages = ext2_readpages,
...@@ -910,7 +926,9 @@ void ext2_truncate (struct inode * inode) ...@@ -910,7 +926,9 @@ void ext2_truncate (struct inode * inode)
iblock = (inode->i_size + blocksize-1) iblock = (inode->i_size + blocksize-1)
>> EXT2_BLOCK_SIZE_BITS(inode->i_sb); >> EXT2_BLOCK_SIZE_BITS(inode->i_sb);
if (test_opt(inode->i_sb, NOBH)) if (mapping_is_xip(inode->i_mapping))
xip_truncate_page(inode->i_mapping, inode->i_size);
else if (test_opt(inode->i_sb, NOBH))
nobh_truncate_page(inode->i_mapping, inode->i_size); nobh_truncate_page(inode->i_mapping, inode->i_size);
else else
block_truncate_page(inode->i_mapping, block_truncate_page(inode->i_mapping,
...@@ -1110,11 +1128,16 @@ void ext2_read_inode (struct inode * inode) ...@@ -1110,11 +1128,16 @@ void ext2_read_inode (struct inode * inode)
if (S_ISREG(inode->i_mode)) { if (S_ISREG(inode->i_mode)) {
inode->i_op = &ext2_file_inode_operations; inode->i_op = &ext2_file_inode_operations;
inode->i_fop = &ext2_file_operations; if (ext2_use_xip(inode->i_sb)) {
if (test_opt(inode->i_sb, NOBH)) inode->i_mapping->a_ops = &ext2_aops_xip;
inode->i_fop = &ext2_xip_file_operations;
} else if (test_opt(inode->i_sb, NOBH)) {
inode->i_mapping->a_ops = &ext2_nobh_aops; inode->i_mapping->a_ops = &ext2_nobh_aops;
else inode->i_fop = &ext2_file_operations;
} else {
inode->i_mapping->a_ops = &ext2_aops; inode->i_mapping->a_ops = &ext2_aops;
inode->i_fop = &ext2_file_operations;
}
} else if (S_ISDIR(inode->i_mode)) { } else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &ext2_dir_inode_operations; inode->i_op = &ext2_dir_inode_operations;
inode->i_fop = &ext2_dir_operations; inode->i_fop = &ext2_dir_operations;
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "ext2.h" #include "ext2.h"
#include "xattr.h" #include "xattr.h"
#include "acl.h" #include "acl.h"
#include "xip.h"
/* /*
* Couple of helper functions - make the code slightly cleaner. * Couple of helper functions - make the code slightly cleaner.
...@@ -127,11 +128,16 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, int mode, st ...@@ -127,11 +128,16 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, int mode, st
int err = PTR_ERR(inode); int err = PTR_ERR(inode);
if (!IS_ERR(inode)) { if (!IS_ERR(inode)) {
inode->i_op = &ext2_file_inode_operations; inode->i_op = &ext2_file_inode_operations;
inode->i_fop = &ext2_file_operations; if (ext2_use_xip(inode->i_sb)) {
if (test_opt(inode->i_sb, NOBH)) inode->i_mapping->a_ops = &ext2_aops_xip;
inode->i_fop = &ext2_xip_file_operations;
} else if (test_opt(inode->i_sb, NOBH)) {
inode->i_mapping->a_ops = &ext2_nobh_aops; inode->i_mapping->a_ops = &ext2_nobh_aops;
else inode->i_fop = &ext2_file_operations;
} else {
inode->i_mapping->a_ops = &ext2_aops; inode->i_mapping->a_ops = &ext2_aops;
inode->i_fop = &ext2_file_operations;
}
mark_inode_dirty(inode); mark_inode_dirty(inode);
err = ext2_add_nondir(dentry, inode); err = ext2_add_nondir(dentry, inode);
} }
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "ext2.h" #include "ext2.h"
#include "xattr.h" #include "xattr.h"
#include "acl.h" #include "acl.h"
#include "xip.h"
static void ext2_sync_super(struct super_block *sb, static void ext2_sync_super(struct super_block *sb,
struct ext2_super_block *es); struct ext2_super_block *es);
...@@ -257,7 +258,7 @@ enum { ...@@ -257,7 +258,7 @@ enum {
Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh,
Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_xip,
Opt_ignore, Opt_err, Opt_ignore, Opt_err,
}; };
...@@ -286,6 +287,7 @@ static match_table_t tokens = { ...@@ -286,6 +287,7 @@ static match_table_t tokens = {
{Opt_nouser_xattr, "nouser_xattr"}, {Opt_nouser_xattr, "nouser_xattr"},
{Opt_acl, "acl"}, {Opt_acl, "acl"},
{Opt_noacl, "noacl"}, {Opt_noacl, "noacl"},
{Opt_xip, "xip"},
{Opt_ignore, "grpquota"}, {Opt_ignore, "grpquota"},
{Opt_ignore, "noquota"}, {Opt_ignore, "noquota"},
{Opt_ignore, "quota"}, {Opt_ignore, "quota"},
...@@ -397,6 +399,13 @@ static int parse_options (char * options, ...@@ -397,6 +399,13 @@ static int parse_options (char * options,
printk("EXT2 (no)acl options not supported\n"); printk("EXT2 (no)acl options not supported\n");
break; break;
#endif #endif
case Opt_xip:
#ifdef CONFIG_EXT2_FS_XIP
set_opt (sbi->s_mount_opt, XIP);
#else
printk("EXT2 xip option not supported\n");
#endif
break;
case Opt_ignore: case Opt_ignore:
break; break;
default: default:
...@@ -640,6 +649,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) ...@@ -640,6 +649,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? ((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ?
MS_POSIXACL : 0); MS_POSIXACL : 0);
ext2_xip_verify_sb(sb); /* see if bdev supports xip, unset
EXT2_MOUNT_XIP if not */
if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV && if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV &&
(EXT2_HAS_COMPAT_FEATURE(sb, ~0U) || (EXT2_HAS_COMPAT_FEATURE(sb, ~0U) ||
EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) || EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
...@@ -668,6 +680,13 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) ...@@ -668,6 +680,13 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size); blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size);
if ((ext2_use_xip(sb)) && ((blocksize != PAGE_SIZE) ||
(sb->s_blocksize != blocksize))) {
if (!silent)
printk("XIP: Unsupported blocksize\n");
goto failed_mount;
}
/* If the blocksize doesn't match, re-read the thing.. */ /* If the blocksize doesn't match, re-read the thing.. */
if (sb->s_blocksize != blocksize) { if (sb->s_blocksize != blocksize) {
brelse(bh); brelse(bh);
...@@ -916,6 +935,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) ...@@ -916,6 +935,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
{ {
struct ext2_sb_info * sbi = EXT2_SB(sb); struct ext2_sb_info * sbi = EXT2_SB(sb);
struct ext2_super_block * es; struct ext2_super_block * es;
unsigned long old_mount_opt = sbi->s_mount_opt;
/* /*
* Allow the "check" option to be passed as a remount option. * Allow the "check" option to be passed as a remount option.
...@@ -927,6 +947,11 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) ...@@ -927,6 +947,11 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); ((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
es = sbi->s_es; es = sbi->s_es;
if (((sbi->s_mount_opt & EXT2_MOUNT_XIP) !=
(old_mount_opt & EXT2_MOUNT_XIP)) &&
invalidate_inodes(sb))
ext2_warning(sb, __FUNCTION__, "busy inodes while remounting "\
"xip remain in cache (no functional problem)");
if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
return 0; return 0;
if (*flags & MS_RDONLY) { if (*flags & MS_RDONLY) {
......
/*
* linux/fs/ext2/xip.c
*
* Copyright (C) 2005 IBM Corporation
* Author: Carsten Otte (cotte@de.ibm.com)
*/
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/genhd.h>
#include <linux/buffer_head.h>
#include <linux/ext2_fs_sb.h>
#include <linux/ext2_fs.h>
#include "ext2.h"
#include "xip.h"
static inline int
__inode_direct_access(struct inode *inode, sector_t sector, unsigned long *data) {
BUG_ON(!inode->i_sb->s_bdev->bd_disk->fops->direct_access);
return inode->i_sb->s_bdev->bd_disk->fops
->direct_access(inode->i_sb->s_bdev,sector,data);
}
int
ext2_clear_xip_target(struct inode *inode, int block) {
sector_t sector = block*(PAGE_SIZE/512);
unsigned long data;
int rc;
rc = __inode_direct_access(inode, sector, &data);
if (rc)
return rc;
clear_page((void*)data);
return 0;
}
void ext2_xip_verify_sb(struct super_block *sb)
{
struct ext2_sb_info *sbi = EXT2_SB(sb);
if ((sbi->s_mount_opt & EXT2_MOUNT_XIP)) {
if ((sb->s_bdev == NULL) ||
sb->s_bdev->bd_disk == NULL ||
sb->s_bdev->bd_disk->fops == NULL ||
sb->s_bdev->bd_disk->fops->direct_access == NULL) {
sbi->s_mount_opt &= (~EXT2_MOUNT_XIP);
ext2_warning(sb, __FUNCTION__,
"ignoring xip option - not supported by bdev");
}
}
}
struct page*
ext2_get_xip_page(struct address_space *mapping, sector_t blockno,
int create)
{
int rc;
unsigned long data;
struct buffer_head tmp;
tmp.b_state = 0;
tmp.b_blocknr = 0;
rc = ext2_get_block(mapping->host, blockno/(PAGE_SIZE/512) , &tmp,
create);
if (rc)
return ERR_PTR(rc);
if (tmp.b_blocknr == 0) {
/* SPARSE block */
BUG_ON(create);
return ERR_PTR(-ENODATA);
}
rc = __inode_direct_access
(mapping->host,tmp.b_blocknr*(PAGE_SIZE/512) ,&data);
if (rc)
return ERR_PTR(rc);
SetPageUptodate(virt_to_page(data));
return virt_to_page(data);
}
/*
* linux/fs/ext2/xip.h
*
* Copyright (C) 2005 IBM Corporation
* Author: Carsten Otte (cotte@de.ibm.com)
*/
#ifdef CONFIG_EXT2_FS_XIP
extern void ext2_xip_verify_sb (struct super_block *);
extern int ext2_clear_xip_target (struct inode *, int);
static inline int ext2_use_xip (struct super_block *sb)
{
struct ext2_sb_info *sbi = EXT2_SB(sb);
return (sbi->s_mount_opt & EXT2_MOUNT_XIP);
}
struct page* ext2_get_xip_page (struct address_space *, sector_t, int);
#define mapping_is_xip(map) unlikely(map->a_ops->get_xip_page)
#else
#define mapping_is_xip(map) 0
#define ext2_xip_verify_sb(sb) do { } while (0)
#define ext2_use_xip(sb) 0
#define ext2_clear_xip_target(inode, chain) 0
#define ext2_get_xip_page NULL
#endif
...@@ -300,18 +300,19 @@ struct ext2_inode { ...@@ -300,18 +300,19 @@ struct ext2_inode {
/* /*
* Mount flags * Mount flags
*/ */
#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */ #define EXT2_MOUNT_CHECK 0x000001 /* Do mount-time checks */
#define EXT2_MOUNT_OLDALLOC 0x0002 /* Don't use the new Orlov allocator */ #define EXT2_MOUNT_OLDALLOC 0x000002 /* Don't use the new Orlov allocator */
#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */ #define EXT2_MOUNT_GRPID 0x000004 /* Create files with directory's group */
#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */ #define EXT2_MOUNT_DEBUG 0x000008 /* Some debugging messages */
#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */ #define EXT2_MOUNT_ERRORS_CONT 0x000010 /* Continue on errors */
#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */ #define EXT2_MOUNT_ERRORS_RO 0x000020 /* Remount fs ro on errors */
#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */ #define EXT2_MOUNT_ERRORS_PANIC 0x000040 /* Panic on errors */
#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */ #define EXT2_MOUNT_MINIX_DF 0x000080 /* Mimics the Minix statfs */
#define EXT2_MOUNT_NOBH 0x0100 /* No buffer_heads */ #define EXT2_MOUNT_NOBH 0x000100 /* No buffer_heads */
#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */ #define EXT2_MOUNT_NO_UID32 0x000200 /* Disable 32-bit UIDs */
#define EXT2_MOUNT_XATTR_USER 0x4000 /* Extended user attributes */ #define EXT2_MOUNT_XATTR_USER 0x004000 /* Extended user attributes */
#define EXT2_MOUNT_POSIX_ACL 0x8000 /* POSIX Access Control Lists */ #define EXT2_MOUNT_POSIX_ACL 0x008000 /* POSIX Access Control Lists */
#define EXT2_MOUNT_XIP 0x010000 /* Execute in place */
#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt #define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
#define set_opt(o, opt) o |= EXT2_MOUNT_##opt #define set_opt(o, opt) o |= EXT2_MOUNT_##opt
......
...@@ -1513,6 +1513,11 @@ extern ssize_t xip_file_aio_write(struct kiocb *iocb, const char __user *buf, ...@@ -1513,6 +1513,11 @@ extern ssize_t xip_file_aio_write(struct kiocb *iocb, const char __user *buf,
extern ssize_t xip_file_writev(struct file *file, const struct iovec *iov, extern ssize_t xip_file_writev(struct file *file, const struct iovec *iov,
unsigned long nr_segs, loff_t *ppos); unsigned long nr_segs, loff_t *ppos);
extern int xip_truncate_page(struct address_space *mapping, loff_t from); extern int xip_truncate_page(struct address_space *mapping, loff_t from);
#else
static inline int xip_truncate_page(struct address_space *mapping, loff_t from)
{
return 0;
}
#endif #endif
static inline void do_generic_file_read(struct file * filp, loff_t *ppos, static inline void do_generic_file_read(struct file * filp, loff_t *ppos,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment