Merge tag 'nfsd-6.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 28 Mar 2024 21:35:32 +0000 (14:35 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 28 Mar 2024 21:35:32 +0000 (14:35 -0700)
Pull nfsd fixes from Chuck Lever:

 - Address three recently introduced regressions

* tag 'nfsd-6.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux:
  NFSD: CREATE_SESSION must never cache NFS4ERR_DELAY replies
  SUNRPC: Revert 561141dd494382217bace4d1a51d08168420eace
  nfsd: Fix error cleanup path in nfsd_rename()

1  2 
fs/nfsd/nfs4state.c
fs/nfsd/vfs.c

diff --combined fs/nfsd/nfs4state.c
index 1a93c7fcf76c55ee2a34a99ec72f48b2c167c0f8,5fcd93f7cb8c7d1b8560beaa2ca1245a2abc60fb..2391ab3c3231975bde1606875339b7736975054f
@@@ -1257,7 -1257,7 +1257,7 @@@ static void nfs4_unlock_deleg_lease(str
  
        WARN_ON_ONCE(!fp->fi_delegees);
  
 -      vfs_setlease(nf->nf_file, F_UNLCK, NULL, (void **)&dp);
 +      kernel_setlease(nf->nf_file, F_UNLCK, NULL, (void **)&dp);
        put_deleg_file(fp);
  }
  
@@@ -3831,15 -3831,20 +3831,20 @@@ nfsd4_create_session(struct svc_rqst *r
        else
                cs_slot = &unconf->cl_cs_slot;
        status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
-       if (status) {
-               if (status == nfserr_replay_cache) {
-                       status = nfsd4_replay_create_session(cr_ses, cs_slot);
-                       goto out_free_conn;
-               }
+       switch (status) {
+       case nfs_ok:
+               cs_slot->sl_seqid++;
+               cr_ses->seqid = cs_slot->sl_seqid;
+               break;
+       case nfserr_replay_cache:
+               status = nfsd4_replay_create_session(cr_ses, cs_slot);
+               fallthrough;
+       case nfserr_jukebox:
+               /* The server MUST NOT cache NFS4ERR_DELAY */
+               goto out_free_conn;
+       default:
                goto out_cache_error;
        }
-       cs_slot->sl_seqid++;
-       cr_ses->seqid = cs_slot->sl_seqid;
  
        /* RFC 8881 Section 18.36.4 Phase 3: Client ID confirmation. */
        if (conf) {
                old = find_confirmed_client_by_name(&unconf->cl_name, nn);
                if (old) {
                        status = mark_client_expired_locked(old);
-                       if (status) {
-                               old = NULL;
-                               goto out_cache_error;
-                       }
+                       if (status)
+                               goto out_expired_error;
                        trace_nfsd_clid_replaced(&old->cl_clientid);
                }
                move_to_confirmed(unconf);
                expire_client(old);
        return status;
  
+ out_expired_error:
+       old = NULL;
+       /*
+        * Revert the slot seq_nr change so the server will process
+        * the client's resend instead of returning a cached response.
+        */
+       if (status == nfserr_jukebox) {
+               cs_slot->sl_seqid--;
+               cr_ses->seqid = cs_slot->sl_seqid;
+               goto out_free_conn;
+       }
  out_cache_error:
        nfsd4_cache_create_session(cr_ses, cs_slot, status);
  out_free_conn:
@@@ -5189,9 -5203,9 +5203,9 @@@ static void nfsd_break_one_deleg(struc
  
  /* Called from break_lease() with flc_lock held. */
  static bool
 -nfsd_break_deleg_cb(struct file_lock *fl)
 +nfsd_break_deleg_cb(struct file_lease *fl)
  {
 -      struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner;
 +      struct nfs4_delegation *dp = (struct nfs4_delegation *) fl->c.flc_owner;
        struct nfs4_file *fp = dp->dl_stid.sc_file;
        struct nfs4_client *clp = dp->dl_stid.sc_client;
        struct nfsd_net *nn;
   *   %true: Lease conflict was resolved
   *   %false: Lease conflict was not resolved.
   */
 -static bool nfsd_breaker_owns_lease(struct file_lock *fl)
 +static bool nfsd_breaker_owns_lease(struct file_lease *fl)
  {
 -      struct nfs4_delegation *dl = fl->fl_owner;
 +      struct nfs4_delegation *dl = fl->c.flc_owner;
        struct svc_rqst *rqst;
        struct nfs4_client *clp;
  
  }
  
  static int
 -nfsd_change_deleg_cb(struct file_lock *onlist, int arg,
 +nfsd_change_deleg_cb(struct file_lease *onlist, int arg,
                     struct list_head *dispose)
  {
 -      struct nfs4_delegation *dp = (struct nfs4_delegation *)onlist->fl_owner;
 +      struct nfs4_delegation *dp = (struct nfs4_delegation *) onlist->c.flc_owner;
        struct nfs4_client *clp = dp->dl_stid.sc_client;
  
        if (arg & F_UNLCK) {
                return -EAGAIN;
  }
  
 -static const struct lock_manager_operations nfsd_lease_mng_ops = {
 +static const struct lease_manager_operations nfsd_lease_mng_ops = {
        .lm_breaker_owns_lease = nfsd_breaker_owns_lease,
        .lm_break = nfsd_break_deleg_cb,
        .lm_change = nfsd_change_deleg_cb,
@@@ -5601,20 -5615,21 +5615,20 @@@ static bool nfsd4_cb_channel_good(struc
        return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
  }
  
 -static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp,
 +static struct file_lease *nfs4_alloc_init_lease(struct nfs4_delegation *dp,
                                                int flag)
  {
 -      struct file_lock *fl;
 +      struct file_lease *fl;
  
 -      fl = locks_alloc_lock();
 +      fl = locks_alloc_lease();
        if (!fl)
                return NULL;
        fl->fl_lmops = &nfsd_lease_mng_ops;
 -      fl->fl_flags = FL_DELEG;
 -      fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
 -      fl->fl_end = OFFSET_MAX;
 -      fl->fl_owner = (fl_owner_t)dp;
 -      fl->fl_pid = current->tgid;
 -      fl->fl_file = dp->dl_stid.sc_file->fi_deleg_file->nf_file;
 +      fl->c.flc_flags = FL_DELEG;
 +      fl->c.flc_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
 +      fl->c.flc_owner = (fl_owner_t)dp;
 +      fl->c.flc_pid = current->tgid;
 +      fl->c.flc_file = dp->dl_stid.sc_file->fi_deleg_file->nf_file;
        return fl;
  }
  
@@@ -5732,7 -5747,7 +5746,7 @@@ nfs4_set_delegation(struct nfsd4_open *
        struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate;
        struct nfs4_delegation *dp;
        struct nfsd_file *nf = NULL;
 -      struct file_lock *fl;
 +      struct file_lease *fl;
        u32 dl_type;
  
        /*
        if (!fl)
                goto out_clnt_odstate;
  
 -      status = vfs_setlease(fp->fi_deleg_file->nf_file, fl->fl_type, &fl, NULL);
 +      status = kernel_setlease(fp->fi_deleg_file->nf_file,
 +                                    fl->c.flc_type, &fl, NULL);
        if (fl)
 -              locks_free_lock(fl);
 +              locks_free_lease(fl);
        if (status)
                goto out_clnt_odstate;
  
  
        return dp;
  out_unlock:
 -      vfs_setlease(fp->fi_deleg_file->nf_file, F_UNLCK, NULL, (void **)&dp);
 +      kernel_setlease(fp->fi_deleg_file->nf_file, F_UNLCK, NULL, (void **)&dp);
  out_clnt_odstate:
        put_clnt_odstate(dp->dl_clnt_odstate);
        nfs4_put_stid(&dp->dl_stid);
@@@ -7498,7 -7512,7 +7512,7 @@@ nfsd4_lm_put_owner(fl_owner_t owner
  static bool
  nfsd4_lm_lock_expirable(struct file_lock *cfl)
  {
 -      struct nfs4_lockowner *lo = (struct nfs4_lockowner *)cfl->fl_owner;
 +      struct nfs4_lockowner *lo = (struct nfs4_lockowner *) cfl->c.flc_owner;
        struct nfs4_client *clp = lo->lo_owner.so_client;
        struct nfsd_net *nn;
  
@@@ -7520,7 -7534,7 +7534,7 @@@ nfsd4_lm_expire_lock(void
  static void
  nfsd4_lm_notify(struct file_lock *fl)
  {
 -      struct nfs4_lockowner           *lo = (struct nfs4_lockowner *)fl->fl_owner;
 +      struct nfs4_lockowner           *lo = (struct nfs4_lockowner *) fl->c.flc_owner;
        struct net                      *net = lo->lo_owner.so_client->net;
        struct nfsd_net                 *nn = net_generic(net, nfsd_net_id);
        struct nfsd4_blocked_lock       *nbl = container_of(fl,
@@@ -7557,7 -7571,7 +7571,7 @@@ nfs4_set_lock_denied(struct file_lock *
        struct nfs4_lockowner *lo;
  
        if (fl->fl_lmops == &nfsd_posix_mng_ops) {
 -              lo = (struct nfs4_lockowner *) fl->fl_owner;
 +              lo = (struct nfs4_lockowner *) fl->c.flc_owner;
                xdr_netobj_dup(&deny->ld_owner, &lo->lo_owner.so_owner,
                                                GFP_KERNEL);
                if (!deny->ld_owner.data)
@@@ -7576,7 -7590,7 +7590,7 @@@ nevermind
        if (fl->fl_end != NFS4_MAX_UINT64)
                deny->ld_length = fl->fl_end - fl->fl_start + 1;        
        deny->ld_type = NFS4_READ_LT;
 -      if (fl->fl_type != F_RDLCK)
 +      if (fl->c.flc_type != F_RDLCK)
                deny->ld_type = NFS4_WRITE_LT;
  }
  
@@@ -7842,8 -7856,8 +7856,8 @@@ nfsd4_lock(struct svc_rqst *rqstp, stru
        int lkflg;
        int err;
        bool new = false;
 -      unsigned char fl_type;
 -      unsigned int fl_flags = FL_POSIX;
 +      unsigned char type;
 +      unsigned int flags = FL_POSIX;
        struct net *net = SVC_NET(rqstp);
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
  
                goto out;
  
        if (lock->lk_reclaim)
 -              fl_flags |= FL_RECLAIM;
 +              flags |= FL_RECLAIM;
  
        fp = lock_stp->st_stid.sc_file;
        switch (lock->lk_type) {
                case NFS4_READW_LT:
                        if (nfsd4_has_session(cstate) ||
                            exportfs_lock_op_is_async(sb->s_export_op))
 -                              fl_flags |= FL_SLEEP;
 +                              flags |= FL_SLEEP;
                        fallthrough;
                case NFS4_READ_LT:
                        spin_lock(&fp->fi_lock);
                        if (nf)
                                get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ);
                        spin_unlock(&fp->fi_lock);
 -                      fl_type = F_RDLCK;
 +                      type = F_RDLCK;
                        break;
                case NFS4_WRITEW_LT:
                        if (nfsd4_has_session(cstate) ||
                            exportfs_lock_op_is_async(sb->s_export_op))
 -                              fl_flags |= FL_SLEEP;
 +                              flags |= FL_SLEEP;
                        fallthrough;
                case NFS4_WRITE_LT:
                        spin_lock(&fp->fi_lock);
                        if (nf)
                                get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE);
                        spin_unlock(&fp->fi_lock);
 -                      fl_type = F_WRLCK;
 +                      type = F_WRLCK;
                        break;
                default:
                        status = nfserr_inval;
         * on those filesystems:
         */
        if (!exportfs_lock_op_is_async(sb->s_export_op))
 -              fl_flags &= ~FL_SLEEP;
 +              flags &= ~FL_SLEEP;
  
        nbl = find_or_allocate_block(lock_sop, &fp->fi_fhandle, nn);
        if (!nbl) {
        }
  
        file_lock = &nbl->nbl_lock;
 -      file_lock->fl_type = fl_type;
 -      file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner));
 -      file_lock->fl_pid = current->tgid;
 -      file_lock->fl_file = nf->nf_file;
 -      file_lock->fl_flags = fl_flags;
 +      file_lock->c.flc_type = type;
 +      file_lock->c.flc_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(&lock_sop->lo_owner));
 +      file_lock->c.flc_pid = current->tgid;
 +      file_lock->c.flc_file = nf->nf_file;
 +      file_lock->c.flc_flags = flags;
        file_lock->fl_lmops = &nfsd_posix_mng_ops;
        file_lock->fl_start = lock->lk_offset;
        file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length);
                goto out;
        }
  
 -      if (fl_flags & FL_SLEEP) {
 +      if (flags & FL_SLEEP) {
                nbl->nbl_time = ktime_get_boottime_seconds();
                spin_lock(&nn->blocked_locks_lock);
                list_add_tail(&nbl->nbl_list, &lock_sop->lo_blocked);
  out:
        if (nbl) {
                /* dequeue it if we queued it before */
 -              if (fl_flags & FL_SLEEP) {
 +              if (flags & FL_SLEEP) {
                        spin_lock(&nn->blocked_locks_lock);
                        if (!list_empty(&nbl->nbl_list) &&
                            !list_empty(&nbl->nbl_lru)) {
@@@ -8087,9 -8101,9 +8101,9 @@@ static __be32 nfsd_test_lock(struct svc
        err = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ));
        if (err)
                goto out;
 -      lock->fl_file = nf->nf_file;
 +      lock->c.flc_file = nf->nf_file;
        err = nfserrno(vfs_test_lock(nf->nf_file, lock));
 -      lock->fl_file = NULL;
 +      lock->c.flc_file = NULL;
  out:
        inode_unlock(inode);
        nfsd_file_put(nf);
@@@ -8134,11 -8148,11 +8148,11 @@@ nfsd4_lockt(struct svc_rqst *rqstp, str
        switch (lockt->lt_type) {
                case NFS4_READ_LT:
                case NFS4_READW_LT:
 -                      file_lock->fl_type = F_RDLCK;
 +                      file_lock->c.flc_type = F_RDLCK;
                        break;
                case NFS4_WRITE_LT:
                case NFS4_WRITEW_LT:
 -                      file_lock->fl_type = F_WRLCK;
 +                      file_lock->c.flc_type = F_WRLCK;
                        break;
                default:
                        dprintk("NFSD: nfs4_lockt: bad lock type!\n");
  
        lo = find_lockowner_str(cstate->clp, &lockt->lt_owner);
        if (lo)
 -              file_lock->fl_owner = (fl_owner_t)lo;
 -      file_lock->fl_pid = current->tgid;
 -      file_lock->fl_flags = FL_POSIX;
 +              file_lock->c.flc_owner = (fl_owner_t)lo;
 +      file_lock->c.flc_pid = current->tgid;
 +      file_lock->c.flc_flags = FL_POSIX;
  
        file_lock->fl_start = lockt->lt_offset;
        file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length);
        if (status)
                goto out;
  
 -      if (file_lock->fl_type != F_UNLCK) {
 +      if (file_lock->c.flc_type != F_UNLCK) {
                status = nfserr_denied;
                nfs4_set_lock_denied(file_lock, &lockt->lt_denied);
        }
@@@ -8217,11 -8231,11 +8231,11 @@@ nfsd4_locku(struct svc_rqst *rqstp, str
                goto put_file;
        }
  
 -      file_lock->fl_type = F_UNLCK;
 -      file_lock->fl_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner));
 -      file_lock->fl_pid = current->tgid;
 -      file_lock->fl_file = nf->nf_file;
 -      file_lock->fl_flags = FL_POSIX;
 +      file_lock->c.flc_type = F_UNLCK;
 +      file_lock->c.flc_owner = (fl_owner_t)lockowner(nfs4_get_stateowner(stp->st_stateowner));
 +      file_lock->c.flc_pid = current->tgid;
 +      file_lock->c.flc_file = nf->nf_file;
 +      file_lock->c.flc_flags = FL_POSIX;
        file_lock->fl_lmops = &nfsd_posix_mng_ops;
        file_lock->fl_start = locku->lu_offset;
  
@@@ -8278,8 -8292,8 +8292,8 @@@ check_for_locks(struct nfs4_file *fp, s
  
        if (flctx && !list_empty_careful(&flctx->flc_posix)) {
                spin_lock(&flctx->flc_lock);
 -              list_for_each_entry(fl, &flctx->flc_posix, fl_list) {
 -                      if (fl->fl_owner == (fl_owner_t)lowner) {
 +              for_each_file_lock(fl, &flctx->flc_posix) {
 +                      if (fl->c.flc_owner == (fl_owner_t)lowner) {
                                status = true;
                                break;
                        }
@@@ -8802,7 -8816,7 +8816,7 @@@ nfsd4_deleg_getattr_conflict(struct svc
        __be32 status;
        struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
        struct file_lock_context *ctx;
 -      struct file_lock *fl;
 +      struct file_lease *fl;
        struct nfs4_delegation *dp;
        struct iattr attrs;
        struct nfs4_cb_fattr *ncf;
        if (!ctx)
                return 0;
        spin_lock(&ctx->flc_lock);
 -      list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
 -              if (fl->fl_flags == FL_LAYOUT)
 +      for_each_file_lock(fl, &ctx->flc_lease) {
 +              unsigned char type = fl->c.flc_type;
 +
 +              if (fl->c.flc_flags == FL_LAYOUT)
                        continue;
                if (fl->fl_lmops != &nfsd_lease_mng_ops) {
                        /*
                         * we are done; there isn't any write delegation
                         * on this inode
                         */
 -                      if (fl->fl_type == F_RDLCK)
 +                      if (type == F_RDLCK)
                                break;
                        goto break_lease;
                }
 -              if (fl->fl_type == F_WRLCK) {
 -                      dp = fl->fl_owner;
 +              if (type == F_WRLCK) {
 +                      dp = fl->c.flc_owner;
                        if (dp->dl_recall.cb_clp == *(rqstp->rq_lease_breaker)) {
                                spin_unlock(&ctx->flc_lock);
                                return 0;
                        }
  break_lease:
                        nfsd_stats_wdeleg_getattr_inc(nn);
 -                      dp = fl->fl_owner;
 +                      dp = fl->c.flc_owner;
                        ncf = &dp->dl_cb_fattr;
                        nfs4_cb_getattr(&dp->dl_cb_fattr);
                        spin_unlock(&ctx->flc_lock);
diff --combined fs/nfsd/vfs.c
index 6a9464262fae6bea461c4764ce98c53ca20f9754,daf5221ef922606cc378ecc178a8411a7256aaa8..2e41eb4c3cec76f00227f5f689bda39430a90b04
@@@ -25,6 -25,7 +25,6 @@@
  #include <linux/posix_acl_xattr.h>
  #include <linux/xattr.h>
  #include <linux/jhash.h>
 -#include <linux/ima.h>
  #include <linux/pagemap.h>
  #include <linux/slab.h>
  #include <linux/uaccess.h>
@@@ -894,7 -895,7 +894,7 @@@ __nfsd_open(struct svc_rqst *rqstp, str
                goto out;
        }
  
 -      host_err = ima_file_check(file, may_flags);
 +      host_err = security_file_post_open(file, may_flags);
        if (host_err) {
                fput(file);
                goto out;
@@@ -1852,7 -1853,7 +1852,7 @@@ retry
        trap = lock_rename(tdentry, fdentry);
        if (IS_ERR(trap)) {
                err = (rqstp->rq_vers == 2) ? nfserr_acces : nfserr_xdev;
-               goto out;
+               goto out_want_write;
        }
        err = fh_fill_pre_attrs(ffhp);
        if (err != nfs_ok)
        }
  out_unlock:
        unlock_rename(tdentry, fdentry);
+ out_want_write:
        fh_drop_write(ffhp);
  
        /*