[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: Carsten Otte <cotte@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Carsten Otte
2005-06-23 22:05:26 -07:00
committed by Linus Torvalds
parent ceffc07852
commit 6d79125bba
11 changed files with 223 additions and 20 deletions

View File

@@ -50,6 +50,23 @@ config EXT2_FS_SECURITY
If you are not using a security module that requires using
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
tristate "Ext3 journalling file system support"
help

View File

@@ -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_POSIX_ACL) += acl.o
ext2-$(CONFIG_EXT2_FS_SECURITY) += xattr_security.o
ext2-$(CONFIG_EXT2_FS_XIP) += xip.o

View File

@@ -147,9 +147,11 @@ extern struct file_operations ext2_dir_operations;
/* file.c */
extern struct inode_operations ext2_file_inode_operations;
extern struct file_operations ext2_file_operations;
extern struct file_operations ext2_xip_file_operations;
/* inode.c */
extern struct address_space_operations ext2_aops;
extern struct address_space_operations ext2_aops_xip;
extern struct address_space_operations ext2_nobh_aops;
/* namei.c */

View File

@@ -55,6 +55,24 @@ struct file_operations ext2_file_operations = {
.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 = {
.truncate = ext2_truncate,
#ifdef CONFIG_EXT2_FS_XATTR

View File

@@ -33,6 +33,7 @@
#include <linux/mpage.h>
#include "ext2.h"
#include "acl.h"
#include "xip.h"
MODULE_AUTHOR("Remy Card and others");
MODULE_DESCRIPTION("Second Extended Filesystem");
@@ -594,6 +595,16 @@ out:
if (err)
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)
goto changed;
@@ -691,6 +702,11 @@ struct address_space_operations ext2_aops = {
.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 = {
.readpage = ext2_readpage,
.readpages = ext2_readpages,
@@ -910,7 +926,9 @@ void ext2_truncate (struct inode * inode)
iblock = (inode->i_size + blocksize-1)
>> 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);
else
block_truncate_page(inode->i_mapping,
@@ -1110,11 +1128,16 @@ void ext2_read_inode (struct inode * inode)
if (S_ISREG(inode->i_mode)) {
inode->i_op = &ext2_file_inode_operations;
inode->i_fop = &ext2_file_operations;
if (test_opt(inode->i_sb, NOBH))
if (ext2_use_xip(inode->i_sb)) {
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;
else
inode->i_fop = &ext2_file_operations;
} else {
inode->i_mapping->a_ops = &ext2_aops;
inode->i_fop = &ext2_file_operations;
}
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &ext2_dir_inode_operations;
inode->i_fop = &ext2_dir_operations;

View File

@@ -34,6 +34,7 @@
#include "ext2.h"
#include "xattr.h"
#include "acl.h"
#include "xip.h"
/*
* 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
int err = PTR_ERR(inode);
if (!IS_ERR(inode)) {
inode->i_op = &ext2_file_inode_operations;
inode->i_fop = &ext2_file_operations;
if (test_opt(inode->i_sb, NOBH))
if (ext2_use_xip(inode->i_sb)) {
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;
else
inode->i_fop = &ext2_file_operations;
} else {
inode->i_mapping->a_ops = &ext2_aops;
inode->i_fop = &ext2_file_operations;
}
mark_inode_dirty(inode);
err = ext2_add_nondir(dentry, inode);
}

View File

@@ -31,6 +31,7 @@
#include "ext2.h"
#include "xattr.h"
#include "acl.h"
#include "xip.h"
static void ext2_sync_super(struct super_block *sb,
struct ext2_super_block *es);
@@ -257,7 +258,7 @@ enum {
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_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,
};
@@ -286,6 +287,7 @@ static match_table_t tokens = {
{Opt_nouser_xattr, "nouser_xattr"},
{Opt_acl, "acl"},
{Opt_noacl, "noacl"},
{Opt_xip, "xip"},
{Opt_ignore, "grpquota"},
{Opt_ignore, "noquota"},
{Opt_ignore, "quota"},
@@ -397,6 +399,13 @@ static int parse_options (char * options,
printk("EXT2 (no)acl options not supported\n");
break;
#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:
break;
default:
@@ -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) ?
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 &&
(EXT2_HAS_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)
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 (sb->s_blocksize != blocksize) {
brelse(bh);
@@ -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_super_block * es;
unsigned long old_mount_opt = sbi->s_mount_opt;
/*
* 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)
((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
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))
return 0;
if (*flags & MS_RDONLY) {

80
fs/ext2/xip.c Normal file
View File

@@ -0,0 +1,80 @@
/*
* 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);
}

25
fs/ext2/xip.h Normal file
View File

@@ -0,0 +1,25 @@
/*
* 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