Commit 6d79125bba55ee82701f1c7d4ebbc1aa20ecbe4e

Authored by Carsten Otte
Committed by Linus Torvalds
1 parent ceffc07852

[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

... ... @@ -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
... ... @@ -10,4 +10,5 @@
10 10 ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
11 11 ext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.o
12 12 ext2-$(CONFIG_EXT2_FS_SECURITY) += xattr_security.o
  13 +ext2-$(CONFIG_EXT2_FS_XIP) += xip.o
... ... @@ -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 */
... ... @@ -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
... ... @@ -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;
... ... @@ -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 }
... ... @@ -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) {
  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 +}
  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
... ... @@ -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,