aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2013-06-03 08:40:22 -0400
committerMiklos Szeredi <mszeredi@suse.cz>2013-06-03 08:40:22 -0400
commit28420dad233520811c0e0860e7fb4975ed863fc4 (patch)
treeb5a8248227aad4b8fbde6b047257f629283e15dc /fs
parentbee6c307800bbb26ba1a855b1841c2f0c4b7622a (diff)
fuse: fix readdirplus Oops in fuse_dentry_revalidate
Fix bug introduced by commit 4582a4ab2a "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: Bernd Schubert <bernd.schubert@itwm.fraunhofer.de> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> CC: Feng Shuo <steve.shuo.feng@gmail.com> CC: stable@vger.kernel.org
Diffstat (limited to 'fs')
-rw-r--r--fs/fuse/dir.c12
-rw-r--r--fs/fuse/inode.c7
2 files changed, 13 insertions, 6 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 254df56b847b..f3f783dc4f75 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -180,6 +180,8 @@ u64 fuse_get_attr_version(struct fuse_conn *fc)
180static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags) 180static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
181{ 181{
182 struct inode *inode; 182 struct inode *inode;
183 struct dentry *parent;
184 struct fuse_conn *fc;
183 185
184 inode = ACCESS_ONCE(entry->d_inode); 186 inode = ACCESS_ONCE(entry->d_inode);
185 if (inode && is_bad_inode(inode)) 187 if (inode && is_bad_inode(inode))
@@ -187,10 +189,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
187 else if (fuse_dentry_time(entry) < get_jiffies_64()) { 189 else if (fuse_dentry_time(entry) < get_jiffies_64()) {
188 int err; 190 int err;
189 struct fuse_entry_out outarg; 191 struct fuse_entry_out outarg;
190 struct fuse_conn *fc;
191 struct fuse_req *req; 192 struct fuse_req *req;
192 struct fuse_forget_link *forget; 193 struct fuse_forget_link *forget;
193 struct dentry *parent;
194 u64 attr_version; 194 u64 attr_version;
195 195
196 /* For negative dentries, always do a fresh lookup */ 196 /* For negative dentries, always do a fresh lookup */
@@ -241,8 +241,14 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
241 entry_attr_timeout(&outarg), 241 entry_attr_timeout(&outarg),
242 attr_version); 242 attr_version);
243 fuse_change_entry_timeout(entry, &outarg); 243 fuse_change_entry_timeout(entry, &outarg);
244 } else if (inode) {
245 fc = get_fuse_conn(inode);
246 if (fc->readdirplus_auto) {
247 parent = dget_parent(entry);
248 fuse_advise_use_readdirplus(parent->d_inode);
249 dput(parent);
250 }
244 } 251 }
245 fuse_advise_use_readdirplus(inode);
246 return 1; 252 return 1;
247} 253}
248 254
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 6201f81e4d3a..9a0cdde14a08 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -867,10 +867,11 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
867 fc->dont_mask = 1; 867 fc->dont_mask = 1;
868 if (arg->flags & FUSE_AUTO_INVAL_DATA) 868 if (arg->flags & FUSE_AUTO_INVAL_DATA)
869 fc->auto_inval_data = 1; 869 fc->auto_inval_data = 1;
870 if (arg->flags & FUSE_DO_READDIRPLUS) 870 if (arg->flags & FUSE_DO_READDIRPLUS) {
871 fc->do_readdirplus = 1; 871 fc->do_readdirplus = 1;
872 if (arg->flags & FUSE_READDIRPLUS_AUTO) 872 if (arg->flags & FUSE_READDIRPLUS_AUTO)
873 fc->readdirplus_auto = 1; 873 fc->readdirplus_auto = 1;
874 }
874 if (arg->flags & FUSE_ASYNC_DIO) 875 if (arg->flags & FUSE_ASYNC_DIO)
875 fc->async_dio = 1; 876 fc->async_dio = 1;
876 } else { 877 } else {