diff options
Diffstat (limited to 'fs/fuse/dir.c')
-rw-r--r-- | fs/fuse/dir.c | 20 |
1 files changed, 13 insertions, 7 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 62b43b577bfc..b7989f2ab4c4 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -182,6 +182,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) | |||
182 | struct inode *inode; | 182 | struct inode *inode; |
183 | struct dentry *parent; | 183 | struct dentry *parent; |
184 | struct fuse_conn *fc; | 184 | struct fuse_conn *fc; |
185 | struct fuse_inode *fi; | ||
185 | int ret; | 186 | int ret; |
186 | 187 | ||
187 | inode = ACCESS_ONCE(entry->d_inode); | 188 | inode = ACCESS_ONCE(entry->d_inode); |
@@ -228,7 +229,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) | |||
228 | if (!err && !outarg.nodeid) | 229 | if (!err && !outarg.nodeid) |
229 | err = -ENOENT; | 230 | err = -ENOENT; |
230 | if (!err) { | 231 | if (!err) { |
231 | struct fuse_inode *fi = get_fuse_inode(inode); | 232 | fi = get_fuse_inode(inode); |
232 | if (outarg.nodeid != get_node_id(inode)) { | 233 | if (outarg.nodeid != get_node_id(inode)) { |
233 | fuse_queue_forget(fc, forget, outarg.nodeid, 1); | 234 | fuse_queue_forget(fc, forget, outarg.nodeid, 1); |
234 | goto invalid; | 235 | goto invalid; |
@@ -246,8 +247,11 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) | |||
246 | attr_version); | 247 | attr_version); |
247 | fuse_change_entry_timeout(entry, &outarg); | 248 | fuse_change_entry_timeout(entry, &outarg); |
248 | } else if (inode) { | 249 | } else if (inode) { |
249 | fc = get_fuse_conn(inode); | 250 | fi = get_fuse_inode(inode); |
250 | if (fc->readdirplus_auto) { | 251 | if (flags & LOOKUP_RCU) { |
252 | if (test_bit(FUSE_I_INIT_RDPLUS, &fi->state)) | ||
253 | return -ECHILD; | ||
254 | } else if (test_and_clear_bit(FUSE_I_INIT_RDPLUS, &fi->state)) { | ||
251 | parent = dget_parent(entry); | 255 | parent = dget_parent(entry); |
252 | fuse_advise_use_readdirplus(parent->d_inode); | 256 | fuse_advise_use_readdirplus(parent->d_inode); |
253 | dput(parent); | 257 | dput(parent); |
@@ -259,7 +263,8 @@ out: | |||
259 | 263 | ||
260 | invalid: | 264 | invalid: |
261 | ret = 0; | 265 | ret = 0; |
262 | if (check_submounts_and_drop(entry) != 0) | 266 | |
267 | if (!(flags & LOOKUP_RCU) && check_submounts_and_drop(entry) != 0) | ||
263 | ret = 1; | 268 | ret = 1; |
264 | goto out; | 269 | goto out; |
265 | } | 270 | } |
@@ -1063,6 +1068,8 @@ static int fuse_access(struct inode *inode, int mask) | |||
1063 | struct fuse_access_in inarg; | 1068 | struct fuse_access_in inarg; |
1064 | int err; | 1069 | int err; |
1065 | 1070 | ||
1071 | BUG_ON(mask & MAY_NOT_BLOCK); | ||
1072 | |||
1066 | if (fc->no_access) | 1073 | if (fc->no_access) |
1067 | return 0; | 1074 | return 0; |
1068 | 1075 | ||
@@ -1150,9 +1157,6 @@ static int fuse_permission(struct inode *inode, int mask) | |||
1150 | noticed immediately, only after the attribute | 1157 | noticed immediately, only after the attribute |
1151 | timeout has expired */ | 1158 | timeout has expired */ |
1152 | } else if (mask & (MAY_ACCESS | MAY_CHDIR)) { | 1159 | } else if (mask & (MAY_ACCESS | MAY_CHDIR)) { |
1153 | if (mask & MAY_NOT_BLOCK) | ||
1154 | return -ECHILD; | ||
1155 | |||
1156 | err = fuse_access(inode, mask); | 1160 | err = fuse_access(inode, mask); |
1157 | } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { | 1161 | } else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) { |
1158 | if (!(inode->i_mode & S_IXUGO)) { | 1162 | if (!(inode->i_mode & S_IXUGO)) { |
@@ -1291,6 +1295,8 @@ static int fuse_direntplus_link(struct file *file, | |||
1291 | } | 1295 | } |
1292 | 1296 | ||
1293 | found: | 1297 | found: |
1298 | if (fc->readdirplus_auto) | ||
1299 | set_bit(FUSE_I_INIT_RDPLUS, &get_fuse_inode(inode)->state); | ||
1294 | fuse_change_entry_timeout(dentry, o); | 1300 | fuse_change_entry_timeout(dentry, o); |
1295 | 1301 | ||
1296 | err = 0; | 1302 | err = 0; |