Re: [PATCH v2] NFSv4.2: Update mode bits after ALLOCATE and DEALLOCATE

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 2022-09-01 at 14:22 -0400, Trond Myklebust wrote:
> On Thu, 2022-09-01 at 14:05 -0400, Anna Schumaker wrote:
> > From: Anna Schumaker <Anna.Schumaker@xxxxxxxxxx>
> > 
> > The fallocate call invalidates suid and sgid bits as part of normal
> > operation. We need to mark the mode bits as invalid when using
> > fallocate
> > with an suid so these will be updated the next time the user looks
> > at
> > them.
> > 
> > This fixes xfstests generic/683 and generic/684.
> > 
> > Reported-by: Yue Cui <cuiyue-fnst@xxxxxxxxxxx>
> > Fixes: 913eca1aea87 ("NFS: Fallocate should use the
> > nfs4_fattr_bitmap")
> > Signed-off-by: Anna Schumaker <Anna.Schumaker@xxxxxxxxxx>
> > ---
> >  fs/nfs/internal.h  | 25 +++++++++++++++++++++++++
> >  fs/nfs/nfs42proc.c | 13 ++++++++++++-
> >  fs/nfs/write.c     | 25 -------------------------
> >  3 files changed, 37 insertions(+), 26 deletions(-)
> > 
> > diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
> > index 27c720d71b4e..898dd95bc7a7 100644
> > --- a/fs/nfs/internal.h
> > +++ b/fs/nfs/internal.h
> > @@ -606,6 +606,31 @@ static inline gfp_t nfs_io_gfp_mask(void)
> >         return GFP_KERNEL;
> >  }
> >  
> > +/*
> > + * Special version of should_remove_suid() that ignores
> > capabilities.
> > + */
> > +static inline int nfs_should_remove_suid(const struct inode
> > *inode)
> > +{
> > +       umode_t mode = inode->i_mode;
> > +       int kill = 0;
> > +
> > +       /* suid always must be killed */
> > +       if (unlikely(mode & S_ISUID))
> > +               kill = ATTR_KILL_SUID;
> > +
> > +       /*
> > +        * sgid without any exec bits is just a mandatory locking
> > mark; leave
> > +        * it alone.  If some exec bits are set, it's a real sgid;
> > kill it.
> > +        */
> > +       if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
> > +               kill |= ATTR_KILL_SGID;
> > +
> > +       if (unlikely(kill && S_ISREG(mode)))
> > +               return kill;
> > +
> > +       return 0;
> > +}
> > +
> >  /* unlink.c */
> >  extern struct rpc_task *
> >  nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
> > diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
> > index 068c45b3bc1a..23023ddf75d1 100644
> > --- a/fs/nfs/nfs42proc.c
> > +++ b/fs/nfs/nfs42proc.c
> > @@ -56,6 +56,7 @@ static int _nfs42_proc_fallocate(struct
> > rpc_message
> > *msg, struct file *filep,
> >         struct nfs42_falloc_res res = {
> >                 .falloc_server  = server,
> >         };
> > +       unsigned int invalid = 0;
> >         int status;
> >  
> >         msg->rpc_argp = &args;
> > @@ -78,10 +79,20 @@ static int _nfs42_proc_fallocate(struct
> > rpc_message *msg, struct file *filep,
> >  
> >         status = nfs4_call_sync(server->client, server, msg,
> >                                 &args.seq_args, &res.seq_res, 0);
> > +
> > +       if (!res.falloc_fattr->valid)
> > +               invalid |= NFS_INO_INVALID_ATTR;

Oh wait... We shouldn't need this.^^^^^^^^^
nfs_post_op_update_inode_force_wcc() will do the right thing for you
here.

> > +       if (nfs_should_remove_suid(inode))
> > +               invalid |= NFS_INO_INVALID_MODE;
> > +       if (invalid) {
> > +               spin_lock(&inode->i_lock);
> > +               nfs_set_cache_invalid(inode, NFS_INO_INVALID_MODE);
> > +               spin_unlock(&inode->i_lock);
> > +       }
> 
> This all really wants to go into the 'if (status == 0)' below.
> > +
> >         if (status == 0)
> >                 status = nfs_post_op_update_inode_force_wcc(inode,
> >                                                            
> > res.falloc_fattr);
> > -
> >         if (msg->rpc_proc ==
> > &nfs4_procedures[NFSPROC4_CLNT_ALLOCATE])
> >                 trace_nfs4_fallocate(inode, &args, status);
> >         else
> > diff --git a/fs/nfs/write.c b/fs/nfs/write.c
> > index 1843fa235d9b..f41d24b54fd1 100644
> > --- a/fs/nfs/write.c
> > +++ b/fs/nfs/write.c
> > @@ -1496,31 +1496,6 @@ void nfs_commit_prepare(struct rpc_task
> > *task,
> > void *calldata)
> >         NFS_PROTO(data->inode)->commit_rpc_prepare(task, data);
> >  }
> >  
> > -/*
> > - * Special version of should_remove_suid() that ignores
> > capabilities.
> > - */
> > -static int nfs_should_remove_suid(const struct inode *inode)
> > -{
> > -       umode_t mode = inode->i_mode;
> > -       int kill = 0;
> > -
> > -       /* suid always must be killed */
> > -       if (unlikely(mode & S_ISUID))
> > -               kill = ATTR_KILL_SUID;
> > -
> > -       /*
> > -        * sgid without any exec bits is just a mandatory locking
> > mark; leave
> > -        * it alone.  If some exec bits are set, it's a real sgid;
> > kill it.
> > -        */
> > -       if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
> > -               kill |= ATTR_KILL_SGID;
> > -
> > -       if (unlikely(kill && S_ISREG(mode)))
> > -               return kill;
> > -
> > -       return 0;
> > -}
> > -
> >  static void nfs_writeback_check_extend(struct nfs_pgio_header
> > *hdr,
> >                 struct nfs_fattr *fattr)
> >  {
> 
> Otherwise, looks OK.
> 

-- 
Trond Myklebust
Linux NFS client maintainer, Hammerspace
trond.myklebust@xxxxxxxxxxxxxxx






[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux