aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext2
diff options
context:
space:
mode:
authorCarsten Otte <cotte@de.ibm.com>2005-06-24 01:05:26 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-24 03:06:41 -0400
commit6d79125bba55ee82701f1c7d4ebbc1aa20ecbe4e (patch)
treefbd7f82fea19fd89e09312fe89919774b94a6efe /fs/ext2
parentceffc078528befc008c6f2c2c4decda79eabd534 (diff)
[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>
Diffstat (limited to 'fs/ext2')
-rw-r--r--fs/ext2/Makefile1
-rw-r--r--fs/ext2/ext2.h2
-rw-r--r--fs/ext2/file.c18
-rw-r--r--fs/ext2/inode.c31
-rw-r--r--fs/ext2/namei.c12
-rw-r--r--fs/ext2/super.c27
-rw-r--r--fs/ext2/xip.c80
-rw-r--r--fs/ext2/xip.h25
8 files changed, 188 insertions, 8 deletions
diff --git a/fs/ext2/Makefile b/fs/ext2/Makefile
index ee240a14e70f..c5d02da73bc3 100644
--- a/fs/ext2/Makefile
+++ b/fs/ext2/Makefile
@@ -10,3 +10,4 @@ ext2-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
10ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o 10ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
11ext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.o 11ext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.o
12ext2-$(CONFIG_EXT2_FS_SECURITY) += xattr_security.o 12ext2-$(CONFIG_EXT2_FS_SECURITY) += xattr_security.o
13ext2-$(CONFIG_EXT2_FS_XIP) += xip.o
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index 8f0fd726c3f1..eed521d22cf0 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -147,9 +147,11 @@ extern struct file_operations ext2_dir_operations;
147/* file.c */ 147/* file.c */
148extern struct inode_operations ext2_file_inode_operations; 148extern struct inode_operations ext2_file_inode_operations;
149extern struct file_operations ext2_file_operations; 149extern struct file_operations ext2_file_operations;
150extern struct file_operations ext2_xip_file_operations;
150 151
151/* inode.c */ 152/* inode.c */
152extern struct address_space_operations ext2_aops; 153extern struct address_space_operations ext2_aops;
154extern struct address_space_operations ext2_aops_xip;
153extern struct address_space_operations ext2_nobh_aops; 155extern struct address_space_operations ext2_nobh_aops;
154 156
155/* namei.c */ 157/* namei.c */
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index f5e86141ec54..2b3d572365af 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -55,6 +55,24 @@ struct file_operations ext2_file_operations = {
55 .sendfile = generic_file_sendfile, 55 .sendfile = generic_file_sendfile,
56}; 56};
57 57
58#ifdef CONFIG_EXT2_FS_XIP
59struct file_operations ext2_xip_file_operations = {
60 .llseek = generic_file_llseek,
61 .read = do_sync_read,
62 .write = do_sync_write,
63 .aio_read = xip_file_aio_read,
64 .aio_write = xip_file_aio_write,
65 .ioctl = ext2_ioctl,
66 .mmap = xip_file_mmap,
67 .open = generic_file_open,
68 .release = ext2_release_file,
69 .fsync = ext2_sync_file,
70 .readv = xip_file_readv,
71 .writev = xip_file_writev,
72 .sendfile = xip_file_sendfile,
73};
74#endif
75
58struct inode_operations ext2_file_inode_operations = { 76struct inode_operations ext2_file_inode_operations = {
59 .truncate = ext2_truncate, 77 .truncate = ext2_truncate,
60#ifdef CONFIG_EXT2_FS_XATTR 78#ifdef CONFIG_EXT2_FS_XATTR
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index a50d9db4b6e4..53dceb0c6593 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -33,6 +33,7 @@
33#include <linux/mpage.h> 33#include <linux/mpage.h>
34#include "ext2.h" 34#include "ext2.h"
35#include "acl.h" 35#include "acl.h"
36#include "xip.h"
36 37
37MODULE_AUTHOR("Remy Card and others"); 38MODULE_AUTHOR("Remy Card and others");
38MODULE_DESCRIPTION("Second Extended Filesystem"); 39MODULE_DESCRIPTION("Second Extended Filesystem");
@@ -594,6 +595,16 @@ out:
594 if (err) 595 if (err)
595 goto cleanup; 596 goto cleanup;
596 597
598 if (ext2_use_xip(inode->i_sb)) {
599 /*
600 * we need to clear the block
601 */
602 err = ext2_clear_xip_target (inode,
603 le32_to_cpu(chain[depth-1].key));
604 if (err)
605 goto cleanup;
606 }
607
597 if (ext2_splice_branch(inode, iblock, chain, partial, left) < 0) 608 if (ext2_splice_branch(inode, iblock, chain, partial, left) < 0)
598 goto changed; 609 goto changed;
599 610
@@ -691,6 +702,11 @@ struct address_space_operations ext2_aops = {
691 .writepages = ext2_writepages, 702 .writepages = ext2_writepages,
692}; 703};
693 704
705struct address_space_operations ext2_aops_xip = {
706 .bmap = ext2_bmap,
707 .get_xip_page = ext2_get_xip_page,
708};
709
694struct address_space_operations ext2_nobh_aops = { 710struct address_space_operations ext2_nobh_aops = {
695 .readpage = ext2_readpage, 711 .readpage = ext2_readpage,
696 .readpages = ext2_readpages, 712 .readpages = ext2_readpages,
@@ -910,7 +926,9 @@ void ext2_truncate (struct inode * inode)
910 iblock = (inode->i_size + blocksize-1) 926 iblock = (inode->i_size + blocksize-1)
911 >> EXT2_BLOCK_SIZE_BITS(inode->i_sb); 927 >> EXT2_BLOCK_SIZE_BITS(inode->i_sb);
912 928
913 if (test_opt(inode->i_sb, NOBH)) 929 if (mapping_is_xip(inode->i_mapping))
930 xip_truncate_page(inode->i_mapping, inode->i_size);
931 else if (test_opt(inode->i_sb, NOBH))
914 nobh_truncate_page(inode->i_mapping, inode->i_size); 932 nobh_truncate_page(inode->i_mapping, inode->i_size);
915 else 933 else
916 block_truncate_page(inode->i_mapping, 934 block_truncate_page(inode->i_mapping,
@@ -1110,11 +1128,16 @@ void ext2_read_inode (struct inode * inode)
1110 1128
1111 if (S_ISREG(inode->i_mode)) { 1129 if (S_ISREG(inode->i_mode)) {
1112 inode->i_op = &ext2_file_inode_operations; 1130 inode->i_op = &ext2_file_inode_operations;
1113 inode->i_fop = &ext2_file_operations; 1131 if (ext2_use_xip(inode->i_sb)) {
1114 if (test_opt(inode->i_sb, NOBH)) 1132 inode->i_mapping->a_ops = &ext2_aops_xip;
1133 inode->i_fop = &ext2_xip_file_operations;
1134 } else if (test_opt(inode->i_sb, NOBH)) {
1115 inode->i_mapping->a_ops = &ext2_nobh_aops; 1135 inode->i_mapping->a_ops = &ext2_nobh_aops;
1116 else 1136 inode->i_fop = &ext2_file_operations;
1137 } else {
1117 inode->i_mapping->a_ops = &ext2_aops; 1138 inode->i_mapping->a_ops = &ext2_aops;
1139 inode->i_fop = &ext2_file_operations;
1140 }
1118 } else if (S_ISDIR(inode->i_mode)) { 1141 } else if (S_ISDIR(inode->i_mode)) {
1119 inode->i_op = &ext2_dir_inode_operations; 1142 inode->i_op = &ext2_dir_inode_operations;
1120 inode->i_fop = &ext2_dir_operations; 1143 inode->i_fop = &ext2_dir_operations;
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 3176b3d3ffa8..c5513953c825 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -34,6 +34,7 @@
34#include "ext2.h" 34#include "ext2.h"
35#include "xattr.h" 35#include "xattr.h"
36#include "acl.h" 36#include "acl.h"
37#include "xip.h"
37 38
38/* 39/*
39 * Couple of helper functions - make the code slightly cleaner. 40 * 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 int err = PTR_ERR(inode); 128 int err = PTR_ERR(inode);
128 if (!IS_ERR(inode)) { 129 if (!IS_ERR(inode)) {
129 inode->i_op = &ext2_file_inode_operations; 130 inode->i_op = &ext2_file_inode_operations;
130 inode->i_fop = &ext2_file_operations; 131 if (ext2_use_xip(inode->i_sb)) {
131 if (test_opt(inode->i_sb, NOBH)) 132 inode->i_mapping->a_ops = &ext2_aops_xip;
133 inode->i_fop = &ext2_xip_file_operations;
134 } else if (test_opt(inode->i_sb, NOBH)) {
132 inode->i_mapping->a_ops = &ext2_nobh_aops; 135 inode->i_mapping->a_ops = &ext2_nobh_aops;
133 else 136 inode->i_fop = &ext2_file_operations;
137 } else {
134 inode->i_mapping->a_ops = &ext2_aops; 138 inode->i_mapping->a_ops = &ext2_aops;
139 inode->i_fop = &ext2_file_operations;
140 }
135 mark_inode_dirty(inode); 141 mark_inode_dirty(inode);
136 err = ext2_add_nondir(dentry, inode); 142 err = ext2_add_nondir(dentry, inode);
137 } 143 }
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 661c3d98d946..876e391f2871 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -31,6 +31,7 @@
31#include "ext2.h" 31#include "ext2.h"
32#include "xattr.h" 32#include "xattr.h"
33#include "acl.h" 33#include "acl.h"
34#include "xip.h"
34 35
35static void ext2_sync_super(struct super_block *sb, 36static void ext2_sync_super(struct super_block *sb,
36 struct ext2_super_block *es); 37 struct ext2_super_block *es);
@@ -257,7 +258,7 @@ enum {
257 Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, 258 Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
258 Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, 259 Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
259 Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh, 260 Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh,
260 Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, 261 Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_xip,
261 Opt_ignore, Opt_err, 262 Opt_ignore, Opt_err,
262}; 263};
263 264
@@ -286,6 +287,7 @@ static match_table_t tokens = {
286 {Opt_nouser_xattr, "nouser_xattr"}, 287 {Opt_nouser_xattr, "nouser_xattr"},
287 {Opt_acl, "acl"}, 288 {Opt_acl, "acl"},
288 {Opt_noacl, "noacl"}, 289 {Opt_noacl, "noacl"},
290 {Opt_xip, "xip"},
289 {Opt_ignore, "grpquota"}, 291 {Opt_ignore, "grpquota"},
290 {Opt_ignore, "noquota"}, 292 {Opt_ignore, "noquota"},
291 {Opt_ignore, "quota"}, 293 {Opt_ignore, "quota"},
@@ -397,6 +399,13 @@ static int parse_options (char * options,
397 printk("EXT2 (no)acl options not supported\n"); 399 printk("EXT2 (no)acl options not supported\n");
398 break; 400 break;
399#endif 401#endif
402 case Opt_xip:
403#ifdef CONFIG_EXT2_FS_XIP
404 set_opt (sbi->s_mount_opt, XIP);
405#else
406 printk("EXT2 xip option not supported\n");
407#endif
408 break;
400 case Opt_ignore: 409 case Opt_ignore:
401 break; 410 break;
402 default: 411 default:
@@ -640,6 +649,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
640 ((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? 649 ((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ?
641 MS_POSIXACL : 0); 650 MS_POSIXACL : 0);
642 651
652 ext2_xip_verify_sb(sb); /* see if bdev supports xip, unset
653 EXT2_MOUNT_XIP if not */
654
643 if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV && 655 if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV &&
644 (EXT2_HAS_COMPAT_FEATURE(sb, ~0U) || 656 (EXT2_HAS_COMPAT_FEATURE(sb, ~0U) ||
645 EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) || 657 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 680
669 blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size); 681 blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size);
670 682
683 if ((ext2_use_xip(sb)) && ((blocksize != PAGE_SIZE) ||
684 (sb->s_blocksize != blocksize))) {
685 if (!silent)
686 printk("XIP: Unsupported blocksize\n");
687 goto failed_mount;
688 }
689
671 /* If the blocksize doesn't match, re-read the thing.. */ 690 /* If the blocksize doesn't match, re-read the thing.. */
672 if (sb->s_blocksize != blocksize) { 691 if (sb->s_blocksize != blocksize) {
673 brelse(bh); 692 brelse(bh);
@@ -916,6 +935,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
916{ 935{
917 struct ext2_sb_info * sbi = EXT2_SB(sb); 936 struct ext2_sb_info * sbi = EXT2_SB(sb);
918 struct ext2_super_block * es; 937 struct ext2_super_block * es;
938 unsigned long old_mount_opt = sbi->s_mount_opt;
919 939
920 /* 940 /*
921 * Allow the "check" option to be passed as a remount option. 941 * 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 ((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); 947 ((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
928 948
929 es = sbi->s_es; 949 es = sbi->s_es;
950 if (((sbi->s_mount_opt & EXT2_MOUNT_XIP) !=
951 (old_mount_opt & EXT2_MOUNT_XIP)) &&
952 invalidate_inodes(sb))
953 ext2_warning(sb, __FUNCTION__, "busy inodes while remounting "\
954 "xip remain in cache (no functional problem)");
930 if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) 955 if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
931 return 0; 956 return 0;
932 if (*flags & MS_RDONLY) { 957 if (*flags & MS_RDONLY) {
diff --git a/fs/ext2/xip.c b/fs/ext2/xip.c
new file mode 100644
index 000000000000..d44431d1a338
--- /dev/null
+++ b/fs/ext2/xip.c
@@ -0,0 +1,80 @@
1/*
2 * linux/fs/ext2/xip.c
3 *
4 * Copyright (C) 2005 IBM Corporation
5 * Author: Carsten Otte (cotte@de.ibm.com)
6 */
7
8#include <linux/mm.h>
9#include <linux/fs.h>
10#include <linux/genhd.h>
11#include <linux/buffer_head.h>
12#include <linux/ext2_fs_sb.h>
13#include <linux/ext2_fs.h>
14#include "ext2.h"
15#include "xip.h"
16
17static inline int
18__inode_direct_access(struct inode *inode, sector_t sector, unsigned long *data) {
19 BUG_ON(!inode->i_sb->s_bdev->bd_disk->fops->direct_access);
20 return inode->i_sb->s_bdev->bd_disk->fops
21 ->direct_access(inode->i_sb->s_bdev,sector,data);
22}
23
24int
25ext2_clear_xip_target(struct inode *inode, int block) {
26 sector_t sector = block*(PAGE_SIZE/512);
27 unsigned long data;
28 int rc;
29
30 rc = __inode_direct_access(inode, sector, &data);
31 if (rc)
32 return rc;
33 clear_page((void*)data);
34 return 0;
35}
36
37void ext2_xip_verify_sb(struct super_block *sb)
38{
39 struct ext2_sb_info *sbi = EXT2_SB(sb);
40
41 if ((sbi->s_mount_opt & EXT2_MOUNT_XIP)) {
42 if ((sb->s_bdev == NULL) ||
43 sb->s_bdev->bd_disk == NULL ||
44 sb->s_bdev->bd_disk->fops == NULL ||
45 sb->s_bdev->bd_disk->fops->direct_access == NULL) {
46 sbi->s_mount_opt &= (~EXT2_MOUNT_XIP);
47 ext2_warning(sb, __FUNCTION__,
48 "ignoring xip option - not supported by bdev");
49 }
50 }
51}
52
53struct page*
54ext2_get_xip_page(struct address_space *mapping, sector_t blockno,
55 int create)
56{
57 int rc;
58 unsigned long data;
59 struct buffer_head tmp;
60
61 tmp.b_state = 0;
62 tmp.b_blocknr = 0;
63 rc = ext2_get_block(mapping->host, blockno/(PAGE_SIZE/512) , &tmp,
64 create);
65 if (rc)
66 return ERR_PTR(rc);
67 if (tmp.b_blocknr == 0) {
68 /* SPARSE block */
69 BUG_ON(create);
70 return ERR_PTR(-ENODATA);
71 }
72
73 rc = __inode_direct_access
74 (mapping->host,tmp.b_blocknr*(PAGE_SIZE/512) ,&data);
75 if (rc)
76 return ERR_PTR(rc);
77
78 SetPageUptodate(virt_to_page(data));
79 return virt_to_page(data);
80}
diff --git a/fs/ext2/xip.h b/fs/ext2/xip.h
new file mode 100644
index 000000000000..aa85331d6c56
--- /dev/null
+++ b/fs/ext2/xip.h
@@ -0,0 +1,25 @@
1/*
2 * linux/fs/ext2/xip.h
3 *
4 * Copyright (C) 2005 IBM Corporation
5 * Author: Carsten Otte (cotte@de.ibm.com)
6 */
7
8#ifdef CONFIG_EXT2_FS_XIP
9extern void ext2_xip_verify_sb (struct super_block *);
10extern int ext2_clear_xip_target (struct inode *, int);
11
12static inline int ext2_use_xip (struct super_block *sb)
13{
14 struct ext2_sb_info *sbi = EXT2_SB(sb);
15 return (sbi->s_mount_opt & EXT2_MOUNT_XIP);
16}
17struct page* ext2_get_xip_page (struct address_space *, sector_t, int);
18#define mapping_is_xip(map) unlikely(map->a_ops->get_xip_page)
19#else
20#define mapping_is_xip(map) 0
21#define ext2_xip_verify_sb(sb) do { } while (0)
22#define ext2_use_xip(sb) 0
23#define ext2_clear_xip_target(inode, chain) 0
24#define ext2_get_xip_page NULL
25#endif