NFS: Fix another OPEN_DOWNGRADE bug
[firefly-linux-kernel-4.4.55.git] / fs / nfs / nfs4proc.c
index 89818036f035b01eaaa4e45797205d53f48e9934..fc215ab4dcd51a6d879da5dbcabf3710b4dd281e 100644 (file)
@@ -1385,6 +1385,7 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s
         * Protect the call to nfs4_state_set_mode_locked and
         * serialise the stateid update
         */
+       spin_lock(&state->owner->so_lock);
        write_seqlock(&state->seqlock);
        if (deleg_stateid != NULL) {
                nfs4_stateid_copy(&state->stateid, deleg_stateid);
@@ -1393,7 +1394,6 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s
        if (open_stateid != NULL)
                nfs_set_open_stateid_locked(state, open_stateid, fmode);
        write_sequnlock(&state->seqlock);
-       spin_lock(&state->owner->so_lock);
        update_open_stateflags(state, fmode);
        spin_unlock(&state->owner->so_lock);
 }
@@ -2461,9 +2461,9 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
                dentry = d_add_unique(dentry, igrab(state->inode));
                if (dentry == NULL) {
                        dentry = opendata->dentry;
-               } else if (dentry != ctx->dentry) {
+               } else {
                        dput(ctx->dentry);
-                       ctx->dentry = dget(dentry);
+                       ctx->dentry = dentry;
                }
                nfs_set_verifier(dentry,
                                nfs_save_change_attribute(d_inode(opendata->dir)));
@@ -2854,12 +2854,11 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
                        call_close |= is_wronly;
                else if (is_wronly)
                        calldata->arg.fmode |= FMODE_WRITE;
+               if (calldata->arg.fmode != (FMODE_READ|FMODE_WRITE))
+                       call_close |= is_rdwr;
        } else if (is_rdwr)
                calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;
 
-       if (calldata->arg.fmode == 0)
-               call_close |= is_rdwr;
-
        if (!nfs4_valid_open_stateid(state))
                call_close = 0;
        spin_unlock(&state->owner->so_lock);
@@ -8054,7 +8053,6 @@ static void nfs4_layoutreturn_release(void *calldata)
                pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
        pnfs_mark_matching_lsegs_invalid(lo, &freeme, &lrp->args.range);
        pnfs_clear_layoutreturn_waitbit(lo);
-       lo->plh_block_lgets--;
        spin_unlock(&lo->plh_inode->i_lock);
        pnfs_free_lseg_list(&freeme);
        pnfs_put_layout_hdr(lrp->args.layout);