Commit 6d79125bba55ee82701f1c7d4ebbc1aa20ecbe4e
Committed by
Linus Torvalds
1 parent
ceffc07852
Exists in
master
and in
4 other branches
[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>
Showing 11 changed files with 223 additions and 20 deletions Side-by-side Diff
fs/Kconfig
... | ... | @@ -50,6 +50,23 @@ |
50 | 50 | If you are not using a security module that requires using |
51 | 51 | extended attributes for file security labels, say N. |
52 | 52 | |
53 | +config EXT2_FS_XIP | |
54 | + bool "Ext2 execute in place support" | |
55 | + depends on EXT2_FS | |
56 | + help | |
57 | + Execute in place can be used on memory-backed block devices. If you | |
58 | + enable this option, you can select to mount block devices which are | |
59 | + capable of this feature without using the page cache. | |
60 | + | |
61 | + If you do not use a block device that is capable of using this, | |
62 | + or if unsure, say N. | |
63 | + | |
64 | +config FS_XIP | |
65 | +# execute in place | |
66 | + bool | |
67 | + depends on EXT2_FS_XIP | |
68 | + default y | |
69 | + | |
53 | 70 | config EXT3_FS |
54 | 71 | tristate "Ext3 journalling file system support" |
55 | 72 | help |
fs/ext2/Makefile
fs/ext2/ext2.h
... | ... | @@ -147,9 +147,11 @@ |
147 | 147 | /* file.c */ |
148 | 148 | extern struct inode_operations ext2_file_inode_operations; |
149 | 149 | extern struct file_operations ext2_file_operations; |
150 | +extern struct file_operations ext2_xip_file_operations; | |
150 | 151 | |
151 | 152 | /* inode.c */ |
152 | 153 | extern struct address_space_operations ext2_aops; |
154 | +extern struct address_space_operations ext2_aops_xip; | |
153 | 155 | extern struct address_space_operations ext2_nobh_aops; |
154 | 156 | |
155 | 157 | /* namei.c */ |
fs/ext2/file.c
... | ... | @@ -55,6 +55,24 @@ |
55 | 55 | .sendfile = generic_file_sendfile, |
56 | 56 | }; |
57 | 57 | |
58 | +#ifdef CONFIG_EXT2_FS_XIP | |
59 | +struct 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 | + | |
58 | 76 | struct inode_operations ext2_file_inode_operations = { |
59 | 77 | .truncate = ext2_truncate, |
60 | 78 | #ifdef CONFIG_EXT2_FS_XATTR |
fs/ext2/inode.c
... | ... | @@ -33,6 +33,7 @@ |
33 | 33 | #include <linux/mpage.h> |
34 | 34 | #include "ext2.h" |
35 | 35 | #include "acl.h" |
36 | +#include "xip.h" | |
36 | 37 | |
37 | 38 | MODULE_AUTHOR("Remy Card and others"); |
38 | 39 | MODULE_DESCRIPTION("Second Extended Filesystem"); |
... | ... | @@ -594,6 +595,16 @@ |
594 | 595 | if (err) |
595 | 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 | 608 | if (ext2_splice_branch(inode, iblock, chain, partial, left) < 0) |
598 | 609 | goto changed; |
599 | 610 | |
... | ... | @@ -691,6 +702,11 @@ |
691 | 702 | .writepages = ext2_writepages, |
692 | 703 | }; |
693 | 704 | |
705 | +struct address_space_operations ext2_aops_xip = { | |
706 | + .bmap = ext2_bmap, | |
707 | + .get_xip_page = ext2_get_xip_page, | |
708 | +}; | |
709 | + | |
694 | 710 | struct address_space_operations ext2_nobh_aops = { |
695 | 711 | .readpage = ext2_readpage, |
696 | 712 | .readpages = ext2_readpages, |
... | ... | @@ -910,7 +926,9 @@ |
910 | 926 | iblock = (inode->i_size + blocksize-1) |
911 | 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 | 932 | nobh_truncate_page(inode->i_mapping, inode->i_size); |
915 | 933 | else |
916 | 934 | block_truncate_page(inode->i_mapping, |
917 | 935 | |
918 | 936 | |
... | ... | @@ -1110,11 +1128,16 @@ |
1110 | 1128 | |
1111 | 1129 | if (S_ISREG(inode->i_mode)) { |
1112 | 1130 | inode->i_op = &ext2_file_inode_operations; |
1113 | - inode->i_fop = &ext2_file_operations; | |
1114 | - if (test_opt(inode->i_sb, NOBH)) | |
1131 | + if (ext2_use_xip(inode->i_sb)) { | |
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 | 1135 | inode->i_mapping->a_ops = &ext2_nobh_aops; |
1116 | - else | |
1136 | + inode->i_fop = &ext2_file_operations; | |
1137 | + } else { | |
1117 | 1138 | inode->i_mapping->a_ops = &ext2_aops; |
1139 | + inode->i_fop = &ext2_file_operations; | |
1140 | + } | |
1118 | 1141 | } else if (S_ISDIR(inode->i_mode)) { |
1119 | 1142 | inode->i_op = &ext2_dir_inode_operations; |
1120 | 1143 | inode->i_fop = &ext2_dir_operations; |
fs/ext2/namei.c
... | ... | @@ -34,6 +34,7 @@ |
34 | 34 | #include "ext2.h" |
35 | 35 | #include "xattr.h" |
36 | 36 | #include "acl.h" |
37 | +#include "xip.h" | |
37 | 38 | |
38 | 39 | /* |
39 | 40 | * Couple of helper functions - make the code slightly cleaner. |
40 | 41 | |
41 | 42 | |
... | ... | @@ -127,11 +128,16 @@ |
127 | 128 | int err = PTR_ERR(inode); |
128 | 129 | if (!IS_ERR(inode)) { |
129 | 130 | inode->i_op = &ext2_file_inode_operations; |
130 | - inode->i_fop = &ext2_file_operations; | |
131 | - if (test_opt(inode->i_sb, NOBH)) | |
131 | + if (ext2_use_xip(inode->i_sb)) { | |
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 | 135 | inode->i_mapping->a_ops = &ext2_nobh_aops; |
133 | - else | |
136 | + inode->i_fop = &ext2_file_operations; | |
137 | + } else { | |
134 | 138 | inode->i_mapping->a_ops = &ext2_aops; |
139 | + inode->i_fop = &ext2_file_operations; | |
140 | + } | |
135 | 141 | mark_inode_dirty(inode); |
136 | 142 | err = ext2_add_nondir(dentry, inode); |
137 | 143 | } |
fs/ext2/super.c
... | ... | @@ -31,6 +31,7 @@ |
31 | 31 | #include "ext2.h" |
32 | 32 | #include "xattr.h" |
33 | 33 | #include "acl.h" |
34 | +#include "xip.h" | |
34 | 35 | |
35 | 36 | static void ext2_sync_super(struct super_block *sb, |
36 | 37 | struct ext2_super_block *es); |
... | ... | @@ -257,7 +258,7 @@ |
257 | 258 | Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, |
258 | 259 | Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, |
259 | 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 | 262 | Opt_ignore, Opt_err, |
262 | 263 | }; |
263 | 264 | |
... | ... | @@ -286,6 +287,7 @@ |
286 | 287 | {Opt_nouser_xattr, "nouser_xattr"}, |
287 | 288 | {Opt_acl, "acl"}, |
288 | 289 | {Opt_noacl, "noacl"}, |
290 | + {Opt_xip, "xip"}, | |
289 | 291 | {Opt_ignore, "grpquota"}, |
290 | 292 | {Opt_ignore, "noquota"}, |
291 | 293 | {Opt_ignore, "quota"}, |
... | ... | @@ -397,6 +399,13 @@ |
397 | 399 | printk("EXT2 (no)acl options not supported\n"); |
398 | 400 | break; |
399 | 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 | 409 | case Opt_ignore: |
401 | 410 | break; |
402 | 411 | default: |
... | ... | @@ -640,6 +649,9 @@ |
640 | 649 | ((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? |
641 | 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 | 655 | if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV && |
644 | 656 | (EXT2_HAS_COMPAT_FEATURE(sb, ~0U) || |
645 | 657 | EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) || |
... | ... | @@ -668,6 +680,13 @@ |
668 | 680 | |
669 | 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 | 690 | /* If the blocksize doesn't match, re-read the thing.. */ |
672 | 691 | if (sb->s_blocksize != blocksize) { |
673 | 692 | brelse(bh); |
... | ... | @@ -916,6 +935,7 @@ |
916 | 935 | { |
917 | 936 | struct ext2_sb_info * sbi = EXT2_SB(sb); |
918 | 937 | struct ext2_super_block * es; |
938 | + unsigned long old_mount_opt = sbi->s_mount_opt; | |
919 | 939 | |
920 | 940 | /* |
921 | 941 | * Allow the "check" option to be passed as a remount option. |
... | ... | @@ -927,6 +947,11 @@ |
927 | 947 | ((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); |
928 | 948 | |
929 | 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 | 955 | if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) |
931 | 956 | return 0; |
932 | 957 | if (*flags & MS_RDONLY) { |
fs/ext2/xip.c
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 | + | |
17 | +static 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 | + | |
24 | +int | |
25 | +ext2_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 | + | |
37 | +void 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 | + | |
53 | +struct page* | |
54 | +ext2_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 | +} |
fs/ext2/xip.h
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 | |
9 | +extern void ext2_xip_verify_sb (struct super_block *); | |
10 | +extern int ext2_clear_xip_target (struct inode *, int); | |
11 | + | |
12 | +static 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 | +} | |
17 | +struct 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 |
include/linux/ext2_fs.h
... | ... | @@ -300,18 +300,19 @@ |
300 | 300 | /* |
301 | 301 | * Mount flags |
302 | 302 | */ |
303 | -#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */ | |
304 | -#define EXT2_MOUNT_OLDALLOC 0x0002 /* Don't use the new Orlov allocator */ | |
305 | -#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */ | |
306 | -#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */ | |
307 | -#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */ | |
308 | -#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */ | |
309 | -#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */ | |
310 | -#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */ | |
311 | -#define EXT2_MOUNT_NOBH 0x0100 /* No buffer_heads */ | |
312 | -#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */ | |
313 | -#define EXT2_MOUNT_XATTR_USER 0x4000 /* Extended user attributes */ | |
314 | -#define EXT2_MOUNT_POSIX_ACL 0x8000 /* POSIX Access Control Lists */ | |
303 | +#define EXT2_MOUNT_CHECK 0x000001 /* Do mount-time checks */ | |
304 | +#define EXT2_MOUNT_OLDALLOC 0x000002 /* Don't use the new Orlov allocator */ | |
305 | +#define EXT2_MOUNT_GRPID 0x000004 /* Create files with directory's group */ | |
306 | +#define EXT2_MOUNT_DEBUG 0x000008 /* Some debugging messages */ | |
307 | +#define EXT2_MOUNT_ERRORS_CONT 0x000010 /* Continue on errors */ | |
308 | +#define EXT2_MOUNT_ERRORS_RO 0x000020 /* Remount fs ro on errors */ | |
309 | +#define EXT2_MOUNT_ERRORS_PANIC 0x000040 /* Panic on errors */ | |
310 | +#define EXT2_MOUNT_MINIX_DF 0x000080 /* Mimics the Minix statfs */ | |
311 | +#define EXT2_MOUNT_NOBH 0x000100 /* No buffer_heads */ | |
312 | +#define EXT2_MOUNT_NO_UID32 0x000200 /* Disable 32-bit UIDs */ | |
313 | +#define EXT2_MOUNT_XATTR_USER 0x004000 /* Extended user attributes */ | |
314 | +#define EXT2_MOUNT_POSIX_ACL 0x008000 /* POSIX Access Control Lists */ | |
315 | +#define EXT2_MOUNT_XIP 0x010000 /* Execute in place */ | |
315 | 316 | |
316 | 317 | #define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt |
317 | 318 | #define set_opt(o, opt) o |= EXT2_MOUNT_##opt |
include/linux/fs.h
... | ... | @@ -1513,6 +1513,11 @@ |
1513 | 1513 | extern ssize_t xip_file_writev(struct file *file, const struct iovec *iov, |
1514 | 1514 | unsigned long nr_segs, loff_t *ppos); |
1515 | 1515 | extern int xip_truncate_page(struct address_space *mapping, loff_t from); |
1516 | +#else | |
1517 | +static inline int xip_truncate_page(struct address_space *mapping, loff_t from) | |
1518 | +{ | |
1519 | + return 0; | |
1520 | +} | |
1516 | 1521 | #endif |
1517 | 1522 | |
1518 | 1523 | static inline void do_generic_file_read(struct file * filp, loff_t *ppos, |