diff options
Diffstat (limited to 'fs')
270 files changed, 6343 insertions, 3229 deletions
diff --git a/fs/9p/acl.c b/fs/9p/acl.c index 12d602351dbe..6e58c4ca1e6e 100644 --- a/fs/9p/acl.c +++ b/fs/9p/acl.c | |||
@@ -91,11 +91,14 @@ static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type) | |||
91 | return acl; | 91 | return acl; |
92 | } | 92 | } |
93 | 93 | ||
94 | int v9fs_check_acl(struct inode *inode, int mask) | 94 | int v9fs_check_acl(struct inode *inode, int mask, unsigned int flags) |
95 | { | 95 | { |
96 | struct posix_acl *acl; | 96 | struct posix_acl *acl; |
97 | struct v9fs_session_info *v9ses; | 97 | struct v9fs_session_info *v9ses; |
98 | 98 | ||
99 | if (flags & IPERM_FLAG_RCU) | ||
100 | return -ECHILD; | ||
101 | |||
99 | v9ses = v9fs_inode2v9ses(inode); | 102 | v9ses = v9fs_inode2v9ses(inode); |
100 | if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) { | 103 | if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) { |
101 | /* | 104 | /* |
diff --git a/fs/9p/acl.h b/fs/9p/acl.h index 59e18c2e8c7e..7ef3ac9f6d95 100644 --- a/fs/9p/acl.h +++ b/fs/9p/acl.h | |||
@@ -16,7 +16,7 @@ | |||
16 | 16 | ||
17 | #ifdef CONFIG_9P_FS_POSIX_ACL | 17 | #ifdef CONFIG_9P_FS_POSIX_ACL |
18 | extern int v9fs_get_acl(struct inode *, struct p9_fid *); | 18 | extern int v9fs_get_acl(struct inode *, struct p9_fid *); |
19 | extern int v9fs_check_acl(struct inode *inode, int mask); | 19 | extern int v9fs_check_acl(struct inode *inode, int mask, unsigned int flags); |
20 | extern int v9fs_acl_chmod(struct dentry *); | 20 | extern int v9fs_acl_chmod(struct dentry *); |
21 | extern int v9fs_set_create_acl(struct dentry *, | 21 | extern int v9fs_set_create_acl(struct dentry *, |
22 | struct posix_acl *, struct posix_acl *); | 22 | struct posix_acl *, struct posix_acl *); |
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index cbf4e50f3933..466d2a4fc5cb 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c | |||
@@ -51,7 +51,7 @@ | |||
51 | * | 51 | * |
52 | */ | 52 | */ |
53 | 53 | ||
54 | static int v9fs_dentry_delete(struct dentry *dentry) | 54 | static int v9fs_dentry_delete(const struct dentry *dentry) |
55 | { | 55 | { |
56 | P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_name.name, | 56 | P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_name.name, |
57 | dentry); | 57 | dentry); |
@@ -68,7 +68,7 @@ static int v9fs_dentry_delete(struct dentry *dentry) | |||
68 | * | 68 | * |
69 | */ | 69 | */ |
70 | 70 | ||
71 | static int v9fs_cached_dentry_delete(struct dentry *dentry) | 71 | static int v9fs_cached_dentry_delete(const struct dentry *dentry) |
72 | { | 72 | { |
73 | struct inode *inode = dentry->d_inode; | 73 | struct inode *inode = dentry->d_inode; |
74 | P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_name.name, | 74 | P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_name.name, |
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 34bf71b56542..59782981b225 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
@@ -237,10 +237,17 @@ struct inode *v9fs_alloc_inode(struct super_block *sb) | |||
237 | * | 237 | * |
238 | */ | 238 | */ |
239 | 239 | ||
240 | void v9fs_destroy_inode(struct inode *inode) | 240 | static void v9fs_i_callback(struct rcu_head *head) |
241 | { | 241 | { |
242 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
243 | INIT_LIST_HEAD(&inode->i_dentry); | ||
242 | kmem_cache_free(vcookie_cache, v9fs_inode2cookie(inode)); | 244 | kmem_cache_free(vcookie_cache, v9fs_inode2cookie(inode)); |
243 | } | 245 | } |
246 | |||
247 | void v9fs_destroy_inode(struct inode *inode) | ||
248 | { | ||
249 | call_rcu(&inode->i_rcu, v9fs_i_callback); | ||
250 | } | ||
244 | #endif | 251 | #endif |
245 | 252 | ||
246 | /** | 253 | /** |
@@ -270,11 +277,11 @@ static struct dentry *v9fs_dentry_from_dir_inode(struct inode *inode) | |||
270 | { | 277 | { |
271 | struct dentry *dentry; | 278 | struct dentry *dentry; |
272 | 279 | ||
273 | spin_lock(&dcache_lock); | 280 | spin_lock(&inode->i_lock); |
274 | /* Directory should have only one entry. */ | 281 | /* Directory should have only one entry. */ |
275 | BUG_ON(S_ISDIR(inode->i_mode) && !list_is_singular(&inode->i_dentry)); | 282 | BUG_ON(S_ISDIR(inode->i_mode) && !list_is_singular(&inode->i_dentry)); |
276 | dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias); | 283 | dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias); |
277 | spin_unlock(&dcache_lock); | 284 | spin_unlock(&inode->i_lock); |
278 | return dentry; | 285 | return dentry; |
279 | } | 286 | } |
280 | 287 | ||
@@ -628,9 +635,9 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, | |||
628 | } | 635 | } |
629 | 636 | ||
630 | if (v9ses->cache) | 637 | if (v9ses->cache) |
631 | dentry->d_op = &v9fs_cached_dentry_operations; | 638 | d_set_d_op(dentry, &v9fs_cached_dentry_operations); |
632 | else | 639 | else |
633 | dentry->d_op = &v9fs_dentry_operations; | 640 | d_set_d_op(dentry, &v9fs_dentry_operations); |
634 | 641 | ||
635 | d_instantiate(dentry, inode); | 642 | d_instantiate(dentry, inode); |
636 | err = v9fs_fid_add(dentry, fid); | 643 | err = v9fs_fid_add(dentry, fid); |
@@ -742,7 +749,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, | |||
742 | err); | 749 | err); |
743 | goto error; | 750 | goto error; |
744 | } | 751 | } |
745 | dentry->d_op = &v9fs_cached_dentry_operations; | 752 | d_set_d_op(dentry, &v9fs_cached_dentry_operations); |
746 | d_instantiate(dentry, inode); | 753 | d_instantiate(dentry, inode); |
747 | err = v9fs_fid_add(dentry, fid); | 754 | err = v9fs_fid_add(dentry, fid); |
748 | if (err < 0) | 755 | if (err < 0) |
@@ -760,7 +767,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, | |||
760 | err = PTR_ERR(inode); | 767 | err = PTR_ERR(inode); |
761 | goto error; | 768 | goto error; |
762 | } | 769 | } |
763 | dentry->d_op = &v9fs_dentry_operations; | 770 | d_set_d_op(dentry, &v9fs_dentry_operations); |
764 | d_instantiate(dentry, inode); | 771 | d_instantiate(dentry, inode); |
765 | } | 772 | } |
766 | /* Now set the ACL based on the default value */ | 773 | /* Now set the ACL based on the default value */ |
@@ -949,7 +956,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, | |||
949 | err); | 956 | err); |
950 | goto error; | 957 | goto error; |
951 | } | 958 | } |
952 | dentry->d_op = &v9fs_cached_dentry_operations; | 959 | d_set_d_op(dentry, &v9fs_cached_dentry_operations); |
953 | d_instantiate(dentry, inode); | 960 | d_instantiate(dentry, inode); |
954 | err = v9fs_fid_add(dentry, fid); | 961 | err = v9fs_fid_add(dentry, fid); |
955 | if (err < 0) | 962 | if (err < 0) |
@@ -966,7 +973,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, | |||
966 | err = PTR_ERR(inode); | 973 | err = PTR_ERR(inode); |
967 | goto error; | 974 | goto error; |
968 | } | 975 | } |
969 | dentry->d_op = &v9fs_dentry_operations; | 976 | d_set_d_op(dentry, &v9fs_dentry_operations); |
970 | d_instantiate(dentry, inode); | 977 | d_instantiate(dentry, inode); |
971 | } | 978 | } |
972 | /* Now set the ACL based on the default value */ | 979 | /* Now set the ACL based on the default value */ |
@@ -1034,9 +1041,9 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
1034 | 1041 | ||
1035 | inst_out: | 1042 | inst_out: |
1036 | if (v9ses->cache) | 1043 | if (v9ses->cache) |
1037 | dentry->d_op = &v9fs_cached_dentry_operations; | 1044 | d_set_d_op(dentry, &v9fs_cached_dentry_operations); |
1038 | else | 1045 | else |
1039 | dentry->d_op = &v9fs_dentry_operations; | 1046 | d_set_d_op(dentry, &v9fs_dentry_operations); |
1040 | 1047 | ||
1041 | d_add(dentry, inode); | 1048 | d_add(dentry, inode); |
1042 | return NULL; | 1049 | return NULL; |
@@ -1702,7 +1709,7 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry, | |||
1702 | err); | 1709 | err); |
1703 | goto error; | 1710 | goto error; |
1704 | } | 1711 | } |
1705 | dentry->d_op = &v9fs_cached_dentry_operations; | 1712 | d_set_d_op(dentry, &v9fs_cached_dentry_operations); |
1706 | d_instantiate(dentry, inode); | 1713 | d_instantiate(dentry, inode); |
1707 | err = v9fs_fid_add(dentry, fid); | 1714 | err = v9fs_fid_add(dentry, fid); |
1708 | if (err < 0) | 1715 | if (err < 0) |
@@ -1715,7 +1722,7 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry, | |||
1715 | err = PTR_ERR(inode); | 1722 | err = PTR_ERR(inode); |
1716 | goto error; | 1723 | goto error; |
1717 | } | 1724 | } |
1718 | dentry->d_op = &v9fs_dentry_operations; | 1725 | d_set_d_op(dentry, &v9fs_dentry_operations); |
1719 | d_instantiate(dentry, inode); | 1726 | d_instantiate(dentry, inode); |
1720 | } | 1727 | } |
1721 | 1728 | ||
@@ -1849,7 +1856,7 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir, | |||
1849 | ihold(old_dentry->d_inode); | 1856 | ihold(old_dentry->d_inode); |
1850 | } | 1857 | } |
1851 | 1858 | ||
1852 | dentry->d_op = old_dentry->d_op; | 1859 | d_set_d_op(dentry, old_dentry->d_op); |
1853 | d_instantiate(dentry, old_dentry->d_inode); | 1860 | d_instantiate(dentry, old_dentry->d_inode); |
1854 | 1861 | ||
1855 | return err; | 1862 | return err; |
@@ -1973,7 +1980,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode, | |||
1973 | err); | 1980 | err); |
1974 | goto error; | 1981 | goto error; |
1975 | } | 1982 | } |
1976 | dentry->d_op = &v9fs_cached_dentry_operations; | 1983 | d_set_d_op(dentry, &v9fs_cached_dentry_operations); |
1977 | d_instantiate(dentry, inode); | 1984 | d_instantiate(dentry, inode); |
1978 | err = v9fs_fid_add(dentry, fid); | 1985 | err = v9fs_fid_add(dentry, fid); |
1979 | if (err < 0) | 1986 | if (err < 0) |
@@ -1989,7 +1996,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode, | |||
1989 | err = PTR_ERR(inode); | 1996 | err = PTR_ERR(inode); |
1990 | goto error; | 1997 | goto error; |
1991 | } | 1998 | } |
1992 | dentry->d_op = &v9fs_dentry_operations; | 1999 | d_set_d_op(dentry, &v9fs_dentry_operations); |
1993 | d_instantiate(dentry, inode); | 2000 | d_instantiate(dentry, inode); |
1994 | } | 2001 | } |
1995 | /* Now set the ACL based on the default value */ | 2002 | /* Now set the ACL based on the default value */ |
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c index f4287e4de744..bf7693c384f9 100644 --- a/fs/adfs/dir.c +++ b/fs/adfs/dir.c | |||
@@ -201,7 +201,8 @@ const struct file_operations adfs_dir_operations = { | |||
201 | }; | 201 | }; |
202 | 202 | ||
203 | static int | 203 | static int |
204 | adfs_hash(struct dentry *parent, struct qstr *qstr) | 204 | adfs_hash(const struct dentry *parent, const struct inode *inode, |
205 | struct qstr *qstr) | ||
205 | { | 206 | { |
206 | const unsigned int name_len = ADFS_SB(parent->d_sb)->s_namelen; | 207 | const unsigned int name_len = ADFS_SB(parent->d_sb)->s_namelen; |
207 | const unsigned char *name; | 208 | const unsigned char *name; |
@@ -237,17 +238,19 @@ adfs_hash(struct dentry *parent, struct qstr *qstr) | |||
237 | * requirements of the underlying filesystem. | 238 | * requirements of the underlying filesystem. |
238 | */ | 239 | */ |
239 | static int | 240 | static int |
240 | adfs_compare(struct dentry *parent, struct qstr *entry, struct qstr *name) | 241 | adfs_compare(const struct dentry *parent, const struct inode *pinode, |
242 | const struct dentry *dentry, const struct inode *inode, | ||
243 | unsigned int len, const char *str, const struct qstr *name) | ||
241 | { | 244 | { |
242 | int i; | 245 | int i; |
243 | 246 | ||
244 | if (entry->len != name->len) | 247 | if (len != name->len) |
245 | return 1; | 248 | return 1; |
246 | 249 | ||
247 | for (i = 0; i < name->len; i++) { | 250 | for (i = 0; i < name->len; i++) { |
248 | char a, b; | 251 | char a, b; |
249 | 252 | ||
250 | a = entry->name[i]; | 253 | a = str[i]; |
251 | b = name->name[i]; | 254 | b = name->name[i]; |
252 | 255 | ||
253 | if (a >= 'A' && a <= 'Z') | 256 | if (a >= 'A' && a <= 'Z') |
@@ -273,7 +276,7 @@ adfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
273 | struct object_info obj; | 276 | struct object_info obj; |
274 | int error; | 277 | int error; |
275 | 278 | ||
276 | dentry->d_op = &adfs_dentry_operations; | 279 | d_set_d_op(dentry, &adfs_dentry_operations); |
277 | lock_kernel(); | 280 | lock_kernel(); |
278 | error = adfs_dir_lookup_byname(dir, &dentry->d_name, &obj); | 281 | error = adfs_dir_lookup_byname(dir, &dentry->d_name, &obj); |
279 | if (error == 0) { | 282 | if (error == 0) { |
diff --git a/fs/adfs/super.c b/fs/adfs/super.c index 959dbff2d42d..a4041b52fbca 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c | |||
@@ -240,11 +240,18 @@ static struct inode *adfs_alloc_inode(struct super_block *sb) | |||
240 | return &ei->vfs_inode; | 240 | return &ei->vfs_inode; |
241 | } | 241 | } |
242 | 242 | ||
243 | static void adfs_destroy_inode(struct inode *inode) | 243 | static void adfs_i_callback(struct rcu_head *head) |
244 | { | 244 | { |
245 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
246 | INIT_LIST_HEAD(&inode->i_dentry); | ||
245 | kmem_cache_free(adfs_inode_cachep, ADFS_I(inode)); | 247 | kmem_cache_free(adfs_inode_cachep, ADFS_I(inode)); |
246 | } | 248 | } |
247 | 249 | ||
250 | static void adfs_destroy_inode(struct inode *inode) | ||
251 | { | ||
252 | call_rcu(&inode->i_rcu, adfs_i_callback); | ||
253 | } | ||
254 | |||
248 | static void init_once(void *foo) | 255 | static void init_once(void *foo) |
249 | { | 256 | { |
250 | struct adfs_inode_info *ei = (struct adfs_inode_info *) foo; | 257 | struct adfs_inode_info *ei = (struct adfs_inode_info *) foo; |
@@ -477,7 +484,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) | |||
477 | adfs_error(sb, "get root inode failed\n"); | 484 | adfs_error(sb, "get root inode failed\n"); |
478 | goto error; | 485 | goto error; |
479 | } else | 486 | } else |
480 | sb->s_root->d_op = &adfs_dentry_operations; | 487 | d_set_d_op(sb->s_root, &adfs_dentry_operations); |
481 | unlock_kernel(); | 488 | unlock_kernel(); |
482 | return 0; | 489 | return 0; |
483 | 490 | ||
diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c index 7d0f0a30f7a3..3a4557e8325c 100644 --- a/fs/affs/amigaffs.c +++ b/fs/affs/amigaffs.c | |||
@@ -128,7 +128,7 @@ affs_fix_dcache(struct dentry *dentry, u32 entry_ino) | |||
128 | void *data = dentry->d_fsdata; | 128 | void *data = dentry->d_fsdata; |
129 | struct list_head *head, *next; | 129 | struct list_head *head, *next; |
130 | 130 | ||
131 | spin_lock(&dcache_lock); | 131 | spin_lock(&inode->i_lock); |
132 | head = &inode->i_dentry; | 132 | head = &inode->i_dentry; |
133 | next = head->next; | 133 | next = head->next; |
134 | while (next != head) { | 134 | while (next != head) { |
@@ -139,7 +139,7 @@ affs_fix_dcache(struct dentry *dentry, u32 entry_ino) | |||
139 | } | 139 | } |
140 | next = next->next; | 140 | next = next->next; |
141 | } | 141 | } |
142 | spin_unlock(&dcache_lock); | 142 | spin_unlock(&inode->i_lock); |
143 | } | 143 | } |
144 | 144 | ||
145 | 145 | ||
diff --git a/fs/affs/namei.c b/fs/affs/namei.c index 914d1c0bc07a..944a4042fb65 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c | |||
@@ -13,11 +13,19 @@ | |||
13 | typedef int (*toupper_t)(int); | 13 | typedef int (*toupper_t)(int); |
14 | 14 | ||
15 | static int affs_toupper(int ch); | 15 | static int affs_toupper(int ch); |
16 | static int affs_hash_dentry(struct dentry *, struct qstr *); | 16 | static int affs_hash_dentry(const struct dentry *, |
17 | static int affs_compare_dentry(struct dentry *, struct qstr *, struct qstr *); | 17 | const struct inode *, struct qstr *); |
18 | static int affs_compare_dentry(const struct dentry *parent, | ||
19 | const struct inode *pinode, | ||
20 | const struct dentry *dentry, const struct inode *inode, | ||
21 | unsigned int len, const char *str, const struct qstr *name); | ||
18 | static int affs_intl_toupper(int ch); | 22 | static int affs_intl_toupper(int ch); |
19 | static int affs_intl_hash_dentry(struct dentry *, struct qstr *); | 23 | static int affs_intl_hash_dentry(const struct dentry *, |
20 | static int affs_intl_compare_dentry(struct dentry *, struct qstr *, struct qstr *); | 24 | const struct inode *, struct qstr *); |
25 | static int affs_intl_compare_dentry(const struct dentry *parent, | ||
26 | const struct inode *pinode, | ||
27 | const struct dentry *dentry, const struct inode *inode, | ||
28 | unsigned int len, const char *str, const struct qstr *name); | ||
21 | 29 | ||
22 | const struct dentry_operations affs_dentry_operations = { | 30 | const struct dentry_operations affs_dentry_operations = { |
23 | .d_hash = affs_hash_dentry, | 31 | .d_hash = affs_hash_dentry, |
@@ -58,13 +66,13 @@ affs_get_toupper(struct super_block *sb) | |||
58 | * Note: the dentry argument is the parent dentry. | 66 | * Note: the dentry argument is the parent dentry. |
59 | */ | 67 | */ |
60 | static inline int | 68 | static inline int |
61 | __affs_hash_dentry(struct dentry *dentry, struct qstr *qstr, toupper_t toupper) | 69 | __affs_hash_dentry(struct qstr *qstr, toupper_t toupper) |
62 | { | 70 | { |
63 | const u8 *name = qstr->name; | 71 | const u8 *name = qstr->name; |
64 | unsigned long hash; | 72 | unsigned long hash; |
65 | int i; | 73 | int i; |
66 | 74 | ||
67 | i = affs_check_name(qstr->name,qstr->len); | 75 | i = affs_check_name(qstr->name, qstr->len); |
68 | if (i) | 76 | if (i) |
69 | return i; | 77 | return i; |
70 | 78 | ||
@@ -78,39 +86,41 @@ __affs_hash_dentry(struct dentry *dentry, struct qstr *qstr, toupper_t toupper) | |||
78 | } | 86 | } |
79 | 87 | ||
80 | static int | 88 | static int |
81 | affs_hash_dentry(struct dentry *dentry, struct qstr *qstr) | 89 | affs_hash_dentry(const struct dentry *dentry, const struct inode *inode, |
90 | struct qstr *qstr) | ||
82 | { | 91 | { |
83 | return __affs_hash_dentry(dentry, qstr, affs_toupper); | 92 | return __affs_hash_dentry(qstr, affs_toupper); |
84 | } | 93 | } |
85 | static int | 94 | static int |
86 | affs_intl_hash_dentry(struct dentry *dentry, struct qstr *qstr) | 95 | affs_intl_hash_dentry(const struct dentry *dentry, const struct inode *inode, |
96 | struct qstr *qstr) | ||
87 | { | 97 | { |
88 | return __affs_hash_dentry(dentry, qstr, affs_intl_toupper); | 98 | return __affs_hash_dentry(qstr, affs_intl_toupper); |
89 | } | 99 | } |
90 | 100 | ||
91 | static inline int | 101 | static inline int __affs_compare_dentry(unsigned int len, |
92 | __affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b, toupper_t toupper) | 102 | const char *str, const struct qstr *name, toupper_t toupper) |
93 | { | 103 | { |
94 | const u8 *aname = a->name; | 104 | const u8 *aname = str; |
95 | const u8 *bname = b->name; | 105 | const u8 *bname = name->name; |
96 | int len; | ||
97 | 106 | ||
98 | /* 'a' is the qstr of an already existing dentry, so the name | 107 | /* |
99 | * must be valid. 'b' must be validated first. | 108 | * 'str' is the name of an already existing dentry, so the name |
109 | * must be valid. 'name' must be validated first. | ||
100 | */ | 110 | */ |
101 | 111 | ||
102 | if (affs_check_name(b->name,b->len)) | 112 | if (affs_check_name(name->name, name->len)) |
103 | return 1; | 113 | return 1; |
104 | 114 | ||
105 | /* If the names are longer than the allowed 30 chars, | 115 | /* |
116 | * If the names are longer than the allowed 30 chars, | ||
106 | * the excess is ignored, so their length may differ. | 117 | * the excess is ignored, so their length may differ. |
107 | */ | 118 | */ |
108 | len = a->len; | ||
109 | if (len >= 30) { | 119 | if (len >= 30) { |
110 | if (b->len < 30) | 120 | if (name->len < 30) |
111 | return 1; | 121 | return 1; |
112 | len = 30; | 122 | len = 30; |
113 | } else if (len != b->len) | 123 | } else if (len != name->len) |
114 | return 1; | 124 | return 1; |
115 | 125 | ||
116 | for (; len > 0; len--) | 126 | for (; len > 0; len--) |
@@ -121,14 +131,18 @@ __affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b, tou | |||
121 | } | 131 | } |
122 | 132 | ||
123 | static int | 133 | static int |
124 | affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) | 134 | affs_compare_dentry(const struct dentry *parent, const struct inode *pinode, |
135 | const struct dentry *dentry, const struct inode *inode, | ||
136 | unsigned int len, const char *str, const struct qstr *name) | ||
125 | { | 137 | { |
126 | return __affs_compare_dentry(dentry, a, b, affs_toupper); | 138 | return __affs_compare_dentry(len, str, name, affs_toupper); |
127 | } | 139 | } |
128 | static int | 140 | static int |
129 | affs_intl_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) | 141 | affs_intl_compare_dentry(const struct dentry *parent,const struct inode *pinode, |
142 | const struct dentry *dentry, const struct inode *inode, | ||
143 | unsigned int len, const char *str, const struct qstr *name) | ||
130 | { | 144 | { |
131 | return __affs_compare_dentry(dentry, a, b, affs_intl_toupper); | 145 | return __affs_compare_dentry(len, str, name, affs_intl_toupper); |
132 | } | 146 | } |
133 | 147 | ||
134 | /* | 148 | /* |
@@ -226,7 +240,7 @@ affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | |||
226 | if (IS_ERR(inode)) | 240 | if (IS_ERR(inode)) |
227 | return ERR_CAST(inode); | 241 | return ERR_CAST(inode); |
228 | } | 242 | } |
229 | dentry->d_op = AFFS_SB(sb)->s_flags & SF_INTL ? &affs_intl_dentry_operations : &affs_dentry_operations; | 243 | d_set_d_op(dentry, AFFS_SB(sb)->s_flags & SF_INTL ? &affs_intl_dentry_operations : &affs_dentry_operations); |
230 | d_add(dentry, inode); | 244 | d_add(dentry, inode); |
231 | return NULL; | 245 | return NULL; |
232 | } | 246 | } |
diff --git a/fs/affs/super.c b/fs/affs/super.c index 0cf7f4384cbd..d39081bbe7ce 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c | |||
@@ -95,11 +95,18 @@ static struct inode *affs_alloc_inode(struct super_block *sb) | |||
95 | return &i->vfs_inode; | 95 | return &i->vfs_inode; |
96 | } | 96 | } |
97 | 97 | ||
98 | static void affs_destroy_inode(struct inode *inode) | 98 | static void affs_i_callback(struct rcu_head *head) |
99 | { | 99 | { |
100 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
101 | INIT_LIST_HEAD(&inode->i_dentry); | ||
100 | kmem_cache_free(affs_inode_cachep, AFFS_I(inode)); | 102 | kmem_cache_free(affs_inode_cachep, AFFS_I(inode)); |
101 | } | 103 | } |
102 | 104 | ||
105 | static void affs_destroy_inode(struct inode *inode) | ||
106 | { | ||
107 | call_rcu(&inode->i_rcu, affs_i_callback); | ||
108 | } | ||
109 | |||
103 | static void init_once(void *foo) | 110 | static void init_once(void *foo) |
104 | { | 111 | { |
105 | struct affs_inode_info *ei = (struct affs_inode_info *) foo; | 112 | struct affs_inode_info *ei = (struct affs_inode_info *) foo; |
@@ -475,7 +482,7 @@ got_root: | |||
475 | printk(KERN_ERR "AFFS: Get root inode failed\n"); | 482 | printk(KERN_ERR "AFFS: Get root inode failed\n"); |
476 | goto out_error; | 483 | goto out_error; |
477 | } | 484 | } |
478 | sb->s_root->d_op = &affs_dentry_operations; | 485 | d_set_d_op(sb->s_root, &affs_dentry_operations); |
479 | 486 | ||
480 | pr_debug("AFFS: s_flags=%lX\n",sb->s_flags); | 487 | pr_debug("AFFS: s_flags=%lX\n",sb->s_flags); |
481 | return 0; | 488 | return 0; |
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 5439e1bc9a86..34a3263d60a4 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/fs.h> | 15 | #include <linux/fs.h> |
16 | #include <linux/namei.h> | ||
16 | #include <linux/pagemap.h> | 17 | #include <linux/pagemap.h> |
17 | #include <linux/ctype.h> | 18 | #include <linux/ctype.h> |
18 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
@@ -23,7 +24,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, | |||
23 | static int afs_dir_open(struct inode *inode, struct file *file); | 24 | static int afs_dir_open(struct inode *inode, struct file *file); |
24 | static int afs_readdir(struct file *file, void *dirent, filldir_t filldir); | 25 | static int afs_readdir(struct file *file, void *dirent, filldir_t filldir); |
25 | static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd); | 26 | static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd); |
26 | static int afs_d_delete(struct dentry *dentry); | 27 | static int afs_d_delete(const struct dentry *dentry); |
27 | static void afs_d_release(struct dentry *dentry); | 28 | static void afs_d_release(struct dentry *dentry); |
28 | static int afs_lookup_filldir(void *_cookie, const char *name, int nlen, | 29 | static int afs_lookup_filldir(void *_cookie, const char *name, int nlen, |
29 | loff_t fpos, u64 ino, unsigned dtype); | 30 | loff_t fpos, u64 ino, unsigned dtype); |
@@ -581,7 +582,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, | |||
581 | } | 582 | } |
582 | 583 | ||
583 | success: | 584 | success: |
584 | dentry->d_op = &afs_fs_dentry_operations; | 585 | d_set_d_op(dentry, &afs_fs_dentry_operations); |
585 | 586 | ||
586 | d_add(dentry, inode); | 587 | d_add(dentry, inode); |
587 | _leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%llu }", | 588 | _leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%llu }", |
@@ -607,6 +608,9 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
607 | void *dir_version; | 608 | void *dir_version; |
608 | int ret; | 609 | int ret; |
609 | 610 | ||
611 | if (nd->flags & LOOKUP_RCU) | ||
612 | return -ECHILD; | ||
613 | |||
610 | vnode = AFS_FS_I(dentry->d_inode); | 614 | vnode = AFS_FS_I(dentry->d_inode); |
611 | 615 | ||
612 | if (dentry->d_inode) | 616 | if (dentry->d_inode) |
@@ -730,7 +734,7 @@ out_bad: | |||
730 | * - called from dput() when d_count is going to 0. | 734 | * - called from dput() when d_count is going to 0. |
731 | * - return 1 to request dentry be unhashed, 0 otherwise | 735 | * - return 1 to request dentry be unhashed, 0 otherwise |
732 | */ | 736 | */ |
733 | static int afs_d_delete(struct dentry *dentry) | 737 | static int afs_d_delete(const struct dentry *dentry) |
734 | { | 738 | { |
735 | _enter("%s", dentry->d_name.name); | 739 | _enter("%s", dentry->d_name.name); |
736 | 740 | ||
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index cca8eef736fc..6d4bc1c8ff60 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
@@ -624,7 +624,7 @@ extern void afs_clear_permits(struct afs_vnode *); | |||
624 | extern void afs_cache_permit(struct afs_vnode *, struct key *, long); | 624 | extern void afs_cache_permit(struct afs_vnode *, struct key *, long); |
625 | extern void afs_zap_permits(struct rcu_head *); | 625 | extern void afs_zap_permits(struct rcu_head *); |
626 | extern struct key *afs_request_key(struct afs_cell *); | 626 | extern struct key *afs_request_key(struct afs_cell *); |
627 | extern int afs_permission(struct inode *, int); | 627 | extern int afs_permission(struct inode *, int, unsigned int); |
628 | 628 | ||
629 | /* | 629 | /* |
630 | * server.c | 630 | * server.c |
diff --git a/fs/afs/security.c b/fs/afs/security.c index bb4ed144d0e4..f44b9d355377 100644 --- a/fs/afs/security.c +++ b/fs/afs/security.c | |||
@@ -285,13 +285,16 @@ static int afs_check_permit(struct afs_vnode *vnode, struct key *key, | |||
285 | * - AFS ACLs are attached to directories only, and a file is controlled by its | 285 | * - AFS ACLs are attached to directories only, and a file is controlled by its |
286 | * parent directory's ACL | 286 | * parent directory's ACL |
287 | */ | 287 | */ |
288 | int afs_permission(struct inode *inode, int mask) | 288 | int afs_permission(struct inode *inode, int mask, unsigned int flags) |
289 | { | 289 | { |
290 | struct afs_vnode *vnode = AFS_FS_I(inode); | 290 | struct afs_vnode *vnode = AFS_FS_I(inode); |
291 | afs_access_t uninitialized_var(access); | 291 | afs_access_t uninitialized_var(access); |
292 | struct key *key; | 292 | struct key *key; |
293 | int ret; | 293 | int ret; |
294 | 294 | ||
295 | if (flags & IPERM_FLAG_RCU) | ||
296 | return -ECHILD; | ||
297 | |||
295 | _enter("{{%x:%u},%lx},%x,", | 298 | _enter("{{%x:%u},%lx},%x,", |
296 | vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask); | 299 | vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask); |
297 | 300 | ||
@@ -347,7 +350,7 @@ int afs_permission(struct inode *inode, int mask) | |||
347 | } | 350 | } |
348 | 351 | ||
349 | key_put(key); | 352 | key_put(key); |
350 | ret = generic_permission(inode, mask, NULL); | 353 | ret = generic_permission(inode, mask, flags, NULL); |
351 | _leave(" = %d", ret); | 354 | _leave(" = %d", ret); |
352 | return ret; | 355 | return ret; |
353 | 356 | ||
diff --git a/fs/afs/super.c b/fs/afs/super.c index 27201cffece4..f901a9d7c111 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c | |||
@@ -498,6 +498,14 @@ static struct inode *afs_alloc_inode(struct super_block *sb) | |||
498 | return &vnode->vfs_inode; | 498 | return &vnode->vfs_inode; |
499 | } | 499 | } |
500 | 500 | ||
501 | static void afs_i_callback(struct rcu_head *head) | ||
502 | { | ||
503 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
504 | struct afs_vnode *vnode = AFS_FS_I(inode); | ||
505 | INIT_LIST_HEAD(&inode->i_dentry); | ||
506 | kmem_cache_free(afs_inode_cachep, vnode); | ||
507 | } | ||
508 | |||
501 | /* | 509 | /* |
502 | * destroy an AFS inode struct | 510 | * destroy an AFS inode struct |
503 | */ | 511 | */ |
@@ -511,7 +519,7 @@ static void afs_destroy_inode(struct inode *inode) | |||
511 | 519 | ||
512 | ASSERTCMP(vnode->server, ==, NULL); | 520 | ASSERTCMP(vnode->server, ==, NULL); |
513 | 521 | ||
514 | kmem_cache_free(afs_inode_cachep, vnode); | 522 | call_rcu(&inode->i_rcu, afs_i_callback); |
515 | atomic_dec(&afs_count_active_inodes); | 523 | atomic_dec(&afs_count_active_inodes); |
516 | } | 524 | } |
517 | 525 | ||
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index 57ce55b2564c..5fd38112a6ca 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c | |||
@@ -102,7 +102,7 @@ struct file *anon_inode_getfile(const char *name, | |||
102 | this.name = name; | 102 | this.name = name; |
103 | this.len = strlen(name); | 103 | this.len = strlen(name); |
104 | this.hash = 0; | 104 | this.hash = 0; |
105 | path.dentry = d_alloc(anon_inode_mnt->mnt_sb->s_root, &this); | 105 | path.dentry = d_alloc_pseudo(anon_inode_mnt->mnt_sb, &this); |
106 | if (!path.dentry) | 106 | if (!path.dentry) |
107 | goto err_module; | 107 | goto err_module; |
108 | 108 | ||
@@ -113,7 +113,7 @@ struct file *anon_inode_getfile(const char *name, | |||
113 | */ | 113 | */ |
114 | ihold(anon_inode_inode); | 114 | ihold(anon_inode_inode); |
115 | 115 | ||
116 | path.dentry->d_op = &anon_inodefs_dentry_operations; | 116 | d_set_d_op(path.dentry, &anon_inodefs_dentry_operations); |
117 | d_instantiate(path.dentry, anon_inode_inode); | 117 | d_instantiate(path.dentry, anon_inode_inode); |
118 | 118 | ||
119 | error = -ENFILE; | 119 | error = -ENFILE; |
@@ -232,7 +232,7 @@ static int __init anon_inode_init(void) | |||
232 | return 0; | 232 | return 0; |
233 | 233 | ||
234 | err_mntput: | 234 | err_mntput: |
235 | mntput(anon_inode_mnt); | 235 | mntput_long(anon_inode_mnt); |
236 | err_unregister_filesystem: | 236 | err_unregister_filesystem: |
237 | unregister_filesystem(&anon_inode_fs_type); | 237 | unregister_filesystem(&anon_inode_fs_type); |
238 | err_exit: | 238 | err_exit: |
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 3d283abf67d7..0fffe1c24cec 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/auto_fs4.h> | 16 | #include <linux/auto_fs4.h> |
17 | #include <linux/auto_dev-ioctl.h> | 17 | #include <linux/auto_dev-ioctl.h> |
18 | #include <linux/mutex.h> | 18 | #include <linux/mutex.h> |
19 | #include <linux/spinlock.h> | ||
19 | #include <linux/list.h> | 20 | #include <linux/list.h> |
20 | 21 | ||
21 | /* This is the range of ioctl() numbers we claim as ours */ | 22 | /* This is the range of ioctl() numbers we claim as ours */ |
@@ -60,6 +61,8 @@ do { \ | |||
60 | current->pid, __func__, ##args); \ | 61 | current->pid, __func__, ##args); \ |
61 | } while (0) | 62 | } while (0) |
62 | 63 | ||
64 | extern spinlock_t autofs4_lock; | ||
65 | |||
63 | /* Unified info structure. This is pointed to by both the dentry and | 66 | /* Unified info structure. This is pointed to by both the dentry and |
64 | inode structures. Each file in the filesystem has an instance of this | 67 | inode structures. Each file in the filesystem has an instance of this |
65 | structure. It holds a reference to the dentry, so dentries are never | 68 | structure. It holds a reference to the dentry, so dentries are never |
@@ -254,17 +257,15 @@ static inline int simple_positive(struct dentry *dentry) | |||
254 | return dentry->d_inode && !d_unhashed(dentry); | 257 | return dentry->d_inode && !d_unhashed(dentry); |
255 | } | 258 | } |
256 | 259 | ||
257 | static inline int __simple_empty(struct dentry *dentry) | 260 | static inline void __autofs4_add_expiring(struct dentry *dentry) |
258 | { | 261 | { |
259 | struct dentry *child; | 262 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); |
260 | int ret = 0; | 263 | struct autofs_info *ino = autofs4_dentry_ino(dentry); |
261 | 264 | if (ino) { | |
262 | list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) | 265 | if (list_empty(&ino->expiring)) |
263 | if (simple_positive(child)) | 266 | list_add(&ino->expiring, &sbi->expiring_list); |
264 | goto out; | 267 | } |
265 | ret = 1; | 268 | return; |
266 | out: | ||
267 | return ret; | ||
268 | } | 269 | } |
269 | 270 | ||
270 | static inline void autofs4_add_expiring(struct dentry *dentry) | 271 | static inline void autofs4_add_expiring(struct dentry *dentry) |
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index a796c9417fb1..cc1d01365905 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -91,24 +91,64 @@ done: | |||
91 | } | 91 | } |
92 | 92 | ||
93 | /* | 93 | /* |
94 | * Calculate next entry in top down tree traversal. | 94 | * Calculate and dget next entry in top down tree traversal. |
95 | * From next_mnt in namespace.c - elegant. | ||
96 | */ | 95 | */ |
97 | static struct dentry *next_dentry(struct dentry *p, struct dentry *root) | 96 | static struct dentry *get_next_positive_dentry(struct dentry *prev, |
97 | struct dentry *root) | ||
98 | { | 98 | { |
99 | struct list_head *next = p->d_subdirs.next; | 99 | struct list_head *next; |
100 | struct dentry *p, *ret; | ||
101 | |||
102 | if (prev == NULL) | ||
103 | return dget(prev); | ||
100 | 104 | ||
105 | spin_lock(&autofs4_lock); | ||
106 | relock: | ||
107 | p = prev; | ||
108 | spin_lock(&p->d_lock); | ||
109 | again: | ||
110 | next = p->d_subdirs.next; | ||
101 | if (next == &p->d_subdirs) { | 111 | if (next == &p->d_subdirs) { |
102 | while (1) { | 112 | while (1) { |
103 | if (p == root) | 113 | struct dentry *parent; |
114 | |||
115 | if (p == root) { | ||
116 | spin_unlock(&p->d_lock); | ||
117 | spin_unlock(&autofs4_lock); | ||
118 | dput(prev); | ||
104 | return NULL; | 119 | return NULL; |
120 | } | ||
121 | |||
122 | parent = p->d_parent; | ||
123 | if (!spin_trylock(&parent->d_lock)) { | ||
124 | spin_unlock(&p->d_lock); | ||
125 | cpu_relax(); | ||
126 | goto relock; | ||
127 | } | ||
128 | spin_unlock(&p->d_lock); | ||
105 | next = p->d_u.d_child.next; | 129 | next = p->d_u.d_child.next; |
106 | if (next != &p->d_parent->d_subdirs) | 130 | p = parent; |
131 | if (next != &parent->d_subdirs) | ||
107 | break; | 132 | break; |
108 | p = p->d_parent; | ||
109 | } | 133 | } |
110 | } | 134 | } |
111 | return list_entry(next, struct dentry, d_u.d_child); | 135 | ret = list_entry(next, struct dentry, d_u.d_child); |
136 | |||
137 | spin_lock_nested(&ret->d_lock, DENTRY_D_LOCK_NESTED); | ||
138 | /* Negative dentry - try next */ | ||
139 | if (!simple_positive(ret)) { | ||
140 | spin_unlock(&ret->d_lock); | ||
141 | p = ret; | ||
142 | goto again; | ||
143 | } | ||
144 | dget_dlock(ret); | ||
145 | spin_unlock(&ret->d_lock); | ||
146 | spin_unlock(&p->d_lock); | ||
147 | spin_unlock(&autofs4_lock); | ||
148 | |||
149 | dput(prev); | ||
150 | |||
151 | return ret; | ||
112 | } | 152 | } |
113 | 153 | ||
114 | /* | 154 | /* |
@@ -158,18 +198,11 @@ static int autofs4_tree_busy(struct vfsmount *mnt, | |||
158 | if (!simple_positive(top)) | 198 | if (!simple_positive(top)) |
159 | return 1; | 199 | return 1; |
160 | 200 | ||
161 | spin_lock(&dcache_lock); | 201 | p = NULL; |
162 | for (p = top; p; p = next_dentry(p, top)) { | 202 | while ((p = get_next_positive_dentry(p, top))) { |
163 | /* Negative dentry - give up */ | ||
164 | if (!simple_positive(p)) | ||
165 | continue; | ||
166 | |||
167 | DPRINTK("dentry %p %.*s", | 203 | DPRINTK("dentry %p %.*s", |
168 | p, (int) p->d_name.len, p->d_name.name); | 204 | p, (int) p->d_name.len, p->d_name.name); |
169 | 205 | ||
170 | p = dget(p); | ||
171 | spin_unlock(&dcache_lock); | ||
172 | |||
173 | /* | 206 | /* |
174 | * Is someone visiting anywhere in the subtree ? | 207 | * Is someone visiting anywhere in the subtree ? |
175 | * If there's no mount we need to check the usage | 208 | * If there's no mount we need to check the usage |
@@ -198,16 +231,13 @@ static int autofs4_tree_busy(struct vfsmount *mnt, | |||
198 | else | 231 | else |
199 | ino_count++; | 232 | ino_count++; |
200 | 233 | ||
201 | if (atomic_read(&p->d_count) > ino_count) { | 234 | if (p->d_count > ino_count) { |
202 | top_ino->last_used = jiffies; | 235 | top_ino->last_used = jiffies; |
203 | dput(p); | 236 | dput(p); |
204 | return 1; | 237 | return 1; |
205 | } | 238 | } |
206 | } | 239 | } |
207 | dput(p); | ||
208 | spin_lock(&dcache_lock); | ||
209 | } | 240 | } |
210 | spin_unlock(&dcache_lock); | ||
211 | 241 | ||
212 | /* Timeout of a tree mount is ultimately determined by its top dentry */ | 242 | /* Timeout of a tree mount is ultimately determined by its top dentry */ |
213 | if (!autofs4_can_expire(top, timeout, do_now)) | 243 | if (!autofs4_can_expire(top, timeout, do_now)) |
@@ -226,32 +256,21 @@ static struct dentry *autofs4_check_leaves(struct vfsmount *mnt, | |||
226 | DPRINTK("parent %p %.*s", | 256 | DPRINTK("parent %p %.*s", |
227 | parent, (int)parent->d_name.len, parent->d_name.name); | 257 | parent, (int)parent->d_name.len, parent->d_name.name); |
228 | 258 | ||
229 | spin_lock(&dcache_lock); | 259 | p = NULL; |
230 | for (p = parent; p; p = next_dentry(p, parent)) { | 260 | while ((p = get_next_positive_dentry(p, parent))) { |
231 | /* Negative dentry - give up */ | ||
232 | if (!simple_positive(p)) | ||
233 | continue; | ||
234 | |||
235 | DPRINTK("dentry %p %.*s", | 261 | DPRINTK("dentry %p %.*s", |
236 | p, (int) p->d_name.len, p->d_name.name); | 262 | p, (int) p->d_name.len, p->d_name.name); |
237 | 263 | ||
238 | p = dget(p); | ||
239 | spin_unlock(&dcache_lock); | ||
240 | |||
241 | if (d_mountpoint(p)) { | 264 | if (d_mountpoint(p)) { |
242 | /* Can we umount this guy */ | 265 | /* Can we umount this guy */ |
243 | if (autofs4_mount_busy(mnt, p)) | 266 | if (autofs4_mount_busy(mnt, p)) |
244 | goto cont; | 267 | continue; |
245 | 268 | ||
246 | /* Can we expire this guy */ | 269 | /* Can we expire this guy */ |
247 | if (autofs4_can_expire(p, timeout, do_now)) | 270 | if (autofs4_can_expire(p, timeout, do_now)) |
248 | return p; | 271 | return p; |
249 | } | 272 | } |
250 | cont: | ||
251 | dput(p); | ||
252 | spin_lock(&dcache_lock); | ||
253 | } | 273 | } |
254 | spin_unlock(&dcache_lock); | ||
255 | return NULL; | 274 | return NULL; |
256 | } | 275 | } |
257 | 276 | ||
@@ -276,7 +295,9 @@ struct dentry *autofs4_expire_direct(struct super_block *sb, | |||
276 | struct autofs_info *ino = autofs4_dentry_ino(root); | 295 | struct autofs_info *ino = autofs4_dentry_ino(root); |
277 | if (d_mountpoint(root)) { | 296 | if (d_mountpoint(root)) { |
278 | ino->flags |= AUTOFS_INF_MOUNTPOINT; | 297 | ino->flags |= AUTOFS_INF_MOUNTPOINT; |
279 | root->d_mounted--; | 298 | spin_lock(&root->d_lock); |
299 | root->d_flags &= ~DCACHE_MOUNTED; | ||
300 | spin_unlock(&root->d_lock); | ||
280 | } | 301 | } |
281 | ino->flags |= AUTOFS_INF_EXPIRING; | 302 | ino->flags |= AUTOFS_INF_EXPIRING; |
282 | init_completion(&ino->expire_complete); | 303 | init_completion(&ino->expire_complete); |
@@ -302,8 +323,8 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
302 | { | 323 | { |
303 | unsigned long timeout; | 324 | unsigned long timeout; |
304 | struct dentry *root = sb->s_root; | 325 | struct dentry *root = sb->s_root; |
326 | struct dentry *dentry; | ||
305 | struct dentry *expired = NULL; | 327 | struct dentry *expired = NULL; |
306 | struct list_head *next; | ||
307 | int do_now = how & AUTOFS_EXP_IMMEDIATE; | 328 | int do_now = how & AUTOFS_EXP_IMMEDIATE; |
308 | int exp_leaves = how & AUTOFS_EXP_LEAVES; | 329 | int exp_leaves = how & AUTOFS_EXP_LEAVES; |
309 | struct autofs_info *ino; | 330 | struct autofs_info *ino; |
@@ -315,23 +336,8 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
315 | now = jiffies; | 336 | now = jiffies; |
316 | timeout = sbi->exp_timeout; | 337 | timeout = sbi->exp_timeout; |
317 | 338 | ||
318 | spin_lock(&dcache_lock); | 339 | dentry = NULL; |
319 | next = root->d_subdirs.next; | 340 | while ((dentry = get_next_positive_dentry(dentry, root))) { |
320 | |||
321 | /* On exit from the loop expire is set to a dgot dentry | ||
322 | * to expire or it's NULL */ | ||
323 | while ( next != &root->d_subdirs ) { | ||
324 | struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child); | ||
325 | |||
326 | /* Negative dentry - give up */ | ||
327 | if (!simple_positive(dentry)) { | ||
328 | next = next->next; | ||
329 | continue; | ||
330 | } | ||
331 | |||
332 | dentry = dget(dentry); | ||
333 | spin_unlock(&dcache_lock); | ||
334 | |||
335 | spin_lock(&sbi->fs_lock); | 341 | spin_lock(&sbi->fs_lock); |
336 | ino = autofs4_dentry_ino(dentry); | 342 | ino = autofs4_dentry_ino(dentry); |
337 | 343 | ||
@@ -347,7 +353,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
347 | 353 | ||
348 | /* Path walk currently on this dentry? */ | 354 | /* Path walk currently on this dentry? */ |
349 | ino_count = atomic_read(&ino->count) + 2; | 355 | ino_count = atomic_read(&ino->count) + 2; |
350 | if (atomic_read(&dentry->d_count) > ino_count) | 356 | if (dentry->d_count > ino_count) |
351 | goto next; | 357 | goto next; |
352 | 358 | ||
353 | /* Can we umount this guy */ | 359 | /* Can we umount this guy */ |
@@ -369,7 +375,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
369 | if (!exp_leaves) { | 375 | if (!exp_leaves) { |
370 | /* Path walk currently on this dentry? */ | 376 | /* Path walk currently on this dentry? */ |
371 | ino_count = atomic_read(&ino->count) + 1; | 377 | ino_count = atomic_read(&ino->count) + 1; |
372 | if (atomic_read(&dentry->d_count) > ino_count) | 378 | if (dentry->d_count > ino_count) |
373 | goto next; | 379 | goto next; |
374 | 380 | ||
375 | if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { | 381 | if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { |
@@ -383,7 +389,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
383 | } else { | 389 | } else { |
384 | /* Path walk currently on this dentry? */ | 390 | /* Path walk currently on this dentry? */ |
385 | ino_count = atomic_read(&ino->count) + 1; | 391 | ino_count = atomic_read(&ino->count) + 1; |
386 | if (atomic_read(&dentry->d_count) > ino_count) | 392 | if (dentry->d_count > ino_count) |
387 | goto next; | 393 | goto next; |
388 | 394 | ||
389 | expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); | 395 | expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); |
@@ -394,11 +400,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb, | |||
394 | } | 400 | } |
395 | next: | 401 | next: |
396 | spin_unlock(&sbi->fs_lock); | 402 | spin_unlock(&sbi->fs_lock); |
397 | dput(dentry); | ||
398 | spin_lock(&dcache_lock); | ||
399 | next = next->next; | ||
400 | } | 403 | } |
401 | spin_unlock(&dcache_lock); | ||
402 | return NULL; | 404 | return NULL; |
403 | 405 | ||
404 | found: | 406 | found: |
@@ -408,9 +410,13 @@ found: | |||
408 | ino->flags |= AUTOFS_INF_EXPIRING; | 410 | ino->flags |= AUTOFS_INF_EXPIRING; |
409 | init_completion(&ino->expire_complete); | 411 | init_completion(&ino->expire_complete); |
410 | spin_unlock(&sbi->fs_lock); | 412 | spin_unlock(&sbi->fs_lock); |
411 | spin_lock(&dcache_lock); | 413 | spin_lock(&autofs4_lock); |
414 | spin_lock(&expired->d_parent->d_lock); | ||
415 | spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED); | ||
412 | list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); | 416 | list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); |
413 | spin_unlock(&dcache_lock); | 417 | spin_unlock(&expired->d_lock); |
418 | spin_unlock(&expired->d_parent->d_lock); | ||
419 | spin_unlock(&autofs4_lock); | ||
414 | return expired; | 420 | return expired; |
415 | } | 421 | } |
416 | 422 | ||
@@ -499,7 +505,14 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt, | |||
499 | 505 | ||
500 | spin_lock(&sbi->fs_lock); | 506 | spin_lock(&sbi->fs_lock); |
501 | if (ino->flags & AUTOFS_INF_MOUNTPOINT) { | 507 | if (ino->flags & AUTOFS_INF_MOUNTPOINT) { |
502 | sb->s_root->d_mounted++; | 508 | spin_lock(&sb->s_root->d_lock); |
509 | /* | ||
510 | * If we haven't been expired away, then reset | ||
511 | * mounted status. | ||
512 | */ | ||
513 | if (mnt->mnt_parent != mnt) | ||
514 | sb->s_root->d_flags |= DCACHE_MOUNTED; | ||
515 | spin_unlock(&sb->s_root->d_lock); | ||
503 | ino->flags &= ~AUTOFS_INF_MOUNTPOINT; | 516 | ino->flags &= ~AUTOFS_INF_MOUNTPOINT; |
504 | } | 517 | } |
505 | ino->flags &= ~AUTOFS_INF_EXPIRING; | 518 | ino->flags &= ~AUTOFS_INF_EXPIRING; |
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index ac87e49fa706..a7bdb9dcac84 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c | |||
@@ -309,7 +309,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) | |||
309 | goto fail_iput; | 309 | goto fail_iput; |
310 | pipe = NULL; | 310 | pipe = NULL; |
311 | 311 | ||
312 | root->d_op = &autofs4_sb_dentry_operations; | 312 | d_set_d_op(root, &autofs4_sb_dentry_operations); |
313 | root->d_fsdata = ino; | 313 | root->d_fsdata = ino; |
314 | 314 | ||
315 | /* Can this call block? */ | 315 | /* Can this call block? */ |
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index d5c1401f0031..651e4ef563b1 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -23,6 +23,8 @@ | |||
23 | 23 | ||
24 | #include "autofs_i.h" | 24 | #include "autofs_i.h" |
25 | 25 | ||
26 | DEFINE_SPINLOCK(autofs4_lock); | ||
27 | |||
26 | static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *); | 28 | static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *); |
27 | static int autofs4_dir_unlink(struct inode *,struct dentry *); | 29 | static int autofs4_dir_unlink(struct inode *,struct dentry *); |
28 | static int autofs4_dir_rmdir(struct inode *,struct dentry *); | 30 | static int autofs4_dir_rmdir(struct inode *,struct dentry *); |
@@ -142,12 +144,15 @@ static int autofs4_dir_open(struct inode *inode, struct file *file) | |||
142 | * autofs file system so just let the libfs routines handle | 144 | * autofs file system so just let the libfs routines handle |
143 | * it. | 145 | * it. |
144 | */ | 146 | */ |
145 | spin_lock(&dcache_lock); | 147 | spin_lock(&autofs4_lock); |
148 | spin_lock(&dentry->d_lock); | ||
146 | if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { | 149 | if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { |
147 | spin_unlock(&dcache_lock); | 150 | spin_unlock(&dentry->d_lock); |
151 | spin_unlock(&autofs4_lock); | ||
148 | return -ENOENT; | 152 | return -ENOENT; |
149 | } | 153 | } |
150 | spin_unlock(&dcache_lock); | 154 | spin_unlock(&dentry->d_lock); |
155 | spin_unlock(&autofs4_lock); | ||
151 | 156 | ||
152 | out: | 157 | out: |
153 | return dcache_dir_open(inode, file); | 158 | return dcache_dir_open(inode, file); |
@@ -252,9 +257,11 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
252 | /* We trigger a mount for almost all flags */ | 257 | /* We trigger a mount for almost all flags */ |
253 | lookup_type = autofs4_need_mount(nd->flags); | 258 | lookup_type = autofs4_need_mount(nd->flags); |
254 | spin_lock(&sbi->fs_lock); | 259 | spin_lock(&sbi->fs_lock); |
255 | spin_lock(&dcache_lock); | 260 | spin_lock(&autofs4_lock); |
261 | spin_lock(&dentry->d_lock); | ||
256 | if (!(lookup_type || ino->flags & AUTOFS_INF_PENDING)) { | 262 | if (!(lookup_type || ino->flags & AUTOFS_INF_PENDING)) { |
257 | spin_unlock(&dcache_lock); | 263 | spin_unlock(&dentry->d_lock); |
264 | spin_unlock(&autofs4_lock); | ||
258 | spin_unlock(&sbi->fs_lock); | 265 | spin_unlock(&sbi->fs_lock); |
259 | goto follow; | 266 | goto follow; |
260 | } | 267 | } |
@@ -266,7 +273,8 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
266 | */ | 273 | */ |
267 | if (ino->flags & AUTOFS_INF_PENDING || | 274 | if (ino->flags & AUTOFS_INF_PENDING || |
268 | (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) { | 275 | (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) { |
269 | spin_unlock(&dcache_lock); | 276 | spin_unlock(&dentry->d_lock); |
277 | spin_unlock(&autofs4_lock); | ||
270 | spin_unlock(&sbi->fs_lock); | 278 | spin_unlock(&sbi->fs_lock); |
271 | 279 | ||
272 | status = try_to_fill_dentry(dentry, nd->flags); | 280 | status = try_to_fill_dentry(dentry, nd->flags); |
@@ -275,7 +283,8 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
275 | 283 | ||
276 | goto follow; | 284 | goto follow; |
277 | } | 285 | } |
278 | spin_unlock(&dcache_lock); | 286 | spin_unlock(&dentry->d_lock); |
287 | spin_unlock(&autofs4_lock); | ||
279 | spin_unlock(&sbi->fs_lock); | 288 | spin_unlock(&sbi->fs_lock); |
280 | follow: | 289 | follow: |
281 | /* | 290 | /* |
@@ -306,12 +315,19 @@ out_error: | |||
306 | */ | 315 | */ |
307 | static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | 316 | static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) |
308 | { | 317 | { |
309 | struct inode *dir = dentry->d_parent->d_inode; | 318 | struct inode *dir; |
310 | struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); | 319 | struct autofs_sb_info *sbi; |
311 | int oz_mode = autofs4_oz_mode(sbi); | 320 | int oz_mode; |
312 | int flags = nd ? nd->flags : 0; | 321 | int flags = nd ? nd->flags : 0; |
313 | int status = 1; | 322 | int status = 1; |
314 | 323 | ||
324 | if (flags & LOOKUP_RCU) | ||
325 | return -ECHILD; | ||
326 | |||
327 | dir = dentry->d_parent->d_inode; | ||
328 | sbi = autofs4_sbi(dir->i_sb); | ||
329 | oz_mode = autofs4_oz_mode(sbi); | ||
330 | |||
315 | /* Pending dentry */ | 331 | /* Pending dentry */ |
316 | spin_lock(&sbi->fs_lock); | 332 | spin_lock(&sbi->fs_lock); |
317 | if (autofs4_ispending(dentry)) { | 333 | if (autofs4_ispending(dentry)) { |
@@ -346,12 +362,14 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
346 | return 0; | 362 | return 0; |
347 | 363 | ||
348 | /* Check for a non-mountpoint directory with no contents */ | 364 | /* Check for a non-mountpoint directory with no contents */ |
349 | spin_lock(&dcache_lock); | 365 | spin_lock(&autofs4_lock); |
366 | spin_lock(&dentry->d_lock); | ||
350 | if (S_ISDIR(dentry->d_inode->i_mode) && | 367 | if (S_ISDIR(dentry->d_inode->i_mode) && |
351 | !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { | 368 | !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { |
352 | DPRINTK("dentry=%p %.*s, emptydir", | 369 | DPRINTK("dentry=%p %.*s, emptydir", |
353 | dentry, dentry->d_name.len, dentry->d_name.name); | 370 | dentry, dentry->d_name.len, dentry->d_name.name); |
354 | spin_unlock(&dcache_lock); | 371 | spin_unlock(&dentry->d_lock); |
372 | spin_unlock(&autofs4_lock); | ||
355 | 373 | ||
356 | /* The daemon never causes a mount to trigger */ | 374 | /* The daemon never causes a mount to trigger */ |
357 | if (oz_mode) | 375 | if (oz_mode) |
@@ -367,7 +385,8 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
367 | 385 | ||
368 | return status; | 386 | return status; |
369 | } | 387 | } |
370 | spin_unlock(&dcache_lock); | 388 | spin_unlock(&dentry->d_lock); |
389 | spin_unlock(&autofs4_lock); | ||
371 | 390 | ||
372 | return 1; | 391 | return 1; |
373 | } | 392 | } |
@@ -422,7 +441,7 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry) | |||
422 | const unsigned char *str = name->name; | 441 | const unsigned char *str = name->name; |
423 | struct list_head *p, *head; | 442 | struct list_head *p, *head; |
424 | 443 | ||
425 | spin_lock(&dcache_lock); | 444 | spin_lock(&autofs4_lock); |
426 | spin_lock(&sbi->lookup_lock); | 445 | spin_lock(&sbi->lookup_lock); |
427 | head = &sbi->active_list; | 446 | head = &sbi->active_list; |
428 | list_for_each(p, head) { | 447 | list_for_each(p, head) { |
@@ -436,7 +455,7 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry) | |||
436 | spin_lock(&active->d_lock); | 455 | spin_lock(&active->d_lock); |
437 | 456 | ||
438 | /* Already gone? */ | 457 | /* Already gone? */ |
439 | if (atomic_read(&active->d_count) == 0) | 458 | if (active->d_count == 0) |
440 | goto next; | 459 | goto next; |
441 | 460 | ||
442 | qstr = &active->d_name; | 461 | qstr = &active->d_name; |
@@ -452,17 +471,17 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry) | |||
452 | goto next; | 471 | goto next; |
453 | 472 | ||
454 | if (d_unhashed(active)) { | 473 | if (d_unhashed(active)) { |
455 | dget(active); | 474 | dget_dlock(active); |
456 | spin_unlock(&active->d_lock); | 475 | spin_unlock(&active->d_lock); |
457 | spin_unlock(&sbi->lookup_lock); | 476 | spin_unlock(&sbi->lookup_lock); |
458 | spin_unlock(&dcache_lock); | 477 | spin_unlock(&autofs4_lock); |
459 | return active; | 478 | return active; |
460 | } | 479 | } |
461 | next: | 480 | next: |
462 | spin_unlock(&active->d_lock); | 481 | spin_unlock(&active->d_lock); |
463 | } | 482 | } |
464 | spin_unlock(&sbi->lookup_lock); | 483 | spin_unlock(&sbi->lookup_lock); |
465 | spin_unlock(&dcache_lock); | 484 | spin_unlock(&autofs4_lock); |
466 | 485 | ||
467 | return NULL; | 486 | return NULL; |
468 | } | 487 | } |
@@ -477,7 +496,7 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry) | |||
477 | const unsigned char *str = name->name; | 496 | const unsigned char *str = name->name; |
478 | struct list_head *p, *head; | 497 | struct list_head *p, *head; |
479 | 498 | ||
480 | spin_lock(&dcache_lock); | 499 | spin_lock(&autofs4_lock); |
481 | spin_lock(&sbi->lookup_lock); | 500 | spin_lock(&sbi->lookup_lock); |
482 | head = &sbi->expiring_list; | 501 | head = &sbi->expiring_list; |
483 | list_for_each(p, head) { | 502 | list_for_each(p, head) { |
@@ -507,17 +526,17 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry) | |||
507 | goto next; | 526 | goto next; |
508 | 527 | ||
509 | if (d_unhashed(expiring)) { | 528 | if (d_unhashed(expiring)) { |
510 | dget(expiring); | 529 | dget_dlock(expiring); |
511 | spin_unlock(&expiring->d_lock); | 530 | spin_unlock(&expiring->d_lock); |
512 | spin_unlock(&sbi->lookup_lock); | 531 | spin_unlock(&sbi->lookup_lock); |
513 | spin_unlock(&dcache_lock); | 532 | spin_unlock(&autofs4_lock); |
514 | return expiring; | 533 | return expiring; |
515 | } | 534 | } |
516 | next: | 535 | next: |
517 | spin_unlock(&expiring->d_lock); | 536 | spin_unlock(&expiring->d_lock); |
518 | } | 537 | } |
519 | spin_unlock(&sbi->lookup_lock); | 538 | spin_unlock(&sbi->lookup_lock); |
520 | spin_unlock(&dcache_lock); | 539 | spin_unlock(&autofs4_lock); |
521 | 540 | ||
522 | return NULL; | 541 | return NULL; |
523 | } | 542 | } |
@@ -559,7 +578,7 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s | |||
559 | * we check for the hashed dentry and return the newly | 578 | * we check for the hashed dentry and return the newly |
560 | * hashed dentry. | 579 | * hashed dentry. |
561 | */ | 580 | */ |
562 | dentry->d_op = &autofs4_root_dentry_operations; | 581 | d_set_d_op(dentry, &autofs4_root_dentry_operations); |
563 | 582 | ||
564 | /* | 583 | /* |
565 | * And we need to ensure that the same dentry is used for | 584 | * And we need to ensure that the same dentry is used for |
@@ -698,9 +717,9 @@ static int autofs4_dir_symlink(struct inode *dir, | |||
698 | d_add(dentry, inode); | 717 | d_add(dentry, inode); |
699 | 718 | ||
700 | if (dir == dir->i_sb->s_root->d_inode) | 719 | if (dir == dir->i_sb->s_root->d_inode) |
701 | dentry->d_op = &autofs4_root_dentry_operations; | 720 | d_set_d_op(dentry, &autofs4_root_dentry_operations); |
702 | else | 721 | else |
703 | dentry->d_op = &autofs4_dentry_operations; | 722 | d_set_d_op(dentry, &autofs4_dentry_operations); |
704 | 723 | ||
705 | dentry->d_fsdata = ino; | 724 | dentry->d_fsdata = ino; |
706 | ino->dentry = dget(dentry); | 725 | ino->dentry = dget(dentry); |
@@ -753,12 +772,12 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry) | |||
753 | 772 | ||
754 | dir->i_mtime = CURRENT_TIME; | 773 | dir->i_mtime = CURRENT_TIME; |
755 | 774 | ||
756 | spin_lock(&dcache_lock); | 775 | spin_lock(&autofs4_lock); |
757 | autofs4_add_expiring(dentry); | 776 | autofs4_add_expiring(dentry); |
758 | spin_lock(&dentry->d_lock); | 777 | spin_lock(&dentry->d_lock); |
759 | __d_drop(dentry); | 778 | __d_drop(dentry); |
760 | spin_unlock(&dentry->d_lock); | 779 | spin_unlock(&dentry->d_lock); |
761 | spin_unlock(&dcache_lock); | 780 | spin_unlock(&autofs4_lock); |
762 | 781 | ||
763 | return 0; | 782 | return 0; |
764 | } | 783 | } |
@@ -775,16 +794,20 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry) | |||
775 | if (!autofs4_oz_mode(sbi)) | 794 | if (!autofs4_oz_mode(sbi)) |
776 | return -EACCES; | 795 | return -EACCES; |
777 | 796 | ||
778 | spin_lock(&dcache_lock); | 797 | spin_lock(&autofs4_lock); |
798 | spin_lock(&sbi->lookup_lock); | ||
799 | spin_lock(&dentry->d_lock); | ||
779 | if (!list_empty(&dentry->d_subdirs)) { | 800 | if (!list_empty(&dentry->d_subdirs)) { |
780 | spin_unlock(&dcache_lock); | 801 | spin_unlock(&dentry->d_lock); |
802 | spin_unlock(&sbi->lookup_lock); | ||
803 | spin_unlock(&autofs4_lock); | ||
781 | return -ENOTEMPTY; | 804 | return -ENOTEMPTY; |
782 | } | 805 | } |
783 | autofs4_add_expiring(dentry); | 806 | __autofs4_add_expiring(dentry); |
784 | spin_lock(&dentry->d_lock); | 807 | spin_unlock(&sbi->lookup_lock); |
785 | __d_drop(dentry); | 808 | __d_drop(dentry); |
786 | spin_unlock(&dentry->d_lock); | 809 | spin_unlock(&dentry->d_lock); |
787 | spin_unlock(&dcache_lock); | 810 | spin_unlock(&autofs4_lock); |
788 | 811 | ||
789 | if (atomic_dec_and_test(&ino->count)) { | 812 | if (atomic_dec_and_test(&ino->count)) { |
790 | p_ino = autofs4_dentry_ino(dentry->d_parent); | 813 | p_ino = autofs4_dentry_ino(dentry->d_parent); |
@@ -829,9 +852,9 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
829 | d_add(dentry, inode); | 852 | d_add(dentry, inode); |
830 | 853 | ||
831 | if (dir == dir->i_sb->s_root->d_inode) | 854 | if (dir == dir->i_sb->s_root->d_inode) |
832 | dentry->d_op = &autofs4_root_dentry_operations; | 855 | d_set_d_op(dentry, &autofs4_root_dentry_operations); |
833 | else | 856 | else |
834 | dentry->d_op = &autofs4_dentry_operations; | 857 | d_set_d_op(dentry, &autofs4_dentry_operations); |
835 | 858 | ||
836 | dentry->d_fsdata = ino; | 859 | dentry->d_fsdata = ino; |
837 | ino->dentry = dget(dentry); | 860 | ino->dentry = dget(dentry); |
@@ -980,19 +1003,11 @@ static int autofs4_root_ioctl_unlocked(struct inode *inode, struct file *filp, | |||
980 | } | 1003 | } |
981 | } | 1004 | } |
982 | 1005 | ||
983 | static DEFINE_MUTEX(autofs4_ioctl_mutex); | ||
984 | |||
985 | static long autofs4_root_ioctl(struct file *filp, | 1006 | static long autofs4_root_ioctl(struct file *filp, |
986 | unsigned int cmd, unsigned long arg) | 1007 | unsigned int cmd, unsigned long arg) |
987 | { | 1008 | { |
988 | long ret; | ||
989 | struct inode *inode = filp->f_dentry->d_inode; | 1009 | struct inode *inode = filp->f_dentry->d_inode; |
990 | 1010 | return autofs4_root_ioctl_unlocked(inode, filp, cmd, arg); | |
991 | mutex_lock(&autofs4_ioctl_mutex); | ||
992 | ret = autofs4_root_ioctl_unlocked(inode, filp, cmd, arg); | ||
993 | mutex_unlock(&autofs4_ioctl_mutex); | ||
994 | |||
995 | return ret; | ||
996 | } | 1011 | } |
997 | 1012 | ||
998 | #ifdef CONFIG_COMPAT | 1013 | #ifdef CONFIG_COMPAT |
@@ -1002,13 +1017,11 @@ static long autofs4_root_compat_ioctl(struct file *filp, | |||
1002 | struct inode *inode = filp->f_path.dentry->d_inode; | 1017 | struct inode *inode = filp->f_path.dentry->d_inode; |
1003 | int ret; | 1018 | int ret; |
1004 | 1019 | ||
1005 | mutex_lock(&autofs4_ioctl_mutex); | ||
1006 | if (cmd == AUTOFS_IOC_READY || cmd == AUTOFS_IOC_FAIL) | 1020 | if (cmd == AUTOFS_IOC_READY || cmd == AUTOFS_IOC_FAIL) |
1007 | ret = autofs4_root_ioctl_unlocked(inode, filp, cmd, arg); | 1021 | ret = autofs4_root_ioctl_unlocked(inode, filp, cmd, arg); |
1008 | else | 1022 | else |
1009 | ret = autofs4_root_ioctl_unlocked(inode, filp, cmd, | 1023 | ret = autofs4_root_ioctl_unlocked(inode, filp, cmd, |
1010 | (unsigned long)compat_ptr(arg)); | 1024 | (unsigned long)compat_ptr(arg)); |
1011 | mutex_unlock(&autofs4_ioctl_mutex); | ||
1012 | 1025 | ||
1013 | return ret; | 1026 | return ret; |
1014 | } | 1027 | } |
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 2341375386f8..c5f8459c905e 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c | |||
@@ -186,16 +186,26 @@ static int autofs4_getpath(struct autofs_sb_info *sbi, | |||
186 | { | 186 | { |
187 | struct dentry *root = sbi->sb->s_root; | 187 | struct dentry *root = sbi->sb->s_root; |
188 | struct dentry *tmp; | 188 | struct dentry *tmp; |
189 | char *buf = *name; | 189 | char *buf; |
190 | char *p; | 190 | char *p; |
191 | int len = 0; | 191 | int len; |
192 | unsigned seq; | ||
192 | 193 | ||
193 | spin_lock(&dcache_lock); | 194 | rename_retry: |
195 | buf = *name; | ||
196 | len = 0; | ||
197 | |||
198 | seq = read_seqbegin(&rename_lock); | ||
199 | rcu_read_lock(); | ||
200 | spin_lock(&autofs4_lock); | ||
194 | for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent) | 201 | for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent) |
195 | len += tmp->d_name.len + 1; | 202 | len += tmp->d_name.len + 1; |
196 | 203 | ||
197 | if (!len || --len > NAME_MAX) { | 204 | if (!len || --len > NAME_MAX) { |
198 | spin_unlock(&dcache_lock); | 205 | spin_unlock(&autofs4_lock); |
206 | rcu_read_unlock(); | ||
207 | if (read_seqretry(&rename_lock, seq)) | ||
208 | goto rename_retry; | ||
199 | return 0; | 209 | return 0; |
200 | } | 210 | } |
201 | 211 | ||
@@ -208,7 +218,10 @@ static int autofs4_getpath(struct autofs_sb_info *sbi, | |||
208 | p -= tmp->d_name.len; | 218 | p -= tmp->d_name.len; |
209 | strncpy(p, tmp->d_name.name, tmp->d_name.len); | 219 | strncpy(p, tmp->d_name.name, tmp->d_name.len); |
210 | } | 220 | } |
211 | spin_unlock(&dcache_lock); | 221 | spin_unlock(&autofs4_lock); |
222 | rcu_read_unlock(); | ||
223 | if (read_seqretry(&rename_lock, seq)) | ||
224 | goto rename_retry; | ||
212 | 225 | ||
213 | return len; | 226 | return len; |
214 | } | 227 | } |
diff --git a/fs/bad_inode.c b/fs/bad_inode.c index f024d8aaddef..9ad2369d9e35 100644 --- a/fs/bad_inode.c +++ b/fs/bad_inode.c | |||
@@ -229,8 +229,11 @@ static int bad_inode_readlink(struct dentry *dentry, char __user *buffer, | |||
229 | return -EIO; | 229 | return -EIO; |
230 | } | 230 | } |
231 | 231 | ||
232 | static int bad_inode_permission(struct inode *inode, int mask) | 232 | static int bad_inode_permission(struct inode *inode, int mask, unsigned int flags) |
233 | { | 233 | { |
234 | if (flags & IPERM_FLAG_RCU) | ||
235 | return -ECHILD; | ||
236 | |||
234 | return -EIO; | 237 | return -EIO; |
235 | } | 238 | } |
236 | 239 | ||
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index aa4e7c7ae3c6..de93581b79a2 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c | |||
@@ -284,12 +284,18 @@ befs_alloc_inode(struct super_block *sb) | |||
284 | return &bi->vfs_inode; | 284 | return &bi->vfs_inode; |
285 | } | 285 | } |
286 | 286 | ||
287 | static void | 287 | static void befs_i_callback(struct rcu_head *head) |
288 | befs_destroy_inode(struct inode *inode) | ||
289 | { | 288 | { |
289 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
290 | INIT_LIST_HEAD(&inode->i_dentry); | ||
290 | kmem_cache_free(befs_inode_cachep, BEFS_I(inode)); | 291 | kmem_cache_free(befs_inode_cachep, BEFS_I(inode)); |
291 | } | 292 | } |
292 | 293 | ||
294 | static void befs_destroy_inode(struct inode *inode) | ||
295 | { | ||
296 | call_rcu(&inode->i_rcu, befs_i_callback); | ||
297 | } | ||
298 | |||
293 | static void init_once(void *foo) | 299 | static void init_once(void *foo) |
294 | { | 300 | { |
295 | struct befs_inode_info *bi = (struct befs_inode_info *) foo; | 301 | struct befs_inode_info *bi = (struct befs_inode_info *) foo; |
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 76db6d7d49bb..a8e37f81d097 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c | |||
@@ -248,11 +248,18 @@ static struct inode *bfs_alloc_inode(struct super_block *sb) | |||
248 | return &bi->vfs_inode; | 248 | return &bi->vfs_inode; |
249 | } | 249 | } |
250 | 250 | ||
251 | static void bfs_destroy_inode(struct inode *inode) | 251 | static void bfs_i_callback(struct rcu_head *head) |
252 | { | 252 | { |
253 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
254 | INIT_LIST_HEAD(&inode->i_dentry); | ||
253 | kmem_cache_free(bfs_inode_cachep, BFS_I(inode)); | 255 | kmem_cache_free(bfs_inode_cachep, BFS_I(inode)); |
254 | } | 256 | } |
255 | 257 | ||
258 | static void bfs_destroy_inode(struct inode *inode) | ||
259 | { | ||
260 | call_rcu(&inode->i_rcu, bfs_i_callback); | ||
261 | } | ||
262 | |||
256 | static void init_once(void *foo) | 263 | static void init_once(void *foo) |
257 | { | 264 | { |
258 | struct bfs_inode_info *bi = foo; | 265 | struct bfs_inode_info *bi = foo; |
diff --git a/fs/block_dev.c b/fs/block_dev.c index 4230252fd689..771f23527010 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
@@ -409,13 +409,20 @@ static struct inode *bdev_alloc_inode(struct super_block *sb) | |||
409 | return &ei->vfs_inode; | 409 | return &ei->vfs_inode; |
410 | } | 410 | } |
411 | 411 | ||
412 | static void bdev_destroy_inode(struct inode *inode) | 412 | static void bdev_i_callback(struct rcu_head *head) |
413 | { | 413 | { |
414 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
414 | struct bdev_inode *bdi = BDEV_I(inode); | 415 | struct bdev_inode *bdi = BDEV_I(inode); |
415 | 416 | ||
417 | INIT_LIST_HEAD(&inode->i_dentry); | ||
416 | kmem_cache_free(bdev_cachep, bdi); | 418 | kmem_cache_free(bdev_cachep, bdi); |
417 | } | 419 | } |
418 | 420 | ||
421 | static void bdev_destroy_inode(struct inode *inode) | ||
422 | { | ||
423 | call_rcu(&inode->i_rcu, bdev_i_callback); | ||
424 | } | ||
425 | |||
419 | static void init_once(void *foo) | 426 | static void init_once(void *foo) |
420 | { | 427 | { |
421 | struct bdev_inode *ei = (struct bdev_inode *) foo; | 428 | struct bdev_inode *ei = (struct bdev_inode *) foo; |
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 2222d161c7b6..6ae2c8cac9d5 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c | |||
@@ -185,18 +185,23 @@ static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name, | |||
185 | return ret; | 185 | return ret; |
186 | } | 186 | } |
187 | 187 | ||
188 | int btrfs_check_acl(struct inode *inode, int mask) | 188 | int btrfs_check_acl(struct inode *inode, int mask, unsigned int flags) |
189 | { | 189 | { |
190 | struct posix_acl *acl; | ||
191 | int error = -EAGAIN; | 190 | int error = -EAGAIN; |
192 | 191 | ||
193 | acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS); | 192 | if (flags & IPERM_FLAG_RCU) { |
193 | if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) | ||
194 | error = -ECHILD; | ||
194 | 195 | ||
195 | if (IS_ERR(acl)) | 196 | } else { |
196 | return PTR_ERR(acl); | 197 | struct posix_acl *acl; |
197 | if (acl) { | 198 | acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS); |
198 | error = posix_acl_permission(inode, acl, mask); | 199 | if (IS_ERR(acl)) |
199 | posix_acl_release(acl); | 200 | return PTR_ERR(acl); |
201 | if (acl) { | ||
202 | error = posix_acl_permission(inode, acl, mask); | ||
203 | posix_acl_release(acl); | ||
204 | } | ||
200 | } | 205 | } |
201 | 206 | ||
202 | return error; | 207 | return error; |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index af52f6d7a4d8..a142d204b526 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -2544,7 +2544,7 @@ int btrfs_sync_fs(struct super_block *sb, int wait); | |||
2544 | 2544 | ||
2545 | /* acl.c */ | 2545 | /* acl.c */ |
2546 | #ifdef CONFIG_BTRFS_FS_POSIX_ACL | 2546 | #ifdef CONFIG_BTRFS_FS_POSIX_ACL |
2547 | int btrfs_check_acl(struct inode *inode, int mask); | 2547 | int btrfs_check_acl(struct inode *inode, int mask, unsigned int flags); |
2548 | #else | 2548 | #else |
2549 | #define btrfs_check_acl NULL | 2549 | #define btrfs_check_acl NULL |
2550 | #endif | 2550 | #endif |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index c547cca26a26..51d2e4de34eb 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -696,6 +696,7 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, | |||
696 | __btree_submit_bio_done); | 696 | __btree_submit_bio_done); |
697 | } | 697 | } |
698 | 698 | ||
699 | #ifdef CONFIG_MIGRATION | ||
699 | static int btree_migratepage(struct address_space *mapping, | 700 | static int btree_migratepage(struct address_space *mapping, |
700 | struct page *newpage, struct page *page) | 701 | struct page *newpage, struct page *page) |
701 | { | 702 | { |
@@ -712,12 +713,9 @@ static int btree_migratepage(struct address_space *mapping, | |||
712 | if (page_has_private(page) && | 713 | if (page_has_private(page) && |
713 | !try_to_release_page(page, GFP_KERNEL)) | 714 | !try_to_release_page(page, GFP_KERNEL)) |
714 | return -EAGAIN; | 715 | return -EAGAIN; |
715 | #ifdef CONFIG_MIGRATION | ||
716 | return migrate_page(mapping, newpage, page); | 716 | return migrate_page(mapping, newpage, page); |
717 | #else | ||
718 | return -ENOSYS; | ||
719 | #endif | ||
720 | } | 717 | } |
718 | #endif | ||
721 | 719 | ||
722 | static int btree_writepage(struct page *page, struct writeback_control *wbc) | 720 | static int btree_writepage(struct page *page, struct writeback_control *wbc) |
723 | { | 721 | { |
@@ -1009,7 +1007,10 @@ static int find_and_setup_root(struct btrfs_root *tree_root, | |||
1009 | blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); | 1007 | blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); |
1010 | root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), | 1008 | root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), |
1011 | blocksize, generation); | 1009 | blocksize, generation); |
1012 | BUG_ON(!root->node); | 1010 | if (!root->node || !btrfs_buffer_uptodate(root->node, generation)) { |
1011 | free_extent_buffer(root->node); | ||
1012 | return -EIO; | ||
1013 | } | ||
1013 | root->commit_root = btrfs_root_node(root); | 1014 | root->commit_root = btrfs_root_node(root); |
1014 | return 0; | 1015 | return 0; |
1015 | } | 1016 | } |
diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c index 6f0444473594..0ccf9a8afcdf 100644 --- a/fs/btrfs/export.c +++ b/fs/btrfs/export.c | |||
@@ -110,7 +110,7 @@ static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid, | |||
110 | 110 | ||
111 | dentry = d_obtain_alias(inode); | 111 | dentry = d_obtain_alias(inode); |
112 | if (!IS_ERR(dentry)) | 112 | if (!IS_ERR(dentry)) |
113 | dentry->d_op = &btrfs_dentry_operations; | 113 | d_set_d_op(dentry, &btrfs_dentry_operations); |
114 | return dentry; | 114 | return dentry; |
115 | fail: | 115 | fail: |
116 | srcu_read_unlock(&fs_info->subvol_srcu, index); | 116 | srcu_read_unlock(&fs_info->subvol_srcu, index); |
@@ -166,7 +166,7 @@ static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh, | |||
166 | static struct dentry *btrfs_get_parent(struct dentry *child) | 166 | static struct dentry *btrfs_get_parent(struct dentry *child) |
167 | { | 167 | { |
168 | struct inode *dir = child->d_inode; | 168 | struct inode *dir = child->d_inode; |
169 | static struct dentry *dentry; | 169 | struct dentry *dentry; |
170 | struct btrfs_root *root = BTRFS_I(dir)->root; | 170 | struct btrfs_root *root = BTRFS_I(dir)->root; |
171 | struct btrfs_path *path; | 171 | struct btrfs_path *path; |
172 | struct extent_buffer *leaf; | 172 | struct extent_buffer *leaf; |
@@ -225,7 +225,7 @@ static struct dentry *btrfs_get_parent(struct dentry *child) | |||
225 | key.offset = 0; | 225 | key.offset = 0; |
226 | dentry = d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root, NULL)); | 226 | dentry = d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root, NULL)); |
227 | if (!IS_ERR(dentry)) | 227 | if (!IS_ERR(dentry)) |
228 | dentry->d_op = &btrfs_dentry_operations; | 228 | d_set_d_op(dentry, &btrfs_dentry_operations); |
229 | return dentry; | 229 | return dentry; |
230 | fail: | 230 | fail: |
231 | btrfs_free_path(path); | 231 | btrfs_free_path(path); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index bcd59c7dfb57..227e5815d838 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -429,6 +429,7 @@ err: | |||
429 | 429 | ||
430 | static int cache_block_group(struct btrfs_block_group_cache *cache, | 430 | static int cache_block_group(struct btrfs_block_group_cache *cache, |
431 | struct btrfs_trans_handle *trans, | 431 | struct btrfs_trans_handle *trans, |
432 | struct btrfs_root *root, | ||
432 | int load_cache_only) | 433 | int load_cache_only) |
433 | { | 434 | { |
434 | struct btrfs_fs_info *fs_info = cache->fs_info; | 435 | struct btrfs_fs_info *fs_info = cache->fs_info; |
@@ -442,9 +443,12 @@ static int cache_block_group(struct btrfs_block_group_cache *cache, | |||
442 | 443 | ||
443 | /* | 444 | /* |
444 | * We can't do the read from on-disk cache during a commit since we need | 445 | * We can't do the read from on-disk cache during a commit since we need |
445 | * to have the normal tree locking. | 446 | * to have the normal tree locking. Also if we are currently trying to |
447 | * allocate blocks for the tree root we can't do the fast caching since | ||
448 | * we likely hold important locks. | ||
446 | */ | 449 | */ |
447 | if (!trans->transaction->in_commit) { | 450 | if (!trans->transaction->in_commit && |
451 | (root && root != root->fs_info->tree_root)) { | ||
448 | spin_lock(&cache->lock); | 452 | spin_lock(&cache->lock); |
449 | if (cache->cached != BTRFS_CACHE_NO) { | 453 | if (cache->cached != BTRFS_CACHE_NO) { |
450 | spin_unlock(&cache->lock); | 454 | spin_unlock(&cache->lock); |
@@ -2741,6 +2745,7 @@ static int cache_save_setup(struct btrfs_block_group_cache *block_group, | |||
2741 | struct btrfs_root *root = block_group->fs_info->tree_root; | 2745 | struct btrfs_root *root = block_group->fs_info->tree_root; |
2742 | struct inode *inode = NULL; | 2746 | struct inode *inode = NULL; |
2743 | u64 alloc_hint = 0; | 2747 | u64 alloc_hint = 0; |
2748 | int dcs = BTRFS_DC_ERROR; | ||
2744 | int num_pages = 0; | 2749 | int num_pages = 0; |
2745 | int retries = 0; | 2750 | int retries = 0; |
2746 | int ret = 0; | 2751 | int ret = 0; |
@@ -2795,6 +2800,8 @@ again: | |||
2795 | 2800 | ||
2796 | spin_lock(&block_group->lock); | 2801 | spin_lock(&block_group->lock); |
2797 | if (block_group->cached != BTRFS_CACHE_FINISHED) { | 2802 | if (block_group->cached != BTRFS_CACHE_FINISHED) { |
2803 | /* We're not cached, don't bother trying to write stuff out */ | ||
2804 | dcs = BTRFS_DC_WRITTEN; | ||
2798 | spin_unlock(&block_group->lock); | 2805 | spin_unlock(&block_group->lock); |
2799 | goto out_put; | 2806 | goto out_put; |
2800 | } | 2807 | } |
@@ -2821,6 +2828,8 @@ again: | |||
2821 | ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, num_pages, | 2828 | ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, num_pages, |
2822 | num_pages, num_pages, | 2829 | num_pages, num_pages, |
2823 | &alloc_hint); | 2830 | &alloc_hint); |
2831 | if (!ret) | ||
2832 | dcs = BTRFS_DC_SETUP; | ||
2824 | btrfs_free_reserved_data_space(inode, num_pages); | 2833 | btrfs_free_reserved_data_space(inode, num_pages); |
2825 | out_put: | 2834 | out_put: |
2826 | iput(inode); | 2835 | iput(inode); |
@@ -2828,10 +2837,7 @@ out_free: | |||
2828 | btrfs_release_path(root, path); | 2837 | btrfs_release_path(root, path); |
2829 | out: | 2838 | out: |
2830 | spin_lock(&block_group->lock); | 2839 | spin_lock(&block_group->lock); |
2831 | if (ret) | 2840 | block_group->disk_cache_state = dcs; |
2832 | block_group->disk_cache_state = BTRFS_DC_ERROR; | ||
2833 | else | ||
2834 | block_group->disk_cache_state = BTRFS_DC_SETUP; | ||
2835 | spin_unlock(&block_group->lock); | 2841 | spin_unlock(&block_group->lock); |
2836 | 2842 | ||
2837 | return ret; | 2843 | return ret; |
@@ -3037,7 +3043,13 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags) | |||
3037 | 3043 | ||
3038 | u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags) | 3044 | u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags) |
3039 | { | 3045 | { |
3040 | u64 num_devices = root->fs_info->fs_devices->rw_devices; | 3046 | /* |
3047 | * we add in the count of missing devices because we want | ||
3048 | * to make sure that any RAID levels on a degraded FS | ||
3049 | * continue to be honored. | ||
3050 | */ | ||
3051 | u64 num_devices = root->fs_info->fs_devices->rw_devices + | ||
3052 | root->fs_info->fs_devices->missing_devices; | ||
3041 | 3053 | ||
3042 | if (num_devices == 1) | 3054 | if (num_devices == 1) |
3043 | flags &= ~(BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID0); | 3055 | flags &= ~(BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID0); |
@@ -4080,7 +4092,7 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
4080 | * space back to the block group, otherwise we will leak space. | 4092 | * space back to the block group, otherwise we will leak space. |
4081 | */ | 4093 | */ |
4082 | if (!alloc && cache->cached == BTRFS_CACHE_NO) | 4094 | if (!alloc && cache->cached == BTRFS_CACHE_NO) |
4083 | cache_block_group(cache, trans, 1); | 4095 | cache_block_group(cache, trans, NULL, 1); |
4084 | 4096 | ||
4085 | byte_in_group = bytenr - cache->key.objectid; | 4097 | byte_in_group = bytenr - cache->key.objectid; |
4086 | WARN_ON(byte_in_group > cache->key.offset); | 4098 | WARN_ON(byte_in_group > cache->key.offset); |
@@ -4930,11 +4942,31 @@ search: | |||
4930 | btrfs_get_block_group(block_group); | 4942 | btrfs_get_block_group(block_group); |
4931 | search_start = block_group->key.objectid; | 4943 | search_start = block_group->key.objectid; |
4932 | 4944 | ||
4945 | /* | ||
4946 | * this can happen if we end up cycling through all the | ||
4947 | * raid types, but we want to make sure we only allocate | ||
4948 | * for the proper type. | ||
4949 | */ | ||
4950 | if (!block_group_bits(block_group, data)) { | ||
4951 | u64 extra = BTRFS_BLOCK_GROUP_DUP | | ||
4952 | BTRFS_BLOCK_GROUP_RAID1 | | ||
4953 | BTRFS_BLOCK_GROUP_RAID10; | ||
4954 | |||
4955 | /* | ||
4956 | * if they asked for extra copies and this block group | ||
4957 | * doesn't provide them, bail. This does allow us to | ||
4958 | * fill raid0 from raid1. | ||
4959 | */ | ||
4960 | if ((data & extra) && !(block_group->flags & extra)) | ||
4961 | goto loop; | ||
4962 | } | ||
4963 | |||
4933 | have_block_group: | 4964 | have_block_group: |
4934 | if (unlikely(block_group->cached == BTRFS_CACHE_NO)) { | 4965 | if (unlikely(block_group->cached == BTRFS_CACHE_NO)) { |
4935 | u64 free_percent; | 4966 | u64 free_percent; |
4936 | 4967 | ||
4937 | ret = cache_block_group(block_group, trans, 1); | 4968 | ret = cache_block_group(block_group, trans, |
4969 | orig_root, 1); | ||
4938 | if (block_group->cached == BTRFS_CACHE_FINISHED) | 4970 | if (block_group->cached == BTRFS_CACHE_FINISHED) |
4939 | goto have_block_group; | 4971 | goto have_block_group; |
4940 | 4972 | ||
@@ -4958,7 +4990,8 @@ have_block_group: | |||
4958 | if (loop > LOOP_CACHING_NOWAIT || | 4990 | if (loop > LOOP_CACHING_NOWAIT || |
4959 | (loop > LOOP_FIND_IDEAL && | 4991 | (loop > LOOP_FIND_IDEAL && |
4960 | atomic_read(&space_info->caching_threads) < 2)) { | 4992 | atomic_read(&space_info->caching_threads) < 2)) { |
4961 | ret = cache_block_group(block_group, trans, 0); | 4993 | ret = cache_block_group(block_group, trans, |
4994 | orig_root, 0); | ||
4962 | BUG_ON(ret); | 4995 | BUG_ON(ret); |
4963 | } | 4996 | } |
4964 | found_uncached_bg = true; | 4997 | found_uncached_bg = true; |
@@ -5515,7 +5548,7 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, | |||
5515 | u64 num_bytes = ins->offset; | 5548 | u64 num_bytes = ins->offset; |
5516 | 5549 | ||
5517 | block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid); | 5550 | block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid); |
5518 | cache_block_group(block_group, trans, 0); | 5551 | cache_block_group(block_group, trans, NULL, 0); |
5519 | caching_ctl = get_caching_control(block_group); | 5552 | caching_ctl = get_caching_control(block_group); |
5520 | 5553 | ||
5521 | if (!caching_ctl) { | 5554 | if (!caching_ctl) { |
@@ -6300,9 +6333,13 @@ int btrfs_drop_snapshot(struct btrfs_root *root, | |||
6300 | NULL, NULL); | 6333 | NULL, NULL); |
6301 | BUG_ON(ret < 0); | 6334 | BUG_ON(ret < 0); |
6302 | if (ret > 0) { | 6335 | if (ret > 0) { |
6303 | ret = btrfs_del_orphan_item(trans, tree_root, | 6336 | /* if we fail to delete the orphan item this time |
6304 | root->root_key.objectid); | 6337 | * around, it'll get picked up the next time. |
6305 | BUG_ON(ret); | 6338 | * |
6339 | * The most common failure here is just -ENOENT. | ||
6340 | */ | ||
6341 | btrfs_del_orphan_item(trans, tree_root, | ||
6342 | root->root_key.objectid); | ||
6306 | } | 6343 | } |
6307 | } | 6344 | } |
6308 | 6345 | ||
@@ -7878,7 +7915,14 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags) | |||
7878 | u64 stripped = BTRFS_BLOCK_GROUP_RAID0 | | 7915 | u64 stripped = BTRFS_BLOCK_GROUP_RAID0 | |
7879 | BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10; | 7916 | BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10; |
7880 | 7917 | ||
7881 | num_devices = root->fs_info->fs_devices->rw_devices; | 7918 | /* |
7919 | * we add in the count of missing devices because we want | ||
7920 | * to make sure that any RAID levels on a degraded FS | ||
7921 | * continue to be honored. | ||
7922 | */ | ||
7923 | num_devices = root->fs_info->fs_devices->rw_devices + | ||
7924 | root->fs_info->fs_devices->missing_devices; | ||
7925 | |||
7882 | if (num_devices == 1) { | 7926 | if (num_devices == 1) { |
7883 | stripped |= BTRFS_BLOCK_GROUP_DUP; | 7927 | stripped |= BTRFS_BLOCK_GROUP_DUP; |
7884 | stripped = flags & ~stripped; | 7928 | stripped = flags & ~stripped; |
@@ -8247,7 +8291,6 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
8247 | break; | 8291 | break; |
8248 | if (ret != 0) | 8292 | if (ret != 0) |
8249 | goto error; | 8293 | goto error; |
8250 | |||
8251 | leaf = path->nodes[0]; | 8294 | leaf = path->nodes[0]; |
8252 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | 8295 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); |
8253 | cache = kzalloc(sizeof(*cache), GFP_NOFS); | 8296 | cache = kzalloc(sizeof(*cache), GFP_NOFS); |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index c1faded5fca0..66836d85763b 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -48,30 +48,34 @@ static noinline int btrfs_copy_from_user(loff_t pos, int num_pages, | |||
48 | struct page **prepared_pages, | 48 | struct page **prepared_pages, |
49 | struct iov_iter *i) | 49 | struct iov_iter *i) |
50 | { | 50 | { |
51 | size_t copied; | 51 | size_t copied = 0; |
52 | int pg = 0; | 52 | int pg = 0; |
53 | int offset = pos & (PAGE_CACHE_SIZE - 1); | 53 | int offset = pos & (PAGE_CACHE_SIZE - 1); |
54 | int total_copied = 0; | ||
54 | 55 | ||
55 | while (write_bytes > 0) { | 56 | while (write_bytes > 0) { |
56 | size_t count = min_t(size_t, | 57 | size_t count = min_t(size_t, |
57 | PAGE_CACHE_SIZE - offset, write_bytes); | 58 | PAGE_CACHE_SIZE - offset, write_bytes); |
58 | struct page *page = prepared_pages[pg]; | 59 | struct page *page = prepared_pages[pg]; |
59 | again: | 60 | /* |
60 | if (unlikely(iov_iter_fault_in_readable(i, count))) | 61 | * Copy data from userspace to the current page |
61 | return -EFAULT; | 62 | * |
62 | 63 | * Disable pagefault to avoid recursive lock since | |
63 | /* Copy data from userspace to the current page */ | 64 | * the pages are already locked |
64 | copied = iov_iter_copy_from_user(page, i, offset, count); | 65 | */ |
66 | pagefault_disable(); | ||
67 | copied = iov_iter_copy_from_user_atomic(page, i, offset, count); | ||
68 | pagefault_enable(); | ||
65 | 69 | ||
66 | /* Flush processor's dcache for this page */ | 70 | /* Flush processor's dcache for this page */ |
67 | flush_dcache_page(page); | 71 | flush_dcache_page(page); |
68 | iov_iter_advance(i, copied); | 72 | iov_iter_advance(i, copied); |
69 | write_bytes -= copied; | 73 | write_bytes -= copied; |
74 | total_copied += copied; | ||
70 | 75 | ||
76 | /* Return to btrfs_file_aio_write to fault page */ | ||
71 | if (unlikely(copied == 0)) { | 77 | if (unlikely(copied == 0)) { |
72 | count = min_t(size_t, PAGE_CACHE_SIZE - offset, | 78 | break; |
73 | iov_iter_single_seg_count(i)); | ||
74 | goto again; | ||
75 | } | 79 | } |
76 | 80 | ||
77 | if (unlikely(copied < PAGE_CACHE_SIZE - offset)) { | 81 | if (unlikely(copied < PAGE_CACHE_SIZE - offset)) { |
@@ -81,7 +85,7 @@ again: | |||
81 | offset = 0; | 85 | offset = 0; |
82 | } | 86 | } |
83 | } | 87 | } |
84 | return 0; | 88 | return total_copied; |
85 | } | 89 | } |
86 | 90 | ||
87 | /* | 91 | /* |
@@ -854,6 +858,8 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, | |||
854 | unsigned long last_index; | 858 | unsigned long last_index; |
855 | int will_write; | 859 | int will_write; |
856 | int buffered = 0; | 860 | int buffered = 0; |
861 | int copied = 0; | ||
862 | int dirty_pages = 0; | ||
857 | 863 | ||
858 | will_write = ((file->f_flags & O_DSYNC) || IS_SYNC(inode) || | 864 | will_write = ((file->f_flags & O_DSYNC) || IS_SYNC(inode) || |
859 | (file->f_flags & O_DIRECT)); | 865 | (file->f_flags & O_DIRECT)); |
@@ -970,7 +976,17 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, | |||
970 | WARN_ON(num_pages > nrptrs); | 976 | WARN_ON(num_pages > nrptrs); |
971 | memset(pages, 0, sizeof(struct page *) * nrptrs); | 977 | memset(pages, 0, sizeof(struct page *) * nrptrs); |
972 | 978 | ||
973 | ret = btrfs_delalloc_reserve_space(inode, write_bytes); | 979 | /* |
980 | * Fault pages before locking them in prepare_pages | ||
981 | * to avoid recursive lock | ||
982 | */ | ||
983 | if (unlikely(iov_iter_fault_in_readable(&i, write_bytes))) { | ||
984 | ret = -EFAULT; | ||
985 | goto out; | ||
986 | } | ||
987 | |||
988 | ret = btrfs_delalloc_reserve_space(inode, | ||
989 | num_pages << PAGE_CACHE_SHIFT); | ||
974 | if (ret) | 990 | if (ret) |
975 | goto out; | 991 | goto out; |
976 | 992 | ||
@@ -978,37 +994,49 @@ static ssize_t btrfs_file_aio_write(struct kiocb *iocb, | |||
978 | pos, first_index, last_index, | 994 | pos, first_index, last_index, |
979 | write_bytes); | 995 | write_bytes); |
980 | if (ret) { | 996 | if (ret) { |
981 | btrfs_delalloc_release_space(inode, write_bytes); | 997 | btrfs_delalloc_release_space(inode, |
998 | num_pages << PAGE_CACHE_SHIFT); | ||
982 | goto out; | 999 | goto out; |
983 | } | 1000 | } |
984 | 1001 | ||
985 | ret = btrfs_copy_from_user(pos, num_pages, | 1002 | copied = btrfs_copy_from_user(pos, num_pages, |
986 | write_bytes, pages, &i); | 1003 | write_bytes, pages, &i); |
987 | if (ret == 0) { | 1004 | dirty_pages = (copied + PAGE_CACHE_SIZE - 1) >> |
1005 | PAGE_CACHE_SHIFT; | ||
1006 | |||
1007 | if (num_pages > dirty_pages) { | ||
1008 | if (copied > 0) | ||
1009 | atomic_inc( | ||
1010 | &BTRFS_I(inode)->outstanding_extents); | ||
1011 | btrfs_delalloc_release_space(inode, | ||
1012 | (num_pages - dirty_pages) << | ||
1013 | PAGE_CACHE_SHIFT); | ||
1014 | } | ||
1015 | |||
1016 | if (copied > 0) { | ||
988 | dirty_and_release_pages(NULL, root, file, pages, | 1017 | dirty_and_release_pages(NULL, root, file, pages, |
989 | num_pages, pos, write_bytes); | 1018 | dirty_pages, pos, copied); |
990 | } | 1019 | } |
991 | 1020 | ||
992 | btrfs_drop_pages(pages, num_pages); | 1021 | btrfs_drop_pages(pages, num_pages); |
993 | if (ret) { | ||
994 | btrfs_delalloc_release_space(inode, write_bytes); | ||
995 | goto out; | ||
996 | } | ||
997 | 1022 | ||
998 | if (will_write) { | 1023 | if (copied > 0) { |
999 | filemap_fdatawrite_range(inode->i_mapping, pos, | 1024 | if (will_write) { |
1000 | pos + write_bytes - 1); | 1025 | filemap_fdatawrite_range(inode->i_mapping, pos, |
1001 | } else { | 1026 | pos + copied - 1); |
1002 | balance_dirty_pages_ratelimited_nr(inode->i_mapping, | 1027 | } else { |
1003 | num_pages); | 1028 | balance_dirty_pages_ratelimited_nr( |
1004 | if (num_pages < | 1029 | inode->i_mapping, |
1005 | (root->leafsize >> PAGE_CACHE_SHIFT) + 1) | 1030 | dirty_pages); |
1006 | btrfs_btree_balance_dirty(root, 1); | 1031 | if (dirty_pages < |
1007 | btrfs_throttle(root); | 1032 | (root->leafsize >> PAGE_CACHE_SHIFT) + 1) |
1033 | btrfs_btree_balance_dirty(root, 1); | ||
1034 | btrfs_throttle(root); | ||
1035 | } | ||
1008 | } | 1036 | } |
1009 | 1037 | ||
1010 | pos += write_bytes; | 1038 | pos += copied; |
1011 | num_written += write_bytes; | 1039 | num_written += copied; |
1012 | 1040 | ||
1013 | cond_resched(); | 1041 | cond_resched(); |
1014 | } | 1042 | } |
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c index 22ee0dc2e6b8..60d684266959 100644 --- a/fs/btrfs/free-space-cache.c +++ b/fs/btrfs/free-space-cache.c | |||
@@ -290,7 +290,7 @@ int load_free_space_cache(struct btrfs_fs_info *fs_info, | |||
290 | (unsigned long long)BTRFS_I(inode)->generation, | 290 | (unsigned long long)BTRFS_I(inode)->generation, |
291 | (unsigned long long)generation, | 291 | (unsigned long long)generation, |
292 | (unsigned long long)block_group->key.objectid); | 292 | (unsigned long long)block_group->key.objectid); |
293 | goto out; | 293 | goto free_cache; |
294 | } | 294 | } |
295 | 295 | ||
296 | if (!num_entries) | 296 | if (!num_entries) |
@@ -524,6 +524,12 @@ int btrfs_write_out_cache(struct btrfs_root *root, | |||
524 | return 0; | 524 | return 0; |
525 | } | 525 | } |
526 | 526 | ||
527 | node = rb_first(&block_group->free_space_offset); | ||
528 | if (!node) { | ||
529 | iput(inode); | ||
530 | return 0; | ||
531 | } | ||
532 | |||
527 | last_index = (i_size_read(inode) - 1) >> PAGE_CACHE_SHIFT; | 533 | last_index = (i_size_read(inode) - 1) >> PAGE_CACHE_SHIFT; |
528 | filemap_write_and_wait(inode->i_mapping); | 534 | filemap_write_and_wait(inode->i_mapping); |
529 | btrfs_wait_ordered_range(inode, inode->i_size & | 535 | btrfs_wait_ordered_range(inode, inode->i_size & |
@@ -543,10 +549,6 @@ int btrfs_write_out_cache(struct btrfs_root *root, | |||
543 | */ | 549 | */ |
544 | first_page_offset = (sizeof(u32) * num_checksums) + sizeof(u64); | 550 | first_page_offset = (sizeof(u32) * num_checksums) + sizeof(u64); |
545 | 551 | ||
546 | node = rb_first(&block_group->free_space_offset); | ||
547 | if (!node) | ||
548 | goto out_free; | ||
549 | |||
550 | /* | 552 | /* |
551 | * Lock all pages first so we can lock the extent safely. | 553 | * Lock all pages first so we can lock the extent safely. |
552 | * | 554 | * |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 8039390bd6a6..a0ff46a47895 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -495,7 +495,7 @@ again: | |||
495 | add_async_extent(async_cow, start, num_bytes, | 495 | add_async_extent(async_cow, start, num_bytes, |
496 | total_compressed, pages, nr_pages_ret); | 496 | total_compressed, pages, nr_pages_ret); |
497 | 497 | ||
498 | if (start + num_bytes < end && start + num_bytes < actual_end) { | 498 | if (start + num_bytes < end) { |
499 | start += num_bytes; | 499 | start += num_bytes; |
500 | pages = NULL; | 500 | pages = NULL; |
501 | cond_resched(); | 501 | cond_resched(); |
@@ -4084,7 +4084,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) | |||
4084 | int index; | 4084 | int index; |
4085 | int ret; | 4085 | int ret; |
4086 | 4086 | ||
4087 | dentry->d_op = &btrfs_dentry_operations; | 4087 | d_set_d_op(dentry, &btrfs_dentry_operations); |
4088 | 4088 | ||
4089 | if (dentry->d_name.len > BTRFS_NAME_LEN) | 4089 | if (dentry->d_name.len > BTRFS_NAME_LEN) |
4090 | return ERR_PTR(-ENAMETOOLONG); | 4090 | return ERR_PTR(-ENAMETOOLONG); |
@@ -4127,7 +4127,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) | |||
4127 | return inode; | 4127 | return inode; |
4128 | } | 4128 | } |
4129 | 4129 | ||
4130 | static int btrfs_dentry_delete(struct dentry *dentry) | 4130 | static int btrfs_dentry_delete(const struct dentry *dentry) |
4131 | { | 4131 | { |
4132 | struct btrfs_root *root; | 4132 | struct btrfs_root *root; |
4133 | 4133 | ||
@@ -5712,9 +5712,9 @@ static void btrfs_end_dio_bio(struct bio *bio, int err) | |||
5712 | 5712 | ||
5713 | if (err) { | 5713 | if (err) { |
5714 | printk(KERN_ERR "btrfs direct IO failed ino %lu rw %lu " | 5714 | printk(KERN_ERR "btrfs direct IO failed ino %lu rw %lu " |
5715 | "disk_bytenr %lu len %u err no %d\n", | 5715 | "sector %#Lx len %u err no %d\n", |
5716 | dip->inode->i_ino, bio->bi_rw, bio->bi_sector, | 5716 | dip->inode->i_ino, bio->bi_rw, |
5717 | bio->bi_size, err); | 5717 | (unsigned long long)bio->bi_sector, bio->bi_size, err); |
5718 | dip->errors = 1; | 5718 | dip->errors = 1; |
5719 | 5719 | ||
5720 | /* | 5720 | /* |
@@ -5934,8 +5934,7 @@ free_ordered: | |||
5934 | */ | 5934 | */ |
5935 | if (write) { | 5935 | if (write) { |
5936 | struct btrfs_ordered_extent *ordered; | 5936 | struct btrfs_ordered_extent *ordered; |
5937 | ordered = btrfs_lookup_ordered_extent(inode, | 5937 | ordered = btrfs_lookup_ordered_extent(inode, file_offset); |
5938 | dip->logical_offset); | ||
5939 | if (!test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags) && | 5938 | if (!test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags) && |
5940 | !test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags)) | 5939 | !test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags)) |
5941 | btrfs_free_reserved_extent(root, ordered->start, | 5940 | btrfs_free_reserved_extent(root, ordered->start, |
@@ -6496,6 +6495,13 @@ struct inode *btrfs_alloc_inode(struct super_block *sb) | |||
6496 | return inode; | 6495 | return inode; |
6497 | } | 6496 | } |
6498 | 6497 | ||
6498 | static void btrfs_i_callback(struct rcu_head *head) | ||
6499 | { | ||
6500 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
6501 | INIT_LIST_HEAD(&inode->i_dentry); | ||
6502 | kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode)); | ||
6503 | } | ||
6504 | |||
6499 | void btrfs_destroy_inode(struct inode *inode) | 6505 | void btrfs_destroy_inode(struct inode *inode) |
6500 | { | 6506 | { |
6501 | struct btrfs_ordered_extent *ordered; | 6507 | struct btrfs_ordered_extent *ordered; |
@@ -6565,7 +6571,7 @@ void btrfs_destroy_inode(struct inode *inode) | |||
6565 | inode_tree_del(inode); | 6571 | inode_tree_del(inode); |
6566 | btrfs_drop_extent_cache(inode, 0, (u64)-1, 0); | 6572 | btrfs_drop_extent_cache(inode, 0, (u64)-1, 0); |
6567 | free: | 6573 | free: |
6568 | kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode)); | 6574 | call_rcu(&inode->i_rcu, btrfs_i_callback); |
6569 | } | 6575 | } |
6570 | 6576 | ||
6571 | int btrfs_drop_inode(struct inode *inode) | 6577 | int btrfs_drop_inode(struct inode *inode) |
@@ -7205,11 +7211,11 @@ static int btrfs_set_page_dirty(struct page *page) | |||
7205 | return __set_page_dirty_nobuffers(page); | 7211 | return __set_page_dirty_nobuffers(page); |
7206 | } | 7212 | } |
7207 | 7213 | ||
7208 | static int btrfs_permission(struct inode *inode, int mask) | 7214 | static int btrfs_permission(struct inode *inode, int mask, unsigned int flags) |
7209 | { | 7215 | { |
7210 | if ((BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) && (mask & MAY_WRITE)) | 7216 | if ((BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) && (mask & MAY_WRITE)) |
7211 | return -EACCES; | 7217 | return -EACCES; |
7212 | return generic_permission(inode, mask, btrfs_check_acl); | 7218 | return generic_permission(inode, mask, flags, btrfs_check_acl); |
7213 | } | 7219 | } |
7214 | 7220 | ||
7215 | static const struct inode_operations btrfs_dir_inode_operations = { | 7221 | static const struct inode_operations btrfs_dir_inode_operations = { |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index f1c9bb4079ed..f87552a1d7ea 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -947,23 +947,42 @@ out: | |||
947 | 947 | ||
948 | static noinline int btrfs_ioctl_snap_create(struct file *file, | 948 | static noinline int btrfs_ioctl_snap_create(struct file *file, |
949 | void __user *arg, int subvol, | 949 | void __user *arg, int subvol, |
950 | int async) | 950 | int v2) |
951 | { | 951 | { |
952 | struct btrfs_ioctl_vol_args *vol_args = NULL; | 952 | struct btrfs_ioctl_vol_args *vol_args = NULL; |
953 | struct btrfs_ioctl_async_vol_args *async_vol_args = NULL; | 953 | struct btrfs_ioctl_vol_args_v2 *vol_args_v2 = NULL; |
954 | char *name; | 954 | char *name; |
955 | u64 fd; | 955 | u64 fd; |
956 | u64 transid = 0; | ||
957 | int ret; | 956 | int ret; |
958 | 957 | ||
959 | if (async) { | 958 | if (v2) { |
960 | async_vol_args = memdup_user(arg, sizeof(*async_vol_args)); | 959 | u64 transid = 0; |
961 | if (IS_ERR(async_vol_args)) | 960 | u64 *ptr = NULL; |
962 | return PTR_ERR(async_vol_args); | ||
963 | 961 | ||
964 | name = async_vol_args->name; | 962 | vol_args_v2 = memdup_user(arg, sizeof(*vol_args_v2)); |
965 | fd = async_vol_args->fd; | 963 | if (IS_ERR(vol_args_v2)) |
966 | async_vol_args->name[BTRFS_SNAPSHOT_NAME_MAX] = '\0'; | 964 | return PTR_ERR(vol_args_v2); |
965 | |||
966 | if (vol_args_v2->flags & ~BTRFS_SUBVOL_CREATE_ASYNC) { | ||
967 | ret = -EINVAL; | ||
968 | goto out; | ||
969 | } | ||
970 | |||
971 | name = vol_args_v2->name; | ||
972 | fd = vol_args_v2->fd; | ||
973 | vol_args_v2->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; | ||
974 | |||
975 | if (vol_args_v2->flags & BTRFS_SUBVOL_CREATE_ASYNC) | ||
976 | ptr = &transid; | ||
977 | |||
978 | ret = btrfs_ioctl_snap_create_transid(file, name, fd, | ||
979 | subvol, ptr); | ||
980 | |||
981 | if (ret == 0 && ptr && | ||
982 | copy_to_user(arg + | ||
983 | offsetof(struct btrfs_ioctl_vol_args_v2, | ||
984 | transid), ptr, sizeof(*ptr))) | ||
985 | ret = -EFAULT; | ||
967 | } else { | 986 | } else { |
968 | vol_args = memdup_user(arg, sizeof(*vol_args)); | 987 | vol_args = memdup_user(arg, sizeof(*vol_args)); |
969 | if (IS_ERR(vol_args)) | 988 | if (IS_ERR(vol_args)) |
@@ -971,20 +990,13 @@ static noinline int btrfs_ioctl_snap_create(struct file *file, | |||
971 | name = vol_args->name; | 990 | name = vol_args->name; |
972 | fd = vol_args->fd; | 991 | fd = vol_args->fd; |
973 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; | 992 | vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; |
974 | } | ||
975 | |||
976 | ret = btrfs_ioctl_snap_create_transid(file, name, fd, | ||
977 | subvol, &transid); | ||
978 | 993 | ||
979 | if (!ret && async) { | 994 | ret = btrfs_ioctl_snap_create_transid(file, name, fd, |
980 | if (copy_to_user(arg + | 995 | subvol, NULL); |
981 | offsetof(struct btrfs_ioctl_async_vol_args, | ||
982 | transid), &transid, sizeof(transid))) | ||
983 | return -EFAULT; | ||
984 | } | 996 | } |
985 | 997 | out: | |
986 | kfree(vol_args); | 998 | kfree(vol_args); |
987 | kfree(async_vol_args); | 999 | kfree(vol_args_v2); |
988 | 1000 | ||
989 | return ret; | 1001 | return ret; |
990 | } | 1002 | } |
@@ -2246,7 +2258,7 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
2246 | return btrfs_ioctl_getversion(file, argp); | 2258 | return btrfs_ioctl_getversion(file, argp); |
2247 | case BTRFS_IOC_SNAP_CREATE: | 2259 | case BTRFS_IOC_SNAP_CREATE: |
2248 | return btrfs_ioctl_snap_create(file, argp, 0, 0); | 2260 | return btrfs_ioctl_snap_create(file, argp, 0, 0); |
2249 | case BTRFS_IOC_SNAP_CREATE_ASYNC: | 2261 | case BTRFS_IOC_SNAP_CREATE_V2: |
2250 | return btrfs_ioctl_snap_create(file, argp, 0, 1); | 2262 | return btrfs_ioctl_snap_create(file, argp, 0, 1); |
2251 | case BTRFS_IOC_SUBVOL_CREATE: | 2263 | case BTRFS_IOC_SUBVOL_CREATE: |
2252 | return btrfs_ioctl_snap_create(file, argp, 1, 0); | 2264 | return btrfs_ioctl_snap_create(file, argp, 1, 0); |
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index 17c99ebdf960..c344d12c646b 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h | |||
@@ -30,11 +30,15 @@ struct btrfs_ioctl_vol_args { | |||
30 | char name[BTRFS_PATH_NAME_MAX + 1]; | 30 | char name[BTRFS_PATH_NAME_MAX + 1]; |
31 | }; | 31 | }; |
32 | 32 | ||
33 | #define BTRFS_SNAPSHOT_NAME_MAX 4079 | 33 | #define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0) |
34 | struct btrfs_ioctl_async_vol_args { | 34 | |
35 | #define BTRFS_SUBVOL_NAME_MAX 4039 | ||
36 | struct btrfs_ioctl_vol_args_v2 { | ||
35 | __s64 fd; | 37 | __s64 fd; |
36 | __u64 transid; | 38 | __u64 transid; |
37 | char name[BTRFS_SNAPSHOT_NAME_MAX + 1]; | 39 | __u64 flags; |
40 | __u64 unused[4]; | ||
41 | char name[BTRFS_SUBVOL_NAME_MAX + 1]; | ||
38 | }; | 42 | }; |
39 | 43 | ||
40 | #define BTRFS_INO_LOOKUP_PATH_MAX 4080 | 44 | #define BTRFS_INO_LOOKUP_PATH_MAX 4080 |
@@ -187,6 +191,6 @@ struct btrfs_ioctl_space_args { | |||
187 | struct btrfs_ioctl_space_args) | 191 | struct btrfs_ioctl_space_args) |
188 | #define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64) | 192 | #define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64) |
189 | #define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64) | 193 | #define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64) |
190 | #define BTRFS_IOC_SNAP_CREATE_ASYNC _IOW(BTRFS_IOCTL_MAGIC, 23, \ | 194 | #define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \ |
191 | struct btrfs_ioctl_async_vol_args) | 195 | struct btrfs_ioctl_vol_args_v2) |
192 | #endif | 196 | #endif |
diff --git a/fs/btrfs/orphan.c b/fs/btrfs/orphan.c index 79cba5fbc28e..f8be250963a0 100644 --- a/fs/btrfs/orphan.c +++ b/fs/btrfs/orphan.c | |||
@@ -56,8 +56,12 @@ int btrfs_del_orphan_item(struct btrfs_trans_handle *trans, | |||
56 | return -ENOMEM; | 56 | return -ENOMEM; |
57 | 57 | ||
58 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); | 58 | ret = btrfs_search_slot(trans, root, &key, path, -1, 1); |
59 | if (ret) | 59 | if (ret < 0) |
60 | goto out; | 60 | goto out; |
61 | if (ret) { | ||
62 | ret = -ENOENT; | ||
63 | goto out; | ||
64 | } | ||
61 | 65 | ||
62 | ret = btrfs_del_item(trans, root, path); | 66 | ret = btrfs_del_item(trans, root, path); |
63 | 67 | ||
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index dbb51ea7a13c..883c6fa1367e 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -685,9 +685,9 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, | |||
685 | mutex_unlock(&root->d_inode->i_mutex); | 685 | mutex_unlock(&root->d_inode->i_mutex); |
686 | 686 | ||
687 | if (IS_ERR(new_root)) { | 687 | if (IS_ERR(new_root)) { |
688 | dput(root); | ||
688 | deactivate_locked_super(s); | 689 | deactivate_locked_super(s); |
689 | error = PTR_ERR(new_root); | 690 | error = PTR_ERR(new_root); |
690 | dput(root); | ||
691 | goto error_free_subvol_name; | 691 | goto error_free_subvol_name; |
692 | } | 692 | } |
693 | if (!new_root->d_inode) { | 693 | if (!new_root->d_inode) { |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index cc04dc1445d6..6b9884507837 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -412,12 +412,16 @@ static noinline int device_list_add(const char *path, | |||
412 | 412 | ||
413 | device->fs_devices = fs_devices; | 413 | device->fs_devices = fs_devices; |
414 | fs_devices->num_devices++; | 414 | fs_devices->num_devices++; |
415 | } else if (strcmp(device->name, path)) { | 415 | } else if (!device->name || strcmp(device->name, path)) { |
416 | name = kstrdup(path, GFP_NOFS); | 416 | name = kstrdup(path, GFP_NOFS); |
417 | if (!name) | 417 | if (!name) |
418 | return -ENOMEM; | 418 | return -ENOMEM; |
419 | kfree(device->name); | 419 | kfree(device->name); |
420 | device->name = name; | 420 | device->name = name; |
421 | if (device->missing) { | ||
422 | fs_devices->missing_devices--; | ||
423 | device->missing = 0; | ||
424 | } | ||
421 | } | 425 | } |
422 | 426 | ||
423 | if (found_transid > fs_devices->latest_trans) { | 427 | if (found_transid > fs_devices->latest_trans) { |
@@ -1236,6 +1240,9 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path) | |||
1236 | 1240 | ||
1237 | device->fs_devices->num_devices--; | 1241 | device->fs_devices->num_devices--; |
1238 | 1242 | ||
1243 | if (device->missing) | ||
1244 | root->fs_info->fs_devices->missing_devices--; | ||
1245 | |||
1239 | next_device = list_entry(root->fs_info->fs_devices->devices.next, | 1246 | next_device = list_entry(root->fs_info->fs_devices->devices.next, |
1240 | struct btrfs_device, dev_list); | 1247 | struct btrfs_device, dev_list); |
1241 | if (device->bdev == root->fs_info->sb->s_bdev) | 1248 | if (device->bdev == root->fs_info->sb->s_bdev) |
@@ -3080,7 +3087,9 @@ static struct btrfs_device *add_missing_dev(struct btrfs_root *root, | |||
3080 | device->devid = devid; | 3087 | device->devid = devid; |
3081 | device->work.func = pending_bios_fn; | 3088 | device->work.func = pending_bios_fn; |
3082 | device->fs_devices = fs_devices; | 3089 | device->fs_devices = fs_devices; |
3090 | device->missing = 1; | ||
3083 | fs_devices->num_devices++; | 3091 | fs_devices->num_devices++; |
3092 | fs_devices->missing_devices++; | ||
3084 | spin_lock_init(&device->io_lock); | 3093 | spin_lock_init(&device->io_lock); |
3085 | INIT_LIST_HEAD(&device->dev_alloc_list); | 3094 | INIT_LIST_HEAD(&device->dev_alloc_list); |
3086 | memcpy(device->uuid, dev_uuid, BTRFS_UUID_SIZE); | 3095 | memcpy(device->uuid, dev_uuid, BTRFS_UUID_SIZE); |
@@ -3278,6 +3287,15 @@ static int read_one_dev(struct btrfs_root *root, | |||
3278 | device = add_missing_dev(root, devid, dev_uuid); | 3287 | device = add_missing_dev(root, devid, dev_uuid); |
3279 | if (!device) | 3288 | if (!device) |
3280 | return -ENOMEM; | 3289 | return -ENOMEM; |
3290 | } else if (!device->missing) { | ||
3291 | /* | ||
3292 | * this happens when a device that was properly setup | ||
3293 | * in the device info lists suddenly goes bad. | ||
3294 | * device->bdev is NULL, and so we have to set | ||
3295 | * device->missing to one here | ||
3296 | */ | ||
3297 | root->fs_info->fs_devices->missing_devices++; | ||
3298 | device->missing = 1; | ||
3281 | } | 3299 | } |
3282 | } | 3300 | } |
3283 | 3301 | ||
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 2b638b6e4eea..2740db49eb04 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h | |||
@@ -44,6 +44,7 @@ struct btrfs_device { | |||
44 | 44 | ||
45 | int writeable; | 45 | int writeable; |
46 | int in_fs_metadata; | 46 | int in_fs_metadata; |
47 | int missing; | ||
47 | 48 | ||
48 | spinlock_t io_lock; | 49 | spinlock_t io_lock; |
49 | 50 | ||
@@ -93,6 +94,7 @@ struct btrfs_fs_devices { | |||
93 | u64 num_devices; | 94 | u64 num_devices; |
94 | u64 open_devices; | 95 | u64 open_devices; |
95 | u64 rw_devices; | 96 | u64 rw_devices; |
97 | u64 missing_devices; | ||
96 | u64 total_rw_bytes; | 98 | u64 total_rw_bytes; |
97 | struct block_device *latest_bdev; | 99 | struct block_device *latest_bdev; |
98 | 100 | ||
diff --git a/fs/buffer.c b/fs/buffer.c index 5930e382959b..2219a76e2caf 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -1270,12 +1270,10 @@ static inline void check_irqs_on(void) | |||
1270 | static void bh_lru_install(struct buffer_head *bh) | 1270 | static void bh_lru_install(struct buffer_head *bh) |
1271 | { | 1271 | { |
1272 | struct buffer_head *evictee = NULL; | 1272 | struct buffer_head *evictee = NULL; |
1273 | struct bh_lru *lru; | ||
1274 | 1273 | ||
1275 | check_irqs_on(); | 1274 | check_irqs_on(); |
1276 | bh_lru_lock(); | 1275 | bh_lru_lock(); |
1277 | lru = &__get_cpu_var(bh_lrus); | 1276 | if (__this_cpu_read(bh_lrus.bhs[0]) != bh) { |
1278 | if (lru->bhs[0] != bh) { | ||
1279 | struct buffer_head *bhs[BH_LRU_SIZE]; | 1277 | struct buffer_head *bhs[BH_LRU_SIZE]; |
1280 | int in; | 1278 | int in; |
1281 | int out = 0; | 1279 | int out = 0; |
@@ -1283,7 +1281,8 @@ static void bh_lru_install(struct buffer_head *bh) | |||
1283 | get_bh(bh); | 1281 | get_bh(bh); |
1284 | bhs[out++] = bh; | 1282 | bhs[out++] = bh; |
1285 | for (in = 0; in < BH_LRU_SIZE; in++) { | 1283 | for (in = 0; in < BH_LRU_SIZE; in++) { |
1286 | struct buffer_head *bh2 = lru->bhs[in]; | 1284 | struct buffer_head *bh2 = |
1285 | __this_cpu_read(bh_lrus.bhs[in]); | ||
1287 | 1286 | ||
1288 | if (bh2 == bh) { | 1287 | if (bh2 == bh) { |
1289 | __brelse(bh2); | 1288 | __brelse(bh2); |
@@ -1298,7 +1297,7 @@ static void bh_lru_install(struct buffer_head *bh) | |||
1298 | } | 1297 | } |
1299 | while (out < BH_LRU_SIZE) | 1298 | while (out < BH_LRU_SIZE) |
1300 | bhs[out++] = NULL; | 1299 | bhs[out++] = NULL; |
1301 | memcpy(lru->bhs, bhs, sizeof(bhs)); | 1300 | memcpy(__this_cpu_ptr(&bh_lrus.bhs), bhs, sizeof(bhs)); |
1302 | } | 1301 | } |
1303 | bh_lru_unlock(); | 1302 | bh_lru_unlock(); |
1304 | 1303 | ||
@@ -1313,23 +1312,22 @@ static struct buffer_head * | |||
1313 | lookup_bh_lru(struct block_device *bdev, sector_t block, unsigned size) | 1312 | lookup_bh_lru(struct block_device *bdev, sector_t block, unsigned size) |
1314 | { | 1313 | { |
1315 | struct buffer_head *ret = NULL; | 1314 | struct buffer_head *ret = NULL; |
1316 | struct bh_lru *lru; | ||
1317 | unsigned int i; | 1315 | unsigned int i; |
1318 | 1316 | ||
1319 | check_irqs_on(); | 1317 | check_irqs_on(); |
1320 | bh_lru_lock(); | 1318 | bh_lru_lock(); |
1321 | lru = &__get_cpu_var(bh_lrus); | ||
1322 | for (i = 0; i < BH_LRU_SIZE; i++) { | 1319 | for (i = 0; i < BH_LRU_SIZE; i++) { |
1323 | struct buffer_head *bh = lru->bhs[i]; | 1320 | struct buffer_head *bh = __this_cpu_read(bh_lrus.bhs[i]); |
1324 | 1321 | ||
1325 | if (bh && bh->b_bdev == bdev && | 1322 | if (bh && bh->b_bdev == bdev && |
1326 | bh->b_blocknr == block && bh->b_size == size) { | 1323 | bh->b_blocknr == block && bh->b_size == size) { |
1327 | if (i) { | 1324 | if (i) { |
1328 | while (i) { | 1325 | while (i) { |
1329 | lru->bhs[i] = lru->bhs[i - 1]; | 1326 | __this_cpu_write(bh_lrus.bhs[i], |
1327 | __this_cpu_read(bh_lrus.bhs[i - 1])); | ||
1330 | i--; | 1328 | i--; |
1331 | } | 1329 | } |
1332 | lru->bhs[0] = bh; | 1330 | __this_cpu_write(bh_lrus.bhs[0], bh); |
1333 | } | 1331 | } |
1334 | get_bh(bh); | 1332 | get_bh(bh); |
1335 | ret = bh; | 1333 | ret = bh; |
@@ -3203,22 +3201,23 @@ static void recalc_bh_state(void) | |||
3203 | int i; | 3201 | int i; |
3204 | int tot = 0; | 3202 | int tot = 0; |
3205 | 3203 | ||
3206 | if (__get_cpu_var(bh_accounting).ratelimit++ < 4096) | 3204 | if (__this_cpu_inc_return(bh_accounting.ratelimit) - 1 < 4096) |
3207 | return; | 3205 | return; |
3208 | __get_cpu_var(bh_accounting).ratelimit = 0; | 3206 | __this_cpu_write(bh_accounting.ratelimit, 0); |
3209 | for_each_online_cpu(i) | 3207 | for_each_online_cpu(i) |
3210 | tot += per_cpu(bh_accounting, i).nr; | 3208 | tot += per_cpu(bh_accounting, i).nr; |
3211 | buffer_heads_over_limit = (tot > max_buffer_heads); | 3209 | buffer_heads_over_limit = (tot > max_buffer_heads); |
3212 | } | 3210 | } |
3213 | 3211 | ||
3214 | struct buffer_head *alloc_buffer_head(gfp_t gfp_flags) | 3212 | struct buffer_head *alloc_buffer_head(gfp_t gfp_flags) |
3215 | { | 3213 | { |
3216 | struct buffer_head *ret = kmem_cache_zalloc(bh_cachep, gfp_flags); | 3214 | struct buffer_head *ret = kmem_cache_zalloc(bh_cachep, gfp_flags); |
3217 | if (ret) { | 3215 | if (ret) { |
3218 | INIT_LIST_HEAD(&ret->b_assoc_buffers); | 3216 | INIT_LIST_HEAD(&ret->b_assoc_buffers); |
3219 | get_cpu_var(bh_accounting).nr++; | 3217 | preempt_disable(); |
3218 | __this_cpu_inc(bh_accounting.nr); | ||
3220 | recalc_bh_state(); | 3219 | recalc_bh_state(); |
3221 | put_cpu_var(bh_accounting); | 3220 | preempt_enable(); |
3222 | } | 3221 | } |
3223 | return ret; | 3222 | return ret; |
3224 | } | 3223 | } |
@@ -3228,9 +3227,10 @@ void free_buffer_head(struct buffer_head *bh) | |||
3228 | { | 3227 | { |
3229 | BUG_ON(!list_empty(&bh->b_assoc_buffers)); | 3228 | BUG_ON(!list_empty(&bh->b_assoc_buffers)); |
3230 | kmem_cache_free(bh_cachep, bh); | 3229 | kmem_cache_free(bh_cachep, bh); |
3231 | get_cpu_var(bh_accounting).nr--; | 3230 | preempt_disable(); |
3231 | __this_cpu_dec(bh_accounting.nr); | ||
3232 | recalc_bh_state(); | 3232 | recalc_bh_state(); |
3233 | put_cpu_var(bh_accounting); | 3233 | preempt_enable(); |
3234 | } | 3234 | } |
3235 | EXPORT_SYMBOL(free_buffer_head); | 3235 | EXPORT_SYMBOL(free_buffer_head); |
3236 | 3236 | ||
@@ -3243,9 +3243,8 @@ static void buffer_exit_cpu(int cpu) | |||
3243 | brelse(b->bhs[i]); | 3243 | brelse(b->bhs[i]); |
3244 | b->bhs[i] = NULL; | 3244 | b->bhs[i] = NULL; |
3245 | } | 3245 | } |
3246 | get_cpu_var(bh_accounting).nr += per_cpu(bh_accounting, cpu).nr; | 3246 | this_cpu_add(bh_accounting.nr, per_cpu(bh_accounting, cpu).nr); |
3247 | per_cpu(bh_accounting, cpu).nr = 0; | 3247 | per_cpu(bh_accounting, cpu).nr = 0; |
3248 | put_cpu_var(bh_accounting); | ||
3249 | } | 3248 | } |
3250 | 3249 | ||
3251 | static int buffer_cpu_notify(struct notifier_block *self, | 3250 | static int buffer_cpu_notify(struct notifier_block *self, |
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 7d447af84ec4..fa7ca04ee816 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
@@ -40,12 +40,13 @@ int ceph_init_dentry(struct dentry *dentry) | |||
40 | if (dentry->d_fsdata) | 40 | if (dentry->d_fsdata) |
41 | return 0; | 41 | return 0; |
42 | 42 | ||
43 | if (ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP) | 43 | if (dentry->d_parent == NULL || /* nfs fh_to_dentry */ |
44 | dentry->d_op = &ceph_dentry_ops; | 44 | ceph_snap(dentry->d_parent->d_inode) == CEPH_NOSNAP) |
45 | d_set_d_op(dentry, &ceph_dentry_ops); | ||
45 | else if (ceph_snap(dentry->d_parent->d_inode) == CEPH_SNAPDIR) | 46 | else if (ceph_snap(dentry->d_parent->d_inode) == CEPH_SNAPDIR) |
46 | dentry->d_op = &ceph_snapdir_dentry_ops; | 47 | d_set_d_op(dentry, &ceph_snapdir_dentry_ops); |
47 | else | 48 | else |
48 | dentry->d_op = &ceph_snap_dentry_ops; | 49 | d_set_d_op(dentry, &ceph_snap_dentry_ops); |
49 | 50 | ||
50 | di = kmem_cache_alloc(ceph_dentry_cachep, GFP_NOFS | __GFP_ZERO); | 51 | di = kmem_cache_alloc(ceph_dentry_cachep, GFP_NOFS | __GFP_ZERO); |
51 | if (!di) | 52 | if (!di) |
@@ -111,11 +112,11 @@ static int __dcache_readdir(struct file *filp, | |||
111 | dout("__dcache_readdir %p at %llu (last %p)\n", dir, filp->f_pos, | 112 | dout("__dcache_readdir %p at %llu (last %p)\n", dir, filp->f_pos, |
112 | last); | 113 | last); |
113 | 114 | ||
114 | spin_lock(&dcache_lock); | 115 | spin_lock(&parent->d_lock); |
115 | 116 | ||
116 | /* start at beginning? */ | 117 | /* start at beginning? */ |
117 | if (filp->f_pos == 2 || (last && | 118 | if (filp->f_pos == 2 || last == NULL || |
118 | filp->f_pos < ceph_dentry(last)->offset)) { | 119 | filp->f_pos < ceph_dentry(last)->offset) { |
119 | if (list_empty(&parent->d_subdirs)) | 120 | if (list_empty(&parent->d_subdirs)) |
120 | goto out_unlock; | 121 | goto out_unlock; |
121 | p = parent->d_subdirs.prev; | 122 | p = parent->d_subdirs.prev; |
@@ -135,6 +136,7 @@ more: | |||
135 | fi->at_end = 1; | 136 | fi->at_end = 1; |
136 | goto out_unlock; | 137 | goto out_unlock; |
137 | } | 138 | } |
139 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | ||
138 | if (!d_unhashed(dentry) && dentry->d_inode && | 140 | if (!d_unhashed(dentry) && dentry->d_inode && |
139 | ceph_snap(dentry->d_inode) != CEPH_SNAPDIR && | 141 | ceph_snap(dentry->d_inode) != CEPH_SNAPDIR && |
140 | ceph_ino(dentry->d_inode) != CEPH_INO_CEPH && | 142 | ceph_ino(dentry->d_inode) != CEPH_INO_CEPH && |
@@ -144,13 +146,15 @@ more: | |||
144 | dentry->d_name.len, dentry->d_name.name, di->offset, | 146 | dentry->d_name.len, dentry->d_name.name, di->offset, |
145 | filp->f_pos, d_unhashed(dentry) ? " unhashed" : "", | 147 | filp->f_pos, d_unhashed(dentry) ? " unhashed" : "", |
146 | !dentry->d_inode ? " null" : ""); | 148 | !dentry->d_inode ? " null" : ""); |
149 | spin_unlock(&dentry->d_lock); | ||
147 | p = p->prev; | 150 | p = p->prev; |
148 | dentry = list_entry(p, struct dentry, d_u.d_child); | 151 | dentry = list_entry(p, struct dentry, d_u.d_child); |
149 | di = ceph_dentry(dentry); | 152 | di = ceph_dentry(dentry); |
150 | } | 153 | } |
151 | 154 | ||
152 | atomic_inc(&dentry->d_count); | 155 | dget_dlock(dentry); |
153 | spin_unlock(&dcache_lock); | 156 | spin_unlock(&dentry->d_lock); |
157 | spin_unlock(&parent->d_lock); | ||
154 | 158 | ||
155 | dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, filp->f_pos, | 159 | dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, filp->f_pos, |
156 | dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode); | 160 | dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode); |
@@ -176,19 +180,19 @@ more: | |||
176 | 180 | ||
177 | filp->f_pos++; | 181 | filp->f_pos++; |
178 | 182 | ||
179 | /* make sure a dentry wasn't dropped while we didn't have dcache_lock */ | 183 | /* make sure a dentry wasn't dropped while we didn't have parent lock */ |
180 | if (!ceph_i_test(dir, CEPH_I_COMPLETE)) { | 184 | if (!ceph_i_test(dir, CEPH_I_COMPLETE)) { |
181 | dout(" lost I_COMPLETE on %p; falling back to mds\n", dir); | 185 | dout(" lost I_COMPLETE on %p; falling back to mds\n", dir); |
182 | err = -EAGAIN; | 186 | err = -EAGAIN; |
183 | goto out; | 187 | goto out; |
184 | } | 188 | } |
185 | 189 | ||
186 | spin_lock(&dcache_lock); | 190 | spin_lock(&parent->d_lock); |
187 | p = p->prev; /* advance to next dentry */ | 191 | p = p->prev; /* advance to next dentry */ |
188 | goto more; | 192 | goto more; |
189 | 193 | ||
190 | out_unlock: | 194 | out_unlock: |
191 | spin_unlock(&dcache_lock); | 195 | spin_unlock(&parent->d_lock); |
192 | out: | 196 | out: |
193 | if (last) | 197 | if (last) |
194 | dput(last); | 198 | dput(last); |
@@ -986,7 +990,12 @@ static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry) | |||
986 | */ | 990 | */ |
987 | static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd) | 991 | static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd) |
988 | { | 992 | { |
989 | struct inode *dir = dentry->d_parent->d_inode; | 993 | struct inode *dir; |
994 | |||
995 | if (nd->flags & LOOKUP_RCU) | ||
996 | return -ECHILD; | ||
997 | |||
998 | dir = dentry->d_parent->d_inode; | ||
990 | 999 | ||
991 | dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry, | 1000 | dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry, |
992 | dentry->d_name.len, dentry->d_name.name, dentry->d_inode, | 1001 | dentry->d_name.len, dentry->d_name.name, dentry->d_inode, |
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 8d79b8912e31..7d0e4a82d898 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c | |||
@@ -282,7 +282,8 @@ int ceph_release(struct inode *inode, struct file *file) | |||
282 | static int striped_read(struct inode *inode, | 282 | static int striped_read(struct inode *inode, |
283 | u64 off, u64 len, | 283 | u64 off, u64 len, |
284 | struct page **pages, int num_pages, | 284 | struct page **pages, int num_pages, |
285 | int *checkeof, bool align_to_pages) | 285 | int *checkeof, bool align_to_pages, |
286 | unsigned long buf_align) | ||
286 | { | 287 | { |
287 | struct ceph_fs_client *fsc = ceph_inode_to_client(inode); | 288 | struct ceph_fs_client *fsc = ceph_inode_to_client(inode); |
288 | struct ceph_inode_info *ci = ceph_inode(inode); | 289 | struct ceph_inode_info *ci = ceph_inode(inode); |
@@ -307,7 +308,7 @@ static int striped_read(struct inode *inode, | |||
307 | 308 | ||
308 | more: | 309 | more: |
309 | if (align_to_pages) | 310 | if (align_to_pages) |
310 | page_align = (pos - io_align) & ~PAGE_MASK; | 311 | page_align = (pos - io_align + buf_align) & ~PAGE_MASK; |
311 | else | 312 | else |
312 | page_align = pos & ~PAGE_MASK; | 313 | page_align = pos & ~PAGE_MASK; |
313 | this_len = left; | 314 | this_len = left; |
@@ -376,16 +377,18 @@ static ssize_t ceph_sync_read(struct file *file, char __user *data, | |||
376 | struct inode *inode = file->f_dentry->d_inode; | 377 | struct inode *inode = file->f_dentry->d_inode; |
377 | struct page **pages; | 378 | struct page **pages; |
378 | u64 off = *poff; | 379 | u64 off = *poff; |
379 | int num_pages = calc_pages_for(off, len); | 380 | int num_pages, ret; |
380 | int ret; | ||
381 | 381 | ||
382 | dout("sync_read on file %p %llu~%u %s\n", file, off, len, | 382 | dout("sync_read on file %p %llu~%u %s\n", file, off, len, |
383 | (file->f_flags & O_DIRECT) ? "O_DIRECT" : ""); | 383 | (file->f_flags & O_DIRECT) ? "O_DIRECT" : ""); |
384 | 384 | ||
385 | if (file->f_flags & O_DIRECT) | 385 | if (file->f_flags & O_DIRECT) { |
386 | pages = ceph_get_direct_page_vector(data, num_pages); | 386 | num_pages = calc_pages_for((unsigned long)data, len); |
387 | else | 387 | pages = ceph_get_direct_page_vector(data, num_pages, true); |
388 | } else { | ||
389 | num_pages = calc_pages_for(off, len); | ||
388 | pages = ceph_alloc_page_vector(num_pages, GFP_NOFS); | 390 | pages = ceph_alloc_page_vector(num_pages, GFP_NOFS); |
391 | } | ||
389 | if (IS_ERR(pages)) | 392 | if (IS_ERR(pages)) |
390 | return PTR_ERR(pages); | 393 | return PTR_ERR(pages); |
391 | 394 | ||
@@ -400,7 +403,8 @@ static ssize_t ceph_sync_read(struct file *file, char __user *data, | |||
400 | goto done; | 403 | goto done; |
401 | 404 | ||
402 | ret = striped_read(inode, off, len, pages, num_pages, checkeof, | 405 | ret = striped_read(inode, off, len, pages, num_pages, checkeof, |
403 | file->f_flags & O_DIRECT); | 406 | file->f_flags & O_DIRECT, |
407 | (unsigned long)data & ~PAGE_MASK); | ||
404 | 408 | ||
405 | if (ret >= 0 && (file->f_flags & O_DIRECT) == 0) | 409 | if (ret >= 0 && (file->f_flags & O_DIRECT) == 0) |
406 | ret = ceph_copy_page_vector_to_user(pages, data, off, ret); | 410 | ret = ceph_copy_page_vector_to_user(pages, data, off, ret); |
@@ -409,7 +413,7 @@ static ssize_t ceph_sync_read(struct file *file, char __user *data, | |||
409 | 413 | ||
410 | done: | 414 | done: |
411 | if (file->f_flags & O_DIRECT) | 415 | if (file->f_flags & O_DIRECT) |
412 | ceph_put_page_vector(pages, num_pages); | 416 | ceph_put_page_vector(pages, num_pages, true); |
413 | else | 417 | else |
414 | ceph_release_page_vector(pages, num_pages); | 418 | ceph_release_page_vector(pages, num_pages); |
415 | dout("sync_read result %d\n", ret); | 419 | dout("sync_read result %d\n", ret); |
@@ -456,6 +460,7 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data, | |||
456 | int do_sync = 0; | 460 | int do_sync = 0; |
457 | int check_caps = 0; | 461 | int check_caps = 0; |
458 | int page_align, io_align; | 462 | int page_align, io_align; |
463 | unsigned long buf_align; | ||
459 | int ret; | 464 | int ret; |
460 | struct timespec mtime = CURRENT_TIME; | 465 | struct timespec mtime = CURRENT_TIME; |
461 | 466 | ||
@@ -471,6 +476,7 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data, | |||
471 | pos = *offset; | 476 | pos = *offset; |
472 | 477 | ||
473 | io_align = pos & ~PAGE_MASK; | 478 | io_align = pos & ~PAGE_MASK; |
479 | buf_align = (unsigned long)data & ~PAGE_MASK; | ||
474 | 480 | ||
475 | ret = filemap_write_and_wait_range(inode->i_mapping, pos, pos + left); | 481 | ret = filemap_write_and_wait_range(inode->i_mapping, pos, pos + left); |
476 | if (ret < 0) | 482 | if (ret < 0) |
@@ -496,12 +502,15 @@ static ssize_t ceph_sync_write(struct file *file, const char __user *data, | |||
496 | */ | 502 | */ |
497 | more: | 503 | more: |
498 | len = left; | 504 | len = left; |
499 | if (file->f_flags & O_DIRECT) | 505 | if (file->f_flags & O_DIRECT) { |
500 | /* write from beginning of first page, regardless of | 506 | /* write from beginning of first page, regardless of |
501 | io alignment */ | 507 | io alignment */ |
502 | page_align = (pos - io_align) & ~PAGE_MASK; | 508 | page_align = (pos - io_align + buf_align) & ~PAGE_MASK; |
503 | else | 509 | num_pages = calc_pages_for((unsigned long)data, len); |
510 | } else { | ||
504 | page_align = pos & ~PAGE_MASK; | 511 | page_align = pos & ~PAGE_MASK; |
512 | num_pages = calc_pages_for(pos, len); | ||
513 | } | ||
505 | req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout, | 514 | req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout, |
506 | ceph_vino(inode), pos, &len, | 515 | ceph_vino(inode), pos, &len, |
507 | CEPH_OSD_OP_WRITE, flags, | 516 | CEPH_OSD_OP_WRITE, flags, |
@@ -512,10 +521,8 @@ more: | |||
512 | if (!req) | 521 | if (!req) |
513 | return -ENOMEM; | 522 | return -ENOMEM; |
514 | 523 | ||
515 | num_pages = calc_pages_for(pos, len); | ||
516 | |||
517 | if (file->f_flags & O_DIRECT) { | 524 | if (file->f_flags & O_DIRECT) { |
518 | pages = ceph_get_direct_page_vector(data, num_pages); | 525 | pages = ceph_get_direct_page_vector(data, num_pages, false); |
519 | if (IS_ERR(pages)) { | 526 | if (IS_ERR(pages)) { |
520 | ret = PTR_ERR(pages); | 527 | ret = PTR_ERR(pages); |
521 | goto out; | 528 | goto out; |
@@ -565,7 +572,7 @@ more: | |||
565 | } | 572 | } |
566 | 573 | ||
567 | if (file->f_flags & O_DIRECT) | 574 | if (file->f_flags & O_DIRECT) |
568 | ceph_put_page_vector(pages, num_pages); | 575 | ceph_put_page_vector(pages, num_pages, false); |
569 | else if (file->f_flags & O_SYNC) | 576 | else if (file->f_flags & O_SYNC) |
570 | ceph_release_page_vector(pages, num_pages); | 577 | ceph_release_page_vector(pages, num_pages); |
571 | 578 | ||
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index bf1286588f26..e61de4f7b99d 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
@@ -368,6 +368,15 @@ struct inode *ceph_alloc_inode(struct super_block *sb) | |||
368 | return &ci->vfs_inode; | 368 | return &ci->vfs_inode; |
369 | } | 369 | } |
370 | 370 | ||
371 | static void ceph_i_callback(struct rcu_head *head) | ||
372 | { | ||
373 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
374 | struct ceph_inode_info *ci = ceph_inode(inode); | ||
375 | |||
376 | INIT_LIST_HEAD(&inode->i_dentry); | ||
377 | kmem_cache_free(ceph_inode_cachep, ci); | ||
378 | } | ||
379 | |||
371 | void ceph_destroy_inode(struct inode *inode) | 380 | void ceph_destroy_inode(struct inode *inode) |
372 | { | 381 | { |
373 | struct ceph_inode_info *ci = ceph_inode(inode); | 382 | struct ceph_inode_info *ci = ceph_inode(inode); |
@@ -407,7 +416,7 @@ void ceph_destroy_inode(struct inode *inode) | |||
407 | if (ci->i_xattrs.prealloc_blob) | 416 | if (ci->i_xattrs.prealloc_blob) |
408 | ceph_buffer_put(ci->i_xattrs.prealloc_blob); | 417 | ceph_buffer_put(ci->i_xattrs.prealloc_blob); |
409 | 418 | ||
410 | kmem_cache_free(ceph_inode_cachep, ci); | 419 | call_rcu(&inode->i_rcu, ceph_i_callback); |
411 | } | 420 | } |
412 | 421 | ||
413 | 422 | ||
@@ -841,13 +850,13 @@ static void ceph_set_dentry_offset(struct dentry *dn) | |||
841 | di->offset = ceph_inode(inode)->i_max_offset++; | 850 | di->offset = ceph_inode(inode)->i_max_offset++; |
842 | spin_unlock(&inode->i_lock); | 851 | spin_unlock(&inode->i_lock); |
843 | 852 | ||
844 | spin_lock(&dcache_lock); | 853 | spin_lock(&dir->d_lock); |
845 | spin_lock(&dn->d_lock); | 854 | spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED); |
846 | list_move(&dn->d_u.d_child, &dir->d_subdirs); | 855 | list_move(&dn->d_u.d_child, &dir->d_subdirs); |
847 | dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset, | 856 | dout("set_dentry_offset %p %lld (%p %p)\n", dn, di->offset, |
848 | dn->d_u.d_child.prev, dn->d_u.d_child.next); | 857 | dn->d_u.d_child.prev, dn->d_u.d_child.next); |
849 | spin_unlock(&dn->d_lock); | 858 | spin_unlock(&dn->d_lock); |
850 | spin_unlock(&dcache_lock); | 859 | spin_unlock(&dir->d_lock); |
851 | } | 860 | } |
852 | 861 | ||
853 | /* | 862 | /* |
@@ -879,8 +888,8 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in, | |||
879 | } else if (realdn) { | 888 | } else if (realdn) { |
880 | dout("dn %p (%d) spliced with %p (%d) " | 889 | dout("dn %p (%d) spliced with %p (%d) " |
881 | "inode %p ino %llx.%llx\n", | 890 | "inode %p ino %llx.%llx\n", |
882 | dn, atomic_read(&dn->d_count), | 891 | dn, dn->d_count, |
883 | realdn, atomic_read(&realdn->d_count), | 892 | realdn, realdn->d_count, |
884 | realdn->d_inode, ceph_vinop(realdn->d_inode)); | 893 | realdn->d_inode, ceph_vinop(realdn->d_inode)); |
885 | dput(dn); | 894 | dput(dn); |
886 | dn = realdn; | 895 | dn = realdn; |
@@ -1231,11 +1240,11 @@ retry_lookup: | |||
1231 | goto retry_lookup; | 1240 | goto retry_lookup; |
1232 | } else { | 1241 | } else { |
1233 | /* reorder parent's d_subdirs */ | 1242 | /* reorder parent's d_subdirs */ |
1234 | spin_lock(&dcache_lock); | 1243 | spin_lock(&parent->d_lock); |
1235 | spin_lock(&dn->d_lock); | 1244 | spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED); |
1236 | list_move(&dn->d_u.d_child, &parent->d_subdirs); | 1245 | list_move(&dn->d_u.d_child, &parent->d_subdirs); |
1237 | spin_unlock(&dn->d_lock); | 1246 | spin_unlock(&dn->d_lock); |
1238 | spin_unlock(&dcache_lock); | 1247 | spin_unlock(&parent->d_lock); |
1239 | } | 1248 | } |
1240 | 1249 | ||
1241 | di = dn->d_fsdata; | 1250 | di = dn->d_fsdata; |
@@ -1772,12 +1781,17 @@ int ceph_do_getattr(struct inode *inode, int mask) | |||
1772 | * Check inode permissions. We verify we have a valid value for | 1781 | * Check inode permissions. We verify we have a valid value for |
1773 | * the AUTH cap, then call the generic handler. | 1782 | * the AUTH cap, then call the generic handler. |
1774 | */ | 1783 | */ |
1775 | int ceph_permission(struct inode *inode, int mask) | 1784 | int ceph_permission(struct inode *inode, int mask, unsigned int flags) |
1776 | { | 1785 | { |
1777 | int err = ceph_do_getattr(inode, CEPH_CAP_AUTH_SHARED); | 1786 | int err; |
1787 | |||
1788 | if (flags & IPERM_FLAG_RCU) | ||
1789 | return -ECHILD; | ||
1790 | |||
1791 | err = ceph_do_getattr(inode, CEPH_CAP_AUTH_SHARED); | ||
1778 | 1792 | ||
1779 | if (!err) | 1793 | if (!err) |
1780 | err = generic_permission(inode, mask, NULL); | 1794 | err = generic_permission(inode, mask, flags, NULL); |
1781 | return err; | 1795 | return err; |
1782 | } | 1796 | } |
1783 | 1797 | ||
diff --git a/fs/ceph/ioctl.h b/fs/ceph/ioctl.h index a6ce54e94eb5..52e8fd74d450 100644 --- a/fs/ceph/ioctl.h +++ b/fs/ceph/ioctl.h | |||
@@ -4,7 +4,7 @@ | |||
4 | #include <linux/ioctl.h> | 4 | #include <linux/ioctl.h> |
5 | #include <linux/types.h> | 5 | #include <linux/types.h> |
6 | 6 | ||
7 | #define CEPH_IOCTL_MAGIC 0x98 | 7 | #define CEPH_IOCTL_MAGIC 0x97 |
8 | 8 | ||
9 | /* just use u64 to align sanely on all archs */ | 9 | /* just use u64 to align sanely on all archs */ |
10 | struct ceph_ioctl_layout { | 10 | struct ceph_ioctl_layout { |
diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c index 40abde93c345..476b329867d4 100644 --- a/fs/ceph/locks.c +++ b/fs/ceph/locks.c | |||
@@ -11,40 +11,68 @@ | |||
11 | * Implement fcntl and flock locking functions. | 11 | * Implement fcntl and flock locking functions. |
12 | */ | 12 | */ |
13 | static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file, | 13 | static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file, |
14 | u64 pid, u64 pid_ns, | 14 | int cmd, u8 wait, struct file_lock *fl) |
15 | int cmd, u64 start, u64 length, u8 wait) | ||
16 | { | 15 | { |
17 | struct inode *inode = file->f_dentry->d_inode; | 16 | struct inode *inode = file->f_dentry->d_inode; |
18 | struct ceph_mds_client *mdsc = | 17 | struct ceph_mds_client *mdsc = |
19 | ceph_sb_to_client(inode->i_sb)->mdsc; | 18 | ceph_sb_to_client(inode->i_sb)->mdsc; |
20 | struct ceph_mds_request *req; | 19 | struct ceph_mds_request *req; |
21 | int err; | 20 | int err; |
21 | u64 length = 0; | ||
22 | 22 | ||
23 | req = ceph_mdsc_create_request(mdsc, operation, USE_AUTH_MDS); | 23 | req = ceph_mdsc_create_request(mdsc, operation, USE_AUTH_MDS); |
24 | if (IS_ERR(req)) | 24 | if (IS_ERR(req)) |
25 | return PTR_ERR(req); | 25 | return PTR_ERR(req); |
26 | req->r_inode = igrab(inode); | 26 | req->r_inode = igrab(inode); |
27 | 27 | ||
28 | /* mds requires start and length rather than start and end */ | ||
29 | if (LLONG_MAX == fl->fl_end) | ||
30 | length = 0; | ||
31 | else | ||
32 | length = fl->fl_end - fl->fl_start + 1; | ||
33 | |||
28 | dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, " | 34 | dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, " |
29 | "length: %llu, wait: %d, type`: %d", (int)lock_type, | 35 | "length: %llu, wait: %d, type`: %d", (int)lock_type, |
30 | (int)operation, pid, start, length, wait, cmd); | 36 | (int)operation, (u64)fl->fl_pid, fl->fl_start, |
37 | length, wait, fl->fl_type); | ||
38 | |||
31 | 39 | ||
32 | req->r_args.filelock_change.rule = lock_type; | 40 | req->r_args.filelock_change.rule = lock_type; |
33 | req->r_args.filelock_change.type = cmd; | 41 | req->r_args.filelock_change.type = cmd; |
34 | req->r_args.filelock_change.pid = cpu_to_le64(pid); | 42 | req->r_args.filelock_change.pid = cpu_to_le64((u64)fl->fl_pid); |
35 | /* This should be adjusted, but I'm not sure if | 43 | /* This should be adjusted, but I'm not sure if |
36 | namespaces actually get id numbers*/ | 44 | namespaces actually get id numbers*/ |
37 | req->r_args.filelock_change.pid_namespace = | 45 | req->r_args.filelock_change.pid_namespace = |
38 | cpu_to_le64((u64)pid_ns); | 46 | cpu_to_le64((u64)(unsigned long)fl->fl_nspid); |
39 | req->r_args.filelock_change.start = cpu_to_le64(start); | 47 | req->r_args.filelock_change.start = cpu_to_le64(fl->fl_start); |
40 | req->r_args.filelock_change.length = cpu_to_le64(length); | 48 | req->r_args.filelock_change.length = cpu_to_le64(length); |
41 | req->r_args.filelock_change.wait = wait; | 49 | req->r_args.filelock_change.wait = wait; |
42 | 50 | ||
43 | err = ceph_mdsc_do_request(mdsc, inode, req); | 51 | err = ceph_mdsc_do_request(mdsc, inode, req); |
52 | |||
53 | if ( operation == CEPH_MDS_OP_GETFILELOCK){ | ||
54 | fl->fl_pid = le64_to_cpu(req->r_reply_info.filelock_reply->pid); | ||
55 | if (CEPH_LOCK_SHARED == req->r_reply_info.filelock_reply->type) | ||
56 | fl->fl_type = F_RDLCK; | ||
57 | else if (CEPH_LOCK_EXCL == req->r_reply_info.filelock_reply->type) | ||
58 | fl->fl_type = F_WRLCK; | ||
59 | else | ||
60 | fl->fl_type = F_UNLCK; | ||
61 | |||
62 | fl->fl_start = le64_to_cpu(req->r_reply_info.filelock_reply->start); | ||
63 | length = le64_to_cpu(req->r_reply_info.filelock_reply->start) + | ||
64 | le64_to_cpu(req->r_reply_info.filelock_reply->length); | ||
65 | if (length >= 1) | ||
66 | fl->fl_end = length -1; | ||
67 | else | ||
68 | fl->fl_end = 0; | ||
69 | |||
70 | } | ||
44 | ceph_mdsc_put_request(req); | 71 | ceph_mdsc_put_request(req); |
45 | dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, " | 72 | dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, " |
46 | "length: %llu, wait: %d, type`: %d err code %d", (int)lock_type, | 73 | "length: %llu, wait: %d, type`: %d, err code %d", (int)lock_type, |
47 | (int)operation, pid, start, length, wait, cmd, err); | 74 | (int)operation, (u64)fl->fl_pid, fl->fl_start, |
75 | length, wait, fl->fl_type, err); | ||
48 | return err; | 76 | return err; |
49 | } | 77 | } |
50 | 78 | ||
@@ -54,7 +82,6 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file, | |||
54 | */ | 82 | */ |
55 | int ceph_lock(struct file *file, int cmd, struct file_lock *fl) | 83 | int ceph_lock(struct file *file, int cmd, struct file_lock *fl) |
56 | { | 84 | { |
57 | u64 length; | ||
58 | u8 lock_cmd; | 85 | u8 lock_cmd; |
59 | int err; | 86 | int err; |
60 | u8 wait = 0; | 87 | u8 wait = 0; |
@@ -76,29 +103,20 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl) | |||
76 | else | 103 | else |
77 | lock_cmd = CEPH_LOCK_UNLOCK; | 104 | lock_cmd = CEPH_LOCK_UNLOCK; |
78 | 105 | ||
79 | if (LLONG_MAX == fl->fl_end) | 106 | err = ceph_lock_message(CEPH_LOCK_FCNTL, op, file, lock_cmd, wait, fl); |
80 | length = 0; | ||
81 | else | ||
82 | length = fl->fl_end - fl->fl_start + 1; | ||
83 | |||
84 | err = ceph_lock_message(CEPH_LOCK_FCNTL, op, file, | ||
85 | (u64)fl->fl_pid, | ||
86 | (u64)(unsigned long)fl->fl_nspid, | ||
87 | lock_cmd, fl->fl_start, | ||
88 | length, wait); | ||
89 | if (!err) { | 107 | if (!err) { |
90 | dout("mds locked, locking locally"); | 108 | if ( op != CEPH_MDS_OP_GETFILELOCK ){ |
91 | err = posix_lock_file(file, fl, NULL); | 109 | dout("mds locked, locking locally"); |
92 | if (err && (CEPH_MDS_OP_SETFILELOCK == op)) { | 110 | err = posix_lock_file(file, fl, NULL); |
93 | /* undo! This should only happen if the kernel detects | 111 | if (err && (CEPH_MDS_OP_SETFILELOCK == op)) { |
94 | * local deadlock. */ | 112 | /* undo! This should only happen if the kernel detects |
95 | ceph_lock_message(CEPH_LOCK_FCNTL, op, file, | 113 | * local deadlock. */ |
96 | (u64)fl->fl_pid, | 114 | ceph_lock_message(CEPH_LOCK_FCNTL, op, file, |
97 | (u64)(unsigned long)fl->fl_nspid, | 115 | CEPH_LOCK_UNLOCK, 0, fl); |
98 | CEPH_LOCK_UNLOCK, fl->fl_start, | 116 | dout("got %d on posix_lock_file, undid lock", err); |
99 | length, 0); | 117 | } |
100 | dout("got %d on posix_lock_file, undid lock", err); | ||
101 | } | 118 | } |
119 | |||
102 | } else { | 120 | } else { |
103 | dout("mds returned error code %d", err); | 121 | dout("mds returned error code %d", err); |
104 | } | 122 | } |
@@ -107,7 +125,6 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl) | |||
107 | 125 | ||
108 | int ceph_flock(struct file *file, int cmd, struct file_lock *fl) | 126 | int ceph_flock(struct file *file, int cmd, struct file_lock *fl) |
109 | { | 127 | { |
110 | u64 length; | ||
111 | u8 lock_cmd; | 128 | u8 lock_cmd; |
112 | int err; | 129 | int err; |
113 | u8 wait = 1; | 130 | u8 wait = 1; |
@@ -127,26 +144,15 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl) | |||
127 | lock_cmd = CEPH_LOCK_EXCL; | 144 | lock_cmd = CEPH_LOCK_EXCL; |
128 | else | 145 | else |
129 | lock_cmd = CEPH_LOCK_UNLOCK; | 146 | lock_cmd = CEPH_LOCK_UNLOCK; |
130 | /* mds requires start and length rather than start and end */ | ||
131 | if (LLONG_MAX == fl->fl_end) | ||
132 | length = 0; | ||
133 | else | ||
134 | length = fl->fl_end - fl->fl_start + 1; | ||
135 | 147 | ||
136 | err = ceph_lock_message(CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK, | 148 | err = ceph_lock_message(CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK, |
137 | file, (u64)fl->fl_pid, | 149 | file, lock_cmd, wait, fl); |
138 | (u64)(unsigned long)fl->fl_nspid, | ||
139 | lock_cmd, fl->fl_start, | ||
140 | length, wait); | ||
141 | if (!err) { | 150 | if (!err) { |
142 | err = flock_lock_file_wait(file, fl); | 151 | err = flock_lock_file_wait(file, fl); |
143 | if (err) { | 152 | if (err) { |
144 | ceph_lock_message(CEPH_LOCK_FLOCK, | 153 | ceph_lock_message(CEPH_LOCK_FLOCK, |
145 | CEPH_MDS_OP_SETFILELOCK, | 154 | CEPH_MDS_OP_SETFILELOCK, |
146 | file, (u64)fl->fl_pid, | 155 | file, CEPH_LOCK_UNLOCK, 0, fl); |
147 | (u64)(unsigned long)fl->fl_nspid, | ||
148 | CEPH_LOCK_UNLOCK, fl->fl_start, | ||
149 | length, 0); | ||
150 | dout("got %d on flock_lock_file_wait, undid lock", err); | 156 | dout("got %d on flock_lock_file_wait, undid lock", err); |
151 | } | 157 | } |
152 | } else { | 158 | } else { |
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 098b18508479..a50fca1e03be 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
@@ -202,6 +202,38 @@ out_bad: | |||
202 | } | 202 | } |
203 | 203 | ||
204 | /* | 204 | /* |
205 | * parse fcntl F_GETLK results | ||
206 | */ | ||
207 | static int parse_reply_info_filelock(void **p, void *end, | ||
208 | struct ceph_mds_reply_info_parsed *info) | ||
209 | { | ||
210 | if (*p + sizeof(*info->filelock_reply) > end) | ||
211 | goto bad; | ||
212 | |||
213 | info->filelock_reply = *p; | ||
214 | *p += sizeof(*info->filelock_reply); | ||
215 | |||
216 | if (unlikely(*p != end)) | ||
217 | goto bad; | ||
218 | return 0; | ||
219 | |||
220 | bad: | ||
221 | return -EIO; | ||
222 | } | ||
223 | |||
224 | /* | ||
225 | * parse extra results | ||
226 | */ | ||
227 | static int parse_reply_info_extra(void **p, void *end, | ||
228 | struct ceph_mds_reply_info_parsed *info) | ||
229 | { | ||
230 | if (info->head->op == CEPH_MDS_OP_GETFILELOCK) | ||
231 | return parse_reply_info_filelock(p, end, info); | ||
232 | else | ||
233 | return parse_reply_info_dir(p, end, info); | ||
234 | } | ||
235 | |||
236 | /* | ||
205 | * parse entire mds reply | 237 | * parse entire mds reply |
206 | */ | 238 | */ |
207 | static int parse_reply_info(struct ceph_msg *msg, | 239 | static int parse_reply_info(struct ceph_msg *msg, |
@@ -223,10 +255,10 @@ static int parse_reply_info(struct ceph_msg *msg, | |||
223 | goto out_bad; | 255 | goto out_bad; |
224 | } | 256 | } |
225 | 257 | ||
226 | /* dir content */ | 258 | /* extra */ |
227 | ceph_decode_32_safe(&p, end, len, bad); | 259 | ceph_decode_32_safe(&p, end, len, bad); |
228 | if (len > 0) { | 260 | if (len > 0) { |
229 | err = parse_reply_info_dir(&p, p+len, info); | 261 | err = parse_reply_info_extra(&p, p+len, info); |
230 | if (err < 0) | 262 | if (err < 0) |
231 | goto out_bad; | 263 | goto out_bad; |
232 | } | 264 | } |
@@ -1454,7 +1486,7 @@ retry: | |||
1454 | *base = ceph_ino(temp->d_inode); | 1486 | *base = ceph_ino(temp->d_inode); |
1455 | *plen = len; | 1487 | *plen = len; |
1456 | dout("build_path on %p %d built %llx '%.*s'\n", | 1488 | dout("build_path on %p %d built %llx '%.*s'\n", |
1457 | dentry, atomic_read(&dentry->d_count), *base, len, path); | 1489 | dentry, dentry->d_count, *base, len, path); |
1458 | return path; | 1490 | return path; |
1459 | } | 1491 | } |
1460 | 1492 | ||
@@ -2074,7 +2106,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) | |||
2074 | 2106 | ||
2075 | mutex_lock(&session->s_mutex); | 2107 | mutex_lock(&session->s_mutex); |
2076 | if (err < 0) { | 2108 | if (err < 0) { |
2077 | pr_err("mdsc_handle_reply got corrupt reply mds%d\n", mds); | 2109 | pr_err("mdsc_handle_reply got corrupt reply mds%d(tid:%lld)\n", mds, tid); |
2078 | ceph_msg_dump(msg); | 2110 | ceph_msg_dump(msg); |
2079 | goto out_err; | 2111 | goto out_err; |
2080 | } | 2112 | } |
@@ -2094,7 +2126,8 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) | |||
2094 | mutex_lock(&req->r_fill_mutex); | 2126 | mutex_lock(&req->r_fill_mutex); |
2095 | err = ceph_fill_trace(mdsc->fsc->sb, req, req->r_session); | 2127 | err = ceph_fill_trace(mdsc->fsc->sb, req, req->r_session); |
2096 | if (err == 0) { | 2128 | if (err == 0) { |
2097 | if (result == 0 && rinfo->dir_nr) | 2129 | if (result == 0 && req->r_op != CEPH_MDS_OP_GETFILELOCK && |
2130 | rinfo->dir_nr) | ||
2098 | ceph_readdir_prepopulate(req, req->r_session); | 2131 | ceph_readdir_prepopulate(req, req->r_session); |
2099 | ceph_unreserve_caps(mdsc, &req->r_caps_reservation); | 2132 | ceph_unreserve_caps(mdsc, &req->r_caps_reservation); |
2100 | } | 2133 | } |
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 9341fd4f1432..aabe563b54db 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h | |||
@@ -42,26 +42,37 @@ struct ceph_mds_reply_info_in { | |||
42 | }; | 42 | }; |
43 | 43 | ||
44 | /* | 44 | /* |
45 | * parsed info about an mds reply, including information about the | 45 | * parsed info about an mds reply, including information about |
46 | * target inode and/or its parent directory and dentry, and directory | 46 | * either: 1) the target inode and/or its parent directory and dentry, |
47 | * contents (for readdir results). | 47 | * and directory contents (for readdir results), or |
48 | * 2) the file range lock info (for fcntl F_GETLK results). | ||
48 | */ | 49 | */ |
49 | struct ceph_mds_reply_info_parsed { | 50 | struct ceph_mds_reply_info_parsed { |
50 | struct ceph_mds_reply_head *head; | 51 | struct ceph_mds_reply_head *head; |
51 | 52 | ||
53 | /* trace */ | ||
52 | struct ceph_mds_reply_info_in diri, targeti; | 54 | struct ceph_mds_reply_info_in diri, targeti; |
53 | struct ceph_mds_reply_dirfrag *dirfrag; | 55 | struct ceph_mds_reply_dirfrag *dirfrag; |
54 | char *dname; | 56 | char *dname; |
55 | u32 dname_len; | 57 | u32 dname_len; |
56 | struct ceph_mds_reply_lease *dlease; | 58 | struct ceph_mds_reply_lease *dlease; |
57 | 59 | ||
58 | struct ceph_mds_reply_dirfrag *dir_dir; | 60 | /* extra */ |
59 | int dir_nr; | 61 | union { |
60 | char **dir_dname; | 62 | /* for fcntl F_GETLK results */ |
61 | u32 *dir_dname_len; | 63 | struct ceph_filelock *filelock_reply; |
62 | struct ceph_mds_reply_lease **dir_dlease; | 64 | |
63 | struct ceph_mds_reply_info_in *dir_in; | 65 | /* for readdir results */ |
64 | u8 dir_complete, dir_end; | 66 | struct { |
67 | struct ceph_mds_reply_dirfrag *dir_dir; | ||
68 | int dir_nr; | ||
69 | char **dir_dname; | ||
70 | u32 *dir_dname_len; | ||
71 | struct ceph_mds_reply_lease **dir_dlease; | ||
72 | struct ceph_mds_reply_info_in *dir_in; | ||
73 | u8 dir_complete, dir_end; | ||
74 | }; | ||
75 | }; | ||
65 | 76 | ||
66 | /* encoded blob describing snapshot contexts for certain | 77 | /* encoded blob describing snapshot contexts for certain |
67 | operations (e.g., open) */ | 78 | operations (e.g., open) */ |
diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 7f01728a4657..4553d8829edb 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h | |||
@@ -665,7 +665,7 @@ extern void ceph_queue_invalidate(struct inode *inode); | |||
665 | extern void ceph_queue_writeback(struct inode *inode); | 665 | extern void ceph_queue_writeback(struct inode *inode); |
666 | 666 | ||
667 | extern int ceph_do_getattr(struct inode *inode, int mask); | 667 | extern int ceph_do_getattr(struct inode *inode, int mask); |
668 | extern int ceph_permission(struct inode *inode, int mask); | 668 | extern int ceph_permission(struct inode *inode, int mask, unsigned int flags); |
669 | extern int ceph_setattr(struct dentry *dentry, struct iattr *attr); | 669 | extern int ceph_setattr(struct dentry *dentry, struct iattr *attr); |
670 | extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry, | 670 | extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry, |
671 | struct kstat *stat); | 671 | struct kstat *stat); |
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index adefa60a9bdc..43b19dd39191 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile | |||
@@ -6,7 +6,9 @@ obj-$(CONFIG_CIFS) += cifs.o | |||
6 | cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \ | 6 | cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \ |
7 | link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o \ | 7 | link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o \ |
8 | md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o \ | 8 | md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o \ |
9 | readdir.o ioctl.o sess.o export.o cifsacl.o | 9 | readdir.o ioctl.o sess.o export.o |
10 | |||
11 | cifs-$(CONFIG_CIFS_ACL) += cifsacl.o | ||
10 | 12 | ||
11 | cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o | 13 | cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o |
12 | 14 | ||
diff --git a/fs/cifs/README b/fs/cifs/README index ee68d1036544..46af99ab3614 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
@@ -337,6 +337,15 @@ A partial list of the supported mount options follows: | |||
337 | wsize default write size (default 57344) | 337 | wsize default write size (default 57344) |
338 | maximum wsize currently allowed by CIFS is 57344 (fourteen | 338 | maximum wsize currently allowed by CIFS is 57344 (fourteen |
339 | 4096 byte pages) | 339 | 4096 byte pages) |
340 | actimeo=n attribute cache timeout in seconds (default 1 second). | ||
341 | After this timeout, the cifs client requests fresh attribute | ||
342 | information from the server. This option allows to tune the | ||
343 | attribute cache timeout to suit the workload needs. Shorter | ||
344 | timeouts mean better the cache coherency, but increased number | ||
345 | of calls to the server. Longer timeouts mean reduced number | ||
346 | of calls to the server at the expense of less stricter cache | ||
347 | coherency checks (i.e. incorrect attribute cache for a short | ||
348 | period of time). | ||
340 | rw mount the network share read-write (note that the | 349 | rw mount the network share read-write (note that the |
341 | server may still consider the share read-only) | 350 | server may still consider the share read-only) |
342 | ro mount network share read-only | 351 | ro mount network share read-only |
diff --git a/fs/cifs/cache.c b/fs/cifs/cache.c index 224d7bbd1fcc..e654dfd092c3 100644 --- a/fs/cifs/cache.c +++ b/fs/cifs/cache.c | |||
@@ -64,7 +64,9 @@ static uint16_t cifs_server_get_key(const void *cookie_netfs_data, | |||
64 | void *buffer, uint16_t maxbuf) | 64 | void *buffer, uint16_t maxbuf) |
65 | { | 65 | { |
66 | const struct TCP_Server_Info *server = cookie_netfs_data; | 66 | const struct TCP_Server_Info *server = cookie_netfs_data; |
67 | const struct sockaddr *sa = (struct sockaddr *) &server->addr.sockAddr; | 67 | const struct sockaddr *sa = (struct sockaddr *) &server->dstaddr; |
68 | const struct sockaddr_in *addr = (struct sockaddr_in *) sa; | ||
69 | const struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) sa; | ||
68 | struct cifs_server_key *key = buffer; | 70 | struct cifs_server_key *key = buffer; |
69 | uint16_t key_len = sizeof(struct cifs_server_key); | 71 | uint16_t key_len = sizeof(struct cifs_server_key); |
70 | 72 | ||
@@ -76,16 +78,16 @@ static uint16_t cifs_server_get_key(const void *cookie_netfs_data, | |||
76 | */ | 78 | */ |
77 | switch (sa->sa_family) { | 79 | switch (sa->sa_family) { |
78 | case AF_INET: | 80 | case AF_INET: |
79 | key->family = server->addr.sockAddr.sin_family; | 81 | key->family = sa->sa_family; |
80 | key->port = server->addr.sockAddr.sin_port; | 82 | key->port = addr->sin_port; |
81 | key->addr[0].ipv4_addr = server->addr.sockAddr.sin_addr; | 83 | key->addr[0].ipv4_addr = addr->sin_addr; |
82 | key_len += sizeof(key->addr[0].ipv4_addr); | 84 | key_len += sizeof(key->addr[0].ipv4_addr); |
83 | break; | 85 | break; |
84 | 86 | ||
85 | case AF_INET6: | 87 | case AF_INET6: |
86 | key->family = server->addr.sockAddr6.sin6_family; | 88 | key->family = sa->sa_family; |
87 | key->port = server->addr.sockAddr6.sin6_port; | 89 | key->port = addr6->sin6_port; |
88 | key->addr[0].ipv6_addr = server->addr.sockAddr6.sin6_addr; | 90 | key->addr[0].ipv6_addr = addr6->sin6_addr; |
89 | key_len += sizeof(key->addr[0].ipv6_addr); | 91 | key_len += sizeof(key->addr[0].ipv6_addr); |
90 | break; | 92 | break; |
91 | 93 | ||
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 103ab8b605b0..ede98300a8cd 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c | |||
@@ -119,29 +119,27 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) | |||
119 | "Display Internal CIFS Data Structures for Debugging\n" | 119 | "Display Internal CIFS Data Structures for Debugging\n" |
120 | "---------------------------------------------------\n"); | 120 | "---------------------------------------------------\n"); |
121 | seq_printf(m, "CIFS Version %s\n", CIFS_VERSION); | 121 | seq_printf(m, "CIFS Version %s\n", CIFS_VERSION); |
122 | seq_printf(m, "Features: "); | 122 | seq_printf(m, "Features:"); |
123 | #ifdef CONFIG_CIFS_DFS_UPCALL | 123 | #ifdef CONFIG_CIFS_DFS_UPCALL |
124 | seq_printf(m, "dfs"); | 124 | seq_printf(m, " dfs"); |
125 | seq_putc(m, ' '); | ||
126 | #endif | 125 | #endif |
127 | #ifdef CONFIG_CIFS_FSCACHE | 126 | #ifdef CONFIG_CIFS_FSCACHE |
128 | seq_printf(m, "fscache"); | 127 | seq_printf(m, " fscache"); |
129 | seq_putc(m, ' '); | ||
130 | #endif | 128 | #endif |
131 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 129 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
132 | seq_printf(m, "lanman"); | 130 | seq_printf(m, " lanman"); |
133 | seq_putc(m, ' '); | ||
134 | #endif | 131 | #endif |
135 | #ifdef CONFIG_CIFS_POSIX | 132 | #ifdef CONFIG_CIFS_POSIX |
136 | seq_printf(m, "posix"); | 133 | seq_printf(m, " posix"); |
137 | seq_putc(m, ' '); | ||
138 | #endif | 134 | #endif |
139 | #ifdef CONFIG_CIFS_UPCALL | 135 | #ifdef CONFIG_CIFS_UPCALL |
140 | seq_printf(m, "spnego"); | 136 | seq_printf(m, " spnego"); |
141 | seq_putc(m, ' '); | ||
142 | #endif | 137 | #endif |
143 | #ifdef CONFIG_CIFS_XATTR | 138 | #ifdef CONFIG_CIFS_XATTR |
144 | seq_printf(m, "xattr"); | 139 | seq_printf(m, " xattr"); |
140 | #endif | ||
141 | #ifdef CONFIG_CIFS_ACL | ||
142 | seq_printf(m, " acl"); | ||
145 | #endif | 143 | #endif |
146 | seq_putc(m, '\n'); | 144 | seq_putc(m, '\n'); |
147 | seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid); | 145 | seq_printf(m, "Active VFS Requests: %d\n", GlobalTotalActiveXid); |
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index e9a393c9c2ca..7852cd677051 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h | |||
@@ -48,6 +48,7 @@ struct cifs_sb_info { | |||
48 | struct nls_table *local_nls; | 48 | struct nls_table *local_nls; |
49 | unsigned int rsize; | 49 | unsigned int rsize; |
50 | unsigned int wsize; | 50 | unsigned int wsize; |
51 | unsigned long actimeo; /* attribute cache timeout (jiffies) */ | ||
51 | atomic_t active; | 52 | atomic_t active; |
52 | uid_t mnt_uid; | 53 | uid_t mnt_uid; |
53 | gid_t mnt_gid; | 54 | gid_t mnt_gid; |
diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 87044906cd1f..4dfba8283165 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c | |||
@@ -98,6 +98,8 @@ struct key * | |||
98 | cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | 98 | cifs_get_spnego_key(struct cifsSesInfo *sesInfo) |
99 | { | 99 | { |
100 | struct TCP_Server_Info *server = sesInfo->server; | 100 | struct TCP_Server_Info *server = sesInfo->server; |
101 | struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr; | ||
102 | struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr; | ||
101 | char *description, *dp; | 103 | char *description, *dp; |
102 | size_t desc_len; | 104 | size_t desc_len; |
103 | struct key *spnego_key; | 105 | struct key *spnego_key; |
@@ -127,10 +129,10 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) | |||
127 | dp = description + strlen(description); | 129 | dp = description + strlen(description); |
128 | 130 | ||
129 | /* add the server address */ | 131 | /* add the server address */ |
130 | if (server->addr.sockAddr.sin_family == AF_INET) | 132 | if (server->dstaddr.ss_family == AF_INET) |
131 | sprintf(dp, "ip4=%pI4", &server->addr.sockAddr.sin_addr); | 133 | sprintf(dp, "ip4=%pI4", &sa->sin_addr); |
132 | else if (server->addr.sockAddr.sin_family == AF_INET6) | 134 | else if (server->dstaddr.ss_family == AF_INET6) |
133 | sprintf(dp, "ip6=%pI6", &server->addr.sockAddr6.sin6_addr); | 135 | sprintf(dp, "ip6=%pI6", &sa6->sin6_addr); |
134 | else | 136 | else |
135 | goto out; | 137 | goto out; |
136 | 138 | ||
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index c6ebea088ac7..a437ec391a01 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c | |||
@@ -30,8 +30,6 @@ | |||
30 | #include "cifs_debug.h" | 30 | #include "cifs_debug.h" |
31 | 31 | ||
32 | 32 | ||
33 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
34 | |||
35 | static struct cifs_wksid wksidarr[NUM_WK_SIDS] = { | 33 | static struct cifs_wksid wksidarr[NUM_WK_SIDS] = { |
36 | {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"}, | 34 | {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"}, |
37 | {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"}, | 35 | {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"}, |
@@ -774,4 +772,3 @@ int mode_to_cifs_acl(struct inode *inode, const char *path, __u64 nmode) | |||
774 | 772 | ||
775 | return rc; | 773 | return rc; |
776 | } | 774 | } |
777 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | ||
diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index 6c8096cf5155..c4ae7d036563 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h | |||
@@ -74,11 +74,7 @@ struct cifs_wksid { | |||
74 | char sidname[SIDNAMELENGTH]; | 74 | char sidname[SIDNAMELENGTH]; |
75 | } __attribute__((packed)); | 75 | } __attribute__((packed)); |
76 | 76 | ||
77 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
78 | |||
79 | extern int match_sid(struct cifs_sid *); | 77 | extern int match_sid(struct cifs_sid *); |
80 | extern int compare_sids(const struct cifs_sid *, const struct cifs_sid *); | 78 | extern int compare_sids(const struct cifs_sid *, const struct cifs_sid *); |
81 | 79 | ||
82 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | ||
83 | |||
84 | #endif /* _CIFSACL_H */ | 80 | #endif /* _CIFSACL_H */ |
diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index f856732161ab..66f3d50d0676 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c | |||
@@ -72,6 +72,7 @@ static int cifs_calculate_signature(const struct smb_hdr *cifs_pdu, | |||
72 | return 0; | 72 | return 0; |
73 | } | 73 | } |
74 | 74 | ||
75 | /* must be called with server->srv_mutex held */ | ||
75 | int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, | 76 | int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, |
76 | __u32 *pexpected_response_sequence_number) | 77 | __u32 *pexpected_response_sequence_number) |
77 | { | 78 | { |
@@ -84,14 +85,12 @@ int cifs_sign_smb(struct smb_hdr *cifs_pdu, struct TCP_Server_Info *server, | |||
84 | if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) | 85 | if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) |
85 | return rc; | 86 | return rc; |
86 | 87 | ||
87 | spin_lock(&GlobalMid_Lock); | ||
88 | cifs_pdu->Signature.Sequence.SequenceNumber = | 88 | cifs_pdu->Signature.Sequence.SequenceNumber = |
89 | cpu_to_le32(server->sequence_number); | 89 | cpu_to_le32(server->sequence_number); |
90 | cifs_pdu->Signature.Sequence.Reserved = 0; | 90 | cifs_pdu->Signature.Sequence.Reserved = 0; |
91 | 91 | ||
92 | *pexpected_response_sequence_number = server->sequence_number++; | 92 | *pexpected_response_sequence_number = server->sequence_number++; |
93 | server->sequence_number++; | 93 | server->sequence_number++; |
94 | spin_unlock(&GlobalMid_Lock); | ||
95 | 94 | ||
96 | rc = cifs_calculate_signature(cifs_pdu, server, smb_signature); | 95 | rc = cifs_calculate_signature(cifs_pdu, server, smb_signature); |
97 | if (rc) | 96 | if (rc) |
@@ -149,6 +148,7 @@ static int cifs_calc_signature2(const struct kvec *iov, int n_vec, | |||
149 | return rc; | 148 | return rc; |
150 | } | 149 | } |
151 | 150 | ||
151 | /* must be called with server->srv_mutex held */ | ||
152 | int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | 152 | int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, |
153 | __u32 *pexpected_response_sequence_number) | 153 | __u32 *pexpected_response_sequence_number) |
154 | { | 154 | { |
@@ -162,14 +162,12 @@ int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server, | |||
162 | if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) | 162 | if ((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) |
163 | return rc; | 163 | return rc; |
164 | 164 | ||
165 | spin_lock(&GlobalMid_Lock); | ||
166 | cifs_pdu->Signature.Sequence.SequenceNumber = | 165 | cifs_pdu->Signature.Sequence.SequenceNumber = |
167 | cpu_to_le32(server->sequence_number); | 166 | cpu_to_le32(server->sequence_number); |
168 | cifs_pdu->Signature.Sequence.Reserved = 0; | 167 | cifs_pdu->Signature.Sequence.Reserved = 0; |
169 | 168 | ||
170 | *pexpected_response_sequence_number = server->sequence_number++; | 169 | *pexpected_response_sequence_number = server->sequence_number++; |
171 | server->sequence_number++; | 170 | server->sequence_number++; |
172 | spin_unlock(&GlobalMid_Lock); | ||
173 | 171 | ||
174 | rc = cifs_calc_signature2(iov, n_vec, server, smb_signature); | 172 | rc = cifs_calc_signature2(iov, n_vec, server, smb_signature); |
175 | if (rc) | 173 | if (rc) |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 76c8a906a63e..5e7075d5f139 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -283,10 +283,13 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
283 | return 0; | 283 | return 0; |
284 | } | 284 | } |
285 | 285 | ||
286 | static int cifs_permission(struct inode *inode, int mask) | 286 | static int cifs_permission(struct inode *inode, int mask, unsigned int flags) |
287 | { | 287 | { |
288 | struct cifs_sb_info *cifs_sb; | 288 | struct cifs_sb_info *cifs_sb; |
289 | 289 | ||
290 | if (flags & IPERM_FLAG_RCU) | ||
291 | return -ECHILD; | ||
292 | |||
290 | cifs_sb = CIFS_SB(inode->i_sb); | 293 | cifs_sb = CIFS_SB(inode->i_sb); |
291 | 294 | ||
292 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) { | 295 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) { |
@@ -298,7 +301,7 @@ static int cifs_permission(struct inode *inode, int mask) | |||
298 | on the client (above and beyond ACL on servers) for | 301 | on the client (above and beyond ACL on servers) for |
299 | servers which do not support setting and viewing mode bits, | 302 | servers which do not support setting and viewing mode bits, |
300 | so allowing client to check permissions is useful */ | 303 | so allowing client to check permissions is useful */ |
301 | return generic_permission(inode, mask, NULL); | 304 | return generic_permission(inode, mask, flags, NULL); |
302 | } | 305 | } |
303 | 306 | ||
304 | static struct kmem_cache *cifs_inode_cachep; | 307 | static struct kmem_cache *cifs_inode_cachep; |
@@ -326,6 +329,8 @@ cifs_alloc_inode(struct super_block *sb) | |||
326 | cifs_inode->invalid_mapping = false; | 329 | cifs_inode->invalid_mapping = false; |
327 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ | 330 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ |
328 | cifs_inode->server_eof = 0; | 331 | cifs_inode->server_eof = 0; |
332 | cifs_inode->uniqueid = 0; | ||
333 | cifs_inode->createtime = 0; | ||
329 | 334 | ||
330 | /* Can not set i_flags here - they get immediately overwritten | 335 | /* Can not set i_flags here - they get immediately overwritten |
331 | to zero by the VFS */ | 336 | to zero by the VFS */ |
@@ -334,10 +339,17 @@ cifs_alloc_inode(struct super_block *sb) | |||
334 | return &cifs_inode->vfs_inode; | 339 | return &cifs_inode->vfs_inode; |
335 | } | 340 | } |
336 | 341 | ||
342 | static void cifs_i_callback(struct rcu_head *head) | ||
343 | { | ||
344 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
345 | INIT_LIST_HEAD(&inode->i_dentry); | ||
346 | kmem_cache_free(cifs_inode_cachep, CIFS_I(inode)); | ||
347 | } | ||
348 | |||
337 | static void | 349 | static void |
338 | cifs_destroy_inode(struct inode *inode) | 350 | cifs_destroy_inode(struct inode *inode) |
339 | { | 351 | { |
340 | kmem_cache_free(cifs_inode_cachep, CIFS_I(inode)); | 352 | call_rcu(&inode->i_rcu, cifs_i_callback); |
341 | } | 353 | } |
342 | 354 | ||
343 | static void | 355 | static void |
@@ -351,18 +363,19 @@ cifs_evict_inode(struct inode *inode) | |||
351 | static void | 363 | static void |
352 | cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) | 364 | cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server) |
353 | { | 365 | { |
366 | struct sockaddr_in *sa = (struct sockaddr_in *) &server->dstaddr; | ||
367 | struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *) &server->dstaddr; | ||
368 | |||
354 | seq_printf(s, ",addr="); | 369 | seq_printf(s, ",addr="); |
355 | 370 | ||
356 | switch (server->addr.sockAddr.sin_family) { | 371 | switch (server->dstaddr.ss_family) { |
357 | case AF_INET: | 372 | case AF_INET: |
358 | seq_printf(s, "%pI4", &server->addr.sockAddr.sin_addr.s_addr); | 373 | seq_printf(s, "%pI4", &sa->sin_addr.s_addr); |
359 | break; | 374 | break; |
360 | case AF_INET6: | 375 | case AF_INET6: |
361 | seq_printf(s, "%pI6", | 376 | seq_printf(s, "%pI6", &sa6->sin6_addr.s6_addr); |
362 | &server->addr.sockAddr6.sin6_addr.s6_addr); | 377 | if (sa6->sin6_scope_id) |
363 | if (server->addr.sockAddr6.sin6_scope_id) | 378 | seq_printf(s, "%%%u", sa6->sin6_scope_id); |
364 | seq_printf(s, "%%%u", | ||
365 | server->addr.sockAddr6.sin6_scope_id); | ||
366 | break; | 379 | break; |
367 | default: | 380 | default: |
368 | seq_printf(s, "(unknown)"); | 381 | seq_printf(s, "(unknown)"); |
@@ -463,6 +476,8 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) | |||
463 | 476 | ||
464 | seq_printf(s, ",rsize=%d", cifs_sb->rsize); | 477 | seq_printf(s, ",rsize=%d", cifs_sb->rsize); |
465 | seq_printf(s, ",wsize=%d", cifs_sb->wsize); | 478 | seq_printf(s, ",wsize=%d", cifs_sb->wsize); |
479 | /* convert actimeo and display it in seconds */ | ||
480 | seq_printf(s, ",actimeo=%lu", cifs_sb->actimeo / HZ); | ||
466 | 481 | ||
467 | return 0; | 482 | return 0; |
468 | } | 483 | } |
@@ -935,7 +950,6 @@ init_cifs(void) | |||
935 | GlobalCurrentXid = 0; | 950 | GlobalCurrentXid = 0; |
936 | GlobalTotalActiveXid = 0; | 951 | GlobalTotalActiveXid = 0; |
937 | GlobalMaxActiveXid = 0; | 952 | GlobalMaxActiveXid = 0; |
938 | memset(Local_System_Name, 0, 15); | ||
939 | spin_lock_init(&cifs_tcp_ses_lock); | 953 | spin_lock_init(&cifs_tcp_ses_lock); |
940 | spin_lock_init(&cifs_file_list_lock); | 954 | spin_lock_init(&cifs_file_list_lock); |
941 | spin_lock_init(&GlobalMid_Lock); | 955 | spin_lock_init(&GlobalMid_Lock); |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index b577bf0a1bb3..606ca8bb7102 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -45,6 +45,16 @@ | |||
45 | #define CIFS_MIN_RCV_POOL 4 | 45 | #define CIFS_MIN_RCV_POOL 4 |
46 | 46 | ||
47 | /* | 47 | /* |
48 | * default attribute cache timeout (jiffies) | ||
49 | */ | ||
50 | #define CIFS_DEF_ACTIMEO (1 * HZ) | ||
51 | |||
52 | /* | ||
53 | * max attribute cache timeout (jiffies) - 2^30 | ||
54 | */ | ||
55 | #define CIFS_MAX_ACTIMEO (1 << 30) | ||
56 | |||
57 | /* | ||
48 | * MAX_REQ is the maximum number of requests that WE will send | 58 | * MAX_REQ is the maximum number of requests that WE will send |
49 | * on one socket concurrently. It also matches the most common | 59 | * on one socket concurrently. It also matches the most common |
50 | * value of max multiplex returned by servers. We may | 60 | * value of max multiplex returned by servers. We may |
@@ -153,10 +163,7 @@ struct TCP_Server_Info { | |||
153 | char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; | 163 | char server_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; |
154 | char *hostname; /* hostname portion of UNC string */ | 164 | char *hostname; /* hostname portion of UNC string */ |
155 | struct socket *ssocket; | 165 | struct socket *ssocket; |
156 | union { | 166 | struct sockaddr_storage dstaddr; |
157 | struct sockaddr_in sockAddr; | ||
158 | struct sockaddr_in6 sockAddr6; | ||
159 | } addr; | ||
160 | struct sockaddr_storage srcaddr; /* locally bind to this IP */ | 167 | struct sockaddr_storage srcaddr; /* locally bind to this IP */ |
161 | wait_queue_head_t response_q; | 168 | wait_queue_head_t response_q; |
162 | wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/ | 169 | wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/ |
@@ -200,7 +207,7 @@ struct TCP_Server_Info { | |||
200 | char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */ | 207 | char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */ |
201 | /* 16th byte of RFC1001 workstation name is always null */ | 208 | /* 16th byte of RFC1001 workstation name is always null */ |
202 | char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; | 209 | char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL]; |
203 | __u32 sequence_number; /* needed for CIFS PDU signature */ | 210 | __u32 sequence_number; /* for signing, protected by srv_mutex */ |
204 | struct session_key session_key; | 211 | struct session_key session_key; |
205 | unsigned long lstrp; /* when we got last response from this server */ | 212 | unsigned long lstrp; /* when we got last response from this server */ |
206 | u16 dialect; /* dialect index that server chose */ | 213 | u16 dialect; /* dialect index that server chose */ |
@@ -446,6 +453,7 @@ struct cifsInodeInfo { | |||
446 | bool invalid_mapping:1; /* pagecache is invalid */ | 453 | bool invalid_mapping:1; /* pagecache is invalid */ |
447 | u64 server_eof; /* current file size on server */ | 454 | u64 server_eof; /* current file size on server */ |
448 | u64 uniqueid; /* server inode number */ | 455 | u64 uniqueid; /* server inode number */ |
456 | u64 createtime; /* creation time on server */ | ||
449 | #ifdef CONFIG_CIFS_FSCACHE | 457 | #ifdef CONFIG_CIFS_FSCACHE |
450 | struct fscache_cookie *fscache; | 458 | struct fscache_cookie *fscache; |
451 | #endif | 459 | #endif |
@@ -566,6 +574,7 @@ struct cifs_fattr { | |||
566 | u64 cf_uniqueid; | 574 | u64 cf_uniqueid; |
567 | u64 cf_eof; | 575 | u64 cf_eof; |
568 | u64 cf_bytes; | 576 | u64 cf_bytes; |
577 | u64 cf_createtime; | ||
569 | uid_t cf_uid; | 578 | uid_t cf_uid; |
570 | gid_t cf_gid; | 579 | gid_t cf_gid; |
571 | umode_t cf_mode; | 580 | umode_t cf_mode; |
@@ -746,8 +755,6 @@ GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */ | |||
746 | GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */ | 755 | GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */ |
747 | GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above & list operations */ | 756 | GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above & list operations */ |
748 | /* on midQ entries */ | 757 | /* on midQ entries */ |
749 | GLOBAL_EXTERN char Local_System_Name[15]; | ||
750 | |||
751 | /* | 758 | /* |
752 | * Global counters, updated atomically | 759 | * Global counters, updated atomically |
753 | */ | 760 | */ |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index db961dc4fd3d..e6d1481b16c1 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -54,7 +54,8 @@ do { \ | |||
54 | __func__, curr_xid, (int)rc); \ | 54 | __func__, curr_xid, (int)rc); \ |
55 | } while (0) | 55 | } while (0) |
56 | extern char *build_path_from_dentry(struct dentry *); | 56 | extern char *build_path_from_dentry(struct dentry *); |
57 | extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb); | 57 | extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb, |
58 | struct cifsTconInfo *tcon); | ||
58 | extern char *build_wildcard_path_from_dentry(struct dentry *direntry); | 59 | extern char *build_wildcard_path_from_dentry(struct dentry *direntry); |
59 | extern char *cifs_compose_mount_options(const char *sb_mountdata, | 60 | extern char *cifs_compose_mount_options(const char *sb_mountdata, |
60 | const char *fullpath, const struct dfs_info3_param *ref, | 61 | const char *fullpath, const struct dfs_info3_param *ref, |
@@ -79,9 +80,7 @@ extern bool is_valid_oplock_break(struct smb_hdr *smb, | |||
79 | struct TCP_Server_Info *); | 80 | struct TCP_Server_Info *); |
80 | extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); | 81 | extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); |
81 | extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool); | 82 | extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool); |
82 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
83 | extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool); | 83 | extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool); |
84 | #endif | ||
85 | extern unsigned int smbCalcSize(struct smb_hdr *ptr); | 84 | extern unsigned int smbCalcSize(struct smb_hdr *ptr); |
86 | extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); | 85 | extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); |
87 | extern int decode_negTokenInit(unsigned char *security_blob, int length, | 86 | extern int decode_negTokenInit(unsigned char *security_blob, int length, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 2f2632b6df5a..2f6795e524d3 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -401,15 +401,12 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
401 | else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) { | 401 | else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) { |
402 | cFYI(1, "Kerberos only mechanism, enable extended security"); | 402 | cFYI(1, "Kerberos only mechanism, enable extended security"); |
403 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 403 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
404 | } | 404 | } else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP) |
405 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
406 | else if ((secFlags & CIFSSEC_MUST_NTLMSSP) == CIFSSEC_MUST_NTLMSSP) | ||
407 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 405 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
408 | else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) { | 406 | else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_NTLMSSP) { |
409 | cFYI(1, "NTLMSSP only mechanism, enable extended security"); | 407 | cFYI(1, "NTLMSSP only mechanism, enable extended security"); |
410 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 408 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
411 | } | 409 | } |
412 | #endif | ||
413 | 410 | ||
414 | count = 0; | 411 | count = 0; |
415 | for (i = 0; i < CIFS_NUM_PROT; i++) { | 412 | for (i = 0; i < CIFS_NUM_PROT; i++) { |
@@ -2478,95 +2475,6 @@ querySymLinkRetry: | |||
2478 | } | 2475 | } |
2479 | 2476 | ||
2480 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 2477 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
2481 | /* Initialize NT TRANSACT SMB into small smb request buffer. | ||
2482 | This assumes that all NT TRANSACTS that we init here have | ||
2483 | total parm and data under about 400 bytes (to fit in small cifs | ||
2484 | buffer size), which is the case so far, it easily fits. NB: | ||
2485 | Setup words themselves and ByteCount | ||
2486 | MaxSetupCount (size of returned setup area) and | ||
2487 | MaxParameterCount (returned parms size) must be set by caller */ | ||
2488 | static int | ||
2489 | smb_init_nttransact(const __u16 sub_command, const int setup_count, | ||
2490 | const int parm_len, struct cifsTconInfo *tcon, | ||
2491 | void **ret_buf) | ||
2492 | { | ||
2493 | int rc; | ||
2494 | __u32 temp_offset; | ||
2495 | struct smb_com_ntransact_req *pSMB; | ||
2496 | |||
2497 | rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon, | ||
2498 | (void **)&pSMB); | ||
2499 | if (rc) | ||
2500 | return rc; | ||
2501 | *ret_buf = (void *)pSMB; | ||
2502 | pSMB->Reserved = 0; | ||
2503 | pSMB->TotalParameterCount = cpu_to_le32(parm_len); | ||
2504 | pSMB->TotalDataCount = 0; | ||
2505 | pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - | ||
2506 | MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); | ||
2507 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
2508 | pSMB->DataCount = pSMB->TotalDataCount; | ||
2509 | temp_offset = offsetof(struct smb_com_ntransact_req, Parms) + | ||
2510 | (setup_count * 2) - 4 /* for rfc1001 length itself */; | ||
2511 | pSMB->ParameterOffset = cpu_to_le32(temp_offset); | ||
2512 | pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len); | ||
2513 | pSMB->SetupCount = setup_count; /* no need to le convert byte fields */ | ||
2514 | pSMB->SubCommand = cpu_to_le16(sub_command); | ||
2515 | return 0; | ||
2516 | } | ||
2517 | |||
2518 | static int | ||
2519 | validate_ntransact(char *buf, char **ppparm, char **ppdata, | ||
2520 | __u32 *pparmlen, __u32 *pdatalen) | ||
2521 | { | ||
2522 | char *end_of_smb; | ||
2523 | __u32 data_count, data_offset, parm_count, parm_offset; | ||
2524 | struct smb_com_ntransact_rsp *pSMBr; | ||
2525 | |||
2526 | *pdatalen = 0; | ||
2527 | *pparmlen = 0; | ||
2528 | |||
2529 | if (buf == NULL) | ||
2530 | return -EINVAL; | ||
2531 | |||
2532 | pSMBr = (struct smb_com_ntransact_rsp *)buf; | ||
2533 | |||
2534 | /* ByteCount was converted from little endian in SendReceive */ | ||
2535 | end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount + | ||
2536 | (char *)&pSMBr->ByteCount; | ||
2537 | |||
2538 | data_offset = le32_to_cpu(pSMBr->DataOffset); | ||
2539 | data_count = le32_to_cpu(pSMBr->DataCount); | ||
2540 | parm_offset = le32_to_cpu(pSMBr->ParameterOffset); | ||
2541 | parm_count = le32_to_cpu(pSMBr->ParameterCount); | ||
2542 | |||
2543 | *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset; | ||
2544 | *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset; | ||
2545 | |||
2546 | /* should we also check that parm and data areas do not overlap? */ | ||
2547 | if (*ppparm > end_of_smb) { | ||
2548 | cFYI(1, "parms start after end of smb"); | ||
2549 | return -EINVAL; | ||
2550 | } else if (parm_count + *ppparm > end_of_smb) { | ||
2551 | cFYI(1, "parm end after end of smb"); | ||
2552 | return -EINVAL; | ||
2553 | } else if (*ppdata > end_of_smb) { | ||
2554 | cFYI(1, "data starts after end of smb"); | ||
2555 | return -EINVAL; | ||
2556 | } else if (data_count + *ppdata > end_of_smb) { | ||
2557 | cFYI(1, "data %p + count %d (%p) past smb end %p start %p", | ||
2558 | *ppdata, data_count, (data_count + *ppdata), | ||
2559 | end_of_smb, pSMBr); | ||
2560 | return -EINVAL; | ||
2561 | } else if (parm_count + data_count > pSMBr->ByteCount) { | ||
2562 | cFYI(1, "parm count and data count larger than SMB"); | ||
2563 | return -EINVAL; | ||
2564 | } | ||
2565 | *pdatalen = data_count; | ||
2566 | *pparmlen = parm_count; | ||
2567 | return 0; | ||
2568 | } | ||
2569 | |||
2570 | int | 2478 | int |
2571 | CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | 2479 | CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, |
2572 | const unsigned char *searchName, | 2480 | const unsigned char *searchName, |
@@ -3056,7 +2964,97 @@ GetExtAttrOut: | |||
3056 | 2964 | ||
3057 | #endif /* CONFIG_POSIX */ | 2965 | #endif /* CONFIG_POSIX */ |
3058 | 2966 | ||
3059 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 2967 | #ifdef CONFIG_CIFS_ACL |
2968 | /* | ||
2969 | * Initialize NT TRANSACT SMB into small smb request buffer. This assumes that | ||
2970 | * all NT TRANSACTS that we init here have total parm and data under about 400 | ||
2971 | * bytes (to fit in small cifs buffer size), which is the case so far, it | ||
2972 | * easily fits. NB: Setup words themselves and ByteCount MaxSetupCount (size of | ||
2973 | * returned setup area) and MaxParameterCount (returned parms size) must be set | ||
2974 | * by caller | ||
2975 | */ | ||
2976 | static int | ||
2977 | smb_init_nttransact(const __u16 sub_command, const int setup_count, | ||
2978 | const int parm_len, struct cifsTconInfo *tcon, | ||
2979 | void **ret_buf) | ||
2980 | { | ||
2981 | int rc; | ||
2982 | __u32 temp_offset; | ||
2983 | struct smb_com_ntransact_req *pSMB; | ||
2984 | |||
2985 | rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon, | ||
2986 | (void **)&pSMB); | ||
2987 | if (rc) | ||
2988 | return rc; | ||
2989 | *ret_buf = (void *)pSMB; | ||
2990 | pSMB->Reserved = 0; | ||
2991 | pSMB->TotalParameterCount = cpu_to_le32(parm_len); | ||
2992 | pSMB->TotalDataCount = 0; | ||
2993 | pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - | ||
2994 | MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); | ||
2995 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
2996 | pSMB->DataCount = pSMB->TotalDataCount; | ||
2997 | temp_offset = offsetof(struct smb_com_ntransact_req, Parms) + | ||
2998 | (setup_count * 2) - 4 /* for rfc1001 length itself */; | ||
2999 | pSMB->ParameterOffset = cpu_to_le32(temp_offset); | ||
3000 | pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len); | ||
3001 | pSMB->SetupCount = setup_count; /* no need to le convert byte fields */ | ||
3002 | pSMB->SubCommand = cpu_to_le16(sub_command); | ||
3003 | return 0; | ||
3004 | } | ||
3005 | |||
3006 | static int | ||
3007 | validate_ntransact(char *buf, char **ppparm, char **ppdata, | ||
3008 | __u32 *pparmlen, __u32 *pdatalen) | ||
3009 | { | ||
3010 | char *end_of_smb; | ||
3011 | __u32 data_count, data_offset, parm_count, parm_offset; | ||
3012 | struct smb_com_ntransact_rsp *pSMBr; | ||
3013 | |||
3014 | *pdatalen = 0; | ||
3015 | *pparmlen = 0; | ||
3016 | |||
3017 | if (buf == NULL) | ||
3018 | return -EINVAL; | ||
3019 | |||
3020 | pSMBr = (struct smb_com_ntransact_rsp *)buf; | ||
3021 | |||
3022 | /* ByteCount was converted from little endian in SendReceive */ | ||
3023 | end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount + | ||
3024 | (char *)&pSMBr->ByteCount; | ||
3025 | |||
3026 | data_offset = le32_to_cpu(pSMBr->DataOffset); | ||
3027 | data_count = le32_to_cpu(pSMBr->DataCount); | ||
3028 | parm_offset = le32_to_cpu(pSMBr->ParameterOffset); | ||
3029 | parm_count = le32_to_cpu(pSMBr->ParameterCount); | ||
3030 | |||
3031 | *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset; | ||
3032 | *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset; | ||
3033 | |||
3034 | /* should we also check that parm and data areas do not overlap? */ | ||
3035 | if (*ppparm > end_of_smb) { | ||
3036 | cFYI(1, "parms start after end of smb"); | ||
3037 | return -EINVAL; | ||
3038 | } else if (parm_count + *ppparm > end_of_smb) { | ||
3039 | cFYI(1, "parm end after end of smb"); | ||
3040 | return -EINVAL; | ||
3041 | } else if (*ppdata > end_of_smb) { | ||
3042 | cFYI(1, "data starts after end of smb"); | ||
3043 | return -EINVAL; | ||
3044 | } else if (data_count + *ppdata > end_of_smb) { | ||
3045 | cFYI(1, "data %p + count %d (%p) past smb end %p start %p", | ||
3046 | *ppdata, data_count, (data_count + *ppdata), | ||
3047 | end_of_smb, pSMBr); | ||
3048 | return -EINVAL; | ||
3049 | } else if (parm_count + data_count > pSMBr->ByteCount) { | ||
3050 | cFYI(1, "parm count and data count larger than SMB"); | ||
3051 | return -EINVAL; | ||
3052 | } | ||
3053 | *pdatalen = data_count; | ||
3054 | *pparmlen = parm_count; | ||
3055 | return 0; | ||
3056 | } | ||
3057 | |||
3060 | /* Get Security Descriptor (by handle) from remote server for a file or dir */ | 3058 | /* Get Security Descriptor (by handle) from remote server for a file or dir */ |
3061 | int | 3059 | int |
3062 | CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, | 3060 | CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, |
@@ -3214,7 +3212,7 @@ setCifsAclRetry: | |||
3214 | return (rc); | 3212 | return (rc); |
3215 | } | 3213 | } |
3216 | 3214 | ||
3217 | #endif /* CONFIG_CIFS_EXPERIMENTAL */ | 3215 | #endif /* CONFIG_CIFS_ACL */ |
3218 | 3216 | ||
3219 | /* Legacy Query Path Information call for lookup to old servers such | 3217 | /* Legacy Query Path Information call for lookup to old servers such |
3220 | as Win9x/WinME */ | 3218 | as Win9x/WinME */ |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 32fa4d9b5dbc..a65d311d163a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -64,8 +64,8 @@ struct smb_vol { | |||
64 | char *UNC; | 64 | char *UNC; |
65 | char *UNCip; | 65 | char *UNCip; |
66 | char *iocharset; /* local code page for mapping to and from Unicode */ | 66 | char *iocharset; /* local code page for mapping to and from Unicode */ |
67 | char source_rfc1001_name[16]; /* netbios name of client */ | 67 | char source_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* clnt nb name */ |
68 | char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */ | 68 | char target_rfc1001_name[RFC1001_NAME_LEN_WITH_NULL]; /* srvr nb name */ |
69 | uid_t cred_uid; | 69 | uid_t cred_uid; |
70 | uid_t linux_uid; | 70 | uid_t linux_uid; |
71 | gid_t linux_gid; | 71 | gid_t linux_gid; |
@@ -105,6 +105,7 @@ struct smb_vol { | |||
105 | unsigned int wsize; | 105 | unsigned int wsize; |
106 | bool sockopt_tcp_nodelay:1; | 106 | bool sockopt_tcp_nodelay:1; |
107 | unsigned short int port; | 107 | unsigned short int port; |
108 | unsigned long actimeo; /* attribute cache timeout (jiffies) */ | ||
108 | char *prepath; | 109 | char *prepath; |
109 | struct sockaddr_storage srcaddr; /* allow binding to a local IP */ | 110 | struct sockaddr_storage srcaddr; /* allow binding to a local IP */ |
110 | struct nls_table *local_nls; | 111 | struct nls_table *local_nls; |
@@ -114,8 +115,8 @@ struct smb_vol { | |||
114 | #define TLINK_ERROR_EXPIRE (1 * HZ) | 115 | #define TLINK_ERROR_EXPIRE (1 * HZ) |
115 | #define TLINK_IDLE_EXPIRE (600 * HZ) | 116 | #define TLINK_IDLE_EXPIRE (600 * HZ) |
116 | 117 | ||
117 | static int ipv4_connect(struct TCP_Server_Info *server); | 118 | static int ip_connect(struct TCP_Server_Info *server); |
118 | static int ipv6_connect(struct TCP_Server_Info *server); | 119 | static int generic_ip_connect(struct TCP_Server_Info *server); |
119 | static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); | 120 | static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); |
120 | static void cifs_prune_tlinks(struct work_struct *work); | 121 | static void cifs_prune_tlinks(struct work_struct *work); |
121 | 122 | ||
@@ -199,10 +200,9 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
199 | while ((server->tcpStatus != CifsExiting) && | 200 | while ((server->tcpStatus != CifsExiting) && |
200 | (server->tcpStatus != CifsGood)) { | 201 | (server->tcpStatus != CifsGood)) { |
201 | try_to_freeze(); | 202 | try_to_freeze(); |
202 | if (server->addr.sockAddr6.sin6_family == AF_INET6) | 203 | |
203 | rc = ipv6_connect(server); | 204 | /* we should try only the port we connected to before */ |
204 | else | 205 | rc = generic_ip_connect(server); |
205 | rc = ipv4_connect(server); | ||
206 | if (rc) { | 206 | if (rc) { |
207 | cFYI(1, "reconnect error %d", rc); | 207 | cFYI(1, "reconnect error %d", rc); |
208 | msleep(3000); | 208 | msleep(3000); |
@@ -476,7 +476,7 @@ incomplete_rcv: | |||
476 | * initialize frame) | 476 | * initialize frame) |
477 | */ | 477 | */ |
478 | cifs_set_port((struct sockaddr *) | 478 | cifs_set_port((struct sockaddr *) |
479 | &server->addr.sockAddr, CIFS_PORT); | 479 | &server->dstaddr, CIFS_PORT); |
480 | cifs_reconnect(server); | 480 | cifs_reconnect(server); |
481 | csocket = server->ssocket; | 481 | csocket = server->ssocket; |
482 | wake_up(&server->response_q); | 482 | wake_up(&server->response_q); |
@@ -806,24 +806,21 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
806 | short int override_gid = -1; | 806 | short int override_gid = -1; |
807 | bool uid_specified = false; | 807 | bool uid_specified = false; |
808 | bool gid_specified = false; | 808 | bool gid_specified = false; |
809 | char *nodename = utsname()->nodename; | ||
809 | 810 | ||
810 | separator[0] = ','; | 811 | separator[0] = ','; |
811 | separator[1] = 0; | 812 | separator[1] = 0; |
812 | 813 | ||
813 | if (Local_System_Name[0] != 0) | 814 | /* |
814 | memcpy(vol->source_rfc1001_name, Local_System_Name, 15); | 815 | * does not have to be perfect mapping since field is |
815 | else { | 816 | * informational, only used for servers that do not support |
816 | char *nodename = utsname()->nodename; | 817 | * port 445 and it can be overridden at mount time |
817 | int n = strnlen(nodename, 15); | 818 | */ |
818 | memset(vol->source_rfc1001_name, 0x20, 15); | 819 | memset(vol->source_rfc1001_name, 0x20, RFC1001_NAME_LEN); |
819 | for (i = 0; i < n; i++) { | 820 | for (i = 0; i < strnlen(nodename, RFC1001_NAME_LEN); i++) |
820 | /* does not have to be perfect mapping since field is | 821 | vol->source_rfc1001_name[i] = toupper(nodename[i]); |
821 | informational, only used for servers that do not support | 822 | |
822 | port 445 and it can be overridden at mount time */ | 823 | vol->source_rfc1001_name[RFC1001_NAME_LEN] = 0; |
823 | vol->source_rfc1001_name[i] = toupper(nodename[i]); | ||
824 | } | ||
825 | } | ||
826 | vol->source_rfc1001_name[15] = 0; | ||
827 | /* null target name indicates to use *SMBSERVR default called name | 824 | /* null target name indicates to use *SMBSERVR default called name |
828 | if we end up sending RFC1001 session initialize */ | 825 | if we end up sending RFC1001 session initialize */ |
829 | vol->target_rfc1001_name[0] = 0; | 826 | vol->target_rfc1001_name[0] = 0; |
@@ -840,6 +837,8 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
840 | /* default to using server inode numbers where available */ | 837 | /* default to using server inode numbers where available */ |
841 | vol->server_ino = 1; | 838 | vol->server_ino = 1; |
842 | 839 | ||
840 | vol->actimeo = CIFS_DEF_ACTIMEO; | ||
841 | |||
843 | if (!options) | 842 | if (!options) |
844 | return 1; | 843 | return 1; |
845 | 844 | ||
@@ -985,13 +984,11 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
985 | return 1; | 984 | return 1; |
986 | } else if (strnicmp(value, "krb5", 4) == 0) { | 985 | } else if (strnicmp(value, "krb5", 4) == 0) { |
987 | vol->secFlg |= CIFSSEC_MAY_KRB5; | 986 | vol->secFlg |= CIFSSEC_MAY_KRB5; |
988 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
989 | } else if (strnicmp(value, "ntlmsspi", 8) == 0) { | 987 | } else if (strnicmp(value, "ntlmsspi", 8) == 0) { |
990 | vol->secFlg |= CIFSSEC_MAY_NTLMSSP | | 988 | vol->secFlg |= CIFSSEC_MAY_NTLMSSP | |
991 | CIFSSEC_MUST_SIGN; | 989 | CIFSSEC_MUST_SIGN; |
992 | } else if (strnicmp(value, "ntlmssp", 7) == 0) { | 990 | } else if (strnicmp(value, "ntlmssp", 7) == 0) { |
993 | vol->secFlg |= CIFSSEC_MAY_NTLMSSP; | 991 | vol->secFlg |= CIFSSEC_MAY_NTLMSSP; |
994 | #endif | ||
995 | } else if (strnicmp(value, "ntlmv2i", 7) == 0) { | 992 | } else if (strnicmp(value, "ntlmv2i", 7) == 0) { |
996 | vol->secFlg |= CIFSSEC_MAY_NTLMV2 | | 993 | vol->secFlg |= CIFSSEC_MAY_NTLMV2 | |
997 | CIFSSEC_MUST_SIGN; | 994 | CIFSSEC_MUST_SIGN; |
@@ -1168,22 +1165,22 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1168 | if (!value || !*value || (*value == ' ')) { | 1165 | if (!value || !*value || (*value == ' ')) { |
1169 | cFYI(1, "invalid (empty) netbiosname"); | 1166 | cFYI(1, "invalid (empty) netbiosname"); |
1170 | } else { | 1167 | } else { |
1171 | memset(vol->source_rfc1001_name, 0x20, 15); | 1168 | memset(vol->source_rfc1001_name, 0x20, |
1172 | for (i = 0; i < 15; i++) { | 1169 | RFC1001_NAME_LEN); |
1173 | /* BB are there cases in which a comma can be | 1170 | /* |
1174 | valid in this workstation netbios name (and need | 1171 | * FIXME: are there cases in which a comma can |
1175 | special handling)? */ | 1172 | * be valid in workstation netbios name (and |
1176 | 1173 | * need special handling)? | |
1177 | /* We do not uppercase netbiosname for user */ | 1174 | */ |
1175 | for (i = 0; i < RFC1001_NAME_LEN; i++) { | ||
1176 | /* don't ucase netbiosname for user */ | ||
1178 | if (value[i] == 0) | 1177 | if (value[i] == 0) |
1179 | break; | 1178 | break; |
1180 | else | 1179 | vol->source_rfc1001_name[i] = value[i]; |
1181 | vol->source_rfc1001_name[i] = | ||
1182 | value[i]; | ||
1183 | } | 1180 | } |
1184 | /* The string has 16th byte zero still from | 1181 | /* The string has 16th byte zero still from |
1185 | set at top of the function */ | 1182 | set at top of the function */ |
1186 | if ((i == 15) && (value[i] != 0)) | 1183 | if (i == RFC1001_NAME_LEN && value[i] != 0) |
1187 | printk(KERN_WARNING "CIFS: netbiosname" | 1184 | printk(KERN_WARNING "CIFS: netbiosname" |
1188 | " longer than 15 truncated.\n"); | 1185 | " longer than 15 truncated.\n"); |
1189 | } | 1186 | } |
@@ -1193,7 +1190,8 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1193 | cFYI(1, "empty server netbiosname specified"); | 1190 | cFYI(1, "empty server netbiosname specified"); |
1194 | } else { | 1191 | } else { |
1195 | /* last byte, type, is 0x20 for servr type */ | 1192 | /* last byte, type, is 0x20 for servr type */ |
1196 | memset(vol->target_rfc1001_name, 0x20, 16); | 1193 | memset(vol->target_rfc1001_name, 0x20, |
1194 | RFC1001_NAME_LEN_WITH_NULL); | ||
1197 | 1195 | ||
1198 | for (i = 0; i < 15; i++) { | 1196 | for (i = 0; i < 15; i++) { |
1199 | /* BB are there cases in which a comma can be | 1197 | /* BB are there cases in which a comma can be |
@@ -1210,10 +1208,20 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1210 | } | 1208 | } |
1211 | /* The string has 16th byte zero still from | 1209 | /* The string has 16th byte zero still from |
1212 | set at top of the function */ | 1210 | set at top of the function */ |
1213 | if ((i == 15) && (value[i] != 0)) | 1211 | if (i == RFC1001_NAME_LEN && value[i] != 0) |
1214 | printk(KERN_WARNING "CIFS: server net" | 1212 | printk(KERN_WARNING "CIFS: server net" |
1215 | "biosname longer than 15 truncated.\n"); | 1213 | "biosname longer than 15 truncated.\n"); |
1216 | } | 1214 | } |
1215 | } else if (strnicmp(data, "actimeo", 7) == 0) { | ||
1216 | if (value && *value) { | ||
1217 | vol->actimeo = HZ * simple_strtoul(value, | ||
1218 | &value, 0); | ||
1219 | if (vol->actimeo > CIFS_MAX_ACTIMEO) { | ||
1220 | cERROR(1, "CIFS: attribute cache" | ||
1221 | "timeout too large"); | ||
1222 | return 1; | ||
1223 | } | ||
1224 | } | ||
1217 | } else if (strnicmp(data, "credentials", 4) == 0) { | 1225 | } else if (strnicmp(data, "credentials", 4) == 0) { |
1218 | /* ignore */ | 1226 | /* ignore */ |
1219 | } else if (strnicmp(data, "version", 3) == 0) { | 1227 | } else if (strnicmp(data, "version", 3) == 0) { |
@@ -1331,10 +1339,8 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1331 | vol->no_psx_acl = 0; | 1339 | vol->no_psx_acl = 0; |
1332 | } else if (strnicmp(data, "noacl", 5) == 0) { | 1340 | } else if (strnicmp(data, "noacl", 5) == 0) { |
1333 | vol->no_psx_acl = 1; | 1341 | vol->no_psx_acl = 1; |
1334 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
1335 | } else if (strnicmp(data, "locallease", 6) == 0) { | 1342 | } else if (strnicmp(data, "locallease", 6) == 0) { |
1336 | vol->local_lease = 1; | 1343 | vol->local_lease = 1; |
1337 | #endif | ||
1338 | } else if (strnicmp(data, "sign", 4) == 0) { | 1344 | } else if (strnicmp(data, "sign", 4) == 0) { |
1339 | vol->secFlg |= CIFSSEC_MUST_SIGN; | 1345 | vol->secFlg |= CIFSSEC_MUST_SIGN; |
1340 | } else if (strnicmp(data, "seal", 4) == 0) { | 1346 | } else if (strnicmp(data, "seal", 4) == 0) { |
@@ -1444,35 +1450,71 @@ srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs) | |||
1444 | } | 1450 | } |
1445 | } | 1451 | } |
1446 | 1452 | ||
1453 | /* | ||
1454 | * If no port is specified in addr structure, we try to match with 445 port | ||
1455 | * and if it fails - with 139 ports. It should be called only if address | ||
1456 | * families of server and addr are equal. | ||
1457 | */ | ||
1458 | static bool | ||
1459 | match_port(struct TCP_Server_Info *server, struct sockaddr *addr) | ||
1460 | { | ||
1461 | unsigned short int port, *sport; | ||
1462 | |||
1463 | switch (addr->sa_family) { | ||
1464 | case AF_INET: | ||
1465 | sport = &((struct sockaddr_in *) &server->dstaddr)->sin_port; | ||
1466 | port = ((struct sockaddr_in *) addr)->sin_port; | ||
1467 | break; | ||
1468 | case AF_INET6: | ||
1469 | sport = &((struct sockaddr_in6 *) &server->dstaddr)->sin6_port; | ||
1470 | port = ((struct sockaddr_in6 *) addr)->sin6_port; | ||
1471 | break; | ||
1472 | default: | ||
1473 | WARN_ON(1); | ||
1474 | return false; | ||
1475 | } | ||
1476 | |||
1477 | if (!port) { | ||
1478 | port = htons(CIFS_PORT); | ||
1479 | if (port == *sport) | ||
1480 | return true; | ||
1481 | |||
1482 | port = htons(RFC1001_PORT); | ||
1483 | } | ||
1484 | |||
1485 | return port == *sport; | ||
1486 | } | ||
1447 | 1487 | ||
1448 | static bool | 1488 | static bool |
1449 | match_address(struct TCP_Server_Info *server, struct sockaddr *addr, | 1489 | match_address(struct TCP_Server_Info *server, struct sockaddr *addr, |
1450 | struct sockaddr *srcaddr) | 1490 | struct sockaddr *srcaddr) |
1451 | { | 1491 | { |
1452 | struct sockaddr_in *addr4 = (struct sockaddr_in *)addr; | ||
1453 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; | ||
1454 | |||
1455 | switch (addr->sa_family) { | 1492 | switch (addr->sa_family) { |
1456 | case AF_INET: | 1493 | case AF_INET: { |
1457 | if (addr4->sin_addr.s_addr != | 1494 | struct sockaddr_in *addr4 = (struct sockaddr_in *)addr; |
1458 | server->addr.sockAddr.sin_addr.s_addr) | 1495 | struct sockaddr_in *srv_addr4 = |
1459 | return false; | 1496 | (struct sockaddr_in *)&server->dstaddr; |
1460 | if (addr4->sin_port && | 1497 | |
1461 | addr4->sin_port != server->addr.sockAddr.sin_port) | 1498 | if (addr4->sin_addr.s_addr != srv_addr4->sin_addr.s_addr) |
1462 | return false; | 1499 | return false; |
1463 | break; | 1500 | break; |
1464 | case AF_INET6: | 1501 | } |
1502 | case AF_INET6: { | ||
1503 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; | ||
1504 | struct sockaddr_in6 *srv_addr6 = | ||
1505 | (struct sockaddr_in6 *)&server->dstaddr; | ||
1506 | |||
1465 | if (!ipv6_addr_equal(&addr6->sin6_addr, | 1507 | if (!ipv6_addr_equal(&addr6->sin6_addr, |
1466 | &server->addr.sockAddr6.sin6_addr)) | 1508 | &srv_addr6->sin6_addr)) |
1467 | return false; | 1509 | return false; |
1468 | if (addr6->sin6_scope_id != | 1510 | if (addr6->sin6_scope_id != srv_addr6->sin6_scope_id) |
1469 | server->addr.sockAddr6.sin6_scope_id) | ||
1470 | return false; | ||
1471 | if (addr6->sin6_port && | ||
1472 | addr6->sin6_port != server->addr.sockAddr6.sin6_port) | ||
1473 | return false; | 1511 | return false; |
1474 | break; | 1512 | break; |
1475 | } | 1513 | } |
1514 | default: | ||
1515 | WARN_ON(1); | ||
1516 | return false; /* don't expect to be here */ | ||
1517 | } | ||
1476 | 1518 | ||
1477 | if (!srcip_matches(srcaddr, (struct sockaddr *)&server->srcaddr)) | 1519 | if (!srcip_matches(srcaddr, (struct sockaddr *)&server->srcaddr)) |
1478 | return false; | 1520 | return false; |
@@ -1539,6 +1581,9 @@ cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol) | |||
1539 | (struct sockaddr *)&vol->srcaddr)) | 1581 | (struct sockaddr *)&vol->srcaddr)) |
1540 | continue; | 1582 | continue; |
1541 | 1583 | ||
1584 | if (!match_port(server, addr)) | ||
1585 | continue; | ||
1586 | |||
1542 | if (!match_security(server, vol)) | 1587 | if (!match_security(server, vol)) |
1543 | continue; | 1588 | continue; |
1544 | 1589 | ||
@@ -1671,14 +1716,13 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1671 | cFYI(1, "attempting ipv6 connect"); | 1716 | cFYI(1, "attempting ipv6 connect"); |
1672 | /* BB should we allow ipv6 on port 139? */ | 1717 | /* BB should we allow ipv6 on port 139? */ |
1673 | /* other OS never observed in Wild doing 139 with v6 */ | 1718 | /* other OS never observed in Wild doing 139 with v6 */ |
1674 | memcpy(&tcp_ses->addr.sockAddr6, sin_server6, | 1719 | memcpy(&tcp_ses->dstaddr, sin_server6, |
1675 | sizeof(struct sockaddr_in6)); | 1720 | sizeof(struct sockaddr_in6)); |
1676 | rc = ipv6_connect(tcp_ses); | 1721 | } else |
1677 | } else { | 1722 | memcpy(&tcp_ses->dstaddr, sin_server, |
1678 | memcpy(&tcp_ses->addr.sockAddr, sin_server, | 1723 | sizeof(struct sockaddr_in)); |
1679 | sizeof(struct sockaddr_in)); | 1724 | |
1680 | rc = ipv4_connect(tcp_ses); | 1725 | rc = ip_connect(tcp_ses); |
1681 | } | ||
1682 | if (rc < 0) { | 1726 | if (rc < 0) { |
1683 | cERROR(1, "Error connecting to socket. Aborting operation"); | 1727 | cERROR(1, "Error connecting to socket. Aborting operation"); |
1684 | goto out_err_crypto_release; | 1728 | goto out_err_crypto_release; |
@@ -1783,6 +1827,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1783 | { | 1827 | { |
1784 | int rc = -ENOMEM, xid; | 1828 | int rc = -ENOMEM, xid; |
1785 | struct cifsSesInfo *ses; | 1829 | struct cifsSesInfo *ses; |
1830 | struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; | ||
1831 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr; | ||
1786 | 1832 | ||
1787 | xid = GetXid(); | 1833 | xid = GetXid(); |
1788 | 1834 | ||
@@ -1826,12 +1872,10 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1826 | 1872 | ||
1827 | /* new SMB session uses our server ref */ | 1873 | /* new SMB session uses our server ref */ |
1828 | ses->server = server; | 1874 | ses->server = server; |
1829 | if (server->addr.sockAddr6.sin6_family == AF_INET6) | 1875 | if (server->dstaddr.ss_family == AF_INET6) |
1830 | sprintf(ses->serverName, "%pI6", | 1876 | sprintf(ses->serverName, "%pI6", &addr6->sin6_addr); |
1831 | &server->addr.sockAddr6.sin6_addr); | ||
1832 | else | 1877 | else |
1833 | sprintf(ses->serverName, "%pI4", | 1878 | sprintf(ses->serverName, "%pI4", &addr->sin_addr); |
1834 | &server->addr.sockAddr.sin_addr.s_addr); | ||
1835 | 1879 | ||
1836 | if (volume_info->username) | 1880 | if (volume_info->username) |
1837 | strncpy(ses->userName, volume_info->username, | 1881 | strncpy(ses->userName, volume_info->username, |
@@ -2126,19 +2170,106 @@ bind_socket(struct TCP_Server_Info *server) | |||
2126 | } | 2170 | } |
2127 | 2171 | ||
2128 | static int | 2172 | static int |
2129 | ipv4_connect(struct TCP_Server_Info *server) | 2173 | ip_rfc1001_connect(struct TCP_Server_Info *server) |
2130 | { | 2174 | { |
2131 | int rc = 0; | 2175 | int rc = 0; |
2132 | int val; | 2176 | /* |
2133 | bool connected = false; | 2177 | * some servers require RFC1001 sessinit before sending |
2134 | __be16 orig_port = 0; | 2178 | * negprot - BB check reconnection in case where second |
2179 | * sessinit is sent but no second negprot | ||
2180 | */ | ||
2181 | struct rfc1002_session_packet *ses_init_buf; | ||
2182 | struct smb_hdr *smb_buf; | ||
2183 | ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), | ||
2184 | GFP_KERNEL); | ||
2185 | if (ses_init_buf) { | ||
2186 | ses_init_buf->trailer.session_req.called_len = 32; | ||
2187 | |||
2188 | if (server->server_RFC1001_name && | ||
2189 | server->server_RFC1001_name[0] != 0) | ||
2190 | rfc1002mangle(ses_init_buf->trailer. | ||
2191 | session_req.called_name, | ||
2192 | server->server_RFC1001_name, | ||
2193 | RFC1001_NAME_LEN_WITH_NULL); | ||
2194 | else | ||
2195 | rfc1002mangle(ses_init_buf->trailer. | ||
2196 | session_req.called_name, | ||
2197 | DEFAULT_CIFS_CALLED_NAME, | ||
2198 | RFC1001_NAME_LEN_WITH_NULL); | ||
2199 | |||
2200 | ses_init_buf->trailer.session_req.calling_len = 32; | ||
2201 | |||
2202 | /* | ||
2203 | * calling name ends in null (byte 16) from old smb | ||
2204 | * convention. | ||
2205 | */ | ||
2206 | if (server->workstation_RFC1001_name && | ||
2207 | server->workstation_RFC1001_name[0] != 0) | ||
2208 | rfc1002mangle(ses_init_buf->trailer. | ||
2209 | session_req.calling_name, | ||
2210 | server->workstation_RFC1001_name, | ||
2211 | RFC1001_NAME_LEN_WITH_NULL); | ||
2212 | else | ||
2213 | rfc1002mangle(ses_init_buf->trailer. | ||
2214 | session_req.calling_name, | ||
2215 | "LINUX_CIFS_CLNT", | ||
2216 | RFC1001_NAME_LEN_WITH_NULL); | ||
2217 | |||
2218 | ses_init_buf->trailer.session_req.scope1 = 0; | ||
2219 | ses_init_buf->trailer.session_req.scope2 = 0; | ||
2220 | smb_buf = (struct smb_hdr *)ses_init_buf; | ||
2221 | |||
2222 | /* sizeof RFC1002_SESSION_REQUEST with no scope */ | ||
2223 | smb_buf->smb_buf_length = 0x81000044; | ||
2224 | rc = smb_send(server, smb_buf, 0x44); | ||
2225 | kfree(ses_init_buf); | ||
2226 | /* | ||
2227 | * RFC1001 layer in at least one server | ||
2228 | * requires very short break before negprot | ||
2229 | * presumably because not expecting negprot | ||
2230 | * to follow so fast. This is a simple | ||
2231 | * solution that works without | ||
2232 | * complicating the code and causes no | ||
2233 | * significant slowing down on mount | ||
2234 | * for everyone else | ||
2235 | */ | ||
2236 | usleep_range(1000, 2000); | ||
2237 | } | ||
2238 | /* | ||
2239 | * else the negprot may still work without this | ||
2240 | * even though malloc failed | ||
2241 | */ | ||
2242 | |||
2243 | return rc; | ||
2244 | } | ||
2245 | |||
2246 | static int | ||
2247 | generic_ip_connect(struct TCP_Server_Info *server) | ||
2248 | { | ||
2249 | int rc = 0; | ||
2250 | unsigned short int sport; | ||
2251 | int slen, sfamily; | ||
2135 | struct socket *socket = server->ssocket; | 2252 | struct socket *socket = server->ssocket; |
2253 | struct sockaddr *saddr; | ||
2254 | |||
2255 | saddr = (struct sockaddr *) &server->dstaddr; | ||
2256 | |||
2257 | if (server->dstaddr.ss_family == AF_INET6) { | ||
2258 | sport = ((struct sockaddr_in6 *) saddr)->sin6_port; | ||
2259 | slen = sizeof(struct sockaddr_in6); | ||
2260 | sfamily = AF_INET6; | ||
2261 | } else { | ||
2262 | sport = ((struct sockaddr_in *) saddr)->sin_port; | ||
2263 | slen = sizeof(struct sockaddr_in); | ||
2264 | sfamily = AF_INET; | ||
2265 | } | ||
2136 | 2266 | ||
2137 | if (socket == NULL) { | 2267 | if (socket == NULL) { |
2138 | rc = sock_create_kern(PF_INET, SOCK_STREAM, | 2268 | rc = sock_create_kern(sfamily, SOCK_STREAM, |
2139 | IPPROTO_TCP, &socket); | 2269 | IPPROTO_TCP, &socket); |
2140 | if (rc < 0) { | 2270 | if (rc < 0) { |
2141 | cERROR(1, "Error %d creating socket", rc); | 2271 | cERROR(1, "Error %d creating socket", rc); |
2272 | server->ssocket = NULL; | ||
2142 | return rc; | 2273 | return rc; |
2143 | } | 2274 | } |
2144 | 2275 | ||
@@ -2146,63 +2277,28 @@ ipv4_connect(struct TCP_Server_Info *server) | |||
2146 | cFYI(1, "Socket created"); | 2277 | cFYI(1, "Socket created"); |
2147 | server->ssocket = socket; | 2278 | server->ssocket = socket; |
2148 | socket->sk->sk_allocation = GFP_NOFS; | 2279 | socket->sk->sk_allocation = GFP_NOFS; |
2149 | cifs_reclassify_socket4(socket); | 2280 | if (sfamily == AF_INET6) |
2281 | cifs_reclassify_socket6(socket); | ||
2282 | else | ||
2283 | cifs_reclassify_socket4(socket); | ||
2150 | } | 2284 | } |
2151 | 2285 | ||
2152 | rc = bind_socket(server); | 2286 | rc = bind_socket(server); |
2153 | if (rc < 0) | 2287 | if (rc < 0) |
2154 | return rc; | 2288 | return rc; |
2155 | 2289 | ||
2156 | /* user overrode default port */ | 2290 | rc = socket->ops->connect(socket, saddr, slen, 0); |
2157 | if (server->addr.sockAddr.sin_port) { | 2291 | if (rc < 0) { |
2158 | rc = socket->ops->connect(socket, (struct sockaddr *) | 2292 | cFYI(1, "Error %d connecting to server", rc); |
2159 | &server->addr.sockAddr, | ||
2160 | sizeof(struct sockaddr_in), 0); | ||
2161 | if (rc >= 0) | ||
2162 | connected = true; | ||
2163 | } | ||
2164 | |||
2165 | if (!connected) { | ||
2166 | /* save original port so we can retry user specified port | ||
2167 | later if fall back ports fail this time */ | ||
2168 | orig_port = server->addr.sockAddr.sin_port; | ||
2169 | |||
2170 | /* do not retry on the same port we just failed on */ | ||
2171 | if (server->addr.sockAddr.sin_port != htons(CIFS_PORT)) { | ||
2172 | server->addr.sockAddr.sin_port = htons(CIFS_PORT); | ||
2173 | rc = socket->ops->connect(socket, | ||
2174 | (struct sockaddr *) | ||
2175 | &server->addr.sockAddr, | ||
2176 | sizeof(struct sockaddr_in), 0); | ||
2177 | if (rc >= 0) | ||
2178 | connected = true; | ||
2179 | } | ||
2180 | } | ||
2181 | if (!connected) { | ||
2182 | server->addr.sockAddr.sin_port = htons(RFC1001_PORT); | ||
2183 | rc = socket->ops->connect(socket, (struct sockaddr *) | ||
2184 | &server->addr.sockAddr, | ||
2185 | sizeof(struct sockaddr_in), 0); | ||
2186 | if (rc >= 0) | ||
2187 | connected = true; | ||
2188 | } | ||
2189 | |||
2190 | /* give up here - unless we want to retry on different | ||
2191 | protocol families some day */ | ||
2192 | if (!connected) { | ||
2193 | if (orig_port) | ||
2194 | server->addr.sockAddr.sin_port = orig_port; | ||
2195 | cFYI(1, "Error %d connecting to server via ipv4", rc); | ||
2196 | sock_release(socket); | 2293 | sock_release(socket); |
2197 | server->ssocket = NULL; | 2294 | server->ssocket = NULL; |
2198 | return rc; | 2295 | return rc; |
2199 | } | 2296 | } |
2200 | 2297 | ||
2201 | |||
2202 | /* | 2298 | /* |
2203 | * Eventually check for other socket options to change from | 2299 | * Eventually check for other socket options to change from |
2204 | * the default. sock_setsockopt not used because it expects | 2300 | * the default. sock_setsockopt not used because it expects |
2205 | * user space buffer | 2301 | * user space buffer |
2206 | */ | 2302 | */ |
2207 | socket->sk->sk_rcvtimeo = 7 * HZ; | 2303 | socket->sk->sk_rcvtimeo = 7 * HZ; |
2208 | socket->sk->sk_sndtimeo = 5 * HZ; | 2304 | socket->sk->sk_sndtimeo = 5 * HZ; |
@@ -2216,7 +2312,7 @@ ipv4_connect(struct TCP_Server_Info *server) | |||
2216 | } | 2312 | } |
2217 | 2313 | ||
2218 | if (server->tcp_nodelay) { | 2314 | if (server->tcp_nodelay) { |
2219 | val = 1; | 2315 | int val = 1; |
2220 | rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY, | 2316 | rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY, |
2221 | (char *)&val, sizeof(val)); | 2317 | (char *)&val, sizeof(val)); |
2222 | if (rc) | 2318 | if (rc) |
@@ -2227,161 +2323,39 @@ ipv4_connect(struct TCP_Server_Info *server) | |||
2227 | socket->sk->sk_sndbuf, | 2323 | socket->sk->sk_sndbuf, |
2228 | socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo); | 2324 | socket->sk->sk_rcvbuf, socket->sk->sk_rcvtimeo); |
2229 | 2325 | ||
2230 | /* send RFC1001 sessinit */ | 2326 | if (sport == htons(RFC1001_PORT)) |
2231 | if (server->addr.sockAddr.sin_port == htons(RFC1001_PORT)) { | 2327 | rc = ip_rfc1001_connect(server); |
2232 | /* some servers require RFC1001 sessinit before sending | ||
2233 | negprot - BB check reconnection in case where second | ||
2234 | sessinit is sent but no second negprot */ | ||
2235 | struct rfc1002_session_packet *ses_init_buf; | ||
2236 | struct smb_hdr *smb_buf; | ||
2237 | ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), | ||
2238 | GFP_KERNEL); | ||
2239 | if (ses_init_buf) { | ||
2240 | ses_init_buf->trailer.session_req.called_len = 32; | ||
2241 | if (server->server_RFC1001_name && | ||
2242 | server->server_RFC1001_name[0] != 0) | ||
2243 | rfc1002mangle(ses_init_buf->trailer. | ||
2244 | session_req.called_name, | ||
2245 | server->server_RFC1001_name, | ||
2246 | RFC1001_NAME_LEN_WITH_NULL); | ||
2247 | else | ||
2248 | rfc1002mangle(ses_init_buf->trailer. | ||
2249 | session_req.called_name, | ||
2250 | DEFAULT_CIFS_CALLED_NAME, | ||
2251 | RFC1001_NAME_LEN_WITH_NULL); | ||
2252 | |||
2253 | ses_init_buf->trailer.session_req.calling_len = 32; | ||
2254 | |||
2255 | /* calling name ends in null (byte 16) from old smb | ||
2256 | convention. */ | ||
2257 | if (server->workstation_RFC1001_name && | ||
2258 | server->workstation_RFC1001_name[0] != 0) | ||
2259 | rfc1002mangle(ses_init_buf->trailer. | ||
2260 | session_req.calling_name, | ||
2261 | server->workstation_RFC1001_name, | ||
2262 | RFC1001_NAME_LEN_WITH_NULL); | ||
2263 | else | ||
2264 | rfc1002mangle(ses_init_buf->trailer. | ||
2265 | session_req.calling_name, | ||
2266 | "LINUX_CIFS_CLNT", | ||
2267 | RFC1001_NAME_LEN_WITH_NULL); | ||
2268 | |||
2269 | ses_init_buf->trailer.session_req.scope1 = 0; | ||
2270 | ses_init_buf->trailer.session_req.scope2 = 0; | ||
2271 | smb_buf = (struct smb_hdr *)ses_init_buf; | ||
2272 | /* sizeof RFC1002_SESSION_REQUEST with no scope */ | ||
2273 | smb_buf->smb_buf_length = 0x81000044; | ||
2274 | rc = smb_send(server, smb_buf, 0x44); | ||
2275 | kfree(ses_init_buf); | ||
2276 | msleep(1); /* RFC1001 layer in at least one server | ||
2277 | requires very short break before negprot | ||
2278 | presumably because not expecting negprot | ||
2279 | to follow so fast. This is a simple | ||
2280 | solution that works without | ||
2281 | complicating the code and causes no | ||
2282 | significant slowing down on mount | ||
2283 | for everyone else */ | ||
2284 | } | ||
2285 | /* else the negprot may still work without this | ||
2286 | even though malloc failed */ | ||
2287 | |||
2288 | } | ||
2289 | 2328 | ||
2290 | return rc; | 2329 | return rc; |
2291 | } | 2330 | } |
2292 | 2331 | ||
2293 | static int | 2332 | static int |
2294 | ipv6_connect(struct TCP_Server_Info *server) | 2333 | ip_connect(struct TCP_Server_Info *server) |
2295 | { | 2334 | { |
2296 | int rc = 0; | 2335 | unsigned short int *sport; |
2297 | int val; | 2336 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&server->dstaddr; |
2298 | bool connected = false; | 2337 | struct sockaddr_in *addr = (struct sockaddr_in *)&server->dstaddr; |
2299 | __be16 orig_port = 0; | ||
2300 | struct socket *socket = server->ssocket; | ||
2301 | 2338 | ||
2302 | if (socket == NULL) { | 2339 | if (server->dstaddr.ss_family == AF_INET6) |
2303 | rc = sock_create_kern(PF_INET6, SOCK_STREAM, | 2340 | sport = &addr6->sin6_port; |
2304 | IPPROTO_TCP, &socket); | 2341 | else |
2305 | if (rc < 0) { | 2342 | sport = &addr->sin_port; |
2306 | cERROR(1, "Error %d creating ipv6 socket", rc); | ||
2307 | socket = NULL; | ||
2308 | return rc; | ||
2309 | } | ||
2310 | 2343 | ||
2311 | /* BB other socket options to set KEEPALIVE, NODELAY? */ | 2344 | if (*sport == 0) { |
2312 | cFYI(1, "ipv6 Socket created"); | 2345 | int rc; |
2313 | server->ssocket = socket; | ||
2314 | socket->sk->sk_allocation = GFP_NOFS; | ||
2315 | cifs_reclassify_socket6(socket); | ||
2316 | } | ||
2317 | 2346 | ||
2318 | rc = bind_socket(server); | 2347 | /* try with 445 port at first */ |
2319 | if (rc < 0) | 2348 | *sport = htons(CIFS_PORT); |
2320 | return rc; | ||
2321 | 2349 | ||
2322 | /* user overrode default port */ | 2350 | rc = generic_ip_connect(server); |
2323 | if (server->addr.sockAddr6.sin6_port) { | ||
2324 | rc = socket->ops->connect(socket, | ||
2325 | (struct sockaddr *) &server->addr.sockAddr6, | ||
2326 | sizeof(struct sockaddr_in6), 0); | ||
2327 | if (rc >= 0) | 2351 | if (rc >= 0) |
2328 | connected = true; | 2352 | return rc; |
2329 | } | ||
2330 | |||
2331 | if (!connected) { | ||
2332 | /* save original port so we can retry user specified port | ||
2333 | later if fall back ports fail this time */ | ||
2334 | |||
2335 | orig_port = server->addr.sockAddr6.sin6_port; | ||
2336 | /* do not retry on the same port we just failed on */ | ||
2337 | if (server->addr.sockAddr6.sin6_port != htons(CIFS_PORT)) { | ||
2338 | server->addr.sockAddr6.sin6_port = htons(CIFS_PORT); | ||
2339 | rc = socket->ops->connect(socket, (struct sockaddr *) | ||
2340 | &server->addr.sockAddr6, | ||
2341 | sizeof(struct sockaddr_in6), 0); | ||
2342 | if (rc >= 0) | ||
2343 | connected = true; | ||
2344 | } | ||
2345 | } | ||
2346 | if (!connected) { | ||
2347 | server->addr.sockAddr6.sin6_port = htons(RFC1001_PORT); | ||
2348 | rc = socket->ops->connect(socket, (struct sockaddr *) | ||
2349 | &server->addr.sockAddr6, | ||
2350 | sizeof(struct sockaddr_in6), 0); | ||
2351 | if (rc >= 0) | ||
2352 | connected = true; | ||
2353 | } | ||
2354 | |||
2355 | /* give up here - unless we want to retry on different | ||
2356 | protocol families some day */ | ||
2357 | if (!connected) { | ||
2358 | if (orig_port) | ||
2359 | server->addr.sockAddr6.sin6_port = orig_port; | ||
2360 | cFYI(1, "Error %d connecting to server via ipv6", rc); | ||
2361 | sock_release(socket); | ||
2362 | server->ssocket = NULL; | ||
2363 | return rc; | ||
2364 | } | ||
2365 | |||
2366 | /* | ||
2367 | * Eventually check for other socket options to change from | ||
2368 | * the default. sock_setsockopt not used because it expects | ||
2369 | * user space buffer | ||
2370 | */ | ||
2371 | socket->sk->sk_rcvtimeo = 7 * HZ; | ||
2372 | socket->sk->sk_sndtimeo = 5 * HZ; | ||
2373 | 2353 | ||
2374 | if (server->tcp_nodelay) { | 2354 | /* if it failed, try with 139 port */ |
2375 | val = 1; | 2355 | *sport = htons(RFC1001_PORT); |
2376 | rc = kernel_setsockopt(socket, SOL_TCP, TCP_NODELAY, | ||
2377 | (char *)&val, sizeof(val)); | ||
2378 | if (rc) | ||
2379 | cFYI(1, "set TCP_NODELAY socket option error %d", rc); | ||
2380 | } | 2356 | } |
2381 | 2357 | ||
2382 | server->ssocket = socket; | 2358 | return generic_ip_connect(server); |
2383 | |||
2384 | return rc; | ||
2385 | } | 2359 | } |
2386 | 2360 | ||
2387 | void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, | 2361 | void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, |
@@ -2571,6 +2545,8 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, | |||
2571 | cFYI(1, "file mode: 0x%x dir mode: 0x%x", | 2545 | cFYI(1, "file mode: 0x%x dir mode: 0x%x", |
2572 | cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode); | 2546 | cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode); |
2573 | 2547 | ||
2548 | cifs_sb->actimeo = pvolume_info->actimeo; | ||
2549 | |||
2574 | if (pvolume_info->noperm) | 2550 | if (pvolume_info->noperm) |
2575 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; | 2551 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; |
2576 | if (pvolume_info->setuids) | 2552 | if (pvolume_info->setuids) |
@@ -2821,13 +2797,13 @@ remote_path_check: | |||
2821 | /* check if a whole path (including prepath) is not remote */ | 2797 | /* check if a whole path (including prepath) is not remote */ |
2822 | if (!rc && cifs_sb->prepathlen && tcon) { | 2798 | if (!rc && cifs_sb->prepathlen && tcon) { |
2823 | /* build_path_to_root works only when we have a valid tcon */ | 2799 | /* build_path_to_root works only when we have a valid tcon */ |
2824 | full_path = cifs_build_path_to_root(cifs_sb); | 2800 | full_path = cifs_build_path_to_root(cifs_sb, tcon); |
2825 | if (full_path == NULL) { | 2801 | if (full_path == NULL) { |
2826 | rc = -ENOMEM; | 2802 | rc = -ENOMEM; |
2827 | goto mount_fail_check; | 2803 | goto mount_fail_check; |
2828 | } | 2804 | } |
2829 | rc = is_path_accessible(xid, tcon, cifs_sb, full_path); | 2805 | rc = is_path_accessible(xid, tcon, cifs_sb, full_path); |
2830 | if (rc != -EREMOTE) { | 2806 | if (rc != 0 && rc != -EREMOTE) { |
2831 | kfree(full_path); | 2807 | kfree(full_path); |
2832 | goto mount_fail_check; | 2808 | goto mount_fail_check; |
2833 | } | 2809 | } |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 3840eddbfb7a..2e773825835e 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -135,9 +135,9 @@ static void setup_cifs_dentry(struct cifsTconInfo *tcon, | |||
135 | struct inode *newinode) | 135 | struct inode *newinode) |
136 | { | 136 | { |
137 | if (tcon->nocase) | 137 | if (tcon->nocase) |
138 | direntry->d_op = &cifs_ci_dentry_ops; | 138 | d_set_d_op(direntry, &cifs_ci_dentry_ops); |
139 | else | 139 | else |
140 | direntry->d_op = &cifs_dentry_ops; | 140 | d_set_d_op(direntry, &cifs_dentry_ops); |
141 | d_instantiate(direntry, newinode); | 141 | d_instantiate(direntry, newinode); |
142 | } | 142 | } |
143 | 143 | ||
@@ -293,10 +293,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
293 | args.uid = NO_CHANGE_64; | 293 | args.uid = NO_CHANGE_64; |
294 | args.gid = NO_CHANGE_64; | 294 | args.gid = NO_CHANGE_64; |
295 | } | 295 | } |
296 | CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, | 296 | CIFSSMBUnixSetFileInfo(xid, tcon, &args, fileHandle, |
297 | cifs_sb->local_nls, | 297 | current->tgid); |
298 | cifs_sb->mnt_cifs_flags & | ||
299 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
300 | } else { | 298 | } else { |
301 | /* BB implement mode setting via Windows security | 299 | /* BB implement mode setting via Windows security |
302 | descriptors e.g. */ | 300 | descriptors e.g. */ |
@@ -421,9 +419,9 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, | |||
421 | rc = cifs_get_inode_info_unix(&newinode, full_path, | 419 | rc = cifs_get_inode_info_unix(&newinode, full_path, |
422 | inode->i_sb, xid); | 420 | inode->i_sb, xid); |
423 | if (pTcon->nocase) | 421 | if (pTcon->nocase) |
424 | direntry->d_op = &cifs_ci_dentry_ops; | 422 | d_set_d_op(direntry, &cifs_ci_dentry_ops); |
425 | else | 423 | else |
426 | direntry->d_op = &cifs_dentry_ops; | 424 | d_set_d_op(direntry, &cifs_dentry_ops); |
427 | 425 | ||
428 | if (rc == 0) | 426 | if (rc == 0) |
429 | d_instantiate(direntry, newinode); | 427 | d_instantiate(direntry, newinode); |
@@ -604,9 +602,9 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
604 | 602 | ||
605 | if ((rc == 0) && (newInode != NULL)) { | 603 | if ((rc == 0) && (newInode != NULL)) { |
606 | if (pTcon->nocase) | 604 | if (pTcon->nocase) |
607 | direntry->d_op = &cifs_ci_dentry_ops; | 605 | d_set_d_op(direntry, &cifs_ci_dentry_ops); |
608 | else | 606 | else |
609 | direntry->d_op = &cifs_dentry_ops; | 607 | d_set_d_op(direntry, &cifs_dentry_ops); |
610 | d_add(direntry, newInode); | 608 | d_add(direntry, newInode); |
611 | if (posix_open) { | 609 | if (posix_open) { |
612 | filp = lookup_instantiate_filp(nd, direntry, | 610 | filp = lookup_instantiate_filp(nd, direntry, |
@@ -634,9 +632,9 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
634 | rc = 0; | 632 | rc = 0; |
635 | direntry->d_time = jiffies; | 633 | direntry->d_time = jiffies; |
636 | if (pTcon->nocase) | 634 | if (pTcon->nocase) |
637 | direntry->d_op = &cifs_ci_dentry_ops; | 635 | d_set_d_op(direntry, &cifs_ci_dentry_ops); |
638 | else | 636 | else |
639 | direntry->d_op = &cifs_dentry_ops; | 637 | d_set_d_op(direntry, &cifs_dentry_ops); |
640 | d_add(direntry, NULL); | 638 | d_add(direntry, NULL); |
641 | /* if it was once a directory (but how can we tell?) we could do | 639 | /* if it was once a directory (but how can we tell?) we could do |
642 | shrink_dcache_parent(direntry); */ | 640 | shrink_dcache_parent(direntry); */ |
@@ -656,22 +654,37 @@ lookup_out: | |||
656 | static int | 654 | static int |
657 | cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) | 655 | cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) |
658 | { | 656 | { |
659 | int isValid = 1; | 657 | if (nd->flags & LOOKUP_RCU) |
658 | return -ECHILD; | ||
660 | 659 | ||
661 | if (direntry->d_inode) { | 660 | if (direntry->d_inode) { |
662 | if (cifs_revalidate_dentry(direntry)) | 661 | if (cifs_revalidate_dentry(direntry)) |
663 | return 0; | 662 | return 0; |
664 | } else { | 663 | else |
665 | cFYI(1, "neg dentry 0x%p name = %s", | 664 | return 1; |
666 | direntry, direntry->d_name.name); | 665 | } |
667 | if (time_after(jiffies, direntry->d_time + HZ) || | 666 | |
668 | !lookupCacheEnabled) { | 667 | /* |
669 | d_drop(direntry); | 668 | * This may be nfsd (or something), anyway, we can't see the |
670 | isValid = 0; | 669 | * intent of this. So, since this can be for creation, drop it. |
671 | } | 670 | */ |
671 | if (!nd) | ||
672 | return 0; | ||
673 | |||
674 | /* | ||
675 | * Drop the negative dentry, in order to make sure to use the | ||
676 | * case sensitive name which is specified by user if this is | ||
677 | * for creation. | ||
678 | */ | ||
679 | if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) { | ||
680 | if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) | ||
681 | return 0; | ||
672 | } | 682 | } |
673 | 683 | ||
674 | return isValid; | 684 | if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled) |
685 | return 0; | ||
686 | |||
687 | return 1; | ||
675 | } | 688 | } |
676 | 689 | ||
677 | /* static int cifs_d_delete(struct dentry *direntry) | 690 | /* static int cifs_d_delete(struct dentry *direntry) |
@@ -688,9 +701,10 @@ const struct dentry_operations cifs_dentry_ops = { | |||
688 | /* d_delete: cifs_d_delete, */ /* not needed except for debugging */ | 701 | /* d_delete: cifs_d_delete, */ /* not needed except for debugging */ |
689 | }; | 702 | }; |
690 | 703 | ||
691 | static int cifs_ci_hash(struct dentry *dentry, struct qstr *q) | 704 | static int cifs_ci_hash(const struct dentry *dentry, const struct inode *inode, |
705 | struct qstr *q) | ||
692 | { | 706 | { |
693 | struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls; | 707 | struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls; |
694 | unsigned long hash; | 708 | unsigned long hash; |
695 | int i; | 709 | int i; |
696 | 710 | ||
@@ -703,21 +717,16 @@ static int cifs_ci_hash(struct dentry *dentry, struct qstr *q) | |||
703 | return 0; | 717 | return 0; |
704 | } | 718 | } |
705 | 719 | ||
706 | static int cifs_ci_compare(struct dentry *dentry, struct qstr *a, | 720 | static int cifs_ci_compare(const struct dentry *parent, |
707 | struct qstr *b) | 721 | const struct inode *pinode, |
722 | const struct dentry *dentry, const struct inode *inode, | ||
723 | unsigned int len, const char *str, const struct qstr *name) | ||
708 | { | 724 | { |
709 | struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls; | 725 | struct nls_table *codepage = CIFS_SB(pinode->i_sb)->local_nls; |
710 | 726 | ||
711 | if ((a->len == b->len) && | 727 | if ((name->len == len) && |
712 | (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) { | 728 | (nls_strnicmp(codepage, name->name, str, len) == 0)) |
713 | /* | ||
714 | * To preserve case, don't let an existing negative dentry's | ||
715 | * case take precedence. If a is not a negative dentry, this | ||
716 | * should have no side effects | ||
717 | */ | ||
718 | memcpy((void *)a->name, b->name, a->len); | ||
719 | return 0; | 729 | return 0; |
720 | } | ||
721 | return 1; | 730 | return 1; |
722 | } | 731 | } |
723 | 732 | ||
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index b857ce5db775..d843631c028d 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -104,53 +104,6 @@ static inline int cifs_get_disposition(unsigned int flags) | |||
104 | return FILE_OPEN; | 104 | return FILE_OPEN; |
105 | } | 105 | } |
106 | 106 | ||
107 | static inline int cifs_open_inode_helper(struct inode *inode, | ||
108 | struct cifsTconInfo *pTcon, __u32 oplock, FILE_ALL_INFO *buf, | ||
109 | char *full_path, int xid) | ||
110 | { | ||
111 | struct cifsInodeInfo *pCifsInode = CIFS_I(inode); | ||
112 | struct timespec temp; | ||
113 | int rc; | ||
114 | |||
115 | if (pCifsInode->clientCanCacheRead) { | ||
116 | /* we have the inode open somewhere else | ||
117 | no need to discard cache data */ | ||
118 | goto client_can_cache; | ||
119 | } | ||
120 | |||
121 | /* BB need same check in cifs_create too? */ | ||
122 | /* if not oplocked, invalidate inode pages if mtime or file | ||
123 | size changed */ | ||
124 | temp = cifs_NTtimeToUnix(buf->LastWriteTime); | ||
125 | if (timespec_equal(&inode->i_mtime, &temp) && | ||
126 | (inode->i_size == | ||
127 | (loff_t)le64_to_cpu(buf->EndOfFile))) { | ||
128 | cFYI(1, "inode unchanged on server"); | ||
129 | } else { | ||
130 | if (inode->i_mapping) { | ||
131 | /* BB no need to lock inode until after invalidate | ||
132 | since namei code should already have it locked? */ | ||
133 | rc = filemap_write_and_wait(inode->i_mapping); | ||
134 | mapping_set_error(inode->i_mapping, rc); | ||
135 | } | ||
136 | cFYI(1, "invalidating remote inode since open detected it " | ||
137 | "changed"); | ||
138 | invalidate_remote_inode(inode); | ||
139 | } | ||
140 | |||
141 | client_can_cache: | ||
142 | if (pTcon->unix_ext) | ||
143 | rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, | ||
144 | xid); | ||
145 | else | ||
146 | rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb, | ||
147 | xid, NULL); | ||
148 | |||
149 | cifs_set_oplock_level(pCifsInode, oplock); | ||
150 | |||
151 | return rc; | ||
152 | } | ||
153 | |||
154 | int cifs_posix_open(char *full_path, struct inode **pinode, | 107 | int cifs_posix_open(char *full_path, struct inode **pinode, |
155 | struct super_block *sb, int mode, unsigned int f_flags, | 108 | struct super_block *sb, int mode, unsigned int f_flags, |
156 | __u32 *poplock, __u16 *pnetfid, int xid) | 109 | __u32 *poplock, __u16 *pnetfid, int xid) |
@@ -213,6 +166,76 @@ posix_open_ret: | |||
213 | return rc; | 166 | return rc; |
214 | } | 167 | } |
215 | 168 | ||
169 | static int | ||
170 | cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, | ||
171 | struct cifsTconInfo *tcon, unsigned int f_flags, __u32 *poplock, | ||
172 | __u16 *pnetfid, int xid) | ||
173 | { | ||
174 | int rc; | ||
175 | int desiredAccess; | ||
176 | int disposition; | ||
177 | FILE_ALL_INFO *buf; | ||
178 | |||
179 | desiredAccess = cifs_convert_flags(f_flags); | ||
180 | |||
181 | /********************************************************************* | ||
182 | * open flag mapping table: | ||
183 | * | ||
184 | * POSIX Flag CIFS Disposition | ||
185 | * ---------- ---------------- | ||
186 | * O_CREAT FILE_OPEN_IF | ||
187 | * O_CREAT | O_EXCL FILE_CREATE | ||
188 | * O_CREAT | O_TRUNC FILE_OVERWRITE_IF | ||
189 | * O_TRUNC FILE_OVERWRITE | ||
190 | * none of the above FILE_OPEN | ||
191 | * | ||
192 | * Note that there is not a direct match between disposition | ||
193 | * FILE_SUPERSEDE (ie create whether or not file exists although | ||
194 | * O_CREAT | O_TRUNC is similar but truncates the existing | ||
195 | * file rather than creating a new file as FILE_SUPERSEDE does | ||
196 | * (which uses the attributes / metadata passed in on open call) | ||
197 | *? | ||
198 | *? O_SYNC is a reasonable match to CIFS writethrough flag | ||
199 | *? and the read write flags match reasonably. O_LARGEFILE | ||
200 | *? is irrelevant because largefile support is always used | ||
201 | *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY, | ||
202 | * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation | ||
203 | *********************************************************************/ | ||
204 | |||
205 | disposition = cifs_get_disposition(f_flags); | ||
206 | |||
207 | /* BB pass O_SYNC flag through on file attributes .. BB */ | ||
208 | |||
209 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | ||
210 | if (!buf) | ||
211 | return -ENOMEM; | ||
212 | |||
213 | if (tcon->ses->capabilities & CAP_NT_SMBS) | ||
214 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, | ||
215 | desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf, | ||
216 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | ||
217 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
218 | else | ||
219 | rc = SMBLegacyOpen(xid, tcon, full_path, disposition, | ||
220 | desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf, | ||
221 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | ||
222 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
223 | |||
224 | if (rc) | ||
225 | goto out; | ||
226 | |||
227 | if (tcon->unix_ext) | ||
228 | rc = cifs_get_inode_info_unix(&inode, full_path, inode->i_sb, | ||
229 | xid); | ||
230 | else | ||
231 | rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb, | ||
232 | xid, pnetfid); | ||
233 | |||
234 | out: | ||
235 | kfree(buf); | ||
236 | return rc; | ||
237 | } | ||
238 | |||
216 | struct cifsFileInfo * | 239 | struct cifsFileInfo * |
217 | cifs_new_fileinfo(__u16 fileHandle, struct file *file, | 240 | cifs_new_fileinfo(__u16 fileHandle, struct file *file, |
218 | struct tcon_link *tlink, __u32 oplock) | 241 | struct tcon_link *tlink, __u32 oplock) |
@@ -317,10 +340,8 @@ int cifs_open(struct inode *inode, struct file *file) | |||
317 | struct cifsFileInfo *pCifsFile = NULL; | 340 | struct cifsFileInfo *pCifsFile = NULL; |
318 | struct cifsInodeInfo *pCifsInode; | 341 | struct cifsInodeInfo *pCifsInode; |
319 | char *full_path = NULL; | 342 | char *full_path = NULL; |
320 | int desiredAccess; | 343 | bool posix_open_ok = false; |
321 | int disposition; | ||
322 | __u16 netfid; | 344 | __u16 netfid; |
323 | FILE_ALL_INFO *buf = NULL; | ||
324 | 345 | ||
325 | xid = GetXid(); | 346 | xid = GetXid(); |
326 | 347 | ||
@@ -358,17 +379,7 @@ int cifs_open(struct inode *inode, struct file *file) | |||
358 | file->f_flags, &oplock, &netfid, xid); | 379 | file->f_flags, &oplock, &netfid, xid); |
359 | if (rc == 0) { | 380 | if (rc == 0) { |
360 | cFYI(1, "posix open succeeded"); | 381 | cFYI(1, "posix open succeeded"); |
361 | 382 | posix_open_ok = true; | |
362 | pCifsFile = cifs_new_fileinfo(netfid, file, tlink, | ||
363 | oplock); | ||
364 | if (pCifsFile == NULL) { | ||
365 | CIFSSMBClose(xid, tcon, netfid); | ||
366 | rc = -ENOMEM; | ||
367 | } | ||
368 | |||
369 | cifs_fscache_set_inode_cookie(inode, file); | ||
370 | |||
371 | goto out; | ||
372 | } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { | 383 | } else if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { |
373 | if (tcon->ses->serverNOS) | 384 | if (tcon->ses->serverNOS) |
374 | cERROR(1, "server %s of type %s returned" | 385 | cERROR(1, "server %s of type %s returned" |
@@ -385,103 +396,39 @@ int cifs_open(struct inode *inode, struct file *file) | |||
385 | or DFS errors */ | 396 | or DFS errors */ |
386 | } | 397 | } |
387 | 398 | ||
388 | desiredAccess = cifs_convert_flags(file->f_flags); | 399 | if (!posix_open_ok) { |
389 | 400 | rc = cifs_nt_open(full_path, inode, cifs_sb, tcon, | |
390 | /********************************************************************* | 401 | file->f_flags, &oplock, &netfid, xid); |
391 | * open flag mapping table: | 402 | if (rc) |
392 | * | 403 | goto out; |
393 | * POSIX Flag CIFS Disposition | ||
394 | * ---------- ---------------- | ||
395 | * O_CREAT FILE_OPEN_IF | ||
396 | * O_CREAT | O_EXCL FILE_CREATE | ||
397 | * O_CREAT | O_TRUNC FILE_OVERWRITE_IF | ||
398 | * O_TRUNC FILE_OVERWRITE | ||
399 | * none of the above FILE_OPEN | ||
400 | * | ||
401 | * Note that there is not a direct match between disposition | ||
402 | * FILE_SUPERSEDE (ie create whether or not file exists although | ||
403 | * O_CREAT | O_TRUNC is similar but truncates the existing | ||
404 | * file rather than creating a new file as FILE_SUPERSEDE does | ||
405 | * (which uses the attributes / metadata passed in on open call) | ||
406 | *? | ||
407 | *? O_SYNC is a reasonable match to CIFS writethrough flag | ||
408 | *? and the read write flags match reasonably. O_LARGEFILE | ||
409 | *? is irrelevant because largefile support is always used | ||
410 | *? by this client. Flags O_APPEND, O_DIRECT, O_DIRECTORY, | ||
411 | * O_FASYNC, O_NOFOLLOW, O_NONBLOCK need further investigation | ||
412 | *********************************************************************/ | ||
413 | |||
414 | disposition = cifs_get_disposition(file->f_flags); | ||
415 | |||
416 | /* BB pass O_SYNC flag through on file attributes .. BB */ | ||
417 | |||
418 | /* Also refresh inode by passing in file_info buf returned by SMBOpen | ||
419 | and calling get_inode_info with returned buf (at least helps | ||
420 | non-Unix server case) */ | ||
421 | |||
422 | /* BB we can not do this if this is the second open of a file | ||
423 | and the first handle has writebehind data, we might be | ||
424 | able to simply do a filemap_fdatawrite/filemap_fdatawait first */ | ||
425 | buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL); | ||
426 | if (!buf) { | ||
427 | rc = -ENOMEM; | ||
428 | goto out; | ||
429 | } | ||
430 | |||
431 | if (tcon->ses->capabilities & CAP_NT_SMBS) | ||
432 | rc = CIFSSMBOpen(xid, tcon, full_path, disposition, | ||
433 | desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, | ||
434 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | ||
435 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
436 | else | ||
437 | rc = -EIO; /* no NT SMB support fall into legacy open below */ | ||
438 | |||
439 | if (rc == -EIO) { | ||
440 | /* Old server, try legacy style OpenX */ | ||
441 | rc = SMBLegacyOpen(xid, tcon, full_path, disposition, | ||
442 | desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, | ||
443 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | ||
444 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
445 | } | ||
446 | if (rc) { | ||
447 | cFYI(1, "cifs_open returned 0x%x", rc); | ||
448 | goto out; | ||
449 | } | 404 | } |
450 | 405 | ||
451 | rc = cifs_open_inode_helper(inode, tcon, oplock, buf, full_path, xid); | ||
452 | if (rc != 0) | ||
453 | goto out; | ||
454 | |||
455 | pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock); | 406 | pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock); |
456 | if (pCifsFile == NULL) { | 407 | if (pCifsFile == NULL) { |
408 | CIFSSMBClose(xid, tcon, netfid); | ||
457 | rc = -ENOMEM; | 409 | rc = -ENOMEM; |
458 | goto out; | 410 | goto out; |
459 | } | 411 | } |
460 | 412 | ||
461 | cifs_fscache_set_inode_cookie(inode, file); | 413 | cifs_fscache_set_inode_cookie(inode, file); |
462 | 414 | ||
463 | if (oplock & CIFS_CREATE_ACTION) { | 415 | if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) { |
464 | /* time to set mode which we can not set earlier due to | 416 | /* time to set mode which we can not set earlier due to |
465 | problems creating new read-only files */ | 417 | problems creating new read-only files */ |
466 | if (tcon->unix_ext) { | 418 | struct cifs_unix_set_info_args args = { |
467 | struct cifs_unix_set_info_args args = { | 419 | .mode = inode->i_mode, |
468 | .mode = inode->i_mode, | 420 | .uid = NO_CHANGE_64, |
469 | .uid = NO_CHANGE_64, | 421 | .gid = NO_CHANGE_64, |
470 | .gid = NO_CHANGE_64, | 422 | .ctime = NO_CHANGE_64, |
471 | .ctime = NO_CHANGE_64, | 423 | .atime = NO_CHANGE_64, |
472 | .atime = NO_CHANGE_64, | 424 | .mtime = NO_CHANGE_64, |
473 | .mtime = NO_CHANGE_64, | 425 | .device = 0, |
474 | .device = 0, | 426 | }; |
475 | }; | 427 | CIFSSMBUnixSetFileInfo(xid, tcon, &args, netfid, |
476 | CIFSSMBUnixSetPathInfo(xid, tcon, full_path, &args, | 428 | pCifsFile->pid); |
477 | cifs_sb->local_nls, | ||
478 | cifs_sb->mnt_cifs_flags & | ||
479 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
480 | } | ||
481 | } | 429 | } |
482 | 430 | ||
483 | out: | 431 | out: |
484 | kfree(buf); | ||
485 | kfree(full_path); | 432 | kfree(full_path); |
486 | FreeXid(xid); | 433 | FreeXid(xid); |
487 | cifs_put_tlink(tlink); | 434 | cifs_put_tlink(tlink); |
@@ -1108,7 +1055,6 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, | |||
1108 | return total_written; | 1055 | return total_written; |
1109 | } | 1056 | } |
1110 | 1057 | ||
1111 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
1112 | struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, | 1058 | struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, |
1113 | bool fsuid_only) | 1059 | bool fsuid_only) |
1114 | { | 1060 | { |
@@ -1142,7 +1088,6 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, | |||
1142 | spin_unlock(&cifs_file_list_lock); | 1088 | spin_unlock(&cifs_file_list_lock); |
1143 | return NULL; | 1089 | return NULL; |
1144 | } | 1090 | } |
1145 | #endif | ||
1146 | 1091 | ||
1147 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, | 1092 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, |
1148 | bool fsuid_only) | 1093 | bool fsuid_only) |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 28cb6e735943..0c7e36910e31 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -518,6 +518,7 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info, | |||
518 | 518 | ||
519 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); | 519 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); |
520 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); | 520 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); |
521 | fattr->cf_createtime = le64_to_cpu(info->CreationTime); | ||
521 | 522 | ||
522 | if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { | 523 | if (fattr->cf_cifsattrs & ATTR_DIRECTORY) { |
523 | fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; | 524 | fattr->cf_mode = S_IFDIR | cifs_sb->mnt_dir_mode; |
@@ -686,7 +687,7 @@ int cifs_get_inode_info(struct inode **pinode, | |||
686 | cFYI(1, "cifs_sfu_type failed: %d", tmprc); | 687 | cFYI(1, "cifs_sfu_type failed: %d", tmprc); |
687 | } | 688 | } |
688 | 689 | ||
689 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 690 | #ifdef CONFIG_CIFS_ACL |
690 | /* fill in 0777 bits from ACL */ | 691 | /* fill in 0777 bits from ACL */ |
691 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { | 692 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { |
692 | rc = cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, | 693 | rc = cifs_acl_to_fattr(cifs_sb, &fattr, *pinode, full_path, |
@@ -697,7 +698,7 @@ int cifs_get_inode_info(struct inode **pinode, | |||
697 | goto cgii_exit; | 698 | goto cgii_exit; |
698 | } | 699 | } |
699 | } | 700 | } |
700 | #endif | 701 | #endif /* CONFIG_CIFS_ACL */ |
701 | 702 | ||
702 | /* fill in remaining high mode bits e.g. SUID, VTX */ | 703 | /* fill in remaining high mode bits e.g. SUID, VTX */ |
703 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) | 704 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) |
@@ -728,12 +729,12 @@ static const struct inode_operations cifs_ipc_inode_ops = { | |||
728 | .lookup = cifs_lookup, | 729 | .lookup = cifs_lookup, |
729 | }; | 730 | }; |
730 | 731 | ||
731 | char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb) | 732 | char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb, |
733 | struct cifsTconInfo *tcon) | ||
732 | { | 734 | { |
733 | int pplen = cifs_sb->prepathlen; | 735 | int pplen = cifs_sb->prepathlen; |
734 | int dfsplen; | 736 | int dfsplen; |
735 | char *full_path = NULL; | 737 | char *full_path = NULL; |
736 | struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); | ||
737 | 738 | ||
738 | /* if no prefix path, simply set path to the root of share to "" */ | 739 | /* if no prefix path, simply set path to the root of share to "" */ |
739 | if (pplen == 0) { | 740 | if (pplen == 0) { |
@@ -779,6 +780,10 @@ cifs_find_inode(struct inode *inode, void *opaque) | |||
779 | if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) | 780 | if (CIFS_I(inode)->uniqueid != fattr->cf_uniqueid) |
780 | return 0; | 781 | return 0; |
781 | 782 | ||
783 | /* use createtime like an i_generation field */ | ||
784 | if (CIFS_I(inode)->createtime != fattr->cf_createtime) | ||
785 | return 0; | ||
786 | |||
782 | /* don't match inode of different type */ | 787 | /* don't match inode of different type */ |
783 | if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT)) | 788 | if ((inode->i_mode & S_IFMT) != (fattr->cf_mode & S_IFMT)) |
784 | return 0; | 789 | return 0; |
@@ -796,6 +801,7 @@ cifs_init_inode(struct inode *inode, void *opaque) | |||
796 | struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; | 801 | struct cifs_fattr *fattr = (struct cifs_fattr *) opaque; |
797 | 802 | ||
798 | CIFS_I(inode)->uniqueid = fattr->cf_uniqueid; | 803 | CIFS_I(inode)->uniqueid = fattr->cf_uniqueid; |
804 | CIFS_I(inode)->createtime = fattr->cf_createtime; | ||
799 | return 0; | 805 | return 0; |
800 | } | 806 | } |
801 | 807 | ||
@@ -809,14 +815,14 @@ inode_has_hashed_dentries(struct inode *inode) | |||
809 | { | 815 | { |
810 | struct dentry *dentry; | 816 | struct dentry *dentry; |
811 | 817 | ||
812 | spin_lock(&dcache_lock); | 818 | spin_lock(&inode->i_lock); |
813 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { | 819 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { |
814 | if (!d_unhashed(dentry) || IS_ROOT(dentry)) { | 820 | if (!d_unhashed(dentry) || IS_ROOT(dentry)) { |
815 | spin_unlock(&dcache_lock); | 821 | spin_unlock(&inode->i_lock); |
816 | return true; | 822 | return true; |
817 | } | 823 | } |
818 | } | 824 | } |
819 | spin_unlock(&dcache_lock); | 825 | spin_unlock(&inode->i_lock); |
820 | return false; | 826 | return false; |
821 | } | 827 | } |
822 | 828 | ||
@@ -875,7 +881,7 @@ struct inode *cifs_root_iget(struct super_block *sb, unsigned long ino) | |||
875 | char *full_path; | 881 | char *full_path; |
876 | struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); | 882 | struct cifsTconInfo *tcon = cifs_sb_master_tcon(cifs_sb); |
877 | 883 | ||
878 | full_path = cifs_build_path_to_root(cifs_sb); | 884 | full_path = cifs_build_path_to_root(cifs_sb, tcon); |
879 | if (full_path == NULL) | 885 | if (full_path == NULL) |
880 | return ERR_PTR(-ENOMEM); | 886 | return ERR_PTR(-ENOMEM); |
881 | 887 | ||
@@ -1319,9 +1325,9 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
1319 | to set uid/gid */ | 1325 | to set uid/gid */ |
1320 | inc_nlink(inode); | 1326 | inc_nlink(inode); |
1321 | if (pTcon->nocase) | 1327 | if (pTcon->nocase) |
1322 | direntry->d_op = &cifs_ci_dentry_ops; | 1328 | d_set_d_op(direntry, &cifs_ci_dentry_ops); |
1323 | else | 1329 | else |
1324 | direntry->d_op = &cifs_dentry_ops; | 1330 | d_set_d_op(direntry, &cifs_dentry_ops); |
1325 | 1331 | ||
1326 | cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb); | 1332 | cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb); |
1327 | cifs_fill_uniqueid(inode->i_sb, &fattr); | 1333 | cifs_fill_uniqueid(inode->i_sb, &fattr); |
@@ -1363,9 +1369,9 @@ mkdir_get_info: | |||
1363 | inode->i_sb, xid, NULL); | 1369 | inode->i_sb, xid, NULL); |
1364 | 1370 | ||
1365 | if (pTcon->nocase) | 1371 | if (pTcon->nocase) |
1366 | direntry->d_op = &cifs_ci_dentry_ops; | 1372 | d_set_d_op(direntry, &cifs_ci_dentry_ops); |
1367 | else | 1373 | else |
1368 | direntry->d_op = &cifs_dentry_ops; | 1374 | d_set_d_op(direntry, &cifs_dentry_ops); |
1369 | d_instantiate(direntry, newinode); | 1375 | d_instantiate(direntry, newinode); |
1370 | /* setting nlink not necessary except in cases where we | 1376 | /* setting nlink not necessary except in cases where we |
1371 | * failed to get it from the server or was set bogus */ | 1377 | * failed to get it from the server or was set bogus */ |
@@ -1653,6 +1659,7 @@ static bool | |||
1653 | cifs_inode_needs_reval(struct inode *inode) | 1659 | cifs_inode_needs_reval(struct inode *inode) |
1654 | { | 1660 | { |
1655 | struct cifsInodeInfo *cifs_i = CIFS_I(inode); | 1661 | struct cifsInodeInfo *cifs_i = CIFS_I(inode); |
1662 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
1656 | 1663 | ||
1657 | if (cifs_i->clientCanCacheRead) | 1664 | if (cifs_i->clientCanCacheRead) |
1658 | return false; | 1665 | return false; |
@@ -1663,12 +1670,12 @@ cifs_inode_needs_reval(struct inode *inode) | |||
1663 | if (cifs_i->time == 0) | 1670 | if (cifs_i->time == 0) |
1664 | return true; | 1671 | return true; |
1665 | 1672 | ||
1666 | /* FIXME: the actimeo should be tunable */ | 1673 | if (!time_in_range(jiffies, cifs_i->time, |
1667 | if (time_after_eq(jiffies, cifs_i->time + HZ)) | 1674 | cifs_i->time + cifs_sb->actimeo)) |
1668 | return true; | 1675 | return true; |
1669 | 1676 | ||
1670 | /* hardlinked files w/ noserverino get "special" treatment */ | 1677 | /* hardlinked files w/ noserverino get "special" treatment */ |
1671 | if (!(CIFS_SB(inode->i_sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && | 1678 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) && |
1672 | S_ISREG(inode->i_mode) && inode->i_nlink != 1) | 1679 | S_ISREG(inode->i_mode) && inode->i_nlink != 1) |
1673 | return true; | 1680 | return true; |
1674 | 1681 | ||
@@ -2121,7 +2128,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
2121 | 2128 | ||
2122 | if (attrs->ia_valid & ATTR_MODE) { | 2129 | if (attrs->ia_valid & ATTR_MODE) { |
2123 | rc = 0; | 2130 | rc = 0; |
2124 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 2131 | #ifdef CONFIG_CIFS_ACL |
2125 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { | 2132 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { |
2126 | rc = mode_to_cifs_acl(inode, full_path, mode); | 2133 | rc = mode_to_cifs_acl(inode, full_path, mode); |
2127 | if (rc) { | 2134 | if (rc) { |
@@ -2130,7 +2137,7 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
2130 | goto cifs_setattr_exit; | 2137 | goto cifs_setattr_exit; |
2131 | } | 2138 | } |
2132 | } else | 2139 | } else |
2133 | #endif | 2140 | #endif /* CONFIG_CIFS_ACL */ |
2134 | if (((mode & S_IWUGO) == 0) && | 2141 | if (((mode & S_IWUGO) == 0) && |
2135 | (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { | 2142 | (cifsInode->cifsAttrs & ATTR_READONLY) == 0) { |
2136 | 2143 | ||
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 85cdbf831e7b..fe2f6a93c49e 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
@@ -525,9 +525,9 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) | |||
525 | rc); | 525 | rc); |
526 | } else { | 526 | } else { |
527 | if (pTcon->nocase) | 527 | if (pTcon->nocase) |
528 | direntry->d_op = &cifs_ci_dentry_ops; | 528 | d_set_d_op(direntry, &cifs_ci_dentry_ops); |
529 | else | 529 | else |
530 | direntry->d_op = &cifs_dentry_ops; | 530 | d_set_d_op(direntry, &cifs_dentry_ops); |
531 | d_instantiate(direntry, newinode); | 531 | d_instantiate(direntry, newinode); |
532 | } | 532 | } |
533 | } | 533 | } |
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 32d300e8f20e..76b1b37c9e6b 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
@@ -79,7 +79,7 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name, | |||
79 | cFYI(1, "For %s", name->name); | 79 | cFYI(1, "For %s", name->name); |
80 | 80 | ||
81 | if (parent->d_op && parent->d_op->d_hash) | 81 | if (parent->d_op && parent->d_op->d_hash) |
82 | parent->d_op->d_hash(parent, name); | 82 | parent->d_op->d_hash(parent, parent->d_inode, name); |
83 | else | 83 | else |
84 | name->hash = full_name_hash(name->name, name->len); | 84 | name->hash = full_name_hash(name->name, name->len); |
85 | 85 | ||
@@ -103,9 +103,9 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name, | |||
103 | } | 103 | } |
104 | 104 | ||
105 | if (cifs_sb_master_tcon(CIFS_SB(sb))->nocase) | 105 | if (cifs_sb_master_tcon(CIFS_SB(sb))->nocase) |
106 | dentry->d_op = &cifs_ci_dentry_ops; | 106 | d_set_d_op(dentry, &cifs_ci_dentry_ops); |
107 | else | 107 | else |
108 | dentry->d_op = &cifs_dentry_ops; | 108 | d_set_d_op(dentry, &cifs_dentry_ops); |
109 | 109 | ||
110 | alias = d_materialise_unique(dentry, inode); | 110 | alias = d_materialise_unique(dentry, inode); |
111 | if (alias != NULL) { | 111 | if (alias != NULL) { |
@@ -160,6 +160,7 @@ cifs_dir_info_to_fattr(struct cifs_fattr *fattr, FILE_DIRECTORY_INFO *info, | |||
160 | fattr->cf_cifsattrs = le32_to_cpu(info->ExtFileAttributes); | 160 | fattr->cf_cifsattrs = le32_to_cpu(info->ExtFileAttributes); |
161 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); | 161 | fattr->cf_eof = le64_to_cpu(info->EndOfFile); |
162 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); | 162 | fattr->cf_bytes = le64_to_cpu(info->AllocationSize); |
163 | fattr->cf_createtime = le64_to_cpu(info->CreationTime); | ||
163 | fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); | 164 | fattr->cf_atime = cifs_NTtimeToUnix(info->LastAccessTime); |
164 | fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); | 165 | fattr->cf_ctime = cifs_NTtimeToUnix(info->ChangeTime); |
165 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); | 166 | fattr->cf_mtime = cifs_NTtimeToUnix(info->LastWriteTime); |
@@ -759,18 +760,6 @@ static int cifs_filldir(char *pfindEntry, struct file *file, filldir_t filldir, | |||
759 | rc = filldir(direntry, qstring.name, qstring.len, file->f_pos, | 760 | rc = filldir(direntry, qstring.name, qstring.len, file->f_pos, |
760 | ino, fattr.cf_dtype); | 761 | ino, fattr.cf_dtype); |
761 | 762 | ||
762 | /* | ||
763 | * we can not return filldir errors to the caller since they are | ||
764 | * "normal" when the stat blocksize is too small - we return remapped | ||
765 | * error instead | ||
766 | * | ||
767 | * FIXME: This looks bogus. filldir returns -EOVERFLOW in the above | ||
768 | * case already. Why should we be clobbering other errors from it? | ||
769 | */ | ||
770 | if (rc) { | ||
771 | cFYI(1, "filldir rc = %d", rc); | ||
772 | rc = -EOVERFLOW; | ||
773 | } | ||
774 | dput(tmp_dentry); | 763 | dput(tmp_dentry); |
775 | return rc; | 764 | return rc; |
776 | } | 765 | } |
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 7b01d3f6eed6..eb746486e49e 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c | |||
@@ -420,7 +420,6 @@ static int decode_ntlmssp_challenge(char *bcc_ptr, int blob_len, | |||
420 | return 0; | 420 | return 0; |
421 | } | 421 | } |
422 | 422 | ||
423 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
424 | /* BB Move to ntlmssp.c eventually */ | 423 | /* BB Move to ntlmssp.c eventually */ |
425 | 424 | ||
426 | /* We do not malloc the blob, it is passed in pbuffer, because | 425 | /* We do not malloc the blob, it is passed in pbuffer, because |
@@ -431,13 +430,14 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, | |||
431 | NEGOTIATE_MESSAGE *sec_blob = (NEGOTIATE_MESSAGE *)pbuffer; | 430 | NEGOTIATE_MESSAGE *sec_blob = (NEGOTIATE_MESSAGE *)pbuffer; |
432 | __u32 flags; | 431 | __u32 flags; |
433 | 432 | ||
433 | memset(pbuffer, 0, sizeof(NEGOTIATE_MESSAGE)); | ||
434 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); | 434 | memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); |
435 | sec_blob->MessageType = NtLmNegotiate; | 435 | sec_blob->MessageType = NtLmNegotiate; |
436 | 436 | ||
437 | /* BB is NTLMV2 session security format easier to use here? */ | 437 | /* BB is NTLMV2 session security format easier to use here? */ |
438 | flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | | 438 | flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | |
439 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | | 439 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | |
440 | NTLMSSP_NEGOTIATE_NTLM; | 440 | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC; |
441 | if (ses->server->secMode & | 441 | if (ses->server->secMode & |
442 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { | 442 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) { |
443 | flags |= NTLMSSP_NEGOTIATE_SIGN; | 443 | flags |= NTLMSSP_NEGOTIATE_SIGN; |
@@ -446,7 +446,7 @@ static void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, | |||
446 | NTLMSSP_NEGOTIATE_EXTENDED_SEC; | 446 | NTLMSSP_NEGOTIATE_EXTENDED_SEC; |
447 | } | 447 | } |
448 | 448 | ||
449 | sec_blob->NegotiateFlags |= cpu_to_le32(flags); | 449 | sec_blob->NegotiateFlags = cpu_to_le32(flags); |
450 | 450 | ||
451 | sec_blob->WorkstationName.BufferOffset = 0; | 451 | sec_blob->WorkstationName.BufferOffset = 0; |
452 | sec_blob->WorkstationName.Length = 0; | 452 | sec_blob->WorkstationName.Length = 0; |
@@ -477,7 +477,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
477 | flags = NTLMSSP_NEGOTIATE_56 | | 477 | flags = NTLMSSP_NEGOTIATE_56 | |
478 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO | | 478 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO | |
479 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | | 479 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | |
480 | NTLMSSP_NEGOTIATE_NTLM; | 480 | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC; |
481 | if (ses->server->secMode & | 481 | if (ses->server->secMode & |
482 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 482 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
483 | flags |= NTLMSSP_NEGOTIATE_SIGN; | 483 | flags |= NTLMSSP_NEGOTIATE_SIGN; |
@@ -485,7 +485,7 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
485 | flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; | 485 | flags |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN; |
486 | 486 | ||
487 | tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE); | 487 | tmp = pbuffer + sizeof(AUTHENTICATE_MESSAGE); |
488 | sec_blob->NegotiateFlags |= cpu_to_le32(flags); | 488 | sec_blob->NegotiateFlags = cpu_to_le32(flags); |
489 | 489 | ||
490 | sec_blob->LmChallengeResponse.BufferOffset = | 490 | sec_blob->LmChallengeResponse.BufferOffset = |
491 | cpu_to_le32(sizeof(AUTHENTICATE_MESSAGE)); | 491 | cpu_to_le32(sizeof(AUTHENTICATE_MESSAGE)); |
@@ -544,8 +544,9 @@ static int build_ntlmssp_auth_blob(unsigned char *pbuffer, | |||
544 | sec_blob->WorkstationName.MaximumLength = 0; | 544 | sec_blob->WorkstationName.MaximumLength = 0; |
545 | tmp += 2; | 545 | tmp += 2; |
546 | 546 | ||
547 | if ((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) && | 547 | if (((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) || |
548 | !calc_seckey(ses)) { | 548 | (ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_EXTENDED_SEC)) |
549 | && !calc_seckey(ses)) { | ||
549 | memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE); | 550 | memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE); |
550 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); | 551 | sec_blob->SessionKey.BufferOffset = cpu_to_le32(tmp - pbuffer); |
551 | sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE); | 552 | sec_blob->SessionKey.Length = cpu_to_le16(CIFS_CPHTXT_SIZE); |
@@ -563,17 +564,6 @@ setup_ntlmv2_ret: | |||
563 | return rc; | 564 | return rc; |
564 | } | 565 | } |
565 | 566 | ||
566 | |||
567 | static void setup_ntlmssp_neg_req(SESSION_SETUP_ANDX *pSMB, | ||
568 | struct cifsSesInfo *ses) | ||
569 | { | ||
570 | build_ntlmssp_negotiate_blob(&pSMB->req.SecurityBlob[0], ses); | ||
571 | pSMB->req.SecurityBlobLength = cpu_to_le16(sizeof(NEGOTIATE_MESSAGE)); | ||
572 | |||
573 | return; | ||
574 | } | ||
575 | #endif | ||
576 | |||
577 | int | 567 | int |
578 | CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, | 568 | CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, |
579 | const struct nls_table *nls_cp) | 569 | const struct nls_table *nls_cp) |
@@ -814,71 +804,70 @@ ssetup_ntlmssp_authenticate: | |||
814 | rc = -ENOSYS; | 804 | rc = -ENOSYS; |
815 | goto ssetup_exit; | 805 | goto ssetup_exit; |
816 | #endif /* CONFIG_CIFS_UPCALL */ | 806 | #endif /* CONFIG_CIFS_UPCALL */ |
817 | } else { | 807 | } else if (type == RawNTLMSSP) { |
818 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 808 | if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { |
819 | if (type == RawNTLMSSP) { | 809 | cERROR(1, "NTLMSSP requires Unicode support"); |
820 | if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) { | 810 | rc = -ENOSYS; |
821 | cERROR(1, "NTLMSSP requires Unicode support"); | 811 | goto ssetup_exit; |
822 | rc = -ENOSYS; | 812 | } |
813 | |||
814 | cFYI(1, "ntlmssp session setup phase %d", phase); | ||
815 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
816 | capabilities |= CAP_EXTENDED_SECURITY; | ||
817 | pSMB->req.Capabilities |= cpu_to_le32(capabilities); | ||
818 | switch(phase) { | ||
819 | case NtLmNegotiate: | ||
820 | build_ntlmssp_negotiate_blob( | ||
821 | pSMB->req.SecurityBlob, ses); | ||
822 | iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); | ||
823 | iov[1].iov_base = pSMB->req.SecurityBlob; | ||
824 | pSMB->req.SecurityBlobLength = | ||
825 | cpu_to_le16(sizeof(NEGOTIATE_MESSAGE)); | ||
826 | break; | ||
827 | case NtLmAuthenticate: | ||
828 | /* | ||
829 | * 5 is an empirical value, large enough to hold | ||
830 | * authenticate message plus max 10 of av paris, | ||
831 | * domain, user, workstation names, flags, etc. | ||
832 | */ | ||
833 | ntlmsspblob = kzalloc( | ||
834 | 5*sizeof(struct _AUTHENTICATE_MESSAGE), | ||
835 | GFP_KERNEL); | ||
836 | if (!ntlmsspblob) { | ||
837 | cERROR(1, "Can't allocate NTLMSSP blob"); | ||
838 | rc = -ENOMEM; | ||
823 | goto ssetup_exit; | 839 | goto ssetup_exit; |
824 | } | 840 | } |
825 | 841 | ||
826 | cFYI(1, "ntlmssp session setup phase %d", phase); | 842 | rc = build_ntlmssp_auth_blob(ntlmsspblob, |
827 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 843 | &blob_len, ses, nls_cp); |
828 | capabilities |= CAP_EXTENDED_SECURITY; | 844 | if (rc) |
829 | pSMB->req.Capabilities |= cpu_to_le32(capabilities); | ||
830 | if (phase == NtLmNegotiate) { | ||
831 | setup_ntlmssp_neg_req(pSMB, ses); | ||
832 | iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE); | ||
833 | iov[1].iov_base = &pSMB->req.SecurityBlob[0]; | ||
834 | } else if (phase == NtLmAuthenticate) { | ||
835 | /* 5 is an empirical value, large enought to | ||
836 | * hold authenticate message, max 10 of | ||
837 | * av paris, doamin,user,workstation mames, | ||
838 | * flags etc.. | ||
839 | */ | ||
840 | ntlmsspblob = kmalloc( | ||
841 | 5*sizeof(struct _AUTHENTICATE_MESSAGE), | ||
842 | GFP_KERNEL); | ||
843 | if (!ntlmsspblob) { | ||
844 | cERROR(1, "Can't allocate NTLMSSP"); | ||
845 | rc = -ENOMEM; | ||
846 | goto ssetup_exit; | ||
847 | } | ||
848 | |||
849 | rc = build_ntlmssp_auth_blob(ntlmsspblob, | ||
850 | &blob_len, ses, nls_cp); | ||
851 | if (rc) | ||
852 | goto ssetup_exit; | ||
853 | iov[1].iov_len = blob_len; | ||
854 | iov[1].iov_base = ntlmsspblob; | ||
855 | pSMB->req.SecurityBlobLength = | ||
856 | cpu_to_le16(blob_len); | ||
857 | /* Make sure that we tell the server that we | ||
858 | are using the uid that it just gave us back | ||
859 | on the response (challenge) */ | ||
860 | smb_buf->Uid = ses->Suid; | ||
861 | } else { | ||
862 | cERROR(1, "invalid phase %d", phase); | ||
863 | rc = -ENOSYS; | ||
864 | goto ssetup_exit; | 845 | goto ssetup_exit; |
865 | } | 846 | iov[1].iov_len = blob_len; |
866 | /* unicode strings must be word aligned */ | 847 | iov[1].iov_base = ntlmsspblob; |
867 | if ((iov[0].iov_len + iov[1].iov_len) % 2) { | 848 | pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len); |
868 | *bcc_ptr = 0; | 849 | /* |
869 | bcc_ptr++; | 850 | * Make sure that we tell the server that we are using |
870 | } | 851 | * the uid that it just gave us back on the response |
871 | unicode_oslm_strings(&bcc_ptr, nls_cp); | 852 | * (challenge) |
872 | } else { | 853 | */ |
873 | cERROR(1, "secType %d not supported!", type); | 854 | smb_buf->Uid = ses->Suid; |
855 | break; | ||
856 | default: | ||
857 | cERROR(1, "invalid phase %d", phase); | ||
874 | rc = -ENOSYS; | 858 | rc = -ENOSYS; |
875 | goto ssetup_exit; | 859 | goto ssetup_exit; |
876 | } | 860 | } |
877 | #else | 861 | /* unicode strings must be word aligned */ |
862 | if ((iov[0].iov_len + iov[1].iov_len) % 2) { | ||
863 | *bcc_ptr = 0; | ||
864 | bcc_ptr++; | ||
865 | } | ||
866 | unicode_oslm_strings(&bcc_ptr, nls_cp); | ||
867 | } else { | ||
878 | cERROR(1, "secType %d not supported!", type); | 868 | cERROR(1, "secType %d not supported!", type); |
879 | rc = -ENOSYS; | 869 | rc = -ENOSYS; |
880 | goto ssetup_exit; | 870 | goto ssetup_exit; |
881 | #endif | ||
882 | } | 871 | } |
883 | 872 | ||
884 | iov[2].iov_base = str_area; | 873 | iov[2].iov_base = str_area; |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index e0588cdf4cc5..59ca81b16919 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -119,7 +119,7 @@ smb_sendv(struct TCP_Server_Info *server, struct kvec *iov, int n_vec) | |||
119 | if (ssocket == NULL) | 119 | if (ssocket == NULL) |
120 | return -ENOTSOCK; /* BB eventually add reconnect code here */ | 120 | return -ENOTSOCK; /* BB eventually add reconnect code here */ |
121 | 121 | ||
122 | smb_msg.msg_name = (struct sockaddr *) &server->addr.sockAddr; | 122 | smb_msg.msg_name = (struct sockaddr *) &server->dstaddr; |
123 | smb_msg.msg_namelen = sizeof(struct sockaddr); | 123 | smb_msg.msg_namelen = sizeof(struct sockaddr); |
124 | smb_msg.msg_control = NULL; | 124 | smb_msg.msg_control = NULL; |
125 | smb_msg.msg_controllen = 0; | 125 | smb_msg.msg_controllen = 0; |
diff --git a/fs/coda/cache.c b/fs/coda/cache.c index 9060f08e70cf..5525e1c660fd 100644 --- a/fs/coda/cache.c +++ b/fs/coda/cache.c | |||
@@ -93,7 +93,7 @@ static void coda_flag_children(struct dentry *parent, int flag) | |||
93 | struct list_head *child; | 93 | struct list_head *child; |
94 | struct dentry *de; | 94 | struct dentry *de; |
95 | 95 | ||
96 | spin_lock(&dcache_lock); | 96 | spin_lock(&parent->d_lock); |
97 | list_for_each(child, &parent->d_subdirs) | 97 | list_for_each(child, &parent->d_subdirs) |
98 | { | 98 | { |
99 | de = list_entry(child, struct dentry, d_u.d_child); | 99 | de = list_entry(child, struct dentry, d_u.d_child); |
@@ -102,7 +102,7 @@ static void coda_flag_children(struct dentry *parent, int flag) | |||
102 | continue; | 102 | continue; |
103 | coda_flag_inode(de->d_inode, flag); | 103 | coda_flag_inode(de->d_inode, flag); |
104 | } | 104 | } |
105 | spin_unlock(&dcache_lock); | 105 | spin_unlock(&parent->d_lock); |
106 | return; | 106 | return; |
107 | } | 107 | } |
108 | 108 | ||
diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 5d8b35539601..29badd91360f 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/errno.h> | 18 | #include <linux/errno.h> |
19 | #include <linux/string.h> | 19 | #include <linux/string.h> |
20 | #include <linux/spinlock.h> | 20 | #include <linux/spinlock.h> |
21 | #include <linux/namei.h> | ||
21 | 22 | ||
22 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
23 | 24 | ||
@@ -47,7 +48,7 @@ static int coda_readdir(struct file *file, void *buf, filldir_t filldir); | |||
47 | 48 | ||
48 | /* dentry ops */ | 49 | /* dentry ops */ |
49 | static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd); | 50 | static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd); |
50 | static int coda_dentry_delete(struct dentry *); | 51 | static int coda_dentry_delete(const struct dentry *); |
51 | 52 | ||
52 | /* support routines */ | 53 | /* support routines */ |
53 | static int coda_venus_readdir(struct file *coda_file, void *buf, | 54 | static int coda_venus_readdir(struct file *coda_file, void *buf, |
@@ -125,7 +126,7 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struc | |||
125 | return ERR_PTR(error); | 126 | return ERR_PTR(error); |
126 | 127 | ||
127 | exit: | 128 | exit: |
128 | entry->d_op = &coda_dentry_operations; | 129 | d_set_d_op(entry, &coda_dentry_operations); |
129 | 130 | ||
130 | if (inode && (type & CODA_NOCACHE)) | 131 | if (inode && (type & CODA_NOCACHE)) |
131 | coda_flag_inode(inode, C_VATTR | C_PURGE); | 132 | coda_flag_inode(inode, C_VATTR | C_PURGE); |
@@ -134,10 +135,13 @@ exit: | |||
134 | } | 135 | } |
135 | 136 | ||
136 | 137 | ||
137 | int coda_permission(struct inode *inode, int mask) | 138 | int coda_permission(struct inode *inode, int mask, unsigned int flags) |
138 | { | 139 | { |
139 | int error; | 140 | int error; |
140 | 141 | ||
142 | if (flags & IPERM_FLAG_RCU) | ||
143 | return -ECHILD; | ||
144 | |||
141 | mask &= MAY_READ | MAY_WRITE | MAY_EXEC; | 145 | mask &= MAY_READ | MAY_WRITE | MAY_EXEC; |
142 | 146 | ||
143 | if (!mask) | 147 | if (!mask) |
@@ -541,9 +545,13 @@ out: | |||
541 | /* called when a cache lookup succeeds */ | 545 | /* called when a cache lookup succeeds */ |
542 | static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd) | 546 | static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd) |
543 | { | 547 | { |
544 | struct inode *inode = de->d_inode; | 548 | struct inode *inode; |
545 | struct coda_inode_info *cii; | 549 | struct coda_inode_info *cii; |
546 | 550 | ||
551 | if (nd->flags & LOOKUP_RCU) | ||
552 | return -ECHILD; | ||
553 | |||
554 | inode = de->d_inode; | ||
547 | if (!inode || coda_isroot(inode)) | 555 | if (!inode || coda_isroot(inode)) |
548 | goto out; | 556 | goto out; |
549 | if (is_bad_inode(inode)) | 557 | if (is_bad_inode(inode)) |
@@ -559,7 +567,7 @@ static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd) | |||
559 | if (cii->c_flags & C_FLUSH) | 567 | if (cii->c_flags & C_FLUSH) |
560 | coda_flag_inode_children(inode, C_FLUSH); | 568 | coda_flag_inode_children(inode, C_FLUSH); |
561 | 569 | ||
562 | if (atomic_read(&de->d_count) > 1) | 570 | if (de->d_count > 1) |
563 | /* pretend it's valid, but don't change the flags */ | 571 | /* pretend it's valid, but don't change the flags */ |
564 | goto out; | 572 | goto out; |
565 | 573 | ||
@@ -577,7 +585,7 @@ out: | |||
577 | * This is the callback from dput() when d_count is going to 0. | 585 | * This is the callback from dput() when d_count is going to 0. |
578 | * We use this to unhash dentries with bad inodes. | 586 | * We use this to unhash dentries with bad inodes. |
579 | */ | 587 | */ |
580 | static int coda_dentry_delete(struct dentry * dentry) | 588 | static int coda_dentry_delete(const struct dentry * dentry) |
581 | { | 589 | { |
582 | int flags; | 590 | int flags; |
583 | 591 | ||
diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 5ea57c8c7f97..50dc7d189f56 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c | |||
@@ -56,11 +56,18 @@ static struct inode *coda_alloc_inode(struct super_block *sb) | |||
56 | return &ei->vfs_inode; | 56 | return &ei->vfs_inode; |
57 | } | 57 | } |
58 | 58 | ||
59 | static void coda_destroy_inode(struct inode *inode) | 59 | static void coda_i_callback(struct rcu_head *head) |
60 | { | 60 | { |
61 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
62 | INIT_LIST_HEAD(&inode->i_dentry); | ||
61 | kmem_cache_free(coda_inode_cachep, ITOC(inode)); | 63 | kmem_cache_free(coda_inode_cachep, ITOC(inode)); |
62 | } | 64 | } |
63 | 65 | ||
66 | static void coda_destroy_inode(struct inode *inode) | ||
67 | { | ||
68 | call_rcu(&inode->i_rcu, coda_i_callback); | ||
69 | } | ||
70 | |||
64 | static void init_once(void *foo) | 71 | static void init_once(void *foo) |
65 | { | 72 | { |
66 | struct coda_inode_info *ei = (struct coda_inode_info *) foo; | 73 | struct coda_inode_info *ei = (struct coda_inode_info *) foo; |
diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c index 2fd89b5c5c7b..741f0bd03918 100644 --- a/fs/coda/pioctl.c +++ b/fs/coda/pioctl.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include <linux/coda_psdev.h> | 24 | #include <linux/coda_psdev.h> |
25 | 25 | ||
26 | /* pioctl ops */ | 26 | /* pioctl ops */ |
27 | static int coda_ioctl_permission(struct inode *inode, int mask); | 27 | static int coda_ioctl_permission(struct inode *inode, int mask, unsigned int flags); |
28 | static long coda_pioctl(struct file *filp, unsigned int cmd, | 28 | static long coda_pioctl(struct file *filp, unsigned int cmd, |
29 | unsigned long user_data); | 29 | unsigned long user_data); |
30 | 30 | ||
@@ -41,8 +41,10 @@ const struct file_operations coda_ioctl_operations = { | |||
41 | }; | 41 | }; |
42 | 42 | ||
43 | /* the coda pioctl inode ops */ | 43 | /* the coda pioctl inode ops */ |
44 | static int coda_ioctl_permission(struct inode *inode, int mask) | 44 | static int coda_ioctl_permission(struct inode *inode, int mask, unsigned int flags) |
45 | { | 45 | { |
46 | if (flags & IPERM_FLAG_RCU) | ||
47 | return -ECHILD; | ||
46 | return (mask & MAY_EXEC) ? -EACCES : 0; | 48 | return (mask & MAY_EXEC) ? -EACCES : 0; |
47 | } | 49 | } |
48 | 50 | ||
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index a60579b007b0..61abb638b4bf 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c | |||
@@ -42,7 +42,7 @@ | |||
42 | #include <linux/tty.h> | 42 | #include <linux/tty.h> |
43 | #include <linux/vt_kern.h> | 43 | #include <linux/vt_kern.h> |
44 | #include <linux/fb.h> | 44 | #include <linux/fb.h> |
45 | #include <linux/videodev.h> | 45 | #include <linux/videodev2.h> |
46 | #include <linux/netdevice.h> | 46 | #include <linux/netdevice.h> |
47 | #include <linux/raw.h> | 47 | #include <linux/raw.h> |
48 | #include <linux/blkdev.h> | 48 | #include <linux/blkdev.h> |
@@ -836,6 +836,7 @@ COMPATIBLE_IOCTL(TCSETSW) | |||
836 | COMPATIBLE_IOCTL(TCSETSF) | 836 | COMPATIBLE_IOCTL(TCSETSF) |
837 | COMPATIBLE_IOCTL(TIOCLINUX) | 837 | COMPATIBLE_IOCTL(TIOCLINUX) |
838 | COMPATIBLE_IOCTL(TIOCSBRK) | 838 | COMPATIBLE_IOCTL(TIOCSBRK) |
839 | COMPATIBLE_IOCTL(TIOCGDEV) | ||
839 | COMPATIBLE_IOCTL(TIOCCBRK) | 840 | COMPATIBLE_IOCTL(TIOCCBRK) |
840 | COMPATIBLE_IOCTL(TIOCGSID) | 841 | COMPATIBLE_IOCTL(TIOCGSID) |
841 | COMPATIBLE_IOCTL(TIOCGICOUNT) | 842 | COMPATIBLE_IOCTL(TIOCGICOUNT) |
diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h index da6061a6df40..026cf68553a4 100644 --- a/fs/configfs/configfs_internal.h +++ b/fs/configfs/configfs_internal.h | |||
@@ -120,7 +120,7 @@ static inline struct config_item *configfs_get_config_item(struct dentry *dentry | |||
120 | { | 120 | { |
121 | struct config_item * item = NULL; | 121 | struct config_item * item = NULL; |
122 | 122 | ||
123 | spin_lock(&dcache_lock); | 123 | spin_lock(&dentry->d_lock); |
124 | if (!d_unhashed(dentry)) { | 124 | if (!d_unhashed(dentry)) { |
125 | struct configfs_dirent * sd = dentry->d_fsdata; | 125 | struct configfs_dirent * sd = dentry->d_fsdata; |
126 | if (sd->s_type & CONFIGFS_ITEM_LINK) { | 126 | if (sd->s_type & CONFIGFS_ITEM_LINK) { |
@@ -129,7 +129,7 @@ static inline struct config_item *configfs_get_config_item(struct dentry *dentry | |||
129 | } else | 129 | } else |
130 | item = config_item_get(sd->s_element); | 130 | item = config_item_get(sd->s_element); |
131 | } | 131 | } |
132 | spin_unlock(&dcache_lock); | 132 | spin_unlock(&dentry->d_lock); |
133 | 133 | ||
134 | return item; | 134 | return item; |
135 | } | 135 | } |
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 0b502f80c691..36637a8c1ed3 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c | |||
@@ -67,7 +67,7 @@ static void configfs_d_iput(struct dentry * dentry, | |||
67 | * We _must_ delete our dentries on last dput, as the chain-to-parent | 67 | * We _must_ delete our dentries on last dput, as the chain-to-parent |
68 | * behavior is required to clear the parents of default_groups. | 68 | * behavior is required to clear the parents of default_groups. |
69 | */ | 69 | */ |
70 | static int configfs_d_delete(struct dentry *dentry) | 70 | static int configfs_d_delete(const struct dentry *dentry) |
71 | { | 71 | { |
72 | return 1; | 72 | return 1; |
73 | } | 73 | } |
@@ -232,10 +232,8 @@ int configfs_make_dirent(struct configfs_dirent * parent_sd, | |||
232 | 232 | ||
233 | sd->s_mode = mode; | 233 | sd->s_mode = mode; |
234 | sd->s_dentry = dentry; | 234 | sd->s_dentry = dentry; |
235 | if (dentry) { | 235 | if (dentry) |
236 | dentry->d_fsdata = configfs_get(sd); | 236 | dentry->d_fsdata = configfs_get(sd); |
237 | dentry->d_op = &configfs_dentry_ops; | ||
238 | } | ||
239 | 237 | ||
240 | return 0; | 238 | return 0; |
241 | } | 239 | } |
@@ -278,7 +276,6 @@ static int create_dir(struct config_item * k, struct dentry * p, | |||
278 | error = configfs_create(d, mode, init_dir); | 276 | error = configfs_create(d, mode, init_dir); |
279 | if (!error) { | 277 | if (!error) { |
280 | inc_nlink(p->d_inode); | 278 | inc_nlink(p->d_inode); |
281 | (d)->d_op = &configfs_dentry_ops; | ||
282 | } else { | 279 | } else { |
283 | struct configfs_dirent *sd = d->d_fsdata; | 280 | struct configfs_dirent *sd = d->d_fsdata; |
284 | if (sd) { | 281 | if (sd) { |
@@ -371,9 +368,7 @@ int configfs_create_link(struct configfs_symlink *sl, | |||
371 | CONFIGFS_ITEM_LINK); | 368 | CONFIGFS_ITEM_LINK); |
372 | if (!err) { | 369 | if (!err) { |
373 | err = configfs_create(dentry, mode, init_symlink); | 370 | err = configfs_create(dentry, mode, init_symlink); |
374 | if (!err) | 371 | if (err) { |
375 | dentry->d_op = &configfs_dentry_ops; | ||
376 | else { | ||
377 | struct configfs_dirent *sd = dentry->d_fsdata; | 372 | struct configfs_dirent *sd = dentry->d_fsdata; |
378 | if (sd) { | 373 | if (sd) { |
379 | spin_lock(&configfs_dirent_lock); | 374 | spin_lock(&configfs_dirent_lock); |
@@ -399,8 +394,7 @@ static void remove_dir(struct dentry * d) | |||
399 | if (d->d_inode) | 394 | if (d->d_inode) |
400 | simple_rmdir(parent->d_inode,d); | 395 | simple_rmdir(parent->d_inode,d); |
401 | 396 | ||
402 | pr_debug(" o %s removing done (%d)\n",d->d_name.name, | 397 | pr_debug(" o %s removing done (%d)\n",d->d_name.name, d->d_count); |
403 | atomic_read(&d->d_count)); | ||
404 | 398 | ||
405 | dput(parent); | 399 | dput(parent); |
406 | } | 400 | } |
@@ -448,7 +442,7 @@ static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * den | |||
448 | return error; | 442 | return error; |
449 | } | 443 | } |
450 | 444 | ||
451 | dentry->d_op = &configfs_dentry_ops; | 445 | d_set_d_op(dentry, &configfs_dentry_ops); |
452 | d_rehash(dentry); | 446 | d_rehash(dentry); |
453 | 447 | ||
454 | return 0; | 448 | return 0; |
@@ -493,7 +487,11 @@ static struct dentry * configfs_lookup(struct inode *dir, | |||
493 | * If it doesn't exist and it isn't a NOT_PINNED item, | 487 | * If it doesn't exist and it isn't a NOT_PINNED item, |
494 | * it must be negative. | 488 | * it must be negative. |
495 | */ | 489 | */ |
496 | return simple_lookup(dir, dentry, nd); | 490 | if (dentry->d_name.len > NAME_MAX) |
491 | return ERR_PTR(-ENAMETOOLONG); | ||
492 | d_set_d_op(dentry, &configfs_dentry_ops); | ||
493 | d_add(dentry, NULL); | ||
494 | return NULL; | ||
497 | } | 495 | } |
498 | 496 | ||
499 | out: | 497 | out: |
@@ -685,6 +683,7 @@ static int create_default_group(struct config_group *parent_group, | |||
685 | ret = -ENOMEM; | 683 | ret = -ENOMEM; |
686 | child = d_alloc(parent, &name); | 684 | child = d_alloc(parent, &name); |
687 | if (child) { | 685 | if (child) { |
686 | d_set_d_op(child, &configfs_dentry_ops); | ||
688 | d_add(child, NULL); | 687 | d_add(child, NULL); |
689 | 688 | ||
690 | ret = configfs_attach_group(&parent_group->cg_item, | 689 | ret = configfs_attach_group(&parent_group->cg_item, |
@@ -1682,6 +1681,7 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys) | |||
1682 | err = -ENOMEM; | 1681 | err = -ENOMEM; |
1683 | dentry = d_alloc(configfs_sb->s_root, &name); | 1682 | dentry = d_alloc(configfs_sb->s_root, &name); |
1684 | if (dentry) { | 1683 | if (dentry) { |
1684 | d_set_d_op(dentry, &configfs_dentry_ops); | ||
1685 | d_add(dentry, NULL); | 1685 | d_add(dentry, NULL); |
1686 | 1686 | ||
1687 | err = configfs_attach_group(sd->s_element, &group->cg_item, | 1687 | err = configfs_attach_group(sd->s_element, &group->cg_item, |
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index 253476d78ed8..c83f4768eeaa 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c | |||
@@ -250,18 +250,14 @@ void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent) | |||
250 | struct dentry * dentry = sd->s_dentry; | 250 | struct dentry * dentry = sd->s_dentry; |
251 | 251 | ||
252 | if (dentry) { | 252 | if (dentry) { |
253 | spin_lock(&dcache_lock); | ||
254 | spin_lock(&dentry->d_lock); | 253 | spin_lock(&dentry->d_lock); |
255 | if (!(d_unhashed(dentry) && dentry->d_inode)) { | 254 | if (!(d_unhashed(dentry) && dentry->d_inode)) { |
256 | dget_locked(dentry); | 255 | dget_dlock(dentry); |
257 | __d_drop(dentry); | 256 | __d_drop(dentry); |
258 | spin_unlock(&dentry->d_lock); | 257 | spin_unlock(&dentry->d_lock); |
259 | spin_unlock(&dcache_lock); | ||
260 | simple_unlink(parent->d_inode, dentry); | 258 | simple_unlink(parent->d_inode, dentry); |
261 | } else { | 259 | } else |
262 | spin_unlock(&dentry->d_lock); | 260 | spin_unlock(&dentry->d_lock); |
263 | spin_unlock(&dcache_lock); | ||
264 | } | ||
265 | } | 261 | } |
266 | } | 262 | } |
267 | 263 | ||
diff --git a/fs/dcache.c b/fs/dcache.c index 23702a9d4e6d..5699d4c027cb 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -33,20 +33,58 @@ | |||
33 | #include <linux/bootmem.h> | 33 | #include <linux/bootmem.h> |
34 | #include <linux/fs_struct.h> | 34 | #include <linux/fs_struct.h> |
35 | #include <linux/hardirq.h> | 35 | #include <linux/hardirq.h> |
36 | #include <linux/bit_spinlock.h> | ||
37 | #include <linux/rculist_bl.h> | ||
36 | #include "internal.h" | 38 | #include "internal.h" |
37 | 39 | ||
40 | /* | ||
41 | * Usage: | ||
42 | * dcache->d_inode->i_lock protects: | ||
43 | * - i_dentry, d_alias, d_inode of aliases | ||
44 | * dcache_hash_bucket lock protects: | ||
45 | * - the dcache hash table | ||
46 | * s_anon bl list spinlock protects: | ||
47 | * - the s_anon list (see __d_drop) | ||
48 | * dcache_lru_lock protects: | ||
49 | * - the dcache lru lists and counters | ||
50 | * d_lock protects: | ||
51 | * - d_flags | ||
52 | * - d_name | ||
53 | * - d_lru | ||
54 | * - d_count | ||
55 | * - d_unhashed() | ||
56 | * - d_parent and d_subdirs | ||
57 | * - childrens' d_child and d_parent | ||
58 | * - d_alias, d_inode | ||
59 | * | ||
60 | * Ordering: | ||
61 | * dentry->d_inode->i_lock | ||
62 | * dentry->d_lock | ||
63 | * dcache_lru_lock | ||
64 | * dcache_hash_bucket lock | ||
65 | * s_anon lock | ||
66 | * | ||
67 | * If there is an ancestor relationship: | ||
68 | * dentry->d_parent->...->d_parent->d_lock | ||
69 | * ... | ||
70 | * dentry->d_parent->d_lock | ||
71 | * dentry->d_lock | ||
72 | * | ||
73 | * If no ancestor relationship: | ||
74 | * if (dentry1 < dentry2) | ||
75 | * dentry1->d_lock | ||
76 | * dentry2->d_lock | ||
77 | */ | ||
38 | int sysctl_vfs_cache_pressure __read_mostly = 100; | 78 | int sysctl_vfs_cache_pressure __read_mostly = 100; |
39 | EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure); | 79 | EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure); |
40 | 80 | ||
41 | __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lock); | 81 | static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lru_lock); |
42 | __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock); | 82 | __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock); |
43 | 83 | ||
44 | EXPORT_SYMBOL(dcache_lock); | 84 | EXPORT_SYMBOL(rename_lock); |
45 | 85 | ||
46 | static struct kmem_cache *dentry_cache __read_mostly; | 86 | static struct kmem_cache *dentry_cache __read_mostly; |
47 | 87 | ||
48 | #define DNAME_INLINE_LEN (sizeof(struct dentry)-offsetof(struct dentry,d_iname)) | ||
49 | |||
50 | /* | 88 | /* |
51 | * This is the single most critical data structure when it comes | 89 | * This is the single most critical data structure when it comes |
52 | * to the dcache: the hashtable for lookups. Somebody should try | 90 | * to the dcache: the hashtable for lookups. Somebody should try |
@@ -60,22 +98,51 @@ static struct kmem_cache *dentry_cache __read_mostly; | |||
60 | 98 | ||
61 | static unsigned int d_hash_mask __read_mostly; | 99 | static unsigned int d_hash_mask __read_mostly; |
62 | static unsigned int d_hash_shift __read_mostly; | 100 | static unsigned int d_hash_shift __read_mostly; |
63 | static struct hlist_head *dentry_hashtable __read_mostly; | 101 | |
102 | struct dcache_hash_bucket { | ||
103 | struct hlist_bl_head head; | ||
104 | }; | ||
105 | static struct dcache_hash_bucket *dentry_hashtable __read_mostly; | ||
106 | |||
107 | static inline struct dcache_hash_bucket *d_hash(struct dentry *parent, | ||
108 | unsigned long hash) | ||
109 | { | ||
110 | hash += ((unsigned long) parent ^ GOLDEN_RATIO_PRIME) / L1_CACHE_BYTES; | ||
111 | hash = hash ^ ((hash ^ GOLDEN_RATIO_PRIME) >> D_HASHBITS); | ||
112 | return dentry_hashtable + (hash & D_HASHMASK); | ||
113 | } | ||
114 | |||
115 | static inline void spin_lock_bucket(struct dcache_hash_bucket *b) | ||
116 | { | ||
117 | bit_spin_lock(0, (unsigned long *)&b->head.first); | ||
118 | } | ||
119 | |||
120 | static inline void spin_unlock_bucket(struct dcache_hash_bucket *b) | ||
121 | { | ||
122 | __bit_spin_unlock(0, (unsigned long *)&b->head.first); | ||
123 | } | ||
64 | 124 | ||
65 | /* Statistics gathering. */ | 125 | /* Statistics gathering. */ |
66 | struct dentry_stat_t dentry_stat = { | 126 | struct dentry_stat_t dentry_stat = { |
67 | .age_limit = 45, | 127 | .age_limit = 45, |
68 | }; | 128 | }; |
69 | 129 | ||
70 | static struct percpu_counter nr_dentry __cacheline_aligned_in_smp; | 130 | static DEFINE_PER_CPU(unsigned int, nr_dentry); |
71 | static struct percpu_counter nr_dentry_unused __cacheline_aligned_in_smp; | ||
72 | 131 | ||
73 | #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS) | 132 | #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS) |
133 | static int get_nr_dentry(void) | ||
134 | { | ||
135 | int i; | ||
136 | int sum = 0; | ||
137 | for_each_possible_cpu(i) | ||
138 | sum += per_cpu(nr_dentry, i); | ||
139 | return sum < 0 ? 0 : sum; | ||
140 | } | ||
141 | |||
74 | int proc_nr_dentry(ctl_table *table, int write, void __user *buffer, | 142 | int proc_nr_dentry(ctl_table *table, int write, void __user *buffer, |
75 | size_t *lenp, loff_t *ppos) | 143 | size_t *lenp, loff_t *ppos) |
76 | { | 144 | { |
77 | dentry_stat.nr_dentry = percpu_counter_sum_positive(&nr_dentry); | 145 | dentry_stat.nr_dentry = get_nr_dentry(); |
78 | dentry_stat.nr_unused = percpu_counter_sum_positive(&nr_dentry_unused); | ||
79 | return proc_dointvec(table, write, buffer, lenp, ppos); | 146 | return proc_dointvec(table, write, buffer, lenp, ppos); |
80 | } | 147 | } |
81 | #endif | 148 | #endif |
@@ -91,35 +158,50 @@ static void __d_free(struct rcu_head *head) | |||
91 | } | 158 | } |
92 | 159 | ||
93 | /* | 160 | /* |
94 | * no dcache_lock, please. | 161 | * no locks, please. |
95 | */ | 162 | */ |
96 | static void d_free(struct dentry *dentry) | 163 | static void d_free(struct dentry *dentry) |
97 | { | 164 | { |
98 | percpu_counter_dec(&nr_dentry); | 165 | BUG_ON(dentry->d_count); |
166 | this_cpu_dec(nr_dentry); | ||
99 | if (dentry->d_op && dentry->d_op->d_release) | 167 | if (dentry->d_op && dentry->d_op->d_release) |
100 | dentry->d_op->d_release(dentry); | 168 | dentry->d_op->d_release(dentry); |
101 | 169 | ||
102 | /* if dentry was never inserted into hash, immediate free is OK */ | 170 | /* if dentry was never inserted into hash, immediate free is OK */ |
103 | if (hlist_unhashed(&dentry->d_hash)) | 171 | if (hlist_bl_unhashed(&dentry->d_hash)) |
104 | __d_free(&dentry->d_u.d_rcu); | 172 | __d_free(&dentry->d_u.d_rcu); |
105 | else | 173 | else |
106 | call_rcu(&dentry->d_u.d_rcu, __d_free); | 174 | call_rcu(&dentry->d_u.d_rcu, __d_free); |
107 | } | 175 | } |
108 | 176 | ||
177 | /** | ||
178 | * dentry_rcuwalk_barrier - invalidate in-progress rcu-walk lookups | ||
179 | * After this call, in-progress rcu-walk path lookup will fail. This | ||
180 | * should be called after unhashing, and after changing d_inode (if | ||
181 | * the dentry has not already been unhashed). | ||
182 | */ | ||
183 | static inline void dentry_rcuwalk_barrier(struct dentry *dentry) | ||
184 | { | ||
185 | assert_spin_locked(&dentry->d_lock); | ||
186 | /* Go through a barrier */ | ||
187 | write_seqcount_barrier(&dentry->d_seq); | ||
188 | } | ||
189 | |||
109 | /* | 190 | /* |
110 | * Release the dentry's inode, using the filesystem | 191 | * Release the dentry's inode, using the filesystem |
111 | * d_iput() operation if defined. | 192 | * d_iput() operation if defined. Dentry has no refcount |
193 | * and is unhashed. | ||
112 | */ | 194 | */ |
113 | static void dentry_iput(struct dentry * dentry) | 195 | static void dentry_iput(struct dentry * dentry) |
114 | __releases(dentry->d_lock) | 196 | __releases(dentry->d_lock) |
115 | __releases(dcache_lock) | 197 | __releases(dentry->d_inode->i_lock) |
116 | { | 198 | { |
117 | struct inode *inode = dentry->d_inode; | 199 | struct inode *inode = dentry->d_inode; |
118 | if (inode) { | 200 | if (inode) { |
119 | dentry->d_inode = NULL; | 201 | dentry->d_inode = NULL; |
120 | list_del_init(&dentry->d_alias); | 202 | list_del_init(&dentry->d_alias); |
121 | spin_unlock(&dentry->d_lock); | 203 | spin_unlock(&dentry->d_lock); |
122 | spin_unlock(&dcache_lock); | 204 | spin_unlock(&inode->i_lock); |
123 | if (!inode->i_nlink) | 205 | if (!inode->i_nlink) |
124 | fsnotify_inoderemove(inode); | 206 | fsnotify_inoderemove(inode); |
125 | if (dentry->d_op && dentry->d_op->d_iput) | 207 | if (dentry->d_op && dentry->d_op->d_iput) |
@@ -128,40 +210,72 @@ static void dentry_iput(struct dentry * dentry) | |||
128 | iput(inode); | 210 | iput(inode); |
129 | } else { | 211 | } else { |
130 | spin_unlock(&dentry->d_lock); | 212 | spin_unlock(&dentry->d_lock); |
131 | spin_unlock(&dcache_lock); | ||
132 | } | 213 | } |
133 | } | 214 | } |
134 | 215 | ||
135 | /* | 216 | /* |
136 | * dentry_lru_(add|del|move_tail) must be called with dcache_lock held. | 217 | * Release the dentry's inode, using the filesystem |
218 | * d_iput() operation if defined. dentry remains in-use. | ||
219 | */ | ||
220 | static void dentry_unlink_inode(struct dentry * dentry) | ||
221 | __releases(dentry->d_lock) | ||
222 | __releases(dentry->d_inode->i_lock) | ||
223 | { | ||
224 | struct inode *inode = dentry->d_inode; | ||
225 | dentry->d_inode = NULL; | ||
226 | list_del_init(&dentry->d_alias); | ||
227 | dentry_rcuwalk_barrier(dentry); | ||
228 | spin_unlock(&dentry->d_lock); | ||
229 | spin_unlock(&inode->i_lock); | ||
230 | if (!inode->i_nlink) | ||
231 | fsnotify_inoderemove(inode); | ||
232 | if (dentry->d_op && dentry->d_op->d_iput) | ||
233 | dentry->d_op->d_iput(dentry, inode); | ||
234 | else | ||
235 | iput(inode); | ||
236 | } | ||
237 | |||
238 | /* | ||
239 | * dentry_lru_(add|del|move_tail) must be called with d_lock held. | ||
137 | */ | 240 | */ |
138 | static void dentry_lru_add(struct dentry *dentry) | 241 | static void dentry_lru_add(struct dentry *dentry) |
139 | { | 242 | { |
140 | if (list_empty(&dentry->d_lru)) { | 243 | if (list_empty(&dentry->d_lru)) { |
244 | spin_lock(&dcache_lru_lock); | ||
141 | list_add(&dentry->d_lru, &dentry->d_sb->s_dentry_lru); | 245 | list_add(&dentry->d_lru, &dentry->d_sb->s_dentry_lru); |
142 | dentry->d_sb->s_nr_dentry_unused++; | 246 | dentry->d_sb->s_nr_dentry_unused++; |
143 | percpu_counter_inc(&nr_dentry_unused); | 247 | dentry_stat.nr_unused++; |
248 | spin_unlock(&dcache_lru_lock); | ||
144 | } | 249 | } |
145 | } | 250 | } |
146 | 251 | ||
252 | static void __dentry_lru_del(struct dentry *dentry) | ||
253 | { | ||
254 | list_del_init(&dentry->d_lru); | ||
255 | dentry->d_sb->s_nr_dentry_unused--; | ||
256 | dentry_stat.nr_unused--; | ||
257 | } | ||
258 | |||
147 | static void dentry_lru_del(struct dentry *dentry) | 259 | static void dentry_lru_del(struct dentry *dentry) |
148 | { | 260 | { |
149 | if (!list_empty(&dentry->d_lru)) { | 261 | if (!list_empty(&dentry->d_lru)) { |
150 | list_del_init(&dentry->d_lru); | 262 | spin_lock(&dcache_lru_lock); |
151 | dentry->d_sb->s_nr_dentry_unused--; | 263 | __dentry_lru_del(dentry); |
152 | percpu_counter_dec(&nr_dentry_unused); | 264 | spin_unlock(&dcache_lru_lock); |
153 | } | 265 | } |
154 | } | 266 | } |
155 | 267 | ||
156 | static void dentry_lru_move_tail(struct dentry *dentry) | 268 | static void dentry_lru_move_tail(struct dentry *dentry) |
157 | { | 269 | { |
270 | spin_lock(&dcache_lru_lock); | ||
158 | if (list_empty(&dentry->d_lru)) { | 271 | if (list_empty(&dentry->d_lru)) { |
159 | list_add_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru); | 272 | list_add_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru); |
160 | dentry->d_sb->s_nr_dentry_unused++; | 273 | dentry->d_sb->s_nr_dentry_unused++; |
161 | percpu_counter_inc(&nr_dentry_unused); | 274 | dentry_stat.nr_unused++; |
162 | } else { | 275 | } else { |
163 | list_move_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru); | 276 | list_move_tail(&dentry->d_lru, &dentry->d_sb->s_dentry_lru); |
164 | } | 277 | } |
278 | spin_unlock(&dcache_lru_lock); | ||
165 | } | 279 | } |
166 | 280 | ||
167 | /** | 281 | /** |
@@ -171,22 +285,115 @@ static void dentry_lru_move_tail(struct dentry *dentry) | |||
171 | * The dentry must already be unhashed and removed from the LRU. | 285 | * The dentry must already be unhashed and removed from the LRU. |
172 | * | 286 | * |
173 | * If this is the root of the dentry tree, return NULL. | 287 | * If this is the root of the dentry tree, return NULL. |
288 | * | ||
289 | * dentry->d_lock and parent->d_lock must be held by caller, and are dropped by | ||
290 | * d_kill. | ||
174 | */ | 291 | */ |
175 | static struct dentry *d_kill(struct dentry *dentry) | 292 | static struct dentry *d_kill(struct dentry *dentry, struct dentry *parent) |
176 | __releases(dentry->d_lock) | 293 | __releases(dentry->d_lock) |
177 | __releases(dcache_lock) | 294 | __releases(parent->d_lock) |
295 | __releases(dentry->d_inode->i_lock) | ||
178 | { | 296 | { |
179 | struct dentry *parent; | 297 | dentry->d_parent = NULL; |
180 | |||
181 | list_del(&dentry->d_u.d_child); | 298 | list_del(&dentry->d_u.d_child); |
182 | /*drops the locks, at that point nobody can reach this dentry */ | 299 | if (parent) |
300 | spin_unlock(&parent->d_lock); | ||
183 | dentry_iput(dentry); | 301 | dentry_iput(dentry); |
302 | /* | ||
303 | * dentry_iput drops the locks, at which point nobody (except | ||
304 | * transient RCU lookups) can reach this dentry. | ||
305 | */ | ||
306 | d_free(dentry); | ||
307 | return parent; | ||
308 | } | ||
309 | |||
310 | /** | ||
311 | * d_drop - drop a dentry | ||
312 | * @dentry: dentry to drop | ||
313 | * | ||
314 | * d_drop() unhashes the entry from the parent dentry hashes, so that it won't | ||
315 | * be found through a VFS lookup any more. Note that this is different from | ||
316 | * deleting the dentry - d_delete will try to mark the dentry negative if | ||
317 | * possible, giving a successful _negative_ lookup, while d_drop will | ||
318 | * just make the cache lookup fail. | ||
319 | * | ||
320 | * d_drop() is used mainly for stuff that wants to invalidate a dentry for some | ||
321 | * reason (NFS timeouts or autofs deletes). | ||
322 | * | ||
323 | * __d_drop requires dentry->d_lock. | ||
324 | */ | ||
325 | void __d_drop(struct dentry *dentry) | ||
326 | { | ||
327 | if (!(dentry->d_flags & DCACHE_UNHASHED)) { | ||
328 | if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED)) { | ||
329 | bit_spin_lock(0, | ||
330 | (unsigned long *)&dentry->d_sb->s_anon.first); | ||
331 | dentry->d_flags |= DCACHE_UNHASHED; | ||
332 | hlist_bl_del_init(&dentry->d_hash); | ||
333 | __bit_spin_unlock(0, | ||
334 | (unsigned long *)&dentry->d_sb->s_anon.first); | ||
335 | } else { | ||
336 | struct dcache_hash_bucket *b; | ||
337 | b = d_hash(dentry->d_parent, dentry->d_name.hash); | ||
338 | spin_lock_bucket(b); | ||
339 | /* | ||
340 | * We may not actually need to put DCACHE_UNHASHED | ||
341 | * manipulations under the hash lock, but follow | ||
342 | * the principle of least surprise. | ||
343 | */ | ||
344 | dentry->d_flags |= DCACHE_UNHASHED; | ||
345 | hlist_bl_del_rcu(&dentry->d_hash); | ||
346 | spin_unlock_bucket(b); | ||
347 | dentry_rcuwalk_barrier(dentry); | ||
348 | } | ||
349 | } | ||
350 | } | ||
351 | EXPORT_SYMBOL(__d_drop); | ||
352 | |||
353 | void d_drop(struct dentry *dentry) | ||
354 | { | ||
355 | spin_lock(&dentry->d_lock); | ||
356 | __d_drop(dentry); | ||
357 | spin_unlock(&dentry->d_lock); | ||
358 | } | ||
359 | EXPORT_SYMBOL(d_drop); | ||
360 | |||
361 | /* | ||
362 | * Finish off a dentry we've decided to kill. | ||
363 | * dentry->d_lock must be held, returns with it unlocked. | ||
364 | * If ref is non-zero, then decrement the refcount too. | ||
365 | * Returns dentry requiring refcount drop, or NULL if we're done. | ||
366 | */ | ||
367 | static inline struct dentry *dentry_kill(struct dentry *dentry, int ref) | ||
368 | __releases(dentry->d_lock) | ||
369 | { | ||
370 | struct inode *inode; | ||
371 | struct dentry *parent; | ||
372 | |||
373 | inode = dentry->d_inode; | ||
374 | if (inode && !spin_trylock(&inode->i_lock)) { | ||
375 | relock: | ||
376 | spin_unlock(&dentry->d_lock); | ||
377 | cpu_relax(); | ||
378 | return dentry; /* try again with same dentry */ | ||
379 | } | ||
184 | if (IS_ROOT(dentry)) | 380 | if (IS_ROOT(dentry)) |
185 | parent = NULL; | 381 | parent = NULL; |
186 | else | 382 | else |
187 | parent = dentry->d_parent; | 383 | parent = dentry->d_parent; |
188 | d_free(dentry); | 384 | if (parent && !spin_trylock(&parent->d_lock)) { |
189 | return parent; | 385 | if (inode) |
386 | spin_unlock(&inode->i_lock); | ||
387 | goto relock; | ||
388 | } | ||
389 | |||
390 | if (ref) | ||
391 | dentry->d_count--; | ||
392 | /* if dentry was on the d_lru list delete it from there */ | ||
393 | dentry_lru_del(dentry); | ||
394 | /* if it was on the hash then remove it */ | ||
395 | __d_drop(dentry); | ||
396 | return d_kill(dentry, parent); | ||
190 | } | 397 | } |
191 | 398 | ||
192 | /* | 399 | /* |
@@ -214,34 +421,26 @@ static struct dentry *d_kill(struct dentry *dentry) | |||
214 | * call the dentry unlink method as well as removing it from the queues and | 421 | * call the dentry unlink method as well as removing it from the queues and |
215 | * releasing its resources. If the parent dentries were scheduled for release | 422 | * releasing its resources. If the parent dentries were scheduled for release |
216 | * they too may now get deleted. | 423 | * they too may now get deleted. |
217 | * | ||
218 | * no dcache lock, please. | ||
219 | */ | 424 | */ |
220 | |||
221 | void dput(struct dentry *dentry) | 425 | void dput(struct dentry *dentry) |
222 | { | 426 | { |
223 | if (!dentry) | 427 | if (!dentry) |
224 | return; | 428 | return; |
225 | 429 | ||
226 | repeat: | 430 | repeat: |
227 | if (atomic_read(&dentry->d_count) == 1) | 431 | if (dentry->d_count == 1) |
228 | might_sleep(); | 432 | might_sleep(); |
229 | if (!atomic_dec_and_lock(&dentry->d_count, &dcache_lock)) | ||
230 | return; | ||
231 | |||
232 | spin_lock(&dentry->d_lock); | 433 | spin_lock(&dentry->d_lock); |
233 | if (atomic_read(&dentry->d_count)) { | 434 | BUG_ON(!dentry->d_count); |
435 | if (dentry->d_count > 1) { | ||
436 | dentry->d_count--; | ||
234 | spin_unlock(&dentry->d_lock); | 437 | spin_unlock(&dentry->d_lock); |
235 | spin_unlock(&dcache_lock); | ||
236 | return; | 438 | return; |
237 | } | 439 | } |
238 | 440 | ||
239 | /* | 441 | if (dentry->d_flags & DCACHE_OP_DELETE) { |
240 | * AV: ->d_delete() is _NOT_ allowed to block now. | ||
241 | */ | ||
242 | if (dentry->d_op && dentry->d_op->d_delete) { | ||
243 | if (dentry->d_op->d_delete(dentry)) | 442 | if (dentry->d_op->d_delete(dentry)) |
244 | goto unhash_it; | 443 | goto kill_it; |
245 | } | 444 | } |
246 | 445 | ||
247 | /* Unreachable? Get rid of it */ | 446 | /* Unreachable? Get rid of it */ |
@@ -252,16 +451,12 @@ repeat: | |||
252 | dentry->d_flags |= DCACHE_REFERENCED; | 451 | dentry->d_flags |= DCACHE_REFERENCED; |
253 | dentry_lru_add(dentry); | 452 | dentry_lru_add(dentry); |
254 | 453 | ||
255 | spin_unlock(&dentry->d_lock); | 454 | dentry->d_count--; |
256 | spin_unlock(&dcache_lock); | 455 | spin_unlock(&dentry->d_lock); |
257 | return; | 456 | return; |
258 | 457 | ||
259 | unhash_it: | ||
260 | __d_drop(dentry); | ||
261 | kill_it: | 458 | kill_it: |
262 | /* if dentry was on the d_lru list delete it from there */ | 459 | dentry = dentry_kill(dentry, 1); |
263 | dentry_lru_del(dentry); | ||
264 | dentry = d_kill(dentry); | ||
265 | if (dentry) | 460 | if (dentry) |
266 | goto repeat; | 461 | goto repeat; |
267 | } | 462 | } |
@@ -284,9 +479,9 @@ int d_invalidate(struct dentry * dentry) | |||
284 | /* | 479 | /* |
285 | * If it's already been dropped, return OK. | 480 | * If it's already been dropped, return OK. |
286 | */ | 481 | */ |
287 | spin_lock(&dcache_lock); | 482 | spin_lock(&dentry->d_lock); |
288 | if (d_unhashed(dentry)) { | 483 | if (d_unhashed(dentry)) { |
289 | spin_unlock(&dcache_lock); | 484 | spin_unlock(&dentry->d_lock); |
290 | return 0; | 485 | return 0; |
291 | } | 486 | } |
292 | /* | 487 | /* |
@@ -294,9 +489,9 @@ int d_invalidate(struct dentry * dentry) | |||
294 | * to get rid of unused child entries. | 489 | * to get rid of unused child entries. |
295 | */ | 490 | */ |
296 | if (!list_empty(&dentry->d_subdirs)) { | 491 | if (!list_empty(&dentry->d_subdirs)) { |
297 | spin_unlock(&dcache_lock); | 492 | spin_unlock(&dentry->d_lock); |
298 | shrink_dcache_parent(dentry); | 493 | shrink_dcache_parent(dentry); |
299 | spin_lock(&dcache_lock); | 494 | spin_lock(&dentry->d_lock); |
300 | } | 495 | } |
301 | 496 | ||
302 | /* | 497 | /* |
@@ -309,35 +504,61 @@ int d_invalidate(struct dentry * dentry) | |||
309 | * we might still populate it if it was a | 504 | * we might still populate it if it was a |
310 | * working directory or similar). | 505 | * working directory or similar). |
311 | */ | 506 | */ |
312 | spin_lock(&dentry->d_lock); | 507 | if (dentry->d_count > 1) { |
313 | if (atomic_read(&dentry->d_count) > 1) { | ||
314 | if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { | 508 | if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) { |
315 | spin_unlock(&dentry->d_lock); | 509 | spin_unlock(&dentry->d_lock); |
316 | spin_unlock(&dcache_lock); | ||
317 | return -EBUSY; | 510 | return -EBUSY; |
318 | } | 511 | } |
319 | } | 512 | } |
320 | 513 | ||
321 | __d_drop(dentry); | 514 | __d_drop(dentry); |
322 | spin_unlock(&dentry->d_lock); | 515 | spin_unlock(&dentry->d_lock); |
323 | spin_unlock(&dcache_lock); | ||
324 | return 0; | 516 | return 0; |
325 | } | 517 | } |
326 | EXPORT_SYMBOL(d_invalidate); | 518 | EXPORT_SYMBOL(d_invalidate); |
327 | 519 | ||
328 | /* This should be called _only_ with dcache_lock held */ | 520 | /* This must be called with d_lock held */ |
329 | static inline struct dentry * __dget_locked(struct dentry *dentry) | 521 | static inline void __dget_dlock(struct dentry *dentry) |
330 | { | 522 | { |
331 | atomic_inc(&dentry->d_count); | 523 | dentry->d_count++; |
332 | dentry_lru_del(dentry); | ||
333 | return dentry; | ||
334 | } | 524 | } |
335 | 525 | ||
336 | struct dentry * dget_locked(struct dentry *dentry) | 526 | static inline void __dget(struct dentry *dentry) |
337 | { | 527 | { |
338 | return __dget_locked(dentry); | 528 | spin_lock(&dentry->d_lock); |
529 | __dget_dlock(dentry); | ||
530 | spin_unlock(&dentry->d_lock); | ||
531 | } | ||
532 | |||
533 | struct dentry *dget_parent(struct dentry *dentry) | ||
534 | { | ||
535 | struct dentry *ret; | ||
536 | |||
537 | repeat: | ||
538 | /* | ||
539 | * Don't need rcu_dereference because we re-check it was correct under | ||
540 | * the lock. | ||
541 | */ | ||
542 | rcu_read_lock(); | ||
543 | ret = dentry->d_parent; | ||
544 | if (!ret) { | ||
545 | rcu_read_unlock(); | ||
546 | goto out; | ||
547 | } | ||
548 | spin_lock(&ret->d_lock); | ||
549 | if (unlikely(ret != dentry->d_parent)) { | ||
550 | spin_unlock(&ret->d_lock); | ||
551 | rcu_read_unlock(); | ||
552 | goto repeat; | ||
553 | } | ||
554 | rcu_read_unlock(); | ||
555 | BUG_ON(!ret->d_count); | ||
556 | ret->d_count++; | ||
557 | spin_unlock(&ret->d_lock); | ||
558 | out: | ||
559 | return ret; | ||
339 | } | 560 | } |
340 | EXPORT_SYMBOL(dget_locked); | 561 | EXPORT_SYMBOL(dget_parent); |
341 | 562 | ||
342 | /** | 563 | /** |
343 | * d_find_alias - grab a hashed alias of inode | 564 | * d_find_alias - grab a hashed alias of inode |
@@ -355,42 +576,51 @@ EXPORT_SYMBOL(dget_locked); | |||
355 | * any other hashed alias over that one unless @want_discon is set, | 576 | * any other hashed alias over that one unless @want_discon is set, |
356 | * in which case only return an IS_ROOT, DCACHE_DISCONNECTED alias. | 577 | * in which case only return an IS_ROOT, DCACHE_DISCONNECTED alias. |
357 | */ | 578 | */ |
358 | 579 | static struct dentry *__d_find_alias(struct inode *inode, int want_discon) | |
359 | static struct dentry * __d_find_alias(struct inode *inode, int want_discon) | ||
360 | { | 580 | { |
361 | struct list_head *head, *next, *tmp; | 581 | struct dentry *alias, *discon_alias; |
362 | struct dentry *alias, *discon_alias=NULL; | ||
363 | 582 | ||
364 | head = &inode->i_dentry; | 583 | again: |
365 | next = inode->i_dentry.next; | 584 | discon_alias = NULL; |
366 | while (next != head) { | 585 | list_for_each_entry(alias, &inode->i_dentry, d_alias) { |
367 | tmp = next; | 586 | spin_lock(&alias->d_lock); |
368 | next = tmp->next; | ||
369 | prefetch(next); | ||
370 | alias = list_entry(tmp, struct dentry, d_alias); | ||
371 | if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) { | 587 | if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) { |
372 | if (IS_ROOT(alias) && | 588 | if (IS_ROOT(alias) && |
373 | (alias->d_flags & DCACHE_DISCONNECTED)) | 589 | (alias->d_flags & DCACHE_DISCONNECTED)) { |
374 | discon_alias = alias; | 590 | discon_alias = alias; |
375 | else if (!want_discon) { | 591 | } else if (!want_discon) { |
376 | __dget_locked(alias); | 592 | __dget_dlock(alias); |
593 | spin_unlock(&alias->d_lock); | ||
594 | return alias; | ||
595 | } | ||
596 | } | ||
597 | spin_unlock(&alias->d_lock); | ||
598 | } | ||
599 | if (discon_alias) { | ||
600 | alias = discon_alias; | ||
601 | spin_lock(&alias->d_lock); | ||
602 | if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) { | ||
603 | if (IS_ROOT(alias) && | ||
604 | (alias->d_flags & DCACHE_DISCONNECTED)) { | ||
605 | __dget_dlock(alias); | ||
606 | spin_unlock(&alias->d_lock); | ||
377 | return alias; | 607 | return alias; |
378 | } | 608 | } |
379 | } | 609 | } |
610 | spin_unlock(&alias->d_lock); | ||
611 | goto again; | ||
380 | } | 612 | } |
381 | if (discon_alias) | 613 | return NULL; |
382 | __dget_locked(discon_alias); | ||
383 | return discon_alias; | ||
384 | } | 614 | } |
385 | 615 | ||
386 | struct dentry * d_find_alias(struct inode *inode) | 616 | struct dentry *d_find_alias(struct inode *inode) |
387 | { | 617 | { |
388 | struct dentry *de = NULL; | 618 | struct dentry *de = NULL; |
389 | 619 | ||
390 | if (!list_empty(&inode->i_dentry)) { | 620 | if (!list_empty(&inode->i_dentry)) { |
391 | spin_lock(&dcache_lock); | 621 | spin_lock(&inode->i_lock); |
392 | de = __d_find_alias(inode, 0); | 622 | de = __d_find_alias(inode, 0); |
393 | spin_unlock(&dcache_lock); | 623 | spin_unlock(&inode->i_lock); |
394 | } | 624 | } |
395 | return de; | 625 | return de; |
396 | } | 626 | } |
@@ -404,54 +634,61 @@ void d_prune_aliases(struct inode *inode) | |||
404 | { | 634 | { |
405 | struct dentry *dentry; | 635 | struct dentry *dentry; |
406 | restart: | 636 | restart: |
407 | spin_lock(&dcache_lock); | 637 | spin_lock(&inode->i_lock); |
408 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { | 638 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { |
409 | spin_lock(&dentry->d_lock); | 639 | spin_lock(&dentry->d_lock); |
410 | if (!atomic_read(&dentry->d_count)) { | 640 | if (!dentry->d_count) { |
411 | __dget_locked(dentry); | 641 | __dget_dlock(dentry); |
412 | __d_drop(dentry); | 642 | __d_drop(dentry); |
413 | spin_unlock(&dentry->d_lock); | 643 | spin_unlock(&dentry->d_lock); |
414 | spin_unlock(&dcache_lock); | 644 | spin_unlock(&inode->i_lock); |
415 | dput(dentry); | 645 | dput(dentry); |
416 | goto restart; | 646 | goto restart; |
417 | } | 647 | } |
418 | spin_unlock(&dentry->d_lock); | 648 | spin_unlock(&dentry->d_lock); |
419 | } | 649 | } |
420 | spin_unlock(&dcache_lock); | 650 | spin_unlock(&inode->i_lock); |
421 | } | 651 | } |
422 | EXPORT_SYMBOL(d_prune_aliases); | 652 | EXPORT_SYMBOL(d_prune_aliases); |
423 | 653 | ||
424 | /* | 654 | /* |
425 | * Throw away a dentry - free the inode, dput the parent. This requires that | 655 | * Try to throw away a dentry - free the inode, dput the parent. |
426 | * the LRU list has already been removed. | 656 | * Requires dentry->d_lock is held, and dentry->d_count == 0. |
657 | * Releases dentry->d_lock. | ||
427 | * | 658 | * |
428 | * Try to prune ancestors as well. This is necessary to prevent | 659 | * This may fail if locks cannot be acquired no problem, just try again. |
429 | * quadratic behavior of shrink_dcache_parent(), but is also expected | ||
430 | * to be beneficial in reducing dentry cache fragmentation. | ||
431 | */ | 660 | */ |
432 | static void prune_one_dentry(struct dentry * dentry) | 661 | static void try_prune_one_dentry(struct dentry *dentry) |
433 | __releases(dentry->d_lock) | 662 | __releases(dentry->d_lock) |
434 | __releases(dcache_lock) | ||
435 | __acquires(dcache_lock) | ||
436 | { | 663 | { |
437 | __d_drop(dentry); | 664 | struct dentry *parent; |
438 | dentry = d_kill(dentry); | ||
439 | 665 | ||
666 | parent = dentry_kill(dentry, 0); | ||
440 | /* | 667 | /* |
441 | * Prune ancestors. Locking is simpler than in dput(), | 668 | * If dentry_kill returns NULL, we have nothing more to do. |
442 | * because dcache_lock needs to be taken anyway. | 669 | * if it returns the same dentry, trylocks failed. In either |
670 | * case, just loop again. | ||
671 | * | ||
672 | * Otherwise, we need to prune ancestors too. This is necessary | ||
673 | * to prevent quadratic behavior of shrink_dcache_parent(), but | ||
674 | * is also expected to be beneficial in reducing dentry cache | ||
675 | * fragmentation. | ||
443 | */ | 676 | */ |
444 | spin_lock(&dcache_lock); | 677 | if (!parent) |
678 | return; | ||
679 | if (parent == dentry) | ||
680 | return; | ||
681 | |||
682 | /* Prune ancestors. */ | ||
683 | dentry = parent; | ||
445 | while (dentry) { | 684 | while (dentry) { |
446 | if (!atomic_dec_and_lock(&dentry->d_count, &dentry->d_lock)) | 685 | spin_lock(&dentry->d_lock); |
686 | if (dentry->d_count > 1) { | ||
687 | dentry->d_count--; | ||
688 | spin_unlock(&dentry->d_lock); | ||
447 | return; | 689 | return; |
448 | 690 | } | |
449 | if (dentry->d_op && dentry->d_op->d_delete) | 691 | dentry = dentry_kill(dentry, 1); |
450 | dentry->d_op->d_delete(dentry); | ||
451 | dentry_lru_del(dentry); | ||
452 | __d_drop(dentry); | ||
453 | dentry = d_kill(dentry); | ||
454 | spin_lock(&dcache_lock); | ||
455 | } | 692 | } |
456 | } | 693 | } |
457 | 694 | ||
@@ -459,24 +696,35 @@ static void shrink_dentry_list(struct list_head *list) | |||
459 | { | 696 | { |
460 | struct dentry *dentry; | 697 | struct dentry *dentry; |
461 | 698 | ||
462 | while (!list_empty(list)) { | 699 | rcu_read_lock(); |
463 | dentry = list_entry(list->prev, struct dentry, d_lru); | 700 | for (;;) { |
464 | dentry_lru_del(dentry); | 701 | dentry = list_entry_rcu(list->prev, struct dentry, d_lru); |
702 | if (&dentry->d_lru == list) | ||
703 | break; /* empty */ | ||
704 | spin_lock(&dentry->d_lock); | ||
705 | if (dentry != list_entry(list->prev, struct dentry, d_lru)) { | ||
706 | spin_unlock(&dentry->d_lock); | ||
707 | continue; | ||
708 | } | ||
465 | 709 | ||
466 | /* | 710 | /* |
467 | * We found an inuse dentry which was not removed from | 711 | * We found an inuse dentry which was not removed from |
468 | * the LRU because of laziness during lookup. Do not free | 712 | * the LRU because of laziness during lookup. Do not free |
469 | * it - just keep it off the LRU list. | 713 | * it - just keep it off the LRU list. |
470 | */ | 714 | */ |
471 | spin_lock(&dentry->d_lock); | 715 | if (dentry->d_count) { |
472 | if (atomic_read(&dentry->d_count)) { | 716 | dentry_lru_del(dentry); |
473 | spin_unlock(&dentry->d_lock); | 717 | spin_unlock(&dentry->d_lock); |
474 | continue; | 718 | continue; |
475 | } | 719 | } |
476 | prune_one_dentry(dentry); | 720 | |
477 | /* dentry->d_lock was dropped in prune_one_dentry() */ | 721 | rcu_read_unlock(); |
478 | cond_resched_lock(&dcache_lock); | 722 | |
723 | try_prune_one_dentry(dentry); | ||
724 | |||
725 | rcu_read_lock(); | ||
479 | } | 726 | } |
727 | rcu_read_unlock(); | ||
480 | } | 728 | } |
481 | 729 | ||
482 | /** | 730 | /** |
@@ -495,42 +743,44 @@ static void __shrink_dcache_sb(struct super_block *sb, int *count, int flags) | |||
495 | LIST_HEAD(tmp); | 743 | LIST_HEAD(tmp); |
496 | int cnt = *count; | 744 | int cnt = *count; |
497 | 745 | ||
498 | spin_lock(&dcache_lock); | 746 | relock: |
747 | spin_lock(&dcache_lru_lock); | ||
499 | while (!list_empty(&sb->s_dentry_lru)) { | 748 | while (!list_empty(&sb->s_dentry_lru)) { |
500 | dentry = list_entry(sb->s_dentry_lru.prev, | 749 | dentry = list_entry(sb->s_dentry_lru.prev, |
501 | struct dentry, d_lru); | 750 | struct dentry, d_lru); |
502 | BUG_ON(dentry->d_sb != sb); | 751 | BUG_ON(dentry->d_sb != sb); |
503 | 752 | ||
753 | if (!spin_trylock(&dentry->d_lock)) { | ||
754 | spin_unlock(&dcache_lru_lock); | ||
755 | cpu_relax(); | ||
756 | goto relock; | ||
757 | } | ||
758 | |||
504 | /* | 759 | /* |
505 | * If we are honouring the DCACHE_REFERENCED flag and the | 760 | * If we are honouring the DCACHE_REFERENCED flag and the |
506 | * dentry has this flag set, don't free it. Clear the flag | 761 | * dentry has this flag set, don't free it. Clear the flag |
507 | * and put it back on the LRU. | 762 | * and put it back on the LRU. |
508 | */ | 763 | */ |
509 | if (flags & DCACHE_REFERENCED) { | 764 | if (flags & DCACHE_REFERENCED && |
510 | spin_lock(&dentry->d_lock); | 765 | dentry->d_flags & DCACHE_REFERENCED) { |
511 | if (dentry->d_flags & DCACHE_REFERENCED) { | 766 | dentry->d_flags &= ~DCACHE_REFERENCED; |
512 | dentry->d_flags &= ~DCACHE_REFERENCED; | 767 | list_move(&dentry->d_lru, &referenced); |
513 | list_move(&dentry->d_lru, &referenced); | ||
514 | spin_unlock(&dentry->d_lock); | ||
515 | cond_resched_lock(&dcache_lock); | ||
516 | continue; | ||
517 | } | ||
518 | spin_unlock(&dentry->d_lock); | 768 | spin_unlock(&dentry->d_lock); |
769 | } else { | ||
770 | list_move_tail(&dentry->d_lru, &tmp); | ||
771 | spin_unlock(&dentry->d_lock); | ||
772 | if (!--cnt) | ||
773 | break; | ||
519 | } | 774 | } |
520 | 775 | cond_resched_lock(&dcache_lru_lock); | |
521 | list_move_tail(&dentry->d_lru, &tmp); | ||
522 | if (!--cnt) | ||
523 | break; | ||
524 | cond_resched_lock(&dcache_lock); | ||
525 | } | 776 | } |
526 | |||
527 | *count = cnt; | ||
528 | shrink_dentry_list(&tmp); | ||
529 | |||
530 | if (!list_empty(&referenced)) | 777 | if (!list_empty(&referenced)) |
531 | list_splice(&referenced, &sb->s_dentry_lru); | 778 | list_splice(&referenced, &sb->s_dentry_lru); |
532 | spin_unlock(&dcache_lock); | 779 | spin_unlock(&dcache_lru_lock); |
533 | 780 | ||
781 | shrink_dentry_list(&tmp); | ||
782 | |||
783 | *count = cnt; | ||
534 | } | 784 | } |
535 | 785 | ||
536 | /** | 786 | /** |
@@ -546,13 +796,12 @@ static void prune_dcache(int count) | |||
546 | { | 796 | { |
547 | struct super_block *sb, *p = NULL; | 797 | struct super_block *sb, *p = NULL; |
548 | int w_count; | 798 | int w_count; |
549 | int unused = percpu_counter_sum_positive(&nr_dentry_unused); | 799 | int unused = dentry_stat.nr_unused; |
550 | int prune_ratio; | 800 | int prune_ratio; |
551 | int pruned; | 801 | int pruned; |
552 | 802 | ||
553 | if (unused == 0 || count == 0) | 803 | if (unused == 0 || count == 0) |
554 | return; | 804 | return; |
555 | spin_lock(&dcache_lock); | ||
556 | if (count >= unused) | 805 | if (count >= unused) |
557 | prune_ratio = 1; | 806 | prune_ratio = 1; |
558 | else | 807 | else |
@@ -589,11 +838,9 @@ static void prune_dcache(int count) | |||
589 | if (down_read_trylock(&sb->s_umount)) { | 838 | if (down_read_trylock(&sb->s_umount)) { |
590 | if ((sb->s_root != NULL) && | 839 | if ((sb->s_root != NULL) && |
591 | (!list_empty(&sb->s_dentry_lru))) { | 840 | (!list_empty(&sb->s_dentry_lru))) { |
592 | spin_unlock(&dcache_lock); | ||
593 | __shrink_dcache_sb(sb, &w_count, | 841 | __shrink_dcache_sb(sb, &w_count, |
594 | DCACHE_REFERENCED); | 842 | DCACHE_REFERENCED); |
595 | pruned -= w_count; | 843 | pruned -= w_count; |
596 | spin_lock(&dcache_lock); | ||
597 | } | 844 | } |
598 | up_read(&sb->s_umount); | 845 | up_read(&sb->s_umount); |
599 | } | 846 | } |
@@ -609,7 +856,6 @@ static void prune_dcache(int count) | |||
609 | if (p) | 856 | if (p) |
610 | __put_super(p); | 857 | __put_super(p); |
611 | spin_unlock(&sb_lock); | 858 | spin_unlock(&sb_lock); |
612 | spin_unlock(&dcache_lock); | ||
613 | } | 859 | } |
614 | 860 | ||
615 | /** | 861 | /** |
@@ -623,12 +869,14 @@ void shrink_dcache_sb(struct super_block *sb) | |||
623 | { | 869 | { |
624 | LIST_HEAD(tmp); | 870 | LIST_HEAD(tmp); |
625 | 871 | ||
626 | spin_lock(&dcache_lock); | 872 | spin_lock(&dcache_lru_lock); |
627 | while (!list_empty(&sb->s_dentry_lru)) { | 873 | while (!list_empty(&sb->s_dentry_lru)) { |
628 | list_splice_init(&sb->s_dentry_lru, &tmp); | 874 | list_splice_init(&sb->s_dentry_lru, &tmp); |
875 | spin_unlock(&dcache_lru_lock); | ||
629 | shrink_dentry_list(&tmp); | 876 | shrink_dentry_list(&tmp); |
877 | spin_lock(&dcache_lru_lock); | ||
630 | } | 878 | } |
631 | spin_unlock(&dcache_lock); | 879 | spin_unlock(&dcache_lru_lock); |
632 | } | 880 | } |
633 | EXPORT_SYMBOL(shrink_dcache_sb); | 881 | EXPORT_SYMBOL(shrink_dcache_sb); |
634 | 882 | ||
@@ -645,10 +893,10 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
645 | BUG_ON(!IS_ROOT(dentry)); | 893 | BUG_ON(!IS_ROOT(dentry)); |
646 | 894 | ||
647 | /* detach this root from the system */ | 895 | /* detach this root from the system */ |
648 | spin_lock(&dcache_lock); | 896 | spin_lock(&dentry->d_lock); |
649 | dentry_lru_del(dentry); | 897 | dentry_lru_del(dentry); |
650 | __d_drop(dentry); | 898 | __d_drop(dentry); |
651 | spin_unlock(&dcache_lock); | 899 | spin_unlock(&dentry->d_lock); |
652 | 900 | ||
653 | for (;;) { | 901 | for (;;) { |
654 | /* descend to the first leaf in the current subtree */ | 902 | /* descend to the first leaf in the current subtree */ |
@@ -657,14 +905,16 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
657 | 905 | ||
658 | /* this is a branch with children - detach all of them | 906 | /* this is a branch with children - detach all of them |
659 | * from the system in one go */ | 907 | * from the system in one go */ |
660 | spin_lock(&dcache_lock); | 908 | spin_lock(&dentry->d_lock); |
661 | list_for_each_entry(loop, &dentry->d_subdirs, | 909 | list_for_each_entry(loop, &dentry->d_subdirs, |
662 | d_u.d_child) { | 910 | d_u.d_child) { |
911 | spin_lock_nested(&loop->d_lock, | ||
912 | DENTRY_D_LOCK_NESTED); | ||
663 | dentry_lru_del(loop); | 913 | dentry_lru_del(loop); |
664 | __d_drop(loop); | 914 | __d_drop(loop); |
665 | cond_resched_lock(&dcache_lock); | 915 | spin_unlock(&loop->d_lock); |
666 | } | 916 | } |
667 | spin_unlock(&dcache_lock); | 917 | spin_unlock(&dentry->d_lock); |
668 | 918 | ||
669 | /* move to the first child */ | 919 | /* move to the first child */ |
670 | dentry = list_entry(dentry->d_subdirs.next, | 920 | dentry = list_entry(dentry->d_subdirs.next, |
@@ -676,7 +926,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
676 | do { | 926 | do { |
677 | struct inode *inode; | 927 | struct inode *inode; |
678 | 928 | ||
679 | if (atomic_read(&dentry->d_count) != 0) { | 929 | if (dentry->d_count != 0) { |
680 | printk(KERN_ERR | 930 | printk(KERN_ERR |
681 | "BUG: Dentry %p{i=%lx,n=%s}" | 931 | "BUG: Dentry %p{i=%lx,n=%s}" |
682 | " still in use (%d)" | 932 | " still in use (%d)" |
@@ -685,20 +935,23 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
685 | dentry->d_inode ? | 935 | dentry->d_inode ? |
686 | dentry->d_inode->i_ino : 0UL, | 936 | dentry->d_inode->i_ino : 0UL, |
687 | dentry->d_name.name, | 937 | dentry->d_name.name, |
688 | atomic_read(&dentry->d_count), | 938 | dentry->d_count, |
689 | dentry->d_sb->s_type->name, | 939 | dentry->d_sb->s_type->name, |
690 | dentry->d_sb->s_id); | 940 | dentry->d_sb->s_id); |
691 | BUG(); | 941 | BUG(); |
692 | } | 942 | } |
693 | 943 | ||
694 | if (IS_ROOT(dentry)) | 944 | if (IS_ROOT(dentry)) { |
695 | parent = NULL; | 945 | parent = NULL; |
696 | else { | 946 | list_del(&dentry->d_u.d_child); |
947 | } else { | ||
697 | parent = dentry->d_parent; | 948 | parent = dentry->d_parent; |
698 | atomic_dec(&parent->d_count); | 949 | spin_lock(&parent->d_lock); |
950 | parent->d_count--; | ||
951 | list_del(&dentry->d_u.d_child); | ||
952 | spin_unlock(&parent->d_lock); | ||
699 | } | 953 | } |
700 | 954 | ||
701 | list_del(&dentry->d_u.d_child); | ||
702 | detached++; | 955 | detached++; |
703 | 956 | ||
704 | inode = dentry->d_inode; | 957 | inode = dentry->d_inode; |
@@ -728,8 +981,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) | |||
728 | 981 | ||
729 | /* | 982 | /* |
730 | * destroy the dentries attached to a superblock on unmounting | 983 | * destroy the dentries attached to a superblock on unmounting |
731 | * - we don't need to use dentry->d_lock, and only need dcache_lock when | 984 | * - we don't need to use dentry->d_lock because: |
732 | * removing the dentry from the system lists and hashes because: | ||
733 | * - the superblock is detached from all mountings and open files, so the | 985 | * - the superblock is detached from all mountings and open files, so the |
734 | * dentry trees will not be rearranged by the VFS | 986 | * dentry trees will not be rearranged by the VFS |
735 | * - s_umount is write-locked, so the memory pressure shrinker will ignore | 987 | * - s_umount is write-locked, so the memory pressure shrinker will ignore |
@@ -746,11 +998,13 @@ void shrink_dcache_for_umount(struct super_block *sb) | |||
746 | 998 | ||
747 | dentry = sb->s_root; | 999 | dentry = sb->s_root; |
748 | sb->s_root = NULL; | 1000 | sb->s_root = NULL; |
749 | atomic_dec(&dentry->d_count); | 1001 | spin_lock(&dentry->d_lock); |
1002 | dentry->d_count--; | ||
1003 | spin_unlock(&dentry->d_lock); | ||
750 | shrink_dcache_for_umount_subtree(dentry); | 1004 | shrink_dcache_for_umount_subtree(dentry); |
751 | 1005 | ||
752 | while (!hlist_empty(&sb->s_anon)) { | 1006 | while (!hlist_bl_empty(&sb->s_anon)) { |
753 | dentry = hlist_entry(sb->s_anon.first, struct dentry, d_hash); | 1007 | dentry = hlist_bl_entry(hlist_bl_first(&sb->s_anon), struct dentry, d_hash); |
754 | shrink_dcache_for_umount_subtree(dentry); | 1008 | shrink_dcache_for_umount_subtree(dentry); |
755 | } | 1009 | } |
756 | } | 1010 | } |
@@ -768,15 +1022,20 @@ void shrink_dcache_for_umount(struct super_block *sb) | |||
768 | * Return true if the parent or its subdirectories contain | 1022 | * Return true if the parent or its subdirectories contain |
769 | * a mount point | 1023 | * a mount point |
770 | */ | 1024 | */ |
771 | |||
772 | int have_submounts(struct dentry *parent) | 1025 | int have_submounts(struct dentry *parent) |
773 | { | 1026 | { |
774 | struct dentry *this_parent = parent; | 1027 | struct dentry *this_parent; |
775 | struct list_head *next; | 1028 | struct list_head *next; |
1029 | unsigned seq; | ||
1030 | int locked = 0; | ||
1031 | |||
1032 | seq = read_seqbegin(&rename_lock); | ||
1033 | again: | ||
1034 | this_parent = parent; | ||
776 | 1035 | ||
777 | spin_lock(&dcache_lock); | ||
778 | if (d_mountpoint(parent)) | 1036 | if (d_mountpoint(parent)) |
779 | goto positive; | 1037 | goto positive; |
1038 | spin_lock(&this_parent->d_lock); | ||
780 | repeat: | 1039 | repeat: |
781 | next = this_parent->d_subdirs.next; | 1040 | next = this_parent->d_subdirs.next; |
782 | resume: | 1041 | resume: |
@@ -784,27 +1043,65 @@ resume: | |||
784 | struct list_head *tmp = next; | 1043 | struct list_head *tmp = next; |
785 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); | 1044 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); |
786 | next = tmp->next; | 1045 | next = tmp->next; |
1046 | |||
1047 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | ||
787 | /* Have we found a mount point ? */ | 1048 | /* Have we found a mount point ? */ |
788 | if (d_mountpoint(dentry)) | 1049 | if (d_mountpoint(dentry)) { |
1050 | spin_unlock(&dentry->d_lock); | ||
1051 | spin_unlock(&this_parent->d_lock); | ||
789 | goto positive; | 1052 | goto positive; |
1053 | } | ||
790 | if (!list_empty(&dentry->d_subdirs)) { | 1054 | if (!list_empty(&dentry->d_subdirs)) { |
1055 | spin_unlock(&this_parent->d_lock); | ||
1056 | spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_); | ||
791 | this_parent = dentry; | 1057 | this_parent = dentry; |
1058 | spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_); | ||
792 | goto repeat; | 1059 | goto repeat; |
793 | } | 1060 | } |
1061 | spin_unlock(&dentry->d_lock); | ||
794 | } | 1062 | } |
795 | /* | 1063 | /* |
796 | * All done at this level ... ascend and resume the search. | 1064 | * All done at this level ... ascend and resume the search. |
797 | */ | 1065 | */ |
798 | if (this_parent != parent) { | 1066 | if (this_parent != parent) { |
799 | next = this_parent->d_u.d_child.next; | 1067 | struct dentry *tmp; |
800 | this_parent = this_parent->d_parent; | 1068 | struct dentry *child; |
1069 | |||
1070 | tmp = this_parent->d_parent; | ||
1071 | rcu_read_lock(); | ||
1072 | spin_unlock(&this_parent->d_lock); | ||
1073 | child = this_parent; | ||
1074 | this_parent = tmp; | ||
1075 | spin_lock(&this_parent->d_lock); | ||
1076 | /* might go back up the wrong parent if we have had a rename | ||
1077 | * or deletion */ | ||
1078 | if (this_parent != child->d_parent || | ||
1079 | (!locked && read_seqretry(&rename_lock, seq))) { | ||
1080 | spin_unlock(&this_parent->d_lock); | ||
1081 | rcu_read_unlock(); | ||
1082 | goto rename_retry; | ||
1083 | } | ||
1084 | rcu_read_unlock(); | ||
1085 | next = child->d_u.d_child.next; | ||
801 | goto resume; | 1086 | goto resume; |
802 | } | 1087 | } |
803 | spin_unlock(&dcache_lock); | 1088 | spin_unlock(&this_parent->d_lock); |
1089 | if (!locked && read_seqretry(&rename_lock, seq)) | ||
1090 | goto rename_retry; | ||
1091 | if (locked) | ||
1092 | write_sequnlock(&rename_lock); | ||
804 | return 0; /* No mount points found in tree */ | 1093 | return 0; /* No mount points found in tree */ |
805 | positive: | 1094 | positive: |
806 | spin_unlock(&dcache_lock); | 1095 | if (!locked && read_seqretry(&rename_lock, seq)) |
1096 | goto rename_retry; | ||
1097 | if (locked) | ||
1098 | write_sequnlock(&rename_lock); | ||
807 | return 1; | 1099 | return 1; |
1100 | |||
1101 | rename_retry: | ||
1102 | locked = 1; | ||
1103 | write_seqlock(&rename_lock); | ||
1104 | goto again; | ||
808 | } | 1105 | } |
809 | EXPORT_SYMBOL(have_submounts); | 1106 | EXPORT_SYMBOL(have_submounts); |
810 | 1107 | ||
@@ -824,11 +1121,16 @@ EXPORT_SYMBOL(have_submounts); | |||
824 | */ | 1121 | */ |
825 | static int select_parent(struct dentry * parent) | 1122 | static int select_parent(struct dentry * parent) |
826 | { | 1123 | { |
827 | struct dentry *this_parent = parent; | 1124 | struct dentry *this_parent; |
828 | struct list_head *next; | 1125 | struct list_head *next; |
1126 | unsigned seq; | ||
829 | int found = 0; | 1127 | int found = 0; |
1128 | int locked = 0; | ||
830 | 1129 | ||
831 | spin_lock(&dcache_lock); | 1130 | seq = read_seqbegin(&rename_lock); |
1131 | again: | ||
1132 | this_parent = parent; | ||
1133 | spin_lock(&this_parent->d_lock); | ||
832 | repeat: | 1134 | repeat: |
833 | next = this_parent->d_subdirs.next; | 1135 | next = this_parent->d_subdirs.next; |
834 | resume: | 1136 | resume: |
@@ -837,11 +1139,13 @@ resume: | |||
837 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); | 1139 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); |
838 | next = tmp->next; | 1140 | next = tmp->next; |
839 | 1141 | ||
1142 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | ||
1143 | |||
840 | /* | 1144 | /* |
841 | * move only zero ref count dentries to the end | 1145 | * move only zero ref count dentries to the end |
842 | * of the unused list for prune_dcache | 1146 | * of the unused list for prune_dcache |
843 | */ | 1147 | */ |
844 | if (!atomic_read(&dentry->d_count)) { | 1148 | if (!dentry->d_count) { |
845 | dentry_lru_move_tail(dentry); | 1149 | dentry_lru_move_tail(dentry); |
846 | found++; | 1150 | found++; |
847 | } else { | 1151 | } else { |
@@ -853,28 +1157,63 @@ resume: | |||
853 | * ensures forward progress). We'll be coming back to find | 1157 | * ensures forward progress). We'll be coming back to find |
854 | * the rest. | 1158 | * the rest. |
855 | */ | 1159 | */ |
856 | if (found && need_resched()) | 1160 | if (found && need_resched()) { |
1161 | spin_unlock(&dentry->d_lock); | ||
857 | goto out; | 1162 | goto out; |
1163 | } | ||
858 | 1164 | ||
859 | /* | 1165 | /* |
860 | * Descend a level if the d_subdirs list is non-empty. | 1166 | * Descend a level if the d_subdirs list is non-empty. |
861 | */ | 1167 | */ |
862 | if (!list_empty(&dentry->d_subdirs)) { | 1168 | if (!list_empty(&dentry->d_subdirs)) { |
1169 | spin_unlock(&this_parent->d_lock); | ||
1170 | spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_); | ||
863 | this_parent = dentry; | 1171 | this_parent = dentry; |
1172 | spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_); | ||
864 | goto repeat; | 1173 | goto repeat; |
865 | } | 1174 | } |
1175 | |||
1176 | spin_unlock(&dentry->d_lock); | ||
866 | } | 1177 | } |
867 | /* | 1178 | /* |
868 | * All done at this level ... ascend and resume the search. | 1179 | * All done at this level ... ascend and resume the search. |
869 | */ | 1180 | */ |
870 | if (this_parent != parent) { | 1181 | if (this_parent != parent) { |
871 | next = this_parent->d_u.d_child.next; | 1182 | struct dentry *tmp; |
872 | this_parent = this_parent->d_parent; | 1183 | struct dentry *child; |
1184 | |||
1185 | tmp = this_parent->d_parent; | ||
1186 | rcu_read_lock(); | ||
1187 | spin_unlock(&this_parent->d_lock); | ||
1188 | child = this_parent; | ||
1189 | this_parent = tmp; | ||
1190 | spin_lock(&this_parent->d_lock); | ||
1191 | /* might go back up the wrong parent if we have had a rename | ||
1192 | * or deletion */ | ||
1193 | if (this_parent != child->d_parent || | ||
1194 | (!locked && read_seqretry(&rename_lock, seq))) { | ||
1195 | spin_unlock(&this_parent->d_lock); | ||
1196 | rcu_read_unlock(); | ||
1197 | goto rename_retry; | ||
1198 | } | ||
1199 | rcu_read_unlock(); | ||
1200 | next = child->d_u.d_child.next; | ||
873 | goto resume; | 1201 | goto resume; |
874 | } | 1202 | } |
875 | out: | 1203 | out: |
876 | spin_unlock(&dcache_lock); | 1204 | spin_unlock(&this_parent->d_lock); |
1205 | if (!locked && read_seqretry(&rename_lock, seq)) | ||
1206 | goto rename_retry; | ||
1207 | if (locked) | ||
1208 | write_sequnlock(&rename_lock); | ||
877 | return found; | 1209 | return found; |
1210 | |||
1211 | rename_retry: | ||
1212 | if (found) | ||
1213 | return found; | ||
1214 | locked = 1; | ||
1215 | write_seqlock(&rename_lock); | ||
1216 | goto again; | ||
878 | } | 1217 | } |
879 | 1218 | ||
880 | /** | 1219 | /** |
@@ -908,16 +1247,13 @@ EXPORT_SYMBOL(shrink_dcache_parent); | |||
908 | */ | 1247 | */ |
909 | static int shrink_dcache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask) | 1248 | static int shrink_dcache_memory(struct shrinker *shrink, int nr, gfp_t gfp_mask) |
910 | { | 1249 | { |
911 | int nr_unused; | ||
912 | |||
913 | if (nr) { | 1250 | if (nr) { |
914 | if (!(gfp_mask & __GFP_FS)) | 1251 | if (!(gfp_mask & __GFP_FS)) |
915 | return -1; | 1252 | return -1; |
916 | prune_dcache(nr); | 1253 | prune_dcache(nr); |
917 | } | 1254 | } |
918 | 1255 | ||
919 | nr_unused = percpu_counter_sum_positive(&nr_dentry_unused); | 1256 | return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure; |
920 | return (nr_unused / 100) * sysctl_vfs_cache_pressure; | ||
921 | } | 1257 | } |
922 | 1258 | ||
923 | static struct shrinker dcache_shrinker = { | 1259 | static struct shrinker dcache_shrinker = { |
@@ -960,38 +1296,52 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) | |||
960 | memcpy(dname, name->name, name->len); | 1296 | memcpy(dname, name->name, name->len); |
961 | dname[name->len] = 0; | 1297 | dname[name->len] = 0; |
962 | 1298 | ||
963 | atomic_set(&dentry->d_count, 1); | 1299 | dentry->d_count = 1; |
964 | dentry->d_flags = DCACHE_UNHASHED; | 1300 | dentry->d_flags = DCACHE_UNHASHED; |
965 | spin_lock_init(&dentry->d_lock); | 1301 | spin_lock_init(&dentry->d_lock); |
1302 | seqcount_init(&dentry->d_seq); | ||
966 | dentry->d_inode = NULL; | 1303 | dentry->d_inode = NULL; |
967 | dentry->d_parent = NULL; | 1304 | dentry->d_parent = NULL; |
968 | dentry->d_sb = NULL; | 1305 | dentry->d_sb = NULL; |
969 | dentry->d_op = NULL; | 1306 | dentry->d_op = NULL; |
970 | dentry->d_fsdata = NULL; | 1307 | dentry->d_fsdata = NULL; |
971 | dentry->d_mounted = 0; | 1308 | INIT_HLIST_BL_NODE(&dentry->d_hash); |
972 | INIT_HLIST_NODE(&dentry->d_hash); | ||
973 | INIT_LIST_HEAD(&dentry->d_lru); | 1309 | INIT_LIST_HEAD(&dentry->d_lru); |
974 | INIT_LIST_HEAD(&dentry->d_subdirs); | 1310 | INIT_LIST_HEAD(&dentry->d_subdirs); |
975 | INIT_LIST_HEAD(&dentry->d_alias); | 1311 | INIT_LIST_HEAD(&dentry->d_alias); |
1312 | INIT_LIST_HEAD(&dentry->d_u.d_child); | ||
976 | 1313 | ||
977 | if (parent) { | 1314 | if (parent) { |
978 | dentry->d_parent = dget(parent); | 1315 | spin_lock(&parent->d_lock); |
1316 | /* | ||
1317 | * don't need child lock because it is not subject | ||
1318 | * to concurrency here | ||
1319 | */ | ||
1320 | __dget_dlock(parent); | ||
1321 | dentry->d_parent = parent; | ||
979 | dentry->d_sb = parent->d_sb; | 1322 | dentry->d_sb = parent->d_sb; |
980 | } else { | ||
981 | INIT_LIST_HEAD(&dentry->d_u.d_child); | ||
982 | } | ||
983 | |||
984 | spin_lock(&dcache_lock); | ||
985 | if (parent) | ||
986 | list_add(&dentry->d_u.d_child, &parent->d_subdirs); | 1323 | list_add(&dentry->d_u.d_child, &parent->d_subdirs); |
987 | spin_unlock(&dcache_lock); | 1324 | spin_unlock(&parent->d_lock); |
1325 | } | ||
988 | 1326 | ||
989 | percpu_counter_inc(&nr_dentry); | 1327 | this_cpu_inc(nr_dentry); |
990 | 1328 | ||
991 | return dentry; | 1329 | return dentry; |
992 | } | 1330 | } |
993 | EXPORT_SYMBOL(d_alloc); | 1331 | EXPORT_SYMBOL(d_alloc); |
994 | 1332 | ||
1333 | struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name) | ||
1334 | { | ||
1335 | struct dentry *dentry = d_alloc(NULL, name); | ||
1336 | if (dentry) { | ||
1337 | dentry->d_sb = sb; | ||
1338 | dentry->d_parent = dentry; | ||
1339 | dentry->d_flags |= DCACHE_DISCONNECTED; | ||
1340 | } | ||
1341 | return dentry; | ||
1342 | } | ||
1343 | EXPORT_SYMBOL(d_alloc_pseudo); | ||
1344 | |||
995 | struct dentry *d_alloc_name(struct dentry *parent, const char *name) | 1345 | struct dentry *d_alloc_name(struct dentry *parent, const char *name) |
996 | { | 1346 | { |
997 | struct qstr q; | 1347 | struct qstr q; |
@@ -1003,12 +1353,36 @@ struct dentry *d_alloc_name(struct dentry *parent, const char *name) | |||
1003 | } | 1353 | } |
1004 | EXPORT_SYMBOL(d_alloc_name); | 1354 | EXPORT_SYMBOL(d_alloc_name); |
1005 | 1355 | ||
1006 | /* the caller must hold dcache_lock */ | 1356 | void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op) |
1357 | { | ||
1358 | BUG_ON(dentry->d_op); | ||
1359 | BUG_ON(dentry->d_flags & (DCACHE_OP_HASH | | ||
1360 | DCACHE_OP_COMPARE | | ||
1361 | DCACHE_OP_REVALIDATE | | ||
1362 | DCACHE_OP_DELETE )); | ||
1363 | dentry->d_op = op; | ||
1364 | if (!op) | ||
1365 | return; | ||
1366 | if (op->d_hash) | ||
1367 | dentry->d_flags |= DCACHE_OP_HASH; | ||
1368 | if (op->d_compare) | ||
1369 | dentry->d_flags |= DCACHE_OP_COMPARE; | ||
1370 | if (op->d_revalidate) | ||
1371 | dentry->d_flags |= DCACHE_OP_REVALIDATE; | ||
1372 | if (op->d_delete) | ||
1373 | dentry->d_flags |= DCACHE_OP_DELETE; | ||
1374 | |||
1375 | } | ||
1376 | EXPORT_SYMBOL(d_set_d_op); | ||
1377 | |||
1007 | static void __d_instantiate(struct dentry *dentry, struct inode *inode) | 1378 | static void __d_instantiate(struct dentry *dentry, struct inode *inode) |
1008 | { | 1379 | { |
1380 | spin_lock(&dentry->d_lock); | ||
1009 | if (inode) | 1381 | if (inode) |
1010 | list_add(&dentry->d_alias, &inode->i_dentry); | 1382 | list_add(&dentry->d_alias, &inode->i_dentry); |
1011 | dentry->d_inode = inode; | 1383 | dentry->d_inode = inode; |
1384 | dentry_rcuwalk_barrier(dentry); | ||
1385 | spin_unlock(&dentry->d_lock); | ||
1012 | fsnotify_d_instantiate(dentry, inode); | 1386 | fsnotify_d_instantiate(dentry, inode); |
1013 | } | 1387 | } |
1014 | 1388 | ||
@@ -1030,9 +1404,11 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode) | |||
1030 | void d_instantiate(struct dentry *entry, struct inode * inode) | 1404 | void d_instantiate(struct dentry *entry, struct inode * inode) |
1031 | { | 1405 | { |
1032 | BUG_ON(!list_empty(&entry->d_alias)); | 1406 | BUG_ON(!list_empty(&entry->d_alias)); |
1033 | spin_lock(&dcache_lock); | 1407 | if (inode) |
1408 | spin_lock(&inode->i_lock); | ||
1034 | __d_instantiate(entry, inode); | 1409 | __d_instantiate(entry, inode); |
1035 | spin_unlock(&dcache_lock); | 1410 | if (inode) |
1411 | spin_unlock(&inode->i_lock); | ||
1036 | security_d_instantiate(entry, inode); | 1412 | security_d_instantiate(entry, inode); |
1037 | } | 1413 | } |
1038 | EXPORT_SYMBOL(d_instantiate); | 1414 | EXPORT_SYMBOL(d_instantiate); |
@@ -1069,15 +1445,18 @@ static struct dentry *__d_instantiate_unique(struct dentry *entry, | |||
1069 | list_for_each_entry(alias, &inode->i_dentry, d_alias) { | 1445 | list_for_each_entry(alias, &inode->i_dentry, d_alias) { |
1070 | struct qstr *qstr = &alias->d_name; | 1446 | struct qstr *qstr = &alias->d_name; |
1071 | 1447 | ||
1448 | /* | ||
1449 | * Don't need alias->d_lock here, because aliases with | ||
1450 | * d_parent == entry->d_parent are not subject to name or | ||
1451 | * parent changes, because the parent inode i_mutex is held. | ||
1452 | */ | ||
1072 | if (qstr->hash != hash) | 1453 | if (qstr->hash != hash) |
1073 | continue; | 1454 | continue; |
1074 | if (alias->d_parent != entry->d_parent) | 1455 | if (alias->d_parent != entry->d_parent) |
1075 | continue; | 1456 | continue; |
1076 | if (qstr->len != len) | 1457 | if (dentry_cmp(qstr->name, qstr->len, name, len)) |
1077 | continue; | 1458 | continue; |
1078 | if (memcmp(qstr->name, name, len)) | 1459 | __dget(alias); |
1079 | continue; | ||
1080 | dget_locked(alias); | ||
1081 | return alias; | 1460 | return alias; |
1082 | } | 1461 | } |
1083 | 1462 | ||
@@ -1091,9 +1470,11 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode) | |||
1091 | 1470 | ||
1092 | BUG_ON(!list_empty(&entry->d_alias)); | 1471 | BUG_ON(!list_empty(&entry->d_alias)); |
1093 | 1472 | ||
1094 | spin_lock(&dcache_lock); | 1473 | if (inode) |
1474 | spin_lock(&inode->i_lock); | ||
1095 | result = __d_instantiate_unique(entry, inode); | 1475 | result = __d_instantiate_unique(entry, inode); |
1096 | spin_unlock(&dcache_lock); | 1476 | if (inode) |
1477 | spin_unlock(&inode->i_lock); | ||
1097 | 1478 | ||
1098 | if (!result) { | 1479 | if (!result) { |
1099 | security_d_instantiate(entry, inode); | 1480 | security_d_instantiate(entry, inode); |
@@ -1134,14 +1515,6 @@ struct dentry * d_alloc_root(struct inode * root_inode) | |||
1134 | } | 1515 | } |
1135 | EXPORT_SYMBOL(d_alloc_root); | 1516 | EXPORT_SYMBOL(d_alloc_root); |
1136 | 1517 | ||
1137 | static inline struct hlist_head *d_hash(struct dentry *parent, | ||
1138 | unsigned long hash) | ||
1139 | { | ||
1140 | hash += ((unsigned long) parent ^ GOLDEN_RATIO_PRIME) / L1_CACHE_BYTES; | ||
1141 | hash = hash ^ ((hash ^ GOLDEN_RATIO_PRIME) >> D_HASHBITS); | ||
1142 | return dentry_hashtable + (hash & D_HASHMASK); | ||
1143 | } | ||
1144 | |||
1145 | /** | 1518 | /** |
1146 | * d_obtain_alias - find or allocate a dentry for a given inode | 1519 | * d_obtain_alias - find or allocate a dentry for a given inode |
1147 | * @inode: inode to allocate the dentry for | 1520 | * @inode: inode to allocate the dentry for |
@@ -1182,10 +1555,11 @@ struct dentry *d_obtain_alias(struct inode *inode) | |||
1182 | } | 1555 | } |
1183 | tmp->d_parent = tmp; /* make sure dput doesn't croak */ | 1556 | tmp->d_parent = tmp; /* make sure dput doesn't croak */ |
1184 | 1557 | ||
1185 | spin_lock(&dcache_lock); | 1558 | |
1559 | spin_lock(&inode->i_lock); | ||
1186 | res = __d_find_alias(inode, 0); | 1560 | res = __d_find_alias(inode, 0); |
1187 | if (res) { | 1561 | if (res) { |
1188 | spin_unlock(&dcache_lock); | 1562 | spin_unlock(&inode->i_lock); |
1189 | dput(tmp); | 1563 | dput(tmp); |
1190 | goto out_iput; | 1564 | goto out_iput; |
1191 | } | 1565 | } |
@@ -1195,12 +1569,14 @@ struct dentry *d_obtain_alias(struct inode *inode) | |||
1195 | tmp->d_sb = inode->i_sb; | 1569 | tmp->d_sb = inode->i_sb; |
1196 | tmp->d_inode = inode; | 1570 | tmp->d_inode = inode; |
1197 | tmp->d_flags |= DCACHE_DISCONNECTED; | 1571 | tmp->d_flags |= DCACHE_DISCONNECTED; |
1198 | tmp->d_flags &= ~DCACHE_UNHASHED; | ||
1199 | list_add(&tmp->d_alias, &inode->i_dentry); | 1572 | list_add(&tmp->d_alias, &inode->i_dentry); |
1200 | hlist_add_head(&tmp->d_hash, &inode->i_sb->s_anon); | 1573 | bit_spin_lock(0, (unsigned long *)&tmp->d_sb->s_anon.first); |
1574 | tmp->d_flags &= ~DCACHE_UNHASHED; | ||
1575 | hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon); | ||
1576 | __bit_spin_unlock(0, (unsigned long *)&tmp->d_sb->s_anon.first); | ||
1201 | spin_unlock(&tmp->d_lock); | 1577 | spin_unlock(&tmp->d_lock); |
1578 | spin_unlock(&inode->i_lock); | ||
1202 | 1579 | ||
1203 | spin_unlock(&dcache_lock); | ||
1204 | return tmp; | 1580 | return tmp; |
1205 | 1581 | ||
1206 | out_iput: | 1582 | out_iput: |
@@ -1230,18 +1606,18 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) | |||
1230 | struct dentry *new = NULL; | 1606 | struct dentry *new = NULL; |
1231 | 1607 | ||
1232 | if (inode && S_ISDIR(inode->i_mode)) { | 1608 | if (inode && S_ISDIR(inode->i_mode)) { |
1233 | spin_lock(&dcache_lock); | 1609 | spin_lock(&inode->i_lock); |
1234 | new = __d_find_alias(inode, 1); | 1610 | new = __d_find_alias(inode, 1); |
1235 | if (new) { | 1611 | if (new) { |
1236 | BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED)); | 1612 | BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED)); |
1237 | spin_unlock(&dcache_lock); | 1613 | spin_unlock(&inode->i_lock); |
1238 | security_d_instantiate(new, inode); | 1614 | security_d_instantiate(new, inode); |
1239 | d_move(new, dentry); | 1615 | d_move(new, dentry); |
1240 | iput(inode); | 1616 | iput(inode); |
1241 | } else { | 1617 | } else { |
1242 | /* already taking dcache_lock, so d_add() by hand */ | 1618 | /* already taking inode->i_lock, so d_add() by hand */ |
1243 | __d_instantiate(dentry, inode); | 1619 | __d_instantiate(dentry, inode); |
1244 | spin_unlock(&dcache_lock); | 1620 | spin_unlock(&inode->i_lock); |
1245 | security_d_instantiate(dentry, inode); | 1621 | security_d_instantiate(dentry, inode); |
1246 | d_rehash(dentry); | 1622 | d_rehash(dentry); |
1247 | } | 1623 | } |
@@ -1314,10 +1690,10 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, | |||
1314 | * Negative dentry: instantiate it unless the inode is a directory and | 1690 | * Negative dentry: instantiate it unless the inode is a directory and |
1315 | * already has a dentry. | 1691 | * already has a dentry. |
1316 | */ | 1692 | */ |
1317 | spin_lock(&dcache_lock); | 1693 | spin_lock(&inode->i_lock); |
1318 | if (!S_ISDIR(inode->i_mode) || list_empty(&inode->i_dentry)) { | 1694 | if (!S_ISDIR(inode->i_mode) || list_empty(&inode->i_dentry)) { |
1319 | __d_instantiate(found, inode); | 1695 | __d_instantiate(found, inode); |
1320 | spin_unlock(&dcache_lock); | 1696 | spin_unlock(&inode->i_lock); |
1321 | security_d_instantiate(found, inode); | 1697 | security_d_instantiate(found, inode); |
1322 | return found; | 1698 | return found; |
1323 | } | 1699 | } |
@@ -1327,8 +1703,8 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, | |||
1327 | * reference to it, move it in place and use it. | 1703 | * reference to it, move it in place and use it. |
1328 | */ | 1704 | */ |
1329 | new = list_entry(inode->i_dentry.next, struct dentry, d_alias); | 1705 | new = list_entry(inode->i_dentry.next, struct dentry, d_alias); |
1330 | dget_locked(new); | 1706 | __dget(new); |
1331 | spin_unlock(&dcache_lock); | 1707 | spin_unlock(&inode->i_lock); |
1332 | security_d_instantiate(found, inode); | 1708 | security_d_instantiate(found, inode); |
1333 | d_move(new, found); | 1709 | d_move(new, found); |
1334 | iput(inode); | 1710 | iput(inode); |
@@ -1342,6 +1718,112 @@ err_out: | |||
1342 | EXPORT_SYMBOL(d_add_ci); | 1718 | EXPORT_SYMBOL(d_add_ci); |
1343 | 1719 | ||
1344 | /** | 1720 | /** |
1721 | * __d_lookup_rcu - search for a dentry (racy, store-free) | ||
1722 | * @parent: parent dentry | ||
1723 | * @name: qstr of name we wish to find | ||
1724 | * @seq: returns d_seq value at the point where the dentry was found | ||
1725 | * @inode: returns dentry->d_inode when the inode was found valid. | ||
1726 | * Returns: dentry, or NULL | ||
1727 | * | ||
1728 | * __d_lookup_rcu is the dcache lookup function for rcu-walk name | ||
1729 | * resolution (store-free path walking) design described in | ||
1730 | * Documentation/filesystems/path-lookup.txt. | ||
1731 | * | ||
1732 | * This is not to be used outside core vfs. | ||
1733 | * | ||
1734 | * __d_lookup_rcu must only be used in rcu-walk mode, ie. with vfsmount lock | ||
1735 | * held, and rcu_read_lock held. The returned dentry must not be stored into | ||
1736 | * without taking d_lock and checking d_seq sequence count against @seq | ||
1737 | * returned here. | ||
1738 | * | ||
1739 | * A refcount may be taken on the found dentry with the __d_rcu_to_refcount | ||
1740 | * function. | ||
1741 | * | ||
1742 | * Alternatively, __d_lookup_rcu may be called again to look up the child of | ||
1743 | * the returned dentry, so long as its parent's seqlock is checked after the | ||
1744 | * child is looked up. Thus, an interlocking stepping of sequence lock checks | ||
1745 | * is formed, giving integrity down the path walk. | ||
1746 | */ | ||
1747 | struct dentry *__d_lookup_rcu(struct dentry *parent, struct qstr *name, | ||
1748 | unsigned *seq, struct inode **inode) | ||
1749 | { | ||
1750 | unsigned int len = name->len; | ||
1751 | unsigned int hash = name->hash; | ||
1752 | const unsigned char *str = name->name; | ||
1753 | struct dcache_hash_bucket *b = d_hash(parent, hash); | ||
1754 | struct hlist_bl_node *node; | ||
1755 | struct dentry *dentry; | ||
1756 | |||
1757 | /* | ||
1758 | * Note: There is significant duplication with __d_lookup_rcu which is | ||
1759 | * required to prevent single threaded performance regressions | ||
1760 | * especially on architectures where smp_rmb (in seqcounts) are costly. | ||
1761 | * Keep the two functions in sync. | ||
1762 | */ | ||
1763 | |||
1764 | /* | ||
1765 | * The hash list is protected using RCU. | ||
1766 | * | ||
1767 | * Carefully use d_seq when comparing a candidate dentry, to avoid | ||
1768 | * races with d_move(). | ||
1769 | * | ||
1770 | * It is possible that concurrent renames can mess up our list | ||
1771 | * walk here and result in missing our dentry, resulting in the | ||
1772 | * false-negative result. d_lookup() protects against concurrent | ||
1773 | * renames using rename_lock seqlock. | ||
1774 | * | ||
1775 | * See Documentation/vfs/dcache-locking.txt for more details. | ||
1776 | */ | ||
1777 | hlist_bl_for_each_entry_rcu(dentry, node, &b->head, d_hash) { | ||
1778 | struct inode *i; | ||
1779 | const char *tname; | ||
1780 | int tlen; | ||
1781 | |||
1782 | if (dentry->d_name.hash != hash) | ||
1783 | continue; | ||
1784 | |||
1785 | seqretry: | ||
1786 | *seq = read_seqcount_begin(&dentry->d_seq); | ||
1787 | if (dentry->d_parent != parent) | ||
1788 | continue; | ||
1789 | if (d_unhashed(dentry)) | ||
1790 | continue; | ||
1791 | tlen = dentry->d_name.len; | ||
1792 | tname = dentry->d_name.name; | ||
1793 | i = dentry->d_inode; | ||
1794 | prefetch(tname); | ||
1795 | if (i) | ||
1796 | prefetch(i); | ||
1797 | /* | ||
1798 | * This seqcount check is required to ensure name and | ||
1799 | * len are loaded atomically, so as not to walk off the | ||
1800 | * edge of memory when walking. If we could load this | ||
1801 | * atomically some other way, we could drop this check. | ||
1802 | */ | ||
1803 | if (read_seqcount_retry(&dentry->d_seq, *seq)) | ||
1804 | goto seqretry; | ||
1805 | if (parent->d_flags & DCACHE_OP_COMPARE) { | ||
1806 | if (parent->d_op->d_compare(parent, *inode, | ||
1807 | dentry, i, | ||
1808 | tlen, tname, name)) | ||
1809 | continue; | ||
1810 | } else { | ||
1811 | if (dentry_cmp(tname, tlen, str, len)) | ||
1812 | continue; | ||
1813 | } | ||
1814 | /* | ||
1815 | * No extra seqcount check is required after the name | ||
1816 | * compare. The caller must perform a seqcount check in | ||
1817 | * order to do anything useful with the returned dentry | ||
1818 | * anyway. | ||
1819 | */ | ||
1820 | *inode = i; | ||
1821 | return dentry; | ||
1822 | } | ||
1823 | return NULL; | ||
1824 | } | ||
1825 | |||
1826 | /** | ||
1345 | * d_lookup - search for a dentry | 1827 | * d_lookup - search for a dentry |
1346 | * @parent: parent dentry | 1828 | * @parent: parent dentry |
1347 | * @name: qstr of name we wish to find | 1829 | * @name: qstr of name we wish to find |
@@ -1352,10 +1834,10 @@ EXPORT_SYMBOL(d_add_ci); | |||
1352 | * dentry is returned. The caller must use dput to free the entry when it has | 1834 | * dentry is returned. The caller must use dput to free the entry when it has |
1353 | * finished using it. %NULL is returned if the dentry does not exist. | 1835 | * finished using it. %NULL is returned if the dentry does not exist. |
1354 | */ | 1836 | */ |
1355 | struct dentry * d_lookup(struct dentry * parent, struct qstr * name) | 1837 | struct dentry *d_lookup(struct dentry *parent, struct qstr *name) |
1356 | { | 1838 | { |
1357 | struct dentry * dentry = NULL; | 1839 | struct dentry *dentry; |
1358 | unsigned long seq; | 1840 | unsigned seq; |
1359 | 1841 | ||
1360 | do { | 1842 | do { |
1361 | seq = read_seqbegin(&rename_lock); | 1843 | seq = read_seqbegin(&rename_lock); |
@@ -1367,7 +1849,7 @@ struct dentry * d_lookup(struct dentry * parent, struct qstr * name) | |||
1367 | } | 1849 | } |
1368 | EXPORT_SYMBOL(d_lookup); | 1850 | EXPORT_SYMBOL(d_lookup); |
1369 | 1851 | ||
1370 | /* | 1852 | /** |
1371 | * __d_lookup - search for a dentry (racy) | 1853 | * __d_lookup - search for a dentry (racy) |
1372 | * @parent: parent dentry | 1854 | * @parent: parent dentry |
1373 | * @name: qstr of name we wish to find | 1855 | * @name: qstr of name we wish to find |
@@ -1382,17 +1864,24 @@ EXPORT_SYMBOL(d_lookup); | |||
1382 | * | 1864 | * |
1383 | * __d_lookup callers must be commented. | 1865 | * __d_lookup callers must be commented. |
1384 | */ | 1866 | */ |
1385 | struct dentry * __d_lookup(struct dentry * parent, struct qstr * name) | 1867 | struct dentry *__d_lookup(struct dentry *parent, struct qstr *name) |
1386 | { | 1868 | { |
1387 | unsigned int len = name->len; | 1869 | unsigned int len = name->len; |
1388 | unsigned int hash = name->hash; | 1870 | unsigned int hash = name->hash; |
1389 | const unsigned char *str = name->name; | 1871 | const unsigned char *str = name->name; |
1390 | struct hlist_head *head = d_hash(parent,hash); | 1872 | struct dcache_hash_bucket *b = d_hash(parent, hash); |
1873 | struct hlist_bl_node *node; | ||
1391 | struct dentry *found = NULL; | 1874 | struct dentry *found = NULL; |
1392 | struct hlist_node *node; | ||
1393 | struct dentry *dentry; | 1875 | struct dentry *dentry; |
1394 | 1876 | ||
1395 | /* | 1877 | /* |
1878 | * Note: There is significant duplication with __d_lookup_rcu which is | ||
1879 | * required to prevent single threaded performance regressions | ||
1880 | * especially on architectures where smp_rmb (in seqcounts) are costly. | ||
1881 | * Keep the two functions in sync. | ||
1882 | */ | ||
1883 | |||
1884 | /* | ||
1396 | * The hash list is protected using RCU. | 1885 | * The hash list is protected using RCU. |
1397 | * | 1886 | * |
1398 | * Take d_lock when comparing a candidate dentry, to avoid races | 1887 | * Take d_lock when comparing a candidate dentry, to avoid races |
@@ -1407,25 +1896,16 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name) | |||
1407 | */ | 1896 | */ |
1408 | rcu_read_lock(); | 1897 | rcu_read_lock(); |
1409 | 1898 | ||
1410 | hlist_for_each_entry_rcu(dentry, node, head, d_hash) { | 1899 | hlist_bl_for_each_entry_rcu(dentry, node, &b->head, d_hash) { |
1411 | struct qstr *qstr; | 1900 | const char *tname; |
1901 | int tlen; | ||
1412 | 1902 | ||
1413 | if (dentry->d_name.hash != hash) | 1903 | if (dentry->d_name.hash != hash) |
1414 | continue; | 1904 | continue; |
1415 | if (dentry->d_parent != parent) | ||
1416 | continue; | ||
1417 | 1905 | ||
1418 | spin_lock(&dentry->d_lock); | 1906 | spin_lock(&dentry->d_lock); |
1419 | |||
1420 | /* | ||
1421 | * Recheck the dentry after taking the lock - d_move may have | ||
1422 | * changed things. Don't bother checking the hash because | ||
1423 | * we're about to compare the whole name anyway. | ||
1424 | */ | ||
1425 | if (dentry->d_parent != parent) | 1907 | if (dentry->d_parent != parent) |
1426 | goto next; | 1908 | goto next; |
1427 | |||
1428 | /* non-existing due to RCU? */ | ||
1429 | if (d_unhashed(dentry)) | 1909 | if (d_unhashed(dentry)) |
1430 | goto next; | 1910 | goto next; |
1431 | 1911 | ||
@@ -1433,18 +1913,19 @@ struct dentry * __d_lookup(struct dentry * parent, struct qstr * name) | |||
1433 | * It is safe to compare names since d_move() cannot | 1913 | * It is safe to compare names since d_move() cannot |
1434 | * change the qstr (protected by d_lock). | 1914 | * change the qstr (protected by d_lock). |
1435 | */ | 1915 | */ |
1436 | qstr = &dentry->d_name; | 1916 | tlen = dentry->d_name.len; |
1437 | if (parent->d_op && parent->d_op->d_compare) { | 1917 | tname = dentry->d_name.name; |
1438 | if (parent->d_op->d_compare(parent, qstr, name)) | 1918 | if (parent->d_flags & DCACHE_OP_COMPARE) { |
1919 | if (parent->d_op->d_compare(parent, parent->d_inode, | ||
1920 | dentry, dentry->d_inode, | ||
1921 | tlen, tname, name)) | ||
1439 | goto next; | 1922 | goto next; |
1440 | } else { | 1923 | } else { |
1441 | if (qstr->len != len) | 1924 | if (dentry_cmp(tname, tlen, str, len)) |
1442 | goto next; | ||
1443 | if (memcmp(qstr->name, str, len)) | ||
1444 | goto next; | 1925 | goto next; |
1445 | } | 1926 | } |
1446 | 1927 | ||
1447 | atomic_inc(&dentry->d_count); | 1928 | dentry->d_count++; |
1448 | found = dentry; | 1929 | found = dentry; |
1449 | spin_unlock(&dentry->d_lock); | 1930 | spin_unlock(&dentry->d_lock); |
1450 | break; | 1931 | break; |
@@ -1473,8 +1954,8 @@ struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name) | |||
1473 | * routine may choose to leave the hash value unchanged. | 1954 | * routine may choose to leave the hash value unchanged. |
1474 | */ | 1955 | */ |
1475 | name->hash = full_name_hash(name->name, name->len); | 1956 | name->hash = full_name_hash(name->name, name->len); |
1476 | if (dir->d_op && dir->d_op->d_hash) { | 1957 | if (dir->d_flags & DCACHE_OP_HASH) { |
1477 | if (dir->d_op->d_hash(dir, name) < 0) | 1958 | if (dir->d_op->d_hash(dir, dir->d_inode, name) < 0) |
1478 | goto out; | 1959 | goto out; |
1479 | } | 1960 | } |
1480 | dentry = d_lookup(dir, name); | 1961 | dentry = d_lookup(dir, name); |
@@ -1483,34 +1964,32 @@ out: | |||
1483 | } | 1964 | } |
1484 | 1965 | ||
1485 | /** | 1966 | /** |
1486 | * d_validate - verify dentry provided from insecure source | 1967 | * d_validate - verify dentry provided from insecure source (deprecated) |
1487 | * @dentry: The dentry alleged to be valid child of @dparent | 1968 | * @dentry: The dentry alleged to be valid child of @dparent |
1488 | * @dparent: The parent dentry (known to be valid) | 1969 | * @dparent: The parent dentry (known to be valid) |
1489 | * | 1970 | * |
1490 | * An insecure source has sent us a dentry, here we verify it and dget() it. | 1971 | * An insecure source has sent us a dentry, here we verify it and dget() it. |
1491 | * This is used by ncpfs in its readdir implementation. | 1972 | * This is used by ncpfs in its readdir implementation. |
1492 | * Zero is returned in the dentry is invalid. | 1973 | * Zero is returned in the dentry is invalid. |
1974 | * | ||
1975 | * This function is slow for big directories, and deprecated, do not use it. | ||
1493 | */ | 1976 | */ |
1494 | int d_validate(struct dentry *dentry, struct dentry *parent) | 1977 | int d_validate(struct dentry *dentry, struct dentry *dparent) |
1495 | { | 1978 | { |
1496 | struct hlist_head *head = d_hash(parent, dentry->d_name.hash); | 1979 | struct dentry *child; |
1497 | struct hlist_node *node; | ||
1498 | struct dentry *d; | ||
1499 | |||
1500 | /* Check whether the ptr might be valid at all.. */ | ||
1501 | if (!kmem_ptr_validate(dentry_cache, dentry)) | ||
1502 | return 0; | ||
1503 | if (dentry->d_parent != parent) | ||
1504 | return 0; | ||
1505 | 1980 | ||
1506 | rcu_read_lock(); | 1981 | spin_lock(&dparent->d_lock); |
1507 | hlist_for_each_entry_rcu(d, node, head, d_hash) { | 1982 | list_for_each_entry(child, &dparent->d_subdirs, d_u.d_child) { |
1508 | if (d == dentry) { | 1983 | if (dentry == child) { |
1509 | dget(dentry); | 1984 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); |
1985 | __dget_dlock(dentry); | ||
1986 | spin_unlock(&dentry->d_lock); | ||
1987 | spin_unlock(&dparent->d_lock); | ||
1510 | return 1; | 1988 | return 1; |
1511 | } | 1989 | } |
1512 | } | 1990 | } |
1513 | rcu_read_unlock(); | 1991 | spin_unlock(&dparent->d_lock); |
1992 | |||
1514 | return 0; | 1993 | return 0; |
1515 | } | 1994 | } |
1516 | EXPORT_SYMBOL(d_validate); | 1995 | EXPORT_SYMBOL(d_validate); |
@@ -1538,16 +2017,23 @@ EXPORT_SYMBOL(d_validate); | |||
1538 | 2017 | ||
1539 | void d_delete(struct dentry * dentry) | 2018 | void d_delete(struct dentry * dentry) |
1540 | { | 2019 | { |
2020 | struct inode *inode; | ||
1541 | int isdir = 0; | 2021 | int isdir = 0; |
1542 | /* | 2022 | /* |
1543 | * Are we the only user? | 2023 | * Are we the only user? |
1544 | */ | 2024 | */ |
1545 | spin_lock(&dcache_lock); | 2025 | again: |
1546 | spin_lock(&dentry->d_lock); | 2026 | spin_lock(&dentry->d_lock); |
1547 | isdir = S_ISDIR(dentry->d_inode->i_mode); | 2027 | inode = dentry->d_inode; |
1548 | if (atomic_read(&dentry->d_count) == 1) { | 2028 | isdir = S_ISDIR(inode->i_mode); |
2029 | if (dentry->d_count == 1) { | ||
2030 | if (inode && !spin_trylock(&inode->i_lock)) { | ||
2031 | spin_unlock(&dentry->d_lock); | ||
2032 | cpu_relax(); | ||
2033 | goto again; | ||
2034 | } | ||
1549 | dentry->d_flags &= ~DCACHE_CANT_MOUNT; | 2035 | dentry->d_flags &= ~DCACHE_CANT_MOUNT; |
1550 | dentry_iput(dentry); | 2036 | dentry_unlink_inode(dentry); |
1551 | fsnotify_nameremove(dentry, isdir); | 2037 | fsnotify_nameremove(dentry, isdir); |
1552 | return; | 2038 | return; |
1553 | } | 2039 | } |
@@ -1556,17 +2042,18 @@ void d_delete(struct dentry * dentry) | |||
1556 | __d_drop(dentry); | 2042 | __d_drop(dentry); |
1557 | 2043 | ||
1558 | spin_unlock(&dentry->d_lock); | 2044 | spin_unlock(&dentry->d_lock); |
1559 | spin_unlock(&dcache_lock); | ||
1560 | 2045 | ||
1561 | fsnotify_nameremove(dentry, isdir); | 2046 | fsnotify_nameremove(dentry, isdir); |
1562 | } | 2047 | } |
1563 | EXPORT_SYMBOL(d_delete); | 2048 | EXPORT_SYMBOL(d_delete); |
1564 | 2049 | ||
1565 | static void __d_rehash(struct dentry * entry, struct hlist_head *list) | 2050 | static void __d_rehash(struct dentry * entry, struct dcache_hash_bucket *b) |
1566 | { | 2051 | { |
1567 | 2052 | BUG_ON(!d_unhashed(entry)); | |
2053 | spin_lock_bucket(b); | ||
1568 | entry->d_flags &= ~DCACHE_UNHASHED; | 2054 | entry->d_flags &= ~DCACHE_UNHASHED; |
1569 | hlist_add_head_rcu(&entry->d_hash, list); | 2055 | hlist_bl_add_head_rcu(&entry->d_hash, &b->head); |
2056 | spin_unlock_bucket(b); | ||
1570 | } | 2057 | } |
1571 | 2058 | ||
1572 | static void _d_rehash(struct dentry * entry) | 2059 | static void _d_rehash(struct dentry * entry) |
@@ -1583,25 +2070,39 @@ static void _d_rehash(struct dentry * entry) | |||
1583 | 2070 | ||
1584 | void d_rehash(struct dentry * entry) | 2071 | void d_rehash(struct dentry * entry) |
1585 | { | 2072 | { |
1586 | spin_lock(&dcache_lock); | ||
1587 | spin_lock(&entry->d_lock); | 2073 | spin_lock(&entry->d_lock); |
1588 | _d_rehash(entry); | 2074 | _d_rehash(entry); |
1589 | spin_unlock(&entry->d_lock); | 2075 | spin_unlock(&entry->d_lock); |
1590 | spin_unlock(&dcache_lock); | ||
1591 | } | 2076 | } |
1592 | EXPORT_SYMBOL(d_rehash); | 2077 | EXPORT_SYMBOL(d_rehash); |
1593 | 2078 | ||
1594 | /* | 2079 | /** |
1595 | * When switching names, the actual string doesn't strictly have to | 2080 | * dentry_update_name_case - update case insensitive dentry with a new name |
1596 | * be preserved in the target - because we're dropping the target | 2081 | * @dentry: dentry to be updated |
1597 | * anyway. As such, we can just do a simple memcpy() to copy over | 2082 | * @name: new name |
1598 | * the new name before we switch. | ||
1599 | * | 2083 | * |
1600 | * Note that we have to be a lot more careful about getting the hash | 2084 | * Update a case insensitive dentry with new case of name. |
1601 | * switched - we have to switch the hash value properly even if it | 2085 | * |
1602 | * then no longer matches the actual (corrupted) string of the target. | 2086 | * dentry must have been returned by d_lookup with name @name. Old and new |
1603 | * The hash value has to match the hash queue that the dentry is on.. | 2087 | * name lengths must match (ie. no d_compare which allows mismatched name |
2088 | * lengths). | ||
2089 | * | ||
2090 | * Parent inode i_mutex must be held over d_lookup and into this call (to | ||
2091 | * keep renames and concurrent inserts, and readdir(2) away). | ||
1604 | */ | 2092 | */ |
2093 | void dentry_update_name_case(struct dentry *dentry, struct qstr *name) | ||
2094 | { | ||
2095 | BUG_ON(!mutex_is_locked(&dentry->d_inode->i_mutex)); | ||
2096 | BUG_ON(dentry->d_name.len != name->len); /* d_lookup gives this */ | ||
2097 | |||
2098 | spin_lock(&dentry->d_lock); | ||
2099 | write_seqcount_begin(&dentry->d_seq); | ||
2100 | memcpy((unsigned char *)dentry->d_name.name, name->name, name->len); | ||
2101 | write_seqcount_end(&dentry->d_seq); | ||
2102 | spin_unlock(&dentry->d_lock); | ||
2103 | } | ||
2104 | EXPORT_SYMBOL(dentry_update_name_case); | ||
2105 | |||
1605 | static void switch_names(struct dentry *dentry, struct dentry *target) | 2106 | static void switch_names(struct dentry *dentry, struct dentry *target) |
1606 | { | 2107 | { |
1607 | if (dname_external(target)) { | 2108 | if (dname_external(target)) { |
@@ -1643,54 +2144,84 @@ static void switch_names(struct dentry *dentry, struct dentry *target) | |||
1643 | swap(dentry->d_name.len, target->d_name.len); | 2144 | swap(dentry->d_name.len, target->d_name.len); |
1644 | } | 2145 | } |
1645 | 2146 | ||
2147 | static void dentry_lock_for_move(struct dentry *dentry, struct dentry *target) | ||
2148 | { | ||
2149 | /* | ||
2150 | * XXXX: do we really need to take target->d_lock? | ||
2151 | */ | ||
2152 | if (IS_ROOT(dentry) || dentry->d_parent == target->d_parent) | ||
2153 | spin_lock(&target->d_parent->d_lock); | ||
2154 | else { | ||
2155 | if (d_ancestor(dentry->d_parent, target->d_parent)) { | ||
2156 | spin_lock(&dentry->d_parent->d_lock); | ||
2157 | spin_lock_nested(&target->d_parent->d_lock, | ||
2158 | DENTRY_D_LOCK_NESTED); | ||
2159 | } else { | ||
2160 | spin_lock(&target->d_parent->d_lock); | ||
2161 | spin_lock_nested(&dentry->d_parent->d_lock, | ||
2162 | DENTRY_D_LOCK_NESTED); | ||
2163 | } | ||
2164 | } | ||
2165 | if (target < dentry) { | ||
2166 | spin_lock_nested(&target->d_lock, 2); | ||
2167 | spin_lock_nested(&dentry->d_lock, 3); | ||
2168 | } else { | ||
2169 | spin_lock_nested(&dentry->d_lock, 2); | ||
2170 | spin_lock_nested(&target->d_lock, 3); | ||
2171 | } | ||
2172 | } | ||
2173 | |||
2174 | static void dentry_unlock_parents_for_move(struct dentry *dentry, | ||
2175 | struct dentry *target) | ||
2176 | { | ||
2177 | if (target->d_parent != dentry->d_parent) | ||
2178 | spin_unlock(&dentry->d_parent->d_lock); | ||
2179 | if (target->d_parent != target) | ||
2180 | spin_unlock(&target->d_parent->d_lock); | ||
2181 | } | ||
2182 | |||
1646 | /* | 2183 | /* |
1647 | * We cannibalize "target" when moving dentry on top of it, | 2184 | * When switching names, the actual string doesn't strictly have to |
1648 | * because it's going to be thrown away anyway. We could be more | 2185 | * be preserved in the target - because we're dropping the target |
1649 | * polite about it, though. | 2186 | * anyway. As such, we can just do a simple memcpy() to copy over |
1650 | * | 2187 | * the new name before we switch. |
1651 | * This forceful removal will result in ugly /proc output if | 2188 | * |
1652 | * somebody holds a file open that got deleted due to a rename. | 2189 | * Note that we have to be a lot more careful about getting the hash |
1653 | * We could be nicer about the deleted file, and let it show | 2190 | * switched - we have to switch the hash value properly even if it |
1654 | * up under the name it had before it was deleted rather than | 2191 | * then no longer matches the actual (corrupted) string of the target. |
1655 | * under the original name of the file that was moved on top of it. | 2192 | * The hash value has to match the hash queue that the dentry is on.. |
1656 | */ | 2193 | */ |
1657 | |||
1658 | /* | 2194 | /* |
1659 | * d_move_locked - move a dentry | 2195 | * d_move - move a dentry |
1660 | * @dentry: entry to move | 2196 | * @dentry: entry to move |
1661 | * @target: new dentry | 2197 | * @target: new dentry |
1662 | * | 2198 | * |
1663 | * Update the dcache to reflect the move of a file name. Negative | 2199 | * Update the dcache to reflect the move of a file name. Negative |
1664 | * dcache entries should not be moved in this way. | 2200 | * dcache entries should not be moved in this way. |
1665 | */ | 2201 | */ |
1666 | static void d_move_locked(struct dentry * dentry, struct dentry * target) | 2202 | void d_move(struct dentry * dentry, struct dentry * target) |
1667 | { | 2203 | { |
1668 | struct hlist_head *list; | ||
1669 | |||
1670 | if (!dentry->d_inode) | 2204 | if (!dentry->d_inode) |
1671 | printk(KERN_WARNING "VFS: moving negative dcache entry\n"); | 2205 | printk(KERN_WARNING "VFS: moving negative dcache entry\n"); |
1672 | 2206 | ||
2207 | BUG_ON(d_ancestor(dentry, target)); | ||
2208 | BUG_ON(d_ancestor(target, dentry)); | ||
2209 | |||
1673 | write_seqlock(&rename_lock); | 2210 | write_seqlock(&rename_lock); |
1674 | /* | ||
1675 | * XXXX: do we really need to take target->d_lock? | ||
1676 | */ | ||
1677 | if (target < dentry) { | ||
1678 | spin_lock(&target->d_lock); | ||
1679 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | ||
1680 | } else { | ||
1681 | spin_lock(&dentry->d_lock); | ||
1682 | spin_lock_nested(&target->d_lock, DENTRY_D_LOCK_NESTED); | ||
1683 | } | ||
1684 | 2211 | ||
1685 | /* Move the dentry to the target hash queue, if on different bucket */ | 2212 | dentry_lock_for_move(dentry, target); |
1686 | if (d_unhashed(dentry)) | ||
1687 | goto already_unhashed; | ||
1688 | 2213 | ||
1689 | hlist_del_rcu(&dentry->d_hash); | 2214 | write_seqcount_begin(&dentry->d_seq); |
2215 | write_seqcount_begin(&target->d_seq); | ||
1690 | 2216 | ||
1691 | already_unhashed: | 2217 | /* __d_drop does write_seqcount_barrier, but they're OK to nest. */ |
1692 | list = d_hash(target->d_parent, target->d_name.hash); | 2218 | |
1693 | __d_rehash(dentry, list); | 2219 | /* |
2220 | * Move the dentry to the target hash queue. Don't bother checking | ||
2221 | * for the same hash queue because of how unlikely it is. | ||
2222 | */ | ||
2223 | __d_drop(dentry); | ||
2224 | __d_rehash(dentry, d_hash(target->d_parent, target->d_name.hash)); | ||
1694 | 2225 | ||
1695 | /* Unhash the target: dput() will then get rid of it */ | 2226 | /* Unhash the target: dput() will then get rid of it */ |
1696 | __d_drop(target); | 2227 | __d_drop(target); |
@@ -1715,27 +2246,16 @@ already_unhashed: | |||
1715 | } | 2246 | } |
1716 | 2247 | ||
1717 | list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); | 2248 | list_add(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs); |
2249 | |||
2250 | write_seqcount_end(&target->d_seq); | ||
2251 | write_seqcount_end(&dentry->d_seq); | ||
2252 | |||
2253 | dentry_unlock_parents_for_move(dentry, target); | ||
1718 | spin_unlock(&target->d_lock); | 2254 | spin_unlock(&target->d_lock); |
1719 | fsnotify_d_move(dentry); | 2255 | fsnotify_d_move(dentry); |
1720 | spin_unlock(&dentry->d_lock); | 2256 | spin_unlock(&dentry->d_lock); |
1721 | write_sequnlock(&rename_lock); | 2257 | write_sequnlock(&rename_lock); |
1722 | } | 2258 | } |
1723 | |||
1724 | /** | ||
1725 | * d_move - move a dentry | ||
1726 | * @dentry: entry to move | ||
1727 | * @target: new dentry | ||
1728 | * | ||
1729 | * Update the dcache to reflect the move of a file name. Negative | ||
1730 | * dcache entries should not be moved in this way. | ||
1731 | */ | ||
1732 | |||
1733 | void d_move(struct dentry * dentry, struct dentry * target) | ||
1734 | { | ||
1735 | spin_lock(&dcache_lock); | ||
1736 | d_move_locked(dentry, target); | ||
1737 | spin_unlock(&dcache_lock); | ||
1738 | } | ||
1739 | EXPORT_SYMBOL(d_move); | 2259 | EXPORT_SYMBOL(d_move); |
1740 | 2260 | ||
1741 | /** | 2261 | /** |
@@ -1761,13 +2281,13 @@ struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2) | |||
1761 | * This helper attempts to cope with remotely renamed directories | 2281 | * This helper attempts to cope with remotely renamed directories |
1762 | * | 2282 | * |
1763 | * It assumes that the caller is already holding | 2283 | * It assumes that the caller is already holding |
1764 | * dentry->d_parent->d_inode->i_mutex and the dcache_lock | 2284 | * dentry->d_parent->d_inode->i_mutex and the inode->i_lock |
1765 | * | 2285 | * |
1766 | * Note: If ever the locking in lock_rename() changes, then please | 2286 | * Note: If ever the locking in lock_rename() changes, then please |
1767 | * remember to update this too... | 2287 | * remember to update this too... |
1768 | */ | 2288 | */ |
1769 | static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias) | 2289 | static struct dentry *__d_unalias(struct inode *inode, |
1770 | __releases(dcache_lock) | 2290 | struct dentry *dentry, struct dentry *alias) |
1771 | { | 2291 | { |
1772 | struct mutex *m1 = NULL, *m2 = NULL; | 2292 | struct mutex *m1 = NULL, *m2 = NULL; |
1773 | struct dentry *ret; | 2293 | struct dentry *ret; |
@@ -1790,10 +2310,10 @@ static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias) | |||
1790 | goto out_err; | 2310 | goto out_err; |
1791 | m2 = &alias->d_parent->d_inode->i_mutex; | 2311 | m2 = &alias->d_parent->d_inode->i_mutex; |
1792 | out_unalias: | 2312 | out_unalias: |
1793 | d_move_locked(alias, dentry); | 2313 | d_move(alias, dentry); |
1794 | ret = alias; | 2314 | ret = alias; |
1795 | out_err: | 2315 | out_err: |
1796 | spin_unlock(&dcache_lock); | 2316 | spin_unlock(&inode->i_lock); |
1797 | if (m2) | 2317 | if (m2) |
1798 | mutex_unlock(m2); | 2318 | mutex_unlock(m2); |
1799 | if (m1) | 2319 | if (m1) |
@@ -1804,17 +2324,23 @@ out_err: | |||
1804 | /* | 2324 | /* |
1805 | * Prepare an anonymous dentry for life in the superblock's dentry tree as a | 2325 | * Prepare an anonymous dentry for life in the superblock's dentry tree as a |
1806 | * named dentry in place of the dentry to be replaced. | 2326 | * named dentry in place of the dentry to be replaced. |
2327 | * returns with anon->d_lock held! | ||
1807 | */ | 2328 | */ |
1808 | static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) | 2329 | static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) |
1809 | { | 2330 | { |
1810 | struct dentry *dparent, *aparent; | 2331 | struct dentry *dparent, *aparent; |
1811 | 2332 | ||
1812 | switch_names(dentry, anon); | 2333 | dentry_lock_for_move(anon, dentry); |
1813 | swap(dentry->d_name.hash, anon->d_name.hash); | 2334 | |
2335 | write_seqcount_begin(&dentry->d_seq); | ||
2336 | write_seqcount_begin(&anon->d_seq); | ||
1814 | 2337 | ||
1815 | dparent = dentry->d_parent; | 2338 | dparent = dentry->d_parent; |
1816 | aparent = anon->d_parent; | 2339 | aparent = anon->d_parent; |
1817 | 2340 | ||
2341 | switch_names(dentry, anon); | ||
2342 | swap(dentry->d_name.hash, anon->d_name.hash); | ||
2343 | |||
1818 | dentry->d_parent = (aparent == anon) ? dentry : aparent; | 2344 | dentry->d_parent = (aparent == anon) ? dentry : aparent; |
1819 | list_del(&dentry->d_u.d_child); | 2345 | list_del(&dentry->d_u.d_child); |
1820 | if (!IS_ROOT(dentry)) | 2346 | if (!IS_ROOT(dentry)) |
@@ -1829,6 +2355,13 @@ static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) | |||
1829 | else | 2355 | else |
1830 | INIT_LIST_HEAD(&anon->d_u.d_child); | 2356 | INIT_LIST_HEAD(&anon->d_u.d_child); |
1831 | 2357 | ||
2358 | write_seqcount_end(&dentry->d_seq); | ||
2359 | write_seqcount_end(&anon->d_seq); | ||
2360 | |||
2361 | dentry_unlock_parents_for_move(anon, dentry); | ||
2362 | spin_unlock(&dentry->d_lock); | ||
2363 | |||
2364 | /* anon->d_lock still locked, returns locked */ | ||
1832 | anon->d_flags &= ~DCACHE_DISCONNECTED; | 2365 | anon->d_flags &= ~DCACHE_DISCONNECTED; |
1833 | } | 2366 | } |
1834 | 2367 | ||
@@ -1846,14 +2379,15 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) | |||
1846 | 2379 | ||
1847 | BUG_ON(!d_unhashed(dentry)); | 2380 | BUG_ON(!d_unhashed(dentry)); |
1848 | 2381 | ||
1849 | spin_lock(&dcache_lock); | ||
1850 | |||
1851 | if (!inode) { | 2382 | if (!inode) { |
1852 | actual = dentry; | 2383 | actual = dentry; |
1853 | __d_instantiate(dentry, NULL); | 2384 | __d_instantiate(dentry, NULL); |
1854 | goto found_lock; | 2385 | d_rehash(actual); |
2386 | goto out_nolock; | ||
1855 | } | 2387 | } |
1856 | 2388 | ||
2389 | spin_lock(&inode->i_lock); | ||
2390 | |||
1857 | if (S_ISDIR(inode->i_mode)) { | 2391 | if (S_ISDIR(inode->i_mode)) { |
1858 | struct dentry *alias; | 2392 | struct dentry *alias; |
1859 | 2393 | ||
@@ -1864,13 +2398,12 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) | |||
1864 | /* Is this an anonymous mountpoint that we could splice | 2398 | /* Is this an anonymous mountpoint that we could splice |
1865 | * into our tree? */ | 2399 | * into our tree? */ |
1866 | if (IS_ROOT(alias)) { | 2400 | if (IS_ROOT(alias)) { |
1867 | spin_lock(&alias->d_lock); | ||
1868 | __d_materialise_dentry(dentry, alias); | 2401 | __d_materialise_dentry(dentry, alias); |
1869 | __d_drop(alias); | 2402 | __d_drop(alias); |
1870 | goto found; | 2403 | goto found; |
1871 | } | 2404 | } |
1872 | /* Nope, but we must(!) avoid directory aliasing */ | 2405 | /* Nope, but we must(!) avoid directory aliasing */ |
1873 | actual = __d_unalias(dentry, alias); | 2406 | actual = __d_unalias(inode, dentry, alias); |
1874 | if (IS_ERR(actual)) | 2407 | if (IS_ERR(actual)) |
1875 | dput(alias); | 2408 | dput(alias); |
1876 | goto out_nolock; | 2409 | goto out_nolock; |
@@ -1881,15 +2414,14 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) | |||
1881 | actual = __d_instantiate_unique(dentry, inode); | 2414 | actual = __d_instantiate_unique(dentry, inode); |
1882 | if (!actual) | 2415 | if (!actual) |
1883 | actual = dentry; | 2416 | actual = dentry; |
1884 | else if (unlikely(!d_unhashed(actual))) | 2417 | else |
1885 | goto shouldnt_be_hashed; | 2418 | BUG_ON(!d_unhashed(actual)); |
1886 | 2419 | ||
1887 | found_lock: | ||
1888 | spin_lock(&actual->d_lock); | 2420 | spin_lock(&actual->d_lock); |
1889 | found: | 2421 | found: |
1890 | _d_rehash(actual); | 2422 | _d_rehash(actual); |
1891 | spin_unlock(&actual->d_lock); | 2423 | spin_unlock(&actual->d_lock); |
1892 | spin_unlock(&dcache_lock); | 2424 | spin_unlock(&inode->i_lock); |
1893 | out_nolock: | 2425 | out_nolock: |
1894 | if (actual == dentry) { | 2426 | if (actual == dentry) { |
1895 | security_d_instantiate(dentry, inode); | 2427 | security_d_instantiate(dentry, inode); |
@@ -1898,10 +2430,6 @@ out_nolock: | |||
1898 | 2430 | ||
1899 | iput(inode); | 2431 | iput(inode); |
1900 | return actual; | 2432 | return actual; |
1901 | |||
1902 | shouldnt_be_hashed: | ||
1903 | spin_unlock(&dcache_lock); | ||
1904 | BUG(); | ||
1905 | } | 2433 | } |
1906 | EXPORT_SYMBOL_GPL(d_materialise_unique); | 2434 | EXPORT_SYMBOL_GPL(d_materialise_unique); |
1907 | 2435 | ||
@@ -1928,7 +2456,7 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name) | |||
1928 | * @buffer: pointer to the end of the buffer | 2456 | * @buffer: pointer to the end of the buffer |
1929 | * @buflen: pointer to buffer length | 2457 | * @buflen: pointer to buffer length |
1930 | * | 2458 | * |
1931 | * Caller holds the dcache_lock. | 2459 | * Caller holds the rename_lock. |
1932 | * | 2460 | * |
1933 | * If path is not reachable from the supplied root, then the value of | 2461 | * If path is not reachable from the supplied root, then the value of |
1934 | * root is changed (without modifying refcounts). | 2462 | * root is changed (without modifying refcounts). |
@@ -1956,7 +2484,9 @@ static int prepend_path(const struct path *path, struct path *root, | |||
1956 | } | 2484 | } |
1957 | parent = dentry->d_parent; | 2485 | parent = dentry->d_parent; |
1958 | prefetch(parent); | 2486 | prefetch(parent); |
2487 | spin_lock(&dentry->d_lock); | ||
1959 | error = prepend_name(buffer, buflen, &dentry->d_name); | 2488 | error = prepend_name(buffer, buflen, &dentry->d_name); |
2489 | spin_unlock(&dentry->d_lock); | ||
1960 | if (!error) | 2490 | if (!error) |
1961 | error = prepend(buffer, buflen, "/", 1); | 2491 | error = prepend(buffer, buflen, "/", 1); |
1962 | if (error) | 2492 | if (error) |
@@ -2012,9 +2542,9 @@ char *__d_path(const struct path *path, struct path *root, | |||
2012 | int error; | 2542 | int error; |
2013 | 2543 | ||
2014 | prepend(&res, &buflen, "\0", 1); | 2544 | prepend(&res, &buflen, "\0", 1); |
2015 | spin_lock(&dcache_lock); | 2545 | write_seqlock(&rename_lock); |
2016 | error = prepend_path(path, root, &res, &buflen); | 2546 | error = prepend_path(path, root, &res, &buflen); |
2017 | spin_unlock(&dcache_lock); | 2547 | write_sequnlock(&rename_lock); |
2018 | 2548 | ||
2019 | if (error) | 2549 | if (error) |
2020 | return ERR_PTR(error); | 2550 | return ERR_PTR(error); |
@@ -2076,12 +2606,12 @@ char *d_path(const struct path *path, char *buf, int buflen) | |||
2076 | return path->dentry->d_op->d_dname(path->dentry, buf, buflen); | 2606 | return path->dentry->d_op->d_dname(path->dentry, buf, buflen); |
2077 | 2607 | ||
2078 | get_fs_root(current->fs, &root); | 2608 | get_fs_root(current->fs, &root); |
2079 | spin_lock(&dcache_lock); | 2609 | write_seqlock(&rename_lock); |
2080 | tmp = root; | 2610 | tmp = root; |
2081 | error = path_with_deleted(path, &tmp, &res, &buflen); | 2611 | error = path_with_deleted(path, &tmp, &res, &buflen); |
2082 | if (error) | 2612 | if (error) |
2083 | res = ERR_PTR(error); | 2613 | res = ERR_PTR(error); |
2084 | spin_unlock(&dcache_lock); | 2614 | write_sequnlock(&rename_lock); |
2085 | path_put(&root); | 2615 | path_put(&root); |
2086 | return res; | 2616 | return res; |
2087 | } | 2617 | } |
@@ -2107,12 +2637,12 @@ char *d_path_with_unreachable(const struct path *path, char *buf, int buflen) | |||
2107 | return path->dentry->d_op->d_dname(path->dentry, buf, buflen); | 2637 | return path->dentry->d_op->d_dname(path->dentry, buf, buflen); |
2108 | 2638 | ||
2109 | get_fs_root(current->fs, &root); | 2639 | get_fs_root(current->fs, &root); |
2110 | spin_lock(&dcache_lock); | 2640 | write_seqlock(&rename_lock); |
2111 | tmp = root; | 2641 | tmp = root; |
2112 | error = path_with_deleted(path, &tmp, &res, &buflen); | 2642 | error = path_with_deleted(path, &tmp, &res, &buflen); |
2113 | if (!error && !path_equal(&tmp, &root)) | 2643 | if (!error && !path_equal(&tmp, &root)) |
2114 | error = prepend_unreachable(&res, &buflen); | 2644 | error = prepend_unreachable(&res, &buflen); |
2115 | spin_unlock(&dcache_lock); | 2645 | write_sequnlock(&rename_lock); |
2116 | path_put(&root); | 2646 | path_put(&root); |
2117 | if (error) | 2647 | if (error) |
2118 | res = ERR_PTR(error); | 2648 | res = ERR_PTR(error); |
@@ -2144,7 +2674,7 @@ char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen, | |||
2144 | /* | 2674 | /* |
2145 | * Write full pathname from the root of the filesystem into the buffer. | 2675 | * Write full pathname from the root of the filesystem into the buffer. |
2146 | */ | 2676 | */ |
2147 | char *__dentry_path(struct dentry *dentry, char *buf, int buflen) | 2677 | static char *__dentry_path(struct dentry *dentry, char *buf, int buflen) |
2148 | { | 2678 | { |
2149 | char *end = buf + buflen; | 2679 | char *end = buf + buflen; |
2150 | char *retval; | 2680 | char *retval; |
@@ -2158,10 +2688,13 @@ char *__dentry_path(struct dentry *dentry, char *buf, int buflen) | |||
2158 | 2688 | ||
2159 | while (!IS_ROOT(dentry)) { | 2689 | while (!IS_ROOT(dentry)) { |
2160 | struct dentry *parent = dentry->d_parent; | 2690 | struct dentry *parent = dentry->d_parent; |
2691 | int error; | ||
2161 | 2692 | ||
2162 | prefetch(parent); | 2693 | prefetch(parent); |
2163 | if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) || | 2694 | spin_lock(&dentry->d_lock); |
2164 | (prepend(&end, &buflen, "/", 1) != 0)) | 2695 | error = prepend_name(&end, &buflen, &dentry->d_name); |
2696 | spin_unlock(&dentry->d_lock); | ||
2697 | if (error != 0 || prepend(&end, &buflen, "/", 1) != 0) | ||
2165 | goto Elong; | 2698 | goto Elong; |
2166 | 2699 | ||
2167 | retval = end; | 2700 | retval = end; |
@@ -2171,14 +2704,25 @@ char *__dentry_path(struct dentry *dentry, char *buf, int buflen) | |||
2171 | Elong: | 2704 | Elong: |
2172 | return ERR_PTR(-ENAMETOOLONG); | 2705 | return ERR_PTR(-ENAMETOOLONG); |
2173 | } | 2706 | } |
2174 | EXPORT_SYMBOL(__dentry_path); | 2707 | |
2708 | char *dentry_path_raw(struct dentry *dentry, char *buf, int buflen) | ||
2709 | { | ||
2710 | char *retval; | ||
2711 | |||
2712 | write_seqlock(&rename_lock); | ||
2713 | retval = __dentry_path(dentry, buf, buflen); | ||
2714 | write_sequnlock(&rename_lock); | ||
2715 | |||
2716 | return retval; | ||
2717 | } | ||
2718 | EXPORT_SYMBOL(dentry_path_raw); | ||
2175 | 2719 | ||
2176 | char *dentry_path(struct dentry *dentry, char *buf, int buflen) | 2720 | char *dentry_path(struct dentry *dentry, char *buf, int buflen) |
2177 | { | 2721 | { |
2178 | char *p = NULL; | 2722 | char *p = NULL; |
2179 | char *retval; | 2723 | char *retval; |
2180 | 2724 | ||
2181 | spin_lock(&dcache_lock); | 2725 | write_seqlock(&rename_lock); |
2182 | if (d_unlinked(dentry)) { | 2726 | if (d_unlinked(dentry)) { |
2183 | p = buf + buflen; | 2727 | p = buf + buflen; |
2184 | if (prepend(&p, &buflen, "//deleted", 10) != 0) | 2728 | if (prepend(&p, &buflen, "//deleted", 10) != 0) |
@@ -2186,12 +2730,11 @@ char *dentry_path(struct dentry *dentry, char *buf, int buflen) | |||
2186 | buflen++; | 2730 | buflen++; |
2187 | } | 2731 | } |
2188 | retval = __dentry_path(dentry, buf, buflen); | 2732 | retval = __dentry_path(dentry, buf, buflen); |
2189 | spin_unlock(&dcache_lock); | 2733 | write_sequnlock(&rename_lock); |
2190 | if (!IS_ERR(retval) && p) | 2734 | if (!IS_ERR(retval) && p) |
2191 | *p = '/'; /* restore '/' overriden with '\0' */ | 2735 | *p = '/'; /* restore '/' overriden with '\0' */ |
2192 | return retval; | 2736 | return retval; |
2193 | Elong: | 2737 | Elong: |
2194 | spin_unlock(&dcache_lock); | ||
2195 | return ERR_PTR(-ENAMETOOLONG); | 2738 | return ERR_PTR(-ENAMETOOLONG); |
2196 | } | 2739 | } |
2197 | 2740 | ||
@@ -2225,7 +2768,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) | |||
2225 | get_fs_root_and_pwd(current->fs, &root, &pwd); | 2768 | get_fs_root_and_pwd(current->fs, &root, &pwd); |
2226 | 2769 | ||
2227 | error = -ENOENT; | 2770 | error = -ENOENT; |
2228 | spin_lock(&dcache_lock); | 2771 | write_seqlock(&rename_lock); |
2229 | if (!d_unlinked(pwd.dentry)) { | 2772 | if (!d_unlinked(pwd.dentry)) { |
2230 | unsigned long len; | 2773 | unsigned long len; |
2231 | struct path tmp = root; | 2774 | struct path tmp = root; |
@@ -2234,7 +2777,7 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) | |||
2234 | 2777 | ||
2235 | prepend(&cwd, &buflen, "\0", 1); | 2778 | prepend(&cwd, &buflen, "\0", 1); |
2236 | error = prepend_path(&pwd, &tmp, &cwd, &buflen); | 2779 | error = prepend_path(&pwd, &tmp, &cwd, &buflen); |
2237 | spin_unlock(&dcache_lock); | 2780 | write_sequnlock(&rename_lock); |
2238 | 2781 | ||
2239 | if (error) | 2782 | if (error) |
2240 | goto out; | 2783 | goto out; |
@@ -2253,8 +2796,9 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) | |||
2253 | if (copy_to_user(buf, cwd, len)) | 2796 | if (copy_to_user(buf, cwd, len)) |
2254 | error = -EFAULT; | 2797 | error = -EFAULT; |
2255 | } | 2798 | } |
2256 | } else | 2799 | } else { |
2257 | spin_unlock(&dcache_lock); | 2800 | write_sequnlock(&rename_lock); |
2801 | } | ||
2258 | 2802 | ||
2259 | out: | 2803 | out: |
2260 | path_put(&pwd); | 2804 | path_put(&pwd); |
@@ -2282,25 +2826,25 @@ out: | |||
2282 | int is_subdir(struct dentry *new_dentry, struct dentry *old_dentry) | 2826 | int is_subdir(struct dentry *new_dentry, struct dentry *old_dentry) |
2283 | { | 2827 | { |
2284 | int result; | 2828 | int result; |
2285 | unsigned long seq; | 2829 | unsigned seq; |
2286 | 2830 | ||
2287 | if (new_dentry == old_dentry) | 2831 | if (new_dentry == old_dentry) |
2288 | return 1; | 2832 | return 1; |
2289 | 2833 | ||
2290 | /* | ||
2291 | * Need rcu_readlock to protect against the d_parent trashing | ||
2292 | * due to d_move | ||
2293 | */ | ||
2294 | rcu_read_lock(); | ||
2295 | do { | 2834 | do { |
2296 | /* for restarting inner loop in case of seq retry */ | 2835 | /* for restarting inner loop in case of seq retry */ |
2297 | seq = read_seqbegin(&rename_lock); | 2836 | seq = read_seqbegin(&rename_lock); |
2837 | /* | ||
2838 | * Need rcu_readlock to protect against the d_parent trashing | ||
2839 | * due to d_move | ||
2840 | */ | ||
2841 | rcu_read_lock(); | ||
2298 | if (d_ancestor(old_dentry, new_dentry)) | 2842 | if (d_ancestor(old_dentry, new_dentry)) |
2299 | result = 1; | 2843 | result = 1; |
2300 | else | 2844 | else |
2301 | result = 0; | 2845 | result = 0; |
2846 | rcu_read_unlock(); | ||
2302 | } while (read_seqretry(&rename_lock, seq)); | 2847 | } while (read_seqretry(&rename_lock, seq)); |
2303 | rcu_read_unlock(); | ||
2304 | 2848 | ||
2305 | return result; | 2849 | return result; |
2306 | } | 2850 | } |
@@ -2332,10 +2876,15 @@ EXPORT_SYMBOL(path_is_under); | |||
2332 | 2876 | ||
2333 | void d_genocide(struct dentry *root) | 2877 | void d_genocide(struct dentry *root) |
2334 | { | 2878 | { |
2335 | struct dentry *this_parent = root; | 2879 | struct dentry *this_parent; |
2336 | struct list_head *next; | 2880 | struct list_head *next; |
2881 | unsigned seq; | ||
2882 | int locked = 0; | ||
2337 | 2883 | ||
2338 | spin_lock(&dcache_lock); | 2884 | seq = read_seqbegin(&rename_lock); |
2885 | again: | ||
2886 | this_parent = root; | ||
2887 | spin_lock(&this_parent->d_lock); | ||
2339 | repeat: | 2888 | repeat: |
2340 | next = this_parent->d_subdirs.next; | 2889 | next = this_parent->d_subdirs.next; |
2341 | resume: | 2890 | resume: |
@@ -2343,21 +2892,62 @@ resume: | |||
2343 | struct list_head *tmp = next; | 2892 | struct list_head *tmp = next; |
2344 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); | 2893 | struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); |
2345 | next = tmp->next; | 2894 | next = tmp->next; |
2346 | if (d_unhashed(dentry)||!dentry->d_inode) | 2895 | |
2896 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | ||
2897 | if (d_unhashed(dentry) || !dentry->d_inode) { | ||
2898 | spin_unlock(&dentry->d_lock); | ||
2347 | continue; | 2899 | continue; |
2900 | } | ||
2348 | if (!list_empty(&dentry->d_subdirs)) { | 2901 | if (!list_empty(&dentry->d_subdirs)) { |
2902 | spin_unlock(&this_parent->d_lock); | ||
2903 | spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_); | ||
2349 | this_parent = dentry; | 2904 | this_parent = dentry; |
2905 | spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_); | ||
2350 | goto repeat; | 2906 | goto repeat; |
2351 | } | 2907 | } |
2352 | atomic_dec(&dentry->d_count); | 2908 | if (!(dentry->d_flags & DCACHE_GENOCIDE)) { |
2909 | dentry->d_flags |= DCACHE_GENOCIDE; | ||
2910 | dentry->d_count--; | ||
2911 | } | ||
2912 | spin_unlock(&dentry->d_lock); | ||
2353 | } | 2913 | } |
2354 | if (this_parent != root) { | 2914 | if (this_parent != root) { |
2355 | next = this_parent->d_u.d_child.next; | 2915 | struct dentry *tmp; |
2356 | atomic_dec(&this_parent->d_count); | 2916 | struct dentry *child; |
2357 | this_parent = this_parent->d_parent; | 2917 | |
2918 | tmp = this_parent->d_parent; | ||
2919 | if (!(this_parent->d_flags & DCACHE_GENOCIDE)) { | ||
2920 | this_parent->d_flags |= DCACHE_GENOCIDE; | ||
2921 | this_parent->d_count--; | ||
2922 | } | ||
2923 | rcu_read_lock(); | ||
2924 | spin_unlock(&this_parent->d_lock); | ||
2925 | child = this_parent; | ||
2926 | this_parent = tmp; | ||
2927 | spin_lock(&this_parent->d_lock); | ||
2928 | /* might go back up the wrong parent if we have had a rename | ||
2929 | * or deletion */ | ||
2930 | if (this_parent != child->d_parent || | ||
2931 | (!locked && read_seqretry(&rename_lock, seq))) { | ||
2932 | spin_unlock(&this_parent->d_lock); | ||
2933 | rcu_read_unlock(); | ||
2934 | goto rename_retry; | ||
2935 | } | ||
2936 | rcu_read_unlock(); | ||
2937 | next = child->d_u.d_child.next; | ||
2358 | goto resume; | 2938 | goto resume; |
2359 | } | 2939 | } |
2360 | spin_unlock(&dcache_lock); | 2940 | spin_unlock(&this_parent->d_lock); |
2941 | if (!locked && read_seqretry(&rename_lock, seq)) | ||
2942 | goto rename_retry; | ||
2943 | if (locked) | ||
2944 | write_sequnlock(&rename_lock); | ||
2945 | return; | ||
2946 | |||
2947 | rename_retry: | ||
2948 | locked = 1; | ||
2949 | write_seqlock(&rename_lock); | ||
2950 | goto again; | ||
2361 | } | 2951 | } |
2362 | 2952 | ||
2363 | /** | 2953 | /** |
@@ -2411,7 +3001,7 @@ static void __init dcache_init_early(void) | |||
2411 | 3001 | ||
2412 | dentry_hashtable = | 3002 | dentry_hashtable = |
2413 | alloc_large_system_hash("Dentry cache", | 3003 | alloc_large_system_hash("Dentry cache", |
2414 | sizeof(struct hlist_head), | 3004 | sizeof(struct dcache_hash_bucket), |
2415 | dhash_entries, | 3005 | dhash_entries, |
2416 | 13, | 3006 | 13, |
2417 | HASH_EARLY, | 3007 | HASH_EARLY, |
@@ -2420,16 +3010,13 @@ static void __init dcache_init_early(void) | |||
2420 | 0); | 3010 | 0); |
2421 | 3011 | ||
2422 | for (loop = 0; loop < (1 << d_hash_shift); loop++) | 3012 | for (loop = 0; loop < (1 << d_hash_shift); loop++) |
2423 | INIT_HLIST_HEAD(&dentry_hashtable[loop]); | 3013 | INIT_HLIST_BL_HEAD(&dentry_hashtable[loop].head); |
2424 | } | 3014 | } |
2425 | 3015 | ||
2426 | static void __init dcache_init(void) | 3016 | static void __init dcache_init(void) |
2427 | { | 3017 | { |
2428 | int loop; | 3018 | int loop; |
2429 | 3019 | ||
2430 | percpu_counter_init(&nr_dentry, 0); | ||
2431 | percpu_counter_init(&nr_dentry_unused, 0); | ||
2432 | |||
2433 | /* | 3020 | /* |
2434 | * A constructor could be added for stable state like the lists, | 3021 | * A constructor could be added for stable state like the lists, |
2435 | * but it is probably not worth it because of the cache nature | 3022 | * but it is probably not worth it because of the cache nature |
@@ -2446,7 +3033,7 @@ static void __init dcache_init(void) | |||
2446 | 3033 | ||
2447 | dentry_hashtable = | 3034 | dentry_hashtable = |
2448 | alloc_large_system_hash("Dentry cache", | 3035 | alloc_large_system_hash("Dentry cache", |
2449 | sizeof(struct hlist_head), | 3036 | sizeof(struct dcache_hash_bucket), |
2450 | dhash_entries, | 3037 | dhash_entries, |
2451 | 13, | 3038 | 13, |
2452 | 0, | 3039 | 0, |
@@ -2455,7 +3042,7 @@ static void __init dcache_init(void) | |||
2455 | 0); | 3042 | 0); |
2456 | 3043 | ||
2457 | for (loop = 0; loop < (1 << d_hash_shift); loop++) | 3044 | for (loop = 0; loop < (1 << d_hash_shift); loop++) |
2458 | INIT_HLIST_HEAD(&dentry_hashtable[loop]); | 3045 | INIT_HLIST_BL_HEAD(&dentry_hashtable[loop].head); |
2459 | } | 3046 | } |
2460 | 3047 | ||
2461 | /* SLAB cache for __getname() consumers */ | 3048 | /* SLAB cache for __getname() consumers */ |
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index 37a34c2c622a..9c64ae9e4c1a 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c | |||
@@ -63,6 +63,9 @@ | |||
63 | #define NEEDED_RMEM (4*1024*1024) | 63 | #define NEEDED_RMEM (4*1024*1024) |
64 | #define CONN_HASH_SIZE 32 | 64 | #define CONN_HASH_SIZE 32 |
65 | 65 | ||
66 | /* Number of messages to send before rescheduling */ | ||
67 | #define MAX_SEND_MSG_COUNT 25 | ||
68 | |||
66 | struct cbuf { | 69 | struct cbuf { |
67 | unsigned int base; | 70 | unsigned int base; |
68 | unsigned int len; | 71 | unsigned int len; |
@@ -108,6 +111,7 @@ struct connection { | |||
108 | #define CF_INIT_PENDING 4 | 111 | #define CF_INIT_PENDING 4 |
109 | #define CF_IS_OTHERCON 5 | 112 | #define CF_IS_OTHERCON 5 |
110 | #define CF_CLOSE 6 | 113 | #define CF_CLOSE 6 |
114 | #define CF_APP_LIMITED 7 | ||
111 | struct list_head writequeue; /* List of outgoing writequeue_entries */ | 115 | struct list_head writequeue; /* List of outgoing writequeue_entries */ |
112 | spinlock_t writequeue_lock; | 116 | spinlock_t writequeue_lock; |
113 | int (*rx_action) (struct connection *); /* What to do when active */ | 117 | int (*rx_action) (struct connection *); /* What to do when active */ |
@@ -295,7 +299,17 @@ static void lowcomms_write_space(struct sock *sk) | |||
295 | { | 299 | { |
296 | struct connection *con = sock2con(sk); | 300 | struct connection *con = sock2con(sk); |
297 | 301 | ||
298 | if (con && !test_and_set_bit(CF_WRITE_PENDING, &con->flags)) | 302 | if (!con) |
303 | return; | ||
304 | |||
305 | clear_bit(SOCK_NOSPACE, &con->sock->flags); | ||
306 | |||
307 | if (test_and_clear_bit(CF_APP_LIMITED, &con->flags)) { | ||
308 | con->sock->sk->sk_write_pending--; | ||
309 | clear_bit(SOCK_ASYNC_NOSPACE, &con->sock->flags); | ||
310 | } | ||
311 | |||
312 | if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) | ||
299 | queue_work(send_workqueue, &con->swork); | 313 | queue_work(send_workqueue, &con->swork); |
300 | } | 314 | } |
301 | 315 | ||
@@ -915,6 +929,7 @@ static void tcp_connect_to_sock(struct connection *con) | |||
915 | struct sockaddr_storage saddr, src_addr; | 929 | struct sockaddr_storage saddr, src_addr; |
916 | int addr_len; | 930 | int addr_len; |
917 | struct socket *sock = NULL; | 931 | struct socket *sock = NULL; |
932 | int one = 1; | ||
918 | 933 | ||
919 | if (con->nodeid == 0) { | 934 | if (con->nodeid == 0) { |
920 | log_print("attempt to connect sock 0 foiled"); | 935 | log_print("attempt to connect sock 0 foiled"); |
@@ -960,6 +975,11 @@ static void tcp_connect_to_sock(struct connection *con) | |||
960 | make_sockaddr(&saddr, dlm_config.ci_tcp_port, &addr_len); | 975 | make_sockaddr(&saddr, dlm_config.ci_tcp_port, &addr_len); |
961 | 976 | ||
962 | log_print("connecting to %d", con->nodeid); | 977 | log_print("connecting to %d", con->nodeid); |
978 | |||
979 | /* Turn off Nagle's algorithm */ | ||
980 | kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&one, | ||
981 | sizeof(one)); | ||
982 | |||
963 | result = | 983 | result = |
964 | sock->ops->connect(sock, (struct sockaddr *)&saddr, addr_len, | 984 | sock->ops->connect(sock, (struct sockaddr *)&saddr, addr_len, |
965 | O_NONBLOCK); | 985 | O_NONBLOCK); |
@@ -1011,6 +1031,10 @@ static struct socket *tcp_create_listen_sock(struct connection *con, | |||
1011 | goto create_out; | 1031 | goto create_out; |
1012 | } | 1032 | } |
1013 | 1033 | ||
1034 | /* Turn off Nagle's algorithm */ | ||
1035 | kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&one, | ||
1036 | sizeof(one)); | ||
1037 | |||
1014 | result = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, | 1038 | result = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, |
1015 | (char *)&one, sizeof(one)); | 1039 | (char *)&one, sizeof(one)); |
1016 | 1040 | ||
@@ -1297,6 +1321,7 @@ static void send_to_sock(struct connection *con) | |||
1297 | const int msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; | 1321 | const int msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL; |
1298 | struct writequeue_entry *e; | 1322 | struct writequeue_entry *e; |
1299 | int len, offset; | 1323 | int len, offset; |
1324 | int count = 0; | ||
1300 | 1325 | ||
1301 | mutex_lock(&con->sock_mutex); | 1326 | mutex_lock(&con->sock_mutex); |
1302 | if (con->sock == NULL) | 1327 | if (con->sock == NULL) |
@@ -1319,14 +1344,27 @@ static void send_to_sock(struct connection *con) | |||
1319 | ret = kernel_sendpage(con->sock, e->page, offset, len, | 1344 | ret = kernel_sendpage(con->sock, e->page, offset, len, |
1320 | msg_flags); | 1345 | msg_flags); |
1321 | if (ret == -EAGAIN || ret == 0) { | 1346 | if (ret == -EAGAIN || ret == 0) { |
1347 | if (ret == -EAGAIN && | ||
1348 | test_bit(SOCK_ASYNC_NOSPACE, &con->sock->flags) && | ||
1349 | !test_and_set_bit(CF_APP_LIMITED, &con->flags)) { | ||
1350 | /* Notify TCP that we're limited by the | ||
1351 | * application window size. | ||
1352 | */ | ||
1353 | set_bit(SOCK_NOSPACE, &con->sock->flags); | ||
1354 | con->sock->sk->sk_write_pending++; | ||
1355 | } | ||
1322 | cond_resched(); | 1356 | cond_resched(); |
1323 | goto out; | 1357 | goto out; |
1324 | } | 1358 | } |
1325 | if (ret <= 0) | 1359 | if (ret <= 0) |
1326 | goto send_error; | 1360 | goto send_error; |
1327 | } | 1361 | } |
1328 | /* Don't starve people filling buffers */ | 1362 | |
1363 | /* Don't starve people filling buffers */ | ||
1364 | if (++count >= MAX_SEND_MSG_COUNT) { | ||
1329 | cond_resched(); | 1365 | cond_resched(); |
1366 | count = 0; | ||
1367 | } | ||
1330 | 1368 | ||
1331 | spin_lock(&con->writequeue_lock); | 1369 | spin_lock(&con->writequeue_lock); |
1332 | e->offset += ret; | 1370 | e->offset += ret; |
@@ -1430,20 +1468,19 @@ static void work_stop(void) | |||
1430 | 1468 | ||
1431 | static int work_start(void) | 1469 | static int work_start(void) |
1432 | { | 1470 | { |
1433 | int error; | 1471 | recv_workqueue = alloc_workqueue("dlm_recv", WQ_MEM_RECLAIM | |
1434 | recv_workqueue = create_workqueue("dlm_recv"); | 1472 | WQ_HIGHPRI | WQ_FREEZEABLE, 0); |
1435 | error = IS_ERR(recv_workqueue); | 1473 | if (!recv_workqueue) { |
1436 | if (error) { | 1474 | log_print("can't start dlm_recv"); |
1437 | log_print("can't start dlm_recv %d", error); | 1475 | return -ENOMEM; |
1438 | return error; | ||
1439 | } | 1476 | } |
1440 | 1477 | ||
1441 | send_workqueue = create_singlethread_workqueue("dlm_send"); | 1478 | send_workqueue = alloc_workqueue("dlm_send", WQ_MEM_RECLAIM | |
1442 | error = IS_ERR(send_workqueue); | 1479 | WQ_HIGHPRI | WQ_FREEZEABLE, 0); |
1443 | if (error) { | 1480 | if (!send_workqueue) { |
1444 | log_print("can't start dlm_send %d", error); | 1481 | log_print("can't start dlm_send"); |
1445 | destroy_workqueue(recv_workqueue); | 1482 | destroy_workqueue(recv_workqueue); |
1446 | return error; | 1483 | return -ENOMEM; |
1447 | } | 1484 | } |
1448 | 1485 | ||
1449 | return 0; | 1486 | return 0; |
diff --git a/fs/ecryptfs/dentry.c b/fs/ecryptfs/dentry.c index 906e803f7f79..6fc4f319b550 100644 --- a/fs/ecryptfs/dentry.c +++ b/fs/ecryptfs/dentry.c | |||
@@ -44,12 +44,17 @@ | |||
44 | */ | 44 | */ |
45 | static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd) | 45 | static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd) |
46 | { | 46 | { |
47 | struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); | 47 | struct dentry *lower_dentry; |
48 | struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); | 48 | struct vfsmount *lower_mnt; |
49 | struct dentry *dentry_save; | 49 | struct dentry *dentry_save; |
50 | struct vfsmount *vfsmount_save; | 50 | struct vfsmount *vfsmount_save; |
51 | int rc = 1; | 51 | int rc = 1; |
52 | 52 | ||
53 | if (nd->flags & LOOKUP_RCU) | ||
54 | return -ECHILD; | ||
55 | |||
56 | lower_dentry = ecryptfs_dentry_to_lower(dentry); | ||
57 | lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry); | ||
53 | if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate) | 58 | if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate) |
54 | goto out; | 59 | goto out; |
55 | dentry_save = nd->path.dentry; | 60 | dentry_save = nd->path.dentry; |
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 9d1a22d62765..337352a94751 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c | |||
@@ -260,7 +260,7 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, | |||
260 | ecryptfs_dentry->d_parent)); | 260 | ecryptfs_dentry->d_parent)); |
261 | lower_inode = lower_dentry->d_inode; | 261 | lower_inode = lower_dentry->d_inode; |
262 | fsstack_copy_attr_atime(ecryptfs_dir_inode, lower_dir_dentry->d_inode); | 262 | fsstack_copy_attr_atime(ecryptfs_dir_inode, lower_dir_dentry->d_inode); |
263 | BUG_ON(!atomic_read(&lower_dentry->d_count)); | 263 | BUG_ON(!lower_dentry->d_count); |
264 | ecryptfs_set_dentry_private(ecryptfs_dentry, | 264 | ecryptfs_set_dentry_private(ecryptfs_dentry, |
265 | kmem_cache_alloc(ecryptfs_dentry_info_cache, | 265 | kmem_cache_alloc(ecryptfs_dentry_info_cache, |
266 | GFP_KERNEL)); | 266 | GFP_KERNEL)); |
@@ -441,7 +441,7 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, | |||
441 | struct qstr lower_name; | 441 | struct qstr lower_name; |
442 | int rc = 0; | 442 | int rc = 0; |
443 | 443 | ||
444 | ecryptfs_dentry->d_op = &ecryptfs_dops; | 444 | d_set_d_op(ecryptfs_dentry, &ecryptfs_dops); |
445 | if ((ecryptfs_dentry->d_name.len == 1 | 445 | if ((ecryptfs_dentry->d_name.len == 1 |
446 | && !strcmp(ecryptfs_dentry->d_name.name, ".")) | 446 | && !strcmp(ecryptfs_dentry->d_name.name, ".")) |
447 | || (ecryptfs_dentry->d_name.len == 2 | 447 | || (ecryptfs_dentry->d_name.len == 2 |
@@ -454,7 +454,7 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, | |||
454 | lower_name.hash = ecryptfs_dentry->d_name.hash; | 454 | lower_name.hash = ecryptfs_dentry->d_name.hash; |
455 | if (lower_dir_dentry->d_op && lower_dir_dentry->d_op->d_hash) { | 455 | if (lower_dir_dentry->d_op && lower_dir_dentry->d_op->d_hash) { |
456 | rc = lower_dir_dentry->d_op->d_hash(lower_dir_dentry, | 456 | rc = lower_dir_dentry->d_op->d_hash(lower_dir_dentry, |
457 | &lower_name); | 457 | lower_dir_dentry->d_inode, &lower_name); |
458 | if (rc < 0) | 458 | if (rc < 0) |
459 | goto out_d_drop; | 459 | goto out_d_drop; |
460 | } | 460 | } |
@@ -489,7 +489,7 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, | |||
489 | lower_name.hash = full_name_hash(lower_name.name, lower_name.len); | 489 | lower_name.hash = full_name_hash(lower_name.name, lower_name.len); |
490 | if (lower_dir_dentry->d_op && lower_dir_dentry->d_op->d_hash) { | 490 | if (lower_dir_dentry->d_op && lower_dir_dentry->d_op->d_hash) { |
491 | rc = lower_dir_dentry->d_op->d_hash(lower_dir_dentry, | 491 | rc = lower_dir_dentry->d_op->d_hash(lower_dir_dentry, |
492 | &lower_name); | 492 | lower_dir_dentry->d_inode, &lower_name); |
493 | if (rc < 0) | 493 | if (rc < 0) |
494 | goto out_d_drop; | 494 | goto out_d_drop; |
495 | } | 495 | } |
@@ -980,8 +980,10 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) | |||
980 | } | 980 | } |
981 | 981 | ||
982 | static int | 982 | static int |
983 | ecryptfs_permission(struct inode *inode, int mask) | 983 | ecryptfs_permission(struct inode *inode, int mask, unsigned int flags) |
984 | { | 984 | { |
985 | if (flags & IPERM_FLAG_RCU) | ||
986 | return -ECHILD; | ||
985 | return inode_permission(ecryptfs_inode_to_lower(inode), mask); | 987 | return inode_permission(ecryptfs_inode_to_lower(inode), mask); |
986 | } | 988 | } |
987 | 989 | ||
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index a9dbd62518e6..351038675376 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c | |||
@@ -189,7 +189,7 @@ int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry, | |||
189 | if (special_file(lower_inode->i_mode)) | 189 | if (special_file(lower_inode->i_mode)) |
190 | init_special_inode(inode, lower_inode->i_mode, | 190 | init_special_inode(inode, lower_inode->i_mode, |
191 | lower_inode->i_rdev); | 191 | lower_inode->i_rdev); |
192 | dentry->d_op = &ecryptfs_dops; | 192 | d_set_d_op(dentry, &ecryptfs_dops); |
193 | fsstack_copy_attr_all(inode, lower_inode); | 193 | fsstack_copy_attr_all(inode, lower_inode); |
194 | /* This size will be overwritten for real files w/ headers and | 194 | /* This size will be overwritten for real files w/ headers and |
195 | * other metadata */ | 195 | * other metadata */ |
@@ -594,7 +594,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags | |||
594 | deactivate_locked_super(s); | 594 | deactivate_locked_super(s); |
595 | goto out; | 595 | goto out; |
596 | } | 596 | } |
597 | s->s_root->d_op = &ecryptfs_dops; | 597 | d_set_d_op(s->s_root, &ecryptfs_dops); |
598 | s->s_root->d_sb = s; | 598 | s->s_root->d_sb = s; |
599 | s->s_root->d_parent = s->s_root; | 599 | s->s_root->d_parent = s->s_root; |
600 | 600 | ||
diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c index 2720178b7718..3042fe123a34 100644 --- a/fs/ecryptfs/super.c +++ b/fs/ecryptfs/super.c | |||
@@ -62,6 +62,16 @@ out: | |||
62 | return inode; | 62 | return inode; |
63 | } | 63 | } |
64 | 64 | ||
65 | static void ecryptfs_i_callback(struct rcu_head *head) | ||
66 | { | ||
67 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
68 | struct ecryptfs_inode_info *inode_info; | ||
69 | inode_info = ecryptfs_inode_to_private(inode); | ||
70 | |||
71 | INIT_LIST_HEAD(&inode->i_dentry); | ||
72 | kmem_cache_free(ecryptfs_inode_info_cache, inode_info); | ||
73 | } | ||
74 | |||
65 | /** | 75 | /** |
66 | * ecryptfs_destroy_inode | 76 | * ecryptfs_destroy_inode |
67 | * @inode: The ecryptfs inode | 77 | * @inode: The ecryptfs inode |
@@ -88,7 +98,7 @@ static void ecryptfs_destroy_inode(struct inode *inode) | |||
88 | } | 98 | } |
89 | } | 99 | } |
90 | ecryptfs_destroy_crypt_stat(&inode_info->crypt_stat); | 100 | ecryptfs_destroy_crypt_stat(&inode_info->crypt_stat); |
91 | kmem_cache_free(ecryptfs_inode_info_cache, inode_info); | 101 | call_rcu(&inode->i_rcu, ecryptfs_i_callback); |
92 | } | 102 | } |
93 | 103 | ||
94 | /** | 104 | /** |
diff --git a/fs/efs/super.c b/fs/efs/super.c index 5073a07652cc..0f31acb0131c 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c | |||
@@ -65,11 +65,18 @@ static struct inode *efs_alloc_inode(struct super_block *sb) | |||
65 | return &ei->vfs_inode; | 65 | return &ei->vfs_inode; |
66 | } | 66 | } |
67 | 67 | ||
68 | static void efs_destroy_inode(struct inode *inode) | 68 | static void efs_i_callback(struct rcu_head *head) |
69 | { | 69 | { |
70 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
71 | INIT_LIST_HEAD(&inode->i_dentry); | ||
70 | kmem_cache_free(efs_inode_cachep, INODE_INFO(inode)); | 72 | kmem_cache_free(efs_inode_cachep, INODE_INFO(inode)); |
71 | } | 73 | } |
72 | 74 | ||
75 | static void efs_destroy_inode(struct inode *inode) | ||
76 | { | ||
77 | call_rcu(&inode->i_rcu, efs_i_callback); | ||
78 | } | ||
79 | |||
73 | static void init_once(void *foo) | 80 | static void init_once(void *foo) |
74 | { | 81 | { |
75 | struct efs_inode_info *ei = (struct efs_inode_info *) foo; | 82 | struct efs_inode_info *ei = (struct efs_inode_info *) foo; |
@@ -275,6 +275,11 @@ static int __bprm_mm_init(struct linux_binprm *bprm) | |||
275 | vma->vm_flags = VM_STACK_FLAGS | VM_STACK_INCOMPLETE_SETUP; | 275 | vma->vm_flags = VM_STACK_FLAGS | VM_STACK_INCOMPLETE_SETUP; |
276 | vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); | 276 | vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); |
277 | INIT_LIST_HEAD(&vma->anon_vma_chain); | 277 | INIT_LIST_HEAD(&vma->anon_vma_chain); |
278 | |||
279 | err = security_file_mmap(NULL, 0, 0, 0, vma->vm_start, 1); | ||
280 | if (err) | ||
281 | goto err; | ||
282 | |||
278 | err = insert_vm_struct(mm, vma); | 283 | err = insert_vm_struct(mm, vma); |
279 | if (err) | 284 | if (err) |
280 | goto err; | 285 | goto err; |
diff --git a/fs/exofs/super.c b/fs/exofs/super.c index 79c3ae6e0456..8c6c4669b381 100644 --- a/fs/exofs/super.c +++ b/fs/exofs/super.c | |||
@@ -150,12 +150,19 @@ static struct inode *exofs_alloc_inode(struct super_block *sb) | |||
150 | return &oi->vfs_inode; | 150 | return &oi->vfs_inode; |
151 | } | 151 | } |
152 | 152 | ||
153 | static void exofs_i_callback(struct rcu_head *head) | ||
154 | { | ||
155 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
156 | INIT_LIST_HEAD(&inode->i_dentry); | ||
157 | kmem_cache_free(exofs_inode_cachep, exofs_i(inode)); | ||
158 | } | ||
159 | |||
153 | /* | 160 | /* |
154 | * Remove an inode from the cache | 161 | * Remove an inode from the cache |
155 | */ | 162 | */ |
156 | static void exofs_destroy_inode(struct inode *inode) | 163 | static void exofs_destroy_inode(struct inode *inode) |
157 | { | 164 | { |
158 | kmem_cache_free(exofs_inode_cachep, exofs_i(inode)); | 165 | call_rcu(&inode->i_rcu, exofs_i_callback); |
159 | } | 166 | } |
160 | 167 | ||
161 | /* | 168 | /* |
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index 51b304056f10..4b6825740dd5 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c | |||
@@ -43,24 +43,26 @@ find_acceptable_alias(struct dentry *result, | |||
43 | void *context) | 43 | void *context) |
44 | { | 44 | { |
45 | struct dentry *dentry, *toput = NULL; | 45 | struct dentry *dentry, *toput = NULL; |
46 | struct inode *inode; | ||
46 | 47 | ||
47 | if (acceptable(context, result)) | 48 | if (acceptable(context, result)) |
48 | return result; | 49 | return result; |
49 | 50 | ||
50 | spin_lock(&dcache_lock); | 51 | inode = result->d_inode; |
51 | list_for_each_entry(dentry, &result->d_inode->i_dentry, d_alias) { | 52 | spin_lock(&inode->i_lock); |
52 | dget_locked(dentry); | 53 | list_for_each_entry(dentry, &inode->i_dentry, d_alias) { |
53 | spin_unlock(&dcache_lock); | 54 | dget(dentry); |
55 | spin_unlock(&inode->i_lock); | ||
54 | if (toput) | 56 | if (toput) |
55 | dput(toput); | 57 | dput(toput); |
56 | if (dentry != result && acceptable(context, dentry)) { | 58 | if (dentry != result && acceptable(context, dentry)) { |
57 | dput(result); | 59 | dput(result); |
58 | return dentry; | 60 | return dentry; |
59 | } | 61 | } |
60 | spin_lock(&dcache_lock); | 62 | spin_lock(&inode->i_lock); |
61 | toput = dentry; | 63 | toput = dentry; |
62 | } | 64 | } |
63 | spin_unlock(&dcache_lock); | 65 | spin_unlock(&inode->i_lock); |
64 | 66 | ||
65 | if (toput) | 67 | if (toput) |
66 | dput(toput); | 68 | dput(toput); |
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c index 2bcc0431bada..7b4180554a62 100644 --- a/fs/ext2/acl.c +++ b/fs/ext2/acl.c | |||
@@ -232,10 +232,17 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
232 | } | 232 | } |
233 | 233 | ||
234 | int | 234 | int |
235 | ext2_check_acl(struct inode *inode, int mask) | 235 | ext2_check_acl(struct inode *inode, int mask, unsigned int flags) |
236 | { | 236 | { |
237 | struct posix_acl *acl = ext2_get_acl(inode, ACL_TYPE_ACCESS); | 237 | struct posix_acl *acl; |
238 | |||
239 | if (flags & IPERM_FLAG_RCU) { | ||
240 | if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) | ||
241 | return -ECHILD; | ||
242 | return -EAGAIN; | ||
243 | } | ||
238 | 244 | ||
245 | acl = ext2_get_acl(inode, ACL_TYPE_ACCESS); | ||
239 | if (IS_ERR(acl)) | 246 | if (IS_ERR(acl)) |
240 | return PTR_ERR(acl); | 247 | return PTR_ERR(acl); |
241 | if (acl) { | 248 | if (acl) { |
diff --git a/fs/ext2/acl.h b/fs/ext2/acl.h index 3ff6cbb9ac44..c939b7b12099 100644 --- a/fs/ext2/acl.h +++ b/fs/ext2/acl.h | |||
@@ -54,7 +54,7 @@ static inline int ext2_acl_count(size_t size) | |||
54 | #ifdef CONFIG_EXT2_FS_POSIX_ACL | 54 | #ifdef CONFIG_EXT2_FS_POSIX_ACL |
55 | 55 | ||
56 | /* acl.c */ | 56 | /* acl.c */ |
57 | extern int ext2_check_acl (struct inode *, int); | 57 | extern int ext2_check_acl (struct inode *, int, unsigned int); |
58 | extern int ext2_acl_chmod (struct inode *); | 58 | extern int ext2_acl_chmod (struct inode *); |
59 | extern int ext2_init_acl (struct inode *, struct inode *); | 59 | extern int ext2_init_acl (struct inode *, struct inode *); |
60 | 60 | ||
diff --git a/fs/ext2/super.c b/fs/ext2/super.c index d89e0b6a2d78..e0c6380ff992 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c | |||
@@ -161,11 +161,18 @@ static struct inode *ext2_alloc_inode(struct super_block *sb) | |||
161 | return &ei->vfs_inode; | 161 | return &ei->vfs_inode; |
162 | } | 162 | } |
163 | 163 | ||
164 | static void ext2_destroy_inode(struct inode *inode) | 164 | static void ext2_i_callback(struct rcu_head *head) |
165 | { | 165 | { |
166 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
167 | INIT_LIST_HEAD(&inode->i_dentry); | ||
166 | kmem_cache_free(ext2_inode_cachep, EXT2_I(inode)); | 168 | kmem_cache_free(ext2_inode_cachep, EXT2_I(inode)); |
167 | } | 169 | } |
168 | 170 | ||
171 | static void ext2_destroy_inode(struct inode *inode) | ||
172 | { | ||
173 | call_rcu(&inode->i_rcu, ext2_i_callback); | ||
174 | } | ||
175 | |||
169 | static void init_once(void *foo) | 176 | static void init_once(void *foo) |
170 | { | 177 | { |
171 | struct ext2_inode_info *ei = (struct ext2_inode_info *) foo; | 178 | struct ext2_inode_info *ei = (struct ext2_inode_info *) foo; |
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index 8a11fe212183..e4fa49e6c539 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c | |||
@@ -240,10 +240,17 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type, | |||
240 | } | 240 | } |
241 | 241 | ||
242 | int | 242 | int |
243 | ext3_check_acl(struct inode *inode, int mask) | 243 | ext3_check_acl(struct inode *inode, int mask, unsigned int flags) |
244 | { | 244 | { |
245 | struct posix_acl *acl = ext3_get_acl(inode, ACL_TYPE_ACCESS); | 245 | struct posix_acl *acl; |
246 | |||
247 | if (flags & IPERM_FLAG_RCU) { | ||
248 | if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) | ||
249 | return -ECHILD; | ||
250 | return -EAGAIN; | ||
251 | } | ||
246 | 252 | ||
253 | acl = ext3_get_acl(inode, ACL_TYPE_ACCESS); | ||
247 | if (IS_ERR(acl)) | 254 | if (IS_ERR(acl)) |
248 | return PTR_ERR(acl); | 255 | return PTR_ERR(acl); |
249 | if (acl) { | 256 | if (acl) { |
diff --git a/fs/ext3/acl.h b/fs/ext3/acl.h index 597334626de9..5faf8048e906 100644 --- a/fs/ext3/acl.h +++ b/fs/ext3/acl.h | |||
@@ -54,7 +54,7 @@ static inline int ext3_acl_count(size_t size) | |||
54 | #ifdef CONFIG_EXT3_FS_POSIX_ACL | 54 | #ifdef CONFIG_EXT3_FS_POSIX_ACL |
55 | 55 | ||
56 | /* acl.c */ | 56 | /* acl.c */ |
57 | extern int ext3_check_acl (struct inode *, int); | 57 | extern int ext3_check_acl (struct inode *, int, unsigned int); |
58 | extern int ext3_acl_chmod (struct inode *); | 58 | extern int ext3_acl_chmod (struct inode *); |
59 | extern int ext3_init_acl (handle_t *, struct inode *, struct inode *); | 59 | extern int ext3_init_acl (handle_t *, struct inode *, struct inode *); |
60 | 60 | ||
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index acf8695fa8f0..77ce1616f725 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
@@ -479,6 +479,13 @@ static struct inode *ext3_alloc_inode(struct super_block *sb) | |||
479 | return &ei->vfs_inode; | 479 | return &ei->vfs_inode; |
480 | } | 480 | } |
481 | 481 | ||
482 | static void ext3_i_callback(struct rcu_head *head) | ||
483 | { | ||
484 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
485 | INIT_LIST_HEAD(&inode->i_dentry); | ||
486 | kmem_cache_free(ext3_inode_cachep, EXT3_I(inode)); | ||
487 | } | ||
488 | |||
482 | static void ext3_destroy_inode(struct inode *inode) | 489 | static void ext3_destroy_inode(struct inode *inode) |
483 | { | 490 | { |
484 | if (!list_empty(&(EXT3_I(inode)->i_orphan))) { | 491 | if (!list_empty(&(EXT3_I(inode)->i_orphan))) { |
@@ -489,7 +496,7 @@ static void ext3_destroy_inode(struct inode *inode) | |||
489 | false); | 496 | false); |
490 | dump_stack(); | 497 | dump_stack(); |
491 | } | 498 | } |
492 | kmem_cache_free(ext3_inode_cachep, EXT3_I(inode)); | 499 | call_rcu(&inode->i_rcu, ext3_i_callback); |
493 | } | 500 | } |
494 | 501 | ||
495 | static void init_once(void *foo) | 502 | static void init_once(void *foo) |
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c index 5e2ed4504ead..e0270d1f8d82 100644 --- a/fs/ext4/acl.c +++ b/fs/ext4/acl.c | |||
@@ -238,10 +238,17 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type, | |||
238 | } | 238 | } |
239 | 239 | ||
240 | int | 240 | int |
241 | ext4_check_acl(struct inode *inode, int mask) | 241 | ext4_check_acl(struct inode *inode, int mask, unsigned int flags) |
242 | { | 242 | { |
243 | struct posix_acl *acl = ext4_get_acl(inode, ACL_TYPE_ACCESS); | 243 | struct posix_acl *acl; |
244 | |||
245 | if (flags & IPERM_FLAG_RCU) { | ||
246 | if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) | ||
247 | return -ECHILD; | ||
248 | return -EAGAIN; | ||
249 | } | ||
244 | 250 | ||
251 | acl = ext4_get_acl(inode, ACL_TYPE_ACCESS); | ||
245 | if (IS_ERR(acl)) | 252 | if (IS_ERR(acl)) |
246 | return PTR_ERR(acl); | 253 | return PTR_ERR(acl); |
247 | if (acl) { | 254 | if (acl) { |
diff --git a/fs/ext4/acl.h b/fs/ext4/acl.h index 9d843d5deac4..dec821168fd4 100644 --- a/fs/ext4/acl.h +++ b/fs/ext4/acl.h | |||
@@ -54,7 +54,7 @@ static inline int ext4_acl_count(size_t size) | |||
54 | #ifdef CONFIG_EXT4_FS_POSIX_ACL | 54 | #ifdef CONFIG_EXT4_FS_POSIX_ACL |
55 | 55 | ||
56 | /* acl.c */ | 56 | /* acl.c */ |
57 | extern int ext4_check_acl(struct inode *, int); | 57 | extern int ext4_check_acl(struct inode *, int, unsigned int); |
58 | extern int ext4_acl_chmod(struct inode *); | 58 | extern int ext4_acl_chmod(struct inode *); |
59 | extern int ext4_init_acl(handle_t *, struct inode *, struct inode *); | 59 | extern int ext4_init_acl(handle_t *, struct inode *, struct inode *); |
60 | 60 | ||
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 6a5edea2d70b..94ce3d7a1c4b 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -910,6 +910,7 @@ struct ext4_inode_info { | |||
910 | #define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000 /* Journal checksums */ | 910 | #define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000 /* Journal checksums */ |
911 | #define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000 /* Journal Async Commit */ | 911 | #define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000 /* Journal Async Commit */ |
912 | #define EXT4_MOUNT_I_VERSION 0x2000000 /* i_version support */ | 912 | #define EXT4_MOUNT_I_VERSION 0x2000000 /* i_version support */ |
913 | #define EXT4_MOUNT_MBLK_IO_SUBMIT 0x4000000 /* multi-block io submits */ | ||
913 | #define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */ | 914 | #define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */ |
914 | #define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */ | 915 | #define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */ |
915 | #define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */ | 916 | #define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */ |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index bdbe69902207..e659597b690b 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -2125,9 +2125,12 @@ static int mpage_da_submit_io(struct mpage_da_data *mpd, | |||
2125 | */ | 2125 | */ |
2126 | if (unlikely(journal_data && PageChecked(page))) | 2126 | if (unlikely(journal_data && PageChecked(page))) |
2127 | err = __ext4_journalled_writepage(page, len); | 2127 | err = __ext4_journalled_writepage(page, len); |
2128 | else | 2128 | else if (test_opt(inode->i_sb, MBLK_IO_SUBMIT)) |
2129 | err = ext4_bio_write_page(&io_submit, page, | 2129 | err = ext4_bio_write_page(&io_submit, page, |
2130 | len, mpd->wbc); | 2130 | len, mpd->wbc); |
2131 | else | ||
2132 | err = block_write_full_page(page, | ||
2133 | noalloc_get_block_write, mpd->wbc); | ||
2131 | 2134 | ||
2132 | if (!err) | 2135 | if (!err) |
2133 | mpd->pages_written++; | 2136 | mpd->pages_written++; |
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 92203b8a099f..dc40e75cba88 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -872,7 +872,7 @@ static struct buffer_head * ext4_find_entry (struct inode *dir, | |||
872 | if (namelen > EXT4_NAME_LEN) | 872 | if (namelen > EXT4_NAME_LEN) |
873 | return NULL; | 873 | return NULL; |
874 | if ((namelen <= 2) && (name[0] == '.') && | 874 | if ((namelen <= 2) && (name[0] == '.') && |
875 | (name[1] == '.' || name[1] == '0')) { | 875 | (name[1] == '.' || name[1] == '\0')) { |
876 | /* | 876 | /* |
877 | * "." or ".." will only be in the first block | 877 | * "." or ".." will only be in the first block |
878 | * NFS may look up ".."; "." should be handled by the VFS | 878 | * NFS may look up ".."; "." should be handled by the VFS |
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index dc963929de65..981c8477adab 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c | |||
@@ -232,6 +232,8 @@ static int setup_new_group_blocks(struct super_block *sb, | |||
232 | GFP_NOFS); | 232 | GFP_NOFS); |
233 | if (err) | 233 | if (err) |
234 | goto exit_bh; | 234 | goto exit_bh; |
235 | for (i = 0, bit = gdblocks + 1; i < reserved_gdb; i++, bit++) | ||
236 | ext4_set_bit(bit, bh->b_data); | ||
235 | 237 | ||
236 | ext4_debug("mark block bitmap %#04llx (+%llu)\n", input->block_bitmap, | 238 | ext4_debug("mark block bitmap %#04llx (+%llu)\n", input->block_bitmap, |
237 | input->block_bitmap - start); | 239 | input->block_bitmap - start); |
@@ -247,6 +249,9 @@ static int setup_new_group_blocks(struct super_block *sb, | |||
247 | err = sb_issue_zeroout(sb, block, sbi->s_itb_per_group, GFP_NOFS); | 249 | err = sb_issue_zeroout(sb, block, sbi->s_itb_per_group, GFP_NOFS); |
248 | if (err) | 250 | if (err) |
249 | goto exit_bh; | 251 | goto exit_bh; |
252 | for (i = 0, bit = input->inode_table - start; | ||
253 | i < sbi->s_itb_per_group; i++, bit++) | ||
254 | ext4_set_bit(bit, bh->b_data); | ||
250 | 255 | ||
251 | if ((err = extend_or_restart_transaction(handle, 2, bh))) | 256 | if ((err = extend_or_restart_transaction(handle, 2, bh))) |
252 | goto exit_bh; | 257 | goto exit_bh; |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index e32195d6aac3..cd37f9d5e447 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -841,6 +841,13 @@ static int ext4_drop_inode(struct inode *inode) | |||
841 | return drop; | 841 | return drop; |
842 | } | 842 | } |
843 | 843 | ||
844 | static void ext4_i_callback(struct rcu_head *head) | ||
845 | { | ||
846 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
847 | INIT_LIST_HEAD(&inode->i_dentry); | ||
848 | kmem_cache_free(ext4_inode_cachep, EXT4_I(inode)); | ||
849 | } | ||
850 | |||
844 | static void ext4_destroy_inode(struct inode *inode) | 851 | static void ext4_destroy_inode(struct inode *inode) |
845 | { | 852 | { |
846 | ext4_ioend_wait(inode); | 853 | ext4_ioend_wait(inode); |
@@ -853,7 +860,7 @@ static void ext4_destroy_inode(struct inode *inode) | |||
853 | true); | 860 | true); |
854 | dump_stack(); | 861 | dump_stack(); |
855 | } | 862 | } |
856 | kmem_cache_free(ext4_inode_cachep, EXT4_I(inode)); | 863 | call_rcu(&inode->i_rcu, ext4_i_callback); |
857 | } | 864 | } |
858 | 865 | ||
859 | static void init_once(void *foo) | 866 | static void init_once(void *foo) |
@@ -1026,6 +1033,8 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
1026 | !(def_mount_opts & EXT4_DEFM_NODELALLOC)) | 1033 | !(def_mount_opts & EXT4_DEFM_NODELALLOC)) |
1027 | seq_puts(seq, ",nodelalloc"); | 1034 | seq_puts(seq, ",nodelalloc"); |
1028 | 1035 | ||
1036 | if (test_opt(sb, MBLK_IO_SUBMIT)) | ||
1037 | seq_puts(seq, ",mblk_io_submit"); | ||
1029 | if (sbi->s_stripe) | 1038 | if (sbi->s_stripe) |
1030 | seq_printf(seq, ",stripe=%lu", sbi->s_stripe); | 1039 | seq_printf(seq, ",stripe=%lu", sbi->s_stripe); |
1031 | /* | 1040 | /* |
@@ -1239,8 +1248,8 @@ enum { | |||
1239 | Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota, | 1248 | Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota, |
1240 | Opt_noquota, Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err, | 1249 | Opt_noquota, Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err, |
1241 | Opt_resize, Opt_usrquota, Opt_grpquota, Opt_i_version, | 1250 | Opt_resize, Opt_usrquota, Opt_grpquota, Opt_i_version, |
1242 | Opt_stripe, Opt_delalloc, Opt_nodelalloc, | 1251 | Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_mblk_io_submit, |
1243 | Opt_block_validity, Opt_noblock_validity, | 1252 | Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity, |
1244 | Opt_inode_readahead_blks, Opt_journal_ioprio, | 1253 | Opt_inode_readahead_blks, Opt_journal_ioprio, |
1245 | Opt_dioread_nolock, Opt_dioread_lock, | 1254 | Opt_dioread_nolock, Opt_dioread_lock, |
1246 | Opt_discard, Opt_nodiscard, | 1255 | Opt_discard, Opt_nodiscard, |
@@ -1304,6 +1313,8 @@ static const match_table_t tokens = { | |||
1304 | {Opt_resize, "resize"}, | 1313 | {Opt_resize, "resize"}, |
1305 | {Opt_delalloc, "delalloc"}, | 1314 | {Opt_delalloc, "delalloc"}, |
1306 | {Opt_nodelalloc, "nodelalloc"}, | 1315 | {Opt_nodelalloc, "nodelalloc"}, |
1316 | {Opt_mblk_io_submit, "mblk_io_submit"}, | ||
1317 | {Opt_nomblk_io_submit, "nomblk_io_submit"}, | ||
1307 | {Opt_block_validity, "block_validity"}, | 1318 | {Opt_block_validity, "block_validity"}, |
1308 | {Opt_noblock_validity, "noblock_validity"}, | 1319 | {Opt_noblock_validity, "noblock_validity"}, |
1309 | {Opt_inode_readahead_blks, "inode_readahead_blks=%u"}, | 1320 | {Opt_inode_readahead_blks, "inode_readahead_blks=%u"}, |
@@ -1725,6 +1736,12 @@ set_qf_format: | |||
1725 | case Opt_nodelalloc: | 1736 | case Opt_nodelalloc: |
1726 | clear_opt(sbi->s_mount_opt, DELALLOC); | 1737 | clear_opt(sbi->s_mount_opt, DELALLOC); |
1727 | break; | 1738 | break; |
1739 | case Opt_mblk_io_submit: | ||
1740 | set_opt(sbi->s_mount_opt, MBLK_IO_SUBMIT); | ||
1741 | break; | ||
1742 | case Opt_nomblk_io_submit: | ||
1743 | clear_opt(sbi->s_mount_opt, MBLK_IO_SUBMIT); | ||
1744 | break; | ||
1728 | case Opt_stripe: | 1745 | case Opt_stripe: |
1729 | if (match_int(&args[0], &option)) | 1746 | if (match_int(&args[0], &option)) |
1730 | return 0; | 1747 | return 0; |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index ad6998a92c30..206351af7c58 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
@@ -514,11 +514,18 @@ static struct inode *fat_alloc_inode(struct super_block *sb) | |||
514 | return &ei->vfs_inode; | 514 | return &ei->vfs_inode; |
515 | } | 515 | } |
516 | 516 | ||
517 | static void fat_destroy_inode(struct inode *inode) | 517 | static void fat_i_callback(struct rcu_head *head) |
518 | { | 518 | { |
519 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
520 | INIT_LIST_HEAD(&inode->i_dentry); | ||
519 | kmem_cache_free(fat_inode_cachep, MSDOS_I(inode)); | 521 | kmem_cache_free(fat_inode_cachep, MSDOS_I(inode)); |
520 | } | 522 | } |
521 | 523 | ||
524 | static void fat_destroy_inode(struct inode *inode) | ||
525 | { | ||
526 | call_rcu(&inode->i_rcu, fat_i_callback); | ||
527 | } | ||
528 | |||
522 | static void init_once(void *foo) | 529 | static void init_once(void *foo) |
523 | { | 530 | { |
524 | struct msdos_inode_info *ei = (struct msdos_inode_info *)foo; | 531 | struct msdos_inode_info *ei = (struct msdos_inode_info *)foo; |
@@ -743,7 +750,7 @@ static struct dentry *fat_fh_to_dentry(struct super_block *sb, | |||
743 | */ | 750 | */ |
744 | result = d_obtain_alias(inode); | 751 | result = d_obtain_alias(inode); |
745 | if (!IS_ERR(result)) | 752 | if (!IS_ERR(result)) |
746 | result->d_op = sb->s_root->d_op; | 753 | d_set_d_op(result, sb->s_root->d_op); |
747 | return result; | 754 | return result; |
748 | } | 755 | } |
749 | 756 | ||
@@ -793,7 +800,7 @@ static struct dentry *fat_get_parent(struct dentry *child) | |||
793 | 800 | ||
794 | parent = d_obtain_alias(inode); | 801 | parent = d_obtain_alias(inode); |
795 | if (!IS_ERR(parent)) | 802 | if (!IS_ERR(parent)) |
796 | parent->d_op = sb->s_root->d_op; | 803 | d_set_d_op(parent, sb->s_root->d_op); |
797 | out: | 804 | out: |
798 | unlock_super(sb); | 805 | unlock_super(sb); |
799 | 806 | ||
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index 3345aabd1dd7..35ffe43afa4b 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c | |||
@@ -148,7 +148,8 @@ static int msdos_find(struct inode *dir, const unsigned char *name, int len, | |||
148 | * that the existing dentry can be used. The msdos fs routines will | 148 | * that the existing dentry can be used. The msdos fs routines will |
149 | * return ENOENT or EINVAL as appropriate. | 149 | * return ENOENT or EINVAL as appropriate. |
150 | */ | 150 | */ |
151 | static int msdos_hash(struct dentry *dentry, struct qstr *qstr) | 151 | static int msdos_hash(const struct dentry *dentry, const struct inode *inode, |
152 | struct qstr *qstr) | ||
152 | { | 153 | { |
153 | struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options; | 154 | struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options; |
154 | unsigned char msdos_name[MSDOS_NAME]; | 155 | unsigned char msdos_name[MSDOS_NAME]; |
@@ -164,16 +165,18 @@ static int msdos_hash(struct dentry *dentry, struct qstr *qstr) | |||
164 | * Compare two msdos names. If either of the names are invalid, | 165 | * Compare two msdos names. If either of the names are invalid, |
165 | * we fall back to doing the standard name comparison. | 166 | * we fall back to doing the standard name comparison. |
166 | */ | 167 | */ |
167 | static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) | 168 | static int msdos_cmp(const struct dentry *parent, const struct inode *pinode, |
169 | const struct dentry *dentry, const struct inode *inode, | ||
170 | unsigned int len, const char *str, const struct qstr *name) | ||
168 | { | 171 | { |
169 | struct fat_mount_options *options = &MSDOS_SB(dentry->d_sb)->options; | 172 | struct fat_mount_options *options = &MSDOS_SB(parent->d_sb)->options; |
170 | unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME]; | 173 | unsigned char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME]; |
171 | int error; | 174 | int error; |
172 | 175 | ||
173 | error = msdos_format_name(a->name, a->len, a_msdos_name, options); | 176 | error = msdos_format_name(name->name, name->len, a_msdos_name, options); |
174 | if (error) | 177 | if (error) |
175 | goto old_compare; | 178 | goto old_compare; |
176 | error = msdos_format_name(b->name, b->len, b_msdos_name, options); | 179 | error = msdos_format_name(str, len, b_msdos_name, options); |
177 | if (error) | 180 | if (error) |
178 | goto old_compare; | 181 | goto old_compare; |
179 | error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME); | 182 | error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME); |
@@ -182,8 +185,8 @@ out: | |||
182 | 185 | ||
183 | old_compare: | 186 | old_compare: |
184 | error = 1; | 187 | error = 1; |
185 | if (a->len == b->len) | 188 | if (name->len == len) |
186 | error = memcmp(a->name, b->name, a->len); | 189 | error = memcmp(name->name, str, len); |
187 | goto out; | 190 | goto out; |
188 | } | 191 | } |
189 | 192 | ||
@@ -224,10 +227,10 @@ static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry, | |||
224 | } | 227 | } |
225 | out: | 228 | out: |
226 | unlock_super(sb); | 229 | unlock_super(sb); |
227 | dentry->d_op = &msdos_dentry_operations; | 230 | d_set_d_op(dentry, &msdos_dentry_operations); |
228 | dentry = d_splice_alias(inode, dentry); | 231 | dentry = d_splice_alias(inode, dentry); |
229 | if (dentry) | 232 | if (dentry) |
230 | dentry->d_op = &msdos_dentry_operations; | 233 | d_set_d_op(dentry, &msdos_dentry_operations); |
231 | return dentry; | 234 | return dentry; |
232 | 235 | ||
233 | error: | 236 | error: |
@@ -670,7 +673,7 @@ static int msdos_fill_super(struct super_block *sb, void *data, int silent) | |||
670 | } | 673 | } |
671 | 674 | ||
672 | sb->s_flags |= MS_NOATIME; | 675 | sb->s_flags |= MS_NOATIME; |
673 | sb->s_root->d_op = &msdos_dentry_operations; | 676 | d_set_d_op(sb->s_root, &msdos_dentry_operations); |
674 | unlock_super(sb); | 677 | unlock_super(sb); |
675 | return 0; | 678 | return 0; |
676 | } | 679 | } |
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index b936703b8924..e3ffc5e12332 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c | |||
@@ -43,6 +43,9 @@ static int vfat_revalidate_shortname(struct dentry *dentry) | |||
43 | 43 | ||
44 | static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd) | 44 | static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd) |
45 | { | 45 | { |
46 | if (nd->flags & LOOKUP_RCU) | ||
47 | return -ECHILD; | ||
48 | |||
46 | /* This is not negative dentry. Always valid. */ | 49 | /* This is not negative dentry. Always valid. */ |
47 | if (dentry->d_inode) | 50 | if (dentry->d_inode) |
48 | return 1; | 51 | return 1; |
@@ -51,6 +54,9 @@ static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
51 | 54 | ||
52 | static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd) | 55 | static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd) |
53 | { | 56 | { |
57 | if (nd->flags & LOOKUP_RCU) | ||
58 | return -ECHILD; | ||
59 | |||
54 | /* | 60 | /* |
55 | * This is not negative dentry. Always valid. | 61 | * This is not negative dentry. Always valid. |
56 | * | 62 | * |
@@ -85,22 +91,26 @@ static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd) | |||
85 | } | 91 | } |
86 | 92 | ||
87 | /* returns the length of a struct qstr, ignoring trailing dots */ | 93 | /* returns the length of a struct qstr, ignoring trailing dots */ |
88 | static unsigned int vfat_striptail_len(struct qstr *qstr) | 94 | static unsigned int __vfat_striptail_len(unsigned int len, const char *name) |
89 | { | 95 | { |
90 | unsigned int len = qstr->len; | 96 | while (len && name[len - 1] == '.') |
91 | |||
92 | while (len && qstr->name[len - 1] == '.') | ||
93 | len--; | 97 | len--; |
94 | return len; | 98 | return len; |
95 | } | 99 | } |
96 | 100 | ||
101 | static unsigned int vfat_striptail_len(const struct qstr *qstr) | ||
102 | { | ||
103 | return __vfat_striptail_len(qstr->len, qstr->name); | ||
104 | } | ||
105 | |||
97 | /* | 106 | /* |
98 | * Compute the hash for the vfat name corresponding to the dentry. | 107 | * Compute the hash for the vfat name corresponding to the dentry. |
99 | * Note: if the name is invalid, we leave the hash code unchanged so | 108 | * Note: if the name is invalid, we leave the hash code unchanged so |
100 | * that the existing dentry can be used. The vfat fs routines will | 109 | * that the existing dentry can be used. The vfat fs routines will |
101 | * return ENOENT or EINVAL as appropriate. | 110 | * return ENOENT or EINVAL as appropriate. |
102 | */ | 111 | */ |
103 | static int vfat_hash(struct dentry *dentry, struct qstr *qstr) | 112 | static int vfat_hash(const struct dentry *dentry, const struct inode *inode, |
113 | struct qstr *qstr) | ||
104 | { | 114 | { |
105 | qstr->hash = full_name_hash(qstr->name, vfat_striptail_len(qstr)); | 115 | qstr->hash = full_name_hash(qstr->name, vfat_striptail_len(qstr)); |
106 | return 0; | 116 | return 0; |
@@ -112,9 +122,10 @@ static int vfat_hash(struct dentry *dentry, struct qstr *qstr) | |||
112 | * that the existing dentry can be used. The vfat fs routines will | 122 | * that the existing dentry can be used. The vfat fs routines will |
113 | * return ENOENT or EINVAL as appropriate. | 123 | * return ENOENT or EINVAL as appropriate. |
114 | */ | 124 | */ |
115 | static int vfat_hashi(struct dentry *dentry, struct qstr *qstr) | 125 | static int vfat_hashi(const struct dentry *dentry, const struct inode *inode, |
126 | struct qstr *qstr) | ||
116 | { | 127 | { |
117 | struct nls_table *t = MSDOS_SB(dentry->d_inode->i_sb)->nls_io; | 128 | struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io; |
118 | const unsigned char *name; | 129 | const unsigned char *name; |
119 | unsigned int len; | 130 | unsigned int len; |
120 | unsigned long hash; | 131 | unsigned long hash; |
@@ -133,16 +144,18 @@ static int vfat_hashi(struct dentry *dentry, struct qstr *qstr) | |||
133 | /* | 144 | /* |
134 | * Case insensitive compare of two vfat names. | 145 | * Case insensitive compare of two vfat names. |
135 | */ | 146 | */ |
136 | static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b) | 147 | static int vfat_cmpi(const struct dentry *parent, const struct inode *pinode, |
148 | const struct dentry *dentry, const struct inode *inode, | ||
149 | unsigned int len, const char *str, const struct qstr *name) | ||
137 | { | 150 | { |
138 | struct nls_table *t = MSDOS_SB(dentry->d_inode->i_sb)->nls_io; | 151 | struct nls_table *t = MSDOS_SB(parent->d_sb)->nls_io; |
139 | unsigned int alen, blen; | 152 | unsigned int alen, blen; |
140 | 153 | ||
141 | /* A filename cannot end in '.' or we treat it like it has none */ | 154 | /* A filename cannot end in '.' or we treat it like it has none */ |
142 | alen = vfat_striptail_len(a); | 155 | alen = vfat_striptail_len(name); |
143 | blen = vfat_striptail_len(b); | 156 | blen = __vfat_striptail_len(len, str); |
144 | if (alen == blen) { | 157 | if (alen == blen) { |
145 | if (nls_strnicmp(t, a->name, b->name, alen) == 0) | 158 | if (nls_strnicmp(t, name->name, str, alen) == 0) |
146 | return 0; | 159 | return 0; |
147 | } | 160 | } |
148 | return 1; | 161 | return 1; |
@@ -151,15 +164,17 @@ static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b) | |||
151 | /* | 164 | /* |
152 | * Case sensitive compare of two vfat names. | 165 | * Case sensitive compare of two vfat names. |
153 | */ | 166 | */ |
154 | static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b) | 167 | static int vfat_cmp(const struct dentry *parent, const struct inode *pinode, |
168 | const struct dentry *dentry, const struct inode *inode, | ||
169 | unsigned int len, const char *str, const struct qstr *name) | ||
155 | { | 170 | { |
156 | unsigned int alen, blen; | 171 | unsigned int alen, blen; |
157 | 172 | ||
158 | /* A filename cannot end in '.' or we treat it like it has none */ | 173 | /* A filename cannot end in '.' or we treat it like it has none */ |
159 | alen = vfat_striptail_len(a); | 174 | alen = vfat_striptail_len(name); |
160 | blen = vfat_striptail_len(b); | 175 | blen = __vfat_striptail_len(len, str); |
161 | if (alen == blen) { | 176 | if (alen == blen) { |
162 | if (strncmp(a->name, b->name, alen) == 0) | 177 | if (strncmp(name->name, str, alen) == 0) |
163 | return 0; | 178 | return 0; |
164 | } | 179 | } |
165 | return 1; | 180 | return 1; |
@@ -757,11 +772,11 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry, | |||
757 | 772 | ||
758 | out: | 773 | out: |
759 | unlock_super(sb); | 774 | unlock_super(sb); |
760 | dentry->d_op = sb->s_root->d_op; | 775 | d_set_d_op(dentry, sb->s_root->d_op); |
761 | dentry->d_time = dentry->d_parent->d_inode->i_version; | 776 | dentry->d_time = dentry->d_parent->d_inode->i_version; |
762 | dentry = d_splice_alias(inode, dentry); | 777 | dentry = d_splice_alias(inode, dentry); |
763 | if (dentry) { | 778 | if (dentry) { |
764 | dentry->d_op = sb->s_root->d_op; | 779 | d_set_d_op(dentry, sb->s_root->d_op); |
765 | dentry->d_time = dentry->d_parent->d_inode->i_version; | 780 | dentry->d_time = dentry->d_parent->d_inode->i_version; |
766 | } | 781 | } |
767 | return dentry; | 782 | return dentry; |
@@ -1063,9 +1078,9 @@ static int vfat_fill_super(struct super_block *sb, void *data, int silent) | |||
1063 | } | 1078 | } |
1064 | 1079 | ||
1065 | if (MSDOS_SB(sb)->options.name_check != 's') | 1080 | if (MSDOS_SB(sb)->options.name_check != 's') |
1066 | sb->s_root->d_op = &vfat_ci_dentry_ops; | 1081 | d_set_d_op(sb->s_root, &vfat_ci_dentry_ops); |
1067 | else | 1082 | else |
1068 | sb->s_root->d_op = &vfat_dentry_ops; | 1083 | d_set_d_op(sb->s_root, &vfat_dentry_ops); |
1069 | 1084 | ||
1070 | unlock_super(sb); | 1085 | unlock_super(sb); |
1071 | return 0; | 1086 | return 0; |
diff --git a/fs/filesystems.c b/fs/filesystems.c index 68ba492d8eef..751d6b255a12 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c | |||
@@ -115,6 +115,9 @@ int unregister_filesystem(struct file_system_type * fs) | |||
115 | tmp = &(*tmp)->next; | 115 | tmp = &(*tmp)->next; |
116 | } | 116 | } |
117 | write_unlock(&file_systems_lock); | 117 | write_unlock(&file_systems_lock); |
118 | |||
119 | synchronize_rcu(); | ||
120 | |||
118 | return -EINVAL; | 121 | return -EINVAL; |
119 | } | 122 | } |
120 | 123 | ||
diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c index 8c04eac5079d..2ba6719ac612 100644 --- a/fs/freevxfs/vxfs_inode.c +++ b/fs/freevxfs/vxfs_inode.c | |||
@@ -337,6 +337,13 @@ vxfs_iget(struct super_block *sbp, ino_t ino) | |||
337 | return ip; | 337 | return ip; |
338 | } | 338 | } |
339 | 339 | ||
340 | static void vxfs_i_callback(struct rcu_head *head) | ||
341 | { | ||
342 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
343 | INIT_LIST_HEAD(&inode->i_dentry); | ||
344 | kmem_cache_free(vxfs_inode_cachep, inode->i_private); | ||
345 | } | ||
346 | |||
340 | /** | 347 | /** |
341 | * vxfs_evict_inode - remove inode from main memory | 348 | * vxfs_evict_inode - remove inode from main memory |
342 | * @ip: inode to discard. | 349 | * @ip: inode to discard. |
@@ -350,5 +357,5 @@ vxfs_evict_inode(struct inode *ip) | |||
350 | { | 357 | { |
351 | truncate_inode_pages(&ip->i_data, 0); | 358 | truncate_inode_pages(&ip->i_data, 0); |
352 | end_writeback(ip); | 359 | end_writeback(ip); |
353 | kmem_cache_free(vxfs_inode_cachep, ip->i_private); | 360 | call_rcu(&ip->i_rcu, vxfs_i_callback); |
354 | } | 361 | } |
diff --git a/fs/fs_struct.c b/fs/fs_struct.c index ed45a9cf5f3d..68ca487bedb1 100644 --- a/fs/fs_struct.c +++ b/fs/fs_struct.c | |||
@@ -14,12 +14,14 @@ void set_fs_root(struct fs_struct *fs, struct path *path) | |||
14 | struct path old_root; | 14 | struct path old_root; |
15 | 15 | ||
16 | spin_lock(&fs->lock); | 16 | spin_lock(&fs->lock); |
17 | write_seqcount_begin(&fs->seq); | ||
17 | old_root = fs->root; | 18 | old_root = fs->root; |
18 | fs->root = *path; | 19 | fs->root = *path; |
19 | path_get(path); | 20 | path_get_long(path); |
21 | write_seqcount_end(&fs->seq); | ||
20 | spin_unlock(&fs->lock); | 22 | spin_unlock(&fs->lock); |
21 | if (old_root.dentry) | 23 | if (old_root.dentry) |
22 | path_put(&old_root); | 24 | path_put_long(&old_root); |
23 | } | 25 | } |
24 | 26 | ||
25 | /* | 27 | /* |
@@ -31,13 +33,15 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path) | |||
31 | struct path old_pwd; | 33 | struct path old_pwd; |
32 | 34 | ||
33 | spin_lock(&fs->lock); | 35 | spin_lock(&fs->lock); |
36 | write_seqcount_begin(&fs->seq); | ||
34 | old_pwd = fs->pwd; | 37 | old_pwd = fs->pwd; |
35 | fs->pwd = *path; | 38 | fs->pwd = *path; |
36 | path_get(path); | 39 | path_get_long(path); |
40 | write_seqcount_end(&fs->seq); | ||
37 | spin_unlock(&fs->lock); | 41 | spin_unlock(&fs->lock); |
38 | 42 | ||
39 | if (old_pwd.dentry) | 43 | if (old_pwd.dentry) |
40 | path_put(&old_pwd); | 44 | path_put_long(&old_pwd); |
41 | } | 45 | } |
42 | 46 | ||
43 | void chroot_fs_refs(struct path *old_root, struct path *new_root) | 47 | void chroot_fs_refs(struct path *old_root, struct path *new_root) |
@@ -52,31 +56,33 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root) | |||
52 | fs = p->fs; | 56 | fs = p->fs; |
53 | if (fs) { | 57 | if (fs) { |
54 | spin_lock(&fs->lock); | 58 | spin_lock(&fs->lock); |
59 | write_seqcount_begin(&fs->seq); | ||
55 | if (fs->root.dentry == old_root->dentry | 60 | if (fs->root.dentry == old_root->dentry |
56 | && fs->root.mnt == old_root->mnt) { | 61 | && fs->root.mnt == old_root->mnt) { |
57 | path_get(new_root); | 62 | path_get_long(new_root); |
58 | fs->root = *new_root; | 63 | fs->root = *new_root; |
59 | count++; | 64 | count++; |
60 | } | 65 | } |
61 | if (fs->pwd.dentry == old_root->dentry | 66 | if (fs->pwd.dentry == old_root->dentry |
62 | && fs->pwd.mnt == old_root->mnt) { | 67 | && fs->pwd.mnt == old_root->mnt) { |
63 | path_get(new_root); | 68 | path_get_long(new_root); |
64 | fs->pwd = *new_root; | 69 | fs->pwd = *new_root; |
65 | count++; | 70 | count++; |
66 | } | 71 | } |
72 | write_seqcount_end(&fs->seq); | ||
67 | spin_unlock(&fs->lock); | 73 | spin_unlock(&fs->lock); |
68 | } | 74 | } |
69 | task_unlock(p); | 75 | task_unlock(p); |
70 | } while_each_thread(g, p); | 76 | } while_each_thread(g, p); |
71 | read_unlock(&tasklist_lock); | 77 | read_unlock(&tasklist_lock); |
72 | while (count--) | 78 | while (count--) |
73 | path_put(old_root); | 79 | path_put_long(old_root); |
74 | } | 80 | } |
75 | 81 | ||
76 | void free_fs_struct(struct fs_struct *fs) | 82 | void free_fs_struct(struct fs_struct *fs) |
77 | { | 83 | { |
78 | path_put(&fs->root); | 84 | path_put_long(&fs->root); |
79 | path_put(&fs->pwd); | 85 | path_put_long(&fs->pwd); |
80 | kmem_cache_free(fs_cachep, fs); | 86 | kmem_cache_free(fs_cachep, fs); |
81 | } | 87 | } |
82 | 88 | ||
@@ -88,8 +94,10 @@ void exit_fs(struct task_struct *tsk) | |||
88 | int kill; | 94 | int kill; |
89 | task_lock(tsk); | 95 | task_lock(tsk); |
90 | spin_lock(&fs->lock); | 96 | spin_lock(&fs->lock); |
97 | write_seqcount_begin(&fs->seq); | ||
91 | tsk->fs = NULL; | 98 | tsk->fs = NULL; |
92 | kill = !--fs->users; | 99 | kill = !--fs->users; |
100 | write_seqcount_end(&fs->seq); | ||
93 | spin_unlock(&fs->lock); | 101 | spin_unlock(&fs->lock); |
94 | task_unlock(tsk); | 102 | task_unlock(tsk); |
95 | if (kill) | 103 | if (kill) |
@@ -105,8 +113,15 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old) | |||
105 | fs->users = 1; | 113 | fs->users = 1; |
106 | fs->in_exec = 0; | 114 | fs->in_exec = 0; |
107 | spin_lock_init(&fs->lock); | 115 | spin_lock_init(&fs->lock); |
116 | seqcount_init(&fs->seq); | ||
108 | fs->umask = old->umask; | 117 | fs->umask = old->umask; |
109 | get_fs_root_and_pwd(old, &fs->root, &fs->pwd); | 118 | |
119 | spin_lock(&old->lock); | ||
120 | fs->root = old->root; | ||
121 | path_get_long(&fs->root); | ||
122 | fs->pwd = old->pwd; | ||
123 | path_get_long(&fs->pwd); | ||
124 | spin_unlock(&old->lock); | ||
110 | } | 125 | } |
111 | return fs; | 126 | return fs; |
112 | } | 127 | } |
@@ -144,6 +159,7 @@ EXPORT_SYMBOL(current_umask); | |||
144 | struct fs_struct init_fs = { | 159 | struct fs_struct init_fs = { |
145 | .users = 1, | 160 | .users = 1, |
146 | .lock = __SPIN_LOCK_UNLOCKED(init_fs.lock), | 161 | .lock = __SPIN_LOCK_UNLOCKED(init_fs.lock), |
162 | .seq = SEQCNT_ZERO, | ||
147 | .umask = 0022, | 163 | .umask = 0022, |
148 | }; | 164 | }; |
149 | 165 | ||
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 6e07696308dc..cf8d28d1fbad 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -251,6 +251,20 @@ static void queue_request(struct fuse_conn *fc, struct fuse_req *req) | |||
251 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); | 251 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); |
252 | } | 252 | } |
253 | 253 | ||
254 | void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, | ||
255 | u64 nodeid, u64 nlookup) | ||
256 | { | ||
257 | forget->forget_one.nodeid = nodeid; | ||
258 | forget->forget_one.nlookup = nlookup; | ||
259 | |||
260 | spin_lock(&fc->lock); | ||
261 | fc->forget_list_tail->next = forget; | ||
262 | fc->forget_list_tail = forget; | ||
263 | wake_up(&fc->waitq); | ||
264 | kill_fasync(&fc->fasync, SIGIO, POLL_IN); | ||
265 | spin_unlock(&fc->lock); | ||
266 | } | ||
267 | |||
254 | static void flush_bg_queue(struct fuse_conn *fc) | 268 | static void flush_bg_queue(struct fuse_conn *fc) |
255 | { | 269 | { |
256 | while (fc->active_background < fc->max_background && | 270 | while (fc->active_background < fc->max_background && |
@@ -438,12 +452,6 @@ static void fuse_request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) | |||
438 | } | 452 | } |
439 | } | 453 | } |
440 | 454 | ||
441 | void fuse_request_send_noreply(struct fuse_conn *fc, struct fuse_req *req) | ||
442 | { | ||
443 | req->isreply = 0; | ||
444 | fuse_request_send_nowait(fc, req); | ||
445 | } | ||
446 | |||
447 | void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req) | 455 | void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req) |
448 | { | 456 | { |
449 | req->isreply = 1; | 457 | req->isreply = 1; |
@@ -896,9 +904,15 @@ static int fuse_copy_args(struct fuse_copy_state *cs, unsigned numargs, | |||
896 | return err; | 904 | return err; |
897 | } | 905 | } |
898 | 906 | ||
907 | static int forget_pending(struct fuse_conn *fc) | ||
908 | { | ||
909 | return fc->forget_list_head.next != NULL; | ||
910 | } | ||
911 | |||
899 | static int request_pending(struct fuse_conn *fc) | 912 | static int request_pending(struct fuse_conn *fc) |
900 | { | 913 | { |
901 | return !list_empty(&fc->pending) || !list_empty(&fc->interrupts); | 914 | return !list_empty(&fc->pending) || !list_empty(&fc->interrupts) || |
915 | forget_pending(fc); | ||
902 | } | 916 | } |
903 | 917 | ||
904 | /* Wait until a request is available on the pending list */ | 918 | /* Wait until a request is available on the pending list */ |
@@ -960,6 +974,120 @@ __releases(fc->lock) | |||
960 | return err ? err : reqsize; | 974 | return err ? err : reqsize; |
961 | } | 975 | } |
962 | 976 | ||
977 | static struct fuse_forget_link *dequeue_forget(struct fuse_conn *fc, | ||
978 | unsigned max, | ||
979 | unsigned *countp) | ||
980 | { | ||
981 | struct fuse_forget_link *head = fc->forget_list_head.next; | ||
982 | struct fuse_forget_link **newhead = &head; | ||
983 | unsigned count; | ||
984 | |||
985 | for (count = 0; *newhead != NULL && count < max; count++) | ||
986 | newhead = &(*newhead)->next; | ||
987 | |||
988 | fc->forget_list_head.next = *newhead; | ||
989 | *newhead = NULL; | ||
990 | if (fc->forget_list_head.next == NULL) | ||
991 | fc->forget_list_tail = &fc->forget_list_head; | ||
992 | |||
993 | if (countp != NULL) | ||
994 | *countp = count; | ||
995 | |||
996 | return head; | ||
997 | } | ||
998 | |||
999 | static int fuse_read_single_forget(struct fuse_conn *fc, | ||
1000 | struct fuse_copy_state *cs, | ||
1001 | size_t nbytes) | ||
1002 | __releases(fc->lock) | ||
1003 | { | ||
1004 | int err; | ||
1005 | struct fuse_forget_link *forget = dequeue_forget(fc, 1, NULL); | ||
1006 | struct fuse_forget_in arg = { | ||
1007 | .nlookup = forget->forget_one.nlookup, | ||
1008 | }; | ||
1009 | struct fuse_in_header ih = { | ||
1010 | .opcode = FUSE_FORGET, | ||
1011 | .nodeid = forget->forget_one.nodeid, | ||
1012 | .unique = fuse_get_unique(fc), | ||
1013 | .len = sizeof(ih) + sizeof(arg), | ||
1014 | }; | ||
1015 | |||
1016 | spin_unlock(&fc->lock); | ||
1017 | kfree(forget); | ||
1018 | if (nbytes < ih.len) | ||
1019 | return -EINVAL; | ||
1020 | |||
1021 | err = fuse_copy_one(cs, &ih, sizeof(ih)); | ||
1022 | if (!err) | ||
1023 | err = fuse_copy_one(cs, &arg, sizeof(arg)); | ||
1024 | fuse_copy_finish(cs); | ||
1025 | |||
1026 | if (err) | ||
1027 | return err; | ||
1028 | |||
1029 | return ih.len; | ||
1030 | } | ||
1031 | |||
1032 | static int fuse_read_batch_forget(struct fuse_conn *fc, | ||
1033 | struct fuse_copy_state *cs, size_t nbytes) | ||
1034 | __releases(fc->lock) | ||
1035 | { | ||
1036 | int err; | ||
1037 | unsigned max_forgets; | ||
1038 | unsigned count; | ||
1039 | struct fuse_forget_link *head; | ||
1040 | struct fuse_batch_forget_in arg = { .count = 0 }; | ||
1041 | struct fuse_in_header ih = { | ||
1042 | .opcode = FUSE_BATCH_FORGET, | ||
1043 | .unique = fuse_get_unique(fc), | ||
1044 | .len = sizeof(ih) + sizeof(arg), | ||
1045 | }; | ||
1046 | |||
1047 | if (nbytes < ih.len) { | ||
1048 | spin_unlock(&fc->lock); | ||
1049 | return -EINVAL; | ||
1050 | } | ||
1051 | |||
1052 | max_forgets = (nbytes - ih.len) / sizeof(struct fuse_forget_one); | ||
1053 | head = dequeue_forget(fc, max_forgets, &count); | ||
1054 | spin_unlock(&fc->lock); | ||
1055 | |||
1056 | arg.count = count; | ||
1057 | ih.len += count * sizeof(struct fuse_forget_one); | ||
1058 | err = fuse_copy_one(cs, &ih, sizeof(ih)); | ||
1059 | if (!err) | ||
1060 | err = fuse_copy_one(cs, &arg, sizeof(arg)); | ||
1061 | |||
1062 | while (head) { | ||
1063 | struct fuse_forget_link *forget = head; | ||
1064 | |||
1065 | if (!err) { | ||
1066 | err = fuse_copy_one(cs, &forget->forget_one, | ||
1067 | sizeof(forget->forget_one)); | ||
1068 | } | ||
1069 | head = forget->next; | ||
1070 | kfree(forget); | ||
1071 | } | ||
1072 | |||
1073 | fuse_copy_finish(cs); | ||
1074 | |||
1075 | if (err) | ||
1076 | return err; | ||
1077 | |||
1078 | return ih.len; | ||
1079 | } | ||
1080 | |||
1081 | static int fuse_read_forget(struct fuse_conn *fc, struct fuse_copy_state *cs, | ||
1082 | size_t nbytes) | ||
1083 | __releases(fc->lock) | ||
1084 | { | ||
1085 | if (fc->minor < 16 || fc->forget_list_head.next->next == NULL) | ||
1086 | return fuse_read_single_forget(fc, cs, nbytes); | ||
1087 | else | ||
1088 | return fuse_read_batch_forget(fc, cs, nbytes); | ||
1089 | } | ||
1090 | |||
963 | /* | 1091 | /* |
964 | * Read a single request into the userspace filesystem's buffer. This | 1092 | * Read a single request into the userspace filesystem's buffer. This |
965 | * function waits until a request is available, then removes it from | 1093 | * function waits until a request is available, then removes it from |
@@ -998,6 +1126,14 @@ static ssize_t fuse_dev_do_read(struct fuse_conn *fc, struct file *file, | |||
998 | return fuse_read_interrupt(fc, cs, nbytes, req); | 1126 | return fuse_read_interrupt(fc, cs, nbytes, req); |
999 | } | 1127 | } |
1000 | 1128 | ||
1129 | if (forget_pending(fc)) { | ||
1130 | if (list_empty(&fc->pending) || fc->forget_batch-- > 0) | ||
1131 | return fuse_read_forget(fc, cs, nbytes); | ||
1132 | |||
1133 | if (fc->forget_batch <= -8) | ||
1134 | fc->forget_batch = 16; | ||
1135 | } | ||
1136 | |||
1001 | req = list_entry(fc->pending.next, struct fuse_req, list); | 1137 | req = list_entry(fc->pending.next, struct fuse_req, list); |
1002 | req->state = FUSE_REQ_READING; | 1138 | req->state = FUSE_REQ_READING; |
1003 | list_move(&req->list, &fc->io); | 1139 | list_move(&req->list, &fc->io); |
@@ -1090,7 +1226,7 @@ static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos, | |||
1090 | if (!fc) | 1226 | if (!fc) |
1091 | return -EPERM; | 1227 | return -EPERM; |
1092 | 1228 | ||
1093 | bufs = kmalloc(pipe->buffers * sizeof (struct pipe_buffer), GFP_KERNEL); | 1229 | bufs = kmalloc(pipe->buffers * sizeof(struct pipe_buffer), GFP_KERNEL); |
1094 | if (!bufs) | 1230 | if (!bufs) |
1095 | return -ENOMEM; | 1231 | return -ENOMEM; |
1096 | 1232 | ||
@@ -1626,7 +1762,7 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe, | |||
1626 | if (!fc) | 1762 | if (!fc) |
1627 | return -EPERM; | 1763 | return -EPERM; |
1628 | 1764 | ||
1629 | bufs = kmalloc(pipe->buffers * sizeof (struct pipe_buffer), GFP_KERNEL); | 1765 | bufs = kmalloc(pipe->buffers * sizeof(struct pipe_buffer), GFP_KERNEL); |
1630 | if (!bufs) | 1766 | if (!bufs) |
1631 | return -ENOMEM; | 1767 | return -ENOMEM; |
1632 | 1768 | ||
@@ -1770,6 +1906,8 @@ __acquires(fc->lock) | |||
1770 | flush_bg_queue(fc); | 1906 | flush_bg_queue(fc); |
1771 | end_requests(fc, &fc->pending); | 1907 | end_requests(fc, &fc->pending); |
1772 | end_requests(fc, &fc->processing); | 1908 | end_requests(fc, &fc->processing); |
1909 | while (forget_pending(fc)) | ||
1910 | kfree(dequeue_forget(fc, 1, NULL)); | ||
1773 | } | 1911 | } |
1774 | 1912 | ||
1775 | /* | 1913 | /* |
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index c9627c95482d..042af7346ec1 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -10,9 +10,9 @@ | |||
10 | 10 | ||
11 | #include <linux/pagemap.h> | 11 | #include <linux/pagemap.h> |
12 | #include <linux/file.h> | 12 | #include <linux/file.h> |
13 | #include <linux/gfp.h> | ||
14 | #include <linux/sched.h> | 13 | #include <linux/sched.h> |
15 | #include <linux/namei.h> | 14 | #include <linux/namei.h> |
15 | #include <linux/slab.h> | ||
16 | 16 | ||
17 | #if BITS_PER_LONG >= 64 | 17 | #if BITS_PER_LONG >= 64 |
18 | static inline void fuse_dentry_settime(struct dentry *entry, u64 time) | 18 | static inline void fuse_dentry_settime(struct dentry *entry, u64 time) |
@@ -156,8 +156,12 @@ u64 fuse_get_attr_version(struct fuse_conn *fc) | |||
156 | */ | 156 | */ |
157 | static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | 157 | static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) |
158 | { | 158 | { |
159 | struct inode *inode = entry->d_inode; | 159 | struct inode *inode; |
160 | 160 | ||
161 | if (nd->flags & LOOKUP_RCU) | ||
162 | return -ECHILD; | ||
163 | |||
164 | inode = entry->d_inode; | ||
161 | if (inode && is_bad_inode(inode)) | 165 | if (inode && is_bad_inode(inode)) |
162 | return 0; | 166 | return 0; |
163 | else if (fuse_dentry_time(entry) < get_jiffies_64()) { | 167 | else if (fuse_dentry_time(entry) < get_jiffies_64()) { |
@@ -165,7 +169,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
165 | struct fuse_entry_out outarg; | 169 | struct fuse_entry_out outarg; |
166 | struct fuse_conn *fc; | 170 | struct fuse_conn *fc; |
167 | struct fuse_req *req; | 171 | struct fuse_req *req; |
168 | struct fuse_req *forget_req; | 172 | struct fuse_forget_link *forget; |
169 | struct dentry *parent; | 173 | struct dentry *parent; |
170 | u64 attr_version; | 174 | u64 attr_version; |
171 | 175 | ||
@@ -178,8 +182,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
178 | if (IS_ERR(req)) | 182 | if (IS_ERR(req)) |
179 | return 0; | 183 | return 0; |
180 | 184 | ||
181 | forget_req = fuse_get_req(fc); | 185 | forget = fuse_alloc_forget(); |
182 | if (IS_ERR(forget_req)) { | 186 | if (!forget) { |
183 | fuse_put_request(fc, req); | 187 | fuse_put_request(fc, req); |
184 | return 0; | 188 | return 0; |
185 | } | 189 | } |
@@ -199,15 +203,14 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
199 | if (!err) { | 203 | if (!err) { |
200 | struct fuse_inode *fi = get_fuse_inode(inode); | 204 | struct fuse_inode *fi = get_fuse_inode(inode); |
201 | if (outarg.nodeid != get_node_id(inode)) { | 205 | if (outarg.nodeid != get_node_id(inode)) { |
202 | fuse_send_forget(fc, forget_req, | 206 | fuse_queue_forget(fc, forget, outarg.nodeid, 1); |
203 | outarg.nodeid, 1); | ||
204 | return 0; | 207 | return 0; |
205 | } | 208 | } |
206 | spin_lock(&fc->lock); | 209 | spin_lock(&fc->lock); |
207 | fi->nlookup++; | 210 | fi->nlookup++; |
208 | spin_unlock(&fc->lock); | 211 | spin_unlock(&fc->lock); |
209 | } | 212 | } |
210 | fuse_put_request(fc, forget_req); | 213 | kfree(forget); |
211 | if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) | 214 | if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) |
212 | return 0; | 215 | return 0; |
213 | 216 | ||
@@ -259,7 +262,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, | |||
259 | { | 262 | { |
260 | struct fuse_conn *fc = get_fuse_conn_super(sb); | 263 | struct fuse_conn *fc = get_fuse_conn_super(sb); |
261 | struct fuse_req *req; | 264 | struct fuse_req *req; |
262 | struct fuse_req *forget_req; | 265 | struct fuse_forget_link *forget; |
263 | u64 attr_version; | 266 | u64 attr_version; |
264 | int err; | 267 | int err; |
265 | 268 | ||
@@ -273,9 +276,9 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, | |||
273 | if (IS_ERR(req)) | 276 | if (IS_ERR(req)) |
274 | goto out; | 277 | goto out; |
275 | 278 | ||
276 | forget_req = fuse_get_req(fc); | 279 | forget = fuse_alloc_forget(); |
277 | err = PTR_ERR(forget_req); | 280 | err = -ENOMEM; |
278 | if (IS_ERR(forget_req)) { | 281 | if (!forget) { |
279 | fuse_put_request(fc, req); | 282 | fuse_put_request(fc, req); |
280 | goto out; | 283 | goto out; |
281 | } | 284 | } |
@@ -301,13 +304,13 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, | |||
301 | attr_version); | 304 | attr_version); |
302 | err = -ENOMEM; | 305 | err = -ENOMEM; |
303 | if (!*inode) { | 306 | if (!*inode) { |
304 | fuse_send_forget(fc, forget_req, outarg->nodeid, 1); | 307 | fuse_queue_forget(fc, forget, outarg->nodeid, 1); |
305 | goto out; | 308 | goto out; |
306 | } | 309 | } |
307 | err = 0; | 310 | err = 0; |
308 | 311 | ||
309 | out_put_forget: | 312 | out_put_forget: |
310 | fuse_put_request(fc, forget_req); | 313 | kfree(forget); |
311 | out: | 314 | out: |
312 | return err; | 315 | return err; |
313 | } | 316 | } |
@@ -347,7 +350,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
347 | } | 350 | } |
348 | 351 | ||
349 | entry = newent ? newent : entry; | 352 | entry = newent ? newent : entry; |
350 | entry->d_op = &fuse_dentry_operations; | 353 | d_set_d_op(entry, &fuse_dentry_operations); |
351 | if (outarg_valid) | 354 | if (outarg_valid) |
352 | fuse_change_entry_timeout(entry, &outarg); | 355 | fuse_change_entry_timeout(entry, &outarg); |
353 | else | 356 | else |
@@ -374,7 +377,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
374 | struct inode *inode; | 377 | struct inode *inode; |
375 | struct fuse_conn *fc = get_fuse_conn(dir); | 378 | struct fuse_conn *fc = get_fuse_conn(dir); |
376 | struct fuse_req *req; | 379 | struct fuse_req *req; |
377 | struct fuse_req *forget_req; | 380 | struct fuse_forget_link *forget; |
378 | struct fuse_create_in inarg; | 381 | struct fuse_create_in inarg; |
379 | struct fuse_open_out outopen; | 382 | struct fuse_open_out outopen; |
380 | struct fuse_entry_out outentry; | 383 | struct fuse_entry_out outentry; |
@@ -388,9 +391,9 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
388 | if (flags & O_DIRECT) | 391 | if (flags & O_DIRECT) |
389 | return -EINVAL; | 392 | return -EINVAL; |
390 | 393 | ||
391 | forget_req = fuse_get_req(fc); | 394 | forget = fuse_alloc_forget(); |
392 | if (IS_ERR(forget_req)) | 395 | if (!forget) |
393 | return PTR_ERR(forget_req); | 396 | return -ENOMEM; |
394 | 397 | ||
395 | req = fuse_get_req(fc); | 398 | req = fuse_get_req(fc); |
396 | err = PTR_ERR(req); | 399 | err = PTR_ERR(req); |
@@ -448,10 +451,10 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
448 | if (!inode) { | 451 | if (!inode) { |
449 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); | 452 | flags &= ~(O_CREAT | O_EXCL | O_TRUNC); |
450 | fuse_sync_release(ff, flags); | 453 | fuse_sync_release(ff, flags); |
451 | fuse_send_forget(fc, forget_req, outentry.nodeid, 1); | 454 | fuse_queue_forget(fc, forget, outentry.nodeid, 1); |
452 | return -ENOMEM; | 455 | return -ENOMEM; |
453 | } | 456 | } |
454 | fuse_put_request(fc, forget_req); | 457 | kfree(forget); |
455 | d_instantiate(entry, inode); | 458 | d_instantiate(entry, inode); |
456 | fuse_change_entry_timeout(entry, &outentry); | 459 | fuse_change_entry_timeout(entry, &outentry); |
457 | fuse_invalidate_attr(dir); | 460 | fuse_invalidate_attr(dir); |
@@ -469,7 +472,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, | |||
469 | out_put_request: | 472 | out_put_request: |
470 | fuse_put_request(fc, req); | 473 | fuse_put_request(fc, req); |
471 | out_put_forget_req: | 474 | out_put_forget_req: |
472 | fuse_put_request(fc, forget_req); | 475 | kfree(forget); |
473 | return err; | 476 | return err; |
474 | } | 477 | } |
475 | 478 | ||
@@ -483,12 +486,12 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
483 | struct fuse_entry_out outarg; | 486 | struct fuse_entry_out outarg; |
484 | struct inode *inode; | 487 | struct inode *inode; |
485 | int err; | 488 | int err; |
486 | struct fuse_req *forget_req; | 489 | struct fuse_forget_link *forget; |
487 | 490 | ||
488 | forget_req = fuse_get_req(fc); | 491 | forget = fuse_alloc_forget(); |
489 | if (IS_ERR(forget_req)) { | 492 | if (!forget) { |
490 | fuse_put_request(fc, req); | 493 | fuse_put_request(fc, req); |
491 | return PTR_ERR(forget_req); | 494 | return -ENOMEM; |
492 | } | 495 | } |
493 | 496 | ||
494 | memset(&outarg, 0, sizeof(outarg)); | 497 | memset(&outarg, 0, sizeof(outarg)); |
@@ -515,10 +518,10 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
515 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, | 518 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
516 | &outarg.attr, entry_attr_timeout(&outarg), 0); | 519 | &outarg.attr, entry_attr_timeout(&outarg), 0); |
517 | if (!inode) { | 520 | if (!inode) { |
518 | fuse_send_forget(fc, forget_req, outarg.nodeid, 1); | 521 | fuse_queue_forget(fc, forget, outarg.nodeid, 1); |
519 | return -ENOMEM; | 522 | return -ENOMEM; |
520 | } | 523 | } |
521 | fuse_put_request(fc, forget_req); | 524 | kfree(forget); |
522 | 525 | ||
523 | if (S_ISDIR(inode->i_mode)) { | 526 | if (S_ISDIR(inode->i_mode)) { |
524 | struct dentry *alias; | 527 | struct dentry *alias; |
@@ -541,7 +544,7 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
541 | return 0; | 544 | return 0; |
542 | 545 | ||
543 | out_put_forget_req: | 546 | out_put_forget_req: |
544 | fuse_put_request(fc, forget_req); | 547 | kfree(forget); |
545 | return err; | 548 | return err; |
546 | } | 549 | } |
547 | 550 | ||
@@ -981,12 +984,15 @@ static int fuse_access(struct inode *inode, int mask) | |||
981 | * access request is sent. Execute permission is still checked | 984 | * access request is sent. Execute permission is still checked |
982 | * locally based on file mode. | 985 | * locally based on file mode. |
983 | */ | 986 | */ |
984 | static int fuse_permission(struct inode *inode, int mask) | 987 | static int fuse_permission(struct inode *inode, int mask, unsigned int flags) |
985 | { | 988 | { |
986 | struct fuse_conn *fc = get_fuse_conn(inode); | 989 | struct fuse_conn *fc = get_fuse_conn(inode); |
987 | bool refreshed = false; | 990 | bool refreshed = false; |
988 | int err = 0; | 991 | int err = 0; |
989 | 992 | ||
993 | if (flags & IPERM_FLAG_RCU) | ||
994 | return -ECHILD; | ||
995 | |||
990 | if (!fuse_allow_task(fc, current)) | 996 | if (!fuse_allow_task(fc, current)) |
991 | return -EACCES; | 997 | return -EACCES; |
992 | 998 | ||
@@ -1001,7 +1007,7 @@ static int fuse_permission(struct inode *inode, int mask) | |||
1001 | } | 1007 | } |
1002 | 1008 | ||
1003 | if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { | 1009 | if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { |
1004 | err = generic_permission(inode, mask, NULL); | 1010 | err = generic_permission(inode, mask, flags, NULL); |
1005 | 1011 | ||
1006 | /* If permission is denied, try to refresh file | 1012 | /* If permission is denied, try to refresh file |
1007 | attributes. This is also needed, because the root | 1013 | attributes. This is also needed, because the root |
@@ -1009,7 +1015,8 @@ static int fuse_permission(struct inode *inode, int mask) | |||
1009 | if (err == -EACCES && !refreshed) { | 1015 | if (err == -EACCES && !refreshed) { |
1010 | err = fuse_do_getattr(inode, NULL, NULL); | 1016 | err = fuse_do_getattr(inode, NULL, NULL); |
1011 | if (!err) | 1017 | if (!err) |
1012 | err = generic_permission(inode, mask, NULL); | 1018 | err = generic_permission(inode, mask, |
1019 | flags, NULL); | ||
1013 | } | 1020 | } |
1014 | 1021 | ||
1015 | /* Note: the opposite of the above test does not | 1022 | /* Note: the opposite of the above test does not |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 9242d294fe90..95da1bc1c826 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/compat.h> | ||
16 | 17 | ||
17 | static const struct file_operations fuse_direct_io_file_operations; | 18 | static const struct file_operations fuse_direct_io_file_operations; |
18 | 19 | ||
@@ -1628,6 +1629,94 @@ static int fuse_ioctl_copy_user(struct page **pages, struct iovec *iov, | |||
1628 | } | 1629 | } |
1629 | 1630 | ||
1630 | /* | 1631 | /* |
1632 | * CUSE servers compiled on 32bit broke on 64bit kernels because the | ||
1633 | * ABI was defined to be 'struct iovec' which is different on 32bit | ||
1634 | * and 64bit. Fortunately we can determine which structure the server | ||
1635 | * used from the size of the reply. | ||
1636 | */ | ||
1637 | static int fuse_copy_ioctl_iovec_old(struct iovec *dst, void *src, | ||
1638 | size_t transferred, unsigned count, | ||
1639 | bool is_compat) | ||
1640 | { | ||
1641 | #ifdef CONFIG_COMPAT | ||
1642 | if (count * sizeof(struct compat_iovec) == transferred) { | ||
1643 | struct compat_iovec *ciov = src; | ||
1644 | unsigned i; | ||
1645 | |||
1646 | /* | ||
1647 | * With this interface a 32bit server cannot support | ||
1648 | * non-compat (i.e. ones coming from 64bit apps) ioctl | ||
1649 | * requests | ||
1650 | */ | ||
1651 | if (!is_compat) | ||
1652 | return -EINVAL; | ||
1653 | |||
1654 | for (i = 0; i < count; i++) { | ||
1655 | dst[i].iov_base = compat_ptr(ciov[i].iov_base); | ||
1656 | dst[i].iov_len = ciov[i].iov_len; | ||
1657 | } | ||
1658 | return 0; | ||
1659 | } | ||
1660 | #endif | ||
1661 | |||
1662 | if (count * sizeof(struct iovec) != transferred) | ||
1663 | return -EIO; | ||
1664 | |||
1665 | memcpy(dst, src, transferred); | ||
1666 | return 0; | ||
1667 | } | ||
1668 | |||
1669 | /* Make sure iov_length() won't overflow */ | ||
1670 | static int fuse_verify_ioctl_iov(struct iovec *iov, size_t count) | ||
1671 | { | ||
1672 | size_t n; | ||
1673 | u32 max = FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT; | ||
1674 | |||
1675 | for (n = 0; n < count; n++) { | ||
1676 | if (iov->iov_len > (size_t) max) | ||
1677 | return -ENOMEM; | ||
1678 | max -= iov->iov_len; | ||
1679 | } | ||
1680 | return 0; | ||
1681 | } | ||
1682 | |||
1683 | static int fuse_copy_ioctl_iovec(struct fuse_conn *fc, struct iovec *dst, | ||
1684 | void *src, size_t transferred, unsigned count, | ||
1685 | bool is_compat) | ||
1686 | { | ||
1687 | unsigned i; | ||
1688 | struct fuse_ioctl_iovec *fiov = src; | ||
1689 | |||
1690 | if (fc->minor < 16) { | ||
1691 | return fuse_copy_ioctl_iovec_old(dst, src, transferred, | ||
1692 | count, is_compat); | ||
1693 | } | ||
1694 | |||
1695 | if (count * sizeof(struct fuse_ioctl_iovec) != transferred) | ||
1696 | return -EIO; | ||
1697 | |||
1698 | for (i = 0; i < count; i++) { | ||
1699 | /* Did the server supply an inappropriate value? */ | ||
1700 | if (fiov[i].base != (unsigned long) fiov[i].base || | ||
1701 | fiov[i].len != (unsigned long) fiov[i].len) | ||
1702 | return -EIO; | ||
1703 | |||
1704 | dst[i].iov_base = (void __user *) (unsigned long) fiov[i].base; | ||
1705 | dst[i].iov_len = (size_t) fiov[i].len; | ||
1706 | |||
1707 | #ifdef CONFIG_COMPAT | ||
1708 | if (is_compat && | ||
1709 | (ptr_to_compat(dst[i].iov_base) != fiov[i].base || | ||
1710 | (compat_size_t) dst[i].iov_len != fiov[i].len)) | ||
1711 | return -EIO; | ||
1712 | #endif | ||
1713 | } | ||
1714 | |||
1715 | return 0; | ||
1716 | } | ||
1717 | |||
1718 | |||
1719 | /* | ||
1631 | * For ioctls, there is no generic way to determine how much memory | 1720 | * For ioctls, there is no generic way to determine how much memory |
1632 | * needs to be read and/or written. Furthermore, ioctls are allowed | 1721 | * needs to be read and/or written. Furthermore, ioctls are allowed |
1633 | * to dereference the passed pointer, so the parameter requires deep | 1722 | * to dereference the passed pointer, so the parameter requires deep |
@@ -1687,18 +1776,25 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, | |||
1687 | struct fuse_ioctl_out outarg; | 1776 | struct fuse_ioctl_out outarg; |
1688 | struct fuse_req *req = NULL; | 1777 | struct fuse_req *req = NULL; |
1689 | struct page **pages = NULL; | 1778 | struct page **pages = NULL; |
1690 | struct page *iov_page = NULL; | 1779 | struct iovec *iov_page = NULL; |
1691 | struct iovec *in_iov = NULL, *out_iov = NULL; | 1780 | struct iovec *in_iov = NULL, *out_iov = NULL; |
1692 | unsigned int in_iovs = 0, out_iovs = 0, num_pages = 0, max_pages; | 1781 | unsigned int in_iovs = 0, out_iovs = 0, num_pages = 0, max_pages; |
1693 | size_t in_size, out_size, transferred; | 1782 | size_t in_size, out_size, transferred; |
1694 | int err; | 1783 | int err; |
1695 | 1784 | ||
1785 | #if BITS_PER_LONG == 32 | ||
1786 | inarg.flags |= FUSE_IOCTL_32BIT; | ||
1787 | #else | ||
1788 | if (flags & FUSE_IOCTL_COMPAT) | ||
1789 | inarg.flags |= FUSE_IOCTL_32BIT; | ||
1790 | #endif | ||
1791 | |||
1696 | /* assume all the iovs returned by client always fits in a page */ | 1792 | /* assume all the iovs returned by client always fits in a page */ |
1697 | BUILD_BUG_ON(sizeof(struct iovec) * FUSE_IOCTL_MAX_IOV > PAGE_SIZE); | 1793 | BUILD_BUG_ON(sizeof(struct fuse_ioctl_iovec) * FUSE_IOCTL_MAX_IOV > PAGE_SIZE); |
1698 | 1794 | ||
1699 | err = -ENOMEM; | 1795 | err = -ENOMEM; |
1700 | pages = kzalloc(sizeof(pages[0]) * FUSE_MAX_PAGES_PER_REQ, GFP_KERNEL); | 1796 | pages = kzalloc(sizeof(pages[0]) * FUSE_MAX_PAGES_PER_REQ, GFP_KERNEL); |
1701 | iov_page = alloc_page(GFP_KERNEL); | 1797 | iov_page = (struct iovec *) __get_free_page(GFP_KERNEL); |
1702 | if (!pages || !iov_page) | 1798 | if (!pages || !iov_page) |
1703 | goto out; | 1799 | goto out; |
1704 | 1800 | ||
@@ -1707,7 +1803,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, | |||
1707 | * RETRY from server is not allowed. | 1803 | * RETRY from server is not allowed. |
1708 | */ | 1804 | */ |
1709 | if (!(flags & FUSE_IOCTL_UNRESTRICTED)) { | 1805 | if (!(flags & FUSE_IOCTL_UNRESTRICTED)) { |
1710 | struct iovec *iov = page_address(iov_page); | 1806 | struct iovec *iov = iov_page; |
1711 | 1807 | ||
1712 | iov->iov_base = (void __user *)arg; | 1808 | iov->iov_base = (void __user *)arg; |
1713 | iov->iov_len = _IOC_SIZE(cmd); | 1809 | iov->iov_len = _IOC_SIZE(cmd); |
@@ -1788,7 +1884,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, | |||
1788 | 1884 | ||
1789 | /* did it ask for retry? */ | 1885 | /* did it ask for retry? */ |
1790 | if (outarg.flags & FUSE_IOCTL_RETRY) { | 1886 | if (outarg.flags & FUSE_IOCTL_RETRY) { |
1791 | char *vaddr; | 1887 | void *vaddr; |
1792 | 1888 | ||
1793 | /* no retry if in restricted mode */ | 1889 | /* no retry if in restricted mode */ |
1794 | err = -EIO; | 1890 | err = -EIO; |
@@ -1808,18 +1904,25 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, | |||
1808 | in_iovs + out_iovs > FUSE_IOCTL_MAX_IOV) | 1904 | in_iovs + out_iovs > FUSE_IOCTL_MAX_IOV) |
1809 | goto out; | 1905 | goto out; |
1810 | 1906 | ||
1811 | err = -EIO; | ||
1812 | if ((in_iovs + out_iovs) * sizeof(struct iovec) != transferred) | ||
1813 | goto out; | ||
1814 | |||
1815 | /* okay, copy in iovs and retry */ | ||
1816 | vaddr = kmap_atomic(pages[0], KM_USER0); | 1907 | vaddr = kmap_atomic(pages[0], KM_USER0); |
1817 | memcpy(page_address(iov_page), vaddr, transferred); | 1908 | err = fuse_copy_ioctl_iovec(fc, iov_page, vaddr, |
1909 | transferred, in_iovs + out_iovs, | ||
1910 | (flags & FUSE_IOCTL_COMPAT) != 0); | ||
1818 | kunmap_atomic(vaddr, KM_USER0); | 1911 | kunmap_atomic(vaddr, KM_USER0); |
1912 | if (err) | ||
1913 | goto out; | ||
1819 | 1914 | ||
1820 | in_iov = page_address(iov_page); | 1915 | in_iov = iov_page; |
1821 | out_iov = in_iov + in_iovs; | 1916 | out_iov = in_iov + in_iovs; |
1822 | 1917 | ||
1918 | err = fuse_verify_ioctl_iov(in_iov, in_iovs); | ||
1919 | if (err) | ||
1920 | goto out; | ||
1921 | |||
1922 | err = fuse_verify_ioctl_iov(out_iov, out_iovs); | ||
1923 | if (err) | ||
1924 | goto out; | ||
1925 | |||
1823 | goto retry; | 1926 | goto retry; |
1824 | } | 1927 | } |
1825 | 1928 | ||
@@ -1831,8 +1934,7 @@ long fuse_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg, | |||
1831 | out: | 1934 | out: |
1832 | if (req) | 1935 | if (req) |
1833 | fuse_put_request(fc, req); | 1936 | fuse_put_request(fc, req); |
1834 | if (iov_page) | 1937 | free_page((unsigned long) iov_page); |
1835 | __free_page(iov_page); | ||
1836 | while (num_pages) | 1938 | while (num_pages) |
1837 | __free_page(pages[--num_pages]); | 1939 | __free_page(pages[--num_pages]); |
1838 | kfree(pages); | 1940 | kfree(pages); |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 57d4a3a0f102..ae5744a2f9e9 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -53,6 +53,12 @@ extern struct mutex fuse_mutex; | |||
53 | extern unsigned max_user_bgreq; | 53 | extern unsigned max_user_bgreq; |
54 | extern unsigned max_user_congthresh; | 54 | extern unsigned max_user_congthresh; |
55 | 55 | ||
56 | /* One forget request */ | ||
57 | struct fuse_forget_link { | ||
58 | struct fuse_forget_one forget_one; | ||
59 | struct fuse_forget_link *next; | ||
60 | }; | ||
61 | |||
56 | /** FUSE inode */ | 62 | /** FUSE inode */ |
57 | struct fuse_inode { | 63 | struct fuse_inode { |
58 | /** Inode data */ | 64 | /** Inode data */ |
@@ -66,7 +72,7 @@ struct fuse_inode { | |||
66 | u64 nlookup; | 72 | u64 nlookup; |
67 | 73 | ||
68 | /** The request used for sending the FORGET message */ | 74 | /** The request used for sending the FORGET message */ |
69 | struct fuse_req *forget_req; | 75 | struct fuse_forget_link *forget; |
70 | 76 | ||
71 | /** Time in jiffies until the file attributes are valid */ | 77 | /** Time in jiffies until the file attributes are valid */ |
72 | u64 i_time; | 78 | u64 i_time; |
@@ -255,7 +261,6 @@ struct fuse_req { | |||
255 | 261 | ||
256 | /** Data for asynchronous requests */ | 262 | /** Data for asynchronous requests */ |
257 | union { | 263 | union { |
258 | struct fuse_forget_in forget_in; | ||
259 | struct { | 264 | struct { |
260 | struct fuse_release_in in; | 265 | struct fuse_release_in in; |
261 | struct path path; | 266 | struct path path; |
@@ -369,6 +374,13 @@ struct fuse_conn { | |||
369 | /** Pending interrupts */ | 374 | /** Pending interrupts */ |
370 | struct list_head interrupts; | 375 | struct list_head interrupts; |
371 | 376 | ||
377 | /** Queue of pending forgets */ | ||
378 | struct fuse_forget_link forget_list_head; | ||
379 | struct fuse_forget_link *forget_list_tail; | ||
380 | |||
381 | /** Batching of FORGET requests (positive indicates FORGET batch) */ | ||
382 | int forget_batch; | ||
383 | |||
372 | /** Flag indicating if connection is blocked. This will be | 384 | /** Flag indicating if connection is blocked. This will be |
373 | the case before the INIT reply is received, and if there | 385 | the case before the INIT reply is received, and if there |
374 | are too many outstading backgrounds requests */ | 386 | are too many outstading backgrounds requests */ |
@@ -543,8 +555,10 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name, | |||
543 | /** | 555 | /** |
544 | * Send FORGET command | 556 | * Send FORGET command |
545 | */ | 557 | */ |
546 | void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, | 558 | void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget, |
547 | u64 nodeid, u64 nlookup); | 559 | u64 nodeid, u64 nlookup); |
560 | |||
561 | struct fuse_forget_link *fuse_alloc_forget(void); | ||
548 | 562 | ||
549 | /** | 563 | /** |
550 | * Initialize READ or READDIR request | 564 | * Initialize READ or READDIR request |
@@ -656,11 +670,6 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req); | |||
656 | void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req); | 670 | void fuse_request_send(struct fuse_conn *fc, struct fuse_req *req); |
657 | 671 | ||
658 | /** | 672 | /** |
659 | * Send a request with no reply | ||
660 | */ | ||
661 | void fuse_request_send_noreply(struct fuse_conn *fc, struct fuse_req *req); | ||
662 | |||
663 | /** | ||
664 | * Send a request in the background | 673 | * Send a request in the background |
665 | */ | 674 | */ |
666 | void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req); | 675 | void fuse_request_send_background(struct fuse_conn *fc, struct fuse_req *req); |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index cfce3ad86a92..f62b32cffea9 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -71,6 +71,11 @@ struct fuse_mount_data { | |||
71 | unsigned blksize; | 71 | unsigned blksize; |
72 | }; | 72 | }; |
73 | 73 | ||
74 | struct fuse_forget_link *fuse_alloc_forget() | ||
75 | { | ||
76 | return kzalloc(sizeof(struct fuse_forget_link), GFP_KERNEL); | ||
77 | } | ||
78 | |||
74 | static struct inode *fuse_alloc_inode(struct super_block *sb) | 79 | static struct inode *fuse_alloc_inode(struct super_block *sb) |
75 | { | 80 | { |
76 | struct inode *inode; | 81 | struct inode *inode; |
@@ -90,8 +95,8 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) | |||
90 | INIT_LIST_HEAD(&fi->queued_writes); | 95 | INIT_LIST_HEAD(&fi->queued_writes); |
91 | INIT_LIST_HEAD(&fi->writepages); | 96 | INIT_LIST_HEAD(&fi->writepages); |
92 | init_waitqueue_head(&fi->page_waitq); | 97 | init_waitqueue_head(&fi->page_waitq); |
93 | fi->forget_req = fuse_request_alloc(); | 98 | fi->forget = fuse_alloc_forget(); |
94 | if (!fi->forget_req) { | 99 | if (!fi->forget) { |
95 | kmem_cache_free(fuse_inode_cachep, inode); | 100 | kmem_cache_free(fuse_inode_cachep, inode); |
96 | return NULL; | 101 | return NULL; |
97 | } | 102 | } |
@@ -99,27 +104,20 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) | |||
99 | return inode; | 104 | return inode; |
100 | } | 105 | } |
101 | 106 | ||
102 | static void fuse_destroy_inode(struct inode *inode) | 107 | static void fuse_i_callback(struct rcu_head *head) |
103 | { | 108 | { |
104 | struct fuse_inode *fi = get_fuse_inode(inode); | 109 | struct inode *inode = container_of(head, struct inode, i_rcu); |
105 | BUG_ON(!list_empty(&fi->write_files)); | 110 | INIT_LIST_HEAD(&inode->i_dentry); |
106 | BUG_ON(!list_empty(&fi->queued_writes)); | ||
107 | if (fi->forget_req) | ||
108 | fuse_request_free(fi->forget_req); | ||
109 | kmem_cache_free(fuse_inode_cachep, inode); | 111 | kmem_cache_free(fuse_inode_cachep, inode); |
110 | } | 112 | } |
111 | 113 | ||
112 | void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, | 114 | static void fuse_destroy_inode(struct inode *inode) |
113 | u64 nodeid, u64 nlookup) | ||
114 | { | 115 | { |
115 | struct fuse_forget_in *inarg = &req->misc.forget_in; | 116 | struct fuse_inode *fi = get_fuse_inode(inode); |
116 | inarg->nlookup = nlookup; | 117 | BUG_ON(!list_empty(&fi->write_files)); |
117 | req->in.h.opcode = FUSE_FORGET; | 118 | BUG_ON(!list_empty(&fi->queued_writes)); |
118 | req->in.h.nodeid = nodeid; | 119 | kfree(fi->forget); |
119 | req->in.numargs = 1; | 120 | call_rcu(&inode->i_rcu, fuse_i_callback); |
120 | req->in.args[0].size = sizeof(struct fuse_forget_in); | ||
121 | req->in.args[0].value = inarg; | ||
122 | fuse_request_send_noreply(fc, req); | ||
123 | } | 121 | } |
124 | 122 | ||
125 | static void fuse_evict_inode(struct inode *inode) | 123 | static void fuse_evict_inode(struct inode *inode) |
@@ -129,8 +127,8 @@ static void fuse_evict_inode(struct inode *inode) | |||
129 | if (inode->i_sb->s_flags & MS_ACTIVE) { | 127 | if (inode->i_sb->s_flags & MS_ACTIVE) { |
130 | struct fuse_conn *fc = get_fuse_conn(inode); | 128 | struct fuse_conn *fc = get_fuse_conn(inode); |
131 | struct fuse_inode *fi = get_fuse_inode(inode); | 129 | struct fuse_inode *fi = get_fuse_inode(inode); |
132 | fuse_send_forget(fc, fi->forget_req, fi->nodeid, fi->nlookup); | 130 | fuse_queue_forget(fc, fi->forget, fi->nodeid, fi->nlookup); |
133 | fi->forget_req = NULL; | 131 | fi->forget = NULL; |
134 | } | 132 | } |
135 | } | 133 | } |
136 | 134 | ||
@@ -534,6 +532,7 @@ void fuse_conn_init(struct fuse_conn *fc) | |||
534 | INIT_LIST_HEAD(&fc->interrupts); | 532 | INIT_LIST_HEAD(&fc->interrupts); |
535 | INIT_LIST_HEAD(&fc->bg_queue); | 533 | INIT_LIST_HEAD(&fc->bg_queue); |
536 | INIT_LIST_HEAD(&fc->entry); | 534 | INIT_LIST_HEAD(&fc->entry); |
535 | fc->forget_list_tail = &fc->forget_list_head; | ||
537 | atomic_set(&fc->num_waiting, 0); | 536 | atomic_set(&fc->num_waiting, 0); |
538 | fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND; | 537 | fc->max_background = FUSE_DEFAULT_MAX_BACKGROUND; |
539 | fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD; | 538 | fc->congestion_threshold = FUSE_DEFAULT_CONGESTION_THRESHOLD; |
@@ -619,7 +618,7 @@ static struct dentry *fuse_get_dentry(struct super_block *sb, | |||
619 | 618 | ||
620 | entry = d_obtain_alias(inode); | 619 | entry = d_obtain_alias(inode); |
621 | if (!IS_ERR(entry) && get_node_id(inode) != FUSE_ROOT_ID) { | 620 | if (!IS_ERR(entry) && get_node_id(inode) != FUSE_ROOT_ID) { |
622 | entry->d_op = &fuse_dentry_operations; | 621 | d_set_d_op(entry, &fuse_dentry_operations); |
623 | fuse_invalidate_entry_cache(entry); | 622 | fuse_invalidate_entry_cache(entry); |
624 | } | 623 | } |
625 | 624 | ||
@@ -721,7 +720,7 @@ static struct dentry *fuse_get_parent(struct dentry *child) | |||
721 | 720 | ||
722 | parent = d_obtain_alias(inode); | 721 | parent = d_obtain_alias(inode); |
723 | if (!IS_ERR(parent) && get_node_id(inode) != FUSE_ROOT_ID) { | 722 | if (!IS_ERR(parent) && get_node_id(inode) != FUSE_ROOT_ID) { |
724 | parent->d_op = &fuse_dentry_operations; | 723 | d_set_d_op(parent, &fuse_dentry_operations); |
725 | fuse_invalidate_entry_cache(parent); | 724 | fuse_invalidate_entry_cache(parent); |
726 | } | 725 | } |
727 | 726 | ||
diff --git a/fs/generic_acl.c b/fs/generic_acl.c index 6bc9e3a5a693..06c48a891832 100644 --- a/fs/generic_acl.c +++ b/fs/generic_acl.c | |||
@@ -190,14 +190,20 @@ generic_acl_chmod(struct inode *inode) | |||
190 | } | 190 | } |
191 | 191 | ||
192 | int | 192 | int |
193 | generic_check_acl(struct inode *inode, int mask) | 193 | generic_check_acl(struct inode *inode, int mask, unsigned int flags) |
194 | { | 194 | { |
195 | struct posix_acl *acl = get_cached_acl(inode, ACL_TYPE_ACCESS); | 195 | if (flags & IPERM_FLAG_RCU) { |
196 | 196 | if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) | |
197 | if (acl) { | 197 | return -ECHILD; |
198 | int error = posix_acl_permission(inode, acl, mask); | 198 | } else { |
199 | posix_acl_release(acl); | 199 | struct posix_acl *acl; |
200 | return error; | 200 | |
201 | acl = get_cached_acl(inode, ACL_TYPE_ACCESS); | ||
202 | if (acl) { | ||
203 | int error = posix_acl_permission(inode, acl, mask); | ||
204 | posix_acl_release(acl); | ||
205 | return error; | ||
206 | } | ||
201 | } | 207 | } |
202 | return -EAGAIN; | 208 | return -EAGAIN; |
203 | } | 209 | } |
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c index 48171f4c943d..7118f1a780a9 100644 --- a/fs/gfs2/acl.c +++ b/fs/gfs2/acl.c | |||
@@ -75,11 +75,14 @@ static struct posix_acl *gfs2_acl_get(struct gfs2_inode *ip, int type) | |||
75 | * Returns: errno | 75 | * Returns: errno |
76 | */ | 76 | */ |
77 | 77 | ||
78 | int gfs2_check_acl(struct inode *inode, int mask) | 78 | int gfs2_check_acl(struct inode *inode, int mask, unsigned int flags) |
79 | { | 79 | { |
80 | struct posix_acl *acl; | 80 | struct posix_acl *acl; |
81 | int error; | 81 | int error; |
82 | 82 | ||
83 | if (flags & IPERM_FLAG_RCU) | ||
84 | return -ECHILD; | ||
85 | |||
83 | acl = gfs2_acl_get(GFS2_I(inode), ACL_TYPE_ACCESS); | 86 | acl = gfs2_acl_get(GFS2_I(inode), ACL_TYPE_ACCESS); |
84 | if (IS_ERR(acl)) | 87 | if (IS_ERR(acl)) |
85 | return PTR_ERR(acl); | 88 | return PTR_ERR(acl); |
diff --git a/fs/gfs2/acl.h b/fs/gfs2/acl.h index b522b0cb39ea..a93907c8159b 100644 --- a/fs/gfs2/acl.h +++ b/fs/gfs2/acl.h | |||
@@ -16,7 +16,7 @@ | |||
16 | #define GFS2_POSIX_ACL_DEFAULT "posix_acl_default" | 16 | #define GFS2_POSIX_ACL_DEFAULT "posix_acl_default" |
17 | #define GFS2_ACL_MAX_ENTRIES 25 | 17 | #define GFS2_ACL_MAX_ENTRIES 25 |
18 | 18 | ||
19 | extern int gfs2_check_acl(struct inode *inode, int mask); | 19 | extern int gfs2_check_acl(struct inode *inode, int mask, unsigned int); |
20 | extern int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode); | 20 | extern int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode); |
21 | extern int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr); | 21 | extern int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr); |
22 | extern const struct xattr_handler gfs2_xattr_system_handler; | 22 | extern const struct xattr_handler gfs2_xattr_system_handler; |
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 5476c066d4ee..3c4039d5eef1 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c | |||
@@ -763,7 +763,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, | |||
763 | int metadata; | 763 | int metadata; |
764 | unsigned int revokes = 0; | 764 | unsigned int revokes = 0; |
765 | int x; | 765 | int x; |
766 | int error; | 766 | int error = 0; |
767 | 767 | ||
768 | if (!*top) | 768 | if (!*top) |
769 | sm->sm_first = 0; | 769 | sm->sm_first = 0; |
@@ -780,7 +780,11 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh, | |||
780 | if (metadata) | 780 | if (metadata) |
781 | revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs; | 781 | revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs; |
782 | 782 | ||
783 | error = gfs2_rindex_hold(sdp, &ip->i_alloc->al_ri_gh); | 783 | if (ip != GFS2_I(sdp->sd_rindex)) |
784 | error = gfs2_rindex_hold(sdp, &ip->i_alloc->al_ri_gh); | ||
785 | else if (!sdp->sd_rgrps) | ||
786 | error = gfs2_ri_update(ip); | ||
787 | |||
784 | if (error) | 788 | if (error) |
785 | return error; | 789 | return error; |
786 | 790 | ||
@@ -879,7 +883,8 @@ out_rg_gunlock: | |||
879 | out_rlist: | 883 | out_rlist: |
880 | gfs2_rlist_free(&rlist); | 884 | gfs2_rlist_free(&rlist); |
881 | out: | 885 | out: |
882 | gfs2_glock_dq_uninit(&ip->i_alloc->al_ri_gh); | 886 | if (ip != GFS2_I(sdp->sd_rindex)) |
887 | gfs2_glock_dq_uninit(&ip->i_alloc->al_ri_gh); | ||
883 | return error; | 888 | return error; |
884 | } | 889 | } |
885 | 890 | ||
diff --git a/fs/gfs2/dentry.c b/fs/gfs2/dentry.c index 6798755b3858..4a456338b873 100644 --- a/fs/gfs2/dentry.c +++ b/fs/gfs2/dentry.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <linux/completion.h> | 11 | #include <linux/completion.h> |
12 | #include <linux/buffer_head.h> | 12 | #include <linux/buffer_head.h> |
13 | #include <linux/gfs2_ondisk.h> | 13 | #include <linux/gfs2_ondisk.h> |
14 | #include <linux/namei.h> | ||
14 | #include <linux/crc32.h> | 15 | #include <linux/crc32.h> |
15 | 16 | ||
16 | #include "gfs2.h" | 17 | #include "gfs2.h" |
@@ -34,15 +35,23 @@ | |||
34 | 35 | ||
35 | static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) | 36 | static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd) |
36 | { | 37 | { |
37 | struct dentry *parent = dget_parent(dentry); | 38 | struct dentry *parent; |
38 | struct gfs2_sbd *sdp = GFS2_SB(parent->d_inode); | 39 | struct gfs2_sbd *sdp; |
39 | struct gfs2_inode *dip = GFS2_I(parent->d_inode); | 40 | struct gfs2_inode *dip; |
40 | struct inode *inode = dentry->d_inode; | 41 | struct inode *inode; |
41 | struct gfs2_holder d_gh; | 42 | struct gfs2_holder d_gh; |
42 | struct gfs2_inode *ip = NULL; | 43 | struct gfs2_inode *ip = NULL; |
43 | int error; | 44 | int error; |
44 | int had_lock = 0; | 45 | int had_lock = 0; |
45 | 46 | ||
47 | if (nd->flags & LOOKUP_RCU) | ||
48 | return -ECHILD; | ||
49 | |||
50 | parent = dget_parent(dentry); | ||
51 | sdp = GFS2_SB(parent->d_inode); | ||
52 | dip = GFS2_I(parent->d_inode); | ||
53 | inode = dentry->d_inode; | ||
54 | |||
46 | if (inode) { | 55 | if (inode) { |
47 | if (is_bad_inode(inode)) | 56 | if (is_bad_inode(inode)) |
48 | goto invalid; | 57 | goto invalid; |
@@ -100,13 +109,14 @@ fail: | |||
100 | return 0; | 109 | return 0; |
101 | } | 110 | } |
102 | 111 | ||
103 | static int gfs2_dhash(struct dentry *dentry, struct qstr *str) | 112 | static int gfs2_dhash(const struct dentry *dentry, const struct inode *inode, |
113 | struct qstr *str) | ||
104 | { | 114 | { |
105 | str->hash = gfs2_disk_hash(str->name, str->len); | 115 | str->hash = gfs2_disk_hash(str->name, str->len); |
106 | return 0; | 116 | return 0; |
107 | } | 117 | } |
108 | 118 | ||
109 | static int gfs2_dentry_delete(struct dentry *dentry) | 119 | static int gfs2_dentry_delete(const struct dentry *dentry) |
110 | { | 120 | { |
111 | struct gfs2_inode *ginode; | 121 | struct gfs2_inode *ginode; |
112 | 122 | ||
diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c index 5ab3839dfcb9..97012ecff560 100644 --- a/fs/gfs2/export.c +++ b/fs/gfs2/export.c | |||
@@ -130,7 +130,7 @@ static struct dentry *gfs2_get_parent(struct dentry *child) | |||
130 | 130 | ||
131 | dentry = d_obtain_alias(gfs2_lookupi(child->d_inode, &gfs2_qdotdot, 1)); | 131 | dentry = d_obtain_alias(gfs2_lookupi(child->d_inode, &gfs2_qdotdot, 1)); |
132 | if (!IS_ERR(dentry)) | 132 | if (!IS_ERR(dentry)) |
133 | dentry->d_op = &gfs2_dops; | 133 | d_set_d_op(dentry, &gfs2_dops); |
134 | return dentry; | 134 | return dentry; |
135 | } | 135 | } |
136 | 136 | ||
@@ -158,7 +158,7 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, | |||
158 | out_inode: | 158 | out_inode: |
159 | dentry = d_obtain_alias(inode); | 159 | dentry = d_obtain_alias(inode); |
160 | if (!IS_ERR(dentry)) | 160 | if (!IS_ERR(dentry)) |
161 | dentry->d_op = &gfs2_dops; | 161 | d_set_d_op(dentry, &gfs2_dops); |
162 | return dentry; | 162 | return dentry; |
163 | } | 163 | } |
164 | 164 | ||
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index aa996471ec5c..fca6689e12e6 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c | |||
@@ -241,7 +241,7 @@ static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask) | |||
241 | !capable(CAP_LINUX_IMMUTABLE)) | 241 | !capable(CAP_LINUX_IMMUTABLE)) |
242 | goto out; | 242 | goto out; |
243 | if (!IS_IMMUTABLE(inode)) { | 243 | if (!IS_IMMUTABLE(inode)) { |
244 | error = gfs2_permission(inode, MAY_WRITE); | 244 | error = gfs2_permission(inode, MAY_WRITE, 0); |
245 | if (error) | 245 | if (error) |
246 | goto out; | 246 | goto out; |
247 | } | 247 | } |
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index f92c17704169..08a8beb152e6 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c | |||
@@ -541,21 +541,6 @@ out_locked: | |||
541 | spin_unlock(&gl->gl_spin); | 541 | spin_unlock(&gl->gl_spin); |
542 | } | 542 | } |
543 | 543 | ||
544 | static unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock, | ||
545 | unsigned int req_state, | ||
546 | unsigned int flags) | ||
547 | { | ||
548 | int ret = LM_OUT_ERROR; | ||
549 | |||
550 | if (!sdp->sd_lockstruct.ls_ops->lm_lock) | ||
551 | return req_state == LM_ST_UNLOCKED ? 0 : req_state; | ||
552 | |||
553 | if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) | ||
554 | ret = sdp->sd_lockstruct.ls_ops->lm_lock(lock, | ||
555 | req_state, flags); | ||
556 | return ret; | ||
557 | } | ||
558 | |||
559 | /** | 544 | /** |
560 | * do_xmote - Calls the DLM to change the state of a lock | 545 | * do_xmote - Calls the DLM to change the state of a lock |
561 | * @gl: The lock state | 546 | * @gl: The lock state |
@@ -575,13 +560,14 @@ __acquires(&gl->gl_spin) | |||
575 | 560 | ||
576 | lck_flags &= (LM_FLAG_TRY | LM_FLAG_TRY_1CB | LM_FLAG_NOEXP | | 561 | lck_flags &= (LM_FLAG_TRY | LM_FLAG_TRY_1CB | LM_FLAG_NOEXP | |
577 | LM_FLAG_PRIORITY); | 562 | LM_FLAG_PRIORITY); |
578 | BUG_ON(gl->gl_state == target); | 563 | GLOCK_BUG_ON(gl, gl->gl_state == target); |
579 | BUG_ON(gl->gl_state == gl->gl_target); | 564 | GLOCK_BUG_ON(gl, gl->gl_state == gl->gl_target); |
580 | if ((target == LM_ST_UNLOCKED || target == LM_ST_DEFERRED) && | 565 | if ((target == LM_ST_UNLOCKED || target == LM_ST_DEFERRED) && |
581 | glops->go_inval) { | 566 | glops->go_inval) { |
582 | set_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags); | 567 | set_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags); |
583 | do_error(gl, 0); /* Fail queued try locks */ | 568 | do_error(gl, 0); /* Fail queued try locks */ |
584 | } | 569 | } |
570 | gl->gl_req = target; | ||
585 | spin_unlock(&gl->gl_spin); | 571 | spin_unlock(&gl->gl_spin); |
586 | if (glops->go_xmote_th) | 572 | if (glops->go_xmote_th) |
587 | glops->go_xmote_th(gl); | 573 | glops->go_xmote_th(gl); |
@@ -594,15 +580,17 @@ __acquires(&gl->gl_spin) | |||
594 | gl->gl_state == LM_ST_DEFERRED) && | 580 | gl->gl_state == LM_ST_DEFERRED) && |
595 | !(lck_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB))) | 581 | !(lck_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB))) |
596 | lck_flags |= LM_FLAG_TRY_1CB; | 582 | lck_flags |= LM_FLAG_TRY_1CB; |
597 | ret = gfs2_lm_lock(sdp, gl, target, lck_flags); | ||
598 | 583 | ||
599 | if (!(ret & LM_OUT_ASYNC)) { | 584 | if (sdp->sd_lockstruct.ls_ops->lm_lock) { |
600 | finish_xmote(gl, ret); | 585 | /* lock_dlm */ |
586 | ret = sdp->sd_lockstruct.ls_ops->lm_lock(gl, target, lck_flags); | ||
587 | GLOCK_BUG_ON(gl, ret); | ||
588 | } else { /* lock_nolock */ | ||
589 | finish_xmote(gl, target); | ||
601 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) | 590 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) |
602 | gfs2_glock_put(gl); | 591 | gfs2_glock_put(gl); |
603 | } else { | ||
604 | GLOCK_BUG_ON(gl, ret != LM_OUT_ASYNC); | ||
605 | } | 592 | } |
593 | |||
606 | spin_lock(&gl->gl_spin); | 594 | spin_lock(&gl->gl_spin); |
607 | } | 595 | } |
608 | 596 | ||
@@ -951,17 +939,22 @@ int gfs2_glock_wait(struct gfs2_holder *gh) | |||
951 | 939 | ||
952 | void gfs2_print_dbg(struct seq_file *seq, const char *fmt, ...) | 940 | void gfs2_print_dbg(struct seq_file *seq, const char *fmt, ...) |
953 | { | 941 | { |
942 | struct va_format vaf; | ||
954 | va_list args; | 943 | va_list args; |
955 | 944 | ||
956 | va_start(args, fmt); | 945 | va_start(args, fmt); |
946 | |||
957 | if (seq) { | 947 | if (seq) { |
958 | struct gfs2_glock_iter *gi = seq->private; | 948 | struct gfs2_glock_iter *gi = seq->private; |
959 | vsprintf(gi->string, fmt, args); | 949 | vsprintf(gi->string, fmt, args); |
960 | seq_printf(seq, gi->string); | 950 | seq_printf(seq, gi->string); |
961 | } else { | 951 | } else { |
962 | printk(KERN_ERR " "); | 952 | vaf.fmt = fmt; |
963 | vprintk(fmt, args); | 953 | vaf.va = &args; |
954 | |||
955 | printk(KERN_ERR " %pV", &vaf); | ||
964 | } | 956 | } |
957 | |||
965 | va_end(args); | 958 | va_end(args); |
966 | } | 959 | } |
967 | 960 | ||
@@ -1361,24 +1354,28 @@ static int gfs2_should_freeze(const struct gfs2_glock *gl) | |||
1361 | * @gl: Pointer to the glock | 1354 | * @gl: Pointer to the glock |
1362 | * @ret: The return value from the dlm | 1355 | * @ret: The return value from the dlm |
1363 | * | 1356 | * |
1357 | * The gl_reply field is under the gl_spin lock so that it is ok | ||
1358 | * to use a bitfield shared with other glock state fields. | ||
1364 | */ | 1359 | */ |
1365 | 1360 | ||
1366 | void gfs2_glock_complete(struct gfs2_glock *gl, int ret) | 1361 | void gfs2_glock_complete(struct gfs2_glock *gl, int ret) |
1367 | { | 1362 | { |
1368 | struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct; | 1363 | struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct; |
1369 | 1364 | ||
1365 | spin_lock(&gl->gl_spin); | ||
1370 | gl->gl_reply = ret; | 1366 | gl->gl_reply = ret; |
1371 | 1367 | ||
1372 | if (unlikely(test_bit(DFL_BLOCK_LOCKS, &ls->ls_flags))) { | 1368 | if (unlikely(test_bit(DFL_BLOCK_LOCKS, &ls->ls_flags))) { |
1373 | spin_lock(&gl->gl_spin); | ||
1374 | if (gfs2_should_freeze(gl)) { | 1369 | if (gfs2_should_freeze(gl)) { |
1375 | set_bit(GLF_FROZEN, &gl->gl_flags); | 1370 | set_bit(GLF_FROZEN, &gl->gl_flags); |
1376 | spin_unlock(&gl->gl_spin); | 1371 | spin_unlock(&gl->gl_spin); |
1377 | return; | 1372 | return; |
1378 | } | 1373 | } |
1379 | spin_unlock(&gl->gl_spin); | ||
1380 | } | 1374 | } |
1375 | |||
1376 | spin_unlock(&gl->gl_spin); | ||
1381 | set_bit(GLF_REPLY_PENDING, &gl->gl_flags); | 1377 | set_bit(GLF_REPLY_PENDING, &gl->gl_flags); |
1378 | smp_wmb(); | ||
1382 | gfs2_glock_hold(gl); | 1379 | gfs2_glock_hold(gl); |
1383 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) | 1380 | if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) |
1384 | gfs2_glock_put(gl); | 1381 | gfs2_glock_put(gl); |
@@ -1626,18 +1623,17 @@ static const char *hflags2str(char *buf, unsigned flags, unsigned long iflags) | |||
1626 | static int dump_holder(struct seq_file *seq, const struct gfs2_holder *gh) | 1623 | static int dump_holder(struct seq_file *seq, const struct gfs2_holder *gh) |
1627 | { | 1624 | { |
1628 | struct task_struct *gh_owner = NULL; | 1625 | struct task_struct *gh_owner = NULL; |
1629 | char buffer[KSYM_SYMBOL_LEN]; | ||
1630 | char flags_buf[32]; | 1626 | char flags_buf[32]; |
1631 | 1627 | ||
1632 | sprint_symbol(buffer, gh->gh_ip); | ||
1633 | if (gh->gh_owner_pid) | 1628 | if (gh->gh_owner_pid) |
1634 | gh_owner = pid_task(gh->gh_owner_pid, PIDTYPE_PID); | 1629 | gh_owner = pid_task(gh->gh_owner_pid, PIDTYPE_PID); |
1635 | gfs2_print_dbg(seq, " H: s:%s f:%s e:%d p:%ld [%s] %s\n", | 1630 | gfs2_print_dbg(seq, " H: s:%s f:%s e:%d p:%ld [%s] %pS\n", |
1636 | state2str(gh->gh_state), | 1631 | state2str(gh->gh_state), |
1637 | hflags2str(flags_buf, gh->gh_flags, gh->gh_iflags), | 1632 | hflags2str(flags_buf, gh->gh_flags, gh->gh_iflags), |
1638 | gh->gh_error, | 1633 | gh->gh_error, |
1639 | gh->gh_owner_pid ? (long)pid_nr(gh->gh_owner_pid) : -1, | 1634 | gh->gh_owner_pid ? (long)pid_nr(gh->gh_owner_pid) : -1, |
1640 | gh_owner ? gh_owner->comm : "(ended)", buffer); | 1635 | gh_owner ? gh_owner->comm : "(ended)", |
1636 | (void *)gh->gh_ip); | ||
1641 | return 0; | 1637 | return 0; |
1642 | } | 1638 | } |
1643 | 1639 | ||
@@ -1782,12 +1778,13 @@ int __init gfs2_glock_init(void) | |||
1782 | } | 1778 | } |
1783 | #endif | 1779 | #endif |
1784 | 1780 | ||
1785 | glock_workqueue = alloc_workqueue("glock_workqueue", WQ_RESCUER | | 1781 | glock_workqueue = alloc_workqueue("glock_workqueue", WQ_MEM_RECLAIM | |
1786 | WQ_HIGHPRI | WQ_FREEZEABLE, 0); | 1782 | WQ_HIGHPRI | WQ_FREEZEABLE, 0); |
1787 | if (IS_ERR(glock_workqueue)) | 1783 | if (IS_ERR(glock_workqueue)) |
1788 | return PTR_ERR(glock_workqueue); | 1784 | return PTR_ERR(glock_workqueue); |
1789 | gfs2_delete_workqueue = alloc_workqueue("delete_workqueue", WQ_RESCUER | | 1785 | gfs2_delete_workqueue = alloc_workqueue("delete_workqueue", |
1790 | WQ_FREEZEABLE, 0); | 1786 | WQ_MEM_RECLAIM | WQ_FREEZEABLE, |
1787 | 0); | ||
1791 | if (IS_ERR(gfs2_delete_workqueue)) { | 1788 | if (IS_ERR(gfs2_delete_workqueue)) { |
1792 | destroy_workqueue(glock_workqueue); | 1789 | destroy_workqueue(glock_workqueue); |
1793 | return PTR_ERR(gfs2_delete_workqueue); | 1790 | return PTR_ERR(gfs2_delete_workqueue); |
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h index db1c26d6d220..691851ceb615 100644 --- a/fs/gfs2/glock.h +++ b/fs/gfs2/glock.h | |||
@@ -87,11 +87,10 @@ enum { | |||
87 | #define GL_ASYNC 0x00000040 | 87 | #define GL_ASYNC 0x00000040 |
88 | #define GL_EXACT 0x00000080 | 88 | #define GL_EXACT 0x00000080 |
89 | #define GL_SKIP 0x00000100 | 89 | #define GL_SKIP 0x00000100 |
90 | #define GL_ATIME 0x00000200 | ||
91 | #define GL_NOCACHE 0x00000400 | 90 | #define GL_NOCACHE 0x00000400 |
92 | 91 | ||
93 | /* | 92 | /* |
94 | * lm_lock() and lm_async_cb return flags | 93 | * lm_async_cb return flags |
95 | * | 94 | * |
96 | * LM_OUT_ST_MASK | 95 | * LM_OUT_ST_MASK |
97 | * Masks the lower two bits of lock state in the returned value. | 96 | * Masks the lower two bits of lock state in the returned value. |
@@ -99,15 +98,11 @@ enum { | |||
99 | * LM_OUT_CANCELED | 98 | * LM_OUT_CANCELED |
100 | * The lock request was canceled. | 99 | * The lock request was canceled. |
101 | * | 100 | * |
102 | * LM_OUT_ASYNC | ||
103 | * The result of the request will be returned in an LM_CB_ASYNC callback. | ||
104 | * | ||
105 | */ | 101 | */ |
106 | 102 | ||
107 | #define LM_OUT_ST_MASK 0x00000003 | 103 | #define LM_OUT_ST_MASK 0x00000003 |
108 | #define LM_OUT_CANCELED 0x00000008 | 104 | #define LM_OUT_CANCELED 0x00000008 |
109 | #define LM_OUT_ASYNC 0x00000080 | 105 | #define LM_OUT_ERROR 0x00000004 |
110 | #define LM_OUT_ERROR 0x00000100 | ||
111 | 106 | ||
112 | /* | 107 | /* |
113 | * lm_recovery_done() messages | 108 | * lm_recovery_done() messages |
@@ -124,25 +119,12 @@ struct lm_lockops { | |||
124 | void (*lm_unmount) (struct gfs2_sbd *sdp); | 119 | void (*lm_unmount) (struct gfs2_sbd *sdp); |
125 | void (*lm_withdraw) (struct gfs2_sbd *sdp); | 120 | void (*lm_withdraw) (struct gfs2_sbd *sdp); |
126 | void (*lm_put_lock) (struct kmem_cache *cachep, struct gfs2_glock *gl); | 121 | void (*lm_put_lock) (struct kmem_cache *cachep, struct gfs2_glock *gl); |
127 | unsigned int (*lm_lock) (struct gfs2_glock *gl, | 122 | int (*lm_lock) (struct gfs2_glock *gl, unsigned int req_state, |
128 | unsigned int req_state, unsigned int flags); | 123 | unsigned int flags); |
129 | void (*lm_cancel) (struct gfs2_glock *gl); | 124 | void (*lm_cancel) (struct gfs2_glock *gl); |
130 | const match_table_t *lm_tokens; | 125 | const match_table_t *lm_tokens; |
131 | }; | 126 | }; |
132 | 127 | ||
133 | #define LM_FLAG_TRY 0x00000001 | ||
134 | #define LM_FLAG_TRY_1CB 0x00000002 | ||
135 | #define LM_FLAG_NOEXP 0x00000004 | ||
136 | #define LM_FLAG_ANY 0x00000008 | ||
137 | #define LM_FLAG_PRIORITY 0x00000010 | ||
138 | |||
139 | #define GL_ASYNC 0x00000040 | ||
140 | #define GL_EXACT 0x00000080 | ||
141 | #define GL_SKIP 0x00000100 | ||
142 | #define GL_NOCACHE 0x00000400 | ||
143 | |||
144 | #define GLR_TRYFAILED 13 | ||
145 | |||
146 | extern struct workqueue_struct *gfs2_delete_workqueue; | 128 | extern struct workqueue_struct *gfs2_delete_workqueue; |
147 | static inline struct gfs2_holder *gfs2_glock_is_locked_by_me(struct gfs2_glock *gl) | 129 | static inline struct gfs2_holder *gfs2_glock_is_locked_by_me(struct gfs2_glock *gl) |
148 | { | 130 | { |
@@ -212,6 +194,8 @@ int gfs2_glock_nq_num(struct gfs2_sbd *sdp, | |||
212 | int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs); | 194 | int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs); |
213 | void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs); | 195 | void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs); |
214 | void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs); | 196 | void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs); |
197 | |||
198 | __attribute__ ((format(printf, 2, 3))) | ||
215 | void gfs2_print_dbg(struct seq_file *seq, const char *fmt, ...); | 199 | void gfs2_print_dbg(struct seq_file *seq, const char *fmt, ...); |
216 | 200 | ||
217 | /** | 201 | /** |
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 0d149dcc04e5..263561bf1a50 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c | |||
@@ -325,7 +325,6 @@ static void trans_go_sync(struct gfs2_glock *gl) | |||
325 | 325 | ||
326 | if (gl->gl_state != LM_ST_UNLOCKED && | 326 | if (gl->gl_state != LM_ST_UNLOCKED && |
327 | test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { | 327 | test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { |
328 | flush_workqueue(gfs2_delete_workqueue); | ||
329 | gfs2_meta_syncfs(sdp); | 328 | gfs2_meta_syncfs(sdp); |
330 | gfs2_log_shutdown(sdp); | 329 | gfs2_log_shutdown(sdp); |
331 | } | 330 | } |
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 764fbb49efc8..a79790c06275 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
@@ -11,6 +11,7 @@ | |||
11 | #define __INCORE_DOT_H__ | 11 | #define __INCORE_DOT_H__ |
12 | 12 | ||
13 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
14 | #include <linux/kobject.h> | ||
14 | #include <linux/workqueue.h> | 15 | #include <linux/workqueue.h> |
15 | #include <linux/dlm.h> | 16 | #include <linux/dlm.h> |
16 | #include <linux/buffer_head.h> | 17 | #include <linux/buffer_head.h> |
@@ -207,12 +208,14 @@ struct gfs2_glock { | |||
207 | 208 | ||
208 | spinlock_t gl_spin; | 209 | spinlock_t gl_spin; |
209 | 210 | ||
210 | unsigned int gl_state; | 211 | /* State fields protected by gl_spin */ |
211 | unsigned int gl_target; | 212 | unsigned int gl_state:2, /* Current state */ |
212 | unsigned int gl_reply; | 213 | gl_target:2, /* Target state */ |
214 | gl_demote_state:2, /* State requested by remote node */ | ||
215 | gl_req:2, /* State in last dlm request */ | ||
216 | gl_reply:8; /* Last reply from the dlm */ | ||
217 | |||
213 | unsigned int gl_hash; | 218 | unsigned int gl_hash; |
214 | unsigned int gl_req; | ||
215 | unsigned int gl_demote_state; /* state requested by remote node */ | ||
216 | unsigned long gl_demote_time; /* time of first demote request */ | 219 | unsigned long gl_demote_time; /* time of first demote request */ |
217 | struct list_head gl_holders; | 220 | struct list_head gl_holders; |
218 | 221 | ||
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index e1213f7f9217..2232b3c780bd 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
@@ -509,7 +509,7 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, | |||
509 | } | 509 | } |
510 | 510 | ||
511 | if (!is_root) { | 511 | if (!is_root) { |
512 | error = gfs2_permission(dir, MAY_EXEC); | 512 | error = gfs2_permission(dir, MAY_EXEC, 0); |
513 | if (error) | 513 | if (error) |
514 | goto out; | 514 | goto out; |
515 | } | 515 | } |
@@ -539,7 +539,7 @@ static int create_ok(struct gfs2_inode *dip, const struct qstr *name, | |||
539 | { | 539 | { |
540 | int error; | 540 | int error; |
541 | 541 | ||
542 | error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC); | 542 | error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, 0); |
543 | if (error) | 543 | if (error) |
544 | return error; | 544 | return error; |
545 | 545 | ||
@@ -916,17 +916,8 @@ static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) | |||
916 | if (error) | 916 | if (error) |
917 | return error; | 917 | return error; |
918 | 918 | ||
919 | if ((attr->ia_valid & ATTR_SIZE) && | ||
920 | attr->ia_size != i_size_read(inode)) { | ||
921 | error = vmtruncate(inode, attr->ia_size); | ||
922 | if (error) | ||
923 | return error; | ||
924 | } | ||
925 | |||
926 | setattr_copy(inode, attr); | 919 | setattr_copy(inode, attr); |
927 | mark_inode_dirty(inode); | 920 | mark_inode_dirty(inode); |
928 | |||
929 | gfs2_assert_warn(GFS2_SB(inode), !error); | ||
930 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 921 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); |
931 | gfs2_dinode_out(ip, dibh->b_data); | 922 | gfs2_dinode_out(ip, dibh->b_data); |
932 | brelse(dibh); | 923 | brelse(dibh); |
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h index d8499fadcc53..732a183efdb3 100644 --- a/fs/gfs2/inode.h +++ b/fs/gfs2/inode.h | |||
@@ -113,7 +113,7 @@ extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, | |||
113 | extern struct inode *gfs2_createi(struct gfs2_holder *ghs, | 113 | extern struct inode *gfs2_createi(struct gfs2_holder *ghs, |
114 | const struct qstr *name, | 114 | const struct qstr *name, |
115 | unsigned int mode, dev_t dev); | 115 | unsigned int mode, dev_t dev); |
116 | extern int gfs2_permission(struct inode *inode, int mask); | 116 | extern int gfs2_permission(struct inode *inode, int mask, unsigned int flags); |
117 | extern int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr); | 117 | extern int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr); |
118 | extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name); | 118 | extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name); |
119 | extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf); | 119 | extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf); |
diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c index 1c09425b45fd..6e493aee28f8 100644 --- a/fs/gfs2/lock_dlm.c +++ b/fs/gfs2/lock_dlm.c | |||
@@ -146,15 +146,13 @@ static u32 make_flags(const u32 lkid, const unsigned int gfs_flags, | |||
146 | return lkf; | 146 | return lkf; |
147 | } | 147 | } |
148 | 148 | ||
149 | static unsigned int gdlm_lock(struct gfs2_glock *gl, | 149 | static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state, |
150 | unsigned int req_state, unsigned int flags) | 150 | unsigned int flags) |
151 | { | 151 | { |
152 | struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct; | 152 | struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct; |
153 | int error; | ||
154 | int req; | 153 | int req; |
155 | u32 lkf; | 154 | u32 lkf; |
156 | 155 | ||
157 | gl->gl_req = req_state; | ||
158 | req = make_mode(req_state); | 156 | req = make_mode(req_state); |
159 | lkf = make_flags(gl->gl_lksb.sb_lkid, flags, req); | 157 | lkf = make_flags(gl->gl_lksb.sb_lkid, flags, req); |
160 | 158 | ||
@@ -162,13 +160,8 @@ static unsigned int gdlm_lock(struct gfs2_glock *gl, | |||
162 | * Submit the actual lock request. | 160 | * Submit the actual lock request. |
163 | */ | 161 | */ |
164 | 162 | ||
165 | error = dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, gl->gl_strname, | 163 | return dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, gl->gl_strname, |
166 | GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast); | 164 | GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast); |
167 | if (error == -EAGAIN) | ||
168 | return 0; | ||
169 | if (error) | ||
170 | return LM_OUT_ERROR; | ||
171 | return LM_OUT_ASYNC; | ||
172 | } | 165 | } |
173 | 166 | ||
174 | static void gdlm_put_lock(struct kmem_cache *cachep, struct gfs2_glock *gl) | 167 | static void gdlm_put_lock(struct kmem_cache *cachep, struct gfs2_glock *gl) |
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 3eb1393f7b81..2aeabd4218cc 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c | |||
@@ -440,7 +440,7 @@ static int gfs2_lookup_root(struct super_block *sb, struct dentry **dptr, | |||
440 | iput(inode); | 440 | iput(inode); |
441 | return -ENOMEM; | 441 | return -ENOMEM; |
442 | } | 442 | } |
443 | dentry->d_op = &gfs2_dops; | 443 | d_set_d_op(dentry, &gfs2_dops); |
444 | *dptr = dentry; | 444 | *dptr = dentry; |
445 | return 0; | 445 | return 0; |
446 | } | 446 | } |
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 12cbea7502c2..1501db4f0e6d 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c | |||
@@ -106,7 +106,7 @@ static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, | |||
106 | { | 106 | { |
107 | struct inode *inode = NULL; | 107 | struct inode *inode = NULL; |
108 | 108 | ||
109 | dentry->d_op = &gfs2_dops; | 109 | d_set_d_op(dentry, &gfs2_dops); |
110 | 110 | ||
111 | inode = gfs2_lookupi(dir, &dentry->d_name, 0); | 111 | inode = gfs2_lookupi(dir, &dentry->d_name, 0); |
112 | if (inode && IS_ERR(inode)) | 112 | if (inode && IS_ERR(inode)) |
@@ -166,7 +166,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir, | |||
166 | if (error) | 166 | if (error) |
167 | goto out_child; | 167 | goto out_child; |
168 | 168 | ||
169 | error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC); | 169 | error = gfs2_permission(dir, MAY_WRITE | MAY_EXEC, 0); |
170 | if (error) | 170 | if (error) |
171 | goto out_gunlock; | 171 | goto out_gunlock; |
172 | 172 | ||
@@ -289,7 +289,7 @@ static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name, | |||
289 | if (IS_APPEND(&dip->i_inode)) | 289 | if (IS_APPEND(&dip->i_inode)) |
290 | return -EPERM; | 290 | return -EPERM; |
291 | 291 | ||
292 | error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC); | 292 | error = gfs2_permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, 0); |
293 | if (error) | 293 | if (error) |
294 | return error; | 294 | return error; |
295 | 295 | ||
@@ -822,7 +822,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, | |||
822 | } | 822 | } |
823 | } | 823 | } |
824 | } else { | 824 | } else { |
825 | error = gfs2_permission(ndir, MAY_WRITE | MAY_EXEC); | 825 | error = gfs2_permission(ndir, MAY_WRITE | MAY_EXEC, 0); |
826 | if (error) | 826 | if (error) |
827 | goto out_gunlock; | 827 | goto out_gunlock; |
828 | 828 | ||
@@ -857,7 +857,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, | |||
857 | /* Check out the dir to be renamed */ | 857 | /* Check out the dir to be renamed */ |
858 | 858 | ||
859 | if (dir_rename) { | 859 | if (dir_rename) { |
860 | error = gfs2_permission(odentry->d_inode, MAY_WRITE); | 860 | error = gfs2_permission(odentry->d_inode, MAY_WRITE, 0); |
861 | if (error) | 861 | if (error) |
862 | goto out_gunlock; | 862 | goto out_gunlock; |
863 | } | 863 | } |
@@ -1041,13 +1041,17 @@ static void gfs2_put_link(struct dentry *dentry, struct nameidata *nd, void *p) | |||
1041 | * Returns: errno | 1041 | * Returns: errno |
1042 | */ | 1042 | */ |
1043 | 1043 | ||
1044 | int gfs2_permission(struct inode *inode, int mask) | 1044 | int gfs2_permission(struct inode *inode, int mask, unsigned int flags) |
1045 | { | 1045 | { |
1046 | struct gfs2_inode *ip = GFS2_I(inode); | 1046 | struct gfs2_inode *ip; |
1047 | struct gfs2_holder i_gh; | 1047 | struct gfs2_holder i_gh; |
1048 | int error; | 1048 | int error; |
1049 | int unlock = 0; | 1049 | int unlock = 0; |
1050 | 1050 | ||
1051 | if (flags & IPERM_FLAG_RCU) | ||
1052 | return -ECHILD; | ||
1053 | |||
1054 | ip = GFS2_I(inode); | ||
1051 | if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { | 1055 | if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { |
1052 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); | 1056 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh); |
1053 | if (error) | 1057 | if (error) |
@@ -1058,7 +1062,7 @@ int gfs2_permission(struct inode *inode, int mask) | |||
1058 | if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode)) | 1062 | if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode)) |
1059 | error = -EACCES; | 1063 | error = -EACCES; |
1060 | else | 1064 | else |
1061 | error = generic_permission(inode, mask, gfs2_check_acl); | 1065 | error = generic_permission(inode, mask, flags, gfs2_check_acl); |
1062 | if (unlock) | 1066 | if (unlock) |
1063 | gfs2_glock_dq_uninit(&i_gh); | 1067 | gfs2_glock_dq_uninit(&i_gh); |
1064 | 1068 | ||
@@ -1069,7 +1073,6 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) | |||
1069 | { | 1073 | { |
1070 | struct gfs2_inode *ip = GFS2_I(inode); | 1074 | struct gfs2_inode *ip = GFS2_I(inode); |
1071 | struct gfs2_sbd *sdp = GFS2_SB(inode); | 1075 | struct gfs2_sbd *sdp = GFS2_SB(inode); |
1072 | struct buffer_head *dibh; | ||
1073 | u32 ouid, ogid, nuid, ngid; | 1076 | u32 ouid, ogid, nuid, ngid; |
1074 | int error; | 1077 | int error; |
1075 | 1078 | ||
@@ -1100,25 +1103,10 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) | |||
1100 | if (error) | 1103 | if (error) |
1101 | goto out_gunlock_q; | 1104 | goto out_gunlock_q; |
1102 | 1105 | ||
1103 | error = gfs2_meta_inode_buffer(ip, &dibh); | 1106 | error = gfs2_setattr_simple(ip, attr); |
1104 | if (error) | 1107 | if (error) |
1105 | goto out_end_trans; | 1108 | goto out_end_trans; |
1106 | 1109 | ||
1107 | if ((attr->ia_valid & ATTR_SIZE) && | ||
1108 | attr->ia_size != i_size_read(inode)) { | ||
1109 | int error; | ||
1110 | |||
1111 | error = vmtruncate(inode, attr->ia_size); | ||
1112 | gfs2_assert_warn(sdp, !error); | ||
1113 | } | ||
1114 | |||
1115 | setattr_copy(inode, attr); | ||
1116 | mark_inode_dirty(inode); | ||
1117 | |||
1118 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | ||
1119 | gfs2_dinode_out(ip, dibh->b_data); | ||
1120 | brelse(dibh); | ||
1121 | |||
1122 | if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) { | 1110 | if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) { |
1123 | u64 blocks = gfs2_get_inode_blocks(&ip->i_inode); | 1111 | u64 blocks = gfs2_get_inode_blocks(&ip->i_inode); |
1124 | gfs2_quota_change(ip, -blocks, ouid, ogid); | 1112 | gfs2_quota_change(ip, -blocks, ouid, ogid); |
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index f606baf9ba72..a689901963de 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c | |||
@@ -666,6 +666,10 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, | |||
666 | qp->qu_limit = cpu_to_be64(fdq->d_blk_hardlimit >> sdp->sd_fsb2bb_shift); | 666 | qp->qu_limit = cpu_to_be64(fdq->d_blk_hardlimit >> sdp->sd_fsb2bb_shift); |
667 | qd->qd_qb.qb_limit = qp->qu_limit; | 667 | qd->qd_qb.qb_limit = qp->qu_limit; |
668 | } | 668 | } |
669 | if (fdq->d_fieldmask & FS_DQ_BCOUNT) { | ||
670 | qp->qu_value = cpu_to_be64(fdq->d_bcount >> sdp->sd_fsb2bb_shift); | ||
671 | qd->qd_qb.qb_value = qp->qu_value; | ||
672 | } | ||
669 | } | 673 | } |
670 | 674 | ||
671 | /* Write the quota into the quota file on disk */ | 675 | /* Write the quota into the quota file on disk */ |
@@ -1509,7 +1513,7 @@ out: | |||
1509 | } | 1513 | } |
1510 | 1514 | ||
1511 | /* GFS2 only supports a subset of the XFS fields */ | 1515 | /* GFS2 only supports a subset of the XFS fields */ |
1512 | #define GFS2_FIELDMASK (FS_DQ_BSOFT|FS_DQ_BHARD) | 1516 | #define GFS2_FIELDMASK (FS_DQ_BSOFT|FS_DQ_BHARD|FS_DQ_BCOUNT) |
1513 | 1517 | ||
1514 | static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id, | 1518 | static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id, |
1515 | struct fs_disk_quota *fdq) | 1519 | struct fs_disk_quota *fdq) |
@@ -1569,9 +1573,15 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id, | |||
1569 | if ((fdq->d_fieldmask & FS_DQ_BSOFT) && | 1573 | if ((fdq->d_fieldmask & FS_DQ_BSOFT) && |
1570 | ((fdq->d_blk_softlimit >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_warn))) | 1574 | ((fdq->d_blk_softlimit >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_warn))) |
1571 | fdq->d_fieldmask ^= FS_DQ_BSOFT; | 1575 | fdq->d_fieldmask ^= FS_DQ_BSOFT; |
1576 | |||
1572 | if ((fdq->d_fieldmask & FS_DQ_BHARD) && | 1577 | if ((fdq->d_fieldmask & FS_DQ_BHARD) && |
1573 | ((fdq->d_blk_hardlimit >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_limit))) | 1578 | ((fdq->d_blk_hardlimit >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_limit))) |
1574 | fdq->d_fieldmask ^= FS_DQ_BHARD; | 1579 | fdq->d_fieldmask ^= FS_DQ_BHARD; |
1580 | |||
1581 | if ((fdq->d_fieldmask & FS_DQ_BCOUNT) && | ||
1582 | ((fdq->d_bcount >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_value))) | ||
1583 | fdq->d_fieldmask ^= FS_DQ_BCOUNT; | ||
1584 | |||
1575 | if (fdq->d_fieldmask == 0) | 1585 | if (fdq->d_fieldmask == 0) |
1576 | goto out_i; | 1586 | goto out_i; |
1577 | 1587 | ||
@@ -1620,4 +1630,3 @@ const struct quotactl_ops gfs2_quotactl_ops = { | |||
1620 | .get_dqblk = gfs2_get_dqblk, | 1630 | .get_dqblk = gfs2_get_dqblk, |
1621 | .set_dqblk = gfs2_set_dqblk, | 1631 | .set_dqblk = gfs2_set_dqblk, |
1622 | }; | 1632 | }; |
1623 | |||
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 33c8407b876f..7293ea27020c 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -500,7 +500,7 @@ u64 gfs2_ri_total(struct gfs2_sbd *sdp) | |||
500 | for (rgrps = 0;; rgrps++) { | 500 | for (rgrps = 0;; rgrps++) { |
501 | loff_t pos = rgrps * sizeof(struct gfs2_rindex); | 501 | loff_t pos = rgrps * sizeof(struct gfs2_rindex); |
502 | 502 | ||
503 | if (pos + sizeof(struct gfs2_rindex) >= i_size_read(inode)) | 503 | if (pos + sizeof(struct gfs2_rindex) > i_size_read(inode)) |
504 | break; | 504 | break; |
505 | error = gfs2_internal_read(ip, &ra_state, buf, &pos, | 505 | error = gfs2_internal_read(ip, &ra_state, buf, &pos, |
506 | sizeof(struct gfs2_rindex)); | 506 | sizeof(struct gfs2_rindex)); |
@@ -583,7 +583,7 @@ static int read_rindex_entry(struct gfs2_inode *ip, | |||
583 | * Returns: 0 on successful update, error code otherwise | 583 | * Returns: 0 on successful update, error code otherwise |
584 | */ | 584 | */ |
585 | 585 | ||
586 | static int gfs2_ri_update(struct gfs2_inode *ip) | 586 | int gfs2_ri_update(struct gfs2_inode *ip) |
587 | { | 587 | { |
588 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 588 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
589 | struct inode *inode = &ip->i_inode; | 589 | struct inode *inode = &ip->i_inode; |
@@ -614,46 +614,6 @@ static int gfs2_ri_update(struct gfs2_inode *ip) | |||
614 | } | 614 | } |
615 | 615 | ||
616 | /** | 616 | /** |
617 | * gfs2_ri_update_special - Pull in a new resource index from the disk | ||
618 | * | ||
619 | * This is a special version that's safe to call from gfs2_inplace_reserve_i. | ||
620 | * In this case we know that we don't have any resource groups in memory yet. | ||
621 | * | ||
622 | * @ip: pointer to the rindex inode | ||
623 | * | ||
624 | * Returns: 0 on successful update, error code otherwise | ||
625 | */ | ||
626 | static int gfs2_ri_update_special(struct gfs2_inode *ip) | ||
627 | { | ||
628 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | ||
629 | struct inode *inode = &ip->i_inode; | ||
630 | struct file_ra_state ra_state; | ||
631 | struct gfs2_rgrpd *rgd; | ||
632 | unsigned int max_data = 0; | ||
633 | int error; | ||
634 | |||
635 | file_ra_state_init(&ra_state, inode->i_mapping); | ||
636 | for (sdp->sd_rgrps = 0;; sdp->sd_rgrps++) { | ||
637 | /* Ignore partials */ | ||
638 | if ((sdp->sd_rgrps + 1) * sizeof(struct gfs2_rindex) > | ||
639 | i_size_read(inode)) | ||
640 | break; | ||
641 | error = read_rindex_entry(ip, &ra_state); | ||
642 | if (error) { | ||
643 | clear_rgrpdi(sdp); | ||
644 | return error; | ||
645 | } | ||
646 | } | ||
647 | list_for_each_entry(rgd, &sdp->sd_rindex_list, rd_list) | ||
648 | if (rgd->rd_data > max_data) | ||
649 | max_data = rgd->rd_data; | ||
650 | sdp->sd_max_rg_data = max_data; | ||
651 | |||
652 | sdp->sd_rindex_uptodate = 1; | ||
653 | return 0; | ||
654 | } | ||
655 | |||
656 | /** | ||
657 | * gfs2_rindex_hold - Grab a lock on the rindex | 617 | * gfs2_rindex_hold - Grab a lock on the rindex |
658 | * @sdp: The GFS2 superblock | 618 | * @sdp: The GFS2 superblock |
659 | * @ri_gh: the glock holder | 619 | * @ri_gh: the glock holder |
@@ -1226,16 +1186,25 @@ int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex, | |||
1226 | error = gfs2_rindex_hold(sdp, &al->al_ri_gh); | 1186 | error = gfs2_rindex_hold(sdp, &al->al_ri_gh); |
1227 | else if (!sdp->sd_rgrps) /* We may not have the rindex read | 1187 | else if (!sdp->sd_rgrps) /* We may not have the rindex read |
1228 | in, so: */ | 1188 | in, so: */ |
1229 | error = gfs2_ri_update_special(ip); | 1189 | error = gfs2_ri_update(ip); |
1230 | if (error) | 1190 | if (error) |
1231 | return error; | 1191 | return error; |
1232 | } | 1192 | } |
1233 | 1193 | ||
1194 | try_again: | ||
1234 | do { | 1195 | do { |
1235 | error = get_local_rgrp(ip, &last_unlinked); | 1196 | error = get_local_rgrp(ip, &last_unlinked); |
1236 | /* If there is no space, flushing the log may release some */ | 1197 | /* If there is no space, flushing the log may release some */ |
1237 | if (error) | 1198 | if (error) { |
1199 | if (ip == GFS2_I(sdp->sd_rindex) && | ||
1200 | !sdp->sd_rindex_uptodate) { | ||
1201 | error = gfs2_ri_update(ip); | ||
1202 | if (error) | ||
1203 | return error; | ||
1204 | goto try_again; | ||
1205 | } | ||
1238 | gfs2_log_flush(sdp, NULL); | 1206 | gfs2_log_flush(sdp, NULL); |
1207 | } | ||
1239 | } while (error && tries++ < 3); | 1208 | } while (error && tries++ < 3); |
1240 | 1209 | ||
1241 | if (error) { | 1210 | if (error) { |
diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index 0e35c0466f9a..50c2bb04369c 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h | |||
@@ -48,6 +48,7 @@ extern int gfs2_inplace_reserve_i(struct gfs2_inode *ip, int hold_rindex, | |||
48 | 48 | ||
49 | extern void gfs2_inplace_release(struct gfs2_inode *ip); | 49 | extern void gfs2_inplace_release(struct gfs2_inode *ip); |
50 | 50 | ||
51 | extern int gfs2_ri_update(struct gfs2_inode *ip); | ||
51 | extern int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n); | 52 | extern int gfs2_alloc_block(struct gfs2_inode *ip, u64 *bn, unsigned int *n); |
52 | extern int gfs2_alloc_di(struct gfs2_inode *ip, u64 *bn, u64 *generation); | 53 | extern int gfs2_alloc_di(struct gfs2_inode *ip, u64 *bn, u64 *generation); |
53 | 54 | ||
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 2b2c4997430b..16c2ecac7eb7 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c | |||
@@ -1405,11 +1405,18 @@ static struct inode *gfs2_alloc_inode(struct super_block *sb) | |||
1405 | return &ip->i_inode; | 1405 | return &ip->i_inode; |
1406 | } | 1406 | } |
1407 | 1407 | ||
1408 | static void gfs2_destroy_inode(struct inode *inode) | 1408 | static void gfs2_i_callback(struct rcu_head *head) |
1409 | { | 1409 | { |
1410 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
1411 | INIT_LIST_HEAD(&inode->i_dentry); | ||
1410 | kmem_cache_free(gfs2_inode_cachep, inode); | 1412 | kmem_cache_free(gfs2_inode_cachep, inode); |
1411 | } | 1413 | } |
1412 | 1414 | ||
1415 | static void gfs2_destroy_inode(struct inode *inode) | ||
1416 | { | ||
1417 | call_rcu(&inode->i_rcu, gfs2_i_callback); | ||
1418 | } | ||
1419 | |||
1413 | const struct super_operations gfs2_super_ops = { | 1420 | const struct super_operations gfs2_super_ops = { |
1414 | .alloc_inode = gfs2_alloc_inode, | 1421 | .alloc_inode = gfs2_alloc_inode, |
1415 | .destroy_inode = gfs2_destroy_inode, | 1422 | .destroy_inode = gfs2_destroy_inode, |
diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c index 30b58f07c8a6..439b61c03262 100644 --- a/fs/gfs2/xattr.c +++ b/fs/gfs2/xattr.c | |||
@@ -1296,10 +1296,8 @@ fail: | |||
1296 | 1296 | ||
1297 | int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data) | 1297 | int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data) |
1298 | { | 1298 | { |
1299 | struct inode *inode = &ip->i_inode; | ||
1300 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1299 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
1301 | struct gfs2_ea_location el; | 1300 | struct gfs2_ea_location el; |
1302 | struct buffer_head *dibh; | ||
1303 | int error; | 1301 | int error; |
1304 | 1302 | ||
1305 | error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, GFS2_POSIX_ACL_ACCESS, &el); | 1303 | error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, GFS2_POSIX_ACL_ACCESS, &el); |
@@ -1321,26 +1319,7 @@ int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data) | |||
1321 | if (error) | 1319 | if (error) |
1322 | return error; | 1320 | return error; |
1323 | 1321 | ||
1324 | error = gfs2_meta_inode_buffer(ip, &dibh); | 1322 | error = gfs2_setattr_simple(ip, attr); |
1325 | if (error) | ||
1326 | goto out_trans_end; | ||
1327 | |||
1328 | if ((attr->ia_valid & ATTR_SIZE) && | ||
1329 | attr->ia_size != i_size_read(inode)) { | ||
1330 | int error; | ||
1331 | |||
1332 | error = vmtruncate(inode, attr->ia_size); | ||
1333 | gfs2_assert_warn(GFS2_SB(inode), !error); | ||
1334 | } | ||
1335 | |||
1336 | setattr_copy(inode, attr); | ||
1337 | mark_inode_dirty(inode); | ||
1338 | |||
1339 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | ||
1340 | gfs2_dinode_out(ip, dibh->b_data); | ||
1341 | brelse(dibh); | ||
1342 | |||
1343 | out_trans_end: | ||
1344 | gfs2_trans_end(sdp); | 1323 | gfs2_trans_end(sdp); |
1345 | return error; | 1324 | return error; |
1346 | } | 1325 | } |
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index 2b3b8611b41b..ea4aefe7c652 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c | |||
@@ -25,7 +25,7 @@ static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry, | |||
25 | struct inode *inode = NULL; | 25 | struct inode *inode = NULL; |
26 | int res; | 26 | int res; |
27 | 27 | ||
28 | dentry->d_op = &hfs_dentry_operations; | 28 | d_set_d_op(dentry, &hfs_dentry_operations); |
29 | 29 | ||
30 | hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd); | 30 | hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd); |
31 | hfs_cat_build_key(dir->i_sb, fd.search_key, dir->i_ino, &dentry->d_name); | 31 | hfs_cat_build_key(dir->i_sb, fd.search_key, dir->i_ino, &dentry->d_name); |
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h index c8cffb81e849..ad97c2d58287 100644 --- a/fs/hfs/hfs_fs.h +++ b/fs/hfs/hfs_fs.h | |||
@@ -213,10 +213,14 @@ extern int hfs_part_find(struct super_block *, sector_t *, sector_t *); | |||
213 | /* string.c */ | 213 | /* string.c */ |
214 | extern const struct dentry_operations hfs_dentry_operations; | 214 | extern const struct dentry_operations hfs_dentry_operations; |
215 | 215 | ||
216 | extern int hfs_hash_dentry(struct dentry *, struct qstr *); | 216 | extern int hfs_hash_dentry(const struct dentry *, const struct inode *, |
217 | struct qstr *); | ||
217 | extern int hfs_strcmp(const unsigned char *, unsigned int, | 218 | extern int hfs_strcmp(const unsigned char *, unsigned int, |
218 | const unsigned char *, unsigned int); | 219 | const unsigned char *, unsigned int); |
219 | extern int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *); | 220 | extern int hfs_compare_dentry(const struct dentry *parent, |
221 | const struct inode *pinode, | ||
222 | const struct dentry *dentry, const struct inode *inode, | ||
223 | unsigned int len, const char *str, const struct qstr *name); | ||
220 | 224 | ||
221 | /* trans.c */ | 225 | /* trans.c */ |
222 | extern void hfs_asc2mac(struct super_block *, struct hfs_name *, struct qstr *); | 226 | extern void hfs_asc2mac(struct super_block *, struct hfs_name *, struct qstr *); |
diff --git a/fs/hfs/string.c b/fs/hfs/string.c index 927a5af79428..495a976a3cc9 100644 --- a/fs/hfs/string.c +++ b/fs/hfs/string.c | |||
@@ -51,7 +51,8 @@ static unsigned char caseorder[256] = { | |||
51 | /* | 51 | /* |
52 | * Hash a string to an integer in a case-independent way | 52 | * Hash a string to an integer in a case-independent way |
53 | */ | 53 | */ |
54 | int hfs_hash_dentry(struct dentry *dentry, struct qstr *this) | 54 | int hfs_hash_dentry(const struct dentry *dentry, const struct inode *inode, |
55 | struct qstr *this) | ||
55 | { | 56 | { |
56 | const unsigned char *name = this->name; | 57 | const unsigned char *name = this->name; |
57 | unsigned int hash, len = this->len; | 58 | unsigned int hash, len = this->len; |
@@ -92,21 +93,21 @@ int hfs_strcmp(const unsigned char *s1, unsigned int len1, | |||
92 | * Test for equality of two strings in the HFS filename character ordering. | 93 | * Test for equality of two strings in the HFS filename character ordering. |
93 | * return 1 on failure and 0 on success | 94 | * return 1 on failure and 0 on success |
94 | */ | 95 | */ |
95 | int hfs_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *s2) | 96 | int hfs_compare_dentry(const struct dentry *parent, const struct inode *pinode, |
97 | const struct dentry *dentry, const struct inode *inode, | ||
98 | unsigned int len, const char *str, const struct qstr *name) | ||
96 | { | 99 | { |
97 | const unsigned char *n1, *n2; | 100 | const unsigned char *n1, *n2; |
98 | int len; | ||
99 | 101 | ||
100 | len = s1->len; | ||
101 | if (len >= HFS_NAMELEN) { | 102 | if (len >= HFS_NAMELEN) { |
102 | if (s2->len < HFS_NAMELEN) | 103 | if (name->len < HFS_NAMELEN) |
103 | return 1; | 104 | return 1; |
104 | len = HFS_NAMELEN; | 105 | len = HFS_NAMELEN; |
105 | } else if (len != s2->len) | 106 | } else if (len != name->len) |
106 | return 1; | 107 | return 1; |
107 | 108 | ||
108 | n1 = s1->name; | 109 | n1 = str; |
109 | n2 = s2->name; | 110 | n2 = name->name; |
110 | while (len--) { | 111 | while (len--) { |
111 | if (caseorder[*n1++] != caseorder[*n2++]) | 112 | if (caseorder[*n1++] != caseorder[*n2++]) |
112 | return 1; | 113 | return 1; |
diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 4824c27cebb8..0bef62aa4f42 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c | |||
@@ -167,11 +167,18 @@ static struct inode *hfs_alloc_inode(struct super_block *sb) | |||
167 | return i ? &i->vfs_inode : NULL; | 167 | return i ? &i->vfs_inode : NULL; |
168 | } | 168 | } |
169 | 169 | ||
170 | static void hfs_destroy_inode(struct inode *inode) | 170 | static void hfs_i_callback(struct rcu_head *head) |
171 | { | 171 | { |
172 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
173 | INIT_LIST_HEAD(&inode->i_dentry); | ||
172 | kmem_cache_free(hfs_inode_cachep, HFS_I(inode)); | 174 | kmem_cache_free(hfs_inode_cachep, HFS_I(inode)); |
173 | } | 175 | } |
174 | 176 | ||
177 | static void hfs_destroy_inode(struct inode *inode) | ||
178 | { | ||
179 | call_rcu(&inode->i_rcu, hfs_i_callback); | ||
180 | } | ||
181 | |||
175 | static const struct super_operations hfs_super_operations = { | 182 | static const struct super_operations hfs_super_operations = { |
176 | .alloc_inode = hfs_alloc_inode, | 183 | .alloc_inode = hfs_alloc_inode, |
177 | .destroy_inode = hfs_destroy_inode, | 184 | .destroy_inode = hfs_destroy_inode, |
@@ -427,7 +434,7 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent) | |||
427 | if (!sb->s_root) | 434 | if (!sb->s_root) |
428 | goto bail_iput; | 435 | goto bail_iput; |
429 | 436 | ||
430 | sb->s_root->d_op = &hfs_dentry_operations; | 437 | d_set_d_op(sb->s_root, &hfs_dentry_operations); |
431 | 438 | ||
432 | /* everything's okay */ | 439 | /* everything's okay */ |
433 | return 0; | 440 | return 0; |
diff --git a/fs/hfs/sysdep.c b/fs/hfs/sysdep.c index 7478f5c219aa..19cf291eb91f 100644 --- a/fs/hfs/sysdep.c +++ b/fs/hfs/sysdep.c | |||
@@ -8,15 +8,20 @@ | |||
8 | * This file contains the code to do various system dependent things. | 8 | * This file contains the code to do various system dependent things. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/namei.h> | ||
11 | #include "hfs_fs.h" | 12 | #include "hfs_fs.h" |
12 | 13 | ||
13 | /* dentry case-handling: just lowercase everything */ | 14 | /* dentry case-handling: just lowercase everything */ |
14 | 15 | ||
15 | static int hfs_revalidate_dentry(struct dentry *dentry, struct nameidata *nd) | 16 | static int hfs_revalidate_dentry(struct dentry *dentry, struct nameidata *nd) |
16 | { | 17 | { |
17 | struct inode *inode = dentry->d_inode; | 18 | struct inode *inode; |
18 | int diff; | 19 | int diff; |
19 | 20 | ||
21 | if (nd->flags & LOOKUP_RCU) | ||
22 | return -ECHILD; | ||
23 | |||
24 | inode = dentry->d_inode; | ||
20 | if(!inode) | 25 | if(!inode) |
21 | return 1; | 26 | return 1; |
22 | 27 | ||
diff --git a/fs/hfsplus/bfind.c b/fs/hfsplus/bfind.c index d182438c7ae4..5d799c13205f 100644 --- a/fs/hfsplus/bfind.c +++ b/fs/hfsplus/bfind.c | |||
@@ -22,7 +22,8 @@ int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd) | |||
22 | return -ENOMEM; | 22 | return -ENOMEM; |
23 | fd->search_key = ptr; | 23 | fd->search_key = ptr; |
24 | fd->key = ptr + tree->max_key_len + 2; | 24 | fd->key = ptr + tree->max_key_len + 2; |
25 | dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n", tree->cnid, __builtin_return_address(0)); | 25 | dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n", |
26 | tree->cnid, __builtin_return_address(0)); | ||
26 | mutex_lock(&tree->tree_lock); | 27 | mutex_lock(&tree->tree_lock); |
27 | return 0; | 28 | return 0; |
28 | } | 29 | } |
@@ -31,7 +32,8 @@ void hfs_find_exit(struct hfs_find_data *fd) | |||
31 | { | 32 | { |
32 | hfs_bnode_put(fd->bnode); | 33 | hfs_bnode_put(fd->bnode); |
33 | kfree(fd->search_key); | 34 | kfree(fd->search_key); |
34 | dprint(DBG_BNODE_REFS, "find_exit: %d (%p)\n", fd->tree->cnid, __builtin_return_address(0)); | 35 | dprint(DBG_BNODE_REFS, "find_exit: %d (%p)\n", |
36 | fd->tree->cnid, __builtin_return_address(0)); | ||
35 | mutex_unlock(&fd->tree->tree_lock); | 37 | mutex_unlock(&fd->tree->tree_lock); |
36 | fd->tree = NULL; | 38 | fd->tree = NULL; |
37 | } | 39 | } |
diff --git a/fs/hfsplus/bitmap.c b/fs/hfsplus/bitmap.c index ad57f5991eb1..1cad80c789cb 100644 --- a/fs/hfsplus/bitmap.c +++ b/fs/hfsplus/bitmap.c | |||
@@ -15,7 +15,8 @@ | |||
15 | 15 | ||
16 | #define PAGE_CACHE_BITS (PAGE_CACHE_SIZE * 8) | 16 | #define PAGE_CACHE_BITS (PAGE_CACHE_SIZE * 8) |
17 | 17 | ||
18 | int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *max) | 18 | int hfsplus_block_allocate(struct super_block *sb, u32 size, |
19 | u32 offset, u32 *max) | ||
19 | { | 20 | { |
20 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); | 21 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); |
21 | struct page *page; | 22 | struct page *page; |
diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c index 29da6574ba77..1c42cc5b899f 100644 --- a/fs/hfsplus/bnode.c +++ b/fs/hfsplus/bnode.c | |||
@@ -42,7 +42,7 @@ void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len) | |||
42 | u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off) | 42 | u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off) |
43 | { | 43 | { |
44 | __be16 data; | 44 | __be16 data; |
45 | // optimize later... | 45 | /* TODO: optimize later... */ |
46 | hfs_bnode_read(node, &data, off, 2); | 46 | hfs_bnode_read(node, &data, off, 2); |
47 | return be16_to_cpu(data); | 47 | return be16_to_cpu(data); |
48 | } | 48 | } |
@@ -50,7 +50,7 @@ u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off) | |||
50 | u8 hfs_bnode_read_u8(struct hfs_bnode *node, int off) | 50 | u8 hfs_bnode_read_u8(struct hfs_bnode *node, int off) |
51 | { | 51 | { |
52 | u8 data; | 52 | u8 data; |
53 | // optimize later... | 53 | /* TODO: optimize later... */ |
54 | hfs_bnode_read(node, &data, off, 1); | 54 | hfs_bnode_read(node, &data, off, 1); |
55 | return data; | 55 | return data; |
56 | } | 56 | } |
@@ -96,7 +96,7 @@ void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len) | |||
96 | void hfs_bnode_write_u16(struct hfs_bnode *node, int off, u16 data) | 96 | void hfs_bnode_write_u16(struct hfs_bnode *node, int off, u16 data) |
97 | { | 97 | { |
98 | __be16 v = cpu_to_be16(data); | 98 | __be16 v = cpu_to_be16(data); |
99 | // optimize later... | 99 | /* TODO: optimize later... */ |
100 | hfs_bnode_write(node, &v, off, 2); | 100 | hfs_bnode_write(node, &v, off, 2); |
101 | } | 101 | } |
102 | 102 | ||
@@ -212,7 +212,8 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len) | |||
212 | dst_page--; | 212 | dst_page--; |
213 | } | 213 | } |
214 | src -= len; | 214 | src -= len; |
215 | memmove(kmap(*dst_page) + src, kmap(*src_page) + src, len); | 215 | memmove(kmap(*dst_page) + src, |
216 | kmap(*src_page) + src, len); | ||
216 | kunmap(*src_page); | 217 | kunmap(*src_page); |
217 | set_page_dirty(*dst_page); | 218 | set_page_dirty(*dst_page); |
218 | kunmap(*dst_page); | 219 | kunmap(*dst_page); |
@@ -250,14 +251,16 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len) | |||
250 | 251 | ||
251 | if (src == dst) { | 252 | if (src == dst) { |
252 | l = min(len, (int)PAGE_CACHE_SIZE - src); | 253 | l = min(len, (int)PAGE_CACHE_SIZE - src); |
253 | memmove(kmap(*dst_page) + src, kmap(*src_page) + src, l); | 254 | memmove(kmap(*dst_page) + src, |
255 | kmap(*src_page) + src, l); | ||
254 | kunmap(*src_page); | 256 | kunmap(*src_page); |
255 | set_page_dirty(*dst_page); | 257 | set_page_dirty(*dst_page); |
256 | kunmap(*dst_page); | 258 | kunmap(*dst_page); |
257 | 259 | ||
258 | while ((len -= l) != 0) { | 260 | while ((len -= l) != 0) { |
259 | l = min(len, (int)PAGE_CACHE_SIZE); | 261 | l = min(len, (int)PAGE_CACHE_SIZE); |
260 | memmove(kmap(*++dst_page), kmap(*++src_page), l); | 262 | memmove(kmap(*++dst_page), |
263 | kmap(*++src_page), l); | ||
261 | kunmap(*src_page); | 264 | kunmap(*src_page); |
262 | set_page_dirty(*dst_page); | 265 | set_page_dirty(*dst_page); |
263 | kunmap(*dst_page); | 266 | kunmap(*dst_page); |
@@ -268,7 +271,8 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len) | |||
268 | do { | 271 | do { |
269 | src_ptr = kmap(*src_page) + src; | 272 | src_ptr = kmap(*src_page) + src; |
270 | dst_ptr = kmap(*dst_page) + dst; | 273 | dst_ptr = kmap(*dst_page) + dst; |
271 | if (PAGE_CACHE_SIZE - src < PAGE_CACHE_SIZE - dst) { | 274 | if (PAGE_CACHE_SIZE - src < |
275 | PAGE_CACHE_SIZE - dst) { | ||
272 | l = PAGE_CACHE_SIZE - src; | 276 | l = PAGE_CACHE_SIZE - src; |
273 | src = 0; | 277 | src = 0; |
274 | dst += l; | 278 | dst += l; |
@@ -340,7 +344,8 @@ void hfs_bnode_unlink(struct hfs_bnode *node) | |||
340 | return; | 344 | return; |
341 | tmp->next = node->next; | 345 | tmp->next = node->next; |
342 | cnid = cpu_to_be32(tmp->next); | 346 | cnid = cpu_to_be32(tmp->next); |
343 | hfs_bnode_write(tmp, &cnid, offsetof(struct hfs_bnode_desc, next), 4); | 347 | hfs_bnode_write(tmp, &cnid, |
348 | offsetof(struct hfs_bnode_desc, next), 4); | ||
344 | hfs_bnode_put(tmp); | 349 | hfs_bnode_put(tmp); |
345 | } else if (node->type == HFS_NODE_LEAF) | 350 | } else if (node->type == HFS_NODE_LEAF) |
346 | tree->leaf_head = node->next; | 351 | tree->leaf_head = node->next; |
@@ -351,15 +356,15 @@ void hfs_bnode_unlink(struct hfs_bnode *node) | |||
351 | return; | 356 | return; |
352 | tmp->prev = node->prev; | 357 | tmp->prev = node->prev; |
353 | cnid = cpu_to_be32(tmp->prev); | 358 | cnid = cpu_to_be32(tmp->prev); |
354 | hfs_bnode_write(tmp, &cnid, offsetof(struct hfs_bnode_desc, prev), 4); | 359 | hfs_bnode_write(tmp, &cnid, |
360 | offsetof(struct hfs_bnode_desc, prev), 4); | ||
355 | hfs_bnode_put(tmp); | 361 | hfs_bnode_put(tmp); |
356 | } else if (node->type == HFS_NODE_LEAF) | 362 | } else if (node->type == HFS_NODE_LEAF) |
357 | tree->leaf_tail = node->prev; | 363 | tree->leaf_tail = node->prev; |
358 | 364 | ||
359 | // move down? | 365 | /* move down? */ |
360 | if (!node->prev && !node->next) { | 366 | if (!node->prev && !node->next) |
361 | printk(KERN_DEBUG "hfs_btree_del_level\n"); | 367 | dprint(DBG_BNODE_MOD, "hfs_btree_del_level\n"); |
362 | } | ||
363 | if (!node->parent) { | 368 | if (!node->parent) { |
364 | tree->root = 0; | 369 | tree->root = 0; |
365 | tree->depth = 0; | 370 | tree->depth = 0; |
@@ -379,16 +384,16 @@ struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *tree, u32 cnid) | |||
379 | struct hfs_bnode *node; | 384 | struct hfs_bnode *node; |
380 | 385 | ||
381 | if (cnid >= tree->node_count) { | 386 | if (cnid >= tree->node_count) { |
382 | printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid); | 387 | printk(KERN_ERR "hfs: request for non-existent node " |
388 | "%d in B*Tree\n", | ||
389 | cnid); | ||
383 | return NULL; | 390 | return NULL; |
384 | } | 391 | } |
385 | 392 | ||
386 | for (node = tree->node_hash[hfs_bnode_hash(cnid)]; | 393 | for (node = tree->node_hash[hfs_bnode_hash(cnid)]; |
387 | node; node = node->next_hash) { | 394 | node; node = node->next_hash) |
388 | if (node->this == cnid) { | 395 | if (node->this == cnid) |
389 | return node; | 396 | return node; |
390 | } | ||
391 | } | ||
392 | return NULL; | 397 | return NULL; |
393 | } | 398 | } |
394 | 399 | ||
@@ -402,7 +407,9 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid) | |||
402 | loff_t off; | 407 | loff_t off; |
403 | 408 | ||
404 | if (cnid >= tree->node_count) { | 409 | if (cnid >= tree->node_count) { |
405 | printk(KERN_ERR "hfs: request for non-existent node %d in B*Tree\n", cnid); | 410 | printk(KERN_ERR "hfs: request for non-existent node " |
411 | "%d in B*Tree\n", | ||
412 | cnid); | ||
406 | return NULL; | 413 | return NULL; |
407 | } | 414 | } |
408 | 415 | ||
@@ -429,7 +436,8 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid) | |||
429 | } else { | 436 | } else { |
430 | spin_unlock(&tree->hash_lock); | 437 | spin_unlock(&tree->hash_lock); |
431 | kfree(node); | 438 | kfree(node); |
432 | wait_event(node2->lock_wq, !test_bit(HFS_BNODE_NEW, &node2->flags)); | 439 | wait_event(node2->lock_wq, |
440 | !test_bit(HFS_BNODE_NEW, &node2->flags)); | ||
433 | return node2; | 441 | return node2; |
434 | } | 442 | } |
435 | spin_unlock(&tree->hash_lock); | 443 | spin_unlock(&tree->hash_lock); |
@@ -483,7 +491,8 @@ struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num) | |||
483 | if (node) { | 491 | if (node) { |
484 | hfs_bnode_get(node); | 492 | hfs_bnode_get(node); |
485 | spin_unlock(&tree->hash_lock); | 493 | spin_unlock(&tree->hash_lock); |
486 | wait_event(node->lock_wq, !test_bit(HFS_BNODE_NEW, &node->flags)); | 494 | wait_event(node->lock_wq, |
495 | !test_bit(HFS_BNODE_NEW, &node->flags)); | ||
487 | if (test_bit(HFS_BNODE_ERROR, &node->flags)) | 496 | if (test_bit(HFS_BNODE_ERROR, &node->flags)) |
488 | goto node_error; | 497 | goto node_error; |
489 | return node; | 498 | return node; |
@@ -497,7 +506,8 @@ struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num) | |||
497 | if (!test_bit(HFS_BNODE_NEW, &node->flags)) | 506 | if (!test_bit(HFS_BNODE_NEW, &node->flags)) |
498 | return node; | 507 | return node; |
499 | 508 | ||
500 | desc = (struct hfs_bnode_desc *)(kmap(node->page[0]) + node->page_offset); | 509 | desc = (struct hfs_bnode_desc *)(kmap(node->page[0]) + |
510 | node->page_offset); | ||
501 | node->prev = be32_to_cpu(desc->prev); | 511 | node->prev = be32_to_cpu(desc->prev); |
502 | node->next = be32_to_cpu(desc->next); | 512 | node->next = be32_to_cpu(desc->next); |
503 | node->num_recs = be16_to_cpu(desc->num_recs); | 513 | node->num_recs = be16_to_cpu(desc->num_recs); |
@@ -556,11 +566,13 @@ node_error: | |||
556 | 566 | ||
557 | void hfs_bnode_free(struct hfs_bnode *node) | 567 | void hfs_bnode_free(struct hfs_bnode *node) |
558 | { | 568 | { |
559 | //int i; | 569 | #if 0 |
570 | int i; | ||
560 | 571 | ||
561 | //for (i = 0; i < node->tree->pages_per_bnode; i++) | 572 | for (i = 0; i < node->tree->pages_per_bnode; i++) |
562 | // if (node->page[i]) | 573 | if (node->page[i]) |
563 | // page_cache_release(node->page[i]); | 574 | page_cache_release(node->page[i]); |
575 | #endif | ||
564 | kfree(node); | 576 | kfree(node); |
565 | } | 577 | } |
566 | 578 | ||
@@ -607,7 +619,8 @@ void hfs_bnode_get(struct hfs_bnode *node) | |||
607 | if (node) { | 619 | if (node) { |
608 | atomic_inc(&node->refcnt); | 620 | atomic_inc(&node->refcnt); |
609 | dprint(DBG_BNODE_REFS, "get_node(%d:%d): %d\n", | 621 | dprint(DBG_BNODE_REFS, "get_node(%d:%d): %d\n", |
610 | node->tree->cnid, node->this, atomic_read(&node->refcnt)); | 622 | node->tree->cnid, node->this, |
623 | atomic_read(&node->refcnt)); | ||
611 | } | 624 | } |
612 | } | 625 | } |
613 | 626 | ||
@@ -619,7 +632,8 @@ void hfs_bnode_put(struct hfs_bnode *node) | |||
619 | int i; | 632 | int i; |
620 | 633 | ||
621 | dprint(DBG_BNODE_REFS, "put_node(%d:%d): %d\n", | 634 | dprint(DBG_BNODE_REFS, "put_node(%d:%d): %d\n", |
622 | node->tree->cnid, node->this, atomic_read(&node->refcnt)); | 635 | node->tree->cnid, node->this, |
636 | atomic_read(&node->refcnt)); | ||
623 | BUG_ON(!atomic_read(&node->refcnt)); | 637 | BUG_ON(!atomic_read(&node->refcnt)); |
624 | if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock)) | 638 | if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock)) |
625 | return; | 639 | return; |
diff --git a/fs/hfsplus/brec.c b/fs/hfsplus/brec.c index 2f39d05443e1..2312de34bd42 100644 --- a/fs/hfsplus/brec.c +++ b/fs/hfsplus/brec.c | |||
@@ -39,7 +39,8 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec) | |||
39 | !(node->tree->attributes & HFS_TREE_VARIDXKEYS)) { | 39 | !(node->tree->attributes & HFS_TREE_VARIDXKEYS)) { |
40 | retval = node->tree->max_key_len + 2; | 40 | retval = node->tree->max_key_len + 2; |
41 | } else { | 41 | } else { |
42 | recoff = hfs_bnode_read_u16(node, node->tree->node_size - (rec + 1) * 2); | 42 | recoff = hfs_bnode_read_u16(node, |
43 | node->tree->node_size - (rec + 1) * 2); | ||
43 | if (!recoff) | 44 | if (!recoff) |
44 | return 0; | 45 | return 0; |
45 | 46 | ||
@@ -84,7 +85,8 @@ again: | |||
84 | end_rec_off = tree->node_size - (node->num_recs + 1) * 2; | 85 | end_rec_off = tree->node_size - (node->num_recs + 1) * 2; |
85 | end_off = hfs_bnode_read_u16(node, end_rec_off); | 86 | end_off = hfs_bnode_read_u16(node, end_rec_off); |
86 | end_rec_off -= 2; | 87 | end_rec_off -= 2; |
87 | dprint(DBG_BNODE_MOD, "insert_rec: %d, %d, %d, %d\n", rec, size, end_off, end_rec_off); | 88 | dprint(DBG_BNODE_MOD, "insert_rec: %d, %d, %d, %d\n", |
89 | rec, size, end_off, end_rec_off); | ||
88 | if (size > end_rec_off - end_off) { | 90 | if (size > end_rec_off - end_off) { |
89 | if (new_node) | 91 | if (new_node) |
90 | panic("not enough room!\n"); | 92 | panic("not enough room!\n"); |
@@ -99,7 +101,9 @@ again: | |||
99 | } | 101 | } |
100 | node->num_recs++; | 102 | node->num_recs++; |
101 | /* write new last offset */ | 103 | /* write new last offset */ |
102 | hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs); | 104 | hfs_bnode_write_u16(node, |
105 | offsetof(struct hfs_bnode_desc, num_recs), | ||
106 | node->num_recs); | ||
103 | hfs_bnode_write_u16(node, end_rec_off, end_off + size); | 107 | hfs_bnode_write_u16(node, end_rec_off, end_off + size); |
104 | data_off = end_off; | 108 | data_off = end_off; |
105 | data_rec_off = end_rec_off + 2; | 109 | data_rec_off = end_rec_off + 2; |
@@ -151,7 +155,8 @@ skip: | |||
151 | if (tree->attributes & HFS_TREE_VARIDXKEYS) | 155 | if (tree->attributes & HFS_TREE_VARIDXKEYS) |
152 | key_len = be16_to_cpu(fd->search_key->key_len) + 2; | 156 | key_len = be16_to_cpu(fd->search_key->key_len) + 2; |
153 | else { | 157 | else { |
154 | fd->search_key->key_len = cpu_to_be16(tree->max_key_len); | 158 | fd->search_key->key_len = |
159 | cpu_to_be16(tree->max_key_len); | ||
155 | key_len = tree->max_key_len + 2; | 160 | key_len = tree->max_key_len + 2; |
156 | } | 161 | } |
157 | goto again; | 162 | goto again; |
@@ -180,7 +185,8 @@ again: | |||
180 | mark_inode_dirty(tree->inode); | 185 | mark_inode_dirty(tree->inode); |
181 | } | 186 | } |
182 | hfs_bnode_dump(node); | 187 | hfs_bnode_dump(node); |
183 | dprint(DBG_BNODE_MOD, "remove_rec: %d, %d\n", fd->record, fd->keylength + fd->entrylength); | 188 | dprint(DBG_BNODE_MOD, "remove_rec: %d, %d\n", |
189 | fd->record, fd->keylength + fd->entrylength); | ||
184 | if (!--node->num_recs) { | 190 | if (!--node->num_recs) { |
185 | hfs_bnode_unlink(node); | 191 | hfs_bnode_unlink(node); |
186 | if (!node->parent) | 192 | if (!node->parent) |
@@ -194,7 +200,9 @@ again: | |||
194 | __hfs_brec_find(node, fd); | 200 | __hfs_brec_find(node, fd); |
195 | goto again; | 201 | goto again; |
196 | } | 202 | } |
197 | hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs); | 203 | hfs_bnode_write_u16(node, |
204 | offsetof(struct hfs_bnode_desc, num_recs), | ||
205 | node->num_recs); | ||
198 | 206 | ||
199 | if (rec_off == end_off) | 207 | if (rec_off == end_off) |
200 | goto skip; | 208 | goto skip; |
@@ -364,7 +372,8 @@ again: | |||
364 | newkeylen = hfs_bnode_read_u16(node, 14) + 2; | 372 | newkeylen = hfs_bnode_read_u16(node, 14) + 2; |
365 | else | 373 | else |
366 | fd->keylength = newkeylen = tree->max_key_len + 2; | 374 | fd->keylength = newkeylen = tree->max_key_len + 2; |
367 | dprint(DBG_BNODE_MOD, "update_rec: %d, %d, %d\n", rec, fd->keylength, newkeylen); | 375 | dprint(DBG_BNODE_MOD, "update_rec: %d, %d, %d\n", |
376 | rec, fd->keylength, newkeylen); | ||
368 | 377 | ||
369 | rec_off = tree->node_size - (rec + 2) * 2; | 378 | rec_off = tree->node_size - (rec + 2) * 2; |
370 | end_rec_off = tree->node_size - (parent->num_recs + 1) * 2; | 379 | end_rec_off = tree->node_size - (parent->num_recs + 1) * 2; |
@@ -375,7 +384,7 @@ again: | |||
375 | end_off = hfs_bnode_read_u16(parent, end_rec_off); | 384 | end_off = hfs_bnode_read_u16(parent, end_rec_off); |
376 | if (end_rec_off - end_off < diff) { | 385 | if (end_rec_off - end_off < diff) { |
377 | 386 | ||
378 | printk(KERN_DEBUG "hfs: splitting index node...\n"); | 387 | dprint(DBG_BNODE_MOD, "hfs: splitting index node.\n"); |
379 | fd->bnode = parent; | 388 | fd->bnode = parent; |
380 | new_node = hfs_bnode_split(fd); | 389 | new_node = hfs_bnode_split(fd); |
381 | if (IS_ERR(new_node)) | 390 | if (IS_ERR(new_node)) |
@@ -383,7 +392,8 @@ again: | |||
383 | parent = fd->bnode; | 392 | parent = fd->bnode; |
384 | rec = fd->record; | 393 | rec = fd->record; |
385 | rec_off = tree->node_size - (rec + 2) * 2; | 394 | rec_off = tree->node_size - (rec + 2) * 2; |
386 | end_rec_off = tree->node_size - (parent->num_recs + 1) * 2; | 395 | end_rec_off = tree->node_size - |
396 | (parent->num_recs + 1) * 2; | ||
387 | } | 397 | } |
388 | } | 398 | } |
389 | 399 | ||
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c index 22e4d4e32999..21023d9f8ff3 100644 --- a/fs/hfsplus/btree.c +++ b/fs/hfsplus/btree.c | |||
@@ -51,7 +51,8 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) | |||
51 | goto free_inode; | 51 | goto free_inode; |
52 | 52 | ||
53 | /* Load the header */ | 53 | /* Load the header */ |
54 | head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc)); | 54 | head = (struct hfs_btree_header_rec *)(kmap(page) + |
55 | sizeof(struct hfs_bnode_desc)); | ||
55 | tree->root = be32_to_cpu(head->root); | 56 | tree->root = be32_to_cpu(head->root); |
56 | tree->leaf_count = be32_to_cpu(head->leaf_count); | 57 | tree->leaf_count = be32_to_cpu(head->leaf_count); |
57 | tree->leaf_head = be32_to_cpu(head->leaf_head); | 58 | tree->leaf_head = be32_to_cpu(head->leaf_head); |
@@ -115,7 +116,9 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id) | |||
115 | 116 | ||
116 | tree->node_size_shift = ffs(size) - 1; | 117 | tree->node_size_shift = ffs(size) - 1; |
117 | 118 | ||
118 | tree->pages_per_bnode = (tree->node_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 119 | tree->pages_per_bnode = |
120 | (tree->node_size + PAGE_CACHE_SIZE - 1) >> | ||
121 | PAGE_CACHE_SHIFT; | ||
119 | 122 | ||
120 | kunmap(page); | 123 | kunmap(page); |
121 | page_cache_release(page); | 124 | page_cache_release(page); |
@@ -144,8 +147,10 @@ void hfs_btree_close(struct hfs_btree *tree) | |||
144 | while ((node = tree->node_hash[i])) { | 147 | while ((node = tree->node_hash[i])) { |
145 | tree->node_hash[i] = node->next_hash; | 148 | tree->node_hash[i] = node->next_hash; |
146 | if (atomic_read(&node->refcnt)) | 149 | if (atomic_read(&node->refcnt)) |
147 | printk(KERN_CRIT "hfs: node %d:%d still has %d user(s)!\n", | 150 | printk(KERN_CRIT "hfs: node %d:%d " |
148 | node->tree->cnid, node->this, atomic_read(&node->refcnt)); | 151 | "still has %d user(s)!\n", |
152 | node->tree->cnid, node->this, | ||
153 | atomic_read(&node->refcnt)); | ||
149 | hfs_bnode_free(node); | 154 | hfs_bnode_free(node); |
150 | tree->node_hash_cnt--; | 155 | tree->node_hash_cnt--; |
151 | } | 156 | } |
@@ -166,7 +171,8 @@ void hfs_btree_write(struct hfs_btree *tree) | |||
166 | return; | 171 | return; |
167 | /* Load the header */ | 172 | /* Load the header */ |
168 | page = node->page[0]; | 173 | page = node->page[0]; |
169 | head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc)); | 174 | head = (struct hfs_btree_header_rec *)(kmap(page) + |
175 | sizeof(struct hfs_bnode_desc)); | ||
170 | 176 | ||
171 | head->root = cpu_to_be32(tree->root); | 177 | head->root = cpu_to_be32(tree->root); |
172 | head->leaf_count = cpu_to_be32(tree->leaf_count); | 178 | head->leaf_count = cpu_to_be32(tree->leaf_count); |
@@ -272,7 +278,8 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree) | |||
272 | tree->free_nodes--; | 278 | tree->free_nodes--; |
273 | mark_inode_dirty(tree->inode); | 279 | mark_inode_dirty(tree->inode); |
274 | hfs_bnode_put(node); | 280 | hfs_bnode_put(node); |
275 | return hfs_bnode_create(tree, idx); | 281 | return hfs_bnode_create(tree, |
282 | idx); | ||
276 | } | 283 | } |
277 | } | 284 | } |
278 | } | 285 | } |
@@ -287,7 +294,7 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree) | |||
287 | kunmap(*pagep); | 294 | kunmap(*pagep); |
288 | nidx = node->next; | 295 | nidx = node->next; |
289 | if (!nidx) { | 296 | if (!nidx) { |
290 | printk(KERN_DEBUG "hfs: create new bmap node...\n"); | 297 | dprint(DBG_BNODE_MOD, "hfs: create new bmap node.\n"); |
291 | next_node = hfs_bmap_new_bmap(node, idx); | 298 | next_node = hfs_bmap_new_bmap(node, idx); |
292 | } else | 299 | } else |
293 | next_node = hfs_bnode_find(tree, nidx); | 300 | next_node = hfs_bnode_find(tree, nidx); |
@@ -329,7 +336,9 @@ void hfs_bmap_free(struct hfs_bnode *node) | |||
329 | hfs_bnode_put(node); | 336 | hfs_bnode_put(node); |
330 | if (!i) { | 337 | if (!i) { |
331 | /* panic */; | 338 | /* panic */; |
332 | printk(KERN_CRIT "hfs: unable to free bnode %u. bmap not found!\n", node->this); | 339 | printk(KERN_CRIT "hfs: unable to free bnode %u. " |
340 | "bmap not found!\n", | ||
341 | node->this); | ||
333 | return; | 342 | return; |
334 | } | 343 | } |
335 | node = hfs_bnode_find(tree, i); | 344 | node = hfs_bnode_find(tree, i); |
@@ -337,7 +346,9 @@ void hfs_bmap_free(struct hfs_bnode *node) | |||
337 | return; | 346 | return; |
338 | if (node->type != HFS_NODE_MAP) { | 347 | if (node->type != HFS_NODE_MAP) { |
339 | /* panic */; | 348 | /* panic */; |
340 | printk(KERN_CRIT "hfs: invalid bmap found! (%u,%d)\n", node->this, node->type); | 349 | printk(KERN_CRIT "hfs: invalid bmap found! " |
350 | "(%u,%d)\n", | ||
351 | node->this, node->type); | ||
341 | hfs_bnode_put(node); | 352 | hfs_bnode_put(node); |
342 | return; | 353 | return; |
343 | } | 354 | } |
@@ -350,7 +361,9 @@ void hfs_bmap_free(struct hfs_bnode *node) | |||
350 | m = 1 << (~nidx & 7); | 361 | m = 1 << (~nidx & 7); |
351 | byte = data[off]; | 362 | byte = data[off]; |
352 | if (!(byte & m)) { | 363 | if (!(byte & m)) { |
353 | printk(KERN_CRIT "hfs: trying to free free bnode %u(%d)\n", node->this, node->type); | 364 | printk(KERN_CRIT "hfs: trying to free free bnode " |
365 | "%u(%d)\n", | ||
366 | node->this, node->type); | ||
354 | kunmap(page); | 367 | kunmap(page); |
355 | hfs_bnode_put(node); | 368 | hfs_bnode_put(node); |
356 | return; | 369 | return; |
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c index 8af45fc5b051..b4ba1b319333 100644 --- a/fs/hfsplus/catalog.c +++ b/fs/hfsplus/catalog.c | |||
@@ -91,7 +91,8 @@ void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms) | |||
91 | perms->dev = 0; | 91 | perms->dev = 0; |
92 | } | 92 | } |
93 | 93 | ||
94 | static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct inode *inode) | 94 | static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, |
95 | u32 cnid, struct inode *inode) | ||
95 | { | 96 | { |
96 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); | 97 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); |
97 | 98 | ||
@@ -128,20 +129,32 @@ static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct i | |||
128 | if (cnid == inode->i_ino) { | 129 | if (cnid == inode->i_ino) { |
129 | hfsplus_cat_set_perms(inode, &file->permissions); | 130 | hfsplus_cat_set_perms(inode, &file->permissions); |
130 | if (S_ISLNK(inode->i_mode)) { | 131 | if (S_ISLNK(inode->i_mode)) { |
131 | file->user_info.fdType = cpu_to_be32(HFSP_SYMLINK_TYPE); | 132 | file->user_info.fdType = |
132 | file->user_info.fdCreator = cpu_to_be32(HFSP_SYMLINK_CREATOR); | 133 | cpu_to_be32(HFSP_SYMLINK_TYPE); |
134 | file->user_info.fdCreator = | ||
135 | cpu_to_be32(HFSP_SYMLINK_CREATOR); | ||
133 | } else { | 136 | } else { |
134 | file->user_info.fdType = cpu_to_be32(sbi->type); | 137 | file->user_info.fdType = |
135 | file->user_info.fdCreator = cpu_to_be32(sbi->creator); | 138 | cpu_to_be32(sbi->type); |
139 | file->user_info.fdCreator = | ||
140 | cpu_to_be32(sbi->creator); | ||
136 | } | 141 | } |
137 | if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE) | 142 | if (HFSPLUS_FLG_IMMUTABLE & |
138 | file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED); | 143 | (file->permissions.rootflags | |
144 | file->permissions.userflags)) | ||
145 | file->flags |= | ||
146 | cpu_to_be16(HFSPLUS_FILE_LOCKED); | ||
139 | } else { | 147 | } else { |
140 | file->user_info.fdType = cpu_to_be32(HFSP_HARDLINK_TYPE); | 148 | file->user_info.fdType = |
141 | file->user_info.fdCreator = cpu_to_be32(HFSP_HFSPLUS_CREATOR); | 149 | cpu_to_be32(HFSP_HARDLINK_TYPE); |
142 | file->user_info.fdFlags = cpu_to_be16(0x100); | 150 | file->user_info.fdCreator = |
143 | file->create_date = HFSPLUS_I(sbi->hidden_dir)->create_date; | 151 | cpu_to_be32(HFSP_HFSPLUS_CREATOR); |
144 | file->permissions.dev = cpu_to_be32(HFSPLUS_I(inode)->linkid); | 152 | file->user_info.fdFlags = |
153 | cpu_to_be16(0x100); | ||
154 | file->create_date = | ||
155 | HFSPLUS_I(sbi->hidden_dir)->create_date; | ||
156 | file->permissions.dev = | ||
157 | cpu_to_be32(HFSPLUS_I(inode)->linkid); | ||
145 | } | 158 | } |
146 | return sizeof(*file); | 159 | return sizeof(*file); |
147 | } | 160 | } |
@@ -182,12 +195,14 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid, | |||
182 | return -EIO; | 195 | return -EIO; |
183 | } | 196 | } |
184 | 197 | ||
185 | hfsplus_cat_build_key_uni(fd->search_key, be32_to_cpu(tmp.thread.parentID), | 198 | hfsplus_cat_build_key_uni(fd->search_key, |
186 | &tmp.thread.nodeName); | 199 | be32_to_cpu(tmp.thread.parentID), |
200 | &tmp.thread.nodeName); | ||
187 | return hfs_brec_find(fd); | 201 | return hfs_brec_find(fd); |
188 | } | 202 | } |
189 | 203 | ||
190 | int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct inode *inode) | 204 | int hfsplus_create_cat(u32 cnid, struct inode *dir, |
205 | struct qstr *str, struct inode *inode) | ||
191 | { | 206 | { |
192 | struct super_block *sb = dir->i_sb; | 207 | struct super_block *sb = dir->i_sb; |
193 | struct hfs_find_data fd; | 208 | struct hfs_find_data fd; |
@@ -195,13 +210,15 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct ino | |||
195 | int entry_size; | 210 | int entry_size; |
196 | int err; | 211 | int err; |
197 | 212 | ||
198 | dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n", str->name, cnid, inode->i_nlink); | 213 | dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n", |
214 | str->name, cnid, inode->i_nlink); | ||
199 | hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); | 215 | hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); |
200 | 216 | ||
201 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); | 217 | hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); |
202 | entry_size = hfsplus_fill_cat_thread(sb, &entry, S_ISDIR(inode->i_mode) ? | 218 | entry_size = hfsplus_fill_cat_thread(sb, &entry, |
219 | S_ISDIR(inode->i_mode) ? | ||
203 | HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD, | 220 | HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD, |
204 | dir->i_ino, str); | 221 | dir->i_ino, str); |
205 | err = hfs_brec_find(&fd); | 222 | err = hfs_brec_find(&fd); |
206 | if (err != -ENOENT) { | 223 | if (err != -ENOENT) { |
207 | if (!err) | 224 | if (!err) |
@@ -227,7 +244,8 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir, struct qstr *str, struct ino | |||
227 | 244 | ||
228 | dir->i_size++; | 245 | dir->i_size++; |
229 | dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; | 246 | dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; |
230 | mark_inode_dirty(dir); | 247 | hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY); |
248 | |||
231 | hfs_find_exit(&fd); | 249 | hfs_find_exit(&fd); |
232 | return 0; | 250 | return 0; |
233 | 251 | ||
@@ -249,7 +267,8 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) | |||
249 | int err, off; | 267 | int err, off; |
250 | u16 type; | 268 | u16 type; |
251 | 269 | ||
252 | dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid); | 270 | dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n", |
271 | str ? str->name : NULL, cnid); | ||
253 | hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); | 272 | hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); |
254 | 273 | ||
255 | if (!str) { | 274 | if (!str) { |
@@ -260,11 +279,15 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) | |||
260 | if (err) | 279 | if (err) |
261 | goto out; | 280 | goto out; |
262 | 281 | ||
263 | off = fd.entryoffset + offsetof(struct hfsplus_cat_thread, nodeName); | 282 | off = fd.entryoffset + |
283 | offsetof(struct hfsplus_cat_thread, nodeName); | ||
264 | fd.search_key->cat.parent = cpu_to_be32(dir->i_ino); | 284 | fd.search_key->cat.parent = cpu_to_be32(dir->i_ino); |
265 | hfs_bnode_read(fd.bnode, &fd.search_key->cat.name.length, off, 2); | 285 | hfs_bnode_read(fd.bnode, |
286 | &fd.search_key->cat.name.length, off, 2); | ||
266 | len = be16_to_cpu(fd.search_key->cat.name.length) * 2; | 287 | len = be16_to_cpu(fd.search_key->cat.name.length) * 2; |
267 | hfs_bnode_read(fd.bnode, &fd.search_key->cat.name.unicode, off + 2, len); | 288 | hfs_bnode_read(fd.bnode, |
289 | &fd.search_key->cat.name.unicode, | ||
290 | off + 2, len); | ||
268 | fd.search_key->key_len = cpu_to_be16(6 + len); | 291 | fd.search_key->key_len = cpu_to_be16(6 + len); |
269 | } else | 292 | } else |
270 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); | 293 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); |
@@ -281,7 +304,8 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) | |||
281 | hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_DATA); | 304 | hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_DATA); |
282 | #endif | 305 | #endif |
283 | 306 | ||
284 | off = fd.entryoffset + offsetof(struct hfsplus_cat_file, rsrc_fork); | 307 | off = fd.entryoffset + |
308 | offsetof(struct hfsplus_cat_file, rsrc_fork); | ||
285 | hfs_bnode_read(fd.bnode, &fork, off, sizeof(fork)); | 309 | hfs_bnode_read(fd.bnode, &fork, off, sizeof(fork)); |
286 | hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_RSRC); | 310 | hfsplus_free_fork(sb, cnid, &fork, HFSPLUS_TYPE_RSRC); |
287 | } | 311 | } |
@@ -308,7 +332,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str) | |||
308 | 332 | ||
309 | dir->i_size--; | 333 | dir->i_size--; |
310 | dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; | 334 | dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; |
311 | mark_inode_dirty(dir); | 335 | hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY); |
312 | out: | 336 | out: |
313 | hfs_find_exit(&fd); | 337 | hfs_find_exit(&fd); |
314 | 338 | ||
@@ -325,7 +349,8 @@ int hfsplus_rename_cat(u32 cnid, | |||
325 | int entry_size, type; | 349 | int entry_size, type; |
326 | int err = 0; | 350 | int err = 0; |
327 | 351 | ||
328 | dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", cnid, src_dir->i_ino, src_name->name, | 352 | dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n", |
353 | cnid, src_dir->i_ino, src_name->name, | ||
329 | dst_dir->i_ino, dst_name->name); | 354 | dst_dir->i_ino, dst_name->name); |
330 | hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd); | 355 | hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd); |
331 | dst_fd = src_fd; | 356 | dst_fd = src_fd; |
@@ -353,7 +378,6 @@ int hfsplus_rename_cat(u32 cnid, | |||
353 | goto out; | 378 | goto out; |
354 | dst_dir->i_size++; | 379 | dst_dir->i_size++; |
355 | dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC; | 380 | dst_dir->i_mtime = dst_dir->i_ctime = CURRENT_TIME_SEC; |
356 | mark_inode_dirty(dst_dir); | ||
357 | 381 | ||
358 | /* finally remove the old entry */ | 382 | /* finally remove the old entry */ |
359 | hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); | 383 | hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); |
@@ -365,7 +389,6 @@ int hfsplus_rename_cat(u32 cnid, | |||
365 | goto out; | 389 | goto out; |
366 | src_dir->i_size--; | 390 | src_dir->i_size--; |
367 | src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC; | 391 | src_dir->i_mtime = src_dir->i_ctime = CURRENT_TIME_SEC; |
368 | mark_inode_dirty(src_dir); | ||
369 | 392 | ||
370 | /* remove old thread entry */ | 393 | /* remove old thread entry */ |
371 | hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL); | 394 | hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL); |
@@ -379,7 +402,8 @@ int hfsplus_rename_cat(u32 cnid, | |||
379 | 402 | ||
380 | /* create new thread entry */ | 403 | /* create new thread entry */ |
381 | hfsplus_cat_build_key(sb, dst_fd.search_key, cnid, NULL); | 404 | hfsplus_cat_build_key(sb, dst_fd.search_key, cnid, NULL); |
382 | entry_size = hfsplus_fill_cat_thread(sb, &entry, type, dst_dir->i_ino, dst_name); | 405 | entry_size = hfsplus_fill_cat_thread(sb, &entry, type, |
406 | dst_dir->i_ino, dst_name); | ||
383 | err = hfs_brec_find(&dst_fd); | 407 | err = hfs_brec_find(&dst_fd); |
384 | if (err != -ENOENT) { | 408 | if (err != -ENOENT) { |
385 | if (!err) | 409 | if (!err) |
@@ -387,6 +411,9 @@ int hfsplus_rename_cat(u32 cnid, | |||
387 | goto out; | 411 | goto out; |
388 | } | 412 | } |
389 | err = hfs_brec_insert(&dst_fd, &entry, entry_size); | 413 | err = hfs_brec_insert(&dst_fd, &entry, entry_size); |
414 | |||
415 | hfsplus_mark_inode_dirty(dst_dir, HFSPLUS_I_CAT_DIRTY); | ||
416 | hfsplus_mark_inode_dirty(src_dir, HFSPLUS_I_CAT_DIRTY); | ||
390 | out: | 417 | out: |
391 | hfs_bnode_put(dst_fd.bnode); | 418 | hfs_bnode_put(dst_fd.bnode); |
392 | hfs_find_exit(&src_fd); | 419 | hfs_find_exit(&src_fd); |
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index 9d59c0571f59..f896dc843026 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c | |||
@@ -37,7 +37,7 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry, | |||
37 | 37 | ||
38 | sb = dir->i_sb; | 38 | sb = dir->i_sb; |
39 | 39 | ||
40 | dentry->d_op = &hfsplus_dentry_operations; | 40 | d_set_d_op(dentry, &hfsplus_dentry_operations); |
41 | dentry->d_fsdata = NULL; | 41 | dentry->d_fsdata = NULL; |
42 | hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); | 42 | hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); |
43 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name); | 43 | hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name); |
@@ -66,11 +66,17 @@ again: | |||
66 | goto fail; | 66 | goto fail; |
67 | } | 67 | } |
68 | cnid = be32_to_cpu(entry.file.id); | 68 | cnid = be32_to_cpu(entry.file.id); |
69 | if (entry.file.user_info.fdType == cpu_to_be32(HFSP_HARDLINK_TYPE) && | 69 | if (entry.file.user_info.fdType == |
70 | entry.file.user_info.fdCreator == cpu_to_be32(HFSP_HFSPLUS_CREATOR) && | 70 | cpu_to_be32(HFSP_HARDLINK_TYPE) && |
71 | (entry.file.create_date == HFSPLUS_I(HFSPLUS_SB(sb)->hidden_dir)->create_date || | 71 | entry.file.user_info.fdCreator == |
72 | entry.file.create_date == HFSPLUS_I(sb->s_root->d_inode)->create_date) && | 72 | cpu_to_be32(HFSP_HFSPLUS_CREATOR) && |
73 | HFSPLUS_SB(sb)->hidden_dir) { | 73 | (entry.file.create_date == |
74 | HFSPLUS_I(HFSPLUS_SB(sb)->hidden_dir)-> | ||
75 | create_date || | ||
76 | entry.file.create_date == | ||
77 | HFSPLUS_I(sb->s_root->d_inode)-> | ||
78 | create_date) && | ||
79 | HFSPLUS_SB(sb)->hidden_dir) { | ||
74 | struct qstr str; | 80 | struct qstr str; |
75 | char name[32]; | 81 | char name[32]; |
76 | 82 | ||
@@ -83,11 +89,13 @@ again: | |||
83 | linkid = 0; | 89 | linkid = 0; |
84 | } else { | 90 | } else { |
85 | dentry->d_fsdata = (void *)(unsigned long)cnid; | 91 | dentry->d_fsdata = (void *)(unsigned long)cnid; |
86 | linkid = be32_to_cpu(entry.file.permissions.dev); | 92 | linkid = |
93 | be32_to_cpu(entry.file.permissions.dev); | ||
87 | str.len = sprintf(name, "iNode%d", linkid); | 94 | str.len = sprintf(name, "iNode%d", linkid); |
88 | str.name = name; | 95 | str.name = name; |
89 | hfsplus_cat_build_key(sb, fd.search_key, | 96 | hfsplus_cat_build_key(sb, fd.search_key, |
90 | HFSPLUS_SB(sb)->hidden_dir->i_ino, &str); | 97 | HFSPLUS_SB(sb)->hidden_dir->i_ino, |
98 | &str); | ||
91 | goto again; | 99 | goto again; |
92 | } | 100 | } |
93 | } else if (!dentry->d_fsdata) | 101 | } else if (!dentry->d_fsdata) |
@@ -139,7 +147,8 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
139 | filp->f_pos++; | 147 | filp->f_pos++; |
140 | /* fall through */ | 148 | /* fall through */ |
141 | case 1: | 149 | case 1: |
142 | hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); | 150 | hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, |
151 | fd.entrylength); | ||
143 | if (be16_to_cpu(entry.type) != HFSPLUS_FOLDER_THREAD) { | 152 | if (be16_to_cpu(entry.type) != HFSPLUS_FOLDER_THREAD) { |
144 | printk(KERN_ERR "hfs: bad catalog folder thread\n"); | 153 | printk(KERN_ERR "hfs: bad catalog folder thread\n"); |
145 | err = -EIO; | 154 | err = -EIO; |
@@ -169,14 +178,16 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
169 | err = -EIO; | 178 | err = -EIO; |
170 | goto out; | 179 | goto out; |
171 | } | 180 | } |
172 | hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, fd.entrylength); | 181 | hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, |
182 | fd.entrylength); | ||
173 | type = be16_to_cpu(entry.type); | 183 | type = be16_to_cpu(entry.type); |
174 | len = HFSPLUS_MAX_STRLEN; | 184 | len = HFSPLUS_MAX_STRLEN; |
175 | err = hfsplus_uni2asc(sb, &fd.key->cat.name, strbuf, &len); | 185 | err = hfsplus_uni2asc(sb, &fd.key->cat.name, strbuf, &len); |
176 | if (err) | 186 | if (err) |
177 | goto out; | 187 | goto out; |
178 | if (type == HFSPLUS_FOLDER) { | 188 | if (type == HFSPLUS_FOLDER) { |
179 | if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) { | 189 | if (fd.entrylength < |
190 | sizeof(struct hfsplus_cat_folder)) { | ||
180 | printk(KERN_ERR "hfs: small dir entry\n"); | 191 | printk(KERN_ERR "hfs: small dir entry\n"); |
181 | err = -EIO; | 192 | err = -EIO; |
182 | goto out; | 193 | goto out; |
@@ -202,7 +213,7 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
202 | err = -EIO; | 213 | err = -EIO; |
203 | goto out; | 214 | goto out; |
204 | } | 215 | } |
205 | next: | 216 | next: |
206 | filp->f_pos++; | 217 | filp->f_pos++; |
207 | if (filp->f_pos >= inode->i_size) | 218 | if (filp->f_pos >= inode->i_size) |
208 | goto out; | 219 | goto out; |
@@ -273,7 +284,8 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir, | |||
273 | HFSPLUS_I(inode)->linkid = id; | 284 | HFSPLUS_I(inode)->linkid = id; |
274 | cnid = sbi->next_cnid++; | 285 | cnid = sbi->next_cnid++; |
275 | src_dentry->d_fsdata = (void *)(unsigned long)cnid; | 286 | src_dentry->d_fsdata = (void *)(unsigned long)cnid; |
276 | res = hfsplus_create_cat(cnid, src_dir, &src_dentry->d_name, inode); | 287 | res = hfsplus_create_cat(cnid, src_dir, |
288 | &src_dentry->d_name, inode); | ||
277 | if (res) | 289 | if (res) |
278 | /* panic? */ | 290 | /* panic? */ |
279 | goto out; | 291 | goto out; |
@@ -485,6 +497,7 @@ const struct inode_operations hfsplus_dir_inode_operations = { | |||
485 | }; | 497 | }; |
486 | 498 | ||
487 | const struct file_operations hfsplus_dir_operations = { | 499 | const struct file_operations hfsplus_dir_operations = { |
500 | .fsync = hfsplus_file_fsync, | ||
488 | .read = generic_read_dir, | 501 | .read = generic_read_dir, |
489 | .readdir = hfsplus_readdir, | 502 | .readdir = hfsplus_readdir, |
490 | .unlocked_ioctl = hfsplus_ioctl, | 503 | .unlocked_ioctl = hfsplus_ioctl, |
diff --git a/fs/hfsplus/extents.c b/fs/hfsplus/extents.c index 0c9cb1820a52..52a0bcaa7b6d 100644 --- a/fs/hfsplus/extents.c +++ b/fs/hfsplus/extents.c | |||
@@ -83,7 +83,8 @@ static u32 hfsplus_ext_lastblock(struct hfsplus_extent *ext) | |||
83 | return be32_to_cpu(ext->start_block) + be32_to_cpu(ext->block_count); | 83 | return be32_to_cpu(ext->start_block) + be32_to_cpu(ext->block_count); |
84 | } | 84 | } |
85 | 85 | ||
86 | static void __hfsplus_ext_write_extent(struct inode *inode, struct hfs_find_data *fd) | 86 | static void __hfsplus_ext_write_extent(struct inode *inode, |
87 | struct hfs_find_data *fd) | ||
87 | { | 88 | { |
88 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); | 89 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
89 | int res; | 90 | int res; |
@@ -95,24 +96,32 @@ static void __hfsplus_ext_write_extent(struct inode *inode, struct hfs_find_data | |||
95 | HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); | 96 | HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); |
96 | 97 | ||
97 | res = hfs_brec_find(fd); | 98 | res = hfs_brec_find(fd); |
98 | if (hip->flags & HFSPLUS_FLG_EXT_NEW) { | 99 | if (hip->extent_state & HFSPLUS_EXT_NEW) { |
99 | if (res != -ENOENT) | 100 | if (res != -ENOENT) |
100 | return; | 101 | return; |
101 | hfs_brec_insert(fd, hip->cached_extents, | 102 | hfs_brec_insert(fd, hip->cached_extents, |
102 | sizeof(hfsplus_extent_rec)); | 103 | sizeof(hfsplus_extent_rec)); |
103 | hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW); | 104 | hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW); |
104 | } else { | 105 | } else { |
105 | if (res) | 106 | if (res) |
106 | return; | 107 | return; |
107 | hfs_bnode_write(fd->bnode, hip->cached_extents, | 108 | hfs_bnode_write(fd->bnode, hip->cached_extents, |
108 | fd->entryoffset, fd->entrylength); | 109 | fd->entryoffset, fd->entrylength); |
109 | hip->flags &= ~HFSPLUS_FLG_EXT_DIRTY; | 110 | hip->extent_state &= ~HFSPLUS_EXT_DIRTY; |
110 | } | 111 | } |
112 | |||
113 | /* | ||
114 | * We can't just use hfsplus_mark_inode_dirty here, because we | ||
115 | * also get called from hfsplus_write_inode, which should not | ||
116 | * redirty the inode. Instead the callers have to be careful | ||
117 | * to explicily mark the inode dirty, too. | ||
118 | */ | ||
119 | set_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags); | ||
111 | } | 120 | } |
112 | 121 | ||
113 | static void hfsplus_ext_write_extent_locked(struct inode *inode) | 122 | static void hfsplus_ext_write_extent_locked(struct inode *inode) |
114 | { | 123 | { |
115 | if (HFSPLUS_I(inode)->flags & HFSPLUS_FLG_EXT_DIRTY) { | 124 | if (HFSPLUS_I(inode)->extent_state & HFSPLUS_EXT_DIRTY) { |
116 | struct hfs_find_data fd; | 125 | struct hfs_find_data fd; |
117 | 126 | ||
118 | hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd); | 127 | hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd); |
@@ -144,18 +153,20 @@ static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd, | |||
144 | return -ENOENT; | 153 | return -ENOENT; |
145 | if (fd->entrylength != sizeof(hfsplus_extent_rec)) | 154 | if (fd->entrylength != sizeof(hfsplus_extent_rec)) |
146 | return -EIO; | 155 | return -EIO; |
147 | hfs_bnode_read(fd->bnode, extent, fd->entryoffset, sizeof(hfsplus_extent_rec)); | 156 | hfs_bnode_read(fd->bnode, extent, fd->entryoffset, |
157 | sizeof(hfsplus_extent_rec)); | ||
148 | return 0; | 158 | return 0; |
149 | } | 159 | } |
150 | 160 | ||
151 | static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd, struct inode *inode, u32 block) | 161 | static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd, |
162 | struct inode *inode, u32 block) | ||
152 | { | 163 | { |
153 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); | 164 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
154 | int res; | 165 | int res; |
155 | 166 | ||
156 | WARN_ON(!mutex_is_locked(&hip->extents_lock)); | 167 | WARN_ON(!mutex_is_locked(&hip->extents_lock)); |
157 | 168 | ||
158 | if (hip->flags & HFSPLUS_FLG_EXT_DIRTY) | 169 | if (hip->extent_state & HFSPLUS_EXT_DIRTY) |
159 | __hfsplus_ext_write_extent(inode, fd); | 170 | __hfsplus_ext_write_extent(inode, fd); |
160 | 171 | ||
161 | res = __hfsplus_ext_read_extent(fd, hip->cached_extents, inode->i_ino, | 172 | res = __hfsplus_ext_read_extent(fd, hip->cached_extents, inode->i_ino, |
@@ -164,10 +175,11 @@ static inline int __hfsplus_ext_cache_extent(struct hfs_find_data *fd, struct in | |||
164 | HFSPLUS_TYPE_DATA); | 175 | HFSPLUS_TYPE_DATA); |
165 | if (!res) { | 176 | if (!res) { |
166 | hip->cached_start = be32_to_cpu(fd->key->ext.start_block); | 177 | hip->cached_start = be32_to_cpu(fd->key->ext.start_block); |
167 | hip->cached_blocks = hfsplus_ext_block_count(hip->cached_extents); | 178 | hip->cached_blocks = |
179 | hfsplus_ext_block_count(hip->cached_extents); | ||
168 | } else { | 180 | } else { |
169 | hip->cached_start = hip->cached_blocks = 0; | 181 | hip->cached_start = hip->cached_blocks = 0; |
170 | hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW); | 182 | hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW); |
171 | } | 183 | } |
172 | return res; | 184 | return res; |
173 | } | 185 | } |
@@ -197,6 +209,7 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock, | |||
197 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); | 209 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
198 | int res = -EIO; | 210 | int res = -EIO; |
199 | u32 ablock, dblock, mask; | 211 | u32 ablock, dblock, mask; |
212 | int was_dirty = 0; | ||
200 | int shift; | 213 | int shift; |
201 | 214 | ||
202 | /* Convert inode block to disk allocation block */ | 215 | /* Convert inode block to disk allocation block */ |
@@ -223,27 +236,37 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock, | |||
223 | return -EIO; | 236 | return -EIO; |
224 | 237 | ||
225 | mutex_lock(&hip->extents_lock); | 238 | mutex_lock(&hip->extents_lock); |
239 | |||
240 | /* | ||
241 | * hfsplus_ext_read_extent will write out a cached extent into | ||
242 | * the extents btree. In that case we may have to mark the inode | ||
243 | * dirty even for a pure read of an extent here. | ||
244 | */ | ||
245 | was_dirty = (hip->extent_state & HFSPLUS_EXT_DIRTY); | ||
226 | res = hfsplus_ext_read_extent(inode, ablock); | 246 | res = hfsplus_ext_read_extent(inode, ablock); |
227 | if (!res) { | 247 | if (res) { |
228 | dblock = hfsplus_ext_find_block(hip->cached_extents, | ||
229 | ablock - hip->cached_start); | ||
230 | } else { | ||
231 | mutex_unlock(&hip->extents_lock); | 248 | mutex_unlock(&hip->extents_lock); |
232 | return -EIO; | 249 | return -EIO; |
233 | } | 250 | } |
251 | dblock = hfsplus_ext_find_block(hip->cached_extents, | ||
252 | ablock - hip->cached_start); | ||
234 | mutex_unlock(&hip->extents_lock); | 253 | mutex_unlock(&hip->extents_lock); |
235 | 254 | ||
236 | done: | 255 | done: |
237 | dprint(DBG_EXTENT, "get_block(%lu): %llu - %u\n", inode->i_ino, (long long)iblock, dblock); | 256 | dprint(DBG_EXTENT, "get_block(%lu): %llu - %u\n", |
257 | inode->i_ino, (long long)iblock, dblock); | ||
238 | mask = (1 << sbi->fs_shift) - 1; | 258 | mask = (1 << sbi->fs_shift) - 1; |
239 | map_bh(bh_result, sb, (dblock << sbi->fs_shift) + sbi->blockoffset + (iblock & mask)); | 259 | map_bh(bh_result, sb, |
260 | (dblock << sbi->fs_shift) + sbi->blockoffset + | ||
261 | (iblock & mask)); | ||
240 | if (create) { | 262 | if (create) { |
241 | set_buffer_new(bh_result); | 263 | set_buffer_new(bh_result); |
242 | hip->phys_size += sb->s_blocksize; | 264 | hip->phys_size += sb->s_blocksize; |
243 | hip->fs_blocks++; | 265 | hip->fs_blocks++; |
244 | inode_add_bytes(inode, sb->s_blocksize); | 266 | inode_add_bytes(inode, sb->s_blocksize); |
245 | mark_inode_dirty(inode); | ||
246 | } | 267 | } |
268 | if (create || was_dirty) | ||
269 | mark_inode_dirty(inode); | ||
247 | return 0; | 270 | return 0; |
248 | } | 271 | } |
249 | 272 | ||
@@ -326,7 +349,8 @@ found: | |||
326 | } | 349 | } |
327 | } | 350 | } |
328 | 351 | ||
329 | int hfsplus_free_fork(struct super_block *sb, u32 cnid, struct hfsplus_fork_raw *fork, int type) | 352 | int hfsplus_free_fork(struct super_block *sb, u32 cnid, |
353 | struct hfsplus_fork_raw *fork, int type) | ||
330 | { | 354 | { |
331 | struct hfs_find_data fd; | 355 | struct hfs_find_data fd; |
332 | hfsplus_extent_rec ext_entry; | 356 | hfsplus_extent_rec ext_entry; |
@@ -373,12 +397,13 @@ int hfsplus_file_extend(struct inode *inode) | |||
373 | u32 start, len, goal; | 397 | u32 start, len, goal; |
374 | int res; | 398 | int res; |
375 | 399 | ||
376 | if (sbi->alloc_file->i_size * 8 < | 400 | if (sbi->total_blocks - sbi->free_blocks + 8 > |
377 | sbi->total_blocks - sbi->free_blocks + 8) { | 401 | sbi->alloc_file->i_size * 8) { |
378 | // extend alloc file | 402 | /* extend alloc file */ |
379 | printk(KERN_ERR "hfs: extend alloc file! (%Lu,%u,%u)\n", | 403 | printk(KERN_ERR "hfs: extend alloc file! " |
380 | sbi->alloc_file->i_size * 8, | 404 | "(%llu,%u,%u)\n", |
381 | sbi->total_blocks, sbi->free_blocks); | 405 | sbi->alloc_file->i_size * 8, |
406 | sbi->total_blocks, sbi->free_blocks); | ||
382 | return -ENOSPC; | 407 | return -ENOSPC; |
383 | } | 408 | } |
384 | 409 | ||
@@ -429,7 +454,7 @@ int hfsplus_file_extend(struct inode *inode) | |||
429 | start, len); | 454 | start, len); |
430 | if (!res) { | 455 | if (!res) { |
431 | hfsplus_dump_extent(hip->cached_extents); | 456 | hfsplus_dump_extent(hip->cached_extents); |
432 | hip->flags |= HFSPLUS_FLG_EXT_DIRTY; | 457 | hip->extent_state |= HFSPLUS_EXT_DIRTY; |
433 | hip->cached_blocks += len; | 458 | hip->cached_blocks += len; |
434 | } else if (res == -ENOSPC) | 459 | } else if (res == -ENOSPC) |
435 | goto insert_extent; | 460 | goto insert_extent; |
@@ -438,7 +463,7 @@ out: | |||
438 | mutex_unlock(&hip->extents_lock); | 463 | mutex_unlock(&hip->extents_lock); |
439 | if (!res) { | 464 | if (!res) { |
440 | hip->alloc_blocks += len; | 465 | hip->alloc_blocks += len; |
441 | mark_inode_dirty(inode); | 466 | hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY); |
442 | } | 467 | } |
443 | return res; | 468 | return res; |
444 | 469 | ||
@@ -450,7 +475,7 @@ insert_extent: | |||
450 | hip->cached_extents[0].start_block = cpu_to_be32(start); | 475 | hip->cached_extents[0].start_block = cpu_to_be32(start); |
451 | hip->cached_extents[0].block_count = cpu_to_be32(len); | 476 | hip->cached_extents[0].block_count = cpu_to_be32(len); |
452 | hfsplus_dump_extent(hip->cached_extents); | 477 | hfsplus_dump_extent(hip->cached_extents); |
453 | hip->flags |= HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW; | 478 | hip->extent_state |= HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW; |
454 | hip->cached_start = hip->alloc_blocks; | 479 | hip->cached_start = hip->alloc_blocks; |
455 | hip->cached_blocks = len; | 480 | hip->cached_blocks = len; |
456 | 481 | ||
@@ -466,8 +491,9 @@ void hfsplus_file_truncate(struct inode *inode) | |||
466 | u32 alloc_cnt, blk_cnt, start; | 491 | u32 alloc_cnt, blk_cnt, start; |
467 | int res; | 492 | int res; |
468 | 493 | ||
469 | dprint(DBG_INODE, "truncate: %lu, %Lu -> %Lu\n", | 494 | dprint(DBG_INODE, "truncate: %lu, %llu -> %llu\n", |
470 | inode->i_ino, (long long)hip->phys_size, inode->i_size); | 495 | inode->i_ino, (long long)hip->phys_size, |
496 | inode->i_size); | ||
471 | 497 | ||
472 | if (inode->i_size > hip->phys_size) { | 498 | if (inode->i_size > hip->phys_size) { |
473 | struct address_space *mapping = inode->i_mapping; | 499 | struct address_space *mapping = inode->i_mapping; |
@@ -481,7 +507,8 @@ void hfsplus_file_truncate(struct inode *inode) | |||
481 | &page, &fsdata); | 507 | &page, &fsdata); |
482 | if (res) | 508 | if (res) |
483 | return; | 509 | return; |
484 | res = pagecache_write_end(NULL, mapping, size, 0, 0, page, fsdata); | 510 | res = pagecache_write_end(NULL, mapping, size, |
511 | 0, 0, page, fsdata); | ||
485 | if (res < 0) | 512 | if (res < 0) |
486 | return; | 513 | return; |
487 | mark_inode_dirty(inode); | 514 | mark_inode_dirty(inode); |
@@ -513,12 +540,12 @@ void hfsplus_file_truncate(struct inode *inode) | |||
513 | alloc_cnt - start, alloc_cnt - blk_cnt); | 540 | alloc_cnt - start, alloc_cnt - blk_cnt); |
514 | hfsplus_dump_extent(hip->cached_extents); | 541 | hfsplus_dump_extent(hip->cached_extents); |
515 | if (blk_cnt > start) { | 542 | if (blk_cnt > start) { |
516 | hip->flags |= HFSPLUS_FLG_EXT_DIRTY; | 543 | hip->extent_state |= HFSPLUS_EXT_DIRTY; |
517 | break; | 544 | break; |
518 | } | 545 | } |
519 | alloc_cnt = start; | 546 | alloc_cnt = start; |
520 | hip->cached_start = hip->cached_blocks = 0; | 547 | hip->cached_start = hip->cached_blocks = 0; |
521 | hip->flags &= ~(HFSPLUS_FLG_EXT_DIRTY | HFSPLUS_FLG_EXT_NEW); | 548 | hip->extent_state &= ~(HFSPLUS_EXT_DIRTY | HFSPLUS_EXT_NEW); |
522 | hfs_brec_remove(&fd); | 549 | hfs_brec_remove(&fd); |
523 | } | 550 | } |
524 | hfs_find_exit(&fd); | 551 | hfs_find_exit(&fd); |
@@ -527,7 +554,8 @@ void hfsplus_file_truncate(struct inode *inode) | |||
527 | hip->alloc_blocks = blk_cnt; | 554 | hip->alloc_blocks = blk_cnt; |
528 | out: | 555 | out: |
529 | hip->phys_size = inode->i_size; | 556 | hip->phys_size = inode->i_size; |
530 | hip->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; | 557 | hip->fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> |
558 | sb->s_blocksize_bits; | ||
531 | inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits); | 559 | inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits); |
532 | mark_inode_dirty(inode); | 560 | hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ALLOC_DIRTY); |
533 | } | 561 | } |
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index cb3653efb57a..d6857523336d 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h | |||
@@ -23,13 +23,16 @@ | |||
23 | #define DBG_EXTENT 0x00000020 | 23 | #define DBG_EXTENT 0x00000020 |
24 | #define DBG_BITMAP 0x00000040 | 24 | #define DBG_BITMAP 0x00000040 |
25 | 25 | ||
26 | //#define DBG_MASK (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD) | 26 | #if 0 |
27 | //#define DBG_MASK (DBG_BNODE_MOD|DBG_CAT_MOD|DBG_INODE) | 27 | #define DBG_MASK (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD) |
28 | //#define DBG_MASK (DBG_CAT_MOD|DBG_BNODE_REFS|DBG_INODE|DBG_EXTENT) | 28 | #define DBG_MASK (DBG_BNODE_MOD|DBG_CAT_MOD|DBG_INODE) |
29 | #define DBG_MASK (DBG_CAT_MOD|DBG_BNODE_REFS|DBG_INODE|DBG_EXTENT) | ||
30 | #endif | ||
29 | #define DBG_MASK (0) | 31 | #define DBG_MASK (0) |
30 | 32 | ||
31 | #define dprint(flg, fmt, args...) \ | 33 | #define dprint(flg, fmt, args...) \ |
32 | if (flg & DBG_MASK) printk(fmt , ## args) | 34 | if (flg & DBG_MASK) \ |
35 | printk(fmt , ## args) | ||
33 | 36 | ||
34 | /* Runtime config options */ | 37 | /* Runtime config options */ |
35 | #define HFSPLUS_DEF_CR_TYPE 0x3F3F3F3F /* '????' */ | 38 | #define HFSPLUS_DEF_CR_TYPE 0x3F3F3F3F /* '????' */ |
@@ -37,7 +40,8 @@ | |||
37 | #define HFSPLUS_TYPE_DATA 0x00 | 40 | #define HFSPLUS_TYPE_DATA 0x00 |
38 | #define HFSPLUS_TYPE_RSRC 0xFF | 41 | #define HFSPLUS_TYPE_RSRC 0xFF |
39 | 42 | ||
40 | typedef int (*btree_keycmp)(const hfsplus_btree_key *, const hfsplus_btree_key *); | 43 | typedef int (*btree_keycmp)(const hfsplus_btree_key *, |
44 | const hfsplus_btree_key *); | ||
41 | 45 | ||
42 | #define NODE_HASH_SIZE 256 | 46 | #define NODE_HASH_SIZE 256 |
43 | 47 | ||
@@ -61,7 +65,6 @@ struct hfs_btree { | |||
61 | unsigned int max_key_len; | 65 | unsigned int max_key_len; |
62 | unsigned int depth; | 66 | unsigned int depth; |
63 | 67 | ||
64 | //unsigned int map1_size, map_size; | ||
65 | struct mutex tree_lock; | 68 | struct mutex tree_lock; |
66 | 69 | ||
67 | unsigned int pages_per_bnode; | 70 | unsigned int pages_per_bnode; |
@@ -107,8 +110,8 @@ struct hfsplus_vh; | |||
107 | struct hfs_btree; | 110 | struct hfs_btree; |
108 | 111 | ||
109 | struct hfsplus_sb_info { | 112 | struct hfsplus_sb_info { |
110 | struct buffer_head *s_vhbh; | ||
111 | struct hfsplus_vh *s_vhdr; | 113 | struct hfsplus_vh *s_vhdr; |
114 | struct hfsplus_vh *s_backup_vhdr; | ||
112 | struct hfs_btree *ext_tree; | 115 | struct hfs_btree *ext_tree; |
113 | struct hfs_btree *cat_tree; | 116 | struct hfs_btree *cat_tree; |
114 | struct hfs_btree *attr_tree; | 117 | struct hfs_btree *attr_tree; |
@@ -118,7 +121,8 @@ struct hfsplus_sb_info { | |||
118 | 121 | ||
119 | /* Runtime variables */ | 122 | /* Runtime variables */ |
120 | u32 blockoffset; | 123 | u32 blockoffset; |
121 | u32 sect_count; | 124 | sector_t part_start; |
125 | sector_t sect_count; | ||
122 | int fs_shift; | 126 | int fs_shift; |
123 | 127 | ||
124 | /* immutable data from the volume header */ | 128 | /* immutable data from the volume header */ |
@@ -155,6 +159,12 @@ struct hfsplus_sb_info { | |||
155 | #define HFSPLUS_SB_FORCE 2 | 159 | #define HFSPLUS_SB_FORCE 2 |
156 | #define HFSPLUS_SB_HFSX 3 | 160 | #define HFSPLUS_SB_HFSX 3 |
157 | #define HFSPLUS_SB_CASEFOLD 4 | 161 | #define HFSPLUS_SB_CASEFOLD 4 |
162 | #define HFSPLUS_SB_NOBARRIER 5 | ||
163 | |||
164 | static inline struct hfsplus_sb_info *HFSPLUS_SB(struct super_block *sb) | ||
165 | { | ||
166 | return sb->s_fs_info; | ||
167 | } | ||
158 | 168 | ||
159 | 169 | ||
160 | struct hfsplus_inode_info { | 170 | struct hfsplus_inode_info { |
@@ -170,7 +180,7 @@ struct hfsplus_inode_info { | |||
170 | u32 cached_blocks; | 180 | u32 cached_blocks; |
171 | hfsplus_extent_rec first_extents; | 181 | hfsplus_extent_rec first_extents; |
172 | hfsplus_extent_rec cached_extents; | 182 | hfsplus_extent_rec cached_extents; |
173 | unsigned long flags; | 183 | unsigned int extent_state; |
174 | struct mutex extents_lock; | 184 | struct mutex extents_lock; |
175 | 185 | ||
176 | /* | 186 | /* |
@@ -185,6 +195,11 @@ struct hfsplus_inode_info { | |||
185 | u32 linkid; | 195 | u32 linkid; |
186 | 196 | ||
187 | /* | 197 | /* |
198 | * Accessed using atomic bitops. | ||
199 | */ | ||
200 | unsigned long flags; | ||
201 | |||
202 | /* | ||
188 | * Protected by i_mutex. | 203 | * Protected by i_mutex. |
189 | */ | 204 | */ |
190 | sector_t fs_blocks; | 205 | sector_t fs_blocks; |
@@ -195,12 +210,34 @@ struct hfsplus_inode_info { | |||
195 | struct inode vfs_inode; | 210 | struct inode vfs_inode; |
196 | }; | 211 | }; |
197 | 212 | ||
198 | #define HFSPLUS_FLG_RSRC 0x0001 | 213 | #define HFSPLUS_EXT_DIRTY 0x0001 |
199 | #define HFSPLUS_FLG_EXT_DIRTY 0x0002 | 214 | #define HFSPLUS_EXT_NEW 0x0002 |
200 | #define HFSPLUS_FLG_EXT_NEW 0x0004 | 215 | |
216 | #define HFSPLUS_I_RSRC 0 /* represents a resource fork */ | ||
217 | #define HFSPLUS_I_CAT_DIRTY 1 /* has changes in the catalog tree */ | ||
218 | #define HFSPLUS_I_EXT_DIRTY 2 /* has changes in the extent tree */ | ||
219 | #define HFSPLUS_I_ALLOC_DIRTY 3 /* has changes in the allocation file */ | ||
220 | |||
221 | #define HFSPLUS_IS_RSRC(inode) \ | ||
222 | test_bit(HFSPLUS_I_RSRC, &HFSPLUS_I(inode)->flags) | ||
223 | |||
224 | static inline struct hfsplus_inode_info *HFSPLUS_I(struct inode *inode) | ||
225 | { | ||
226 | return list_entry(inode, struct hfsplus_inode_info, vfs_inode); | ||
227 | } | ||
201 | 228 | ||
202 | #define HFSPLUS_IS_DATA(inode) (!(HFSPLUS_I(inode)->flags & HFSPLUS_FLG_RSRC)) | 229 | /* |
203 | #define HFSPLUS_IS_RSRC(inode) (HFSPLUS_I(inode)->flags & HFSPLUS_FLG_RSRC) | 230 | * Mark an inode dirty, and also mark the btree in which the |
231 | * specific type of metadata is stored. | ||
232 | * For data or metadata that gets written back by into the catalog btree | ||
233 | * by hfsplus_write_inode a plain mark_inode_dirty call is enough. | ||
234 | */ | ||
235 | static inline void hfsplus_mark_inode_dirty(struct inode *inode, | ||
236 | unsigned int flag) | ||
237 | { | ||
238 | set_bit(flag, &HFSPLUS_I(inode)->flags); | ||
239 | mark_inode_dirty(inode); | ||
240 | } | ||
204 | 241 | ||
205 | struct hfs_find_data { | 242 | struct hfs_find_data { |
206 | /* filled by caller */ | 243 | /* filled by caller */ |
@@ -318,9 +355,12 @@ int hfs_brec_read(struct hfs_find_data *, void *, int); | |||
318 | int hfs_brec_goto(struct hfs_find_data *, int); | 355 | int hfs_brec_goto(struct hfs_find_data *, int); |
319 | 356 | ||
320 | /* catalog.c */ | 357 | /* catalog.c */ |
321 | int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); | 358 | int hfsplus_cat_case_cmp_key(const hfsplus_btree_key *, |
322 | int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); | 359 | const hfsplus_btree_key *); |
323 | void hfsplus_cat_build_key(struct super_block *sb, hfsplus_btree_key *, u32, struct qstr *); | 360 | int hfsplus_cat_bin_cmp_key(const hfsplus_btree_key *, |
361 | const hfsplus_btree_key *); | ||
362 | void hfsplus_cat_build_key(struct super_block *sb, | ||
363 | hfsplus_btree_key *, u32, struct qstr *); | ||
324 | int hfsplus_find_cat(struct super_block *, u32, struct hfs_find_data *); | 364 | int hfsplus_find_cat(struct super_block *, u32, struct hfs_find_data *); |
325 | int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *); | 365 | int hfsplus_create_cat(u32, struct inode *, struct qstr *, struct inode *); |
326 | int hfsplus_delete_cat(u32, struct inode *, struct qstr *); | 366 | int hfsplus_delete_cat(u32, struct inode *, struct qstr *); |
@@ -336,7 +376,8 @@ extern const struct file_operations hfsplus_dir_operations; | |||
336 | int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); | 376 | int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *); |
337 | void hfsplus_ext_write_extent(struct inode *); | 377 | void hfsplus_ext_write_extent(struct inode *); |
338 | int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int); | 378 | int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int); |
339 | int hfsplus_free_fork(struct super_block *, u32, struct hfsplus_fork_raw *, int); | 379 | int hfsplus_free_fork(struct super_block *, u32, |
380 | struct hfsplus_fork_raw *, int); | ||
340 | int hfsplus_file_extend(struct inode *); | 381 | int hfsplus_file_extend(struct inode *); |
341 | void hfsplus_file_truncate(struct inode *); | 382 | void hfsplus_file_truncate(struct inode *); |
342 | 383 | ||
@@ -351,6 +392,7 @@ int hfsplus_cat_read_inode(struct inode *, struct hfs_find_data *); | |||
351 | int hfsplus_cat_write_inode(struct inode *); | 392 | int hfsplus_cat_write_inode(struct inode *); |
352 | struct inode *hfsplus_new_inode(struct super_block *, int); | 393 | struct inode *hfsplus_new_inode(struct super_block *, int); |
353 | void hfsplus_delete_inode(struct inode *); | 394 | void hfsplus_delete_inode(struct inode *); |
395 | int hfsplus_file_fsync(struct file *file, int datasync); | ||
354 | 396 | ||
355 | /* ioctl.c */ | 397 | /* ioctl.c */ |
356 | long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); | 398 | long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); |
@@ -362,6 +404,7 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size); | |||
362 | 404 | ||
363 | /* options.c */ | 405 | /* options.c */ |
364 | int hfsplus_parse_options(char *, struct hfsplus_sb_info *); | 406 | int hfsplus_parse_options(char *, struct hfsplus_sb_info *); |
407 | int hfsplus_parse_options_remount(char *input, int *force); | ||
365 | void hfsplus_fill_defaults(struct hfsplus_sb_info *); | 408 | void hfsplus_fill_defaults(struct hfsplus_sb_info *); |
366 | int hfsplus_show_options(struct seq_file *, struct vfsmount *); | 409 | int hfsplus_show_options(struct seq_file *, struct vfsmount *); |
367 | 410 | ||
@@ -375,45 +418,26 @@ extern u16 hfsplus_decompose_table[]; | |||
375 | extern u16 hfsplus_compose_table[]; | 418 | extern u16 hfsplus_compose_table[]; |
376 | 419 | ||
377 | /* unicode.c */ | 420 | /* unicode.c */ |
378 | int hfsplus_strcasecmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); | 421 | int hfsplus_strcasecmp(const struct hfsplus_unistr *, |
379 | int hfsplus_strcmp(const struct hfsplus_unistr *, const struct hfsplus_unistr *); | 422 | const struct hfsplus_unistr *); |
380 | int hfsplus_uni2asc(struct super_block *, const struct hfsplus_unistr *, char *, int *); | 423 | int hfsplus_strcmp(const struct hfsplus_unistr *, |
381 | int hfsplus_asc2uni(struct super_block *, struct hfsplus_unistr *, const char *, int); | 424 | const struct hfsplus_unistr *); |
382 | int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str); | 425 | int hfsplus_uni2asc(struct super_block *, |
383 | int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *s2); | 426 | const struct hfsplus_unistr *, char *, int *); |
427 | int hfsplus_asc2uni(struct super_block *, | ||
428 | struct hfsplus_unistr *, const char *, int); | ||
429 | int hfsplus_hash_dentry(const struct dentry *dentry, | ||
430 | const struct inode *inode, struct qstr *str); | ||
431 | int hfsplus_compare_dentry(const struct dentry *parent, | ||
432 | const struct inode *pinode, | ||
433 | const struct dentry *dentry, const struct inode *inode, | ||
434 | unsigned int len, const char *str, const struct qstr *name); | ||
384 | 435 | ||
385 | /* wrapper.c */ | 436 | /* wrapper.c */ |
386 | int hfsplus_read_wrapper(struct super_block *); | 437 | int hfsplus_read_wrapper(struct super_block *); |
387 | |||
388 | int hfs_part_find(struct super_block *, sector_t *, sector_t *); | 438 | int hfs_part_find(struct super_block *, sector_t *, sector_t *); |
389 | 439 | int hfsplus_submit_bio(struct block_device *bdev, sector_t sector, | |
390 | /* access macros */ | 440 | void *data, int rw); |
391 | static inline struct hfsplus_sb_info *HFSPLUS_SB(struct super_block *sb) | ||
392 | { | ||
393 | return sb->s_fs_info; | ||
394 | } | ||
395 | |||
396 | static inline struct hfsplus_inode_info *HFSPLUS_I(struct inode *inode) | ||
397 | { | ||
398 | return list_entry(inode, struct hfsplus_inode_info, vfs_inode); | ||
399 | } | ||
400 | |||
401 | #define sb_bread512(sb, sec, data) ({ \ | ||
402 | struct buffer_head *__bh; \ | ||
403 | sector_t __block; \ | ||
404 | loff_t __start; \ | ||
405 | int __offset; \ | ||
406 | \ | ||
407 | __start = (loff_t)(sec) << HFSPLUS_SECTOR_SHIFT;\ | ||
408 | __block = __start >> (sb)->s_blocksize_bits; \ | ||
409 | __offset = __start & ((sb)->s_blocksize - 1); \ | ||
410 | __bh = sb_bread((sb), __block); \ | ||
411 | if (likely(__bh != NULL)) \ | ||
412 | data = (void *)(__bh->b_data + __offset);\ | ||
413 | else \ | ||
414 | data = NULL; \ | ||
415 | __bh; \ | ||
416 | }) | ||
417 | 441 | ||
418 | /* time macros */ | 442 | /* time macros */ |
419 | #define __hfsp_mt2ut(t) (be32_to_cpu(t) - 2082844800U) | 443 | #define __hfsp_mt2ut(t) (be32_to_cpu(t) - 2082844800U) |
diff --git a/fs/hfsplus/hfsplus_raw.h b/fs/hfsplus/hfsplus_raw.h index 6892899fd6fb..927cdd6d5bf5 100644 --- a/fs/hfsplus/hfsplus_raw.h +++ b/fs/hfsplus/hfsplus_raw.h | |||
@@ -36,7 +36,8 @@ | |||
36 | #define HFSP_WRAPOFF_EMBEDSIG 0x7C | 36 | #define HFSP_WRAPOFF_EMBEDSIG 0x7C |
37 | #define HFSP_WRAPOFF_EMBEDEXT 0x7E | 37 | #define HFSP_WRAPOFF_EMBEDEXT 0x7E |
38 | 38 | ||
39 | #define HFSP_HIDDENDIR_NAME "\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80HFS+ Private Data" | 39 | #define HFSP_HIDDENDIR_NAME \ |
40 | "\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80\xe2\x90\x80HFS+ Private Data" | ||
40 | 41 | ||
41 | #define HFSP_HARDLINK_TYPE 0x686c6e6b /* 'hlnk' */ | 42 | #define HFSP_HARDLINK_TYPE 0x686c6e6b /* 'hlnk' */ |
42 | #define HFSP_HFSPLUS_CREATOR 0x6866732b /* 'hfs+' */ | 43 | #define HFSP_HFSPLUS_CREATOR 0x6866732b /* 'hfs+' */ |
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 8afd7e84f98d..a8df651747f0 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c | |||
@@ -8,6 +8,7 @@ | |||
8 | * Inode handling routines | 8 | * Inode handling routines |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/blkdev.h> | ||
11 | #include <linux/mm.h> | 12 | #include <linux/mm.h> |
12 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
13 | #include <linux/pagemap.h> | 14 | #include <linux/pagemap.h> |
@@ -77,7 +78,8 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask) | |||
77 | if (!tree) | 78 | if (!tree) |
78 | return 0; | 79 | return 0; |
79 | if (tree->node_size >= PAGE_CACHE_SIZE) { | 80 | if (tree->node_size >= PAGE_CACHE_SIZE) { |
80 | nidx = page->index >> (tree->node_size_shift - PAGE_CACHE_SHIFT); | 81 | nidx = page->index >> |
82 | (tree->node_size_shift - PAGE_CACHE_SHIFT); | ||
81 | spin_lock(&tree->hash_lock); | 83 | spin_lock(&tree->hash_lock); |
82 | node = hfs_bnode_findhash(tree, nidx); | 84 | node = hfs_bnode_findhash(tree, nidx); |
83 | if (!node) | 85 | if (!node) |
@@ -90,7 +92,8 @@ static int hfsplus_releasepage(struct page *page, gfp_t mask) | |||
90 | } | 92 | } |
91 | spin_unlock(&tree->hash_lock); | 93 | spin_unlock(&tree->hash_lock); |
92 | } else { | 94 | } else { |
93 | nidx = page->index << (PAGE_CACHE_SHIFT - tree->node_size_shift); | 95 | nidx = page->index << |
96 | (PAGE_CACHE_SHIFT - tree->node_size_shift); | ||
94 | i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift); | 97 | i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift); |
95 | spin_lock(&tree->hash_lock); | 98 | spin_lock(&tree->hash_lock); |
96 | do { | 99 | do { |
@@ -166,8 +169,8 @@ const struct dentry_operations hfsplus_dentry_operations = { | |||
166 | .d_compare = hfsplus_compare_dentry, | 169 | .d_compare = hfsplus_compare_dentry, |
167 | }; | 170 | }; |
168 | 171 | ||
169 | static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dentry, | 172 | static struct dentry *hfsplus_file_lookup(struct inode *dir, |
170 | struct nameidata *nd) | 173 | struct dentry *dentry, struct nameidata *nd) |
171 | { | 174 | { |
172 | struct hfs_find_data fd; | 175 | struct hfs_find_data fd; |
173 | struct super_block *sb = dir->i_sb; | 176 | struct super_block *sb = dir->i_sb; |
@@ -190,7 +193,9 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dent | |||
190 | inode->i_ino = dir->i_ino; | 193 | inode->i_ino = dir->i_ino; |
191 | INIT_LIST_HEAD(&hip->open_dir_list); | 194 | INIT_LIST_HEAD(&hip->open_dir_list); |
192 | mutex_init(&hip->extents_lock); | 195 | mutex_init(&hip->extents_lock); |
193 | hip->flags = HFSPLUS_FLG_RSRC; | 196 | hip->extent_state = 0; |
197 | hip->flags = 0; | ||
198 | set_bit(HFSPLUS_I_RSRC, &hip->flags); | ||
194 | 199 | ||
195 | hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); | 200 | hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); |
196 | err = hfsplus_find_cat(sb, dir->i_ino, &fd); | 201 | err = hfsplus_find_cat(sb, dir->i_ino, &fd); |
@@ -219,7 +224,8 @@ out: | |||
219 | return NULL; | 224 | return NULL; |
220 | } | 225 | } |
221 | 226 | ||
222 | static void hfsplus_get_perms(struct inode *inode, struct hfsplus_perm *perms, int dir) | 227 | static void hfsplus_get_perms(struct inode *inode, |
228 | struct hfsplus_perm *perms, int dir) | ||
223 | { | 229 | { |
224 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); | 230 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); |
225 | u16 mode; | 231 | u16 mode; |
@@ -302,29 +308,41 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) | |||
302 | return 0; | 308 | return 0; |
303 | } | 309 | } |
304 | 310 | ||
305 | static int hfsplus_file_fsync(struct file *filp, int datasync) | 311 | int hfsplus_file_fsync(struct file *file, int datasync) |
306 | { | 312 | { |
307 | struct inode *inode = filp->f_mapping->host; | 313 | struct inode *inode = file->f_mapping->host; |
308 | struct super_block * sb; | 314 | struct hfsplus_inode_info *hip = HFSPLUS_I(inode); |
309 | int ret, err; | 315 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); |
310 | 316 | int error = 0, error2; | |
311 | /* sync the inode to buffers */ | 317 | |
312 | ret = write_inode_now(inode, 0); | 318 | /* |
313 | 319 | * Sync inode metadata into the catalog and extent trees. | |
314 | /* sync the superblock to buffers */ | 320 | */ |
315 | sb = inode->i_sb; | 321 | sync_inode_metadata(inode, 1); |
316 | if (sb->s_dirt) { | 322 | |
317 | if (!(sb->s_flags & MS_RDONLY)) | 323 | /* |
318 | hfsplus_sync_fs(sb, 1); | 324 | * And explicitly write out the btrees. |
319 | else | 325 | */ |
320 | sb->s_dirt = 0; | 326 | if (test_and_clear_bit(HFSPLUS_I_CAT_DIRTY, &hip->flags)) |
327 | error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping); | ||
328 | |||
329 | if (test_and_clear_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags)) { | ||
330 | error2 = | ||
331 | filemap_write_and_wait(sbi->ext_tree->inode->i_mapping); | ||
332 | if (!error) | ||
333 | error = error2; | ||
321 | } | 334 | } |
322 | 335 | ||
323 | /* .. finally sync the buffers to disk */ | 336 | if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) { |
324 | err = sync_blockdev(sb->s_bdev); | 337 | error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); |
325 | if (!ret) | 338 | if (!error) |
326 | ret = err; | 339 | error = error2; |
327 | return ret; | 340 | } |
341 | |||
342 | if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) | ||
343 | blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); | ||
344 | |||
345 | return error; | ||
328 | } | 346 | } |
329 | 347 | ||
330 | static const struct inode_operations hfsplus_file_inode_operations = { | 348 | static const struct inode_operations hfsplus_file_inode_operations = { |
@@ -337,7 +355,7 @@ static const struct inode_operations hfsplus_file_inode_operations = { | |||
337 | }; | 355 | }; |
338 | 356 | ||
339 | static const struct file_operations hfsplus_file_operations = { | 357 | static const struct file_operations hfsplus_file_operations = { |
340 | .llseek = generic_file_llseek, | 358 | .llseek = generic_file_llseek, |
341 | .read = do_sync_read, | 359 | .read = do_sync_read, |
342 | .aio_read = generic_file_aio_read, | 360 | .aio_read = generic_file_aio_read, |
343 | .write = do_sync_write, | 361 | .write = do_sync_write, |
@@ -370,6 +388,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, int mode) | |||
370 | INIT_LIST_HEAD(&hip->open_dir_list); | 388 | INIT_LIST_HEAD(&hip->open_dir_list); |
371 | mutex_init(&hip->extents_lock); | 389 | mutex_init(&hip->extents_lock); |
372 | atomic_set(&hip->opencnt, 0); | 390 | atomic_set(&hip->opencnt, 0); |
391 | hip->extent_state = 0; | ||
373 | hip->flags = 0; | 392 | hip->flags = 0; |
374 | memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec)); | 393 | memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec)); |
375 | memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); | 394 | memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); |
@@ -457,7 +476,8 @@ void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork) | |||
457 | } | 476 | } |
458 | } | 477 | } |
459 | 478 | ||
460 | void hfsplus_inode_write_fork(struct inode *inode, struct hfsplus_fork_raw *fork) | 479 | void hfsplus_inode_write_fork(struct inode *inode, |
480 | struct hfsplus_fork_raw *fork) | ||
461 | { | 481 | { |
462 | memcpy(&fork->extents, &HFSPLUS_I(inode)->first_extents, | 482 | memcpy(&fork->extents, &HFSPLUS_I(inode)->first_extents, |
463 | sizeof(hfsplus_extent_rec)); | 483 | sizeof(hfsplus_extent_rec)); |
@@ -499,13 +519,14 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd) | |||
499 | hfs_bnode_read(fd->bnode, &entry, fd->entryoffset, | 519 | hfs_bnode_read(fd->bnode, &entry, fd->entryoffset, |
500 | sizeof(struct hfsplus_cat_file)); | 520 | sizeof(struct hfsplus_cat_file)); |
501 | 521 | ||
502 | hfsplus_inode_read_fork(inode, HFSPLUS_IS_DATA(inode) ? | 522 | hfsplus_inode_read_fork(inode, HFSPLUS_IS_RSRC(inode) ? |
503 | &file->data_fork : &file->rsrc_fork); | 523 | &file->rsrc_fork : &file->data_fork); |
504 | hfsplus_get_perms(inode, &file->permissions, 0); | 524 | hfsplus_get_perms(inode, &file->permissions, 0); |
505 | inode->i_nlink = 1; | 525 | inode->i_nlink = 1; |
506 | if (S_ISREG(inode->i_mode)) { | 526 | if (S_ISREG(inode->i_mode)) { |
507 | if (file->permissions.dev) | 527 | if (file->permissions.dev) |
508 | inode->i_nlink = be32_to_cpu(file->permissions.dev); | 528 | inode->i_nlink = |
529 | be32_to_cpu(file->permissions.dev); | ||
509 | inode->i_op = &hfsplus_file_inode_operations; | 530 | inode->i_op = &hfsplus_file_inode_operations; |
510 | inode->i_fop = &hfsplus_file_operations; | 531 | inode->i_fop = &hfsplus_file_operations; |
511 | inode->i_mapping->a_ops = &hfsplus_aops; | 532 | inode->i_mapping->a_ops = &hfsplus_aops; |
@@ -578,7 +599,9 @@ int hfsplus_cat_write_inode(struct inode *inode) | |||
578 | sizeof(struct hfsplus_cat_file)); | 599 | sizeof(struct hfsplus_cat_file)); |
579 | hfsplus_inode_write_fork(inode, &file->data_fork); | 600 | hfsplus_inode_write_fork(inode, &file->data_fork); |
580 | hfsplus_cat_set_perms(inode, &file->permissions); | 601 | hfsplus_cat_set_perms(inode, &file->permissions); |
581 | if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE) | 602 | if (HFSPLUS_FLG_IMMUTABLE & |
603 | (file->permissions.rootflags | | ||
604 | file->permissions.userflags)) | ||
582 | file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED); | 605 | file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED); |
583 | else | 606 | else |
584 | file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED); | 607 | file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED); |
@@ -588,6 +611,8 @@ int hfsplus_cat_write_inode(struct inode *inode) | |||
588 | hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, | 611 | hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, |
589 | sizeof(struct hfsplus_cat_file)); | 612 | sizeof(struct hfsplus_cat_file)); |
590 | } | 613 | } |
614 | |||
615 | set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags); | ||
591 | out: | 616 | out: |
592 | hfs_find_exit(&fd); | 617 | hfs_find_exit(&fd); |
593 | return 0; | 618 | return 0; |
diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c index 40a85a3ded6e..508ce662ce12 100644 --- a/fs/hfsplus/ioctl.c +++ b/fs/hfsplus/ioctl.c | |||
@@ -28,7 +28,7 @@ static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags) | |||
28 | 28 | ||
29 | if (inode->i_flags & S_IMMUTABLE) | 29 | if (inode->i_flags & S_IMMUTABLE) |
30 | flags |= FS_IMMUTABLE_FL; | 30 | flags |= FS_IMMUTABLE_FL; |
31 | if (inode->i_flags |= S_APPEND) | 31 | if (inode->i_flags & S_APPEND) |
32 | flags |= FS_APPEND_FL; | 32 | flags |= FS_APPEND_FL; |
33 | if (hip->userflags & HFSPLUS_FLG_NODUMP) | 33 | if (hip->userflags & HFSPLUS_FLG_NODUMP) |
34 | flags |= FS_NODUMP_FL; | 34 | flags |= FS_NODUMP_FL; |
@@ -147,9 +147,11 @@ int hfsplus_setxattr(struct dentry *dentry, const char *name, | |||
147 | res = -ERANGE; | 147 | res = -ERANGE; |
148 | } else | 148 | } else |
149 | res = -EOPNOTSUPP; | 149 | res = -EOPNOTSUPP; |
150 | if (!res) | 150 | if (!res) { |
151 | hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, | 151 | hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, |
152 | sizeof(struct hfsplus_cat_file)); | 152 | sizeof(struct hfsplus_cat_file)); |
153 | hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); | ||
154 | } | ||
153 | out: | 155 | out: |
154 | hfs_find_exit(&fd); | 156 | hfs_find_exit(&fd); |
155 | return res; | 157 | return res; |
diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c index f9ab276a4d8d..bb62a5882147 100644 --- a/fs/hfsplus/options.c +++ b/fs/hfsplus/options.c | |||
@@ -23,6 +23,7 @@ enum { | |||
23 | opt_umask, opt_uid, opt_gid, | 23 | opt_umask, opt_uid, opt_gid, |
24 | opt_part, opt_session, opt_nls, | 24 | opt_part, opt_session, opt_nls, |
25 | opt_nodecompose, opt_decompose, | 25 | opt_nodecompose, opt_decompose, |
26 | opt_barrier, opt_nobarrier, | ||
26 | opt_force, opt_err | 27 | opt_force, opt_err |
27 | }; | 28 | }; |
28 | 29 | ||
@@ -37,6 +38,8 @@ static const match_table_t tokens = { | |||
37 | { opt_nls, "nls=%s" }, | 38 | { opt_nls, "nls=%s" }, |
38 | { opt_decompose, "decompose" }, | 39 | { opt_decompose, "decompose" }, |
39 | { opt_nodecompose, "nodecompose" }, | 40 | { opt_nodecompose, "nodecompose" }, |
41 | { opt_barrier, "barrier" }, | ||
42 | { opt_nobarrier, "nobarrier" }, | ||
40 | { opt_force, "force" }, | 43 | { opt_force, "force" }, |
41 | { opt_err, NULL } | 44 | { opt_err, NULL } |
42 | }; | 45 | }; |
@@ -65,6 +68,32 @@ static inline int match_fourchar(substring_t *arg, u32 *result) | |||
65 | return 0; | 68 | return 0; |
66 | } | 69 | } |
67 | 70 | ||
71 | int hfsplus_parse_options_remount(char *input, int *force) | ||
72 | { | ||
73 | char *p; | ||
74 | substring_t args[MAX_OPT_ARGS]; | ||
75 | int token; | ||
76 | |||
77 | if (!input) | ||
78 | return 0; | ||
79 | |||
80 | while ((p = strsep(&input, ",")) != NULL) { | ||
81 | if (!*p) | ||
82 | continue; | ||
83 | |||
84 | token = match_token(p, tokens, args); | ||
85 | switch (token) { | ||
86 | case opt_force: | ||
87 | *force = 1; | ||
88 | break; | ||
89 | default: | ||
90 | break; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | return 1; | ||
95 | } | ||
96 | |||
68 | /* Parse options from mount. Returns 0 on failure */ | 97 | /* Parse options from mount. Returns 0 on failure */ |
69 | /* input is the options passed to mount() as a string */ | 98 | /* input is the options passed to mount() as a string */ |
70 | int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi) | 99 | int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi) |
@@ -136,7 +165,9 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi) | |||
136 | if (p) | 165 | if (p) |
137 | sbi->nls = load_nls(p); | 166 | sbi->nls = load_nls(p); |
138 | if (!sbi->nls) { | 167 | if (!sbi->nls) { |
139 | printk(KERN_ERR "hfs: unable to load nls mapping \"%s\"\n", p); | 168 | printk(KERN_ERR "hfs: unable to load " |
169 | "nls mapping \"%s\"\n", | ||
170 | p); | ||
140 | kfree(p); | 171 | kfree(p); |
141 | return 0; | 172 | return 0; |
142 | } | 173 | } |
@@ -148,6 +179,12 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi) | |||
148 | case opt_nodecompose: | 179 | case opt_nodecompose: |
149 | set_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags); | 180 | set_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags); |
150 | break; | 181 | break; |
182 | case opt_barrier: | ||
183 | clear_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags); | ||
184 | break; | ||
185 | case opt_nobarrier: | ||
186 | set_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags); | ||
187 | break; | ||
151 | case opt_force: | 188 | case opt_force: |
152 | set_bit(HFSPLUS_SB_FORCE, &sbi->flags); | 189 | set_bit(HFSPLUS_SB_FORCE, &sbi->flags); |
153 | break; | 190 | break; |
@@ -177,7 +214,8 @@ int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt) | |||
177 | seq_printf(seq, ",creator=%.4s", (char *)&sbi->creator); | 214 | seq_printf(seq, ",creator=%.4s", (char *)&sbi->creator); |
178 | if (sbi->type != HFSPLUS_DEF_CR_TYPE) | 215 | if (sbi->type != HFSPLUS_DEF_CR_TYPE) |
179 | seq_printf(seq, ",type=%.4s", (char *)&sbi->type); | 216 | seq_printf(seq, ",type=%.4s", (char *)&sbi->type); |
180 | seq_printf(seq, ",umask=%o,uid=%u,gid=%u", sbi->umask, sbi->uid, sbi->gid); | 217 | seq_printf(seq, ",umask=%o,uid=%u,gid=%u", sbi->umask, |
218 | sbi->uid, sbi->gid); | ||
181 | if (sbi->part >= 0) | 219 | if (sbi->part >= 0) |
182 | seq_printf(seq, ",part=%u", sbi->part); | 220 | seq_printf(seq, ",part=%u", sbi->part); |
183 | if (sbi->session >= 0) | 221 | if (sbi->session >= 0) |
@@ -186,5 +224,7 @@ int hfsplus_show_options(struct seq_file *seq, struct vfsmount *mnt) | |||
186 | seq_printf(seq, ",nls=%s", sbi->nls->charset); | 224 | seq_printf(seq, ",nls=%s", sbi->nls->charset); |
187 | if (test_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags)) | 225 | if (test_bit(HFSPLUS_SB_NODECOMPOSE, &sbi->flags)) |
188 | seq_printf(seq, ",nodecompose"); | 226 | seq_printf(seq, ",nodecompose"); |
227 | if (test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) | ||
228 | seq_printf(seq, ",nobarrier"); | ||
189 | return 0; | 229 | return 0; |
190 | } | 230 | } |
diff --git a/fs/hfsplus/part_tbl.c b/fs/hfsplus/part_tbl.c index 208b16c645cc..d66ad113b1cc 100644 --- a/fs/hfsplus/part_tbl.c +++ b/fs/hfsplus/part_tbl.c | |||
@@ -2,7 +2,8 @@ | |||
2 | * linux/fs/hfsplus/part_tbl.c | 2 | * linux/fs/hfsplus/part_tbl.c |
3 | * | 3 | * |
4 | * Copyright (C) 1996-1997 Paul H. Hargrove | 4 | * Copyright (C) 1996-1997 Paul H. Hargrove |
5 | * This file may be distributed under the terms of the GNU General Public License. | 5 | * This file may be distributed under the terms of |
6 | * the GNU General Public License. | ||
6 | * | 7 | * |
7 | * Original code to handle the new style Mac partition table based on | 8 | * Original code to handle the new style Mac partition table based on |
8 | * a patch contributed by Holger Schemel (aeglos@valinor.owl.de). | 9 | * a patch contributed by Holger Schemel (aeglos@valinor.owl.de). |
@@ -13,6 +14,7 @@ | |||
13 | * | 14 | * |
14 | */ | 15 | */ |
15 | 16 | ||
17 | #include <linux/slab.h> | ||
16 | #include "hfsplus_fs.h" | 18 | #include "hfsplus_fs.h" |
17 | 19 | ||
18 | /* offsets to various blocks */ | 20 | /* offsets to various blocks */ |
@@ -58,77 +60,94 @@ struct new_pmap { | |||
58 | */ | 60 | */ |
59 | struct old_pmap { | 61 | struct old_pmap { |
60 | __be16 pdSig; /* Signature bytes */ | 62 | __be16 pdSig; /* Signature bytes */ |
61 | struct old_pmap_entry { | 63 | struct old_pmap_entry { |
62 | __be32 pdStart; | 64 | __be32 pdStart; |
63 | __be32 pdSize; | 65 | __be32 pdSize; |
64 | __be32 pdFSID; | 66 | __be32 pdFSID; |
65 | } pdEntry[42]; | 67 | } pdEntry[42]; |
66 | } __packed; | 68 | } __packed; |
67 | 69 | ||
70 | static int hfs_parse_old_pmap(struct super_block *sb, struct old_pmap *pm, | ||
71 | sector_t *part_start, sector_t *part_size) | ||
72 | { | ||
73 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); | ||
74 | int i; | ||
75 | |||
76 | for (i = 0; i < 42; i++) { | ||
77 | struct old_pmap_entry *p = &pm->pdEntry[i]; | ||
78 | |||
79 | if (p->pdStart && p->pdSize && | ||
80 | p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ && | ||
81 | (sbi->part < 0 || sbi->part == i)) { | ||
82 | *part_start += be32_to_cpu(p->pdStart); | ||
83 | *part_size = be32_to_cpu(p->pdSize); | ||
84 | return 0; | ||
85 | } | ||
86 | } | ||
87 | |||
88 | return -ENOENT; | ||
89 | } | ||
90 | |||
91 | static int hfs_parse_new_pmap(struct super_block *sb, struct new_pmap *pm, | ||
92 | sector_t *part_start, sector_t *part_size) | ||
93 | { | ||
94 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); | ||
95 | int size = be32_to_cpu(pm->pmMapBlkCnt); | ||
96 | int res; | ||
97 | int i = 0; | ||
98 | |||
99 | do { | ||
100 | if (!memcmp(pm->pmPartType, "Apple_HFS", 9) && | ||
101 | (sbi->part < 0 || sbi->part == i)) { | ||
102 | *part_start += be32_to_cpu(pm->pmPyPartStart); | ||
103 | *part_size = be32_to_cpu(pm->pmPartBlkCnt); | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | if (++i >= size) | ||
108 | return -ENOENT; | ||
109 | |||
110 | res = hfsplus_submit_bio(sb->s_bdev, | ||
111 | *part_start + HFS_PMAP_BLK + i, | ||
112 | pm, READ); | ||
113 | if (res) | ||
114 | return res; | ||
115 | } while (pm->pmSig == cpu_to_be16(HFS_NEW_PMAP_MAGIC)); | ||
116 | |||
117 | return -ENOENT; | ||
118 | } | ||
119 | |||
68 | /* | 120 | /* |
69 | * hfs_part_find() | 121 | * Parse the partition map looking for the start and length of a |
70 | * | 122 | * HFS/HFS+ partition. |
71 | * Parse the partition map looking for the | ||
72 | * start and length of the 'part'th HFS partition. | ||
73 | */ | 123 | */ |
74 | int hfs_part_find(struct super_block *sb, | 124 | int hfs_part_find(struct super_block *sb, |
75 | sector_t *part_start, sector_t *part_size) | 125 | sector_t *part_start, sector_t *part_size) |
76 | { | 126 | { |
77 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); | 127 | void *data; |
78 | struct buffer_head *bh; | 128 | int res; |
79 | __be16 *data; | 129 | |
80 | int i, size, res; | 130 | data = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL); |
131 | if (!data) | ||
132 | return -ENOMEM; | ||
81 | 133 | ||
82 | res = -ENOENT; | 134 | res = hfsplus_submit_bio(sb->s_bdev, *part_start + HFS_PMAP_BLK, |
83 | bh = sb_bread512(sb, *part_start + HFS_PMAP_BLK, data); | 135 | data, READ); |
84 | if (!bh) | 136 | if (res) |
85 | return -EIO; | 137 | return res; |
86 | 138 | ||
87 | switch (be16_to_cpu(*data)) { | 139 | switch (be16_to_cpu(*((__be16 *)data))) { |
88 | case HFS_OLD_PMAP_MAGIC: | 140 | case HFS_OLD_PMAP_MAGIC: |
89 | { | 141 | res = hfs_parse_old_pmap(sb, data, part_start, part_size); |
90 | struct old_pmap *pm; | ||
91 | struct old_pmap_entry *p; | ||
92 | |||
93 | pm = (struct old_pmap *)bh->b_data; | ||
94 | p = pm->pdEntry; | ||
95 | size = 42; | ||
96 | for (i = 0; i < size; p++, i++) { | ||
97 | if (p->pdStart && p->pdSize && | ||
98 | p->pdFSID == cpu_to_be32(0x54465331)/*"TFS1"*/ && | ||
99 | (sbi->part < 0 || sbi->part == i)) { | ||
100 | *part_start += be32_to_cpu(p->pdStart); | ||
101 | *part_size = be32_to_cpu(p->pdSize); | ||
102 | res = 0; | ||
103 | } | ||
104 | } | ||
105 | break; | 142 | break; |
106 | } | ||
107 | case HFS_NEW_PMAP_MAGIC: | 143 | case HFS_NEW_PMAP_MAGIC: |
108 | { | 144 | res = hfs_parse_new_pmap(sb, data, part_start, part_size); |
109 | struct new_pmap *pm; | 145 | break; |
110 | 146 | default: | |
111 | pm = (struct new_pmap *)bh->b_data; | 147 | res = -ENOENT; |
112 | size = be32_to_cpu(pm->pmMapBlkCnt); | ||
113 | for (i = 0; i < size;) { | ||
114 | if (!memcmp(pm->pmPartType,"Apple_HFS", 9) && | ||
115 | (sbi->part < 0 || sbi->part == i)) { | ||
116 | *part_start += be32_to_cpu(pm->pmPyPartStart); | ||
117 | *part_size = be32_to_cpu(pm->pmPartBlkCnt); | ||
118 | res = 0; | ||
119 | break; | ||
120 | } | ||
121 | brelse(bh); | ||
122 | bh = sb_bread512(sb, *part_start + HFS_PMAP_BLK + ++i, pm); | ||
123 | if (!bh) | ||
124 | return -EIO; | ||
125 | if (pm->pmSig != cpu_to_be16(HFS_NEW_PMAP_MAGIC)) | ||
126 | break; | ||
127 | } | ||
128 | break; | 148 | break; |
129 | } | ||
130 | } | 149 | } |
131 | brelse(bh); | ||
132 | 150 | ||
151 | kfree(data); | ||
133 | return res; | 152 | return res; |
134 | } | 153 | } |
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 52cc746d3ba3..6ee6ad20acf2 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/pagemap.h> | 12 | #include <linux/pagemap.h> |
13 | #include <linux/blkdev.h> | ||
13 | #include <linux/fs.h> | 14 | #include <linux/fs.h> |
14 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
15 | #include <linux/vfs.h> | 16 | #include <linux/vfs.h> |
@@ -66,6 +67,7 @@ struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino) | |||
66 | INIT_LIST_HEAD(&HFSPLUS_I(inode)->open_dir_list); | 67 | INIT_LIST_HEAD(&HFSPLUS_I(inode)->open_dir_list); |
67 | mutex_init(&HFSPLUS_I(inode)->extents_lock); | 68 | mutex_init(&HFSPLUS_I(inode)->extents_lock); |
68 | HFSPLUS_I(inode)->flags = 0; | 69 | HFSPLUS_I(inode)->flags = 0; |
70 | HFSPLUS_I(inode)->extent_state = 0; | ||
69 | HFSPLUS_I(inode)->rsrc_inode = NULL; | 71 | HFSPLUS_I(inode)->rsrc_inode = NULL; |
70 | atomic_set(&HFSPLUS_I(inode)->opencnt, 0); | 72 | atomic_set(&HFSPLUS_I(inode)->opencnt, 0); |
71 | 73 | ||
@@ -157,45 +159,65 @@ int hfsplus_sync_fs(struct super_block *sb, int wait) | |||
157 | { | 159 | { |
158 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); | 160 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); |
159 | struct hfsplus_vh *vhdr = sbi->s_vhdr; | 161 | struct hfsplus_vh *vhdr = sbi->s_vhdr; |
162 | int write_backup = 0; | ||
163 | int error, error2; | ||
164 | |||
165 | if (!wait) | ||
166 | return 0; | ||
160 | 167 | ||
161 | dprint(DBG_SUPER, "hfsplus_write_super\n"); | 168 | dprint(DBG_SUPER, "hfsplus_write_super\n"); |
162 | 169 | ||
163 | mutex_lock(&sbi->vh_mutex); | ||
164 | mutex_lock(&sbi->alloc_mutex); | ||
165 | sb->s_dirt = 0; | 170 | sb->s_dirt = 0; |
166 | 171 | ||
172 | /* | ||
173 | * Explicitly write out the special metadata inodes. | ||
174 | * | ||
175 | * While these special inodes are marked as hashed and written | ||
176 | * out peridocically by the flusher threads we redirty them | ||
177 | * during writeout of normal inodes, and thus the life lock | ||
178 | * prevents us from getting the latest state to disk. | ||
179 | */ | ||
180 | error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping); | ||
181 | error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping); | ||
182 | if (!error) | ||
183 | error = error2; | ||
184 | error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); | ||
185 | if (!error) | ||
186 | error = error2; | ||
187 | |||
188 | mutex_lock(&sbi->vh_mutex); | ||
189 | mutex_lock(&sbi->alloc_mutex); | ||
167 | vhdr->free_blocks = cpu_to_be32(sbi->free_blocks); | 190 | vhdr->free_blocks = cpu_to_be32(sbi->free_blocks); |
168 | vhdr->next_cnid = cpu_to_be32(sbi->next_cnid); | 191 | vhdr->next_cnid = cpu_to_be32(sbi->next_cnid); |
169 | vhdr->folder_count = cpu_to_be32(sbi->folder_count); | 192 | vhdr->folder_count = cpu_to_be32(sbi->folder_count); |
170 | vhdr->file_count = cpu_to_be32(sbi->file_count); | 193 | vhdr->file_count = cpu_to_be32(sbi->file_count); |
171 | 194 | ||
172 | mark_buffer_dirty(sbi->s_vhbh); | ||
173 | if (test_and_clear_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags)) { | 195 | if (test_and_clear_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags)) { |
174 | if (sbi->sect_count) { | 196 | memcpy(sbi->s_backup_vhdr, sbi->s_vhdr, sizeof(*sbi->s_vhdr)); |
175 | struct buffer_head *bh; | 197 | write_backup = 1; |
176 | u32 block, offset; | ||
177 | |||
178 | block = sbi->blockoffset; | ||
179 | block += (sbi->sect_count - 2) >> (sb->s_blocksize_bits - 9); | ||
180 | offset = ((sbi->sect_count - 2) << 9) & (sb->s_blocksize - 1); | ||
181 | printk(KERN_DEBUG "hfs: backup: %u,%u,%u,%u\n", | ||
182 | sbi->blockoffset, sbi->sect_count, | ||
183 | block, offset); | ||
184 | bh = sb_bread(sb, block); | ||
185 | if (bh) { | ||
186 | vhdr = (struct hfsplus_vh *)(bh->b_data + offset); | ||
187 | if (be16_to_cpu(vhdr->signature) == HFSPLUS_VOLHEAD_SIG) { | ||
188 | memcpy(vhdr, sbi->s_vhdr, sizeof(*vhdr)); | ||
189 | mark_buffer_dirty(bh); | ||
190 | brelse(bh); | ||
191 | } else | ||
192 | printk(KERN_WARNING "hfs: backup not found!\n"); | ||
193 | } | ||
194 | } | ||
195 | } | 198 | } |
199 | |||
200 | error2 = hfsplus_submit_bio(sb->s_bdev, | ||
201 | sbi->part_start + HFSPLUS_VOLHEAD_SECTOR, | ||
202 | sbi->s_vhdr, WRITE_SYNC); | ||
203 | if (!error) | ||
204 | error = error2; | ||
205 | if (!write_backup) | ||
206 | goto out; | ||
207 | |||
208 | error2 = hfsplus_submit_bio(sb->s_bdev, | ||
209 | sbi->part_start + sbi->sect_count - 2, | ||
210 | sbi->s_backup_vhdr, WRITE_SYNC); | ||
211 | if (!error) | ||
212 | error2 = error; | ||
213 | out: | ||
196 | mutex_unlock(&sbi->alloc_mutex); | 214 | mutex_unlock(&sbi->alloc_mutex); |
197 | mutex_unlock(&sbi->vh_mutex); | 215 | mutex_unlock(&sbi->vh_mutex); |
198 | return 0; | 216 | |
217 | if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) | ||
218 | blkdev_issue_flush(sb->s_bdev, GFP_KERNEL, NULL); | ||
219 | |||
220 | return error; | ||
199 | } | 221 | } |
200 | 222 | ||
201 | static void hfsplus_write_super(struct super_block *sb) | 223 | static void hfsplus_write_super(struct super_block *sb) |
@@ -215,23 +237,22 @@ static void hfsplus_put_super(struct super_block *sb) | |||
215 | if (!sb->s_fs_info) | 237 | if (!sb->s_fs_info) |
216 | return; | 238 | return; |
217 | 239 | ||
218 | if (sb->s_dirt) | ||
219 | hfsplus_write_super(sb); | ||
220 | if (!(sb->s_flags & MS_RDONLY) && sbi->s_vhdr) { | 240 | if (!(sb->s_flags & MS_RDONLY) && sbi->s_vhdr) { |
221 | struct hfsplus_vh *vhdr = sbi->s_vhdr; | 241 | struct hfsplus_vh *vhdr = sbi->s_vhdr; |
222 | 242 | ||
223 | vhdr->modify_date = hfsp_now2mt(); | 243 | vhdr->modify_date = hfsp_now2mt(); |
224 | vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_UNMNT); | 244 | vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_UNMNT); |
225 | vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_INCNSTNT); | 245 | vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_INCNSTNT); |
226 | mark_buffer_dirty(sbi->s_vhbh); | 246 | |
227 | sync_dirty_buffer(sbi->s_vhbh); | 247 | hfsplus_sync_fs(sb, 1); |
228 | } | 248 | } |
229 | 249 | ||
230 | hfs_btree_close(sbi->cat_tree); | 250 | hfs_btree_close(sbi->cat_tree); |
231 | hfs_btree_close(sbi->ext_tree); | 251 | hfs_btree_close(sbi->ext_tree); |
232 | iput(sbi->alloc_file); | 252 | iput(sbi->alloc_file); |
233 | iput(sbi->hidden_dir); | 253 | iput(sbi->hidden_dir); |
234 | brelse(sbi->s_vhbh); | 254 | kfree(sbi->s_vhdr); |
255 | kfree(sbi->s_backup_vhdr); | ||
235 | unload_nls(sbi->nls); | 256 | unload_nls(sbi->nls); |
236 | kfree(sb->s_fs_info); | 257 | kfree(sb->s_fs_info); |
237 | sb->s_fs_info = NULL; | 258 | sb->s_fs_info = NULL; |
@@ -263,26 +284,31 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data) | |||
263 | return 0; | 284 | return 0; |
264 | if (!(*flags & MS_RDONLY)) { | 285 | if (!(*flags & MS_RDONLY)) { |
265 | struct hfsplus_vh *vhdr = HFSPLUS_SB(sb)->s_vhdr; | 286 | struct hfsplus_vh *vhdr = HFSPLUS_SB(sb)->s_vhdr; |
266 | struct hfsplus_sb_info sbi; | 287 | int force = 0; |
267 | 288 | ||
268 | memset(&sbi, 0, sizeof(struct hfsplus_sb_info)); | 289 | if (!hfsplus_parse_options_remount(data, &force)) |
269 | sbi.nls = HFSPLUS_SB(sb)->nls; | ||
270 | if (!hfsplus_parse_options(data, &sbi)) | ||
271 | return -EINVAL; | 290 | return -EINVAL; |
272 | 291 | ||
273 | if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { | 292 | if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { |
274 | printk(KERN_WARNING "hfs: filesystem was not cleanly unmounted, " | 293 | printk(KERN_WARNING "hfs: filesystem was " |
275 | "running fsck.hfsplus is recommended. leaving read-only.\n"); | 294 | "not cleanly unmounted, " |
295 | "running fsck.hfsplus is recommended. " | ||
296 | "leaving read-only.\n"); | ||
276 | sb->s_flags |= MS_RDONLY; | 297 | sb->s_flags |= MS_RDONLY; |
277 | *flags |= MS_RDONLY; | 298 | *flags |= MS_RDONLY; |
278 | } else if (test_bit(HFSPLUS_SB_FORCE, &sbi.flags)) { | 299 | } else if (force) { |
279 | /* nothing */ | 300 | /* nothing */ |
280 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { | 301 | } else if (vhdr->attributes & |
281 | printk(KERN_WARNING "hfs: filesystem is marked locked, leaving read-only.\n"); | 302 | cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { |
303 | printk(KERN_WARNING "hfs: filesystem is marked locked, " | ||
304 | "leaving read-only.\n"); | ||
282 | sb->s_flags |= MS_RDONLY; | 305 | sb->s_flags |= MS_RDONLY; |
283 | *flags |= MS_RDONLY; | 306 | *flags |= MS_RDONLY; |
284 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { | 307 | } else if (vhdr->attributes & |
285 | printk(KERN_WARNING "hfs: filesystem is marked journaled, leaving read-only.\n"); | 308 | cpu_to_be32(HFSPLUS_VOL_JOURNALED)) { |
309 | printk(KERN_WARNING "hfs: filesystem is " | ||
310 | "marked journaled, " | ||
311 | "leaving read-only.\n"); | ||
286 | sb->s_flags |= MS_RDONLY; | 312 | sb->s_flags |= MS_RDONLY; |
287 | *flags |= MS_RDONLY; | 313 | *flags |= MS_RDONLY; |
288 | } | 314 | } |
@@ -372,17 +398,22 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
372 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 398 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
373 | 399 | ||
374 | if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { | 400 | if (!(vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_UNMNT))) { |
375 | printk(KERN_WARNING "hfs: Filesystem was not cleanly unmounted, " | 401 | printk(KERN_WARNING "hfs: Filesystem was " |
376 | "running fsck.hfsplus is recommended. mounting read-only.\n"); | 402 | "not cleanly unmounted, " |
403 | "running fsck.hfsplus is recommended. " | ||
404 | "mounting read-only.\n"); | ||
377 | sb->s_flags |= MS_RDONLY; | 405 | sb->s_flags |= MS_RDONLY; |
378 | } else if (test_and_clear_bit(HFSPLUS_SB_FORCE, &sbi->flags)) { | 406 | } else if (test_and_clear_bit(HFSPLUS_SB_FORCE, &sbi->flags)) { |
379 | /* nothing */ | 407 | /* nothing */ |
380 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { | 408 | } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) { |
381 | printk(KERN_WARNING "hfs: Filesystem is marked locked, mounting read-only.\n"); | 409 | printk(KERN_WARNING "hfs: Filesystem is marked locked, mounting read-only.\n"); |
382 | sb->s_flags |= MS_RDONLY; | 410 | sb->s_flags |= MS_RDONLY; |
383 | } else if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) && !(sb->s_flags & MS_RDONLY)) { | 411 | } else if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) && |
384 | printk(KERN_WARNING "hfs: write access to a journaled filesystem is not supported, " | 412 | !(sb->s_flags & MS_RDONLY)) { |
385 | "use the force option at your own risk, mounting read-only.\n"); | 413 | printk(KERN_WARNING "hfs: write access to " |
414 | "a journaled filesystem is not supported, " | ||
415 | "use the force option at your own risk, " | ||
416 | "mounting read-only.\n"); | ||
386 | sb->s_flags |= MS_RDONLY; | 417 | sb->s_flags |= MS_RDONLY; |
387 | } | 418 | } |
388 | 419 | ||
@@ -419,7 +450,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
419 | err = -ENOMEM; | 450 | err = -ENOMEM; |
420 | goto cleanup; | 451 | goto cleanup; |
421 | } | 452 | } |
422 | sb->s_root->d_op = &hfsplus_dentry_operations; | 453 | d_set_d_op(sb->s_root, &hfsplus_dentry_operations); |
423 | 454 | ||
424 | str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1; | 455 | str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1; |
425 | str.name = HFSP_HIDDENDIR_NAME; | 456 | str.name = HFSP_HIDDENDIR_NAME; |
@@ -449,19 +480,16 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
449 | be32_add_cpu(&vhdr->write_count, 1); | 480 | be32_add_cpu(&vhdr->write_count, 1); |
450 | vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT); | 481 | vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT); |
451 | vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT); | 482 | vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT); |
452 | mark_buffer_dirty(sbi->s_vhbh); | 483 | hfsplus_sync_fs(sb, 1); |
453 | sync_dirty_buffer(sbi->s_vhbh); | ||
454 | 484 | ||
455 | if (!sbi->hidden_dir) { | 485 | if (!sbi->hidden_dir) { |
456 | printk(KERN_DEBUG "hfs: create hidden dir...\n"); | ||
457 | |||
458 | mutex_lock(&sbi->vh_mutex); | 486 | mutex_lock(&sbi->vh_mutex); |
459 | sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR); | 487 | sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR); |
460 | hfsplus_create_cat(sbi->hidden_dir->i_ino, sb->s_root->d_inode, | 488 | hfsplus_create_cat(sbi->hidden_dir->i_ino, sb->s_root->d_inode, |
461 | &str, sbi->hidden_dir); | 489 | &str, sbi->hidden_dir); |
462 | mutex_unlock(&sbi->vh_mutex); | 490 | mutex_unlock(&sbi->vh_mutex); |
463 | 491 | ||
464 | mark_inode_dirty(sbi->hidden_dir); | 492 | hfsplus_mark_inode_dirty(sbi->hidden_dir, HFSPLUS_I_CAT_DIRTY); |
465 | } | 493 | } |
466 | out: | 494 | out: |
467 | unload_nls(sbi->nls); | 495 | unload_nls(sbi->nls); |
@@ -488,11 +516,19 @@ static struct inode *hfsplus_alloc_inode(struct super_block *sb) | |||
488 | return i ? &i->vfs_inode : NULL; | 516 | return i ? &i->vfs_inode : NULL; |
489 | } | 517 | } |
490 | 518 | ||
491 | static void hfsplus_destroy_inode(struct inode *inode) | 519 | static void hfsplus_i_callback(struct rcu_head *head) |
492 | { | 520 | { |
521 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
522 | |||
523 | INIT_LIST_HEAD(&inode->i_dentry); | ||
493 | kmem_cache_free(hfsplus_inode_cachep, HFSPLUS_I(inode)); | 524 | kmem_cache_free(hfsplus_inode_cachep, HFSPLUS_I(inode)); |
494 | } | 525 | } |
495 | 526 | ||
527 | static void hfsplus_destroy_inode(struct inode *inode) | ||
528 | { | ||
529 | call_rcu(&inode->i_rcu, hfsplus_i_callback); | ||
530 | } | ||
531 | |||
496 | #define HFSPLUS_INODE_SIZE sizeof(struct hfsplus_inode_info) | 532 | #define HFSPLUS_INODE_SIZE sizeof(struct hfsplus_inode_info) |
497 | 533 | ||
498 | static struct dentry *hfsplus_mount(struct file_system_type *fs_type, | 534 | static struct dentry *hfsplus_mount(struct file_system_type *fs_type, |
diff --git a/fs/hfsplus/unicode.c b/fs/hfsplus/unicode.c index b66d67de882c..a3f0bfcc881e 100644 --- a/fs/hfsplus/unicode.c +++ b/fs/hfsplus/unicode.c | |||
@@ -17,14 +17,14 @@ | |||
17 | /* Returns folded char, or 0 if ignorable */ | 17 | /* Returns folded char, or 0 if ignorable */ |
18 | static inline u16 case_fold(u16 c) | 18 | static inline u16 case_fold(u16 c) |
19 | { | 19 | { |
20 | u16 tmp; | 20 | u16 tmp; |
21 | 21 | ||
22 | tmp = hfsplus_case_fold_table[c >> 8]; | 22 | tmp = hfsplus_case_fold_table[c >> 8]; |
23 | if (tmp) | 23 | if (tmp) |
24 | tmp = hfsplus_case_fold_table[tmp + (c & 0xff)]; | 24 | tmp = hfsplus_case_fold_table[tmp + (c & 0xff)]; |
25 | else | 25 | else |
26 | tmp = c; | 26 | tmp = c; |
27 | return tmp; | 27 | return tmp; |
28 | } | 28 | } |
29 | 29 | ||
30 | /* Compare unicode strings, return values like normal strcmp */ | 30 | /* Compare unicode strings, return values like normal strcmp */ |
@@ -118,7 +118,9 @@ static u16 *hfsplus_compose_lookup(u16 *p, u16 cc) | |||
118 | return NULL; | 118 | return NULL; |
119 | } | 119 | } |
120 | 120 | ||
121 | int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, char *astr, int *len_p) | 121 | int hfsplus_uni2asc(struct super_block *sb, |
122 | const struct hfsplus_unistr *ustr, | ||
123 | char *astr, int *len_p) | ||
122 | { | 124 | { |
123 | const hfsplus_unichr *ip; | 125 | const hfsplus_unichr *ip; |
124 | struct nls_table *nls = HFSPLUS_SB(sb)->nls; | 126 | struct nls_table *nls = HFSPLUS_SB(sb)->nls; |
@@ -171,7 +173,8 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c | |||
171 | goto same; | 173 | goto same; |
172 | c1 = be16_to_cpu(*ip); | 174 | c1 = be16_to_cpu(*ip); |
173 | if (likely(compose)) | 175 | if (likely(compose)) |
174 | ce1 = hfsplus_compose_lookup(hfsplus_compose_table, c1); | 176 | ce1 = hfsplus_compose_lookup( |
177 | hfsplus_compose_table, c1); | ||
175 | if (ce1) | 178 | if (ce1) |
176 | break; | 179 | break; |
177 | switch (c0) { | 180 | switch (c0) { |
@@ -199,7 +202,8 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c | |||
199 | if (ce2) { | 202 | if (ce2) { |
200 | i = 1; | 203 | i = 1; |
201 | while (i < ustrlen) { | 204 | while (i < ustrlen) { |
202 | ce1 = hfsplus_compose_lookup(ce2, be16_to_cpu(ip[i])); | 205 | ce1 = hfsplus_compose_lookup(ce2, |
206 | be16_to_cpu(ip[i])); | ||
203 | if (!ce1) | 207 | if (!ce1) |
204 | break; | 208 | break; |
205 | i++; | 209 | i++; |
@@ -211,7 +215,7 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c | |||
211 | goto done; | 215 | goto done; |
212 | } | 216 | } |
213 | } | 217 | } |
214 | same: | 218 | same: |
215 | switch (c0) { | 219 | switch (c0) { |
216 | case 0: | 220 | case 0: |
217 | cc = 0x2400; | 221 | cc = 0x2400; |
@@ -222,7 +226,7 @@ int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr, c | |||
222 | default: | 226 | default: |
223 | cc = c0; | 227 | cc = c0; |
224 | } | 228 | } |
225 | done: | 229 | done: |
226 | res = nls->uni2char(cc, op, len); | 230 | res = nls->uni2char(cc, op, len); |
227 | if (res < 0) { | 231 | if (res < 0) { |
228 | if (res == -ENAMETOOLONG) | 232 | if (res == -ENAMETOOLONG) |
@@ -320,7 +324,8 @@ int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, | |||
320 | * Composed unicode characters are decomposed and case-folding is performed | 324 | * Composed unicode characters are decomposed and case-folding is performed |
321 | * if the appropriate bits are (un)set on the superblock. | 325 | * if the appropriate bits are (un)set on the superblock. |
322 | */ | 326 | */ |
323 | int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str) | 327 | int hfsplus_hash_dentry(const struct dentry *dentry, const struct inode *inode, |
328 | struct qstr *str) | ||
324 | { | 329 | { |
325 | struct super_block *sb = dentry->d_sb; | 330 | struct super_block *sb = dentry->d_sb; |
326 | const char *astr; | 331 | const char *astr; |
@@ -363,9 +368,12 @@ int hfsplus_hash_dentry(struct dentry *dentry, struct qstr *str) | |||
363 | * Composed unicode characters are decomposed and case-folding is performed | 368 | * Composed unicode characters are decomposed and case-folding is performed |
364 | * if the appropriate bits are (un)set on the superblock. | 369 | * if the appropriate bits are (un)set on the superblock. |
365 | */ | 370 | */ |
366 | int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr *s2) | 371 | int hfsplus_compare_dentry(const struct dentry *parent, |
372 | const struct inode *pinode, | ||
373 | const struct dentry *dentry, const struct inode *inode, | ||
374 | unsigned int len, const char *str, const struct qstr *name) | ||
367 | { | 375 | { |
368 | struct super_block *sb = dentry->d_sb; | 376 | struct super_block *sb = parent->d_sb; |
369 | int casefold, decompose, size; | 377 | int casefold, decompose, size; |
370 | int dsize1, dsize2, len1, len2; | 378 | int dsize1, dsize2, len1, len2; |
371 | const u16 *dstr1, *dstr2; | 379 | const u16 *dstr1, *dstr2; |
@@ -375,10 +383,10 @@ int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr * | |||
375 | 383 | ||
376 | casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags); | 384 | casefold = test_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags); |
377 | decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags); | 385 | decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags); |
378 | astr1 = s1->name; | 386 | astr1 = str; |
379 | len1 = s1->len; | 387 | len1 = len; |
380 | astr2 = s2->name; | 388 | astr2 = name->name; |
381 | len2 = s2->len; | 389 | len2 = name->len; |
382 | dsize1 = dsize2 = 0; | 390 | dsize1 = dsize2 = 0; |
383 | dstr1 = dstr2 = NULL; | 391 | dstr1 = dstr2 = NULL; |
384 | 392 | ||
@@ -388,7 +396,9 @@ int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr * | |||
388 | astr1 += size; | 396 | astr1 += size; |
389 | len1 -= size; | 397 | len1 -= size; |
390 | 398 | ||
391 | if (!decompose || !(dstr1 = decompose_unichar(c, &dsize1))) { | 399 | if (decompose) |
400 | dstr1 = decompose_unichar(c, &dsize1); | ||
401 | if (!decompose || !dstr1) { | ||
392 | c1 = c; | 402 | c1 = c; |
393 | dstr1 = &c1; | 403 | dstr1 = &c1; |
394 | dsize1 = 1; | 404 | dsize1 = 1; |
@@ -400,7 +410,9 @@ int hfsplus_compare_dentry(struct dentry *dentry, struct qstr *s1, struct qstr * | |||
400 | astr2 += size; | 410 | astr2 += size; |
401 | len2 -= size; | 411 | len2 -= size; |
402 | 412 | ||
403 | if (!decompose || !(dstr2 = decompose_unichar(c, &dsize2))) { | 413 | if (decompose) |
414 | dstr2 = decompose_unichar(c, &dsize2); | ||
415 | if (!decompose || !dstr2) { | ||
404 | c2 = c; | 416 | c2 = c; |
405 | dstr2 = &c2; | 417 | dstr2 = &c2; |
406 | dsize2 = 1; | 418 | dsize2 = 1; |
diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c index 8972c20b3216..196231794f64 100644 --- a/fs/hfsplus/wrapper.c +++ b/fs/hfsplus/wrapper.c | |||
@@ -24,6 +24,40 @@ struct hfsplus_wd { | |||
24 | u16 embed_count; | 24 | u16 embed_count; |
25 | }; | 25 | }; |
26 | 26 | ||
27 | static void hfsplus_end_io_sync(struct bio *bio, int err) | ||
28 | { | ||
29 | if (err) | ||
30 | clear_bit(BIO_UPTODATE, &bio->bi_flags); | ||
31 | complete(bio->bi_private); | ||
32 | } | ||
33 | |||
34 | int hfsplus_submit_bio(struct block_device *bdev, sector_t sector, | ||
35 | void *data, int rw) | ||
36 | { | ||
37 | DECLARE_COMPLETION_ONSTACK(wait); | ||
38 | struct bio *bio; | ||
39 | |||
40 | bio = bio_alloc(GFP_NOIO, 1); | ||
41 | bio->bi_sector = sector; | ||
42 | bio->bi_bdev = bdev; | ||
43 | bio->bi_end_io = hfsplus_end_io_sync; | ||
44 | bio->bi_private = &wait; | ||
45 | |||
46 | /* | ||
47 | * We always submit one sector at a time, so bio_add_page must not fail. | ||
48 | */ | ||
49 | if (bio_add_page(bio, virt_to_page(data), HFSPLUS_SECTOR_SIZE, | ||
50 | offset_in_page(data)) != HFSPLUS_SECTOR_SIZE) | ||
51 | BUG(); | ||
52 | |||
53 | submit_bio(rw, bio); | ||
54 | wait_for_completion(&wait); | ||
55 | |||
56 | if (!bio_flagged(bio, BIO_UPTODATE)) | ||
57 | return -EIO; | ||
58 | return 0; | ||
59 | } | ||
60 | |||
27 | static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd) | 61 | static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd) |
28 | { | 62 | { |
29 | u32 extent; | 63 | u32 extent; |
@@ -40,12 +74,14 @@ static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd) | |||
40 | !(attrib & HFSP_WRAP_ATTRIB_SPARED)) | 74 | !(attrib & HFSP_WRAP_ATTRIB_SPARED)) |
41 | return 0; | 75 | return 0; |
42 | 76 | ||
43 | wd->ablk_size = be32_to_cpu(*(__be32 *)(bufptr + HFSP_WRAPOFF_ABLKSIZE)); | 77 | wd->ablk_size = |
78 | be32_to_cpu(*(__be32 *)(bufptr + HFSP_WRAPOFF_ABLKSIZE)); | ||
44 | if (wd->ablk_size < HFSPLUS_SECTOR_SIZE) | 79 | if (wd->ablk_size < HFSPLUS_SECTOR_SIZE) |
45 | return 0; | 80 | return 0; |
46 | if (wd->ablk_size % HFSPLUS_SECTOR_SIZE) | 81 | if (wd->ablk_size % HFSPLUS_SECTOR_SIZE) |
47 | return 0; | 82 | return 0; |
48 | wd->ablk_start = be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ABLKSTART)); | 83 | wd->ablk_start = |
84 | be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ABLKSTART)); | ||
49 | 85 | ||
50 | extent = get_unaligned_be32(bufptr + HFSP_WRAPOFF_EMBEDEXT); | 86 | extent = get_unaligned_be32(bufptr + HFSP_WRAPOFF_EMBEDEXT); |
51 | wd->embed_start = (extent >> 16) & 0xFFFF; | 87 | wd->embed_start = (extent >> 16) & 0xFFFF; |
@@ -68,7 +104,8 @@ static int hfsplus_get_last_session(struct super_block *sb, | |||
68 | if (HFSPLUS_SB(sb)->session >= 0) { | 104 | if (HFSPLUS_SB(sb)->session >= 0) { |
69 | te.cdte_track = HFSPLUS_SB(sb)->session; | 105 | te.cdte_track = HFSPLUS_SB(sb)->session; |
70 | te.cdte_format = CDROM_LBA; | 106 | te.cdte_format = CDROM_LBA; |
71 | res = ioctl_by_bdev(sb->s_bdev, CDROMREADTOCENTRY, (unsigned long)&te); | 107 | res = ioctl_by_bdev(sb->s_bdev, |
108 | CDROMREADTOCENTRY, (unsigned long)&te); | ||
72 | if (!res && (te.cdte_ctrl & CDROM_DATA_TRACK) == 4) { | 109 | if (!res && (te.cdte_ctrl & CDROM_DATA_TRACK) == 4) { |
73 | *start = (sector_t)te.cdte_addr.lba << 2; | 110 | *start = (sector_t)te.cdte_addr.lba << 2; |
74 | return 0; | 111 | return 0; |
@@ -77,7 +114,8 @@ static int hfsplus_get_last_session(struct super_block *sb, | |||
77 | return -EINVAL; | 114 | return -EINVAL; |
78 | } | 115 | } |
79 | ms_info.addr_format = CDROM_LBA; | 116 | ms_info.addr_format = CDROM_LBA; |
80 | res = ioctl_by_bdev(sb->s_bdev, CDROMMULTISESSION, (unsigned long)&ms_info); | 117 | res = ioctl_by_bdev(sb->s_bdev, CDROMMULTISESSION, |
118 | (unsigned long)&ms_info); | ||
81 | if (!res && ms_info.xa_flag) | 119 | if (!res && ms_info.xa_flag) |
82 | *start = (sector_t)ms_info.addr.lba << 2; | 120 | *start = (sector_t)ms_info.addr.lba << 2; |
83 | return 0; | 121 | return 0; |
@@ -88,100 +126,112 @@ static int hfsplus_get_last_session(struct super_block *sb, | |||
88 | int hfsplus_read_wrapper(struct super_block *sb) | 126 | int hfsplus_read_wrapper(struct super_block *sb) |
89 | { | 127 | { |
90 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); | 128 | struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); |
91 | struct buffer_head *bh; | ||
92 | struct hfsplus_vh *vhdr; | ||
93 | struct hfsplus_wd wd; | 129 | struct hfsplus_wd wd; |
94 | sector_t part_start, part_size; | 130 | sector_t part_start, part_size; |
95 | u32 blocksize; | 131 | u32 blocksize; |
132 | int error = 0; | ||
96 | 133 | ||
134 | error = -EINVAL; | ||
97 | blocksize = sb_min_blocksize(sb, HFSPLUS_SECTOR_SIZE); | 135 | blocksize = sb_min_blocksize(sb, HFSPLUS_SECTOR_SIZE); |
98 | if (!blocksize) | 136 | if (!blocksize) |
99 | return -EINVAL; | 137 | goto out; |
100 | 138 | ||
101 | if (hfsplus_get_last_session(sb, &part_start, &part_size)) | 139 | if (hfsplus_get_last_session(sb, &part_start, &part_size)) |
102 | return -EINVAL; | 140 | goto out; |
103 | if ((u64)part_start + part_size > 0x100000000ULL) { | 141 | if ((u64)part_start + part_size > 0x100000000ULL) { |
104 | pr_err("hfs: volumes larger than 2TB are not supported yet\n"); | 142 | pr_err("hfs: volumes larger than 2TB are not supported yet\n"); |
105 | return -EINVAL; | 143 | goto out; |
106 | } | 144 | } |
107 | while (1) { | ||
108 | bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr); | ||
109 | if (!bh) | ||
110 | return -EIO; | ||
111 | |||
112 | if (vhdr->signature == cpu_to_be16(HFSP_WRAP_MAGIC)) { | ||
113 | if (!hfsplus_read_mdb(vhdr, &wd)) | ||
114 | goto error; | ||
115 | wd.ablk_size >>= HFSPLUS_SECTOR_SHIFT; | ||
116 | part_start += wd.ablk_start + wd.embed_start * wd.ablk_size; | ||
117 | part_size = wd.embed_count * wd.ablk_size; | ||
118 | brelse(bh); | ||
119 | bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr); | ||
120 | if (!bh) | ||
121 | return -EIO; | ||
122 | } | ||
123 | if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIG)) | ||
124 | break; | ||
125 | if (vhdr->signature == cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) { | ||
126 | set_bit(HFSPLUS_SB_HFSX, &sbi->flags); | ||
127 | break; | ||
128 | } | ||
129 | brelse(bh); | ||
130 | 145 | ||
131 | /* check for a partition block | 146 | error = -ENOMEM; |
147 | sbi->s_vhdr = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL); | ||
148 | if (!sbi->s_vhdr) | ||
149 | goto out; | ||
150 | sbi->s_backup_vhdr = kmalloc(HFSPLUS_SECTOR_SIZE, GFP_KERNEL); | ||
151 | if (!sbi->s_backup_vhdr) | ||
152 | goto out_free_vhdr; | ||
153 | |||
154 | reread: | ||
155 | error = hfsplus_submit_bio(sb->s_bdev, | ||
156 | part_start + HFSPLUS_VOLHEAD_SECTOR, | ||
157 | sbi->s_vhdr, READ); | ||
158 | if (error) | ||
159 | goto out_free_backup_vhdr; | ||
160 | |||
161 | error = -EINVAL; | ||
162 | switch (sbi->s_vhdr->signature) { | ||
163 | case cpu_to_be16(HFSPLUS_VOLHEAD_SIGX): | ||
164 | set_bit(HFSPLUS_SB_HFSX, &sbi->flags); | ||
165 | /*FALLTHRU*/ | ||
166 | case cpu_to_be16(HFSPLUS_VOLHEAD_SIG): | ||
167 | break; | ||
168 | case cpu_to_be16(HFSP_WRAP_MAGIC): | ||
169 | if (!hfsplus_read_mdb(sbi->s_vhdr, &wd)) | ||
170 | goto out; | ||
171 | wd.ablk_size >>= HFSPLUS_SECTOR_SHIFT; | ||
172 | part_start += wd.ablk_start + wd.embed_start * wd.ablk_size; | ||
173 | part_size = wd.embed_count * wd.ablk_size; | ||
174 | goto reread; | ||
175 | default: | ||
176 | /* | ||
177 | * Check for a partition block. | ||
178 | * | ||
132 | * (should do this only for cdrom/loop though) | 179 | * (should do this only for cdrom/loop though) |
133 | */ | 180 | */ |
134 | if (hfs_part_find(sb, &part_start, &part_size)) | 181 | if (hfs_part_find(sb, &part_start, &part_size)) |
135 | return -EINVAL; | 182 | goto out; |
183 | goto reread; | ||
184 | } | ||
185 | |||
186 | error = hfsplus_submit_bio(sb->s_bdev, | ||
187 | part_start + part_size - 2, | ||
188 | sbi->s_backup_vhdr, READ); | ||
189 | if (error) | ||
190 | goto out_free_backup_vhdr; | ||
191 | |||
192 | error = -EINVAL; | ||
193 | if (sbi->s_backup_vhdr->signature != sbi->s_vhdr->signature) { | ||
194 | printk(KERN_WARNING | ||
195 | "hfs: invalid secondary volume header\n"); | ||
196 | goto out_free_backup_vhdr; | ||
136 | } | 197 | } |
137 | 198 | ||
138 | blocksize = be32_to_cpu(vhdr->blocksize); | 199 | blocksize = be32_to_cpu(sbi->s_vhdr->blocksize); |
139 | brelse(bh); | ||
140 | 200 | ||
141 | /* block size must be at least as large as a sector | 201 | /* |
142 | * and a multiple of 2 | 202 | * Block size must be at least as large as a sector and a multiple of 2. |
143 | */ | 203 | */ |
144 | if (blocksize < HFSPLUS_SECTOR_SIZE || | 204 | if (blocksize < HFSPLUS_SECTOR_SIZE || ((blocksize - 1) & blocksize)) |
145 | ((blocksize - 1) & blocksize)) | 205 | goto out_free_backup_vhdr; |
146 | return -EINVAL; | ||
147 | sbi->alloc_blksz = blocksize; | 206 | sbi->alloc_blksz = blocksize; |
148 | sbi->alloc_blksz_shift = 0; | 207 | sbi->alloc_blksz_shift = 0; |
149 | while ((blocksize >>= 1) != 0) | 208 | while ((blocksize >>= 1) != 0) |
150 | sbi->alloc_blksz_shift++; | 209 | sbi->alloc_blksz_shift++; |
151 | blocksize = min(sbi->alloc_blksz, (u32)PAGE_SIZE); | 210 | blocksize = min(sbi->alloc_blksz, (u32)PAGE_SIZE); |
152 | 211 | ||
153 | /* align block size to block offset */ | 212 | /* |
213 | * Align block size to block offset. | ||
214 | */ | ||
154 | while (part_start & ((blocksize >> HFSPLUS_SECTOR_SHIFT) - 1)) | 215 | while (part_start & ((blocksize >> HFSPLUS_SECTOR_SHIFT) - 1)) |
155 | blocksize >>= 1; | 216 | blocksize >>= 1; |
156 | 217 | ||
157 | if (sb_set_blocksize(sb, blocksize) != blocksize) { | 218 | if (sb_set_blocksize(sb, blocksize) != blocksize) { |
158 | printk(KERN_ERR "hfs: unable to set blocksize to %u!\n", blocksize); | 219 | printk(KERN_ERR "hfs: unable to set blocksize to %u!\n", |
159 | return -EINVAL; | 220 | blocksize); |
221 | goto out_free_backup_vhdr; | ||
160 | } | 222 | } |
161 | 223 | ||
162 | sbi->blockoffset = | 224 | sbi->blockoffset = |
163 | part_start >> (sb->s_blocksize_bits - HFSPLUS_SECTOR_SHIFT); | 225 | part_start >> (sb->s_blocksize_bits - HFSPLUS_SECTOR_SHIFT); |
226 | sbi->part_start = part_start; | ||
164 | sbi->sect_count = part_size; | 227 | sbi->sect_count = part_size; |
165 | sbi->fs_shift = sbi->alloc_blksz_shift - sb->s_blocksize_bits; | 228 | sbi->fs_shift = sbi->alloc_blksz_shift - sb->s_blocksize_bits; |
166 | |||
167 | bh = sb_bread512(sb, part_start + HFSPLUS_VOLHEAD_SECTOR, vhdr); | ||
168 | if (!bh) | ||
169 | return -EIO; | ||
170 | |||
171 | /* should still be the same... */ | ||
172 | if (test_bit(HFSPLUS_SB_HFSX, &sbi->flags)) { | ||
173 | if (vhdr->signature != cpu_to_be16(HFSPLUS_VOLHEAD_SIGX)) | ||
174 | goto error; | ||
175 | } else { | ||
176 | if (vhdr->signature != cpu_to_be16(HFSPLUS_VOLHEAD_SIG)) | ||
177 | goto error; | ||
178 | } | ||
179 | |||
180 | sbi->s_vhbh = bh; | ||
181 | sbi->s_vhdr = vhdr; | ||
182 | |||
183 | return 0; | 229 | return 0; |
184 | error: | 230 | |
185 | brelse(bh); | 231 | out_free_backup_vhdr: |
186 | return -EINVAL; | 232 | kfree(sbi->s_backup_vhdr); |
233 | out_free_vhdr: | ||
234 | kfree(sbi->s_vhdr); | ||
235 | out: | ||
236 | return error; | ||
187 | } | 237 | } |
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 2c0f148a49e6..d3244d949a4e 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c | |||
@@ -32,7 +32,7 @@ static inline struct hostfs_inode_info *HOSTFS_I(struct inode *inode) | |||
32 | 32 | ||
33 | #define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode) | 33 | #define FILE_HOSTFS_I(file) HOSTFS_I((file)->f_path.dentry->d_inode) |
34 | 34 | ||
35 | static int hostfs_d_delete(struct dentry *dentry) | 35 | static int hostfs_d_delete(const struct dentry *dentry) |
36 | { | 36 | { |
37 | return 1; | 37 | return 1; |
38 | } | 38 | } |
@@ -92,12 +92,10 @@ __uml_setup("hostfs=", hostfs_args, | |||
92 | 92 | ||
93 | static char *__dentry_name(struct dentry *dentry, char *name) | 93 | static char *__dentry_name(struct dentry *dentry, char *name) |
94 | { | 94 | { |
95 | char *p = __dentry_path(dentry, name, PATH_MAX); | 95 | char *p = dentry_path_raw(dentry, name, PATH_MAX); |
96 | char *root; | 96 | char *root; |
97 | size_t len; | 97 | size_t len; |
98 | 98 | ||
99 | spin_unlock(&dcache_lock); | ||
100 | |||
101 | root = dentry->d_sb->s_fs_info; | 99 | root = dentry->d_sb->s_fs_info; |
102 | len = strlen(root); | 100 | len = strlen(root); |
103 | if (IS_ERR(p)) { | 101 | if (IS_ERR(p)) { |
@@ -123,25 +121,23 @@ static char *dentry_name(struct dentry *dentry) | |||
123 | if (!name) | 121 | if (!name) |
124 | return NULL; | 122 | return NULL; |
125 | 123 | ||
126 | spin_lock(&dcache_lock); | ||
127 | return __dentry_name(dentry, name); /* will unlock */ | 124 | return __dentry_name(dentry, name); /* will unlock */ |
128 | } | 125 | } |
129 | 126 | ||
130 | static char *inode_name(struct inode *ino) | 127 | static char *inode_name(struct inode *ino) |
131 | { | 128 | { |
132 | struct dentry *dentry; | 129 | struct dentry *dentry; |
133 | char *name = __getname(); | 130 | char *name; |
134 | if (!name) | ||
135 | return NULL; | ||
136 | 131 | ||
137 | spin_lock(&dcache_lock); | 132 | dentry = d_find_alias(ino); |
138 | if (list_empty(&ino->i_dentry)) { | 133 | if (!dentry) |
139 | spin_unlock(&dcache_lock); | ||
140 | __putname(name); | ||
141 | return NULL; | 134 | return NULL; |
142 | } | 135 | |
143 | dentry = list_first_entry(&ino->i_dentry, struct dentry, d_alias); | 136 | name = dentry_name(dentry); |
144 | return __dentry_name(dentry, name); /* will unlock */ | 137 | |
138 | dput(dentry); | ||
139 | |||
140 | return name; | ||
145 | } | 141 | } |
146 | 142 | ||
147 | static char *follow_link(char *link) | 143 | static char *follow_link(char *link) |
@@ -251,11 +247,18 @@ static void hostfs_evict_inode(struct inode *inode) | |||
251 | } | 247 | } |
252 | } | 248 | } |
253 | 249 | ||
254 | static void hostfs_destroy_inode(struct inode *inode) | 250 | static void hostfs_i_callback(struct rcu_head *head) |
255 | { | 251 | { |
252 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
253 | INIT_LIST_HEAD(&inode->i_dentry); | ||
256 | kfree(HOSTFS_I(inode)); | 254 | kfree(HOSTFS_I(inode)); |
257 | } | 255 | } |
258 | 256 | ||
257 | static void hostfs_destroy_inode(struct inode *inode) | ||
258 | { | ||
259 | call_rcu(&inode->i_rcu, hostfs_i_callback); | ||
260 | } | ||
261 | |||
259 | static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs) | 262 | static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs) |
260 | { | 263 | { |
261 | const char *root_path = vfs->mnt_sb->s_fs_info; | 264 | const char *root_path = vfs->mnt_sb->s_fs_info; |
@@ -609,7 +612,7 @@ struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry, | |||
609 | goto out_put; | 612 | goto out_put; |
610 | 613 | ||
611 | d_add(dentry, inode); | 614 | d_add(dentry, inode); |
612 | dentry->d_op = &hostfs_dentry_ops; | 615 | d_set_d_op(dentry, &hostfs_dentry_ops); |
613 | return NULL; | 616 | return NULL; |
614 | 617 | ||
615 | out_put: | 618 | out_put: |
@@ -746,11 +749,14 @@ int hostfs_rename(struct inode *from_ino, struct dentry *from, | |||
746 | return err; | 749 | return err; |
747 | } | 750 | } |
748 | 751 | ||
749 | int hostfs_permission(struct inode *ino, int desired) | 752 | int hostfs_permission(struct inode *ino, int desired, unsigned int flags) |
750 | { | 753 | { |
751 | char *name; | 754 | char *name; |
752 | int r = 0, w = 0, x = 0, err; | 755 | int r = 0, w = 0, x = 0, err; |
753 | 756 | ||
757 | if (flags & IPERM_FLAG_RCU) | ||
758 | return -ECHILD; | ||
759 | |||
754 | if (desired & MAY_READ) r = 1; | 760 | if (desired & MAY_READ) r = 1; |
755 | if (desired & MAY_WRITE) w = 1; | 761 | if (desired & MAY_WRITE) w = 1; |
756 | if (desired & MAY_EXEC) x = 1; | 762 | if (desired & MAY_EXEC) x = 1; |
@@ -765,7 +771,7 @@ int hostfs_permission(struct inode *ino, int desired) | |||
765 | err = access_file(name, r, w, x); | 771 | err = access_file(name, r, w, x); |
766 | __putname(name); | 772 | __putname(name); |
767 | if (!err) | 773 | if (!err) |
768 | err = generic_permission(ino, desired, NULL); | 774 | err = generic_permission(ino, desired, flags, NULL); |
769 | return err; | 775 | return err; |
770 | } | 776 | } |
771 | 777 | ||
diff --git a/fs/hpfs/dentry.c b/fs/hpfs/dentry.c index 67d9d36b3d5f..32c13a94e1e9 100644 --- a/fs/hpfs/dentry.c +++ b/fs/hpfs/dentry.c | |||
@@ -12,7 +12,8 @@ | |||
12 | * Note: the dentry argument is the parent dentry. | 12 | * Note: the dentry argument is the parent dentry. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | static int hpfs_hash_dentry(struct dentry *dentry, struct qstr *qstr) | 15 | static int hpfs_hash_dentry(const struct dentry *dentry, const struct inode *inode, |
16 | struct qstr *qstr) | ||
16 | { | 17 | { |
17 | unsigned long hash; | 18 | unsigned long hash; |
18 | int i; | 19 | int i; |
@@ -34,19 +35,25 @@ static int hpfs_hash_dentry(struct dentry *dentry, struct qstr *qstr) | |||
34 | return 0; | 35 | return 0; |
35 | } | 36 | } |
36 | 37 | ||
37 | static int hpfs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) | 38 | static int hpfs_compare_dentry(const struct dentry *parent, |
39 | const struct inode *pinode, | ||
40 | const struct dentry *dentry, const struct inode *inode, | ||
41 | unsigned int len, const char *str, const struct qstr *name) | ||
38 | { | 42 | { |
39 | unsigned al=a->len; | 43 | unsigned al = len; |
40 | unsigned bl=b->len; | 44 | unsigned bl = name->len; |
41 | hpfs_adjust_length(a->name, &al); | 45 | |
46 | hpfs_adjust_length(str, &al); | ||
42 | /*hpfs_adjust_length(b->name, &bl);*/ | 47 | /*hpfs_adjust_length(b->name, &bl);*/ |
43 | /* 'a' is the qstr of an already existing dentry, so the name | 48 | |
44 | * must be valid. 'b' must be validated first. | 49 | /* |
50 | * 'str' is the nane of an already existing dentry, so the name | ||
51 | * must be valid. 'name' must be validated first. | ||
45 | */ | 52 | */ |
46 | 53 | ||
47 | if (hpfs_chk_name(b->name, &bl)) | 54 | if (hpfs_chk_name(name->name, &bl)) |
48 | return 1; | 55 | return 1; |
49 | if (hpfs_compare_names(dentry->d_sb, a->name, al, b->name, bl, 0)) | 56 | if (hpfs_compare_names(parent->d_sb, str, al, name->name, bl, 0)) |
50 | return 1; | 57 | return 1; |
51 | return 0; | 58 | return 0; |
52 | } | 59 | } |
@@ -58,5 +65,5 @@ static const struct dentry_operations hpfs_dentry_operations = { | |||
58 | 65 | ||
59 | void hpfs_set_dentry_operations(struct dentry *dentry) | 66 | void hpfs_set_dentry_operations(struct dentry *dentry) |
60 | { | 67 | { |
61 | dentry->d_op = &hpfs_dentry_operations; | 68 | d_set_d_op(dentry, &hpfs_dentry_operations); |
62 | } | 69 | } |
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index 11c2b4080f65..f4ad9e31ddc4 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c | |||
@@ -419,7 +419,7 @@ again: | |||
419 | unlock_kernel(); | 419 | unlock_kernel(); |
420 | return -ENOSPC; | 420 | return -ENOSPC; |
421 | } | 421 | } |
422 | if (generic_permission(inode, MAY_WRITE, NULL) || | 422 | if (generic_permission(inode, MAY_WRITE, 0, NULL) || |
423 | !S_ISREG(inode->i_mode) || | 423 | !S_ISREG(inode->i_mode) || |
424 | get_write_access(inode)) { | 424 | get_write_access(inode)) { |
425 | d_rehash(dentry); | 425 | d_rehash(dentry); |
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 6c5f01597c3a..49935ba78db8 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c | |||
@@ -177,11 +177,18 @@ static struct inode *hpfs_alloc_inode(struct super_block *sb) | |||
177 | return &ei->vfs_inode; | 177 | return &ei->vfs_inode; |
178 | } | 178 | } |
179 | 179 | ||
180 | static void hpfs_destroy_inode(struct inode *inode) | 180 | static void hpfs_i_callback(struct rcu_head *head) |
181 | { | 181 | { |
182 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
183 | INIT_LIST_HEAD(&inode->i_dentry); | ||
182 | kmem_cache_free(hpfs_inode_cachep, hpfs_i(inode)); | 184 | kmem_cache_free(hpfs_inode_cachep, hpfs_i(inode)); |
183 | } | 185 | } |
184 | 186 | ||
187 | static void hpfs_destroy_inode(struct inode *inode) | ||
188 | { | ||
189 | call_rcu(&inode->i_rcu, hpfs_i_callback); | ||
190 | } | ||
191 | |||
185 | static void init_once(void *foo) | 192 | static void init_once(void *foo) |
186 | { | 193 | { |
187 | struct hpfs_inode_info *ei = (struct hpfs_inode_info *) foo; | 194 | struct hpfs_inode_info *ei = (struct hpfs_inode_info *) foo; |
diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c index f702b5f713fc..87ed48e0343d 100644 --- a/fs/hppfs/hppfs.c +++ b/fs/hppfs/hppfs.c | |||
@@ -632,11 +632,18 @@ void hppfs_evict_inode(struct inode *ino) | |||
632 | mntput(ino->i_sb->s_fs_info); | 632 | mntput(ino->i_sb->s_fs_info); |
633 | } | 633 | } |
634 | 634 | ||
635 | static void hppfs_destroy_inode(struct inode *inode) | 635 | static void hppfs_i_callback(struct rcu_head *head) |
636 | { | 636 | { |
637 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
638 | INIT_LIST_HEAD(&inode->i_dentry); | ||
637 | kfree(HPPFS_I(inode)); | 639 | kfree(HPPFS_I(inode)); |
638 | } | 640 | } |
639 | 641 | ||
642 | static void hppfs_destroy_inode(struct inode *inode) | ||
643 | { | ||
644 | call_rcu(&inode->i_rcu, hppfs_i_callback); | ||
645 | } | ||
646 | |||
640 | static const struct super_operations hppfs_sbops = { | 647 | static const struct super_operations hppfs_sbops = { |
641 | .alloc_inode = hppfs_alloc_inode, | 648 | .alloc_inode = hppfs_alloc_inode, |
642 | .destroy_inode = hppfs_destroy_inode, | 649 | .destroy_inode = hppfs_destroy_inode, |
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index a5fe68189eed..9885082b470f 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
@@ -663,11 +663,18 @@ static struct inode *hugetlbfs_alloc_inode(struct super_block *sb) | |||
663 | return &p->vfs_inode; | 663 | return &p->vfs_inode; |
664 | } | 664 | } |
665 | 665 | ||
666 | static void hugetlbfs_i_callback(struct rcu_head *head) | ||
667 | { | ||
668 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
669 | INIT_LIST_HEAD(&inode->i_dentry); | ||
670 | kmem_cache_free(hugetlbfs_inode_cachep, HUGETLBFS_I(inode)); | ||
671 | } | ||
672 | |||
666 | static void hugetlbfs_destroy_inode(struct inode *inode) | 673 | static void hugetlbfs_destroy_inode(struct inode *inode) |
667 | { | 674 | { |
668 | hugetlbfs_inc_free_inodes(HUGETLBFS_SB(inode->i_sb)); | 675 | hugetlbfs_inc_free_inodes(HUGETLBFS_SB(inode->i_sb)); |
669 | mpol_free_shared_policy(&HUGETLBFS_I(inode)->policy); | 676 | mpol_free_shared_policy(&HUGETLBFS_I(inode)->policy); |
670 | kmem_cache_free(hugetlbfs_inode_cachep, HUGETLBFS_I(inode)); | 677 | call_rcu(&inode->i_rcu, hugetlbfs_i_callback); |
671 | } | 678 | } |
672 | 679 | ||
673 | static const struct address_space_operations hugetlbfs_aops = { | 680 | static const struct address_space_operations hugetlbfs_aops = { |
diff --git a/fs/inode.c b/fs/inode.c index ae2727ab0c3a..da85e56378f3 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
@@ -102,26 +102,29 @@ static DECLARE_RWSEM(iprune_sem); | |||
102 | */ | 102 | */ |
103 | struct inodes_stat_t inodes_stat; | 103 | struct inodes_stat_t inodes_stat; |
104 | 104 | ||
105 | static struct percpu_counter nr_inodes __cacheline_aligned_in_smp; | 105 | static DEFINE_PER_CPU(unsigned int, nr_inodes); |
106 | static struct percpu_counter nr_inodes_unused __cacheline_aligned_in_smp; | ||
107 | 106 | ||
108 | static struct kmem_cache *inode_cachep __read_mostly; | 107 | static struct kmem_cache *inode_cachep __read_mostly; |
109 | 108 | ||
110 | static inline int get_nr_inodes(void) | 109 | static int get_nr_inodes(void) |
111 | { | 110 | { |
112 | return percpu_counter_sum_positive(&nr_inodes); | 111 | int i; |
112 | int sum = 0; | ||
113 | for_each_possible_cpu(i) | ||
114 | sum += per_cpu(nr_inodes, i); | ||
115 | return sum < 0 ? 0 : sum; | ||
113 | } | 116 | } |
114 | 117 | ||
115 | static inline int get_nr_inodes_unused(void) | 118 | static inline int get_nr_inodes_unused(void) |
116 | { | 119 | { |
117 | return percpu_counter_sum_positive(&nr_inodes_unused); | 120 | return inodes_stat.nr_unused; |
118 | } | 121 | } |
119 | 122 | ||
120 | int get_nr_dirty_inodes(void) | 123 | int get_nr_dirty_inodes(void) |
121 | { | 124 | { |
125 | /* not actually dirty inodes, but a wild approximation */ | ||
122 | int nr_dirty = get_nr_inodes() - get_nr_inodes_unused(); | 126 | int nr_dirty = get_nr_inodes() - get_nr_inodes_unused(); |
123 | return nr_dirty > 0 ? nr_dirty : 0; | 127 | return nr_dirty > 0 ? nr_dirty : 0; |
124 | |||
125 | } | 128 | } |
126 | 129 | ||
127 | /* | 130 | /* |
@@ -132,7 +135,6 @@ int proc_nr_inodes(ctl_table *table, int write, | |||
132 | void __user *buffer, size_t *lenp, loff_t *ppos) | 135 | void __user *buffer, size_t *lenp, loff_t *ppos) |
133 | { | 136 | { |
134 | inodes_stat.nr_inodes = get_nr_inodes(); | 137 | inodes_stat.nr_inodes = get_nr_inodes(); |
135 | inodes_stat.nr_unused = get_nr_inodes_unused(); | ||
136 | return proc_dointvec(table, write, buffer, lenp, ppos); | 138 | return proc_dointvec(table, write, buffer, lenp, ppos); |
137 | } | 139 | } |
138 | #endif | 140 | #endif |
@@ -224,7 +226,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode) | |||
224 | inode->i_fsnotify_mask = 0; | 226 | inode->i_fsnotify_mask = 0; |
225 | #endif | 227 | #endif |
226 | 228 | ||
227 | percpu_counter_inc(&nr_inodes); | 229 | this_cpu_inc(nr_inodes); |
228 | 230 | ||
229 | return 0; | 231 | return 0; |
230 | out: | 232 | out: |
@@ -255,6 +257,12 @@ static struct inode *alloc_inode(struct super_block *sb) | |||
255 | return inode; | 257 | return inode; |
256 | } | 258 | } |
257 | 259 | ||
260 | void free_inode_nonrcu(struct inode *inode) | ||
261 | { | ||
262 | kmem_cache_free(inode_cachep, inode); | ||
263 | } | ||
264 | EXPORT_SYMBOL(free_inode_nonrcu); | ||
265 | |||
258 | void __destroy_inode(struct inode *inode) | 266 | void __destroy_inode(struct inode *inode) |
259 | { | 267 | { |
260 | BUG_ON(inode_has_buffers(inode)); | 268 | BUG_ON(inode_has_buffers(inode)); |
@@ -266,10 +274,17 @@ void __destroy_inode(struct inode *inode) | |||
266 | if (inode->i_default_acl && inode->i_default_acl != ACL_NOT_CACHED) | 274 | if (inode->i_default_acl && inode->i_default_acl != ACL_NOT_CACHED) |
267 | posix_acl_release(inode->i_default_acl); | 275 | posix_acl_release(inode->i_default_acl); |
268 | #endif | 276 | #endif |
269 | percpu_counter_dec(&nr_inodes); | 277 | this_cpu_dec(nr_inodes); |
270 | } | 278 | } |
271 | EXPORT_SYMBOL(__destroy_inode); | 279 | EXPORT_SYMBOL(__destroy_inode); |
272 | 280 | ||
281 | static void i_callback(struct rcu_head *head) | ||
282 | { | ||
283 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
284 | INIT_LIST_HEAD(&inode->i_dentry); | ||
285 | kmem_cache_free(inode_cachep, inode); | ||
286 | } | ||
287 | |||
273 | static void destroy_inode(struct inode *inode) | 288 | static void destroy_inode(struct inode *inode) |
274 | { | 289 | { |
275 | BUG_ON(!list_empty(&inode->i_lru)); | 290 | BUG_ON(!list_empty(&inode->i_lru)); |
@@ -277,7 +292,7 @@ static void destroy_inode(struct inode *inode) | |||
277 | if (inode->i_sb->s_op->destroy_inode) | 292 | if (inode->i_sb->s_op->destroy_inode) |
278 | inode->i_sb->s_op->destroy_inode(inode); | 293 | inode->i_sb->s_op->destroy_inode(inode); |
279 | else | 294 | else |
280 | kmem_cache_free(inode_cachep, (inode)); | 295 | call_rcu(&inode->i_rcu, i_callback); |
281 | } | 296 | } |
282 | 297 | ||
283 | /* | 298 | /* |
@@ -335,7 +350,7 @@ static void inode_lru_list_add(struct inode *inode) | |||
335 | { | 350 | { |
336 | if (list_empty(&inode->i_lru)) { | 351 | if (list_empty(&inode->i_lru)) { |
337 | list_add(&inode->i_lru, &inode_lru); | 352 | list_add(&inode->i_lru, &inode_lru); |
338 | percpu_counter_inc(&nr_inodes_unused); | 353 | inodes_stat.nr_unused++; |
339 | } | 354 | } |
340 | } | 355 | } |
341 | 356 | ||
@@ -343,7 +358,7 @@ static void inode_lru_list_del(struct inode *inode) | |||
343 | { | 358 | { |
344 | if (!list_empty(&inode->i_lru)) { | 359 | if (!list_empty(&inode->i_lru)) { |
345 | list_del_init(&inode->i_lru); | 360 | list_del_init(&inode->i_lru); |
346 | percpu_counter_dec(&nr_inodes_unused); | 361 | inodes_stat.nr_unused--; |
347 | } | 362 | } |
348 | } | 363 | } |
349 | 364 | ||
@@ -430,6 +445,7 @@ void end_writeback(struct inode *inode) | |||
430 | BUG_ON(!(inode->i_state & I_FREEING)); | 445 | BUG_ON(!(inode->i_state & I_FREEING)); |
431 | BUG_ON(inode->i_state & I_CLEAR); | 446 | BUG_ON(inode->i_state & I_CLEAR); |
432 | inode_sync_wait(inode); | 447 | inode_sync_wait(inode); |
448 | /* don't need i_lock here, no concurrent mods to i_state */ | ||
433 | inode->i_state = I_FREEING | I_CLEAR; | 449 | inode->i_state = I_FREEING | I_CLEAR; |
434 | } | 450 | } |
435 | EXPORT_SYMBOL(end_writeback); | 451 | EXPORT_SYMBOL(end_writeback); |
@@ -513,7 +529,7 @@ void evict_inodes(struct super_block *sb) | |||
513 | list_move(&inode->i_lru, &dispose); | 529 | list_move(&inode->i_lru, &dispose); |
514 | list_del_init(&inode->i_wb_list); | 530 | list_del_init(&inode->i_wb_list); |
515 | if (!(inode->i_state & (I_DIRTY | I_SYNC))) | 531 | if (!(inode->i_state & (I_DIRTY | I_SYNC))) |
516 | percpu_counter_dec(&nr_inodes_unused); | 532 | inodes_stat.nr_unused--; |
517 | } | 533 | } |
518 | spin_unlock(&inode_lock); | 534 | spin_unlock(&inode_lock); |
519 | 535 | ||
@@ -554,7 +570,7 @@ int invalidate_inodes(struct super_block *sb) | |||
554 | list_move(&inode->i_lru, &dispose); | 570 | list_move(&inode->i_lru, &dispose); |
555 | list_del_init(&inode->i_wb_list); | 571 | list_del_init(&inode->i_wb_list); |
556 | if (!(inode->i_state & (I_DIRTY | I_SYNC))) | 572 | if (!(inode->i_state & (I_DIRTY | I_SYNC))) |
557 | percpu_counter_dec(&nr_inodes_unused); | 573 | inodes_stat.nr_unused--; |
558 | } | 574 | } |
559 | spin_unlock(&inode_lock); | 575 | spin_unlock(&inode_lock); |
560 | 576 | ||
@@ -616,7 +632,7 @@ static void prune_icache(int nr_to_scan) | |||
616 | if (atomic_read(&inode->i_count) || | 632 | if (atomic_read(&inode->i_count) || |
617 | (inode->i_state & ~I_REFERENCED)) { | 633 | (inode->i_state & ~I_REFERENCED)) { |
618 | list_del_init(&inode->i_lru); | 634 | list_del_init(&inode->i_lru); |
619 | percpu_counter_dec(&nr_inodes_unused); | 635 | inodes_stat.nr_unused--; |
620 | continue; | 636 | continue; |
621 | } | 637 | } |
622 | 638 | ||
@@ -650,7 +666,7 @@ static void prune_icache(int nr_to_scan) | |||
650 | */ | 666 | */ |
651 | list_move(&inode->i_lru, &freeable); | 667 | list_move(&inode->i_lru, &freeable); |
652 | list_del_init(&inode->i_wb_list); | 668 | list_del_init(&inode->i_wb_list); |
653 | percpu_counter_dec(&nr_inodes_unused); | 669 | inodes_stat.nr_unused--; |
654 | } | 670 | } |
655 | if (current_is_kswapd()) | 671 | if (current_is_kswapd()) |
656 | __count_vm_events(KSWAPD_INODESTEAL, reap); | 672 | __count_vm_events(KSWAPD_INODESTEAL, reap); |
@@ -1648,8 +1664,6 @@ void __init inode_init(void) | |||
1648 | SLAB_MEM_SPREAD), | 1664 | SLAB_MEM_SPREAD), |
1649 | init_once); | 1665 | init_once); |
1650 | register_shrinker(&icache_shrinker); | 1666 | register_shrinker(&icache_shrinker); |
1651 | percpu_counter_init(&nr_inodes, 0); | ||
1652 | percpu_counter_init(&nr_inodes_unused, 0); | ||
1653 | 1667 | ||
1654 | /* Hash may have been set up in inode_init_early */ | 1668 | /* Hash may have been set up in inode_init_early */ |
1655 | if (!hashdist) | 1669 | if (!hashdist) |
diff --git a/fs/internal.h b/fs/internal.h index e43b9a4dbf4e..9687c2ee2735 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
@@ -63,6 +63,7 @@ extern int copy_mount_string(const void __user *, char **); | |||
63 | 63 | ||
64 | extern void free_vfsmnt(struct vfsmount *); | 64 | extern void free_vfsmnt(struct vfsmount *); |
65 | extern struct vfsmount *alloc_vfsmnt(const char *); | 65 | extern struct vfsmount *alloc_vfsmnt(const char *); |
66 | extern unsigned int mnt_get_count(struct vfsmount *mnt); | ||
66 | extern struct vfsmount *__lookup_mnt(struct vfsmount *, struct dentry *, int); | 67 | extern struct vfsmount *__lookup_mnt(struct vfsmount *, struct dentry *, int); |
67 | extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *, | 68 | extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *, |
68 | struct vfsmount *); | 69 | struct vfsmount *); |
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index bfdeb82a53be..844a7903c72f 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c | |||
@@ -26,16 +26,32 @@ | |||
26 | 26 | ||
27 | #define BEQUIET | 27 | #define BEQUIET |
28 | 28 | ||
29 | static int isofs_hashi(struct dentry *parent, struct qstr *qstr); | 29 | static int isofs_hashi(const struct dentry *parent, const struct inode *inode, |
30 | static int isofs_hash(struct dentry *parent, struct qstr *qstr); | 30 | struct qstr *qstr); |
31 | static int isofs_dentry_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b); | 31 | static int isofs_hash(const struct dentry *parent, const struct inode *inode, |
32 | static int isofs_dentry_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b); | 32 | struct qstr *qstr); |
33 | static int isofs_dentry_cmpi(const struct dentry *parent, | ||
34 | const struct inode *pinode, | ||
35 | const struct dentry *dentry, const struct inode *inode, | ||
36 | unsigned int len, const char *str, const struct qstr *name); | ||
37 | static int isofs_dentry_cmp(const struct dentry *parent, | ||
38 | const struct inode *pinode, | ||
39 | const struct dentry *dentry, const struct inode *inode, | ||
40 | unsigned int len, const char *str, const struct qstr *name); | ||
33 | 41 | ||
34 | #ifdef CONFIG_JOLIET | 42 | #ifdef CONFIG_JOLIET |
35 | static int isofs_hashi_ms(struct dentry *parent, struct qstr *qstr); | 43 | static int isofs_hashi_ms(const struct dentry *parent, const struct inode *inode, |
36 | static int isofs_hash_ms(struct dentry *parent, struct qstr *qstr); | 44 | struct qstr *qstr); |
37 | static int isofs_dentry_cmpi_ms(struct dentry *dentry, struct qstr *a, struct qstr *b); | 45 | static int isofs_hash_ms(const struct dentry *parent, const struct inode *inode, |
38 | static int isofs_dentry_cmp_ms(struct dentry *dentry, struct qstr *a, struct qstr *b); | 46 | struct qstr *qstr); |
47 | static int isofs_dentry_cmpi_ms(const struct dentry *parent, | ||
48 | const struct inode *pinode, | ||
49 | const struct dentry *dentry, const struct inode *inode, | ||
50 | unsigned int len, const char *str, const struct qstr *name); | ||
51 | static int isofs_dentry_cmp_ms(const struct dentry *parent, | ||
52 | const struct inode *pinode, | ||
53 | const struct dentry *dentry, const struct inode *inode, | ||
54 | unsigned int len, const char *str, const struct qstr *name); | ||
39 | #endif | 55 | #endif |
40 | 56 | ||
41 | static void isofs_put_super(struct super_block *sb) | 57 | static void isofs_put_super(struct super_block *sb) |
@@ -65,11 +81,18 @@ static struct inode *isofs_alloc_inode(struct super_block *sb) | |||
65 | return &ei->vfs_inode; | 81 | return &ei->vfs_inode; |
66 | } | 82 | } |
67 | 83 | ||
68 | static void isofs_destroy_inode(struct inode *inode) | 84 | static void isofs_i_callback(struct rcu_head *head) |
69 | { | 85 | { |
86 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
87 | INIT_LIST_HEAD(&inode->i_dentry); | ||
70 | kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode)); | 88 | kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode)); |
71 | } | 89 | } |
72 | 90 | ||
91 | static void isofs_destroy_inode(struct inode *inode) | ||
92 | { | ||
93 | call_rcu(&inode->i_rcu, isofs_i_callback); | ||
94 | } | ||
95 | |||
73 | static void init_once(void *foo) | 96 | static void init_once(void *foo) |
74 | { | 97 | { |
75 | struct iso_inode_info *ei = foo; | 98 | struct iso_inode_info *ei = foo; |
@@ -160,7 +183,7 @@ struct iso9660_options{ | |||
160 | * Compute the hash for the isofs name corresponding to the dentry. | 183 | * Compute the hash for the isofs name corresponding to the dentry. |
161 | */ | 184 | */ |
162 | static int | 185 | static int |
163 | isofs_hash_common(struct dentry *dentry, struct qstr *qstr, int ms) | 186 | isofs_hash_common(const struct dentry *dentry, struct qstr *qstr, int ms) |
164 | { | 187 | { |
165 | const char *name; | 188 | const char *name; |
166 | int len; | 189 | int len; |
@@ -181,7 +204,7 @@ isofs_hash_common(struct dentry *dentry, struct qstr *qstr, int ms) | |||
181 | * Compute the hash for the isofs name corresponding to the dentry. | 204 | * Compute the hash for the isofs name corresponding to the dentry. |
182 | */ | 205 | */ |
183 | static int | 206 | static int |
184 | isofs_hashi_common(struct dentry *dentry, struct qstr *qstr, int ms) | 207 | isofs_hashi_common(const struct dentry *dentry, struct qstr *qstr, int ms) |
185 | { | 208 | { |
186 | const char *name; | 209 | const char *name; |
187 | int len; | 210 | int len; |
@@ -206,100 +229,94 @@ isofs_hashi_common(struct dentry *dentry, struct qstr *qstr, int ms) | |||
206 | } | 229 | } |
207 | 230 | ||
208 | /* | 231 | /* |
209 | * Case insensitive compare of two isofs names. | 232 | * Compare of two isofs names. |
210 | */ | ||
211 | static int isofs_dentry_cmpi_common(struct dentry *dentry, struct qstr *a, | ||
212 | struct qstr *b, int ms) | ||
213 | { | ||
214 | int alen, blen; | ||
215 | |||
216 | /* A filename cannot end in '.' or we treat it like it has none */ | ||
217 | alen = a->len; | ||
218 | blen = b->len; | ||
219 | if (ms) { | ||
220 | while (alen && a->name[alen-1] == '.') | ||
221 | alen--; | ||
222 | while (blen && b->name[blen-1] == '.') | ||
223 | blen--; | ||
224 | } | ||
225 | if (alen == blen) { | ||
226 | if (strnicmp(a->name, b->name, alen) == 0) | ||
227 | return 0; | ||
228 | } | ||
229 | return 1; | ||
230 | } | ||
231 | |||
232 | /* | ||
233 | * Case sensitive compare of two isofs names. | ||
234 | */ | 233 | */ |
235 | static int isofs_dentry_cmp_common(struct dentry *dentry, struct qstr *a, | 234 | static int isofs_dentry_cmp_common( |
236 | struct qstr *b, int ms) | 235 | unsigned int len, const char *str, |
236 | const struct qstr *name, int ms, int ci) | ||
237 | { | 237 | { |
238 | int alen, blen; | 238 | int alen, blen; |
239 | 239 | ||
240 | /* A filename cannot end in '.' or we treat it like it has none */ | 240 | /* A filename cannot end in '.' or we treat it like it has none */ |
241 | alen = a->len; | 241 | alen = name->len; |
242 | blen = b->len; | 242 | blen = len; |
243 | if (ms) { | 243 | if (ms) { |
244 | while (alen && a->name[alen-1] == '.') | 244 | while (alen && name->name[alen-1] == '.') |
245 | alen--; | 245 | alen--; |
246 | while (blen && b->name[blen-1] == '.') | 246 | while (blen && str[blen-1] == '.') |
247 | blen--; | 247 | blen--; |
248 | } | 248 | } |
249 | if (alen == blen) { | 249 | if (alen == blen) { |
250 | if (strncmp(a->name, b->name, alen) == 0) | 250 | if (ci) { |
251 | return 0; | 251 | if (strnicmp(name->name, str, alen) == 0) |
252 | return 0; | ||
253 | } else { | ||
254 | if (strncmp(name->name, str, alen) == 0) | ||
255 | return 0; | ||
256 | } | ||
252 | } | 257 | } |
253 | return 1; | 258 | return 1; |
254 | } | 259 | } |
255 | 260 | ||
256 | static int | 261 | static int |
257 | isofs_hash(struct dentry *dentry, struct qstr *qstr) | 262 | isofs_hash(const struct dentry *dentry, const struct inode *inode, |
263 | struct qstr *qstr) | ||
258 | { | 264 | { |
259 | return isofs_hash_common(dentry, qstr, 0); | 265 | return isofs_hash_common(dentry, qstr, 0); |
260 | } | 266 | } |
261 | 267 | ||
262 | static int | 268 | static int |
263 | isofs_hashi(struct dentry *dentry, struct qstr *qstr) | 269 | isofs_hashi(const struct dentry *dentry, const struct inode *inode, |
270 | struct qstr *qstr) | ||
264 | { | 271 | { |
265 | return isofs_hashi_common(dentry, qstr, 0); | 272 | return isofs_hashi_common(dentry, qstr, 0); |
266 | } | 273 | } |
267 | 274 | ||
268 | static int | 275 | static int |
269 | isofs_dentry_cmp(struct dentry *dentry,struct qstr *a,struct qstr *b) | 276 | isofs_dentry_cmp(const struct dentry *parent, const struct inode *pinode, |
277 | const struct dentry *dentry, const struct inode *inode, | ||
278 | unsigned int len, const char *str, const struct qstr *name) | ||
270 | { | 279 | { |
271 | return isofs_dentry_cmp_common(dentry, a, b, 0); | 280 | return isofs_dentry_cmp_common(len, str, name, 0, 0); |
272 | } | 281 | } |
273 | 282 | ||
274 | static int | 283 | static int |
275 | isofs_dentry_cmpi(struct dentry *dentry,struct qstr *a,struct qstr *b) | 284 | isofs_dentry_cmpi(const struct dentry *parent, const struct inode *pinode, |
285 | const struct dentry *dentry, const struct inode *inode, | ||
286 | unsigned int len, const char *str, const struct qstr *name) | ||
276 | { | 287 | { |
277 | return isofs_dentry_cmpi_common(dentry, a, b, 0); | 288 | return isofs_dentry_cmp_common(len, str, name, 0, 1); |
278 | } | 289 | } |
279 | 290 | ||
280 | #ifdef CONFIG_JOLIET | 291 | #ifdef CONFIG_JOLIET |
281 | static int | 292 | static int |
282 | isofs_hash_ms(struct dentry *dentry, struct qstr *qstr) | 293 | isofs_hash_ms(const struct dentry *dentry, const struct inode *inode, |
294 | struct qstr *qstr) | ||
283 | { | 295 | { |
284 | return isofs_hash_common(dentry, qstr, 1); | 296 | return isofs_hash_common(dentry, qstr, 1); |
285 | } | 297 | } |
286 | 298 | ||
287 | static int | 299 | static int |
288 | isofs_hashi_ms(struct dentry *dentry, struct qstr *qstr) | 300 | isofs_hashi_ms(const struct dentry *dentry, const struct inode *inode, |
301 | struct qstr *qstr) | ||
289 | { | 302 | { |
290 | return isofs_hashi_common(dentry, qstr, 1); | 303 | return isofs_hashi_common(dentry, qstr, 1); |
291 | } | 304 | } |
292 | 305 | ||
293 | static int | 306 | static int |
294 | isofs_dentry_cmp_ms(struct dentry *dentry,struct qstr *a,struct qstr *b) | 307 | isofs_dentry_cmp_ms(const struct dentry *parent, const struct inode *pinode, |
308 | const struct dentry *dentry, const struct inode *inode, | ||
309 | unsigned int len, const char *str, const struct qstr *name) | ||
295 | { | 310 | { |
296 | return isofs_dentry_cmp_common(dentry, a, b, 1); | 311 | return isofs_dentry_cmp_common(len, str, name, 1, 0); |
297 | } | 312 | } |
298 | 313 | ||
299 | static int | 314 | static int |
300 | isofs_dentry_cmpi_ms(struct dentry *dentry,struct qstr *a,struct qstr *b) | 315 | isofs_dentry_cmpi_ms(const struct dentry *parent, const struct inode *pinode, |
316 | const struct dentry *dentry, const struct inode *inode, | ||
317 | unsigned int len, const char *str, const struct qstr *name) | ||
301 | { | 318 | { |
302 | return isofs_dentry_cmpi_common(dentry, a, b, 1); | 319 | return isofs_dentry_cmp_common(len, str, name, 1, 1); |
303 | } | 320 | } |
304 | #endif | 321 | #endif |
305 | 322 | ||
@@ -932,7 +949,7 @@ root_found: | |||
932 | table += 2; | 949 | table += 2; |
933 | if (opt.check == 'r') | 950 | if (opt.check == 'r') |
934 | table++; | 951 | table++; |
935 | s->s_root->d_op = &isofs_dentry_ops[table]; | 952 | d_set_d_op(s->s_root, &isofs_dentry_ops[table]); |
936 | 953 | ||
937 | kfree(opt.iocharset); | 954 | kfree(opt.iocharset); |
938 | 955 | ||
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c index 0d23abfd4280..679a849c3b27 100644 --- a/fs/isofs/namei.c +++ b/fs/isofs/namei.c | |||
@@ -37,7 +37,8 @@ isofs_cmp(struct dentry *dentry, const char *compare, int dlen) | |||
37 | 37 | ||
38 | qstr.name = compare; | 38 | qstr.name = compare; |
39 | qstr.len = dlen; | 39 | qstr.len = dlen; |
40 | return dentry->d_op->d_compare(dentry, &dentry->d_name, &qstr); | 40 | return dentry->d_op->d_compare(NULL, NULL, NULL, NULL, |
41 | dentry->d_name.len, dentry->d_name.name, &qstr); | ||
41 | } | 42 | } |
42 | 43 | ||
43 | /* | 44 | /* |
@@ -171,7 +172,7 @@ struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, struct nam | |||
171 | struct inode *inode; | 172 | struct inode *inode; |
172 | struct page *page; | 173 | struct page *page; |
173 | 174 | ||
174 | dentry->d_op = dir->i_sb->s_root->d_op; | 175 | d_set_d_op(dentry, dir->i_sb->s_root->d_op); |
175 | 176 | ||
176 | page = alloc_page(GFP_USER); | 177 | page = alloc_page(GFP_USER); |
177 | if (!page) | 178 | if (!page) |
diff --git a/fs/jffs2/acl.c b/fs/jffs2/acl.c index 54a92fd02bbd..95b79672150a 100644 --- a/fs/jffs2/acl.c +++ b/fs/jffs2/acl.c | |||
@@ -259,11 +259,14 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
259 | return rc; | 259 | return rc; |
260 | } | 260 | } |
261 | 261 | ||
262 | int jffs2_check_acl(struct inode *inode, int mask) | 262 | int jffs2_check_acl(struct inode *inode, int mask, unsigned int flags) |
263 | { | 263 | { |
264 | struct posix_acl *acl; | 264 | struct posix_acl *acl; |
265 | int rc; | 265 | int rc; |
266 | 266 | ||
267 | if (flags & IPERM_FLAG_RCU) | ||
268 | return -ECHILD; | ||
269 | |||
267 | acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS); | 270 | acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS); |
268 | if (IS_ERR(acl)) | 271 | if (IS_ERR(acl)) |
269 | return PTR_ERR(acl); | 272 | return PTR_ERR(acl); |
diff --git a/fs/jffs2/acl.h b/fs/jffs2/acl.h index 5e42de8d9541..3119f59253d3 100644 --- a/fs/jffs2/acl.h +++ b/fs/jffs2/acl.h | |||
@@ -26,7 +26,7 @@ struct jffs2_acl_header { | |||
26 | 26 | ||
27 | #ifdef CONFIG_JFFS2_FS_POSIX_ACL | 27 | #ifdef CONFIG_JFFS2_FS_POSIX_ACL |
28 | 28 | ||
29 | extern int jffs2_check_acl(struct inode *, int); | 29 | extern int jffs2_check_acl(struct inode *, int, unsigned int); |
30 | extern int jffs2_acl_chmod(struct inode *); | 30 | extern int jffs2_acl_chmod(struct inode *); |
31 | extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *); | 31 | extern int jffs2_init_acl_pre(struct inode *, struct inode *, int *); |
32 | extern int jffs2_init_acl_post(struct inode *); | 32 | extern int jffs2_init_acl_post(struct inode *); |
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index c86041b866a4..853b8e300084 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c | |||
@@ -40,11 +40,18 @@ static struct inode *jffs2_alloc_inode(struct super_block *sb) | |||
40 | return &f->vfs_inode; | 40 | return &f->vfs_inode; |
41 | } | 41 | } |
42 | 42 | ||
43 | static void jffs2_destroy_inode(struct inode *inode) | 43 | static void jffs2_i_callback(struct rcu_head *head) |
44 | { | 44 | { |
45 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
46 | INIT_LIST_HEAD(&inode->i_dentry); | ||
45 | kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode)); | 47 | kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode)); |
46 | } | 48 | } |
47 | 49 | ||
50 | static void jffs2_destroy_inode(struct inode *inode) | ||
51 | { | ||
52 | call_rcu(&inode->i_rcu, jffs2_i_callback); | ||
53 | } | ||
54 | |||
48 | static void jffs2_i_init_once(void *foo) | 55 | static void jffs2_i_init_once(void *foo) |
49 | { | 56 | { |
50 | struct jffs2_inode_info *f = foo; | 57 | struct jffs2_inode_info *f = foo; |
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index 1057a4998e4e..e5de9422fa32 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c | |||
@@ -114,10 +114,14 @@ out: | |||
114 | return rc; | 114 | return rc; |
115 | } | 115 | } |
116 | 116 | ||
117 | int jfs_check_acl(struct inode *inode, int mask) | 117 | int jfs_check_acl(struct inode *inode, int mask, unsigned int flags) |
118 | { | 118 | { |
119 | struct posix_acl *acl = jfs_get_acl(inode, ACL_TYPE_ACCESS); | 119 | struct posix_acl *acl; |
120 | |||
121 | if (flags & IPERM_FLAG_RCU) | ||
122 | return -ECHILD; | ||
120 | 123 | ||
124 | acl = jfs_get_acl(inode, ACL_TYPE_ACCESS); | ||
121 | if (IS_ERR(acl)) | 125 | if (IS_ERR(acl)) |
122 | return PTR_ERR(acl); | 126 | return PTR_ERR(acl); |
123 | if (acl) { | 127 | if (acl) { |
diff --git a/fs/jfs/jfs_acl.h b/fs/jfs/jfs_acl.h index 54e07559878d..f9285c4900fa 100644 --- a/fs/jfs/jfs_acl.h +++ b/fs/jfs/jfs_acl.h | |||
@@ -20,7 +20,7 @@ | |||
20 | 20 | ||
21 | #ifdef CONFIG_JFS_POSIX_ACL | 21 | #ifdef CONFIG_JFS_POSIX_ACL |
22 | 22 | ||
23 | int jfs_check_acl(struct inode *, int); | 23 | int jfs_check_acl(struct inode *, int, unsigned int flags); |
24 | int jfs_init_acl(tid_t, struct inode *, struct inode *); | 24 | int jfs_init_acl(tid_t, struct inode *, struct inode *); |
25 | int jfs_acl_chmod(struct inode *inode); | 25 | int jfs_acl_chmod(struct inode *inode); |
26 | 26 | ||
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 231ca4af9bce..4414e3a42264 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c | |||
@@ -18,6 +18,7 @@ | |||
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
21 | #include <linux/namei.h> | ||
21 | #include <linux/ctype.h> | 22 | #include <linux/ctype.h> |
22 | #include <linux/quotaops.h> | 23 | #include <linux/quotaops.h> |
23 | #include <linux/exportfs.h> | 24 | #include <linux/exportfs.h> |
@@ -1465,7 +1466,7 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc | |||
1465 | jfs_info("jfs_lookup: name = %s", name); | 1466 | jfs_info("jfs_lookup: name = %s", name); |
1466 | 1467 | ||
1467 | if (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2) | 1468 | if (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2) |
1468 | dentry->d_op = &jfs_ci_dentry_operations; | 1469 | d_set_d_op(dentry, &jfs_ci_dentry_operations); |
1469 | 1470 | ||
1470 | if ((name[0] == '.') && (len == 1)) | 1471 | if ((name[0] == '.') && (len == 1)) |
1471 | inum = dip->i_ino; | 1472 | inum = dip->i_ino; |
@@ -1494,7 +1495,7 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc | |||
1494 | dentry = d_splice_alias(ip, dentry); | 1495 | dentry = d_splice_alias(ip, dentry); |
1495 | 1496 | ||
1496 | if (dentry && (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2)) | 1497 | if (dentry && (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2)) |
1497 | dentry->d_op = &jfs_ci_dentry_operations; | 1498 | d_set_d_op(dentry, &jfs_ci_dentry_operations); |
1498 | 1499 | ||
1499 | return dentry; | 1500 | return dentry; |
1500 | } | 1501 | } |
@@ -1573,7 +1574,8 @@ const struct file_operations jfs_dir_operations = { | |||
1573 | .llseek = generic_file_llseek, | 1574 | .llseek = generic_file_llseek, |
1574 | }; | 1575 | }; |
1575 | 1576 | ||
1576 | static int jfs_ci_hash(struct dentry *dir, struct qstr *this) | 1577 | static int jfs_ci_hash(const struct dentry *dir, const struct inode *inode, |
1578 | struct qstr *this) | ||
1577 | { | 1579 | { |
1578 | unsigned long hash; | 1580 | unsigned long hash; |
1579 | int i; | 1581 | int i; |
@@ -1586,32 +1588,63 @@ static int jfs_ci_hash(struct dentry *dir, struct qstr *this) | |||
1586 | return 0; | 1588 | return 0; |
1587 | } | 1589 | } |
1588 | 1590 | ||
1589 | static int jfs_ci_compare(struct dentry *dir, struct qstr *a, struct qstr *b) | 1591 | static int jfs_ci_compare(const struct dentry *parent, |
1592 | const struct inode *pinode, | ||
1593 | const struct dentry *dentry, const struct inode *inode, | ||
1594 | unsigned int len, const char *str, const struct qstr *name) | ||
1590 | { | 1595 | { |
1591 | int i, result = 1; | 1596 | int i, result = 1; |
1592 | 1597 | ||
1593 | if (a->len != b->len) | 1598 | if (len != name->len) |
1594 | goto out; | 1599 | goto out; |
1595 | for (i=0; i < a->len; i++) { | 1600 | for (i=0; i < len; i++) { |
1596 | if (tolower(a->name[i]) != tolower(b->name[i])) | 1601 | if (tolower(str[i]) != tolower(name->name[i])) |
1597 | goto out; | 1602 | goto out; |
1598 | } | 1603 | } |
1599 | result = 0; | 1604 | result = 0; |
1605 | out: | ||
1606 | return result; | ||
1607 | } | ||
1600 | 1608 | ||
1609 | static int jfs_ci_revalidate(struct dentry *dentry, struct nameidata *nd) | ||
1610 | { | ||
1611 | if (nd->flags & LOOKUP_RCU) | ||
1612 | return -ECHILD; | ||
1601 | /* | 1613 | /* |
1602 | * We want creates to preserve case. A negative dentry, a, that | 1614 | * This is not negative dentry. Always valid. |
1603 | * has a different case than b may cause a new entry to be created | 1615 | * |
1604 | * with the wrong case. Since we can't tell if a comes from a negative | 1616 | * Note, rename() to existing directory entry will have ->d_inode, |
1605 | * dentry, we blindly replace it with b. This should be harmless if | 1617 | * and will use existing name which isn't specified name by user. |
1606 | * a is not a negative dentry. | 1618 | * |
1619 | * We may be able to drop this positive dentry here. But dropping | ||
1620 | * positive dentry isn't good idea. So it's unsupported like | ||
1621 | * rename("filename", "FILENAME") for now. | ||
1607 | */ | 1622 | */ |
1608 | memcpy((unsigned char *)a->name, b->name, a->len); | 1623 | if (dentry->d_inode) |
1609 | out: | 1624 | return 1; |
1610 | return result; | 1625 | |
1626 | /* | ||
1627 | * This may be nfsd (or something), anyway, we can't see the | ||
1628 | * intent of this. So, since this can be for creation, drop it. | ||
1629 | */ | ||
1630 | if (!nd) | ||
1631 | return 0; | ||
1632 | |||
1633 | /* | ||
1634 | * Drop the negative dentry, in order to make sure to use the | ||
1635 | * case sensitive name which is specified by user if this is | ||
1636 | * for creation. | ||
1637 | */ | ||
1638 | if (!(nd->flags & (LOOKUP_CONTINUE | LOOKUP_PARENT))) { | ||
1639 | if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET)) | ||
1640 | return 0; | ||
1641 | } | ||
1642 | return 1; | ||
1611 | } | 1643 | } |
1612 | 1644 | ||
1613 | const struct dentry_operations jfs_ci_dentry_operations = | 1645 | const struct dentry_operations jfs_ci_dentry_operations = |
1614 | { | 1646 | { |
1615 | .d_hash = jfs_ci_hash, | 1647 | .d_hash = jfs_ci_hash, |
1616 | .d_compare = jfs_ci_compare, | 1648 | .d_compare = jfs_ci_compare, |
1649 | .d_revalidate = jfs_ci_revalidate, | ||
1617 | }; | 1650 | }; |
diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 0669fc1cc3bf..3150d766e0d4 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c | |||
@@ -115,6 +115,14 @@ static struct inode *jfs_alloc_inode(struct super_block *sb) | |||
115 | return &jfs_inode->vfs_inode; | 115 | return &jfs_inode->vfs_inode; |
116 | } | 116 | } |
117 | 117 | ||
118 | static void jfs_i_callback(struct rcu_head *head) | ||
119 | { | ||
120 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
121 | struct jfs_inode_info *ji = JFS_IP(inode); | ||
122 | INIT_LIST_HEAD(&inode->i_dentry); | ||
123 | kmem_cache_free(jfs_inode_cachep, ji); | ||
124 | } | ||
125 | |||
118 | static void jfs_destroy_inode(struct inode *inode) | 126 | static void jfs_destroy_inode(struct inode *inode) |
119 | { | 127 | { |
120 | struct jfs_inode_info *ji = JFS_IP(inode); | 128 | struct jfs_inode_info *ji = JFS_IP(inode); |
@@ -128,7 +136,7 @@ static void jfs_destroy_inode(struct inode *inode) | |||
128 | ji->active_ag = -1; | 136 | ji->active_ag = -1; |
129 | } | 137 | } |
130 | spin_unlock_irq(&ji->ag_lock); | 138 | spin_unlock_irq(&ji->ag_lock); |
131 | kmem_cache_free(jfs_inode_cachep, ji); | 139 | call_rcu(&inode->i_rcu, jfs_i_callback); |
132 | } | 140 | } |
133 | 141 | ||
134 | static int jfs_statfs(struct dentry *dentry, struct kstatfs *buf) | 142 | static int jfs_statfs(struct dentry *dentry, struct kstatfs *buf) |
@@ -517,7 +525,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) | |||
517 | goto out_no_root; | 525 | goto out_no_root; |
518 | 526 | ||
519 | if (sbi->mntflag & JFS_OS2) | 527 | if (sbi->mntflag & JFS_OS2) |
520 | sb->s_root->d_op = &jfs_ci_dentry_operations; | 528 | d_set_d_op(sb->s_root, &jfs_ci_dentry_operations); |
521 | 529 | ||
522 | /* logical blocks are represented by 40 bits in pxd_t, etc. */ | 530 | /* logical blocks are represented by 40 bits in pxd_t, etc. */ |
523 | sb->s_maxbytes = ((u64) sb->s_blocksize) << 40; | 531 | sb->s_maxbytes = ((u64) sb->s_blocksize) << 40; |
diff --git a/fs/libfs.c b/fs/libfs.c index a3accdf528ad..889311e3d06b 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
@@ -16,6 +16,11 @@ | |||
16 | 16 | ||
17 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
18 | 18 | ||
19 | static inline int simple_positive(struct dentry *dentry) | ||
20 | { | ||
21 | return dentry->d_inode && !d_unhashed(dentry); | ||
22 | } | ||
23 | |||
19 | int simple_getattr(struct vfsmount *mnt, struct dentry *dentry, | 24 | int simple_getattr(struct vfsmount *mnt, struct dentry *dentry, |
20 | struct kstat *stat) | 25 | struct kstat *stat) |
21 | { | 26 | { |
@@ -37,7 +42,7 @@ int simple_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
37 | * Retaining negative dentries for an in-memory filesystem just wastes | 42 | * Retaining negative dentries for an in-memory filesystem just wastes |
38 | * memory and lookup time: arrange for them to be deleted immediately. | 43 | * memory and lookup time: arrange for them to be deleted immediately. |
39 | */ | 44 | */ |
40 | static int simple_delete_dentry(struct dentry *dentry) | 45 | static int simple_delete_dentry(const struct dentry *dentry) |
41 | { | 46 | { |
42 | return 1; | 47 | return 1; |
43 | } | 48 | } |
@@ -54,7 +59,7 @@ struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, struct na | |||
54 | 59 | ||
55 | if (dentry->d_name.len > NAME_MAX) | 60 | if (dentry->d_name.len > NAME_MAX) |
56 | return ERR_PTR(-ENAMETOOLONG); | 61 | return ERR_PTR(-ENAMETOOLONG); |
57 | dentry->d_op = &simple_dentry_operations; | 62 | d_set_d_op(dentry, &simple_dentry_operations); |
58 | d_add(dentry, NULL); | 63 | d_add(dentry, NULL); |
59 | return NULL; | 64 | return NULL; |
60 | } | 65 | } |
@@ -76,7 +81,8 @@ int dcache_dir_close(struct inode *inode, struct file *file) | |||
76 | 81 | ||
77 | loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) | 82 | loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) |
78 | { | 83 | { |
79 | mutex_lock(&file->f_path.dentry->d_inode->i_mutex); | 84 | struct dentry *dentry = file->f_path.dentry; |
85 | mutex_lock(&dentry->d_inode->i_mutex); | ||
80 | switch (origin) { | 86 | switch (origin) { |
81 | case 1: | 87 | case 1: |
82 | offset += file->f_pos; | 88 | offset += file->f_pos; |
@@ -84,7 +90,7 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) | |||
84 | if (offset >= 0) | 90 | if (offset >= 0) |
85 | break; | 91 | break; |
86 | default: | 92 | default: |
87 | mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); | 93 | mutex_unlock(&dentry->d_inode->i_mutex); |
88 | return -EINVAL; | 94 | return -EINVAL; |
89 | } | 95 | } |
90 | if (offset != file->f_pos) { | 96 | if (offset != file->f_pos) { |
@@ -94,21 +100,24 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int origin) | |||
94 | struct dentry *cursor = file->private_data; | 100 | struct dentry *cursor = file->private_data; |
95 | loff_t n = file->f_pos - 2; | 101 | loff_t n = file->f_pos - 2; |
96 | 102 | ||
97 | spin_lock(&dcache_lock); | 103 | spin_lock(&dentry->d_lock); |
104 | /* d_lock not required for cursor */ | ||
98 | list_del(&cursor->d_u.d_child); | 105 | list_del(&cursor->d_u.d_child); |
99 | p = file->f_path.dentry->d_subdirs.next; | 106 | p = dentry->d_subdirs.next; |
100 | while (n && p != &file->f_path.dentry->d_subdirs) { | 107 | while (n && p != &dentry->d_subdirs) { |
101 | struct dentry *next; | 108 | struct dentry *next; |
102 | next = list_entry(p, struct dentry, d_u.d_child); | 109 | next = list_entry(p, struct dentry, d_u.d_child); |
103 | if (!d_unhashed(next) && next->d_inode) | 110 | spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); |
111 | if (simple_positive(next)) | ||
104 | n--; | 112 | n--; |
113 | spin_unlock(&next->d_lock); | ||
105 | p = p->next; | 114 | p = p->next; |
106 | } | 115 | } |
107 | list_add_tail(&cursor->d_u.d_child, p); | 116 | list_add_tail(&cursor->d_u.d_child, p); |
108 | spin_unlock(&dcache_lock); | 117 | spin_unlock(&dentry->d_lock); |
109 | } | 118 | } |
110 | } | 119 | } |
111 | mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); | 120 | mutex_unlock(&dentry->d_inode->i_mutex); |
112 | return offset; | 121 | return offset; |
113 | } | 122 | } |
114 | 123 | ||
@@ -148,29 +157,35 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
148 | i++; | 157 | i++; |
149 | /* fallthrough */ | 158 | /* fallthrough */ |
150 | default: | 159 | default: |
151 | spin_lock(&dcache_lock); | 160 | spin_lock(&dentry->d_lock); |
152 | if (filp->f_pos == 2) | 161 | if (filp->f_pos == 2) |
153 | list_move(q, &dentry->d_subdirs); | 162 | list_move(q, &dentry->d_subdirs); |
154 | 163 | ||
155 | for (p=q->next; p != &dentry->d_subdirs; p=p->next) { | 164 | for (p=q->next; p != &dentry->d_subdirs; p=p->next) { |
156 | struct dentry *next; | 165 | struct dentry *next; |
157 | next = list_entry(p, struct dentry, d_u.d_child); | 166 | next = list_entry(p, struct dentry, d_u.d_child); |
158 | if (d_unhashed(next) || !next->d_inode) | 167 | spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); |
168 | if (!simple_positive(next)) { | ||
169 | spin_unlock(&next->d_lock); | ||
159 | continue; | 170 | continue; |
171 | } | ||
160 | 172 | ||
161 | spin_unlock(&dcache_lock); | 173 | spin_unlock(&next->d_lock); |
174 | spin_unlock(&dentry->d_lock); | ||
162 | if (filldir(dirent, next->d_name.name, | 175 | if (filldir(dirent, next->d_name.name, |
163 | next->d_name.len, filp->f_pos, | 176 | next->d_name.len, filp->f_pos, |
164 | next->d_inode->i_ino, | 177 | next->d_inode->i_ino, |
165 | dt_type(next->d_inode)) < 0) | 178 | dt_type(next->d_inode)) < 0) |
166 | return 0; | 179 | return 0; |
167 | spin_lock(&dcache_lock); | 180 | spin_lock(&dentry->d_lock); |
181 | spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED); | ||
168 | /* next is still alive */ | 182 | /* next is still alive */ |
169 | list_move(q, p); | 183 | list_move(q, p); |
184 | spin_unlock(&next->d_lock); | ||
170 | p = q; | 185 | p = q; |
171 | filp->f_pos++; | 186 | filp->f_pos++; |
172 | } | 187 | } |
173 | spin_unlock(&dcache_lock); | 188 | spin_unlock(&dentry->d_lock); |
174 | } | 189 | } |
175 | return 0; | 190 | return 0; |
176 | } | 191 | } |
@@ -259,23 +274,23 @@ int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *den | |||
259 | return 0; | 274 | return 0; |
260 | } | 275 | } |
261 | 276 | ||
262 | static inline int simple_positive(struct dentry *dentry) | ||
263 | { | ||
264 | return dentry->d_inode && !d_unhashed(dentry); | ||
265 | } | ||
266 | |||
267 | int simple_empty(struct dentry *dentry) | 277 | int simple_empty(struct dentry *dentry) |
268 | { | 278 | { |
269 | struct dentry *child; | 279 | struct dentry *child; |
270 | int ret = 0; | 280 | int ret = 0; |
271 | 281 | ||
272 | spin_lock(&dcache_lock); | 282 | spin_lock(&dentry->d_lock); |
273 | list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) | 283 | list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) { |
274 | if (simple_positive(child)) | 284 | spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); |
285 | if (simple_positive(child)) { | ||
286 | spin_unlock(&child->d_lock); | ||
275 | goto out; | 287 | goto out; |
288 | } | ||
289 | spin_unlock(&child->d_lock); | ||
290 | } | ||
276 | ret = 1; | 291 | ret = 1; |
277 | out: | 292 | out: |
278 | spin_unlock(&dcache_lock); | 293 | spin_unlock(&dentry->d_lock); |
279 | return ret; | 294 | return ret; |
280 | } | 295 | } |
281 | 296 | ||
diff --git a/fs/locks.c b/fs/locks.c index 8729347bcd1a..08415b2a6d36 100644 --- a/fs/locks.c +++ b/fs/locks.c | |||
@@ -1389,7 +1389,7 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp) | |||
1389 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) | 1389 | if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0)) |
1390 | goto out; | 1390 | goto out; |
1391 | if ((arg == F_WRLCK) | 1391 | if ((arg == F_WRLCK) |
1392 | && ((atomic_read(&dentry->d_count) > 1) | 1392 | && ((dentry->d_count > 1) |
1393 | || (atomic_read(&inode->i_count) > 1))) | 1393 | || (atomic_read(&inode->i_count) > 1))) |
1394 | goto out; | 1394 | goto out; |
1395 | } | 1395 | } |
diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c index 409dfd65e9a1..f9ddf0c388c8 100644 --- a/fs/logfs/dir.c +++ b/fs/logfs/dir.c | |||
@@ -555,9 +555,11 @@ static int logfs_symlink(struct inode *dir, struct dentry *dentry, | |||
555 | return __logfs_create(dir, dentry, inode, target, destlen); | 555 | return __logfs_create(dir, dentry, inode, target, destlen); |
556 | } | 556 | } |
557 | 557 | ||
558 | static int logfs_permission(struct inode *inode, int mask) | 558 | static int logfs_permission(struct inode *inode, int mask, unsigned int flags) |
559 | { | 559 | { |
560 | return generic_permission(inode, mask, NULL); | 560 | if (flags & IPERM_FLAG_RCU) |
561 | return -ECHILD; | ||
562 | return generic_permission(inode, mask, flags, NULL); | ||
561 | } | 563 | } |
562 | 564 | ||
563 | static int logfs_link(struct dentry *old_dentry, struct inode *dir, | 565 | static int logfs_link(struct dentry *old_dentry, struct inode *dir, |
diff --git a/fs/logfs/inode.c b/fs/logfs/inode.c index d8c71ece098f..03b8c240aeda 100644 --- a/fs/logfs/inode.c +++ b/fs/logfs/inode.c | |||
@@ -141,13 +141,20 @@ struct inode *logfs_safe_iget(struct super_block *sb, ino_t ino, int *is_cached) | |||
141 | return __logfs_iget(sb, ino); | 141 | return __logfs_iget(sb, ino); |
142 | } | 142 | } |
143 | 143 | ||
144 | static void logfs_i_callback(struct rcu_head *head) | ||
145 | { | ||
146 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
147 | INIT_LIST_HEAD(&inode->i_dentry); | ||
148 | kmem_cache_free(logfs_inode_cache, logfs_inode(inode)); | ||
149 | } | ||
150 | |||
144 | static void __logfs_destroy_inode(struct inode *inode) | 151 | static void __logfs_destroy_inode(struct inode *inode) |
145 | { | 152 | { |
146 | struct logfs_inode *li = logfs_inode(inode); | 153 | struct logfs_inode *li = logfs_inode(inode); |
147 | 154 | ||
148 | BUG_ON(li->li_block); | 155 | BUG_ON(li->li_block); |
149 | list_del(&li->li_freeing_list); | 156 | list_del(&li->li_freeing_list); |
150 | kmem_cache_free(logfs_inode_cache, li); | 157 | call_rcu(&inode->i_rcu, logfs_i_callback); |
151 | } | 158 | } |
152 | 159 | ||
153 | static void logfs_destroy_inode(struct inode *inode) | 160 | static void logfs_destroy_inode(struct inode *inode) |
diff --git a/fs/logfs/journal.c b/fs/logfs/journal.c index f46ee8b0e135..9da29706f91c 100644 --- a/fs/logfs/journal.c +++ b/fs/logfs/journal.c | |||
@@ -828,7 +828,7 @@ void do_logfs_journal_wl_pass(struct super_block *sb) | |||
828 | super->s_journal_seg[i] = segno; | 828 | super->s_journal_seg[i] = segno; |
829 | super->s_journal_ec[i] = ec; | 829 | super->s_journal_ec[i] = ec; |
830 | logfs_set_segment_reserved(sb, segno); | 830 | logfs_set_segment_reserved(sb, segno); |
831 | err = btree_insert32(head, segno, (void *)1, GFP_KERNEL); | 831 | err = btree_insert32(head, segno, (void *)1, GFP_NOFS); |
832 | BUG_ON(err); /* mempool should prevent this */ | 832 | BUG_ON(err); /* mempool should prevent this */ |
833 | err = logfs_erase_segment(sb, segno, 1); | 833 | err = logfs_erase_segment(sb, segno, 1); |
834 | BUG_ON(err); /* FIXME: remount-ro would be nicer */ | 834 | BUG_ON(err); /* FIXME: remount-ro would be nicer */ |
diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c index 6127baf0e188..ee99a9f5dfd3 100644 --- a/fs/logfs/readwrite.c +++ b/fs/logfs/readwrite.c | |||
@@ -1994,6 +1994,9 @@ static int do_write_inode(struct inode *inode) | |||
1994 | 1994 | ||
1995 | /* FIXME: transaction is part of logfs_block now. Is that enough? */ | 1995 | /* FIXME: transaction is part of logfs_block now. Is that enough? */ |
1996 | err = logfs_write_buf(master_inode, page, 0); | 1996 | err = logfs_write_buf(master_inode, page, 0); |
1997 | if (err) | ||
1998 | move_page_to_inode(inode, page); | ||
1999 | |||
1997 | logfs_put_write_page(page); | 2000 | logfs_put_write_page(page); |
1998 | return err; | 2001 | return err; |
1999 | } | 2002 | } |
diff --git a/fs/minix/inode.c b/fs/minix/inode.c index fb2020858a34..ae0b83f476a6 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c | |||
@@ -68,11 +68,18 @@ static struct inode *minix_alloc_inode(struct super_block *sb) | |||
68 | return &ei->vfs_inode; | 68 | return &ei->vfs_inode; |
69 | } | 69 | } |
70 | 70 | ||
71 | static void minix_destroy_inode(struct inode *inode) | 71 | static void minix_i_callback(struct rcu_head *head) |
72 | { | 72 | { |
73 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
74 | INIT_LIST_HEAD(&inode->i_dentry); | ||
73 | kmem_cache_free(minix_inode_cachep, minix_i(inode)); | 75 | kmem_cache_free(minix_inode_cachep, minix_i(inode)); |
74 | } | 76 | } |
75 | 77 | ||
78 | static void minix_destroy_inode(struct inode *inode) | ||
79 | { | ||
80 | call_rcu(&inode->i_rcu, minix_i_callback); | ||
81 | } | ||
82 | |||
76 | static void init_once(void *foo) | 83 | static void init_once(void *foo) |
77 | { | 84 | { |
78 | struct minix_inode_info *ei = (struct minix_inode_info *) foo; | 85 | struct minix_inode_info *ei = (struct minix_inode_info *) foo; |
diff --git a/fs/minix/namei.c b/fs/minix/namei.c index c0d35a3accef..1b9e07728a9f 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c | |||
@@ -23,7 +23,7 @@ static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, st | |||
23 | struct inode * inode = NULL; | 23 | struct inode * inode = NULL; |
24 | ino_t ino; | 24 | ino_t ino; |
25 | 25 | ||
26 | dentry->d_op = dir->i_sb->s_root->d_op; | 26 | d_set_d_op(dentry, dir->i_sb->s_root->d_op); |
27 | 27 | ||
28 | if (dentry->d_name.len > minix_sb(dir->i_sb)->s_namelen) | 28 | if (dentry->d_name.len > minix_sb(dir->i_sb)->s_namelen) |
29 | return ERR_PTR(-ENAMETOOLONG); | 29 | return ERR_PTR(-ENAMETOOLONG); |
diff --git a/fs/namei.c b/fs/namei.c index 5362af9b7372..24ece10470b6 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -169,8 +169,8 @@ EXPORT_SYMBOL(putname); | |||
169 | /* | 169 | /* |
170 | * This does basic POSIX ACL permission checking | 170 | * This does basic POSIX ACL permission checking |
171 | */ | 171 | */ |
172 | static int acl_permission_check(struct inode *inode, int mask, | 172 | static int acl_permission_check(struct inode *inode, int mask, unsigned int flags, |
173 | int (*check_acl)(struct inode *inode, int mask)) | 173 | int (*check_acl)(struct inode *inode, int mask, unsigned int flags)) |
174 | { | 174 | { |
175 | umode_t mode = inode->i_mode; | 175 | umode_t mode = inode->i_mode; |
176 | 176 | ||
@@ -180,7 +180,7 @@ static int acl_permission_check(struct inode *inode, int mask, | |||
180 | mode >>= 6; | 180 | mode >>= 6; |
181 | else { | 181 | else { |
182 | if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) { | 182 | if (IS_POSIXACL(inode) && (mode & S_IRWXG) && check_acl) { |
183 | int error = check_acl(inode, mask); | 183 | int error = check_acl(inode, mask, flags); |
184 | if (error != -EAGAIN) | 184 | if (error != -EAGAIN) |
185 | return error; | 185 | return error; |
186 | } | 186 | } |
@@ -198,25 +198,30 @@ static int acl_permission_check(struct inode *inode, int mask, | |||
198 | } | 198 | } |
199 | 199 | ||
200 | /** | 200 | /** |
201 | * generic_permission - check for access rights on a Posix-like filesystem | 201 | * generic_permission - check for access rights on a Posix-like filesystem |
202 | * @inode: inode to check access rights for | 202 | * @inode: inode to check access rights for |
203 | * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) | 203 | * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) |
204 | * @check_acl: optional callback to check for Posix ACLs | 204 | * @check_acl: optional callback to check for Posix ACLs |
205 | * @flags: IPERM_FLAG_ flags. | ||
205 | * | 206 | * |
206 | * Used to check for read/write/execute permissions on a file. | 207 | * Used to check for read/write/execute permissions on a file. |
207 | * We use "fsuid" for this, letting us set arbitrary permissions | 208 | * We use "fsuid" for this, letting us set arbitrary permissions |
208 | * for filesystem access without changing the "normal" uids which | 209 | * for filesystem access without changing the "normal" uids which |
209 | * are used for other things.. | 210 | * are used for other things. |
211 | * | ||
212 | * generic_permission is rcu-walk aware. It returns -ECHILD in case an rcu-walk | ||
213 | * request cannot be satisfied (eg. requires blocking or too much complexity). | ||
214 | * It would then be called again in ref-walk mode. | ||
210 | */ | 215 | */ |
211 | int generic_permission(struct inode *inode, int mask, | 216 | int generic_permission(struct inode *inode, int mask, unsigned int flags, |
212 | int (*check_acl)(struct inode *inode, int mask)) | 217 | int (*check_acl)(struct inode *inode, int mask, unsigned int flags)) |
213 | { | 218 | { |
214 | int ret; | 219 | int ret; |
215 | 220 | ||
216 | /* | 221 | /* |
217 | * Do the basic POSIX ACL permission checks. | 222 | * Do the basic POSIX ACL permission checks. |
218 | */ | 223 | */ |
219 | ret = acl_permission_check(inode, mask, check_acl); | 224 | ret = acl_permission_check(inode, mask, flags, check_acl); |
220 | if (ret != -EACCES) | 225 | if (ret != -EACCES) |
221 | return ret; | 226 | return ret; |
222 | 227 | ||
@@ -271,9 +276,10 @@ int inode_permission(struct inode *inode, int mask) | |||
271 | } | 276 | } |
272 | 277 | ||
273 | if (inode->i_op->permission) | 278 | if (inode->i_op->permission) |
274 | retval = inode->i_op->permission(inode, mask); | 279 | retval = inode->i_op->permission(inode, mask, 0); |
275 | else | 280 | else |
276 | retval = generic_permission(inode, mask, inode->i_op->check_acl); | 281 | retval = generic_permission(inode, mask, 0, |
282 | inode->i_op->check_acl); | ||
277 | 283 | ||
278 | if (retval) | 284 | if (retval) |
279 | return retval; | 285 | return retval; |
@@ -362,6 +368,18 @@ void path_get(struct path *path) | |||
362 | EXPORT_SYMBOL(path_get); | 368 | EXPORT_SYMBOL(path_get); |
363 | 369 | ||
364 | /** | 370 | /** |
371 | * path_get_long - get a long reference to a path | ||
372 | * @path: path to get the reference to | ||
373 | * | ||
374 | * Given a path increment the reference count to the dentry and the vfsmount. | ||
375 | */ | ||
376 | void path_get_long(struct path *path) | ||
377 | { | ||
378 | mntget_long(path->mnt); | ||
379 | dget(path->dentry); | ||
380 | } | ||
381 | |||
382 | /** | ||
365 | * path_put - put a reference to a path | 383 | * path_put - put a reference to a path |
366 | * @path: path to put the reference to | 384 | * @path: path to put the reference to |
367 | * | 385 | * |
@@ -375,6 +393,185 @@ void path_put(struct path *path) | |||
375 | EXPORT_SYMBOL(path_put); | 393 | EXPORT_SYMBOL(path_put); |
376 | 394 | ||
377 | /** | 395 | /** |
396 | * path_put_long - put a long reference to a path | ||
397 | * @path: path to put the reference to | ||
398 | * | ||
399 | * Given a path decrement the reference count to the dentry and the vfsmount. | ||
400 | */ | ||
401 | void path_put_long(struct path *path) | ||
402 | { | ||
403 | dput(path->dentry); | ||
404 | mntput_long(path->mnt); | ||
405 | } | ||
406 | |||
407 | /** | ||
408 | * nameidata_drop_rcu - drop this nameidata out of rcu-walk | ||
409 | * @nd: nameidata pathwalk data to drop | ||
410 | * Returns: 0 on success, -ECHILD on failure | ||
411 | * | ||
412 | * Path walking has 2 modes, rcu-walk and ref-walk (see | ||
413 | * Documentation/filesystems/path-lookup.txt). __drop_rcu* functions attempt | ||
414 | * to drop out of rcu-walk mode and take normal reference counts on dentries | ||
415 | * and vfsmounts to transition to rcu-walk mode. __drop_rcu* functions take | ||
416 | * refcounts at the last known good point before rcu-walk got stuck, so | ||
417 | * ref-walk may continue from there. If this is not successful (eg. a seqcount | ||
418 | * has changed), then failure is returned and path walk restarts from the | ||
419 | * beginning in ref-walk mode. | ||
420 | * | ||
421 | * nameidata_drop_rcu attempts to drop the current nd->path and nd->root into | ||
422 | * ref-walk. Must be called from rcu-walk context. | ||
423 | */ | ||
424 | static int nameidata_drop_rcu(struct nameidata *nd) | ||
425 | { | ||
426 | struct fs_struct *fs = current->fs; | ||
427 | struct dentry *dentry = nd->path.dentry; | ||
428 | |||
429 | BUG_ON(!(nd->flags & LOOKUP_RCU)); | ||
430 | if (nd->root.mnt) { | ||
431 | spin_lock(&fs->lock); | ||
432 | if (nd->root.mnt != fs->root.mnt || | ||
433 | nd->root.dentry != fs->root.dentry) | ||
434 | goto err_root; | ||
435 | } | ||
436 | spin_lock(&dentry->d_lock); | ||
437 | if (!__d_rcu_to_refcount(dentry, nd->seq)) | ||
438 | goto err; | ||
439 | BUG_ON(nd->inode != dentry->d_inode); | ||
440 | spin_unlock(&dentry->d_lock); | ||
441 | if (nd->root.mnt) { | ||
442 | path_get(&nd->root); | ||
443 | spin_unlock(&fs->lock); | ||
444 | } | ||
445 | mntget(nd->path.mnt); | ||
446 | |||
447 | rcu_read_unlock(); | ||
448 | br_read_unlock(vfsmount_lock); | ||
449 | nd->flags &= ~LOOKUP_RCU; | ||
450 | return 0; | ||
451 | err: | ||
452 | spin_unlock(&dentry->d_lock); | ||
453 | err_root: | ||
454 | if (nd->root.mnt) | ||
455 | spin_unlock(&fs->lock); | ||
456 | return -ECHILD; | ||
457 | } | ||
458 | |||
459 | /* Try to drop out of rcu-walk mode if we were in it, otherwise do nothing. */ | ||
460 | static inline int nameidata_drop_rcu_maybe(struct nameidata *nd) | ||
461 | { | ||
462 | if (nd->flags & LOOKUP_RCU) | ||
463 | return nameidata_drop_rcu(nd); | ||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | /** | ||
468 | * nameidata_dentry_drop_rcu - drop nameidata and dentry out of rcu-walk | ||
469 | * @nd: nameidata pathwalk data to drop | ||
470 | * @dentry: dentry to drop | ||
471 | * Returns: 0 on success, -ECHILD on failure | ||
472 | * | ||
473 | * nameidata_dentry_drop_rcu attempts to drop the current nd->path and nd->root, | ||
474 | * and dentry into ref-walk. @dentry must be a path found by a do_lookup call on | ||
475 | * @nd. Must be called from rcu-walk context. | ||
476 | */ | ||
477 | static int nameidata_dentry_drop_rcu(struct nameidata *nd, struct dentry *dentry) | ||
478 | { | ||
479 | struct fs_struct *fs = current->fs; | ||
480 | struct dentry *parent = nd->path.dentry; | ||
481 | |||
482 | BUG_ON(!(nd->flags & LOOKUP_RCU)); | ||
483 | if (nd->root.mnt) { | ||
484 | spin_lock(&fs->lock); | ||
485 | if (nd->root.mnt != fs->root.mnt || | ||
486 | nd->root.dentry != fs->root.dentry) | ||
487 | goto err_root; | ||
488 | } | ||
489 | spin_lock(&parent->d_lock); | ||
490 | spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); | ||
491 | if (!__d_rcu_to_refcount(dentry, nd->seq)) | ||
492 | goto err; | ||
493 | /* | ||
494 | * If the sequence check on the child dentry passed, then the child has | ||
495 | * not been removed from its parent. This means the parent dentry must | ||
496 | * be valid and able to take a reference at this point. | ||
497 | */ | ||
498 | BUG_ON(!IS_ROOT(dentry) && dentry->d_parent != parent); | ||
499 | BUG_ON(!parent->d_count); | ||
500 | parent->d_count++; | ||
501 | spin_unlock(&dentry->d_lock); | ||
502 | spin_unlock(&parent->d_lock); | ||
503 | if (nd->root.mnt) { | ||
504 | path_get(&nd->root); | ||
505 | spin_unlock(&fs->lock); | ||
506 | } | ||
507 | mntget(nd->path.mnt); | ||
508 | |||
509 | rcu_read_unlock(); | ||
510 | br_read_unlock(vfsmount_lock); | ||
511 | nd->flags &= ~LOOKUP_RCU; | ||
512 | return 0; | ||
513 | err: | ||
514 | spin_unlock(&dentry->d_lock); | ||
515 | spin_unlock(&parent->d_lock); | ||
516 | err_root: | ||
517 | if (nd->root.mnt) | ||
518 | spin_unlock(&fs->lock); | ||
519 | return -ECHILD; | ||
520 | } | ||
521 | |||
522 | /* Try to drop out of rcu-walk mode if we were in it, otherwise do nothing. */ | ||
523 | static inline int nameidata_dentry_drop_rcu_maybe(struct nameidata *nd, struct dentry *dentry) | ||
524 | { | ||
525 | if (nd->flags & LOOKUP_RCU) | ||
526 | return nameidata_dentry_drop_rcu(nd, dentry); | ||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | /** | ||
531 | * nameidata_drop_rcu_last - drop nameidata ending path walk out of rcu-walk | ||
532 | * @nd: nameidata pathwalk data to drop | ||
533 | * Returns: 0 on success, -ECHILD on failure | ||
534 | * | ||
535 | * nameidata_drop_rcu_last attempts to drop the current nd->path into ref-walk. | ||
536 | * nd->path should be the final element of the lookup, so nd->root is discarded. | ||
537 | * Must be called from rcu-walk context. | ||
538 | */ | ||
539 | static int nameidata_drop_rcu_last(struct nameidata *nd) | ||
540 | { | ||
541 | struct dentry *dentry = nd->path.dentry; | ||
542 | |||
543 | BUG_ON(!(nd->flags & LOOKUP_RCU)); | ||
544 | nd->flags &= ~LOOKUP_RCU; | ||
545 | nd->root.mnt = NULL; | ||
546 | spin_lock(&dentry->d_lock); | ||
547 | if (!__d_rcu_to_refcount(dentry, nd->seq)) | ||
548 | goto err_unlock; | ||
549 | BUG_ON(nd->inode != dentry->d_inode); | ||
550 | spin_unlock(&dentry->d_lock); | ||
551 | |||
552 | mntget(nd->path.mnt); | ||
553 | |||
554 | rcu_read_unlock(); | ||
555 | br_read_unlock(vfsmount_lock); | ||
556 | |||
557 | return 0; | ||
558 | |||
559 | err_unlock: | ||
560 | spin_unlock(&dentry->d_lock); | ||
561 | rcu_read_unlock(); | ||
562 | br_read_unlock(vfsmount_lock); | ||
563 | return -ECHILD; | ||
564 | } | ||
565 | |||
566 | /* Try to drop out of rcu-walk mode if we were in it, otherwise do nothing. */ | ||
567 | static inline int nameidata_drop_rcu_last_maybe(struct nameidata *nd) | ||
568 | { | ||
569 | if (likely(nd->flags & LOOKUP_RCU)) | ||
570 | return nameidata_drop_rcu_last(nd); | ||
571 | return 0; | ||
572 | } | ||
573 | |||
574 | /** | ||
378 | * release_open_intent - free up open intent resources | 575 | * release_open_intent - free up open intent resources |
379 | * @nd: pointer to nameidata | 576 | * @nd: pointer to nameidata |
380 | */ | 577 | */ |
@@ -386,10 +583,26 @@ void release_open_intent(struct nameidata *nd) | |||
386 | fput(nd->intent.open.file); | 583 | fput(nd->intent.open.file); |
387 | } | 584 | } |
388 | 585 | ||
586 | static int d_revalidate(struct dentry *dentry, struct nameidata *nd) | ||
587 | { | ||
588 | int status; | ||
589 | |||
590 | status = dentry->d_op->d_revalidate(dentry, nd); | ||
591 | if (status == -ECHILD) { | ||
592 | if (nameidata_dentry_drop_rcu(nd, dentry)) | ||
593 | return status; | ||
594 | status = dentry->d_op->d_revalidate(dentry, nd); | ||
595 | } | ||
596 | |||
597 | return status; | ||
598 | } | ||
599 | |||
389 | static inline struct dentry * | 600 | static inline struct dentry * |
390 | do_revalidate(struct dentry *dentry, struct nameidata *nd) | 601 | do_revalidate(struct dentry *dentry, struct nameidata *nd) |
391 | { | 602 | { |
392 | int status = dentry->d_op->d_revalidate(dentry, nd); | 603 | int status; |
604 | |||
605 | status = d_revalidate(dentry, nd); | ||
393 | if (unlikely(status <= 0)) { | 606 | if (unlikely(status <= 0)) { |
394 | /* | 607 | /* |
395 | * The dentry failed validation. | 608 | * The dentry failed validation. |
@@ -397,19 +610,36 @@ do_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
397 | * the dentry otherwise d_revalidate is asking us | 610 | * the dentry otherwise d_revalidate is asking us |
398 | * to return a fail status. | 611 | * to return a fail status. |
399 | */ | 612 | */ |
400 | if (!status) { | 613 | if (status < 0) { |
614 | /* If we're in rcu-walk, we don't have a ref */ | ||
615 | if (!(nd->flags & LOOKUP_RCU)) | ||
616 | dput(dentry); | ||
617 | dentry = ERR_PTR(status); | ||
618 | |||
619 | } else { | ||
620 | /* Don't d_invalidate in rcu-walk mode */ | ||
621 | if (nameidata_dentry_drop_rcu_maybe(nd, dentry)) | ||
622 | return ERR_PTR(-ECHILD); | ||
401 | if (!d_invalidate(dentry)) { | 623 | if (!d_invalidate(dentry)) { |
402 | dput(dentry); | 624 | dput(dentry); |
403 | dentry = NULL; | 625 | dentry = NULL; |
404 | } | 626 | } |
405 | } else { | ||
406 | dput(dentry); | ||
407 | dentry = ERR_PTR(status); | ||
408 | } | 627 | } |
409 | } | 628 | } |
410 | return dentry; | 629 | return dentry; |
411 | } | 630 | } |
412 | 631 | ||
632 | static inline int need_reval_dot(struct dentry *dentry) | ||
633 | { | ||
634 | if (likely(!(dentry->d_flags & DCACHE_OP_REVALIDATE))) | ||
635 | return 0; | ||
636 | |||
637 | if (likely(!(dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT))) | ||
638 | return 0; | ||
639 | |||
640 | return 1; | ||
641 | } | ||
642 | |||
413 | /* | 643 | /* |
414 | * force_reval_path - force revalidation of a dentry | 644 | * force_reval_path - force revalidation of a dentry |
415 | * | 645 | * |
@@ -433,13 +663,12 @@ force_reval_path(struct path *path, struct nameidata *nd) | |||
433 | 663 | ||
434 | /* | 664 | /* |
435 | * only check on filesystems where it's possible for the dentry to | 665 | * only check on filesystems where it's possible for the dentry to |
436 | * become stale. It's assumed that if this flag is set then the | 666 | * become stale. |
437 | * d_revalidate op will also be defined. | ||
438 | */ | 667 | */ |
439 | if (!(dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)) | 668 | if (!need_reval_dot(dentry)) |
440 | return 0; | 669 | return 0; |
441 | 670 | ||
442 | status = dentry->d_op->d_revalidate(dentry, nd); | 671 | status = d_revalidate(dentry, nd); |
443 | if (status > 0) | 672 | if (status > 0) |
444 | return 0; | 673 | return 0; |
445 | 674 | ||
@@ -459,26 +688,27 @@ force_reval_path(struct path *path, struct nameidata *nd) | |||
459 | * short-cut DAC fails, then call ->permission() to do more | 688 | * short-cut DAC fails, then call ->permission() to do more |
460 | * complete permission check. | 689 | * complete permission check. |
461 | */ | 690 | */ |
462 | static int exec_permission(struct inode *inode) | 691 | static inline int exec_permission(struct inode *inode, unsigned int flags) |
463 | { | 692 | { |
464 | int ret; | 693 | int ret; |
465 | 694 | ||
466 | if (inode->i_op->permission) { | 695 | if (inode->i_op->permission) { |
467 | ret = inode->i_op->permission(inode, MAY_EXEC); | 696 | ret = inode->i_op->permission(inode, MAY_EXEC, flags); |
468 | if (!ret) | 697 | } else { |
469 | goto ok; | 698 | ret = acl_permission_check(inode, MAY_EXEC, flags, |
470 | return ret; | 699 | inode->i_op->check_acl); |
471 | } | 700 | } |
472 | ret = acl_permission_check(inode, MAY_EXEC, inode->i_op->check_acl); | 701 | if (likely(!ret)) |
473 | if (!ret) | ||
474 | goto ok; | 702 | goto ok; |
703 | if (ret == -ECHILD) | ||
704 | return ret; | ||
475 | 705 | ||
476 | if (capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH)) | 706 | if (capable(CAP_DAC_OVERRIDE) || capable(CAP_DAC_READ_SEARCH)) |
477 | goto ok; | 707 | goto ok; |
478 | 708 | ||
479 | return ret; | 709 | return ret; |
480 | ok: | 710 | ok: |
481 | return security_inode_permission(inode, MAY_EXEC); | 711 | return security_inode_exec_permission(inode, flags); |
482 | } | 712 | } |
483 | 713 | ||
484 | static __always_inline void set_root(struct nameidata *nd) | 714 | static __always_inline void set_root(struct nameidata *nd) |
@@ -489,8 +719,23 @@ static __always_inline void set_root(struct nameidata *nd) | |||
489 | 719 | ||
490 | static int link_path_walk(const char *, struct nameidata *); | 720 | static int link_path_walk(const char *, struct nameidata *); |
491 | 721 | ||
722 | static __always_inline void set_root_rcu(struct nameidata *nd) | ||
723 | { | ||
724 | if (!nd->root.mnt) { | ||
725 | struct fs_struct *fs = current->fs; | ||
726 | unsigned seq; | ||
727 | |||
728 | do { | ||
729 | seq = read_seqcount_begin(&fs->seq); | ||
730 | nd->root = fs->root; | ||
731 | } while (read_seqcount_retry(&fs->seq, seq)); | ||
732 | } | ||
733 | } | ||
734 | |||
492 | static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link) | 735 | static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link) |
493 | { | 736 | { |
737 | int ret; | ||
738 | |||
494 | if (IS_ERR(link)) | 739 | if (IS_ERR(link)) |
495 | goto fail; | 740 | goto fail; |
496 | 741 | ||
@@ -500,8 +745,10 @@ static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *l | |||
500 | nd->path = nd->root; | 745 | nd->path = nd->root; |
501 | path_get(&nd->root); | 746 | path_get(&nd->root); |
502 | } | 747 | } |
748 | nd->inode = nd->path.dentry->d_inode; | ||
503 | 749 | ||
504 | return link_path_walk(link, nd); | 750 | ret = link_path_walk(link, nd); |
751 | return ret; | ||
505 | fail: | 752 | fail: |
506 | path_put(&nd->path); | 753 | path_put(&nd->path); |
507 | return PTR_ERR(link); | 754 | return PTR_ERR(link); |
@@ -516,11 +763,12 @@ static void path_put_conditional(struct path *path, struct nameidata *nd) | |||
516 | 763 | ||
517 | static inline void path_to_nameidata(struct path *path, struct nameidata *nd) | 764 | static inline void path_to_nameidata(struct path *path, struct nameidata *nd) |
518 | { | 765 | { |
519 | dput(nd->path.dentry); | 766 | if (!(nd->flags & LOOKUP_RCU)) { |
520 | if (nd->path.mnt != path->mnt) { | 767 | dput(nd->path.dentry); |
521 | mntput(nd->path.mnt); | 768 | if (nd->path.mnt != path->mnt) |
522 | nd->path.mnt = path->mnt; | 769 | mntput(nd->path.mnt); |
523 | } | 770 | } |
771 | nd->path.mnt = path->mnt; | ||
524 | nd->path.dentry = path->dentry; | 772 | nd->path.dentry = path->dentry; |
525 | } | 773 | } |
526 | 774 | ||
@@ -535,9 +783,11 @@ __do_follow_link(struct path *path, struct nameidata *nd, void **p) | |||
535 | 783 | ||
536 | if (path->mnt != nd->path.mnt) { | 784 | if (path->mnt != nd->path.mnt) { |
537 | path_to_nameidata(path, nd); | 785 | path_to_nameidata(path, nd); |
786 | nd->inode = nd->path.dentry->d_inode; | ||
538 | dget(dentry); | 787 | dget(dentry); |
539 | } | 788 | } |
540 | mntget(path->mnt); | 789 | mntget(path->mnt); |
790 | |||
541 | nd->last_type = LAST_BIND; | 791 | nd->last_type = LAST_BIND; |
542 | *p = dentry->d_inode->i_op->follow_link(dentry, nd); | 792 | *p = dentry->d_inode->i_op->follow_link(dentry, nd); |
543 | error = PTR_ERR(*p); | 793 | error = PTR_ERR(*p); |
@@ -591,6 +841,20 @@ loop: | |||
591 | return err; | 841 | return err; |
592 | } | 842 | } |
593 | 843 | ||
844 | static int follow_up_rcu(struct path *path) | ||
845 | { | ||
846 | struct vfsmount *parent; | ||
847 | struct dentry *mountpoint; | ||
848 | |||
849 | parent = path->mnt->mnt_parent; | ||
850 | if (parent == path->mnt) | ||
851 | return 0; | ||
852 | mountpoint = path->mnt->mnt_mountpoint; | ||
853 | path->dentry = mountpoint; | ||
854 | path->mnt = parent; | ||
855 | return 1; | ||
856 | } | ||
857 | |||
594 | int follow_up(struct path *path) | 858 | int follow_up(struct path *path) |
595 | { | 859 | { |
596 | struct vfsmount *parent; | 860 | struct vfsmount *parent; |
@@ -612,9 +876,24 @@ int follow_up(struct path *path) | |||
612 | return 1; | 876 | return 1; |
613 | } | 877 | } |
614 | 878 | ||
615 | /* no need for dcache_lock, as serialization is taken care in | 879 | /* |
616 | * namespace.c | 880 | * serialization is taken care of in namespace.c |
617 | */ | 881 | */ |
882 | static void __follow_mount_rcu(struct nameidata *nd, struct path *path, | ||
883 | struct inode **inode) | ||
884 | { | ||
885 | while (d_mountpoint(path->dentry)) { | ||
886 | struct vfsmount *mounted; | ||
887 | mounted = __lookup_mnt(path->mnt, path->dentry, 1); | ||
888 | if (!mounted) | ||
889 | return; | ||
890 | path->mnt = mounted; | ||
891 | path->dentry = mounted->mnt_root; | ||
892 | nd->seq = read_seqcount_begin(&path->dentry->d_seq); | ||
893 | *inode = path->dentry->d_inode; | ||
894 | } | ||
895 | } | ||
896 | |||
618 | static int __follow_mount(struct path *path) | 897 | static int __follow_mount(struct path *path) |
619 | { | 898 | { |
620 | int res = 0; | 899 | int res = 0; |
@@ -645,9 +924,6 @@ static void follow_mount(struct path *path) | |||
645 | } | 924 | } |
646 | } | 925 | } |
647 | 926 | ||
648 | /* no need for dcache_lock, as serialization is taken care in | ||
649 | * namespace.c | ||
650 | */ | ||
651 | int follow_down(struct path *path) | 927 | int follow_down(struct path *path) |
652 | { | 928 | { |
653 | struct vfsmount *mounted; | 929 | struct vfsmount *mounted; |
@@ -663,7 +939,42 @@ int follow_down(struct path *path) | |||
663 | return 0; | 939 | return 0; |
664 | } | 940 | } |
665 | 941 | ||
666 | static __always_inline void follow_dotdot(struct nameidata *nd) | 942 | static int follow_dotdot_rcu(struct nameidata *nd) |
943 | { | ||
944 | struct inode *inode = nd->inode; | ||
945 | |||
946 | set_root_rcu(nd); | ||
947 | |||
948 | while(1) { | ||
949 | if (nd->path.dentry == nd->root.dentry && | ||
950 | nd->path.mnt == nd->root.mnt) { | ||
951 | break; | ||
952 | } | ||
953 | if (nd->path.dentry != nd->path.mnt->mnt_root) { | ||
954 | struct dentry *old = nd->path.dentry; | ||
955 | struct dentry *parent = old->d_parent; | ||
956 | unsigned seq; | ||
957 | |||
958 | seq = read_seqcount_begin(&parent->d_seq); | ||
959 | if (read_seqcount_retry(&old->d_seq, nd->seq)) | ||
960 | return -ECHILD; | ||
961 | inode = parent->d_inode; | ||
962 | nd->path.dentry = parent; | ||
963 | nd->seq = seq; | ||
964 | break; | ||
965 | } | ||
966 | if (!follow_up_rcu(&nd->path)) | ||
967 | break; | ||
968 | nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); | ||
969 | inode = nd->path.dentry->d_inode; | ||
970 | } | ||
971 | __follow_mount_rcu(nd, &nd->path, &inode); | ||
972 | nd->inode = inode; | ||
973 | |||
974 | return 0; | ||
975 | } | ||
976 | |||
977 | static void follow_dotdot(struct nameidata *nd) | ||
667 | { | 978 | { |
668 | set_root(nd); | 979 | set_root(nd); |
669 | 980 | ||
@@ -684,6 +995,7 @@ static __always_inline void follow_dotdot(struct nameidata *nd) | |||
684 | break; | 995 | break; |
685 | } | 996 | } |
686 | follow_mount(&nd->path); | 997 | follow_mount(&nd->path); |
998 | nd->inode = nd->path.dentry->d_inode; | ||
687 | } | 999 | } |
688 | 1000 | ||
689 | /* | 1001 | /* |
@@ -721,17 +1033,17 @@ static struct dentry *d_alloc_and_lookup(struct dentry *parent, | |||
721 | * It _is_ time-critical. | 1033 | * It _is_ time-critical. |
722 | */ | 1034 | */ |
723 | static int do_lookup(struct nameidata *nd, struct qstr *name, | 1035 | static int do_lookup(struct nameidata *nd, struct qstr *name, |
724 | struct path *path) | 1036 | struct path *path, struct inode **inode) |
725 | { | 1037 | { |
726 | struct vfsmount *mnt = nd->path.mnt; | 1038 | struct vfsmount *mnt = nd->path.mnt; |
727 | struct dentry *dentry, *parent; | 1039 | struct dentry *dentry, *parent = nd->path.dentry; |
728 | struct inode *dir; | 1040 | struct inode *dir; |
729 | /* | 1041 | /* |
730 | * See if the low-level filesystem might want | 1042 | * See if the low-level filesystem might want |
731 | * to use its own hash.. | 1043 | * to use its own hash.. |
732 | */ | 1044 | */ |
733 | if (nd->path.dentry->d_op && nd->path.dentry->d_op->d_hash) { | 1045 | if (unlikely(parent->d_flags & DCACHE_OP_HASH)) { |
734 | int err = nd->path.dentry->d_op->d_hash(nd->path.dentry, name); | 1046 | int err = parent->d_op->d_hash(parent, nd->inode, name); |
735 | if (err < 0) | 1047 | if (err < 0) |
736 | return err; | 1048 | return err; |
737 | } | 1049 | } |
@@ -741,21 +1053,44 @@ static int do_lookup(struct nameidata *nd, struct qstr *name, | |||
741 | * of a false negative due to a concurrent rename, we're going to | 1053 | * of a false negative due to a concurrent rename, we're going to |
742 | * do the non-racy lookup, below. | 1054 | * do the non-racy lookup, below. |
743 | */ | 1055 | */ |
744 | dentry = __d_lookup(nd->path.dentry, name); | 1056 | if (nd->flags & LOOKUP_RCU) { |
745 | if (!dentry) | 1057 | unsigned seq; |
746 | goto need_lookup; | 1058 | |
1059 | *inode = nd->inode; | ||
1060 | dentry = __d_lookup_rcu(parent, name, &seq, inode); | ||
1061 | if (!dentry) { | ||
1062 | if (nameidata_drop_rcu(nd)) | ||
1063 | return -ECHILD; | ||
1064 | goto need_lookup; | ||
1065 | } | ||
1066 | /* Memory barrier in read_seqcount_begin of child is enough */ | ||
1067 | if (__read_seqcount_retry(&parent->d_seq, nd->seq)) | ||
1068 | return -ECHILD; | ||
1069 | |||
1070 | nd->seq = seq; | ||
1071 | if (dentry->d_flags & DCACHE_OP_REVALIDATE) | ||
1072 | goto need_revalidate; | ||
1073 | path->mnt = mnt; | ||
1074 | path->dentry = dentry; | ||
1075 | __follow_mount_rcu(nd, path, inode); | ||
1076 | } else { | ||
1077 | dentry = __d_lookup(parent, name); | ||
1078 | if (!dentry) | ||
1079 | goto need_lookup; | ||
747 | found: | 1080 | found: |
748 | if (dentry->d_op && dentry->d_op->d_revalidate) | 1081 | if (dentry->d_flags & DCACHE_OP_REVALIDATE) |
749 | goto need_revalidate; | 1082 | goto need_revalidate; |
750 | done: | 1083 | done: |
751 | path->mnt = mnt; | 1084 | path->mnt = mnt; |
752 | path->dentry = dentry; | 1085 | path->dentry = dentry; |
753 | __follow_mount(path); | 1086 | __follow_mount(path); |
1087 | *inode = path->dentry->d_inode; | ||
1088 | } | ||
754 | return 0; | 1089 | return 0; |
755 | 1090 | ||
756 | need_lookup: | 1091 | need_lookup: |
757 | parent = nd->path.dentry; | ||
758 | dir = parent->d_inode; | 1092 | dir = parent->d_inode; |
1093 | BUG_ON(nd->inode != dir); | ||
759 | 1094 | ||
760 | mutex_lock(&dir->i_mutex); | 1095 | mutex_lock(&dir->i_mutex); |
761 | /* | 1096 | /* |
@@ -817,7 +1152,6 @@ static inline int follow_on_final(struct inode *inode, unsigned lookup_flags) | |||
817 | static int link_path_walk(const char *name, struct nameidata *nd) | 1152 | static int link_path_walk(const char *name, struct nameidata *nd) |
818 | { | 1153 | { |
819 | struct path next; | 1154 | struct path next; |
820 | struct inode *inode; | ||
821 | int err; | 1155 | int err; |
822 | unsigned int lookup_flags = nd->flags; | 1156 | unsigned int lookup_flags = nd->flags; |
823 | 1157 | ||
@@ -826,18 +1160,28 @@ static int link_path_walk(const char *name, struct nameidata *nd) | |||
826 | if (!*name) | 1160 | if (!*name) |
827 | goto return_reval; | 1161 | goto return_reval; |
828 | 1162 | ||
829 | inode = nd->path.dentry->d_inode; | ||
830 | if (nd->depth) | 1163 | if (nd->depth) |
831 | lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE); | 1164 | lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE); |
832 | 1165 | ||
833 | /* At this point we know we have a real path component. */ | 1166 | /* At this point we know we have a real path component. */ |
834 | for(;;) { | 1167 | for(;;) { |
1168 | struct inode *inode; | ||
835 | unsigned long hash; | 1169 | unsigned long hash; |
836 | struct qstr this; | 1170 | struct qstr this; |
837 | unsigned int c; | 1171 | unsigned int c; |
838 | 1172 | ||
839 | nd->flags |= LOOKUP_CONTINUE; | 1173 | nd->flags |= LOOKUP_CONTINUE; |
840 | err = exec_permission(inode); | 1174 | if (nd->flags & LOOKUP_RCU) { |
1175 | err = exec_permission(nd->inode, IPERM_FLAG_RCU); | ||
1176 | if (err == -ECHILD) { | ||
1177 | if (nameidata_drop_rcu(nd)) | ||
1178 | return -ECHILD; | ||
1179 | goto exec_again; | ||
1180 | } | ||
1181 | } else { | ||
1182 | exec_again: | ||
1183 | err = exec_permission(nd->inode, 0); | ||
1184 | } | ||
841 | if (err) | 1185 | if (err) |
842 | break; | 1186 | break; |
843 | 1187 | ||
@@ -868,37 +1212,44 @@ static int link_path_walk(const char *name, struct nameidata *nd) | |||
868 | if (this.name[0] == '.') switch (this.len) { | 1212 | if (this.name[0] == '.') switch (this.len) { |
869 | default: | 1213 | default: |
870 | break; | 1214 | break; |
871 | case 2: | 1215 | case 2: |
872 | if (this.name[1] != '.') | 1216 | if (this.name[1] != '.') |
873 | break; | 1217 | break; |
874 | follow_dotdot(nd); | 1218 | if (nd->flags & LOOKUP_RCU) { |
875 | inode = nd->path.dentry->d_inode; | 1219 | if (follow_dotdot_rcu(nd)) |
1220 | return -ECHILD; | ||
1221 | } else | ||
1222 | follow_dotdot(nd); | ||
876 | /* fallthrough */ | 1223 | /* fallthrough */ |
877 | case 1: | 1224 | case 1: |
878 | continue; | 1225 | continue; |
879 | } | 1226 | } |
880 | /* This does the actual lookups.. */ | 1227 | /* This does the actual lookups.. */ |
881 | err = do_lookup(nd, &this, &next); | 1228 | err = do_lookup(nd, &this, &next, &inode); |
882 | if (err) | 1229 | if (err) |
883 | break; | 1230 | break; |
884 | |||
885 | err = -ENOENT; | 1231 | err = -ENOENT; |
886 | inode = next.dentry->d_inode; | ||
887 | if (!inode) | 1232 | if (!inode) |
888 | goto out_dput; | 1233 | goto out_dput; |
889 | 1234 | ||
890 | if (inode->i_op->follow_link) { | 1235 | if (inode->i_op->follow_link) { |
1236 | /* We commonly drop rcu-walk here */ | ||
1237 | if (nameidata_dentry_drop_rcu_maybe(nd, next.dentry)) | ||
1238 | return -ECHILD; | ||
1239 | BUG_ON(inode != next.dentry->d_inode); | ||
891 | err = do_follow_link(&next, nd); | 1240 | err = do_follow_link(&next, nd); |
892 | if (err) | 1241 | if (err) |
893 | goto return_err; | 1242 | goto return_err; |
1243 | nd->inode = nd->path.dentry->d_inode; | ||
894 | err = -ENOENT; | 1244 | err = -ENOENT; |
895 | inode = nd->path.dentry->d_inode; | 1245 | if (!nd->inode) |
896 | if (!inode) | ||
897 | break; | 1246 | break; |
898 | } else | 1247 | } else { |
899 | path_to_nameidata(&next, nd); | 1248 | path_to_nameidata(&next, nd); |
1249 | nd->inode = inode; | ||
1250 | } | ||
900 | err = -ENOTDIR; | 1251 | err = -ENOTDIR; |
901 | if (!inode->i_op->lookup) | 1252 | if (!nd->inode->i_op->lookup) |
902 | break; | 1253 | break; |
903 | continue; | 1254 | continue; |
904 | /* here ends the main loop */ | 1255 | /* here ends the main loop */ |
@@ -913,32 +1264,39 @@ last_component: | |||
913 | if (this.name[0] == '.') switch (this.len) { | 1264 | if (this.name[0] == '.') switch (this.len) { |
914 | default: | 1265 | default: |
915 | break; | 1266 | break; |
916 | case 2: | 1267 | case 2: |
917 | if (this.name[1] != '.') | 1268 | if (this.name[1] != '.') |
918 | break; | 1269 | break; |
919 | follow_dotdot(nd); | 1270 | if (nd->flags & LOOKUP_RCU) { |
920 | inode = nd->path.dentry->d_inode; | 1271 | if (follow_dotdot_rcu(nd)) |
1272 | return -ECHILD; | ||
1273 | } else | ||
1274 | follow_dotdot(nd); | ||
921 | /* fallthrough */ | 1275 | /* fallthrough */ |
922 | case 1: | 1276 | case 1: |
923 | goto return_reval; | 1277 | goto return_reval; |
924 | } | 1278 | } |
925 | err = do_lookup(nd, &this, &next); | 1279 | err = do_lookup(nd, &this, &next, &inode); |
926 | if (err) | 1280 | if (err) |
927 | break; | 1281 | break; |
928 | inode = next.dentry->d_inode; | ||
929 | if (follow_on_final(inode, lookup_flags)) { | 1282 | if (follow_on_final(inode, lookup_flags)) { |
1283 | if (nameidata_dentry_drop_rcu_maybe(nd, next.dentry)) | ||
1284 | return -ECHILD; | ||
1285 | BUG_ON(inode != next.dentry->d_inode); | ||
930 | err = do_follow_link(&next, nd); | 1286 | err = do_follow_link(&next, nd); |
931 | if (err) | 1287 | if (err) |
932 | goto return_err; | 1288 | goto return_err; |
933 | inode = nd->path.dentry->d_inode; | 1289 | nd->inode = nd->path.dentry->d_inode; |
934 | } else | 1290 | } else { |
935 | path_to_nameidata(&next, nd); | 1291 | path_to_nameidata(&next, nd); |
1292 | nd->inode = inode; | ||
1293 | } | ||
936 | err = -ENOENT; | 1294 | err = -ENOENT; |
937 | if (!inode) | 1295 | if (!nd->inode) |
938 | break; | 1296 | break; |
939 | if (lookup_flags & LOOKUP_DIRECTORY) { | 1297 | if (lookup_flags & LOOKUP_DIRECTORY) { |
940 | err = -ENOTDIR; | 1298 | err = -ENOTDIR; |
941 | if (!inode->i_op->lookup) | 1299 | if (!nd->inode->i_op->lookup) |
942 | break; | 1300 | break; |
943 | } | 1301 | } |
944 | goto return_base; | 1302 | goto return_base; |
@@ -958,25 +1316,43 @@ return_reval: | |||
958 | * We bypassed the ordinary revalidation routines. | 1316 | * We bypassed the ordinary revalidation routines. |
959 | * We may need to check the cached dentry for staleness. | 1317 | * We may need to check the cached dentry for staleness. |
960 | */ | 1318 | */ |
961 | if (nd->path.dentry && nd->path.dentry->d_sb && | 1319 | if (need_reval_dot(nd->path.dentry)) { |
962 | (nd->path.dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)) { | ||
963 | err = -ESTALE; | ||
964 | /* Note: we do not d_invalidate() */ | 1320 | /* Note: we do not d_invalidate() */ |
965 | if (!nd->path.dentry->d_op->d_revalidate( | 1321 | err = d_revalidate(nd->path.dentry, nd); |
966 | nd->path.dentry, nd)) | 1322 | if (!err) |
1323 | err = -ESTALE; | ||
1324 | if (err < 0) | ||
967 | break; | 1325 | break; |
968 | } | 1326 | } |
969 | return_base: | 1327 | return_base: |
1328 | if (nameidata_drop_rcu_last_maybe(nd)) | ||
1329 | return -ECHILD; | ||
970 | return 0; | 1330 | return 0; |
971 | out_dput: | 1331 | out_dput: |
972 | path_put_conditional(&next, nd); | 1332 | if (!(nd->flags & LOOKUP_RCU)) |
1333 | path_put_conditional(&next, nd); | ||
973 | break; | 1334 | break; |
974 | } | 1335 | } |
975 | path_put(&nd->path); | 1336 | if (!(nd->flags & LOOKUP_RCU)) |
1337 | path_put(&nd->path); | ||
976 | return_err: | 1338 | return_err: |
977 | return err; | 1339 | return err; |
978 | } | 1340 | } |
979 | 1341 | ||
1342 | static inline int path_walk_rcu(const char *name, struct nameidata *nd) | ||
1343 | { | ||
1344 | current->total_link_count = 0; | ||
1345 | |||
1346 | return link_path_walk(name, nd); | ||
1347 | } | ||
1348 | |||
1349 | static inline int path_walk_simple(const char *name, struct nameidata *nd) | ||
1350 | { | ||
1351 | current->total_link_count = 0; | ||
1352 | |||
1353 | return link_path_walk(name, nd); | ||
1354 | } | ||
1355 | |||
980 | static int path_walk(const char *name, struct nameidata *nd) | 1356 | static int path_walk(const char *name, struct nameidata *nd) |
981 | { | 1357 | { |
982 | struct path save = nd->path; | 1358 | struct path save = nd->path; |
@@ -1002,6 +1378,93 @@ static int path_walk(const char *name, struct nameidata *nd) | |||
1002 | return result; | 1378 | return result; |
1003 | } | 1379 | } |
1004 | 1380 | ||
1381 | static void path_finish_rcu(struct nameidata *nd) | ||
1382 | { | ||
1383 | if (nd->flags & LOOKUP_RCU) { | ||
1384 | /* RCU dangling. Cancel it. */ | ||
1385 | nd->flags &= ~LOOKUP_RCU; | ||
1386 | nd->root.mnt = NULL; | ||
1387 | rcu_read_unlock(); | ||
1388 | br_read_unlock(vfsmount_lock); | ||
1389 | } | ||
1390 | if (nd->file) | ||
1391 | fput(nd->file); | ||
1392 | } | ||
1393 | |||
1394 | static int path_init_rcu(int dfd, const char *name, unsigned int flags, struct nameidata *nd) | ||
1395 | { | ||
1396 | int retval = 0; | ||
1397 | int fput_needed; | ||
1398 | struct file *file; | ||
1399 | |||
1400 | nd->last_type = LAST_ROOT; /* if there are only slashes... */ | ||
1401 | nd->flags = flags | LOOKUP_RCU; | ||
1402 | nd->depth = 0; | ||
1403 | nd->root.mnt = NULL; | ||
1404 | nd->file = NULL; | ||
1405 | |||
1406 | if (*name=='/') { | ||
1407 | struct fs_struct *fs = current->fs; | ||
1408 | unsigned seq; | ||
1409 | |||
1410 | br_read_lock(vfsmount_lock); | ||
1411 | rcu_read_lock(); | ||
1412 | |||
1413 | do { | ||
1414 | seq = read_seqcount_begin(&fs->seq); | ||
1415 | nd->root = fs->root; | ||
1416 | nd->path = nd->root; | ||
1417 | nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); | ||
1418 | } while (read_seqcount_retry(&fs->seq, seq)); | ||
1419 | |||
1420 | } else if (dfd == AT_FDCWD) { | ||
1421 | struct fs_struct *fs = current->fs; | ||
1422 | unsigned seq; | ||
1423 | |||
1424 | br_read_lock(vfsmount_lock); | ||
1425 | rcu_read_lock(); | ||
1426 | |||
1427 | do { | ||
1428 | seq = read_seqcount_begin(&fs->seq); | ||
1429 | nd->path = fs->pwd; | ||
1430 | nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); | ||
1431 | } while (read_seqcount_retry(&fs->seq, seq)); | ||
1432 | |||
1433 | } else { | ||
1434 | struct dentry *dentry; | ||
1435 | |||
1436 | file = fget_light(dfd, &fput_needed); | ||
1437 | retval = -EBADF; | ||
1438 | if (!file) | ||
1439 | goto out_fail; | ||
1440 | |||
1441 | dentry = file->f_path.dentry; | ||
1442 | |||
1443 | retval = -ENOTDIR; | ||
1444 | if (!S_ISDIR(dentry->d_inode->i_mode)) | ||
1445 | goto fput_fail; | ||
1446 | |||
1447 | retval = file_permission(file, MAY_EXEC); | ||
1448 | if (retval) | ||
1449 | goto fput_fail; | ||
1450 | |||
1451 | nd->path = file->f_path; | ||
1452 | if (fput_needed) | ||
1453 | nd->file = file; | ||
1454 | |||
1455 | nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); | ||
1456 | br_read_lock(vfsmount_lock); | ||
1457 | rcu_read_lock(); | ||
1458 | } | ||
1459 | nd->inode = nd->path.dentry->d_inode; | ||
1460 | return 0; | ||
1461 | |||
1462 | fput_fail: | ||
1463 | fput_light(file, fput_needed); | ||
1464 | out_fail: | ||
1465 | return retval; | ||
1466 | } | ||
1467 | |||
1005 | static int path_init(int dfd, const char *name, unsigned int flags, struct nameidata *nd) | 1468 | static int path_init(int dfd, const char *name, unsigned int flags, struct nameidata *nd) |
1006 | { | 1469 | { |
1007 | int retval = 0; | 1470 | int retval = 0; |
@@ -1042,6 +1505,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, struct namei | |||
1042 | 1505 | ||
1043 | fput_light(file, fput_needed); | 1506 | fput_light(file, fput_needed); |
1044 | } | 1507 | } |
1508 | nd->inode = nd->path.dentry->d_inode; | ||
1045 | return 0; | 1509 | return 0; |
1046 | 1510 | ||
1047 | fput_fail: | 1511 | fput_fail: |
@@ -1054,16 +1518,53 @@ out_fail: | |||
1054 | static int do_path_lookup(int dfd, const char *name, | 1518 | static int do_path_lookup(int dfd, const char *name, |
1055 | unsigned int flags, struct nameidata *nd) | 1519 | unsigned int flags, struct nameidata *nd) |
1056 | { | 1520 | { |
1057 | int retval = path_init(dfd, name, flags, nd); | 1521 | int retval; |
1058 | if (!retval) | 1522 | |
1059 | retval = path_walk(name, nd); | 1523 | /* |
1060 | if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry && | 1524 | * Path walking is largely split up into 2 different synchronisation |
1061 | nd->path.dentry->d_inode)) | 1525 | * schemes, rcu-walk and ref-walk (explained in |
1062 | audit_inode(name, nd->path.dentry); | 1526 | * Documentation/filesystems/path-lookup.txt). These share much of the |
1527 | * path walk code, but some things particularly setup, cleanup, and | ||
1528 | * following mounts are sufficiently divergent that functions are | ||
1529 | * duplicated. Typically there is a function foo(), and its RCU | ||
1530 | * analogue, foo_rcu(). | ||
1531 | * | ||
1532 | * -ECHILD is the error number of choice (just to avoid clashes) that | ||
1533 | * is returned if some aspect of an rcu-walk fails. Such an error must | ||
1534 | * be handled by restarting a traditional ref-walk (which will always | ||
1535 | * be able to complete). | ||
1536 | */ | ||
1537 | retval = path_init_rcu(dfd, name, flags, nd); | ||
1538 | if (unlikely(retval)) | ||
1539 | return retval; | ||
1540 | retval = path_walk_rcu(name, nd); | ||
1541 | path_finish_rcu(nd); | ||
1063 | if (nd->root.mnt) { | 1542 | if (nd->root.mnt) { |
1064 | path_put(&nd->root); | 1543 | path_put(&nd->root); |
1065 | nd->root.mnt = NULL; | 1544 | nd->root.mnt = NULL; |
1066 | } | 1545 | } |
1546 | |||
1547 | if (unlikely(retval == -ECHILD || retval == -ESTALE)) { | ||
1548 | /* slower, locked walk */ | ||
1549 | if (retval == -ESTALE) | ||
1550 | flags |= LOOKUP_REVAL; | ||
1551 | retval = path_init(dfd, name, flags, nd); | ||
1552 | if (unlikely(retval)) | ||
1553 | return retval; | ||
1554 | retval = path_walk(name, nd); | ||
1555 | if (nd->root.mnt) { | ||
1556 | path_put(&nd->root); | ||
1557 | nd->root.mnt = NULL; | ||
1558 | } | ||
1559 | } | ||
1560 | |||
1561 | if (likely(!retval)) { | ||
1562 | if (unlikely(!audit_dummy_context())) { | ||
1563 | if (nd->path.dentry && nd->inode) | ||
1564 | audit_inode(name, nd->path.dentry); | ||
1565 | } | ||
1566 | } | ||
1567 | |||
1067 | return retval; | 1568 | return retval; |
1068 | } | 1569 | } |
1069 | 1570 | ||
@@ -1106,10 +1607,11 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, | |||
1106 | path_get(&nd->path); | 1607 | path_get(&nd->path); |
1107 | nd->root = nd->path; | 1608 | nd->root = nd->path; |
1108 | path_get(&nd->root); | 1609 | path_get(&nd->root); |
1610 | nd->inode = nd->path.dentry->d_inode; | ||
1109 | 1611 | ||
1110 | retval = path_walk(name, nd); | 1612 | retval = path_walk(name, nd); |
1111 | if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry && | 1613 | if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry && |
1112 | nd->path.dentry->d_inode)) | 1614 | nd->inode)) |
1113 | audit_inode(name, nd->path.dentry); | 1615 | audit_inode(name, nd->path.dentry); |
1114 | 1616 | ||
1115 | path_put(&nd->root); | 1617 | path_put(&nd->root); |
@@ -1125,7 +1627,7 @@ static struct dentry *__lookup_hash(struct qstr *name, | |||
1125 | struct dentry *dentry; | 1627 | struct dentry *dentry; |
1126 | int err; | 1628 | int err; |
1127 | 1629 | ||
1128 | err = exec_permission(inode); | 1630 | err = exec_permission(inode, 0); |
1129 | if (err) | 1631 | if (err) |
1130 | return ERR_PTR(err); | 1632 | return ERR_PTR(err); |
1131 | 1633 | ||
@@ -1133,8 +1635,8 @@ static struct dentry *__lookup_hash(struct qstr *name, | |||
1133 | * See if the low-level filesystem might want | 1635 | * See if the low-level filesystem might want |
1134 | * to use its own hash.. | 1636 | * to use its own hash.. |
1135 | */ | 1637 | */ |
1136 | if (base->d_op && base->d_op->d_hash) { | 1638 | if (base->d_flags & DCACHE_OP_HASH) { |
1137 | err = base->d_op->d_hash(base, name); | 1639 | err = base->d_op->d_hash(base, inode, name); |
1138 | dentry = ERR_PTR(err); | 1640 | dentry = ERR_PTR(err); |
1139 | if (err < 0) | 1641 | if (err < 0) |
1140 | goto out; | 1642 | goto out; |
@@ -1147,7 +1649,7 @@ static struct dentry *__lookup_hash(struct qstr *name, | |||
1147 | */ | 1649 | */ |
1148 | dentry = d_lookup(base, name); | 1650 | dentry = d_lookup(base, name); |
1149 | 1651 | ||
1150 | if (dentry && dentry->d_op && dentry->d_op->d_revalidate) | 1652 | if (dentry && (dentry->d_flags & DCACHE_OP_REVALIDATE)) |
1151 | dentry = do_revalidate(dentry, nd); | 1653 | dentry = do_revalidate(dentry, nd); |
1152 | 1654 | ||
1153 | if (!dentry) | 1655 | if (!dentry) |
@@ -1490,6 +1992,7 @@ out_unlock: | |||
1490 | mutex_unlock(&dir->d_inode->i_mutex); | 1992 | mutex_unlock(&dir->d_inode->i_mutex); |
1491 | dput(nd->path.dentry); | 1993 | dput(nd->path.dentry); |
1492 | nd->path.dentry = path->dentry; | 1994 | nd->path.dentry = path->dentry; |
1995 | |||
1493 | if (error) | 1996 | if (error) |
1494 | return error; | 1997 | return error; |
1495 | /* Don't check for write permission, don't truncate */ | 1998 | /* Don't check for write permission, don't truncate */ |
@@ -1584,6 +2087,9 @@ exit: | |||
1584 | return ERR_PTR(error); | 2087 | return ERR_PTR(error); |
1585 | } | 2088 | } |
1586 | 2089 | ||
2090 | /* | ||
2091 | * Handle O_CREAT case for do_filp_open | ||
2092 | */ | ||
1587 | static struct file *do_last(struct nameidata *nd, struct path *path, | 2093 | static struct file *do_last(struct nameidata *nd, struct path *path, |
1588 | int open_flag, int acc_mode, | 2094 | int open_flag, int acc_mode, |
1589 | int mode, const char *pathname) | 2095 | int mode, const char *pathname) |
@@ -1597,50 +2103,25 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
1597 | follow_dotdot(nd); | 2103 | follow_dotdot(nd); |
1598 | dir = nd->path.dentry; | 2104 | dir = nd->path.dentry; |
1599 | case LAST_DOT: | 2105 | case LAST_DOT: |
1600 | if (nd->path.mnt->mnt_sb->s_type->fs_flags & FS_REVAL_DOT) { | 2106 | if (need_reval_dot(dir)) { |
1601 | if (!dir->d_op->d_revalidate(dir, nd)) { | 2107 | error = d_revalidate(nd->path.dentry, nd); |
2108 | if (!error) | ||
1602 | error = -ESTALE; | 2109 | error = -ESTALE; |
2110 | if (error < 0) | ||
1603 | goto exit; | 2111 | goto exit; |
1604 | } | ||
1605 | } | 2112 | } |
1606 | /* fallthrough */ | 2113 | /* fallthrough */ |
1607 | case LAST_ROOT: | 2114 | case LAST_ROOT: |
1608 | if (open_flag & O_CREAT) | 2115 | goto exit; |
1609 | goto exit; | ||
1610 | /* fallthrough */ | ||
1611 | case LAST_BIND: | 2116 | case LAST_BIND: |
1612 | audit_inode(pathname, dir); | 2117 | audit_inode(pathname, dir); |
1613 | goto ok; | 2118 | goto ok; |
1614 | } | 2119 | } |
1615 | 2120 | ||
1616 | /* trailing slashes? */ | 2121 | /* trailing slashes? */ |
1617 | if (nd->last.name[nd->last.len]) { | 2122 | if (nd->last.name[nd->last.len]) |
1618 | if (open_flag & O_CREAT) | 2123 | goto exit; |
1619 | goto exit; | ||
1620 | nd->flags |= LOOKUP_DIRECTORY | LOOKUP_FOLLOW; | ||
1621 | } | ||
1622 | |||
1623 | /* just plain open? */ | ||
1624 | if (!(open_flag & O_CREAT)) { | ||
1625 | error = do_lookup(nd, &nd->last, path); | ||
1626 | if (error) | ||
1627 | goto exit; | ||
1628 | error = -ENOENT; | ||
1629 | if (!path->dentry->d_inode) | ||
1630 | goto exit_dput; | ||
1631 | if (path->dentry->d_inode->i_op->follow_link) | ||
1632 | return NULL; | ||
1633 | error = -ENOTDIR; | ||
1634 | if (nd->flags & LOOKUP_DIRECTORY) { | ||
1635 | if (!path->dentry->d_inode->i_op->lookup) | ||
1636 | goto exit_dput; | ||
1637 | } | ||
1638 | path_to_nameidata(path, nd); | ||
1639 | audit_inode(pathname, nd->path.dentry); | ||
1640 | goto ok; | ||
1641 | } | ||
1642 | 2124 | ||
1643 | /* OK, it's O_CREAT */ | ||
1644 | mutex_lock(&dir->d_inode->i_mutex); | 2125 | mutex_lock(&dir->d_inode->i_mutex); |
1645 | 2126 | ||
1646 | path->dentry = lookup_hash(nd); | 2127 | path->dentry = lookup_hash(nd); |
@@ -1711,8 +2192,9 @@ static struct file *do_last(struct nameidata *nd, struct path *path, | |||
1711 | return NULL; | 2192 | return NULL; |
1712 | 2193 | ||
1713 | path_to_nameidata(path, nd); | 2194 | path_to_nameidata(path, nd); |
2195 | nd->inode = path->dentry->d_inode; | ||
1714 | error = -EISDIR; | 2196 | error = -EISDIR; |
1715 | if (S_ISDIR(path->dentry->d_inode->i_mode)) | 2197 | if (S_ISDIR(nd->inode->i_mode)) |
1716 | goto exit; | 2198 | goto exit; |
1717 | ok: | 2199 | ok: |
1718 | filp = finish_open(nd, open_flag, acc_mode); | 2200 | filp = finish_open(nd, open_flag, acc_mode); |
@@ -1743,11 +2225,14 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
1743 | struct path path; | 2225 | struct path path; |
1744 | int count = 0; | 2226 | int count = 0; |
1745 | int flag = open_to_namei_flags(open_flag); | 2227 | int flag = open_to_namei_flags(open_flag); |
1746 | int force_reval = 0; | 2228 | int flags; |
1747 | 2229 | ||
1748 | if (!(open_flag & O_CREAT)) | 2230 | if (!(open_flag & O_CREAT)) |
1749 | mode = 0; | 2231 | mode = 0; |
1750 | 2232 | ||
2233 | /* Must never be set by userspace */ | ||
2234 | open_flag &= ~FMODE_NONOTIFY; | ||
2235 | |||
1751 | /* | 2236 | /* |
1752 | * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only | 2237 | * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only |
1753 | * check for O_DSYNC if the need any syncing at all we enforce it's | 2238 | * check for O_DSYNC if the need any syncing at all we enforce it's |
@@ -1769,54 +2254,84 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
1769 | if (open_flag & O_APPEND) | 2254 | if (open_flag & O_APPEND) |
1770 | acc_mode |= MAY_APPEND; | 2255 | acc_mode |= MAY_APPEND; |
1771 | 2256 | ||
1772 | /* find the parent */ | 2257 | flags = LOOKUP_OPEN; |
1773 | reval: | 2258 | if (open_flag & O_CREAT) { |
1774 | error = path_init(dfd, pathname, LOOKUP_PARENT, &nd); | 2259 | flags |= LOOKUP_CREATE; |
2260 | if (open_flag & O_EXCL) | ||
2261 | flags |= LOOKUP_EXCL; | ||
2262 | } | ||
2263 | if (open_flag & O_DIRECTORY) | ||
2264 | flags |= LOOKUP_DIRECTORY; | ||
2265 | if (!(open_flag & O_NOFOLLOW)) | ||
2266 | flags |= LOOKUP_FOLLOW; | ||
2267 | |||
2268 | filp = get_empty_filp(); | ||
2269 | if (!filp) | ||
2270 | return ERR_PTR(-ENFILE); | ||
2271 | |||
2272 | filp->f_flags = open_flag; | ||
2273 | nd.intent.open.file = filp; | ||
2274 | nd.intent.open.flags = flag; | ||
2275 | nd.intent.open.create_mode = mode; | ||
2276 | |||
2277 | if (open_flag & O_CREAT) | ||
2278 | goto creat; | ||
2279 | |||
2280 | /* !O_CREAT, simple open */ | ||
2281 | error = do_path_lookup(dfd, pathname, flags, &nd); | ||
2282 | if (unlikely(error)) | ||
2283 | goto out_filp; | ||
2284 | error = -ELOOP; | ||
2285 | if (!(nd.flags & LOOKUP_FOLLOW)) { | ||
2286 | if (nd.inode->i_op->follow_link) | ||
2287 | goto out_path; | ||
2288 | } | ||
2289 | error = -ENOTDIR; | ||
2290 | if (nd.flags & LOOKUP_DIRECTORY) { | ||
2291 | if (!nd.inode->i_op->lookup) | ||
2292 | goto out_path; | ||
2293 | } | ||
2294 | audit_inode(pathname, nd.path.dentry); | ||
2295 | filp = finish_open(&nd, open_flag, acc_mode); | ||
2296 | return filp; | ||
2297 | |||
2298 | creat: | ||
2299 | /* OK, have to create the file. Find the parent. */ | ||
2300 | error = path_init_rcu(dfd, pathname, | ||
2301 | LOOKUP_PARENT | (flags & LOOKUP_REVAL), &nd); | ||
1775 | if (error) | 2302 | if (error) |
1776 | return ERR_PTR(error); | 2303 | goto out_filp; |
1777 | if (force_reval) | 2304 | error = path_walk_rcu(pathname, &nd); |
1778 | nd.flags |= LOOKUP_REVAL; | 2305 | path_finish_rcu(&nd); |
2306 | if (unlikely(error == -ECHILD || error == -ESTALE)) { | ||
2307 | /* slower, locked walk */ | ||
2308 | if (error == -ESTALE) { | ||
2309 | reval: | ||
2310 | flags |= LOOKUP_REVAL; | ||
2311 | } | ||
2312 | error = path_init(dfd, pathname, | ||
2313 | LOOKUP_PARENT | (flags & LOOKUP_REVAL), &nd); | ||
2314 | if (error) | ||
2315 | goto out_filp; | ||
1779 | 2316 | ||
1780 | current->total_link_count = 0; | 2317 | error = path_walk_simple(pathname, &nd); |
1781 | error = link_path_walk(pathname, &nd); | ||
1782 | if (error) { | ||
1783 | filp = ERR_PTR(error); | ||
1784 | goto out; | ||
1785 | } | 2318 | } |
1786 | if (unlikely(!audit_dummy_context()) && (open_flag & O_CREAT)) | 2319 | if (unlikely(error)) |
2320 | goto out_filp; | ||
2321 | if (unlikely(!audit_dummy_context())) | ||
1787 | audit_inode(pathname, nd.path.dentry); | 2322 | audit_inode(pathname, nd.path.dentry); |
1788 | 2323 | ||
1789 | /* | 2324 | /* |
1790 | * We have the parent and last component. | 2325 | * We have the parent and last component. |
1791 | */ | 2326 | */ |
1792 | 2327 | nd.flags = flags; | |
1793 | error = -ENFILE; | ||
1794 | filp = get_empty_filp(); | ||
1795 | if (filp == NULL) | ||
1796 | goto exit_parent; | ||
1797 | nd.intent.open.file = filp; | ||
1798 | filp->f_flags = open_flag; | ||
1799 | nd.intent.open.flags = flag; | ||
1800 | nd.intent.open.create_mode = mode; | ||
1801 | nd.flags &= ~LOOKUP_PARENT; | ||
1802 | nd.flags |= LOOKUP_OPEN; | ||
1803 | if (open_flag & O_CREAT) { | ||
1804 | nd.flags |= LOOKUP_CREATE; | ||
1805 | if (open_flag & O_EXCL) | ||
1806 | nd.flags |= LOOKUP_EXCL; | ||
1807 | } | ||
1808 | if (open_flag & O_DIRECTORY) | ||
1809 | nd.flags |= LOOKUP_DIRECTORY; | ||
1810 | if (!(open_flag & O_NOFOLLOW)) | ||
1811 | nd.flags |= LOOKUP_FOLLOW; | ||
1812 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); | 2328 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); |
1813 | while (unlikely(!filp)) { /* trailing symlink */ | 2329 | while (unlikely(!filp)) { /* trailing symlink */ |
1814 | struct path holder; | 2330 | struct path holder; |
1815 | struct inode *inode = path.dentry->d_inode; | ||
1816 | void *cookie; | 2331 | void *cookie; |
1817 | error = -ELOOP; | 2332 | error = -ELOOP; |
1818 | /* S_ISDIR part is a temporary automount kludge */ | 2333 | /* S_ISDIR part is a temporary automount kludge */ |
1819 | if (!(nd.flags & LOOKUP_FOLLOW) && !S_ISDIR(inode->i_mode)) | 2334 | if (!(nd.flags & LOOKUP_FOLLOW) && !S_ISDIR(nd.inode->i_mode)) |
1820 | goto exit_dput; | 2335 | goto exit_dput; |
1821 | if (count++ == 32) | 2336 | if (count++ == 32) |
1822 | goto exit_dput; | 2337 | goto exit_dput; |
@@ -1837,36 +2352,33 @@ reval: | |||
1837 | goto exit_dput; | 2352 | goto exit_dput; |
1838 | error = __do_follow_link(&path, &nd, &cookie); | 2353 | error = __do_follow_link(&path, &nd, &cookie); |
1839 | if (unlikely(error)) { | 2354 | if (unlikely(error)) { |
2355 | if (!IS_ERR(cookie) && nd.inode->i_op->put_link) | ||
2356 | nd.inode->i_op->put_link(path.dentry, &nd, cookie); | ||
1840 | /* nd.path had been dropped */ | 2357 | /* nd.path had been dropped */ |
1841 | if (!IS_ERR(cookie) && inode->i_op->put_link) | 2358 | nd.path = path; |
1842 | inode->i_op->put_link(path.dentry, &nd, cookie); | 2359 | goto out_path; |
1843 | path_put(&path); | ||
1844 | release_open_intent(&nd); | ||
1845 | filp = ERR_PTR(error); | ||
1846 | goto out; | ||
1847 | } | 2360 | } |
1848 | holder = path; | 2361 | holder = path; |
1849 | nd.flags &= ~LOOKUP_PARENT; | 2362 | nd.flags &= ~LOOKUP_PARENT; |
1850 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); | 2363 | filp = do_last(&nd, &path, open_flag, acc_mode, mode, pathname); |
1851 | if (inode->i_op->put_link) | 2364 | if (nd.inode->i_op->put_link) |
1852 | inode->i_op->put_link(holder.dentry, &nd, cookie); | 2365 | nd.inode->i_op->put_link(holder.dentry, &nd, cookie); |
1853 | path_put(&holder); | 2366 | path_put(&holder); |
1854 | } | 2367 | } |
1855 | out: | 2368 | out: |
1856 | if (nd.root.mnt) | 2369 | if (nd.root.mnt) |
1857 | path_put(&nd.root); | 2370 | path_put(&nd.root); |
1858 | if (filp == ERR_PTR(-ESTALE) && !force_reval) { | 2371 | if (filp == ERR_PTR(-ESTALE) && !(flags & LOOKUP_REVAL)) |
1859 | force_reval = 1; | ||
1860 | goto reval; | 2372 | goto reval; |
1861 | } | ||
1862 | return filp; | 2373 | return filp; |
1863 | 2374 | ||
1864 | exit_dput: | 2375 | exit_dput: |
1865 | path_put_conditional(&path, &nd); | 2376 | path_put_conditional(&path, &nd); |
2377 | out_path: | ||
2378 | path_put(&nd.path); | ||
2379 | out_filp: | ||
1866 | if (!IS_ERR(nd.intent.open.file)) | 2380 | if (!IS_ERR(nd.intent.open.file)) |
1867 | release_open_intent(&nd); | 2381 | release_open_intent(&nd); |
1868 | exit_parent: | ||
1869 | path_put(&nd.path); | ||
1870 | filp = ERR_PTR(error); | 2382 | filp = ERR_PTR(error); |
1871 | goto out; | 2383 | goto out; |
1872 | } | 2384 | } |
@@ -2127,12 +2639,10 @@ void dentry_unhash(struct dentry *dentry) | |||
2127 | { | 2639 | { |
2128 | dget(dentry); | 2640 | dget(dentry); |
2129 | shrink_dcache_parent(dentry); | 2641 | shrink_dcache_parent(dentry); |
2130 | spin_lock(&dcache_lock); | ||
2131 | spin_lock(&dentry->d_lock); | 2642 | spin_lock(&dentry->d_lock); |
2132 | if (atomic_read(&dentry->d_count) == 2) | 2643 | if (dentry->d_count == 2) |
2133 | __d_drop(dentry); | 2644 | __d_drop(dentry); |
2134 | spin_unlock(&dentry->d_lock); | 2645 | spin_unlock(&dentry->d_lock); |
2135 | spin_unlock(&dcache_lock); | ||
2136 | } | 2646 | } |
2137 | 2647 | ||
2138 | int vfs_rmdir(struct inode *dir, struct dentry *dentry) | 2648 | int vfs_rmdir(struct inode *dir, struct dentry *dentry) |
diff --git a/fs/namespace.c b/fs/namespace.c index 3dbfc072ec70..3ddfd9046c44 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -138,6 +138,64 @@ void mnt_release_group_id(struct vfsmount *mnt) | |||
138 | mnt->mnt_group_id = 0; | 138 | mnt->mnt_group_id = 0; |
139 | } | 139 | } |
140 | 140 | ||
141 | /* | ||
142 | * vfsmount lock must be held for read | ||
143 | */ | ||
144 | static inline void mnt_add_count(struct vfsmount *mnt, int n) | ||
145 | { | ||
146 | #ifdef CONFIG_SMP | ||
147 | this_cpu_add(mnt->mnt_pcp->mnt_count, n); | ||
148 | #else | ||
149 | preempt_disable(); | ||
150 | mnt->mnt_count += n; | ||
151 | preempt_enable(); | ||
152 | #endif | ||
153 | } | ||
154 | |||
155 | static inline void mnt_set_count(struct vfsmount *mnt, int n) | ||
156 | { | ||
157 | #ifdef CONFIG_SMP | ||
158 | this_cpu_write(mnt->mnt_pcp->mnt_count, n); | ||
159 | #else | ||
160 | mnt->mnt_count = n; | ||
161 | #endif | ||
162 | } | ||
163 | |||
164 | /* | ||
165 | * vfsmount lock must be held for read | ||
166 | */ | ||
167 | static inline void mnt_inc_count(struct vfsmount *mnt) | ||
168 | { | ||
169 | mnt_add_count(mnt, 1); | ||
170 | } | ||
171 | |||
172 | /* | ||
173 | * vfsmount lock must be held for read | ||
174 | */ | ||
175 | static inline void mnt_dec_count(struct vfsmount *mnt) | ||
176 | { | ||
177 | mnt_add_count(mnt, -1); | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * vfsmount lock must be held for write | ||
182 | */ | ||
183 | unsigned int mnt_get_count(struct vfsmount *mnt) | ||
184 | { | ||
185 | #ifdef CONFIG_SMP | ||
186 | unsigned int count = atomic_read(&mnt->mnt_longrefs); | ||
187 | int cpu; | ||
188 | |||
189 | for_each_possible_cpu(cpu) { | ||
190 | count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_count; | ||
191 | } | ||
192 | |||
193 | return count; | ||
194 | #else | ||
195 | return mnt->mnt_count; | ||
196 | #endif | ||
197 | } | ||
198 | |||
141 | struct vfsmount *alloc_vfsmnt(const char *name) | 199 | struct vfsmount *alloc_vfsmnt(const char *name) |
142 | { | 200 | { |
143 | struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); | 201 | struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); |
@@ -154,7 +212,17 @@ struct vfsmount *alloc_vfsmnt(const char *name) | |||
154 | goto out_free_id; | 212 | goto out_free_id; |
155 | } | 213 | } |
156 | 214 | ||
157 | atomic_set(&mnt->mnt_count, 1); | 215 | #ifdef CONFIG_SMP |
216 | mnt->mnt_pcp = alloc_percpu(struct mnt_pcp); | ||
217 | if (!mnt->mnt_pcp) | ||
218 | goto out_free_devname; | ||
219 | |||
220 | atomic_set(&mnt->mnt_longrefs, 1); | ||
221 | #else | ||
222 | mnt->mnt_count = 1; | ||
223 | mnt->mnt_writers = 0; | ||
224 | #endif | ||
225 | |||
158 | INIT_LIST_HEAD(&mnt->mnt_hash); | 226 | INIT_LIST_HEAD(&mnt->mnt_hash); |
159 | INIT_LIST_HEAD(&mnt->mnt_child); | 227 | INIT_LIST_HEAD(&mnt->mnt_child); |
160 | INIT_LIST_HEAD(&mnt->mnt_mounts); | 228 | INIT_LIST_HEAD(&mnt->mnt_mounts); |
@@ -166,13 +234,6 @@ struct vfsmount *alloc_vfsmnt(const char *name) | |||
166 | #ifdef CONFIG_FSNOTIFY | 234 | #ifdef CONFIG_FSNOTIFY |
167 | INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks); | 235 | INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks); |
168 | #endif | 236 | #endif |
169 | #ifdef CONFIG_SMP | ||
170 | mnt->mnt_writers = alloc_percpu(int); | ||
171 | if (!mnt->mnt_writers) | ||
172 | goto out_free_devname; | ||
173 | #else | ||
174 | mnt->mnt_writers = 0; | ||
175 | #endif | ||
176 | } | 237 | } |
177 | return mnt; | 238 | return mnt; |
178 | 239 | ||
@@ -216,32 +277,32 @@ int __mnt_is_readonly(struct vfsmount *mnt) | |||
216 | } | 277 | } |
217 | EXPORT_SYMBOL_GPL(__mnt_is_readonly); | 278 | EXPORT_SYMBOL_GPL(__mnt_is_readonly); |
218 | 279 | ||
219 | static inline void inc_mnt_writers(struct vfsmount *mnt) | 280 | static inline void mnt_inc_writers(struct vfsmount *mnt) |
220 | { | 281 | { |
221 | #ifdef CONFIG_SMP | 282 | #ifdef CONFIG_SMP |
222 | (*per_cpu_ptr(mnt->mnt_writers, smp_processor_id()))++; | 283 | this_cpu_inc(mnt->mnt_pcp->mnt_writers); |
223 | #else | 284 | #else |
224 | mnt->mnt_writers++; | 285 | mnt->mnt_writers++; |
225 | #endif | 286 | #endif |
226 | } | 287 | } |
227 | 288 | ||
228 | static inline void dec_mnt_writers(struct vfsmount *mnt) | 289 | static inline void mnt_dec_writers(struct vfsmount *mnt) |
229 | { | 290 | { |
230 | #ifdef CONFIG_SMP | 291 | #ifdef CONFIG_SMP |
231 | (*per_cpu_ptr(mnt->mnt_writers, smp_processor_id()))--; | 292 | this_cpu_dec(mnt->mnt_pcp->mnt_writers); |
232 | #else | 293 | #else |
233 | mnt->mnt_writers--; | 294 | mnt->mnt_writers--; |
234 | #endif | 295 | #endif |
235 | } | 296 | } |
236 | 297 | ||
237 | static unsigned int count_mnt_writers(struct vfsmount *mnt) | 298 | static unsigned int mnt_get_writers(struct vfsmount *mnt) |
238 | { | 299 | { |
239 | #ifdef CONFIG_SMP | 300 | #ifdef CONFIG_SMP |
240 | unsigned int count = 0; | 301 | unsigned int count = 0; |
241 | int cpu; | 302 | int cpu; |
242 | 303 | ||
243 | for_each_possible_cpu(cpu) { | 304 | for_each_possible_cpu(cpu) { |
244 | count += *per_cpu_ptr(mnt->mnt_writers, cpu); | 305 | count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_writers; |
245 | } | 306 | } |
246 | 307 | ||
247 | return count; | 308 | return count; |
@@ -273,9 +334,9 @@ int mnt_want_write(struct vfsmount *mnt) | |||
273 | int ret = 0; | 334 | int ret = 0; |
274 | 335 | ||
275 | preempt_disable(); | 336 | preempt_disable(); |
276 | inc_mnt_writers(mnt); | 337 | mnt_inc_writers(mnt); |
277 | /* | 338 | /* |
278 | * The store to inc_mnt_writers must be visible before we pass | 339 | * The store to mnt_inc_writers must be visible before we pass |
279 | * MNT_WRITE_HOLD loop below, so that the slowpath can see our | 340 | * MNT_WRITE_HOLD loop below, so that the slowpath can see our |
280 | * incremented count after it has set MNT_WRITE_HOLD. | 341 | * incremented count after it has set MNT_WRITE_HOLD. |
281 | */ | 342 | */ |
@@ -289,7 +350,7 @@ int mnt_want_write(struct vfsmount *mnt) | |||
289 | */ | 350 | */ |
290 | smp_rmb(); | 351 | smp_rmb(); |
291 | if (__mnt_is_readonly(mnt)) { | 352 | if (__mnt_is_readonly(mnt)) { |
292 | dec_mnt_writers(mnt); | 353 | mnt_dec_writers(mnt); |
293 | ret = -EROFS; | 354 | ret = -EROFS; |
294 | goto out; | 355 | goto out; |
295 | } | 356 | } |
@@ -317,7 +378,7 @@ int mnt_clone_write(struct vfsmount *mnt) | |||
317 | if (__mnt_is_readonly(mnt)) | 378 | if (__mnt_is_readonly(mnt)) |
318 | return -EROFS; | 379 | return -EROFS; |
319 | preempt_disable(); | 380 | preempt_disable(); |
320 | inc_mnt_writers(mnt); | 381 | mnt_inc_writers(mnt); |
321 | preempt_enable(); | 382 | preempt_enable(); |
322 | return 0; | 383 | return 0; |
323 | } | 384 | } |
@@ -351,7 +412,7 @@ EXPORT_SYMBOL_GPL(mnt_want_write_file); | |||
351 | void mnt_drop_write(struct vfsmount *mnt) | 412 | void mnt_drop_write(struct vfsmount *mnt) |
352 | { | 413 | { |
353 | preempt_disable(); | 414 | preempt_disable(); |
354 | dec_mnt_writers(mnt); | 415 | mnt_dec_writers(mnt); |
355 | preempt_enable(); | 416 | preempt_enable(); |
356 | } | 417 | } |
357 | EXPORT_SYMBOL_GPL(mnt_drop_write); | 418 | EXPORT_SYMBOL_GPL(mnt_drop_write); |
@@ -384,7 +445,7 @@ static int mnt_make_readonly(struct vfsmount *mnt) | |||
384 | * MNT_WRITE_HOLD, so it can't be decremented by another CPU while | 445 | * MNT_WRITE_HOLD, so it can't be decremented by another CPU while |
385 | * we're counting up here. | 446 | * we're counting up here. |
386 | */ | 447 | */ |
387 | if (count_mnt_writers(mnt) > 0) | 448 | if (mnt_get_writers(mnt) > 0) |
388 | ret = -EBUSY; | 449 | ret = -EBUSY; |
389 | else | 450 | else |
390 | mnt->mnt_flags |= MNT_READONLY; | 451 | mnt->mnt_flags |= MNT_READONLY; |
@@ -418,7 +479,7 @@ void free_vfsmnt(struct vfsmount *mnt) | |||
418 | kfree(mnt->mnt_devname); | 479 | kfree(mnt->mnt_devname); |
419 | mnt_free_id(mnt); | 480 | mnt_free_id(mnt); |
420 | #ifdef CONFIG_SMP | 481 | #ifdef CONFIG_SMP |
421 | free_percpu(mnt->mnt_writers); | 482 | free_percpu(mnt->mnt_pcp); |
422 | #endif | 483 | #endif |
423 | kmem_cache_free(mnt_cache, mnt); | 484 | kmem_cache_free(mnt_cache, mnt); |
424 | } | 485 | } |
@@ -492,6 +553,27 @@ static void __touch_mnt_namespace(struct mnt_namespace *ns) | |||
492 | } | 553 | } |
493 | 554 | ||
494 | /* | 555 | /* |
556 | * Clear dentry's mounted state if it has no remaining mounts. | ||
557 | * vfsmount_lock must be held for write. | ||
558 | */ | ||
559 | static void dentry_reset_mounted(struct vfsmount *mnt, struct dentry *dentry) | ||
560 | { | ||
561 | unsigned u; | ||
562 | |||
563 | for (u = 0; u < HASH_SIZE; u++) { | ||
564 | struct vfsmount *p; | ||
565 | |||
566 | list_for_each_entry(p, &mount_hashtable[u], mnt_hash) { | ||
567 | if (p->mnt_mountpoint == dentry) | ||
568 | return; | ||
569 | } | ||
570 | } | ||
571 | spin_lock(&dentry->d_lock); | ||
572 | dentry->d_flags &= ~DCACHE_MOUNTED; | ||
573 | spin_unlock(&dentry->d_lock); | ||
574 | } | ||
575 | |||
576 | /* | ||
495 | * vfsmount lock must be held for write | 577 | * vfsmount lock must be held for write |
496 | */ | 578 | */ |
497 | static void detach_mnt(struct vfsmount *mnt, struct path *old_path) | 579 | static void detach_mnt(struct vfsmount *mnt, struct path *old_path) |
@@ -502,7 +584,7 @@ static void detach_mnt(struct vfsmount *mnt, struct path *old_path) | |||
502 | mnt->mnt_mountpoint = mnt->mnt_root; | 584 | mnt->mnt_mountpoint = mnt->mnt_root; |
503 | list_del_init(&mnt->mnt_child); | 585 | list_del_init(&mnt->mnt_child); |
504 | list_del_init(&mnt->mnt_hash); | 586 | list_del_init(&mnt->mnt_hash); |
505 | old_path->dentry->d_mounted--; | 587 | dentry_reset_mounted(old_path->mnt, old_path->dentry); |
506 | } | 588 | } |
507 | 589 | ||
508 | /* | 590 | /* |
@@ -513,7 +595,9 @@ void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry, | |||
513 | { | 595 | { |
514 | child_mnt->mnt_parent = mntget(mnt); | 596 | child_mnt->mnt_parent = mntget(mnt); |
515 | child_mnt->mnt_mountpoint = dget(dentry); | 597 | child_mnt->mnt_mountpoint = dget(dentry); |
516 | dentry->d_mounted++; | 598 | spin_lock(&dentry->d_lock); |
599 | dentry->d_flags |= DCACHE_MOUNTED; | ||
600 | spin_unlock(&dentry->d_lock); | ||
517 | } | 601 | } |
518 | 602 | ||
519 | /* | 603 | /* |
@@ -629,9 +713,10 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root, | |||
629 | return NULL; | 713 | return NULL; |
630 | } | 714 | } |
631 | 715 | ||
632 | static inline void __mntput(struct vfsmount *mnt) | 716 | static inline void mntfree(struct vfsmount *mnt) |
633 | { | 717 | { |
634 | struct super_block *sb = mnt->mnt_sb; | 718 | struct super_block *sb = mnt->mnt_sb; |
719 | |||
635 | /* | 720 | /* |
636 | * This probably indicates that somebody messed | 721 | * This probably indicates that somebody messed |
637 | * up a mnt_want/drop_write() pair. If this | 722 | * up a mnt_want/drop_write() pair. If this |
@@ -639,38 +724,123 @@ static inline void __mntput(struct vfsmount *mnt) | |||
639 | * to make r/w->r/o transitions. | 724 | * to make r/w->r/o transitions. |
640 | */ | 725 | */ |
641 | /* | 726 | /* |
642 | * atomic_dec_and_lock() used to deal with ->mnt_count decrements | 727 | * The locking used to deal with mnt_count decrement provides barriers, |
643 | * provides barriers, so count_mnt_writers() below is safe. AV | 728 | * so mnt_get_writers() below is safe. |
644 | */ | 729 | */ |
645 | WARN_ON(count_mnt_writers(mnt)); | 730 | WARN_ON(mnt_get_writers(mnt)); |
646 | fsnotify_vfsmount_delete(mnt); | 731 | fsnotify_vfsmount_delete(mnt); |
647 | dput(mnt->mnt_root); | 732 | dput(mnt->mnt_root); |
648 | free_vfsmnt(mnt); | 733 | free_vfsmnt(mnt); |
649 | deactivate_super(sb); | 734 | deactivate_super(sb); |
650 | } | 735 | } |
651 | 736 | ||
652 | void mntput_no_expire(struct vfsmount *mnt) | 737 | #ifdef CONFIG_SMP |
653 | { | 738 | static inline void __mntput(struct vfsmount *mnt, int longrefs) |
654 | repeat: | 739 | { |
655 | if (atomic_add_unless(&mnt->mnt_count, -1, 1)) | 740 | if (!longrefs) { |
656 | return; | 741 | put_again: |
742 | br_read_lock(vfsmount_lock); | ||
743 | if (likely(atomic_read(&mnt->mnt_longrefs))) { | ||
744 | mnt_dec_count(mnt); | ||
745 | br_read_unlock(vfsmount_lock); | ||
746 | return; | ||
747 | } | ||
748 | br_read_unlock(vfsmount_lock); | ||
749 | } else { | ||
750 | BUG_ON(!atomic_read(&mnt->mnt_longrefs)); | ||
751 | if (atomic_add_unless(&mnt->mnt_longrefs, -1, 1)) | ||
752 | return; | ||
753 | } | ||
754 | |||
657 | br_write_lock(vfsmount_lock); | 755 | br_write_lock(vfsmount_lock); |
658 | if (!atomic_dec_and_test(&mnt->mnt_count)) { | 756 | if (!longrefs) |
757 | mnt_dec_count(mnt); | ||
758 | else | ||
759 | atomic_dec(&mnt->mnt_longrefs); | ||
760 | if (mnt_get_count(mnt)) { | ||
659 | br_write_unlock(vfsmount_lock); | 761 | br_write_unlock(vfsmount_lock); |
660 | return; | 762 | return; |
661 | } | 763 | } |
662 | if (likely(!mnt->mnt_pinned)) { | 764 | if (unlikely(mnt->mnt_pinned)) { |
765 | mnt_add_count(mnt, mnt->mnt_pinned + 1); | ||
766 | mnt->mnt_pinned = 0; | ||
663 | br_write_unlock(vfsmount_lock); | 767 | br_write_unlock(vfsmount_lock); |
664 | __mntput(mnt); | 768 | acct_auto_close_mnt(mnt); |
769 | goto put_again; | ||
770 | } | ||
771 | br_write_unlock(vfsmount_lock); | ||
772 | mntfree(mnt); | ||
773 | } | ||
774 | #else | ||
775 | static inline void __mntput(struct vfsmount *mnt, int longrefs) | ||
776 | { | ||
777 | put_again: | ||
778 | mnt_dec_count(mnt); | ||
779 | if (likely(mnt_get_count(mnt))) | ||
665 | return; | 780 | return; |
781 | br_write_lock(vfsmount_lock); | ||
782 | if (unlikely(mnt->mnt_pinned)) { | ||
783 | mnt_add_count(mnt, mnt->mnt_pinned + 1); | ||
784 | mnt->mnt_pinned = 0; | ||
785 | br_write_unlock(vfsmount_lock); | ||
786 | acct_auto_close_mnt(mnt); | ||
787 | goto put_again; | ||
666 | } | 788 | } |
667 | atomic_add(mnt->mnt_pinned + 1, &mnt->mnt_count); | ||
668 | mnt->mnt_pinned = 0; | ||
669 | br_write_unlock(vfsmount_lock); | 789 | br_write_unlock(vfsmount_lock); |
670 | acct_auto_close_mnt(mnt); | 790 | mntfree(mnt); |
671 | goto repeat; | 791 | } |
792 | #endif | ||
793 | |||
794 | static void mntput_no_expire(struct vfsmount *mnt) | ||
795 | { | ||
796 | __mntput(mnt, 0); | ||
797 | } | ||
798 | |||
799 | void mntput(struct vfsmount *mnt) | ||
800 | { | ||
801 | if (mnt) { | ||
802 | /* avoid cacheline pingpong, hope gcc doesn't get "smart" */ | ||
803 | if (unlikely(mnt->mnt_expiry_mark)) | ||
804 | mnt->mnt_expiry_mark = 0; | ||
805 | __mntput(mnt, 0); | ||
806 | } | ||
807 | } | ||
808 | EXPORT_SYMBOL(mntput); | ||
809 | |||
810 | struct vfsmount *mntget(struct vfsmount *mnt) | ||
811 | { | ||
812 | if (mnt) | ||
813 | mnt_inc_count(mnt); | ||
814 | return mnt; | ||
672 | } | 815 | } |
673 | EXPORT_SYMBOL(mntput_no_expire); | 816 | EXPORT_SYMBOL(mntget); |
817 | |||
818 | void mntput_long(struct vfsmount *mnt) | ||
819 | { | ||
820 | #ifdef CONFIG_SMP | ||
821 | if (mnt) { | ||
822 | /* avoid cacheline pingpong, hope gcc doesn't get "smart" */ | ||
823 | if (unlikely(mnt->mnt_expiry_mark)) | ||
824 | mnt->mnt_expiry_mark = 0; | ||
825 | __mntput(mnt, 1); | ||
826 | } | ||
827 | #else | ||
828 | mntput(mnt); | ||
829 | #endif | ||
830 | } | ||
831 | EXPORT_SYMBOL(mntput_long); | ||
832 | |||
833 | struct vfsmount *mntget_long(struct vfsmount *mnt) | ||
834 | { | ||
835 | #ifdef CONFIG_SMP | ||
836 | if (mnt) | ||
837 | atomic_inc(&mnt->mnt_longrefs); | ||
838 | return mnt; | ||
839 | #else | ||
840 | return mntget(mnt); | ||
841 | #endif | ||
842 | } | ||
843 | EXPORT_SYMBOL(mntget_long); | ||
674 | 844 | ||
675 | void mnt_pin(struct vfsmount *mnt) | 845 | void mnt_pin(struct vfsmount *mnt) |
676 | { | 846 | { |
@@ -678,19 +848,17 @@ void mnt_pin(struct vfsmount *mnt) | |||
678 | mnt->mnt_pinned++; | 848 | mnt->mnt_pinned++; |
679 | br_write_unlock(vfsmount_lock); | 849 | br_write_unlock(vfsmount_lock); |
680 | } | 850 | } |
681 | |||
682 | EXPORT_SYMBOL(mnt_pin); | 851 | EXPORT_SYMBOL(mnt_pin); |
683 | 852 | ||
684 | void mnt_unpin(struct vfsmount *mnt) | 853 | void mnt_unpin(struct vfsmount *mnt) |
685 | { | 854 | { |
686 | br_write_lock(vfsmount_lock); | 855 | br_write_lock(vfsmount_lock); |
687 | if (mnt->mnt_pinned) { | 856 | if (mnt->mnt_pinned) { |
688 | atomic_inc(&mnt->mnt_count); | 857 | mnt_inc_count(mnt); |
689 | mnt->mnt_pinned--; | 858 | mnt->mnt_pinned--; |
690 | } | 859 | } |
691 | br_write_unlock(vfsmount_lock); | 860 | br_write_unlock(vfsmount_lock); |
692 | } | 861 | } |
693 | |||
694 | EXPORT_SYMBOL(mnt_unpin); | 862 | EXPORT_SYMBOL(mnt_unpin); |
695 | 863 | ||
696 | static inline void mangle(struct seq_file *m, const char *s) | 864 | static inline void mangle(struct seq_file *m, const char *s) |
@@ -985,12 +1153,13 @@ int may_umount_tree(struct vfsmount *mnt) | |||
985 | int minimum_refs = 0; | 1153 | int minimum_refs = 0; |
986 | struct vfsmount *p; | 1154 | struct vfsmount *p; |
987 | 1155 | ||
988 | br_read_lock(vfsmount_lock); | 1156 | /* write lock needed for mnt_get_count */ |
1157 | br_write_lock(vfsmount_lock); | ||
989 | for (p = mnt; p; p = next_mnt(p, mnt)) { | 1158 | for (p = mnt; p; p = next_mnt(p, mnt)) { |
990 | actual_refs += atomic_read(&p->mnt_count); | 1159 | actual_refs += mnt_get_count(p); |
991 | minimum_refs += 2; | 1160 | minimum_refs += 2; |
992 | } | 1161 | } |
993 | br_read_unlock(vfsmount_lock); | 1162 | br_write_unlock(vfsmount_lock); |
994 | 1163 | ||
995 | if (actual_refs > minimum_refs) | 1164 | if (actual_refs > minimum_refs) |
996 | return 0; | 1165 | return 0; |
@@ -1017,10 +1186,10 @@ int may_umount(struct vfsmount *mnt) | |||
1017 | { | 1186 | { |
1018 | int ret = 1; | 1187 | int ret = 1; |
1019 | down_read(&namespace_sem); | 1188 | down_read(&namespace_sem); |
1020 | br_read_lock(vfsmount_lock); | 1189 | br_write_lock(vfsmount_lock); |
1021 | if (propagate_mount_busy(mnt, 2)) | 1190 | if (propagate_mount_busy(mnt, 2)) |
1022 | ret = 0; | 1191 | ret = 0; |
1023 | br_read_unlock(vfsmount_lock); | 1192 | br_write_unlock(vfsmount_lock); |
1024 | up_read(&namespace_sem); | 1193 | up_read(&namespace_sem); |
1025 | return ret; | 1194 | return ret; |
1026 | } | 1195 | } |
@@ -1047,7 +1216,7 @@ void release_mounts(struct list_head *head) | |||
1047 | dput(dentry); | 1216 | dput(dentry); |
1048 | mntput(m); | 1217 | mntput(m); |
1049 | } | 1218 | } |
1050 | mntput(mnt); | 1219 | mntput_long(mnt); |
1051 | } | 1220 | } |
1052 | } | 1221 | } |
1053 | 1222 | ||
@@ -1073,7 +1242,7 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) | |||
1073 | list_del_init(&p->mnt_child); | 1242 | list_del_init(&p->mnt_child); |
1074 | if (p->mnt_parent != p) { | 1243 | if (p->mnt_parent != p) { |
1075 | p->mnt_parent->mnt_ghosts++; | 1244 | p->mnt_parent->mnt_ghosts++; |
1076 | p->mnt_mountpoint->d_mounted--; | 1245 | dentry_reset_mounted(p->mnt_parent, p->mnt_mountpoint); |
1077 | } | 1246 | } |
1078 | change_mnt_propagation(p, MS_PRIVATE); | 1247 | change_mnt_propagation(p, MS_PRIVATE); |
1079 | } | 1248 | } |
@@ -1102,8 +1271,16 @@ static int do_umount(struct vfsmount *mnt, int flags) | |||
1102 | flags & (MNT_FORCE | MNT_DETACH)) | 1271 | flags & (MNT_FORCE | MNT_DETACH)) |
1103 | return -EINVAL; | 1272 | return -EINVAL; |
1104 | 1273 | ||
1105 | if (atomic_read(&mnt->mnt_count) != 2) | 1274 | /* |
1275 | * probably don't strictly need the lock here if we examined | ||
1276 | * all race cases, but it's a slowpath. | ||
1277 | */ | ||
1278 | br_write_lock(vfsmount_lock); | ||
1279 | if (mnt_get_count(mnt) != 2) { | ||
1280 | br_write_lock(vfsmount_lock); | ||
1106 | return -EBUSY; | 1281 | return -EBUSY; |
1282 | } | ||
1283 | br_write_unlock(vfsmount_lock); | ||
1107 | 1284 | ||
1108 | if (!xchg(&mnt->mnt_expiry_mark, 1)) | 1285 | if (!xchg(&mnt->mnt_expiry_mark, 1)) |
1109 | return -EAGAIN; | 1286 | return -EAGAIN; |
@@ -1792,7 +1969,7 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path, | |||
1792 | 1969 | ||
1793 | unlock: | 1970 | unlock: |
1794 | up_write(&namespace_sem); | 1971 | up_write(&namespace_sem); |
1795 | mntput(newmnt); | 1972 | mntput_long(newmnt); |
1796 | return err; | 1973 | return err; |
1797 | } | 1974 | } |
1798 | 1975 | ||
@@ -2125,11 +2302,11 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
2125 | if (fs) { | 2302 | if (fs) { |
2126 | if (p == fs->root.mnt) { | 2303 | if (p == fs->root.mnt) { |
2127 | rootmnt = p; | 2304 | rootmnt = p; |
2128 | fs->root.mnt = mntget(q); | 2305 | fs->root.mnt = mntget_long(q); |
2129 | } | 2306 | } |
2130 | if (p == fs->pwd.mnt) { | 2307 | if (p == fs->pwd.mnt) { |
2131 | pwdmnt = p; | 2308 | pwdmnt = p; |
2132 | fs->pwd.mnt = mntget(q); | 2309 | fs->pwd.mnt = mntget_long(q); |
2133 | } | 2310 | } |
2134 | } | 2311 | } |
2135 | p = next_mnt(p, mnt_ns->root); | 2312 | p = next_mnt(p, mnt_ns->root); |
@@ -2138,9 +2315,9 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
2138 | up_write(&namespace_sem); | 2315 | up_write(&namespace_sem); |
2139 | 2316 | ||
2140 | if (rootmnt) | 2317 | if (rootmnt) |
2141 | mntput(rootmnt); | 2318 | mntput_long(rootmnt); |
2142 | if (pwdmnt) | 2319 | if (pwdmnt) |
2143 | mntput(pwdmnt); | 2320 | mntput_long(pwdmnt); |
2144 | 2321 | ||
2145 | return new_ns; | 2322 | return new_ns; |
2146 | } | 2323 | } |
@@ -2327,6 +2504,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, | |||
2327 | touch_mnt_namespace(current->nsproxy->mnt_ns); | 2504 | touch_mnt_namespace(current->nsproxy->mnt_ns); |
2328 | br_write_unlock(vfsmount_lock); | 2505 | br_write_unlock(vfsmount_lock); |
2329 | chroot_fs_refs(&root, &new); | 2506 | chroot_fs_refs(&root, &new); |
2507 | |||
2330 | error = 0; | 2508 | error = 0; |
2331 | path_put(&root_parent); | 2509 | path_put(&root_parent); |
2332 | path_put(&parent_path); | 2510 | path_put(&parent_path); |
@@ -2353,6 +2531,7 @@ static void __init init_mount_tree(void) | |||
2353 | mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); | 2531 | mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); |
2354 | if (IS_ERR(mnt)) | 2532 | if (IS_ERR(mnt)) |
2355 | panic("Can't create rootfs"); | 2533 | panic("Can't create rootfs"); |
2534 | |||
2356 | ns = create_mnt_ns(mnt); | 2535 | ns = create_mnt_ns(mnt); |
2357 | if (IS_ERR(ns)) | 2536 | if (IS_ERR(ns)) |
2358 | panic("Can't allocate initial namespace"); | 2537 | panic("Can't allocate initial namespace"); |
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index f22b12e7d337..28f136d4aaec 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/vmalloc.h> | 18 | #include <linux/vmalloc.h> |
19 | #include <linux/mm.h> | 19 | #include <linux/mm.h> |
20 | #include <linux/namei.h> | ||
20 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
21 | #include <asm/byteorder.h> | 22 | #include <asm/byteorder.h> |
22 | 23 | ||
@@ -74,9 +75,12 @@ const struct inode_operations ncp_dir_inode_operations = | |||
74 | * Dentry operations routines | 75 | * Dentry operations routines |
75 | */ | 76 | */ |
76 | static int ncp_lookup_validate(struct dentry *, struct nameidata *); | 77 | static int ncp_lookup_validate(struct dentry *, struct nameidata *); |
77 | static int ncp_hash_dentry(struct dentry *, struct qstr *); | 78 | static int ncp_hash_dentry(const struct dentry *, const struct inode *, |
78 | static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *); | 79 | struct qstr *); |
79 | static int ncp_delete_dentry(struct dentry *); | 80 | static int ncp_compare_dentry(const struct dentry *, const struct inode *, |
81 | const struct dentry *, const struct inode *, | ||
82 | unsigned int, const char *, const struct qstr *); | ||
83 | static int ncp_delete_dentry(const struct dentry *); | ||
80 | 84 | ||
81 | static const struct dentry_operations ncp_dentry_operations = | 85 | static const struct dentry_operations ncp_dentry_operations = |
82 | { | 86 | { |
@@ -113,10 +117,10 @@ static inline int ncp_preserve_entry_case(struct inode *i, __u32 nscreator) | |||
113 | 117 | ||
114 | #define ncp_preserve_case(i) (ncp_namespace(i) != NW_NS_DOS) | 118 | #define ncp_preserve_case(i) (ncp_namespace(i) != NW_NS_DOS) |
115 | 119 | ||
116 | static inline int ncp_case_sensitive(struct dentry *dentry) | 120 | static inline int ncp_case_sensitive(const struct inode *i) |
117 | { | 121 | { |
118 | #ifdef CONFIG_NCPFS_NFS_NS | 122 | #ifdef CONFIG_NCPFS_NFS_NS |
119 | return ncp_namespace(dentry->d_inode) == NW_NS_NFS; | 123 | return ncp_namespace(i) == NW_NS_NFS; |
120 | #else | 124 | #else |
121 | return 0; | 125 | return 0; |
122 | #endif /* CONFIG_NCPFS_NFS_NS */ | 126 | #endif /* CONFIG_NCPFS_NFS_NS */ |
@@ -127,14 +131,16 @@ static inline int ncp_case_sensitive(struct dentry *dentry) | |||
127 | * is case-sensitive. | 131 | * is case-sensitive. |
128 | */ | 132 | */ |
129 | static int | 133 | static int |
130 | ncp_hash_dentry(struct dentry *dentry, struct qstr *this) | 134 | ncp_hash_dentry(const struct dentry *dentry, const struct inode *inode, |
135 | struct qstr *this) | ||
131 | { | 136 | { |
132 | if (!ncp_case_sensitive(dentry)) { | 137 | if (!ncp_case_sensitive(inode)) { |
138 | struct super_block *sb = dentry->d_sb; | ||
133 | struct nls_table *t; | 139 | struct nls_table *t; |
134 | unsigned long hash; | 140 | unsigned long hash; |
135 | int i; | 141 | int i; |
136 | 142 | ||
137 | t = NCP_IO_TABLE(dentry); | 143 | t = NCP_IO_TABLE(sb); |
138 | hash = init_name_hash(); | 144 | hash = init_name_hash(); |
139 | for (i=0; i<this->len ; i++) | 145 | for (i=0; i<this->len ; i++) |
140 | hash = partial_name_hash(ncp_tolower(t, this->name[i]), | 146 | hash = partial_name_hash(ncp_tolower(t, this->name[i]), |
@@ -145,15 +151,17 @@ ncp_hash_dentry(struct dentry *dentry, struct qstr *this) | |||
145 | } | 151 | } |
146 | 152 | ||
147 | static int | 153 | static int |
148 | ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) | 154 | ncp_compare_dentry(const struct dentry *parent, const struct inode *pinode, |
155 | const struct dentry *dentry, const struct inode *inode, | ||
156 | unsigned int len, const char *str, const struct qstr *name) | ||
149 | { | 157 | { |
150 | if (a->len != b->len) | 158 | if (len != name->len) |
151 | return 1; | 159 | return 1; |
152 | 160 | ||
153 | if (ncp_case_sensitive(dentry)) | 161 | if (ncp_case_sensitive(pinode)) |
154 | return strncmp(a->name, b->name, a->len); | 162 | return strncmp(str, name->name, len); |
155 | 163 | ||
156 | return ncp_strnicmp(NCP_IO_TABLE(dentry), a->name, b->name, a->len); | 164 | return ncp_strnicmp(NCP_IO_TABLE(pinode->i_sb), str, name->name, len); |
157 | } | 165 | } |
158 | 166 | ||
159 | /* | 167 | /* |
@@ -162,7 +170,7 @@ ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) | |||
162 | * Closing files can be safely postponed until iput() - it's done there anyway. | 170 | * Closing files can be safely postponed until iput() - it's done there anyway. |
163 | */ | 171 | */ |
164 | static int | 172 | static int |
165 | ncp_delete_dentry(struct dentry * dentry) | 173 | ncp_delete_dentry(const struct dentry * dentry) |
166 | { | 174 | { |
167 | struct inode *inode = dentry->d_inode; | 175 | struct inode *inode = dentry->d_inode; |
168 | 176 | ||
@@ -301,6 +309,9 @@ ncp_lookup_validate(struct dentry *dentry, struct nameidata *nd) | |||
301 | int res, val = 0, len; | 309 | int res, val = 0, len; |
302 | __u8 __name[NCP_MAXPATHLEN + 1]; | 310 | __u8 __name[NCP_MAXPATHLEN + 1]; |
303 | 311 | ||
312 | if (nd->flags & LOOKUP_RCU) | ||
313 | return -ECHILD; | ||
314 | |||
304 | parent = dget_parent(dentry); | 315 | parent = dget_parent(dentry); |
305 | dir = parent->d_inode; | 316 | dir = parent->d_inode; |
306 | 317 | ||
@@ -384,21 +395,21 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) | |||
384 | } | 395 | } |
385 | 396 | ||
386 | /* If a pointer is invalid, we search the dentry. */ | 397 | /* If a pointer is invalid, we search the dentry. */ |
387 | spin_lock(&dcache_lock); | 398 | spin_lock(&parent->d_lock); |
388 | next = parent->d_subdirs.next; | 399 | next = parent->d_subdirs.next; |
389 | while (next != &parent->d_subdirs) { | 400 | while (next != &parent->d_subdirs) { |
390 | dent = list_entry(next, struct dentry, d_u.d_child); | 401 | dent = list_entry(next, struct dentry, d_u.d_child); |
391 | if ((unsigned long)dent->d_fsdata == fpos) { | 402 | if ((unsigned long)dent->d_fsdata == fpos) { |
392 | if (dent->d_inode) | 403 | if (dent->d_inode) |
393 | dget_locked(dent); | 404 | dget(dent); |
394 | else | 405 | else |
395 | dent = NULL; | 406 | dent = NULL; |
396 | spin_unlock(&dcache_lock); | 407 | spin_unlock(&parent->d_lock); |
397 | goto out; | 408 | goto out; |
398 | } | 409 | } |
399 | next = next->next; | 410 | next = next->next; |
400 | } | 411 | } |
401 | spin_unlock(&dcache_lock); | 412 | spin_unlock(&parent->d_lock); |
402 | return NULL; | 413 | return NULL; |
403 | 414 | ||
404 | out: | 415 | out: |
@@ -592,7 +603,7 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | |||
592 | qname.hash = full_name_hash(qname.name, qname.len); | 603 | qname.hash = full_name_hash(qname.name, qname.len); |
593 | 604 | ||
594 | if (dentry->d_op && dentry->d_op->d_hash) | 605 | if (dentry->d_op && dentry->d_op->d_hash) |
595 | if (dentry->d_op->d_hash(dentry, &qname) != 0) | 606 | if (dentry->d_op->d_hash(dentry, dentry->d_inode, &qname) != 0) |
596 | goto end_advance; | 607 | goto end_advance; |
597 | 608 | ||
598 | newdent = d_lookup(dentry, &qname); | 609 | newdent = d_lookup(dentry, &qname); |
@@ -611,35 +622,12 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | |||
611 | shrink_dcache_parent(newdent); | 622 | shrink_dcache_parent(newdent); |
612 | 623 | ||
613 | /* | 624 | /* |
614 | * It is not as dangerous as it looks. NetWare's OS2 namespace is | 625 | * NetWare's OS2 namespace is case preserving yet case |
615 | * case preserving yet case insensitive. So we update dentry's name | 626 | * insensitive. So we update dentry's name as received from |
616 | * as received from server. We found dentry via d_lookup with our | 627 | * server. Parent dir's i_mutex is locked because we're in |
617 | * hash, so we know that hash does not change, and so replacing name | 628 | * readdir. |
618 | * should be reasonably safe. | ||
619 | */ | 629 | */ |
620 | if (qname.len == newdent->d_name.len && | 630 | dentry_update_name_case(newdent, &qname); |
621 | memcmp(newdent->d_name.name, qname.name, newdent->d_name.len)) { | ||
622 | struct inode *inode = newdent->d_inode; | ||
623 | |||
624 | /* | ||
625 | * Inside ncpfs all uses of d_name are either for debugging, | ||
626 | * or on functions which acquire inode mutex (mknod, creat, | ||
627 | * lookup). So grab i_mutex here, to be sure. d_path | ||
628 | * uses dcache_lock when generating path, so we should too. | ||
629 | * And finally d_compare is protected by dentry's d_lock, so | ||
630 | * here we go. | ||
631 | */ | ||
632 | if (inode) | ||
633 | mutex_lock(&inode->i_mutex); | ||
634 | spin_lock(&dcache_lock); | ||
635 | spin_lock(&newdent->d_lock); | ||
636 | memcpy((char *) newdent->d_name.name, qname.name, | ||
637 | newdent->d_name.len); | ||
638 | spin_unlock(&newdent->d_lock); | ||
639 | spin_unlock(&dcache_lock); | ||
640 | if (inode) | ||
641 | mutex_unlock(&inode->i_mutex); | ||
642 | } | ||
643 | } | 631 | } |
644 | 632 | ||
645 | if (!newdent->d_inode) { | 633 | if (!newdent->d_inode) { |
@@ -649,7 +637,7 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | |||
649 | entry->ino = iunique(dir->i_sb, 2); | 637 | entry->ino = iunique(dir->i_sb, 2); |
650 | inode = ncp_iget(dir->i_sb, entry); | 638 | inode = ncp_iget(dir->i_sb, entry); |
651 | if (inode) { | 639 | if (inode) { |
652 | newdent->d_op = &ncp_dentry_operations; | 640 | d_set_d_op(newdent, &ncp_dentry_operations); |
653 | d_instantiate(newdent, inode); | 641 | d_instantiate(newdent, inode); |
654 | if (!hashed) | 642 | if (!hashed) |
655 | d_rehash(newdent); | 643 | d_rehash(newdent); |
@@ -657,7 +645,7 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | |||
657 | } else { | 645 | } else { |
658 | struct inode *inode = newdent->d_inode; | 646 | struct inode *inode = newdent->d_inode; |
659 | 647 | ||
660 | mutex_lock(&inode->i_mutex); | 648 | mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD); |
661 | ncp_update_inode2(inode, entry); | 649 | ncp_update_inode2(inode, entry); |
662 | mutex_unlock(&inode->i_mutex); | 650 | mutex_unlock(&inode->i_mutex); |
663 | } | 651 | } |
@@ -905,7 +893,7 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struc | |||
905 | if (inode) { | 893 | if (inode) { |
906 | ncp_new_dentry(dentry); | 894 | ncp_new_dentry(dentry); |
907 | add_entry: | 895 | add_entry: |
908 | dentry->d_op = &ncp_dentry_operations; | 896 | d_set_d_op(dentry, &ncp_dentry_operations); |
909 | d_add(dentry, inode); | 897 | d_add(dentry, inode); |
910 | error = 0; | 898 | error = 0; |
911 | } | 899 | } |
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 8fb93b604e73..9b39a5dd4131 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/vfs.h> | 29 | #include <linux/vfs.h> |
30 | #include <linux/mount.h> | 30 | #include <linux/mount.h> |
31 | #include <linux/seq_file.h> | 31 | #include <linux/seq_file.h> |
32 | #include <linux/namei.h> | ||
32 | 33 | ||
33 | #include <linux/ncp_fs.h> | 34 | #include <linux/ncp_fs.h> |
34 | 35 | ||
@@ -58,11 +59,18 @@ static struct inode *ncp_alloc_inode(struct super_block *sb) | |||
58 | return &ei->vfs_inode; | 59 | return &ei->vfs_inode; |
59 | } | 60 | } |
60 | 61 | ||
61 | static void ncp_destroy_inode(struct inode *inode) | 62 | static void ncp_i_callback(struct rcu_head *head) |
62 | { | 63 | { |
64 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
65 | INIT_LIST_HEAD(&inode->i_dentry); | ||
63 | kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode)); | 66 | kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode)); |
64 | } | 67 | } |
65 | 68 | ||
69 | static void ncp_destroy_inode(struct inode *inode) | ||
70 | { | ||
71 | call_rcu(&inode->i_rcu, ncp_i_callback); | ||
72 | } | ||
73 | |||
66 | static void init_once(void *foo) | 74 | static void init_once(void *foo) |
67 | { | 75 | { |
68 | struct ncp_inode_info *ei = (struct ncp_inode_info *) foo; | 76 | struct ncp_inode_info *ei = (struct ncp_inode_info *) foo; |
@@ -309,7 +317,12 @@ static void ncp_stop_tasks(struct ncp_server *server) { | |||
309 | sk->sk_write_space = server->write_space; | 317 | sk->sk_write_space = server->write_space; |
310 | release_sock(sk); | 318 | release_sock(sk); |
311 | del_timer_sync(&server->timeout_tm); | 319 | del_timer_sync(&server->timeout_tm); |
312 | flush_scheduled_work(); | 320 | |
321 | flush_work_sync(&server->rcv.tq); | ||
322 | if (sk->sk_socket->type == SOCK_STREAM) | ||
323 | flush_work_sync(&server->tx.tq); | ||
324 | else | ||
325 | flush_work_sync(&server->timeout_tq); | ||
313 | } | 326 | } |
314 | 327 | ||
315 | static int ncp_show_options(struct seq_file *seq, struct vfsmount *mnt) | 328 | static int ncp_show_options(struct seq_file *seq, struct vfsmount *mnt) |
@@ -710,7 +723,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) | |||
710 | sb->s_root = d_alloc_root(root_inode); | 723 | sb->s_root = d_alloc_root(root_inode); |
711 | if (!sb->s_root) | 724 | if (!sb->s_root) |
712 | goto out_no_root; | 725 | goto out_no_root; |
713 | sb->s_root->d_op = &ncp_root_dentry_operations; | 726 | d_set_d_op(sb->s_root, &ncp_root_dentry_operations); |
714 | return 0; | 727 | return 0; |
715 | 728 | ||
716 | out_no_root: | 729 | out_no_root: |
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h index 3c57eca634ce..1220df75ff22 100644 --- a/fs/ncpfs/ncplib_kernel.h +++ b/fs/ncpfs/ncplib_kernel.h | |||
@@ -135,7 +135,7 @@ int ncp__vol2io(struct ncp_server *, unsigned char *, unsigned int *, | |||
135 | const unsigned char *, unsigned int, int); | 135 | const unsigned char *, unsigned int, int); |
136 | 136 | ||
137 | #define NCP_ESC ':' | 137 | #define NCP_ESC ':' |
138 | #define NCP_IO_TABLE(dentry) (NCP_SERVER((dentry)->d_inode)->nls_io) | 138 | #define NCP_IO_TABLE(sb) (NCP_SBP(sb)->nls_io) |
139 | #define ncp_tolower(t, c) nls_tolower(t, c) | 139 | #define ncp_tolower(t, c) nls_tolower(t, c) |
140 | #define ncp_toupper(t, c) nls_toupper(t, c) | 140 | #define ncp_toupper(t, c) nls_toupper(t, c) |
141 | #define ncp_strnicmp(t, s1, s2, len) \ | 141 | #define ncp_strnicmp(t, s1, s2, len) \ |
@@ -150,15 +150,15 @@ int ncp__io2vol(unsigned char *, unsigned int *, | |||
150 | int ncp__vol2io(unsigned char *, unsigned int *, | 150 | int ncp__vol2io(unsigned char *, unsigned int *, |
151 | const unsigned char *, unsigned int, int); | 151 | const unsigned char *, unsigned int, int); |
152 | 152 | ||
153 | #define NCP_IO_TABLE(dentry) NULL | 153 | #define NCP_IO_TABLE(sb) NULL |
154 | #define ncp_tolower(t, c) tolower(c) | 154 | #define ncp_tolower(t, c) tolower(c) |
155 | #define ncp_toupper(t, c) toupper(c) | 155 | #define ncp_toupper(t, c) toupper(c) |
156 | #define ncp_io2vol(S,m,i,n,k,U) ncp__io2vol(m,i,n,k,U) | 156 | #define ncp_io2vol(S,m,i,n,k,U) ncp__io2vol(m,i,n,k,U) |
157 | #define ncp_vol2io(S,m,i,n,k,U) ncp__vol2io(m,i,n,k,U) | 157 | #define ncp_vol2io(S,m,i,n,k,U) ncp__vol2io(m,i,n,k,U) |
158 | 158 | ||
159 | 159 | ||
160 | static inline int ncp_strnicmp(struct nls_table *t, const unsigned char *s1, | 160 | static inline int ncp_strnicmp(const struct nls_table *t, |
161 | const unsigned char *s2, int len) | 161 | const unsigned char *s1, const unsigned char *s2, int len) |
162 | { | 162 | { |
163 | while (len--) { | 163 | while (len--) { |
164 | if (tolower(*s1++) != tolower(*s2++)) | 164 | if (tolower(*s1++) != tolower(*s2++)) |
@@ -193,7 +193,7 @@ ncp_renew_dentries(struct dentry *parent) | |||
193 | struct list_head *next; | 193 | struct list_head *next; |
194 | struct dentry *dentry; | 194 | struct dentry *dentry; |
195 | 195 | ||
196 | spin_lock(&dcache_lock); | 196 | spin_lock(&parent->d_lock); |
197 | next = parent->d_subdirs.next; | 197 | next = parent->d_subdirs.next; |
198 | while (next != &parent->d_subdirs) { | 198 | while (next != &parent->d_subdirs) { |
199 | dentry = list_entry(next, struct dentry, d_u.d_child); | 199 | dentry = list_entry(next, struct dentry, d_u.d_child); |
@@ -205,7 +205,7 @@ ncp_renew_dentries(struct dentry *parent) | |||
205 | 205 | ||
206 | next = next->next; | 206 | next = next->next; |
207 | } | 207 | } |
208 | spin_unlock(&dcache_lock); | 208 | spin_unlock(&parent->d_lock); |
209 | } | 209 | } |
210 | 210 | ||
211 | static inline void | 211 | static inline void |
@@ -215,7 +215,7 @@ ncp_invalidate_dircache_entries(struct dentry *parent) | |||
215 | struct list_head *next; | 215 | struct list_head *next; |
216 | struct dentry *dentry; | 216 | struct dentry *dentry; |
217 | 217 | ||
218 | spin_lock(&dcache_lock); | 218 | spin_lock(&parent->d_lock); |
219 | next = parent->d_subdirs.next; | 219 | next = parent->d_subdirs.next; |
220 | while (next != &parent->d_subdirs) { | 220 | while (next != &parent->d_subdirs) { |
221 | dentry = list_entry(next, struct dentry, d_u.d_child); | 221 | dentry = list_entry(next, struct dentry, d_u.d_child); |
@@ -223,7 +223,7 @@ ncp_invalidate_dircache_entries(struct dentry *parent) | |||
223 | ncp_age_dentry(server, dentry); | 223 | ncp_age_dentry(server, dentry); |
224 | next = next->next; | 224 | next = next->next; |
225 | } | 225 | } |
226 | spin_unlock(&dcache_lock); | 226 | spin_unlock(&parent->d_lock); |
227 | } | 227 | } |
228 | 228 | ||
229 | struct ncp_cache_head { | 229 | struct ncp_cache_head { |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index f0a384e2ae63..d33da530097a 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -57,7 +57,7 @@ static int nfs_rename(struct inode *, struct dentry *, | |||
57 | struct inode *, struct dentry *); | 57 | struct inode *, struct dentry *); |
58 | static int nfs_fsync_dir(struct file *, int); | 58 | static int nfs_fsync_dir(struct file *, int); |
59 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); | 59 | static loff_t nfs_llseek_dir(struct file *, loff_t, int); |
60 | static int nfs_readdir_clear_array(struct page*, gfp_t); | 60 | static void nfs_readdir_clear_array(struct page*); |
61 | 61 | ||
62 | const struct file_operations nfs_dir_operations = { | 62 | const struct file_operations nfs_dir_operations = { |
63 | .llseek = nfs_llseek_dir, | 63 | .llseek = nfs_llseek_dir, |
@@ -83,8 +83,8 @@ const struct inode_operations nfs_dir_inode_operations = { | |||
83 | .setattr = nfs_setattr, | 83 | .setattr = nfs_setattr, |
84 | }; | 84 | }; |
85 | 85 | ||
86 | const struct address_space_operations nfs_dir_addr_space_ops = { | 86 | const struct address_space_operations nfs_dir_aops = { |
87 | .releasepage = nfs_readdir_clear_array, | 87 | .freepage = nfs_readdir_clear_array, |
88 | }; | 88 | }; |
89 | 89 | ||
90 | #ifdef CONFIG_NFS_V3 | 90 | #ifdef CONFIG_NFS_V3 |
@@ -178,6 +178,7 @@ typedef struct { | |||
178 | struct page *page; | 178 | struct page *page; |
179 | unsigned long page_index; | 179 | unsigned long page_index; |
180 | u64 *dir_cookie; | 180 | u64 *dir_cookie; |
181 | u64 last_cookie; | ||
181 | loff_t current_index; | 182 | loff_t current_index; |
182 | decode_dirent_t decode; | 183 | decode_dirent_t decode; |
183 | 184 | ||
@@ -213,17 +214,15 @@ void nfs_readdir_release_array(struct page *page) | |||
213 | * we are freeing strings created by nfs_add_to_readdir_array() | 214 | * we are freeing strings created by nfs_add_to_readdir_array() |
214 | */ | 215 | */ |
215 | static | 216 | static |
216 | int nfs_readdir_clear_array(struct page *page, gfp_t mask) | 217 | void nfs_readdir_clear_array(struct page *page) |
217 | { | 218 | { |
218 | struct nfs_cache_array *array = nfs_readdir_get_array(page); | 219 | struct nfs_cache_array *array; |
219 | int i; | 220 | int i; |
220 | 221 | ||
221 | if (IS_ERR(array)) | 222 | array = kmap_atomic(page, KM_USER0); |
222 | return PTR_ERR(array); | ||
223 | for (i = 0; i < array->size; i++) | 223 | for (i = 0; i < array->size; i++) |
224 | kfree(array->array[i].string.name); | 224 | kfree(array->array[i].string.name); |
225 | nfs_readdir_release_array(page); | 225 | kunmap_atomic(array, KM_USER0); |
226 | return 0; | ||
227 | } | 226 | } |
228 | 227 | ||
229 | /* | 228 | /* |
@@ -272,7 +271,7 @@ int nfs_readdir_add_to_array(struct nfs_entry *entry, struct page *page) | |||
272 | goto out; | 271 | goto out; |
273 | array->last_cookie = entry->cookie; | 272 | array->last_cookie = entry->cookie; |
274 | array->size++; | 273 | array->size++; |
275 | if (entry->eof == 1) | 274 | if (entry->eof != 0) |
276 | array->eof_index = array->size; | 275 | array->eof_index = array->size; |
277 | out: | 276 | out: |
278 | nfs_readdir_release_array(page); | 277 | nfs_readdir_release_array(page); |
@@ -312,15 +311,14 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des | |||
312 | for (i = 0; i < array->size; i++) { | 311 | for (i = 0; i < array->size; i++) { |
313 | if (array->array[i].cookie == *desc->dir_cookie) { | 312 | if (array->array[i].cookie == *desc->dir_cookie) { |
314 | desc->cache_entry_index = i; | 313 | desc->cache_entry_index = i; |
315 | status = 0; | 314 | return 0; |
316 | goto out; | ||
317 | } | 315 | } |
318 | } | 316 | } |
319 | if (i == array->eof_index) { | 317 | if (array->eof_index >= 0) { |
320 | desc->eof = 1; | ||
321 | status = -EBADCOOKIE; | 318 | status = -EBADCOOKIE; |
319 | if (*desc->dir_cookie == array->last_cookie) | ||
320 | desc->eof = 1; | ||
322 | } | 321 | } |
323 | out: | ||
324 | return status; | 322 | return status; |
325 | } | 323 | } |
326 | 324 | ||
@@ -328,10 +326,7 @@ static | |||
328 | int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc) | 326 | int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc) |
329 | { | 327 | { |
330 | struct nfs_cache_array *array; | 328 | struct nfs_cache_array *array; |
331 | int status = -EBADCOOKIE; | 329 | int status; |
332 | |||
333 | if (desc->dir_cookie == NULL) | ||
334 | goto out; | ||
335 | 330 | ||
336 | array = nfs_readdir_get_array(desc->page); | 331 | array = nfs_readdir_get_array(desc->page); |
337 | if (IS_ERR(array)) { | 332 | if (IS_ERR(array)) { |
@@ -344,6 +339,10 @@ int nfs_readdir_search_array(nfs_readdir_descriptor_t *desc) | |||
344 | else | 339 | else |
345 | status = nfs_readdir_search_for_cookie(array, desc); | 340 | status = nfs_readdir_search_for_cookie(array, desc); |
346 | 341 | ||
342 | if (status == -EAGAIN) { | ||
343 | desc->last_cookie = array->last_cookie; | ||
344 | desc->page_index++; | ||
345 | } | ||
347 | nfs_readdir_release_array(desc->page); | 346 | nfs_readdir_release_array(desc->page); |
348 | out: | 347 | out: |
349 | return status; | 348 | return status; |
@@ -439,7 +438,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) | |||
439 | if (dentry == NULL) | 438 | if (dentry == NULL) |
440 | return; | 439 | return; |
441 | 440 | ||
442 | dentry->d_op = NFS_PROTO(dir)->dentry_ops; | 441 | d_set_d_op(dentry, NFS_PROTO(dir)->dentry_ops); |
443 | inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr); | 442 | inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr); |
444 | if (IS_ERR(inode)) | 443 | if (IS_ERR(inode)) |
445 | goto out; | 444 | goto out; |
@@ -490,7 +489,7 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en | |||
490 | 489 | ||
491 | count++; | 490 | count++; |
492 | 491 | ||
493 | if (desc->plus == 1) | 492 | if (desc->plus != 0) |
494 | nfs_prime_dcache(desc->file->f_path.dentry, entry); | 493 | nfs_prime_dcache(desc->file->f_path.dentry, entry); |
495 | 494 | ||
496 | status = nfs_readdir_add_to_array(entry, page); | 495 | status = nfs_readdir_add_to_array(entry, page); |
@@ -498,7 +497,7 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en | |||
498 | break; | 497 | break; |
499 | } while (!entry->eof); | 498 | } while (!entry->eof); |
500 | 499 | ||
501 | if (count == 0 || (status == -EBADCOOKIE && entry->eof == 1)) { | 500 | if (count == 0 || (status == -EBADCOOKIE && entry->eof != 0)) { |
502 | array = nfs_readdir_get_array(page); | 501 | array = nfs_readdir_get_array(page); |
503 | if (!IS_ERR(array)) { | 502 | if (!IS_ERR(array)) { |
504 | array->eof_index = array->size; | 503 | array->eof_index = array->size; |
@@ -563,7 +562,7 @@ int nfs_readdir_xdr_to_array(nfs_readdir_descriptor_t *desc, struct page *page, | |||
563 | unsigned int array_size = ARRAY_SIZE(pages); | 562 | unsigned int array_size = ARRAY_SIZE(pages); |
564 | 563 | ||
565 | entry.prev_cookie = 0; | 564 | entry.prev_cookie = 0; |
566 | entry.cookie = *desc->dir_cookie; | 565 | entry.cookie = desc->last_cookie; |
567 | entry.eof = 0; | 566 | entry.eof = 0; |
568 | entry.fh = nfs_alloc_fhandle(); | 567 | entry.fh = nfs_alloc_fhandle(); |
569 | entry.fattr = nfs_alloc_fattr(); | 568 | entry.fattr = nfs_alloc_fattr(); |
@@ -636,6 +635,8 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page* page) | |||
636 | static | 635 | static |
637 | void cache_page_release(nfs_readdir_descriptor_t *desc) | 636 | void cache_page_release(nfs_readdir_descriptor_t *desc) |
638 | { | 637 | { |
638 | if (!desc->page->mapping) | ||
639 | nfs_readdir_clear_array(desc->page); | ||
639 | page_cache_release(desc->page); | 640 | page_cache_release(desc->page); |
640 | desc->page = NULL; | 641 | desc->page = NULL; |
641 | } | 642 | } |
@@ -660,9 +661,8 @@ int find_cache_page(nfs_readdir_descriptor_t *desc) | |||
660 | return PTR_ERR(desc->page); | 661 | return PTR_ERR(desc->page); |
661 | 662 | ||
662 | res = nfs_readdir_search_array(desc); | 663 | res = nfs_readdir_search_array(desc); |
663 | if (res == 0) | 664 | if (res != 0) |
664 | return 0; | 665 | cache_page_release(desc); |
665 | cache_page_release(desc); | ||
666 | return res; | 666 | return res; |
667 | } | 667 | } |
668 | 668 | ||
@@ -672,22 +672,16 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) | |||
672 | { | 672 | { |
673 | int res; | 673 | int res; |
674 | 674 | ||
675 | if (desc->page_index == 0) | 675 | if (desc->page_index == 0) { |
676 | desc->current_index = 0; | 676 | desc->current_index = 0; |
677 | while (1) { | 677 | desc->last_cookie = 0; |
678 | res = find_cache_page(desc); | ||
679 | if (res != -EAGAIN) | ||
680 | break; | ||
681 | desc->page_index++; | ||
682 | } | 678 | } |
679 | do { | ||
680 | res = find_cache_page(desc); | ||
681 | } while (res == -EAGAIN); | ||
683 | return res; | 682 | return res; |
684 | } | 683 | } |
685 | 684 | ||
686 | static inline unsigned int dt_type(struct inode *inode) | ||
687 | { | ||
688 | return (inode->i_mode >> 12) & 15; | ||
689 | } | ||
690 | |||
691 | /* | 685 | /* |
692 | * Once we've found the start of the dirent within a page: fill 'er up... | 686 | * Once we've found the start of the dirent within a page: fill 'er up... |
693 | */ | 687 | */ |
@@ -717,13 +711,12 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
717 | break; | 711 | break; |
718 | } | 712 | } |
719 | file->f_pos++; | 713 | file->f_pos++; |
720 | desc->cache_entry_index = i; | ||
721 | if (i < (array->size-1)) | 714 | if (i < (array->size-1)) |
722 | *desc->dir_cookie = array->array[i+1].cookie; | 715 | *desc->dir_cookie = array->array[i+1].cookie; |
723 | else | 716 | else |
724 | *desc->dir_cookie = array->last_cookie; | 717 | *desc->dir_cookie = array->last_cookie; |
725 | } | 718 | } |
726 | if (i == array->eof_index) | 719 | if (array->eof_index >= 0) |
727 | desc->eof = 1; | 720 | desc->eof = 1; |
728 | 721 | ||
729 | nfs_readdir_release_array(desc->page); | 722 | nfs_readdir_release_array(desc->page); |
@@ -764,6 +757,7 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, | |||
764 | } | 757 | } |
765 | 758 | ||
766 | desc->page_index = 0; | 759 | desc->page_index = 0; |
760 | desc->last_cookie = *desc->dir_cookie; | ||
767 | desc->page = page; | 761 | desc->page = page; |
768 | 762 | ||
769 | status = nfs_readdir_xdr_to_array(desc, page, inode); | 763 | status = nfs_readdir_xdr_to_array(desc, page, inode); |
@@ -791,7 +785,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
791 | struct inode *inode = dentry->d_inode; | 785 | struct inode *inode = dentry->d_inode; |
792 | nfs_readdir_descriptor_t my_desc, | 786 | nfs_readdir_descriptor_t my_desc, |
793 | *desc = &my_desc; | 787 | *desc = &my_desc; |
794 | int res = -ENOMEM; | 788 | int res; |
795 | 789 | ||
796 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", | 790 | dfprintk(FILE, "NFS: readdir(%s/%s) starting at cookie %llu\n", |
797 | dentry->d_parent->d_name.name, dentry->d_name.name, | 791 | dentry->d_parent->d_name.name, dentry->d_name.name, |
@@ -816,7 +810,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
816 | if (res < 0) | 810 | if (res < 0) |
817 | goto out; | 811 | goto out; |
818 | 812 | ||
819 | while (desc->eof != 1) { | 813 | do { |
820 | res = readdir_search_pagecache(desc); | 814 | res = readdir_search_pagecache(desc); |
821 | 815 | ||
822 | if (res == -EBADCOOKIE) { | 816 | if (res == -EBADCOOKIE) { |
@@ -844,7 +838,7 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
844 | res = nfs_do_filldir(desc, dirent, filldir); | 838 | res = nfs_do_filldir(desc, dirent, filldir); |
845 | if (res < 0) | 839 | if (res < 0) |
846 | break; | 840 | break; |
847 | } | 841 | } while (!desc->eof); |
848 | out: | 842 | out: |
849 | nfs_unblock_sillyrename(dentry); | 843 | nfs_unblock_sillyrename(dentry); |
850 | if (res > 0) | 844 | if (res > 0) |
@@ -944,7 +938,8 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry) | |||
944 | * component of the path. | 938 | * component of the path. |
945 | * We check for this using LOOKUP_CONTINUE and LOOKUP_PARENT. | 939 | * We check for this using LOOKUP_CONTINUE and LOOKUP_PARENT. |
946 | */ | 940 | */ |
947 | static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd, unsigned int mask) | 941 | static inline unsigned int nfs_lookup_check_intent(struct nameidata *nd, |
942 | unsigned int mask) | ||
948 | { | 943 | { |
949 | if (nd->flags & (LOOKUP_CONTINUE|LOOKUP_PARENT)) | 944 | if (nd->flags & (LOOKUP_CONTINUE|LOOKUP_PARENT)) |
950 | return 0; | 945 | return 0; |
@@ -1024,7 +1019,7 @@ int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry, | |||
1024 | * If the parent directory is seen to have changed, we throw out the | 1019 | * If the parent directory is seen to have changed, we throw out the |
1025 | * cached dentry and do a new lookup. | 1020 | * cached dentry and do a new lookup. |
1026 | */ | 1021 | */ |
1027 | static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) | 1022 | static int nfs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd) |
1028 | { | 1023 | { |
1029 | struct inode *dir; | 1024 | struct inode *dir; |
1030 | struct inode *inode; | 1025 | struct inode *inode; |
@@ -1033,6 +1028,9 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
1033 | struct nfs_fattr *fattr = NULL; | 1028 | struct nfs_fattr *fattr = NULL; |
1034 | int error; | 1029 | int error; |
1035 | 1030 | ||
1031 | if (nd->flags & LOOKUP_RCU) | ||
1032 | return -ECHILD; | ||
1033 | |||
1036 | parent = dget_parent(dentry); | 1034 | parent = dget_parent(dentry); |
1037 | dir = parent->d_inode; | 1035 | dir = parent->d_inode; |
1038 | nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE); | 1036 | nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE); |
@@ -1123,7 +1121,7 @@ out_error: | |||
1123 | /* | 1121 | /* |
1124 | * This is called from dput() when d_count is going to 0. | 1122 | * This is called from dput() when d_count is going to 0. |
1125 | */ | 1123 | */ |
1126 | static int nfs_dentry_delete(struct dentry *dentry) | 1124 | static int nfs_dentry_delete(const struct dentry *dentry) |
1127 | { | 1125 | { |
1128 | dfprintk(VFS, "NFS: dentry_delete(%s/%s, %x)\n", | 1126 | dfprintk(VFS, "NFS: dentry_delete(%s/%s, %x)\n", |
1129 | dentry->d_parent->d_name.name, dentry->d_name.name, | 1127 | dentry->d_parent->d_name.name, dentry->d_name.name, |
@@ -1194,7 +1192,7 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru | |||
1194 | if (dentry->d_name.len > NFS_SERVER(dir)->namelen) | 1192 | if (dentry->d_name.len > NFS_SERVER(dir)->namelen) |
1195 | goto out; | 1193 | goto out; |
1196 | 1194 | ||
1197 | dentry->d_op = NFS_PROTO(dir)->dentry_ops; | 1195 | d_set_d_op(dentry, NFS_PROTO(dir)->dentry_ops); |
1198 | 1196 | ||
1199 | /* | 1197 | /* |
1200 | * If we're doing an exclusive create, optimize away the lookup | 1198 | * If we're doing an exclusive create, optimize away the lookup |
@@ -1339,7 +1337,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry | |||
1339 | res = ERR_PTR(-ENAMETOOLONG); | 1337 | res = ERR_PTR(-ENAMETOOLONG); |
1340 | goto out; | 1338 | goto out; |
1341 | } | 1339 | } |
1342 | dentry->d_op = NFS_PROTO(dir)->dentry_ops; | 1340 | d_set_d_op(dentry, NFS_PROTO(dir)->dentry_ops); |
1343 | 1341 | ||
1344 | /* Let vfs_create() deal with O_EXCL. Instantiate, but don't hash | 1342 | /* Let vfs_create() deal with O_EXCL. Instantiate, but don't hash |
1345 | * the dentry. */ | 1343 | * the dentry. */ |
@@ -1724,11 +1722,9 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry) | |||
1724 | dfprintk(VFS, "NFS: unlink(%s/%ld, %s)\n", dir->i_sb->s_id, | 1722 | dfprintk(VFS, "NFS: unlink(%s/%ld, %s)\n", dir->i_sb->s_id, |
1725 | dir->i_ino, dentry->d_name.name); | 1723 | dir->i_ino, dentry->d_name.name); |
1726 | 1724 | ||
1727 | spin_lock(&dcache_lock); | ||
1728 | spin_lock(&dentry->d_lock); | 1725 | spin_lock(&dentry->d_lock); |
1729 | if (atomic_read(&dentry->d_count) > 1) { | 1726 | if (dentry->d_count > 1) { |
1730 | spin_unlock(&dentry->d_lock); | 1727 | spin_unlock(&dentry->d_lock); |
1731 | spin_unlock(&dcache_lock); | ||
1732 | /* Start asynchronous writeout of the inode */ | 1728 | /* Start asynchronous writeout of the inode */ |
1733 | write_inode_now(dentry->d_inode, 0); | 1729 | write_inode_now(dentry->d_inode, 0); |
1734 | error = nfs_sillyrename(dir, dentry); | 1730 | error = nfs_sillyrename(dir, dentry); |
@@ -1739,7 +1735,6 @@ static int nfs_unlink(struct inode *dir, struct dentry *dentry) | |||
1739 | need_rehash = 1; | 1735 | need_rehash = 1; |
1740 | } | 1736 | } |
1741 | spin_unlock(&dentry->d_lock); | 1737 | spin_unlock(&dentry->d_lock); |
1742 | spin_unlock(&dcache_lock); | ||
1743 | error = nfs_safe_remove(dentry); | 1738 | error = nfs_safe_remove(dentry); |
1744 | if (!error || error == -ENOENT) { | 1739 | if (!error || error == -ENOENT) { |
1745 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 1740 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
@@ -1874,7 +1869,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1874 | dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n", | 1869 | dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n", |
1875 | old_dentry->d_parent->d_name.name, old_dentry->d_name.name, | 1870 | old_dentry->d_parent->d_name.name, old_dentry->d_name.name, |
1876 | new_dentry->d_parent->d_name.name, new_dentry->d_name.name, | 1871 | new_dentry->d_parent->d_name.name, new_dentry->d_name.name, |
1877 | atomic_read(&new_dentry->d_count)); | 1872 | new_dentry->d_count); |
1878 | 1873 | ||
1879 | /* | 1874 | /* |
1880 | * For non-directories, check whether the target is busy and if so, | 1875 | * For non-directories, check whether the target is busy and if so, |
@@ -1892,7 +1887,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1892 | rehash = new_dentry; | 1887 | rehash = new_dentry; |
1893 | } | 1888 | } |
1894 | 1889 | ||
1895 | if (atomic_read(&new_dentry->d_count) > 2) { | 1890 | if (new_dentry->d_count > 2) { |
1896 | int err; | 1891 | int err; |
1897 | 1892 | ||
1898 | /* copy the target dentry's name */ | 1893 | /* copy the target dentry's name */ |
@@ -2194,11 +2189,14 @@ int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags) | |||
2194 | return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags)); | 2189 | return nfs_do_access(inode, cred, nfs_open_permission_mask(openflags)); |
2195 | } | 2190 | } |
2196 | 2191 | ||
2197 | int nfs_permission(struct inode *inode, int mask) | 2192 | int nfs_permission(struct inode *inode, int mask, unsigned int flags) |
2198 | { | 2193 | { |
2199 | struct rpc_cred *cred; | 2194 | struct rpc_cred *cred; |
2200 | int res = 0; | 2195 | int res = 0; |
2201 | 2196 | ||
2197 | if (flags & IPERM_FLAG_RCU) | ||
2198 | return -ECHILD; | ||
2199 | |||
2202 | nfs_inc_stats(inode, NFSIOS_VFSACCESS); | 2200 | nfs_inc_stats(inode, NFSIOS_VFSACCESS); |
2203 | 2201 | ||
2204 | if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0) | 2202 | if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0) |
@@ -2246,7 +2244,7 @@ out: | |||
2246 | out_notsup: | 2244 | out_notsup: |
2247 | res = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 2245 | res = nfs_revalidate_inode(NFS_SERVER(inode), inode); |
2248 | if (res == 0) | 2246 | if (res == 0) |
2249 | res = generic_permission(inode, mask, NULL); | 2247 | res = generic_permission(inode, mask, flags, NULL); |
2250 | goto out; | 2248 | goto out; |
2251 | } | 2249 | } |
2252 | 2250 | ||
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 60677f9f1311..7bf029ef4084 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -693,6 +693,7 @@ do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) | |||
693 | { | 693 | { |
694 | struct inode *inode = filp->f_mapping->host; | 694 | struct inode *inode = filp->f_mapping->host; |
695 | int status = 0; | 695 | int status = 0; |
696 | unsigned int saved_type = fl->fl_type; | ||
696 | 697 | ||
697 | /* Try local locking first */ | 698 | /* Try local locking first */ |
698 | posix_test_lock(filp, fl); | 699 | posix_test_lock(filp, fl); |
@@ -700,6 +701,7 @@ do_getlk(struct file *filp, int cmd, struct file_lock *fl, int is_local) | |||
700 | /* found a conflict */ | 701 | /* found a conflict */ |
701 | goto out; | 702 | goto out; |
702 | } | 703 | } |
704 | fl->fl_type = saved_type; | ||
703 | 705 | ||
704 | if (nfs_have_delegation(inode, FMODE_READ)) | 706 | if (nfs_have_delegation(inode, FMODE_READ)) |
705 | goto out_noconflict; | 707 | goto out_noconflict; |
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index ac7b814ce162..5596c6a2881e 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c | |||
@@ -63,9 +63,11 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i | |||
63 | * This again causes shrink_dcache_for_umount_subtree() to | 63 | * This again causes shrink_dcache_for_umount_subtree() to |
64 | * Oops, since the test for IS_ROOT() will fail. | 64 | * Oops, since the test for IS_ROOT() will fail. |
65 | */ | 65 | */ |
66 | spin_lock(&dcache_lock); | 66 | spin_lock(&sb->s_root->d_inode->i_lock); |
67 | spin_lock(&sb->s_root->d_lock); | ||
67 | list_del_init(&sb->s_root->d_alias); | 68 | list_del_init(&sb->s_root->d_alias); |
68 | spin_unlock(&dcache_lock); | 69 | spin_unlock(&sb->s_root->d_lock); |
70 | spin_unlock(&sb->s_root->d_inode->i_lock); | ||
69 | } | 71 | } |
70 | return 0; | 72 | return 0; |
71 | } | 73 | } |
@@ -119,7 +121,7 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) | |||
119 | security_d_instantiate(ret, inode); | 121 | security_d_instantiate(ret, inode); |
120 | 122 | ||
121 | if (ret->d_op == NULL) | 123 | if (ret->d_op == NULL) |
122 | ret->d_op = server->nfs_client->rpc_ops->dentry_ops; | 124 | d_set_d_op(ret, server->nfs_client->rpc_ops->dentry_ops); |
123 | out: | 125 | out: |
124 | nfs_free_fattr(fsinfo.fattr); | 126 | nfs_free_fattr(fsinfo.fattr); |
125 | return ret; | 127 | return ret; |
@@ -226,7 +228,7 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) | |||
226 | security_d_instantiate(ret, inode); | 228 | security_d_instantiate(ret, inode); |
227 | 229 | ||
228 | if (ret->d_op == NULL) | 230 | if (ret->d_op == NULL) |
229 | ret->d_op = server->nfs_client->rpc_ops->dentry_ops; | 231 | d_set_d_op(ret, server->nfs_client->rpc_ops->dentry_ops); |
230 | 232 | ||
231 | out: | 233 | out: |
232 | nfs_free_fattr(fattr); | 234 | nfs_free_fattr(fattr); |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 314f57164602..017daa3bed38 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -289,6 +289,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) | |||
289 | } else if (S_ISDIR(inode->i_mode)) { | 289 | } else if (S_ISDIR(inode->i_mode)) { |
290 | inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops; | 290 | inode->i_op = NFS_SB(sb)->nfs_client->rpc_ops->dir_inode_ops; |
291 | inode->i_fop = &nfs_dir_operations; | 291 | inode->i_fop = &nfs_dir_operations; |
292 | inode->i_data.a_ops = &nfs_dir_aops; | ||
292 | if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)) | 293 | if (nfs_server_capable(inode, NFS_CAP_READDIRPLUS)) |
293 | set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); | 294 | set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); |
294 | /* Deal with crossing mountpoints */ | 295 | /* Deal with crossing mountpoints */ |
@@ -1437,11 +1438,18 @@ struct inode *nfs_alloc_inode(struct super_block *sb) | |||
1437 | return &nfsi->vfs_inode; | 1438 | return &nfsi->vfs_inode; |
1438 | } | 1439 | } |
1439 | 1440 | ||
1440 | void nfs_destroy_inode(struct inode *inode) | 1441 | static void nfs_i_callback(struct rcu_head *head) |
1441 | { | 1442 | { |
1443 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
1444 | INIT_LIST_HEAD(&inode->i_dentry); | ||
1442 | kmem_cache_free(nfs_inode_cachep, NFS_I(inode)); | 1445 | kmem_cache_free(nfs_inode_cachep, NFS_I(inode)); |
1443 | } | 1446 | } |
1444 | 1447 | ||
1448 | void nfs_destroy_inode(struct inode *inode) | ||
1449 | { | ||
1450 | call_rcu(&inode->i_rcu, nfs_i_callback); | ||
1451 | } | ||
1452 | |||
1445 | static inline void nfs4_init_once(struct nfs_inode *nfsi) | 1453 | static inline void nfs4_init_once(struct nfs_inode *nfsi) |
1446 | { | 1454 | { |
1447 | #ifdef CONFIG_NFS_V4 | 1455 | #ifdef CONFIG_NFS_V4 |
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c index eceafe74f473..4f981f1f6689 100644 --- a/fs/nfs/mount_clnt.c +++ b/fs/nfs/mount_clnt.c | |||
@@ -505,13 +505,13 @@ static struct rpc_procinfo mnt3_procedures[] = { | |||
505 | 505 | ||
506 | static struct rpc_version mnt_version1 = { | 506 | static struct rpc_version mnt_version1 = { |
507 | .number = 1, | 507 | .number = 1, |
508 | .nrprocs = 2, | 508 | .nrprocs = ARRAY_SIZE(mnt_procedures), |
509 | .procs = mnt_procedures, | 509 | .procs = mnt_procedures, |
510 | }; | 510 | }; |
511 | 511 | ||
512 | static struct rpc_version mnt_version3 = { | 512 | static struct rpc_version mnt_version3 = { |
513 | .number = 3, | 513 | .number = 3, |
514 | .nrprocs = 2, | 514 | .nrprocs = ARRAY_SIZE(mnt3_procedures), |
515 | .procs = mnt3_procedures, | 515 | .procs = mnt3_procedures, |
516 | }; | 516 | }; |
517 | 517 | ||
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index db6aa3673cf3..74aaf3963c10 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -49,12 +49,17 @@ char *nfs_path(const char *base, | |||
49 | const struct dentry *dentry, | 49 | const struct dentry *dentry, |
50 | char *buffer, ssize_t buflen) | 50 | char *buffer, ssize_t buflen) |
51 | { | 51 | { |
52 | char *end = buffer+buflen; | 52 | char *end; |
53 | int namelen; | 53 | int namelen; |
54 | unsigned seq; | ||
54 | 55 | ||
56 | rename_retry: | ||
57 | end = buffer+buflen; | ||
55 | *--end = '\0'; | 58 | *--end = '\0'; |
56 | buflen--; | 59 | buflen--; |
57 | spin_lock(&dcache_lock); | 60 | |
61 | seq = read_seqbegin(&rename_lock); | ||
62 | rcu_read_lock(); | ||
58 | while (!IS_ROOT(dentry) && dentry != droot) { | 63 | while (!IS_ROOT(dentry) && dentry != droot) { |
59 | namelen = dentry->d_name.len; | 64 | namelen = dentry->d_name.len; |
60 | buflen -= namelen + 1; | 65 | buflen -= namelen + 1; |
@@ -65,7 +70,9 @@ char *nfs_path(const char *base, | |||
65 | *--end = '/'; | 70 | *--end = '/'; |
66 | dentry = dentry->d_parent; | 71 | dentry = dentry->d_parent; |
67 | } | 72 | } |
68 | spin_unlock(&dcache_lock); | 73 | rcu_read_unlock(); |
74 | if (read_seqretry(&rename_lock, seq)) | ||
75 | goto rename_retry; | ||
69 | if (*end != '/') { | 76 | if (*end != '/') { |
70 | if (--buflen < 0) | 77 | if (--buflen < 0) |
71 | goto Elong; | 78 | goto Elong; |
@@ -82,7 +89,9 @@ char *nfs_path(const char *base, | |||
82 | memcpy(end, base, namelen); | 89 | memcpy(end, base, namelen); |
83 | return end; | 90 | return end; |
84 | Elong_unlock: | 91 | Elong_unlock: |
85 | spin_unlock(&dcache_lock); | 92 | rcu_read_unlock(); |
93 | if (read_seqretry(&rename_lock, seq)) | ||
94 | goto rename_retry; | ||
86 | Elong: | 95 | Elong: |
87 | return ERR_PTR(-ENAMETOOLONG); | 96 | return ERR_PTR(-ENAMETOOLONG); |
88 | } | 97 | } |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6a653ffd8e4e..4435e5e1f904 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -3361,6 +3361,8 @@ static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen) | |||
3361 | ret = nfs_revalidate_inode(server, inode); | 3361 | ret = nfs_revalidate_inode(server, inode); |
3362 | if (ret < 0) | 3362 | if (ret < 0) |
3363 | return ret; | 3363 | return ret; |
3364 | if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL) | ||
3365 | nfs_zap_acl_cache(inode); | ||
3364 | ret = nfs4_read_cached_acl(inode, buf, buflen); | 3366 | ret = nfs4_read_cached_acl(inode, buf, buflen); |
3365 | if (ret != -ENOENT) | 3367 | if (ret != -ENOENT) |
3366 | return ret; | 3368 | return ret; |
@@ -3389,6 +3391,13 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
3389 | nfs_inode_return_delegation(inode); | 3391 | nfs_inode_return_delegation(inode); |
3390 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | 3392 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); |
3391 | ret = nfs4_call_sync(server, &msg, &arg, &res, 1); | 3393 | ret = nfs4_call_sync(server, &msg, &arg, &res, 1); |
3394 | /* | ||
3395 | * Acl update can result in inode attribute update. | ||
3396 | * so mark the attribute cache invalid. | ||
3397 | */ | ||
3398 | spin_lock(&inode->i_lock); | ||
3399 | NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR; | ||
3400 | spin_unlock(&inode->i_lock); | ||
3392 | nfs_access_zap_cache(inode); | 3401 | nfs_access_zap_cache(inode); |
3393 | nfs_zap_acl_cache(inode); | 3402 | nfs_zap_acl_cache(inode); |
3394 | return ret; | 3403 | return ret; |
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 137b549e63db..b68536cc9046 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -115,7 +115,7 @@ int nfs_set_page_tag_locked(struct nfs_page *req) | |||
115 | { | 115 | { |
116 | if (!nfs_lock_request_dontget(req)) | 116 | if (!nfs_lock_request_dontget(req)) |
117 | return 0; | 117 | return 0; |
118 | if (req->wb_page != NULL) | 118 | if (test_bit(PG_MAPPED, &req->wb_flags)) |
119 | radix_tree_tag_set(&NFS_I(req->wb_context->path.dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); | 119 | radix_tree_tag_set(&NFS_I(req->wb_context->path.dentry->d_inode)->nfs_page_tree, req->wb_index, NFS_PAGE_TAG_LOCKED); |
120 | return 1; | 120 | return 1; |
121 | } | 121 | } |
@@ -125,7 +125,7 @@ int nfs_set_page_tag_locked(struct nfs_page *req) | |||
125 | */ | 125 | */ |
126 | void nfs_clear_page_tag_locked(struct nfs_page *req) | 126 | void nfs_clear_page_tag_locked(struct nfs_page *req) |
127 | { | 127 | { |
128 | if (req->wb_page != NULL) { | 128 | if (test_bit(PG_MAPPED, &req->wb_flags)) { |
129 | struct inode *inode = req->wb_context->path.dentry->d_inode; | 129 | struct inode *inode = req->wb_context->path.dentry->d_inode; |
130 | struct nfs_inode *nfsi = NFS_I(inode); | 130 | struct nfs_inode *nfsi = NFS_I(inode); |
131 | 131 | ||
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index e4b62c6f5a6e..aedcaa7f291f 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -152,7 +152,6 @@ static void nfs_readpage_release(struct nfs_page *req) | |||
152 | (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), | 152 | (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), |
153 | req->wb_bytes, | 153 | req->wb_bytes, |
154 | (long long)req_offset(req)); | 154 | (long long)req_offset(req)); |
155 | nfs_clear_request(req); | ||
156 | nfs_release_request(req); | 155 | nfs_release_request(req); |
157 | } | 156 | } |
158 | 157 | ||
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 3c045044fca2..4100630c9a5b 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -1069,12 +1069,10 @@ static int nfs_parse_mount_options(char *raw, | |||
1069 | mnt->flags |= NFS_MOUNT_VER3; | 1069 | mnt->flags |= NFS_MOUNT_VER3; |
1070 | mnt->version = 3; | 1070 | mnt->version = 3; |
1071 | break; | 1071 | break; |
1072 | #ifdef CONFIG_NFS_V4 | ||
1073 | case Opt_v4: | 1072 | case Opt_v4: |
1074 | mnt->flags &= ~NFS_MOUNT_VER3; | 1073 | mnt->flags &= ~NFS_MOUNT_VER3; |
1075 | mnt->version = 4; | 1074 | mnt->version = 4; |
1076 | break; | 1075 | break; |
1077 | #endif | ||
1078 | case Opt_udp: | 1076 | case Opt_udp: |
1079 | mnt->flags &= ~NFS_MOUNT_TCP; | 1077 | mnt->flags &= ~NFS_MOUNT_TCP; |
1080 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; | 1078 | mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP; |
@@ -1286,12 +1284,10 @@ static int nfs_parse_mount_options(char *raw, | |||
1286 | mnt->flags |= NFS_MOUNT_VER3; | 1284 | mnt->flags |= NFS_MOUNT_VER3; |
1287 | mnt->version = 3; | 1285 | mnt->version = 3; |
1288 | break; | 1286 | break; |
1289 | #ifdef CONFIG_NFS_V4 | ||
1290 | case NFS4_VERSION: | 1287 | case NFS4_VERSION: |
1291 | mnt->flags &= ~NFS_MOUNT_VER3; | 1288 | mnt->flags &= ~NFS_MOUNT_VER3; |
1292 | mnt->version = 4; | 1289 | mnt->version = 4; |
1293 | break; | 1290 | break; |
1294 | #endif | ||
1295 | default: | 1291 | default: |
1296 | goto out_invalid_value; | 1292 | goto out_invalid_value; |
1297 | } | 1293 | } |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 7bdec8531400..8fe9eb47a97f 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
@@ -496,7 +496,7 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) | |||
496 | 496 | ||
497 | dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n", | 497 | dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n", |
498 | dentry->d_parent->d_name.name, dentry->d_name.name, | 498 | dentry->d_parent->d_name.name, dentry->d_name.name, |
499 | atomic_read(&dentry->d_count)); | 499 | dentry->d_count); |
500 | nfs_inc_stats(dir, NFSIOS_SILLYRENAME); | 500 | nfs_inc_stats(dir, NFSIOS_SILLYRENAME); |
501 | 501 | ||
502 | /* | 502 | /* |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 4c14c17a5276..10d648ea128b 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -390,6 +390,7 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req) | |||
390 | if (nfs_have_delegation(inode, FMODE_WRITE)) | 390 | if (nfs_have_delegation(inode, FMODE_WRITE)) |
391 | nfsi->change_attr++; | 391 | nfsi->change_attr++; |
392 | } | 392 | } |
393 | set_bit(PG_MAPPED, &req->wb_flags); | ||
393 | SetPagePrivate(req->wb_page); | 394 | SetPagePrivate(req->wb_page); |
394 | set_page_private(req->wb_page, (unsigned long)req); | 395 | set_page_private(req->wb_page, (unsigned long)req); |
395 | nfsi->npages++; | 396 | nfsi->npages++; |
@@ -415,6 +416,7 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
415 | spin_lock(&inode->i_lock); | 416 | spin_lock(&inode->i_lock); |
416 | set_page_private(req->wb_page, 0); | 417 | set_page_private(req->wb_page, 0); |
417 | ClearPagePrivate(req->wb_page); | 418 | ClearPagePrivate(req->wb_page); |
419 | clear_bit(PG_MAPPED, &req->wb_flags); | ||
418 | radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); | 420 | radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); |
419 | nfsi->npages--; | 421 | nfsi->npages--; |
420 | if (!nfsi->npages) { | 422 | if (!nfsi->npages) { |
@@ -422,7 +424,6 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
422 | iput(inode); | 424 | iput(inode); |
423 | } else | 425 | } else |
424 | spin_unlock(&inode->i_lock); | 426 | spin_unlock(&inode->i_lock); |
425 | nfs_clear_request(req); | ||
426 | nfs_release_request(req); | 427 | nfs_release_request(req); |
427 | } | 428 | } |
428 | 429 | ||
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 2a533a0af2a9..7e84a852cdae 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
@@ -260,9 +260,11 @@ void fill_post_wcc(struct svc_fh *fhp) | |||
260 | err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, | 260 | err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, |
261 | &fhp->fh_post_attr); | 261 | &fhp->fh_post_attr); |
262 | fhp->fh_post_change = fhp->fh_dentry->d_inode->i_version; | 262 | fhp->fh_post_change = fhp->fh_dentry->d_inode->i_version; |
263 | if (err) | 263 | if (err) { |
264 | fhp->fh_post_saved = 0; | 264 | fhp->fh_post_saved = 0; |
265 | else | 265 | /* Grab the ctime anyway - set_change_info might use it */ |
266 | fhp->fh_post_attr.ctime = fhp->fh_dentry->d_inode->i_ctime; | ||
267 | } else | ||
266 | fhp->fh_post_saved = 1; | 268 | fhp->fh_post_saved = 1; |
267 | } | 269 | } |
268 | 270 | ||
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 116cab970e0f..fbd18c3074bb 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -4336,7 +4336,7 @@ __nfs4_state_shutdown(void) | |||
4336 | void | 4336 | void |
4337 | nfs4_state_shutdown(void) | 4337 | nfs4_state_shutdown(void) |
4338 | { | 4338 | { |
4339 | cancel_rearming_delayed_workqueue(laundry_wq, &laundromat_work); | 4339 | cancel_delayed_work_sync(&laundromat_work); |
4340 | destroy_workqueue(laundry_wq); | 4340 | destroy_workqueue(laundry_wq); |
4341 | locks_end_grace(&nfsd4_manager); | 4341 | locks_end_grace(&nfsd4_manager); |
4342 | nfs4_lock_state(); | 4342 | nfs4_lock_state(); |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 184938fcff04..3a359023c9f7 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -1756,8 +1756,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1756 | goto out_dput_new; | 1756 | goto out_dput_new; |
1757 | 1757 | ||
1758 | if (svc_msnfs(ffhp) && | 1758 | if (svc_msnfs(ffhp) && |
1759 | ((atomic_read(&odentry->d_count) > 1) | 1759 | ((odentry->d_count > 1) || (ndentry->d_count > 1))) { |
1760 | || (atomic_read(&ndentry->d_count) > 1))) { | ||
1761 | host_err = -EPERM; | 1760 | host_err = -EPERM; |
1762 | goto out_dput_new; | 1761 | goto out_dput_new; |
1763 | } | 1762 | } |
@@ -1843,7 +1842,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
1843 | if (type != S_IFDIR) { /* It's UNLINK */ | 1842 | if (type != S_IFDIR) { /* It's UNLINK */ |
1844 | #ifdef MSNFS | 1843 | #ifdef MSNFS |
1845 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && | 1844 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && |
1846 | (atomic_read(&rdentry->d_count) > 1)) { | 1845 | (rdentry->d_count > 1)) { |
1847 | host_err = -EPERM; | 1846 | host_err = -EPERM; |
1848 | } else | 1847 | } else |
1849 | #endif | 1848 | #endif |
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 4d476ff08ae6..60fce3dc5cb5 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h | |||
@@ -484,18 +484,17 @@ static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp) | |||
484 | static inline void | 484 | static inline void |
485 | set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) | 485 | set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) |
486 | { | 486 | { |
487 | BUG_ON(!fhp->fh_pre_saved || !fhp->fh_post_saved); | 487 | BUG_ON(!fhp->fh_pre_saved); |
488 | cinfo->atomic = 1; | 488 | cinfo->atomic = fhp->fh_post_saved; |
489 | cinfo->change_supported = IS_I_VERSION(fhp->fh_dentry->d_inode); | 489 | cinfo->change_supported = IS_I_VERSION(fhp->fh_dentry->d_inode); |
490 | if (cinfo->change_supported) { | 490 | |
491 | cinfo->before_change = fhp->fh_pre_change; | 491 | cinfo->before_change = fhp->fh_pre_change; |
492 | cinfo->after_change = fhp->fh_post_change; | 492 | cinfo->after_change = fhp->fh_post_change; |
493 | } else { | 493 | cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec; |
494 | cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec; | 494 | cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec; |
495 | cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec; | 495 | cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec; |
496 | cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec; | 496 | cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec; |
497 | cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec; | 497 | |
498 | } | ||
499 | } | 498 | } |
500 | 499 | ||
501 | int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *); | 500 | int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *); |
diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c index 8b782b062baa..3ee67c67cc52 100644 --- a/fs/nilfs2/bmap.c +++ b/fs/nilfs2/bmap.c | |||
@@ -35,7 +35,20 @@ | |||
35 | 35 | ||
36 | struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *bmap) | 36 | struct inode *nilfs_bmap_get_dat(const struct nilfs_bmap *bmap) |
37 | { | 37 | { |
38 | return nilfs_dat_inode(NILFS_I_NILFS(bmap->b_inode)); | 38 | return NILFS_I_NILFS(bmap->b_inode)->ns_dat; |
39 | } | ||
40 | |||
41 | static int nilfs_bmap_convert_error(struct nilfs_bmap *bmap, | ||
42 | const char *fname, int err) | ||
43 | { | ||
44 | struct inode *inode = bmap->b_inode; | ||
45 | |||
46 | if (err == -EINVAL) { | ||
47 | nilfs_error(inode->i_sb, fname, | ||
48 | "broken bmap (inode number=%lu)\n", inode->i_ino); | ||
49 | err = -EIO; | ||
50 | } | ||
51 | return err; | ||
39 | } | 52 | } |
40 | 53 | ||
41 | /** | 54 | /** |
@@ -66,8 +79,10 @@ int nilfs_bmap_lookup_at_level(struct nilfs_bmap *bmap, __u64 key, int level, | |||
66 | 79 | ||
67 | down_read(&bmap->b_sem); | 80 | down_read(&bmap->b_sem); |
68 | ret = bmap->b_ops->bop_lookup(bmap, key, level, ptrp); | 81 | ret = bmap->b_ops->bop_lookup(bmap, key, level, ptrp); |
69 | if (ret < 0) | 82 | if (ret < 0) { |
83 | ret = nilfs_bmap_convert_error(bmap, __func__, ret); | ||
70 | goto out; | 84 | goto out; |
85 | } | ||
71 | if (NILFS_BMAP_USE_VBN(bmap)) { | 86 | if (NILFS_BMAP_USE_VBN(bmap)) { |
72 | ret = nilfs_dat_translate(nilfs_bmap_get_dat(bmap), *ptrp, | 87 | ret = nilfs_dat_translate(nilfs_bmap_get_dat(bmap), *ptrp, |
73 | &blocknr); | 88 | &blocknr); |
@@ -88,7 +103,8 @@ int nilfs_bmap_lookup_contig(struct nilfs_bmap *bmap, __u64 key, __u64 *ptrp, | |||
88 | down_read(&bmap->b_sem); | 103 | down_read(&bmap->b_sem); |
89 | ret = bmap->b_ops->bop_lookup_contig(bmap, key, ptrp, maxblocks); | 104 | ret = bmap->b_ops->bop_lookup_contig(bmap, key, ptrp, maxblocks); |
90 | up_read(&bmap->b_sem); | 105 | up_read(&bmap->b_sem); |
91 | return ret; | 106 | |
107 | return nilfs_bmap_convert_error(bmap, __func__, ret); | ||
92 | } | 108 | } |
93 | 109 | ||
94 | static int nilfs_bmap_do_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) | 110 | static int nilfs_bmap_do_insert(struct nilfs_bmap *bmap, __u64 key, __u64 ptr) |
@@ -144,7 +160,8 @@ int nilfs_bmap_insert(struct nilfs_bmap *bmap, | |||
144 | down_write(&bmap->b_sem); | 160 | down_write(&bmap->b_sem); |
145 | ret = nilfs_bmap_do_insert(bmap, key, rec); | 161 | ret = nilfs_bmap_do_insert(bmap, key, rec); |
146 | up_write(&bmap->b_sem); | 162 | up_write(&bmap->b_sem); |
147 | return ret; | 163 | |
164 | return nilfs_bmap_convert_error(bmap, __func__, ret); | ||
148 | } | 165 | } |
149 | 166 | ||
150 | static int nilfs_bmap_do_delete(struct nilfs_bmap *bmap, __u64 key) | 167 | static int nilfs_bmap_do_delete(struct nilfs_bmap *bmap, __u64 key) |
@@ -180,9 +197,12 @@ int nilfs_bmap_last_key(struct nilfs_bmap *bmap, unsigned long *key) | |||
180 | 197 | ||
181 | down_read(&bmap->b_sem); | 198 | down_read(&bmap->b_sem); |
182 | ret = bmap->b_ops->bop_last_key(bmap, &lastkey); | 199 | ret = bmap->b_ops->bop_last_key(bmap, &lastkey); |
183 | if (!ret) | ||
184 | *key = lastkey; | ||
185 | up_read(&bmap->b_sem); | 200 | up_read(&bmap->b_sem); |
201 | |||
202 | if (ret < 0) | ||
203 | ret = nilfs_bmap_convert_error(bmap, __func__, ret); | ||
204 | else | ||
205 | *key = lastkey; | ||
186 | return ret; | 206 | return ret; |
187 | } | 207 | } |
188 | 208 | ||
@@ -210,7 +230,8 @@ int nilfs_bmap_delete(struct nilfs_bmap *bmap, unsigned long key) | |||
210 | down_write(&bmap->b_sem); | 230 | down_write(&bmap->b_sem); |
211 | ret = nilfs_bmap_do_delete(bmap, key); | 231 | ret = nilfs_bmap_do_delete(bmap, key); |
212 | up_write(&bmap->b_sem); | 232 | up_write(&bmap->b_sem); |
213 | return ret; | 233 | |
234 | return nilfs_bmap_convert_error(bmap, __func__, ret); | ||
214 | } | 235 | } |
215 | 236 | ||
216 | static int nilfs_bmap_do_truncate(struct nilfs_bmap *bmap, unsigned long key) | 237 | static int nilfs_bmap_do_truncate(struct nilfs_bmap *bmap, unsigned long key) |
@@ -261,7 +282,8 @@ int nilfs_bmap_truncate(struct nilfs_bmap *bmap, unsigned long key) | |||
261 | down_write(&bmap->b_sem); | 282 | down_write(&bmap->b_sem); |
262 | ret = nilfs_bmap_do_truncate(bmap, key); | 283 | ret = nilfs_bmap_do_truncate(bmap, key); |
263 | up_write(&bmap->b_sem); | 284 | up_write(&bmap->b_sem); |
264 | return ret; | 285 | |
286 | return nilfs_bmap_convert_error(bmap, __func__, ret); | ||
265 | } | 287 | } |
266 | 288 | ||
267 | /** | 289 | /** |
@@ -300,7 +322,8 @@ int nilfs_bmap_propagate(struct nilfs_bmap *bmap, struct buffer_head *bh) | |||
300 | down_write(&bmap->b_sem); | 322 | down_write(&bmap->b_sem); |
301 | ret = bmap->b_ops->bop_propagate(bmap, bh); | 323 | ret = bmap->b_ops->bop_propagate(bmap, bh); |
302 | up_write(&bmap->b_sem); | 324 | up_write(&bmap->b_sem); |
303 | return ret; | 325 | |
326 | return nilfs_bmap_convert_error(bmap, __func__, ret); | ||
304 | } | 327 | } |
305 | 328 | ||
306 | /** | 329 | /** |
@@ -344,7 +367,8 @@ int nilfs_bmap_assign(struct nilfs_bmap *bmap, | |||
344 | down_write(&bmap->b_sem); | 367 | down_write(&bmap->b_sem); |
345 | ret = bmap->b_ops->bop_assign(bmap, bh, blocknr, binfo); | 368 | ret = bmap->b_ops->bop_assign(bmap, bh, blocknr, binfo); |
346 | up_write(&bmap->b_sem); | 369 | up_write(&bmap->b_sem); |
347 | return ret; | 370 | |
371 | return nilfs_bmap_convert_error(bmap, __func__, ret); | ||
348 | } | 372 | } |
349 | 373 | ||
350 | /** | 374 | /** |
@@ -373,7 +397,8 @@ int nilfs_bmap_mark(struct nilfs_bmap *bmap, __u64 key, int level) | |||
373 | down_write(&bmap->b_sem); | 397 | down_write(&bmap->b_sem); |
374 | ret = bmap->b_ops->bop_mark(bmap, key, level); | 398 | ret = bmap->b_ops->bop_mark(bmap, key, level); |
375 | up_write(&bmap->b_sem); | 399 | up_write(&bmap->b_sem); |
376 | return ret; | 400 | |
401 | return nilfs_bmap_convert_error(bmap, __func__, ret); | ||
377 | } | 402 | } |
378 | 403 | ||
379 | /** | 404 | /** |
diff --git a/fs/nilfs2/btnode.c b/fs/nilfs2/btnode.c index 5115814cb745..388e9e8f5286 100644 --- a/fs/nilfs2/btnode.c +++ b/fs/nilfs2/btnode.c | |||
@@ -104,8 +104,7 @@ int nilfs_btnode_submit_block(struct address_space *btnc, __u64 blocknr, | |||
104 | if (pblocknr == 0) { | 104 | if (pblocknr == 0) { |
105 | pblocknr = blocknr; | 105 | pblocknr = blocknr; |
106 | if (inode->i_ino != NILFS_DAT_INO) { | 106 | if (inode->i_ino != NILFS_DAT_INO) { |
107 | struct inode *dat = | 107 | struct inode *dat = NILFS_I_NILFS(inode)->ns_dat; |
108 | nilfs_dat_inode(NILFS_I_NILFS(inode)); | ||
109 | 108 | ||
110 | /* blocknr is a virtual block number */ | 109 | /* blocknr is a virtual block number */ |
111 | err = nilfs_dat_translate(dat, blocknr, &pblocknr); | 110 | err = nilfs_dat_translate(dat, blocknr, &pblocknr); |
diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c index cb003c8ee1f6..9d45773b79e6 100644 --- a/fs/nilfs2/dir.c +++ b/fs/nilfs2/dir.c | |||
@@ -91,7 +91,6 @@ static void nilfs_commit_chunk(struct page *page, | |||
91 | unsigned from, unsigned to) | 91 | unsigned from, unsigned to) |
92 | { | 92 | { |
93 | struct inode *dir = mapping->host; | 93 | struct inode *dir = mapping->host; |
94 | struct nilfs_sb_info *sbi = NILFS_SB(dir->i_sb); | ||
95 | loff_t pos = page_offset(page) + from; | 94 | loff_t pos = page_offset(page) + from; |
96 | unsigned len = to - from; | 95 | unsigned len = to - from; |
97 | unsigned nr_dirty, copied; | 96 | unsigned nr_dirty, copied; |
@@ -103,7 +102,7 @@ static void nilfs_commit_chunk(struct page *page, | |||
103 | i_size_write(dir, pos + copied); | 102 | i_size_write(dir, pos + copied); |
104 | if (IS_DIRSYNC(dir)) | 103 | if (IS_DIRSYNC(dir)) |
105 | nilfs_set_transaction_flag(NILFS_TI_SYNC); | 104 | nilfs_set_transaction_flag(NILFS_TI_SYNC); |
106 | err = nilfs_set_file_dirty(sbi, dir, nr_dirty); | 105 | err = nilfs_set_file_dirty(dir, nr_dirty); |
107 | WARN_ON(err); /* do not happen */ | 106 | WARN_ON(err); /* do not happen */ |
108 | unlock_page(page); | 107 | unlock_page(page); |
109 | } | 108 | } |
diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c index c9a30d7ff6fc..2f560c9fb808 100644 --- a/fs/nilfs2/file.c +++ b/fs/nilfs2/file.c | |||
@@ -155,6 +155,7 @@ const struct inode_operations nilfs_file_inode_operations = { | |||
155 | .truncate = nilfs_truncate, | 155 | .truncate = nilfs_truncate, |
156 | .setattr = nilfs_setattr, | 156 | .setattr = nilfs_setattr, |
157 | .permission = nilfs_permission, | 157 | .permission = nilfs_permission, |
158 | .fiemap = nilfs_fiemap, | ||
158 | }; | 159 | }; |
159 | 160 | ||
160 | /* end of file */ | 161 | /* end of file */ |
diff --git a/fs/nilfs2/gcinode.c b/fs/nilfs2/gcinode.c index 33ad25ddd5c4..caf9a6a3fb54 100644 --- a/fs/nilfs2/gcinode.c +++ b/fs/nilfs2/gcinode.c | |||
@@ -176,7 +176,6 @@ int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *bh) | |||
176 | int nilfs_init_gcinode(struct inode *inode) | 176 | int nilfs_init_gcinode(struct inode *inode) |
177 | { | 177 | { |
178 | struct nilfs_inode_info *ii = NILFS_I(inode); | 178 | struct nilfs_inode_info *ii = NILFS_I(inode); |
179 | struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; | ||
180 | 179 | ||
181 | inode->i_mode = S_IFREG; | 180 | inode->i_mode = S_IFREG; |
182 | mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS); | 181 | mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS); |
@@ -186,14 +185,6 @@ int nilfs_init_gcinode(struct inode *inode) | |||
186 | ii->i_flags = 0; | 185 | ii->i_flags = 0; |
187 | nilfs_bmap_init_gc(ii->i_bmap); | 186 | nilfs_bmap_init_gc(ii->i_bmap); |
188 | 187 | ||
189 | /* | ||
190 | * Add the inode to GC inode list. Garbage Collection | ||
191 | * is serialized and no two processes manipulate the | ||
192 | * list simultaneously. | ||
193 | */ | ||
194 | igrab(inode); | ||
195 | list_add(&NILFS_I(inode)->i_dirty, &nilfs->ns_gc_inodes); | ||
196 | |||
197 | return 0; | 188 | return 0; |
198 | } | 189 | } |
199 | 190 | ||
diff --git a/fs/nilfs2/ifile.c b/fs/nilfs2/ifile.c index 9f8a2da67f90..bfc73d3a30ed 100644 --- a/fs/nilfs2/ifile.c +++ b/fs/nilfs2/ifile.c | |||
@@ -149,14 +149,9 @@ int nilfs_ifile_get_inode_block(struct inode *ifile, ino_t ino, | |||
149 | } | 149 | } |
150 | 150 | ||
151 | err = nilfs_palloc_get_entry_block(ifile, ino, 0, out_bh); | 151 | err = nilfs_palloc_get_entry_block(ifile, ino, 0, out_bh); |
152 | if (unlikely(err)) { | 152 | if (unlikely(err)) |
153 | if (err == -EINVAL) | 153 | nilfs_warning(sb, __func__, "unable to read inode: %lu", |
154 | nilfs_error(sb, __func__, "ifile is broken"); | 154 | (unsigned long) ino); |
155 | else | ||
156 | nilfs_warning(sb, __func__, | ||
157 | "unable to read inode: %lu", | ||
158 | (unsigned long) ino); | ||
159 | } | ||
160 | return err; | 155 | return err; |
161 | } | 156 | } |
162 | 157 | ||
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 71d4bc8464e0..2fd440d8d6b8 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c | |||
@@ -58,7 +58,7 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff, | |||
58 | struct nilfs_inode_info *ii = NILFS_I(inode); | 58 | struct nilfs_inode_info *ii = NILFS_I(inode); |
59 | __u64 blknum = 0; | 59 | __u64 blknum = 0; |
60 | int err = 0, ret; | 60 | int err = 0, ret; |
61 | struct inode *dat = nilfs_dat_inode(NILFS_I_NILFS(inode)); | 61 | struct inode *dat = NILFS_I_NILFS(inode)->ns_dat; |
62 | unsigned maxblocks = bh_result->b_size >> inode->i_blkbits; | 62 | unsigned maxblocks = bh_result->b_size >> inode->i_blkbits; |
63 | 63 | ||
64 | down_read(&NILFS_MDT(dat)->mi_sem); | 64 | down_read(&NILFS_MDT(dat)->mi_sem); |
@@ -96,11 +96,6 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff, | |||
96 | inode->i_ino, | 96 | inode->i_ino, |
97 | (unsigned long long)blkoff); | 97 | (unsigned long long)blkoff); |
98 | err = 0; | 98 | err = 0; |
99 | } else if (err == -EINVAL) { | ||
100 | nilfs_error(inode->i_sb, __func__, | ||
101 | "broken bmap (inode=%lu)\n", | ||
102 | inode->i_ino); | ||
103 | err = -EIO; | ||
104 | } | 99 | } |
105 | nilfs_transaction_abort(inode->i_sb); | 100 | nilfs_transaction_abort(inode->i_sb); |
106 | goto out; | 101 | goto out; |
@@ -109,6 +104,7 @@ int nilfs_get_block(struct inode *inode, sector_t blkoff, | |||
109 | nilfs_transaction_commit(inode->i_sb); /* never fails */ | 104 | nilfs_transaction_commit(inode->i_sb); /* never fails */ |
110 | /* Error handling should be detailed */ | 105 | /* Error handling should be detailed */ |
111 | set_buffer_new(bh_result); | 106 | set_buffer_new(bh_result); |
107 | set_buffer_delay(bh_result); | ||
112 | map_bh(bh_result, inode->i_sb, 0); /* dbn must be changed | 108 | map_bh(bh_result, inode->i_sb, 0); /* dbn must be changed |
113 | to proper value */ | 109 | to proper value */ |
114 | } else if (ret == -ENOENT) { | 110 | } else if (ret == -ENOENT) { |
@@ -185,10 +181,9 @@ static int nilfs_set_page_dirty(struct page *page) | |||
185 | 181 | ||
186 | if (ret) { | 182 | if (ret) { |
187 | struct inode *inode = page->mapping->host; | 183 | struct inode *inode = page->mapping->host; |
188 | struct nilfs_sb_info *sbi = NILFS_SB(inode->i_sb); | ||
189 | unsigned nr_dirty = 1 << (PAGE_SHIFT - inode->i_blkbits); | 184 | unsigned nr_dirty = 1 << (PAGE_SHIFT - inode->i_blkbits); |
190 | 185 | ||
191 | nilfs_set_file_dirty(sbi, inode, nr_dirty); | 186 | nilfs_set_file_dirty(inode, nr_dirty); |
192 | } | 187 | } |
193 | return ret; | 188 | return ret; |
194 | } | 189 | } |
@@ -229,7 +224,7 @@ static int nilfs_write_end(struct file *file, struct address_space *mapping, | |||
229 | start + copied); | 224 | start + copied); |
230 | copied = generic_write_end(file, mapping, pos, len, copied, page, | 225 | copied = generic_write_end(file, mapping, pos, len, copied, page, |
231 | fsdata); | 226 | fsdata); |
232 | nilfs_set_file_dirty(NILFS_SB(inode->i_sb), inode, nr_dirty); | 227 | nilfs_set_file_dirty(inode, nr_dirty); |
233 | err = nilfs_transaction_commit(inode->i_sb); | 228 | err = nilfs_transaction_commit(inode->i_sb); |
234 | return err ? : copied; | 229 | return err ? : copied; |
235 | } | 230 | } |
@@ -425,13 +420,12 @@ static int __nilfs_read_inode(struct super_block *sb, | |||
425 | struct nilfs_root *root, unsigned long ino, | 420 | struct nilfs_root *root, unsigned long ino, |
426 | struct inode *inode) | 421 | struct inode *inode) |
427 | { | 422 | { |
428 | struct nilfs_sb_info *sbi = NILFS_SB(sb); | 423 | struct the_nilfs *nilfs = NILFS_SB(sb)->s_nilfs; |
429 | struct inode *dat = nilfs_dat_inode(sbi->s_nilfs); | ||
430 | struct buffer_head *bh; | 424 | struct buffer_head *bh; |
431 | struct nilfs_inode *raw_inode; | 425 | struct nilfs_inode *raw_inode; |
432 | int err; | 426 | int err; |
433 | 427 | ||
434 | down_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ | 428 | down_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem); |
435 | err = nilfs_ifile_get_inode_block(root->ifile, ino, &bh); | 429 | err = nilfs_ifile_get_inode_block(root->ifile, ino, &bh); |
436 | if (unlikely(err)) | 430 | if (unlikely(err)) |
437 | goto bad_inode; | 431 | goto bad_inode; |
@@ -461,7 +455,7 @@ static int __nilfs_read_inode(struct super_block *sb, | |||
461 | } | 455 | } |
462 | nilfs_ifile_unmap_inode(root->ifile, ino, bh); | 456 | nilfs_ifile_unmap_inode(root->ifile, ino, bh); |
463 | brelse(bh); | 457 | brelse(bh); |
464 | up_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ | 458 | up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem); |
465 | nilfs_set_inode_flags(inode); | 459 | nilfs_set_inode_flags(inode); |
466 | return 0; | 460 | return 0; |
467 | 461 | ||
@@ -470,7 +464,7 @@ static int __nilfs_read_inode(struct super_block *sb, | |||
470 | brelse(bh); | 464 | brelse(bh); |
471 | 465 | ||
472 | bad_inode: | 466 | bad_inode: |
473 | up_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ | 467 | up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem); |
474 | return err; | 468 | return err; |
475 | } | 469 | } |
476 | 470 | ||
@@ -629,7 +623,7 @@ static void nilfs_truncate_bmap(struct nilfs_inode_info *ii, | |||
629 | 623 | ||
630 | if (!test_bit(NILFS_I_BMAP, &ii->i_state)) | 624 | if (!test_bit(NILFS_I_BMAP, &ii->i_state)) |
631 | return; | 625 | return; |
632 | repeat: | 626 | repeat: |
633 | ret = nilfs_bmap_last_key(ii->i_bmap, &b); | 627 | ret = nilfs_bmap_last_key(ii->i_bmap, &b); |
634 | if (ret == -ENOENT) | 628 | if (ret == -ENOENT) |
635 | return; | 629 | return; |
@@ -646,14 +640,10 @@ static void nilfs_truncate_bmap(struct nilfs_inode_info *ii, | |||
646 | nilfs_bmap_truncate(ii->i_bmap, b) == 0)) | 640 | nilfs_bmap_truncate(ii->i_bmap, b) == 0)) |
647 | goto repeat; | 641 | goto repeat; |
648 | 642 | ||
649 | failed: | 643 | failed: |
650 | if (ret == -EINVAL) | 644 | nilfs_warning(ii->vfs_inode.i_sb, __func__, |
651 | nilfs_error(ii->vfs_inode.i_sb, __func__, | 645 | "failed to truncate bmap (ino=%lu, err=%d)", |
652 | "bmap is broken (ino=%lu)", ii->vfs_inode.i_ino); | 646 | ii->vfs_inode.i_ino, ret); |
653 | else | ||
654 | nilfs_warning(ii->vfs_inode.i_sb, __func__, | ||
655 | "failed to truncate bmap (ino=%lu, err=%d)", | ||
656 | ii->vfs_inode.i_ino, ret); | ||
657 | } | 647 | } |
658 | 648 | ||
659 | void nilfs_truncate(struct inode *inode) | 649 | void nilfs_truncate(struct inode *inode) |
@@ -682,7 +672,7 @@ void nilfs_truncate(struct inode *inode) | |||
682 | nilfs_set_transaction_flag(NILFS_TI_SYNC); | 672 | nilfs_set_transaction_flag(NILFS_TI_SYNC); |
683 | 673 | ||
684 | nilfs_mark_inode_dirty(inode); | 674 | nilfs_mark_inode_dirty(inode); |
685 | nilfs_set_file_dirty(NILFS_SB(sb), inode, 0); | 675 | nilfs_set_file_dirty(inode, 0); |
686 | nilfs_transaction_commit(sb); | 676 | nilfs_transaction_commit(sb); |
687 | /* May construct a logical segment and may fail in sync mode. | 677 | /* May construct a logical segment and may fail in sync mode. |
688 | But truncate has no return value. */ | 678 | But truncate has no return value. */ |
@@ -785,20 +775,24 @@ out_err: | |||
785 | return err; | 775 | return err; |
786 | } | 776 | } |
787 | 777 | ||
788 | int nilfs_permission(struct inode *inode, int mask) | 778 | int nilfs_permission(struct inode *inode, int mask, unsigned int flags) |
789 | { | 779 | { |
790 | struct nilfs_root *root = NILFS_I(inode)->i_root; | 780 | struct nilfs_root *root; |
791 | 781 | ||
782 | if (flags & IPERM_FLAG_RCU) | ||
783 | return -ECHILD; | ||
784 | |||
785 | root = NILFS_I(inode)->i_root; | ||
792 | if ((mask & MAY_WRITE) && root && | 786 | if ((mask & MAY_WRITE) && root && |
793 | root->cno != NILFS_CPTREE_CURRENT_CNO) | 787 | root->cno != NILFS_CPTREE_CURRENT_CNO) |
794 | return -EROFS; /* snapshot is not writable */ | 788 | return -EROFS; /* snapshot is not writable */ |
795 | 789 | ||
796 | return generic_permission(inode, mask, NULL); | 790 | return generic_permission(inode, mask, flags, NULL); |
797 | } | 791 | } |
798 | 792 | ||
799 | int nilfs_load_inode_block(struct nilfs_sb_info *sbi, struct inode *inode, | 793 | int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh) |
800 | struct buffer_head **pbh) | ||
801 | { | 794 | { |
795 | struct nilfs_sb_info *sbi = NILFS_SB(inode->i_sb); | ||
802 | struct nilfs_inode_info *ii = NILFS_I(inode); | 796 | struct nilfs_inode_info *ii = NILFS_I(inode); |
803 | int err; | 797 | int err; |
804 | 798 | ||
@@ -839,9 +833,9 @@ int nilfs_inode_dirty(struct inode *inode) | |||
839 | return ret; | 833 | return ret; |
840 | } | 834 | } |
841 | 835 | ||
842 | int nilfs_set_file_dirty(struct nilfs_sb_info *sbi, struct inode *inode, | 836 | int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty) |
843 | unsigned nr_dirty) | ||
844 | { | 837 | { |
838 | struct nilfs_sb_info *sbi = NILFS_SB(inode->i_sb); | ||
845 | struct nilfs_inode_info *ii = NILFS_I(inode); | 839 | struct nilfs_inode_info *ii = NILFS_I(inode); |
846 | 840 | ||
847 | atomic_add(nr_dirty, &sbi->s_nilfs->ns_ndirtyblks); | 841 | atomic_add(nr_dirty, &sbi->s_nilfs->ns_ndirtyblks); |
@@ -874,11 +868,10 @@ int nilfs_set_file_dirty(struct nilfs_sb_info *sbi, struct inode *inode, | |||
874 | 868 | ||
875 | int nilfs_mark_inode_dirty(struct inode *inode) | 869 | int nilfs_mark_inode_dirty(struct inode *inode) |
876 | { | 870 | { |
877 | struct nilfs_sb_info *sbi = NILFS_SB(inode->i_sb); | ||
878 | struct buffer_head *ibh; | 871 | struct buffer_head *ibh; |
879 | int err; | 872 | int err; |
880 | 873 | ||
881 | err = nilfs_load_inode_block(sbi, inode, &ibh); | 874 | err = nilfs_load_inode_block(inode, &ibh); |
882 | if (unlikely(err)) { | 875 | if (unlikely(err)) { |
883 | nilfs_warning(inode->i_sb, __func__, | 876 | nilfs_warning(inode->i_sb, __func__, |
884 | "failed to reget inode block.\n"); | 877 | "failed to reget inode block.\n"); |
@@ -920,3 +913,134 @@ void nilfs_dirty_inode(struct inode *inode) | |||
920 | nilfs_mark_inode_dirty(inode); | 913 | nilfs_mark_inode_dirty(inode); |
921 | nilfs_transaction_commit(inode->i_sb); /* never fails */ | 914 | nilfs_transaction_commit(inode->i_sb); /* never fails */ |
922 | } | 915 | } |
916 | |||
917 | int nilfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | ||
918 | __u64 start, __u64 len) | ||
919 | { | ||
920 | struct the_nilfs *nilfs = NILFS_I_NILFS(inode); | ||
921 | __u64 logical = 0, phys = 0, size = 0; | ||
922 | __u32 flags = 0; | ||
923 | loff_t isize; | ||
924 | sector_t blkoff, end_blkoff; | ||
925 | sector_t delalloc_blkoff; | ||
926 | unsigned long delalloc_blklen; | ||
927 | unsigned int blkbits = inode->i_blkbits; | ||
928 | int ret, n; | ||
929 | |||
930 | ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC); | ||
931 | if (ret) | ||
932 | return ret; | ||
933 | |||
934 | mutex_lock(&inode->i_mutex); | ||
935 | |||
936 | isize = i_size_read(inode); | ||
937 | |||
938 | blkoff = start >> blkbits; | ||
939 | end_blkoff = (start + len - 1) >> blkbits; | ||
940 | |||
941 | delalloc_blklen = nilfs_find_uncommitted_extent(inode, blkoff, | ||
942 | &delalloc_blkoff); | ||
943 | |||
944 | do { | ||
945 | __u64 blkphy; | ||
946 | unsigned int maxblocks; | ||
947 | |||
948 | if (delalloc_blklen && blkoff == delalloc_blkoff) { | ||
949 | if (size) { | ||
950 | /* End of the current extent */ | ||
951 | ret = fiemap_fill_next_extent( | ||
952 | fieinfo, logical, phys, size, flags); | ||
953 | if (ret) | ||
954 | break; | ||
955 | } | ||
956 | if (blkoff > end_blkoff) | ||
957 | break; | ||
958 | |||
959 | flags = FIEMAP_EXTENT_MERGED | FIEMAP_EXTENT_DELALLOC; | ||
960 | logical = blkoff << blkbits; | ||
961 | phys = 0; | ||
962 | size = delalloc_blklen << blkbits; | ||
963 | |||
964 | blkoff = delalloc_blkoff + delalloc_blklen; | ||
965 | delalloc_blklen = nilfs_find_uncommitted_extent( | ||
966 | inode, blkoff, &delalloc_blkoff); | ||
967 | continue; | ||
968 | } | ||
969 | |||
970 | /* | ||
971 | * Limit the number of blocks that we look up so as | ||
972 | * not to get into the next delayed allocation extent. | ||
973 | */ | ||
974 | maxblocks = INT_MAX; | ||
975 | if (delalloc_blklen) | ||
976 | maxblocks = min_t(sector_t, delalloc_blkoff - blkoff, | ||
977 | maxblocks); | ||
978 | blkphy = 0; | ||
979 | |||
980 | down_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem); | ||
981 | n = nilfs_bmap_lookup_contig( | ||
982 | NILFS_I(inode)->i_bmap, blkoff, &blkphy, maxblocks); | ||
983 | up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem); | ||
984 | |||
985 | if (n < 0) { | ||
986 | int past_eof; | ||
987 | |||
988 | if (unlikely(n != -ENOENT)) | ||
989 | break; /* error */ | ||
990 | |||
991 | /* HOLE */ | ||
992 | blkoff++; | ||
993 | past_eof = ((blkoff << blkbits) >= isize); | ||
994 | |||
995 | if (size) { | ||
996 | /* End of the current extent */ | ||
997 | |||
998 | if (past_eof) | ||
999 | flags |= FIEMAP_EXTENT_LAST; | ||
1000 | |||
1001 | ret = fiemap_fill_next_extent( | ||
1002 | fieinfo, logical, phys, size, flags); | ||
1003 | if (ret) | ||
1004 | break; | ||
1005 | size = 0; | ||
1006 | } | ||
1007 | if (blkoff > end_blkoff || past_eof) | ||
1008 | break; | ||
1009 | } else { | ||
1010 | if (size) { | ||
1011 | if (phys && blkphy << blkbits == phys + size) { | ||
1012 | /* The current extent goes on */ | ||
1013 | size += n << blkbits; | ||
1014 | } else { | ||
1015 | /* Terminate the current extent */ | ||
1016 | ret = fiemap_fill_next_extent( | ||
1017 | fieinfo, logical, phys, size, | ||
1018 | flags); | ||
1019 | if (ret || blkoff > end_blkoff) | ||
1020 | break; | ||
1021 | |||
1022 | /* Start another extent */ | ||
1023 | flags = FIEMAP_EXTENT_MERGED; | ||
1024 | logical = blkoff << blkbits; | ||
1025 | phys = blkphy << blkbits; | ||
1026 | size = n << blkbits; | ||
1027 | } | ||
1028 | } else { | ||
1029 | /* Start a new extent */ | ||
1030 | flags = FIEMAP_EXTENT_MERGED; | ||
1031 | logical = blkoff << blkbits; | ||
1032 | phys = blkphy << blkbits; | ||
1033 | size = n << blkbits; | ||
1034 | } | ||
1035 | blkoff += n; | ||
1036 | } | ||
1037 | cond_resched(); | ||
1038 | } while (true); | ||
1039 | |||
1040 | /* If ret is 1 then we just hit the end of the extent array */ | ||
1041 | if (ret == 1) | ||
1042 | ret = 0; | ||
1043 | |||
1044 | mutex_unlock(&inode->i_mutex); | ||
1045 | return ret; | ||
1046 | } | ||
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index e00d9457c256..496738963fdb 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c | |||
@@ -233,7 +233,7 @@ nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags, | |||
233 | int ret; | 233 | int ret; |
234 | 234 | ||
235 | down_read(&nilfs->ns_segctor_sem); | 235 | down_read(&nilfs->ns_segctor_sem); |
236 | ret = nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, size, nmembs); | 236 | ret = nilfs_dat_get_vinfo(nilfs->ns_dat, buf, size, nmembs); |
237 | up_read(&nilfs->ns_segctor_sem); | 237 | up_read(&nilfs->ns_segctor_sem); |
238 | return ret; | 238 | return ret; |
239 | } | 239 | } |
@@ -242,8 +242,7 @@ static ssize_t | |||
242 | nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, __u64 *posp, int flags, | 242 | nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, __u64 *posp, int flags, |
243 | void *buf, size_t size, size_t nmembs) | 243 | void *buf, size_t size, size_t nmembs) |
244 | { | 244 | { |
245 | struct inode *dat = nilfs_dat_inode(nilfs); | 245 | struct nilfs_bmap *bmap = NILFS_I(nilfs->ns_dat)->i_bmap; |
246 | struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap; | ||
247 | struct nilfs_bdesc *bdescs = buf; | 246 | struct nilfs_bdesc *bdescs = buf; |
248 | int ret, i; | 247 | int ret, i; |
249 | 248 | ||
@@ -337,6 +336,7 @@ static int nilfs_ioctl_move_blocks(struct super_block *sb, | |||
337 | struct nilfs_argv *argv, void *buf) | 336 | struct nilfs_argv *argv, void *buf) |
338 | { | 337 | { |
339 | size_t nmembs = argv->v_nmembs; | 338 | size_t nmembs = argv->v_nmembs; |
339 | struct the_nilfs *nilfs = NILFS_SB(sb)->s_nilfs; | ||
340 | struct inode *inode; | 340 | struct inode *inode; |
341 | struct nilfs_vdesc *vdesc; | 341 | struct nilfs_vdesc *vdesc; |
342 | struct buffer_head *bh, *n; | 342 | struct buffer_head *bh, *n; |
@@ -353,6 +353,17 @@ static int nilfs_ioctl_move_blocks(struct super_block *sb, | |||
353 | ret = PTR_ERR(inode); | 353 | ret = PTR_ERR(inode); |
354 | goto failed; | 354 | goto failed; |
355 | } | 355 | } |
356 | if (list_empty(&NILFS_I(inode)->i_dirty)) { | ||
357 | /* | ||
358 | * Add the inode to GC inode list. Garbage Collection | ||
359 | * is serialized and no two processes manipulate the | ||
360 | * list simultaneously. | ||
361 | */ | ||
362 | igrab(inode); | ||
363 | list_add(&NILFS_I(inode)->i_dirty, | ||
364 | &nilfs->ns_gc_inodes); | ||
365 | } | ||
366 | |||
356 | do { | 367 | do { |
357 | ret = nilfs_ioctl_move_inode_block(inode, vdesc, | 368 | ret = nilfs_ioctl_move_inode_block(inode, vdesc, |
358 | &buffers); | 369 | &buffers); |
@@ -409,7 +420,7 @@ static int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs, | |||
409 | size_t nmembs = argv->v_nmembs; | 420 | size_t nmembs = argv->v_nmembs; |
410 | int ret; | 421 | int ret; |
411 | 422 | ||
412 | ret = nilfs_dat_freev(nilfs_dat_inode(nilfs), buf, nmembs); | 423 | ret = nilfs_dat_freev(nilfs->ns_dat, buf, nmembs); |
413 | 424 | ||
414 | return (ret < 0) ? ret : nmembs; | 425 | return (ret < 0) ? ret : nmembs; |
415 | } | 426 | } |
@@ -418,8 +429,7 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, | |||
418 | struct nilfs_argv *argv, void *buf) | 429 | struct nilfs_argv *argv, void *buf) |
419 | { | 430 | { |
420 | size_t nmembs = argv->v_nmembs; | 431 | size_t nmembs = argv->v_nmembs; |
421 | struct inode *dat = nilfs_dat_inode(nilfs); | 432 | struct nilfs_bmap *bmap = NILFS_I(nilfs->ns_dat)->i_bmap; |
422 | struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap; | ||
423 | struct nilfs_bdesc *bdescs = buf; | 433 | struct nilfs_bdesc *bdescs = buf; |
424 | int ret, i; | 434 | int ret, i; |
425 | 435 | ||
@@ -438,7 +448,7 @@ static int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs, | |||
438 | /* skip dead block */ | 448 | /* skip dead block */ |
439 | continue; | 449 | continue; |
440 | if (bdescs[i].bd_level == 0) { | 450 | if (bdescs[i].bd_level == 0) { |
441 | ret = nilfs_mdt_mark_block_dirty(dat, | 451 | ret = nilfs_mdt_mark_block_dirty(nilfs->ns_dat, |
442 | bdescs[i].bd_offset); | 452 | bdescs[i].bd_offset); |
443 | if (ret < 0) { | 453 | if (ret < 0) { |
444 | WARN_ON(ret == -ENOENT); | 454 | WARN_ON(ret == -ENOENT); |
diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 39a5b84e2c9f..6a0e2a189f60 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c | |||
@@ -237,8 +237,6 @@ static int nilfs_mdt_read_block(struct inode *inode, unsigned long block, | |||
237 | * | 237 | * |
238 | * %-ENOENT - the specified block does not exist (hole block) | 238 | * %-ENOENT - the specified block does not exist (hole block) |
239 | * | 239 | * |
240 | * %-EINVAL - bmap is broken. (the caller should call nilfs_error()) | ||
241 | * | ||
242 | * %-EROFS - Read only filesystem (for create mode) | 240 | * %-EROFS - Read only filesystem (for create mode) |
243 | */ | 241 | */ |
244 | int nilfs_mdt_get_block(struct inode *inode, unsigned long blkoff, int create, | 242 | int nilfs_mdt_get_block(struct inode *inode, unsigned long blkoff, int create, |
@@ -273,8 +271,6 @@ int nilfs_mdt_get_block(struct inode *inode, unsigned long blkoff, int create, | |||
273 | * %-ENOMEM - Insufficient memory available. | 271 | * %-ENOMEM - Insufficient memory available. |
274 | * | 272 | * |
275 | * %-EIO - I/O error | 273 | * %-EIO - I/O error |
276 | * | ||
277 | * %-EINVAL - bmap is broken. (the caller should call nilfs_error()) | ||
278 | */ | 274 | */ |
279 | int nilfs_mdt_delete_block(struct inode *inode, unsigned long block) | 275 | int nilfs_mdt_delete_block(struct inode *inode, unsigned long block) |
280 | { | 276 | { |
@@ -350,8 +346,6 @@ int nilfs_mdt_forget_block(struct inode *inode, unsigned long block) | |||
350 | * %-EIO - I/O error | 346 | * %-EIO - I/O error |
351 | * | 347 | * |
352 | * %-ENOENT - the specified block does not exist (hole block) | 348 | * %-ENOENT - the specified block does not exist (hole block) |
353 | * | ||
354 | * %-EINVAL - bmap is broken. (the caller should call nilfs_error()) | ||
355 | */ | 349 | */ |
356 | int nilfs_mdt_mark_block_dirty(struct inode *inode, unsigned long block) | 350 | int nilfs_mdt_mark_block_dirty(struct inode *inode, unsigned long block) |
357 | { | 351 | { |
@@ -499,31 +493,29 @@ int nilfs_mdt_freeze_buffer(struct inode *inode, struct buffer_head *bh) | |||
499 | struct buffer_head *bh_frozen; | 493 | struct buffer_head *bh_frozen; |
500 | struct page *page; | 494 | struct page *page; |
501 | int blkbits = inode->i_blkbits; | 495 | int blkbits = inode->i_blkbits; |
502 | int ret = -ENOMEM; | ||
503 | 496 | ||
504 | page = grab_cache_page(&shadow->frozen_data, bh->b_page->index); | 497 | page = grab_cache_page(&shadow->frozen_data, bh->b_page->index); |
505 | if (!page) | 498 | if (!page) |
506 | return ret; | 499 | return -ENOMEM; |
507 | 500 | ||
508 | if (!page_has_buffers(page)) | 501 | if (!page_has_buffers(page)) |
509 | create_empty_buffers(page, 1 << blkbits, 0); | 502 | create_empty_buffers(page, 1 << blkbits, 0); |
510 | 503 | ||
511 | bh_frozen = nilfs_page_get_nth_block(page, bh_offset(bh) >> blkbits); | 504 | bh_frozen = nilfs_page_get_nth_block(page, bh_offset(bh) >> blkbits); |
512 | if (bh_frozen) { | 505 | |
513 | if (!buffer_uptodate(bh_frozen)) | 506 | if (!buffer_uptodate(bh_frozen)) |
514 | nilfs_copy_buffer(bh_frozen, bh); | 507 | nilfs_copy_buffer(bh_frozen, bh); |
515 | if (list_empty(&bh_frozen->b_assoc_buffers)) { | 508 | if (list_empty(&bh_frozen->b_assoc_buffers)) { |
516 | list_add_tail(&bh_frozen->b_assoc_buffers, | 509 | list_add_tail(&bh_frozen->b_assoc_buffers, |
517 | &shadow->frozen_buffers); | 510 | &shadow->frozen_buffers); |
518 | set_buffer_nilfs_redirected(bh); | 511 | set_buffer_nilfs_redirected(bh); |
519 | } else { | 512 | } else { |
520 | brelse(bh_frozen); /* already frozen */ | 513 | brelse(bh_frozen); /* already frozen */ |
521 | } | ||
522 | ret = 0; | ||
523 | } | 514 | } |
515 | |||
524 | unlock_page(page); | 516 | unlock_page(page); |
525 | page_cache_release(page); | 517 | page_cache_release(page); |
526 | return ret; | 518 | return 0; |
527 | } | 519 | } |
528 | 520 | ||
529 | struct buffer_head * | 521 | struct buffer_head * |
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index 6e9557ecf161..98034271cd02 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c | |||
@@ -577,6 +577,7 @@ const struct inode_operations nilfs_dir_inode_operations = { | |||
577 | .rename = nilfs_rename, | 577 | .rename = nilfs_rename, |
578 | .setattr = nilfs_setattr, | 578 | .setattr = nilfs_setattr, |
579 | .permission = nilfs_permission, | 579 | .permission = nilfs_permission, |
580 | .fiemap = nilfs_fiemap, | ||
580 | }; | 581 | }; |
581 | 582 | ||
582 | const struct inode_operations nilfs_special_inode_operations = { | 583 | const struct inode_operations nilfs_special_inode_operations = { |
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index f7560da5a567..777e8fd04304 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h | |||
@@ -190,11 +190,6 @@ static inline int nilfs_doing_construction(void) | |||
190 | return nilfs_test_transaction_flag(NILFS_TI_WRITER); | 190 | return nilfs_test_transaction_flag(NILFS_TI_WRITER); |
191 | } | 191 | } |
192 | 192 | ||
193 | static inline struct inode *nilfs_dat_inode(const struct the_nilfs *nilfs) | ||
194 | { | ||
195 | return nilfs->ns_dat; | ||
196 | } | ||
197 | |||
198 | /* | 193 | /* |
199 | * function prototype | 194 | * function prototype |
200 | */ | 195 | */ |
@@ -256,14 +251,14 @@ extern void nilfs_update_inode(struct inode *, struct buffer_head *); | |||
256 | extern void nilfs_truncate(struct inode *); | 251 | extern void nilfs_truncate(struct inode *); |
257 | extern void nilfs_evict_inode(struct inode *); | 252 | extern void nilfs_evict_inode(struct inode *); |
258 | extern int nilfs_setattr(struct dentry *, struct iattr *); | 253 | extern int nilfs_setattr(struct dentry *, struct iattr *); |
259 | int nilfs_permission(struct inode *inode, int mask); | 254 | int nilfs_permission(struct inode *inode, int mask, unsigned int flags); |
260 | extern int nilfs_load_inode_block(struct nilfs_sb_info *, struct inode *, | 255 | int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh); |
261 | struct buffer_head **); | ||
262 | extern int nilfs_inode_dirty(struct inode *); | 256 | extern int nilfs_inode_dirty(struct inode *); |
263 | extern int nilfs_set_file_dirty(struct nilfs_sb_info *, struct inode *, | 257 | int nilfs_set_file_dirty(struct inode *inode, unsigned nr_dirty); |
264 | unsigned); | ||
265 | extern int nilfs_mark_inode_dirty(struct inode *); | 258 | extern int nilfs_mark_inode_dirty(struct inode *); |
266 | extern void nilfs_dirty_inode(struct inode *); | 259 | extern void nilfs_dirty_inode(struct inode *); |
260 | int nilfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | ||
261 | __u64 start, __u64 len); | ||
267 | 262 | ||
268 | /* super.c */ | 263 | /* super.c */ |
269 | extern struct inode *nilfs_alloc_inode(struct super_block *); | 264 | extern struct inode *nilfs_alloc_inode(struct super_block *); |
diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c index a6c3c2e817f8..0c432416cfef 100644 --- a/fs/nilfs2/page.c +++ b/fs/nilfs2/page.c | |||
@@ -491,7 +491,7 @@ unsigned nilfs_page_count_clean_buffers(struct page *page, | |||
491 | } | 491 | } |
492 | return nc; | 492 | return nc; |
493 | } | 493 | } |
494 | 494 | ||
495 | void nilfs_mapping_init_once(struct address_space *mapping) | 495 | void nilfs_mapping_init_once(struct address_space *mapping) |
496 | { | 496 | { |
497 | memset(mapping, 0, sizeof(*mapping)); | 497 | memset(mapping, 0, sizeof(*mapping)); |
@@ -546,3 +546,87 @@ int __nilfs_clear_page_dirty(struct page *page) | |||
546 | } | 546 | } |
547 | return TestClearPageDirty(page); | 547 | return TestClearPageDirty(page); |
548 | } | 548 | } |
549 | |||
550 | /** | ||
551 | * nilfs_find_uncommitted_extent - find extent of uncommitted data | ||
552 | * @inode: inode | ||
553 | * @start_blk: start block offset (in) | ||
554 | * @blkoff: start offset of the found extent (out) | ||
555 | * | ||
556 | * This function searches an extent of buffers marked "delayed" which | ||
557 | * starts from a block offset equal to or larger than @start_blk. If | ||
558 | * such an extent was found, this will store the start offset in | ||
559 | * @blkoff and return its length in blocks. Otherwise, zero is | ||
560 | * returned. | ||
561 | */ | ||
562 | unsigned long nilfs_find_uncommitted_extent(struct inode *inode, | ||
563 | sector_t start_blk, | ||
564 | sector_t *blkoff) | ||
565 | { | ||
566 | unsigned int i; | ||
567 | pgoff_t index; | ||
568 | unsigned int nblocks_in_page; | ||
569 | unsigned long length = 0; | ||
570 | sector_t b; | ||
571 | struct pagevec pvec; | ||
572 | struct page *page; | ||
573 | |||
574 | if (inode->i_mapping->nrpages == 0) | ||
575 | return 0; | ||
576 | |||
577 | index = start_blk >> (PAGE_CACHE_SHIFT - inode->i_blkbits); | ||
578 | nblocks_in_page = 1U << (PAGE_CACHE_SHIFT - inode->i_blkbits); | ||
579 | |||
580 | pagevec_init(&pvec, 0); | ||
581 | |||
582 | repeat: | ||
583 | pvec.nr = find_get_pages_contig(inode->i_mapping, index, PAGEVEC_SIZE, | ||
584 | pvec.pages); | ||
585 | if (pvec.nr == 0) | ||
586 | return length; | ||
587 | |||
588 | if (length > 0 && pvec.pages[0]->index > index) | ||
589 | goto out; | ||
590 | |||
591 | b = pvec.pages[0]->index << (PAGE_CACHE_SHIFT - inode->i_blkbits); | ||
592 | i = 0; | ||
593 | do { | ||
594 | page = pvec.pages[i]; | ||
595 | |||
596 | lock_page(page); | ||
597 | if (page_has_buffers(page)) { | ||
598 | struct buffer_head *bh, *head; | ||
599 | |||
600 | bh = head = page_buffers(page); | ||
601 | do { | ||
602 | if (b < start_blk) | ||
603 | continue; | ||
604 | if (buffer_delay(bh)) { | ||
605 | if (length == 0) | ||
606 | *blkoff = b; | ||
607 | length++; | ||
608 | } else if (length > 0) { | ||
609 | goto out_locked; | ||
610 | } | ||
611 | } while (++b, bh = bh->b_this_page, bh != head); | ||
612 | } else { | ||
613 | if (length > 0) | ||
614 | goto out_locked; | ||
615 | |||
616 | b += nblocks_in_page; | ||
617 | } | ||
618 | unlock_page(page); | ||
619 | |||
620 | } while (++i < pagevec_count(&pvec)); | ||
621 | |||
622 | index = page->index + 1; | ||
623 | pagevec_release(&pvec); | ||
624 | cond_resched(); | ||
625 | goto repeat; | ||
626 | |||
627 | out_locked: | ||
628 | unlock_page(page); | ||
629 | out: | ||
630 | pagevec_release(&pvec); | ||
631 | return length; | ||
632 | } | ||
diff --git a/fs/nilfs2/page.h b/fs/nilfs2/page.h index fb9e8a8a2038..622df27cd891 100644 --- a/fs/nilfs2/page.h +++ b/fs/nilfs2/page.h | |||
@@ -66,6 +66,9 @@ void nilfs_mapping_init(struct address_space *mapping, | |||
66 | struct backing_dev_info *bdi, | 66 | struct backing_dev_info *bdi, |
67 | const struct address_space_operations *aops); | 67 | const struct address_space_operations *aops); |
68 | unsigned nilfs_page_count_clean_buffers(struct page *, unsigned, unsigned); | 68 | unsigned nilfs_page_count_clean_buffers(struct page *, unsigned, unsigned); |
69 | unsigned long nilfs_find_uncommitted_extent(struct inode *inode, | ||
70 | sector_t start_blk, | ||
71 | sector_t *blkoff); | ||
69 | 72 | ||
70 | #define NILFS_PAGE_BUG(page, m, a...) \ | 73 | #define NILFS_PAGE_BUG(page, m, a...) \ |
71 | do { nilfs_page_bug(page); BUG(); } while (0) | 74 | do { nilfs_page_bug(page); BUG(); } while (0) |
diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c index 5d2711c28da7..3dfcd3b7d389 100644 --- a/fs/nilfs2/recovery.c +++ b/fs/nilfs2/recovery.c | |||
@@ -535,7 +535,7 @@ static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs, | |||
535 | if (unlikely(err)) | 535 | if (unlikely(err)) |
536 | goto failed_page; | 536 | goto failed_page; |
537 | 537 | ||
538 | err = nilfs_set_file_dirty(sbi, inode, 1); | 538 | err = nilfs_set_file_dirty(inode, 1); |
539 | if (unlikely(err)) | 539 | if (unlikely(err)) |
540 | goto failed_page; | 540 | goto failed_page; |
541 | 541 | ||
diff --git a/fs/nilfs2/sb.h b/fs/nilfs2/sb.h index 35a07157b980..7a17715f215f 100644 --- a/fs/nilfs2/sb.h +++ b/fs/nilfs2/sb.h | |||
@@ -27,14 +27,6 @@ | |||
27 | #include <linux/types.h> | 27 | #include <linux/types.h> |
28 | #include <linux/fs.h> | 28 | #include <linux/fs.h> |
29 | 29 | ||
30 | /* | ||
31 | * Mount options | ||
32 | */ | ||
33 | struct nilfs_mount_options { | ||
34 | unsigned long mount_opt; | ||
35 | __u64 snapshot_cno; | ||
36 | }; | ||
37 | |||
38 | struct the_nilfs; | 30 | struct the_nilfs; |
39 | struct nilfs_sc_info; | 31 | struct nilfs_sc_info; |
40 | 32 | ||
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 687d090cea34..55ebae5c7f39 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c | |||
@@ -504,17 +504,6 @@ static int nilfs_segctor_add_file_block(struct nilfs_sc_info *sci, | |||
504 | return err; | 504 | return err; |
505 | } | 505 | } |
506 | 506 | ||
507 | static int nilfs_handle_bmap_error(int err, const char *fname, | ||
508 | struct inode *inode, struct super_block *sb) | ||
509 | { | ||
510 | if (err == -EINVAL) { | ||
511 | nilfs_error(sb, fname, "broken bmap (inode=%lu)\n", | ||
512 | inode->i_ino); | ||
513 | err = -EIO; | ||
514 | } | ||
515 | return err; | ||
516 | } | ||
517 | |||
518 | /* | 507 | /* |
519 | * Callback functions that enumerate, mark, and collect dirty blocks | 508 | * Callback functions that enumerate, mark, and collect dirty blocks |
520 | */ | 509 | */ |
@@ -524,9 +513,8 @@ static int nilfs_collect_file_data(struct nilfs_sc_info *sci, | |||
524 | int err; | 513 | int err; |
525 | 514 | ||
526 | err = nilfs_bmap_propagate(NILFS_I(inode)->i_bmap, bh); | 515 | err = nilfs_bmap_propagate(NILFS_I(inode)->i_bmap, bh); |
527 | if (unlikely(err < 0)) | 516 | if (err < 0) |
528 | return nilfs_handle_bmap_error(err, __func__, inode, | 517 | return err; |
529 | sci->sc_super); | ||
530 | 518 | ||
531 | err = nilfs_segctor_add_file_block(sci, bh, inode, | 519 | err = nilfs_segctor_add_file_block(sci, bh, inode, |
532 | sizeof(struct nilfs_binfo_v)); | 520 | sizeof(struct nilfs_binfo_v)); |
@@ -539,13 +527,7 @@ static int nilfs_collect_file_node(struct nilfs_sc_info *sci, | |||
539 | struct buffer_head *bh, | 527 | struct buffer_head *bh, |
540 | struct inode *inode) | 528 | struct inode *inode) |
541 | { | 529 | { |
542 | int err; | 530 | return nilfs_bmap_propagate(NILFS_I(inode)->i_bmap, bh); |
543 | |||
544 | err = nilfs_bmap_propagate(NILFS_I(inode)->i_bmap, bh); | ||
545 | if (unlikely(err < 0)) | ||
546 | return nilfs_handle_bmap_error(err, __func__, inode, | ||
547 | sci->sc_super); | ||
548 | return 0; | ||
549 | } | 531 | } |
550 | 532 | ||
551 | static int nilfs_collect_file_bmap(struct nilfs_sc_info *sci, | 533 | static int nilfs_collect_file_bmap(struct nilfs_sc_info *sci, |
@@ -588,9 +570,8 @@ static int nilfs_collect_dat_data(struct nilfs_sc_info *sci, | |||
588 | int err; | 570 | int err; |
589 | 571 | ||
590 | err = nilfs_bmap_propagate(NILFS_I(inode)->i_bmap, bh); | 572 | err = nilfs_bmap_propagate(NILFS_I(inode)->i_bmap, bh); |
591 | if (unlikely(err < 0)) | 573 | if (err < 0) |
592 | return nilfs_handle_bmap_error(err, __func__, inode, | 574 | return err; |
593 | sci->sc_super); | ||
594 | 575 | ||
595 | err = nilfs_segctor_add_file_block(sci, bh, inode, sizeof(__le64)); | 576 | err = nilfs_segctor_add_file_block(sci, bh, inode, sizeof(__le64)); |
596 | if (!err) | 577 | if (!err) |
@@ -776,9 +757,8 @@ static int nilfs_test_metadata_dirty(struct the_nilfs *nilfs, | |||
776 | ret++; | 757 | ret++; |
777 | if (nilfs_mdt_fetch_dirty(nilfs->ns_sufile)) | 758 | if (nilfs_mdt_fetch_dirty(nilfs->ns_sufile)) |
778 | ret++; | 759 | ret++; |
779 | if (ret || nilfs_doing_gc()) | 760 | if ((ret || nilfs_doing_gc()) && nilfs_mdt_fetch_dirty(nilfs->ns_dat)) |
780 | if (nilfs_mdt_fetch_dirty(nilfs_dat_inode(nilfs))) | 761 | ret++; |
781 | ret++; | ||
782 | return ret; | 762 | return ret; |
783 | } | 763 | } |
784 | 764 | ||
@@ -814,7 +794,7 @@ static void nilfs_segctor_clear_metadata_dirty(struct nilfs_sc_info *sci) | |||
814 | nilfs_mdt_clear_dirty(sci->sc_root->ifile); | 794 | nilfs_mdt_clear_dirty(sci->sc_root->ifile); |
815 | nilfs_mdt_clear_dirty(nilfs->ns_cpfile); | 795 | nilfs_mdt_clear_dirty(nilfs->ns_cpfile); |
816 | nilfs_mdt_clear_dirty(nilfs->ns_sufile); | 796 | nilfs_mdt_clear_dirty(nilfs->ns_sufile); |
817 | nilfs_mdt_clear_dirty(nilfs_dat_inode(nilfs)); | 797 | nilfs_mdt_clear_dirty(nilfs->ns_dat); |
818 | } | 798 | } |
819 | 799 | ||
820 | static int nilfs_segctor_create_checkpoint(struct nilfs_sc_info *sci) | 800 | static int nilfs_segctor_create_checkpoint(struct nilfs_sc_info *sci) |
@@ -923,7 +903,7 @@ static void nilfs_segctor_fill_in_super_root(struct nilfs_sc_info *sci, | |||
923 | nilfs->ns_nongc_ctime : sci->sc_seg_ctime); | 903 | nilfs->ns_nongc_ctime : sci->sc_seg_ctime); |
924 | raw_sr->sr_flags = 0; | 904 | raw_sr->sr_flags = 0; |
925 | 905 | ||
926 | nilfs_write_inode_common(nilfs_dat_inode(nilfs), (void *)raw_sr + | 906 | nilfs_write_inode_common(nilfs->ns_dat, (void *)raw_sr + |
927 | NILFS_SR_DAT_OFFSET(isz), 1); | 907 | NILFS_SR_DAT_OFFSET(isz), 1); |
928 | nilfs_write_inode_common(nilfs->ns_cpfile, (void *)raw_sr + | 908 | nilfs_write_inode_common(nilfs->ns_cpfile, (void *)raw_sr + |
929 | NILFS_SR_CPFILE_OFFSET(isz), 1); | 909 | NILFS_SR_CPFILE_OFFSET(isz), 1); |
@@ -1179,7 +1159,7 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode) | |||
1179 | sci->sc_stage.scnt++; /* Fall through */ | 1159 | sci->sc_stage.scnt++; /* Fall through */ |
1180 | case NILFS_ST_DAT: | 1160 | case NILFS_ST_DAT: |
1181 | dat_stage: | 1161 | dat_stage: |
1182 | err = nilfs_segctor_scan_file(sci, nilfs_dat_inode(nilfs), | 1162 | err = nilfs_segctor_scan_file(sci, nilfs->ns_dat, |
1183 | &nilfs_sc_dat_ops); | 1163 | &nilfs_sc_dat_ops); |
1184 | if (unlikely(err)) | 1164 | if (unlikely(err)) |
1185 | break; | 1165 | break; |
@@ -1563,7 +1543,6 @@ nilfs_segctor_update_payload_blocknr(struct nilfs_sc_info *sci, | |||
1563 | return 0; | 1543 | return 0; |
1564 | 1544 | ||
1565 | failed_bmap: | 1545 | failed_bmap: |
1566 | err = nilfs_handle_bmap_error(err, __func__, inode, sci->sc_super); | ||
1567 | return err; | 1546 | return err; |
1568 | } | 1547 | } |
1569 | 1548 | ||
@@ -1783,6 +1762,7 @@ static void nilfs_clear_copied_buffers(struct list_head *list, int err) | |||
1783 | if (!err) { | 1762 | if (!err) { |
1784 | set_buffer_uptodate(bh); | 1763 | set_buffer_uptodate(bh); |
1785 | clear_buffer_dirty(bh); | 1764 | clear_buffer_dirty(bh); |
1765 | clear_buffer_delay(bh); | ||
1786 | clear_buffer_nilfs_volatile(bh); | 1766 | clear_buffer_nilfs_volatile(bh); |
1787 | } | 1767 | } |
1788 | brelse(bh); /* for b_assoc_buffers */ | 1768 | brelse(bh); /* for b_assoc_buffers */ |
@@ -1909,6 +1889,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci) | |||
1909 | b_assoc_buffers) { | 1889 | b_assoc_buffers) { |
1910 | set_buffer_uptodate(bh); | 1890 | set_buffer_uptodate(bh); |
1911 | clear_buffer_dirty(bh); | 1891 | clear_buffer_dirty(bh); |
1892 | clear_buffer_delay(bh); | ||
1912 | clear_buffer_nilfs_volatile(bh); | 1893 | clear_buffer_nilfs_volatile(bh); |
1913 | clear_buffer_nilfs_redirected(bh); | 1894 | clear_buffer_nilfs_redirected(bh); |
1914 | if (bh == segbuf->sb_super_root) { | 1895 | if (bh == segbuf->sb_super_root) { |
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index f804d41ec9d3..70dfdd532b83 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c | |||
@@ -47,7 +47,6 @@ | |||
47 | #include <linux/crc32.h> | 47 | #include <linux/crc32.h> |
48 | #include <linux/vfs.h> | 48 | #include <linux/vfs.h> |
49 | #include <linux/writeback.h> | 49 | #include <linux/writeback.h> |
50 | #include <linux/kobject.h> | ||
51 | #include <linux/seq_file.h> | 50 | #include <linux/seq_file.h> |
52 | #include <linux/mount.h> | 51 | #include <linux/mount.h> |
53 | #include "nilfs.h" | 52 | #include "nilfs.h" |
@@ -111,12 +110,17 @@ void nilfs_error(struct super_block *sb, const char *function, | |||
111 | const char *fmt, ...) | 110 | const char *fmt, ...) |
112 | { | 111 | { |
113 | struct nilfs_sb_info *sbi = NILFS_SB(sb); | 112 | struct nilfs_sb_info *sbi = NILFS_SB(sb); |
113 | struct va_format vaf; | ||
114 | va_list args; | 114 | va_list args; |
115 | 115 | ||
116 | va_start(args, fmt); | 116 | va_start(args, fmt); |
117 | printk(KERN_CRIT "NILFS error (device %s): %s: ", sb->s_id, function); | 117 | |
118 | vprintk(fmt, args); | 118 | vaf.fmt = fmt; |
119 | printk("\n"); | 119 | vaf.va = &args; |
120 | |||
121 | printk(KERN_CRIT "NILFS error (device %s): %s: %pV\n", | ||
122 | sb->s_id, function, &vaf); | ||
123 | |||
120 | va_end(args); | 124 | va_end(args); |
121 | 125 | ||
122 | if (!(sb->s_flags & MS_RDONLY)) { | 126 | if (!(sb->s_flags & MS_RDONLY)) { |
@@ -136,13 +140,17 @@ void nilfs_error(struct super_block *sb, const char *function, | |||
136 | void nilfs_warning(struct super_block *sb, const char *function, | 140 | void nilfs_warning(struct super_block *sb, const char *function, |
137 | const char *fmt, ...) | 141 | const char *fmt, ...) |
138 | { | 142 | { |
143 | struct va_format vaf; | ||
139 | va_list args; | 144 | va_list args; |
140 | 145 | ||
141 | va_start(args, fmt); | 146 | va_start(args, fmt); |
142 | printk(KERN_WARNING "NILFS warning (device %s): %s: ", | 147 | |
143 | sb->s_id, function); | 148 | vaf.fmt = fmt; |
144 | vprintk(fmt, args); | 149 | vaf.va = &args; |
145 | printk("\n"); | 150 | |
151 | printk(KERN_WARNING "NILFS warning (device %s): %s: %pV\n", | ||
152 | sb->s_id, function, &vaf); | ||
153 | |||
146 | va_end(args); | 154 | va_end(args); |
147 | } | 155 | } |
148 | 156 | ||
@@ -162,10 +170,13 @@ struct inode *nilfs_alloc_inode(struct super_block *sb) | |||
162 | return &ii->vfs_inode; | 170 | return &ii->vfs_inode; |
163 | } | 171 | } |
164 | 172 | ||
165 | void nilfs_destroy_inode(struct inode *inode) | 173 | static void nilfs_i_callback(struct rcu_head *head) |
166 | { | 174 | { |
175 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
167 | struct nilfs_mdt_info *mdi = NILFS_MDT(inode); | 176 | struct nilfs_mdt_info *mdi = NILFS_MDT(inode); |
168 | 177 | ||
178 | INIT_LIST_HEAD(&inode->i_dentry); | ||
179 | |||
169 | if (mdi) { | 180 | if (mdi) { |
170 | kfree(mdi->mi_bgl); /* kfree(NULL) is safe */ | 181 | kfree(mdi->mi_bgl); /* kfree(NULL) is safe */ |
171 | kfree(mdi); | 182 | kfree(mdi); |
@@ -173,6 +184,11 @@ void nilfs_destroy_inode(struct inode *inode) | |||
173 | kmem_cache_free(nilfs_inode_cachep, NILFS_I(inode)); | 184 | kmem_cache_free(nilfs_inode_cachep, NILFS_I(inode)); |
174 | } | 185 | } |
175 | 186 | ||
187 | void nilfs_destroy_inode(struct inode *inode) | ||
188 | { | ||
189 | call_rcu(&inode->i_rcu, nilfs_i_callback); | ||
190 | } | ||
191 | |||
176 | static int nilfs_sync_super(struct nilfs_sb_info *sbi, int flag) | 192 | static int nilfs_sync_super(struct nilfs_sb_info *sbi, int flag) |
177 | { | 193 | { |
178 | struct the_nilfs *nilfs = sbi->s_nilfs; | 194 | struct the_nilfs *nilfs = sbi->s_nilfs; |
@@ -838,7 +854,7 @@ static int nilfs_attach_snapshot(struct super_block *s, __u64 cno, | |||
838 | 854 | ||
839 | static int nilfs_tree_was_touched(struct dentry *root_dentry) | 855 | static int nilfs_tree_was_touched(struct dentry *root_dentry) |
840 | { | 856 | { |
841 | return atomic_read(&root_dentry->d_count) > 1; | 857 | return root_dentry->d_count > 1; |
842 | } | 858 | } |
843 | 859 | ||
844 | /** | 860 | /** |
@@ -1002,11 +1018,11 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) | |||
1002 | struct nilfs_sb_info *sbi = NILFS_SB(sb); | 1018 | struct nilfs_sb_info *sbi = NILFS_SB(sb); |
1003 | struct the_nilfs *nilfs = sbi->s_nilfs; | 1019 | struct the_nilfs *nilfs = sbi->s_nilfs; |
1004 | unsigned long old_sb_flags; | 1020 | unsigned long old_sb_flags; |
1005 | struct nilfs_mount_options old_opts; | 1021 | unsigned long old_mount_opt; |
1006 | int err; | 1022 | int err; |
1007 | 1023 | ||
1008 | old_sb_flags = sb->s_flags; | 1024 | old_sb_flags = sb->s_flags; |
1009 | old_opts.mount_opt = sbi->s_mount_opt; | 1025 | old_mount_opt = sbi->s_mount_opt; |
1010 | 1026 | ||
1011 | if (!parse_options(data, sb, 1)) { | 1027 | if (!parse_options(data, sb, 1)) { |
1012 | err = -EINVAL; | 1028 | err = -EINVAL; |
@@ -1075,7 +1091,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) | |||
1075 | 1091 | ||
1076 | restore_opts: | 1092 | restore_opts: |
1077 | sb->s_flags = old_sb_flags; | 1093 | sb->s_flags = old_sb_flags; |
1078 | sbi->s_mount_opt = old_opts.mount_opt; | 1094 | sbi->s_mount_opt = old_mount_opt; |
1079 | return err; | 1095 | return err; |
1080 | } | 1096 | } |
1081 | 1097 | ||
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 0254be2d73c6..ad4ac607cf57 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c | |||
@@ -329,7 +329,6 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
329 | printk(KERN_INFO "NILFS: recovery complete.\n"); | 329 | printk(KERN_INFO "NILFS: recovery complete.\n"); |
330 | 330 | ||
331 | skip_recovery: | 331 | skip_recovery: |
332 | set_nilfs_loaded(nilfs); | ||
333 | nilfs_clear_recovery_info(&ri); | 332 | nilfs_clear_recovery_info(&ri); |
334 | sbi->s_super->s_flags = s_flags; | 333 | sbi->s_super->s_flags = s_flags; |
335 | return 0; | 334 | return 0; |
@@ -651,12 +650,11 @@ int nilfs_discard_segments(struct the_nilfs *nilfs, __u64 *segnump, | |||
651 | 650 | ||
652 | int nilfs_count_free_blocks(struct the_nilfs *nilfs, sector_t *nblocks) | 651 | int nilfs_count_free_blocks(struct the_nilfs *nilfs, sector_t *nblocks) |
653 | { | 652 | { |
654 | struct inode *dat = nilfs_dat_inode(nilfs); | ||
655 | unsigned long ncleansegs; | 653 | unsigned long ncleansegs; |
656 | 654 | ||
657 | down_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ | 655 | down_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem); |
658 | ncleansegs = nilfs_sufile_get_ncleansegs(nilfs->ns_sufile); | 656 | ncleansegs = nilfs_sufile_get_ncleansegs(nilfs->ns_sufile); |
659 | up_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ | 657 | up_read(&NILFS_MDT(nilfs->ns_dat)->mi_sem); |
660 | *nblocks = (sector_t)ncleansegs * nilfs->ns_blocks_per_segment; | 658 | *nblocks = (sector_t)ncleansegs * nilfs->ns_blocks_per_segment; |
661 | return 0; | 659 | return 0; |
662 | } | 660 | } |
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index 69226e14b745..fd85e4c05c6b 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h | |||
@@ -36,8 +36,6 @@ | |||
36 | /* the_nilfs struct */ | 36 | /* the_nilfs struct */ |
37 | enum { | 37 | enum { |
38 | THE_NILFS_INIT = 0, /* Information from super_block is set */ | 38 | THE_NILFS_INIT = 0, /* Information from super_block is set */ |
39 | THE_NILFS_LOADED, /* Roll-back/roll-forward has done and | ||
40 | the latest checkpoint was loaded */ | ||
41 | THE_NILFS_DISCONTINUED, /* 'next' pointer chain has broken */ | 39 | THE_NILFS_DISCONTINUED, /* 'next' pointer chain has broken */ |
42 | THE_NILFS_GC_RUNNING, /* gc process is running */ | 40 | THE_NILFS_GC_RUNNING, /* gc process is running */ |
43 | THE_NILFS_SB_DIRTY, /* super block is dirty */ | 41 | THE_NILFS_SB_DIRTY, /* super block is dirty */ |
@@ -178,7 +176,6 @@ static inline int nilfs_##name(struct the_nilfs *nilfs) \ | |||
178 | } | 176 | } |
179 | 177 | ||
180 | THE_NILFS_FNS(INIT, init) | 178 | THE_NILFS_FNS(INIT, init) |
181 | THE_NILFS_FNS(LOADED, loaded) | ||
182 | THE_NILFS_FNS(DISCONTINUED, discontinued) | 179 | THE_NILFS_FNS(DISCONTINUED, discontinued) |
183 | THE_NILFS_FNS(GC_RUNNING, gc_running) | 180 | THE_NILFS_FNS(GC_RUNNING, gc_running) |
184 | THE_NILFS_FNS(SB_DIRTY, sb_dirty) | 181 | THE_NILFS_FNS(SB_DIRTY, sb_dirty) |
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index b04f88eed09e..f35794b97e8e 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c | |||
@@ -92,7 +92,11 @@ static int fanotify_get_response_from_access(struct fsnotify_group *group, | |||
92 | 92 | ||
93 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); | 93 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); |
94 | 94 | ||
95 | wait_event(group->fanotify_data.access_waitq, event->response); | 95 | wait_event(group->fanotify_data.access_waitq, event->response || |
96 | atomic_read(&group->fanotify_data.bypass_perm)); | ||
97 | |||
98 | if (!event->response) /* bypass_perm set */ | ||
99 | return 0; | ||
96 | 100 | ||
97 | /* userspace responded, convert to something usable */ | 101 | /* userspace responded, convert to something usable */ |
98 | spin_lock(&event->lock); | 102 | spin_lock(&event->lock); |
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index 063224812b7e..8b61220cffc5 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c | |||
@@ -106,20 +106,29 @@ static int create_fd(struct fsnotify_group *group, struct fsnotify_event *event) | |||
106 | return client_fd; | 106 | return client_fd; |
107 | } | 107 | } |
108 | 108 | ||
109 | static ssize_t fill_event_metadata(struct fsnotify_group *group, | 109 | static int fill_event_metadata(struct fsnotify_group *group, |
110 | struct fanotify_event_metadata *metadata, | 110 | struct fanotify_event_metadata *metadata, |
111 | struct fsnotify_event *event) | 111 | struct fsnotify_event *event) |
112 | { | 112 | { |
113 | int ret = 0; | ||
114 | |||
113 | pr_debug("%s: group=%p metadata=%p event=%p\n", __func__, | 115 | pr_debug("%s: group=%p metadata=%p event=%p\n", __func__, |
114 | group, metadata, event); | 116 | group, metadata, event); |
115 | 117 | ||
116 | metadata->event_len = FAN_EVENT_METADATA_LEN; | 118 | metadata->event_len = FAN_EVENT_METADATA_LEN; |
119 | metadata->metadata_len = FAN_EVENT_METADATA_LEN; | ||
117 | metadata->vers = FANOTIFY_METADATA_VERSION; | 120 | metadata->vers = FANOTIFY_METADATA_VERSION; |
118 | metadata->mask = event->mask & FAN_ALL_OUTGOING_EVENTS; | 121 | metadata->mask = event->mask & FAN_ALL_OUTGOING_EVENTS; |
119 | metadata->pid = pid_vnr(event->tgid); | 122 | metadata->pid = pid_vnr(event->tgid); |
120 | metadata->fd = create_fd(group, event); | 123 | if (unlikely(event->mask & FAN_Q_OVERFLOW)) |
124 | metadata->fd = FAN_NOFD; | ||
125 | else { | ||
126 | metadata->fd = create_fd(group, event); | ||
127 | if (metadata->fd < 0) | ||
128 | ret = metadata->fd; | ||
129 | } | ||
121 | 130 | ||
122 | return metadata->fd; | 131 | return ret; |
123 | } | 132 | } |
124 | 133 | ||
125 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | 134 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS |
@@ -200,7 +209,7 @@ static int prepare_for_access_response(struct fsnotify_group *group, | |||
200 | 209 | ||
201 | mutex_lock(&group->fanotify_data.access_mutex); | 210 | mutex_lock(&group->fanotify_data.access_mutex); |
202 | 211 | ||
203 | if (group->fanotify_data.bypass_perm) { | 212 | if (atomic_read(&group->fanotify_data.bypass_perm)) { |
204 | mutex_unlock(&group->fanotify_data.access_mutex); | 213 | mutex_unlock(&group->fanotify_data.access_mutex); |
205 | kmem_cache_free(fanotify_response_event_cache, re); | 214 | kmem_cache_free(fanotify_response_event_cache, re); |
206 | event->response = FAN_ALLOW; | 215 | event->response = FAN_ALLOW; |
@@ -257,24 +266,34 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, | |||
257 | 266 | ||
258 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); | 267 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); |
259 | 268 | ||
260 | fd = fill_event_metadata(group, &fanotify_event_metadata, event); | 269 | ret = fill_event_metadata(group, &fanotify_event_metadata, event); |
261 | if (fd < 0) | 270 | if (ret < 0) |
262 | return fd; | 271 | goto out; |
263 | 272 | ||
273 | fd = fanotify_event_metadata.fd; | ||
264 | ret = prepare_for_access_response(group, event, fd); | 274 | ret = prepare_for_access_response(group, event, fd); |
265 | if (ret) | 275 | if (ret) |
266 | goto out_close_fd; | 276 | goto out_close_fd; |
267 | 277 | ||
268 | ret = -EFAULT; | 278 | ret = -EFAULT; |
269 | if (copy_to_user(buf, &fanotify_event_metadata, FAN_EVENT_METADATA_LEN)) | 279 | if (copy_to_user(buf, &fanotify_event_metadata, |
280 | fanotify_event_metadata.event_len)) | ||
270 | goto out_kill_access_response; | 281 | goto out_kill_access_response; |
271 | 282 | ||
272 | return FAN_EVENT_METADATA_LEN; | 283 | return fanotify_event_metadata.event_len; |
273 | 284 | ||
274 | out_kill_access_response: | 285 | out_kill_access_response: |
275 | remove_access_response(group, event, fd); | 286 | remove_access_response(group, event, fd); |
276 | out_close_fd: | 287 | out_close_fd: |
277 | sys_close(fd); | 288 | if (fd != FAN_NOFD) |
289 | sys_close(fd); | ||
290 | out: | ||
291 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | ||
292 | if (event->mask & FAN_ALL_PERM_EVENTS) { | ||
293 | event->response = FAN_DENY; | ||
294 | wake_up(&group->fanotify_data.access_waitq); | ||
295 | } | ||
296 | #endif | ||
278 | return ret; | 297 | return ret; |
279 | } | 298 | } |
280 | 299 | ||
@@ -382,7 +401,7 @@ static int fanotify_release(struct inode *ignored, struct file *file) | |||
382 | 401 | ||
383 | mutex_lock(&group->fanotify_data.access_mutex); | 402 | mutex_lock(&group->fanotify_data.access_mutex); |
384 | 403 | ||
385 | group->fanotify_data.bypass_perm = true; | 404 | atomic_inc(&group->fanotify_data.bypass_perm); |
386 | 405 | ||
387 | list_for_each_entry_safe(re, lre, &group->fanotify_data.access_list, list) { | 406 | list_for_each_entry_safe(re, lre, &group->fanotify_data.access_list, list) { |
388 | pr_debug("%s: found group=%p re=%p event=%p\n", __func__, group, | 407 | pr_debug("%s: found group=%p re=%p event=%p\n", __func__, group, |
@@ -586,11 +605,10 @@ static int fanotify_add_vfsmount_mark(struct fsnotify_group *group, | |||
586 | { | 605 | { |
587 | struct fsnotify_mark *fsn_mark; | 606 | struct fsnotify_mark *fsn_mark; |
588 | __u32 added; | 607 | __u32 added; |
608 | int ret = 0; | ||
589 | 609 | ||
590 | fsn_mark = fsnotify_find_vfsmount_mark(group, mnt); | 610 | fsn_mark = fsnotify_find_vfsmount_mark(group, mnt); |
591 | if (!fsn_mark) { | 611 | if (!fsn_mark) { |
592 | int ret; | ||
593 | |||
594 | if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks) | 612 | if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks) |
595 | return -ENOSPC; | 613 | return -ENOSPC; |
596 | 614 | ||
@@ -600,17 +618,16 @@ static int fanotify_add_vfsmount_mark(struct fsnotify_group *group, | |||
600 | 618 | ||
601 | fsnotify_init_mark(fsn_mark, fanotify_free_mark); | 619 | fsnotify_init_mark(fsn_mark, fanotify_free_mark); |
602 | ret = fsnotify_add_mark(fsn_mark, group, NULL, mnt, 0); | 620 | ret = fsnotify_add_mark(fsn_mark, group, NULL, mnt, 0); |
603 | if (ret) { | 621 | if (ret) |
604 | fanotify_free_mark(fsn_mark); | 622 | goto err; |
605 | return ret; | ||
606 | } | ||
607 | } | 623 | } |
608 | added = fanotify_mark_add_to_mask(fsn_mark, mask, flags); | 624 | added = fanotify_mark_add_to_mask(fsn_mark, mask, flags); |
609 | fsnotify_put_mark(fsn_mark); | 625 | |
610 | if (added & ~mnt->mnt_fsnotify_mask) | 626 | if (added & ~mnt->mnt_fsnotify_mask) |
611 | fsnotify_recalc_vfsmount_mask(mnt); | 627 | fsnotify_recalc_vfsmount_mask(mnt); |
612 | 628 | err: | |
613 | return 0; | 629 | fsnotify_put_mark(fsn_mark); |
630 | return ret; | ||
614 | } | 631 | } |
615 | 632 | ||
616 | static int fanotify_add_inode_mark(struct fsnotify_group *group, | 633 | static int fanotify_add_inode_mark(struct fsnotify_group *group, |
@@ -619,6 +636,7 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group, | |||
619 | { | 636 | { |
620 | struct fsnotify_mark *fsn_mark; | 637 | struct fsnotify_mark *fsn_mark; |
621 | __u32 added; | 638 | __u32 added; |
639 | int ret = 0; | ||
622 | 640 | ||
623 | pr_debug("%s: group=%p inode=%p\n", __func__, group, inode); | 641 | pr_debug("%s: group=%p inode=%p\n", __func__, group, inode); |
624 | 642 | ||
@@ -634,8 +652,6 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group, | |||
634 | 652 | ||
635 | fsn_mark = fsnotify_find_inode_mark(group, inode); | 653 | fsn_mark = fsnotify_find_inode_mark(group, inode); |
636 | if (!fsn_mark) { | 654 | if (!fsn_mark) { |
637 | int ret; | ||
638 | |||
639 | if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks) | 655 | if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks) |
640 | return -ENOSPC; | 656 | return -ENOSPC; |
641 | 657 | ||
@@ -645,16 +661,16 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group, | |||
645 | 661 | ||
646 | fsnotify_init_mark(fsn_mark, fanotify_free_mark); | 662 | fsnotify_init_mark(fsn_mark, fanotify_free_mark); |
647 | ret = fsnotify_add_mark(fsn_mark, group, inode, NULL, 0); | 663 | ret = fsnotify_add_mark(fsn_mark, group, inode, NULL, 0); |
648 | if (ret) { | 664 | if (ret) |
649 | fanotify_free_mark(fsn_mark); | 665 | goto err; |
650 | return ret; | ||
651 | } | ||
652 | } | 666 | } |
653 | added = fanotify_mark_add_to_mask(fsn_mark, mask, flags); | 667 | added = fanotify_mark_add_to_mask(fsn_mark, mask, flags); |
654 | fsnotify_put_mark(fsn_mark); | 668 | |
655 | if (added & ~inode->i_fsnotify_mask) | 669 | if (added & ~inode->i_fsnotify_mask) |
656 | fsnotify_recalc_inode_mask(inode); | 670 | fsnotify_recalc_inode_mask(inode); |
657 | return 0; | 671 | err: |
672 | fsnotify_put_mark(fsn_mark); | ||
673 | return ret; | ||
658 | } | 674 | } |
659 | 675 | ||
660 | /* fanotify syscalls */ | 676 | /* fanotify syscalls */ |
@@ -687,8 +703,10 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) | |||
687 | 703 | ||
688 | /* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */ | 704 | /* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */ |
689 | group = fsnotify_alloc_group(&fanotify_fsnotify_ops); | 705 | group = fsnotify_alloc_group(&fanotify_fsnotify_ops); |
690 | if (IS_ERR(group)) | 706 | if (IS_ERR(group)) { |
707 | free_uid(user); | ||
691 | return PTR_ERR(group); | 708 | return PTR_ERR(group); |
709 | } | ||
692 | 710 | ||
693 | group->fanotify_data.user = user; | 711 | group->fanotify_data.user = user; |
694 | atomic_inc(&user->fanotify_listeners); | 712 | atomic_inc(&user->fanotify_listeners); |
@@ -698,6 +716,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) | |||
698 | mutex_init(&group->fanotify_data.access_mutex); | 716 | mutex_init(&group->fanotify_data.access_mutex); |
699 | init_waitqueue_head(&group->fanotify_data.access_waitq); | 717 | init_waitqueue_head(&group->fanotify_data.access_waitq); |
700 | INIT_LIST_HEAD(&group->fanotify_data.access_list); | 718 | INIT_LIST_HEAD(&group->fanotify_data.access_list); |
719 | atomic_set(&group->fanotify_data.bypass_perm, 0); | ||
701 | #endif | 720 | #endif |
702 | switch (flags & FAN_ALL_CLASS_BITS) { | 721 | switch (flags & FAN_ALL_CLASS_BITS) { |
703 | case FAN_CLASS_NOTIF: | 722 | case FAN_CLASS_NOTIF: |
@@ -764,8 +783,10 @@ SYSCALL_DEFINE(fanotify_mark)(int fanotify_fd, unsigned int flags, | |||
764 | if (flags & ~FAN_ALL_MARK_FLAGS) | 783 | if (flags & ~FAN_ALL_MARK_FLAGS) |
765 | return -EINVAL; | 784 | return -EINVAL; |
766 | switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) { | 785 | switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) { |
767 | case FAN_MARK_ADD: | 786 | case FAN_MARK_ADD: /* fallthrough */ |
768 | case FAN_MARK_REMOVE: | 787 | case FAN_MARK_REMOVE: |
788 | if (!mask) | ||
789 | return -EINVAL; | ||
769 | case FAN_MARK_FLUSH: | 790 | case FAN_MARK_FLUSH: |
770 | break; | 791 | break; |
771 | default: | 792 | default: |
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 20dc218707ca..79b47cbb5cd8 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c | |||
@@ -59,7 +59,7 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode) | |||
59 | /* determine if the children should tell inode about their events */ | 59 | /* determine if the children should tell inode about their events */ |
60 | watched = fsnotify_inode_watches_children(inode); | 60 | watched = fsnotify_inode_watches_children(inode); |
61 | 61 | ||
62 | spin_lock(&dcache_lock); | 62 | spin_lock(&inode->i_lock); |
63 | /* run all of the dentries associated with this inode. Since this is a | 63 | /* run all of the dentries associated with this inode. Since this is a |
64 | * directory, there damn well better only be one item on this list */ | 64 | * directory, there damn well better only be one item on this list */ |
65 | list_for_each_entry(alias, &inode->i_dentry, d_alias) { | 65 | list_for_each_entry(alias, &inode->i_dentry, d_alias) { |
@@ -68,19 +68,21 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode) | |||
68 | /* run all of the children of the original inode and fix their | 68 | /* run all of the children of the original inode and fix their |
69 | * d_flags to indicate parental interest (their parent is the | 69 | * d_flags to indicate parental interest (their parent is the |
70 | * original inode) */ | 70 | * original inode) */ |
71 | spin_lock(&alias->d_lock); | ||
71 | list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) { | 72 | list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) { |
72 | if (!child->d_inode) | 73 | if (!child->d_inode) |
73 | continue; | 74 | continue; |
74 | 75 | ||
75 | spin_lock(&child->d_lock); | 76 | spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); |
76 | if (watched) | 77 | if (watched) |
77 | child->d_flags |= DCACHE_FSNOTIFY_PARENT_WATCHED; | 78 | child->d_flags |= DCACHE_FSNOTIFY_PARENT_WATCHED; |
78 | else | 79 | else |
79 | child->d_flags &= ~DCACHE_FSNOTIFY_PARENT_WATCHED; | 80 | child->d_flags &= ~DCACHE_FSNOTIFY_PARENT_WATCHED; |
80 | spin_unlock(&child->d_lock); | 81 | spin_unlock(&child->d_lock); |
81 | } | 82 | } |
83 | spin_unlock(&alias->d_lock); | ||
82 | } | 84 | } |
83 | spin_unlock(&dcache_lock); | 85 | spin_unlock(&inode->i_lock); |
84 | } | 86 | } |
85 | 87 | ||
86 | /* Notify this dentry's parent about a child's events. */ | 88 | /* Notify this dentry's parent about a child's events. */ |
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 444c305a468c..4cd5d5d78f9f 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c | |||
@@ -752,6 +752,7 @@ SYSCALL_DEFINE1(inotify_init1, int, flags) | |||
752 | if (ret >= 0) | 752 | if (ret >= 0) |
753 | return ret; | 753 | return ret; |
754 | 754 | ||
755 | fsnotify_put_group(group); | ||
755 | atomic_dec(&user->inotify_devs); | 756 | atomic_dec(&user->inotify_devs); |
756 | out_free_uid: | 757 | out_free_uid: |
757 | free_uid(user); | 758 | free_uid(user); |
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 93622b175fc7..a627ed82c0a3 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c | |||
@@ -332,6 +332,13 @@ struct inode *ntfs_alloc_big_inode(struct super_block *sb) | |||
332 | return NULL; | 332 | return NULL; |
333 | } | 333 | } |
334 | 334 | ||
335 | static void ntfs_i_callback(struct rcu_head *head) | ||
336 | { | ||
337 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
338 | INIT_LIST_HEAD(&inode->i_dentry); | ||
339 | kmem_cache_free(ntfs_big_inode_cache, NTFS_I(inode)); | ||
340 | } | ||
341 | |||
335 | void ntfs_destroy_big_inode(struct inode *inode) | 342 | void ntfs_destroy_big_inode(struct inode *inode) |
336 | { | 343 | { |
337 | ntfs_inode *ni = NTFS_I(inode); | 344 | ntfs_inode *ni = NTFS_I(inode); |
@@ -340,7 +347,7 @@ void ntfs_destroy_big_inode(struct inode *inode) | |||
340 | BUG_ON(ni->page); | 347 | BUG_ON(ni->page); |
341 | if (!atomic_dec_and_test(&ni->count)) | 348 | if (!atomic_dec_and_test(&ni->count)) |
342 | BUG(); | 349 | BUG(); |
343 | kmem_cache_free(ntfs_big_inode_cache, NTFS_I(inode)); | 350 | call_rcu(&inode->i_rcu, ntfs_i_callback); |
344 | } | 351 | } |
345 | 352 | ||
346 | static inline ntfs_inode *ntfs_alloc_extent_inode(void) | 353 | static inline ntfs_inode *ntfs_alloc_extent_inode(void) |
diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c index 391915093fe1..704f6b1742f3 100644 --- a/fs/ocfs2/acl.c +++ b/fs/ocfs2/acl.c | |||
@@ -291,13 +291,17 @@ static int ocfs2_set_acl(handle_t *handle, | |||
291 | return ret; | 291 | return ret; |
292 | } | 292 | } |
293 | 293 | ||
294 | int ocfs2_check_acl(struct inode *inode, int mask) | 294 | int ocfs2_check_acl(struct inode *inode, int mask, unsigned int flags) |
295 | { | 295 | { |
296 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | 296 | struct ocfs2_super *osb; |
297 | struct buffer_head *di_bh = NULL; | 297 | struct buffer_head *di_bh = NULL; |
298 | struct posix_acl *acl; | 298 | struct posix_acl *acl; |
299 | int ret = -EAGAIN; | 299 | int ret = -EAGAIN; |
300 | 300 | ||
301 | if (flags & IPERM_FLAG_RCU) | ||
302 | return -ECHILD; | ||
303 | |||
304 | osb = OCFS2_SB(inode->i_sb); | ||
301 | if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) | 305 | if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) |
302 | return ret; | 306 | return ret; |
303 | 307 | ||
diff --git a/fs/ocfs2/acl.h b/fs/ocfs2/acl.h index 5c5d31f05853..4fe7c9cf4bfb 100644 --- a/fs/ocfs2/acl.h +++ b/fs/ocfs2/acl.h | |||
@@ -26,7 +26,7 @@ struct ocfs2_acl_entry { | |||
26 | __le32 e_id; | 26 | __le32 e_id; |
27 | }; | 27 | }; |
28 | 28 | ||
29 | extern int ocfs2_check_acl(struct inode *, int); | 29 | extern int ocfs2_check_acl(struct inode *, int, unsigned int); |
30 | extern int ocfs2_acl_chmod(struct inode *); | 30 | extern int ocfs2_acl_chmod(struct inode *); |
31 | extern int ocfs2_init_acl(handle_t *, struct inode *, struct inode *, | 31 | extern int ocfs2_init_acl(handle_t *, struct inode *, struct inode *, |
32 | struct buffer_head *, struct buffer_head *, | 32 | struct buffer_head *, struct buffer_head *, |
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index f1e962cb3b73..0d7c5540ad66 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
@@ -573,11 +573,14 @@ static void ocfs2_dio_end_io(struct kiocb *iocb, | |||
573 | /* this io's submitter should not have unlocked this before we could */ | 573 | /* this io's submitter should not have unlocked this before we could */ |
574 | BUG_ON(!ocfs2_iocb_is_rw_locked(iocb)); | 574 | BUG_ON(!ocfs2_iocb_is_rw_locked(iocb)); |
575 | 575 | ||
576 | if (ocfs2_iocb_is_sem_locked(iocb)) { | ||
577 | up_read(&inode->i_alloc_sem); | ||
578 | ocfs2_iocb_clear_sem_locked(iocb); | ||
579 | } | ||
580 | |||
576 | ocfs2_iocb_clear_rw_locked(iocb); | 581 | ocfs2_iocb_clear_rw_locked(iocb); |
577 | 582 | ||
578 | level = ocfs2_iocb_rw_locked_level(iocb); | 583 | level = ocfs2_iocb_rw_locked_level(iocb); |
579 | if (!level) | ||
580 | up_read(&inode->i_alloc_sem); | ||
581 | ocfs2_rw_unlock(inode, level); | 584 | ocfs2_rw_unlock(inode, level); |
582 | 585 | ||
583 | if (is_async) | 586 | if (is_async) |
diff --git a/fs/ocfs2/aops.h b/fs/ocfs2/aops.h index 76bfdfda691a..eceb456037c1 100644 --- a/fs/ocfs2/aops.h +++ b/fs/ocfs2/aops.h | |||
@@ -68,8 +68,27 @@ static inline void ocfs2_iocb_set_rw_locked(struct kiocb *iocb, int level) | |||
68 | else | 68 | else |
69 | clear_bit(1, (unsigned long *)&iocb->private); | 69 | clear_bit(1, (unsigned long *)&iocb->private); |
70 | } | 70 | } |
71 | |||
72 | /* | ||
73 | * Using a named enum representing lock types in terms of #N bit stored in | ||
74 | * iocb->private, which is going to be used for communication bewteen | ||
75 | * ocfs2_dio_end_io() and ocfs2_file_aio_write/read(). | ||
76 | */ | ||
77 | enum ocfs2_iocb_lock_bits { | ||
78 | OCFS2_IOCB_RW_LOCK = 0, | ||
79 | OCFS2_IOCB_RW_LOCK_LEVEL, | ||
80 | OCFS2_IOCB_SEM, | ||
81 | OCFS2_IOCB_NUM_LOCKS | ||
82 | }; | ||
83 | |||
71 | #define ocfs2_iocb_clear_rw_locked(iocb) \ | 84 | #define ocfs2_iocb_clear_rw_locked(iocb) \ |
72 | clear_bit(0, (unsigned long *)&iocb->private) | 85 | clear_bit(OCFS2_IOCB_RW_LOCK, (unsigned long *)&iocb->private) |
73 | #define ocfs2_iocb_rw_locked_level(iocb) \ | 86 | #define ocfs2_iocb_rw_locked_level(iocb) \ |
74 | test_bit(1, (unsigned long *)&iocb->private) | 87 | test_bit(OCFS2_IOCB_RW_LOCK_LEVEL, (unsigned long *)&iocb->private) |
88 | #define ocfs2_iocb_set_sem_locked(iocb) \ | ||
89 | set_bit(OCFS2_IOCB_SEM, (unsigned long *)&iocb->private) | ||
90 | #define ocfs2_iocb_clear_sem_locked(iocb) \ | ||
91 | clear_bit(OCFS2_IOCB_SEM, (unsigned long *)&iocb->private) | ||
92 | #define ocfs2_iocb_is_sem_locked(iocb) \ | ||
93 | test_bit(OCFS2_IOCB_SEM, (unsigned long *)&iocb->private) | ||
75 | #endif /* OCFS2_FILE_H */ | 94 | #endif /* OCFS2_FILE_H */ |
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 9f26ac9be2a4..9e3d45bcb5fd 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c | |||
@@ -307,8 +307,7 @@ static void o2hb_arm_write_timeout(struct o2hb_region *reg) | |||
307 | 307 | ||
308 | static void o2hb_disarm_write_timeout(struct o2hb_region *reg) | 308 | static void o2hb_disarm_write_timeout(struct o2hb_region *reg) |
309 | { | 309 | { |
310 | cancel_delayed_work(®->hr_write_timeout_work); | 310 | cancel_delayed_work_sync(®->hr_write_timeout_work); |
311 | flush_scheduled_work(); | ||
312 | } | 311 | } |
313 | 312 | ||
314 | static inline void o2hb_bio_wait_init(struct o2hb_bio_wait_ctxt *wc) | 313 | static inline void o2hb_bio_wait_init(struct o2hb_bio_wait_ctxt *wc) |
diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c index c7fba396392d..6c61771469af 100644 --- a/fs/ocfs2/cluster/masklog.c +++ b/fs/ocfs2/cluster/masklog.c | |||
@@ -113,10 +113,11 @@ static struct mlog_attribute mlog_attrs[MLOG_MAX_BITS] = { | |||
113 | define_mask(QUOTA), | 113 | define_mask(QUOTA), |
114 | define_mask(REFCOUNT), | 114 | define_mask(REFCOUNT), |
115 | define_mask(BASTS), | 115 | define_mask(BASTS), |
116 | define_mask(RESERVATIONS), | ||
117 | define_mask(CLUSTER), | ||
116 | define_mask(ERROR), | 118 | define_mask(ERROR), |
117 | define_mask(NOTICE), | 119 | define_mask(NOTICE), |
118 | define_mask(KTHREAD), | 120 | define_mask(KTHREAD), |
119 | define_mask(RESERVATIONS), | ||
120 | }; | 121 | }; |
121 | 122 | ||
122 | static struct attribute *mlog_attr_ptrs[MLOG_MAX_BITS] = {NULL, }; | 123 | static struct attribute *mlog_attr_ptrs[MLOG_MAX_BITS] = {NULL, }; |
diff --git a/fs/ocfs2/cluster/masklog.h b/fs/ocfs2/cluster/masklog.h index ea2ed9f56c94..34d6544357d9 100644 --- a/fs/ocfs2/cluster/masklog.h +++ b/fs/ocfs2/cluster/masklog.h | |||
@@ -81,7 +81,7 @@ | |||
81 | #include <linux/sched.h> | 81 | #include <linux/sched.h> |
82 | 82 | ||
83 | /* bits that are frequently given and infrequently matched in the low word */ | 83 | /* bits that are frequently given and infrequently matched in the low word */ |
84 | /* NOTE: If you add a flag, you need to also update mlog.c! */ | 84 | /* NOTE: If you add a flag, you need to also update masklog.c! */ |
85 | #define ML_ENTRY 0x0000000000000001ULL /* func call entry */ | 85 | #define ML_ENTRY 0x0000000000000001ULL /* func call entry */ |
86 | #define ML_EXIT 0x0000000000000002ULL /* func call exit */ | 86 | #define ML_EXIT 0x0000000000000002ULL /* func call exit */ |
87 | #define ML_TCP 0x0000000000000004ULL /* net cluster/tcp.c */ | 87 | #define ML_TCP 0x0000000000000004ULL /* net cluster/tcp.c */ |
@@ -114,13 +114,14 @@ | |||
114 | #define ML_XATTR 0x0000000020000000ULL /* ocfs2 extended attributes */ | 114 | #define ML_XATTR 0x0000000020000000ULL /* ocfs2 extended attributes */ |
115 | #define ML_QUOTA 0x0000000040000000ULL /* ocfs2 quota operations */ | 115 | #define ML_QUOTA 0x0000000040000000ULL /* ocfs2 quota operations */ |
116 | #define ML_REFCOUNT 0x0000000080000000ULL /* refcount tree operations */ | 116 | #define ML_REFCOUNT 0x0000000080000000ULL /* refcount tree operations */ |
117 | #define ML_BASTS 0x0000001000000000ULL /* dlmglue asts and basts */ | 117 | #define ML_BASTS 0x0000000100000000ULL /* dlmglue asts and basts */ |
118 | #define ML_RESERVATIONS 0x0000000200000000ULL /* ocfs2 alloc reservations */ | ||
119 | #define ML_CLUSTER 0x0000000400000000ULL /* cluster stack */ | ||
120 | |||
118 | /* bits that are infrequently given and frequently matched in the high word */ | 121 | /* bits that are infrequently given and frequently matched in the high word */ |
119 | #define ML_ERROR 0x0000000100000000ULL /* sent to KERN_ERR */ | 122 | #define ML_ERROR 0x1000000000000000ULL /* sent to KERN_ERR */ |
120 | #define ML_NOTICE 0x0000000200000000ULL /* setn to KERN_NOTICE */ | 123 | #define ML_NOTICE 0x2000000000000000ULL /* setn to KERN_NOTICE */ |
121 | #define ML_KTHREAD 0x0000000400000000ULL /* kernel thread activity */ | 124 | #define ML_KTHREAD 0x4000000000000000ULL /* kernel thread activity */ |
122 | #define ML_RESERVATIONS 0x0000000800000000ULL /* ocfs2 alloc reservations */ | ||
123 | #define ML_CLUSTER 0x0000001000000000ULL /* cluster stack */ | ||
124 | 125 | ||
125 | #define MLOG_INITIAL_AND_MASK (ML_ERROR|ML_NOTICE) | 126 | #define MLOG_INITIAL_AND_MASK (ML_ERROR|ML_NOTICE) |
126 | #define MLOG_INITIAL_NOT_MASK (ML_ENTRY|ML_EXIT) | 127 | #define MLOG_INITIAL_NOT_MASK (ML_ENTRY|ML_EXIT) |
diff --git a/fs/ocfs2/cluster/quorum.c b/fs/ocfs2/cluster/quorum.c index cf3e16696216..a87366750f23 100644 --- a/fs/ocfs2/cluster/quorum.c +++ b/fs/ocfs2/cluster/quorum.c | |||
@@ -325,5 +325,7 @@ void o2quo_init(void) | |||
325 | 325 | ||
326 | void o2quo_exit(void) | 326 | void o2quo_exit(void) |
327 | { | 327 | { |
328 | flush_scheduled_work(); | 328 | struct o2quo_state *qs = &o2quo_state; |
329 | |||
330 | flush_work_sync(&qs->qs_work); | ||
329 | } | 331 | } |
diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c index 895532ac4d98..6d80ecc7834f 100644 --- a/fs/ocfs2/dcache.c +++ b/fs/ocfs2/dcache.c | |||
@@ -52,9 +52,15 @@ void ocfs2_dentry_attach_gen(struct dentry *dentry) | |||
52 | static int ocfs2_dentry_revalidate(struct dentry *dentry, | 52 | static int ocfs2_dentry_revalidate(struct dentry *dentry, |
53 | struct nameidata *nd) | 53 | struct nameidata *nd) |
54 | { | 54 | { |
55 | struct inode *inode = dentry->d_inode; | 55 | struct inode *inode; |
56 | int ret = 0; /* if all else fails, just return false */ | 56 | int ret = 0; /* if all else fails, just return false */ |
57 | struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb); | 57 | struct ocfs2_super *osb; |
58 | |||
59 | if (nd->flags & LOOKUP_RCU) | ||
60 | return -ECHILD; | ||
61 | |||
62 | inode = dentry->d_inode; | ||
63 | osb = OCFS2_SB(dentry->d_sb); | ||
58 | 64 | ||
59 | mlog_entry("(0x%p, '%.*s')\n", dentry, | 65 | mlog_entry("(0x%p, '%.*s')\n", dentry, |
60 | dentry->d_name.len, dentry->d_name.name); | 66 | dentry->d_name.len, dentry->d_name.name); |
@@ -169,23 +175,25 @@ struct dentry *ocfs2_find_local_alias(struct inode *inode, | |||
169 | struct list_head *p; | 175 | struct list_head *p; |
170 | struct dentry *dentry = NULL; | 176 | struct dentry *dentry = NULL; |
171 | 177 | ||
172 | spin_lock(&dcache_lock); | 178 | spin_lock(&inode->i_lock); |
173 | |||
174 | list_for_each(p, &inode->i_dentry) { | 179 | list_for_each(p, &inode->i_dentry) { |
175 | dentry = list_entry(p, struct dentry, d_alias); | 180 | dentry = list_entry(p, struct dentry, d_alias); |
176 | 181 | ||
182 | spin_lock(&dentry->d_lock); | ||
177 | if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) { | 183 | if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) { |
178 | mlog(0, "dentry found: %.*s\n", | 184 | mlog(0, "dentry found: %.*s\n", |
179 | dentry->d_name.len, dentry->d_name.name); | 185 | dentry->d_name.len, dentry->d_name.name); |
180 | 186 | ||
181 | dget_locked(dentry); | 187 | dget_dlock(dentry); |
188 | spin_unlock(&dentry->d_lock); | ||
182 | break; | 189 | break; |
183 | } | 190 | } |
191 | spin_unlock(&dentry->d_lock); | ||
184 | 192 | ||
185 | dentry = NULL; | 193 | dentry = NULL; |
186 | } | 194 | } |
187 | 195 | ||
188 | spin_unlock(&dcache_lock); | 196 | spin_unlock(&inode->i_lock); |
189 | 197 | ||
190 | return dentry; | 198 | return dentry; |
191 | } | 199 | } |
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index c49f6de0e7ab..d417b3f9b0c7 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c | |||
@@ -2461,8 +2461,10 @@ static int ocfs2_dx_dir_attach_index(struct ocfs2_super *osb, | |||
2461 | 2461 | ||
2462 | di->i_dx_root = cpu_to_le64(dr_blkno); | 2462 | di->i_dx_root = cpu_to_le64(dr_blkno); |
2463 | 2463 | ||
2464 | spin_lock(&OCFS2_I(dir)->ip_lock); | ||
2464 | OCFS2_I(dir)->ip_dyn_features |= OCFS2_INDEXED_DIR_FL; | 2465 | OCFS2_I(dir)->ip_dyn_features |= OCFS2_INDEXED_DIR_FL; |
2465 | di->i_dyn_features = cpu_to_le16(OCFS2_I(dir)->ip_dyn_features); | 2466 | di->i_dyn_features = cpu_to_le16(OCFS2_I(dir)->ip_dyn_features); |
2467 | spin_unlock(&OCFS2_I(dir)->ip_lock); | ||
2466 | 2468 | ||
2467 | ocfs2_journal_dirty(handle, di_bh); | 2469 | ocfs2_journal_dirty(handle, di_bh); |
2468 | 2470 | ||
@@ -4466,8 +4468,10 @@ static int ocfs2_dx_dir_remove_index(struct inode *dir, | |||
4466 | goto out_commit; | 4468 | goto out_commit; |
4467 | } | 4469 | } |
4468 | 4470 | ||
4471 | spin_lock(&OCFS2_I(dir)->ip_lock); | ||
4469 | OCFS2_I(dir)->ip_dyn_features &= ~OCFS2_INDEXED_DIR_FL; | 4472 | OCFS2_I(dir)->ip_dyn_features &= ~OCFS2_INDEXED_DIR_FL; |
4470 | di->i_dyn_features = cpu_to_le16(OCFS2_I(dir)->ip_dyn_features); | 4473 | di->i_dyn_features = cpu_to_le16(OCFS2_I(dir)->ip_dyn_features); |
4474 | spin_unlock(&OCFS2_I(dir)->ip_lock); | ||
4471 | di->i_dx_root = cpu_to_le64(0ULL); | 4475 | di->i_dx_root = cpu_to_le64(0ULL); |
4472 | 4476 | ||
4473 | ocfs2_journal_dirty(handle, di_bh); | 4477 | ocfs2_journal_dirty(handle, di_bh); |
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index f564b0e5f80d..59f0f6bdfc62 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c | |||
@@ -2346,7 +2346,8 @@ static void dlm_deref_lockres_worker(struct dlm_work_item *item, void *data) | |||
2346 | */ | 2346 | */ |
2347 | static int dlm_is_lockres_migrateable(struct dlm_ctxt *dlm, | 2347 | static int dlm_is_lockres_migrateable(struct dlm_ctxt *dlm, |
2348 | struct dlm_lock_resource *res, | 2348 | struct dlm_lock_resource *res, |
2349 | int *numlocks) | 2349 | int *numlocks, |
2350 | int *hasrefs) | ||
2350 | { | 2351 | { |
2351 | int ret; | 2352 | int ret; |
2352 | int i; | 2353 | int i; |
@@ -2356,6 +2357,9 @@ static int dlm_is_lockres_migrateable(struct dlm_ctxt *dlm, | |||
2356 | 2357 | ||
2357 | assert_spin_locked(&res->spinlock); | 2358 | assert_spin_locked(&res->spinlock); |
2358 | 2359 | ||
2360 | *numlocks = 0; | ||
2361 | *hasrefs = 0; | ||
2362 | |||
2359 | ret = -EINVAL; | 2363 | ret = -EINVAL; |
2360 | if (res->owner == DLM_LOCK_RES_OWNER_UNKNOWN) { | 2364 | if (res->owner == DLM_LOCK_RES_OWNER_UNKNOWN) { |
2361 | mlog(0, "cannot migrate lockres with unknown owner!\n"); | 2365 | mlog(0, "cannot migrate lockres with unknown owner!\n"); |
@@ -2386,7 +2390,13 @@ static int dlm_is_lockres_migrateable(struct dlm_ctxt *dlm, | |||
2386 | } | 2390 | } |
2387 | 2391 | ||
2388 | *numlocks = count; | 2392 | *numlocks = count; |
2389 | mlog(0, "migrateable lockres having %d locks\n", *numlocks); | 2393 | |
2394 | count = find_next_bit(res->refmap, O2NM_MAX_NODES, 0); | ||
2395 | if (count < O2NM_MAX_NODES) | ||
2396 | *hasrefs = 1; | ||
2397 | |||
2398 | mlog(0, "%s: res %.*s, Migrateable, locks %d, refs %d\n", dlm->name, | ||
2399 | res->lockname.len, res->lockname.name, *numlocks, *hasrefs); | ||
2390 | 2400 | ||
2391 | leave: | 2401 | leave: |
2392 | return ret; | 2402 | return ret; |
@@ -2408,7 +2418,7 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm, | |||
2408 | const char *name; | 2418 | const char *name; |
2409 | unsigned int namelen; | 2419 | unsigned int namelen; |
2410 | int mle_added = 0; | 2420 | int mle_added = 0; |
2411 | int numlocks; | 2421 | int numlocks, hasrefs; |
2412 | int wake = 0; | 2422 | int wake = 0; |
2413 | 2423 | ||
2414 | if (!dlm_grab(dlm)) | 2424 | if (!dlm_grab(dlm)) |
@@ -2417,13 +2427,13 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm, | |||
2417 | name = res->lockname.name; | 2427 | name = res->lockname.name; |
2418 | namelen = res->lockname.len; | 2428 | namelen = res->lockname.len; |
2419 | 2429 | ||
2420 | mlog(0, "migrating %.*s to %u\n", namelen, name, target); | 2430 | mlog(0, "%s: Migrating %.*s to %u\n", dlm->name, namelen, name, target); |
2421 | 2431 | ||
2422 | /* | 2432 | /* |
2423 | * ensure this lockres is a proper candidate for migration | 2433 | * ensure this lockres is a proper candidate for migration |
2424 | */ | 2434 | */ |
2425 | spin_lock(&res->spinlock); | 2435 | spin_lock(&res->spinlock); |
2426 | ret = dlm_is_lockres_migrateable(dlm, res, &numlocks); | 2436 | ret = dlm_is_lockres_migrateable(dlm, res, &numlocks, &hasrefs); |
2427 | if (ret < 0) { | 2437 | if (ret < 0) { |
2428 | spin_unlock(&res->spinlock); | 2438 | spin_unlock(&res->spinlock); |
2429 | goto leave; | 2439 | goto leave; |
@@ -2431,10 +2441,8 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm, | |||
2431 | spin_unlock(&res->spinlock); | 2441 | spin_unlock(&res->spinlock); |
2432 | 2442 | ||
2433 | /* no work to do */ | 2443 | /* no work to do */ |
2434 | if (numlocks == 0) { | 2444 | if (numlocks == 0 && !hasrefs) |
2435 | mlog(0, "no locks were found on this lockres! done!\n"); | ||
2436 | goto leave; | 2445 | goto leave; |
2437 | } | ||
2438 | 2446 | ||
2439 | /* | 2447 | /* |
2440 | * preallocate up front | 2448 | * preallocate up front |
@@ -2459,14 +2467,14 @@ static int dlm_migrate_lockres(struct dlm_ctxt *dlm, | |||
2459 | * find a node to migrate the lockres to | 2467 | * find a node to migrate the lockres to |
2460 | */ | 2468 | */ |
2461 | 2469 | ||
2462 | mlog(0, "picking a migration node\n"); | ||
2463 | spin_lock(&dlm->spinlock); | 2470 | spin_lock(&dlm->spinlock); |
2464 | /* pick a new node */ | 2471 | /* pick a new node */ |
2465 | if (!test_bit(target, dlm->domain_map) || | 2472 | if (!test_bit(target, dlm->domain_map) || |
2466 | target >= O2NM_MAX_NODES) { | 2473 | target >= O2NM_MAX_NODES) { |
2467 | target = dlm_pick_migration_target(dlm, res); | 2474 | target = dlm_pick_migration_target(dlm, res); |
2468 | } | 2475 | } |
2469 | mlog(0, "node %u chosen for migration\n", target); | 2476 | mlog(0, "%s: res %.*s, Node %u chosen for migration\n", dlm->name, |
2477 | namelen, name, target); | ||
2470 | 2478 | ||
2471 | if (target >= O2NM_MAX_NODES || | 2479 | if (target >= O2NM_MAX_NODES || |
2472 | !test_bit(target, dlm->domain_map)) { | 2480 | !test_bit(target, dlm->domain_map)) { |
@@ -2667,7 +2675,7 @@ int dlm_empty_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res) | |||
2667 | { | 2675 | { |
2668 | int ret; | 2676 | int ret; |
2669 | int lock_dropped = 0; | 2677 | int lock_dropped = 0; |
2670 | int numlocks; | 2678 | int numlocks, hasrefs; |
2671 | 2679 | ||
2672 | spin_lock(&res->spinlock); | 2680 | spin_lock(&res->spinlock); |
2673 | if (res->owner != dlm->node_num) { | 2681 | if (res->owner != dlm->node_num) { |
@@ -2681,8 +2689,8 @@ int dlm_empty_lockres(struct dlm_ctxt *dlm, struct dlm_lock_resource *res) | |||
2681 | } | 2689 | } |
2682 | 2690 | ||
2683 | /* No need to migrate a lockres having no locks */ | 2691 | /* No need to migrate a lockres having no locks */ |
2684 | ret = dlm_is_lockres_migrateable(dlm, res, &numlocks); | 2692 | ret = dlm_is_lockres_migrateable(dlm, res, &numlocks, &hasrefs); |
2685 | if (ret >= 0 && numlocks == 0) { | 2693 | if (ret >= 0 && numlocks == 0 && !hasrefs) { |
2686 | spin_unlock(&res->spinlock); | 2694 | spin_unlock(&res->spinlock); |
2687 | goto leave; | 2695 | goto leave; |
2688 | } | 2696 | } |
@@ -2915,6 +2923,12 @@ static u8 dlm_pick_migration_target(struct dlm_ctxt *dlm, | |||
2915 | } | 2923 | } |
2916 | queue++; | 2924 | queue++; |
2917 | } | 2925 | } |
2926 | |||
2927 | nodenum = find_next_bit(res->refmap, O2NM_MAX_NODES, 0); | ||
2928 | if (nodenum < O2NM_MAX_NODES) { | ||
2929 | spin_unlock(&res->spinlock); | ||
2930 | return nodenum; | ||
2931 | } | ||
2918 | spin_unlock(&res->spinlock); | 2932 | spin_unlock(&res->spinlock); |
2919 | mlog(0, "have not found a suitable target yet! checking domain map\n"); | 2933 | mlog(0, "have not found a suitable target yet! checking domain map\n"); |
2920 | 2934 | ||
diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c index b2df490a19ed..8c5c0eddc365 100644 --- a/fs/ocfs2/dlmfs/dlmfs.c +++ b/fs/ocfs2/dlmfs/dlmfs.c | |||
@@ -351,11 +351,18 @@ static struct inode *dlmfs_alloc_inode(struct super_block *sb) | |||
351 | return &ip->ip_vfs_inode; | 351 | return &ip->ip_vfs_inode; |
352 | } | 352 | } |
353 | 353 | ||
354 | static void dlmfs_destroy_inode(struct inode *inode) | 354 | static void dlmfs_i_callback(struct rcu_head *head) |
355 | { | 355 | { |
356 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
357 | INIT_LIST_HEAD(&inode->i_dentry); | ||
356 | kmem_cache_free(dlmfs_inode_cache, DLMFS_I(inode)); | 358 | kmem_cache_free(dlmfs_inode_cache, DLMFS_I(inode)); |
357 | } | 359 | } |
358 | 360 | ||
361 | static void dlmfs_destroy_inode(struct inode *inode) | ||
362 | { | ||
363 | call_rcu(&inode->i_rcu, dlmfs_i_callback); | ||
364 | } | ||
365 | |||
359 | static void dlmfs_evict_inode(struct inode *inode) | 366 | static void dlmfs_evict_inode(struct inode *inode) |
360 | { | 367 | { |
361 | int status; | 368 | int status; |
diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c index 19ad145d2af3..6adafa576065 100644 --- a/fs/ocfs2/export.c +++ b/fs/ocfs2/export.c | |||
@@ -138,7 +138,7 @@ check_gen: | |||
138 | 138 | ||
139 | result = d_obtain_alias(inode); | 139 | result = d_obtain_alias(inode); |
140 | if (!IS_ERR(result)) | 140 | if (!IS_ERR(result)) |
141 | result->d_op = &ocfs2_dentry_ops; | 141 | d_set_d_op(result, &ocfs2_dentry_ops); |
142 | else | 142 | else |
143 | mlog_errno(PTR_ERR(result)); | 143 | mlog_errno(PTR_ERR(result)); |
144 | 144 | ||
@@ -176,7 +176,7 @@ static struct dentry *ocfs2_get_parent(struct dentry *child) | |||
176 | 176 | ||
177 | parent = d_obtain_alias(ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0)); | 177 | parent = d_obtain_alias(ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0)); |
178 | if (!IS_ERR(parent)) | 178 | if (!IS_ERR(parent)) |
179 | parent->d_op = &ocfs2_dentry_ops; | 179 | d_set_d_op(parent, &ocfs2_dentry_ops); |
180 | 180 | ||
181 | bail_unlock: | 181 | bail_unlock: |
182 | ocfs2_inode_unlock(dir, 0); | 182 | ocfs2_inode_unlock(dir, 0); |
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 77b4c04a2809..bdadbae09094 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -1307,10 +1307,13 @@ bail: | |||
1307 | return err; | 1307 | return err; |
1308 | } | 1308 | } |
1309 | 1309 | ||
1310 | int ocfs2_permission(struct inode *inode, int mask) | 1310 | int ocfs2_permission(struct inode *inode, int mask, unsigned int flags) |
1311 | { | 1311 | { |
1312 | int ret; | 1312 | int ret; |
1313 | 1313 | ||
1314 | if (flags & IPERM_FLAG_RCU) | ||
1315 | return -ECHILD; | ||
1316 | |||
1314 | mlog_entry_void(); | 1317 | mlog_entry_void(); |
1315 | 1318 | ||
1316 | ret = ocfs2_inode_lock(inode, NULL, 0); | 1319 | ret = ocfs2_inode_lock(inode, NULL, 0); |
@@ -1320,7 +1323,7 @@ int ocfs2_permission(struct inode *inode, int mask) | |||
1320 | goto out; | 1323 | goto out; |
1321 | } | 1324 | } |
1322 | 1325 | ||
1323 | ret = generic_permission(inode, mask, ocfs2_check_acl); | 1326 | ret = generic_permission(inode, mask, flags, ocfs2_check_acl); |
1324 | 1327 | ||
1325 | ocfs2_inode_unlock(inode, 0); | 1328 | ocfs2_inode_unlock(inode, 0); |
1326 | out: | 1329 | out: |
@@ -2241,11 +2244,15 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, | |||
2241 | 2244 | ||
2242 | mutex_lock(&inode->i_mutex); | 2245 | mutex_lock(&inode->i_mutex); |
2243 | 2246 | ||
2247 | ocfs2_iocb_clear_sem_locked(iocb); | ||
2248 | |||
2244 | relock: | 2249 | relock: |
2245 | /* to match setattr's i_mutex -> i_alloc_sem -> rw_lock ordering */ | 2250 | /* to match setattr's i_mutex -> i_alloc_sem -> rw_lock ordering */ |
2246 | if (direct_io) { | 2251 | if (direct_io) { |
2247 | down_read(&inode->i_alloc_sem); | 2252 | down_read(&inode->i_alloc_sem); |
2248 | have_alloc_sem = 1; | 2253 | have_alloc_sem = 1; |
2254 | /* communicate with ocfs2_dio_end_io */ | ||
2255 | ocfs2_iocb_set_sem_locked(iocb); | ||
2249 | } | 2256 | } |
2250 | 2257 | ||
2251 | /* | 2258 | /* |
@@ -2382,8 +2389,10 @@ out: | |||
2382 | ocfs2_rw_unlock(inode, rw_level); | 2389 | ocfs2_rw_unlock(inode, rw_level); |
2383 | 2390 | ||
2384 | out_sems: | 2391 | out_sems: |
2385 | if (have_alloc_sem) | 2392 | if (have_alloc_sem) { |
2386 | up_read(&inode->i_alloc_sem); | 2393 | up_read(&inode->i_alloc_sem); |
2394 | ocfs2_iocb_clear_sem_locked(iocb); | ||
2395 | } | ||
2387 | 2396 | ||
2388 | mutex_unlock(&inode->i_mutex); | 2397 | mutex_unlock(&inode->i_mutex); |
2389 | 2398 | ||
@@ -2527,6 +2536,8 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, | |||
2527 | goto bail; | 2536 | goto bail; |
2528 | } | 2537 | } |
2529 | 2538 | ||
2539 | ocfs2_iocb_clear_sem_locked(iocb); | ||
2540 | |||
2530 | /* | 2541 | /* |
2531 | * buffered reads protect themselves in ->readpage(). O_DIRECT reads | 2542 | * buffered reads protect themselves in ->readpage(). O_DIRECT reads |
2532 | * need locks to protect pending reads from racing with truncate. | 2543 | * need locks to protect pending reads from racing with truncate. |
@@ -2534,6 +2545,7 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, | |||
2534 | if (filp->f_flags & O_DIRECT) { | 2545 | if (filp->f_flags & O_DIRECT) { |
2535 | down_read(&inode->i_alloc_sem); | 2546 | down_read(&inode->i_alloc_sem); |
2536 | have_alloc_sem = 1; | 2547 | have_alloc_sem = 1; |
2548 | ocfs2_iocb_set_sem_locked(iocb); | ||
2537 | 2549 | ||
2538 | ret = ocfs2_rw_lock(inode, 0); | 2550 | ret = ocfs2_rw_lock(inode, 0); |
2539 | if (ret < 0) { | 2551 | if (ret < 0) { |
@@ -2575,8 +2587,10 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, | |||
2575 | } | 2587 | } |
2576 | 2588 | ||
2577 | bail: | 2589 | bail: |
2578 | if (have_alloc_sem) | 2590 | if (have_alloc_sem) { |
2579 | up_read(&inode->i_alloc_sem); | 2591 | up_read(&inode->i_alloc_sem); |
2592 | ocfs2_iocb_clear_sem_locked(iocb); | ||
2593 | } | ||
2580 | if (rw_level != -1) | 2594 | if (rw_level != -1) |
2581 | ocfs2_rw_unlock(inode, rw_level); | 2595 | ocfs2_rw_unlock(inode, rw_level); |
2582 | mlog_exit(ret); | 2596 | mlog_exit(ret); |
diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h index 97bf761c9e7c..f5afbbef6703 100644 --- a/fs/ocfs2/file.h +++ b/fs/ocfs2/file.h | |||
@@ -61,7 +61,7 @@ int ocfs2_zero_extend(struct inode *inode, struct buffer_head *di_bh, | |||
61 | int ocfs2_setattr(struct dentry *dentry, struct iattr *attr); | 61 | int ocfs2_setattr(struct dentry *dentry, struct iattr *attr); |
62 | int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, | 62 | int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, |
63 | struct kstat *stat); | 63 | struct kstat *stat); |
64 | int ocfs2_permission(struct inode *inode, int mask); | 64 | int ocfs2_permission(struct inode *inode, int mask, unsigned int flags); |
65 | 65 | ||
66 | int ocfs2_should_update_atime(struct inode *inode, | 66 | int ocfs2_should_update_atime(struct inode *inode, |
67 | struct vfsmount *vfsmnt); | 67 | struct vfsmount *vfsmnt); |
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index ff5744e1e36f..d14cad6e2e41 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c | |||
@@ -147,7 +147,7 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry, | |||
147 | spin_unlock(&oi->ip_lock); | 147 | spin_unlock(&oi->ip_lock); |
148 | 148 | ||
149 | bail_add: | 149 | bail_add: |
150 | dentry->d_op = &ocfs2_dentry_ops; | 150 | d_set_d_op(dentry, &ocfs2_dentry_ops); |
151 | ret = d_splice_alias(inode, dentry); | 151 | ret = d_splice_alias(inode, dentry); |
152 | 152 | ||
153 | if (inode) { | 153 | if (inode) { |
@@ -415,7 +415,7 @@ static int ocfs2_mknod(struct inode *dir, | |||
415 | mlog_errno(status); | 415 | mlog_errno(status); |
416 | goto leave; | 416 | goto leave; |
417 | } | 417 | } |
418 | dentry->d_op = &ocfs2_dentry_ops; | 418 | d_set_d_op(dentry, &ocfs2_dentry_ops); |
419 | 419 | ||
420 | status = ocfs2_add_entry(handle, dentry, inode, | 420 | status = ocfs2_add_entry(handle, dentry, inode, |
421 | OCFS2_I(inode)->ip_blkno, parent_fe_bh, | 421 | OCFS2_I(inode)->ip_blkno, parent_fe_bh, |
@@ -743,7 +743,7 @@ static int ocfs2_link(struct dentry *old_dentry, | |||
743 | } | 743 | } |
744 | 744 | ||
745 | ihold(inode); | 745 | ihold(inode); |
746 | dentry->d_op = &ocfs2_dentry_ops; | 746 | d_set_d_op(dentry, &ocfs2_dentry_ops); |
747 | d_instantiate(dentry, inode); | 747 | d_instantiate(dentry, inode); |
748 | 748 | ||
749 | out_commit: | 749 | out_commit: |
@@ -1794,7 +1794,7 @@ static int ocfs2_symlink(struct inode *dir, | |||
1794 | mlog_errno(status); | 1794 | mlog_errno(status); |
1795 | goto bail; | 1795 | goto bail; |
1796 | } | 1796 | } |
1797 | dentry->d_op = &ocfs2_dentry_ops; | 1797 | d_set_d_op(dentry, &ocfs2_dentry_ops); |
1798 | 1798 | ||
1799 | status = ocfs2_add_entry(handle, dentry, inode, | 1799 | status = ocfs2_add_entry(handle, dentry, inode, |
1800 | le64_to_cpu(fe->i_blkno), parent_fe_bh, | 1800 | le64_to_cpu(fe->i_blkno), parent_fe_bh, |
@@ -2459,7 +2459,7 @@ int ocfs2_mv_orphaned_inode_to_new(struct inode *dir, | |||
2459 | goto out_commit; | 2459 | goto out_commit; |
2460 | } | 2460 | } |
2461 | 2461 | ||
2462 | dentry->d_op = &ocfs2_dentry_ops; | 2462 | d_set_d_op(dentry, &ocfs2_dentry_ops); |
2463 | d_instantiate(dentry, inode); | 2463 | d_instantiate(dentry, inode); |
2464 | status = 0; | 2464 | status = 0; |
2465 | out_commit: | 2465 | out_commit: |
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h index c2e4f8222e2f..bf2e7764920e 100644 --- a/fs/ocfs2/ocfs2_fs.h +++ b/fs/ocfs2/ocfs2_fs.h | |||
@@ -350,7 +350,7 @@ enum { | |||
350 | #define OCFS2_LAST_LOCAL_SYSTEM_INODE LOCAL_GROUP_QUOTA_SYSTEM_INODE | 350 | #define OCFS2_LAST_LOCAL_SYSTEM_INODE LOCAL_GROUP_QUOTA_SYSTEM_INODE |
351 | NUM_SYSTEM_INODES | 351 | NUM_SYSTEM_INODES |
352 | }; | 352 | }; |
353 | #define NUM_GLOBAL_SYSTEM_INODES OCFS2_LAST_GLOBAL_SYSTEM_INODE | 353 | #define NUM_GLOBAL_SYSTEM_INODES OCFS2_FIRST_LOCAL_SYSTEM_INODE |
354 | #define NUM_LOCAL_SYSTEM_INODES \ | 354 | #define NUM_LOCAL_SYSTEM_INODES \ |
355 | (NUM_SYSTEM_INODES - OCFS2_FIRST_LOCAL_SYSTEM_INODE) | 355 | (NUM_SYSTEM_INODES - OCFS2_FIRST_LOCAL_SYSTEM_INODE) |
356 | 356 | ||
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index cfeab7ce3697..17ff46fa8a10 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c | |||
@@ -569,11 +569,18 @@ static struct inode *ocfs2_alloc_inode(struct super_block *sb) | |||
569 | return &oi->vfs_inode; | 569 | return &oi->vfs_inode; |
570 | } | 570 | } |
571 | 571 | ||
572 | static void ocfs2_destroy_inode(struct inode *inode) | 572 | static void ocfs2_i_callback(struct rcu_head *head) |
573 | { | 573 | { |
574 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
575 | INIT_LIST_HEAD(&inode->i_dentry); | ||
574 | kmem_cache_free(ocfs2_inode_cachep, OCFS2_I(inode)); | 576 | kmem_cache_free(ocfs2_inode_cachep, OCFS2_I(inode)); |
575 | } | 577 | } |
576 | 578 | ||
579 | static void ocfs2_destroy_inode(struct inode *inode) | ||
580 | { | ||
581 | call_rcu(&inode->i_rcu, ocfs2_i_callback); | ||
582 | } | ||
583 | |||
577 | static unsigned long long ocfs2_max_file_offset(unsigned int bbits, | 584 | static unsigned long long ocfs2_max_file_offset(unsigned int bbits, |
578 | unsigned int cbits) | 585 | unsigned int cbits) |
579 | { | 586 | { |
diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index 911e61f348fc..a2a5bff774e3 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c | |||
@@ -343,11 +343,18 @@ static struct inode *openprom_alloc_inode(struct super_block *sb) | |||
343 | return &oi->vfs_inode; | 343 | return &oi->vfs_inode; |
344 | } | 344 | } |
345 | 345 | ||
346 | static void openprom_destroy_inode(struct inode *inode) | 346 | static void openprom_i_callback(struct rcu_head *head) |
347 | { | 347 | { |
348 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
349 | INIT_LIST_HEAD(&inode->i_dentry); | ||
348 | kmem_cache_free(op_inode_cachep, OP_I(inode)); | 350 | kmem_cache_free(op_inode_cachep, OP_I(inode)); |
349 | } | 351 | } |
350 | 352 | ||
353 | static void openprom_destroy_inode(struct inode *inode) | ||
354 | { | ||
355 | call_rcu(&inode->i_rcu, openprom_i_callback); | ||
356 | } | ||
357 | |||
351 | static struct inode *openprom_iget(struct super_block *sb, ino_t ino) | 358 | static struct inode *openprom_iget(struct super_block *sb, ino_t ino) |
352 | { | 359 | { |
353 | struct inode *inode; | 360 | struct inode *inode; |
@@ -999,12 +999,12 @@ struct file *create_write_pipe(int flags) | |||
999 | goto err; | 999 | goto err; |
1000 | 1000 | ||
1001 | err = -ENOMEM; | 1001 | err = -ENOMEM; |
1002 | path.dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &name); | 1002 | path.dentry = d_alloc_pseudo(pipe_mnt->mnt_sb, &name); |
1003 | if (!path.dentry) | 1003 | if (!path.dentry) |
1004 | goto err_inode; | 1004 | goto err_inode; |
1005 | path.mnt = mntget(pipe_mnt); | 1005 | path.mnt = mntget(pipe_mnt); |
1006 | 1006 | ||
1007 | path.dentry->d_op = &pipefs_dentry_operations; | 1007 | d_set_d_op(path.dentry, &pipefs_dentry_operations); |
1008 | d_instantiate(path.dentry, inode); | 1008 | d_instantiate(path.dentry, inode); |
1009 | 1009 | ||
1010 | err = -ENFILE; | 1010 | err = -ENFILE; |
@@ -1253,6 +1253,10 @@ out: | |||
1253 | return ret; | 1253 | return ret; |
1254 | } | 1254 | } |
1255 | 1255 | ||
1256 | static const struct super_operations pipefs_ops = { | ||
1257 | .destroy_inode = free_inode_nonrcu, | ||
1258 | }; | ||
1259 | |||
1256 | /* | 1260 | /* |
1257 | * pipefs should _never_ be mounted by userland - too much of security hassle, | 1261 | * pipefs should _never_ be mounted by userland - too much of security hassle, |
1258 | * no real gain from having the whole whorehouse mounted. So we don't need | 1262 | * no real gain from having the whole whorehouse mounted. So we don't need |
@@ -1262,7 +1266,7 @@ out: | |||
1262 | static struct dentry *pipefs_mount(struct file_system_type *fs_type, | 1266 | static struct dentry *pipefs_mount(struct file_system_type *fs_type, |
1263 | int flags, const char *dev_name, void *data) | 1267 | int flags, const char *dev_name, void *data) |
1264 | { | 1268 | { |
1265 | return mount_pseudo(fs_type, "pipe:", NULL, PIPEFS_MAGIC); | 1269 | return mount_pseudo(fs_type, "pipe:", &pipefs_ops, PIPEFS_MAGIC); |
1266 | } | 1270 | } |
1267 | 1271 | ||
1268 | static struct file_system_type pipe_fs_type = { | 1272 | static struct file_system_type pipe_fs_type = { |
@@ -1288,7 +1292,7 @@ static int __init init_pipe_fs(void) | |||
1288 | static void __exit exit_pipe_fs(void) | 1292 | static void __exit exit_pipe_fs(void) |
1289 | { | 1293 | { |
1290 | unregister_filesystem(&pipe_fs_type); | 1294 | unregister_filesystem(&pipe_fs_type); |
1291 | mntput(pipe_mnt); | 1295 | mntput_long(pipe_mnt); |
1292 | } | 1296 | } |
1293 | 1297 | ||
1294 | fs_initcall(init_pipe_fs); | 1298 | fs_initcall(init_pipe_fs); |
diff --git a/fs/pnode.c b/fs/pnode.c index 8066b8dd748f..d42514e32380 100644 --- a/fs/pnode.c +++ b/fs/pnode.c | |||
@@ -288,7 +288,7 @@ out: | |||
288 | */ | 288 | */ |
289 | static inline int do_refcount_check(struct vfsmount *mnt, int count) | 289 | static inline int do_refcount_check(struct vfsmount *mnt, int count) |
290 | { | 290 | { |
291 | int mycount = atomic_read(&mnt->mnt_count) - mnt->mnt_ghosts; | 291 | int mycount = mnt_get_count(mnt) - mnt->mnt_ghosts; |
292 | return (mycount > count); | 292 | return (mycount > count); |
293 | } | 293 | } |
294 | 294 | ||
@@ -300,7 +300,7 @@ static inline int do_refcount_check(struct vfsmount *mnt, int count) | |||
300 | * Check if any of these mounts that **do not have submounts** | 300 | * Check if any of these mounts that **do not have submounts** |
301 | * have more references than 'refcnt'. If so return busy. | 301 | * have more references than 'refcnt'. If so return busy. |
302 | * | 302 | * |
303 | * vfsmount lock must be held for read or write | 303 | * vfsmount lock must be held for write |
304 | */ | 304 | */ |
305 | int propagate_mount_busy(struct vfsmount *mnt, int refcnt) | 305 | int propagate_mount_busy(struct vfsmount *mnt, int refcnt) |
306 | { | 306 | { |
diff --git a/fs/proc/Makefile b/fs/proc/Makefile index 2758e2afc518..288a49e098bf 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile | |||
@@ -15,6 +15,7 @@ proc-y += devices.o | |||
15 | proc-y += interrupts.o | 15 | proc-y += interrupts.o |
16 | proc-y += loadavg.o | 16 | proc-y += loadavg.o |
17 | proc-y += meminfo.o | 17 | proc-y += meminfo.o |
18 | proc-y += proc_console.o | ||
18 | proc-y += stat.o | 19 | proc-y += stat.o |
19 | proc-y += uptime.o | 20 | proc-y += uptime.o |
20 | proc-y += version.o | 21 | proc-y += version.o |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 182845147fe4..b20962c71a52 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -1407,6 +1407,82 @@ static const struct file_operations proc_pid_sched_operations = { | |||
1407 | 1407 | ||
1408 | #endif | 1408 | #endif |
1409 | 1409 | ||
1410 | #ifdef CONFIG_SCHED_AUTOGROUP | ||
1411 | /* | ||
1412 | * Print out autogroup related information: | ||
1413 | */ | ||
1414 | static int sched_autogroup_show(struct seq_file *m, void *v) | ||
1415 | { | ||
1416 | struct inode *inode = m->private; | ||
1417 | struct task_struct *p; | ||
1418 | |||
1419 | p = get_proc_task(inode); | ||
1420 | if (!p) | ||
1421 | return -ESRCH; | ||
1422 | proc_sched_autogroup_show_task(p, m); | ||
1423 | |||
1424 | put_task_struct(p); | ||
1425 | |||
1426 | return 0; | ||
1427 | } | ||
1428 | |||
1429 | static ssize_t | ||
1430 | sched_autogroup_write(struct file *file, const char __user *buf, | ||
1431 | size_t count, loff_t *offset) | ||
1432 | { | ||
1433 | struct inode *inode = file->f_path.dentry->d_inode; | ||
1434 | struct task_struct *p; | ||
1435 | char buffer[PROC_NUMBUF]; | ||
1436 | long nice; | ||
1437 | int err; | ||
1438 | |||
1439 | memset(buffer, 0, sizeof(buffer)); | ||
1440 | if (count > sizeof(buffer) - 1) | ||
1441 | count = sizeof(buffer) - 1; | ||
1442 | if (copy_from_user(buffer, buf, count)) | ||
1443 | return -EFAULT; | ||
1444 | |||
1445 | err = strict_strtol(strstrip(buffer), 0, &nice); | ||
1446 | if (err) | ||
1447 | return -EINVAL; | ||
1448 | |||
1449 | p = get_proc_task(inode); | ||
1450 | if (!p) | ||
1451 | return -ESRCH; | ||
1452 | |||
1453 | err = nice; | ||
1454 | err = proc_sched_autogroup_set_nice(p, &err); | ||
1455 | if (err) | ||
1456 | count = err; | ||
1457 | |||
1458 | put_task_struct(p); | ||
1459 | |||
1460 | return count; | ||
1461 | } | ||
1462 | |||
1463 | static int sched_autogroup_open(struct inode *inode, struct file *filp) | ||
1464 | { | ||
1465 | int ret; | ||
1466 | |||
1467 | ret = single_open(filp, sched_autogroup_show, NULL); | ||
1468 | if (!ret) { | ||
1469 | struct seq_file *m = filp->private_data; | ||
1470 | |||
1471 | m->private = inode; | ||
1472 | } | ||
1473 | return ret; | ||
1474 | } | ||
1475 | |||
1476 | static const struct file_operations proc_pid_sched_autogroup_operations = { | ||
1477 | .open = sched_autogroup_open, | ||
1478 | .read = seq_read, | ||
1479 | .write = sched_autogroup_write, | ||
1480 | .llseek = seq_lseek, | ||
1481 | .release = single_release, | ||
1482 | }; | ||
1483 | |||
1484 | #endif /* CONFIG_SCHED_AUTOGROUP */ | ||
1485 | |||
1410 | static ssize_t comm_write(struct file *file, const char __user *buf, | 1486 | static ssize_t comm_write(struct file *file, const char __user *buf, |
1411 | size_t count, loff_t *offset) | 1487 | size_t count, loff_t *offset) |
1412 | { | 1488 | { |
@@ -1719,10 +1795,16 @@ static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat | |||
1719 | */ | 1795 | */ |
1720 | static int pid_revalidate(struct dentry *dentry, struct nameidata *nd) | 1796 | static int pid_revalidate(struct dentry *dentry, struct nameidata *nd) |
1721 | { | 1797 | { |
1722 | struct inode *inode = dentry->d_inode; | 1798 | struct inode *inode; |
1723 | struct task_struct *task = get_proc_task(inode); | 1799 | struct task_struct *task; |
1724 | const struct cred *cred; | 1800 | const struct cred *cred; |
1725 | 1801 | ||
1802 | if (nd && nd->flags & LOOKUP_RCU) | ||
1803 | return -ECHILD; | ||
1804 | |||
1805 | inode = dentry->d_inode; | ||
1806 | task = get_proc_task(inode); | ||
1807 | |||
1726 | if (task) { | 1808 | if (task) { |
1727 | if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) || | 1809 | if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) || |
1728 | task_dumpable(task)) { | 1810 | task_dumpable(task)) { |
@@ -1744,7 +1826,7 @@ static int pid_revalidate(struct dentry *dentry, struct nameidata *nd) | |||
1744 | return 0; | 1826 | return 0; |
1745 | } | 1827 | } |
1746 | 1828 | ||
1747 | static int pid_delete_dentry(struct dentry * dentry) | 1829 | static int pid_delete_dentry(const struct dentry * dentry) |
1748 | { | 1830 | { |
1749 | /* Is the task we represent dead? | 1831 | /* Is the task we represent dead? |
1750 | * If so, then don't put the dentry on the lru list, | 1832 | * If so, then don't put the dentry on the lru list, |
@@ -1888,12 +1970,19 @@ static int proc_fd_link(struct inode *inode, struct path *path) | |||
1888 | 1970 | ||
1889 | static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) | 1971 | static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) |
1890 | { | 1972 | { |
1891 | struct inode *inode = dentry->d_inode; | 1973 | struct inode *inode; |
1892 | struct task_struct *task = get_proc_task(inode); | 1974 | struct task_struct *task; |
1893 | int fd = proc_fd(inode); | 1975 | int fd; |
1894 | struct files_struct *files; | 1976 | struct files_struct *files; |
1895 | const struct cred *cred; | 1977 | const struct cred *cred; |
1896 | 1978 | ||
1979 | if (nd && nd->flags & LOOKUP_RCU) | ||
1980 | return -ECHILD; | ||
1981 | |||
1982 | inode = dentry->d_inode; | ||
1983 | task = get_proc_task(inode); | ||
1984 | fd = proc_fd(inode); | ||
1985 | |||
1897 | if (task) { | 1986 | if (task) { |
1898 | files = get_files_struct(task); | 1987 | files = get_files_struct(task); |
1899 | if (files) { | 1988 | if (files) { |
@@ -1969,7 +2058,7 @@ static struct dentry *proc_fd_instantiate(struct inode *dir, | |||
1969 | inode->i_op = &proc_pid_link_inode_operations; | 2058 | inode->i_op = &proc_pid_link_inode_operations; |
1970 | inode->i_size = 64; | 2059 | inode->i_size = 64; |
1971 | ei->op.proc_get_link = proc_fd_link; | 2060 | ei->op.proc_get_link = proc_fd_link; |
1972 | dentry->d_op = &tid_fd_dentry_operations; | 2061 | d_set_d_op(dentry, &tid_fd_dentry_operations); |
1973 | d_add(dentry, inode); | 2062 | d_add(dentry, inode); |
1974 | /* Close the race of the process dying before we return the dentry */ | 2063 | /* Close the race of the process dying before we return the dentry */ |
1975 | if (tid_fd_revalidate(dentry, NULL)) | 2064 | if (tid_fd_revalidate(dentry, NULL)) |
@@ -2101,11 +2190,13 @@ static const struct file_operations proc_fd_operations = { | |||
2101 | * /proc/pid/fd needs a special permission handler so that a process can still | 2190 | * /proc/pid/fd needs a special permission handler so that a process can still |
2102 | * access /proc/self/fd after it has executed a setuid(). | 2191 | * access /proc/self/fd after it has executed a setuid(). |
2103 | */ | 2192 | */ |
2104 | static int proc_fd_permission(struct inode *inode, int mask) | 2193 | static int proc_fd_permission(struct inode *inode, int mask, unsigned int flags) |
2105 | { | 2194 | { |
2106 | int rv; | 2195 | int rv; |
2107 | 2196 | ||
2108 | rv = generic_permission(inode, mask, NULL); | 2197 | if (flags & IPERM_FLAG_RCU) |
2198 | return -ECHILD; | ||
2199 | rv = generic_permission(inode, mask, flags, NULL); | ||
2109 | if (rv == 0) | 2200 | if (rv == 0) |
2110 | return 0; | 2201 | return 0; |
2111 | if (task_pid(current) == proc_pid(inode)) | 2202 | if (task_pid(current) == proc_pid(inode)) |
@@ -2137,7 +2228,7 @@ static struct dentry *proc_fdinfo_instantiate(struct inode *dir, | |||
2137 | ei->fd = fd; | 2228 | ei->fd = fd; |
2138 | inode->i_mode = S_IFREG | S_IRUSR; | 2229 | inode->i_mode = S_IFREG | S_IRUSR; |
2139 | inode->i_fop = &proc_fdinfo_file_operations; | 2230 | inode->i_fop = &proc_fdinfo_file_operations; |
2140 | dentry->d_op = &tid_fd_dentry_operations; | 2231 | d_set_d_op(dentry, &tid_fd_dentry_operations); |
2141 | d_add(dentry, inode); | 2232 | d_add(dentry, inode); |
2142 | /* Close the race of the process dying before we return the dentry */ | 2233 | /* Close the race of the process dying before we return the dentry */ |
2143 | if (tid_fd_revalidate(dentry, NULL)) | 2234 | if (tid_fd_revalidate(dentry, NULL)) |
@@ -2196,7 +2287,7 @@ static struct dentry *proc_pident_instantiate(struct inode *dir, | |||
2196 | if (p->fop) | 2287 | if (p->fop) |
2197 | inode->i_fop = p->fop; | 2288 | inode->i_fop = p->fop; |
2198 | ei->op = p->op; | 2289 | ei->op = p->op; |
2199 | dentry->d_op = &pid_dentry_operations; | 2290 | d_set_d_op(dentry, &pid_dentry_operations); |
2200 | d_add(dentry, inode); | 2291 | d_add(dentry, inode); |
2201 | /* Close the race of the process dying before we return the dentry */ | 2292 | /* Close the race of the process dying before we return the dentry */ |
2202 | if (pid_revalidate(dentry, NULL)) | 2293 | if (pid_revalidate(dentry, NULL)) |
@@ -2563,8 +2654,14 @@ static const struct pid_entry proc_base_stuff[] = { | |||
2563 | */ | 2654 | */ |
2564 | static int proc_base_revalidate(struct dentry *dentry, struct nameidata *nd) | 2655 | static int proc_base_revalidate(struct dentry *dentry, struct nameidata *nd) |
2565 | { | 2656 | { |
2566 | struct inode *inode = dentry->d_inode; | 2657 | struct inode *inode; |
2567 | struct task_struct *task = get_proc_task(inode); | 2658 | struct task_struct *task; |
2659 | |||
2660 | if (nd->flags & LOOKUP_RCU) | ||
2661 | return -ECHILD; | ||
2662 | |||
2663 | inode = dentry->d_inode; | ||
2664 | task = get_proc_task(inode); | ||
2568 | if (task) { | 2665 | if (task) { |
2569 | put_task_struct(task); | 2666 | put_task_struct(task); |
2570 | return 1; | 2667 | return 1; |
@@ -2615,7 +2712,7 @@ static struct dentry *proc_base_instantiate(struct inode *dir, | |||
2615 | if (p->fop) | 2712 | if (p->fop) |
2616 | inode->i_fop = p->fop; | 2713 | inode->i_fop = p->fop; |
2617 | ei->op = p->op; | 2714 | ei->op = p->op; |
2618 | dentry->d_op = &proc_base_dentry_operations; | 2715 | d_set_d_op(dentry, &proc_base_dentry_operations); |
2619 | d_add(dentry, inode); | 2716 | d_add(dentry, inode); |
2620 | error = NULL; | 2717 | error = NULL; |
2621 | out: | 2718 | out: |
@@ -2733,6 +2830,9 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2733 | #ifdef CONFIG_SCHED_DEBUG | 2830 | #ifdef CONFIG_SCHED_DEBUG |
2734 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), | 2831 | REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), |
2735 | #endif | 2832 | #endif |
2833 | #ifdef CONFIG_SCHED_AUTOGROUP | ||
2834 | REG("autogroup", S_IRUGO|S_IWUSR, proc_pid_sched_autogroup_operations), | ||
2835 | #endif | ||
2736 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), | 2836 | REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), |
2737 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK | 2837 | #ifdef CONFIG_HAVE_ARCH_TRACEHOOK |
2738 | INF("syscall", S_IRUSR, proc_pid_syscall), | 2838 | INF("syscall", S_IRUSR, proc_pid_syscall), |
@@ -2926,7 +3026,7 @@ static struct dentry *proc_pid_instantiate(struct inode *dir, | |||
2926 | inode->i_nlink = 2 + pid_entry_count_dirs(tgid_base_stuff, | 3026 | inode->i_nlink = 2 + pid_entry_count_dirs(tgid_base_stuff, |
2927 | ARRAY_SIZE(tgid_base_stuff)); | 3027 | ARRAY_SIZE(tgid_base_stuff)); |
2928 | 3028 | ||
2929 | dentry->d_op = &pid_dentry_operations; | 3029 | d_set_d_op(dentry, &pid_dentry_operations); |
2930 | 3030 | ||
2931 | d_add(dentry, inode); | 3031 | d_add(dentry, inode); |
2932 | /* Close the race of the process dying before we return the dentry */ | 3032 | /* Close the race of the process dying before we return the dentry */ |
@@ -3169,7 +3269,7 @@ static struct dentry *proc_task_instantiate(struct inode *dir, | |||
3169 | inode->i_nlink = 2 + pid_entry_count_dirs(tid_base_stuff, | 3269 | inode->i_nlink = 2 + pid_entry_count_dirs(tid_base_stuff, |
3170 | ARRAY_SIZE(tid_base_stuff)); | 3270 | ARRAY_SIZE(tid_base_stuff)); |
3171 | 3271 | ||
3172 | dentry->d_op = &pid_dentry_operations; | 3272 | d_set_d_op(dentry, &pid_dentry_operations); |
3173 | 3273 | ||
3174 | d_add(dentry, inode); | 3274 | d_add(dentry, inode); |
3175 | /* Close the race of the process dying before we return the dentry */ | 3275 | /* Close the race of the process dying before we return the dentry */ |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index dd29f0337661..f766be29d2c7 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -400,7 +400,7 @@ static const struct inode_operations proc_link_inode_operations = { | |||
400 | * smarter: we could keep a "volatile" flag in the | 400 | * smarter: we could keep a "volatile" flag in the |
401 | * inode to indicate which ones to keep. | 401 | * inode to indicate which ones to keep. |
402 | */ | 402 | */ |
403 | static int proc_delete_dentry(struct dentry * dentry) | 403 | static int proc_delete_dentry(const struct dentry * dentry) |
404 | { | 404 | { |
405 | return 1; | 405 | return 1; |
406 | } | 406 | } |
@@ -439,7 +439,7 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir, | |||
439 | out_unlock: | 439 | out_unlock: |
440 | 440 | ||
441 | if (inode) { | 441 | if (inode) { |
442 | dentry->d_op = &proc_dentry_operations; | 442 | d_set_d_op(dentry, &proc_dentry_operations); |
443 | d_add(dentry, inode); | 443 | d_add(dentry, inode); |
444 | return NULL; | 444 | return NULL; |
445 | } | 445 | } |
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 3ddb6068177c..6bcb926b101b 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
@@ -65,11 +65,18 @@ static struct inode *proc_alloc_inode(struct super_block *sb) | |||
65 | return inode; | 65 | return inode; |
66 | } | 66 | } |
67 | 67 | ||
68 | static void proc_destroy_inode(struct inode *inode) | 68 | static void proc_i_callback(struct rcu_head *head) |
69 | { | 69 | { |
70 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
71 | INIT_LIST_HEAD(&inode->i_dentry); | ||
70 | kmem_cache_free(proc_inode_cachep, PROC_I(inode)); | 72 | kmem_cache_free(proc_inode_cachep, PROC_I(inode)); |
71 | } | 73 | } |
72 | 74 | ||
75 | static void proc_destroy_inode(struct inode *inode) | ||
76 | { | ||
77 | call_rcu(&inode->i_rcu, proc_i_callback); | ||
78 | } | ||
79 | |||
73 | static void init_once(void *foo) | 80 | static void init_once(void *foo) |
74 | { | 81 | { |
75 | struct proc_inode *ei = (struct proc_inode *) foo; | 82 | struct proc_inode *ei = (struct proc_inode *) foo; |
diff --git a/fs/proc/proc_console.c b/fs/proc/proc_console.c new file mode 100644 index 000000000000..8a707609f528 --- /dev/null +++ b/fs/proc/proc_console.c | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2010 Werner Fink, Jiri Slaby | ||
3 | * | ||
4 | * Licensed under GPLv2 | ||
5 | */ | ||
6 | |||
7 | #include <linux/console.h> | ||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/proc_fs.h> | ||
10 | #include <linux/seq_file.h> | ||
11 | #include <linux/tty_driver.h> | ||
12 | |||
13 | /* | ||
14 | * This is handler for /proc/consoles | ||
15 | */ | ||
16 | static int show_console_dev(struct seq_file *m, void *v) | ||
17 | { | ||
18 | static const struct { | ||
19 | short flag; | ||
20 | char name; | ||
21 | } con_flags[] = { | ||
22 | { CON_ENABLED, 'E' }, | ||
23 | { CON_CONSDEV, 'C' }, | ||
24 | { CON_BOOT, 'B' }, | ||
25 | { CON_PRINTBUFFER, 'p' }, | ||
26 | { CON_BRL, 'b' }, | ||
27 | { CON_ANYTIME, 'a' }, | ||
28 | }; | ||
29 | char flags[ARRAY_SIZE(con_flags) + 1]; | ||
30 | struct console *con = v; | ||
31 | unsigned int a; | ||
32 | int len; | ||
33 | dev_t dev = 0; | ||
34 | |||
35 | if (con->device) { | ||
36 | const struct tty_driver *driver; | ||
37 | int index; | ||
38 | driver = con->device(con, &index); | ||
39 | if (driver) { | ||
40 | dev = MKDEV(driver->major, driver->minor_start); | ||
41 | dev += index; | ||
42 | } | ||
43 | } | ||
44 | |||
45 | for (a = 0; a < ARRAY_SIZE(con_flags); a++) | ||
46 | flags[a] = (con->flags & con_flags[a].flag) ? | ||
47 | con_flags[a].name : ' '; | ||
48 | flags[a] = 0; | ||
49 | |||
50 | seq_printf(m, "%s%d%n", con->name, con->index, &len); | ||
51 | len = 21 - len; | ||
52 | if (len < 1) | ||
53 | len = 1; | ||
54 | seq_printf(m, "%*c%c%c%c (%s)", len, ' ', con->read ? 'R' : '-', | ||
55 | con->write ? 'W' : '-', con->unblank ? 'U' : '-', | ||
56 | flags); | ||
57 | if (dev) | ||
58 | seq_printf(m, " %4d:%d", MAJOR(dev), MINOR(dev)); | ||
59 | |||
60 | seq_printf(m, "\n"); | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static void *c_start(struct seq_file *m, loff_t *pos) | ||
66 | { | ||
67 | struct console *con; | ||
68 | loff_t off = 0; | ||
69 | |||
70 | acquire_console_sem(); | ||
71 | for_each_console(con) | ||
72 | if (off++ == *pos) | ||
73 | break; | ||
74 | |||
75 | return con; | ||
76 | } | ||
77 | |||
78 | static void *c_next(struct seq_file *m, void *v, loff_t *pos) | ||
79 | { | ||
80 | struct console *con = v; | ||
81 | ++*pos; | ||
82 | return con->next; | ||
83 | } | ||
84 | |||
85 | static void c_stop(struct seq_file *m, void *v) | ||
86 | { | ||
87 | release_console_sem(); | ||
88 | } | ||
89 | |||
90 | static const struct seq_operations consoles_op = { | ||
91 | .start = c_start, | ||
92 | .next = c_next, | ||
93 | .stop = c_stop, | ||
94 | .show = show_console_dev | ||
95 | }; | ||
96 | |||
97 | static int consoles_open(struct inode *inode, struct file *file) | ||
98 | { | ||
99 | return seq_open(file, &consoles_op); | ||
100 | } | ||
101 | |||
102 | static const struct file_operations proc_consoles_operations = { | ||
103 | .open = consoles_open, | ||
104 | .read = seq_read, | ||
105 | .llseek = seq_lseek, | ||
106 | .release = seq_release, | ||
107 | }; | ||
108 | |||
109 | static int register_proc_consoles(void) | ||
110 | { | ||
111 | proc_create("consoles", 0, NULL, &proc_consoles_operations); | ||
112 | return 0; | ||
113 | } | ||
114 | module_init(register_proc_consoles); | ||
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index b652cb00906b..09a1f92a34ef 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/sysctl.h> | 5 | #include <linux/sysctl.h> |
6 | #include <linux/proc_fs.h> | 6 | #include <linux/proc_fs.h> |
7 | #include <linux/security.h> | 7 | #include <linux/security.h> |
8 | #include <linux/namei.h> | ||
8 | #include "internal.h" | 9 | #include "internal.h" |
9 | 10 | ||
10 | static const struct dentry_operations proc_sys_dentry_operations; | 11 | static const struct dentry_operations proc_sys_dentry_operations; |
@@ -120,7 +121,7 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry, | |||
120 | goto out; | 121 | goto out; |
121 | 122 | ||
122 | err = NULL; | 123 | err = NULL; |
123 | dentry->d_op = &proc_sys_dentry_operations; | 124 | d_set_d_op(dentry, &proc_sys_dentry_operations); |
124 | d_add(dentry, inode); | 125 | d_add(dentry, inode); |
125 | 126 | ||
126 | out: | 127 | out: |
@@ -201,7 +202,7 @@ static int proc_sys_fill_cache(struct file *filp, void *dirent, | |||
201 | dput(child); | 202 | dput(child); |
202 | return -ENOMEM; | 203 | return -ENOMEM; |
203 | } else { | 204 | } else { |
204 | child->d_op = &proc_sys_dentry_operations; | 205 | d_set_d_op(child, &proc_sys_dentry_operations); |
205 | d_add(child, inode); | 206 | d_add(child, inode); |
206 | } | 207 | } |
207 | } else { | 208 | } else { |
@@ -294,7 +295,7 @@ out: | |||
294 | return ret; | 295 | return ret; |
295 | } | 296 | } |
296 | 297 | ||
297 | static int proc_sys_permission(struct inode *inode, int mask) | 298 | static int proc_sys_permission(struct inode *inode, int mask,unsigned int flags) |
298 | { | 299 | { |
299 | /* | 300 | /* |
300 | * sysctl entries that are not writeable, | 301 | * sysctl entries that are not writeable, |
@@ -304,6 +305,9 @@ static int proc_sys_permission(struct inode *inode, int mask) | |||
304 | struct ctl_table *table; | 305 | struct ctl_table *table; |
305 | int error; | 306 | int error; |
306 | 307 | ||
308 | if (flags & IPERM_FLAG_RCU) | ||
309 | return -ECHILD; | ||
310 | |||
307 | /* Executable files are not allowed under /proc/sys/ */ | 311 | /* Executable files are not allowed under /proc/sys/ */ |
308 | if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) | 312 | if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) |
309 | return -EACCES; | 313 | return -EACCES; |
@@ -389,23 +393,30 @@ static const struct inode_operations proc_sys_dir_operations = { | |||
389 | 393 | ||
390 | static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd) | 394 | static int proc_sys_revalidate(struct dentry *dentry, struct nameidata *nd) |
391 | { | 395 | { |
396 | if (nd->flags & LOOKUP_RCU) | ||
397 | return -ECHILD; | ||
392 | return !PROC_I(dentry->d_inode)->sysctl->unregistering; | 398 | return !PROC_I(dentry->d_inode)->sysctl->unregistering; |
393 | } | 399 | } |
394 | 400 | ||
395 | static int proc_sys_delete(struct dentry *dentry) | 401 | static int proc_sys_delete(const struct dentry *dentry) |
396 | { | 402 | { |
397 | return !!PROC_I(dentry->d_inode)->sysctl->unregistering; | 403 | return !!PROC_I(dentry->d_inode)->sysctl->unregistering; |
398 | } | 404 | } |
399 | 405 | ||
400 | static int proc_sys_compare(struct dentry *dir, struct qstr *qstr, | 406 | static int proc_sys_compare(const struct dentry *parent, |
401 | struct qstr *name) | 407 | const struct inode *pinode, |
408 | const struct dentry *dentry, const struct inode *inode, | ||
409 | unsigned int len, const char *str, const struct qstr *name) | ||
402 | { | 410 | { |
403 | struct dentry *dentry = container_of(qstr, struct dentry, d_name); | 411 | /* Although proc doesn't have negative dentries, rcu-walk means |
404 | if (qstr->len != name->len) | 412 | * that inode here can be NULL */ |
413 | if (!inode) | ||
414 | return 0; | ||
415 | if (name->len != len) | ||
405 | return 1; | 416 | return 1; |
406 | if (memcmp(qstr->name, name->name, name->len)) | 417 | if (memcmp(name->name, str, len)) |
407 | return 1; | 418 | return 1; |
408 | return !sysctl_is_seen(PROC_I(dentry->d_inode)->sysctl); | 419 | return !sysctl_is_seen(PROC_I(inode)->sysctl); |
409 | } | 420 | } |
410 | 421 | ||
411 | static const struct dentry_operations proc_sys_dentry_operations = { | 422 | static const struct dentry_operations proc_sys_dentry_operations = { |
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index 2367fb3f70bc..74802bc5ded9 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c | |||
@@ -499,7 +499,7 @@ static int __init parse_crash_elf64_headers(void) | |||
499 | /* Do some basic Verification. */ | 499 | /* Do some basic Verification. */ |
500 | if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 || | 500 | if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 || |
501 | (ehdr.e_type != ET_CORE) || | 501 | (ehdr.e_type != ET_CORE) || |
502 | !vmcore_elf_check_arch(&ehdr) || | 502 | !vmcore_elf64_check_arch(&ehdr) || |
503 | ehdr.e_ident[EI_CLASS] != ELFCLASS64 || | 503 | ehdr.e_ident[EI_CLASS] != ELFCLASS64 || |
504 | ehdr.e_ident[EI_VERSION] != EV_CURRENT || | 504 | ehdr.e_ident[EI_VERSION] != EV_CURRENT || |
505 | ehdr.e_version != EV_CURRENT || | 505 | ehdr.e_version != EV_CURRENT || |
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index fcada42f1aa3..e63b4171d583 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c | |||
@@ -425,11 +425,18 @@ static struct inode *qnx4_alloc_inode(struct super_block *sb) | |||
425 | return &ei->vfs_inode; | 425 | return &ei->vfs_inode; |
426 | } | 426 | } |
427 | 427 | ||
428 | static void qnx4_destroy_inode(struct inode *inode) | 428 | static void qnx4_i_callback(struct rcu_head *head) |
429 | { | 429 | { |
430 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
431 | INIT_LIST_HEAD(&inode->i_dentry); | ||
430 | kmem_cache_free(qnx4_inode_cachep, qnx4_i(inode)); | 432 | kmem_cache_free(qnx4_inode_cachep, qnx4_i(inode)); |
431 | } | 433 | } |
432 | 434 | ||
435 | static void qnx4_destroy_inode(struct inode *inode) | ||
436 | { | ||
437 | call_rcu(&inode->i_rcu, qnx4_i_callback); | ||
438 | } | ||
439 | |||
433 | static void init_once(void *foo) | 440 | static void init_once(void *foo) |
434 | { | 441 | { |
435 | struct qnx4_inode_info *ei = (struct qnx4_inode_info *) foo; | 442 | struct qnx4_inode_info *ei = (struct qnx4_inode_info *) foo; |
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index b243117b8752..2575682a9ead 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
@@ -529,11 +529,18 @@ static struct inode *reiserfs_alloc_inode(struct super_block *sb) | |||
529 | return &ei->vfs_inode; | 529 | return &ei->vfs_inode; |
530 | } | 530 | } |
531 | 531 | ||
532 | static void reiserfs_destroy_inode(struct inode *inode) | 532 | static void reiserfs_i_callback(struct rcu_head *head) |
533 | { | 533 | { |
534 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
535 | INIT_LIST_HEAD(&inode->i_dentry); | ||
534 | kmem_cache_free(reiserfs_inode_cachep, REISERFS_I(inode)); | 536 | kmem_cache_free(reiserfs_inode_cachep, REISERFS_I(inode)); |
535 | } | 537 | } |
536 | 538 | ||
539 | static void reiserfs_destroy_inode(struct inode *inode) | ||
540 | { | ||
541 | call_rcu(&inode->i_rcu, reiserfs_i_callback); | ||
542 | } | ||
543 | |||
537 | static void init_once(void *foo) | 544 | static void init_once(void *foo) |
538 | { | 545 | { |
539 | struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *)foo; | 546 | struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *)foo; |
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 5d04a7828e7a..3cfb2e933644 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c | |||
@@ -870,11 +870,14 @@ out: | |||
870 | return err; | 870 | return err; |
871 | } | 871 | } |
872 | 872 | ||
873 | static int reiserfs_check_acl(struct inode *inode, int mask) | 873 | static int reiserfs_check_acl(struct inode *inode, int mask, unsigned int flags) |
874 | { | 874 | { |
875 | struct posix_acl *acl; | 875 | struct posix_acl *acl; |
876 | int error = -EAGAIN; /* do regular unix permission checks by default */ | 876 | int error = -EAGAIN; /* do regular unix permission checks by default */ |
877 | 877 | ||
878 | if (flags & IPERM_FLAG_RCU) | ||
879 | return -ECHILD; | ||
880 | |||
878 | acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); | 881 | acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS); |
879 | 882 | ||
880 | if (acl) { | 883 | if (acl) { |
@@ -951,8 +954,10 @@ static int xattr_mount_check(struct super_block *s) | |||
951 | return 0; | 954 | return 0; |
952 | } | 955 | } |
953 | 956 | ||
954 | int reiserfs_permission(struct inode *inode, int mask) | 957 | int reiserfs_permission(struct inode *inode, int mask, unsigned int flags) |
955 | { | 958 | { |
959 | if (flags & IPERM_FLAG_RCU) | ||
960 | return -ECHILD; | ||
956 | /* | 961 | /* |
957 | * We don't do permission checks on the internal objects. | 962 | * We don't do permission checks on the internal objects. |
958 | * Permissions are determined by the "owning" object. | 963 | * Permissions are determined by the "owning" object. |
@@ -965,13 +970,16 @@ int reiserfs_permission(struct inode *inode, int mask) | |||
965 | * Stat data v1 doesn't support ACLs. | 970 | * Stat data v1 doesn't support ACLs. |
966 | */ | 971 | */ |
967 | if (get_inode_sd_version(inode) != STAT_DATA_V1) | 972 | if (get_inode_sd_version(inode) != STAT_DATA_V1) |
968 | return generic_permission(inode, mask, reiserfs_check_acl); | 973 | return generic_permission(inode, mask, flags, |
974 | reiserfs_check_acl); | ||
969 | #endif | 975 | #endif |
970 | return generic_permission(inode, mask, NULL); | 976 | return generic_permission(inode, mask, flags, NULL); |
971 | } | 977 | } |
972 | 978 | ||
973 | static int xattr_hide_revalidate(struct dentry *dentry, struct nameidata *nd) | 979 | static int xattr_hide_revalidate(struct dentry *dentry, struct nameidata *nd) |
974 | { | 980 | { |
981 | if (nd->flags & LOOKUP_RCU) | ||
982 | return -ECHILD; | ||
975 | return -EPERM; | 983 | return -EPERM; |
976 | } | 984 | } |
977 | 985 | ||
@@ -990,7 +998,7 @@ int reiserfs_lookup_privroot(struct super_block *s) | |||
990 | strlen(PRIVROOT_NAME)); | 998 | strlen(PRIVROOT_NAME)); |
991 | if (!IS_ERR(dentry)) { | 999 | if (!IS_ERR(dentry)) { |
992 | REISERFS_SB(s)->priv_root = dentry; | 1000 | REISERFS_SB(s)->priv_root = dentry; |
993 | dentry->d_op = &xattr_lookup_poison_ops; | 1001 | d_set_d_op(dentry, &xattr_lookup_poison_ops); |
994 | if (dentry->d_inode) | 1002 | if (dentry->d_inode) |
995 | dentry->d_inode->i_flags |= S_PRIVATE; | 1003 | dentry->d_inode->i_flags |= S_PRIVATE; |
996 | } else | 1004 | } else |
diff --git a/fs/romfs/super.c b/fs/romfs/super.c index 6647f90e55cd..2305e3121cb1 100644 --- a/fs/romfs/super.c +++ b/fs/romfs/super.c | |||
@@ -400,11 +400,18 @@ static struct inode *romfs_alloc_inode(struct super_block *sb) | |||
400 | /* | 400 | /* |
401 | * return a spent inode to the slab cache | 401 | * return a spent inode to the slab cache |
402 | */ | 402 | */ |
403 | static void romfs_destroy_inode(struct inode *inode) | 403 | static void romfs_i_callback(struct rcu_head *head) |
404 | { | 404 | { |
405 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
406 | INIT_LIST_HEAD(&inode->i_dentry); | ||
405 | kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode)); | 407 | kmem_cache_free(romfs_inode_cachep, ROMFS_I(inode)); |
406 | } | 408 | } |
407 | 409 | ||
410 | static void romfs_destroy_inode(struct inode *inode) | ||
411 | { | ||
412 | call_rcu(&inode->i_rcu, romfs_i_callback); | ||
413 | } | ||
414 | |||
408 | /* | 415 | /* |
409 | * get filesystem statistics | 416 | * get filesystem statistics |
410 | */ | 417 | */ |
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 24de30ba34c1..20700b9f2b4c 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c | |||
@@ -440,11 +440,18 @@ static struct inode *squashfs_alloc_inode(struct super_block *sb) | |||
440 | } | 440 | } |
441 | 441 | ||
442 | 442 | ||
443 | static void squashfs_destroy_inode(struct inode *inode) | 443 | static void squashfs_i_callback(struct rcu_head *head) |
444 | { | 444 | { |
445 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
446 | INIT_LIST_HEAD(&inode->i_dentry); | ||
445 | kmem_cache_free(squashfs_inode_cachep, squashfs_i(inode)); | 447 | kmem_cache_free(squashfs_inode_cachep, squashfs_i(inode)); |
446 | } | 448 | } |
447 | 449 | ||
450 | static void squashfs_destroy_inode(struct inode *inode) | ||
451 | { | ||
452 | call_rcu(&inode->i_rcu, squashfs_i_callback); | ||
453 | } | ||
454 | |||
448 | 455 | ||
449 | static struct file_system_type squashfs_fs_type = { | 456 | static struct file_system_type squashfs_fs_type = { |
450 | .owner = THIS_MODULE, | 457 | .owner = THIS_MODULE, |
diff --git a/fs/super.c b/fs/super.c index ca696155cd9a..823e061faa87 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/idr.h> | 30 | #include <linux/idr.h> |
31 | #include <linux/mutex.h> | 31 | #include <linux/mutex.h> |
32 | #include <linux/backing-dev.h> | 32 | #include <linux/backing-dev.h> |
33 | #include <linux/rculist_bl.h> | ||
33 | #include "internal.h" | 34 | #include "internal.h" |
34 | 35 | ||
35 | 36 | ||
@@ -71,7 +72,7 @@ static struct super_block *alloc_super(struct file_system_type *type) | |||
71 | INIT_LIST_HEAD(&s->s_files); | 72 | INIT_LIST_HEAD(&s->s_files); |
72 | #endif | 73 | #endif |
73 | INIT_LIST_HEAD(&s->s_instances); | 74 | INIT_LIST_HEAD(&s->s_instances); |
74 | INIT_HLIST_HEAD(&s->s_anon); | 75 | INIT_HLIST_BL_HEAD(&s->s_anon); |
75 | INIT_LIST_HEAD(&s->s_inodes); | 76 | INIT_LIST_HEAD(&s->s_inodes); |
76 | INIT_LIST_HEAD(&s->s_dentry_lru); | 77 | INIT_LIST_HEAD(&s->s_dentry_lru); |
77 | init_rwsem(&s->s_umount); | 78 | init_rwsem(&s->s_umount); |
@@ -1139,7 +1140,7 @@ static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype) | |||
1139 | return mnt; | 1140 | return mnt; |
1140 | 1141 | ||
1141 | err: | 1142 | err: |
1142 | mntput(mnt); | 1143 | mntput_long(mnt); |
1143 | return ERR_PTR(err); | 1144 | return ERR_PTR(err); |
1144 | } | 1145 | } |
1145 | 1146 | ||
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 7e54bac8c4b0..ea9120a830d8 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -231,7 +231,7 @@ void release_sysfs_dirent(struct sysfs_dirent * sd) | |||
231 | goto repeat; | 231 | goto repeat; |
232 | } | 232 | } |
233 | 233 | ||
234 | static int sysfs_dentry_delete(struct dentry *dentry) | 234 | static int sysfs_dentry_delete(const struct dentry *dentry) |
235 | { | 235 | { |
236 | struct sysfs_dirent *sd = dentry->d_fsdata; | 236 | struct sysfs_dirent *sd = dentry->d_fsdata; |
237 | return !!(sd->s_flags & SYSFS_FLAG_REMOVED); | 237 | return !!(sd->s_flags & SYSFS_FLAG_REMOVED); |
@@ -239,9 +239,13 @@ static int sysfs_dentry_delete(struct dentry *dentry) | |||
239 | 239 | ||
240 | static int sysfs_dentry_revalidate(struct dentry *dentry, struct nameidata *nd) | 240 | static int sysfs_dentry_revalidate(struct dentry *dentry, struct nameidata *nd) |
241 | { | 241 | { |
242 | struct sysfs_dirent *sd = dentry->d_fsdata; | 242 | struct sysfs_dirent *sd; |
243 | int is_dir; | 243 | int is_dir; |
244 | 244 | ||
245 | if (nd->flags & LOOKUP_RCU) | ||
246 | return -ECHILD; | ||
247 | |||
248 | sd = dentry->d_fsdata; | ||
245 | mutex_lock(&sysfs_mutex); | 249 | mutex_lock(&sysfs_mutex); |
246 | 250 | ||
247 | /* The sysfs dirent has been deleted */ | 251 | /* The sysfs dirent has been deleted */ |
@@ -701,7 +705,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
701 | /* instantiate and hash dentry */ | 705 | /* instantiate and hash dentry */ |
702 | ret = d_find_alias(inode); | 706 | ret = d_find_alias(inode); |
703 | if (!ret) { | 707 | if (!ret) { |
704 | dentry->d_op = &sysfs_dentry_ops; | 708 | d_set_d_op(dentry, &sysfs_dentry_ops); |
705 | dentry->d_fsdata = sysfs_get(sd); | 709 | dentry->d_fsdata = sysfs_get(sd); |
706 | d_add(dentry, inode); | 710 | d_add(dentry, inode); |
707 | } else { | 711 | } else { |
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index cffb1fd8ba33..0a12eb89cd32 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
20 | #include <linux/sched.h> | 20 | #include <linux/sched.h> |
21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
22 | #include <linux/sysfs.h> | ||
22 | #include <linux/xattr.h> | 23 | #include <linux/xattr.h> |
23 | #include <linux/security.h> | 24 | #include <linux/security.h> |
24 | #include "sysfs.h" | 25 | #include "sysfs.h" |
@@ -348,13 +349,18 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const cha | |||
348 | return -ENOENT; | 349 | return -ENOENT; |
349 | } | 350 | } |
350 | 351 | ||
351 | int sysfs_permission(struct inode *inode, int mask) | 352 | int sysfs_permission(struct inode *inode, int mask, unsigned int flags) |
352 | { | 353 | { |
353 | struct sysfs_dirent *sd = inode->i_private; | 354 | struct sysfs_dirent *sd; |
355 | |||
356 | if (flags & IPERM_FLAG_RCU) | ||
357 | return -ECHILD; | ||
358 | |||
359 | sd = inode->i_private; | ||
354 | 360 | ||
355 | mutex_lock(&sysfs_mutex); | 361 | mutex_lock(&sysfs_mutex); |
356 | sysfs_refresh_inode(sd, inode); | 362 | sysfs_refresh_inode(sd, inode); |
357 | mutex_unlock(&sysfs_mutex); | 363 | mutex_unlock(&sysfs_mutex); |
358 | 364 | ||
359 | return generic_permission(inode, mask, NULL); | 365 | return generic_permission(inode, mask, flags, NULL); |
360 | } | 366 | } |
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index d9be60a2e956..3d28af31d863 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
@@ -9,6 +9,7 @@ | |||
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/lockdep.h> | 11 | #include <linux/lockdep.h> |
12 | #include <linux/kobject_ns.h> | ||
12 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
13 | 14 | ||
14 | struct sysfs_open_dirent; | 15 | struct sysfs_open_dirent; |
@@ -200,7 +201,7 @@ static inline void __sysfs_put(struct sysfs_dirent *sd) | |||
200 | struct inode *sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd); | 201 | struct inode *sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd); |
201 | void sysfs_evict_inode(struct inode *inode); | 202 | void sysfs_evict_inode(struct inode *inode); |
202 | int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr); | 203 | int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr); |
203 | int sysfs_permission(struct inode *inode, int mask); | 204 | int sysfs_permission(struct inode *inode, int mask, unsigned int flags); |
204 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); | 205 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); |
205 | int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); | 206 | int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); |
206 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, | 207 | int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, |
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index de44d067b9e6..0630eb969a28 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c | |||
@@ -333,11 +333,18 @@ static struct inode *sysv_alloc_inode(struct super_block *sb) | |||
333 | return &si->vfs_inode; | 333 | return &si->vfs_inode; |
334 | } | 334 | } |
335 | 335 | ||
336 | static void sysv_destroy_inode(struct inode *inode) | 336 | static void sysv_i_callback(struct rcu_head *head) |
337 | { | 337 | { |
338 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
339 | INIT_LIST_HEAD(&inode->i_dentry); | ||
338 | kmem_cache_free(sysv_inode_cachep, SYSV_I(inode)); | 340 | kmem_cache_free(sysv_inode_cachep, SYSV_I(inode)); |
339 | } | 341 | } |
340 | 342 | ||
343 | static void sysv_destroy_inode(struct inode *inode) | ||
344 | { | ||
345 | call_rcu(&inode->i_rcu, sysv_i_callback); | ||
346 | } | ||
347 | |||
341 | static void init_once(void *p) | 348 | static void init_once(void *p) |
342 | { | 349 | { |
343 | struct sysv_inode_info *si = (struct sysv_inode_info *)p; | 350 | struct sysv_inode_info *si = (struct sysv_inode_info *)p; |
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index 11e7f7d11cd0..b5e68da2db32 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c | |||
@@ -27,7 +27,8 @@ static int add_nondir(struct dentry *dentry, struct inode *inode) | |||
27 | return err; | 27 | return err; |
28 | } | 28 | } |
29 | 29 | ||
30 | static int sysv_hash(struct dentry *dentry, struct qstr *qstr) | 30 | static int sysv_hash(const struct dentry *dentry, const struct inode *inode, |
31 | struct qstr *qstr) | ||
31 | { | 32 | { |
32 | /* Truncate the name in place, avoids having to define a compare | 33 | /* Truncate the name in place, avoids having to define a compare |
33 | function. */ | 34 | function. */ |
@@ -47,7 +48,7 @@ static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry, st | |||
47 | struct inode * inode = NULL; | 48 | struct inode * inode = NULL; |
48 | ino_t ino; | 49 | ino_t ino; |
49 | 50 | ||
50 | dentry->d_op = dir->i_sb->s_root->d_op; | 51 | d_set_d_op(dentry, dir->i_sb->s_root->d_op); |
51 | if (dentry->d_name.len > SYSV_NAMELEN) | 52 | if (dentry->d_name.len > SYSV_NAMELEN) |
52 | return ERR_PTR(-ENAMETOOLONG); | 53 | return ERR_PTR(-ENAMETOOLONG); |
53 | ino = sysv_inode_by_name(dentry); | 54 | ino = sysv_inode_by_name(dentry); |
diff --git a/fs/sysv/super.c b/fs/sysv/super.c index 3d9c62be0c10..76712aefc4ab 100644 --- a/fs/sysv/super.c +++ b/fs/sysv/super.c | |||
@@ -346,7 +346,7 @@ static int complete_read_super(struct super_block *sb, int silent, int size) | |||
346 | if (sbi->s_forced_ro) | 346 | if (sbi->s_forced_ro) |
347 | sb->s_flags |= MS_RDONLY; | 347 | sb->s_flags |= MS_RDONLY; |
348 | if (sbi->s_truncate) | 348 | if (sbi->s_truncate) |
349 | sb->s_root->d_op = &sysv_dentry_operations; | 349 | d_set_d_op(sb->s_root, &sysv_dentry_operations); |
350 | return 1; | 350 | return 1; |
351 | } | 351 | } |
352 | 352 | ||
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 91fac54c70e3..6e11c2975dcf 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c | |||
@@ -272,12 +272,20 @@ static struct inode *ubifs_alloc_inode(struct super_block *sb) | |||
272 | return &ui->vfs_inode; | 272 | return &ui->vfs_inode; |
273 | }; | 273 | }; |
274 | 274 | ||
275 | static void ubifs_i_callback(struct rcu_head *head) | ||
276 | { | ||
277 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
278 | struct ubifs_inode *ui = ubifs_inode(inode); | ||
279 | INIT_LIST_HEAD(&inode->i_dentry); | ||
280 | kmem_cache_free(ubifs_inode_slab, ui); | ||
281 | } | ||
282 | |||
275 | static void ubifs_destroy_inode(struct inode *inode) | 283 | static void ubifs_destroy_inode(struct inode *inode) |
276 | { | 284 | { |
277 | struct ubifs_inode *ui = ubifs_inode(inode); | 285 | struct ubifs_inode *ui = ubifs_inode(inode); |
278 | 286 | ||
279 | kfree(ui->data); | 287 | kfree(ui->data); |
280 | kmem_cache_free(ubifs_inode_slab, inode); | 288 | call_rcu(&inode->i_rcu, ubifs_i_callback); |
281 | } | 289 | } |
282 | 290 | ||
283 | /* | 291 | /* |
diff --git a/fs/udf/super.c b/fs/udf/super.c index 4a5c7c61836a..b539d53320fb 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c | |||
@@ -139,11 +139,18 @@ static struct inode *udf_alloc_inode(struct super_block *sb) | |||
139 | return &ei->vfs_inode; | 139 | return &ei->vfs_inode; |
140 | } | 140 | } |
141 | 141 | ||
142 | static void udf_destroy_inode(struct inode *inode) | 142 | static void udf_i_callback(struct rcu_head *head) |
143 | { | 143 | { |
144 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
145 | INIT_LIST_HEAD(&inode->i_dentry); | ||
144 | kmem_cache_free(udf_inode_cachep, UDF_I(inode)); | 146 | kmem_cache_free(udf_inode_cachep, UDF_I(inode)); |
145 | } | 147 | } |
146 | 148 | ||
149 | static void udf_destroy_inode(struct inode *inode) | ||
150 | { | ||
151 | call_rcu(&inode->i_rcu, udf_i_callback); | ||
152 | } | ||
153 | |||
147 | static void init_once(void *foo) | 154 | static void init_once(void *foo) |
148 | { | 155 | { |
149 | struct udf_inode_info *ei = (struct udf_inode_info *)foo; | 156 | struct udf_inode_info *ei = (struct udf_inode_info *)foo; |
diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 2c47daed56da..2c61ac5d4e48 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c | |||
@@ -1412,11 +1412,18 @@ static struct inode *ufs_alloc_inode(struct super_block *sb) | |||
1412 | return &ei->vfs_inode; | 1412 | return &ei->vfs_inode; |
1413 | } | 1413 | } |
1414 | 1414 | ||
1415 | static void ufs_destroy_inode(struct inode *inode) | 1415 | static void ufs_i_callback(struct rcu_head *head) |
1416 | { | 1416 | { |
1417 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
1418 | INIT_LIST_HEAD(&inode->i_dentry); | ||
1417 | kmem_cache_free(ufs_inode_cachep, UFS_I(inode)); | 1419 | kmem_cache_free(ufs_inode_cachep, UFS_I(inode)); |
1418 | } | 1420 | } |
1419 | 1421 | ||
1422 | static void ufs_destroy_inode(struct inode *inode) | ||
1423 | { | ||
1424 | call_rcu(&inode->i_rcu, ufs_i_callback); | ||
1425 | } | ||
1426 | |||
1420 | static void init_once(void *foo) | 1427 | static void init_once(void *foo) |
1421 | { | 1428 | { |
1422 | struct ufs_inode_info *ei = (struct ufs_inode_info *) foo; | 1429 | struct ufs_inode_info *ei = (struct ufs_inode_info *) foo; |
diff --git a/fs/xfs/linux-2.6/xfs_acl.c b/fs/xfs/linux-2.6/xfs_acl.c index b2771862fd3d..39f4f809bb68 100644 --- a/fs/xfs/linux-2.6/xfs_acl.c +++ b/fs/xfs/linux-2.6/xfs_acl.c | |||
@@ -219,12 +219,13 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) | |||
219 | } | 219 | } |
220 | 220 | ||
221 | int | 221 | int |
222 | xfs_check_acl(struct inode *inode, int mask) | 222 | xfs_check_acl(struct inode *inode, int mask, unsigned int flags) |
223 | { | 223 | { |
224 | struct xfs_inode *ip = XFS_I(inode); | 224 | struct xfs_inode *ip; |
225 | struct posix_acl *acl; | 225 | struct posix_acl *acl; |
226 | int error = -EAGAIN; | 226 | int error = -EAGAIN; |
227 | 227 | ||
228 | ip = XFS_I(inode); | ||
228 | trace_xfs_check_acl(ip); | 229 | trace_xfs_check_acl(ip); |
229 | 230 | ||
230 | /* | 231 | /* |
@@ -234,6 +235,12 @@ xfs_check_acl(struct inode *inode, int mask) | |||
234 | if (!XFS_IFORK_Q(ip)) | 235 | if (!XFS_IFORK_Q(ip)) |
235 | return -EAGAIN; | 236 | return -EAGAIN; |
236 | 237 | ||
238 | if (flags & IPERM_FLAG_RCU) { | ||
239 | if (!negative_cached_acl(inode, ACL_TYPE_ACCESS)) | ||
240 | return -ECHILD; | ||
241 | return -EAGAIN; | ||
242 | } | ||
243 | |||
237 | acl = xfs_get_acl(inode, ACL_TYPE_ACCESS); | 244 | acl = xfs_get_acl(inode, ACL_TYPE_ACCESS); |
238 | if (IS_ERR(acl)) | 245 | if (IS_ERR(acl)) |
239 | return PTR_ERR(acl); | 246 | return PTR_ERR(acl); |
diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h index 0135e2a669d7..11dd72070cbb 100644 --- a/fs/xfs/xfs_acl.h +++ b/fs/xfs/xfs_acl.h | |||
@@ -42,7 +42,7 @@ struct xfs_acl { | |||
42 | #define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1) | 42 | #define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1) |
43 | 43 | ||
44 | #ifdef CONFIG_XFS_POSIX_ACL | 44 | #ifdef CONFIG_XFS_POSIX_ACL |
45 | extern int xfs_check_acl(struct inode *inode, int mask); | 45 | extern int xfs_check_acl(struct inode *inode, int mask, unsigned int flags); |
46 | extern struct posix_acl *xfs_get_acl(struct inode *inode, int type); | 46 | extern struct posix_acl *xfs_get_acl(struct inode *inode, int type); |
47 | extern int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl); | 47 | extern int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl); |
48 | extern int xfs_acl_chmod(struct inode *inode); | 48 | extern int xfs_acl_chmod(struct inode *inode); |
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 0cdd26932d8e..d7de5a3f7867 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c | |||
@@ -91,6 +91,17 @@ xfs_inode_alloc( | |||
91 | return ip; | 91 | return ip; |
92 | } | 92 | } |
93 | 93 | ||
94 | STATIC void | ||
95 | xfs_inode_free_callback( | ||
96 | struct rcu_head *head) | ||
97 | { | ||
98 | struct inode *inode = container_of(head, struct inode, i_rcu); | ||
99 | struct xfs_inode *ip = XFS_I(inode); | ||
100 | |||
101 | INIT_LIST_HEAD(&inode->i_dentry); | ||
102 | kmem_zone_free(xfs_inode_zone, ip); | ||
103 | } | ||
104 | |||
94 | void | 105 | void |
95 | xfs_inode_free( | 106 | xfs_inode_free( |
96 | struct xfs_inode *ip) | 107 | struct xfs_inode *ip) |
@@ -134,7 +145,7 @@ xfs_inode_free( | |||
134 | ASSERT(!spin_is_locked(&ip->i_flags_lock)); | 145 | ASSERT(!spin_is_locked(&ip->i_flags_lock)); |
135 | ASSERT(completion_done(&ip->i_flush)); | 146 | ASSERT(completion_done(&ip->i_flush)); |
136 | 147 | ||
137 | kmem_zone_free(xfs_inode_zone, ip); | 148 | call_rcu(&ip->i_vnode.i_rcu, xfs_inode_free_callback); |
138 | } | 149 | } |
139 | 150 | ||
140 | /* | 151 | /* |
diff --git a/fs/xfs/xfs_mru_cache.c b/fs/xfs/xfs_mru_cache.c index 45ce15dc5b2b..edfa178bafb6 100644 --- a/fs/xfs/xfs_mru_cache.c +++ b/fs/xfs/xfs_mru_cache.c | |||
@@ -408,7 +408,7 @@ xfs_mru_cache_flush( | |||
408 | spin_lock(&mru->lock); | 408 | spin_lock(&mru->lock); |
409 | if (mru->queued) { | 409 | if (mru->queued) { |
410 | spin_unlock(&mru->lock); | 410 | spin_unlock(&mru->lock); |
411 | cancel_rearming_delayed_workqueue(xfs_mru_reap_wq, &mru->work); | 411 | cancel_delayed_work_sync(&mru->work); |
412 | spin_lock(&mru->lock); | 412 | spin_lock(&mru->lock); |
413 | } | 413 | } |
414 | 414 | ||
diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c index d2af0a8381a6..77a59891734e 100644 --- a/fs/xfs/xfs_rename.c +++ b/fs/xfs/xfs_rename.c | |||
@@ -297,6 +297,7 @@ xfs_rename( | |||
297 | * it and some incremental backup programs won't work without it. | 297 | * it and some incremental backup programs won't work without it. |
298 | */ | 298 | */ |
299 | xfs_trans_ichgtime(tp, src_ip, XFS_ICHGTIME_CHG); | 299 | xfs_trans_ichgtime(tp, src_ip, XFS_ICHGTIME_CHG); |
300 | xfs_trans_log_inode(tp, src_ip, XFS_ILOG_CORE); | ||
300 | 301 | ||
301 | /* | 302 | /* |
302 | * Adjust the link count on src_dp. This is necessary when | 303 | * Adjust the link count on src_dp. This is necessary when |