From nobody Tue Dec 2 02:31:38 2025 Received: from fanzine2.igalia.com (fanzine2.igalia.com [213.97.179.56]) (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 DBEEF2D9491; Thu, 20 Nov 2025 10:55:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=213.97.179.56 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763636160; cv=none; b=tEmIJsICyK7gK/2MhZYPI82kjaQVOZ2M2SzEwF3pl6m6Mu5GqCTWQTbAzhYpBn8LkyVcJKH/73x+wvphDmR+Z2ozcgOxLKYc4g0SEq5z9Dfz2Q7jjVEKZbV3xmd23TeSHnYISSg9I9KNM0wrt1dmuF3TGEwawiG12/dsznRSClE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1763636160; c=relaxed/simple; bh=8Fb1JFU1XDyN5HkfP42mRcmu3leIkP0ZTYVVDmhv4AI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sNd1Z/KorS66wB51Mjqpzh3BlPaU1WrZbqDtpUoSyVzInRqk/p47zueobBWm1JkzyWPIuvODUZ5YuPc93DcwTnxqa/AY/k1XTOZb6SiRm0H6PW2+Ofv1wKJFg6GcAyLiADN+L2f2yLgANm2gDGu1c/NqtOXhk4jzfCbw7093D6E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=igalia.com; spf=pass smtp.mailfrom=igalia.com; dkim=pass (2048-bit key) header.d=igalia.com header.i=@igalia.com header.b=FaA3fhsn; arc=none smtp.client-ip=213.97.179.56 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=igalia.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=igalia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=igalia.com header.i=@igalia.com header.b="FaA3fhsn" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=igalia.com; s=20170329; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=AJSezwXEdBDqaX7YfiQwltaRFSgxJdT+Q/B2BLWl0FI=; b=FaA3fhsnLfsw3K/BkzbrOwPWAp h97qpC7y3qBpctHkaI9KDUxUgRl99lctwiYVyu4T3AGkVP+lbMZO8L65lnDqiIFc0yNS3sosNL1VZ ola4rsRkUQuPs8IsO0FBAnQ7BCLBBZffcfvmAq/dbY0EFZA7KQf4sV9dKLHzkLjHGFANY1ZU365tf D2bQpnj2ng99sLFyzmclqo6WV0Yk16JTvaxNv5H+TygFquaxCQP5TZu/9yWKyeLgJ2TsOXvhksa7u ZDcOL1ZHDEv9S/HUPqTPtf5/9lVLMHJRU11x6jm0iqVHIbXQzKXTjzfhvnYubzPt/KI3LpwtItA3h 4lmiB/Ow==; Received: from bl17-145-117.dsl.telepac.pt ([188.82.145.117] helo=localhost) by fanzine2.igalia.com with utf8esmtpsa (Cipher TLS1.3:ECDHE_SECP256R1__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim) id 1vM2KF-003CKB-AI; Thu, 20 Nov 2025 11:55:42 +0100 From: Luis Henriques To: Miklos Szeredi Cc: Amir Goldstein , "Darrick J. Wong" , Bernd Schubert , Kevin Chen , Horst Birthelmer , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, Matt Harvey , kernel-dev@igalia.com, Luis Henriques Subject: [RFC PATCH v1 2/3] fuse: move fuse_entry_out structs out of the stack Date: Thu, 20 Nov 2025 10:55:34 +0000 Message-ID: <20251120105535.13374-3-luis@igalia.com> In-Reply-To: <20251120105535.13374-1-luis@igalia.com> References: <20251120105535.13374-1-luis@igalia.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 Content-Type: text/plain; charset="utf-8" This patch simply turns all struct fuse_entry_out instances that are allocated in the stack into dynamically allocated structs. This is a preparation patch for further changes, including the extra helper function used to actually allocate the memory. Also, remove all the memset()s that are used to zero-out these structures, as kzalloc() is being used. Signed-off-by: Luis Henriques --- fs/fuse/dir.c | 139 ++++++++++++++++++++++++++++++----------------- fs/fuse/fuse_i.h | 9 +++ fs/fuse/inode.c | 20 +++++-- 3 files changed, 114 insertions(+), 54 deletions(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index ecaec0fea3a1..77d50ea30b61 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -172,7 +172,6 @@ static void fuse_lookup_init(struct fuse_conn *fc, stru= ct fuse_args *args, u64 nodeid, const struct qstr *name, struct fuse_entry_out *outarg) { - memset(outarg, 0, sizeof(struct fuse_entry_out)); args->opcode =3D FUSE_LOOKUP; args->nodeid =3D nodeid; args->in_numargs =3D 3; @@ -213,7 +212,7 @@ static int fuse_dentry_revalidate(struct inode *dir, co= nst struct qstr *name, goto invalid; else if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) || (flags & (LOOKUP_EXCL | LOOKUP_REVAL | LOOKUP_RENAME_TARGET))) { - struct fuse_entry_out outarg; + struct fuse_entry_out *outarg; FUSE_ARGS(args); struct fuse_forget_link *forget; u64 attr_version; @@ -233,20 +232,27 @@ static int fuse_dentry_revalidate(struct inode *dir, = const struct qstr *name, if (!forget) goto out; =20 + outarg =3D fuse_entry_out_alloc(fc); + if (!outarg) { + kfree(forget); + goto out; + } + attr_version =3D fuse_get_attr_version(fm->fc); =20 fuse_lookup_init(fm->fc, &args, get_node_id(dir), - name, &outarg); + name, outarg); ret =3D fuse_simple_request(fm, &args); /* Zero nodeid is same as -ENOENT */ - if (!ret && !outarg.nodeid) + if (!ret && !outarg->nodeid) ret =3D -ENOENT; if (!ret) { 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)) { + if (outarg->nodeid !=3D get_node_id(inode) || + (bool) IS_AUTOMOUNT(inode) !=3D (bool) (outarg->attr.flags & FUSE_A= TTR_SUBMOUNT)) { fuse_queue_forget(fm->fc, forget, - outarg.nodeid, 1); + outarg->nodeid, 1); + kfree(outarg); goto invalid; } spin_lock(&fi->lock); @@ -254,17 +260,22 @@ static int fuse_dentry_revalidate(struct inode *dir, = const struct qstr *name, spin_unlock(&fi->lock); } kfree(forget); - if (ret =3D=3D -ENOMEM || ret =3D=3D -EINTR) + if (ret =3D=3D -ENOMEM || ret =3D=3D -EINTR) { + kfree(outarg); goto out; - if (ret || fuse_invalid_attr(&outarg.attr) || - fuse_stale_inode(inode, outarg.generation, &outarg.attr)) + } + if (ret || fuse_invalid_attr(&outarg->attr) || + fuse_stale_inode(inode, outarg->generation, &outarg->attr)) { + kfree(outarg); goto invalid; + } =20 forget_all_cached_acls(inode); - fuse_change_attributes(inode, &outarg.attr, NULL, - ATTR_TIMEOUT(&outarg), + fuse_change_attributes(inode, &outarg->attr, NULL, + ATTR_TIMEOUT(outarg), attr_version); - fuse_change_entry_timeout(entry, &outarg); + fuse_change_entry_timeout(entry, outarg); + kfree(outarg); } else if (inode) { fi =3D get_fuse_inode(inode); if (flags & LOOKUP_RCU) { @@ -410,7 +421,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid= , const struct qstr *name static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, unsigned int flags) { - struct fuse_entry_out outarg; + struct fuse_entry_out *outarg; struct fuse_conn *fc; struct inode *inode; struct dentry *newent; @@ -424,9 +435,13 @@ static struct dentry *fuse_lookup(struct inode *dir, s= truct dentry *entry, fc =3D get_fuse_conn_super(dir->i_sb); epoch =3D atomic_read(&fc->epoch); =20 + outarg =3D fuse_entry_out_alloc(fc); + if (!outarg) + return ERR_PTR(-ENOMEM); + locked =3D fuse_lock_inode(dir); err =3D fuse_lookup_name(dir->i_sb, get_node_id(dir), &entry->d_name, - &outarg, &inode); + outarg, &inode); fuse_unlock_inode(dir, locked); if (err =3D=3D -ENOENT) { outarg_valid =3D false; @@ -447,17 +462,21 @@ static struct dentry *fuse_lookup(struct inode *dir, = struct dentry *entry, entry =3D newent ? newent : entry; entry->d_time =3D epoch; if (outarg_valid) - fuse_change_entry_timeout(entry, &outarg); + fuse_change_entry_timeout(entry, outarg); else fuse_invalidate_entry_cache(entry); =20 if (inode) fuse_advise_use_readdirplus(dir); + + kfree(outarg); + return newent; =20 - out_iput: +out_iput: iput(inode); - out_err: +out_err: + kfree(outarg); return ERR_PTR(err); } =20 @@ -625,7 +644,7 @@ static int fuse_create_open(struct mnt_idmap *idmap, st= ruct inode *dir, struct fuse_forget_link *forget; struct fuse_create_in inarg; struct fuse_open_out *outopenp; - struct fuse_entry_out outentry; + struct fuse_entry_out *outentry; struct fuse_inode *fi; struct fuse_file *ff; int epoch, err; @@ -640,17 +659,19 @@ static int fuse_create_open(struct mnt_idmap *idmap, = struct inode *dir, if (!forget) goto out_err; =20 - err =3D -ENOMEM; ff =3D fuse_file_alloc(fm, true); if (!ff) goto out_put_forget_req; =20 + outentry =3D fuse_entry_out_alloc(fm->fc); + if (!outentry) + goto out_free_ff; + if (!fm->fc->dont_mask) mode &=3D ~current_umask(); =20 flags &=3D ~O_NOCTTY; memset(&inarg, 0, sizeof(inarg)); - memset(&outentry, 0, sizeof(outentry)); inarg.flags =3D flags; inarg.mode =3D mode; inarg.umask =3D current_umask(); @@ -668,8 +689,8 @@ static int fuse_create_open(struct mnt_idmap *idmap, st= ruct inode *dir, args.in_args[1].size =3D entry->d_name.len + 1; args.in_args[1].value =3D entry->d_name.name; args.out_numargs =3D 2; - args.out_args[0].size =3D sizeof(outentry); - args.out_args[0].value =3D &outentry; + args.out_args[0].size =3D sizeof(*outentry); + args.out_args[0].value =3D outentry; /* Store outarg for fuse_finish_open() */ outopenp =3D &ff->args->open_outarg; args.out_args[1].size =3D sizeof(*outopenp); @@ -677,34 +698,35 @@ static int fuse_create_open(struct mnt_idmap *idmap, = struct inode *dir, =20 err =3D get_create_ext(idmap, &args, dir, entry, mode); if (err) - goto out_free_ff; + goto out_free_outentry; =20 err =3D fuse_simple_idmap_request(idmap, fm, &args); free_ext_value(&args); if (err) - goto out_free_ff; + goto out_free_outentry; =20 err =3D -EIO; - if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid) || - fuse_invalid_attr(&outentry.attr)) - goto out_free_ff; + if (!S_ISREG(outentry->attr.mode) || invalid_nodeid(outentry->nodeid) || + fuse_invalid_attr(&outentry->attr)) + goto out_free_outentry; =20 ff->fh =3D outopenp->fh; - ff->nodeid =3D outentry.nodeid; + ff->nodeid =3D outentry->nodeid; ff->open_flags =3D outopenp->open_flags; - inode =3D fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, - &outentry.attr, ATTR_TIMEOUT(&outentry), 0, 0); + inode =3D fuse_iget(dir->i_sb, outentry->nodeid, outentry->generation, + &outentry->attr, ATTR_TIMEOUT(outentry), 0, 0); 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_queue_forget(fm->fc, forget, outentry->nodeid, 1); err =3D -ENOMEM; + kfree(outentry); goto out_err; } kfree(forget); d_instantiate(entry, inode); entry->d_time =3D epoch; - fuse_change_entry_timeout(entry, &outentry); + fuse_change_entry_timeout(entry, outentry); fuse_dir_changed(dir); err =3D generic_file_open(inode, file); if (!err) { @@ -720,8 +742,13 @@ static int fuse_create_open(struct mnt_idmap *idmap, s= truct inode *dir, else if (!(ff->open_flags & FOPEN_KEEP_CACHE)) invalidate_inode_pages2(inode->i_mapping); } + + kfree(outentry); + return err; =20 +out_free_outentry: + kfree(outentry); out_free_ff: fuse_file_free(ff); out_put_forget_req: @@ -780,7 +807,7 @@ static struct dentry *create_new_entry(struct mnt_idmap= *idmap, struct fuse_moun struct fuse_args *args, struct inode *dir, struct dentry *entry, umode_t mode) { - struct fuse_entry_out outarg; + struct fuse_entry_out *outarg; struct inode *inode; struct dentry *d; struct fuse_forget_link *forget; @@ -795,54 +822,66 @@ static struct dentry *create_new_entry(struct mnt_idm= ap *idmap, struct fuse_moun if (!forget) return ERR_PTR(-ENOMEM); =20 - memset(&outarg, 0, sizeof(outarg)); + outarg =3D fuse_entry_out_alloc(fm->fc); + if (!outarg) { + err =3D -ENOMEM; + goto out_put_forget_req; + } + args->nodeid =3D get_node_id(dir); args->out_numargs =3D 1; - args->out_args[0].size =3D sizeof(outarg); - args->out_args[0].value =3D &outarg; + args->out_args[0].size =3D sizeof(*outarg); + args->out_args[0].value =3D outarg; =20 if (args->opcode !=3D FUSE_LINK) { err =3D get_create_ext(idmap, args, dir, entry, mode); if (err) - goto out_put_forget_req; + goto out_free_outarg; } =20 err =3D fuse_simple_idmap_request(idmap, fm, args); free_ext_value(args); if (err) - goto out_put_forget_req; + goto out_free_outarg; =20 err =3D -EIO; - if (invalid_nodeid(outarg.nodeid) || fuse_invalid_attr(&outarg.attr)) - goto out_put_forget_req; + if (invalid_nodeid(outarg->nodeid) || fuse_invalid_attr(&outarg->attr)) + goto out_free_outarg; =20 - if ((outarg.attr.mode ^ mode) & S_IFMT) - goto out_put_forget_req; + if ((outarg->attr.mode ^ mode) & S_IFMT) + goto out_free_outarg; =20 - inode =3D fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, - &outarg.attr, ATTR_TIMEOUT(&outarg), 0, 0); + inode =3D fuse_iget(dir->i_sb, outarg->nodeid, outarg->generation, + &outarg->attr, ATTR_TIMEOUT(outarg), 0, 0); if (!inode) { - fuse_queue_forget(fm->fc, forget, outarg.nodeid, 1); + fuse_queue_forget(fm->fc, forget, outarg->nodeid, 1); + kfree(outarg); return ERR_PTR(-ENOMEM); } kfree(forget); =20 d_drop(entry); d =3D d_splice_alias(inode, entry); - if (IS_ERR(d)) + if (IS_ERR(d)) { + kfree(outarg); return d; + } =20 if (d) { d->d_time =3D epoch; - fuse_change_entry_timeout(d, &outarg); + fuse_change_entry_timeout(d, outarg); } else { entry->d_time =3D epoch; - fuse_change_entry_timeout(entry, &outarg); + fuse_change_entry_timeout(entry, outarg); } fuse_dir_changed(dir); + kfree(outarg); + return d; =20 - out_put_forget_req: +out_free_outarg: + kfree(outarg); +out_put_forget_req: if (err =3D=3D -EEXIST) fuse_invalidate_entry(entry); kfree(forget); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index f4e9747ed8c7..d997fdcede9b 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1092,6 +1092,15 @@ static inline bool fuse_is_bad(struct inode *inode) return unlikely(test_bit(FUSE_I_BAD, &get_fuse_inode(inode)->state)); } =20 +static inline struct fuse_entry_out *fuse_entry_out_alloc(struct fuse_conn= *fc) +{ + struct fuse_entry_out *entryout; + + entryout =3D kzalloc(sizeof(*entryout), GFP_KERNEL_ACCOUNT); + + return entryout; +} + static inline struct folio **fuse_folios_alloc(unsigned int nfolios, gfp_t= flags, struct fuse_folio_desc **desc) { diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index b9b094c1bc36..30ee37c29057 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -1080,14 +1080,21 @@ static struct dentry *fuse_get_dentry(struct super_= block *sb, =20 inode =3D ilookup5(sb, handle->nodeid, fuse_inode_eq, &handle->nodeid); if (!inode) { - struct fuse_entry_out outarg; + struct fuse_entry_out *outarg; const struct qstr name =3D QSTR_INIT(".", 1); =20 if (!fc->export_support) goto out_err; =20 - err =3D fuse_lookup_name(sb, handle->nodeid, &name, &outarg, + outarg =3D fuse_entry_out_alloc(fc); + if (!outarg) { + err =3D -ENOMEM; + goto out_err; + } + + err =3D fuse_lookup_name(sb, handle->nodeid, &name, outarg, &inode); + kfree(outarg); if (err && err !=3D -ENOENT) goto out_err; if (err || !inode) { @@ -1181,14 +1188,19 @@ static struct dentry *fuse_get_parent(struct dentry= *child) struct fuse_conn *fc =3D get_fuse_conn(child_inode); struct inode *inode; struct dentry *parent; - struct fuse_entry_out outarg; + struct fuse_entry_out *outarg; int err; =20 if (!fc->export_support) return ERR_PTR(-ESTALE); =20 + outarg =3D fuse_entry_out_alloc(fc); + if (!outarg) + return ERR_PTR(-ENOMEM); + err =3D fuse_lookup_name(child_inode->i_sb, get_node_id(child_inode), - &dotdot_name, &outarg, &inode); + &dotdot_name, outarg, &inode); + kfree(outarg); if (err) { if (err =3D=3D -ENOENT) return ERR_PTR(-ESTALE);