diff options
Diffstat (limited to 'fs')
36 files changed, 1396 insertions, 595 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index a7c0cc3203cb..8157f2e2d515 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -50,6 +50,23 @@ config EXT2_FS_SECURITY | |||
50 | If you are not using a security module that requires using | 50 | If you are not using a security module that requires using |
51 | extended attributes for file security labels, say N. | 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 | config EXT3_FS | 70 | config EXT3_FS |
54 | tristate "Ext3 journalling file system support" | 71 | tristate "Ext3 journalling file system support" |
55 | help | 72 | help |
@@ -1413,6 +1430,8 @@ config NFSD_V4 | |||
1413 | bool "Provide NFSv4 server support (EXPERIMENTAL)" | 1430 | bool "Provide NFSv4 server support (EXPERIMENTAL)" |
1414 | depends on NFSD_V3 && EXPERIMENTAL | 1431 | depends on NFSD_V3 && EXPERIMENTAL |
1415 | select NFSD_TCP | 1432 | select NFSD_TCP |
1433 | select CRYPTO_MD5 | ||
1434 | select CRYPTO | ||
1416 | help | 1435 | help |
1417 | If you would like to include the NFSv4 server as well as the NFSv2 | 1436 | If you would like to include the NFSv4 server as well as the NFSv2 |
1418 | and NFSv3 servers, say Y here. This feature is experimental, and | 1437 | and NFSv3 servers, say Y here. This feature is experimental, and |
diff --git a/fs/direct-io.c b/fs/direct-io.c index 1d55e7e67342..0d06097bc995 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c | |||
@@ -215,7 +215,7 @@ static struct page *dio_get_page(struct dio *dio) | |||
215 | static void dio_complete(struct dio *dio, loff_t offset, ssize_t bytes) | 215 | static void dio_complete(struct dio *dio, loff_t offset, ssize_t bytes) |
216 | { | 216 | { |
217 | if (dio->end_io && dio->result) | 217 | if (dio->end_io && dio->result) |
218 | dio->end_io(dio->inode, offset, bytes, dio->map_bh.b_private); | 218 | dio->end_io(dio->iocb, offset, bytes, dio->map_bh.b_private); |
219 | if (dio->lock_type == DIO_LOCKING) | 219 | if (dio->lock_type == DIO_LOCKING) |
220 | up_read(&dio->inode->i_alloc_sem); | 220 | up_read(&dio->inode->i_alloc_sem); |
221 | } | 221 | } |
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..a484412fc782 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c | |||
@@ -55,6 +55,20 @@ 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 = xip_file_read, | ||
62 | .write = xip_file_write, | ||
63 | .ioctl = ext2_ioctl, | ||
64 | .mmap = xip_file_mmap, | ||
65 | .open = generic_file_open, | ||
66 | .release = ext2_release_file, | ||
67 | .fsync = ext2_sync_file, | ||
68 | .sendfile = xip_file_sendfile, | ||
69 | }; | ||
70 | #endif | ||
71 | |||
58 | struct inode_operations ext2_file_inode_operations = { | 72 | struct inode_operations ext2_file_inode_operations = { |
59 | .truncate = ext2_truncate, | 73 | .truncate = ext2_truncate, |
60 | #ifdef CONFIG_EXT2_FS_XATTR | 74 | #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 | ||
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index 133f5aa581bb..3ac38266fc9e 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c | |||
@@ -393,7 +393,8 @@ ext3_acl_chmod(struct inode *inode) | |||
393 | int retries = 0; | 393 | int retries = 0; |
394 | 394 | ||
395 | retry: | 395 | retry: |
396 | handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS); | 396 | handle = ext3_journal_start(inode, |
397 | EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); | ||
397 | if (IS_ERR(handle)) { | 398 | if (IS_ERR(handle)) { |
398 | error = PTR_ERR(handle); | 399 | error = PTR_ERR(handle); |
399 | ext3_std_error(inode->i_sb, error); | 400 | ext3_std_error(inode->i_sb, error); |
@@ -503,7 +504,7 @@ ext3_xattr_set_acl(struct inode *inode, int type, const void *value, | |||
503 | acl = NULL; | 504 | acl = NULL; |
504 | 505 | ||
505 | retry: | 506 | retry: |
506 | handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS); | 507 | handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); |
507 | if (IS_ERR(handle)) | 508 | if (IS_ERR(handle)) |
508 | return PTR_ERR(handle); | 509 | return PTR_ERR(handle); |
509 | error = ext3_set_acl(handle, inode, type, acl); | 510 | error = ext3_set_acl(handle, inode, type, acl); |
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 0d5fa73b18dc..0b2db4f618cb 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -128,7 +128,7 @@ static unsigned long blocks_for_truncate(struct inode *inode) | |||
128 | if (needed > EXT3_MAX_TRANS_DATA) | 128 | if (needed > EXT3_MAX_TRANS_DATA) |
129 | needed = EXT3_MAX_TRANS_DATA; | 129 | needed = EXT3_MAX_TRANS_DATA; |
130 | 130 | ||
131 | return EXT3_DATA_TRANS_BLOCKS + needed; | 131 | return EXT3_DATA_TRANS_BLOCKS(inode->i_sb) + needed; |
132 | } | 132 | } |
133 | 133 | ||
134 | /* | 134 | /* |
@@ -2763,7 +2763,8 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) | |||
2763 | 2763 | ||
2764 | /* (user+group)*(old+new) structure, inode write (sb, | 2764 | /* (user+group)*(old+new) structure, inode write (sb, |
2765 | * inode block, ? - but truncate inode update has it) */ | 2765 | * inode block, ? - but truncate inode update has it) */ |
2766 | handle = ext3_journal_start(inode, 4*EXT3_QUOTA_INIT_BLOCKS+3); | 2766 | handle = ext3_journal_start(inode, 2*(EXT3_QUOTA_INIT_BLOCKS(inode->i_sb)+ |
2767 | EXT3_QUOTA_DEL_BLOCKS(inode->i_sb))+3); | ||
2767 | if (IS_ERR(handle)) { | 2768 | if (IS_ERR(handle)) { |
2768 | error = PTR_ERR(handle); | 2769 | error = PTR_ERR(handle); |
2769 | goto err_out; | 2770 | goto err_out; |
@@ -2861,7 +2862,7 @@ static int ext3_writepage_trans_blocks(struct inode *inode) | |||
2861 | #ifdef CONFIG_QUOTA | 2862 | #ifdef CONFIG_QUOTA |
2862 | /* We know that structure was already allocated during DQUOT_INIT so | 2863 | /* We know that structure was already allocated during DQUOT_INIT so |
2863 | * we will be updating only the data blocks + inodes */ | 2864 | * we will be updating only the data blocks + inodes */ |
2864 | ret += 2*EXT3_QUOTA_TRANS_BLOCKS; | 2865 | ret += 2*EXT3_QUOTA_TRANS_BLOCKS(inode->i_sb); |
2865 | #endif | 2866 | #endif |
2866 | 2867 | ||
2867 | return ret; | 2868 | return ret; |
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 60e44e6dd7a6..50378d8ff84b 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c | |||
@@ -1645,9 +1645,9 @@ static int ext3_create (struct inode * dir, struct dentry * dentry, int mode, | |||
1645 | int err, retries = 0; | 1645 | int err, retries = 0; |
1646 | 1646 | ||
1647 | retry: | 1647 | retry: |
1648 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + | 1648 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + |
1649 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + | 1649 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + |
1650 | 2*EXT3_QUOTA_INIT_BLOCKS); | 1650 | 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb)); |
1651 | if (IS_ERR(handle)) | 1651 | if (IS_ERR(handle)) |
1652 | return PTR_ERR(handle); | 1652 | return PTR_ERR(handle); |
1653 | 1653 | ||
@@ -1679,9 +1679,9 @@ static int ext3_mknod (struct inode * dir, struct dentry *dentry, | |||
1679 | return -EINVAL; | 1679 | return -EINVAL; |
1680 | 1680 | ||
1681 | retry: | 1681 | retry: |
1682 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + | 1682 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + |
1683 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + | 1683 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + |
1684 | 2*EXT3_QUOTA_INIT_BLOCKS); | 1684 | 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb)); |
1685 | if (IS_ERR(handle)) | 1685 | if (IS_ERR(handle)) |
1686 | return PTR_ERR(handle); | 1686 | return PTR_ERR(handle); |
1687 | 1687 | ||
@@ -1715,9 +1715,9 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode) | |||
1715 | return -EMLINK; | 1715 | return -EMLINK; |
1716 | 1716 | ||
1717 | retry: | 1717 | retry: |
1718 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + | 1718 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + |
1719 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + | 1719 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + |
1720 | 2*EXT3_QUOTA_INIT_BLOCKS); | 1720 | 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb)); |
1721 | if (IS_ERR(handle)) | 1721 | if (IS_ERR(handle)) |
1722 | return PTR_ERR(handle); | 1722 | return PTR_ERR(handle); |
1723 | 1723 | ||
@@ -2006,7 +2006,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry) | |||
2006 | /* Initialize quotas before so that eventual writes go in | 2006 | /* Initialize quotas before so that eventual writes go in |
2007 | * separate transaction */ | 2007 | * separate transaction */ |
2008 | DQUOT_INIT(dentry->d_inode); | 2008 | DQUOT_INIT(dentry->d_inode); |
2009 | handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS); | 2009 | handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb)); |
2010 | if (IS_ERR(handle)) | 2010 | if (IS_ERR(handle)) |
2011 | return PTR_ERR(handle); | 2011 | return PTR_ERR(handle); |
2012 | 2012 | ||
@@ -2065,7 +2065,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry) | |||
2065 | /* Initialize quotas before so that eventual writes go | 2065 | /* Initialize quotas before so that eventual writes go |
2066 | * in separate transaction */ | 2066 | * in separate transaction */ |
2067 | DQUOT_INIT(dentry->d_inode); | 2067 | DQUOT_INIT(dentry->d_inode); |
2068 | handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS); | 2068 | handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb)); |
2069 | if (IS_ERR(handle)) | 2069 | if (IS_ERR(handle)) |
2070 | return PTR_ERR(handle); | 2070 | return PTR_ERR(handle); |
2071 | 2071 | ||
@@ -2120,9 +2120,9 @@ static int ext3_symlink (struct inode * dir, | |||
2120 | return -ENAMETOOLONG; | 2120 | return -ENAMETOOLONG; |
2121 | 2121 | ||
2122 | retry: | 2122 | retry: |
2123 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + | 2123 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + |
2124 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 + | 2124 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 + |
2125 | 2*EXT3_QUOTA_INIT_BLOCKS); | 2125 | 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb)); |
2126 | if (IS_ERR(handle)) | 2126 | if (IS_ERR(handle)) |
2127 | return PTR_ERR(handle); | 2127 | return PTR_ERR(handle); |
2128 | 2128 | ||
@@ -2174,7 +2174,7 @@ static int ext3_link (struct dentry * old_dentry, | |||
2174 | return -EMLINK; | 2174 | return -EMLINK; |
2175 | 2175 | ||
2176 | retry: | 2176 | retry: |
2177 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + | 2177 | handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + |
2178 | EXT3_INDEX_EXTRA_TRANS_BLOCKS); | 2178 | EXT3_INDEX_EXTRA_TRANS_BLOCKS); |
2179 | if (IS_ERR(handle)) | 2179 | if (IS_ERR(handle)) |
2180 | return PTR_ERR(handle); | 2180 | return PTR_ERR(handle); |
@@ -2216,7 +2216,8 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, | |||
2216 | * in separate transaction */ | 2216 | * in separate transaction */ |
2217 | if (new_dentry->d_inode) | 2217 | if (new_dentry->d_inode) |
2218 | DQUOT_INIT(new_dentry->d_inode); | 2218 | DQUOT_INIT(new_dentry->d_inode); |
2219 | handle = ext3_journal_start(old_dir, 2 * EXT3_DATA_TRANS_BLOCKS + | 2219 | handle = ext3_journal_start(old_dir, 2 * |
2220 | EXT3_DATA_TRANS_BLOCKS(old_dir->i_sb) + | ||
2220 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2); | 2221 | EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2); |
2221 | if (IS_ERR(handle)) | 2222 | if (IS_ERR(handle)) |
2222 | return PTR_ERR(handle); | 2223 | return PTR_ERR(handle); |
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 9630fbfdc24a..b4b3e8a39131 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
@@ -589,7 +589,7 @@ enum { | |||
589 | Opt_commit, Opt_journal_update, Opt_journal_inum, | 589 | Opt_commit, Opt_journal_update, Opt_journal_inum, |
590 | Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback, | 590 | Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback, |
591 | Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, | 591 | Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, |
592 | Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, | 592 | Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota, |
593 | Opt_ignore, Opt_barrier, Opt_err, Opt_resize, | 593 | Opt_ignore, Opt_barrier, Opt_err, Opt_resize, |
594 | }; | 594 | }; |
595 | 595 | ||
@@ -634,10 +634,10 @@ static match_table_t tokens = { | |||
634 | {Opt_grpjquota, "grpjquota=%s"}, | 634 | {Opt_grpjquota, "grpjquota=%s"}, |
635 | {Opt_jqfmt_vfsold, "jqfmt=vfsold"}, | 635 | {Opt_jqfmt_vfsold, "jqfmt=vfsold"}, |
636 | {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"}, | 636 | {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"}, |
637 | {Opt_ignore, "grpquota"}, | 637 | {Opt_quota, "grpquota"}, |
638 | {Opt_ignore, "noquota"}, | 638 | {Opt_noquota, "noquota"}, |
639 | {Opt_ignore, "quota"}, | 639 | {Opt_quota, "quota"}, |
640 | {Opt_ignore, "usrquota"}, | 640 | {Opt_quota, "usrquota"}, |
641 | {Opt_barrier, "barrier=%u"}, | 641 | {Opt_barrier, "barrier=%u"}, |
642 | {Opt_err, NULL}, | 642 | {Opt_err, NULL}, |
643 | {Opt_resize, "resize"}, | 643 | {Opt_resize, "resize"}, |
@@ -876,6 +876,7 @@ set_qf_name: | |||
876 | sbi->s_qf_names[qtype] = NULL; | 876 | sbi->s_qf_names[qtype] = NULL; |
877 | return 0; | 877 | return 0; |
878 | } | 878 | } |
879 | set_opt(sbi->s_mount_opt, QUOTA); | ||
879 | break; | 880 | break; |
880 | case Opt_offusrjquota: | 881 | case Opt_offusrjquota: |
881 | qtype = USRQUOTA; | 882 | qtype = USRQUOTA; |
@@ -898,6 +899,17 @@ clear_qf_name: | |||
898 | case Opt_jqfmt_vfsv0: | 899 | case Opt_jqfmt_vfsv0: |
899 | sbi->s_jquota_fmt = QFMT_VFS_V0; | 900 | sbi->s_jquota_fmt = QFMT_VFS_V0; |
900 | break; | 901 | break; |
902 | case Opt_quota: | ||
903 | set_opt(sbi->s_mount_opt, QUOTA); | ||
904 | break; | ||
905 | case Opt_noquota: | ||
906 | if (sb_any_quota_enabled(sb)) { | ||
907 | printk(KERN_ERR "EXT3-fs: Cannot change quota " | ||
908 | "options when quota turned on.\n"); | ||
909 | return 0; | ||
910 | } | ||
911 | clear_opt(sbi->s_mount_opt, QUOTA); | ||
912 | break; | ||
901 | #else | 913 | #else |
902 | case Opt_usrjquota: | 914 | case Opt_usrjquota: |
903 | case Opt_grpjquota: | 915 | case Opt_grpjquota: |
@@ -909,6 +921,9 @@ clear_qf_name: | |||
909 | "EXT3-fs: journalled quota options not " | 921 | "EXT3-fs: journalled quota options not " |
910 | "supported.\n"); | 922 | "supported.\n"); |
911 | break; | 923 | break; |
924 | case Opt_quota: | ||
925 | case Opt_noquota: | ||
926 | break; | ||
912 | #endif | 927 | #endif |
913 | case Opt_abort: | 928 | case Opt_abort: |
914 | set_opt(sbi->s_mount_opt, ABORT); | 929 | set_opt(sbi->s_mount_opt, ABORT); |
@@ -2238,7 +2253,7 @@ static int ext3_dquot_initialize(struct inode *inode, int type) | |||
2238 | int ret, err; | 2253 | int ret, err; |
2239 | 2254 | ||
2240 | /* We may create quota structure so we need to reserve enough blocks */ | 2255 | /* We may create quota structure so we need to reserve enough blocks */ |
2241 | handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS); | 2256 | handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS(inode->i_sb)); |
2242 | if (IS_ERR(handle)) | 2257 | if (IS_ERR(handle)) |
2243 | return PTR_ERR(handle); | 2258 | return PTR_ERR(handle); |
2244 | ret = dquot_initialize(inode, type); | 2259 | ret = dquot_initialize(inode, type); |
@@ -2254,7 +2269,7 @@ static int ext3_dquot_drop(struct inode *inode) | |||
2254 | int ret, err; | 2269 | int ret, err; |
2255 | 2270 | ||
2256 | /* We may delete quota structure so we need to reserve enough blocks */ | 2271 | /* We may delete quota structure so we need to reserve enough blocks */ |
2257 | handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS); | 2272 | handle = ext3_journal_start(inode, 2*EXT3_QUOTA_DEL_BLOCKS(inode->i_sb)); |
2258 | if (IS_ERR(handle)) | 2273 | if (IS_ERR(handle)) |
2259 | return PTR_ERR(handle); | 2274 | return PTR_ERR(handle); |
2260 | ret = dquot_drop(inode); | 2275 | ret = dquot_drop(inode); |
@@ -2272,7 +2287,7 @@ static int ext3_write_dquot(struct dquot *dquot) | |||
2272 | 2287 | ||
2273 | inode = dquot_to_inode(dquot); | 2288 | inode = dquot_to_inode(dquot); |
2274 | handle = ext3_journal_start(inode, | 2289 | handle = ext3_journal_start(inode, |
2275 | EXT3_QUOTA_TRANS_BLOCKS); | 2290 | EXT3_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); |
2276 | if (IS_ERR(handle)) | 2291 | if (IS_ERR(handle)) |
2277 | return PTR_ERR(handle); | 2292 | return PTR_ERR(handle); |
2278 | ret = dquot_commit(dquot); | 2293 | ret = dquot_commit(dquot); |
@@ -2288,7 +2303,7 @@ static int ext3_acquire_dquot(struct dquot *dquot) | |||
2288 | handle_t *handle; | 2303 | handle_t *handle; |
2289 | 2304 | ||
2290 | handle = ext3_journal_start(dquot_to_inode(dquot), | 2305 | handle = ext3_journal_start(dquot_to_inode(dquot), |
2291 | EXT3_QUOTA_INIT_BLOCKS); | 2306 | EXT3_QUOTA_INIT_BLOCKS(dquot->dq_sb)); |
2292 | if (IS_ERR(handle)) | 2307 | if (IS_ERR(handle)) |
2293 | return PTR_ERR(handle); | 2308 | return PTR_ERR(handle); |
2294 | ret = dquot_acquire(dquot); | 2309 | ret = dquot_acquire(dquot); |
@@ -2304,7 +2319,7 @@ static int ext3_release_dquot(struct dquot *dquot) | |||
2304 | handle_t *handle; | 2319 | handle_t *handle; |
2305 | 2320 | ||
2306 | handle = ext3_journal_start(dquot_to_inode(dquot), | 2321 | handle = ext3_journal_start(dquot_to_inode(dquot), |
2307 | EXT3_QUOTA_INIT_BLOCKS); | 2322 | EXT3_QUOTA_DEL_BLOCKS(dquot->dq_sb)); |
2308 | if (IS_ERR(handle)) | 2323 | if (IS_ERR(handle)) |
2309 | return PTR_ERR(handle); | 2324 | return PTR_ERR(handle); |
2310 | ret = dquot_release(dquot); | 2325 | ret = dquot_release(dquot); |
@@ -2361,6 +2376,8 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id, | |||
2361 | int err; | 2376 | int err; |
2362 | struct nameidata nd; | 2377 | struct nameidata nd; |
2363 | 2378 | ||
2379 | if (!test_opt(sb, QUOTA)) | ||
2380 | return -EINVAL; | ||
2364 | /* Not journalling quota? */ | 2381 | /* Not journalling quota? */ |
2365 | if (!EXT3_SB(sb)->s_qf_names[USRQUOTA] && | 2382 | if (!EXT3_SB(sb)->s_qf_names[USRQUOTA] && |
2366 | !EXT3_SB(sb)->s_qf_names[GRPQUOTA]) | 2383 | !EXT3_SB(sb)->s_qf_names[GRPQUOTA]) |
diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index 4cbc6d0212d3..3f9dfa643b19 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c | |||
@@ -1044,7 +1044,7 @@ ext3_xattr_set(struct inode *inode, int name_index, const char *name, | |||
1044 | int error, retries = 0; | 1044 | int error, retries = 0; |
1045 | 1045 | ||
1046 | retry: | 1046 | retry: |
1047 | handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS); | 1047 | handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); |
1048 | if (IS_ERR(handle)) { | 1048 | if (IS_ERR(handle)) { |
1049 | error = PTR_ERR(handle); | 1049 | error = PTR_ERR(handle); |
1050 | } else { | 1050 | } else { |
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index b82e470912e8..6e242556b903 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c | |||
@@ -191,7 +191,9 @@ lockd(struct svc_rqst *rqstp) | |||
191 | printk(KERN_DEBUG | 191 | printk(KERN_DEBUG |
192 | "lockd: new process, skipping host shutdown\n"); | 192 | "lockd: new process, skipping host shutdown\n"); |
193 | wake_up(&lockd_exit); | 193 | wake_up(&lockd_exit); |
194 | 194 | ||
195 | flush_signals(current); | ||
196 | |||
195 | /* Exit the RPC thread */ | 197 | /* Exit the RPC thread */ |
196 | svc_exit_thread(rqstp); | 198 | svc_exit_thread(rqstp); |
197 | 199 | ||
diff --git a/fs/namespace.c b/fs/namespace.c index 3b93e5d750eb..208c079e9fdb 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -337,7 +337,7 @@ int may_umount(struct vfsmount *mnt) | |||
337 | 337 | ||
338 | EXPORT_SYMBOL(may_umount); | 338 | EXPORT_SYMBOL(may_umount); |
339 | 339 | ||
340 | void umount_tree(struct vfsmount *mnt) | 340 | static void umount_tree(struct vfsmount *mnt) |
341 | { | 341 | { |
342 | struct vfsmount *p; | 342 | struct vfsmount *p; |
343 | LIST_HEAD(kill); | 343 | LIST_HEAD(kill); |
diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile index 9f043f44c92f..ce341dc76d5e 100644 --- a/fs/nfsd/Makefile +++ b/fs/nfsd/Makefile | |||
@@ -10,5 +10,5 @@ nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o | |||
10 | nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o | 10 | nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o |
11 | nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o | 11 | nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o |
12 | nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \ | 12 | nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \ |
13 | nfs4acl.o nfs4callback.o | 13 | nfs4acl.o nfs4callback.o nfs4recover.o |
14 | nfsd-objs := $(nfsd-y) | 14 | nfsd-objs := $(nfsd-y) |
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index 11ebf6c4aa54..4a2105552ac4 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c | |||
@@ -125,7 +125,7 @@ static short ace2type(struct nfs4_ace *); | |||
125 | static int _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, unsigned int); | 125 | static int _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, unsigned int); |
126 | static struct posix_acl *_nfsv4_to_posix_one(struct nfs4_acl *, unsigned int); | 126 | static struct posix_acl *_nfsv4_to_posix_one(struct nfs4_acl *, unsigned int); |
127 | int nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t); | 127 | int nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t); |
128 | int nfs4_acl_split(struct nfs4_acl *, struct nfs4_acl *); | 128 | static int nfs4_acl_split(struct nfs4_acl *, struct nfs4_acl *); |
129 | 129 | ||
130 | struct nfs4_acl * | 130 | struct nfs4_acl * |
131 | nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl, | 131 | nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl, |
@@ -775,7 +775,7 @@ out_err: | |||
775 | return pacl; | 775 | return pacl; |
776 | } | 776 | } |
777 | 777 | ||
778 | int | 778 | static int |
779 | nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl) | 779 | nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl) |
780 | { | 780 | { |
781 | struct list_head *h, *n; | 781 | struct list_head *h, *n; |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 634465e9cfc6..583c0710e45e 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -54,7 +54,6 @@ | |||
54 | 54 | ||
55 | /* declarations */ | 55 | /* declarations */ |
56 | static void nfs4_cb_null(struct rpc_task *task); | 56 | static void nfs4_cb_null(struct rpc_task *task); |
57 | extern spinlock_t recall_lock; | ||
58 | 57 | ||
59 | /* Index of predefined Linux callback client operations */ | 58 | /* Index of predefined Linux callback client operations */ |
60 | 59 | ||
@@ -329,12 +328,12 @@ out: | |||
329 | .p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2, \ | 328 | .p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2, \ |
330 | } | 329 | } |
331 | 330 | ||
332 | struct rpc_procinfo nfs4_cb_procedures[] = { | 331 | static struct rpc_procinfo nfs4_cb_procedures[] = { |
333 | PROC(CB_NULL, NULL, enc_cb_null, dec_cb_null), | 332 | PROC(CB_NULL, NULL, enc_cb_null, dec_cb_null), |
334 | PROC(CB_RECALL, COMPOUND, enc_cb_recall, dec_cb_recall), | 333 | PROC(CB_RECALL, COMPOUND, enc_cb_recall, dec_cb_recall), |
335 | }; | 334 | }; |
336 | 335 | ||
337 | struct rpc_version nfs_cb_version4 = { | 336 | static struct rpc_version nfs_cb_version4 = { |
338 | .number = 1, | 337 | .number = 1, |
339 | .nrprocs = sizeof(nfs4_cb_procedures)/sizeof(nfs4_cb_procedures[0]), | 338 | .nrprocs = sizeof(nfs4_cb_procedures)/sizeof(nfs4_cb_procedures[0]), |
340 | .procs = nfs4_cb_procedures | 339 | .procs = nfs4_cb_procedures |
@@ -348,7 +347,7 @@ static struct rpc_version * nfs_cb_version[] = { | |||
348 | /* | 347 | /* |
349 | * Use the SETCLIENTID credential | 348 | * Use the SETCLIENTID credential |
350 | */ | 349 | */ |
351 | struct rpc_cred * | 350 | static struct rpc_cred * |
352 | nfsd4_lookupcred(struct nfs4_client *clp, int taskflags) | 351 | nfsd4_lookupcred(struct nfs4_client *clp, int taskflags) |
353 | { | 352 | { |
354 | struct auth_cred acred; | 353 | struct auth_cred acred; |
@@ -387,9 +386,7 @@ nfsd4_probe_callback(struct nfs4_client *clp) | |||
387 | char hostname[32]; | 386 | char hostname[32]; |
388 | int status; | 387 | int status; |
389 | 388 | ||
390 | dprintk("NFSD: probe_callback. cb_parsed %d cb_set %d\n", | 389 | if (atomic_read(&cb->cb_set)) |
391 | cb->cb_parsed, atomic_read(&cb->cb_set)); | ||
392 | if (!cb->cb_parsed || atomic_read(&cb->cb_set)) | ||
393 | return; | 390 | return; |
394 | 391 | ||
395 | /* Initialize address */ | 392 | /* Initialize address */ |
@@ -427,7 +424,7 @@ nfsd4_probe_callback(struct nfs4_client *clp) | |||
427 | * XXX AUTH_UNIX only - need AUTH_GSS.... | 424 | * XXX AUTH_UNIX only - need AUTH_GSS.... |
428 | */ | 425 | */ |
429 | sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr.sin_addr.s_addr)); | 426 | sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr.sin_addr.s_addr)); |
430 | clnt = rpc_create_client(xprt, hostname, program, 1, RPC_AUTH_UNIX); | 427 | clnt = rpc_new_client(xprt, hostname, program, 1, RPC_AUTH_UNIX); |
431 | if (IS_ERR(clnt)) { | 428 | if (IS_ERR(clnt)) { |
432 | dprintk("NFSD: couldn't create callback client\n"); | 429 | dprintk("NFSD: couldn't create callback client\n"); |
433 | goto out_err; | 430 | goto out_err; |
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 4ba540841cf6..5605a26efc57 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c | |||
@@ -104,7 +104,7 @@ ent_update(struct ent *new, struct ent *itm) | |||
104 | ent_init(new, itm); | 104 | ent_init(new, itm); |
105 | } | 105 | } |
106 | 106 | ||
107 | void | 107 | static void |
108 | ent_put(struct cache_head *ch, struct cache_detail *cd) | 108 | ent_put(struct cache_head *ch, struct cache_detail *cd) |
109 | { | 109 | { |
110 | if (cache_put(ch, cd)) { | 110 | if (cache_put(ch, cd)) { |
@@ -186,7 +186,7 @@ warn_no_idmapd(struct cache_detail *detail) | |||
186 | static int idtoname_parse(struct cache_detail *, char *, int); | 186 | static int idtoname_parse(struct cache_detail *, char *, int); |
187 | static struct ent *idtoname_lookup(struct ent *, int); | 187 | static struct ent *idtoname_lookup(struct ent *, int); |
188 | 188 | ||
189 | struct cache_detail idtoname_cache = { | 189 | static struct cache_detail idtoname_cache = { |
190 | .hash_size = ENT_HASHMAX, | 190 | .hash_size = ENT_HASHMAX, |
191 | .hash_table = idtoname_table, | 191 | .hash_table = idtoname_table, |
192 | .name = "nfs4.idtoname", | 192 | .name = "nfs4.idtoname", |
@@ -277,7 +277,7 @@ nametoid_hash(struct ent *ent) | |||
277 | return hash_str(ent->name, ENT_HASHBITS); | 277 | return hash_str(ent->name, ENT_HASHBITS); |
278 | } | 278 | } |
279 | 279 | ||
280 | void | 280 | static void |
281 | nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, | 281 | nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp, |
282 | int *blen) | 282 | int *blen) |
283 | { | 283 | { |
@@ -317,9 +317,9 @@ nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h) | |||
317 | } | 317 | } |
318 | 318 | ||
319 | static struct ent *nametoid_lookup(struct ent *, int); | 319 | static struct ent *nametoid_lookup(struct ent *, int); |
320 | int nametoid_parse(struct cache_detail *, char *, int); | 320 | static int nametoid_parse(struct cache_detail *, char *, int); |
321 | 321 | ||
322 | struct cache_detail nametoid_cache = { | 322 | static struct cache_detail nametoid_cache = { |
323 | .hash_size = ENT_HASHMAX, | 323 | .hash_size = ENT_HASHMAX, |
324 | .hash_table = nametoid_table, | 324 | .hash_table = nametoid_table, |
325 | .name = "nfs4.nametoid", | 325 | .name = "nfs4.nametoid", |
@@ -330,7 +330,7 @@ struct cache_detail nametoid_cache = { | |||
330 | .warn_no_listener = warn_no_idmapd, | 330 | .warn_no_listener = warn_no_idmapd, |
331 | }; | 331 | }; |
332 | 332 | ||
333 | int | 333 | static int |
334 | nametoid_parse(struct cache_detail *cd, char *buf, int buflen) | 334 | nametoid_parse(struct cache_detail *cd, char *buf, int buflen) |
335 | { | 335 | { |
336 | struct ent ent, *res; | 336 | struct ent ent, *res; |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index e8158741e8b5..d71f14517b9c 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <linux/param.h> | 45 | #include <linux/param.h> |
46 | #include <linux/major.h> | 46 | #include <linux/major.h> |
47 | #include <linux/slab.h> | 47 | #include <linux/slab.h> |
48 | #include <linux/file.h> | ||
48 | 49 | ||
49 | #include <linux/sunrpc/svc.h> | 50 | #include <linux/sunrpc/svc.h> |
50 | #include <linux/nfsd/nfsd.h> | 51 | #include <linux/nfsd/nfsd.h> |
@@ -198,6 +199,11 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open | |||
198 | if (status) | 199 | if (status) |
199 | goto out; | 200 | goto out; |
200 | switch (open->op_claim_type) { | 201 | switch (open->op_claim_type) { |
202 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: | ||
203 | status = nfserr_inval; | ||
204 | if (open->op_create) | ||
205 | goto out; | ||
206 | /* fall through */ | ||
201 | case NFS4_OPEN_CLAIM_NULL: | 207 | case NFS4_OPEN_CLAIM_NULL: |
202 | /* | 208 | /* |
203 | * (1) set CURRENT_FH to the file being opened, | 209 | * (1) set CURRENT_FH to the file being opened, |
@@ -220,7 +226,6 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open | |||
220 | if (status) | 226 | if (status) |
221 | goto out; | 227 | goto out; |
222 | break; | 228 | break; |
223 | case NFS4_OPEN_CLAIM_DELEGATE_CUR: | ||
224 | case NFS4_OPEN_CLAIM_DELEGATE_PREV: | 229 | case NFS4_OPEN_CLAIM_DELEGATE_PREV: |
225 | printk("NFSD: unsupported OPEN claim type %d\n", | 230 | printk("NFSD: unsupported OPEN claim type %d\n", |
226 | open->op_claim_type); | 231 | open->op_claim_type); |
@@ -473,26 +478,27 @@ static inline int | |||
473 | nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read) | 478 | nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read) |
474 | { | 479 | { |
475 | int status; | 480 | int status; |
476 | struct file *filp = NULL; | ||
477 | 481 | ||
478 | /* no need to check permission - this will be done in nfsd_read() */ | 482 | /* no need to check permission - this will be done in nfsd_read() */ |
479 | 483 | ||
484 | read->rd_filp = NULL; | ||
480 | if (read->rd_offset >= OFFSET_MAX) | 485 | if (read->rd_offset >= OFFSET_MAX) |
481 | return nfserr_inval; | 486 | return nfserr_inval; |
482 | 487 | ||
483 | nfs4_lock_state(); | 488 | nfs4_lock_state(); |
484 | /* check stateid */ | 489 | /* check stateid */ |
485 | if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid, | 490 | if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid, |
486 | CHECK_FH | RD_STATE, &filp))) { | 491 | CHECK_FH | RD_STATE, &read->rd_filp))) { |
487 | dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); | 492 | dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); |
488 | goto out; | 493 | goto out; |
489 | } | 494 | } |
495 | if (read->rd_filp) | ||
496 | get_file(read->rd_filp); | ||
490 | status = nfs_ok; | 497 | status = nfs_ok; |
491 | out: | 498 | out: |
492 | nfs4_unlock_state(); | 499 | nfs4_unlock_state(); |
493 | read->rd_rqstp = rqstp; | 500 | read->rd_rqstp = rqstp; |
494 | read->rd_fhp = current_fh; | 501 | read->rd_fhp = current_fh; |
495 | read->rd_filp = filp; | ||
496 | return status; | 502 | return status; |
497 | } | 503 | } |
498 | 504 | ||
@@ -532,6 +538,8 @@ nfsd4_remove(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_rem | |||
532 | { | 538 | { |
533 | int status; | 539 | int status; |
534 | 540 | ||
541 | if (nfs4_in_grace()) | ||
542 | return nfserr_grace; | ||
535 | status = nfsd_unlink(rqstp, current_fh, 0, remove->rm_name, remove->rm_namelen); | 543 | status = nfsd_unlink(rqstp, current_fh, 0, remove->rm_name, remove->rm_namelen); |
536 | if (status == nfserr_symlink) | 544 | if (status == nfserr_symlink) |
537 | return nfserr_notdir; | 545 | return nfserr_notdir; |
@@ -550,6 +558,9 @@ nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh, | |||
550 | 558 | ||
551 | if (!save_fh->fh_dentry) | 559 | if (!save_fh->fh_dentry) |
552 | return status; | 560 | return status; |
561 | if (nfs4_in_grace() && !(save_fh->fh_export->ex_flags | ||
562 | & NFSEXP_NOSUBTREECHECK)) | ||
563 | return nfserr_grace; | ||
553 | status = nfsd_rename(rqstp, save_fh, rename->rn_sname, | 564 | status = nfsd_rename(rqstp, save_fh, rename->rn_sname, |
554 | rename->rn_snamelen, current_fh, | 565 | rename->rn_snamelen, current_fh, |
555 | rename->rn_tname, rename->rn_tnamelen); | 566 | rename->rn_tname, rename->rn_tnamelen); |
@@ -624,6 +635,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ | |||
624 | dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); | 635 | dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); |
625 | goto out; | 636 | goto out; |
626 | } | 637 | } |
638 | if (filp) | ||
639 | get_file(filp); | ||
627 | nfs4_unlock_state(); | 640 | nfs4_unlock_state(); |
628 | 641 | ||
629 | write->wr_bytes_written = write->wr_buflen; | 642 | write->wr_bytes_written = write->wr_buflen; |
@@ -635,6 +648,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ | |||
635 | status = nfsd_write(rqstp, current_fh, filp, write->wr_offset, | 648 | status = nfsd_write(rqstp, current_fh, filp, write->wr_offset, |
636 | write->wr_vec, write->wr_vlen, write->wr_buflen, | 649 | write->wr_vec, write->wr_vlen, write->wr_buflen, |
637 | &write->wr_how_written); | 650 | &write->wr_how_written); |
651 | if (filp) | ||
652 | fput(filp); | ||
638 | 653 | ||
639 | if (status == nfserr_symlink) | 654 | if (status == nfserr_symlink) |
640 | status = nfserr_inval; | 655 | status = nfserr_inval; |
@@ -923,6 +938,9 @@ encode_op: | |||
923 | nfs4_put_stateowner(replay_owner); | 938 | nfs4_put_stateowner(replay_owner); |
924 | replay_owner = NULL; | 939 | replay_owner = NULL; |
925 | } | 940 | } |
941 | /* XXX Ugh, we need to get rid of this kind of special case: */ | ||
942 | if (op->opnum == OP_READ && op->u.read.rd_filp) | ||
943 | fput(op->u.read.rd_filp); | ||
926 | } | 944 | } |
927 | 945 | ||
928 | out: | 946 | out: |
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c new file mode 100644 index 000000000000..095f1740f3ae --- /dev/null +++ b/fs/nfsd/nfs4recover.c | |||
@@ -0,0 +1,431 @@ | |||
1 | /* | ||
2 | * linux/fs/nfsd/nfs4recover.c | ||
3 | * | ||
4 | * Copyright (c) 2004 The Regents of the University of Michigan. | ||
5 | * All rights reserved. | ||
6 | * | ||
7 | * Andy Adamson <andros@citi.umich.edu> | ||
8 | * | ||
9 | * Redistribution and use in source and binary forms, with or without | ||
10 | * modification, are permitted provided that the following conditions | ||
11 | * are met: | ||
12 | * | ||
13 | * 1. Redistributions of source code must retain the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer. | ||
15 | * 2. Redistributions in binary form must reproduce the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer in the | ||
17 | * documentation and/or other materials provided with the distribution. | ||
18 | * 3. Neither the name of the University nor the names of its | ||
19 | * contributors may be used to endorse or promote products derived | ||
20 | * from this software without specific prior written permission. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | ||
23 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | ||
24 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
25 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
31 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | * | ||
34 | */ | ||
35 | |||
36 | |||
37 | #include <linux/sunrpc/svc.h> | ||
38 | #include <linux/nfsd/nfsd.h> | ||
39 | #include <linux/nfs4.h> | ||
40 | #include <linux/nfsd/state.h> | ||
41 | #include <linux/nfsd/xdr4.h> | ||
42 | #include <linux/param.h> | ||
43 | #include <linux/file.h> | ||
44 | #include <linux/namei.h> | ||
45 | #include <asm/uaccess.h> | ||
46 | #include <asm/scatterlist.h> | ||
47 | #include <linux/crypto.h> | ||
48 | |||
49 | |||
50 | #define NFSDDBG_FACILITY NFSDDBG_PROC | ||
51 | |||
52 | /* Globals */ | ||
53 | static struct nameidata rec_dir; | ||
54 | static int rec_dir_init = 0; | ||
55 | |||
56 | static void | ||
57 | nfs4_save_user(uid_t *saveuid, gid_t *savegid) | ||
58 | { | ||
59 | *saveuid = current->fsuid; | ||
60 | *savegid = current->fsgid; | ||
61 | current->fsuid = 0; | ||
62 | current->fsgid = 0; | ||
63 | } | ||
64 | |||
65 | static void | ||
66 | nfs4_reset_user(uid_t saveuid, gid_t savegid) | ||
67 | { | ||
68 | current->fsuid = saveuid; | ||
69 | current->fsgid = savegid; | ||
70 | } | ||
71 | |||
72 | static void | ||
73 | md5_to_hex(char *out, char *md5) | ||
74 | { | ||
75 | int i; | ||
76 | |||
77 | for (i=0; i<16; i++) { | ||
78 | unsigned char c = md5[i]; | ||
79 | |||
80 | *out++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1); | ||
81 | *out++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1); | ||
82 | } | ||
83 | *out = '\0'; | ||
84 | } | ||
85 | |||
86 | int | ||
87 | nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname) | ||
88 | { | ||
89 | struct xdr_netobj cksum; | ||
90 | struct crypto_tfm *tfm; | ||
91 | struct scatterlist sg[1]; | ||
92 | int status = nfserr_resource; | ||
93 | |||
94 | dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n", | ||
95 | clname->len, clname->data); | ||
96 | tfm = crypto_alloc_tfm("md5", 0); | ||
97 | if (tfm == NULL) | ||
98 | goto out; | ||
99 | cksum.len = crypto_tfm_alg_digestsize(tfm); | ||
100 | cksum.data = kmalloc(cksum.len, GFP_KERNEL); | ||
101 | if (cksum.data == NULL) | ||
102 | goto out; | ||
103 | crypto_digest_init(tfm); | ||
104 | |||
105 | sg[0].page = virt_to_page(clname->data); | ||
106 | sg[0].offset = offset_in_page(clname->data); | ||
107 | sg[0].length = clname->len; | ||
108 | |||
109 | crypto_digest_update(tfm, sg, 1); | ||
110 | crypto_digest_final(tfm, cksum.data); | ||
111 | |||
112 | md5_to_hex(dname, cksum.data); | ||
113 | |||
114 | kfree(cksum.data); | ||
115 | status = nfs_ok; | ||
116 | out: | ||
117 | if (tfm) | ||
118 | crypto_free_tfm(tfm); | ||
119 | return status; | ||
120 | } | ||
121 | |||
122 | static int | ||
123 | nfsd4_rec_fsync(struct dentry *dentry) | ||
124 | { | ||
125 | struct file *filp; | ||
126 | int status = nfs_ok; | ||
127 | |||
128 | dprintk("NFSD: nfs4_fsync_rec_dir\n"); | ||
129 | filp = dentry_open(dget(dentry), mntget(rec_dir.mnt), O_RDWR); | ||
130 | if (IS_ERR(filp)) { | ||
131 | status = PTR_ERR(filp); | ||
132 | goto out; | ||
133 | } | ||
134 | if (filp->f_op && filp->f_op->fsync) | ||
135 | status = filp->f_op->fsync(filp, filp->f_dentry, 0); | ||
136 | fput(filp); | ||
137 | out: | ||
138 | if (status) | ||
139 | printk("nfsd4: unable to sync recovery directory\n"); | ||
140 | return status; | ||
141 | } | ||
142 | |||
143 | int | ||
144 | nfsd4_create_clid_dir(struct nfs4_client *clp) | ||
145 | { | ||
146 | char *dname = clp->cl_recdir; | ||
147 | struct dentry *dentry; | ||
148 | uid_t uid; | ||
149 | gid_t gid; | ||
150 | int status; | ||
151 | |||
152 | dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname); | ||
153 | |||
154 | if (!rec_dir_init || clp->cl_firststate) | ||
155 | return 0; | ||
156 | |||
157 | nfs4_save_user(&uid, &gid); | ||
158 | |||
159 | /* lock the parent */ | ||
160 | down(&rec_dir.dentry->d_inode->i_sem); | ||
161 | |||
162 | dentry = lookup_one_len(dname, rec_dir.dentry, HEXDIR_LEN-1); | ||
163 | if (IS_ERR(dentry)) { | ||
164 | status = PTR_ERR(dentry); | ||
165 | goto out_unlock; | ||
166 | } | ||
167 | status = -EEXIST; | ||
168 | if (dentry->d_inode) { | ||
169 | dprintk("NFSD: nfsd4_create_clid_dir: DIRECTORY EXISTS\n"); | ||
170 | goto out_put; | ||
171 | } | ||
172 | status = vfs_mkdir(rec_dir.dentry->d_inode, dentry, S_IRWXU); | ||
173 | out_put: | ||
174 | dput(dentry); | ||
175 | out_unlock: | ||
176 | up(&rec_dir.dentry->d_inode->i_sem); | ||
177 | if (status == 0) { | ||
178 | clp->cl_firststate = 1; | ||
179 | status = nfsd4_rec_fsync(rec_dir.dentry); | ||
180 | } | ||
181 | nfs4_reset_user(uid, gid); | ||
182 | dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status); | ||
183 | return status; | ||
184 | } | ||
185 | |||
186 | typedef int (recdir_func)(struct dentry *, struct dentry *); | ||
187 | |||
188 | struct dentry_list { | ||
189 | struct dentry *dentry; | ||
190 | struct list_head list; | ||
191 | }; | ||
192 | |||
193 | struct dentry_list_arg { | ||
194 | struct list_head dentries; | ||
195 | struct dentry *parent; | ||
196 | }; | ||
197 | |||
198 | static int | ||
199 | nfsd4_build_dentrylist(void *arg, const char *name, int namlen, | ||
200 | loff_t offset, ino_t ino, unsigned int d_type) | ||
201 | { | ||
202 | struct dentry_list_arg *dla = arg; | ||
203 | struct list_head *dentries = &dla->dentries; | ||
204 | struct dentry *parent = dla->parent; | ||
205 | struct dentry *dentry; | ||
206 | struct dentry_list *child; | ||
207 | |||
208 | if (name && isdotent(name, namlen)) | ||
209 | return nfs_ok; | ||
210 | dentry = lookup_one_len(name, parent, namlen); | ||
211 | if (IS_ERR(dentry)) | ||
212 | return PTR_ERR(dentry); | ||
213 | child = kmalloc(sizeof(*child), GFP_KERNEL); | ||
214 | if (child == NULL) | ||
215 | return -ENOMEM; | ||
216 | child->dentry = dentry; | ||
217 | list_add(&child->list, dentries); | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static int | ||
222 | nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f) | ||
223 | { | ||
224 | struct file *filp; | ||
225 | struct dentry_list_arg dla = { | ||
226 | .parent = dir, | ||
227 | }; | ||
228 | struct list_head *dentries = &dla.dentries; | ||
229 | struct dentry_list *child; | ||
230 | uid_t uid; | ||
231 | gid_t gid; | ||
232 | int status; | ||
233 | |||
234 | if (!rec_dir_init) | ||
235 | return 0; | ||
236 | |||
237 | nfs4_save_user(&uid, &gid); | ||
238 | |||
239 | filp = dentry_open(dget(dir), mntget(rec_dir.mnt), | ||
240 | O_RDWR); | ||
241 | status = PTR_ERR(filp); | ||
242 | if (IS_ERR(filp)) | ||
243 | goto out; | ||
244 | INIT_LIST_HEAD(dentries); | ||
245 | status = vfs_readdir(filp, nfsd4_build_dentrylist, &dla); | ||
246 | fput(filp); | ||
247 | while (!list_empty(dentries)) { | ||
248 | child = list_entry(dentries->next, struct dentry_list, list); | ||
249 | status = f(dir, child->dentry); | ||
250 | if (status) | ||
251 | goto out; | ||
252 | list_del(&child->list); | ||
253 | dput(child->dentry); | ||
254 | kfree(child); | ||
255 | } | ||
256 | out: | ||
257 | while (!list_empty(dentries)) { | ||
258 | child = list_entry(dentries->next, struct dentry_list, list); | ||
259 | list_del(&child->list); | ||
260 | dput(child->dentry); | ||
261 | kfree(child); | ||
262 | } | ||
263 | nfs4_reset_user(uid, gid); | ||
264 | return status; | ||
265 | } | ||
266 | |||
267 | static int | ||
268 | nfsd4_remove_clid_file(struct dentry *dir, struct dentry *dentry) | ||
269 | { | ||
270 | int status; | ||
271 | |||
272 | if (!S_ISREG(dir->d_inode->i_mode)) { | ||
273 | printk("nfsd4: non-file found in client recovery directory\n"); | ||
274 | return -EINVAL; | ||
275 | } | ||
276 | down(&dir->d_inode->i_sem); | ||
277 | status = vfs_unlink(dir->d_inode, dentry); | ||
278 | up(&dir->d_inode->i_sem); | ||
279 | return status; | ||
280 | } | ||
281 | |||
282 | static int | ||
283 | nfsd4_clear_clid_dir(struct dentry *dir, struct dentry *dentry) | ||
284 | { | ||
285 | int status; | ||
286 | |||
287 | /* For now this directory should already be empty, but we empty it of | ||
288 | * any regular files anyway, just in case the directory was created by | ||
289 | * a kernel from the future.... */ | ||
290 | nfsd4_list_rec_dir(dentry, nfsd4_remove_clid_file); | ||
291 | down(&dir->d_inode->i_sem); | ||
292 | status = vfs_rmdir(dir->d_inode, dentry); | ||
293 | up(&dir->d_inode->i_sem); | ||
294 | return status; | ||
295 | } | ||
296 | |||
297 | static int | ||
298 | nfsd4_unlink_clid_dir(char *name, int namlen) | ||
299 | { | ||
300 | struct dentry *dentry; | ||
301 | int status; | ||
302 | |||
303 | dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name); | ||
304 | |||
305 | dentry = lookup_one_len(name, rec_dir.dentry, namlen); | ||
306 | if (IS_ERR(dentry)) { | ||
307 | status = PTR_ERR(dentry); | ||
308 | return status; | ||
309 | } | ||
310 | status = -ENOENT; | ||
311 | if (!dentry->d_inode) | ||
312 | goto out; | ||
313 | |||
314 | status = nfsd4_clear_clid_dir(rec_dir.dentry, dentry); | ||
315 | out: | ||
316 | dput(dentry); | ||
317 | return status; | ||
318 | } | ||
319 | |||
320 | void | ||
321 | nfsd4_remove_clid_dir(struct nfs4_client *clp) | ||
322 | { | ||
323 | uid_t uid; | ||
324 | gid_t gid; | ||
325 | int status; | ||
326 | |||
327 | if (!rec_dir_init || !clp->cl_firststate) | ||
328 | return; | ||
329 | |||
330 | nfs4_save_user(&uid, &gid); | ||
331 | status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1); | ||
332 | nfs4_reset_user(uid, gid); | ||
333 | if (status == 0) | ||
334 | status = nfsd4_rec_fsync(rec_dir.dentry); | ||
335 | if (status) | ||
336 | printk("NFSD: Failed to remove expired client state directory" | ||
337 | " %.*s\n", HEXDIR_LEN, clp->cl_recdir); | ||
338 | return; | ||
339 | } | ||
340 | |||
341 | static int | ||
342 | purge_old(struct dentry *parent, struct dentry *child) | ||
343 | { | ||
344 | int status; | ||
345 | |||
346 | if (nfs4_has_reclaimed_state(child->d_name.name)) | ||
347 | return nfs_ok; | ||
348 | |||
349 | status = nfsd4_clear_clid_dir(parent, child); | ||
350 | if (status) | ||
351 | printk("failed to remove client recovery directory %s\n", | ||
352 | child->d_name.name); | ||
353 | /* Keep trying, success or failure: */ | ||
354 | return nfs_ok; | ||
355 | } | ||
356 | |||
357 | void | ||
358 | nfsd4_recdir_purge_old(void) { | ||
359 | int status; | ||
360 | |||
361 | if (!rec_dir_init) | ||
362 | return; | ||
363 | status = nfsd4_list_rec_dir(rec_dir.dentry, purge_old); | ||
364 | if (status == 0) | ||
365 | status = nfsd4_rec_fsync(rec_dir.dentry); | ||
366 | if (status) | ||
367 | printk("nfsd4: failed to purge old clients from recovery" | ||
368 | " directory %s\n", rec_dir.dentry->d_name.name); | ||
369 | return; | ||
370 | } | ||
371 | |||
372 | static int | ||
373 | load_recdir(struct dentry *parent, struct dentry *child) | ||
374 | { | ||
375 | if (child->d_name.len != HEXDIR_LEN - 1) { | ||
376 | printk("nfsd4: illegal name %s in recovery directory\n", | ||
377 | child->d_name.name); | ||
378 | /* Keep trying; maybe the others are OK: */ | ||
379 | return nfs_ok; | ||
380 | } | ||
381 | nfs4_client_to_reclaim(child->d_name.name); | ||
382 | return nfs_ok; | ||
383 | } | ||
384 | |||
385 | int | ||
386 | nfsd4_recdir_load(void) { | ||
387 | int status; | ||
388 | |||
389 | status = nfsd4_list_rec_dir(rec_dir.dentry, load_recdir); | ||
390 | if (status) | ||
391 | printk("nfsd4: failed loading clients from recovery" | ||
392 | " directory %s\n", rec_dir.dentry->d_name.name); | ||
393 | return status; | ||
394 | } | ||
395 | |||
396 | /* | ||
397 | * Hold reference to the recovery directory. | ||
398 | */ | ||
399 | |||
400 | void | ||
401 | nfsd4_init_recdir(char *rec_dirname) | ||
402 | { | ||
403 | uid_t uid = 0; | ||
404 | gid_t gid = 0; | ||
405 | int status; | ||
406 | |||
407 | printk("NFSD: Using %s as the NFSv4 state recovery directory\n", | ||
408 | rec_dirname); | ||
409 | |||
410 | BUG_ON(rec_dir_init); | ||
411 | |||
412 | nfs4_save_user(&uid, &gid); | ||
413 | |||
414 | status = path_lookup(rec_dirname, LOOKUP_FOLLOW, &rec_dir); | ||
415 | if (status == -ENOENT) | ||
416 | printk("NFSD: recovery directory %s doesn't exist\n", | ||
417 | rec_dirname); | ||
418 | |||
419 | if (!status) | ||
420 | rec_dir_init = 1; | ||
421 | nfs4_reset_user(uid, gid); | ||
422 | } | ||
423 | |||
424 | void | ||
425 | nfsd4_shutdown_recdir(void) | ||
426 | { | ||
427 | if (!rec_dir_init) | ||
428 | return; | ||
429 | rec_dir_init = 0; | ||
430 | path_release(&rec_dir); | ||
431 | } | ||
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 75e8b137580c..89e36526d7f2 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -48,39 +48,32 @@ | |||
48 | #include <linux/nfs4.h> | 48 | #include <linux/nfs4.h> |
49 | #include <linux/nfsd/state.h> | 49 | #include <linux/nfsd/state.h> |
50 | #include <linux/nfsd/xdr4.h> | 50 | #include <linux/nfsd/xdr4.h> |
51 | #include <linux/namei.h> | ||
51 | 52 | ||
52 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 53 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
53 | 54 | ||
54 | /* Globals */ | 55 | /* Globals */ |
55 | static time_t lease_time = 90; /* default lease time */ | 56 | static time_t lease_time = 90; /* default lease time */ |
56 | static time_t old_lease_time = 90; /* past incarnation lease time */ | 57 | static time_t user_lease_time = 90; |
57 | static u32 nfs4_reclaim_init = 0; | 58 | static time_t boot_time; |
58 | time_t boot_time; | 59 | static int in_grace = 1; |
59 | static time_t grace_end = 0; | ||
60 | static u32 current_clientid = 1; | 60 | static u32 current_clientid = 1; |
61 | static u32 current_ownerid = 1; | 61 | static u32 current_ownerid = 1; |
62 | static u32 current_fileid = 1; | 62 | static u32 current_fileid = 1; |
63 | static u32 current_delegid = 1; | 63 | static u32 current_delegid = 1; |
64 | static u32 nfs4_init; | 64 | static u32 nfs4_init; |
65 | stateid_t zerostateid; /* bits all 0 */ | 65 | static stateid_t zerostateid; /* bits all 0 */ |
66 | stateid_t onestateid; /* bits all 1 */ | 66 | static stateid_t onestateid; /* bits all 1 */ |
67 | 67 | ||
68 | /* debug counters */ | 68 | #define ZERO_STATEID(stateid) (!memcmp((stateid), &zerostateid, sizeof(stateid_t))) |
69 | u32 list_add_perfile = 0; | 69 | #define ONE_STATEID(stateid) (!memcmp((stateid), &onestateid, sizeof(stateid_t))) |
70 | u32 list_del_perfile = 0; | ||
71 | u32 add_perclient = 0; | ||
72 | u32 del_perclient = 0; | ||
73 | u32 alloc_file = 0; | ||
74 | u32 free_file = 0; | ||
75 | u32 vfsopen = 0; | ||
76 | u32 vfsclose = 0; | ||
77 | u32 alloc_delegation= 0; | ||
78 | u32 free_delegation= 0; | ||
79 | 70 | ||
80 | /* forward declarations */ | 71 | /* forward declarations */ |
81 | struct nfs4_stateid * find_stateid(stateid_t *stid, int flags); | 72 | static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags); |
82 | static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid); | 73 | static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid); |
83 | static void release_stateid_lockowners(struct nfs4_stateid *open_stp); | 74 | static void release_stateid_lockowners(struct nfs4_stateid *open_stp); |
75 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; | ||
76 | static void nfs4_set_recdir(char *recdir); | ||
84 | 77 | ||
85 | /* Locking: | 78 | /* Locking: |
86 | * | 79 | * |
@@ -90,6 +83,11 @@ static void release_stateid_lockowners(struct nfs4_stateid *open_stp); | |||
90 | */ | 83 | */ |
91 | static DECLARE_MUTEX(client_sema); | 84 | static DECLARE_MUTEX(client_sema); |
92 | 85 | ||
86 | static kmem_cache_t *stateowner_slab = NULL; | ||
87 | static kmem_cache_t *file_slab = NULL; | ||
88 | static kmem_cache_t *stateid_slab = NULL; | ||
89 | static kmem_cache_t *deleg_slab = NULL; | ||
90 | |||
93 | void | 91 | void |
94 | nfs4_lock_state(void) | 92 | nfs4_lock_state(void) |
95 | { | 93 | { |
@@ -118,16 +116,36 @@ opaque_hashval(const void *ptr, int nbytes) | |||
118 | /* forward declarations */ | 116 | /* forward declarations */ |
119 | static void release_stateowner(struct nfs4_stateowner *sop); | 117 | static void release_stateowner(struct nfs4_stateowner *sop); |
120 | static void release_stateid(struct nfs4_stateid *stp, int flags); | 118 | static void release_stateid(struct nfs4_stateid *stp, int flags); |
121 | static void release_file(struct nfs4_file *fp); | ||
122 | 119 | ||
123 | /* | 120 | /* |
124 | * Delegation state | 121 | * Delegation state |
125 | */ | 122 | */ |
126 | 123 | ||
127 | /* recall_lock protects the del_recall_lru */ | 124 | /* recall_lock protects the del_recall_lru */ |
128 | spinlock_t recall_lock; | 125 | static spinlock_t recall_lock = SPIN_LOCK_UNLOCKED; |
129 | static struct list_head del_recall_lru; | 126 | static struct list_head del_recall_lru; |
130 | 127 | ||
128 | static void | ||
129 | free_nfs4_file(struct kref *kref) | ||
130 | { | ||
131 | struct nfs4_file *fp = container_of(kref, struct nfs4_file, fi_ref); | ||
132 | list_del(&fp->fi_hash); | ||
133 | iput(fp->fi_inode); | ||
134 | kmem_cache_free(file_slab, fp); | ||
135 | } | ||
136 | |||
137 | static inline void | ||
138 | put_nfs4_file(struct nfs4_file *fi) | ||
139 | { | ||
140 | kref_put(&fi->fi_ref, free_nfs4_file); | ||
141 | } | ||
142 | |||
143 | static inline void | ||
144 | get_nfs4_file(struct nfs4_file *fi) | ||
145 | { | ||
146 | kref_get(&fi->fi_ref); | ||
147 | } | ||
148 | |||
131 | static struct nfs4_delegation * | 149 | static struct nfs4_delegation * |
132 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) | 150 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) |
133 | { | 151 | { |
@@ -136,13 +154,14 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
136 | struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback; | 154 | struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback; |
137 | 155 | ||
138 | dprintk("NFSD alloc_init_deleg\n"); | 156 | dprintk("NFSD alloc_init_deleg\n"); |
139 | if ((dp = kmalloc(sizeof(struct nfs4_delegation), | 157 | dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL); |
140 | GFP_KERNEL)) == NULL) | 158 | if (dp == NULL) |
141 | return dp; | 159 | return dp; |
142 | INIT_LIST_HEAD(&dp->dl_del_perfile); | 160 | INIT_LIST_HEAD(&dp->dl_perfile); |
143 | INIT_LIST_HEAD(&dp->dl_del_perclnt); | 161 | INIT_LIST_HEAD(&dp->dl_perclnt); |
144 | INIT_LIST_HEAD(&dp->dl_recall_lru); | 162 | INIT_LIST_HEAD(&dp->dl_recall_lru); |
145 | dp->dl_client = clp; | 163 | dp->dl_client = clp; |
164 | get_nfs4_file(fp); | ||
146 | dp->dl_file = fp; | 165 | dp->dl_file = fp; |
147 | dp->dl_flock = NULL; | 166 | dp->dl_flock = NULL; |
148 | get_file(stp->st_vfs_file); | 167 | get_file(stp->st_vfs_file); |
@@ -160,9 +179,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
160 | current_fh->fh_handle.fh_size); | 179 | current_fh->fh_handle.fh_size); |
161 | dp->dl_time = 0; | 180 | dp->dl_time = 0; |
162 | atomic_set(&dp->dl_count, 1); | 181 | atomic_set(&dp->dl_count, 1); |
163 | list_add(&dp->dl_del_perfile, &fp->fi_del_perfile); | 182 | list_add(&dp->dl_perfile, &fp->fi_delegations); |
164 | list_add(&dp->dl_del_perclnt, &clp->cl_del_perclnt); | 183 | list_add(&dp->dl_perclnt, &clp->cl_delegations); |
165 | alloc_delegation++; | ||
166 | return dp; | 184 | return dp; |
167 | } | 185 | } |
168 | 186 | ||
@@ -171,8 +189,8 @@ nfs4_put_delegation(struct nfs4_delegation *dp) | |||
171 | { | 189 | { |
172 | if (atomic_dec_and_test(&dp->dl_count)) { | 190 | if (atomic_dec_and_test(&dp->dl_count)) { |
173 | dprintk("NFSD: freeing dp %p\n",dp); | 191 | dprintk("NFSD: freeing dp %p\n",dp); |
174 | kfree(dp); | 192 | put_nfs4_file(dp->dl_file); |
175 | free_delegation++; | 193 | kmem_cache_free(deleg_slab, dp); |
176 | } | 194 | } |
177 | } | 195 | } |
178 | 196 | ||
@@ -193,15 +211,14 @@ nfs4_close_delegation(struct nfs4_delegation *dp) | |||
193 | if (dp->dl_flock) | 211 | if (dp->dl_flock) |
194 | setlease(filp, F_UNLCK, &dp->dl_flock); | 212 | setlease(filp, F_UNLCK, &dp->dl_flock); |
195 | nfsd_close(filp); | 213 | nfsd_close(filp); |
196 | vfsclose++; | ||
197 | } | 214 | } |
198 | 215 | ||
199 | /* Called under the state lock. */ | 216 | /* Called under the state lock. */ |
200 | static void | 217 | static void |
201 | unhash_delegation(struct nfs4_delegation *dp) | 218 | unhash_delegation(struct nfs4_delegation *dp) |
202 | { | 219 | { |
203 | list_del_init(&dp->dl_del_perfile); | 220 | list_del_init(&dp->dl_perfile); |
204 | list_del_init(&dp->dl_del_perclnt); | 221 | list_del_init(&dp->dl_perclnt); |
205 | spin_lock(&recall_lock); | 222 | spin_lock(&recall_lock); |
206 | list_del_init(&dp->dl_recall_lru); | 223 | list_del_init(&dp->dl_recall_lru); |
207 | spin_unlock(&recall_lock); | 224 | spin_unlock(&recall_lock); |
@@ -220,8 +237,8 @@ unhash_delegation(struct nfs4_delegation *dp) | |||
220 | 237 | ||
221 | #define clientid_hashval(id) \ | 238 | #define clientid_hashval(id) \ |
222 | ((id) & CLIENT_HASH_MASK) | 239 | ((id) & CLIENT_HASH_MASK) |
223 | #define clientstr_hashval(name, namelen) \ | 240 | #define clientstr_hashval(name) \ |
224 | (opaque_hashval((name), (namelen)) & CLIENT_HASH_MASK) | 241 | (opaque_hashval((name), 8) & CLIENT_HASH_MASK) |
225 | /* | 242 | /* |
226 | * reclaim_str_hashtbl[] holds known client info from previous reset/reboot | 243 | * reclaim_str_hashtbl[] holds known client info from previous reset/reboot |
227 | * used in reboot/reset lease grace period processing | 244 | * used in reboot/reset lease grace period processing |
@@ -331,11 +348,11 @@ expire_client(struct nfs4_client *clp) | |||
331 | 348 | ||
332 | INIT_LIST_HEAD(&reaplist); | 349 | INIT_LIST_HEAD(&reaplist); |
333 | spin_lock(&recall_lock); | 350 | spin_lock(&recall_lock); |
334 | while (!list_empty(&clp->cl_del_perclnt)) { | 351 | while (!list_empty(&clp->cl_delegations)) { |
335 | dp = list_entry(clp->cl_del_perclnt.next, struct nfs4_delegation, dl_del_perclnt); | 352 | dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); |
336 | dprintk("NFSD: expire client. dp %p, fp %p\n", dp, | 353 | dprintk("NFSD: expire client. dp %p, fp %p\n", dp, |
337 | dp->dl_flock); | 354 | dp->dl_flock); |
338 | list_del_init(&dp->dl_del_perclnt); | 355 | list_del_init(&dp->dl_perclnt); |
339 | list_move(&dp->dl_recall_lru, &reaplist); | 356 | list_move(&dp->dl_recall_lru, &reaplist); |
340 | } | 357 | } |
341 | spin_unlock(&recall_lock); | 358 | spin_unlock(&recall_lock); |
@@ -347,26 +364,26 @@ expire_client(struct nfs4_client *clp) | |||
347 | list_del(&clp->cl_idhash); | 364 | list_del(&clp->cl_idhash); |
348 | list_del(&clp->cl_strhash); | 365 | list_del(&clp->cl_strhash); |
349 | list_del(&clp->cl_lru); | 366 | list_del(&clp->cl_lru); |
350 | while (!list_empty(&clp->cl_perclient)) { | 367 | while (!list_empty(&clp->cl_openowners)) { |
351 | sop = list_entry(clp->cl_perclient.next, struct nfs4_stateowner, so_perclient); | 368 | sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient); |
352 | release_stateowner(sop); | 369 | release_stateowner(sop); |
353 | } | 370 | } |
354 | put_nfs4_client(clp); | 371 | put_nfs4_client(clp); |
355 | } | 372 | } |
356 | 373 | ||
357 | static struct nfs4_client * | 374 | static struct nfs4_client * |
358 | create_client(struct xdr_netobj name) { | 375 | create_client(struct xdr_netobj name, char *recdir) { |
359 | struct nfs4_client *clp; | 376 | struct nfs4_client *clp; |
360 | 377 | ||
361 | if (!(clp = alloc_client(name))) | 378 | if (!(clp = alloc_client(name))) |
362 | goto out; | 379 | goto out; |
380 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | ||
363 | atomic_set(&clp->cl_count, 1); | 381 | atomic_set(&clp->cl_count, 1); |
364 | atomic_set(&clp->cl_callback.cb_set, 0); | 382 | atomic_set(&clp->cl_callback.cb_set, 0); |
365 | clp->cl_callback.cb_parsed = 0; | ||
366 | INIT_LIST_HEAD(&clp->cl_idhash); | 383 | INIT_LIST_HEAD(&clp->cl_idhash); |
367 | INIT_LIST_HEAD(&clp->cl_strhash); | 384 | INIT_LIST_HEAD(&clp->cl_strhash); |
368 | INIT_LIST_HEAD(&clp->cl_perclient); | 385 | INIT_LIST_HEAD(&clp->cl_openowners); |
369 | INIT_LIST_HEAD(&clp->cl_del_perclnt); | 386 | INIT_LIST_HEAD(&clp->cl_delegations); |
370 | INIT_LIST_HEAD(&clp->cl_lru); | 387 | INIT_LIST_HEAD(&clp->cl_lru); |
371 | out: | 388 | out: |
372 | return clp; | 389 | return clp; |
@@ -392,11 +409,9 @@ copy_cred(struct svc_cred *target, struct svc_cred *source) { | |||
392 | get_group_info(target->cr_group_info); | 409 | get_group_info(target->cr_group_info); |
393 | } | 410 | } |
394 | 411 | ||
395 | static int | 412 | static inline int |
396 | cmp_name(struct xdr_netobj *n1, struct xdr_netobj *n2) { | 413 | same_name(const char *n1, const char *n2) { |
397 | if (!n1 || !n2) | 414 | return 0 == memcmp(n1, n2, HEXDIR_LEN); |
398 | return 0; | ||
399 | return((n1->len == n2->len) && !memcmp(n1->data, n2->data, n2->len)); | ||
400 | } | 415 | } |
401 | 416 | ||
402 | static int | 417 | static int |
@@ -446,7 +461,7 @@ check_name(struct xdr_netobj name) { | |||
446 | return 1; | 461 | return 1; |
447 | } | 462 | } |
448 | 463 | ||
449 | void | 464 | static void |
450 | add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval) | 465 | add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval) |
451 | { | 466 | { |
452 | unsigned int idhashval; | 467 | unsigned int idhashval; |
@@ -458,7 +473,7 @@ add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval) | |||
458 | clp->cl_time = get_seconds(); | 473 | clp->cl_time = get_seconds(); |
459 | } | 474 | } |
460 | 475 | ||
461 | void | 476 | static void |
462 | move_to_confirmed(struct nfs4_client *clp) | 477 | move_to_confirmed(struct nfs4_client *clp) |
463 | { | 478 | { |
464 | unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); | 479 | unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); |
@@ -468,8 +483,7 @@ move_to_confirmed(struct nfs4_client *clp) | |||
468 | list_del_init(&clp->cl_strhash); | 483 | list_del_init(&clp->cl_strhash); |
469 | list_del_init(&clp->cl_idhash); | 484 | list_del_init(&clp->cl_idhash); |
470 | list_add(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); | 485 | list_add(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); |
471 | strhashval = clientstr_hashval(clp->cl_name.data, | 486 | strhashval = clientstr_hashval(clp->cl_recdir); |
472 | clp->cl_name.len); | ||
473 | list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); | 487 | list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); |
474 | renew_client(clp); | 488 | renew_client(clp); |
475 | } | 489 | } |
@@ -500,6 +514,30 @@ find_unconfirmed_client(clientid_t *clid) | |||
500 | return NULL; | 514 | return NULL; |
501 | } | 515 | } |
502 | 516 | ||
517 | static struct nfs4_client * | ||
518 | find_confirmed_client_by_str(const char *dname, unsigned int hashval) | ||
519 | { | ||
520 | struct nfs4_client *clp; | ||
521 | |||
522 | list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) { | ||
523 | if (same_name(clp->cl_recdir, dname)) | ||
524 | return clp; | ||
525 | } | ||
526 | return NULL; | ||
527 | } | ||
528 | |||
529 | static struct nfs4_client * | ||
530 | find_unconfirmed_client_by_str(const char *dname, unsigned int hashval) | ||
531 | { | ||
532 | struct nfs4_client *clp; | ||
533 | |||
534 | list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) { | ||
535 | if (same_name(clp->cl_recdir, dname)) | ||
536 | return clp; | ||
537 | } | ||
538 | return NULL; | ||
539 | } | ||
540 | |||
503 | /* a helper function for parse_callback */ | 541 | /* a helper function for parse_callback */ |
504 | static int | 542 | static int |
505 | parse_octet(unsigned int *lenp, char **addrp) | 543 | parse_octet(unsigned int *lenp, char **addrp) |
@@ -534,7 +572,7 @@ parse_octet(unsigned int *lenp, char **addrp) | |||
534 | } | 572 | } |
535 | 573 | ||
536 | /* parse and set the setclientid ipv4 callback address */ | 574 | /* parse and set the setclientid ipv4 callback address */ |
537 | int | 575 | static int |
538 | parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigned short *cbportp) | 576 | parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigned short *cbportp) |
539 | { | 577 | { |
540 | int temp = 0; | 578 | int temp = 0; |
@@ -570,7 +608,7 @@ parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigne | |||
570 | return 1; | 608 | return 1; |
571 | } | 609 | } |
572 | 610 | ||
573 | void | 611 | static void |
574 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) | 612 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) |
575 | { | 613 | { |
576 | struct nfs4_callback *cb = &clp->cl_callback; | 614 | struct nfs4_callback *cb = &clp->cl_callback; |
@@ -584,14 +622,12 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) | |||
584 | goto out_err; | 622 | goto out_err; |
585 | cb->cb_prog = se->se_callback_prog; | 623 | cb->cb_prog = se->se_callback_prog; |
586 | cb->cb_ident = se->se_callback_ident; | 624 | cb->cb_ident = se->se_callback_ident; |
587 | cb->cb_parsed = 1; | ||
588 | return; | 625 | return; |
589 | out_err: | 626 | out_err: |
590 | printk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " | 627 | printk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " |
591 | "will not receive delegations\n", | 628 | "will not receive delegations\n", |
592 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); | 629 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); |
593 | 630 | ||
594 | cb->cb_parsed = 0; | ||
595 | return; | 631 | return; |
596 | } | 632 | } |
597 | 633 | ||
@@ -638,59 +674,43 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) | |||
638 | }; | 674 | }; |
639 | nfs4_verifier clverifier = setclid->se_verf; | 675 | nfs4_verifier clverifier = setclid->se_verf; |
640 | unsigned int strhashval; | 676 | unsigned int strhashval; |
641 | struct nfs4_client * conf, * unconf, * new, * clp; | 677 | struct nfs4_client *conf, *unconf, *new; |
642 | int status; | 678 | int status; |
679 | char dname[HEXDIR_LEN]; | ||
643 | 680 | ||
644 | status = nfserr_inval; | 681 | status = nfserr_inval; |
645 | if (!check_name(clname)) | 682 | if (!check_name(clname)) |
646 | goto out; | 683 | goto out; |
647 | 684 | ||
685 | status = nfs4_make_rec_clidname(dname, &clname); | ||
686 | if (status) | ||
687 | goto out; | ||
688 | |||
648 | /* | 689 | /* |
649 | * XXX The Duplicate Request Cache (DRC) has been checked (??) | 690 | * XXX The Duplicate Request Cache (DRC) has been checked (??) |
650 | * We get here on a DRC miss. | 691 | * We get here on a DRC miss. |
651 | */ | 692 | */ |
652 | 693 | ||
653 | strhashval = clientstr_hashval(clname.data, clname.len); | 694 | strhashval = clientstr_hashval(dname); |
654 | 695 | ||
655 | conf = NULL; | ||
656 | nfs4_lock_state(); | 696 | nfs4_lock_state(); |
657 | list_for_each_entry(clp, &conf_str_hashtbl[strhashval], cl_strhash) { | 697 | conf = find_confirmed_client_by_str(dname, strhashval); |
658 | if (!cmp_name(&clp->cl_name, &clname)) | 698 | if (conf) { |
659 | continue; | ||
660 | /* | 699 | /* |
661 | * CASE 0: | 700 | * CASE 0: |
662 | * clname match, confirmed, different principal | 701 | * clname match, confirmed, different principal |
663 | * or different ip_address | 702 | * or different ip_address |
664 | */ | 703 | */ |
665 | status = nfserr_clid_inuse; | 704 | status = nfserr_clid_inuse; |
666 | if (!cmp_creds(&clp->cl_cred,&rqstp->rq_cred)) { | 705 | if (!cmp_creds(&conf->cl_cred, &rqstp->rq_cred) |
667 | printk("NFSD: setclientid: string in use by client" | 706 | || conf->cl_addr != ip_addr) { |
668 | "(clientid %08x/%08x)\n", | ||
669 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); | ||
670 | goto out; | ||
671 | } | ||
672 | if (clp->cl_addr != ip_addr) { | ||
673 | printk("NFSD: setclientid: string in use by client" | 707 | printk("NFSD: setclientid: string in use by client" |
674 | "(clientid %08x/%08x)\n", | 708 | "(clientid %08x/%08x)\n", |
675 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); | 709 | conf->cl_clientid.cl_boot, conf->cl_clientid.cl_id); |
676 | goto out; | 710 | goto out; |
677 | } | 711 | } |
678 | |||
679 | /* | ||
680 | * cl_name match from a previous SETCLIENTID operation | ||
681 | * XXX check for additional matches? | ||
682 | */ | ||
683 | conf = clp; | ||
684 | break; | ||
685 | } | ||
686 | unconf = NULL; | ||
687 | list_for_each_entry(clp, &unconf_str_hashtbl[strhashval], cl_strhash) { | ||
688 | if (!cmp_name(&clp->cl_name, &clname)) | ||
689 | continue; | ||
690 | /* cl_name match from a previous SETCLIENTID operation */ | ||
691 | unconf = clp; | ||
692 | break; | ||
693 | } | 712 | } |
713 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | ||
694 | status = nfserr_resource; | 714 | status = nfserr_resource; |
695 | if (!conf) { | 715 | if (!conf) { |
696 | /* | 716 | /* |
@@ -699,7 +719,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) | |||
699 | */ | 719 | */ |
700 | if (unconf) | 720 | if (unconf) |
701 | expire_client(unconf); | 721 | expire_client(unconf); |
702 | if (!(new = create_client(clname))) | 722 | new = create_client(clname, dname); |
723 | if (new == NULL) | ||
703 | goto out; | 724 | goto out; |
704 | copy_verf(new, &clverifier); | 725 | copy_verf(new, &clverifier); |
705 | new->cl_addr = ip_addr; | 726 | new->cl_addr = ip_addr; |
@@ -722,12 +743,16 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) | |||
722 | * nfs4_client, but with the new callback info and a | 743 | * nfs4_client, but with the new callback info and a |
723 | * new cl_confirm | 744 | * new cl_confirm |
724 | */ | 745 | */ |
725 | if ((unconf) && | 746 | if (unconf) { |
726 | cmp_verf(&unconf->cl_verifier, &conf->cl_verifier) && | 747 | /* Note this is removing unconfirmed {*x***}, |
727 | cmp_clid(&unconf->cl_clientid, &conf->cl_clientid)) { | 748 | * which is stronger than RFC recommended {vxc**}. |
728 | expire_client(unconf); | 749 | * This has the advantage that there is at most |
750 | * one {*x***} in either list at any time. | ||
751 | */ | ||
752 | expire_client(unconf); | ||
729 | } | 753 | } |
730 | if (!(new = create_client(clname))) | 754 | new = create_client(clname, dname); |
755 | if (new == NULL) | ||
731 | goto out; | 756 | goto out; |
732 | copy_verf(new,&conf->cl_verifier); | 757 | copy_verf(new,&conf->cl_verifier); |
733 | new->cl_addr = ip_addr; | 758 | new->cl_addr = ip_addr; |
@@ -745,7 +770,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) | |||
745 | * using input clverifier, clname, and callback info | 770 | * using input clverifier, clname, and callback info |
746 | * and generate a new cl_clientid and cl_confirm. | 771 | * and generate a new cl_clientid and cl_confirm. |
747 | */ | 772 | */ |
748 | if (!(new = create_client(clname))) | 773 | new = create_client(clname, dname); |
774 | if (new == NULL) | ||
749 | goto out; | 775 | goto out; |
750 | copy_verf(new,&clverifier); | 776 | copy_verf(new,&clverifier); |
751 | new->cl_addr = ip_addr; | 777 | new->cl_addr = ip_addr; |
@@ -771,7 +797,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) | |||
771 | * new cl_verifier and a new cl_confirm | 797 | * new cl_verifier and a new cl_confirm |
772 | */ | 798 | */ |
773 | expire_client(unconf); | 799 | expire_client(unconf); |
774 | if (!(new = create_client(clname))) | 800 | new = create_client(clname, dname); |
801 | if (new == NULL) | ||
775 | goto out; | 802 | goto out; |
776 | copy_verf(new,&clverifier); | 803 | copy_verf(new,&clverifier); |
777 | new->cl_addr = ip_addr; | 804 | new->cl_addr = ip_addr; |
@@ -807,7 +834,7 @@ int | |||
807 | nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm) | 834 | nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm) |
808 | { | 835 | { |
809 | u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; | 836 | u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; |
810 | struct nfs4_client *clp, *conf = NULL, *unconf = NULL; | 837 | struct nfs4_client *conf, *unconf; |
811 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; | 838 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; |
812 | clientid_t * clid = &setclientid_confirm->sc_clientid; | 839 | clientid_t * clid = &setclientid_confirm->sc_clientid; |
813 | int status; | 840 | int status; |
@@ -820,102 +847,90 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confi | |||
820 | */ | 847 | */ |
821 | 848 | ||
822 | nfs4_lock_state(); | 849 | nfs4_lock_state(); |
823 | clp = find_confirmed_client(clid); | 850 | |
824 | if (clp) { | 851 | conf = find_confirmed_client(clid); |
825 | status = nfserr_inval; | 852 | unconf = find_unconfirmed_client(clid); |
826 | /* | 853 | |
827 | * Found a record for this clientid. If the IP addresses | 854 | status = nfserr_clid_inuse; |
828 | * don't match, return ERR_INVAL just as if the record had | 855 | if (conf && conf->cl_addr != ip_addr) |
829 | * not been found. | 856 | goto out; |
830 | */ | 857 | if (unconf && unconf->cl_addr != ip_addr) |
831 | if (clp->cl_addr != ip_addr) { | 858 | goto out; |
832 | printk("NFSD: setclientid: string in use by client" | 859 | |
833 | "(clientid %08x/%08x)\n", | ||
834 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); | ||
835 | goto out; | ||
836 | } | ||
837 | conf = clp; | ||
838 | } | ||
839 | clp = find_unconfirmed_client(clid); | ||
840 | if (clp) { | ||
841 | status = nfserr_inval; | ||
842 | if (clp->cl_addr != ip_addr) { | ||
843 | printk("NFSD: setclientid: string in use by client" | ||
844 | "(clientid %08x/%08x)\n", | ||
845 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); | ||
846 | goto out; | ||
847 | } | ||
848 | unconf = clp; | ||
849 | } | ||
850 | /* CASE 1: | ||
851 | * unconf record that matches input clientid and input confirm. | ||
852 | * conf record that matches input clientid. | ||
853 | * conf and unconf records match names, verifiers | ||
854 | */ | ||
855 | if ((conf && unconf) && | 860 | if ((conf && unconf) && |
856 | (cmp_verf(&unconf->cl_confirm, &confirm)) && | 861 | (cmp_verf(&unconf->cl_confirm, &confirm)) && |
857 | (cmp_verf(&conf->cl_verifier, &unconf->cl_verifier)) && | 862 | (cmp_verf(&conf->cl_verifier, &unconf->cl_verifier)) && |
858 | (cmp_name(&conf->cl_name,&unconf->cl_name)) && | 863 | (same_name(conf->cl_recdir,unconf->cl_recdir)) && |
859 | (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm))) { | 864 | (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm))) { |
865 | /* CASE 1: | ||
866 | * unconf record that matches input clientid and input confirm. | ||
867 | * conf record that matches input clientid. | ||
868 | * conf and unconf records match names, verifiers | ||
869 | */ | ||
860 | if (!cmp_creds(&conf->cl_cred, &unconf->cl_cred)) | 870 | if (!cmp_creds(&conf->cl_cred, &unconf->cl_cred)) |
861 | status = nfserr_clid_inuse; | 871 | status = nfserr_clid_inuse; |
862 | else { | 872 | else { |
863 | expire_client(conf); | 873 | /* XXX: We just turn off callbacks until we can handle |
864 | clp = unconf; | 874 | * change request correctly. */ |
865 | move_to_confirmed(unconf); | 875 | atomic_set(&conf->cl_callback.cb_set, 0); |
876 | gen_confirm(conf); | ||
877 | expire_client(unconf); | ||
866 | status = nfs_ok; | 878 | status = nfs_ok; |
879 | |||
867 | } | 880 | } |
868 | goto out; | 881 | } else if ((conf && !unconf) || |
869 | } | ||
870 | /* CASE 2: | ||
871 | * conf record that matches input clientid. | ||
872 | * if unconf record that matches input clientid, then unconf->cl_name | ||
873 | * or unconf->cl_verifier don't match the conf record. | ||
874 | */ | ||
875 | if ((conf && !unconf) || | ||
876 | ((conf && unconf) && | 882 | ((conf && unconf) && |
877 | (!cmp_verf(&conf->cl_verifier, &unconf->cl_verifier) || | 883 | (!cmp_verf(&conf->cl_verifier, &unconf->cl_verifier) || |
878 | !cmp_name(&conf->cl_name, &unconf->cl_name)))) { | 884 | !same_name(conf->cl_recdir, unconf->cl_recdir)))) { |
879 | if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred)) { | 885 | /* CASE 2: |
886 | * conf record that matches input clientid. | ||
887 | * if unconf record matches input clientid, then | ||
888 | * unconf->cl_name or unconf->cl_verifier don't match the | ||
889 | * conf record. | ||
890 | */ | ||
891 | if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred)) | ||
880 | status = nfserr_clid_inuse; | 892 | status = nfserr_clid_inuse; |
881 | } else { | 893 | else |
882 | clp = conf; | ||
883 | status = nfs_ok; | 894 | status = nfs_ok; |
884 | } | 895 | } else if (!conf && unconf |
885 | goto out; | 896 | && cmp_verf(&unconf->cl_confirm, &confirm)) { |
886 | } | 897 | /* CASE 3: |
887 | /* CASE 3: | 898 | * conf record not found. |
888 | * conf record not found. | 899 | * unconf record found. |
889 | * unconf record found. | 900 | * unconf->cl_confirm matches input confirm |
890 | * unconf->cl_confirm matches input confirm | 901 | */ |
891 | */ | ||
892 | if (!conf && unconf && cmp_verf(&unconf->cl_confirm, &confirm)) { | ||
893 | if (!cmp_creds(&unconf->cl_cred, &rqstp->rq_cred)) { | 902 | if (!cmp_creds(&unconf->cl_cred, &rqstp->rq_cred)) { |
894 | status = nfserr_clid_inuse; | 903 | status = nfserr_clid_inuse; |
895 | } else { | 904 | } else { |
896 | status = nfs_ok; | 905 | unsigned int hash = |
897 | clp = unconf; | 906 | clientstr_hashval(unconf->cl_recdir); |
907 | conf = find_confirmed_client_by_str(unconf->cl_recdir, | ||
908 | hash); | ||
909 | if (conf) { | ||
910 | nfsd4_remove_clid_dir(conf); | ||
911 | expire_client(conf); | ||
912 | } | ||
898 | move_to_confirmed(unconf); | 913 | move_to_confirmed(unconf); |
914 | conf = unconf; | ||
915 | status = nfs_ok; | ||
899 | } | 916 | } |
900 | goto out; | 917 | } else if ((!conf || (conf && !cmp_verf(&conf->cl_confirm, &confirm))) |
901 | } | 918 | && (!unconf || (unconf && !cmp_verf(&unconf->cl_confirm, |
902 | /* CASE 4: | 919 | &confirm)))) { |
903 | * conf record not found, or if conf, then conf->cl_confirm does not | 920 | /* CASE 4: |
904 | * match input confirm. | 921 | * conf record not found, or if conf, conf->cl_confirm does not |
905 | * unconf record not found, or if unconf, then unconf->cl_confirm | 922 | * match input confirm. |
906 | * does not match input confirm. | 923 | * unconf record not found, or if unconf, unconf->cl_confirm |
907 | */ | 924 | * does not match input confirm. |
908 | if ((!conf || (conf && !cmp_verf(&conf->cl_confirm, &confirm))) && | 925 | */ |
909 | (!unconf || (unconf && !cmp_verf(&unconf->cl_confirm, &confirm)))) { | ||
910 | status = nfserr_stale_clientid; | 926 | status = nfserr_stale_clientid; |
911 | goto out; | 927 | } else { |
928 | /* check that we have hit one of the cases...*/ | ||
929 | status = nfserr_clid_inuse; | ||
912 | } | 930 | } |
913 | /* check that we have hit one of the cases...*/ | ||
914 | status = nfserr_inval; | ||
915 | goto out; | ||
916 | out: | 931 | out: |
917 | if (!status) | 932 | if (!status) |
918 | nfsd4_probe_callback(clp); | 933 | nfsd4_probe_callback(conf); |
919 | nfs4_unlock_state(); | 934 | nfs4_unlock_state(); |
920 | return status; | 935 | return status; |
921 | } | 936 | } |
@@ -961,60 +976,65 @@ alloc_init_file(struct inode *ino) | |||
961 | struct nfs4_file *fp; | 976 | struct nfs4_file *fp; |
962 | unsigned int hashval = file_hashval(ino); | 977 | unsigned int hashval = file_hashval(ino); |
963 | 978 | ||
964 | if ((fp = kmalloc(sizeof(struct nfs4_file),GFP_KERNEL))) { | 979 | fp = kmem_cache_alloc(file_slab, GFP_KERNEL); |
980 | if (fp) { | ||
981 | kref_init(&fp->fi_ref); | ||
965 | INIT_LIST_HEAD(&fp->fi_hash); | 982 | INIT_LIST_HEAD(&fp->fi_hash); |
966 | INIT_LIST_HEAD(&fp->fi_perfile); | 983 | INIT_LIST_HEAD(&fp->fi_stateids); |
967 | INIT_LIST_HEAD(&fp->fi_del_perfile); | 984 | INIT_LIST_HEAD(&fp->fi_delegations); |
968 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); | 985 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); |
969 | fp->fi_inode = igrab(ino); | 986 | fp->fi_inode = igrab(ino); |
970 | fp->fi_id = current_fileid++; | 987 | fp->fi_id = current_fileid++; |
971 | alloc_file++; | ||
972 | return fp; | 988 | return fp; |
973 | } | 989 | } |
974 | return NULL; | 990 | return NULL; |
975 | } | 991 | } |
976 | 992 | ||
977 | static void | 993 | static void |
978 | release_all_files(void) | 994 | nfsd4_free_slab(kmem_cache_t **slab) |
979 | { | 995 | { |
980 | int i; | 996 | int status; |
981 | struct nfs4_file *fp; | ||
982 | 997 | ||
983 | for (i=0;i<FILE_HASH_SIZE;i++) { | 998 | if (*slab == NULL) |
984 | while (!list_empty(&file_hashtbl[i])) { | 999 | return; |
985 | fp = list_entry(file_hashtbl[i].next, struct nfs4_file, fi_hash); | 1000 | status = kmem_cache_destroy(*slab); |
986 | /* this should never be more than once... */ | 1001 | *slab = NULL; |
987 | if (!list_empty(&fp->fi_perfile) || !list_empty(&fp->fi_del_perfile)) { | 1002 | WARN_ON(status); |
988 | printk("ERROR: release_all_files: file %p is open, creating dangling state !!!\n",fp); | ||
989 | } | ||
990 | release_file(fp); | ||
991 | } | ||
992 | } | ||
993 | } | 1003 | } |
994 | 1004 | ||
995 | kmem_cache_t *stateowner_slab = NULL; | 1005 | static void |
1006 | nfsd4_free_slabs(void) | ||
1007 | { | ||
1008 | nfsd4_free_slab(&stateowner_slab); | ||
1009 | nfsd4_free_slab(&file_slab); | ||
1010 | nfsd4_free_slab(&stateid_slab); | ||
1011 | nfsd4_free_slab(&deleg_slab); | ||
1012 | } | ||
996 | 1013 | ||
997 | static int | 1014 | static int |
998 | nfsd4_init_slabs(void) | 1015 | nfsd4_init_slabs(void) |
999 | { | 1016 | { |
1000 | stateowner_slab = kmem_cache_create("nfsd4_stateowners", | 1017 | stateowner_slab = kmem_cache_create("nfsd4_stateowners", |
1001 | sizeof(struct nfs4_stateowner), 0, 0, NULL, NULL); | 1018 | sizeof(struct nfs4_stateowner), 0, 0, NULL, NULL); |
1002 | if (stateowner_slab == NULL) { | 1019 | if (stateowner_slab == NULL) |
1003 | dprintk("nfsd4: out of memory while initializing nfsv4\n"); | 1020 | goto out_nomem; |
1004 | return -ENOMEM; | 1021 | file_slab = kmem_cache_create("nfsd4_files", |
1005 | } | 1022 | sizeof(struct nfs4_file), 0, 0, NULL, NULL); |
1023 | if (file_slab == NULL) | ||
1024 | goto out_nomem; | ||
1025 | stateid_slab = kmem_cache_create("nfsd4_stateids", | ||
1026 | sizeof(struct nfs4_stateid), 0, 0, NULL, NULL); | ||
1027 | if (stateid_slab == NULL) | ||
1028 | goto out_nomem; | ||
1029 | deleg_slab = kmem_cache_create("nfsd4_delegations", | ||
1030 | sizeof(struct nfs4_delegation), 0, 0, NULL, NULL); | ||
1031 | if (deleg_slab == NULL) | ||
1032 | goto out_nomem; | ||
1006 | return 0; | 1033 | return 0; |
1007 | } | 1034 | out_nomem: |
1008 | 1035 | nfsd4_free_slabs(); | |
1009 | static void | 1036 | dprintk("nfsd4: out of memory while initializing nfsv4\n"); |
1010 | nfsd4_free_slabs(void) | 1037 | return -ENOMEM; |
1011 | { | ||
1012 | int status = 0; | ||
1013 | |||
1014 | if (stateowner_slab) | ||
1015 | status = kmem_cache_destroy(stateowner_slab); | ||
1016 | stateowner_slab = NULL; | ||
1017 | BUG_ON(status); | ||
1018 | } | 1038 | } |
1019 | 1039 | ||
1020 | void | 1040 | void |
@@ -1055,14 +1075,13 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str | |||
1055 | INIT_LIST_HEAD(&sop->so_idhash); | 1075 | INIT_LIST_HEAD(&sop->so_idhash); |
1056 | INIT_LIST_HEAD(&sop->so_strhash); | 1076 | INIT_LIST_HEAD(&sop->so_strhash); |
1057 | INIT_LIST_HEAD(&sop->so_perclient); | 1077 | INIT_LIST_HEAD(&sop->so_perclient); |
1058 | INIT_LIST_HEAD(&sop->so_perfilestate); | 1078 | INIT_LIST_HEAD(&sop->so_stateids); |
1059 | INIT_LIST_HEAD(&sop->so_perlockowner); /* not used */ | 1079 | INIT_LIST_HEAD(&sop->so_perstateid); /* not used */ |
1060 | INIT_LIST_HEAD(&sop->so_close_lru); | 1080 | INIT_LIST_HEAD(&sop->so_close_lru); |
1061 | sop->so_time = 0; | 1081 | sop->so_time = 0; |
1062 | list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]); | 1082 | list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]); |
1063 | list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]); | 1083 | list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]); |
1064 | list_add(&sop->so_perclient, &clp->cl_perclient); | 1084 | list_add(&sop->so_perclient, &clp->cl_openowners); |
1065 | add_perclient++; | ||
1066 | sop->so_is_open_owner = 1; | 1085 | sop->so_is_open_owner = 1; |
1067 | sop->so_id = current_ownerid++; | 1086 | sop->so_id = current_ownerid++; |
1068 | sop->so_client = clp; | 1087 | sop->so_client = clp; |
@@ -1080,10 +1099,10 @@ release_stateid_lockowners(struct nfs4_stateid *open_stp) | |||
1080 | { | 1099 | { |
1081 | struct nfs4_stateowner *lock_sop; | 1100 | struct nfs4_stateowner *lock_sop; |
1082 | 1101 | ||
1083 | while (!list_empty(&open_stp->st_perlockowner)) { | 1102 | while (!list_empty(&open_stp->st_lockowners)) { |
1084 | lock_sop = list_entry(open_stp->st_perlockowner.next, | 1103 | lock_sop = list_entry(open_stp->st_lockowners.next, |
1085 | struct nfs4_stateowner, so_perlockowner); | 1104 | struct nfs4_stateowner, so_perstateid); |
1086 | /* list_del(&open_stp->st_perlockowner); */ | 1105 | /* list_del(&open_stp->st_lockowners); */ |
1087 | BUG_ON(lock_sop->so_is_open_owner); | 1106 | BUG_ON(lock_sop->so_is_open_owner); |
1088 | release_stateowner(lock_sop); | 1107 | release_stateowner(lock_sop); |
1089 | } | 1108 | } |
@@ -1096,14 +1115,12 @@ unhash_stateowner(struct nfs4_stateowner *sop) | |||
1096 | 1115 | ||
1097 | list_del(&sop->so_idhash); | 1116 | list_del(&sop->so_idhash); |
1098 | list_del(&sop->so_strhash); | 1117 | list_del(&sop->so_strhash); |
1099 | if (sop->so_is_open_owner) { | 1118 | if (sop->so_is_open_owner) |
1100 | list_del(&sop->so_perclient); | 1119 | list_del(&sop->so_perclient); |
1101 | del_perclient++; | 1120 | list_del(&sop->so_perstateid); |
1102 | } | 1121 | while (!list_empty(&sop->so_stateids)) { |
1103 | list_del(&sop->so_perlockowner); | 1122 | stp = list_entry(sop->so_stateids.next, |
1104 | while (!list_empty(&sop->so_perfilestate)) { | 1123 | struct nfs4_stateid, st_perstateowner); |
1105 | stp = list_entry(sop->so_perfilestate.next, | ||
1106 | struct nfs4_stateid, st_perfilestate); | ||
1107 | if (sop->so_is_open_owner) | 1124 | if (sop->so_is_open_owner) |
1108 | release_stateid(stp, OPEN_STATE); | 1125 | release_stateid(stp, OPEN_STATE); |
1109 | else | 1126 | else |
@@ -1125,14 +1142,14 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open * | |||
1125 | unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id); | 1142 | unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id); |
1126 | 1143 | ||
1127 | INIT_LIST_HEAD(&stp->st_hash); | 1144 | INIT_LIST_HEAD(&stp->st_hash); |
1128 | INIT_LIST_HEAD(&stp->st_perfilestate); | 1145 | INIT_LIST_HEAD(&stp->st_perstateowner); |
1129 | INIT_LIST_HEAD(&stp->st_perlockowner); | 1146 | INIT_LIST_HEAD(&stp->st_lockowners); |
1130 | INIT_LIST_HEAD(&stp->st_perfile); | 1147 | INIT_LIST_HEAD(&stp->st_perfile); |
1131 | list_add(&stp->st_hash, &stateid_hashtbl[hashval]); | 1148 | list_add(&stp->st_hash, &stateid_hashtbl[hashval]); |
1132 | list_add(&stp->st_perfilestate, &sop->so_perfilestate); | 1149 | list_add(&stp->st_perstateowner, &sop->so_stateids); |
1133 | list_add_perfile++; | 1150 | list_add(&stp->st_perfile, &fp->fi_stateids); |
1134 | list_add(&stp->st_perfile, &fp->fi_perfile); | ||
1135 | stp->st_stateowner = sop; | 1151 | stp->st_stateowner = sop; |
1152 | get_nfs4_file(fp); | ||
1136 | stp->st_file = fp; | 1153 | stp->st_file = fp; |
1137 | stp->st_stateid.si_boot = boot_time; | 1154 | stp->st_stateid.si_boot = boot_time; |
1138 | stp->st_stateid.si_stateownerid = sop->so_id; | 1155 | stp->st_stateid.si_stateownerid = sop->so_id; |
@@ -1150,30 +1167,20 @@ release_stateid(struct nfs4_stateid *stp, int flags) | |||
1150 | struct file *filp = stp->st_vfs_file; | 1167 | struct file *filp = stp->st_vfs_file; |
1151 | 1168 | ||
1152 | list_del(&stp->st_hash); | 1169 | list_del(&stp->st_hash); |
1153 | list_del_perfile++; | ||
1154 | list_del(&stp->st_perfile); | 1170 | list_del(&stp->st_perfile); |
1155 | list_del(&stp->st_perfilestate); | 1171 | list_del(&stp->st_perstateowner); |
1156 | if (flags & OPEN_STATE) { | 1172 | if (flags & OPEN_STATE) { |
1157 | release_stateid_lockowners(stp); | 1173 | release_stateid_lockowners(stp); |
1158 | stp->st_vfs_file = NULL; | 1174 | stp->st_vfs_file = NULL; |
1159 | nfsd_close(filp); | 1175 | nfsd_close(filp); |
1160 | vfsclose++; | ||
1161 | } else if (flags & LOCK_STATE) | 1176 | } else if (flags & LOCK_STATE) |
1162 | locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner); | 1177 | locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner); |
1163 | kfree(stp); | 1178 | put_nfs4_file(stp->st_file); |
1179 | kmem_cache_free(stateid_slab, stp); | ||
1164 | stp = NULL; | 1180 | stp = NULL; |
1165 | } | 1181 | } |
1166 | 1182 | ||
1167 | static void | 1183 | static void |
1168 | release_file(struct nfs4_file *fp) | ||
1169 | { | ||
1170 | free_file++; | ||
1171 | list_del(&fp->fi_hash); | ||
1172 | iput(fp->fi_inode); | ||
1173 | kfree(fp); | ||
1174 | } | ||
1175 | |||
1176 | void | ||
1177 | move_to_close_lru(struct nfs4_stateowner *sop) | 1184 | move_to_close_lru(struct nfs4_stateowner *sop) |
1178 | { | 1185 | { |
1179 | dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop); | 1186 | dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop); |
@@ -1183,11 +1190,10 @@ move_to_close_lru(struct nfs4_stateowner *sop) | |||
1183 | sop->so_time = get_seconds(); | 1190 | sop->so_time = get_seconds(); |
1184 | } | 1191 | } |
1185 | 1192 | ||
1186 | void | 1193 | static void |
1187 | release_state_owner(struct nfs4_stateid *stp, int flag) | 1194 | release_state_owner(struct nfs4_stateid *stp, int flag) |
1188 | { | 1195 | { |
1189 | struct nfs4_stateowner *sop = stp->st_stateowner; | 1196 | struct nfs4_stateowner *sop = stp->st_stateowner; |
1190 | struct nfs4_file *fp = stp->st_file; | ||
1191 | 1197 | ||
1192 | dprintk("NFSD: release_state_owner\n"); | 1198 | dprintk("NFSD: release_state_owner\n"); |
1193 | release_stateid(stp, flag); | 1199 | release_stateid(stp, flag); |
@@ -1196,12 +1202,8 @@ release_state_owner(struct nfs4_stateid *stp, int flag) | |||
1196 | * released by the laundromat service after the lease period | 1202 | * released by the laundromat service after the lease period |
1197 | * to enable us to handle CLOSE replay | 1203 | * to enable us to handle CLOSE replay |
1198 | */ | 1204 | */ |
1199 | if (sop->so_confirmed && list_empty(&sop->so_perfilestate)) | 1205 | if (sop->so_confirmed && list_empty(&sop->so_stateids)) |
1200 | move_to_close_lru(sop); | 1206 | move_to_close_lru(sop); |
1201 | /* unused nfs4_file's are releseed. XXX slab cache? */ | ||
1202 | if (list_empty(&fp->fi_perfile) && list_empty(&fp->fi_del_perfile)) { | ||
1203 | release_file(fp); | ||
1204 | } | ||
1205 | } | 1207 | } |
1206 | 1208 | ||
1207 | static int | 1209 | static int |
@@ -1231,8 +1233,10 @@ find_file(struct inode *ino) | |||
1231 | struct nfs4_file *fp; | 1233 | struct nfs4_file *fp; |
1232 | 1234 | ||
1233 | list_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) { | 1235 | list_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) { |
1234 | if (fp->fi_inode == ino) | 1236 | if (fp->fi_inode == ino) { |
1237 | get_nfs4_file(fp); | ||
1235 | return fp; | 1238 | return fp; |
1239 | } | ||
1236 | } | 1240 | } |
1237 | return NULL; | 1241 | return NULL; |
1238 | } | 1242 | } |
@@ -1240,7 +1244,7 @@ find_file(struct inode *ino) | |||
1240 | #define TEST_ACCESS(x) ((x > 0 || x < 4)?1:0) | 1244 | #define TEST_ACCESS(x) ((x > 0 || x < 4)?1:0) |
1241 | #define TEST_DENY(x) ((x >= 0 || x < 5)?1:0) | 1245 | #define TEST_DENY(x) ((x >= 0 || x < 5)?1:0) |
1242 | 1246 | ||
1243 | void | 1247 | static void |
1244 | set_access(unsigned int *access, unsigned long bmap) { | 1248 | set_access(unsigned int *access, unsigned long bmap) { |
1245 | int i; | 1249 | int i; |
1246 | 1250 | ||
@@ -1251,7 +1255,7 @@ set_access(unsigned int *access, unsigned long bmap) { | |||
1251 | } | 1255 | } |
1252 | } | 1256 | } |
1253 | 1257 | ||
1254 | void | 1258 | static void |
1255 | set_deny(unsigned int *deny, unsigned long bmap) { | 1259 | set_deny(unsigned int *deny, unsigned long bmap) { |
1256 | int i; | 1260 | int i; |
1257 | 1261 | ||
@@ -1277,25 +1281,30 @@ test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) { | |||
1277 | * Called to check deny when READ with all zero stateid or | 1281 | * Called to check deny when READ with all zero stateid or |
1278 | * WRITE with all zero or all one stateid | 1282 | * WRITE with all zero or all one stateid |
1279 | */ | 1283 | */ |
1280 | int | 1284 | static int |
1281 | nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) | 1285 | nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) |
1282 | { | 1286 | { |
1283 | struct inode *ino = current_fh->fh_dentry->d_inode; | 1287 | struct inode *ino = current_fh->fh_dentry->d_inode; |
1284 | struct nfs4_file *fp; | 1288 | struct nfs4_file *fp; |
1285 | struct nfs4_stateid *stp; | 1289 | struct nfs4_stateid *stp; |
1290 | int ret; | ||
1286 | 1291 | ||
1287 | dprintk("NFSD: nfs4_share_conflict\n"); | 1292 | dprintk("NFSD: nfs4_share_conflict\n"); |
1288 | 1293 | ||
1289 | fp = find_file(ino); | 1294 | fp = find_file(ino); |
1290 | if (fp) { | 1295 | if (!fp) |
1296 | return nfs_ok; | ||
1297 | ret = nfserr_share_denied; | ||
1291 | /* Search for conflicting share reservations */ | 1298 | /* Search for conflicting share reservations */ |
1292 | list_for_each_entry(stp, &fp->fi_perfile, st_perfile) { | 1299 | list_for_each_entry(stp, &fp->fi_stateids, st_perfile) { |
1293 | if (test_bit(deny_type, &stp->st_deny_bmap) || | 1300 | if (test_bit(deny_type, &stp->st_deny_bmap) || |
1294 | test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap)) | 1301 | test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap)) |
1295 | return nfserr_share_denied; | 1302 | goto out; |
1296 | } | ||
1297 | } | 1303 | } |
1298 | return nfs_ok; | 1304 | ret = nfs_ok; |
1305 | out: | ||
1306 | put_nfs4_file(fp); | ||
1307 | return ret; | ||
1299 | } | 1308 | } |
1300 | 1309 | ||
1301 | static inline void | 1310 | static inline void |
@@ -1427,7 +1436,7 @@ int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) | |||
1427 | return -EAGAIN; | 1436 | return -EAGAIN; |
1428 | } | 1437 | } |
1429 | 1438 | ||
1430 | struct lock_manager_operations nfsd_lease_mng_ops = { | 1439 | static struct lock_manager_operations nfsd_lease_mng_ops = { |
1431 | .fl_break = nfsd_break_deleg_cb, | 1440 | .fl_break = nfsd_break_deleg_cb, |
1432 | .fl_release_private = nfsd_release_deleg_cb, | 1441 | .fl_release_private = nfsd_release_deleg_cb, |
1433 | .fl_copy_lock = nfsd_copy_lock_deleg_cb, | 1442 | .fl_copy_lock = nfsd_copy_lock_deleg_cb, |
@@ -1526,6 +1535,51 @@ out: | |||
1526 | return status; | 1535 | return status; |
1527 | } | 1536 | } |
1528 | 1537 | ||
1538 | static inline int | ||
1539 | nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) | ||
1540 | { | ||
1541 | if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) | ||
1542 | return nfserr_openmode; | ||
1543 | else | ||
1544 | return nfs_ok; | ||
1545 | } | ||
1546 | |||
1547 | static struct nfs4_delegation * | ||
1548 | find_delegation_file(struct nfs4_file *fp, stateid_t *stid) | ||
1549 | { | ||
1550 | struct nfs4_delegation *dp; | ||
1551 | |||
1552 | list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) { | ||
1553 | if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid) | ||
1554 | return dp; | ||
1555 | } | ||
1556 | return NULL; | ||
1557 | } | ||
1558 | |||
1559 | static int | ||
1560 | nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, | ||
1561 | struct nfs4_delegation **dp) | ||
1562 | { | ||
1563 | int flags; | ||
1564 | int status = nfserr_bad_stateid; | ||
1565 | |||
1566 | *dp = find_delegation_file(fp, &open->op_delegate_stateid); | ||
1567 | if (*dp == NULL) | ||
1568 | goto out; | ||
1569 | flags = open->op_share_access == NFS4_SHARE_ACCESS_READ ? | ||
1570 | RD_STATE : WR_STATE; | ||
1571 | status = nfs4_check_delegmode(*dp, flags); | ||
1572 | if (status) | ||
1573 | *dp = NULL; | ||
1574 | out: | ||
1575 | if (open->op_claim_type != NFS4_OPEN_CLAIM_DELEGATE_CUR) | ||
1576 | return nfs_ok; | ||
1577 | if (status) | ||
1578 | return status; | ||
1579 | open->op_stateowner->so_confirmed = 1; | ||
1580 | return nfs_ok; | ||
1581 | } | ||
1582 | |||
1529 | static int | 1583 | static int |
1530 | nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp) | 1584 | nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp) |
1531 | { | 1585 | { |
@@ -1533,7 +1587,7 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_state | |||
1533 | int status = nfserr_share_denied; | 1587 | int status = nfserr_share_denied; |
1534 | struct nfs4_stateowner *sop = open->op_stateowner; | 1588 | struct nfs4_stateowner *sop = open->op_stateowner; |
1535 | 1589 | ||
1536 | list_for_each_entry(local, &fp->fi_perfile, st_perfile) { | 1590 | list_for_each_entry(local, &fp->fi_stateids, st_perfile) { |
1537 | /* ignore lock owners */ | 1591 | /* ignore lock owners */ |
1538 | if (local->st_stateowner->so_is_open_owner == 0) | 1592 | if (local->st_stateowner->so_is_open_owner == 0) |
1539 | continue; | 1593 | continue; |
@@ -1549,25 +1603,37 @@ out: | |||
1549 | return status; | 1603 | return status; |
1550 | } | 1604 | } |
1551 | 1605 | ||
1606 | static inline struct nfs4_stateid * | ||
1607 | nfs4_alloc_stateid(void) | ||
1608 | { | ||
1609 | return kmem_cache_alloc(stateid_slab, GFP_KERNEL); | ||
1610 | } | ||
1611 | |||
1552 | static int | 1612 | static int |
1553 | nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, | 1613 | nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, |
1614 | struct nfs4_delegation *dp, | ||
1554 | struct svc_fh *cur_fh, int flags) | 1615 | struct svc_fh *cur_fh, int flags) |
1555 | { | 1616 | { |
1556 | struct nfs4_stateid *stp; | 1617 | struct nfs4_stateid *stp; |
1557 | int status; | ||
1558 | 1618 | ||
1559 | stp = kmalloc(sizeof(struct nfs4_stateid), GFP_KERNEL); | 1619 | stp = nfs4_alloc_stateid(); |
1560 | if (stp == NULL) | 1620 | if (stp == NULL) |
1561 | return nfserr_resource; | 1621 | return nfserr_resource; |
1562 | 1622 | ||
1563 | status = nfsd_open(rqstp, cur_fh, S_IFREG, flags, &stp->st_vfs_file); | 1623 | if (dp) { |
1564 | if (status) { | 1624 | get_file(dp->dl_vfs_file); |
1565 | if (status == nfserr_dropit) | 1625 | stp->st_vfs_file = dp->dl_vfs_file; |
1566 | status = nfserr_jukebox; | 1626 | } else { |
1567 | kfree(stp); | 1627 | int status; |
1568 | return status; | 1628 | status = nfsd_open(rqstp, cur_fh, S_IFREG, flags, |
1629 | &stp->st_vfs_file); | ||
1630 | if (status) { | ||
1631 | if (status == nfserr_dropit) | ||
1632 | status = nfserr_jukebox; | ||
1633 | kmem_cache_free(stateid_slab, stp); | ||
1634 | return status; | ||
1635 | } | ||
1569 | } | 1636 | } |
1570 | vfsopen++; | ||
1571 | *stpp = stp; | 1637 | *stpp = stp; |
1572 | return 0; | 1638 | return 0; |
1573 | } | 1639 | } |
@@ -1628,6 +1694,7 @@ nfs4_set_claim_prev(struct nfsd4_open *open, int *status) | |||
1628 | *status = nfserr_reclaim_bad; | 1694 | *status = nfserr_reclaim_bad; |
1629 | else { | 1695 | else { |
1630 | open->op_stateowner->so_confirmed = 1; | 1696 | open->op_stateowner->so_confirmed = 1; |
1697 | open->op_stateowner->so_client->cl_firststate = 1; | ||
1631 | open->op_stateowner->so_seqid--; | 1698 | open->op_stateowner->so_seqid--; |
1632 | } | 1699 | } |
1633 | } | 1700 | } |
@@ -1646,14 +1713,30 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
1646 | int status, flag = 0; | 1713 | int status, flag = 0; |
1647 | 1714 | ||
1648 | flag = NFS4_OPEN_DELEGATE_NONE; | 1715 | flag = NFS4_OPEN_DELEGATE_NONE; |
1649 | if (open->op_claim_type != NFS4_OPEN_CLAIM_NULL | 1716 | open->op_recall = 0; |
1650 | || !atomic_read(&cb->cb_set) || !sop->so_confirmed) | 1717 | switch (open->op_claim_type) { |
1651 | goto out; | 1718 | case NFS4_OPEN_CLAIM_PREVIOUS: |
1652 | 1719 | if (!atomic_read(&cb->cb_set)) | |
1653 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) | 1720 | open->op_recall = 1; |
1654 | flag = NFS4_OPEN_DELEGATE_WRITE; | 1721 | flag = open->op_delegate_type; |
1655 | else | 1722 | if (flag == NFS4_OPEN_DELEGATE_NONE) |
1656 | flag = NFS4_OPEN_DELEGATE_READ; | 1723 | goto out; |
1724 | break; | ||
1725 | case NFS4_OPEN_CLAIM_NULL: | ||
1726 | /* Let's not give out any delegations till everyone's | ||
1727 | * had the chance to reclaim theirs.... */ | ||
1728 | if (nfs4_in_grace()) | ||
1729 | goto out; | ||
1730 | if (!atomic_read(&cb->cb_set) || !sop->so_confirmed) | ||
1731 | goto out; | ||
1732 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) | ||
1733 | flag = NFS4_OPEN_DELEGATE_WRITE; | ||
1734 | else | ||
1735 | flag = NFS4_OPEN_DELEGATE_READ; | ||
1736 | break; | ||
1737 | default: | ||
1738 | goto out; | ||
1739 | } | ||
1657 | 1740 | ||
1658 | dp = alloc_init_deleg(sop->so_client, stp, fh, flag); | 1741 | dp = alloc_init_deleg(sop->so_client, stp, fh, flag); |
1659 | if (dp == NULL) { | 1742 | if (dp == NULL) { |
@@ -1687,6 +1770,10 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta | |||
1687 | dp->dl_stateid.si_fileid, | 1770 | dp->dl_stateid.si_fileid, |
1688 | dp->dl_stateid.si_generation); | 1771 | dp->dl_stateid.si_generation); |
1689 | out: | 1772 | out: |
1773 | if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS | ||
1774 | && flag == NFS4_OPEN_DELEGATE_NONE | ||
1775 | && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) | ||
1776 | printk("NFSD: WARNING: refusing delegation reclaim\n"); | ||
1690 | open->op_delegate_type = flag; | 1777 | open->op_delegate_type = flag; |
1691 | } | 1778 | } |
1692 | 1779 | ||
@@ -1699,6 +1786,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
1699 | struct nfs4_file *fp = NULL; | 1786 | struct nfs4_file *fp = NULL; |
1700 | struct inode *ino = current_fh->fh_dentry->d_inode; | 1787 | struct inode *ino = current_fh->fh_dentry->d_inode; |
1701 | struct nfs4_stateid *stp = NULL; | 1788 | struct nfs4_stateid *stp = NULL; |
1789 | struct nfs4_delegation *dp = NULL; | ||
1702 | int status; | 1790 | int status; |
1703 | 1791 | ||
1704 | status = nfserr_inval; | 1792 | status = nfserr_inval; |
@@ -1713,7 +1801,13 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
1713 | if (fp) { | 1801 | if (fp) { |
1714 | if ((status = nfs4_check_open(fp, open, &stp))) | 1802 | if ((status = nfs4_check_open(fp, open, &stp))) |
1715 | goto out; | 1803 | goto out; |
1804 | status = nfs4_check_deleg(fp, open, &dp); | ||
1805 | if (status) | ||
1806 | goto out; | ||
1716 | } else { | 1807 | } else { |
1808 | status = nfserr_bad_stateid; | ||
1809 | if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) | ||
1810 | goto out; | ||
1717 | status = nfserr_resource; | 1811 | status = nfserr_resource; |
1718 | fp = alloc_init_file(ino); | 1812 | fp = alloc_init_file(ino); |
1719 | if (fp == NULL) | 1813 | if (fp == NULL) |
@@ -1736,7 +1830,8 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
1736 | flags = MAY_WRITE; | 1830 | flags = MAY_WRITE; |
1737 | else | 1831 | else |
1738 | flags = MAY_READ; | 1832 | flags = MAY_READ; |
1739 | if ((status = nfs4_new_open(rqstp, &stp, current_fh, flags))) | 1833 | status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags); |
1834 | if (status) | ||
1740 | goto out; | 1835 | goto out; |
1741 | init_stateid(stp, fp, open); | 1836 | init_stateid(stp, fp, open); |
1742 | status = nfsd4_truncate(rqstp, current_fh, open); | 1837 | status = nfsd4_truncate(rqstp, current_fh, open); |
@@ -1759,10 +1854,8 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
1759 | stp->st_stateid.si_boot, stp->st_stateid.si_stateownerid, | 1854 | stp->st_stateid.si_boot, stp->st_stateid.si_stateownerid, |
1760 | stp->st_stateid.si_fileid, stp->st_stateid.si_generation); | 1855 | stp->st_stateid.si_fileid, stp->st_stateid.si_generation); |
1761 | out: | 1856 | out: |
1762 | /* take the opportunity to clean up unused state */ | 1857 | if (fp) |
1763 | if (fp && list_empty(&fp->fi_perfile) && list_empty(&fp->fi_del_perfile)) | 1858 | put_nfs4_file(fp); |
1764 | release_file(fp); | ||
1765 | |||
1766 | /* CLAIM_PREVIOUS has different error returns */ | 1859 | /* CLAIM_PREVIOUS has different error returns */ |
1767 | nfs4_set_claim_prev(open, &status); | 1860 | nfs4_set_claim_prev(open, &status); |
1768 | /* | 1861 | /* |
@@ -1775,6 +1868,7 @@ out: | |||
1775 | return status; | 1868 | return status; |
1776 | } | 1869 | } |
1777 | 1870 | ||
1871 | static struct workqueue_struct *laundry_wq; | ||
1778 | static struct work_struct laundromat_work; | 1872 | static struct work_struct laundromat_work; |
1779 | static void laundromat_main(void *); | 1873 | static void laundromat_main(void *); |
1780 | static DECLARE_WORK(laundromat_work, laundromat_main, NULL); | 1874 | static DECLARE_WORK(laundromat_work, laundromat_main, NULL); |
@@ -1800,7 +1894,7 @@ nfsd4_renew(clientid_t *clid) | |||
1800 | } | 1894 | } |
1801 | renew_client(clp); | 1895 | renew_client(clp); |
1802 | status = nfserr_cb_path_down; | 1896 | status = nfserr_cb_path_down; |
1803 | if (!list_empty(&clp->cl_del_perclnt) | 1897 | if (!list_empty(&clp->cl_delegations) |
1804 | && !atomic_read(&clp->cl_callback.cb_set)) | 1898 | && !atomic_read(&clp->cl_callback.cb_set)) |
1805 | goto out; | 1899 | goto out; |
1806 | status = nfs_ok; | 1900 | status = nfs_ok; |
@@ -1809,7 +1903,15 @@ out: | |||
1809 | return status; | 1903 | return status; |
1810 | } | 1904 | } |
1811 | 1905 | ||
1812 | time_t | 1906 | static void |
1907 | end_grace(void) | ||
1908 | { | ||
1909 | dprintk("NFSD: end of grace period\n"); | ||
1910 | nfsd4_recdir_purge_old(); | ||
1911 | in_grace = 0; | ||
1912 | } | ||
1913 | |||
1914 | static time_t | ||
1813 | nfs4_laundromat(void) | 1915 | nfs4_laundromat(void) |
1814 | { | 1916 | { |
1815 | struct nfs4_client *clp; | 1917 | struct nfs4_client *clp; |
@@ -1823,6 +1925,8 @@ nfs4_laundromat(void) | |||
1823 | nfs4_lock_state(); | 1925 | nfs4_lock_state(); |
1824 | 1926 | ||
1825 | dprintk("NFSD: laundromat service - starting\n"); | 1927 | dprintk("NFSD: laundromat service - starting\n"); |
1928 | if (in_grace) | ||
1929 | end_grace(); | ||
1826 | list_for_each_safe(pos, next, &client_lru) { | 1930 | list_for_each_safe(pos, next, &client_lru) { |
1827 | clp = list_entry(pos, struct nfs4_client, cl_lru); | 1931 | clp = list_entry(pos, struct nfs4_client, cl_lru); |
1828 | if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { | 1932 | if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { |
@@ -1833,6 +1937,7 @@ nfs4_laundromat(void) | |||
1833 | } | 1937 | } |
1834 | dprintk("NFSD: purging unused client (clientid %08x)\n", | 1938 | dprintk("NFSD: purging unused client (clientid %08x)\n", |
1835 | clp->cl_clientid.cl_id); | 1939 | clp->cl_clientid.cl_id); |
1940 | nfsd4_remove_clid_dir(clp); | ||
1836 | expire_client(clp); | 1941 | expire_client(clp); |
1837 | } | 1942 | } |
1838 | INIT_LIST_HEAD(&reaplist); | 1943 | INIT_LIST_HEAD(&reaplist); |
@@ -1882,13 +1987,13 @@ laundromat_main(void *not_used) | |||
1882 | 1987 | ||
1883 | t = nfs4_laundromat(); | 1988 | t = nfs4_laundromat(); |
1884 | dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); | 1989 | dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); |
1885 | schedule_delayed_work(&laundromat_work, t*HZ); | 1990 | queue_delayed_work(laundry_wq, &laundromat_work, t*HZ); |
1886 | } | 1991 | } |
1887 | 1992 | ||
1888 | /* search ownerid_hashtbl[] and close_lru for stateid owner | 1993 | /* search ownerid_hashtbl[] and close_lru for stateid owner |
1889 | * (stateid->si_stateownerid) | 1994 | * (stateid->si_stateownerid) |
1890 | */ | 1995 | */ |
1891 | struct nfs4_stateowner * | 1996 | static struct nfs4_stateowner * |
1892 | find_openstateowner_id(u32 st_id, int flags) { | 1997 | find_openstateowner_id(u32 st_id, int flags) { |
1893 | struct nfs4_stateowner *local = NULL; | 1998 | struct nfs4_stateowner *local = NULL; |
1894 | 1999 | ||
@@ -1949,15 +2054,6 @@ out: | |||
1949 | } | 2054 | } |
1950 | 2055 | ||
1951 | static inline int | 2056 | static inline int |
1952 | nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) | ||
1953 | { | ||
1954 | if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ)) | ||
1955 | return nfserr_openmode; | ||
1956 | else | ||
1957 | return nfs_ok; | ||
1958 | } | ||
1959 | |||
1960 | static inline int | ||
1961 | check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags) | 2057 | check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags) |
1962 | { | 2058 | { |
1963 | /* Trying to call delegreturn with a special stateid? Yuch: */ | 2059 | /* Trying to call delegreturn with a special stateid? Yuch: */ |
@@ -2071,7 +2167,7 @@ out: | |||
2071 | /* | 2167 | /* |
2072 | * Checks for sequence id mutating operations. | 2168 | * Checks for sequence id mutating operations. |
2073 | */ | 2169 | */ |
2074 | int | 2170 | static int |
2075 | nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, clientid_t *lockclid) | 2171 | nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, clientid_t *lockclid) |
2076 | { | 2172 | { |
2077 | int status; | 2173 | int status; |
@@ -2230,6 +2326,8 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs | |||
2230 | stp->st_stateid.si_stateownerid, | 2326 | stp->st_stateid.si_stateownerid, |
2231 | stp->st_stateid.si_fileid, | 2327 | stp->st_stateid.si_fileid, |
2232 | stp->st_stateid.si_generation); | 2328 | stp->st_stateid.si_generation); |
2329 | |||
2330 | nfsd4_create_clid_dir(sop->so_client); | ||
2233 | out: | 2331 | out: |
2234 | if (oc->oc_stateowner) | 2332 | if (oc->oc_stateowner) |
2235 | nfs4_get_stateowner(oc->oc_stateowner); | 2333 | nfs4_get_stateowner(oc->oc_stateowner); |
@@ -2387,7 +2485,7 @@ static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE]; | |||
2387 | static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE]; | 2485 | static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE]; |
2388 | static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE]; | 2486 | static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE]; |
2389 | 2487 | ||
2390 | struct nfs4_stateid * | 2488 | static struct nfs4_stateid * |
2391 | find_stateid(stateid_t *stid, int flags) | 2489 | find_stateid(stateid_t *stid, int flags) |
2392 | { | 2490 | { |
2393 | struct nfs4_stateid *local = NULL; | 2491 | struct nfs4_stateid *local = NULL; |
@@ -2419,25 +2517,19 @@ find_stateid(stateid_t *stid, int flags) | |||
2419 | static struct nfs4_delegation * | 2517 | static struct nfs4_delegation * |
2420 | find_delegation_stateid(struct inode *ino, stateid_t *stid) | 2518 | find_delegation_stateid(struct inode *ino, stateid_t *stid) |
2421 | { | 2519 | { |
2422 | struct nfs4_delegation *dp = NULL; | 2520 | struct nfs4_file *fp; |
2423 | struct nfs4_file *fp = NULL; | 2521 | struct nfs4_delegation *dl; |
2424 | u32 st_id; | ||
2425 | 2522 | ||
2426 | dprintk("NFSD:find_delegation_stateid stateid=(%08x/%08x/%08x/%08x)\n", | 2523 | dprintk("NFSD:find_delegation_stateid stateid=(%08x/%08x/%08x/%08x)\n", |
2427 | stid->si_boot, stid->si_stateownerid, | 2524 | stid->si_boot, stid->si_stateownerid, |
2428 | stid->si_fileid, stid->si_generation); | 2525 | stid->si_fileid, stid->si_generation); |
2429 | 2526 | ||
2430 | st_id = stid->si_stateownerid; | ||
2431 | fp = find_file(ino); | 2527 | fp = find_file(ino); |
2432 | if (fp) { | 2528 | if (!fp) |
2433 | list_for_each_entry(dp, &fp->fi_del_perfile, dl_del_perfile) { | 2529 | return NULL; |
2434 | if(dp->dl_stateid.si_stateownerid == st_id) { | 2530 | dl = find_delegation_file(fp, stid); |
2435 | dprintk("NFSD: find_delegation dp %p\n",dp); | 2531 | put_nfs4_file(fp); |
2436 | return dp; | 2532 | return dl; |
2437 | } | ||
2438 | } | ||
2439 | } | ||
2440 | return NULL; | ||
2441 | } | 2533 | } |
2442 | 2534 | ||
2443 | /* | 2535 | /* |
@@ -2457,7 +2549,7 @@ nfs4_transform_lock_offset(struct file_lock *lock) | |||
2457 | lock->fl_end = OFFSET_MAX; | 2549 | lock->fl_end = OFFSET_MAX; |
2458 | } | 2550 | } |
2459 | 2551 | ||
2460 | int | 2552 | static int |
2461 | nfs4_verify_lock_stateowner(struct nfs4_stateowner *sop, unsigned int hashval) | 2553 | nfs4_verify_lock_stateowner(struct nfs4_stateowner *sop, unsigned int hashval) |
2462 | { | 2554 | { |
2463 | struct nfs4_stateowner *local = NULL; | 2555 | struct nfs4_stateowner *local = NULL; |
@@ -2498,22 +2590,6 @@ nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) | |||
2498 | } | 2590 | } |
2499 | 2591 | ||
2500 | static struct nfs4_stateowner * | 2592 | static struct nfs4_stateowner * |
2501 | find_lockstateowner(struct xdr_netobj *owner, clientid_t *clid) | ||
2502 | { | ||
2503 | struct nfs4_stateowner *local = NULL; | ||
2504 | int i; | ||
2505 | |||
2506 | for (i = 0; i < LOCK_HASH_SIZE; i++) { | ||
2507 | list_for_each_entry(local, &lock_ownerid_hashtbl[i], so_idhash) { | ||
2508 | if (!cmp_owner_str(local, owner, clid)) | ||
2509 | continue; | ||
2510 | return local; | ||
2511 | } | ||
2512 | } | ||
2513 | return NULL; | ||
2514 | } | ||
2515 | |||
2516 | static struct nfs4_stateowner * | ||
2517 | find_lockstateowner_str(struct inode *inode, clientid_t *clid, | 2593 | find_lockstateowner_str(struct inode *inode, clientid_t *clid, |
2518 | struct xdr_netobj *owner) | 2594 | struct xdr_netobj *owner) |
2519 | { | 2595 | { |
@@ -2548,13 +2624,13 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str | |||
2548 | INIT_LIST_HEAD(&sop->so_idhash); | 2624 | INIT_LIST_HEAD(&sop->so_idhash); |
2549 | INIT_LIST_HEAD(&sop->so_strhash); | 2625 | INIT_LIST_HEAD(&sop->so_strhash); |
2550 | INIT_LIST_HEAD(&sop->so_perclient); | 2626 | INIT_LIST_HEAD(&sop->so_perclient); |
2551 | INIT_LIST_HEAD(&sop->so_perfilestate); | 2627 | INIT_LIST_HEAD(&sop->so_stateids); |
2552 | INIT_LIST_HEAD(&sop->so_perlockowner); | 2628 | INIT_LIST_HEAD(&sop->so_perstateid); |
2553 | INIT_LIST_HEAD(&sop->so_close_lru); /* not used */ | 2629 | INIT_LIST_HEAD(&sop->so_close_lru); /* not used */ |
2554 | sop->so_time = 0; | 2630 | sop->so_time = 0; |
2555 | list_add(&sop->so_idhash, &lock_ownerid_hashtbl[idhashval]); | 2631 | list_add(&sop->so_idhash, &lock_ownerid_hashtbl[idhashval]); |
2556 | list_add(&sop->so_strhash, &lock_ownerstr_hashtbl[strhashval]); | 2632 | list_add(&sop->so_strhash, &lock_ownerstr_hashtbl[strhashval]); |
2557 | list_add(&sop->so_perlockowner, &open_stp->st_perlockowner); | 2633 | list_add(&sop->so_perstateid, &open_stp->st_lockowners); |
2558 | sop->so_is_open_owner = 0; | 2634 | sop->so_is_open_owner = 0; |
2559 | sop->so_id = current_ownerid++; | 2635 | sop->so_id = current_ownerid++; |
2560 | sop->so_client = clp; | 2636 | sop->so_client = clp; |
@@ -2567,24 +2643,24 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str | |||
2567 | return sop; | 2643 | return sop; |
2568 | } | 2644 | } |
2569 | 2645 | ||
2570 | struct nfs4_stateid * | 2646 | static struct nfs4_stateid * |
2571 | alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struct nfs4_stateid *open_stp) | 2647 | alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struct nfs4_stateid *open_stp) |
2572 | { | 2648 | { |
2573 | struct nfs4_stateid *stp; | 2649 | struct nfs4_stateid *stp; |
2574 | unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id); | 2650 | unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id); |
2575 | 2651 | ||
2576 | if ((stp = kmalloc(sizeof(struct nfs4_stateid), | 2652 | stp = nfs4_alloc_stateid(); |
2577 | GFP_KERNEL)) == NULL) | 2653 | if (stp == NULL) |
2578 | goto out; | 2654 | goto out; |
2579 | INIT_LIST_HEAD(&stp->st_hash); | 2655 | INIT_LIST_HEAD(&stp->st_hash); |
2580 | INIT_LIST_HEAD(&stp->st_perfile); | 2656 | INIT_LIST_HEAD(&stp->st_perfile); |
2581 | INIT_LIST_HEAD(&stp->st_perfilestate); | 2657 | INIT_LIST_HEAD(&stp->st_perstateowner); |
2582 | INIT_LIST_HEAD(&stp->st_perlockowner); /* not used */ | 2658 | INIT_LIST_HEAD(&stp->st_lockowners); /* not used */ |
2583 | list_add(&stp->st_hash, &lockstateid_hashtbl[hashval]); | 2659 | list_add(&stp->st_hash, &lockstateid_hashtbl[hashval]); |
2584 | list_add(&stp->st_perfile, &fp->fi_perfile); | 2660 | list_add(&stp->st_perfile, &fp->fi_stateids); |
2585 | list_add_perfile++; | 2661 | list_add(&stp->st_perstateowner, &sop->so_stateids); |
2586 | list_add(&stp->st_perfilestate, &sop->so_perfilestate); | ||
2587 | stp->st_stateowner = sop; | 2662 | stp->st_stateowner = sop; |
2663 | get_nfs4_file(fp); | ||
2588 | stp->st_file = fp; | 2664 | stp->st_file = fp; |
2589 | stp->st_stateid.si_boot = boot_time; | 2665 | stp->st_stateid.si_boot = boot_time; |
2590 | stp->st_stateid.si_stateownerid = sop->so_id; | 2666 | stp->st_stateid.si_stateownerid = sop->so_id; |
@@ -2598,7 +2674,7 @@ out: | |||
2598 | return stp; | 2674 | return stp; |
2599 | } | 2675 | } |
2600 | 2676 | ||
2601 | int | 2677 | static int |
2602 | check_lock_length(u64 offset, u64 length) | 2678 | check_lock_length(u64 offset, u64 length) |
2603 | { | 2679 | { |
2604 | return ((length == 0) || ((length != ~(u64)0) && | 2680 | return ((length == 0) || ((length != ~(u64)0) && |
@@ -2611,7 +2687,7 @@ check_lock_length(u64 offset, u64 length) | |||
2611 | int | 2687 | int |
2612 | nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock) | 2688 | nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock) |
2613 | { | 2689 | { |
2614 | struct nfs4_stateowner *lock_sop = NULL, *open_sop = NULL; | 2690 | struct nfs4_stateowner *open_sop = NULL; |
2615 | struct nfs4_stateid *lock_stp; | 2691 | struct nfs4_stateid *lock_stp; |
2616 | struct file *filp; | 2692 | struct file *filp; |
2617 | struct file_lock file_lock; | 2693 | struct file_lock file_lock; |
@@ -2670,16 +2746,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock | |||
2670 | strhashval = lock_ownerstr_hashval(fp->fi_inode, | 2746 | strhashval = lock_ownerstr_hashval(fp->fi_inode, |
2671 | open_sop->so_client->cl_clientid.cl_id, | 2747 | open_sop->so_client->cl_clientid.cl_id, |
2672 | &lock->v.new.owner); | 2748 | &lock->v.new.owner); |
2673 | /* | 2749 | /* XXX: Do we need to check for duplicate stateowners on |
2674 | * If we already have this lock owner, the client is in | 2750 | * the same file, or should they just be allowed (and |
2675 | * error (or our bookeeping is wrong!) | 2751 | * create new stateids)? */ |
2676 | * for asking for a 'new lock'. | ||
2677 | */ | ||
2678 | status = nfserr_bad_stateid; | ||
2679 | lock_sop = find_lockstateowner(&lock->v.new.owner, | ||
2680 | &lock->v.new.clientid); | ||
2681 | if (lock_sop) | ||
2682 | goto out; | ||
2683 | status = nfserr_resource; | 2752 | status = nfserr_resource; |
2684 | if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock))) | 2753 | if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock))) |
2685 | goto out; | 2754 | goto out; |
@@ -2970,8 +3039,11 @@ int | |||
2970 | nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner) | 3039 | nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner) |
2971 | { | 3040 | { |
2972 | clientid_t *clid = &rlockowner->rl_clientid; | 3041 | clientid_t *clid = &rlockowner->rl_clientid; |
2973 | struct nfs4_stateowner *local = NULL; | 3042 | struct nfs4_stateowner *sop; |
3043 | struct nfs4_stateid *stp; | ||
2974 | struct xdr_netobj *owner = &rlockowner->rl_owner; | 3044 | struct xdr_netobj *owner = &rlockowner->rl_owner; |
3045 | struct list_head matches; | ||
3046 | int i; | ||
2975 | int status; | 3047 | int status; |
2976 | 3048 | ||
2977 | dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", | 3049 | dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", |
@@ -2987,22 +3059,32 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner * | |||
2987 | 3059 | ||
2988 | nfs4_lock_state(); | 3060 | nfs4_lock_state(); |
2989 | 3061 | ||
2990 | status = nfs_ok; | 3062 | status = nfserr_locks_held; |
2991 | local = find_lockstateowner(owner, clid); | 3063 | /* XXX: we're doing a linear search through all the lockowners. |
2992 | if (local) { | 3064 | * Yipes! For now we'll just hope clients aren't really using |
2993 | struct nfs4_stateid *stp; | 3065 | * release_lockowner much, but eventually we have to fix these |
2994 | 3066 | * data structures. */ | |
2995 | /* check for any locks held by any stateid | 3067 | INIT_LIST_HEAD(&matches); |
2996 | * associated with the (lock) stateowner */ | 3068 | for (i = 0; i < LOCK_HASH_SIZE; i++) { |
2997 | status = nfserr_locks_held; | 3069 | list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) { |
2998 | list_for_each_entry(stp, &local->so_perfilestate, | 3070 | if (!cmp_owner_str(sop, owner, clid)) |
2999 | st_perfilestate) { | 3071 | continue; |
3000 | if (check_for_locks(stp->st_vfs_file, local)) | 3072 | list_for_each_entry(stp, &sop->so_stateids, |
3001 | goto out; | 3073 | st_perstateowner) { |
3074 | if (check_for_locks(stp->st_vfs_file, sop)) | ||
3075 | goto out; | ||
3076 | /* Note: so_perclient unused for lockowners, | ||
3077 | * so it's OK to fool with here. */ | ||
3078 | list_add(&sop->so_perclient, &matches); | ||
3079 | } | ||
3002 | } | 3080 | } |
3003 | /* no locks held by (lock) stateowner */ | 3081 | } |
3004 | status = nfs_ok; | 3082 | /* Clients probably won't expect us to return with some (but not all) |
3005 | release_stateowner(local); | 3083 | * of the lockowner state released; so don't release any until all |
3084 | * have been checked. */ | ||
3085 | status = nfs_ok; | ||
3086 | list_for_each_entry(sop, &matches, so_perclient) { | ||
3087 | release_stateowner(sop); | ||
3006 | } | 3088 | } |
3007 | out: | 3089 | out: |
3008 | nfs4_unlock_state(); | 3090 | nfs4_unlock_state(); |
@@ -3010,39 +3092,38 @@ out: | |||
3010 | } | 3092 | } |
3011 | 3093 | ||
3012 | static inline struct nfs4_client_reclaim * | 3094 | static inline struct nfs4_client_reclaim * |
3013 | alloc_reclaim(int namelen) | 3095 | alloc_reclaim(void) |
3014 | { | 3096 | { |
3015 | struct nfs4_client_reclaim *crp = NULL; | 3097 | return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); |
3098 | } | ||
3016 | 3099 | ||
3017 | crp = kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); | 3100 | int |
3018 | if (!crp) | 3101 | nfs4_has_reclaimed_state(const char *name) |
3019 | return NULL; | 3102 | { |
3020 | crp->cr_name.data = kmalloc(namelen, GFP_KERNEL); | 3103 | unsigned int strhashval = clientstr_hashval(name); |
3021 | if (!crp->cr_name.data) { | 3104 | struct nfs4_client *clp; |
3022 | kfree(crp); | 3105 | |
3023 | return NULL; | 3106 | clp = find_confirmed_client_by_str(name, strhashval); |
3024 | } | 3107 | return clp ? 1 : 0; |
3025 | return crp; | ||
3026 | } | 3108 | } |
3027 | 3109 | ||
3028 | /* | 3110 | /* |
3029 | * failure => all reset bets are off, nfserr_no_grace... | 3111 | * failure => all reset bets are off, nfserr_no_grace... |
3030 | */ | 3112 | */ |
3031 | static int | 3113 | int |
3032 | nfs4_client_to_reclaim(char *name, int namlen) | 3114 | nfs4_client_to_reclaim(const char *name) |
3033 | { | 3115 | { |
3034 | unsigned int strhashval; | 3116 | unsigned int strhashval; |
3035 | struct nfs4_client_reclaim *crp = NULL; | 3117 | struct nfs4_client_reclaim *crp = NULL; |
3036 | 3118 | ||
3037 | dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", namlen, name); | 3119 | dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); |
3038 | crp = alloc_reclaim(namlen); | 3120 | crp = alloc_reclaim(); |
3039 | if (!crp) | 3121 | if (!crp) |
3040 | return 0; | 3122 | return 0; |
3041 | strhashval = clientstr_hashval(name, namlen); | 3123 | strhashval = clientstr_hashval(name); |
3042 | INIT_LIST_HEAD(&crp->cr_strhash); | 3124 | INIT_LIST_HEAD(&crp->cr_strhash); |
3043 | list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]); | 3125 | list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]); |
3044 | memcpy(crp->cr_name.data, name, namlen); | 3126 | memcpy(crp->cr_recdir, name, HEXDIR_LEN); |
3045 | crp->cr_name.len = namlen; | ||
3046 | reclaim_str_hashtbl_size++; | 3127 | reclaim_str_hashtbl_size++; |
3047 | return 1; | 3128 | return 1; |
3048 | } | 3129 | } |
@@ -3053,13 +3134,11 @@ nfs4_release_reclaim(void) | |||
3053 | struct nfs4_client_reclaim *crp = NULL; | 3134 | struct nfs4_client_reclaim *crp = NULL; |
3054 | int i; | 3135 | int i; |
3055 | 3136 | ||
3056 | BUG_ON(!nfs4_reclaim_init); | ||
3057 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | 3137 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { |
3058 | while (!list_empty(&reclaim_str_hashtbl[i])) { | 3138 | while (!list_empty(&reclaim_str_hashtbl[i])) { |
3059 | crp = list_entry(reclaim_str_hashtbl[i].next, | 3139 | crp = list_entry(reclaim_str_hashtbl[i].next, |
3060 | struct nfs4_client_reclaim, cr_strhash); | 3140 | struct nfs4_client_reclaim, cr_strhash); |
3061 | list_del(&crp->cr_strhash); | 3141 | list_del(&crp->cr_strhash); |
3062 | kfree(crp->cr_name.data); | ||
3063 | kfree(crp); | 3142 | kfree(crp); |
3064 | reclaim_str_hashtbl_size--; | 3143 | reclaim_str_hashtbl_size--; |
3065 | } | 3144 | } |
@@ -3069,7 +3148,7 @@ nfs4_release_reclaim(void) | |||
3069 | 3148 | ||
3070 | /* | 3149 | /* |
3071 | * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ | 3150 | * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ |
3072 | struct nfs4_client_reclaim * | 3151 | static struct nfs4_client_reclaim * |
3073 | nfs4_find_reclaim_client(clientid_t *clid) | 3152 | nfs4_find_reclaim_client(clientid_t *clid) |
3074 | { | 3153 | { |
3075 | unsigned int strhashval; | 3154 | unsigned int strhashval; |
@@ -3082,13 +3161,14 @@ nfs4_find_reclaim_client(clientid_t *clid) | |||
3082 | if (clp == NULL) | 3161 | if (clp == NULL) |
3083 | return NULL; | 3162 | return NULL; |
3084 | 3163 | ||
3085 | dprintk("NFSD: nfs4_find_reclaim_client for %.*s\n", | 3164 | dprintk("NFSD: nfs4_find_reclaim_client for %.*s with recdir %s\n", |
3086 | clp->cl_name.len, clp->cl_name.data); | 3165 | clp->cl_name.len, clp->cl_name.data, |
3166 | clp->cl_recdir); | ||
3087 | 3167 | ||
3088 | /* find clp->cl_name in reclaim_str_hashtbl */ | 3168 | /* find clp->cl_name in reclaim_str_hashtbl */ |
3089 | strhashval = clientstr_hashval(clp->cl_name.data, clp->cl_name.len); | 3169 | strhashval = clientstr_hashval(clp->cl_recdir); |
3090 | list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) { | 3170 | list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) { |
3091 | if (cmp_name(&crp->cr_name, &clp->cl_name)) { | 3171 | if (same_name(crp->cr_recdir, clp->cl_recdir)) { |
3092 | return crp; | 3172 | return crp; |
3093 | } | 3173 | } |
3094 | } | 3174 | } |
@@ -3101,30 +3181,16 @@ nfs4_find_reclaim_client(clientid_t *clid) | |||
3101 | int | 3181 | int |
3102 | nfs4_check_open_reclaim(clientid_t *clid) | 3182 | nfs4_check_open_reclaim(clientid_t *clid) |
3103 | { | 3183 | { |
3104 | struct nfs4_client_reclaim *crp; | 3184 | return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad; |
3105 | |||
3106 | if ((crp = nfs4_find_reclaim_client(clid)) == NULL) | ||
3107 | return nfserr_reclaim_bad; | ||
3108 | return nfs_ok; | ||
3109 | } | 3185 | } |
3110 | 3186 | ||
3187 | /* initialization to perform at module load time: */ | ||
3111 | 3188 | ||
3112 | /* | 3189 | void |
3113 | * Start and stop routines | 3190 | nfs4_state_init(void) |
3114 | */ | ||
3115 | |||
3116 | static void | ||
3117 | __nfs4_state_init(void) | ||
3118 | { | 3191 | { |
3119 | int i; | 3192 | int i; |
3120 | time_t grace_time; | ||
3121 | 3193 | ||
3122 | if (!nfs4_reclaim_init) { | ||
3123 | for (i = 0; i < CLIENT_HASH_SIZE; i++) | ||
3124 | INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); | ||
3125 | reclaim_str_hashtbl_size = 0; | ||
3126 | nfs4_reclaim_init = 1; | ||
3127 | } | ||
3128 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | 3194 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { |
3129 | INIT_LIST_HEAD(&conf_id_hashtbl[i]); | 3195 | INIT_LIST_HEAD(&conf_id_hashtbl[i]); |
3130 | INIT_LIST_HEAD(&conf_str_hashtbl[i]); | 3196 | INIT_LIST_HEAD(&conf_str_hashtbl[i]); |
@@ -3146,26 +3212,46 @@ __nfs4_state_init(void) | |||
3146 | INIT_LIST_HEAD(&lock_ownerid_hashtbl[i]); | 3212 | INIT_LIST_HEAD(&lock_ownerid_hashtbl[i]); |
3147 | INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]); | 3213 | INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]); |
3148 | } | 3214 | } |
3149 | memset(&zerostateid, 0, sizeof(stateid_t)); | ||
3150 | memset(&onestateid, ~0, sizeof(stateid_t)); | 3215 | memset(&onestateid, ~0, sizeof(stateid_t)); |
3151 | |||
3152 | INIT_LIST_HEAD(&close_lru); | 3216 | INIT_LIST_HEAD(&close_lru); |
3153 | INIT_LIST_HEAD(&client_lru); | 3217 | INIT_LIST_HEAD(&client_lru); |
3154 | INIT_LIST_HEAD(&del_recall_lru); | 3218 | INIT_LIST_HEAD(&del_recall_lru); |
3155 | spin_lock_init(&recall_lock); | 3219 | for (i = 0; i < CLIENT_HASH_SIZE; i++) |
3220 | INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); | ||
3221 | reclaim_str_hashtbl_size = 0; | ||
3222 | } | ||
3223 | |||
3224 | static void | ||
3225 | nfsd4_load_reboot_recovery_data(void) | ||
3226 | { | ||
3227 | int status; | ||
3228 | |||
3229 | nfs4_lock_state(); | ||
3230 | nfsd4_init_recdir(user_recovery_dirname); | ||
3231 | status = nfsd4_recdir_load(); | ||
3232 | nfs4_unlock_state(); | ||
3233 | if (status) | ||
3234 | printk("NFSD: Failure reading reboot recovery data\n"); | ||
3235 | } | ||
3236 | |||
3237 | /* initialization to perform when the nfsd service is started: */ | ||
3238 | |||
3239 | static void | ||
3240 | __nfs4_state_start(void) | ||
3241 | { | ||
3242 | time_t grace_time; | ||
3243 | |||
3156 | boot_time = get_seconds(); | 3244 | boot_time = get_seconds(); |
3157 | grace_time = max(old_lease_time, lease_time); | 3245 | grace_time = max(user_lease_time, lease_time); |
3158 | if (reclaim_str_hashtbl_size == 0) | 3246 | lease_time = user_lease_time; |
3159 | grace_time = 0; | 3247 | in_grace = 1; |
3160 | if (grace_time) | 3248 | printk("NFSD: starting %ld-second grace period\n", grace_time); |
3161 | printk("NFSD: starting %ld-second grace period\n", grace_time); | 3249 | laundry_wq = create_singlethread_workqueue("nfsd4"); |
3162 | grace_end = boot_time + grace_time; | 3250 | queue_delayed_work(laundry_wq, &laundromat_work, grace_time*HZ); |
3163 | INIT_WORK(&laundromat_work,laundromat_main, NULL); | ||
3164 | schedule_delayed_work(&laundromat_work, NFSD_LEASE_TIME*HZ); | ||
3165 | } | 3251 | } |
3166 | 3252 | ||
3167 | int | 3253 | int |
3168 | nfs4_state_init(void) | 3254 | nfs4_state_start(void) |
3169 | { | 3255 | { |
3170 | int status; | 3256 | int status; |
3171 | 3257 | ||
@@ -3174,7 +3260,8 @@ nfs4_state_init(void) | |||
3174 | status = nfsd4_init_slabs(); | 3260 | status = nfsd4_init_slabs(); |
3175 | if (status) | 3261 | if (status) |
3176 | return status; | 3262 | return status; |
3177 | __nfs4_state_init(); | 3263 | nfsd4_load_reboot_recovery_data(); |
3264 | __nfs4_state_start(); | ||
3178 | nfs4_init = 1; | 3265 | nfs4_init = 1; |
3179 | return 0; | 3266 | return 0; |
3180 | } | 3267 | } |
@@ -3182,14 +3269,7 @@ nfs4_state_init(void) | |||
3182 | int | 3269 | int |
3183 | nfs4_in_grace(void) | 3270 | nfs4_in_grace(void) |
3184 | { | 3271 | { |
3185 | return get_seconds() < grace_end; | 3272 | return in_grace; |
3186 | } | ||
3187 | |||
3188 | void | ||
3189 | set_no_grace(void) | ||
3190 | { | ||
3191 | printk("NFSD: ERROR in reboot recovery. State reclaims will fail.\n"); | ||
3192 | grace_end = get_seconds(); | ||
3193 | } | 3273 | } |
3194 | 3274 | ||
3195 | time_t | 3275 | time_t |
@@ -3236,21 +3316,11 @@ __nfs4_state_shutdown(void) | |||
3236 | unhash_delegation(dp); | 3316 | unhash_delegation(dp); |
3237 | } | 3317 | } |
3238 | 3318 | ||
3239 | release_all_files(); | ||
3240 | cancel_delayed_work(&laundromat_work); | 3319 | cancel_delayed_work(&laundromat_work); |
3241 | flush_scheduled_work(); | 3320 | flush_workqueue(laundry_wq); |
3321 | destroy_workqueue(laundry_wq); | ||
3322 | nfsd4_shutdown_recdir(); | ||
3242 | nfs4_init = 0; | 3323 | nfs4_init = 0; |
3243 | dprintk("NFSD: list_add_perfile %d list_del_perfile %d\n", | ||
3244 | list_add_perfile, list_del_perfile); | ||
3245 | dprintk("NFSD: add_perclient %d del_perclient %d\n", | ||
3246 | add_perclient, del_perclient); | ||
3247 | dprintk("NFSD: alloc_file %d free_file %d\n", | ||
3248 | alloc_file, free_file); | ||
3249 | dprintk("NFSD: vfsopen %d vfsclose %d\n", | ||
3250 | vfsopen, vfsclose); | ||
3251 | dprintk("NFSD: alloc_delegation %d free_delegation %d\n", | ||
3252 | alloc_delegation, free_delegation); | ||
3253 | |||
3254 | } | 3324 | } |
3255 | 3325 | ||
3256 | void | 3326 | void |
@@ -3263,56 +3333,48 @@ nfs4_state_shutdown(void) | |||
3263 | nfs4_unlock_state(); | 3333 | nfs4_unlock_state(); |
3264 | } | 3334 | } |
3265 | 3335 | ||
3336 | static void | ||
3337 | nfs4_set_recdir(char *recdir) | ||
3338 | { | ||
3339 | nfs4_lock_state(); | ||
3340 | strcpy(user_recovery_dirname, recdir); | ||
3341 | nfs4_unlock_state(); | ||
3342 | } | ||
3343 | |||
3344 | /* | ||
3345 | * Change the NFSv4 recovery directory to recdir. | ||
3346 | */ | ||
3347 | int | ||
3348 | nfs4_reset_recoverydir(char *recdir) | ||
3349 | { | ||
3350 | int status; | ||
3351 | struct nameidata nd; | ||
3352 | |||
3353 | status = path_lookup(recdir, LOOKUP_FOLLOW, &nd); | ||
3354 | if (status) | ||
3355 | return status; | ||
3356 | status = -ENOTDIR; | ||
3357 | if (S_ISDIR(nd.dentry->d_inode->i_mode)) { | ||
3358 | nfs4_set_recdir(recdir); | ||
3359 | status = 0; | ||
3360 | } | ||
3361 | path_release(&nd); | ||
3362 | return status; | ||
3363 | } | ||
3364 | |||
3266 | /* | 3365 | /* |
3267 | * Called when leasetime is changed. | 3366 | * Called when leasetime is changed. |
3268 | * | 3367 | * |
3269 | * if nfsd is not started, simply set the global lease. | 3368 | * The only way the protocol gives us to handle on-the-fly lease changes is to |
3270 | * | 3369 | * simulate a reboot. Instead of doing that, we just wait till the next time |
3271 | * if nfsd(s) are running, lease change requires nfsv4 state to be reset. | 3370 | * we start to register any changes in lease time. If the administrator |
3272 | * e.g: boot_time is reset, existing nfs4_client structs are | 3371 | * really wants to change the lease time *now*, they can go ahead and bring |
3273 | * used to fill reclaim_str_hashtbl, then all state (except for the | 3372 | * nfsd down and then back up again after changing the lease time. |
3274 | * reclaim_str_hashtbl) is re-initialized. | ||
3275 | * | ||
3276 | * if the old lease time is greater than the new lease time, the grace | ||
3277 | * period needs to be set to the old lease time to allow clients to reclaim | ||
3278 | * their state. XXX - we may want to set the grace period == lease time | ||
3279 | * after an initial grace period == old lease time | ||
3280 | * | ||
3281 | * if an error occurs in this process, the new lease is set, but the server | ||
3282 | * will not honor OPEN or LOCK reclaims, and will return nfserr_no_grace | ||
3283 | * which means OPEN/LOCK/READ/WRITE will fail during grace period. | ||
3284 | * | ||
3285 | * clients will attempt to reset all state with SETCLIENTID/CONFIRM, and | ||
3286 | * OPEN and LOCK reclaims. | ||
3287 | */ | 3373 | */ |
3288 | void | 3374 | void |
3289 | nfs4_reset_lease(time_t leasetime) | 3375 | nfs4_reset_lease(time_t leasetime) |
3290 | { | 3376 | { |
3291 | struct nfs4_client *clp; | 3377 | lock_kernel(); |
3292 | int i; | 3378 | user_lease_time = leasetime; |
3293 | 3379 | unlock_kernel(); | |
3294 | printk("NFSD: New leasetime %ld\n",leasetime); | ||
3295 | if (!nfs4_init) | ||
3296 | return; | ||
3297 | nfs4_lock_state(); | ||
3298 | old_lease_time = lease_time; | ||
3299 | lease_time = leasetime; | ||
3300 | |||
3301 | nfs4_release_reclaim(); | ||
3302 | |||
3303 | /* populate reclaim_str_hashtbl with current confirmed nfs4_clientid */ | ||
3304 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | ||
3305 | list_for_each_entry(clp, &conf_id_hashtbl[i], cl_idhash) { | ||
3306 | if (!nfs4_client_to_reclaim(clp->cl_name.data, | ||
3307 | clp->cl_name.len)) { | ||
3308 | nfs4_release_reclaim(); | ||
3309 | goto init_state; | ||
3310 | } | ||
3311 | } | ||
3312 | } | ||
3313 | init_state: | ||
3314 | __nfs4_state_shutdown(); | ||
3315 | __nfs4_state_init(); | ||
3316 | nfs4_unlock_state(); | ||
3317 | } | 3380 | } |
3318 | |||
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 36a058a112d5..91fb171d2ace 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -136,7 +136,7 @@ xdr_error: \ | |||
136 | } \ | 136 | } \ |
137 | } while (0) | 137 | } while (0) |
138 | 138 | ||
139 | u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes) | 139 | static u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes) |
140 | { | 140 | { |
141 | /* We want more bytes than seem to be available. | 141 | /* We want more bytes than seem to be available. |
142 | * Maybe we need a new page, maybe we have just run out | 142 | * Maybe we need a new page, maybe we have just run out |
@@ -190,7 +190,7 @@ defer_free(struct nfsd4_compoundargs *argp, | |||
190 | return 0; | 190 | return 0; |
191 | } | 191 | } |
192 | 192 | ||
193 | char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes) | 193 | static char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes) |
194 | { | 194 | { |
195 | void *new = NULL; | 195 | void *new = NULL; |
196 | if (p == argp->tmp) { | 196 | if (p == argp->tmp) { |
@@ -1366,7 +1366,10 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
1366 | if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) { | 1366 | if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) { |
1367 | if ((buflen -= 4) < 0) | 1367 | if ((buflen -= 4) < 0) |
1368 | goto out_resource; | 1368 | goto out_resource; |
1369 | WRITE32( NFS4_FH_NOEXPIRE_WITH_OPEN | NFS4_FH_VOL_RENAME ); | 1369 | if (exp->ex_flags & NFSEXP_NOSUBTREECHECK) |
1370 | WRITE32(NFS4_FH_VOLATILE_ANY); | ||
1371 | else | ||
1372 | WRITE32(NFS4_FH_VOLATILE_ANY|NFS4_FH_VOL_RENAME); | ||
1370 | } | 1373 | } |
1371 | if (bmval0 & FATTR4_WORD0_CHANGE) { | 1374 | if (bmval0 & FATTR4_WORD0_CHANGE) { |
1372 | /* | 1375 | /* |
@@ -1969,7 +1972,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open | |||
1969 | case NFS4_OPEN_DELEGATE_READ: | 1972 | case NFS4_OPEN_DELEGATE_READ: |
1970 | RESERVE_SPACE(20 + sizeof(stateid_t)); | 1973 | RESERVE_SPACE(20 + sizeof(stateid_t)); |
1971 | WRITEMEM(&open->op_delegate_stateid, sizeof(stateid_t)); | 1974 | WRITEMEM(&open->op_delegate_stateid, sizeof(stateid_t)); |
1972 | WRITE32(0); | 1975 | WRITE32(open->op_recall); |
1973 | 1976 | ||
1974 | /* | 1977 | /* |
1975 | * TODO: ACE's in delegations | 1978 | * TODO: ACE's in delegations |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 161afdcb8f7d..841c562991e8 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -51,6 +51,7 @@ enum { | |||
51 | NFSD_Fh, | 51 | NFSD_Fh, |
52 | NFSD_Threads, | 52 | NFSD_Threads, |
53 | NFSD_Leasetime, | 53 | NFSD_Leasetime, |
54 | NFSD_RecoveryDir, | ||
54 | }; | 55 | }; |
55 | 56 | ||
56 | /* | 57 | /* |
@@ -66,6 +67,7 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size); | |||
66 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size); | 67 | static ssize_t write_filehandle(struct file *file, char *buf, size_t size); |
67 | static ssize_t write_threads(struct file *file, char *buf, size_t size); | 68 | static ssize_t write_threads(struct file *file, char *buf, size_t size); |
68 | static ssize_t write_leasetime(struct file *file, char *buf, size_t size); | 69 | static ssize_t write_leasetime(struct file *file, char *buf, size_t size); |
70 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size); | ||
69 | 71 | ||
70 | static ssize_t (*write_op[])(struct file *, char *, size_t) = { | 72 | static ssize_t (*write_op[])(struct file *, char *, size_t) = { |
71 | [NFSD_Svc] = write_svc, | 73 | [NFSD_Svc] = write_svc, |
@@ -78,6 +80,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = { | |||
78 | [NFSD_Fh] = write_filehandle, | 80 | [NFSD_Fh] = write_filehandle, |
79 | [NFSD_Threads] = write_threads, | 81 | [NFSD_Threads] = write_threads, |
80 | [NFSD_Leasetime] = write_leasetime, | 82 | [NFSD_Leasetime] = write_leasetime, |
83 | [NFSD_RecoveryDir] = write_recoverydir, | ||
81 | }; | 84 | }; |
82 | 85 | ||
83 | static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) | 86 | static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos) |
@@ -349,6 +352,25 @@ static ssize_t write_leasetime(struct file *file, char *buf, size_t size) | |||
349 | return strlen(buf); | 352 | return strlen(buf); |
350 | } | 353 | } |
351 | 354 | ||
355 | static ssize_t write_recoverydir(struct file *file, char *buf, size_t size) | ||
356 | { | ||
357 | char *mesg = buf; | ||
358 | char *recdir; | ||
359 | int len, status; | ||
360 | |||
361 | if (size > PATH_MAX || buf[size-1] != '\n') | ||
362 | return -EINVAL; | ||
363 | buf[size-1] = 0; | ||
364 | |||
365 | recdir = mesg; | ||
366 | len = qword_get(&mesg, recdir, size); | ||
367 | if (len <= 0) | ||
368 | return -EINVAL; | ||
369 | |||
370 | status = nfs4_reset_recoverydir(recdir); | ||
371 | return strlen(buf); | ||
372 | } | ||
373 | |||
352 | /*----------------------------------------------------------------------------*/ | 374 | /*----------------------------------------------------------------------------*/ |
353 | /* | 375 | /* |
354 | * populating the filesystem. | 376 | * populating the filesystem. |
@@ -369,6 +391,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent) | |||
369 | [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, | 391 | [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, |
370 | #ifdef CONFIG_NFSD_V4 | 392 | #ifdef CONFIG_NFSD_V4 |
371 | [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, | 393 | [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, |
394 | [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR}, | ||
372 | #endif | 395 | #endif |
373 | /* last one */ {""} | 396 | /* last one */ {""} |
374 | }; | 397 | }; |
@@ -397,9 +420,8 @@ static int __init init_nfsd(void) | |||
397 | nfsd_cache_init(); /* RPC reply cache */ | 420 | nfsd_cache_init(); /* RPC reply cache */ |
398 | nfsd_export_init(); /* Exports table */ | 421 | nfsd_export_init(); /* Exports table */ |
399 | nfsd_lockd_init(); /* lockd->nfsd callbacks */ | 422 | nfsd_lockd_init(); /* lockd->nfsd callbacks */ |
400 | #ifdef CONFIG_NFSD_V4 | 423 | nfs4_state_init(); /* NFSv4 locking state */ |
401 | nfsd_idmap_init(); /* Name to ID mapping */ | 424 | nfsd_idmap_init(); /* Name to ID mapping */ |
402 | #endif /* CONFIG_NFSD_V4 */ | ||
403 | if (proc_mkdir("fs/nfs", NULL)) { | 425 | if (proc_mkdir("fs/nfs", NULL)) { |
404 | struct proc_dir_entry *entry; | 426 | struct proc_dir_entry *entry; |
405 | entry = create_proc_entry("fs/nfs/exports", 0, NULL); | 427 | entry = create_proc_entry("fs/nfs/exports", 0, NULL); |
@@ -426,9 +448,7 @@ static void __exit exit_nfsd(void) | |||
426 | remove_proc_entry("fs/nfs", NULL); | 448 | remove_proc_entry("fs/nfs", NULL); |
427 | nfsd_stat_shutdown(); | 449 | nfsd_stat_shutdown(); |
428 | nfsd_lockd_shutdown(); | 450 | nfsd_lockd_shutdown(); |
429 | #ifdef CONFIG_NFSD_V4 | ||
430 | nfsd_idmap_shutdown(); | 451 | nfsd_idmap_shutdown(); |
431 | #endif /* CONFIG_NFSD_V4 */ | ||
432 | unregister_filesystem(&nfsd_fs_type); | 452 | unregister_filesystem(&nfsd_fs_type); |
433 | } | 453 | } |
434 | 454 | ||
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 904df604e86b..07b9a065e9da 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -95,7 +95,7 @@ nfsd_svc(unsigned short port, int nrservs) | |||
95 | error = nfsd_racache_init(2*nrservs); | 95 | error = nfsd_racache_init(2*nrservs); |
96 | if (error<0) | 96 | if (error<0) |
97 | goto out; | 97 | goto out; |
98 | error = nfs4_state_init(); | 98 | error = nfs4_state_start(); |
99 | if (error<0) | 99 | if (error<0) |
100 | goto out; | 100 | goto out; |
101 | if (!nfsd_serv) { | 101 | if (!nfsd_serv) { |
@@ -808,7 +808,9 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) | |||
808 | 808 | ||
809 | /* NB: we're sure to have correct a_ops only after f_op->open */ | 809 | /* NB: we're sure to have correct a_ops only after f_op->open */ |
810 | if (f->f_flags & O_DIRECT) { | 810 | if (f->f_flags & O_DIRECT) { |
811 | if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO) { | 811 | if (!f->f_mapping->a_ops || |
812 | ((!f->f_mapping->a_ops->direct_IO) && | ||
813 | (!f->f_mapping->a_ops->get_xip_page))) { | ||
812 | fput(f); | 814 | fput(f); |
813 | f = ERR_PTR(-EINVAL); | 815 | f = ERR_PTR(-EINVAL); |
814 | } | 816 | } |
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index 2230afff1870..12e91209544e 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c | |||
@@ -201,7 +201,7 @@ static int reiserfs_allocate_blocks_for_region( | |||
201 | /* If we came here, it means we absolutely need to open a transaction, | 201 | /* If we came here, it means we absolutely need to open a transaction, |
202 | since we need to allocate some blocks */ | 202 | since we need to allocate some blocks */ |
203 | reiserfs_write_lock(inode->i_sb); // Journaling stuff and we need that. | 203 | reiserfs_write_lock(inode->i_sb); // Journaling stuff and we need that. |
204 | res = journal_begin(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS); // Wish I know if this number enough | 204 | res = journal_begin(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb)); // Wish I know if this number enough |
205 | if (res) | 205 | if (res) |
206 | goto error_exit; | 206 | goto error_exit; |
207 | reiserfs_update_inode_transaction(inode) ; | 207 | reiserfs_update_inode_transaction(inode) ; |
@@ -576,7 +576,7 @@ error_exit: | |||
576 | int err; | 576 | int err; |
577 | // update any changes we made to blk count | 577 | // update any changes we made to blk count |
578 | reiserfs_update_sd(th, inode); | 578 | reiserfs_update_sd(th, inode); |
579 | err = journal_end(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS); | 579 | err = journal_end(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb)); |
580 | if (err) | 580 | if (err) |
581 | res = err; | 581 | res = err; |
582 | } | 582 | } |
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 2711dff1b7b4..0d5817f81972 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c | |||
@@ -28,7 +28,7 @@ static int reiserfs_prepare_write(struct file *f, struct page *page, | |||
28 | void reiserfs_delete_inode (struct inode * inode) | 28 | void reiserfs_delete_inode (struct inode * inode) |
29 | { | 29 | { |
30 | /* We need blocks for transaction + (user+group) quota update (possibly delete) */ | 30 | /* We need blocks for transaction + (user+group) quota update (possibly delete) */ |
31 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 * REISERFS_QUOTA_INIT_BLOCKS; | 31 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb); |
32 | struct reiserfs_transaction_handle th ; | 32 | struct reiserfs_transaction_handle th ; |
33 | 33 | ||
34 | reiserfs_write_lock(inode->i_sb); | 34 | reiserfs_write_lock(inode->i_sb); |
@@ -591,7 +591,7 @@ int reiserfs_get_block (struct inode * inode, sector_t block, | |||
591 | XXX in practically impossible worst case direct2indirect() | 591 | XXX in practically impossible worst case direct2indirect() |
592 | can incur (much) more than 3 balancings. | 592 | can incur (much) more than 3 balancings. |
593 | quota update for user, group */ | 593 | quota update for user, group */ |
594 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS; | 594 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb); |
595 | int version; | 595 | int version; |
596 | int dangle = 1; | 596 | int dangle = 1; |
597 | loff_t new_offset = (((loff_t)block) << inode->i_sb->s_blocksize_bits) + 1 ; | 597 | loff_t new_offset = (((loff_t)block) << inode->i_sb->s_blocksize_bits) + 1 ; |
@@ -2796,12 +2796,15 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) { | |||
2796 | 2796 | ||
2797 | if (!error) { | 2797 | if (!error) { |
2798 | struct reiserfs_transaction_handle th; | 2798 | struct reiserfs_transaction_handle th; |
2799 | int jbegin_count = 2*(REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb)+REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb))+2; | ||
2799 | 2800 | ||
2800 | /* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */ | 2801 | /* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */ |
2801 | journal_begin(&th, inode->i_sb, 4*REISERFS_QUOTA_INIT_BLOCKS+2); | 2802 | error = journal_begin(&th, inode->i_sb, jbegin_count); |
2803 | if (error) | ||
2804 | goto out; | ||
2802 | error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; | 2805 | error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; |
2803 | if (error) { | 2806 | if (error) { |
2804 | journal_end(&th, inode->i_sb, 4*REISERFS_QUOTA_INIT_BLOCKS+2); | 2807 | journal_end(&th, inode->i_sb, jbegin_count); |
2805 | goto out; | 2808 | goto out; |
2806 | } | 2809 | } |
2807 | /* Update corresponding info in inode so that everything is in | 2810 | /* Update corresponding info in inode so that everything is in |
@@ -2811,7 +2814,7 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) { | |||
2811 | if (attr->ia_valid & ATTR_GID) | 2814 | if (attr->ia_valid & ATTR_GID) |
2812 | inode->i_gid = attr->ia_gid; | 2815 | inode->i_gid = attr->ia_gid; |
2813 | mark_inode_dirty(inode); | 2816 | mark_inode_dirty(inode); |
2814 | journal_end(&th, inode->i_sb, 4*REISERFS_QUOTA_INIT_BLOCKS+2); | 2817 | error = journal_end(&th, inode->i_sb, jbegin_count); |
2815 | } | 2818 | } |
2816 | } | 2819 | } |
2817 | if (!error) | 2820 | if (!error) |
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 3072cfdee959..7b87707acc36 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c | |||
@@ -2631,6 +2631,8 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th, struct sup | |||
2631 | int retval; | 2631 | int retval; |
2632 | 2632 | ||
2633 | reiserfs_check_lock_depth(p_s_sb, "journal_begin") ; | 2633 | reiserfs_check_lock_depth(p_s_sb, "journal_begin") ; |
2634 | if (nblocks > journal->j_trans_max) | ||
2635 | BUG(); | ||
2634 | 2636 | ||
2635 | PROC_INFO_INC( p_s_sb, journal.journal_being ); | 2637 | PROC_INFO_INC( p_s_sb, journal.journal_being ); |
2636 | /* set here for journal_join */ | 2638 | /* set here for journal_join */ |
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index 7d4dc5f5aa8b..4a333255f27a 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c | |||
@@ -586,7 +586,7 @@ static int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode, | |||
586 | int retval; | 586 | int retval; |
587 | struct inode * inode; | 587 | struct inode * inode; |
588 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ | 588 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ |
589 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS); | 589 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb)+REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); |
590 | struct reiserfs_transaction_handle th ; | 590 | struct reiserfs_transaction_handle th ; |
591 | int locked; | 591 | int locked; |
592 | 592 | ||
@@ -653,7 +653,7 @@ static int reiserfs_mknod (struct inode * dir, struct dentry *dentry, int mode, | |||
653 | struct inode * inode; | 653 | struct inode * inode; |
654 | struct reiserfs_transaction_handle th ; | 654 | struct reiserfs_transaction_handle th ; |
655 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ | 655 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ |
656 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS); | 656 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb)+REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); |
657 | int locked; | 657 | int locked; |
658 | 658 | ||
659 | if (!new_valid_dev(rdev)) | 659 | if (!new_valid_dev(rdev)) |
@@ -727,7 +727,7 @@ static int reiserfs_mkdir (struct inode * dir, struct dentry *dentry, int mode) | |||
727 | struct inode * inode; | 727 | struct inode * inode; |
728 | struct reiserfs_transaction_handle th ; | 728 | struct reiserfs_transaction_handle th ; |
729 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ | 729 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ |
730 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS); | 730 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb)+REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); |
731 | int locked; | 731 | int locked; |
732 | 732 | ||
733 | #ifdef DISPLACE_NEW_PACKING_LOCALITIES | 733 | #ifdef DISPLACE_NEW_PACKING_LOCALITIES |
@@ -829,8 +829,10 @@ static int reiserfs_rmdir (struct inode * dir, struct dentry *dentry) | |||
829 | 829 | ||
830 | 830 | ||
831 | /* we will be doing 2 balancings and update 2 stat data, we change quotas | 831 | /* we will be doing 2 balancings and update 2 stat data, we change quotas |
832 | * of the owner of the directory and of the owner of the parent directory */ | 832 | * of the owner of the directory and of the owner of the parent directory. |
833 | jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS); | 833 | * The quota structure is possibly deleted only on last iput => outside |
834 | * of this transaction */ | ||
835 | jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 + 4 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb); | ||
834 | 836 | ||
835 | reiserfs_write_lock(dir->i_sb); | 837 | reiserfs_write_lock(dir->i_sb); |
836 | retval = journal_begin(&th, dir->i_sb, jbegin_count) ; | 838 | retval = journal_begin(&th, dir->i_sb, jbegin_count) ; |
@@ -913,9 +915,10 @@ static int reiserfs_unlink (struct inode * dir, struct dentry *dentry) | |||
913 | inode = dentry->d_inode; | 915 | inode = dentry->d_inode; |
914 | 916 | ||
915 | /* in this transaction we can be doing at max two balancings and update | 917 | /* in this transaction we can be doing at max two balancings and update |
916 | two stat datas, we change quotas of the owner of the directory and of | 918 | * two stat datas, we change quotas of the owner of the directory and of |
917 | the owner of the parent directory */ | 919 | * the owner of the parent directory. The quota structure is possibly |
918 | jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS); | 920 | * deleted only on iput => outside of this transaction */ |
921 | jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 + 4 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb); | ||
919 | 922 | ||
920 | reiserfs_write_lock(dir->i_sb); | 923 | reiserfs_write_lock(dir->i_sb); |
921 | retval = journal_begin(&th, dir->i_sb, jbegin_count) ; | 924 | retval = journal_begin(&th, dir->i_sb, jbegin_count) ; |
@@ -1000,7 +1003,7 @@ static int reiserfs_symlink (struct inode * parent_dir, | |||
1000 | struct reiserfs_transaction_handle th ; | 1003 | struct reiserfs_transaction_handle th ; |
1001 | int mode = S_IFLNK | S_IRWXUGO; | 1004 | int mode = S_IFLNK | S_IRWXUGO; |
1002 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ | 1005 | /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */ |
1003 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS); | 1006 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS(parent_dir->i_sb)+REISERFS_QUOTA_TRANS_BLOCKS(parent_dir->i_sb)); |
1004 | 1007 | ||
1005 | if (!(inode = new_inode(parent_dir->i_sb))) { | 1008 | if (!(inode = new_inode(parent_dir->i_sb))) { |
1006 | return -ENOMEM ; | 1009 | return -ENOMEM ; |
@@ -1076,7 +1079,7 @@ static int reiserfs_link (struct dentry * old_dentry, struct inode * dir, struct | |||
1076 | struct inode *inode = old_dentry->d_inode; | 1079 | struct inode *inode = old_dentry->d_inode; |
1077 | struct reiserfs_transaction_handle th ; | 1080 | struct reiserfs_transaction_handle th ; |
1078 | /* We need blocks for transaction + update of quotas for the owners of the directory */ | 1081 | /* We need blocks for transaction + update of quotas for the owners of the directory */ |
1079 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * REISERFS_QUOTA_TRANS_BLOCKS; | 1082 | int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb); |
1080 | 1083 | ||
1081 | reiserfs_write_lock(dir->i_sb); | 1084 | reiserfs_write_lock(dir->i_sb); |
1082 | if (inode->i_nlink >= REISERFS_LINK_MAX) { | 1085 | if (inode->i_nlink >= REISERFS_LINK_MAX) { |
@@ -1196,7 +1199,7 @@ static int reiserfs_rename (struct inode * old_dir, struct dentry *old_dentry, | |||
1196 | pointed initially and (5) maybe block containing ".." of | 1199 | pointed initially and (5) maybe block containing ".." of |
1197 | renamed directory | 1200 | renamed directory |
1198 | quota updates: two parent directories */ | 1201 | quota updates: two parent directories */ |
1199 | jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 5 + 4 * REISERFS_QUOTA_TRANS_BLOCKS; | 1202 | jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 5 + 4 * REISERFS_QUOTA_TRANS_BLOCKS(old_dir->i_sb); |
1200 | 1203 | ||
1201 | old_inode = old_dentry->d_inode; | 1204 | old_inode = old_dentry->d_inode; |
1202 | new_dentry_inode = new_dentry->d_inode; | 1205 | new_dentry_inode = new_dentry->d_inode; |
diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index c47f8fd31a2d..63158491e152 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c | |||
@@ -223,7 +223,7 @@ extern struct tree_balance * cur_tb; | |||
223 | const struct reiserfs_key MIN_KEY = {0, 0, {{0, 0},}}; | 223 | const struct reiserfs_key MIN_KEY = {0, 0, {{0, 0},}}; |
224 | 224 | ||
225 | /* Maximal possible key. It is never in the tree. */ | 225 | /* Maximal possible key. It is never in the tree. */ |
226 | const struct reiserfs_key MAX_KEY = { | 226 | static const struct reiserfs_key MAX_KEY = { |
227 | __constant_cpu_to_le32(0xffffffff), | 227 | __constant_cpu_to_le32(0xffffffff), |
228 | __constant_cpu_to_le32(0xffffffff), | 228 | __constant_cpu_to_le32(0xffffffff), |
229 | {{__constant_cpu_to_le32(0xffffffff), | 229 | {{__constant_cpu_to_le32(0xffffffff), |
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index aae0779ed5b4..660aefca1fd2 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
@@ -866,8 +866,9 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st | |||
866 | {"jdev", .arg_required = 'j', .values = NULL}, | 866 | {"jdev", .arg_required = 'j', .values = NULL}, |
867 | {"nolargeio", .arg_required = 'w', .values = NULL}, | 867 | {"nolargeio", .arg_required = 'w', .values = NULL}, |
868 | {"commit", .arg_required = 'c', .values = NULL}, | 868 | {"commit", .arg_required = 'c', .values = NULL}, |
869 | {"usrquota",}, | 869 | {"usrquota", .setmask = 1<<REISERFS_QUOTA}, |
870 | {"grpquota",}, | 870 | {"grpquota", .setmask = 1<<REISERFS_QUOTA}, |
871 | {"noquota", .clrmask = 1<<REISERFS_QUOTA}, | ||
871 | {"errors", .arg_required = 'e', .values = error_actions}, | 872 | {"errors", .arg_required = 'e', .values = error_actions}, |
872 | {"usrjquota", .arg_required = 'u'|(1<<REISERFS_OPT_ALLOWEMPTY), .values = NULL}, | 873 | {"usrjquota", .arg_required = 'u'|(1<<REISERFS_OPT_ALLOWEMPTY), .values = NULL}, |
873 | {"grpjquota", .arg_required = 'g'|(1<<REISERFS_OPT_ALLOWEMPTY), .values = NULL}, | 874 | {"grpjquota", .arg_required = 'g'|(1<<REISERFS_OPT_ALLOWEMPTY), .values = NULL}, |
@@ -964,6 +965,7 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st | |||
964 | return 0; | 965 | return 0; |
965 | } | 966 | } |
966 | strcpy(REISERFS_SB(s)->s_qf_names[qtype], arg); | 967 | strcpy(REISERFS_SB(s)->s_qf_names[qtype], arg); |
968 | *mount_options |= 1<<REISERFS_QUOTA; | ||
967 | } | 969 | } |
968 | else { | 970 | else { |
969 | if (REISERFS_SB(s)->s_qf_names[qtype]) { | 971 | if (REISERFS_SB(s)->s_qf_names[qtype]) { |
@@ -995,7 +997,13 @@ static int reiserfs_parse_options (struct super_block * s, char * options, /* st | |||
995 | reiserfs_warning(s, "reiserfs_parse_options: journalled quota format not specified."); | 997 | reiserfs_warning(s, "reiserfs_parse_options: journalled quota format not specified."); |
996 | return 0; | 998 | return 0; |
997 | } | 999 | } |
1000 | /* This checking is not precise wrt the quota type but for our purposes it is sufficient */ | ||
1001 | if (!(*mount_options & (1<<REISERFS_QUOTA)) && sb_any_quota_enabled(s)) { | ||
1002 | reiserfs_warning(s, "reiserfs_parse_options: quota options must be present when quota is turned on."); | ||
1003 | return 0; | ||
1004 | } | ||
998 | #endif | 1005 | #endif |
1006 | |||
999 | return 1; | 1007 | return 1; |
1000 | } | 1008 | } |
1001 | 1009 | ||
@@ -1105,6 +1113,7 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a | |||
1105 | safe_mask |= 1 << REISERFS_ERROR_RO; | 1113 | safe_mask |= 1 << REISERFS_ERROR_RO; |
1106 | safe_mask |= 1 << REISERFS_ERROR_CONTINUE; | 1114 | safe_mask |= 1 << REISERFS_ERROR_CONTINUE; |
1107 | safe_mask |= 1 << REISERFS_ERROR_PANIC; | 1115 | safe_mask |= 1 << REISERFS_ERROR_PANIC; |
1116 | safe_mask |= 1 << REISERFS_QUOTA; | ||
1108 | 1117 | ||
1109 | /* Update the bitmask, taking care to keep | 1118 | /* Update the bitmask, taking care to keep |
1110 | * the bits we're not allowed to change here */ | 1119 | * the bits we're not allowed to change here */ |
@@ -1841,13 +1850,18 @@ static int reiserfs_statfs (struct super_block * s, struct kstatfs * buf) | |||
1841 | static int reiserfs_dquot_initialize(struct inode *inode, int type) | 1850 | static int reiserfs_dquot_initialize(struct inode *inode, int type) |
1842 | { | 1851 | { |
1843 | struct reiserfs_transaction_handle th; | 1852 | struct reiserfs_transaction_handle th; |
1844 | int ret; | 1853 | int ret, err; |
1845 | 1854 | ||
1846 | /* We may create quota structure so we need to reserve enough blocks */ | 1855 | /* We may create quota structure so we need to reserve enough blocks */ |
1847 | reiserfs_write_lock(inode->i_sb); | 1856 | reiserfs_write_lock(inode->i_sb); |
1848 | journal_begin(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS); | 1857 | ret = journal_begin(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb)); |
1858 | if (ret) | ||
1859 | goto out; | ||
1849 | ret = dquot_initialize(inode, type); | 1860 | ret = dquot_initialize(inode, type); |
1850 | journal_end(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS); | 1861 | err = journal_end(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb)); |
1862 | if (!ret && err) | ||
1863 | ret = err; | ||
1864 | out: | ||
1851 | reiserfs_write_unlock(inode->i_sb); | 1865 | reiserfs_write_unlock(inode->i_sb); |
1852 | return ret; | 1866 | return ret; |
1853 | } | 1867 | } |
@@ -1855,13 +1869,18 @@ static int reiserfs_dquot_initialize(struct inode *inode, int type) | |||
1855 | static int reiserfs_dquot_drop(struct inode *inode) | 1869 | static int reiserfs_dquot_drop(struct inode *inode) |
1856 | { | 1870 | { |
1857 | struct reiserfs_transaction_handle th; | 1871 | struct reiserfs_transaction_handle th; |
1858 | int ret; | 1872 | int ret, err; |
1859 | 1873 | ||
1860 | /* We may delete quota structure so we need to reserve enough blocks */ | 1874 | /* We may delete quota structure so we need to reserve enough blocks */ |
1861 | reiserfs_write_lock(inode->i_sb); | 1875 | reiserfs_write_lock(inode->i_sb); |
1862 | journal_begin(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS); | 1876 | ret = journal_begin(&th, inode->i_sb, 2*REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb)); |
1877 | if (ret) | ||
1878 | goto out; | ||
1863 | ret = dquot_drop(inode); | 1879 | ret = dquot_drop(inode); |
1864 | journal_end(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS); | 1880 | err = journal_end(&th, inode->i_sb, 2*REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb)); |
1881 | if (!ret && err) | ||
1882 | ret = err; | ||
1883 | out: | ||
1865 | reiserfs_write_unlock(inode->i_sb); | 1884 | reiserfs_write_unlock(inode->i_sb); |
1866 | return ret; | 1885 | return ret; |
1867 | } | 1886 | } |
@@ -1869,12 +1888,17 @@ static int reiserfs_dquot_drop(struct inode *inode) | |||
1869 | static int reiserfs_write_dquot(struct dquot *dquot) | 1888 | static int reiserfs_write_dquot(struct dquot *dquot) |
1870 | { | 1889 | { |
1871 | struct reiserfs_transaction_handle th; | 1890 | struct reiserfs_transaction_handle th; |
1872 | int ret; | 1891 | int ret, err; |
1873 | 1892 | ||
1874 | reiserfs_write_lock(dquot->dq_sb); | 1893 | reiserfs_write_lock(dquot->dq_sb); |
1875 | journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_TRANS_BLOCKS); | 1894 | ret = journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); |
1895 | if (ret) | ||
1896 | goto out; | ||
1876 | ret = dquot_commit(dquot); | 1897 | ret = dquot_commit(dquot); |
1877 | journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_TRANS_BLOCKS); | 1898 | err = journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); |
1899 | if (!ret && err) | ||
1900 | ret = err; | ||
1901 | out: | ||
1878 | reiserfs_write_unlock(dquot->dq_sb); | 1902 | reiserfs_write_unlock(dquot->dq_sb); |
1879 | return ret; | 1903 | return ret; |
1880 | } | 1904 | } |
@@ -1882,12 +1906,17 @@ static int reiserfs_write_dquot(struct dquot *dquot) | |||
1882 | static int reiserfs_acquire_dquot(struct dquot *dquot) | 1906 | static int reiserfs_acquire_dquot(struct dquot *dquot) |
1883 | { | 1907 | { |
1884 | struct reiserfs_transaction_handle th; | 1908 | struct reiserfs_transaction_handle th; |
1885 | int ret; | 1909 | int ret, err; |
1886 | 1910 | ||
1887 | reiserfs_write_lock(dquot->dq_sb); | 1911 | reiserfs_write_lock(dquot->dq_sb); |
1888 | journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS); | 1912 | ret = journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb)); |
1913 | if (ret) | ||
1914 | goto out; | ||
1889 | ret = dquot_acquire(dquot); | 1915 | ret = dquot_acquire(dquot); |
1890 | journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS); | 1916 | err = journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb)); |
1917 | if (!ret && err) | ||
1918 | ret = err; | ||
1919 | out: | ||
1891 | reiserfs_write_unlock(dquot->dq_sb); | 1920 | reiserfs_write_unlock(dquot->dq_sb); |
1892 | return ret; | 1921 | return ret; |
1893 | } | 1922 | } |
@@ -1895,12 +1924,17 @@ static int reiserfs_acquire_dquot(struct dquot *dquot) | |||
1895 | static int reiserfs_release_dquot(struct dquot *dquot) | 1924 | static int reiserfs_release_dquot(struct dquot *dquot) |
1896 | { | 1925 | { |
1897 | struct reiserfs_transaction_handle th; | 1926 | struct reiserfs_transaction_handle th; |
1898 | int ret; | 1927 | int ret, err; |
1899 | 1928 | ||
1900 | reiserfs_write_lock(dquot->dq_sb); | 1929 | reiserfs_write_lock(dquot->dq_sb); |
1901 | journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS); | 1930 | ret = journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb)); |
1931 | if (ret) | ||
1932 | goto out; | ||
1902 | ret = dquot_release(dquot); | 1933 | ret = dquot_release(dquot); |
1903 | journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS); | 1934 | err = journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb)); |
1935 | if (!ret && err) | ||
1936 | ret = err; | ||
1937 | out: | ||
1904 | reiserfs_write_unlock(dquot->dq_sb); | 1938 | reiserfs_write_unlock(dquot->dq_sb); |
1905 | return ret; | 1939 | return ret; |
1906 | } | 1940 | } |
@@ -1920,13 +1954,18 @@ static int reiserfs_mark_dquot_dirty(struct dquot *dquot) | |||
1920 | static int reiserfs_write_info(struct super_block *sb, int type) | 1954 | static int reiserfs_write_info(struct super_block *sb, int type) |
1921 | { | 1955 | { |
1922 | struct reiserfs_transaction_handle th; | 1956 | struct reiserfs_transaction_handle th; |
1923 | int ret; | 1957 | int ret, err; |
1924 | 1958 | ||
1925 | /* Data block + inode block */ | 1959 | /* Data block + inode block */ |
1926 | reiserfs_write_lock(sb); | 1960 | reiserfs_write_lock(sb); |
1927 | journal_begin(&th, sb, 2); | 1961 | ret = journal_begin(&th, sb, 2); |
1962 | if (ret) | ||
1963 | goto out; | ||
1928 | ret = dquot_commit_info(sb, type); | 1964 | ret = dquot_commit_info(sb, type); |
1929 | journal_end(&th, sb, 2); | 1965 | err = journal_end(&th, sb, 2); |
1966 | if (!ret && err) | ||
1967 | ret = err; | ||
1968 | out: | ||
1930 | reiserfs_write_unlock(sb); | 1969 | reiserfs_write_unlock(sb); |
1931 | return ret; | 1970 | return ret; |
1932 | } | 1971 | } |
@@ -1948,6 +1987,8 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, ch | |||
1948 | int err; | 1987 | int err; |
1949 | struct nameidata nd; | 1988 | struct nameidata nd; |
1950 | 1989 | ||
1990 | if (!(REISERFS_SB(sb)->s_mount_opt & (1<<REISERFS_QUOTA))) | ||
1991 | return -EINVAL; | ||
1951 | err = path_lookup(path, LOOKUP_FOLLOW, &nd); | 1992 | err = path_lookup(path, LOOKUP_FOLLOW, &nd); |
1952 | if (err) | 1993 | if (err) |
1953 | return err; | 1994 | return err; |
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index e9cfa39f4099..d72c1ce48559 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -14,7 +14,7 @@ | |||
14 | #define to_subsys(k) container_of(k,struct subsystem,kset.kobj) | 14 | #define to_subsys(k) container_of(k,struct subsystem,kset.kobj) |
15 | #define to_sattr(a) container_of(a,struct subsys_attribute,attr) | 15 | #define to_sattr(a) container_of(a,struct subsys_attribute,attr) |
16 | 16 | ||
17 | /** | 17 | /* |
18 | * Subsystem file operations. | 18 | * Subsystem file operations. |
19 | * These operations allow subsystems to have files that can be | 19 | * These operations allow subsystems to have files that can be |
20 | * read/written. | 20 | * read/written. |
@@ -192,8 +192,9 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t | |||
192 | 192 | ||
193 | /** | 193 | /** |
194 | * flush_write_buffer - push buffer to kobject. | 194 | * flush_write_buffer - push buffer to kobject. |
195 | * @file: file pointer. | 195 | * @dentry: dentry to the attribute |
196 | * @buffer: data buffer for file. | 196 | * @buffer: data buffer for file. |
197 | * @count: number of bytes | ||
197 | * | 198 | * |
198 | * Get the correct pointers for the kobject and the attribute we're | 199 | * Get the correct pointers for the kobject and the attribute we're |
199 | * dealing with, then call the store() method for the attribute, | 200 | * dealing with, then call the store() method for the attribute, |
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 93ce257cd149..a3a4b5aaf5d9 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c | |||
@@ -149,11 +149,12 @@ linvfs_unwritten_convert( | |||
149 | */ | 149 | */ |
150 | STATIC void | 150 | STATIC void |
151 | linvfs_unwritten_convert_direct( | 151 | linvfs_unwritten_convert_direct( |
152 | struct inode *inode, | 152 | struct kiocb *iocb, |
153 | loff_t offset, | 153 | loff_t offset, |
154 | ssize_t size, | 154 | ssize_t size, |
155 | void *private) | 155 | void *private) |
156 | { | 156 | { |
157 | struct inode *inode = iocb->ki_filp->f_dentry->d_inode; | ||
157 | ASSERT(!private || inode == (struct inode *)private); | 158 | ASSERT(!private || inode == (struct inode *)private); |
158 | 159 | ||
159 | /* private indicates an unwritten extent lay beneath this IO */ | 160 | /* private indicates an unwritten extent lay beneath this IO */ |