diff options
Diffstat (limited to 'fs')
73 files changed, 1010 insertions, 445 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index ee11f8d94085..613df554728d 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -1675,6 +1675,7 @@ config NFSD_V3_ACL | |||
1675 | config NFSD_V4 | 1675 | config NFSD_V4 |
1676 | bool "Provide NFSv4 server support (EXPERIMENTAL)" | 1676 | bool "Provide NFSv4 server support (EXPERIMENTAL)" |
1677 | depends on NFSD_V3 && EXPERIMENTAL | 1677 | depends on NFSD_V3 && EXPERIMENTAL |
1678 | select RPCSEC_GSS_KRB5 | ||
1678 | help | 1679 | help |
1679 | If you would like to include the NFSv4 server as well as the NFSv2 | 1680 | If you would like to include the NFSv4 server as well as the NFSv2 |
1680 | and NFSv3 servers, say Y here. This feature is experimental, and | 1681 | and NFSv3 servers, say Y here. This feature is experimental, and |
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index a260198306c2..b4a75880f6fd 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c | |||
@@ -139,6 +139,7 @@ err_put_filp: | |||
139 | put_filp(file); | 139 | put_filp(file); |
140 | return error; | 140 | return error; |
141 | } | 141 | } |
142 | EXPORT_SYMBOL_GPL(anon_inode_getfd); | ||
142 | 143 | ||
143 | /* | 144 | /* |
144 | * A single inode exists for all anon_inode files. Contrary to pipes, | 145 | * A single inode exists for all anon_inode files. Contrary to pipes, |
@@ -42,7 +42,7 @@ int inode_change_ok(struct inode *inode, struct iattr *attr) | |||
42 | 42 | ||
43 | /* Make sure a caller can chmod. */ | 43 | /* Make sure a caller can chmod. */ |
44 | if (ia_valid & ATTR_MODE) { | 44 | if (ia_valid & ATTR_MODE) { |
45 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 45 | if (!is_owner_or_cap(inode)) |
46 | goto error; | 46 | goto error; |
47 | /* Also check the setgid bit! */ | 47 | /* Also check the setgid bit! */ |
48 | if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : | 48 | if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : |
@@ -52,7 +52,7 @@ int inode_change_ok(struct inode *inode, struct iattr *attr) | |||
52 | 52 | ||
53 | /* Check for setting the inode time. */ | 53 | /* Check for setting the inode time. */ |
54 | if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) { | 54 | if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) { |
55 | if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER)) | 55 | if (!is_owner_or_cap(inode)) |
56 | goto error; | 56 | goto error; |
57 | } | 57 | } |
58 | fine: | 58 | fine: |
diff --git a/fs/buffer.c b/fs/buffer.c index 424165b569f8..0f9006714230 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -356,7 +356,7 @@ static void free_more_memory(void) | |||
356 | for_each_online_pgdat(pgdat) { | 356 | for_each_online_pgdat(pgdat) { |
357 | zones = pgdat->node_zonelists[gfp_zone(GFP_NOFS)].zones; | 357 | zones = pgdat->node_zonelists[gfp_zone(GFP_NOFS)].zones; |
358 | if (*zones) | 358 | if (*zones) |
359 | try_to_free_pages(zones, GFP_NOFS); | 359 | try_to_free_pages(zones, 0, GFP_NOFS); |
360 | } | 360 | } |
361 | } | 361 | } |
362 | 362 | ||
@@ -676,6 +676,39 @@ void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode) | |||
676 | EXPORT_SYMBOL(mark_buffer_dirty_inode); | 676 | EXPORT_SYMBOL(mark_buffer_dirty_inode); |
677 | 677 | ||
678 | /* | 678 | /* |
679 | * Mark the page dirty, and set it dirty in the radix tree, and mark the inode | ||
680 | * dirty. | ||
681 | * | ||
682 | * If warn is true, then emit a warning if the page is not uptodate and has | ||
683 | * not been truncated. | ||
684 | */ | ||
685 | static int __set_page_dirty(struct page *page, | ||
686 | struct address_space *mapping, int warn) | ||
687 | { | ||
688 | if (unlikely(!mapping)) | ||
689 | return !TestSetPageDirty(page); | ||
690 | |||
691 | if (TestSetPageDirty(page)) | ||
692 | return 0; | ||
693 | |||
694 | write_lock_irq(&mapping->tree_lock); | ||
695 | if (page->mapping) { /* Race with truncate? */ | ||
696 | WARN_ON_ONCE(warn && !PageUptodate(page)); | ||
697 | |||
698 | if (mapping_cap_account_dirty(mapping)) { | ||
699 | __inc_zone_page_state(page, NR_FILE_DIRTY); | ||
700 | task_io_account_write(PAGE_CACHE_SIZE); | ||
701 | } | ||
702 | radix_tree_tag_set(&mapping->page_tree, | ||
703 | page_index(page), PAGECACHE_TAG_DIRTY); | ||
704 | } | ||
705 | write_unlock_irq(&mapping->tree_lock); | ||
706 | __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); | ||
707 | |||
708 | return 1; | ||
709 | } | ||
710 | |||
711 | /* | ||
679 | * Add a page to the dirty page list. | 712 | * Add a page to the dirty page list. |
680 | * | 713 | * |
681 | * It is a sad fact of life that this function is called from several places | 714 | * It is a sad fact of life that this function is called from several places |
@@ -702,7 +735,7 @@ EXPORT_SYMBOL(mark_buffer_dirty_inode); | |||
702 | */ | 735 | */ |
703 | int __set_page_dirty_buffers(struct page *page) | 736 | int __set_page_dirty_buffers(struct page *page) |
704 | { | 737 | { |
705 | struct address_space * const mapping = page_mapping(page); | 738 | struct address_space *mapping = page_mapping(page); |
706 | 739 | ||
707 | if (unlikely(!mapping)) | 740 | if (unlikely(!mapping)) |
708 | return !TestSetPageDirty(page); | 741 | return !TestSetPageDirty(page); |
@@ -719,21 +752,7 @@ int __set_page_dirty_buffers(struct page *page) | |||
719 | } | 752 | } |
720 | spin_unlock(&mapping->private_lock); | 753 | spin_unlock(&mapping->private_lock); |
721 | 754 | ||
722 | if (TestSetPageDirty(page)) | 755 | return __set_page_dirty(page, mapping, 1); |
723 | return 0; | ||
724 | |||
725 | write_lock_irq(&mapping->tree_lock); | ||
726 | if (page->mapping) { /* Race with truncate? */ | ||
727 | if (mapping_cap_account_dirty(mapping)) { | ||
728 | __inc_zone_page_state(page, NR_FILE_DIRTY); | ||
729 | task_io_account_write(PAGE_CACHE_SIZE); | ||
730 | } | ||
731 | radix_tree_tag_set(&mapping->page_tree, | ||
732 | page_index(page), PAGECACHE_TAG_DIRTY); | ||
733 | } | ||
734 | write_unlock_irq(&mapping->tree_lock); | ||
735 | __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); | ||
736 | return 1; | ||
737 | } | 756 | } |
738 | EXPORT_SYMBOL(__set_page_dirty_buffers); | 757 | EXPORT_SYMBOL(__set_page_dirty_buffers); |
739 | 758 | ||
@@ -982,7 +1001,7 @@ grow_dev_page(struct block_device *bdev, sector_t block, | |||
982 | struct buffer_head *bh; | 1001 | struct buffer_head *bh; |
983 | 1002 | ||
984 | page = find_or_create_page(inode->i_mapping, index, | 1003 | page = find_or_create_page(inode->i_mapping, index, |
985 | mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); | 1004 | (mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS)|__GFP_MOVABLE); |
986 | if (!page) | 1005 | if (!page) |
987 | return NULL; | 1006 | return NULL; |
988 | 1007 | ||
@@ -1132,8 +1151,9 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size) | |||
1132 | */ | 1151 | */ |
1133 | void fastcall mark_buffer_dirty(struct buffer_head *bh) | 1152 | void fastcall mark_buffer_dirty(struct buffer_head *bh) |
1134 | { | 1153 | { |
1154 | WARN_ON_ONCE(!buffer_uptodate(bh)); | ||
1135 | if (!buffer_dirty(bh) && !test_set_buffer_dirty(bh)) | 1155 | if (!buffer_dirty(bh) && !test_set_buffer_dirty(bh)) |
1136 | __set_page_dirty_nobuffers(bh->b_page); | 1156 | __set_page_dirty(bh->b_page, page_mapping(bh->b_page), 0); |
1137 | } | 1157 | } |
1138 | 1158 | ||
1139 | /* | 1159 | /* |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8b0cbf4a4ad0..bd0f2f2353ce 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -849,6 +849,7 @@ static int cifs_oplock_thread(void * dummyarg) | |||
849 | __u16 netfid; | 849 | __u16 netfid; |
850 | int rc; | 850 | int rc; |
851 | 851 | ||
852 | set_freezable(); | ||
852 | do { | 853 | do { |
853 | if (try_to_freeze()) | 854 | if (try_to_freeze()) |
854 | continue; | 855 | continue; |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index f4e92661b223..0a1b8bd1dfcb 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -363,6 +363,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
363 | GFP_KERNEL); | 363 | GFP_KERNEL); |
364 | } | 364 | } |
365 | 365 | ||
366 | set_freezable(); | ||
366 | while (!kthread_should_stop()) { | 367 | while (!kthread_should_stop()) { |
367 | if (try_to_freeze()) | 368 | if (try_to_freeze()) |
368 | continue; | 369 | continue; |
diff --git a/fs/cifs/export.c b/fs/cifs/export.c index 1d716392c3aa..96df1d51fdc3 100644 --- a/fs/cifs/export.c +++ b/fs/cifs/export.c | |||
@@ -29,6 +29,7 @@ | |||
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <linux/fs.h> | 31 | #include <linux/fs.h> |
32 | #include <linux/exportfs.h> | ||
32 | 33 | ||
33 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 34 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
34 | 35 | ||
diff --git a/fs/dcache.c b/fs/dcache.c index 0e73aa0a0e8b..cb9d05056b54 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -883,6 +883,11 @@ static int shrink_dcache_memory(int nr, gfp_t gfp_mask) | |||
883 | return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure; | 883 | return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure; |
884 | } | 884 | } |
885 | 885 | ||
886 | static struct shrinker dcache_shrinker = { | ||
887 | .shrink = shrink_dcache_memory, | ||
888 | .seeks = DEFAULT_SEEKS, | ||
889 | }; | ||
890 | |||
886 | /** | 891 | /** |
887 | * d_alloc - allocate a dcache entry | 892 | * d_alloc - allocate a dcache entry |
888 | * @parent: parent of entry to allocate | 893 | * @parent: parent of entry to allocate |
@@ -2115,7 +2120,7 @@ static void __init dcache_init(unsigned long mempages) | |||
2115 | dentry_cache = KMEM_CACHE(dentry, | 2120 | dentry_cache = KMEM_CACHE(dentry, |
2116 | SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD); | 2121 | SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD); |
2117 | 2122 | ||
2118 | set_shrinker(DEFAULT_SEEKS, shrink_dcache_memory); | 2123 | register_shrinker(&dcache_shrinker); |
2119 | 2124 | ||
2120 | /* Hash may have been set up in dcache_init_early */ | 2125 | /* Hash may have been set up in dcache_init_early */ |
2121 | if (!hashdist) | 2126 | if (!hashdist) |
diff --git a/fs/dquot.c b/fs/dquot.c index 8819d281500c..7e273151f589 100644 --- a/fs/dquot.c +++ b/fs/dquot.c | |||
@@ -538,6 +538,11 @@ static int shrink_dqcache_memory(int nr, gfp_t gfp_mask) | |||
538 | return (dqstats.free_dquots / 100) * sysctl_vfs_cache_pressure; | 538 | return (dqstats.free_dquots / 100) * sysctl_vfs_cache_pressure; |
539 | } | 539 | } |
540 | 540 | ||
541 | static struct shrinker dqcache_shrinker = { | ||
542 | .shrink = shrink_dqcache_memory, | ||
543 | .seeks = DEFAULT_SEEKS, | ||
544 | }; | ||
545 | |||
541 | /* | 546 | /* |
542 | * Put reference to dquot | 547 | * Put reference to dquot |
543 | * NOTE: If you change this function please check whether dqput_blocks() works right... | 548 | * NOTE: If you change this function please check whether dqput_blocks() works right... |
@@ -1870,7 +1875,7 @@ static int __init dquot_init(void) | |||
1870 | printk("Dquot-cache hash table entries: %ld (order %ld, %ld bytes)\n", | 1875 | printk("Dquot-cache hash table entries: %ld (order %ld, %ld bytes)\n", |
1871 | nr_hash, order, (PAGE_SIZE << order)); | 1876 | nr_hash, order, (PAGE_SIZE << order)); |
1872 | 1877 | ||
1873 | set_shrinker(DEFAULT_SEEKS, shrink_dqcache_memory); | 1878 | register_shrinker(&dqcache_shrinker); |
1874 | 1879 | ||
1875 | return 0; | 1880 | return 0; |
1876 | } | 1881 | } |
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 83e94fedd4e9..e77a2ec71aa5 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c | |||
@@ -282,7 +282,7 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, | |||
282 | struct dentry *lower_dentry; | 282 | struct dentry *lower_dentry; |
283 | struct vfsmount *lower_mnt; | 283 | struct vfsmount *lower_mnt; |
284 | char *encoded_name; | 284 | char *encoded_name; |
285 | unsigned int encoded_namelen; | 285 | int encoded_namelen; |
286 | struct ecryptfs_crypt_stat *crypt_stat = NULL; | 286 | struct ecryptfs_crypt_stat *crypt_stat = NULL; |
287 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat; | 287 | struct ecryptfs_mount_crypt_stat *mount_crypt_stat; |
288 | char *page_virt = NULL; | 288 | char *page_virt = NULL; |
@@ -473,7 +473,7 @@ static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry, | |||
473 | struct dentry *lower_dir_dentry; | 473 | struct dentry *lower_dir_dentry; |
474 | umode_t mode; | 474 | umode_t mode; |
475 | char *encoded_symname; | 475 | char *encoded_symname; |
476 | unsigned int encoded_symlen; | 476 | int encoded_symlen; |
477 | struct ecryptfs_crypt_stat *crypt_stat = NULL; | 477 | struct ecryptfs_crypt_stat *crypt_stat = NULL; |
478 | 478 | ||
479 | lower_dentry = ecryptfs_dentry_to_lower(dentry); | 479 | lower_dentry = ecryptfs_dentry_to_lower(dentry); |
diff --git a/fs/efs/namei.c b/fs/efs/namei.c index ed4a207fe22a..5276b19423c1 100644 --- a/fs/efs/namei.c +++ b/fs/efs/namei.c | |||
@@ -75,6 +75,38 @@ struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct namei | |||
75 | return NULL; | 75 | return NULL; |
76 | } | 76 | } |
77 | 77 | ||
78 | struct dentry *efs_get_dentry(struct super_block *sb, void *vobjp) | ||
79 | { | ||
80 | __u32 *objp = vobjp; | ||
81 | unsigned long ino = objp[0]; | ||
82 | __u32 generation = objp[1]; | ||
83 | struct inode *inode; | ||
84 | struct dentry *result; | ||
85 | |||
86 | if (ino == 0) | ||
87 | return ERR_PTR(-ESTALE); | ||
88 | inode = iget(sb, ino); | ||
89 | if (inode == NULL) | ||
90 | return ERR_PTR(-ENOMEM); | ||
91 | |||
92 | if (is_bad_inode(inode) || | ||
93 | (generation && inode->i_generation != generation)) { | ||
94 | result = ERR_PTR(-ESTALE); | ||
95 | goto out_iput; | ||
96 | } | ||
97 | |||
98 | result = d_alloc_anon(inode); | ||
99 | if (!result) { | ||
100 | result = ERR_PTR(-ENOMEM); | ||
101 | goto out_iput; | ||
102 | } | ||
103 | return result; | ||
104 | |||
105 | out_iput: | ||
106 | iput(inode); | ||
107 | return result; | ||
108 | } | ||
109 | |||
78 | struct dentry *efs_get_parent(struct dentry *child) | 110 | struct dentry *efs_get_parent(struct dentry *child) |
79 | { | 111 | { |
80 | struct dentry *parent; | 112 | struct dentry *parent; |
diff --git a/fs/efs/super.c b/fs/efs/super.c index e0a6839e68ae..d360c81f3a72 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/efs_fs.h> | 11 | #include <linux/efs_fs.h> |
12 | #include <linux/efs_vh.h> | 12 | #include <linux/efs_vh.h> |
13 | #include <linux/efs_fs_sb.h> | 13 | #include <linux/efs_fs_sb.h> |
14 | #include <linux/exportfs.h> | ||
14 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
15 | #include <linux/buffer_head.h> | 16 | #include <linux/buffer_head.h> |
16 | #include <linux/vfs.h> | 17 | #include <linux/vfs.h> |
@@ -113,6 +114,7 @@ static const struct super_operations efs_superblock_operations = { | |||
113 | }; | 114 | }; |
114 | 115 | ||
115 | static struct export_operations efs_export_ops = { | 116 | static struct export_operations efs_export_ops = { |
117 | .get_dentry = efs_get_dentry, | ||
116 | .get_parent = efs_get_parent, | 118 | .get_parent = efs_get_parent, |
117 | }; | 119 | }; |
118 | 120 | ||
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index e98f6cd7200c..8adb32a9387a 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c | |||
@@ -1,15 +1,45 @@ | |||
1 | 1 | ||
2 | #include <linux/exportfs.h> | ||
2 | #include <linux/fs.h> | 3 | #include <linux/fs.h> |
3 | #include <linux/file.h> | 4 | #include <linux/file.h> |
4 | #include <linux/module.h> | 5 | #include <linux/module.h> |
6 | #include <linux/mount.h> | ||
5 | #include <linux/namei.h> | 7 | #include <linux/namei.h> |
6 | 8 | ||
7 | struct export_operations export_op_default; | 9 | #define dprintk(fmt, args...) do{}while(0) |
8 | 10 | ||
9 | #define CALL(ops,fun) ((ops->fun)?(ops->fun):export_op_default.fun) | ||
10 | 11 | ||
11 | #define dprintk(fmt, args...) do{}while(0) | 12 | static int get_name(struct dentry *dentry, char *name, |
13 | struct dentry *child); | ||
14 | |||
15 | |||
16 | static struct dentry *exportfs_get_dentry(struct super_block *sb, void *obj) | ||
17 | { | ||
18 | struct dentry *result = ERR_PTR(-ESTALE); | ||
19 | |||
20 | if (sb->s_export_op->get_dentry) { | ||
21 | result = sb->s_export_op->get_dentry(sb, obj); | ||
22 | if (!result) | ||
23 | result = ERR_PTR(-ESTALE); | ||
24 | } | ||
25 | |||
26 | return result; | ||
27 | } | ||
28 | |||
29 | static int exportfs_get_name(struct dentry *dir, char *name, | ||
30 | struct dentry *child) | ||
31 | { | ||
32 | struct export_operations *nop = dir->d_sb->s_export_op; | ||
12 | 33 | ||
34 | if (nop->get_name) | ||
35 | return nop->get_name(dir, name, child); | ||
36 | else | ||
37 | return get_name(dir, name, child); | ||
38 | } | ||
39 | |||
40 | /* | ||
41 | * Check if the dentry or any of it's aliases is acceptable. | ||
42 | */ | ||
13 | static struct dentry * | 43 | static struct dentry * |
14 | find_acceptable_alias(struct dentry *result, | 44 | find_acceptable_alias(struct dentry *result, |
15 | int (*acceptable)(void *context, struct dentry *dentry), | 45 | int (*acceptable)(void *context, struct dentry *dentry), |
@@ -17,6 +47,9 @@ find_acceptable_alias(struct dentry *result, | |||
17 | { | 47 | { |
18 | struct dentry *dentry, *toput = NULL; | 48 | struct dentry *dentry, *toput = NULL; |
19 | 49 | ||
50 | if (acceptable(context, result)) | ||
51 | return result; | ||
52 | |||
20 | spin_lock(&dcache_lock); | 53 | spin_lock(&dcache_lock); |
21 | list_for_each_entry(dentry, &result->d_inode->i_dentry, d_alias) { | 54 | list_for_each_entry(dentry, &result->d_inode->i_dentry, d_alias) { |
22 | dget_locked(dentry); | 55 | dget_locked(dentry); |
@@ -37,130 +70,50 @@ find_acceptable_alias(struct dentry *result, | |||
37 | return NULL; | 70 | return NULL; |
38 | } | 71 | } |
39 | 72 | ||
40 | /** | 73 | /* |
41 | * find_exported_dentry - helper routine to implement export_operations->decode_fh | 74 | * Find root of a disconnected subtree and return a reference to it. |
42 | * @sb: The &super_block identifying the filesystem | ||
43 | * @obj: An opaque identifier of the object to be found - passed to | ||
44 | * get_inode | ||
45 | * @parent: An optional opqaue identifier of the parent of the object. | ||
46 | * @acceptable: A function used to test possible &dentries to see if they are | ||
47 | * acceptable | ||
48 | * @context: A parameter to @acceptable so that it knows on what basis to | ||
49 | * judge. | ||
50 | * | ||
51 | * find_exported_dentry is the central helper routine to enable file systems | ||
52 | * to provide the decode_fh() export_operation. It's main task is to take | ||
53 | * an &inode, find or create an appropriate &dentry structure, and possibly | ||
54 | * splice this into the dcache in the correct place. | ||
55 | * | ||
56 | * The decode_fh() operation provided by the filesystem should call | ||
57 | * find_exported_dentry() with the same parameters that it received except | ||
58 | * that instead of the file handle fragment, pointers to opaque identifiers | ||
59 | * for the object and optionally its parent are passed. The default decode_fh | ||
60 | * routine passes one pointer to the start of the filehandle fragment, and | ||
61 | * one 8 bytes into the fragment. It is expected that most filesystems will | ||
62 | * take this approach, though the offset to the parent identifier may well be | ||
63 | * different. | ||
64 | * | ||
65 | * find_exported_dentry() will call get_dentry to get an dentry pointer from | ||
66 | * the file system. If any &dentry in the d_alias list is acceptable, it will | ||
67 | * be returned. Otherwise find_exported_dentry() will attempt to splice a new | ||
68 | * &dentry into the dcache using get_name() and get_parent() to find the | ||
69 | * appropriate place. | ||
70 | */ | 75 | */ |
71 | 76 | static struct dentry * | |
72 | struct dentry * | 77 | find_disconnected_root(struct dentry *dentry) |
73 | find_exported_dentry(struct super_block *sb, void *obj, void *parent, | ||
74 | int (*acceptable)(void *context, struct dentry *de), | ||
75 | void *context) | ||
76 | { | 78 | { |
77 | struct dentry *result = NULL; | 79 | dget(dentry); |
78 | struct dentry *target_dir; | 80 | spin_lock(&dentry->d_lock); |
79 | int err; | 81 | while (!IS_ROOT(dentry) && |
80 | struct export_operations *nops = sb->s_export_op; | 82 | (dentry->d_parent->d_flags & DCACHE_DISCONNECTED)) { |
81 | struct dentry *alias; | 83 | struct dentry *parent = dentry->d_parent; |
82 | int noprogress; | 84 | dget(parent); |
83 | char nbuf[NAME_MAX+1]; | 85 | spin_unlock(&dentry->d_lock); |
84 | 86 | dput(dentry); | |
85 | /* | 87 | dentry = parent; |
86 | * Attempt to find the inode. | 88 | spin_lock(&dentry->d_lock); |
87 | */ | ||
88 | result = CALL(sb->s_export_op,get_dentry)(sb,obj); | ||
89 | err = -ESTALE; | ||
90 | if (result == NULL) | ||
91 | goto err_out; | ||
92 | if (IS_ERR(result)) { | ||
93 | err = PTR_ERR(result); | ||
94 | goto err_out; | ||
95 | } | 89 | } |
96 | if (S_ISDIR(result->d_inode->i_mode) && | 90 | spin_unlock(&dentry->d_lock); |
97 | (result->d_flags & DCACHE_DISCONNECTED)) { | 91 | return dentry; |
98 | /* it is an unconnected directory, we must connect it */ | 92 | } |
99 | ; | ||
100 | } else { | ||
101 | if (acceptable(context, result)) | ||
102 | return result; | ||
103 | if (S_ISDIR(result->d_inode->i_mode)) { | ||
104 | err = -EACCES; | ||
105 | goto err_result; | ||
106 | } | ||
107 | 93 | ||
108 | alias = find_acceptable_alias(result, acceptable, context); | ||
109 | if (alias) | ||
110 | return alias; | ||
111 | } | ||
112 | |||
113 | /* It's a directory, or we are required to confirm the file's | ||
114 | * location in the tree based on the parent information | ||
115 | */ | ||
116 | dprintk("find_exported_dentry: need to look harder for %s/%d\n",sb->s_id,*(int*)obj); | ||
117 | if (S_ISDIR(result->d_inode->i_mode)) | ||
118 | target_dir = dget(result); | ||
119 | else { | ||
120 | if (parent == NULL) | ||
121 | goto err_result; | ||
122 | 94 | ||
123 | target_dir = CALL(sb->s_export_op,get_dentry)(sb,parent); | 95 | /* |
124 | if (IS_ERR(target_dir)) | 96 | * Make sure target_dir is fully connected to the dentry tree. |
125 | err = PTR_ERR(target_dir); | 97 | * |
126 | if (target_dir == NULL || IS_ERR(target_dir)) | 98 | * It may already be, as the flag isn't always updated when connection happens. |
127 | goto err_result; | 99 | */ |
128 | } | 100 | static int |
129 | /* | 101 | reconnect_path(struct super_block *sb, struct dentry *target_dir) |
130 | * Now we need to make sure that target_dir is properly connected. | 102 | { |
131 | * It may already be, as the flag isn't always updated when connection | 103 | char nbuf[NAME_MAX+1]; |
132 | * happens. | 104 | int noprogress = 0; |
133 | * So, we walk up parent links until we find a connected directory, | 105 | int err = -ESTALE; |
134 | * or we run out of directories. Then we find the parent, find | ||
135 | * the name of the child in that parent, and do a lookup. | ||
136 | * This should connect the child into the parent | ||
137 | * We then repeat. | ||
138 | */ | ||
139 | 106 | ||
140 | /* it is possible that a confused file system might not let us complete | 107 | /* |
108 | * It is possible that a confused file system might not let us complete | ||
141 | * the path to the root. For example, if get_parent returns a directory | 109 | * the path to the root. For example, if get_parent returns a directory |
142 | * in which we cannot find a name for the child. While this implies a | 110 | * in which we cannot find a name for the child. While this implies a |
143 | * very sick filesystem we don't want it to cause knfsd to spin. Hence | 111 | * very sick filesystem we don't want it to cause knfsd to spin. Hence |
144 | * the noprogress counter. If we go through the loop 10 times (2 is | 112 | * the noprogress counter. If we go through the loop 10 times (2 is |
145 | * probably enough) without getting anywhere, we just give up | 113 | * probably enough) without getting anywhere, we just give up |
146 | */ | 114 | */ |
147 | noprogress= 0; | ||
148 | while (target_dir->d_flags & DCACHE_DISCONNECTED && noprogress++ < 10) { | 115 | while (target_dir->d_flags & DCACHE_DISCONNECTED && noprogress++ < 10) { |
149 | struct dentry *pd = target_dir; | 116 | struct dentry *pd = find_disconnected_root(target_dir); |
150 | |||
151 | dget(pd); | ||
152 | spin_lock(&pd->d_lock); | ||
153 | while (!IS_ROOT(pd) && | ||
154 | (pd->d_parent->d_flags&DCACHE_DISCONNECTED)) { | ||
155 | struct dentry *parent = pd->d_parent; | ||
156 | |||
157 | dget(parent); | ||
158 | spin_unlock(&pd->d_lock); | ||
159 | dput(pd); | ||
160 | pd = parent; | ||
161 | spin_lock(&pd->d_lock); | ||
162 | } | ||
163 | spin_unlock(&pd->d_lock); | ||
164 | 117 | ||
165 | if (!IS_ROOT(pd)) { | 118 | if (!IS_ROOT(pd)) { |
166 | /* must have found a connected parent - great */ | 119 | /* must have found a connected parent - great */ |
@@ -175,29 +128,40 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
175 | spin_unlock(&pd->d_lock); | 128 | spin_unlock(&pd->d_lock); |
176 | noprogress = 0; | 129 | noprogress = 0; |
177 | } else { | 130 | } else { |
178 | /* we have hit the top of a disconnected path. Try | 131 | /* |
179 | * to find parent and connect | 132 | * We have hit the top of a disconnected path, try to |
180 | * note: racing with some other process renaming a | 133 | * find parent and connect. |
181 | * directory isn't much of a problem here. If someone | 134 | * |
182 | * renames the directory, it will end up properly | 135 | * Racing with some other process renaming a directory |
183 | * connected, which is what we want | 136 | * isn't much of a problem here. If someone renames |
137 | * the directory, it will end up properly connected, | ||
138 | * which is what we want | ||
139 | * | ||
140 | * Getting the parent can't be supported generically, | ||
141 | * the locking is too icky. | ||
142 | * | ||
143 | * Instead we just return EACCES. If server reboots | ||
144 | * or inodes get flushed, you lose | ||
184 | */ | 145 | */ |
185 | struct dentry *ppd; | 146 | struct dentry *ppd = ERR_PTR(-EACCES); |
186 | struct dentry *npd; | 147 | struct dentry *npd; |
187 | 148 | ||
188 | mutex_lock(&pd->d_inode->i_mutex); | 149 | mutex_lock(&pd->d_inode->i_mutex); |
189 | ppd = CALL(nops,get_parent)(pd); | 150 | if (sb->s_export_op->get_parent) |
151 | ppd = sb->s_export_op->get_parent(pd); | ||
190 | mutex_unlock(&pd->d_inode->i_mutex); | 152 | mutex_unlock(&pd->d_inode->i_mutex); |
191 | 153 | ||
192 | if (IS_ERR(ppd)) { | 154 | if (IS_ERR(ppd)) { |
193 | err = PTR_ERR(ppd); | 155 | err = PTR_ERR(ppd); |
194 | dprintk("find_exported_dentry: get_parent of %ld failed, err %d\n", | 156 | dprintk("%s: get_parent of %ld failed, err %d\n", |
195 | pd->d_inode->i_ino, err); | 157 | __FUNCTION__, pd->d_inode->i_ino, err); |
196 | dput(pd); | 158 | dput(pd); |
197 | break; | 159 | break; |
198 | } | 160 | } |
199 | dprintk("find_exported_dentry: find name of %lu in %lu\n", pd->d_inode->i_ino, ppd->d_inode->i_ino); | 161 | |
200 | err = CALL(nops,get_name)(ppd, nbuf, pd); | 162 | dprintk("%s: find name of %lu in %lu\n", __FUNCTION__, |
163 | pd->d_inode->i_ino, ppd->d_inode->i_ino); | ||
164 | err = exportfs_get_name(ppd, nbuf, pd); | ||
201 | if (err) { | 165 | if (err) { |
202 | dput(ppd); | 166 | dput(ppd); |
203 | dput(pd); | 167 | dput(pd); |
@@ -208,13 +172,14 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
208 | continue; | 172 | continue; |
209 | break; | 173 | break; |
210 | } | 174 | } |
211 | dprintk("find_exported_dentry: found name: %s\n", nbuf); | 175 | dprintk("%s: found name: %s\n", __FUNCTION__, nbuf); |
212 | mutex_lock(&ppd->d_inode->i_mutex); | 176 | mutex_lock(&ppd->d_inode->i_mutex); |
213 | npd = lookup_one_len(nbuf, ppd, strlen(nbuf)); | 177 | npd = lookup_one_len(nbuf, ppd, strlen(nbuf)); |
214 | mutex_unlock(&ppd->d_inode->i_mutex); | 178 | mutex_unlock(&ppd->d_inode->i_mutex); |
215 | if (IS_ERR(npd)) { | 179 | if (IS_ERR(npd)) { |
216 | err = PTR_ERR(npd); | 180 | err = PTR_ERR(npd); |
217 | dprintk("find_exported_dentry: lookup failed: %d\n", err); | 181 | dprintk("%s: lookup failed: %d\n", |
182 | __FUNCTION__, err); | ||
218 | dput(ppd); | 183 | dput(ppd); |
219 | dput(pd); | 184 | dput(pd); |
220 | break; | 185 | break; |
@@ -227,7 +192,7 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
227 | if (npd == pd) | 192 | if (npd == pd) |
228 | noprogress = 0; | 193 | noprogress = 0; |
229 | else | 194 | else |
230 | printk("find_exported_dentry: npd != pd\n"); | 195 | printk("%s: npd != pd\n", __FUNCTION__); |
231 | dput(npd); | 196 | dput(npd); |
232 | dput(ppd); | 197 | dput(ppd); |
233 | if (IS_ROOT(pd)) { | 198 | if (IS_ROOT(pd)) { |
@@ -243,15 +208,101 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
243 | /* something went wrong - oh-well */ | 208 | /* something went wrong - oh-well */ |
244 | if (!err) | 209 | if (!err) |
245 | err = -ESTALE; | 210 | err = -ESTALE; |
246 | goto err_target; | 211 | return err; |
247 | } | 212 | } |
248 | /* if we weren't after a directory, have one more step to go */ | 213 | |
249 | if (result != target_dir) { | 214 | return 0; |
250 | struct dentry *nresult; | 215 | } |
251 | err = CALL(nops,get_name)(target_dir, nbuf, result); | 216 | |
217 | /** | ||
218 | * find_exported_dentry - helper routine to implement export_operations->decode_fh | ||
219 | * @sb: The &super_block identifying the filesystem | ||
220 | * @obj: An opaque identifier of the object to be found - passed to | ||
221 | * get_inode | ||
222 | * @parent: An optional opqaue identifier of the parent of the object. | ||
223 | * @acceptable: A function used to test possible &dentries to see if they are | ||
224 | * acceptable | ||
225 | * @context: A parameter to @acceptable so that it knows on what basis to | ||
226 | * judge. | ||
227 | * | ||
228 | * find_exported_dentry is the central helper routine to enable file systems | ||
229 | * to provide the decode_fh() export_operation. It's main task is to take | ||
230 | * an &inode, find or create an appropriate &dentry structure, and possibly | ||
231 | * splice this into the dcache in the correct place. | ||
232 | * | ||
233 | * The decode_fh() operation provided by the filesystem should call | ||
234 | * find_exported_dentry() with the same parameters that it received except | ||
235 | * that instead of the file handle fragment, pointers to opaque identifiers | ||
236 | * for the object and optionally its parent are passed. The default decode_fh | ||
237 | * routine passes one pointer to the start of the filehandle fragment, and | ||
238 | * one 8 bytes into the fragment. It is expected that most filesystems will | ||
239 | * take this approach, though the offset to the parent identifier may well be | ||
240 | * different. | ||
241 | * | ||
242 | * find_exported_dentry() will call get_dentry to get an dentry pointer from | ||
243 | * the file system. If any &dentry in the d_alias list is acceptable, it will | ||
244 | * be returned. Otherwise find_exported_dentry() will attempt to splice a new | ||
245 | * &dentry into the dcache using get_name() and get_parent() to find the | ||
246 | * appropriate place. | ||
247 | */ | ||
248 | |||
249 | struct dentry * | ||
250 | find_exported_dentry(struct super_block *sb, void *obj, void *parent, | ||
251 | int (*acceptable)(void *context, struct dentry *de), | ||
252 | void *context) | ||
253 | { | ||
254 | struct dentry *result, *alias; | ||
255 | int err = -ESTALE; | ||
256 | |||
257 | /* | ||
258 | * Attempt to find the inode. | ||
259 | */ | ||
260 | result = exportfs_get_dentry(sb, obj); | ||
261 | if (IS_ERR(result)) | ||
262 | return result; | ||
263 | |||
264 | if (S_ISDIR(result->d_inode->i_mode)) { | ||
265 | if (!(result->d_flags & DCACHE_DISCONNECTED)) { | ||
266 | if (acceptable(context, result)) | ||
267 | return result; | ||
268 | err = -EACCES; | ||
269 | goto err_result; | ||
270 | } | ||
271 | |||
272 | err = reconnect_path(sb, result); | ||
273 | if (err) | ||
274 | goto err_result; | ||
275 | } else { | ||
276 | struct dentry *target_dir, *nresult; | ||
277 | char nbuf[NAME_MAX+1]; | ||
278 | |||
279 | alias = find_acceptable_alias(result, acceptable, context); | ||
280 | if (alias) | ||
281 | return alias; | ||
282 | |||
283 | if (parent == NULL) | ||
284 | goto err_result; | ||
285 | |||
286 | target_dir = exportfs_get_dentry(sb,parent); | ||
287 | if (IS_ERR(target_dir)) { | ||
288 | err = PTR_ERR(target_dir); | ||
289 | goto err_result; | ||
290 | } | ||
291 | |||
292 | err = reconnect_path(sb, target_dir); | ||
293 | if (err) { | ||
294 | dput(target_dir); | ||
295 | goto err_result; | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | * As we weren't after a directory, have one more step to go. | ||
300 | */ | ||
301 | err = exportfs_get_name(target_dir, nbuf, result); | ||
252 | if (!err) { | 302 | if (!err) { |
253 | mutex_lock(&target_dir->d_inode->i_mutex); | 303 | mutex_lock(&target_dir->d_inode->i_mutex); |
254 | nresult = lookup_one_len(nbuf, target_dir, strlen(nbuf)); | 304 | nresult = lookup_one_len(nbuf, target_dir, |
305 | strlen(nbuf)); | ||
255 | mutex_unlock(&target_dir->d_inode->i_mutex); | 306 | mutex_unlock(&target_dir->d_inode->i_mutex); |
256 | if (!IS_ERR(nresult)) { | 307 | if (!IS_ERR(nresult)) { |
257 | if (nresult->d_inode) { | 308 | if (nresult->d_inode) { |
@@ -261,11 +312,8 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
261 | dput(nresult); | 312 | dput(nresult); |
262 | } | 313 | } |
263 | } | 314 | } |
315 | dput(target_dir); | ||
264 | } | 316 | } |
265 | dput(target_dir); | ||
266 | /* now result is properly connected, it is our best bet */ | ||
267 | if (acceptable(context, result)) | ||
268 | return result; | ||
269 | 317 | ||
270 | alias = find_acceptable_alias(result, acceptable, context); | 318 | alias = find_acceptable_alias(result, acceptable, context); |
271 | if (alias) | 319 | if (alias) |
@@ -275,32 +323,16 @@ find_exported_dentry(struct super_block *sb, void *obj, void *parent, | |||
275 | dput(result); | 323 | dput(result); |
276 | /* It might be justifiable to return ESTALE here, | 324 | /* It might be justifiable to return ESTALE here, |
277 | * but the filehandle at-least looks reasonable good | 325 | * but the filehandle at-least looks reasonable good |
278 | * and it just be a permission problem, so returning | 326 | * and it may just be a permission problem, so returning |
279 | * -EACCESS is safer | 327 | * -EACCESS is safer |
280 | */ | 328 | */ |
281 | return ERR_PTR(-EACCES); | 329 | return ERR_PTR(-EACCES); |
282 | 330 | ||
283 | err_target: | ||
284 | dput(target_dir); | ||
285 | err_result: | 331 | err_result: |
286 | dput(result); | 332 | dput(result); |
287 | err_out: | ||
288 | return ERR_PTR(err); | 333 | return ERR_PTR(err); |
289 | } | 334 | } |
290 | 335 | ||
291 | |||
292 | |||
293 | static struct dentry *get_parent(struct dentry *child) | ||
294 | { | ||
295 | /* get_parent cannot be supported generically, the locking | ||
296 | * is too icky. | ||
297 | * instead, we just return EACCES. If server reboots or inodes | ||
298 | * get flushed, you lose | ||
299 | */ | ||
300 | return ERR_PTR(-EACCES); | ||
301 | } | ||
302 | |||
303 | |||
304 | struct getdents_callback { | 336 | struct getdents_callback { |
305 | char *name; /* name that was found. It already points to a | 337 | char *name; /* name that was found. It already points to a |
306 | buffer NAME_MAX+1 is size */ | 338 | buffer NAME_MAX+1 is size */ |
@@ -390,61 +422,6 @@ out: | |||
390 | return error; | 422 | return error; |
391 | } | 423 | } |
392 | 424 | ||
393 | |||
394 | static struct dentry *export_iget(struct super_block *sb, unsigned long ino, __u32 generation) | ||
395 | { | ||
396 | |||
397 | /* iget isn't really right if the inode is currently unallocated!! | ||
398 | * This should really all be done inside each filesystem | ||
399 | * | ||
400 | * ext2fs' read_inode has been strengthed to return a bad_inode if | ||
401 | * the inode had been deleted. | ||
402 | * | ||
403 | * Currently we don't know the generation for parent directory, so | ||
404 | * a generation of 0 means "accept any" | ||
405 | */ | ||
406 | struct inode *inode; | ||
407 | struct dentry *result; | ||
408 | if (ino == 0) | ||
409 | return ERR_PTR(-ESTALE); | ||
410 | inode = iget(sb, ino); | ||
411 | if (inode == NULL) | ||
412 | return ERR_PTR(-ENOMEM); | ||
413 | if (is_bad_inode(inode) | ||
414 | || (generation && inode->i_generation != generation) | ||
415 | ) { | ||
416 | /* we didn't find the right inode.. */ | ||
417 | dprintk("fh_verify: Inode %lu, Bad count: %d %d or version %u %u\n", | ||
418 | inode->i_ino, | ||
419 | inode->i_nlink, atomic_read(&inode->i_count), | ||
420 | inode->i_generation, | ||
421 | generation); | ||
422 | |||
423 | iput(inode); | ||
424 | return ERR_PTR(-ESTALE); | ||
425 | } | ||
426 | /* now to find a dentry. | ||
427 | * If possible, get a well-connected one | ||
428 | */ | ||
429 | result = d_alloc_anon(inode); | ||
430 | if (!result) { | ||
431 | iput(inode); | ||
432 | return ERR_PTR(-ENOMEM); | ||
433 | } | ||
434 | return result; | ||
435 | } | ||
436 | |||
437 | |||
438 | static struct dentry *get_object(struct super_block *sb, void *vobjp) | ||
439 | { | ||
440 | __u32 *objp = vobjp; | ||
441 | unsigned long ino = objp[0]; | ||
442 | __u32 generation = objp[1]; | ||
443 | |||
444 | return export_iget(sb, ino, generation); | ||
445 | } | ||
446 | |||
447 | |||
448 | /** | 425 | /** |
449 | * export_encode_fh - default export_operations->encode_fh function | 426 | * export_encode_fh - default export_operations->encode_fh function |
450 | * @dentry: the dentry to encode | 427 | * @dentry: the dentry to encode |
@@ -517,16 +494,40 @@ static struct dentry *export_decode_fh(struct super_block *sb, __u32 *fh, int fh | |||
517 | acceptable, context); | 494 | acceptable, context); |
518 | } | 495 | } |
519 | 496 | ||
520 | struct export_operations export_op_default = { | 497 | int exportfs_encode_fh(struct dentry *dentry, __u32 *fh, int *max_len, |
521 | .decode_fh = export_decode_fh, | 498 | int connectable) |
522 | .encode_fh = export_encode_fh, | 499 | { |
500 | struct export_operations *nop = dentry->d_sb->s_export_op; | ||
501 | int error; | ||
502 | |||
503 | if (nop->encode_fh) | ||
504 | error = nop->encode_fh(dentry, fh, max_len, connectable); | ||
505 | else | ||
506 | error = export_encode_fh(dentry, fh, max_len, connectable); | ||
523 | 507 | ||
524 | .get_name = get_name, | 508 | return error; |
525 | .get_parent = get_parent, | 509 | } |
526 | .get_dentry = get_object, | 510 | EXPORT_SYMBOL_GPL(exportfs_encode_fh); |
527 | }; | 511 | |
512 | struct dentry *exportfs_decode_fh(struct vfsmount *mnt, __u32 *fh, int fh_len, | ||
513 | int fileid_type, int (*acceptable)(void *, struct dentry *), | ||
514 | void *context) | ||
515 | { | ||
516 | struct export_operations *nop = mnt->mnt_sb->s_export_op; | ||
517 | struct dentry *result; | ||
518 | |||
519 | if (nop->decode_fh) { | ||
520 | result = nop->decode_fh(mnt->mnt_sb, fh, fh_len, fileid_type, | ||
521 | acceptable, context); | ||
522 | } else { | ||
523 | result = export_decode_fh(mnt->mnt_sb, fh, fh_len, fileid_type, | ||
524 | acceptable, context); | ||
525 | } | ||
526 | |||
527 | return result; | ||
528 | } | ||
529 | EXPORT_SYMBOL_GPL(exportfs_decode_fh); | ||
528 | 530 | ||
529 | EXPORT_SYMBOL(export_op_default); | ||
530 | EXPORT_SYMBOL(find_exported_dentry); | 531 | EXPORT_SYMBOL(find_exported_dentry); |
531 | 532 | ||
532 | MODULE_LICENSE("GPL"); | 533 | MODULE_LICENSE("GPL"); |
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c index 7c420b800c34..e58669e1b87c 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c | |||
@@ -464,7 +464,7 @@ ext2_xattr_set_acl(struct inode *inode, int type, const void *value, | |||
464 | 464 | ||
465 | if (!test_opt(inode->i_sb, POSIX_ACL)) | 465 | if (!test_opt(inode->i_sb, POSIX_ACL)) |
466 | return -EOPNOTSUPP; | 466 | return -EOPNOTSUPP; |
467 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 467 | if (!is_owner_or_cap(inode)) |
468 | return -EPERM; | 468 | return -EPERM; |
469 | 469 | ||
470 | if (value) { | 470 | if (value) { |
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c index e85c48218239..3bcd25422ee4 100644 --- a/fs/ext2/ioctl.c +++ b/fs/ext2/ioctl.c | |||
@@ -36,7 +36,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, | |||
36 | if (IS_RDONLY(inode)) | 36 | if (IS_RDONLY(inode)) |
37 | return -EROFS; | 37 | return -EROFS; |
38 | 38 | ||
39 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 39 | if (!is_owner_or_cap(inode)) |
40 | return -EACCES; | 40 | return -EACCES; |
41 | 41 | ||
42 | if (get_user(flags, (int __user *) arg)) | 42 | if (get_user(flags, (int __user *) arg)) |
@@ -74,7 +74,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, | |||
74 | case EXT2_IOC_GETVERSION: | 74 | case EXT2_IOC_GETVERSION: |
75 | return put_user(inode->i_generation, (int __user *) arg); | 75 | return put_user(inode->i_generation, (int __user *) arg); |
76 | case EXT2_IOC_SETVERSION: | 76 | case EXT2_IOC_SETVERSION: |
77 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 77 | if (!is_owner_or_cap(inode)) |
78 | return -EPERM; | 78 | return -EPERM; |
79 | if (IS_RDONLY(inode)) | 79 | if (IS_RDONLY(inode)) |
80 | return -EROFS; | 80 | return -EROFS; |
diff --git a/fs/ext2/super.c b/fs/ext2/super.c index b2efd9083b9b..3eefa97fe204 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/parser.h> | 25 | #include <linux/parser.h> |
26 | #include <linux/random.h> | 26 | #include <linux/random.h> |
27 | #include <linux/buffer_head.h> | 27 | #include <linux/buffer_head.h> |
28 | #include <linux/exportfs.h> | ||
28 | #include <linux/smp_lock.h> | 29 | #include <linux/smp_lock.h> |
29 | #include <linux/vfs.h> | 30 | #include <linux/vfs.h> |
30 | #include <linux/seq_file.h> | 31 | #include <linux/seq_file.h> |
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index 1e5038d9a01b..d34e9967430a 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c | |||
@@ -489,7 +489,7 @@ ext3_xattr_set_acl(struct inode *inode, int type, const void *value, | |||
489 | 489 | ||
490 | if (!test_opt(inode->i_sb, POSIX_ACL)) | 490 | if (!test_opt(inode->i_sb, POSIX_ACL)) |
491 | return -EOPNOTSUPP; | 491 | return -EOPNOTSUPP; |
492 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 492 | if (!is_owner_or_cap(inode)) |
493 | return -EPERM; | 493 | return -EPERM; |
494 | 494 | ||
495 | if (value) { | 495 | if (value) { |
diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c index 965006dba6be..4a2a02c95bf9 100644 --- a/fs/ext3/ioctl.c +++ b/fs/ext3/ioctl.c | |||
@@ -41,7 +41,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, | |||
41 | if (IS_RDONLY(inode)) | 41 | if (IS_RDONLY(inode)) |
42 | return -EROFS; | 42 | return -EROFS; |
43 | 43 | ||
44 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 44 | if (!is_owner_or_cap(inode)) |
45 | return -EACCES; | 45 | return -EACCES; |
46 | 46 | ||
47 | if (get_user(flags, (int __user *) arg)) | 47 | if (get_user(flags, (int __user *) arg)) |
@@ -122,7 +122,7 @@ flags_err: | |||
122 | __u32 generation; | 122 | __u32 generation; |
123 | int err; | 123 | int err; |
124 | 124 | ||
125 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 125 | if (!is_owner_or_cap(inode)) |
126 | return -EPERM; | 126 | return -EPERM; |
127 | if (IS_RDONLY(inode)) | 127 | if (IS_RDONLY(inode)) |
128 | return -EROFS; | 128 | return -EROFS; |
@@ -181,7 +181,7 @@ flags_err: | |||
181 | if (IS_RDONLY(inode)) | 181 | if (IS_RDONLY(inode)) |
182 | return -EROFS; | 182 | return -EROFS; |
183 | 183 | ||
184 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 184 | if (!is_owner_or_cap(inode)) |
185 | return -EACCES; | 185 | return -EACCES; |
186 | 186 | ||
187 | if (get_user(rsv_window_size, (int __user *)arg)) | 187 | if (get_user(rsv_window_size, (int __user *)arg)) |
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 51d1c456cdab..4f84dc86628a 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/parser.h> | 29 | #include <linux/parser.h> |
30 | #include <linux/smp_lock.h> | 30 | #include <linux/smp_lock.h> |
31 | #include <linux/buffer_head.h> | 31 | #include <linux/buffer_head.h> |
32 | #include <linux/exportfs.h> | ||
32 | #include <linux/vfs.h> | 33 | #include <linux/vfs.h> |
33 | #include <linux/random.h> | 34 | #include <linux/random.h> |
34 | #include <linux/mount.h> | 35 | #include <linux/mount.h> |
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index 9e882546d91a..a8bae8cd1d5d 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c | |||
@@ -489,7 +489,7 @@ ext4_xattr_set_acl(struct inode *inode, int type, const void *value, | |||
489 | 489 | ||
490 | if (!test_opt(inode->i_sb, POSIX_ACL)) | 490 | if (!test_opt(inode->i_sb, POSIX_ACL)) |
491 | return -EOPNOTSUPP; | 491 | return -EOPNOTSUPP; |
492 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 492 | if (!is_owner_or_cap(inode)) |
493 | return -EPERM; | 493 | return -EPERM; |
494 | 494 | ||
495 | if (value) { | 495 | if (value) { |
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 500567dd53b6..7b4aa4543c83 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c | |||
@@ -40,7 +40,7 @@ int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, | |||
40 | if (IS_RDONLY(inode)) | 40 | if (IS_RDONLY(inode)) |
41 | return -EROFS; | 41 | return -EROFS; |
42 | 42 | ||
43 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 43 | if (!is_owner_or_cap(inode)) |
44 | return -EACCES; | 44 | return -EACCES; |
45 | 45 | ||
46 | if (get_user(flags, (int __user *) arg)) | 46 | if (get_user(flags, (int __user *) arg)) |
@@ -121,7 +121,7 @@ flags_err: | |||
121 | __u32 generation; | 121 | __u32 generation; |
122 | int err; | 122 | int err; |
123 | 123 | ||
124 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 124 | if (!is_owner_or_cap(inode)) |
125 | return -EPERM; | 125 | return -EPERM; |
126 | if (IS_RDONLY(inode)) | 126 | if (IS_RDONLY(inode)) |
127 | return -EROFS; | 127 | return -EROFS; |
@@ -180,7 +180,7 @@ flags_err: | |||
180 | if (IS_RDONLY(inode)) | 180 | if (IS_RDONLY(inode)) |
181 | return -EROFS; | 181 | return -EROFS; |
182 | 182 | ||
183 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 183 | if (!is_owner_or_cap(inode)) |
184 | return -EACCES; | 184 | return -EACCES; |
185 | 185 | ||
186 | if (get_user(rsv_window_size, (int __user *)arg)) | 186 | if (get_user(rsv_window_size, (int __user *)arg)) |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index d0d8c76c7edb..b806e689c4aa 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/parser.h> | 29 | #include <linux/parser.h> |
30 | #include <linux/smp_lock.h> | 30 | #include <linux/smp_lock.h> |
31 | #include <linux/buffer_head.h> | 31 | #include <linux/buffer_head.h> |
32 | #include <linux/exportfs.h> | ||
32 | #include <linux/vfs.h> | 33 | #include <linux/vfs.h> |
33 | #include <linux/random.h> | 34 | #include <linux/random.h> |
34 | #include <linux/mount.h> | 35 | #include <linux/mount.h> |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index cfaf5877d98b..0a7ddb39a593 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/pagemap.h> | 20 | #include <linux/pagemap.h> |
21 | #include <linux/mpage.h> | 21 | #include <linux/mpage.h> |
22 | #include <linux/buffer_head.h> | 22 | #include <linux/buffer_head.h> |
23 | #include <linux/exportfs.h> | ||
23 | #include <linux/mount.h> | 24 | #include <linux/mount.h> |
24 | #include <linux/vfs.h> | 25 | #include <linux/vfs.h> |
25 | #include <linux/parser.h> | 26 | #include <linux/parser.h> |
diff --git a/fs/fcntl.c b/fs/fcntl.c index 8e382a5d51bd..3f22e9f4f691 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
@@ -215,7 +215,7 @@ static int setfl(int fd, struct file * filp, unsigned long arg) | |||
215 | 215 | ||
216 | /* O_NOATIME can only be set by the owner or superuser */ | 216 | /* O_NOATIME can only be set by the owner or superuser */ |
217 | if ((arg & O_NOATIME) && !(filp->f_flags & O_NOATIME)) | 217 | if ((arg & O_NOATIME) && !(filp->f_flags & O_NOATIME)) |
218 | if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER)) | 218 | if (!is_owner_or_cap(inode)) |
219 | return -EPERM; | 219 | return -EPERM; |
220 | 220 | ||
221 | /* required for strict SunOS emulation */ | 221 | /* required for strict SunOS emulation */ |
diff --git a/fs/generic_acl.c b/fs/generic_acl.c index 9ccb78947171..995d63b2e747 100644 --- a/fs/generic_acl.c +++ b/fs/generic_acl.c | |||
@@ -78,7 +78,7 @@ generic_acl_set(struct inode *inode, struct generic_acl_operations *ops, | |||
78 | 78 | ||
79 | if (S_ISLNK(inode->i_mode)) | 79 | if (S_ISLNK(inode->i_mode)) |
80 | return -EOPNOTSUPP; | 80 | return -EOPNOTSUPP; |
81 | if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER)) | 81 | if (!is_owner_or_cap(inode)) |
82 | return -EPERM; | 82 | return -EPERM; |
83 | if (value) { | 83 | if (value) { |
84 | acl = posix_acl_from_xattr(value, size); | 84 | acl = posix_acl_from_xattr(value, size); |
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 6e80844367ee..1047a8c7226a 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c | |||
@@ -74,7 +74,7 @@ int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access) | |||
74 | { | 74 | { |
75 | if (!GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl) | 75 | if (!GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl) |
76 | return -EOPNOTSUPP; | 76 | return -EOPNOTSUPP; |
77 | if (current->fsuid != ip->i_inode.i_uid && !capable(CAP_FOWNER)) | 77 | if (!is_owner_or_cap(&ip->i_inode)) |
78 | return -EPERM; | 78 | return -EPERM; |
79 | if (S_ISLNK(ip->i_inode.i_mode)) | 79 | if (S_ISLNK(ip->i_inode.i_mode)) |
80 | return -EOPNOTSUPP; | 80 | return -EOPNOTSUPP; |
diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c index 99ea5659bc2c..b8312edee0e4 100644 --- a/fs/gfs2/ops_export.c +++ b/fs/gfs2/ops_export.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/spinlock.h> | 11 | #include <linux/spinlock.h> |
12 | #include <linux/completion.h> | 12 | #include <linux/completion.h> |
13 | #include <linux/buffer_head.h> | 13 | #include <linux/buffer_head.h> |
14 | #include <linux/exportfs.h> | ||
14 | #include <linux/gfs2_ondisk.h> | 15 | #include <linux/gfs2_ondisk.h> |
15 | #include <linux/crc32.h> | 16 | #include <linux/crc32.h> |
16 | #include <linux/lm_interface.h> | 17 | #include <linux/lm_interface.h> |
diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c index 79fd10402ea3..b60c0affbec5 100644 --- a/fs/hfsplus/ioctl.c +++ b/fs/hfsplus/ioctl.c | |||
@@ -38,7 +38,7 @@ int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | |||
38 | if (IS_RDONLY(inode)) | 38 | if (IS_RDONLY(inode)) |
39 | return -EROFS; | 39 | return -EROFS; |
40 | 40 | ||
41 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 41 | if (!is_owner_or_cap(inode)) |
42 | return -EACCES; | 42 | return -EACCES; |
43 | 43 | ||
44 | if (get_user(flags, (int __user *)arg)) | 44 | if (get_user(flags, (int __user *)arg)) |
diff --git a/fs/inode.c b/fs/inode.c index 9a012cc5b6cd..320e088d0b28 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -145,7 +145,7 @@ static struct inode *alloc_inode(struct super_block *sb) | |||
145 | mapping->a_ops = &empty_aops; | 145 | mapping->a_ops = &empty_aops; |
146 | mapping->host = inode; | 146 | mapping->host = inode; |
147 | mapping->flags = 0; | 147 | mapping->flags = 0; |
148 | mapping_set_gfp_mask(mapping, GFP_HIGHUSER); | 148 | mapping_set_gfp_mask(mapping, GFP_HIGHUSER_PAGECACHE); |
149 | mapping->assoc_mapping = NULL; | 149 | mapping->assoc_mapping = NULL; |
150 | mapping->backing_dev_info = &default_backing_dev_info; | 150 | mapping->backing_dev_info = &default_backing_dev_info; |
151 | 151 | ||
@@ -462,6 +462,11 @@ static int shrink_icache_memory(int nr, gfp_t gfp_mask) | |||
462 | return (inodes_stat.nr_unused / 100) * sysctl_vfs_cache_pressure; | 462 | return (inodes_stat.nr_unused / 100) * sysctl_vfs_cache_pressure; |
463 | } | 463 | } |
464 | 464 | ||
465 | static struct shrinker icache_shrinker = { | ||
466 | .shrink = shrink_icache_memory, | ||
467 | .seeks = DEFAULT_SEEKS, | ||
468 | }; | ||
469 | |||
465 | static void __wait_on_freeing_inode(struct inode *inode); | 470 | static void __wait_on_freeing_inode(struct inode *inode); |
466 | /* | 471 | /* |
467 | * Called with the inode lock held. | 472 | * Called with the inode lock held. |
@@ -519,7 +524,13 @@ repeat: | |||
519 | * new_inode - obtain an inode | 524 | * new_inode - obtain an inode |
520 | * @sb: superblock | 525 | * @sb: superblock |
521 | * | 526 | * |
522 | * Allocates a new inode for given superblock. | 527 | * Allocates a new inode for given superblock. The default gfp_mask |
528 | * for allocations related to inode->i_mapping is GFP_HIGHUSER_PAGECACHE. | ||
529 | * If HIGHMEM pages are unsuitable or it is known that pages allocated | ||
530 | * for the page cache are not reclaimable or migratable, | ||
531 | * mapping_set_gfp_mask() must be called with suitable flags on the | ||
532 | * newly created inode's mapping | ||
533 | * | ||
523 | */ | 534 | */ |
524 | struct inode *new_inode(struct super_block *sb) | 535 | struct inode *new_inode(struct super_block *sb) |
525 | { | 536 | { |
@@ -1379,7 +1390,7 @@ void __init inode_init(unsigned long mempages) | |||
1379 | SLAB_MEM_SPREAD), | 1390 | SLAB_MEM_SPREAD), |
1380 | init_once, | 1391 | init_once, |
1381 | NULL); | 1392 | NULL); |
1382 | set_shrinker(DEFAULT_SEEKS, shrink_icache_memory); | 1393 | register_shrinker(&icache_shrinker); |
1383 | 1394 | ||
1384 | /* Hash may have been set up in inode_init_early */ | 1395 | /* Hash may have been set up in inode_init_early */ |
1385 | if (!hashdist) | 1396 | if (!hashdist) |
diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h index efe2872cd4e3..a07e67b1ea7f 100644 --- a/fs/isofs/isofs.h +++ b/fs/isofs/isofs.h | |||
@@ -1,5 +1,6 @@ | |||
1 | #include <linux/fs.h> | 1 | #include <linux/fs.h> |
2 | #include <linux/buffer_head.h> | 2 | #include <linux/buffer_head.h> |
3 | #include <linux/exportfs.h> | ||
3 | #include <linux/iso_fs.h> | 4 | #include <linux/iso_fs.h> |
4 | #include <asm/unaligned.h> | 5 | #include <asm/unaligned.h> |
5 | 6 | ||
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index a46101ee867a..65b3a1b5b88d 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c | |||
@@ -435,7 +435,7 @@ static int jffs2_acl_setxattr(struct inode *inode, int type, const void *value, | |||
435 | struct posix_acl *acl; | 435 | struct posix_acl *acl; |
436 | int rc; | 436 | int rc; |
437 | 437 | ||
438 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 438 | if (!is_owner_or_cap(inode)) |
439 | return -EPERM; | 439 | return -EPERM; |
440 | 440 | ||
441 | if (value) { | 441 | if (value) { |
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 0c82dfcfd246..143c5530caf3 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c | |||
@@ -81,6 +81,7 @@ static int jffs2_garbage_collect_thread(void *_c) | |||
81 | 81 | ||
82 | set_user_nice(current, 10); | 82 | set_user_nice(current, 10); |
83 | 83 | ||
84 | set_freezable(); | ||
84 | for (;;) { | 85 | for (;;) { |
85 | allow_signal(SIGHUP); | 86 | allow_signal(SIGHUP); |
86 | 87 | ||
diff --git a/fs/jfs/ioctl.c b/fs/jfs/ioctl.c index fe063af6fd2f..3c8663bea98c 100644 --- a/fs/jfs/ioctl.c +++ b/fs/jfs/ioctl.c | |||
@@ -69,7 +69,7 @@ int jfs_ioctl(struct inode * inode, struct file * filp, unsigned int cmd, | |||
69 | if (IS_RDONLY(inode)) | 69 | if (IS_RDONLY(inode)) |
70 | return -EROFS; | 70 | return -EROFS; |
71 | 71 | ||
72 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 72 | if (!is_owner_or_cap(inode)) |
73 | return -EACCES; | 73 | return -EACCES; |
74 | 74 | ||
75 | if (get_user(flags, (int __user *) arg)) | 75 | if (get_user(flags, (int __user *) arg)) |
diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h index 2374b595f2e1..f0ec72b263f1 100644 --- a/fs/jfs/jfs_inode.h +++ b/fs/jfs/jfs_inode.h | |||
@@ -32,6 +32,7 @@ extern void jfs_truncate_nolock(struct inode *, loff_t); | |||
32 | extern void jfs_free_zero_link(struct inode *); | 32 | extern void jfs_free_zero_link(struct inode *); |
33 | extern struct dentry *jfs_get_parent(struct dentry *dentry); | 33 | extern struct dentry *jfs_get_parent(struct dentry *dentry); |
34 | extern void jfs_get_inode_flags(struct jfs_inode_info *); | 34 | extern void jfs_get_inode_flags(struct jfs_inode_info *); |
35 | extern struct dentry *jfs_get_dentry(struct super_block *sb, void *vobjp); | ||
35 | extern void jfs_set_inode_flags(struct inode *); | 36 | extern void jfs_set_inode_flags(struct inode *); |
36 | extern int jfs_get_block(struct inode *, sector_t, struct buffer_head *, int); | 37 | extern int jfs_get_block(struct inode *, sector_t, struct buffer_head *, int); |
37 | 38 | ||
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 25161c4121e4..932797ba433b 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c | |||
@@ -1477,6 +1477,38 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc | |||
1477 | return dentry; | 1477 | return dentry; |
1478 | } | 1478 | } |
1479 | 1479 | ||
1480 | struct dentry *jfs_get_dentry(struct super_block *sb, void *vobjp) | ||
1481 | { | ||
1482 | __u32 *objp = vobjp; | ||
1483 | unsigned long ino = objp[0]; | ||
1484 | __u32 generation = objp[1]; | ||
1485 | struct inode *inode; | ||
1486 | struct dentry *result; | ||
1487 | |||
1488 | if (ino == 0) | ||
1489 | return ERR_PTR(-ESTALE); | ||
1490 | inode = iget(sb, ino); | ||
1491 | if (inode == NULL) | ||
1492 | return ERR_PTR(-ENOMEM); | ||
1493 | |||
1494 | if (is_bad_inode(inode) || | ||
1495 | (generation && inode->i_generation != generation)) { | ||
1496 | result = ERR_PTR(-ESTALE); | ||
1497 | goto out_iput; | ||
1498 | } | ||
1499 | |||
1500 | result = d_alloc_anon(inode); | ||
1501 | if (!result) { | ||
1502 | result = ERR_PTR(-ENOMEM); | ||
1503 | goto out_iput; | ||
1504 | } | ||
1505 | return result; | ||
1506 | |||
1507 | out_iput: | ||
1508 | iput(inode); | ||
1509 | return result; | ||
1510 | } | ||
1511 | |||
1480 | struct dentry *jfs_get_parent(struct dentry *dentry) | 1512 | struct dentry *jfs_get_parent(struct dentry *dentry) |
1481 | { | 1513 | { |
1482 | struct super_block *sb = dentry->d_inode->i_sb; | 1514 | struct super_block *sb = dentry->d_inode->i_sb; |
diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 20e4ac1c79a3..929fceca7999 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/kthread.h> | 27 | #include <linux/kthread.h> |
28 | #include <linux/posix_acl.h> | 28 | #include <linux/posix_acl.h> |
29 | #include <linux/buffer_head.h> | 29 | #include <linux/buffer_head.h> |
30 | #include <linux/exportfs.h> | ||
30 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
31 | #include <linux/seq_file.h> | 32 | #include <linux/seq_file.h> |
32 | 33 | ||
@@ -737,6 +738,7 @@ static const struct super_operations jfs_super_operations = { | |||
737 | }; | 738 | }; |
738 | 739 | ||
739 | static struct export_operations jfs_export_operations = { | 740 | static struct export_operations jfs_export_operations = { |
741 | .get_dentry = jfs_get_dentry, | ||
740 | .get_parent = jfs_get_parent, | 742 | .get_parent = jfs_get_parent, |
741 | }; | 743 | }; |
742 | 744 | ||
diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index b2375f0774b7..9b7f2cdaae0a 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c | |||
@@ -697,7 +697,7 @@ static int can_set_system_xattr(struct inode *inode, const char *name, | |||
697 | struct posix_acl *acl; | 697 | struct posix_acl *acl; |
698 | int rc; | 698 | int rc; |
699 | 699 | ||
700 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 700 | if (!is_owner_or_cap(inode)) |
701 | return -EPERM; | 701 | return -EPERM; |
702 | 702 | ||
703 | /* | 703 | /* |
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 26809325469c..82e2192a0d5c 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/smp.h> | 25 | #include <linux/smp.h> |
26 | #include <linux/smp_lock.h> | 26 | #include <linux/smp_lock.h> |
27 | #include <linux/mutex.h> | 27 | #include <linux/mutex.h> |
28 | #include <linux/freezer.h> | ||
28 | 29 | ||
29 | #include <linux/sunrpc/types.h> | 30 | #include <linux/sunrpc/types.h> |
30 | #include <linux/sunrpc/stats.h> | 31 | #include <linux/sunrpc/stats.h> |
@@ -75,18 +76,31 @@ static const int nlm_port_min = 0, nlm_port_max = 65535; | |||
75 | 76 | ||
76 | static struct ctl_table_header * nlm_sysctl_table; | 77 | static struct ctl_table_header * nlm_sysctl_table; |
77 | 78 | ||
78 | static unsigned long set_grace_period(void) | 79 | static unsigned long get_lockd_grace_period(void) |
79 | { | 80 | { |
80 | unsigned long grace_period; | ||
81 | |||
82 | /* Note: nlm_timeout should always be nonzero */ | 81 | /* Note: nlm_timeout should always be nonzero */ |
83 | if (nlm_grace_period) | 82 | if (nlm_grace_period) |
84 | grace_period = ((nlm_grace_period + nlm_timeout - 1) | 83 | return roundup(nlm_grace_period, nlm_timeout) * HZ; |
85 | / nlm_timeout) * nlm_timeout * HZ; | ||
86 | else | 84 | else |
87 | grace_period = nlm_timeout * 5 * HZ; | 85 | return nlm_timeout * 5 * HZ; |
86 | } | ||
87 | |||
88 | unsigned long get_nfs_grace_period(void) | ||
89 | { | ||
90 | unsigned long lockdgrace = get_lockd_grace_period(); | ||
91 | unsigned long nfsdgrace = 0; | ||
92 | |||
93 | if (nlmsvc_ops) | ||
94 | nfsdgrace = nlmsvc_ops->get_grace_period(); | ||
95 | |||
96 | return max(lockdgrace, nfsdgrace); | ||
97 | } | ||
98 | EXPORT_SYMBOL(get_nfs_grace_period); | ||
99 | |||
100 | static unsigned long set_grace_period(void) | ||
101 | { | ||
88 | nlmsvc_grace_period = 1; | 102 | nlmsvc_grace_period = 1; |
89 | return grace_period + jiffies; | 103 | return get_nfs_grace_period() + jiffies; |
90 | } | 104 | } |
91 | 105 | ||
92 | static inline void clear_grace_period(void) | 106 | static inline void clear_grace_period(void) |
@@ -119,6 +133,7 @@ lockd(struct svc_rqst *rqstp) | |||
119 | complete(&lockd_start_done); | 133 | complete(&lockd_start_done); |
120 | 134 | ||
121 | daemonize("lockd"); | 135 | daemonize("lockd"); |
136 | set_freezable(); | ||
122 | 137 | ||
123 | /* Process request with signals blocked, but allow SIGKILL. */ | 138 | /* Process request with signals blocked, but allow SIGKILL. */ |
124 | allow_signal(SIGKILL); | 139 | allow_signal(SIGKILL); |
diff --git a/fs/mbcache.c b/fs/mbcache.c index deeb9dc062d9..fbb1d02f8791 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c | |||
@@ -100,7 +100,6 @@ struct mb_cache { | |||
100 | static LIST_HEAD(mb_cache_list); | 100 | static LIST_HEAD(mb_cache_list); |
101 | static LIST_HEAD(mb_cache_lru_list); | 101 | static LIST_HEAD(mb_cache_lru_list); |
102 | static DEFINE_SPINLOCK(mb_cache_spinlock); | 102 | static DEFINE_SPINLOCK(mb_cache_spinlock); |
103 | static struct shrinker *mb_shrinker; | ||
104 | 103 | ||
105 | static inline int | 104 | static inline int |
106 | mb_cache_indexes(struct mb_cache *cache) | 105 | mb_cache_indexes(struct mb_cache *cache) |
@@ -118,6 +117,10 @@ mb_cache_indexes(struct mb_cache *cache) | |||
118 | 117 | ||
119 | static int mb_cache_shrink_fn(int nr_to_scan, gfp_t gfp_mask); | 118 | static int mb_cache_shrink_fn(int nr_to_scan, gfp_t gfp_mask); |
120 | 119 | ||
120 | static struct shrinker mb_cache_shrinker = { | ||
121 | .shrink = mb_cache_shrink_fn, | ||
122 | .seeks = DEFAULT_SEEKS, | ||
123 | }; | ||
121 | 124 | ||
122 | static inline int | 125 | static inline int |
123 | __mb_cache_entry_is_hashed(struct mb_cache_entry *ce) | 126 | __mb_cache_entry_is_hashed(struct mb_cache_entry *ce) |
@@ -662,13 +665,13 @@ mb_cache_entry_find_next(struct mb_cache_entry *prev, int index, | |||
662 | 665 | ||
663 | static int __init init_mbcache(void) | 666 | static int __init init_mbcache(void) |
664 | { | 667 | { |
665 | mb_shrinker = set_shrinker(DEFAULT_SEEKS, mb_cache_shrink_fn); | 668 | register_shrinker(&mb_cache_shrinker); |
666 | return 0; | 669 | return 0; |
667 | } | 670 | } |
668 | 671 | ||
669 | static void __exit exit_mbcache(void) | 672 | static void __exit exit_mbcache(void) |
670 | { | 673 | { |
671 | remove_shrinker(mb_shrinker); | 674 | unregister_shrinker(&mb_cache_shrinker); |
672 | } | 675 | } |
673 | 676 | ||
674 | module_init(init_mbcache) | 677 | module_init(init_mbcache) |
diff --git a/fs/namei.c b/fs/namei.c index 5e2d98d10c5d..defaa47c11d4 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1576,7 +1576,7 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) | |||
1576 | 1576 | ||
1577 | /* O_NOATIME can only be set by the owner or superuser */ | 1577 | /* O_NOATIME can only be set by the owner or superuser */ |
1578 | if (flag & O_NOATIME) | 1578 | if (flag & O_NOATIME) |
1579 | if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER)) | 1579 | if (!is_owner_or_cap(inode)) |
1580 | return -EPERM; | 1580 | return -EPERM; |
1581 | 1581 | ||
1582 | /* | 1582 | /* |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 75f309c8741a..a796be5051bf 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/sunrpc/svcsock.h> | 14 | #include <linux/sunrpc/svcsock.h> |
15 | #include <linux/nfs_fs.h> | 15 | #include <linux/nfs_fs.h> |
16 | #include <linux/mutex.h> | 16 | #include <linux/mutex.h> |
17 | #include <linux/freezer.h> | ||
17 | 18 | ||
18 | #include <net/inet_sock.h> | 19 | #include <net/inet_sock.h> |
19 | 20 | ||
@@ -67,6 +68,7 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) | |||
67 | daemonize("nfsv4-svc"); | 68 | daemonize("nfsv4-svc"); |
68 | /* Process request with signals blocked, but allow SIGKILL. */ | 69 | /* Process request with signals blocked, but allow SIGKILL. */ |
69 | allow_signal(SIGKILL); | 70 | allow_signal(SIGKILL); |
71 | set_freezable(); | ||
70 | 72 | ||
71 | complete(&nfs_callback_info.started); | 73 | complete(&nfs_callback_info.started); |
72 | 74 | ||
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index a2b1af89ca1a..adffe1615c51 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -300,7 +300,10 @@ static const struct super_operations nfs4_sops = { | |||
300 | }; | 300 | }; |
301 | #endif | 301 | #endif |
302 | 302 | ||
303 | static struct shrinker *acl_shrinker; | 303 | static struct shrinker acl_shrinker = { |
304 | .shrink = nfs_access_cache_shrinker, | ||
305 | .seeks = DEFAULT_SEEKS, | ||
306 | }; | ||
304 | 307 | ||
305 | /* | 308 | /* |
306 | * Register the NFS filesystems | 309 | * Register the NFS filesystems |
@@ -321,7 +324,7 @@ int __init register_nfs_fs(void) | |||
321 | if (ret < 0) | 324 | if (ret < 0) |
322 | goto error_2; | 325 | goto error_2; |
323 | #endif | 326 | #endif |
324 | acl_shrinker = set_shrinker(DEFAULT_SEEKS, nfs_access_cache_shrinker); | 327 | register_shrinker(&acl_shrinker); |
325 | return 0; | 328 | return 0; |
326 | 329 | ||
327 | #ifdef CONFIG_NFS_V4 | 330 | #ifdef CONFIG_NFS_V4 |
@@ -339,8 +342,7 @@ error_0: | |||
339 | */ | 342 | */ |
340 | void __exit unregister_nfs_fs(void) | 343 | void __exit unregister_nfs_fs(void) |
341 | { | 344 | { |
342 | if (acl_shrinker != NULL) | 345 | unregister_shrinker(&acl_shrinker); |
343 | remove_shrinker(acl_shrinker); | ||
344 | #ifdef CONFIG_NFS_V4 | 346 | #ifdef CONFIG_NFS_V4 |
345 | unregister_filesystem(&nfs4_fs_type); | 347 | unregister_filesystem(&nfs4_fs_type); |
346 | nfs_unregister_sysctl(); | 348 | nfs_unregister_sysctl(); |
diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c index 6e92b0fe5323..cf61dc8ae942 100644 --- a/fs/nfsd/auth.c +++ b/fs/nfsd/auth.c | |||
@@ -12,17 +12,31 @@ | |||
12 | 12 | ||
13 | #define CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE)) | 13 | #define CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE)) |
14 | 14 | ||
15 | static int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) | ||
16 | { | ||
17 | struct exp_flavor_info *f; | ||
18 | struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; | ||
19 | |||
20 | for (f = exp->ex_flavors; f < end; f++) { | ||
21 | if (f->pseudoflavor == rqstp->rq_flavor) | ||
22 | return f->flags; | ||
23 | } | ||
24 | return exp->ex_flags; | ||
25 | |||
26 | } | ||
27 | |||
15 | int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) | 28 | int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp) |
16 | { | 29 | { |
17 | struct svc_cred cred = rqstp->rq_cred; | 30 | struct svc_cred cred = rqstp->rq_cred; |
18 | int i; | 31 | int i; |
32 | int flags = nfsexp_flags(rqstp, exp); | ||
19 | int ret; | 33 | int ret; |
20 | 34 | ||
21 | if (exp->ex_flags & NFSEXP_ALLSQUASH) { | 35 | if (flags & NFSEXP_ALLSQUASH) { |
22 | cred.cr_uid = exp->ex_anon_uid; | 36 | cred.cr_uid = exp->ex_anon_uid; |
23 | cred.cr_gid = exp->ex_anon_gid; | 37 | cred.cr_gid = exp->ex_anon_gid; |
24 | cred.cr_group_info = groups_alloc(0); | 38 | cred.cr_group_info = groups_alloc(0); |
25 | } else if (exp->ex_flags & NFSEXP_ROOTSQUASH) { | 39 | } else if (flags & NFSEXP_ROOTSQUASH) { |
26 | struct group_info *gi; | 40 | struct group_info *gi; |
27 | if (!cred.cr_uid) | 41 | if (!cred.cr_uid) |
28 | cred.cr_uid = exp->ex_anon_uid; | 42 | cred.cr_uid = exp->ex_anon_uid; |
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 79bd03b8bbf8..c7bbf460b009 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -26,12 +26,15 @@ | |||
26 | #include <linux/mount.h> | 26 | #include <linux/mount.h> |
27 | #include <linux/hash.h> | 27 | #include <linux/hash.h> |
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/exportfs.h> | ||
29 | 30 | ||
30 | #include <linux/sunrpc/svc.h> | 31 | #include <linux/sunrpc/svc.h> |
31 | #include <linux/nfsd/nfsd.h> | 32 | #include <linux/nfsd/nfsd.h> |
32 | #include <linux/nfsd/nfsfh.h> | 33 | #include <linux/nfsd/nfsfh.h> |
33 | #include <linux/nfsd/syscall.h> | 34 | #include <linux/nfsd/syscall.h> |
34 | #include <linux/lockd/bind.h> | 35 | #include <linux/lockd/bind.h> |
36 | #include <linux/sunrpc/msg_prot.h> | ||
37 | #include <linux/sunrpc/gss_api.h> | ||
35 | 38 | ||
36 | #define NFSDDBG_FACILITY NFSDDBG_EXPORT | 39 | #define NFSDDBG_FACILITY NFSDDBG_EXPORT |
37 | 40 | ||
@@ -451,8 +454,48 @@ out_free_all: | |||
451 | return err; | 454 | return err; |
452 | } | 455 | } |
453 | 456 | ||
457 | static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp) | ||
458 | { | ||
459 | int listsize, err; | ||
460 | struct exp_flavor_info *f; | ||
461 | |||
462 | err = get_int(mesg, &listsize); | ||
463 | if (err) | ||
464 | return err; | ||
465 | if (listsize < 0 || listsize > MAX_SECINFO_LIST) | ||
466 | return -EINVAL; | ||
467 | |||
468 | for (f = exp->ex_flavors; f < exp->ex_flavors + listsize; f++) { | ||
469 | err = get_int(mesg, &f->pseudoflavor); | ||
470 | if (err) | ||
471 | return err; | ||
472 | /* | ||
473 | * Just a quick sanity check; we could also try to check | ||
474 | * whether this pseudoflavor is supported, but at worst | ||
475 | * an unsupported pseudoflavor on the export would just | ||
476 | * be a pseudoflavor that won't match the flavor of any | ||
477 | * authenticated request. The administrator will | ||
478 | * probably discover the problem when someone fails to | ||
479 | * authenticate. | ||
480 | */ | ||
481 | if (f->pseudoflavor < 0) | ||
482 | return -EINVAL; | ||
483 | err = get_int(mesg, &f->flags); | ||
484 | if (err) | ||
485 | return err; | ||
486 | /* Only some flags are allowed to differ between flavors: */ | ||
487 | if (~NFSEXP_SECINFO_FLAGS & (f->flags ^ exp->ex_flags)) | ||
488 | return -EINVAL; | ||
489 | } | ||
490 | exp->ex_nflavors = listsize; | ||
491 | return 0; | ||
492 | } | ||
493 | |||
454 | #else /* CONFIG_NFSD_V4 */ | 494 | #else /* CONFIG_NFSD_V4 */ |
455 | static inline int fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) { return 0; } | 495 | static inline int |
496 | fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc){return 0;} | ||
497 | static inline int | ||
498 | secinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; } | ||
456 | #endif | 499 | #endif |
457 | 500 | ||
458 | static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | 501 | static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) |
@@ -476,6 +519,9 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
476 | 519 | ||
477 | exp.ex_uuid = NULL; | 520 | exp.ex_uuid = NULL; |
478 | 521 | ||
522 | /* secinfo */ | ||
523 | exp.ex_nflavors = 0; | ||
524 | |||
479 | if (mesg[mlen-1] != '\n') | 525 | if (mesg[mlen-1] != '\n') |
480 | return -EINVAL; | 526 | return -EINVAL; |
481 | mesg[mlen-1] = 0; | 527 | mesg[mlen-1] = 0; |
@@ -553,7 +599,9 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
553 | if (exp.ex_uuid == NULL) | 599 | if (exp.ex_uuid == NULL) |
554 | err = -ENOMEM; | 600 | err = -ENOMEM; |
555 | } | 601 | } |
556 | } else | 602 | } else if (strcmp(buf, "secinfo") == 0) |
603 | err = secinfo_parse(&mesg, buf, &exp); | ||
604 | else | ||
557 | /* quietly ignore unknown words and anything | 605 | /* quietly ignore unknown words and anything |
558 | * following. Newer user-space can try to set | 606 | * following. Newer user-space can try to set |
559 | * new values, then see what the result was. | 607 | * new values, then see what the result was. |
@@ -593,6 +641,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
593 | 641 | ||
594 | static void exp_flags(struct seq_file *m, int flag, int fsid, | 642 | static void exp_flags(struct seq_file *m, int flag, int fsid, |
595 | uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs); | 643 | uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs); |
644 | static void show_secinfo(struct seq_file *m, struct svc_export *exp); | ||
596 | 645 | ||
597 | static int svc_export_show(struct seq_file *m, | 646 | static int svc_export_show(struct seq_file *m, |
598 | struct cache_detail *cd, | 647 | struct cache_detail *cd, |
@@ -622,6 +671,7 @@ static int svc_export_show(struct seq_file *m, | |||
622 | seq_printf(m, "%02x", exp->ex_uuid[i]); | 671 | seq_printf(m, "%02x", exp->ex_uuid[i]); |
623 | } | 672 | } |
624 | } | 673 | } |
674 | show_secinfo(m, exp); | ||
625 | } | 675 | } |
626 | seq_puts(m, ")\n"); | 676 | seq_puts(m, ")\n"); |
627 | return 0; | 677 | return 0; |
@@ -654,6 +704,7 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem) | |||
654 | { | 704 | { |
655 | struct svc_export *new = container_of(cnew, struct svc_export, h); | 705 | struct svc_export *new = container_of(cnew, struct svc_export, h); |
656 | struct svc_export *item = container_of(citem, struct svc_export, h); | 706 | struct svc_export *item = container_of(citem, struct svc_export, h); |
707 | int i; | ||
657 | 708 | ||
658 | new->ex_flags = item->ex_flags; | 709 | new->ex_flags = item->ex_flags; |
659 | new->ex_anon_uid = item->ex_anon_uid; | 710 | new->ex_anon_uid = item->ex_anon_uid; |
@@ -669,6 +720,10 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem) | |||
669 | item->ex_fslocs.locations_count = 0; | 720 | item->ex_fslocs.locations_count = 0; |
670 | new->ex_fslocs.migrated = item->ex_fslocs.migrated; | 721 | new->ex_fslocs.migrated = item->ex_fslocs.migrated; |
671 | item->ex_fslocs.migrated = 0; | 722 | item->ex_fslocs.migrated = 0; |
723 | new->ex_nflavors = item->ex_nflavors; | ||
724 | for (i = 0; i < MAX_SECINFO_LIST; i++) { | ||
725 | new->ex_flavors[i] = item->ex_flavors[i]; | ||
726 | } | ||
672 | } | 727 | } |
673 | 728 | ||
674 | static struct cache_head *svc_export_alloc(void) | 729 | static struct cache_head *svc_export_alloc(void) |
@@ -738,16 +793,18 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp) | |||
738 | int err; | 793 | int err; |
739 | 794 | ||
740 | if (!clp) | 795 | if (!clp) |
741 | return NULL; | 796 | return ERR_PTR(-ENOENT); |
742 | 797 | ||
743 | key.ek_client = clp; | 798 | key.ek_client = clp; |
744 | key.ek_fsidtype = fsid_type; | 799 | key.ek_fsidtype = fsid_type; |
745 | memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); | 800 | memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); |
746 | 801 | ||
747 | ek = svc_expkey_lookup(&key); | 802 | ek = svc_expkey_lookup(&key); |
748 | if (ek != NULL) | 803 | if (ek == NULL) |
749 | if ((err = cache_check(&svc_expkey_cache, &ek->h, reqp))) | 804 | return ERR_PTR(-ENOMEM); |
750 | ek = ERR_PTR(err); | 805 | err = cache_check(&svc_expkey_cache, &ek->h, reqp); |
806 | if (err) | ||
807 | return ERR_PTR(err); | ||
751 | return ek; | 808 | return ek; |
752 | } | 809 | } |
753 | 810 | ||
@@ -808,30 +865,21 @@ exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry, | |||
808 | struct cache_req *reqp) | 865 | struct cache_req *reqp) |
809 | { | 866 | { |
810 | struct svc_export *exp, key; | 867 | struct svc_export *exp, key; |
868 | int err; | ||
811 | 869 | ||
812 | if (!clp) | 870 | if (!clp) |
813 | return NULL; | 871 | return ERR_PTR(-ENOENT); |
814 | 872 | ||
815 | key.ex_client = clp; | 873 | key.ex_client = clp; |
816 | key.ex_mnt = mnt; | 874 | key.ex_mnt = mnt; |
817 | key.ex_dentry = dentry; | 875 | key.ex_dentry = dentry; |
818 | 876 | ||
819 | exp = svc_export_lookup(&key); | 877 | exp = svc_export_lookup(&key); |
820 | if (exp != NULL) { | 878 | if (exp == NULL) |
821 | int err; | 879 | return ERR_PTR(-ENOMEM); |
822 | 880 | err = cache_check(&svc_export_cache, &exp->h, reqp); | |
823 | err = cache_check(&svc_export_cache, &exp->h, reqp); | 881 | if (err) |
824 | switch (err) { | 882 | return ERR_PTR(err); |
825 | case 0: break; | ||
826 | case -EAGAIN: | ||
827 | case -ETIMEDOUT: | ||
828 | exp = ERR_PTR(err); | ||
829 | break; | ||
830 | default: | ||
831 | exp = NULL; | ||
832 | } | ||
833 | } | ||
834 | |||
835 | return exp; | 883 | return exp; |
836 | } | 884 | } |
837 | 885 | ||
@@ -847,7 +895,7 @@ exp_parent(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry, | |||
847 | dget(dentry); | 895 | dget(dentry); |
848 | exp = exp_get_by_name(clp, mnt, dentry, reqp); | 896 | exp = exp_get_by_name(clp, mnt, dentry, reqp); |
849 | 897 | ||
850 | while (exp == NULL && !IS_ROOT(dentry)) { | 898 | while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) { |
851 | struct dentry *parent; | 899 | struct dentry *parent; |
852 | 900 | ||
853 | parent = dget_parent(dentry); | 901 | parent = dget_parent(dentry); |
@@ -900,7 +948,7 @@ static void exp_fsid_unhash(struct svc_export *exp) | |||
900 | return; | 948 | return; |
901 | 949 | ||
902 | ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid); | 950 | ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid); |
903 | if (ek && !IS_ERR(ek)) { | 951 | if (!IS_ERR(ek)) { |
904 | ek->h.expiry_time = get_seconds()-1; | 952 | ek->h.expiry_time = get_seconds()-1; |
905 | cache_put(&ek->h, &svc_expkey_cache); | 953 | cache_put(&ek->h, &svc_expkey_cache); |
906 | } | 954 | } |
@@ -938,7 +986,7 @@ static void exp_unhash(struct svc_export *exp) | |||
938 | struct inode *inode = exp->ex_dentry->d_inode; | 986 | struct inode *inode = exp->ex_dentry->d_inode; |
939 | 987 | ||
940 | ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino); | 988 | ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino); |
941 | if (ek && !IS_ERR(ek)) { | 989 | if (!IS_ERR(ek)) { |
942 | ek->h.expiry_time = get_seconds()-1; | 990 | ek->h.expiry_time = get_seconds()-1; |
943 | cache_put(&ek->h, &svc_expkey_cache); | 991 | cache_put(&ek->h, &svc_expkey_cache); |
944 | } | 992 | } |
@@ -989,13 +1037,12 @@ exp_export(struct nfsctl_export *nxp) | |||
989 | 1037 | ||
990 | /* must make sure there won't be an ex_fsid clash */ | 1038 | /* must make sure there won't be an ex_fsid clash */ |
991 | if ((nxp->ex_flags & NFSEXP_FSID) && | 1039 | if ((nxp->ex_flags & NFSEXP_FSID) && |
992 | (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) && | 1040 | (!IS_ERR(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev))) && |
993 | !IS_ERR(fsid_key) && | ||
994 | fsid_key->ek_mnt && | 1041 | fsid_key->ek_mnt && |
995 | (fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) ) | 1042 | (fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) ) |
996 | goto finish; | 1043 | goto finish; |
997 | 1044 | ||
998 | if (exp) { | 1045 | if (!IS_ERR(exp)) { |
999 | /* just a flags/id/fsid update */ | 1046 | /* just a flags/id/fsid update */ |
1000 | 1047 | ||
1001 | exp_fsid_unhash(exp); | 1048 | exp_fsid_unhash(exp); |
@@ -1104,7 +1151,7 @@ exp_unexport(struct nfsctl_export *nxp) | |||
1104 | err = -EINVAL; | 1151 | err = -EINVAL; |
1105 | exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL); | 1152 | exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL); |
1106 | path_release(&nd); | 1153 | path_release(&nd); |
1107 | if (!exp) | 1154 | if (IS_ERR(exp)) |
1108 | goto out_domain; | 1155 | goto out_domain; |
1109 | 1156 | ||
1110 | exp_do_unexport(exp); | 1157 | exp_do_unexport(exp); |
@@ -1149,10 +1196,6 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize) | |||
1149 | err = PTR_ERR(exp); | 1196 | err = PTR_ERR(exp); |
1150 | goto out; | 1197 | goto out; |
1151 | } | 1198 | } |
1152 | if (!exp) { | ||
1153 | dprintk("nfsd: exp_rootfh export not found.\n"); | ||
1154 | goto out; | ||
1155 | } | ||
1156 | 1199 | ||
1157 | /* | 1200 | /* |
1158 | * fh must be initialized before calling fh_compose | 1201 | * fh must be initialized before calling fh_compose |
@@ -1176,17 +1219,130 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, | |||
1176 | { | 1219 | { |
1177 | struct svc_export *exp; | 1220 | struct svc_export *exp; |
1178 | struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp); | 1221 | struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp); |
1179 | if (!ek || IS_ERR(ek)) | 1222 | if (IS_ERR(ek)) |
1180 | return ERR_PTR(PTR_ERR(ek)); | 1223 | return ERR_PTR(PTR_ERR(ek)); |
1181 | 1224 | ||
1182 | exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp); | 1225 | exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp); |
1183 | cache_put(&ek->h, &svc_expkey_cache); | 1226 | cache_put(&ek->h, &svc_expkey_cache); |
1184 | 1227 | ||
1185 | if (!exp || IS_ERR(exp)) | 1228 | if (IS_ERR(exp)) |
1186 | return ERR_PTR(PTR_ERR(exp)); | 1229 | return ERR_PTR(PTR_ERR(exp)); |
1187 | return exp; | 1230 | return exp; |
1188 | } | 1231 | } |
1189 | 1232 | ||
1233 | __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp) | ||
1234 | { | ||
1235 | struct exp_flavor_info *f; | ||
1236 | struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; | ||
1237 | |||
1238 | /* legacy gss-only clients are always OK: */ | ||
1239 | if (exp->ex_client == rqstp->rq_gssclient) | ||
1240 | return 0; | ||
1241 | /* ip-address based client; check sec= export option: */ | ||
1242 | for (f = exp->ex_flavors; f < end; f++) { | ||
1243 | if (f->pseudoflavor == rqstp->rq_flavor) | ||
1244 | return 0; | ||
1245 | } | ||
1246 | /* defaults in absence of sec= options: */ | ||
1247 | if (exp->ex_nflavors == 0) { | ||
1248 | if (rqstp->rq_flavor == RPC_AUTH_NULL || | ||
1249 | rqstp->rq_flavor == RPC_AUTH_UNIX) | ||
1250 | return 0; | ||
1251 | } | ||
1252 | return nfserr_wrongsec; | ||
1253 | } | ||
1254 | |||
1255 | /* | ||
1256 | * Uses rq_client and rq_gssclient to find an export; uses rq_client (an | ||
1257 | * auth_unix client) if it's available and has secinfo information; | ||
1258 | * otherwise, will try to use rq_gssclient. | ||
1259 | * | ||
1260 | * Called from functions that handle requests; functions that do work on | ||
1261 | * behalf of mountd are passed a single client name to use, and should | ||
1262 | * use exp_get_by_name() or exp_find(). | ||
1263 | */ | ||
1264 | struct svc_export * | ||
1265 | rqst_exp_get_by_name(struct svc_rqst *rqstp, struct vfsmount *mnt, | ||
1266 | struct dentry *dentry) | ||
1267 | { | ||
1268 | struct svc_export *gssexp, *exp = NULL; | ||
1269 | |||
1270 | if (rqstp->rq_client == NULL) | ||
1271 | goto gss; | ||
1272 | |||
1273 | /* First try the auth_unix client: */ | ||
1274 | exp = exp_get_by_name(rqstp->rq_client, mnt, dentry, | ||
1275 | &rqstp->rq_chandle); | ||
1276 | if (PTR_ERR(exp) == -ENOENT) | ||
1277 | goto gss; | ||
1278 | if (IS_ERR(exp)) | ||
1279 | return exp; | ||
1280 | /* If it has secinfo, assume there are no gss/... clients */ | ||
1281 | if (exp->ex_nflavors > 0) | ||
1282 | return exp; | ||
1283 | gss: | ||
1284 | /* Otherwise, try falling back on gss client */ | ||
1285 | if (rqstp->rq_gssclient == NULL) | ||
1286 | return exp; | ||
1287 | gssexp = exp_get_by_name(rqstp->rq_gssclient, mnt, dentry, | ||
1288 | &rqstp->rq_chandle); | ||
1289 | if (PTR_ERR(gssexp) == -ENOENT) | ||
1290 | return exp; | ||
1291 | if (exp && !IS_ERR(exp)) | ||
1292 | exp_put(exp); | ||
1293 | return gssexp; | ||
1294 | } | ||
1295 | |||
1296 | struct svc_export * | ||
1297 | rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv) | ||
1298 | { | ||
1299 | struct svc_export *gssexp, *exp = NULL; | ||
1300 | |||
1301 | if (rqstp->rq_client == NULL) | ||
1302 | goto gss; | ||
1303 | |||
1304 | /* First try the auth_unix client: */ | ||
1305 | exp = exp_find(rqstp->rq_client, fsid_type, fsidv, &rqstp->rq_chandle); | ||
1306 | if (PTR_ERR(exp) == -ENOENT) | ||
1307 | goto gss; | ||
1308 | if (IS_ERR(exp)) | ||
1309 | return exp; | ||
1310 | /* If it has secinfo, assume there are no gss/... clients */ | ||
1311 | if (exp->ex_nflavors > 0) | ||
1312 | return exp; | ||
1313 | gss: | ||
1314 | /* Otherwise, try falling back on gss client */ | ||
1315 | if (rqstp->rq_gssclient == NULL) | ||
1316 | return exp; | ||
1317 | gssexp = exp_find(rqstp->rq_gssclient, fsid_type, fsidv, | ||
1318 | &rqstp->rq_chandle); | ||
1319 | if (PTR_ERR(gssexp) == -ENOENT) | ||
1320 | return exp; | ||
1321 | if (exp && !IS_ERR(exp)) | ||
1322 | exp_put(exp); | ||
1323 | return gssexp; | ||
1324 | } | ||
1325 | |||
1326 | struct svc_export * | ||
1327 | rqst_exp_parent(struct svc_rqst *rqstp, struct vfsmount *mnt, | ||
1328 | struct dentry *dentry) | ||
1329 | { | ||
1330 | struct svc_export *exp; | ||
1331 | |||
1332 | dget(dentry); | ||
1333 | exp = rqst_exp_get_by_name(rqstp, mnt, dentry); | ||
1334 | |||
1335 | while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) { | ||
1336 | struct dentry *parent; | ||
1337 | |||
1338 | parent = dget_parent(dentry); | ||
1339 | dput(dentry); | ||
1340 | dentry = parent; | ||
1341 | exp = rqst_exp_get_by_name(rqstp, mnt, dentry); | ||
1342 | } | ||
1343 | dput(dentry); | ||
1344 | return exp; | ||
1345 | } | ||
1190 | 1346 | ||
1191 | /* | 1347 | /* |
1192 | * Called when we need the filehandle for the root of the pseudofs, | 1348 | * Called when we need the filehandle for the root of the pseudofs, |
@@ -1194,8 +1350,7 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv, | |||
1194 | * export point with fsid==0 | 1350 | * export point with fsid==0 |
1195 | */ | 1351 | */ |
1196 | __be32 | 1352 | __be32 |
1197 | exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, | 1353 | exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp) |
1198 | struct cache_req *creq) | ||
1199 | { | 1354 | { |
1200 | struct svc_export *exp; | 1355 | struct svc_export *exp; |
1201 | __be32 rv; | 1356 | __be32 rv; |
@@ -1203,12 +1358,16 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp, | |||
1203 | 1358 | ||
1204 | mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL); | 1359 | mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL); |
1205 | 1360 | ||
1206 | exp = exp_find(clp, FSID_NUM, fsidv, creq); | 1361 | exp = rqst_exp_find(rqstp, FSID_NUM, fsidv); |
1362 | if (PTR_ERR(exp) == -ENOENT) | ||
1363 | return nfserr_perm; | ||
1207 | if (IS_ERR(exp)) | 1364 | if (IS_ERR(exp)) |
1208 | return nfserrno(PTR_ERR(exp)); | 1365 | return nfserrno(PTR_ERR(exp)); |
1209 | if (exp == NULL) | ||
1210 | return nfserr_perm; | ||
1211 | rv = fh_compose(fhp, exp, exp->ex_dentry, NULL); | 1366 | rv = fh_compose(fhp, exp, exp->ex_dentry, NULL); |
1367 | if (rv) | ||
1368 | goto out; | ||
1369 | rv = check_nfsd_access(exp, rqstp); | ||
1370 | out: | ||
1212 | exp_put(exp); | 1371 | exp_put(exp); |
1213 | return rv; | 1372 | return rv; |
1214 | } | 1373 | } |
@@ -1296,28 +1455,62 @@ static struct flags { | |||
1296 | { 0, {"", ""}} | 1455 | { 0, {"", ""}} |
1297 | }; | 1456 | }; |
1298 | 1457 | ||
1299 | static void exp_flags(struct seq_file *m, int flag, int fsid, | 1458 | static void show_expflags(struct seq_file *m, int flags, int mask) |
1300 | uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc) | ||
1301 | { | 1459 | { |
1302 | int first = 0; | ||
1303 | struct flags *flg; | 1460 | struct flags *flg; |
1461 | int state, first = 0; | ||
1304 | 1462 | ||
1305 | for (flg = expflags; flg->flag; flg++) { | 1463 | for (flg = expflags; flg->flag; flg++) { |
1306 | int state = (flg->flag & flag)?0:1; | 1464 | if (flg->flag & ~mask) |
1465 | continue; | ||
1466 | state = (flg->flag & flags) ? 0 : 1; | ||
1307 | if (*flg->name[state]) | 1467 | if (*flg->name[state]) |
1308 | seq_printf(m, "%s%s", first++?",":"", flg->name[state]); | 1468 | seq_printf(m, "%s%s", first++?",":"", flg->name[state]); |
1309 | } | 1469 | } |
1470 | } | ||
1471 | |||
1472 | static void show_secinfo_flags(struct seq_file *m, int flags) | ||
1473 | { | ||
1474 | seq_printf(m, ","); | ||
1475 | show_expflags(m, flags, NFSEXP_SECINFO_FLAGS); | ||
1476 | } | ||
1477 | |||
1478 | static void show_secinfo(struct seq_file *m, struct svc_export *exp) | ||
1479 | { | ||
1480 | struct exp_flavor_info *f; | ||
1481 | struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors; | ||
1482 | int lastflags = 0, first = 0; | ||
1483 | |||
1484 | if (exp->ex_nflavors == 0) | ||
1485 | return; | ||
1486 | for (f = exp->ex_flavors; f < end; f++) { | ||
1487 | if (first || f->flags != lastflags) { | ||
1488 | if (!first) | ||
1489 | show_secinfo_flags(m, lastflags); | ||
1490 | seq_printf(m, ",sec=%d", f->pseudoflavor); | ||
1491 | lastflags = f->flags; | ||
1492 | } else { | ||
1493 | seq_printf(m, ":%d", f->pseudoflavor); | ||
1494 | } | ||
1495 | } | ||
1496 | show_secinfo_flags(m, lastflags); | ||
1497 | } | ||
1498 | |||
1499 | static void exp_flags(struct seq_file *m, int flag, int fsid, | ||
1500 | uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc) | ||
1501 | { | ||
1502 | show_expflags(m, flag, NFSEXP_ALLFLAGS); | ||
1310 | if (flag & NFSEXP_FSID) | 1503 | if (flag & NFSEXP_FSID) |
1311 | seq_printf(m, "%sfsid=%d", first++?",":"", fsid); | 1504 | seq_printf(m, ",fsid=%d", fsid); |
1312 | if (anonu != (uid_t)-2 && anonu != (0x10000-2)) | 1505 | if (anonu != (uid_t)-2 && anonu != (0x10000-2)) |
1313 | seq_printf(m, "%sanonuid=%d", first++?",":"", anonu); | 1506 | seq_printf(m, ",sanonuid=%d", anonu); |
1314 | if (anong != (gid_t)-2 && anong != (0x10000-2)) | 1507 | if (anong != (gid_t)-2 && anong != (0x10000-2)) |
1315 | seq_printf(m, "%sanongid=%d", first++?",":"", anong); | 1508 | seq_printf(m, ",sanongid=%d", anong); |
1316 | if (fsloc && fsloc->locations_count > 0) { | 1509 | if (fsloc && fsloc->locations_count > 0) { |
1317 | char *loctype = (fsloc->migrated) ? "refer" : "replicas"; | 1510 | char *loctype = (fsloc->migrated) ? "refer" : "replicas"; |
1318 | int i; | 1511 | int i; |
1319 | 1512 | ||
1320 | seq_printf(m, "%s%s=", first++?",":"", loctype); | 1513 | seq_printf(m, ",%s=", loctype); |
1321 | seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\"); | 1514 | seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\"); |
1322 | seq_putc(m, '@'); | 1515 | seq_putc(m, '@'); |
1323 | seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\"); | 1516 | seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\"); |
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c index 221acd1f11f6..9e4a568a5013 100644 --- a/fs/nfsd/lockd.c +++ b/fs/nfsd/lockd.c | |||
@@ -65,6 +65,7 @@ nlm_fclose(struct file *filp) | |||
65 | static struct nlmsvc_binding nfsd_nlm_ops = { | 65 | static struct nlmsvc_binding nfsd_nlm_ops = { |
66 | .fopen = nlm_fopen, /* open file for locking */ | 66 | .fopen = nlm_fopen, /* open file for locking */ |
67 | .fclose = nlm_fclose, /* close file */ | 67 | .fclose = nlm_fclose, /* close file */ |
68 | .get_grace_period = get_nfs4_grace_period, | ||
68 | }; | 69 | }; |
69 | 70 | ||
70 | void | 71 | void |
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index cc3b7badd486..b6ed38380ab8 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c | |||
@@ -183,8 +183,13 @@ static void | |||
183 | summarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas) | 183 | summarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas) |
184 | { | 184 | { |
185 | struct posix_acl_entry *pa, *pe; | 185 | struct posix_acl_entry *pa, *pe; |
186 | pas->users = 0; | 186 | |
187 | pas->groups = 0; | 187 | /* |
188 | * Only pas.users and pas.groups need initialization; previous | ||
189 | * posix_acl_valid() calls ensure that the other fields will be | ||
190 | * initialized in the following loop. But, just to placate gcc: | ||
191 | */ | ||
192 | memset(pas, 0, sizeof(*pas)); | ||
188 | pas->mask = 07; | 193 | pas->mask = 07; |
189 | 194 | ||
190 | pe = acl->a_entries + acl->a_count; | 195 | pe = acl->a_entries + acl->a_count; |
@@ -732,13 +737,16 @@ int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl, | |||
732 | *pacl = posix_state_to_acl(&effective_acl_state, flags); | 737 | *pacl = posix_state_to_acl(&effective_acl_state, flags); |
733 | if (IS_ERR(*pacl)) { | 738 | if (IS_ERR(*pacl)) { |
734 | ret = PTR_ERR(*pacl); | 739 | ret = PTR_ERR(*pacl); |
740 | *pacl = NULL; | ||
735 | goto out_dstate; | 741 | goto out_dstate; |
736 | } | 742 | } |
737 | *dpacl = posix_state_to_acl(&default_acl_state, | 743 | *dpacl = posix_state_to_acl(&default_acl_state, |
738 | flags | NFS4_ACL_TYPE_DEFAULT); | 744 | flags | NFS4_ACL_TYPE_DEFAULT); |
739 | if (IS_ERR(*dpacl)) { | 745 | if (IS_ERR(*dpacl)) { |
740 | ret = PTR_ERR(*dpacl); | 746 | ret = PTR_ERR(*dpacl); |
747 | *dpacl = NULL; | ||
741 | posix_acl_release(*pacl); | 748 | posix_acl_release(*pacl); |
749 | *pacl = NULL; | ||
742 | goto out_dstate; | 750 | goto out_dstate; |
743 | } | 751 | } |
744 | sort_pacl(*pacl); | 752 | sort_pacl(*pacl); |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 5443c52b57aa..31d6633c7fe4 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -75,7 +75,7 @@ enum nfs_cb_opnum4 { | |||
75 | #define op_enc_sz 1 | 75 | #define op_enc_sz 1 |
76 | #define op_dec_sz 2 | 76 | #define op_dec_sz 2 |
77 | #define enc_nfs4_fh_sz (1 + (NFS4_FHSIZE >> 2)) | 77 | #define enc_nfs4_fh_sz (1 + (NFS4_FHSIZE >> 2)) |
78 | #define enc_stateid_sz 16 | 78 | #define enc_stateid_sz (NFS4_STATEID_SIZE >> 2) |
79 | #define NFS4_enc_cb_recall_sz (cb_compound_enc_hdr_sz + \ | 79 | #define NFS4_enc_cb_recall_sz (cb_compound_enc_hdr_sz + \ |
80 | 1 + enc_stateid_sz + \ | 80 | 1 + enc_stateid_sz + \ |
81 | enc_nfs4_fh_sz) | 81 | enc_nfs4_fh_sz) |
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index 45aa21ce6784..2cf9a9a2d89c 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c | |||
@@ -587,6 +587,15 @@ idmap_lookup(struct svc_rqst *rqstp, | |||
587 | return ret; | 587 | return ret; |
588 | } | 588 | } |
589 | 589 | ||
590 | static char * | ||
591 | rqst_authname(struct svc_rqst *rqstp) | ||
592 | { | ||
593 | struct auth_domain *clp; | ||
594 | |||
595 | clp = rqstp->rq_gssclient ? rqstp->rq_gssclient : rqstp->rq_client; | ||
596 | return clp->name; | ||
597 | } | ||
598 | |||
590 | static int | 599 | static int |
591 | idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, | 600 | idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, |
592 | uid_t *id) | 601 | uid_t *id) |
@@ -600,7 +609,7 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen | |||
600 | return -EINVAL; | 609 | return -EINVAL; |
601 | memcpy(key.name, name, namelen); | 610 | memcpy(key.name, name, namelen); |
602 | key.name[namelen] = '\0'; | 611 | key.name[namelen] = '\0'; |
603 | strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname)); | 612 | strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); |
604 | ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item); | 613 | ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item); |
605 | if (ret == -ENOENT) | 614 | if (ret == -ENOENT) |
606 | ret = -ESRCH; /* nfserr_badname */ | 615 | ret = -ESRCH; /* nfserr_badname */ |
@@ -620,7 +629,7 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name) | |||
620 | }; | 629 | }; |
621 | int ret; | 630 | int ret; |
622 | 631 | ||
623 | strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname)); | 632 | strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); |
624 | ret = idmap_lookup(rqstp, idtoname_lookup, &key, &idtoname_cache, &item); | 633 | ret = idmap_lookup(rqstp, idtoname_lookup, &key, &idtoname_cache, &item); |
625 | if (ret == -ENOENT) | 634 | if (ret == -ENOENT) |
626 | return sprintf(name, "%u", id); | 635 | return sprintf(name, "%u", id); |
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 8522729830db..3c627128e205 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <linux/nfsd/state.h> | 47 | #include <linux/nfsd/state.h> |
48 | #include <linux/nfsd/xdr4.h> | 48 | #include <linux/nfsd/xdr4.h> |
49 | #include <linux/nfs4_acl.h> | 49 | #include <linux/nfs4_acl.h> |
50 | #include <linux/sunrpc/gss_api.h> | ||
50 | 51 | ||
51 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 52 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
52 | 53 | ||
@@ -286,8 +287,7 @@ nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
286 | __be32 status; | 287 | __be32 status; |
287 | 288 | ||
288 | fh_put(&cstate->current_fh); | 289 | fh_put(&cstate->current_fh); |
289 | status = exp_pseudoroot(rqstp->rq_client, &cstate->current_fh, | 290 | status = exp_pseudoroot(rqstp, &cstate->current_fh); |
290 | &rqstp->rq_chandle); | ||
291 | return status; | 291 | return status; |
292 | } | 292 | } |
293 | 293 | ||
@@ -474,8 +474,8 @@ nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
474 | __be32 ret; | 474 | __be32 ret; |
475 | 475 | ||
476 | fh_init(&tmp_fh, NFS4_FHSIZE); | 476 | fh_init(&tmp_fh, NFS4_FHSIZE); |
477 | if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh, | 477 | ret = exp_pseudoroot(rqstp, &tmp_fh); |
478 | &rqstp->rq_chandle)) != 0) | 478 | if (ret) |
479 | return ret; | 479 | return ret; |
480 | if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) { | 480 | if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) { |
481 | fh_put(&tmp_fh); | 481 | fh_put(&tmp_fh); |
@@ -611,6 +611,30 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
611 | } | 611 | } |
612 | 612 | ||
613 | static __be32 | 613 | static __be32 |
614 | nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | ||
615 | struct nfsd4_secinfo *secinfo) | ||
616 | { | ||
617 | struct svc_fh resfh; | ||
618 | struct svc_export *exp; | ||
619 | struct dentry *dentry; | ||
620 | __be32 err; | ||
621 | |||
622 | fh_init(&resfh, NFS4_FHSIZE); | ||
623 | err = nfsd_lookup_dentry(rqstp, &cstate->current_fh, | ||
624 | secinfo->si_name, secinfo->si_namelen, | ||
625 | &exp, &dentry); | ||
626 | if (err) | ||
627 | return err; | ||
628 | if (dentry->d_inode == NULL) { | ||
629 | exp_put(exp); | ||
630 | err = nfserr_noent; | ||
631 | } else | ||
632 | secinfo->si_exp = exp; | ||
633 | dput(dentry); | ||
634 | return err; | ||
635 | } | ||
636 | |||
637 | static __be32 | ||
614 | nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 638 | nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
615 | struct nfsd4_setattr *setattr) | 639 | struct nfsd4_setattr *setattr) |
616 | { | 640 | { |
@@ -1009,6 +1033,9 @@ static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = { | |||
1009 | [OP_SAVEFH] = { | 1033 | [OP_SAVEFH] = { |
1010 | .op_func = (nfsd4op_func)nfsd4_savefh, | 1034 | .op_func = (nfsd4op_func)nfsd4_savefh, |
1011 | }, | 1035 | }, |
1036 | [OP_SECINFO] = { | ||
1037 | .op_func = (nfsd4op_func)nfsd4_secinfo, | ||
1038 | }, | ||
1012 | [OP_SETATTR] = { | 1039 | [OP_SETATTR] = { |
1013 | .op_func = (nfsd4op_func)nfsd4_setattr, | 1040 | .op_func = (nfsd4op_func)nfsd4_setattr, |
1014 | }, | 1041 | }, |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 8c52913d7cb6..e4a4c87ec8c6 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -49,8 +49,10 @@ | |||
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 | #include <linux/namei.h> |
52 | #include <linux/swap.h> | ||
52 | #include <linux/mutex.h> | 53 | #include <linux/mutex.h> |
53 | #include <linux/lockd/bind.h> | 54 | #include <linux/lockd/bind.h> |
55 | #include <linux/module.h> | ||
54 | 56 | ||
55 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 57 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
56 | 58 | ||
@@ -149,6 +151,7 @@ get_nfs4_file(struct nfs4_file *fi) | |||
149 | } | 151 | } |
150 | 152 | ||
151 | static int num_delegations; | 153 | static int num_delegations; |
154 | unsigned int max_delegations; | ||
152 | 155 | ||
153 | /* | 156 | /* |
154 | * Open owner state (share locks) | 157 | * Open owner state (share locks) |
@@ -192,7 +195,9 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
192 | struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback; | 195 | struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback; |
193 | 196 | ||
194 | dprintk("NFSD alloc_init_deleg\n"); | 197 | dprintk("NFSD alloc_init_deleg\n"); |
195 | if (num_delegations > STATEID_HASH_SIZE * 4) | 198 | if (fp->fi_had_conflict) |
199 | return NULL; | ||
200 | if (num_delegations > max_delegations) | ||
196 | return NULL; | 201 | return NULL; |
197 | dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL); | 202 | dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL); |
198 | if (dp == NULL) | 203 | if (dp == NULL) |
@@ -999,6 +1004,7 @@ alloc_init_file(struct inode *ino) | |||
999 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); | 1004 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); |
1000 | fp->fi_inode = igrab(ino); | 1005 | fp->fi_inode = igrab(ino); |
1001 | fp->fi_id = current_fileid++; | 1006 | fp->fi_id = current_fileid++; |
1007 | fp->fi_had_conflict = false; | ||
1002 | return fp; | 1008 | return fp; |
1003 | } | 1009 | } |
1004 | return NULL; | 1010 | return NULL; |
@@ -1325,6 +1331,7 @@ do_recall(void *__dp) | |||
1325 | { | 1331 | { |
1326 | struct nfs4_delegation *dp = __dp; | 1332 | struct nfs4_delegation *dp = __dp; |
1327 | 1333 | ||
1334 | dp->dl_file->fi_had_conflict = true; | ||
1328 | nfsd4_cb_recall(dp); | 1335 | nfsd4_cb_recall(dp); |
1329 | return 0; | 1336 | return 0; |
1330 | } | 1337 | } |
@@ -3190,20 +3197,49 @@ nfsd4_load_reboot_recovery_data(void) | |||
3190 | printk("NFSD: Failure reading reboot recovery data\n"); | 3197 | printk("NFSD: Failure reading reboot recovery data\n"); |
3191 | } | 3198 | } |
3192 | 3199 | ||
3200 | unsigned long | ||
3201 | get_nfs4_grace_period(void) | ||
3202 | { | ||
3203 | return max(user_lease_time, lease_time) * HZ; | ||
3204 | } | ||
3205 | |||
3206 | /* | ||
3207 | * Since the lifetime of a delegation isn't limited to that of an open, a | ||
3208 | * client may quite reasonably hang on to a delegation as long as it has | ||
3209 | * the inode cached. This becomes an obvious problem the first time a | ||
3210 | * client's inode cache approaches the size of the server's total memory. | ||
3211 | * | ||
3212 | * For now we avoid this problem by imposing a hard limit on the number | ||
3213 | * of delegations, which varies according to the server's memory size. | ||
3214 | */ | ||
3215 | static void | ||
3216 | set_max_delegations(void) | ||
3217 | { | ||
3218 | /* | ||
3219 | * Allow at most 4 delegations per megabyte of RAM. Quick | ||
3220 | * estimates suggest that in the worst case (where every delegation | ||
3221 | * is for a different inode), a delegation could take about 1.5K, | ||
3222 | * giving a worst case usage of about 6% of memory. | ||
3223 | */ | ||
3224 | max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); | ||
3225 | } | ||
3226 | |||
3193 | /* initialization to perform when the nfsd service is started: */ | 3227 | /* initialization to perform when the nfsd service is started: */ |
3194 | 3228 | ||
3195 | static void | 3229 | static void |
3196 | __nfs4_state_start(void) | 3230 | __nfs4_state_start(void) |
3197 | { | 3231 | { |
3198 | time_t grace_time; | 3232 | unsigned long grace_time; |
3199 | 3233 | ||
3200 | boot_time = get_seconds(); | 3234 | boot_time = get_seconds(); |
3201 | grace_time = max(user_lease_time, lease_time); | 3235 | grace_time = get_nfs_grace_period(); |
3202 | lease_time = user_lease_time; | 3236 | lease_time = user_lease_time; |
3203 | in_grace = 1; | 3237 | in_grace = 1; |
3204 | printk("NFSD: starting %ld-second grace period\n", grace_time); | 3238 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", |
3239 | grace_time/HZ); | ||
3205 | laundry_wq = create_singlethread_workqueue("nfsd4"); | 3240 | laundry_wq = create_singlethread_workqueue("nfsd4"); |
3206 | queue_delayed_work(laundry_wq, &laundromat_work, grace_time*HZ); | 3241 | queue_delayed_work(laundry_wq, &laundromat_work, grace_time); |
3242 | set_max_delegations(); | ||
3207 | } | 3243 | } |
3208 | 3244 | ||
3209 | int | 3245 | int |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 15809dfd88a5..b3d55c6747fd 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -56,6 +56,8 @@ | |||
56 | #include <linux/nfsd_idmap.h> | 56 | #include <linux/nfsd_idmap.h> |
57 | #include <linux/nfs4.h> | 57 | #include <linux/nfs4.h> |
58 | #include <linux/nfs4_acl.h> | 58 | #include <linux/nfs4_acl.h> |
59 | #include <linux/sunrpc/gss_api.h> | ||
60 | #include <linux/sunrpc/svcauth_gss.h> | ||
59 | 61 | ||
60 | #define NFSDDBG_FACILITY NFSDDBG_XDR | 62 | #define NFSDDBG_FACILITY NFSDDBG_XDR |
61 | 63 | ||
@@ -819,6 +821,23 @@ nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid) | |||
819 | } | 821 | } |
820 | 822 | ||
821 | static __be32 | 823 | static __be32 |
824 | nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp, | ||
825 | struct nfsd4_secinfo *secinfo) | ||
826 | { | ||
827 | DECODE_HEAD; | ||
828 | |||
829 | READ_BUF(4); | ||
830 | READ32(secinfo->si_namelen); | ||
831 | READ_BUF(secinfo->si_namelen); | ||
832 | SAVEMEM(secinfo->si_name, secinfo->si_namelen); | ||
833 | status = check_filename(secinfo->si_name, secinfo->si_namelen, | ||
834 | nfserr_noent); | ||
835 | if (status) | ||
836 | return status; | ||
837 | DECODE_TAIL; | ||
838 | } | ||
839 | |||
840 | static __be32 | ||
822 | nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr) | 841 | nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr) |
823 | { | 842 | { |
824 | DECODE_HEAD; | 843 | DECODE_HEAD; |
@@ -1131,6 +1150,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
1131 | case OP_SAVEFH: | 1150 | case OP_SAVEFH: |
1132 | op->status = nfs_ok; | 1151 | op->status = nfs_ok; |
1133 | break; | 1152 | break; |
1153 | case OP_SECINFO: | ||
1154 | op->status = nfsd4_decode_secinfo(argp, &op->u.secinfo); | ||
1155 | break; | ||
1134 | case OP_SETATTR: | 1156 | case OP_SETATTR: |
1135 | op->status = nfsd4_decode_setattr(argp, &op->u.setattr); | 1157 | op->status = nfsd4_decode_setattr(argp, &op->u.setattr); |
1136 | break; | 1158 | break; |
@@ -1296,7 +1318,7 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 * | |||
1296 | char *path, *rootpath; | 1318 | char *path, *rootpath; |
1297 | 1319 | ||
1298 | fh_init(&tmp_fh, NFS4_FHSIZE); | 1320 | fh_init(&tmp_fh, NFS4_FHSIZE); |
1299 | *stat = exp_pseudoroot(rqstp->rq_client, &tmp_fh, &rqstp->rq_chandle); | 1321 | *stat = exp_pseudoroot(rqstp, &tmp_fh); |
1300 | if (*stat) | 1322 | if (*stat) |
1301 | return NULL; | 1323 | return NULL; |
1302 | rootpath = tmp_fh.fh_export->ex_path; | 1324 | rootpath = tmp_fh.fh_export->ex_path; |
@@ -1847,11 +1869,19 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd, | |||
1847 | if (d_mountpoint(dentry)) { | 1869 | if (d_mountpoint(dentry)) { |
1848 | int err; | 1870 | int err; |
1849 | 1871 | ||
1872 | /* | ||
1873 | * Why the heck aren't we just using nfsd_lookup?? | ||
1874 | * Different "."/".." handling? Something else? | ||
1875 | * At least, add a comment here to explain.... | ||
1876 | */ | ||
1850 | err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp); | 1877 | err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp); |
1851 | if (err) { | 1878 | if (err) { |
1852 | nfserr = nfserrno(err); | 1879 | nfserr = nfserrno(err); |
1853 | goto out_put; | 1880 | goto out_put; |
1854 | } | 1881 | } |
1882 | nfserr = check_nfsd_access(exp, cd->rd_rqstp); | ||
1883 | if (nfserr) | ||
1884 | goto out_put; | ||
1855 | 1885 | ||
1856 | } | 1886 | } |
1857 | nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval, | 1887 | nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval, |
@@ -2419,6 +2449,72 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ | |||
2419 | } | 2449 | } |
2420 | } | 2450 | } |
2421 | 2451 | ||
2452 | static void | ||
2453 | nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, int nfserr, | ||
2454 | struct nfsd4_secinfo *secinfo) | ||
2455 | { | ||
2456 | int i = 0; | ||
2457 | struct svc_export *exp = secinfo->si_exp; | ||
2458 | u32 nflavs; | ||
2459 | struct exp_flavor_info *flavs; | ||
2460 | struct exp_flavor_info def_flavs[2]; | ||
2461 | ENCODE_HEAD; | ||
2462 | |||
2463 | if (nfserr) | ||
2464 | goto out; | ||
2465 | if (exp->ex_nflavors) { | ||
2466 | flavs = exp->ex_flavors; | ||
2467 | nflavs = exp->ex_nflavors; | ||
2468 | } else { /* Handling of some defaults in absence of real secinfo: */ | ||
2469 | flavs = def_flavs; | ||
2470 | if (exp->ex_client->flavour->flavour == RPC_AUTH_UNIX) { | ||
2471 | nflavs = 2; | ||
2472 | flavs[0].pseudoflavor = RPC_AUTH_UNIX; | ||
2473 | flavs[1].pseudoflavor = RPC_AUTH_NULL; | ||
2474 | } else if (exp->ex_client->flavour->flavour == RPC_AUTH_GSS) { | ||
2475 | nflavs = 1; | ||
2476 | flavs[0].pseudoflavor | ||
2477 | = svcauth_gss_flavor(exp->ex_client); | ||
2478 | } else { | ||
2479 | nflavs = 1; | ||
2480 | flavs[0].pseudoflavor | ||
2481 | = exp->ex_client->flavour->flavour; | ||
2482 | } | ||
2483 | } | ||
2484 | |||
2485 | RESERVE_SPACE(4); | ||
2486 | WRITE32(nflavs); | ||
2487 | ADJUST_ARGS(); | ||
2488 | for (i = 0; i < nflavs; i++) { | ||
2489 | u32 flav = flavs[i].pseudoflavor; | ||
2490 | struct gss_api_mech *gm = gss_mech_get_by_pseudoflavor(flav); | ||
2491 | |||
2492 | if (gm) { | ||
2493 | RESERVE_SPACE(4); | ||
2494 | WRITE32(RPC_AUTH_GSS); | ||
2495 | ADJUST_ARGS(); | ||
2496 | RESERVE_SPACE(4 + gm->gm_oid.len); | ||
2497 | WRITE32(gm->gm_oid.len); | ||
2498 | WRITEMEM(gm->gm_oid.data, gm->gm_oid.len); | ||
2499 | ADJUST_ARGS(); | ||
2500 | RESERVE_SPACE(4); | ||
2501 | WRITE32(0); /* qop */ | ||
2502 | ADJUST_ARGS(); | ||
2503 | RESERVE_SPACE(4); | ||
2504 | WRITE32(gss_pseudoflavor_to_service(gm, flav)); | ||
2505 | ADJUST_ARGS(); | ||
2506 | gss_mech_put(gm); | ||
2507 | } else { | ||
2508 | RESERVE_SPACE(4); | ||
2509 | WRITE32(flav); | ||
2510 | ADJUST_ARGS(); | ||
2511 | } | ||
2512 | } | ||
2513 | out: | ||
2514 | if (exp) | ||
2515 | exp_put(exp); | ||
2516 | } | ||
2517 | |||
2422 | /* | 2518 | /* |
2423 | * The SETATTR encode routine is special -- it always encodes a bitmap, | 2519 | * The SETATTR encode routine is special -- it always encodes a bitmap, |
2424 | * regardless of the error status. | 2520 | * regardless of the error status. |
@@ -2559,6 +2655,9 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) | |||
2559 | break; | 2655 | break; |
2560 | case OP_SAVEFH: | 2656 | case OP_SAVEFH: |
2561 | break; | 2657 | break; |
2658 | case OP_SECINFO: | ||
2659 | nfsd4_encode_secinfo(resp, op->status, &op->u.secinfo); | ||
2660 | break; | ||
2562 | case OP_SETATTR: | 2661 | case OP_SETATTR: |
2563 | nfsd4_encode_setattr(resp, op->status, &op->u.setattr); | 2662 | nfsd4_encode_setattr(resp, op->status, &op->u.setattr); |
2564 | break; | 2663 | break; |
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 71c686dc7257..baac89d917ca 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #include <linux/nfsd/cache.h> | 35 | #include <linux/nfsd/cache.h> |
36 | #include <linux/nfsd/xdr.h> | 36 | #include <linux/nfsd/xdr.h> |
37 | #include <linux/nfsd/syscall.h> | 37 | #include <linux/nfsd/syscall.h> |
38 | #include <linux/nfsd/interface.h> | ||
39 | 38 | ||
40 | #include <asm/uaccess.h> | 39 | #include <asm/uaccess.h> |
41 | 40 | ||
@@ -245,7 +244,7 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size) | |||
245 | } | 244 | } |
246 | exp_readunlock(); | 245 | exp_readunlock(); |
247 | if (err == 0) | 246 | if (err == 0) |
248 | err = res->fh_size + (int)&((struct knfsd_fh*)0)->fh_base; | 247 | err = res->fh_size + offsetof(struct knfsd_fh, fh_base); |
249 | out: | 248 | out: |
250 | return err; | 249 | return err; |
251 | } | 250 | } |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 6ca2d24fc216..0eb464a39aae 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
@@ -15,10 +15,12 @@ | |||
15 | #include <linux/string.h> | 15 | #include <linux/string.h> |
16 | #include <linux/stat.h> | 16 | #include <linux/stat.h> |
17 | #include <linux/dcache.h> | 17 | #include <linux/dcache.h> |
18 | #include <linux/exportfs.h> | ||
18 | #include <linux/mount.h> | 19 | #include <linux/mount.h> |
19 | 20 | ||
20 | #include <linux/sunrpc/clnt.h> | 21 | #include <linux/sunrpc/clnt.h> |
21 | #include <linux/sunrpc/svc.h> | 22 | #include <linux/sunrpc/svc.h> |
23 | #include <linux/sunrpc/svcauth_gss.h> | ||
22 | #include <linux/nfsd/nfsd.h> | 24 | #include <linux/nfsd/nfsd.h> |
23 | 25 | ||
24 | #define NFSDDBG_FACILITY NFSDDBG_FH | 26 | #define NFSDDBG_FACILITY NFSDDBG_FH |
@@ -27,10 +29,6 @@ | |||
27 | static int nfsd_nr_verified; | 29 | static int nfsd_nr_verified; |
28 | static int nfsd_nr_put; | 30 | static int nfsd_nr_put; |
29 | 31 | ||
30 | extern struct export_operations export_op_default; | ||
31 | |||
32 | #define CALL(ops,fun) ((ops->fun)?(ops->fun):export_op_default.fun) | ||
33 | |||
34 | /* | 32 | /* |
35 | * our acceptability function. | 33 | * our acceptability function. |
36 | * if NOSUBTREECHECK, accept anything | 34 | * if NOSUBTREECHECK, accept anything |
@@ -123,8 +121,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | |||
123 | int data_left = fh->fh_size/4; | 121 | int data_left = fh->fh_size/4; |
124 | 122 | ||
125 | error = nfserr_stale; | 123 | error = nfserr_stale; |
126 | if (rqstp->rq_client == NULL) | ||
127 | goto out; | ||
128 | if (rqstp->rq_vers > 2) | 124 | if (rqstp->rq_vers > 2) |
129 | error = nfserr_badhandle; | 125 | error = nfserr_badhandle; |
130 | if (rqstp->rq_vers == 4 && fh->fh_size == 0) | 126 | if (rqstp->rq_vers == 4 && fh->fh_size == 0) |
@@ -148,7 +144,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | |||
148 | fh->fh_fsid[1] = fh->fh_fsid[2]; | 144 | fh->fh_fsid[1] = fh->fh_fsid[2]; |
149 | } | 145 | } |
150 | if ((data_left -= len)<0) goto out; | 146 | if ((data_left -= len)<0) goto out; |
151 | exp = exp_find(rqstp->rq_client, fh->fh_fsid_type, datap, &rqstp->rq_chandle); | 147 | exp = rqst_exp_find(rqstp, fh->fh_fsid_type, datap); |
152 | datap += len; | 148 | datap += len; |
153 | } else { | 149 | } else { |
154 | dev_t xdev; | 150 | dev_t xdev; |
@@ -159,19 +155,17 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | |||
159 | xdev = old_decode_dev(fh->ofh_xdev); | 155 | xdev = old_decode_dev(fh->ofh_xdev); |
160 | xino = u32_to_ino_t(fh->ofh_xino); | 156 | xino = u32_to_ino_t(fh->ofh_xino); |
161 | mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL); | 157 | mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL); |
162 | exp = exp_find(rqstp->rq_client, FSID_DEV, tfh, | 158 | exp = rqst_exp_find(rqstp, FSID_DEV, tfh); |
163 | &rqstp->rq_chandle); | ||
164 | } | 159 | } |
165 | 160 | ||
166 | if (IS_ERR(exp) && (PTR_ERR(exp) == -EAGAIN | 161 | error = nfserr_stale; |
167 | || PTR_ERR(exp) == -ETIMEDOUT)) { | 162 | if (PTR_ERR(exp) == -ENOENT) |
168 | error = nfserrno(PTR_ERR(exp)); | ||
169 | goto out; | 163 | goto out; |
170 | } | ||
171 | 164 | ||
172 | error = nfserr_stale; | 165 | if (IS_ERR(exp)) { |
173 | if (!exp || IS_ERR(exp)) | 166 | error = nfserrno(PTR_ERR(exp)); |
174 | goto out; | 167 | goto out; |
168 | } | ||
175 | 169 | ||
176 | /* Check if the request originated from a secure port. */ | 170 | /* Check if the request originated from a secure port. */ |
177 | error = nfserr_perm; | 171 | error = nfserr_perm; |
@@ -211,11 +205,9 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | |||
211 | if (fileid_type == 0) | 205 | if (fileid_type == 0) |
212 | dentry = dget(exp->ex_dentry); | 206 | dentry = dget(exp->ex_dentry); |
213 | else { | 207 | else { |
214 | struct export_operations *nop = exp->ex_mnt->mnt_sb->s_export_op; | 208 | dentry = exportfs_decode_fh(exp->ex_mnt, datap, |
215 | dentry = CALL(nop,decode_fh)(exp->ex_mnt->mnt_sb, | 209 | data_left, fileid_type, |
216 | datap, data_left, | 210 | nfsd_acceptable, exp); |
217 | fileid_type, | ||
218 | nfsd_acceptable, exp); | ||
219 | } | 211 | } |
220 | if (dentry == NULL) | 212 | if (dentry == NULL) |
221 | goto out; | 213 | goto out; |
@@ -257,8 +249,19 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) | |||
257 | if (error) | 249 | if (error) |
258 | goto out; | 250 | goto out; |
259 | 251 | ||
252 | if (!(access & MAY_LOCK)) { | ||
253 | /* | ||
254 | * pseudoflavor restrictions are not enforced on NLM, | ||
255 | * which clients virtually always use auth_sys for, | ||
256 | * even while using RPCSEC_GSS for NFS. | ||
257 | */ | ||
258 | error = check_nfsd_access(exp, rqstp); | ||
259 | if (error) | ||
260 | goto out; | ||
261 | } | ||
262 | |||
260 | /* Finally, check access permissions. */ | 263 | /* Finally, check access permissions. */ |
261 | error = nfsd_permission(exp, dentry, access); | 264 | error = nfsd_permission(rqstp, exp, dentry, access); |
262 | 265 | ||
263 | if (error) { | 266 | if (error) { |
264 | dprintk("fh_verify: %s/%s permission failure, " | 267 | dprintk("fh_verify: %s/%s permission failure, " |
@@ -286,15 +289,13 @@ out: | |||
286 | static inline int _fh_update(struct dentry *dentry, struct svc_export *exp, | 289 | static inline int _fh_update(struct dentry *dentry, struct svc_export *exp, |
287 | __u32 *datap, int *maxsize) | 290 | __u32 *datap, int *maxsize) |
288 | { | 291 | { |
289 | struct export_operations *nop = exp->ex_mnt->mnt_sb->s_export_op; | ||
290 | |||
291 | if (dentry == exp->ex_dentry) { | 292 | if (dentry == exp->ex_dentry) { |
292 | *maxsize = 0; | 293 | *maxsize = 0; |
293 | return 0; | 294 | return 0; |
294 | } | 295 | } |
295 | 296 | ||
296 | return CALL(nop,encode_fh)(dentry, datap, maxsize, | 297 | return exportfs_encode_fh(dentry, datap, maxsize, |
297 | !(exp->ex_flags&NFSEXP_NOSUBTREECHECK)); | 298 | !(exp->ex_flags & NFSEXP_NOSUBTREECHECK)); |
298 | } | 299 | } |
299 | 300 | ||
300 | /* | 301 | /* |
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index b2c7147aa921..977a71f64e19 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c | |||
@@ -278,7 +278,8 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, | |||
278 | * echo thing > device-special-file-or-pipe | 278 | * echo thing > device-special-file-or-pipe |
279 | * by doing a CREATE with type==0 | 279 | * by doing a CREATE with type==0 |
280 | */ | 280 | */ |
281 | nfserr = nfsd_permission(newfhp->fh_export, | 281 | nfserr = nfsd_permission(rqstp, |
282 | newfhp->fh_export, | ||
282 | newfhp->fh_dentry, | 283 | newfhp->fh_dentry, |
283 | MAY_WRITE|MAY_LOCAL_ACCESS); | 284 | MAY_WRITE|MAY_LOCAL_ACCESS); |
284 | if (nfserr && nfserr != nfserr_rofs) | 285 | if (nfserr && nfserr != nfserr_rofs) |
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index ff55950efb43..a8c89ae4c743 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/smp.h> | 20 | #include <linux/smp.h> |
21 | #include <linux/smp_lock.h> | 21 | #include <linux/smp_lock.h> |
22 | #include <linux/freezer.h> | ||
22 | #include <linux/fs_struct.h> | 23 | #include <linux/fs_struct.h> |
23 | 24 | ||
24 | #include <linux/sunrpc/types.h> | 25 | #include <linux/sunrpc/types.h> |
@@ -432,6 +433,7 @@ nfsd(struct svc_rqst *rqstp) | |||
432 | * dirty pages. | 433 | * dirty pages. |
433 | */ | 434 | */ |
434 | current->flags |= PF_LESS_THROTTLE; | 435 | current->flags |= PF_LESS_THROTTLE; |
436 | set_freezable(); | ||
435 | 437 | ||
436 | /* | 438 | /* |
437 | * The main request loop | 439 | * The main request loop |
@@ -492,6 +494,15 @@ out: | |||
492 | module_put_and_exit(0); | 494 | module_put_and_exit(0); |
493 | } | 495 | } |
494 | 496 | ||
497 | static __be32 map_new_errors(u32 vers, __be32 nfserr) | ||
498 | { | ||
499 | if (nfserr == nfserr_jukebox && vers == 2) | ||
500 | return nfserr_dropit; | ||
501 | if (nfserr == nfserr_wrongsec && vers < 4) | ||
502 | return nfserr_acces; | ||
503 | return nfserr; | ||
504 | } | ||
505 | |||
495 | int | 506 | int |
496 | nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) | 507 | nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) |
497 | { | 508 | { |
@@ -534,6 +545,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) | |||
534 | 545 | ||
535 | /* Now call the procedure handler, and encode NFS status. */ | 546 | /* Now call the procedure handler, and encode NFS status. */ |
536 | nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); | 547 | nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp); |
548 | nfserr = map_new_errors(rqstp->rq_vers, nfserr); | ||
537 | if (nfserr == nfserr_jukebox && rqstp->rq_vers == 2) | 549 | if (nfserr == nfserr_jukebox && rqstp->rq_vers == 2) |
538 | nfserr = nfserr_dropit; | 550 | nfserr = nfserr_dropit; |
539 | if (nfserr == nfserr_dropit) { | 551 | if (nfserr == nfserr_dropit) { |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 945b1cedde2b..e90f4a8a1d01 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -113,7 +113,7 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, | |||
113 | 113 | ||
114 | while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts)); | 114 | while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts)); |
115 | 115 | ||
116 | exp2 = exp_get_by_name(exp->ex_client, mnt, mounts, &rqstp->rq_chandle); | 116 | exp2 = rqst_exp_get_by_name(rqstp, mnt, mounts); |
117 | if (IS_ERR(exp2)) { | 117 | if (IS_ERR(exp2)) { |
118 | err = PTR_ERR(exp2); | 118 | err = PTR_ERR(exp2); |
119 | dput(mounts); | 119 | dput(mounts); |
@@ -135,21 +135,10 @@ out: | |||
135 | return err; | 135 | return err; |
136 | } | 136 | } |
137 | 137 | ||
138 | /* | ||
139 | * Look up one component of a pathname. | ||
140 | * N.B. After this call _both_ fhp and resfh need an fh_put | ||
141 | * | ||
142 | * If the lookup would cross a mountpoint, and the mounted filesystem | ||
143 | * is exported to the client with NFSEXP_NOHIDE, then the lookup is | ||
144 | * accepted as it stands and the mounted directory is | ||
145 | * returned. Otherwise the covered directory is returned. | ||
146 | * NOTE: this mountpoint crossing is not supported properly by all | ||
147 | * clients and is explicitly disallowed for NFSv3 | ||
148 | * NeilBrown <neilb@cse.unsw.edu.au> | ||
149 | */ | ||
150 | __be32 | 138 | __be32 |
151 | nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, | 139 | nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, |
152 | int len, struct svc_fh *resfh) | 140 | const char *name, int len, |
141 | struct svc_export **exp_ret, struct dentry **dentry_ret) | ||
153 | { | 142 | { |
154 | struct svc_export *exp; | 143 | struct svc_export *exp; |
155 | struct dentry *dparent; | 144 | struct dentry *dparent; |
@@ -168,8 +157,6 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, | |||
168 | exp = fhp->fh_export; | 157 | exp = fhp->fh_export; |
169 | exp_get(exp); | 158 | exp_get(exp); |
170 | 159 | ||
171 | err = nfserr_acces; | ||
172 | |||
173 | /* Lookup the name, but don't follow links */ | 160 | /* Lookup the name, but don't follow links */ |
174 | if (isdotent(name, len)) { | 161 | if (isdotent(name, len)) { |
175 | if (len==1) | 162 | if (len==1) |
@@ -190,17 +177,15 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, | |||
190 | dput(dentry); | 177 | dput(dentry); |
191 | dentry = dp; | 178 | dentry = dp; |
192 | 179 | ||
193 | exp2 = exp_parent(exp->ex_client, mnt, dentry, | 180 | exp2 = rqst_exp_parent(rqstp, mnt, dentry); |
194 | &rqstp->rq_chandle); | 181 | if (PTR_ERR(exp2) == -ENOENT) { |
195 | if (IS_ERR(exp2)) { | 182 | dput(dentry); |
183 | dentry = dget(dparent); | ||
184 | } else if (IS_ERR(exp2)) { | ||
196 | host_err = PTR_ERR(exp2); | 185 | host_err = PTR_ERR(exp2); |
197 | dput(dentry); | 186 | dput(dentry); |
198 | mntput(mnt); | 187 | mntput(mnt); |
199 | goto out_nfserr; | 188 | goto out_nfserr; |
200 | } | ||
201 | if (!exp2) { | ||
202 | dput(dentry); | ||
203 | dentry = dget(dparent); | ||
204 | } else { | 189 | } else { |
205 | exp_put(exp); | 190 | exp_put(exp); |
206 | exp = exp2; | 191 | exp = exp2; |
@@ -223,6 +208,41 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, | |||
223 | } | 208 | } |
224 | } | 209 | } |
225 | } | 210 | } |
211 | *dentry_ret = dentry; | ||
212 | *exp_ret = exp; | ||
213 | return 0; | ||
214 | |||
215 | out_nfserr: | ||
216 | exp_put(exp); | ||
217 | return nfserrno(host_err); | ||
218 | } | ||
219 | |||
220 | /* | ||
221 | * Look up one component of a pathname. | ||
222 | * N.B. After this call _both_ fhp and resfh need an fh_put | ||
223 | * | ||
224 | * If the lookup would cross a mountpoint, and the mounted filesystem | ||
225 | * is exported to the client with NFSEXP_NOHIDE, then the lookup is | ||
226 | * accepted as it stands and the mounted directory is | ||
227 | * returned. Otherwise the covered directory is returned. | ||
228 | * NOTE: this mountpoint crossing is not supported properly by all | ||
229 | * clients and is explicitly disallowed for NFSv3 | ||
230 | * NeilBrown <neilb@cse.unsw.edu.au> | ||
231 | */ | ||
232 | __be32 | ||
233 | nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, | ||
234 | int len, struct svc_fh *resfh) | ||
235 | { | ||
236 | struct svc_export *exp; | ||
237 | struct dentry *dentry; | ||
238 | __be32 err; | ||
239 | |||
240 | err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &dentry); | ||
241 | if (err) | ||
242 | return err; | ||
243 | err = check_nfsd_access(exp, rqstp); | ||
244 | if (err) | ||
245 | goto out; | ||
226 | /* | 246 | /* |
227 | * Note: we compose the file handle now, but as the | 247 | * Note: we compose the file handle now, but as the |
228 | * dentry may be negative, it may need to be updated. | 248 | * dentry may be negative, it may need to be updated. |
@@ -230,16 +250,13 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, | |||
230 | err = fh_compose(resfh, exp, dentry, fhp); | 250 | err = fh_compose(resfh, exp, dentry, fhp); |
231 | if (!err && !dentry->d_inode) | 251 | if (!err && !dentry->d_inode) |
232 | err = nfserr_noent; | 252 | err = nfserr_noent; |
233 | dput(dentry); | ||
234 | out: | 253 | out: |
254 | dput(dentry); | ||
235 | exp_put(exp); | 255 | exp_put(exp); |
236 | return err; | 256 | return err; |
237 | |||
238 | out_nfserr: | ||
239 | err = nfserrno(host_err); | ||
240 | goto out; | ||
241 | } | 257 | } |
242 | 258 | ||
259 | |||
243 | /* | 260 | /* |
244 | * Set various file attributes. | 261 | * Set various file attributes. |
245 | * N.B. After this call fhp needs an fh_put | 262 | * N.B. After this call fhp needs an fh_put |
@@ -311,7 +328,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
311 | /* The size case is special. It changes the file as well as the attributes. */ | 328 | /* The size case is special. It changes the file as well as the attributes. */ |
312 | if (iap->ia_valid & ATTR_SIZE) { | 329 | if (iap->ia_valid & ATTR_SIZE) { |
313 | if (iap->ia_size < inode->i_size) { | 330 | if (iap->ia_size < inode->i_size) { |
314 | err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE); | 331 | err = nfsd_permission(rqstp, fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE); |
315 | if (err) | 332 | if (err) |
316 | goto out; | 333 | goto out; |
317 | } | 334 | } |
@@ -435,7 +452,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
435 | /* Get inode */ | 452 | /* Get inode */ |
436 | error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, MAY_SATTR); | 453 | error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, MAY_SATTR); |
437 | if (error) | 454 | if (error) |
438 | goto out; | 455 | return error; |
439 | 456 | ||
440 | dentry = fhp->fh_dentry; | 457 | dentry = fhp->fh_dentry; |
441 | inode = dentry->d_inode; | 458 | inode = dentry->d_inode; |
@@ -444,33 +461,25 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
444 | 461 | ||
445 | host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); | 462 | host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); |
446 | if (host_error == -EINVAL) { | 463 | if (host_error == -EINVAL) { |
447 | error = nfserr_attrnotsupp; | 464 | return nfserr_attrnotsupp; |
448 | goto out; | ||
449 | } else if (host_error < 0) | 465 | } else if (host_error < 0) |
450 | goto out_nfserr; | 466 | goto out_nfserr; |
451 | 467 | ||
452 | host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); | 468 | host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS); |
453 | if (host_error < 0) | 469 | if (host_error < 0) |
454 | goto out_nfserr; | 470 | goto out_release; |
455 | 471 | ||
456 | if (S_ISDIR(inode->i_mode)) { | 472 | if (S_ISDIR(inode->i_mode)) |
457 | host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); | 473 | host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT); |
458 | if (host_error < 0) | ||
459 | goto out_nfserr; | ||
460 | } | ||
461 | |||
462 | error = nfs_ok; | ||
463 | 474 | ||
464 | out: | 475 | out_release: |
465 | posix_acl_release(pacl); | 476 | posix_acl_release(pacl); |
466 | posix_acl_release(dpacl); | 477 | posix_acl_release(dpacl); |
467 | return (error); | ||
468 | out_nfserr: | 478 | out_nfserr: |
469 | if (host_error == -EOPNOTSUPP) | 479 | if (host_error == -EOPNOTSUPP) |
470 | error = nfserr_attrnotsupp; | 480 | return nfserr_attrnotsupp; |
471 | else | 481 | else |
472 | error = nfserrno(host_error); | 482 | return nfserrno(host_error); |
473 | goto out; | ||
474 | } | 483 | } |
475 | 484 | ||
476 | static struct posix_acl * | 485 | static struct posix_acl * |
@@ -607,7 +616,7 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor | |||
607 | 616 | ||
608 | sresult |= map->access; | 617 | sresult |= map->access; |
609 | 618 | ||
610 | err2 = nfsd_permission(export, dentry, map->how); | 619 | err2 = nfsd_permission(rqstp, export, dentry, map->how); |
611 | switch (err2) { | 620 | switch (err2) { |
612 | case nfs_ok: | 621 | case nfs_ok: |
613 | result |= map->access; | 622 | result |= map->access; |
@@ -1034,7 +1043,7 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
1034 | __be32 err; | 1043 | __be32 err; |
1035 | 1044 | ||
1036 | if (file) { | 1045 | if (file) { |
1037 | err = nfsd_permission(fhp->fh_export, fhp->fh_dentry, | 1046 | err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, |
1038 | MAY_READ|MAY_OWNER_OVERRIDE); | 1047 | MAY_READ|MAY_OWNER_OVERRIDE); |
1039 | if (err) | 1048 | if (err) |
1040 | goto out; | 1049 | goto out; |
@@ -1063,7 +1072,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
1063 | __be32 err = 0; | 1072 | __be32 err = 0; |
1064 | 1073 | ||
1065 | if (file) { | 1074 | if (file) { |
1066 | err = nfsd_permission(fhp->fh_export, fhp->fh_dentry, | 1075 | err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, |
1067 | MAY_WRITE|MAY_OWNER_OVERRIDE); | 1076 | MAY_WRITE|MAY_OWNER_OVERRIDE); |
1068 | if (err) | 1077 | if (err) |
1069 | goto out; | 1078 | goto out; |
@@ -1792,7 +1801,8 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat) | |||
1792 | * Check for a user's access permissions to this inode. | 1801 | * Check for a user's access permissions to this inode. |
1793 | */ | 1802 | */ |
1794 | __be32 | 1803 | __be32 |
1795 | nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc) | 1804 | nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, |
1805 | struct dentry *dentry, int acc) | ||
1796 | { | 1806 | { |
1797 | struct inode *inode = dentry->d_inode; | 1807 | struct inode *inode = dentry->d_inode; |
1798 | int err; | 1808 | int err; |
@@ -1823,7 +1833,7 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc) | |||
1823 | */ | 1833 | */ |
1824 | if (!(acc & MAY_LOCAL_ACCESS)) | 1834 | if (!(acc & MAY_LOCAL_ACCESS)) |
1825 | if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) { | 1835 | if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) { |
1826 | if (EX_RDONLY(exp) || IS_RDONLY(inode)) | 1836 | if (EX_RDONLY(exp, rqstp) || IS_RDONLY(inode)) |
1827 | return nfserr_rofs; | 1837 | return nfserr_rofs; |
1828 | if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode)) | 1838 | if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode)) |
1829 | return nfserr_perm; | 1839 | return nfserr_perm; |
diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c index bff01a54675a..e93c6142b23c 100644 --- a/fs/ntfs/namei.c +++ b/fs/ntfs/namei.c | |||
@@ -21,6 +21,7 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/dcache.h> | 23 | #include <linux/dcache.h> |
24 | #include <linux/exportfs.h> | ||
24 | #include <linux/security.h> | 25 | #include <linux/security.h> |
25 | 26 | ||
26 | #include "attrib.h" | 27 | #include "attrib.h" |
diff --git a/fs/ocfs2/export.h b/fs/ocfs2/export.h index 5b77ee7866ef..e08bed9e45a0 100644 --- a/fs/ocfs2/export.h +++ b/fs/ocfs2/export.h | |||
@@ -26,6 +26,8 @@ | |||
26 | #ifndef OCFS2_EXPORT_H | 26 | #ifndef OCFS2_EXPORT_H |
27 | #define OCFS2_EXPORT_H | 27 | #define OCFS2_EXPORT_H |
28 | 28 | ||
29 | #include <linux/exportfs.h> | ||
30 | |||
29 | extern struct export_operations ocfs2_export_ops; | 31 | extern struct export_operations ocfs2_export_ops; |
30 | 32 | ||
31 | #endif /* OCFS2_EXPORT_H */ | 33 | #endif /* OCFS2_EXPORT_H */ |
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index f04c7aa834cb..004c2abbc732 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -1867,7 +1867,8 @@ static ssize_t ocfs2_file_buffered_write(struct file *file, loff_t *ppos, | |||
1867 | loff_t pos; | 1867 | loff_t pos; |
1868 | const struct iovec *cur_iov = iov; | 1868 | const struct iovec *cur_iov = iov; |
1869 | struct page *user_page, *page; | 1869 | struct page *user_page, *page; |
1870 | char *buf, *dst; | 1870 | char * uninitialized_var(buf); |
1871 | char *dst; | ||
1871 | void *fsdata; | 1872 | void *fsdata; |
1872 | 1873 | ||
1873 | /* | 1874 | /* |
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c index bd68c3f2afbe..87dcece7e1b5 100644 --- a/fs/ocfs2/ioctl.c +++ b/fs/ocfs2/ioctl.c | |||
@@ -63,7 +63,7 @@ static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags, | |||
63 | goto bail_unlock; | 63 | goto bail_unlock; |
64 | 64 | ||
65 | status = -EACCES; | 65 | status = -EACCES; |
66 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 66 | if (!is_owner_or_cap(inode)) |
67 | goto bail_unlock; | 67 | goto bail_unlock; |
68 | 68 | ||
69 | if (!S_ISDIR(inode->i_mode)) | 69 | if (!S_ISDIR(inode->i_mode)) |
diff --git a/fs/proc/base.c b/fs/proc/base.c index ae3627337a92..42cb4f5613b6 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -283,7 +283,7 @@ static int proc_pid_auxv(struct task_struct *task, char *buffer) | |||
283 | static int proc_pid_wchan(struct task_struct *task, char *buffer) | 283 | static int proc_pid_wchan(struct task_struct *task, char *buffer) |
284 | { | 284 | { |
285 | unsigned long wchan; | 285 | unsigned long wchan; |
286 | char symname[KSYM_NAME_LEN+1]; | 286 | char symname[KSYM_NAME_LEN]; |
287 | 287 | ||
288 | wchan = get_wchan(task); | 288 | wchan = get_wchan(task); |
289 | 289 | ||
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index d40d22b347b7..ef2b46d099ff 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c | |||
@@ -60,6 +60,7 @@ struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev) | |||
60 | inode->i_blocks = 0; | 60 | inode->i_blocks = 0; |
61 | inode->i_mapping->a_ops = &ramfs_aops; | 61 | inode->i_mapping->a_ops = &ramfs_aops; |
62 | inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info; | 62 | inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info; |
63 | mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER); | ||
63 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 64 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
64 | switch (mode & S_IFMT) { | 65 | switch (mode & S_IFMT) { |
65 | default: | 66 | default: |
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 1272d11399fb..ddde489f1cb2 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c | |||
@@ -7,6 +7,7 @@ | |||
7 | #include <linux/reiserfs_fs.h> | 7 | #include <linux/reiserfs_fs.h> |
8 | #include <linux/reiserfs_acl.h> | 8 | #include <linux/reiserfs_acl.h> |
9 | #include <linux/reiserfs_xattr.h> | 9 | #include <linux/reiserfs_xattr.h> |
10 | #include <linux/exportfs.h> | ||
10 | #include <linux/smp_lock.h> | 11 | #include <linux/smp_lock.h> |
11 | #include <linux/pagemap.h> | 12 | #include <linux/pagemap.h> |
12 | #include <linux/highmem.h> | 13 | #include <linux/highmem.h> |
diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c index b484d2913c0d..11a0fcc2d402 100644 --- a/fs/reiserfs/ioctl.c +++ b/fs/reiserfs/ioctl.c | |||
@@ -51,8 +51,7 @@ int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | |||
51 | if (IS_RDONLY(inode)) | 51 | if (IS_RDONLY(inode)) |
52 | return -EROFS; | 52 | return -EROFS; |
53 | 53 | ||
54 | if ((current->fsuid != inode->i_uid) | 54 | if (!is_owner_or_cap(inode)) |
55 | && !capable(CAP_FOWNER)) | ||
56 | return -EPERM; | 55 | return -EPERM; |
57 | 56 | ||
58 | if (get_user(flags, (int __user *)arg)) | 57 | if (get_user(flags, (int __user *)arg)) |
@@ -81,7 +80,7 @@ int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | |||
81 | case REISERFS_IOC_GETVERSION: | 80 | case REISERFS_IOC_GETVERSION: |
82 | return put_user(inode->i_generation, (int __user *)arg); | 81 | return put_user(inode->i_generation, (int __user *)arg); |
83 | case REISERFS_IOC_SETVERSION: | 82 | case REISERFS_IOC_SETVERSION: |
84 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 83 | if (!is_owner_or_cap(inode)) |
85 | return -EPERM; | 84 | return -EPERM; |
86 | if (IS_RDONLY(inode)) | 85 | if (IS_RDONLY(inode)) |
87 | return -EROFS; | 86 | return -EROFS; |
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index b4ac9119200e..5a93cfe1a032 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/blkdev.h> | 22 | #include <linux/blkdev.h> |
23 | #include <linux/buffer_head.h> | 23 | #include <linux/buffer_head.h> |
24 | #include <linux/exportfs.h> | ||
24 | #include <linux/vfs.h> | 25 | #include <linux/vfs.h> |
25 | #include <linux/mnt_namespace.h> | 26 | #include <linux/mnt_namespace.h> |
26 | #include <linux/mount.h> | 27 | #include <linux/mount.h> |
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c index 5296a29cc5eb..b7e4fa4539de 100644 --- a/fs/reiserfs/xattr_acl.c +++ b/fs/reiserfs/xattr_acl.c | |||
@@ -21,7 +21,7 @@ xattr_set_acl(struct inode *inode, int type, const void *value, size_t size) | |||
21 | 21 | ||
22 | if (!reiserfs_posixacl(inode->i_sb)) | 22 | if (!reiserfs_posixacl(inode->i_sb)) |
23 | return -EOPNOTSUPP; | 23 | return -EOPNOTSUPP; |
24 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | 24 | if (!is_owner_or_cap(inode)) |
25 | return -EPERM; | 25 | return -EPERM; |
26 | 26 | ||
27 | if (value) { | 27 | if (value) { |
diff --git a/fs/udf/super.c b/fs/udf/super.c index 6658afb41cc7..d6a504f5d758 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c | |||
@@ -1356,7 +1356,7 @@ udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) | |||
1356 | case UDF_VIRTUAL_MAP15: | 1356 | case UDF_VIRTUAL_MAP15: |
1357 | case UDF_VIRTUAL_MAP20: | 1357 | case UDF_VIRTUAL_MAP20: |
1358 | { | 1358 | { |
1359 | kernel_lb_addr ino; | 1359 | kernel_lb_addr uninitialized_var(ino); |
1360 | 1360 | ||
1361 | if (!UDF_SB_LASTBLOCK(sb)) | 1361 | if (!UDF_SB_LASTBLOCK(sb)) |
1362 | { | 1362 | { |
diff --git a/fs/utimes.c b/fs/utimes.c index 83a7e69e706c..682eb63b20ad 100644 --- a/fs/utimes.c +++ b/fs/utimes.c | |||
@@ -106,7 +106,7 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags | |||
106 | if (IS_IMMUTABLE(inode)) | 106 | if (IS_IMMUTABLE(inode)) |
107 | goto dput_and_out; | 107 | goto dput_and_out; |
108 | 108 | ||
109 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) { | 109 | if (!is_owner_or_cap(inode)) { |
110 | if (f) { | 110 | if (f) { |
111 | if (!(f->f_mode & FMODE_WRITE)) | 111 | if (!(f->f_mode & FMODE_WRITE)) |
112 | goto dput_and_out; | 112 | goto dput_and_out; |
diff --git a/fs/xattr.c b/fs/xattr.c index 4523aca79659..a44fd92caca3 100644 --- a/fs/xattr.c +++ b/fs/xattr.c | |||
@@ -60,8 +60,7 @@ xattr_permission(struct inode *inode, const char *name, int mask) | |||
60 | if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) | 60 | if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) |
61 | return -EPERM; | 61 | return -EPERM; |
62 | if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) && | 62 | if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) && |
63 | (mask & MAY_WRITE) && (current->fsuid != inode->i_uid) && | 63 | (mask & MAY_WRITE) && !is_owner_or_cap(inode)) |
64 | !capable(CAP_FOWNER)) | ||
65 | return -EPERM; | 64 | return -EPERM; |
66 | } | 65 | } |
67 | 66 | ||
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 2df63622354e..b0f0e58866de 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c | |||
@@ -35,10 +35,13 @@ | |||
35 | #include <linux/freezer.h> | 35 | #include <linux/freezer.h> |
36 | 36 | ||
37 | static kmem_zone_t *xfs_buf_zone; | 37 | static kmem_zone_t *xfs_buf_zone; |
38 | static struct shrinker *xfs_buf_shake; | ||
39 | STATIC int xfsbufd(void *); | 38 | STATIC int xfsbufd(void *); |
40 | STATIC int xfsbufd_wakeup(int, gfp_t); | 39 | STATIC int xfsbufd_wakeup(int, gfp_t); |
41 | STATIC void xfs_buf_delwri_queue(xfs_buf_t *, int); | 40 | STATIC void xfs_buf_delwri_queue(xfs_buf_t *, int); |
41 | static struct shrinker xfs_buf_shake = { | ||
42 | .shrink = xfsbufd_wakeup, | ||
43 | .seeks = DEFAULT_SEEKS, | ||
44 | }; | ||
42 | 45 | ||
43 | static struct workqueue_struct *xfslogd_workqueue; | 46 | static struct workqueue_struct *xfslogd_workqueue; |
44 | struct workqueue_struct *xfsdatad_workqueue; | 47 | struct workqueue_struct *xfsdatad_workqueue; |
@@ -1832,14 +1835,9 @@ xfs_buf_init(void) | |||
1832 | if (!xfsdatad_workqueue) | 1835 | if (!xfsdatad_workqueue) |
1833 | goto out_destroy_xfslogd_workqueue; | 1836 | goto out_destroy_xfslogd_workqueue; |
1834 | 1837 | ||
1835 | xfs_buf_shake = set_shrinker(DEFAULT_SEEKS, xfsbufd_wakeup); | 1838 | register_shrinker(&xfs_buf_shake); |
1836 | if (!xfs_buf_shake) | ||
1837 | goto out_destroy_xfsdatad_workqueue; | ||
1838 | |||
1839 | return 0; | 1839 | return 0; |
1840 | 1840 | ||
1841 | out_destroy_xfsdatad_workqueue: | ||
1842 | destroy_workqueue(xfsdatad_workqueue); | ||
1843 | out_destroy_xfslogd_workqueue: | 1841 | out_destroy_xfslogd_workqueue: |
1844 | destroy_workqueue(xfslogd_workqueue); | 1842 | destroy_workqueue(xfslogd_workqueue); |
1845 | out_free_buf_zone: | 1843 | out_free_buf_zone: |
@@ -1854,7 +1852,7 @@ xfs_buf_init(void) | |||
1854 | void | 1852 | void |
1855 | xfs_buf_terminate(void) | 1853 | xfs_buf_terminate(void) |
1856 | { | 1854 | { |
1857 | remove_shrinker(xfs_buf_shake); | 1855 | unregister_shrinker(&xfs_buf_shake); |
1858 | destroy_workqueue(xfsdatad_workqueue); | 1856 | destroy_workqueue(xfsdatad_workqueue); |
1859 | destroy_workqueue(xfslogd_workqueue); | 1857 | destroy_workqueue(xfslogd_workqueue); |
1860 | kmem_zone_destroy(xfs_buf_zone); | 1858 | kmem_zone_destroy(xfs_buf_zone); |
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 06894cf00b12..4528f9a3f304 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c | |||
@@ -562,6 +562,7 @@ xfssyncd( | |||
562 | bhv_vfs_sync_work_t *work, *n; | 562 | bhv_vfs_sync_work_t *work, *n; |
563 | LIST_HEAD (tmp); | 563 | LIST_HEAD (tmp); |
564 | 564 | ||
565 | set_freezable(); | ||
565 | timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10); | 566 | timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10); |
566 | for (;;) { | 567 | for (;;) { |
567 | timeleft = schedule_timeout_interruptible(timeleft); | 568 | timeleft = schedule_timeout_interruptible(timeleft); |
diff --git a/fs/xfs/linux-2.6/xfs_super.h b/fs/xfs/linux-2.6/xfs_super.h index 33dd1ca13245..201cc3273c84 100644 --- a/fs/xfs/linux-2.6/xfs_super.h +++ b/fs/xfs/linux-2.6/xfs_super.h | |||
@@ -18,6 +18,8 @@ | |||
18 | #ifndef __XFS_SUPER_H__ | 18 | #ifndef __XFS_SUPER_H__ |
19 | #define __XFS_SUPER_H__ | 19 | #define __XFS_SUPER_H__ |
20 | 20 | ||
21 | #include <linux/exportfs.h> | ||
22 | |||
21 | #ifdef CONFIG_XFS_DMAPI | 23 | #ifdef CONFIG_XFS_DMAPI |
22 | # define vfs_insertdmapi(vfs) vfs_insertops(vfsp, &xfs_dmops) | 24 | # define vfs_insertdmapi(vfs) vfs_insertops(vfsp, &xfs_dmops) |
23 | # define vfs_initdmapi() dmapi_init() | 25 | # define vfs_initdmapi() dmapi_init() |
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 7def4c699343..2d274b23ade5 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c | |||
@@ -62,7 +62,6 @@ uint ndquot; | |||
62 | 62 | ||
63 | kmem_zone_t *qm_dqzone; | 63 | kmem_zone_t *qm_dqzone; |
64 | kmem_zone_t *qm_dqtrxzone; | 64 | kmem_zone_t *qm_dqtrxzone; |
65 | static struct shrinker *xfs_qm_shaker; | ||
66 | 65 | ||
67 | static cred_t xfs_zerocr; | 66 | static cred_t xfs_zerocr; |
68 | 67 | ||
@@ -78,6 +77,11 @@ STATIC int xfs_qm_init_quotainos(xfs_mount_t *); | |||
78 | STATIC int xfs_qm_init_quotainfo(xfs_mount_t *); | 77 | STATIC int xfs_qm_init_quotainfo(xfs_mount_t *); |
79 | STATIC int xfs_qm_shake(int, gfp_t); | 78 | STATIC int xfs_qm_shake(int, gfp_t); |
80 | 79 | ||
80 | static struct shrinker xfs_qm_shaker = { | ||
81 | .shrink = xfs_qm_shake, | ||
82 | .seeks = DEFAULT_SEEKS, | ||
83 | }; | ||
84 | |||
81 | #ifdef DEBUG | 85 | #ifdef DEBUG |
82 | extern mutex_t qcheck_lock; | 86 | extern mutex_t qcheck_lock; |
83 | #endif | 87 | #endif |
@@ -149,7 +153,7 @@ xfs_Gqm_init(void) | |||
149 | } else | 153 | } else |
150 | xqm->qm_dqzone = qm_dqzone; | 154 | xqm->qm_dqzone = qm_dqzone; |
151 | 155 | ||
152 | xfs_qm_shaker = set_shrinker(DEFAULT_SEEKS, xfs_qm_shake); | 156 | register_shrinker(&xfs_qm_shaker); |
153 | 157 | ||
154 | /* | 158 | /* |
155 | * The t_dqinfo portion of transactions. | 159 | * The t_dqinfo portion of transactions. |
@@ -181,7 +185,7 @@ xfs_qm_destroy( | |||
181 | 185 | ||
182 | ASSERT(xqm != NULL); | 186 | ASSERT(xqm != NULL); |
183 | ASSERT(xqm->qm_nrefs == 0); | 187 | ASSERT(xqm->qm_nrefs == 0); |
184 | remove_shrinker(xfs_qm_shaker); | 188 | unregister_shrinker(&xfs_qm_shaker); |
185 | hsize = xqm->qm_dqhashmask + 1; | 189 | hsize = xqm->qm_dqhashmask + 1; |
186 | for (i = 0; i < hsize; i++) { | 190 | for (i = 0; i < hsize; i++) { |
187 | xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i])); | 191 | xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i])); |