|
@@ -182,6 +182,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
|
|
|
struct inode *inode;
|
|
|
struct dentry *parent;
|
|
|
struct fuse_conn *fc;
|
|
|
+ struct fuse_inode *fi;
|
|
|
int ret;
|
|
|
|
|
|
inode = ACCESS_ONCE(entry->d_inode);
|
|
@@ -228,7 +229,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
|
|
|
if (!err && !outarg.nodeid)
|
|
|
err = -ENOENT;
|
|
|
if (!err) {
|
|
|
- struct fuse_inode *fi = get_fuse_inode(inode);
|
|
|
+ fi = get_fuse_inode(inode);
|
|
|
if (outarg.nodeid != get_node_id(inode)) {
|
|
|
fuse_queue_forget(fc, forget, outarg.nodeid, 1);
|
|
|
goto invalid;
|
|
@@ -246,8 +247,11 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
|
|
|
attr_version);
|
|
|
fuse_change_entry_timeout(entry, &outarg);
|
|
|
} else if (inode) {
|
|
|
- fc = get_fuse_conn(inode);
|
|
|
- if (fc->readdirplus_auto) {
|
|
|
+ fi = get_fuse_inode(inode);
|
|
|
+ if (flags & LOOKUP_RCU) {
|
|
|
+ if (test_bit(FUSE_I_INIT_RDPLUS, &fi->state))
|
|
|
+ return -ECHILD;
|
|
|
+ } else if (test_and_clear_bit(FUSE_I_INIT_RDPLUS, &fi->state)) {
|
|
|
parent = dget_parent(entry);
|
|
|
fuse_advise_use_readdirplus(parent->d_inode);
|
|
|
dput(parent);
|
|
@@ -259,7 +263,8 @@ out:
|
|
|
|
|
|
invalid:
|
|
|
ret = 0;
|
|
|
- if (check_submounts_and_drop(entry) != 0)
|
|
|
+
|
|
|
+ if (!(flags & LOOKUP_RCU) && check_submounts_and_drop(entry) != 0)
|
|
|
ret = 1;
|
|
|
goto out;
|
|
|
}
|
|
@@ -1063,6 +1068,8 @@ static int fuse_access(struct inode *inode, int mask)
|
|
|
struct fuse_access_in inarg;
|
|
|
int err;
|
|
|
|
|
|
+ BUG_ON(mask & MAY_NOT_BLOCK);
|
|
|
+
|
|
|
if (fc->no_access)
|
|
|
return 0;
|
|
|
|
|
@@ -1150,9 +1157,6 @@ static int fuse_permission(struct inode *inode, int mask)
|
|
|
noticed immediately, only after the attribute
|
|
|
timeout has expired */
|
|
|
} else if (mask & (MAY_ACCESS | MAY_CHDIR)) {
|
|
|
- if (mask & MAY_NOT_BLOCK)
|
|
|
- return -ECHILD;
|
|
|
-
|
|
|
err = fuse_access(inode, mask);
|
|
|
} else if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
|
|
|
if (!(inode->i_mode & S_IXUGO)) {
|
|
@@ -1291,6 +1295,8 @@ static int fuse_direntplus_link(struct file *file,
|
|
|
}
|
|
|
|
|
|
found:
|
|
|
+ if (fc->readdirplus_auto)
|
|
|
+ set_bit(FUSE_I_INIT_RDPLUS, &get_fuse_inode(inode)->state);
|
|
|
fuse_change_entry_timeout(dentry, o);
|
|
|
|
|
|
err = 0;
|