public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Horst Birthelmer <horst@birthelmer.de>
To: Joanne Koong <joannelkoong@gmail.com>
Cc: Horst Birthelmer <horst@birthelmer.com>,
	 Miklos Szeredi <miklos@szeredi.hu>,
	Bernd Schubert <bschubert@ddn.com>,
	 Luis Henriques <luis@igalia.com>,
	linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	 Horst Birthelmer <hbirthelmer@ddn.com>
Subject: Re: Re: [PATCH v6 3/3] fuse: add an implementation of open+getattr
Date: Fri, 27 Feb 2026 08:48:04 +0100	[thread overview]
Message-ID: <aaFJEeeeDrdqSEX9@fedora.fritz.box> (raw)
In-Reply-To: <CAJnrk1ZsvtZh9vZoN=ca_wrs5enTfAQeNBYppOzZH=c+ARaP3Q@mail.gmail.com>

On Thu, Feb 26, 2026 at 11:12:00AM -0800, Joanne Koong wrote:
> On Thu, Feb 26, 2026 at 8:43 AM Horst Birthelmer <horst@birthelmer.com> wrote:
> >
> > From: Horst Birthelmer <hbirthelmer@ddn.com>
> >
> > 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 <hbirthelmer@ddn.com>
> > ---
> >  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..daa95a640c311fc393241bdf727e00a2bc714f35 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 sync)
> >         }
> >  }
> >
> > +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 = fm->fc;
> > +       struct fuse_compound_req *compound;
> > +       struct fuse_args open_args = {};
> > +       struct fuse_args getattr_args = {};
> > +       struct fuse_open_in open_in = {};
> > +       struct fuse_getattr_in getattr_in = {};
> > +       int err;
> > +
> > +       compound = fuse_compound_alloc(fm, 2, FUSE_COMPOUND_SEPARABLE);
> > +       if (!compound)
> > +               return -ENOMEM;
> > +
> > +       open_in.flags = flags & ~(O_CREAT | O_EXCL | O_NOCTTY);
> > +       if (!fm->fc->atomic_o_trunc)
> > +               open_in.flags &= ~O_TRUNC;
> > +
> > +       if (fm->fc->handle_killpriv_v2 &&
> > +           (open_in.flags & O_TRUNC) && !capable(CAP_FSETID))
> > +               open_in.open_flags |= FUSE_OPEN_KILL_SUIDGID;
> 
> Do you think it makes sense to move this chunk of logic into
> fuse_open_args_fill() since this logic has to be done in
> fuse_send_open() as well?
>

Yes, I think that makes sense and would be beneficial to other requests in 
other compounds that will be constructed with that function.

> > +
> > +       fuse_open_args_fill(&open_args, nodeid, opcode, &open_in, outopenp);
> > +
> > +       err = fuse_compound_add(compound, &open_args, NULL);
> > +       if (err)
> > +               goto out;
> > +
> > +       fuse_getattr_args_fill(&getattr_args, nodeid, &getattr_in, outattrp);
> > +
> > +       err = fuse_compound_add(compound, &getattr_args, NULL);
> > +       if (err)
> > +               goto out;
> > +
> > +       err = fuse_compound_send(compound);
> > +       if (err)
> > +               goto out;
> > +
> > +       err = fuse_compound_get_error(compound, 0);
> > +       if (err)
> > +               goto out;
> > +
> > +       ff->fh = outopenp->fh;
> > +       ff->open_flags = outopenp->open_flags;
> 
> It looks like this logic is shared between here and the non-compound
> open path, maybe a bit better to just do this in fuse_file_open()
> instead? That way we also don't need to pass the struct fuse_file *ff
> as an arg either.
> 

Will do that.

> > +
> > +       err = fuse_compound_get_error(compound, 1);
> > +       if (err)
> > +               goto out;
> 
> For this open+getattr case, if getattr fails but the open succeeds,
> should this still succeed the open since they're separable requests? I
> think we had a conversation about it in v4, but imo this case should.
> 
You are right, we had the conversation and other people joined, so I
changed this code but to something else. Sorry about that.

I think your idea will work, since the behavior then is exactly what happens
at the moment with exactly the same drawback.

> > +
> > +       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,
> 
> As I understand it, now every open() is a opengetattr() (except for
> the ioctl path) but is this the desired behavior? for example if there
> was a previous FUSE_LOOKUP that was just done, doesn't this mean
> there's no getattr that's needed since the lookup refreshed the attrs?
> or if the server has reasonable entry_valid and attr_valid timeouts,
> multiple opens() of the same file would only need to send FUSE_OPEN
> and not the FUSE_GETATTR, no?

So your concern is, that we send too many requests?
If the fuse server implwments the compound that is not the case.

> 
> 
> > +                               unsigned int open_flags, bool isdir)
> >  {
> >         struct fuse_conn *fc = fm->fc;
> >         struct fuse_file *ff;
> > @@ -163,23 +226,40 @@ struct fuse_file *fuse_file_open(struct fuse_mount *fm, u64 nodeid,
> >         if (open) {
> >                 /* Store outarg for fuse_finish_open() */
> >                 struct fuse_open_out *outargp = &ff->args->open_outarg;
> > -               int err;
> > +               int err = -ENOSYS;
> >
> > -               err = fuse_send_open(fm, nodeid, open_flags, opcode, outargp);
> > -               if (!err) {
> > -                       ff->fh = outargp->fh;
> > -                       ff->open_flags = outargp->open_flags;
> > -               } else if (err != -ENOSYS) {
> > -                       fuse_file_free(ff);
> > -                       return ERR_PTR(err);
> > -               } else {
> > -                       if (isdir) {
> > +               if (inode) {
> > +                       struct fuse_attr_out attr_outarg;
> > +
> > +                       err = fuse_compound_open_getattr(fm, nodeid, inode,
> > +                                                        open_flags, opcode, ff,
> > +                                                        &attr_outarg, outargp);
> 
> instead of passing in &attr_outarg, what about just having that moved
> to fuse_compound_open_getattr()?
> 

This is a victim of 'code move' already.
I had the code to handle the outarg here before and did not change the functions
signature, which now looks stupid.

> > +               }
> > +
> > +               if (err == -ENOSYS) {
> > +                       err = fuse_send_open(fm, nodeid, open_flags, opcode,
> > +                                            outargp);
> > +                       if (!err) {
> > +                               ff->fh = outargp->fh;
> > +                               ff->open_flags = outargp->open_flags;
> > +                       }
> > +               }
> > +
> > +               if (err) {
> > +                       if (err != -ENOSYS) {
> > +                               /* err is not ENOSYS */
> > +                               fuse_file_free(ff);
> > +                               return ERR_PTR(err);
> > +                       } else {
> >                                 /* No release needed */
> >                                 kfree(ff->args);
> >                                 ff->args = NULL;
> > -                               fc->no_opendir = 1;
> > -                       } else {
> > -                               fc->no_open = 1;
> > +
> > +                               /* we don't have open */
> > +                               if (isdir)
> > +                                       fc->no_opendir = 1;
> > +                               else
> > +                                       fc->no_open = 1;
> 
> kfree(ff->args) and ff->args = NULL should not be called for the
> !isdir case or it leads to the deadlock that was fixed in
> https://lore.kernel.org/linux-fsdevel/20251010220738.3674538-2-joannelkoong@gmail.com/
> 
> I think if you have the "ff->fh = outargp..." and "ff->open_flags =
> ..." logic shared between fuse_compound_open_getattr() and
> fuse_send_open() then the original errorr handling for this could just
> be left as-is.

Very good argument to share the error handling then ...

> 
> Thanks,
> Joanne
> 

Thanks for taking the time,
Horst


  reply	other threads:[~2026-02-27  7:48 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-26 16:43 [PATCH v6 0/3] fuse: compound commands Horst Birthelmer
2026-02-26 16:43 ` [PATCH v6 1/3] fuse: add compound command to combine multiple requests Horst Birthelmer
2026-02-26 23:05   ` Joanne Koong
2026-02-27  9:45   ` Miklos Szeredi
2026-02-27 10:48     ` Horst Birthelmer
2026-02-27 11:29       ` Miklos Szeredi
2026-02-27 11:37         ` Horst Birthelmer
2026-02-27 11:58           ` Miklos Szeredi
2026-03-02  9:56     ` Horst Birthelmer
2026-03-02 11:03       ` Miklos Szeredi
2026-03-02 13:19         ` Horst Birthelmer
2026-03-02 13:30           ` Miklos Szeredi
2026-03-06 14:27     ` Horst Birthelmer
2026-02-26 16:43 ` [PATCH v6 2/3] fuse: create helper functions for filling in fuse args for open and getattr Horst Birthelmer
2026-02-26 16:43 ` [PATCH v6 3/3] fuse: add an implementation of open+getattr Horst Birthelmer
2026-02-26 19:12   ` Joanne Koong
2026-02-27  7:48     ` Horst Birthelmer [this message]
2026-02-27 17:51       ` Joanne Koong
2026-02-27 18:07         ` Joanne Koong
2026-02-28  8:14           ` Horst Birthelmer
2026-03-02 18:56             ` Joanne Koong
2026-03-02 20:03               ` Bernd Schubert
2026-03-03  5:06                 ` Darrick J. Wong
2026-03-03  7:26                   ` Horst Birthelmer
2026-03-03 10:03                   ` Miklos Szeredi
2026-03-03 10:38                     ` Horst Birthelmer
2026-03-03 21:19                       ` Joanne Koong
2026-03-04  9:11                         ` Horst Birthelmer
2026-03-04 21:42                           ` Joanne Koong
2026-03-03 23:13                     ` Joanne Koong
2026-03-04  9:37                       ` Miklos Szeredi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aaFJEeeeDrdqSEX9@fedora.fritz.box \
    --to=horst@birthelmer.de \
    --cc=bschubert@ddn.com \
    --cc=hbirthelmer@ddn.com \
    --cc=horst@birthelmer.com \
    --cc=joannelkoong@gmail.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luis@igalia.com \
    --cc=miklos@szeredi.hu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox