]> Git Repo - linux.git/commitdiff
Merge tag 'nfs-for-4.9-4' of git://git.linux-nfs.org/projects/anna/linux-nfs
authorLinus Torvalds <[email protected]>
Wed, 23 Nov 2016 22:43:40 +0000 (14:43 -0800)
committerLinus Torvalds <[email protected]>
Wed, 23 Nov 2016 22:43:40 +0000 (14:43 -0800)
Pull NFS client bugfixes from Anna Schumaker:
 "Most of these fix regressions or races, but there is one patch for
  stable that Arnd sent me

  Stable bugfix:
   - Hide array-bounds warning

  Bugfixes:
   - Keep a reference on lock states while checking
   - Handle NFS4ERR_OLD_STATEID in nfs4_reclaim_open_state
   - Don't call close if the open stateid has already been cleared
   - Fix CLOSE rases with OPEN
   - Fix a regression in DELEGRETURN"

* tag 'nfs-for-4.9-4' of git://git.linux-nfs.org/projects/anna/linux-nfs:
  NFSv4.x: hide array-bounds warning
  NFSv4.1: Keep a reference on lock states while checking
  NFSv4.1: Handle NFS4ERR_OLD_STATEID in nfs4_reclaim_open_state
  NFSv4: Don't call close if the open stateid has already been cleared
  NFSv4: Fix CLOSE races with OPEN
  NFSv4.1: Fix a regression in DELEGRETURN

1  2 
fs/nfs/nfs4proc.c

diff --combined fs/nfs/nfs4proc.c
index 7897826d7c51bb33f3459939cdb9cac6ab4e9178,e6dc95e0f97e71b7b17371a15a3c33a33592fd1e..241da19b7da4a54a45b1a2bd6cae4cab8cab4dde
@@@ -1451,7 -1451,6 +1451,6 @@@ static void nfs_resync_open_stateid_loc
  }
  
  static void nfs_clear_open_stateid_locked(struct nfs4_state *state,
-               nfs4_stateid *arg_stateid,
                nfs4_stateid *stateid, fmode_t fmode)
  {
        clear_bit(NFS_O_RDWR_STATE, &state->flags);
        }
        if (stateid == NULL)
                return;
-       /* Handle races with OPEN */
-       if (!nfs4_stateid_match_other(arg_stateid, &state->open_stateid) ||
-           (nfs4_stateid_match_other(stateid, &state->open_stateid) &&
-           !nfs4_stateid_is_newer(stateid, &state->open_stateid))) {
+       /* Handle OPEN+OPEN_DOWNGRADE races */
+       if (nfs4_stateid_match_other(stateid, &state->open_stateid) &&
+           !nfs4_stateid_is_newer(stateid, &state->open_stateid)) {
                nfs_resync_open_stateid_locked(state);
                return;
        }
@@@ -1486,7 -1484,9 +1484,9 @@@ static void nfs_clear_open_stateid(stru
        nfs4_stateid *stateid, fmode_t fmode)
  {
        write_seqlock(&state->seqlock);
-       nfs_clear_open_stateid_locked(state, arg_stateid, stateid, fmode);
+       /* Ignore, if the CLOSE argment doesn't match the current stateid */
+       if (nfs4_state_match_open_stateid_other(state, arg_stateid))
+               nfs_clear_open_stateid_locked(state, stateid, fmode);
        write_sequnlock(&state->seqlock);
        if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags))
                nfs4_schedule_state_manager(state->owner->so_server->nfs_client);
@@@ -2564,15 -2564,23 +2564,23 @@@ static void nfs41_check_delegation_stat
  static int nfs41_check_expired_locks(struct nfs4_state *state)
  {
        int status, ret = NFS_OK;
-       struct nfs4_lock_state *lsp;
+       struct nfs4_lock_state *lsp, *prev = NULL;
        struct nfs_server *server = NFS_SERVER(state->inode);
  
        if (!test_bit(LK_STATE_IN_USE, &state->flags))
                goto out;
+       spin_lock(&state->state_lock);
        list_for_each_entry(lsp, &state->lock_states, ls_locks) {
                if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
                        struct rpc_cred *cred = lsp->ls_state->owner->so_cred;
  
+                       atomic_inc(&lsp->ls_count);
+                       spin_unlock(&state->state_lock);
+                       nfs4_put_lock_state(prev);
+                       prev = lsp;
                        status = nfs41_test_and_free_expired_stateid(server,
                                        &lsp->ls_stateid,
                                        cred);
                                        set_bit(NFS_LOCK_LOST, &lsp->ls_flags);
                        } else if (status != NFS_OK) {
                                ret = status;
-                               break;
+                               nfs4_put_lock_state(prev);
+                               goto out;
                        }
+                       spin_lock(&state->state_lock);
                }
-       };
+       }
+       spin_unlock(&state->state_lock);
+       nfs4_put_lock_state(prev);
  out:
        return ret;
  }
@@@ -3122,7 -3134,8 +3134,8 @@@ static void nfs4_close_prepare(struct r
        } else if (is_rdwr)
                calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;
  
-       if (!nfs4_valid_open_stateid(state))
+       if (!nfs4_valid_open_stateid(state) ||
+           test_bit(NFS_OPEN_STATE, &state->flags) == 0)
                call_close = 0;
        spin_unlock(&state->owner->so_lock);
  
@@@ -5569,6 -5582,7 +5582,7 @@@ static void nfs4_delegreturn_done(struc
        switch (task->tk_status) {
        case 0:
                renew_lease(data->res.server, data->timestamp);
+               break;
        case -NFS4ERR_ADMIN_REVOKED:
        case -NFS4ERR_DELEG_REVOKED:
        case -NFS4ERR_EXPIRED:
        case -NFS4ERR_OLD_STATEID:
        case -NFS4ERR_STALE_STATEID:
                task->tk_status = 0;
-               if (data->roc)
-                       pnfs_roc_set_barrier(data->inode, data->roc_barrier);
                break;
        default:
                if (nfs4_async_handle_error(task, data->res.server,
                }
        }
        data->rpc_status = task->tk_status;
+       if (data->roc && data->rpc_status == 0)
+               pnfs_roc_set_barrier(data->inode, data->roc_barrier);
  }
  
  static void nfs4_delegreturn_release(void *calldata)
@@@ -9306,14 -9320,20 +9320,14 @@@ static const struct inode_operations nf
        .permission     = nfs_permission,
        .getattr        = nfs_getattr,
        .setattr        = nfs_setattr,
 -      .getxattr       = generic_getxattr,
 -      .setxattr       = generic_setxattr,
        .listxattr      = nfs4_listxattr,
 -      .removexattr    = generic_removexattr,
  };
  
  static const struct inode_operations nfs4_file_inode_operations = {
        .permission     = nfs_permission,
        .getattr        = nfs_getattr,
        .setattr        = nfs_setattr,
 -      .getxattr       = generic_getxattr,
 -      .setxattr       = generic_setxattr,
        .listxattr      = nfs4_listxattr,
 -      .removexattr    = generic_removexattr,
  };
  
  const struct nfs_rpc_ops nfs_v4_clientops = {
This page took 0.076047 seconds and 4 git commands to generate.