If this refactoring seems cumbersome, it's because the goal is to move
the lookup parts of fuse_dentry_revalidate into a common function. This
function will be used in a subsequent commit. In the meantime, the new
function fuse_dentry_revalidate_lookup is responsible for just the
lookup and validation portions of the revalidate dance. The
fuse_dentry_revalidate function retains the responsibility for
invalidating and mutating any state associated with the origial
fuse_inode and dentry.
Cc: stable@vger.kernel.org
Fixes: 1866d779d5d2 ("fuse: Allow fuse_fill_super_common() for submounts")
Signed-off-by: Krister Johansen <kjlx@templeofstupid.com>
---
fs/fuse/dir.c | 87 +++++++++++++++++++++++++++++++++++----------------
1 file changed, 60 insertions(+), 27 deletions(-)
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index e190d09f220d..afbdd223b0f3 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -183,6 +183,59 @@ static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_args *args,
args->out_args[0].value = outarg;
}
+static int fuse_dentry_revalidate_lookup(struct fuse_mount *fm,
+ struct dentry *entry,
+ struct inode *inode,
+ struct fuse_entry_out *outarg,
+ bool *lookedup)
+{
+ struct dentry *parent;
+ struct fuse_forget_link *forget;
+ struct fuse_inode *fi;
+ FUSE_ARGS(args);
+ int ret;
+
+ forget = fuse_alloc_forget();
+ ret = -ENOMEM;
+ if (!forget)
+ goto out;
+
+ parent = dget_parent(entry);
+ fuse_lookup_init(fm->fc, &args, get_node_id(d_inode(parent)),
+ &entry->d_name, outarg);
+ ret = fuse_simple_request(fm, &args);
+ dput(parent);
+
+ /* Zero nodeid is same as -ENOENT */
+ if (!ret && !outarg->nodeid)
+ ret = -ENOENT;
+ if (!ret) {
+ fi = get_fuse_inode(inode);
+ if (outarg->nodeid != get_node_id(inode) ||
+ (bool) IS_AUTOMOUNT(inode) != (bool) (outarg->attr.flags & FUSE_ATTR_SUBMOUNT)) {
+ fuse_queue_forget(fm->fc, forget,
+ outarg->nodeid, 1);
+ goto invalid;
+ }
+ *lookedup = true;
+ }
+ kfree(forget);
+ if (ret == -ENOMEM || ret == -EINTR)
+ goto out;
+ if (ret || fuse_invalid_attr(&outarg->attr) ||
+ fuse_stale_inode(inode, outarg->generation, &outarg->attr)) {
+ goto invalid;
+ }
+
+ ret = 1;
+out:
+ return ret;
+
+invalid:
+ ret = 0;
+ goto out;
+}
+
/*
* Check whether the dentry is still valid
*
@@ -206,9 +259,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
else if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) ||
(flags & (LOOKUP_EXCL | LOOKUP_REVAL | LOOKUP_RENAME_TARGET))) {
struct fuse_entry_out outarg;
- FUSE_ARGS(args);
- struct fuse_forget_link *forget;
u64 attr_version;
+ bool lookedup = false;
/* For negative dentries, always do a fresh lookup */
if (!inode)
@@ -220,38 +272,19 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
fm = get_fuse_mount(inode);
- forget = fuse_alloc_forget();
- ret = -ENOMEM;
- if (!forget)
- goto out;
-
attr_version = fuse_get_attr_version(fm->fc);
- parent = dget_parent(entry);
- fuse_lookup_init(fm->fc, &args, get_node_id(d_inode(parent)),
- &entry->d_name, &outarg);
- ret = fuse_simple_request(fm, &args);
- dput(parent);
- /* Zero nodeid is same as -ENOENT */
- if (!ret && !outarg.nodeid)
- ret = -ENOENT;
- if (!ret) {
+ ret = fuse_dentry_revalidate_lookup(fm, entry, inode, &outarg,
+ &lookedup);
+ if (ret == -ENOMEM || ret == -EINTR)
+ goto out;
+ if (lookedup) {
fi = get_fuse_inode(inode);
- if (outarg.nodeid != get_node_id(inode) ||
- (bool) IS_AUTOMOUNT(inode) != (bool) (outarg.attr.flags & FUSE_ATTR_SUBMOUNT)) {
- fuse_queue_forget(fm->fc, forget,
- outarg.nodeid, 1);
- goto invalid;
- }
spin_lock(&fi->lock);
fi->nlookup++;
spin_unlock(&fi->lock);
}
- kfree(forget);
- if (ret == -ENOMEM || ret == -EINTR)
- goto out;
- if (ret || fuse_invalid_attr(&outarg.attr) ||
- fuse_stale_inode(inode, outarg.generation, &outarg.attr))
+ if (ret <= 0)
goto invalid;
forget_all_cached_acls(inode);
--
2.25.1
Hi Krister,
kernel test robot noticed the following build warnings:
[auto build test WARNING on linus/master]
[also build test WARNING on v6.6-rc1 next-20230911]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Krister-Johansen/fuse-revalidate-move-lookup-into-a-separate-function/20230912-051352
base: linus/master
patch link: https://lore.kernel.org/r/9a2b0c5b625cd88c561289bf7d4d7dfe305c10ed.1693440240.git.kjlx%40templeofstupid.com
patch subject: [PATCH 1/2] fuse: revalidate: move lookup into a separate function
config: m68k-allyesconfig (https://download.01.org/0day-ci/archive/20230912/202309120853.QbAMM1to-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20230912/202309120853.QbAMM1to-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202309120853.QbAMM1to-lkp@intel.com/
All warnings (new ones prefixed by >>):
fs/fuse/dir.c: In function 'fuse_dentry_revalidate_lookup':
>> fs/fuse/dir.c:194:28: warning: variable 'fi' set but not used [-Wunused-but-set-variable]
194 | struct fuse_inode *fi;
| ^~
vim +/fi +194 fs/fuse/dir.c
185
186 static int fuse_dentry_revalidate_lookup(struct fuse_mount *fm,
187 struct dentry *entry,
188 struct inode *inode,
189 struct fuse_entry_out *outarg,
190 bool *lookedup)
191 {
192 struct dentry *parent;
193 struct fuse_forget_link *forget;
> 194 struct fuse_inode *fi;
195 FUSE_ARGS(args);
196 int ret;
197
198 forget = fuse_alloc_forget();
199 ret = -ENOMEM;
200 if (!forget)
201 goto out;
202
203 parent = dget_parent(entry);
204 fuse_lookup_init(fm->fc, &args, get_node_id(d_inode(parent)),
205 &entry->d_name, outarg);
206 ret = fuse_simple_request(fm, &args);
207 dput(parent);
208
209 /* Zero nodeid is same as -ENOENT */
210 if (!ret && !outarg->nodeid)
211 ret = -ENOENT;
212 if (!ret) {
213 fi = get_fuse_inode(inode);
214 if (outarg->nodeid != get_node_id(inode) ||
215 (bool) IS_AUTOMOUNT(inode) != (bool) (outarg->attr.flags & FUSE_ATTR_SUBMOUNT)) {
216 fuse_queue_forget(fm->fc, forget,
217 outarg->nodeid, 1);
218 goto invalid;
219 }
220 *lookedup = true;
221 }
222 kfree(forget);
223 if (ret == -ENOMEM || ret == -EINTR)
224 goto out;
225 if (ret || fuse_invalid_attr(&outarg->attr) ||
226 fuse_stale_inode(inode, outarg->generation, &outarg->attr)) {
227 goto invalid;
228 }
229
230 ret = 1;
231 out:
232 return ret;
233
234 invalid:
235 ret = 0;
236 goto out;
237 }
238
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
© 2016 - 2026 Red Hat, Inc.