All of lore.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.