Merge tag 'nfs-for-4.19-2' of git://git.linux-nfs.org/projects/anna/linux-nfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 15 Sep 2018 05:25:28 +0000 (19:25 -1000)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 15 Sep 2018 05:25:28 +0000 (19:25 -1000)
Pull NFS client bugfixes from Anna Schumaker:
 "These are a handful of fixes for problems that Trond found. Patch #1
  and #3 have the same name, a second issue was found after applying the
  first patch.

  Stable bugfixes:
   - v4.17+: Fix tracepoint Oops in initiate_file_draining()
   - v4.11+: Fix an infinite loop on I/O

  Other fixes:
   - Return errors if a waiting layoutget is killed
   - Don't open code clearing of delegation state"

* tag 'nfs-for-4.19-2' of git://git.linux-nfs.org/projects/anna/linux-nfs:
  NFS: Don't open code clearing of delegation state
  NFSv4.1 fix infinite loop on I/O.
  NFSv4: Fix a tracepoint Oops in initiate_file_draining()
  pNFS: Ensure we return the error if someone kills a waiting layoutget
  NFSv4: Fix a tracepoint Oops in initiate_file_draining()

1  2 
fs/nfs/nfs4proc.c

diff --combined fs/nfs/nfs4proc.c
@@@ -1637,6 -1637,14 +1637,14 @@@ static void nfs_state_set_delegation(st
        write_sequnlock(&state->seqlock);
  }
  
+ static void nfs_state_clear_delegation(struct nfs4_state *state)
+ {
+       write_seqlock(&state->seqlock);
+       nfs4_stateid_copy(&state->stateid, &state->open_stateid);
+       clear_bit(NFS_DELEGATED_STATE, &state->flags);
+       write_sequnlock(&state->seqlock);
+ }
  static int update_open_stateid(struct nfs4_state *state,
                const nfs4_stateid *open_stateid,
                const nfs4_stateid *delegation,
@@@ -2145,10 -2153,7 +2153,7 @@@ int nfs4_open_delegation_recall(struct 
        if (IS_ERR(opendata))
                return PTR_ERR(opendata);
        nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid);
-       write_seqlock(&state->seqlock);
-       nfs4_stateid_copy(&state->stateid, &state->open_stateid);
-       write_sequnlock(&state->seqlock);
-       clear_bit(NFS_DELEGATED_STATE, &state->flags);
+       nfs_state_clear_delegation(state);
        switch (type & (FMODE_READ|FMODE_WRITE)) {
        case FMODE_READ|FMODE_WRITE:
        case FMODE_WRITE:
@@@ -2601,10 -2606,7 +2606,7 @@@ static void nfs_finish_clear_delegation
                const nfs4_stateid *stateid)
  {
        nfs_remove_bad_delegation(state->inode, stateid);
-       write_seqlock(&state->seqlock);
-       nfs4_stateid_copy(&state->stateid, &state->open_stateid);
-       write_sequnlock(&state->seqlock);
-       clear_bit(NFS_DELEGATED_STATE, &state->flags);
+       nfs_state_clear_delegation(state);
  }
  
  static void nfs40_clear_delegation_stateid(struct nfs4_state *state)
@@@ -2672,15 -2674,20 +2674,20 @@@ static void nfs41_check_delegation_stat
        delegation = rcu_dereference(NFS_I(state->inode)->delegation);
        if (delegation == NULL) {
                rcu_read_unlock();
+               nfs_state_clear_delegation(state);
                return;
        }
  
        nfs4_stateid_copy(&stateid, &delegation->stateid);
-       if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) ||
-               !test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED,
-                       &delegation->flags)) {
+       if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) {
+               rcu_read_unlock();
+               nfs_state_clear_delegation(state);
+               return;
+       }
+       if (!test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED,
+                               &delegation->flags)) {
                rcu_read_unlock();
-               nfs_finish_clear_delegation_stateid(state, &stateid);
                return;
        }
  
@@@ -2993,7 -3000,7 +3000,7 @@@ static int _nfs4_do_open(struct inode *
                }
        }
        if (opened && opendata->file_created)
 -              *opened |= FILE_CREATED;
 +              *opened = 1;
  
        if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server)) {
                *ctx_th = opendata->f_attr.mdsthreshold;
@@@ -6568,34 -6575,34 +6575,34 @@@ static void nfs4_lock_done(struct rpc_t
                if (data->arg.new_lock && !data->cancelled) {
                        data->fl.fl_flags &= ~(FL_SLEEP | FL_ACCESS);
                        if (locks_lock_inode_wait(lsp->ls_state->inode, &data->fl) < 0)
 -                              break;
 +                              goto out_restart;
                }
 -
                if (data->arg.new_lock_owner != 0) {
                        nfs_confirm_seqid(&lsp->ls_seqid, 0);
                        nfs4_stateid_copy(&lsp->ls_stateid, &data->res.stateid);
                        set_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags);
 -                      goto out_done;
 -              } else if (nfs4_update_lock_stateid(lsp, &data->res.stateid))
 -                      goto out_done;
 -
 +              } else if (!nfs4_update_lock_stateid(lsp, &data->res.stateid))
 +                      goto out_restart;
                break;
        case -NFS4ERR_BAD_STATEID:
        case -NFS4ERR_OLD_STATEID:
        case -NFS4ERR_STALE_STATEID:
        case -NFS4ERR_EXPIRED:
                if (data->arg.new_lock_owner != 0) {
 -                      if (nfs4_stateid_match(&data->arg.open_stateid,
 +                      if (!nfs4_stateid_match(&data->arg.open_stateid,
                                                &lsp->ls_state->open_stateid))
 -                              goto out_done;
 -              } else if (nfs4_stateid_match(&data->arg.lock_stateid,
 +                              goto out_restart;
 +              } else if (!nfs4_stateid_match(&data->arg.lock_stateid,
                                                &lsp->ls_stateid))
 -                              goto out_done;
 +                              goto out_restart;
        }
 -      if (!data->cancelled)
 -              rpc_restart_call_prepare(task);
  out_done:
        dprintk("%s: done, ret = %d!\n", __func__, data->rpc_status);
 +      return;
 +out_restart:
 +      if (!data->cancelled)
 +              rpc_restart_call_prepare(task);
 +      goto out_done;
  }
  
  static void nfs4_lock_release(void *calldata)
  
        dprintk("%s: begin!\n", __func__);
        nfs_free_seqid(data->arg.open_seqid);
 -      if (data->cancelled) {
 +      if (data->cancelled && data->rpc_status == 0) {
                struct rpc_task *task;
                task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp,
                                data->arg.lock_seqid);