Commit 28420dad authored by Miklos Szeredi's avatar Miklos Szeredi

fuse: fix readdirplus Oops in fuse_dentry_revalidate

Fix bug introduced by commit 4582a4ab "FUSE: Adapt readdirplus to application
usage patterns".

We need to check for a positive dentry; negative dentries are not added by
readdirplus.  Secondly we need to advise the use of readdirplus on the *parent*,
otherwise the whole thing is useless.  Thirdly all this is only relevant if
"readdirplus_auto" mode is selected by the filesystem.

We advise the use of readdirplus only if the dentry was still valid.  If we had
to redo the lookup then there was no use in doing the -plus version.
Reported-by: default avatarBernd Schubert <bernd.schubert@itwm.fraunhofer.de>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
CC: Feng Shuo <steve.shuo.feng@gmail.com>
CC: stable@vger.kernel.org
parent bee6c307
...@@ -180,6 +180,8 @@ u64 fuse_get_attr_version(struct fuse_conn *fc) ...@@ -180,6 +180,8 @@ u64 fuse_get_attr_version(struct fuse_conn *fc)
static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
{ {
struct inode *inode; struct inode *inode;
struct dentry *parent;
struct fuse_conn *fc;
inode = ACCESS_ONCE(entry->d_inode); inode = ACCESS_ONCE(entry->d_inode);
if (inode && is_bad_inode(inode)) if (inode && is_bad_inode(inode))
...@@ -187,10 +189,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) ...@@ -187,10 +189,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
else if (fuse_dentry_time(entry) < get_jiffies_64()) { else if (fuse_dentry_time(entry) < get_jiffies_64()) {
int err; int err;
struct fuse_entry_out outarg; struct fuse_entry_out outarg;
struct fuse_conn *fc;
struct fuse_req *req; struct fuse_req *req;
struct fuse_forget_link *forget; struct fuse_forget_link *forget;
struct dentry *parent;
u64 attr_version; u64 attr_version;
/* For negative dentries, always do a fresh lookup */ /* For negative dentries, always do a fresh lookup */
...@@ -241,8 +241,14 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) ...@@ -241,8 +241,14 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
entry_attr_timeout(&outarg), entry_attr_timeout(&outarg),
attr_version); attr_version);
fuse_change_entry_timeout(entry, &outarg); fuse_change_entry_timeout(entry, &outarg);
} else if (inode) {
fc = get_fuse_conn(inode);
if (fc->readdirplus_auto) {
parent = dget_parent(entry);
fuse_advise_use_readdirplus(parent->d_inode);
dput(parent);
}
} }
fuse_advise_use_readdirplus(inode);
return 1; return 1;
} }
......
...@@ -867,10 +867,11 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) ...@@ -867,10 +867,11 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
fc->dont_mask = 1; fc->dont_mask = 1;
if (arg->flags & FUSE_AUTO_INVAL_DATA) if (arg->flags & FUSE_AUTO_INVAL_DATA)
fc->auto_inval_data = 1; fc->auto_inval_data = 1;
if (arg->flags & FUSE_DO_READDIRPLUS) if (arg->flags & FUSE_DO_READDIRPLUS) {
fc->do_readdirplus = 1; fc->do_readdirplus = 1;
if (arg->flags & FUSE_READDIRPLUS_AUTO) if (arg->flags & FUSE_READDIRPLUS_AUTO)
fc->readdirplus_auto = 1; fc->readdirplus_auto = 1;
}
if (arg->flags & FUSE_ASYNC_DIO) if (arg->flags & FUSE_ASYNC_DIO)
fc->async_dio = 1; fc->async_dio = 1;
} else { } else {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment