diff options
Diffstat (limited to 'fs/ext2')
-rw-r--r-- | fs/ext2/Makefile | 1 | ||||
-rw-r--r-- | fs/ext2/ext2.h | 2 | ||||
-rw-r--r-- | fs/ext2/file.c | 18 | ||||
-rw-r--r-- | fs/ext2/inode.c | 31 | ||||
-rw-r--r-- | fs/ext2/namei.c | 12 | ||||
-rw-r--r-- | fs/ext2/super.c | 27 | ||||
-rw-r--r-- | fs/ext2/xip.c | 80 | ||||
-rw-r--r-- | fs/ext2/xip.h | 25 |
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 \ | |||
10 | ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o | 10 | ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o |
11 | ext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.o | 11 | ext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.o |
12 | ext2-$(CONFIG_EXT2_FS_SECURITY) += xattr_security.o | 12 | ext2-$(CONFIG_EXT2_FS_SECURITY) += xattr_security.o |
13 | ext2-$(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 */ |
148 | extern struct inode_operations ext2_file_inode_operations; | 148 | extern struct inode_operations ext2_file_inode_operations; |
149 | extern struct file_operations ext2_file_operations; | 149 | extern struct file_operations ext2_file_operations; |
150 | extern struct file_operations ext2_xip_file_operations; | ||
150 | 151 | ||
151 | /* inode.c */ | 152 | /* inode.c */ |
152 | extern struct address_space_operations ext2_aops; | 153 | extern struct address_space_operations ext2_aops; |
154 | extern struct address_space_operations ext2_aops_xip; | ||
153 | extern struct address_space_operations ext2_nobh_aops; | 155 | extern 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 | ||
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 | struct inode_operations ext2_file_inode_operations = { | 76 | struct 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 | ||
37 | MODULE_AUTHOR("Remy Card and others"); | 38 | MODULE_AUTHOR("Remy Card and others"); |
38 | MODULE_DESCRIPTION("Second Extended Filesystem"); | 39 | MODULE_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 | ||
705 | struct address_space_operations ext2_aops_xip = { | ||
706 | .bmap = ext2_bmap, | ||
707 | .get_xip_page = ext2_get_xip_page, | ||
708 | }; | ||
709 | |||
694 | struct address_space_operations ext2_nobh_aops = { | 710 | struct 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 | ||
35 | static void ext2_sync_super(struct super_block *sb, | 36 | static 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 | |||
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 | } | ||
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 | ||
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 | ||