Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target...
[firefly-linux-kernel-4.4.55.git] / fs / nfs / nfs4proc.c
index c347705b016104de8b0360f163e87c19d9b4d78c..2e7c9f7a6f7cc8369bfcefda7a202d34f7a9dbe5 100644 (file)
@@ -495,12 +495,11 @@ static void nfs4_set_sequence_privileged(struct nfs4_sequence_args *args)
        args->sa_privileged = 1;
 }
 
-static int nfs40_setup_sequence(const struct nfs_server *server,
-                               struct nfs4_sequence_args *args,
-                               struct nfs4_sequence_res *res,
-                               struct rpc_task *task)
+int nfs40_setup_sequence(struct nfs4_slot_table *tbl,
+                        struct nfs4_sequence_args *args,
+                        struct nfs4_sequence_res *res,
+                        struct rpc_task *task)
 {
-       struct nfs4_slot_table *tbl = server->nfs_client->cl_slot_tbl;
        struct nfs4_slot *slot;
 
        /* slot already allocated? */
@@ -535,6 +534,7 @@ out_sleep:
        spin_unlock(&tbl->slot_tbl_lock);
        return -EAGAIN;
 }
+EXPORT_SYMBOL_GPL(nfs40_setup_sequence);
 
 static int nfs40_sequence_done(struct rpc_task *task,
                               struct nfs4_sequence_res *res)
@@ -694,8 +694,7 @@ out_retry:
 }
 EXPORT_SYMBOL_GPL(nfs41_sequence_done);
 
-static int nfs4_sequence_done(struct rpc_task *task,
-                              struct nfs4_sequence_res *res)
+int nfs4_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
 {
        if (res->sr_slot == NULL)
                return 1;
@@ -703,6 +702,7 @@ static int nfs4_sequence_done(struct rpc_task *task,
                return nfs40_sequence_done(task, res);
        return nfs41_sequence_done(task, res);
 }
+EXPORT_SYMBOL_GPL(nfs4_sequence_done);
 
 int nfs41_setup_sequence(struct nfs4_session *session,
                                struct nfs4_sequence_args *args,
@@ -777,7 +777,8 @@ static int nfs4_setup_sequence(const struct nfs_server *server,
        int ret = 0;
 
        if (!session)
-               return nfs40_setup_sequence(server, args, res, task);
+               return nfs40_setup_sequence(server->nfs_client->cl_slot_tbl,
+                                           args, res, task);
 
        dprintk("--> %s clp %p session %p sr_slot %u\n",
                __func__, session->clp, session, res->sr_slot ?
@@ -818,14 +819,16 @@ static int nfs4_setup_sequence(const struct nfs_server *server,
                               struct nfs4_sequence_res *res,
                               struct rpc_task *task)
 {
-       return nfs40_setup_sequence(server, args, res, task);
+       return nfs40_setup_sequence(server->nfs_client->cl_slot_tbl,
+                                   args, res, task);
 }
 
-static int nfs4_sequence_done(struct rpc_task *task,
-                              struct nfs4_sequence_res *res)
+int nfs4_sequence_done(struct rpc_task *task,
+                      struct nfs4_sequence_res *res)
 {
        return nfs40_sequence_done(task, res);
 }
+EXPORT_SYMBOL_GPL(nfs4_sequence_done);
 
 #endif /* !CONFIG_NFS_V4_1 */
 
@@ -937,6 +940,31 @@ static bool nfs4_clear_cap_atomic_open_v1(struct nfs_server *server,
        return true;
 }
 
+static u32
+nfs4_map_atomic_open_share(struct nfs_server *server,
+               fmode_t fmode, int openflags)
+{
+       u32 res = 0;
+
+       switch (fmode & (FMODE_READ | FMODE_WRITE)) {
+       case FMODE_READ:
+               res = NFS4_SHARE_ACCESS_READ;
+               break;
+       case FMODE_WRITE:
+               res = NFS4_SHARE_ACCESS_WRITE;
+               break;
+       case FMODE_READ|FMODE_WRITE:
+               res = NFS4_SHARE_ACCESS_BOTH;
+       }
+       if (!(server->caps & NFS_CAP_ATOMIC_OPEN_V1))
+               goto out;
+       /* Want no delegation if we're using O_DIRECT */
+       if (openflags & O_DIRECT)
+               res |= NFS4_SHARE_WANT_NO_DELEG;
+out:
+       return res;
+}
+
 static enum open_claim_type4
 nfs4_map_atomic_open_claim(struct nfs_server *server,
                enum open_claim_type4 claim)
@@ -977,6 +1005,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
        struct dentry *parent = dget_parent(dentry);
        struct inode *dir = parent->d_inode;
        struct nfs_server *server = NFS_SERVER(dir);
+       struct nfs_seqid *(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
        struct nfs4_opendata *p;
 
        p = kzalloc(sizeof(*p), gfp_mask);
@@ -987,8 +1016,9 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
        if (IS_ERR(p->f_label))
                goto err_free_p;
 
-       p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask);
-       if (p->o_arg.seqid == NULL)
+       alloc_seqid = server->nfs_client->cl_mvops->alloc_seqid;
+       p->o_arg.seqid = alloc_seqid(&sp->so_seqid, gfp_mask);
+       if (IS_ERR(p->o_arg.seqid))
                goto err_free_label;
        nfs_sb_active(dentry->d_sb);
        p->dentry = dget(dentry);
@@ -997,6 +1027,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
        atomic_inc(&sp->so_count);
        p->o_arg.open_flags = flags;
        p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
+       p->o_arg.share_access = nfs4_map_atomic_open_share(server,
+                       fmode, flags);
        /* don't put an ACCESS op in OPEN compound if O_EXCL, because ACCESS
         * will return permission denied for all bits until close */
        if (!(flags & O_EXCL)) {
@@ -1167,6 +1199,16 @@ static bool nfs_need_update_open_stateid(struct nfs4_state *state,
        return false;
 }
 
+static void nfs_resync_open_stateid_locked(struct nfs4_state *state)
+{
+       if (state->n_wronly)
+               set_bit(NFS_O_WRONLY_STATE, &state->flags);
+       if (state->n_rdonly)
+               set_bit(NFS_O_RDONLY_STATE, &state->flags);
+       if (state->n_rdwr)
+               set_bit(NFS_O_RDWR_STATE, &state->flags);
+}
+
 static void nfs_clear_open_stateid_locked(struct nfs4_state *state,
                nfs4_stateid *stateid, fmode_t fmode)
 {
@@ -1185,8 +1227,12 @@ static void nfs_clear_open_stateid_locked(struct nfs4_state *state,
        }
        if (stateid == NULL)
                return;
-       if (!nfs_need_update_open_stateid(state, stateid))
+       /* Handle races with OPEN */
+       if (!nfs4_stateid_match_other(stateid, &state->open_stateid) ||
+           !nfs4_stateid_is_newer(stateid, &state->open_stateid)) {
+               nfs_resync_open_stateid_locked(state);
                return;
+       }
        if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
                nfs4_stateid_copy(&state->stateid, stateid);
        nfs4_stateid_copy(&state->open_stateid, stateid);
@@ -1281,6 +1327,23 @@ no_delegation:
        return ret;
 }
 
+static bool nfs4_update_lock_stateid(struct nfs4_lock_state *lsp,
+               const nfs4_stateid *stateid)
+{
+       struct nfs4_state *state = lsp->ls_state;
+       bool ret = false;
+
+       spin_lock(&state->state_lock);
+       if (!nfs4_stateid_match_other(stateid, &lsp->ls_stateid))
+               goto out_noupdate;
+       if (!nfs4_stateid_is_newer(stateid, &lsp->ls_stateid))
+               goto out_noupdate;
+       nfs4_stateid_copy(&lsp->ls_stateid, stateid);
+       ret = true;
+out_noupdate:
+       spin_unlock(&state->state_lock);
+       return ret;
+}
 
 static void nfs4_return_incompatible_delegation(struct inode *inode, fmode_t fmode)
 {
@@ -1679,8 +1742,8 @@ static void nfs4_open_confirm_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs4_opendata *data = calldata;
 
-       nfs40_setup_sequence(data->o_arg.server, &data->c_arg.seq_args,
-                               &data->c_res.seq_res, task);
+       nfs40_setup_sequence(data->o_arg.server->nfs_client->cl_slot_tbl,
+                            &data->c_arg.seq_args, &data->c_res.seq_res, task);
 }
 
 static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata)
@@ -2587,6 +2650,11 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
                case -NFS4ERR_OLD_STATEID:
                case -NFS4ERR_BAD_STATEID:
                case -NFS4ERR_EXPIRED:
+                       if (!nfs4_stateid_match(&calldata->arg.stateid,
+                                               &state->stateid)) {
+                               rpc_restart_call_prepare(task);
+                               goto out_release;
+                       }
                        if (calldata->arg.fmode == 0)
                                break;
                default:
@@ -2619,6 +2687,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
        is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags);
        is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags);
        is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags);
+       nfs4_stateid_copy(&calldata->arg.stateid, &state->stateid);
        /* Calculate the change in open mode */
        calldata->arg.fmode = 0;
        if (state->n_rdwr == 0) {
@@ -2653,6 +2722,9 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
                        goto out_wait;
                    }
        }
+       calldata->arg.share_access =
+               nfs4_map_atomic_open_share(NFS_SERVER(inode),
+                               calldata->arg.fmode, 0);
 
        nfs_fattr_init(calldata->res.fattr);
        calldata->timestamp = jiffies;
@@ -2675,45 +2747,10 @@ static const struct rpc_call_ops nfs4_close_ops = {
        .rpc_release = nfs4_free_closedata,
 };
 
-static bool nfs4_state_has_opener(struct nfs4_state *state)
-{
-       /* first check existing openers */
-       if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0 &&
-           state->n_rdonly != 0)
-               return true;
-
-       if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0 &&
-           state->n_wronly != 0)
-               return true;
-
-       if (test_bit(NFS_O_RDWR_STATE, &state->flags) != 0 &&
-           state->n_rdwr != 0)
-               return true;
-
-       return false;
-}
-
 static bool nfs4_roc(struct inode *inode)
 {
-       struct nfs_inode *nfsi = NFS_I(inode);
-       struct nfs_open_context *ctx;
-       struct nfs4_state *state;
-
-       spin_lock(&inode->i_lock);
-       list_for_each_entry(ctx, &nfsi->open_files, list) {
-               state = ctx->state;
-               if (state == NULL)
-                       continue;
-               if (nfs4_state_has_opener(state)) {
-                       spin_unlock(&inode->i_lock);
-                       return false;
-               }
-       }
-       spin_unlock(&inode->i_lock);
-
-       if (nfs4_check_delegation(inode, FMODE_READ))
+       if (!nfs_have_layout(inode))
                return false;
-
        return pnfs_roc(inode);
 }
 
@@ -2731,6 +2768,7 @@ static bool nfs4_roc(struct inode *inode)
 int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
 {
        struct nfs_server *server = NFS_SERVER(state->inode);
+       struct nfs_seqid *(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
        struct nfs4_closedata *calldata;
        struct nfs4_state_owner *sp = state->owner;
        struct rpc_task *task;
@@ -2757,10 +2795,10 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
        calldata->inode = state->inode;
        calldata->state = state;
        calldata->arg.fh = NFS_FH(state->inode);
-       calldata->arg.stateid = &state->open_stateid;
        /* Serialization for the sequence id */
-       calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid, gfp_mask);
-       if (calldata->arg.seqid == NULL)
+       alloc_seqid = server->nfs_client->cl_mvops->alloc_seqid;
+       calldata->arg.seqid = alloc_seqid(&state->owner->so_seqid, gfp_mask);
+       if (IS_ERR(calldata->arg.seqid))
                goto out_free_calldata;
        calldata->arg.fmode = 0;
        calldata->arg.bitmask = server->cache_consistency_bitmask;
@@ -5137,9 +5175,13 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
 static void nfs4_delegreturn_release(void *calldata)
 {
        struct nfs4_delegreturndata *data = calldata;
+       struct inode *inode = data->inode;
 
-       if (data->roc)
-               pnfs_roc_release(data->inode);
+       if (inode) {
+               if (data->roc)
+                       pnfs_roc_release(inode);
+               nfs_iput_and_deactive(inode);
+       }
        kfree(calldata);
 }
 
@@ -5196,9 +5238,9 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
        nfs_fattr_init(data->res.fattr);
        data->timestamp = jiffies;
        data->rpc_status = 0;
-       data->inode = inode;
-       data->roc = list_empty(&NFS_I(inode)->open_files) ?
-                   pnfs_roc(inode) : false;
+       data->inode = nfs_igrab_and_active(inode);
+       if (data->inode)
+               data->roc = nfs4_roc(inode);
 
        task_setup_data.callback_data = data;
        msg.rpc_argp = &data->args;
@@ -5353,7 +5395,6 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
        p->arg.fl = &p->fl;
        p->arg.seqid = seqid;
        p->res.seqid = seqid;
-       p->arg.stateid = &lsp->ls_stateid;
        p->lsp = lsp;
        atomic_inc(&lsp->ls_count);
        /* Ensure we don't close file until we're done freeing locks! */
@@ -5380,14 +5421,18 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
                return;
        switch (task->tk_status) {
                case 0:
-                       nfs4_stateid_copy(&calldata->lsp->ls_stateid,
-                                       &calldata->res.stateid);
                        renew_lease(calldata->server, calldata->timestamp);
-                       break;
+                       do_vfs_lock(calldata->fl.fl_file, &calldata->fl);
+                       if (nfs4_update_lock_stateid(calldata->lsp,
+                                       &calldata->res.stateid))
+                               break;
                case -NFS4ERR_BAD_STATEID:
                case -NFS4ERR_OLD_STATEID:
                case -NFS4ERR_STALE_STATEID:
                case -NFS4ERR_EXPIRED:
+                       if (!nfs4_stateid_match(&calldata->arg.stateid,
+                                               &calldata->lsp->ls_stateid))
+                               rpc_restart_call_prepare(task);
                        break;
                default:
                        if (nfs4_async_handle_error(task, calldata->server,
@@ -5403,6 +5448,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
 
        if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
                goto out_wait;
+       nfs4_stateid_copy(&calldata->arg.stateid, &calldata->lsp->ls_stateid);
        if (test_bit(NFS_LOCK_INITIALIZED, &calldata->lsp->ls_flags) == 0) {
                /* Note: exit _without_ running nfs4_locku_done */
                goto out_no_action;
@@ -5473,6 +5519,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
        struct nfs_seqid *seqid;
        struct nfs4_lock_state *lsp;
        struct rpc_task *task;
+       struct nfs_seqid *(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
        int status = 0;
        unsigned char fl_flags = request->fl_flags;
 
@@ -5496,9 +5543,10 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
        lsp = request->fl_u.nfs4_fl.owner;
        if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) == 0)
                goto out;
-       seqid = nfs_alloc_seqid(&lsp->ls_seqid, GFP_KERNEL);
+       alloc_seqid = NFS_SERVER(inode)->nfs_client->cl_mvops->alloc_seqid;
+       seqid = alloc_seqid(&lsp->ls_seqid, GFP_KERNEL);
        status = -ENOMEM;
-       if (seqid == NULL)
+       if (IS_ERR(seqid))
                goto out;
        task = nfs4_do_unlck(request, nfs_file_open_context(request->fl_file), lsp, seqid);
        status = PTR_ERR(task);
@@ -5531,6 +5579,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
        struct nfs4_lockdata *p;
        struct inode *inode = lsp->ls_state->inode;
        struct nfs_server *server = NFS_SERVER(inode);
+       struct nfs_seqid *(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
 
        p = kzalloc(sizeof(*p), gfp_mask);
        if (p == NULL)
@@ -5539,12 +5588,12 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
        p->arg.fh = NFS_FH(inode);
        p->arg.fl = &p->fl;
        p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid, gfp_mask);
-       if (p->arg.open_seqid == NULL)
+       if (IS_ERR(p->arg.open_seqid))
                goto out_free;
-       p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid, gfp_mask);
-       if (p->arg.lock_seqid == NULL)
+       alloc_seqid = server->nfs_client->cl_mvops->alloc_seqid;
+       p->arg.lock_seqid = alloc_seqid(&lsp->ls_seqid, gfp_mask);
+       if (IS_ERR(p->arg.lock_seqid))
                goto out_free_seqid;
-       p->arg.lock_stateid = &lsp->ls_stateid;
        p->arg.lock_owner.clientid = server->nfs_client->cl_clientid;
        p->arg.lock_owner.id = lsp->ls_seqid.owner_id;
        p->arg.lock_owner.s_dev = server->s_dev;
@@ -5571,15 +5620,19 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
        if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0)
                goto out_wait;
        /* Do we need to do an open_to_lock_owner? */
-       if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) {
+       if (!test_bit(NFS_LOCK_INITIALIZED, &data->lsp->ls_flags)) {
                if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) {
                        goto out_release_lock_seqid;
                }
-               data->arg.open_stateid = &state->open_stateid;
+               nfs4_stateid_copy(&data->arg.open_stateid,
+                               &state->open_stateid);
                data->arg.new_lock_owner = 1;
                data->res.open_seqid = data->arg.open_seqid;
-       } else
+       } else {
                data->arg.new_lock_owner = 0;
+               nfs4_stateid_copy(&data->arg.lock_stateid,
+                               &data->lsp->ls_stateid);
+       }
        if (!nfs4_valid_open_stateid(state)) {
                data->rpc_status = -EBADF;
                task->tk_action = NULL;
@@ -5603,6 +5656,7 @@ out_wait:
 static void nfs4_lock_done(struct rpc_task *task, void *calldata)
 {
        struct nfs4_lockdata *data = calldata;
+       struct nfs4_lock_state *lsp = data->lsp;
 
        dprintk("%s: begin!\n", __func__);
 
@@ -5610,18 +5664,36 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)
                return;
 
        data->rpc_status = task->tk_status;
-       if (data->arg.new_lock_owner != 0) {
-               if (data->rpc_status == 0)
-                       nfs_confirm_seqid(&data->lsp->ls_seqid, 0);
-               else
-                       goto out;
-       }
-       if (data->rpc_status == 0) {
-               nfs4_stateid_copy(&data->lsp->ls_stateid, &data->res.stateid);
-               set_bit(NFS_LOCK_INITIALIZED, &data->lsp->ls_flags);
-               renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp);
+       switch (task->tk_status) {
+       case 0:
+               renew_lease(NFS_SERVER(data->ctx->dentry->d_inode),
+                               data->timestamp);
+               if (data->arg.new_lock) {
+                       data->fl.fl_flags &= ~(FL_SLEEP | FL_ACCESS);
+                       if (do_vfs_lock(data->fl.fl_file, &data->fl) < 0) {
+                               rpc_restart_call_prepare(task);
+                               break;
+                       }
+               }
+               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);
+               } else if (!nfs4_update_lock_stateid(lsp, &data->res.stateid))
+                       rpc_restart_call_prepare(task);
+               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,
+                                               &lsp->ls_state->open_stateid))
+                               rpc_restart_call_prepare(task);
+               } else if (!nfs4_stateid_match(&data->arg.lock_stateid,
+                                               &lsp->ls_stateid))
+                               rpc_restart_call_prepare(task);
        }
-out:
        dprintk("%s: done, ret = %d!\n", __func__, data->rpc_status);
 }
 
@@ -5702,7 +5774,8 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
                if (recovery_type == NFS_LOCK_RECLAIM)
                        data->arg.reclaim = NFS_LOCK_RECLAIM;
                nfs4_set_sequence_privileged(&data->arg.seq_args);
-       }
+       } else
+               data->arg.new_lock = 1;
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
@@ -5826,10 +5899,8 @@ static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *reques
 
 static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
 {
-       struct nfs4_state_owner *sp = state->owner;
        struct nfs_inode *nfsi = NFS_I(state->inode);
        unsigned char fl_flags = request->fl_flags;
-       unsigned int seq;
        int status = -ENOLCK;
 
        if ((fl_flags & FL_POSIX) &&
@@ -5849,25 +5920,11 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
                /* ...but avoid races with delegation recall... */
                request->fl_flags = fl_flags & ~FL_SLEEP;
                status = do_vfs_lock(request->fl_file, request);
-               goto out_unlock;
-       }
-       seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
-       up_read(&nfsi->rwsem);
-       status = _nfs4_do_setlk(state, cmd, request, NFS_LOCK_NEW);
-       if (status != 0)
+               up_read(&nfsi->rwsem);
                goto out;
-       down_read(&nfsi->rwsem);
-       if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) {
-               status = -NFS4ERR_DELAY;
-               goto out_unlock;
        }
-       /* Note: we always want to sleep here! */
-       request->fl_flags = fl_flags | FL_SLEEP;
-       if (do_vfs_lock(request->fl_file, request) < 0)
-               printk(KERN_WARNING "NFS: %s: VFS is out of sync with lock "
-                       "manager!\n", __func__);
-out_unlock:
        up_read(&nfsi->rwsem);
+       status = _nfs4_do_setlk(state, cmd, request, NFS_LOCK_NEW);
 out:
        request->fl_flags = fl_flags;
        return status;
@@ -5974,8 +6031,8 @@ static void nfs4_release_lockowner_prepare(struct rpc_task *task, void *calldata
 {
        struct nfs_release_lockowner_data *data = calldata;
        struct nfs_server *server = data->server;
-       nfs40_setup_sequence(server, &data->args.seq_args,
-                               &data->res.seq_res, task);
+       nfs40_setup_sequence(server->nfs_client->cl_slot_tbl,
+                            &data->args.seq_args, &data->res.seq_res, task);
        data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
        data->timestamp = jiffies;
 }
@@ -7537,6 +7594,7 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
                return;
        if (pnfs_choose_layoutget_stateid(&lgp->args.stateid,
                                          NFS_I(lgp->args.inode)->layout,
+                                         &lgp->args.range,
                                          lgp->args.ctx->state)) {
                rpc_exit(task, NFS4_OK);
        }
@@ -7792,9 +7850,13 @@ static void nfs4_layoutreturn_release(void *calldata)
        spin_lock(&lo->plh_inode->i_lock);
        if (lrp->res.lrs_present)
                pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
+       pnfs_clear_layoutreturn_waitbit(lo);
+       clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, &lo->plh_flags);
+       rpc_wake_up(&NFS_SERVER(lo->plh_inode)->roc_rpcwaitq);
        lo->plh_block_lgets--;
        spin_unlock(&lo->plh_inode->i_lock);
        pnfs_put_layout_hdr(lrp->args.layout);
+       nfs_iput_and_deactive(lrp->inode);
        kfree(calldata);
        dprintk("<-- %s\n", __func__);
 }
@@ -7805,7 +7867,7 @@ static const struct rpc_call_ops nfs4_layoutreturn_call_ops = {
        .rpc_release = nfs4_layoutreturn_release,
 };
 
-int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp)
+int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp, bool sync)
 {
        struct rpc_task *task;
        struct rpc_message msg = {
@@ -7820,14 +7882,23 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp)
                .callback_ops = &nfs4_layoutreturn_call_ops,
                .callback_data = lrp,
        };
-       int status;
+       int status = 0;
 
        dprintk("--> %s\n", __func__);
+       if (!sync) {
+               lrp->inode = nfs_igrab_and_active(lrp->args.inode);
+               if (!lrp->inode) {
+                       nfs4_layoutreturn_release(lrp);
+                       return -EAGAIN;
+               }
+               task_setup_data.flags |= RPC_TASK_ASYNC;
+       }
        nfs4_init_sequence(&lrp->args.seq_args, &lrp->res.seq_res, 1);
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
-       status = task->tk_status;
+       if (sync)
+               status = task->tk_status;
        trace_nfs4_layoutreturn(lrp->args.inode, status);
        dprintk("<-- %s status=%d\n", __func__, status);
        rpc_put_task(task);
@@ -7921,6 +7992,7 @@ static void nfs4_layoutcommit_release(void *calldata)
        nfs_post_op_update_inode_force_wcc(data->args.inode,
                                           data->res.fattr);
        put_rpccred(data->cred);
+       nfs_iput_and_deactive(data->inode);
        kfree(data);
 }
 
@@ -7945,7 +8017,6 @@ nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)
                .rpc_message = &msg,
                .callback_ops = &nfs4_layoutcommit_ops,
                .callback_data = data,
-               .flags = RPC_TASK_ASYNC,
        };
        struct rpc_task *task;
        int status = 0;
@@ -7956,18 +8027,21 @@ nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)
                data->args.lastbytewritten,
                data->args.inode->i_ino);
 
+       if (!sync) {
+               data->inode = nfs_igrab_and_active(data->args.inode);
+               if (data->inode == NULL) {
+                       nfs4_layoutcommit_release(data);
+                       return -EAGAIN;
+               }
+               task_setup_data.flags = RPC_TASK_ASYNC;
+       }
        nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
-       if (sync == false)
-               goto out;
-       status = nfs4_wait_for_completion_rpc_task(task);
-       if (status != 0)
-               goto out;
-       status = task->tk_status;
+       if (sync)
+               status = task->tk_status;
        trace_nfs4_layoutcommit(data->args.inode, status);
-out:
        dprintk("%s: status %d\n", __func__, status);
        rpc_put_task(task);
        return status;
@@ -8395,6 +8469,7 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
        .match_stateid = nfs4_match_stateid,
        .find_root_sec = nfs4_find_root_sec,
        .free_lock_state = nfs4_release_lockowner,
+       .alloc_seqid = nfs_alloc_seqid,
        .call_sync_ops = &nfs40_call_sync_ops,
        .reboot_recovery_ops = &nfs40_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs40_nograce_recovery_ops,
@@ -8403,6 +8478,12 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
 };
 
 #if defined(CONFIG_NFS_V4_1)
+static struct nfs_seqid *
+nfs_alloc_no_seqid(struct nfs_seqid_counter *arg1, gfp_t arg2)
+{
+       return NULL;
+}
+
 static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
        .minor_version = 1,
        .init_caps = NFS_CAP_READDIRPLUS
@@ -8416,6 +8497,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
        .match_stateid = nfs41_match_stateid,
        .find_root_sec = nfs41_find_root_sec,
        .free_lock_state = nfs41_free_lock_state,
+       .alloc_seqid = nfs_alloc_no_seqid,
        .call_sync_ops = &nfs41_call_sync_ops,
        .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
@@ -8442,6 +8524,7 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
        .find_root_sec = nfs41_find_root_sec,
        .free_lock_state = nfs41_free_lock_state,
        .call_sync_ops = &nfs41_call_sync_ops,
+       .alloc_seqid = nfs_alloc_no_seqid,
        .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
        .state_renewal_ops = &nfs41_state_renewal_ops,