From nobody Tue Apr 7 18:46:59 2026 Received: from smtp03-ext2.udag.de (smtp03-ext2.udag.de [62.146.106.30]) (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 8BCB0364955; Thu, 26 Feb 2026 16:44:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=62.146.106.30 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772124248; cv=none; b=L2FHKzjCFh3wIoNSe2AmKIjcxgcVNmsyxTkIndeM6ivvjYoMRzwUFnIzPaC38Is0U+NvRKGQ/di/P+sFN0C6/O2GU+LgoffyekFCGzrJFtj2zdA6SvNNnMH83fo2IY2D0sXqwBc1JNGL6xANlVnmesfmehKn7DasuhpyWtT5Fks= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772124248; c=relaxed/simple; bh=Wzo8W6GuKhl9trl7/UuvnQRqTZeOq9FOfR9/Ey+Sf6w=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=FUmIop3cLrvq84f0bmOQ1irkTd/ek3tcvsAEAxQXP+/8YpsqKQGrk8ZYO+dJnHihvaa4LgUjll2I7/JtUZhaLIBDIrsbIrnl8j+ai9JmdOIILiAw/zpXZcYuM2N2uPsI4EKY8z6JhROWSrX+kiAvycbHs0XIqrUXJWf8+WUzJNE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=birthelmer.com; spf=pass smtp.mailfrom=birthelmer.com; dkim=pass (2048-bit key) header.d=birthelmer.com header.i=@birthelmer.com header.b=rznISr6Z; arc=none smtp.client-ip=62.146.106.30 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=birthelmer.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=birthelmer.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=birthelmer.com header.i=@birthelmer.com header.b="rznISr6Z" Received: from fedora.fritz.box (200-143-067-156.ip-addr.inexio.net [156.67.143.200]) by smtp03-ext2.udag.de (Postfix) with ESMTPA id 4C816E0364; Thu, 26 Feb 2026 17:43:58 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=birthelmer.com; s=uddkim-202310; t=1772124238; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ZUv8gt5mgSFguSaafivJElSBGQrkctKXF01agrTnXwU=; b=rznISr6Zinc4+u8jBbEkPV7mkk74xRegmqz+8JD/uYC+JJbOCm8eM1Ttf3ro50qkzfdFKE 64Bno29lHWMTHdLLsN0kymt5fewhYW5Fwbuo103lKRHq21ZvFRBSL1O7nRwvCBDwRNYtGY exmwKO/O5KUlCLTmS/WMy3tUcRbjv0tAVY1RFEzVSHwlLzUaRqvJEXU9SPQKAlJfp/nEoC UdQ8ycGzLst7x3o5SOF0H+hq2YKgPNOSTbWXiXcBpL6U1uUZlfgg0nSfDRZJwdtrHxcyyN R3q23Jo0oRbTR9e1NTN67P07b+UCZ1UEs66GFfmiWPm898jgnGrT9iAP1auo+g== Authentication-Results: smtp03-ext2.udag.de; auth=pass smtp.auth=birthelmercom-0001 smtp.mailfrom=horst@birthelmer.com From: Horst Birthelmer Date: Thu, 26 Feb 2026 17:43:55 +0100 Subject: [PATCH v6 3/3] fuse: add an implementation of open+getattr Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260226-fuse-compounds-upstream-v6-3-8585c5fcd2fc@ddn.com> References: <20260226-fuse-compounds-upstream-v6-0-8585c5fcd2fc@ddn.com> In-Reply-To: <20260226-fuse-compounds-upstream-v6-0-8585c5fcd2fc@ddn.com> To: Miklos Szeredi , Bernd Schubert , Joanne Koong , Luis Henriques Cc: linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org, Horst Birthelmer X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1772124235; l=5771; i=hbirthelmer@ddn.com; s=20251006; h=from:subject:message-id; bh=a/RBWGdWP//IlsEU/HBmKi3NpsJuJaZ2v6GDMv26sQE=; b=VwkcEOCotSgofOiok7Lax5jHbZWcNIHNNoHv5zEEmeNUYY1hXUiGUoPxSgfYsnUI0N+HxfFxQ RrMyXFLpASSAgCv2fDBoLyeeCqWPEgISCx5/35GTvV+7yUNoO0Y9JL7 X-Developer-Key: i=hbirthelmer@ddn.com; a=ed25519; pk=v3BVDFoy16EzgHZ23ObqW+kbpURtjrwxgKu8YNDKjGg= From: Horst Birthelmer The discussion about compound commands in fuse was started over an argument to add a new operation that will open a file and return its attributes in the same operation. Here is a demonstration of that use case with compound commands. Signed-off-by: Horst Birthelmer --- fs/fuse/file.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++----= ---- fs/fuse/fuse_i.h | 4 +- fs/fuse/ioctl.c | 2 +- 3 files changed, 99 insertions(+), 18 deletions(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index a408a9668abbb361e2c1e386ebab9dfcb0a7a573..daa95a640c311fc393241bdf727= e00a2bc714f35 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -136,8 +136,71 @@ static void fuse_file_put(struct fuse_file *ff, bool s= ync) } } =20 +static int fuse_compound_open_getattr(struct fuse_mount *fm, u64 nodeid, + struct inode *inode, int flags, int opcode, + struct fuse_file *ff, + struct fuse_attr_out *outattrp, + struct fuse_open_out *outopenp) +{ + struct fuse_conn *fc =3D fm->fc; + struct fuse_compound_req *compound; + struct fuse_args open_args =3D {}; + struct fuse_args getattr_args =3D {}; + struct fuse_open_in open_in =3D {}; + struct fuse_getattr_in getattr_in =3D {}; + int err; + + compound =3D fuse_compound_alloc(fm, 2, FUSE_COMPOUND_SEPARABLE); + if (!compound) + return -ENOMEM; + + open_in.flags =3D flags & ~(O_CREAT | O_EXCL | O_NOCTTY); + if (!fm->fc->atomic_o_trunc) + open_in.flags &=3D ~O_TRUNC; + + if (fm->fc->handle_killpriv_v2 && + (open_in.flags & O_TRUNC) && !capable(CAP_FSETID)) + open_in.open_flags |=3D FUSE_OPEN_KILL_SUIDGID; + + fuse_open_args_fill(&open_args, nodeid, opcode, &open_in, outopenp); + + err =3D fuse_compound_add(compound, &open_args, NULL); + if (err) + goto out; + + fuse_getattr_args_fill(&getattr_args, nodeid, &getattr_in, outattrp); + + err =3D fuse_compound_add(compound, &getattr_args, NULL); + if (err) + goto out; + + err =3D fuse_compound_send(compound); + if (err) + goto out; + + err =3D fuse_compound_get_error(compound, 0); + if (err) + goto out; + + ff->fh =3D outopenp->fh; + ff->open_flags =3D outopenp->open_flags; + + err =3D fuse_compound_get_error(compound, 1); + if (err) + goto out; + + fuse_change_attributes(inode, &outattrp->attr, NULL, + ATTR_TIMEOUT(outattrp), + fuse_get_attr_version(fc)); + +out: + fuse_compound_free(compound); + return err; +} + struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid, - unsigned int open_flags, bool isdir) + struct inode *inode, + unsigned int open_flags, bool isdir) { struct fuse_conn *fc =3D fm->fc; struct fuse_file *ff; @@ -163,23 +226,40 @@ struct fuse_file *fuse_file_open(struct fuse_mount *f= m, u64 nodeid, if (open) { /* Store outarg for fuse_finish_open() */ struct fuse_open_out *outargp =3D &ff->args->open_outarg; - int err; + int err =3D -ENOSYS; =20 - err =3D fuse_send_open(fm, nodeid, open_flags, opcode, outargp); - if (!err) { - ff->fh =3D outargp->fh; - ff->open_flags =3D outargp->open_flags; - } else if (err !=3D -ENOSYS) { - fuse_file_free(ff); - return ERR_PTR(err); - } else { - if (isdir) { + if (inode) { + struct fuse_attr_out attr_outarg; + + err =3D fuse_compound_open_getattr(fm, nodeid, inode, + open_flags, opcode, ff, + &attr_outarg, outargp); + } + + if (err =3D=3D -ENOSYS) { + err =3D fuse_send_open(fm, nodeid, open_flags, opcode, + outargp); + if (!err) { + ff->fh =3D outargp->fh; + ff->open_flags =3D outargp->open_flags; + } + } + + if (err) { + if (err !=3D -ENOSYS) { + /* err is not ENOSYS */ + fuse_file_free(ff); + return ERR_PTR(err); + } else { /* No release needed */ kfree(ff->args); ff->args =3D NULL; - fc->no_opendir =3D 1; - } else { - fc->no_open =3D 1; + + /* we don't have open */ + if (isdir) + fc->no_opendir =3D 1; + else + fc->no_open =3D 1; } } } @@ -195,11 +275,10 @@ struct fuse_file *fuse_file_open(struct fuse_mount *f= m, u64 nodeid, int fuse_do_open(struct fuse_mount *fm, u64 nodeid, struct file *file, bool isdir) { - struct fuse_file *ff =3D fuse_file_open(fm, nodeid, file->f_flags, isdir); + struct fuse_file *ff =3D fuse_file_open(fm, nodeid, file_inode(file), fil= e->f_flags, isdir); =20 if (!IS_ERR(ff)) file->private_data =3D ff; - return PTR_ERR_OR_ZERO(ff); } EXPORT_SYMBOL_GPL(fuse_do_open); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index ff8222b66c4f7b04c0671a980237a43871affd0a..40409a4ab016a061eea20afee76= c8a7fe9c15adb 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1588,7 +1588,9 @@ void fuse_file_io_release(struct fuse_file *ff, struc= t inode *inode); =20 /* file.c */ struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid, - unsigned int open_flags, bool isdir); + struct inode *inode, + unsigned int open_flags, + bool isdir); void fuse_file_release(struct inode *inode, struct fuse_file *ff, unsigned int open_flags, fl_owner_t id, bool isdir); =20 diff --git a/fs/fuse/ioctl.c b/fs/fuse/ioctl.c index fdc175e93f74743eb4d2e5a4bc688df1c62e64c4..07a02e47b2c3a68633d213675a8= cc380a0cf31d8 100644 --- a/fs/fuse/ioctl.c +++ b/fs/fuse/ioctl.c @@ -494,7 +494,7 @@ static struct fuse_file *fuse_priv_ioctl_prepare(struct= inode *inode) if (!S_ISREG(inode->i_mode) && !isdir) return ERR_PTR(-ENOTTY); =20 - return fuse_file_open(fm, get_node_id(inode), O_RDONLY, isdir); + return fuse_file_open(fm, get_node_id(inode), NULL, O_RDONLY, isdir); } =20 static void fuse_priv_ioctl_cleanup(struct inode *inode, struct fuse_file = *ff) --=20 2.53.0