From nobody Mon Sep 16 19:45:30 2024 Received: from szxga05-in.huawei.com (szxga05-in.huawei.com [45.249.212.191]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 210D136D; Fri, 26 Jul 2024 08:37:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.191 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721983084; cv=none; b=iHI87LIAxZPiyOmKHJdqfD8jf9OtM+oGWA7mfWBYQz44LVXX+uZaqUk6qlYFKtFjdgs5N35468Jtntdx9xTjKTTZDtv+mb41FNUiJEbGyX1o1oSrbFNiaKoNuWa8WIwpFSJ04vVqzwXLlco7pssQv69HAVik2jxnvx7QzU45dUo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721983084; c=relaxed/simple; bh=JPN1/EqE7psG706zCMN7NasTfroP+IGNgL45o0xJS7g=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=Qu9JusmLuAmpCzi/skI2j06ARaU0dqARQOPhlIsWd6vzyn4DtEYzSIsWQrk6eMrIEBj/2koJkG9Fbt+NdJxMauDPGlqg2bs7ljMM28CKz+i6LtMqQ66ZgPzVWaP93jGtHXEXarOp52B43nshHlAm/5Uj71SiSZT8Xghr0HH5AvM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; arc=none smtp.client-ip=45.249.212.191 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Received: from mail.maildlp.com (unknown [172.19.162.112]) by szxga05-in.huawei.com (SkyGuard) with ESMTP id 4WVh024Lsvz1HFQV; Fri, 26 Jul 2024 16:35:14 +0800 (CST) Received: from kwepemd100024.china.huawei.com (unknown [7.221.188.41]) by mail.maildlp.com (Postfix) with ESMTPS id E1CF51404F5; Fri, 26 Jul 2024 16:37:57 +0800 (CST) Received: from huawei.com (10.175.124.27) by kwepemd100024.china.huawei.com (7.221.188.41) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Fri, 26 Jul 2024 16:37:57 +0800 From: yangyun To: Miklos Szeredi CC: , Subject: [PATCH 1/2] fuse: replace fuse_queue_forget with fuse_force_forget if error Date: Fri, 26 Jul 2024 16:37:51 +0800 Message-ID: <20240726083752.302301-2-yangyun50@huawei.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20240726083752.302301-1-yangyun50@huawei.com> References: <20240726083752.302301-1-yangyun50@huawei.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) To kwepemd100024.china.huawei.com (7.221.188.41) Content-Type: text/plain; charset="utf-8" Most usecases for 'fuse_queue_forget' in the code are about reverting the lookup count when error happens, except 'fuse_evict_inode' and 'fuse_cleanup_submount_lookup'. Even if there are no errors, it still needs alloc 'struct fuse_forget_link'. It is useless, which contributes to performance degradation and code mess to some extent. 'fuse_force_forget' does not need allocate 'struct fuse_forget_link'in advance, and is only used by readdirplus before this patch for the reason that we do not know how many 'fuse_forget_link' structures will be allocated when error happens. Signed-off-by: yangyun --- fs/fuse/dev.c | 19 +++++++++++++++ fs/fuse/dir.c | 59 +++++++++++------------------------------------ fs/fuse/fuse_i.h | 2 ++ fs/fuse/readdir.c | 29 +++++------------------ 4 files changed, 40 insertions(+), 69 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 9eb191b5c4de..932356833b0d 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -252,6 +252,25 @@ void fuse_queue_forget(struct fuse_conn *fc, struct fu= se_forget_link *forget, } } =20 +void fuse_force_forget(struct fuse_mount *fm, u64 nodeid) +{ + struct fuse_forget_in inarg; + FUSE_ARGS(args); + + memset(&inarg, 0, sizeof(inarg)); + inarg.nlookup =3D 1; + args.opcode =3D FUSE_FORGET; + args.nodeid =3D nodeid; + args.in_numargs =3D 1; + args.in_args[0].size =3D sizeof(inarg); + args.in_args[0].value =3D &inarg; + args.force =3D true; + args.noreply =3D true; + + fuse_simple_request(fm, &args); + /* ignore errors */ +} + static void flush_bg_queue(struct fuse_conn *fc) { struct fuse_iqueue *fiq =3D &fc->iq; diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 2b0d4781f394..6bfb3a128658 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -207,7 +207,6 @@ static int fuse_dentry_revalidate(struct dentry *entry,= unsigned int flags) (flags & (LOOKUP_EXCL | LOOKUP_REVAL | LOOKUP_RENAME_TARGET))) { struct fuse_entry_out outarg; FUSE_ARGS(args); - struct fuse_forget_link *forget; u64 attr_version; =20 /* For negative dentries, always do a fresh lookup */ @@ -220,11 +219,6 @@ static int fuse_dentry_revalidate(struct dentry *entry= , unsigned int flags) =20 fm =3D get_fuse_mount(inode); =20 - forget =3D fuse_alloc_forget(); - ret =3D -ENOMEM; - if (!forget) - goto out; - attr_version =3D fuse_get_attr_version(fm->fc); =20 parent =3D dget_parent(entry); @@ -239,15 +233,13 @@ static int fuse_dentry_revalidate(struct dentry *entr= y, unsigned int flags) fi =3D get_fuse_inode(inode); if (outarg.nodeid !=3D get_node_id(inode) || (bool) IS_AUTOMOUNT(inode) !=3D (bool) (outarg.attr.flags & FUSE_AT= TR_SUBMOUNT)) { - fuse_queue_forget(fm->fc, forget, - outarg.nodeid, 1); + fuse_force_forget(fm, outarg.nodeid); goto invalid; } spin_lock(&fi->lock); fi->nlookup++; spin_unlock(&fi->lock); } - kfree(forget); if (ret =3D=3D -ENOMEM || ret =3D=3D -EINTR) goto out; if (ret || fuse_invalid_attr(&outarg.attr) || @@ -365,7 +357,6 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid= , const struct qstr *name { struct fuse_mount *fm =3D get_fuse_mount_super(sb); FUSE_ARGS(args); - struct fuse_forget_link *forget; u64 attr_version; int err; =20 @@ -374,23 +365,17 @@ int fuse_lookup_name(struct super_block *sb, u64 node= id, const struct qstr *name if (name->len > FUSE_NAME_MAX) goto out; =20 - - forget =3D fuse_alloc_forget(); - err =3D -ENOMEM; - if (!forget) - goto out; - attr_version =3D fuse_get_attr_version(fm->fc); =20 fuse_lookup_init(fm->fc, &args, nodeid, name, outarg); err =3D fuse_simple_request(fm, &args); /* Zero nodeid is same as -ENOENT, but with valid timeout */ if (err || !outarg->nodeid) - goto out_put_forget; + goto out; =20 err =3D -EIO; if (fuse_invalid_attr(&outarg->attr)) - goto out_put_forget; + goto out; if (outarg->nodeid =3D=3D FUSE_ROOT_ID && outarg->generation !=3D 0) { pr_warn_once("root generation should be zero\n"); outarg->generation =3D 0; @@ -401,13 +386,11 @@ int fuse_lookup_name(struct super_block *sb, u64 node= id, const struct qstr *name attr_version); err =3D -ENOMEM; if (!*inode) { - fuse_queue_forget(fm->fc, forget, outarg->nodeid, 1); + fuse_force_forget(fm, outarg->nodeid); goto out; } err =3D 0; =20 - out_put_forget: - kfree(forget); out: return err; } @@ -617,7 +600,6 @@ static int fuse_create_open(struct inode *dir, struct d= entry *entry, struct inode *inode; struct fuse_mount *fm =3D get_fuse_mount(dir); FUSE_ARGS(args); - struct fuse_forget_link *forget; struct fuse_create_in inarg; struct fuse_open_out *outopenp; struct fuse_entry_out outentry; @@ -628,15 +610,10 @@ static int fuse_create_open(struct inode *dir, struct= dentry *entry, /* Userspace expects S_IFREG in create mode */ BUG_ON((mode & S_IFMT) !=3D S_IFREG); =20 - forget =3D fuse_alloc_forget(); - err =3D -ENOMEM; - if (!forget) - goto out_err; - err =3D -ENOMEM; ff =3D fuse_file_alloc(fm, true); if (!ff) - goto out_put_forget_req; + goto out_err; =20 if (!fm->fc->dont_mask) mode &=3D ~current_umask(); @@ -670,7 +647,7 @@ static int fuse_create_open(struct inode *dir, struct d= entry *entry, =20 err =3D get_create_ext(&args, dir, entry, mode); if (err) - goto out_put_forget_req; + goto out_err; =20 err =3D fuse_simple_request(fm, &args); free_ext_value(&args); @@ -690,11 +667,10 @@ static int fuse_create_open(struct inode *dir, struct= dentry *entry, if (!inode) { flags &=3D ~(O_CREAT | O_EXCL | O_TRUNC); fuse_sync_release(NULL, ff, flags); - fuse_queue_forget(fm->fc, forget, outentry.nodeid, 1); + fuse_force_forget(fm, outentry.nodeid); err =3D -ENOMEM; goto out_err; } - kfree(forget); d_instantiate(entry, inode); fuse_change_entry_timeout(entry, &outentry); fuse_dir_changed(dir); @@ -716,8 +692,6 @@ static int fuse_create_open(struct inode *dir, struct d= entry *entry, =20 out_free_ff: fuse_file_free(ff); -out_put_forget_req: - kfree(forget); out_err: return err; } @@ -782,15 +756,10 @@ static int create_new_entry(struct fuse_mount *fm, st= ruct fuse_args *args, struct inode *inode; struct dentry *d; int err; - struct fuse_forget_link *forget; =20 if (fuse_is_bad(dir)) return -EIO; =20 - forget =3D fuse_alloc_forget(); - if (!forget) - return -ENOMEM; - memset(&outarg, 0, sizeof(outarg)); args->nodeid =3D get_node_id(dir); args->out_numargs =3D 1; @@ -800,28 +769,27 @@ static int create_new_entry(struct fuse_mount *fm, st= ruct fuse_args *args, if (args->opcode !=3D FUSE_LINK) { err =3D get_create_ext(args, dir, entry, mode); if (err) - goto out_put_forget_req; + goto out_err; } =20 err =3D fuse_simple_request(fm, args); free_ext_value(args); if (err) - goto out_put_forget_req; + goto out_err; =20 err =3D -EIO; if (invalid_nodeid(outarg.nodeid) || fuse_invalid_attr(&outarg.attr)) - goto out_put_forget_req; + goto out_err; =20 if ((outarg.attr.mode ^ mode) & S_IFMT) - goto out_put_forget_req; + goto out_err; =20 inode =3D fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, &outarg.attr, ATTR_TIMEOUT(&outarg), 0); if (!inode) { - fuse_queue_forget(fm->fc, forget, outarg.nodeid, 1); + fuse_force_forget(fm, outarg.nodeid); return -ENOMEM; } - kfree(forget); =20 d_drop(entry); d =3D d_splice_alias(inode, entry); @@ -837,10 +805,9 @@ static int create_new_entry(struct fuse_mount *fm, str= uct fuse_args *args, fuse_dir_changed(dir); return 0; =20 - out_put_forget_req: + out_err: if (err =3D=3D -EEXIST) fuse_invalidate_entry(entry); - kfree(forget); return err; } =20 diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index f23919610313..b9a5b8ec0de5 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1051,6 +1051,8 @@ int fuse_lookup_name(struct super_block *sb, u64 node= id, const struct qstr *name void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forg= et, u64 nodeid, u64 nlookup); =20 +void fuse_force_forget(struct fuse_mount *fm, u64 nodeid); + struct fuse_forget_link *fuse_alloc_forget(void); =20 struct fuse_forget_link *fuse_dequeue_forget(struct fuse_iqueue *fiq, diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c index 0377b6dc24c8..39f01ac31f7c 100644 --- a/fs/fuse/readdir.c +++ b/fs/fuse/readdir.c @@ -262,27 +262,6 @@ static int fuse_direntplus_link(struct file *file, return 0; } =20 -static void fuse_force_forget(struct file *file, u64 nodeid) -{ - struct inode *inode =3D file_inode(file); - struct fuse_mount *fm =3D get_fuse_mount(inode); - struct fuse_forget_in inarg; - FUSE_ARGS(args); - - memset(&inarg, 0, sizeof(inarg)); - inarg.nlookup =3D 1; - args.opcode =3D FUSE_FORGET; - args.nodeid =3D nodeid; - args.in_numargs =3D 1; - args.in_args[0].size =3D sizeof(inarg); - args.in_args[0].value =3D &inarg; - args.force =3D true; - args.noreply =3D true; - - fuse_simple_request(fm, &args); - /* ignore errors */ -} - static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file, struct dir_context *ctx, u64 attr_version) { @@ -320,8 +299,12 @@ static int parse_dirplusfile(char *buf, size_t nbytes,= struct file *file, nbytes -=3D reclen; =20 ret =3D fuse_direntplus_link(file, direntplus, attr_version); - if (ret) - fuse_force_forget(file, direntplus->entry_out.nodeid); + if (ret) { + struct inode *inode =3D file_inode(file); + struct fuse_mount *fm =3D get_fuse_mount(inode); + + fuse_force_forget(fm, direntplus->entry_out.nodeid); + } } =20 return 0; --=20 2.33.0 From nobody Mon Sep 16 19:45:30 2024 Received: from szxga04-in.huawei.com (szxga04-in.huawei.com [45.249.212.190]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C8491178364; Fri, 26 Jul 2024 08:38:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=45.249.212.190 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721983089; cv=none; b=F6rDLlxaZSMCRom4REwYCo69G/8q+qjglVEQLdYBrh34NL/3MMh7ZE84Q/Ezub6Bbf2obuDi48Od9NHEKa8PM5mWAsAvtZFnowvh2/yQQuawEyDQrc426dGnJO6Twvt6fjbU5hVAQe87zFLnB+BPRDr/i6I16Bt0tOGFjP4W0r4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1721983089; c=relaxed/simple; bh=/hWhfMllA70pWRM2T6uiJE9KAXC26784Z2LWy9Tr0U8=; h=From:To:CC:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=LEOvHZjHIx4eWA9JSe2uN4pDAugxyVX31CzpL9SzsYfnoqxDQ86F40pJ7olYi/6WnRVbWK8RRk8c7rvJi8POc6Tv9Amuh3EwcQYOL61RAAZKYoQYnlDUFvJw1obF2PllKdr8jO+MHn7Cv8eykrikK0WLR8Mv1MgZTn7JEc3sjLo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com; spf=pass smtp.mailfrom=huawei.com; arc=none smtp.client-ip=45.249.212.190 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=huawei.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=huawei.com Received: from mail.maildlp.com (unknown [172.19.88.163]) by szxga04-in.huawei.com (SkyGuard) with ESMTP id 4WVgy35N82z2ClN5; Fri, 26 Jul 2024 16:33:31 +0800 (CST) Received: from kwepemd100024.china.huawei.com (unknown [7.221.188.41]) by mail.maildlp.com (Postfix) with ESMTPS id 27825180042; Fri, 26 Jul 2024 16:37:59 +0800 (CST) Received: from huawei.com (10.175.124.27) by kwepemd100024.china.huawei.com (7.221.188.41) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Fri, 26 Jul 2024 16:37:58 +0800 From: yangyun To: Miklos Szeredi CC: , Subject: [PATCH 2/2] fuse: add support for no forget requests Date: Fri, 26 Jul 2024 16:37:52 +0800 Message-ID: <20240726083752.302301-3-yangyun50@huawei.com> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20240726083752.302301-1-yangyun50@huawei.com> References: <20240726083752.302301-1-yangyun50@huawei.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) To kwepemd100024.china.huawei.com (7.221.188.41) Content-Type: text/plain; charset="utf-8" FUSE_FORGET requests are not used if the fuse file system does not implement the forget operation in userspace (e.g., fuse file system does not cache any inodes). However, the kernel is invisible to the userspace implementation and always sends FUSE_FORGET requests, which can lead to performance degradation because of useless contex switch and memory copy in some cases (e.g., many inodes are evicted from icache which was described in commit 07e77dca8a1f ("fuse: separate queue for FORGET requests")). Just like 'no_interrupt' in 'struct fuse_conn', we add 'no_forget'. But since FUSE_FORGET request does not have a reply from userspce, we can not use ENOSYS to reflect the 'no_forget' assignment. So add the FUSE_NO_FORGET_SUPPORT init flag. Besides, if no_forget is enabled, 'nlookup' in 'struct fuse_inode' does not used and its value change can be disabled which are protected by spin_lock to reduce lock contention. Signed-off-by: yangyun --- fs/fuse/dev.c | 6 ++++++ fs/fuse/dir.c | 4 +--- fs/fuse/fuse_i.h | 24 ++++++++++++++++++++++++ fs/fuse/inode.c | 10 +++++----- fs/fuse/readdir.c | 8 ++------ include/uapi/linux/fuse.h | 3 +++ 6 files changed, 41 insertions(+), 14 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 932356833b0d..10890db9426b 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -238,6 +238,9 @@ void fuse_queue_forget(struct fuse_conn *fc, struct fus= e_forget_link *forget, { struct fuse_iqueue *fiq =3D &fc->iq; =20 + if (fc->no_forget) + return; + forget->forget_one.nodeid =3D nodeid; forget->forget_one.nlookup =3D nlookup; =20 @@ -257,6 +260,9 @@ void fuse_force_forget(struct fuse_mount *fm, u64 nodei= d) struct fuse_forget_in inarg; FUSE_ARGS(args); =20 + if (fm->fc->no_forget) + return; + memset(&inarg, 0, sizeof(inarg)); inarg.nlookup =3D 1; args.opcode =3D FUSE_FORGET; diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 6bfb3a128658..833225ed1d4f 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -236,9 +236,7 @@ static int fuse_dentry_revalidate(struct dentry *entry,= unsigned int flags) fuse_force_forget(fm, outarg.nodeid); goto invalid; } - spin_lock(&fi->lock); - fi->nlookup++; - spin_unlock(&fi->lock); + fuse_nlookup_inc_if_enabled(fm->fc, fi); } if (ret =3D=3D -ENOMEM || ret =3D=3D -EINTR) goto out; diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index b9a5b8ec0de5..924d6b0ad700 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -860,6 +860,9 @@ struct fuse_conn { /** Passthrough support for read/write IO */ unsigned int passthrough:1; =20 + /** Do not send FORGET request */ + unsigned int no_forget:1; + /** Maximum stack depth for passthrough backing files */ int max_stack_depth; =20 @@ -1029,6 +1032,27 @@ static inline void fuse_sync_bucket_dec(struct fuse_= sync_bucket *bucket) rcu_read_unlock(); } =20 +static inline void fuse_nlookup_inc_if_enabled(struct fuse_conn *fc, struc= t fuse_inode *fi) +{ + if (fc->no_forget) + return; + + spin_lock(&fi->lock); + fi->nlookup++; + spin_unlock(&fi->lock); +} + +static inline void fuse_nlookup_dec_if_enabled(struct fuse_conn *fc, struc= t fuse_inode *fi) +{ + if (fc->no_forget) + return; + + spin_lock(&fi->lock); + fi->nlookup--; + spin_lock(&fi->lock); +} + + /** Device operations */ extern const struct file_operations fuse_dev_operations; =20 diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 99e44ea7d875..277dc9479505 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -483,9 +483,7 @@ struct inode *fuse_iget(struct super_block *sb, u64 nod= eid, } } fi =3D get_fuse_inode(inode); - spin_lock(&fi->lock); - fi->nlookup++; - spin_unlock(&fi->lock); + fuse_nlookup_inc_if_enabled(fc, fi); done: fuse_change_attributes(inode, attr, NULL, attr_valid, attr_version); =20 @@ -1331,6 +1329,8 @@ static void process_init_reply(struct fuse_mount *fm,= struct fuse_args *args, } if (flags & FUSE_NO_EXPORT_SUPPORT) fm->sb->s_export_op =3D &fuse_export_fid_operations; + if (flags & FUSE_NO_FORGET_SUPPORT) + fc->no_forget =3D 1; } else { ra_pages =3D fc->max_read / PAGE_SIZE; fc->no_lock =3D 1; @@ -1378,7 +1378,7 @@ void fuse_send_init(struct fuse_mount *fm) FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT | FUSE_INIT_EXT | FUSE_SECURITY_CTX | FUSE_CREATE_SUPP_GROUP | FUSE_HAS_EXPIRE_ONLY | FUSE_DIRECT_IO_ALLOW_MMAP | - FUSE_NO_EXPORT_SUPPORT | FUSE_HAS_RESEND; + FUSE_NO_EXPORT_SUPPORT | FUSE_HAS_RESEND | FUSE_NO_FORGET_SUPPORT; #ifdef CONFIG_FUSE_DAX if (fm->fc->dax) flags |=3D FUSE_MAP_ALIGNMENT; @@ -1593,7 +1593,7 @@ static int fuse_fill_super_submount(struct super_bloc= k *sb, * that, though, so undo it here. */ fi =3D get_fuse_inode(root); - fi->nlookup--; + fuse_nlookup_dec_if_enabled(fm->fc, get_fuse_inode(root)); =20 sb->s_d_op =3D &fuse_dentry_operations; sb->s_root =3D d_make_root(root); diff --git a/fs/fuse/readdir.c b/fs/fuse/readdir.c index 39f01ac31f7c..13922662e07a 100644 --- a/fs/fuse/readdir.c +++ b/fs/fuse/readdir.c @@ -218,9 +218,7 @@ static int fuse_direntplus_link(struct file *file, } =20 fi =3D get_fuse_inode(inode); - spin_lock(&fi->lock); - fi->nlookup++; - spin_unlock(&fi->lock); + fuse_nlookup_inc_if_enabled(fc, fi); =20 forget_all_cached_acls(inode); fuse_change_attributes(inode, &o->attr, NULL, @@ -247,9 +245,7 @@ static int fuse_direntplus_link(struct file *file, if (!IS_ERR(inode)) { struct fuse_inode *fi =3D get_fuse_inode(inode); =20 - spin_lock(&fi->lock); - fi->nlookup--; - spin_unlock(&fi->lock); + fuse_nlookup_dec_if_enabled(fc, fi); } return PTR_ERR(dentry); } diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index d08b99d60f6f..bf660880bc7a 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -217,6 +217,7 @@ * - add backing_id to fuse_open_out, add FOPEN_PASSTHROUGH open flag * - add FUSE_NO_EXPORT_SUPPORT init flag * - add FUSE_NOTIFY_RESEND, add FUSE_HAS_RESEND init flag + * - add FUSE_NO_FORGET_SUPPORT init flag */ =20 #ifndef _LINUX_FUSE_H @@ -421,6 +422,7 @@ struct fuse_file_lock { * FUSE_NO_EXPORT_SUPPORT: explicitly disable export support * FUSE_HAS_RESEND: kernel supports resending pending requests, and the hi= gh bit * of the request ID indicates resend requests + * FUSE_NO_FORGET_SUPPORT: disable forget requests */ #define FUSE_ASYNC_READ (1 << 0) #define FUSE_POSIX_LOCKS (1 << 1) @@ -463,6 +465,7 @@ struct fuse_file_lock { #define FUSE_PASSTHROUGH (1ULL << 37) #define FUSE_NO_EXPORT_SUPPORT (1ULL << 38) #define FUSE_HAS_RESEND (1ULL << 39) +#define FUSE_NO_FORGET_SUPPORT (1ULL << 40) =20 /* Obsolete alias for FUSE_DIRECT_IO_ALLOW_MMAP */ #define FUSE_DIRECT_IO_RELAX FUSE_DIRECT_IO_ALLOW_MMAP --=20 2.33.0