We shall send forget request if lookup/create/open success but returned outarg.attr is invalid, because FUSEdaemon had increase the lookup count Reported-by: Xie Yongji Signed-off-by: Zhang Tianci --- fs/fuse/dir.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 4b6b3d2758ff2..92a10fe2c4825 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -578,8 +578,10 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name goto out_put_forget; err = -EIO; - if (fuse_invalid_attr(&outarg->attr)) + if (fuse_invalid_attr(&outarg->attr)) { + fuse_queue_forget(fm->fc, forget, outarg->nodeid, 1); goto out_put_forget; + } if (outarg->nodeid == FUSE_ROOT_ID && outarg->generation != 0) { pr_warn_once("root generation should be zero\n"); outarg->generation = 0; @@ -879,9 +881,13 @@ static int fuse_create_open(struct mnt_idmap *idmap, struct inode *dir, goto out_free_ff; err = -EIO; - if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid) || - fuse_invalid_attr(&outentry.attr)) + if (invalid_nodeid(outentry.nodeid)) + goto out_free_ff; + + if (!S_ISREG(outentry.attr.mode) || fuse_invalid_attr(&outentry.attr)) { + fuse_queue_forget(fm->fc, forget, outentry.nodeid, 1); goto out_free_ff; + } ff->fh = outopenp->fh; ff->nodeid = outentry.nodeid; @@ -1007,11 +1013,13 @@ static struct dentry *create_new_entry(struct mnt_idmap *idmap, struct fuse_moun goto out_put_forget_req; err = -EIO; - if (invalid_nodeid(outarg.nodeid) || fuse_invalid_attr(&outarg.attr)) + if (invalid_nodeid(outarg.nodeid)) goto out_put_forget_req; - if ((outarg.attr.mode ^ mode) & S_IFMT) + if (fuse_invalid_attr(&outarg.attr) || ((outarg.attr.mode ^ mode) & S_IFMT)) { + fuse_queue_forget(fm->fc, forget, outarg.nodeid, 1); goto out_put_forget_req; + } inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, &outarg.attr, ATTR_TIMEOUT(&outarg), 0, 0); -- 2.39.5