NFSv4.1: We must release the sequence id when we fail to get a session slot
[pandora-kernel.git] / fs / nfs / nfs4proc.c
index 6352741..e0423bb 100644 (file)
@@ -104,6 +104,8 @@ static int nfs4_map_errors(int err)
                return -EACCES;
        case -NFS4ERR_MINOR_VERS_MISMATCH:
                return -EPROTONOSUPPORT;
+       case -NFS4ERR_ACCESS:
+               return -EACCES;
        default:
                dprintk("%s could not handle NFSv4 error %d\n",
                                __func__, -err);
@@ -150,6 +152,12 @@ static const u32 nfs4_pnfs_open_bitmap[3] = {
        FATTR4_WORD2_MDSTHRESHOLD
 };
 
+static const u32 nfs4_open_noattr_bitmap[3] = {
+       FATTR4_WORD0_TYPE
+       | FATTR4_WORD0_CHANGE
+       | FATTR4_WORD0_FILEID,
+};
+
 const u32 nfs4_statfs_bitmap[2] = {
        FATTR4_WORD0_FILES_AVAIL
        | FATTR4_WORD0_FILES_FREE
@@ -331,8 +339,7 @@ static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struc
                        dprintk("%s ERROR: %d Reset session\n", __func__,
                                errorcode);
                        nfs4_schedule_session_recovery(clp->cl_session, errorcode);
-                       exception->retry = 1;
-                       break;
+                       goto wait_on_recovery;
 #endif /* defined(CONFIG_NFS_V4_1) */
                case -NFS4ERR_FILE_OPEN:
                        if (exception->timeout > HZ) {
@@ -832,6 +839,7 @@ static void nfs4_init_opendata_res(struct nfs4_opendata *p)
        p->o_res.seqid = p->o_arg.seqid;
        p->c_res.seqid = p->c_arg.seqid;
        p->o_res.server = p->o_arg.server;
+       p->o_res.access_request = p->o_arg.access;
        nfs_fattr_init(&p->f_attr);
        nfs_fattr_init_names(&p->f_attr, &p->owner_name, &p->group_name);
 }
@@ -860,6 +868,14 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
        p->o_arg.fh = NFS_FH(dir);
        p->o_arg.open_flags = flags;
        p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
+       /* 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)) {
+               /* ask server to check for all possible rights as results
+                * are cached */
+               p->o_arg.access = NFS4_ACCESS_READ | NFS4_ACCESS_MODIFY |
+                                 NFS4_ACCESS_EXTEND | NFS4_ACCESS_EXECUTE;
+       }
        p->o_arg.clientid = server->nfs_client->cl_clientid;
        p->o_arg.id.create_time = ktime_to_ns(sp->so_seqid.create_time);
        p->o_arg.id.uniquifier = sp->so_seqid.owner_id;
@@ -1115,11 +1131,80 @@ out_return_state:
        return state;
 }
 
-static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
+static void
+nfs4_opendata_check_deleg(struct nfs4_opendata *data, struct nfs4_state *state)
+{
+       struct nfs_client *clp = NFS_SERVER(state->inode)->nfs_client;
+       struct nfs_delegation *delegation;
+       int delegation_flags = 0;
+
+       rcu_read_lock();
+       delegation = rcu_dereference(NFS_I(state->inode)->delegation);
+       if (delegation)
+               delegation_flags = delegation->flags;
+       rcu_read_unlock();
+       if (data->o_arg.claim == NFS4_OPEN_CLAIM_DELEGATE_CUR) {
+               pr_err_ratelimited("NFS: Broken NFSv4 server %s is "
+                                  "returning a delegation for "
+                                  "OPEN(CLAIM_DELEGATE_CUR)\n",
+                                  clp->cl_hostname);
+       } else if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0)
+               nfs_inode_set_delegation(state->inode,
+                                        data->owner->so_cred,
+                                        &data->o_res);
+       else
+               nfs_inode_reclaim_delegation(state->inode,
+                                            data->owner->so_cred,
+                                            &data->o_res);
+}
+
+/*
+ * Check the inode attributes against the CLAIM_PREVIOUS returned attributes
+ * and update the nfs4_state.
+ */
+static struct nfs4_state *
+_nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data)
+{
+       struct inode *inode = data->state->inode;
+       struct nfs4_state *state = data->state;
+       int ret;
+
+       if (!data->rpc_done) {
+               ret = data->rpc_status;
+               goto err;
+       }
+
+       ret = -ESTALE;
+       if (!(data->f_attr.valid & NFS_ATTR_FATTR_TYPE) ||
+           !(data->f_attr.valid & NFS_ATTR_FATTR_FILEID) ||
+           !(data->f_attr.valid & NFS_ATTR_FATTR_CHANGE))
+               goto err;
+
+       ret = -ENOMEM;
+       state = nfs4_get_open_state(inode, data->owner);
+       if (state == NULL)
+               goto err;
+
+       ret = nfs_refresh_inode(inode, &data->f_attr);
+       if (ret)
+               goto err;
+
+       if (data->o_res.delegation_type != 0)
+               nfs4_opendata_check_deleg(data, state);
+       update_open_stateid(state, &data->o_res.stateid, NULL,
+                           data->o_arg.fmode);
+
+       return state;
+err:
+       return ERR_PTR(ret);
+
+}
+
+static struct nfs4_state *
+_nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
 {
        struct inode *inode;
        struct nfs4_state *state = NULL;
-       struct nfs_delegation *delegation;
        int ret;
 
        if (!data->rpc_done) {
@@ -1138,30 +1223,8 @@ static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data
        state = nfs4_get_open_state(inode, data->owner);
        if (state == NULL)
                goto err_put_inode;
-       if (data->o_res.delegation_type != 0) {
-               struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
-               int delegation_flags = 0;
-
-               rcu_read_lock();
-               delegation = rcu_dereference(NFS_I(inode)->delegation);
-               if (delegation)
-                       delegation_flags = delegation->flags;
-               rcu_read_unlock();
-               if (data->o_arg.claim == NFS4_OPEN_CLAIM_DELEGATE_CUR) {
-                       pr_err_ratelimited("NFS: Broken NFSv4 server %s is "
-                                       "returning a delegation for "
-                                       "OPEN(CLAIM_DELEGATE_CUR)\n",
-                                       clp->cl_hostname);
-               } else if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0)
-                       nfs_inode_set_delegation(state->inode,
-                                       data->owner->so_cred,
-                                       &data->o_res);
-               else
-                       nfs_inode_reclaim_delegation(state->inode,
-                                       data->owner->so_cred,
-                                       &data->o_res);
-       }
-
+       if (data->o_res.delegation_type != 0)
+               nfs4_opendata_check_deleg(data, state);
        update_open_stateid(state, &data->o_res.stateid, NULL,
                        data->o_arg.fmode);
        iput(inode);
@@ -1173,6 +1236,14 @@ err:
        return ERR_PTR(ret);
 }
 
+static struct nfs4_state *
+nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
+{
+       if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS)
+               return _nfs4_opendata_reclaim_to_nfs4_state(data);
+       return _nfs4_opendata_to_nfs4_state(data);
+}
+
 static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state)
 {
        struct nfs_inode *nfsi = NFS_I(state->inode);
@@ -1494,14 +1565,17 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
        data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid;
        if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
                task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
+               data->o_arg.open_bitmap = &nfs4_open_noattr_bitmap[0];
                nfs_copy_fh(&data->o_res.fh, data->o_arg.fh);
        }
        data->timestamp = jiffies;
        if (nfs4_setup_sequence(data->o_arg.server,
                                &data->o_arg.seq_args,
-                               &data->o_res.seq_res, task))
-               return;
-       rpc_call_start(task);
+                               &data->o_res.seq_res,
+                               task) != 0)
+               nfs_release_seqid(data->o_arg.seqid);
+       else
+               rpc_call_start(task);
        return;
 unlock_no_action:
        rcu_read_unlock();
@@ -1526,7 +1600,8 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata)
                return;
 
        if (task->tk_status == 0) {
-               switch (data->o_res.f_attr->mode & S_IFMT) {
+               if (data->o_res.f_attr->valid & NFS_ATTR_FATTR_TYPE) {
+                       switch (data->o_res.f_attr->mode & S_IFMT) {
                        case S_IFREG:
                                break;
                        case S_IFLNK:
@@ -1537,6 +1612,7 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata)
                                break;
                        default:
                                data->rpc_status = -ENOTDIR;
+                       }
                }
                renew_lease(data->o_res.server, data->timestamp);
                if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM))
@@ -1643,6 +1719,39 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data)
        return status;
 }
 
+static int nfs4_opendata_access(struct rpc_cred *cred,
+                               struct nfs4_opendata *opendata,
+                               struct nfs4_state *state, fmode_t fmode)
+{
+       struct nfs_access_entry cache;
+       u32 mask;
+
+       /* access call failed or for some reason the server doesn't
+        * support any access modes -- defer access call until later */
+       if (opendata->o_res.access_supported == 0)
+               return 0;
+
+       mask = 0;
+       /* don't check MAY_WRITE - a newly created file may not have
+        * write mode bits, but POSIX allows the creating process to write */
+       if (fmode & FMODE_READ)
+               mask |= MAY_READ;
+       if (fmode & FMODE_EXEC)
+               mask |= MAY_EXEC;
+
+       cache.cred = cred;
+       cache.jiffies = jiffies;
+       nfs_access_set_mask(&cache, opendata->o_res.access_result);
+       nfs_access_add_cache(state->inode, &cache);
+
+       if ((mask & ~cache.mask & (MAY_READ | MAY_EXEC)) == 0)
+               return 0;
+
+       /* even though OPEN succeeded, access is denied. Close the file */
+       nfs4_close_state(state, fmode);
+       return -NFS4ERR_ACCESS;
+}
+
 /*
  * Note: On error, nfs4_proc_open will free the struct nfs4_opendata
  */
@@ -1774,7 +1883,11 @@ static void nfs41_clear_delegation_stateid(struct nfs4_state *state)
                 * informs us the stateid is unrecognized. */
                if (status != -NFS4ERR_BAD_STATEID)
                        nfs41_free_stateid(server, stateid);
+               nfs_remove_bad_delegation(state->inode);
 
+               write_seqlock(&state->seqlock);
+               nfs4_stateid_copy(&state->stateid, &state->open_stateid);
+               write_sequnlock(&state->seqlock);
                clear_bit(NFS_DELEGATED_STATE, &state->flags);
        }
 }
@@ -1790,7 +1903,7 @@ static void nfs41_clear_delegation_stateid(struct nfs4_state *state)
 static int nfs41_check_open_stateid(struct nfs4_state *state)
 {
        struct nfs_server *server = NFS_SERVER(state->inode);
-       nfs4_stateid *stateid = &state->stateid;
+       nfs4_stateid *stateid = &state->open_stateid;
        int status;
 
        /* If a state reset has been done, test_stateid is unneeded */
@@ -1896,6 +2009,10 @@ static int _nfs4_do_open(struct inode *dir,
        if (server->caps & NFS_CAP_POSIX_LOCK)
                set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
 
+       status = nfs4_opendata_access(cred, opendata, state, fmode);
+       if (status != 0)
+               goto err_opendata_put;
+
        if (opendata->o_arg.open_flags & O_EXCL) {
                nfs4_exclusive_attrset(opendata, sattr);
 
@@ -1941,7 +2058,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
        struct nfs4_state *res;
        int status;
 
-       fmode &= FMODE_READ|FMODE_WRITE;
+       fmode &= FMODE_READ|FMODE_WRITE|FMODE_EXEC;
        do {
                status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, cred,
                                       &res, ctx_th);
@@ -2013,8 +2130,12 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
        nfs_fattr_init(fattr);
 
        if (state != NULL) {
+               struct nfs_lockowner lockowner = {
+                       .l_owner = current->files,
+                       .l_pid = current->tgid,
+               };
                nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
-                               current->files, current->tgid);
+                               &lockowner);
        } else if (nfs4_copy_delegation_stateid(&arg.stateid, inode,
                                FMODE_WRITE)) {
                /* Use that stateid */
@@ -2133,6 +2254,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
 {
        struct nfs4_closedata *calldata = data;
        struct nfs4_state *state = calldata->state;
+       struct inode *inode = calldata->inode;
        int call_close = 0;
 
        dprintk("%s: begin!\n", __func__);
@@ -2166,21 +2288,19 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
        if (calldata->arg.fmode == 0) {
                task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
                if (calldata->roc &&
-                   pnfs_roc_drain(calldata->inode, &calldata->roc_barrier)) {
-                       rpc_sleep_on(&NFS_SERVER(calldata->inode)->roc_rpcwaitq,
-                                    task, NULL);
+                   pnfs_roc_drain(inode, &calldata->roc_barrier, task))
                        goto out;
-               }
        }
 
        nfs_fattr_init(calldata->res.fattr);
        calldata->timestamp = jiffies;
-       if (nfs4_setup_sequence(NFS_SERVER(calldata->inode),
+       if (nfs4_setup_sequence(NFS_SERVER(inode),
                                &calldata->arg.seq_args,
                                &calldata->res.seq_res,
-                               task))
-               goto out;
-       rpc_call_start(task);
+                               task) != 0)
+               nfs_release_seqid(calldata->arg.seqid);
+       else
+               rpc_call_start(task);
 out:
        dprintk("%s: done!\n", __func__);
 }
@@ -2202,7 +2322,7 @@ static const struct rpc_call_ops nfs4_close_ops = {
  *
  * NOTE: Caller must be holding the sp->so_owner semaphore!
  */
-int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc)
+int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
 {
        struct nfs_server *server = NFS_SERVER(state->inode);
        struct nfs4_closedata *calldata;
@@ -2238,7 +2358,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc)
        calldata->res.fattr = &calldata->fattr;
        calldata->res.seqid = calldata->arg.seqid;
        calldata->res.server = server;
-       calldata->roc = roc;
+       calldata->roc = pnfs_roc(state->inode);
        nfs_sb_active(calldata->inode->i_sb);
 
        msg.rpc_argp = &calldata->arg;
@@ -2255,8 +2375,6 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc)
 out_free_calldata:
        kfree(calldata);
 out:
-       if (roc)
-               pnfs_roc_release(state->inode);
        nfs4_put_open_state(state);
        nfs4_put_state_owner(sp);
        return status;
@@ -2399,7 +2517,7 @@ static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandl
        int ret;
 
        auth = rpcauth_create(flavor, server->client);
-       if (!auth) {
+       if (IS_ERR(auth)) {
                ret = -EIO;
                goto out;
        }
@@ -2767,13 +2885,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
 
        status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
        if (!status) {
-               entry->mask = 0;
-               if (res.access & NFS4_ACCESS_READ)
-                       entry->mask |= MAY_READ;
-               if (res.access & (NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE))
-                       entry->mask |= MAY_WRITE;
-               if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE))
-                       entry->mask |= MAY_EXEC;
+               nfs_access_set_mask(entry, res.access);
                nfs_refresh_inode(inode, res.fattr);
        }
        nfs_free_fattr(res.fattr);
@@ -3215,11 +3327,11 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
                        dentry->d_parent->d_name.name,
                        dentry->d_name.name,
                        (unsigned long long)cookie);
-       nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args);
+       nfs4_setup_readdir(cookie, NFS_I(dir)->cookieverf, dentry, &args);
        res.pgbase = args.pgbase;
        status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0);
        if (status >= 0) {
-               memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE);
+               memcpy(NFS_I(dir)->cookieverf, res.verifier.data, NFS4_VERIFIER_SIZE);
                status += args.pgbase;
        }
 
@@ -3362,8 +3474,11 @@ static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, s
 
        nfs_fattr_init(fsinfo->fattr);
        error = nfs4_do_fsinfo(server, fhandle, fsinfo);
-       if (error == 0)
+       if (error == 0) {
+               /* block layout checks this! */
+               server->pnfs_blksize = fsinfo->blksize;
                set_pnfs_layoutdriver(server, fhandle, fsinfo->layouttype);
+       }
 
        return error;
 }
@@ -3653,11 +3768,11 @@ static inline int nfs4_server_supports_acls(struct nfs_server *server)
                && (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL);
 }
 
-/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_CACHE_SIZE, and that
- * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_CACHE_SIZE) bytes on
+/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_SIZE, and that
+ * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_SIZE) bytes on
  * the stack.
  */
-#define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT)
+#define NFS4ACL_MAXPAGES DIV_ROUND_UP(XATTR_SIZE_MAX, PAGE_SIZE)
 
 static int buf_to_pages_noslab(const void *buf, size_t buflen,
                struct page **pages, unsigned int *pgbase)
@@ -3668,7 +3783,7 @@ static int buf_to_pages_noslab(const void *buf, size_t buflen,
        spages = pages;
 
        do {
-               len = min_t(size_t, PAGE_CACHE_SIZE, buflen);
+               len = min_t(size_t, PAGE_SIZE, buflen);
                newpage = alloc_page(GFP_KERNEL);
 
                if (newpage == NULL)
@@ -3739,7 +3854,7 @@ static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size
        struct nfs4_cached_acl *acl;
        size_t buflen = sizeof(*acl) + acl_len;
 
-       if (pages && buflen <= PAGE_SIZE) {
+       if (buflen <= PAGE_SIZE) {
                acl = kmalloc(buflen, GFP_KERNEL);
                if (acl == NULL)
                        goto out;
@@ -3782,17 +3897,15 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
-       int ret = -ENOMEM, npages, i;
-       size_t acl_len = 0;
+       unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);
+       int ret = -ENOMEM, i;
 
-       npages = (buflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
        /* As long as we're doing a round trip to the server anyway,
         * let's be prepared for a page of acl data. */
        if (npages == 0)
                npages = 1;
-
-       /* Add an extra page to handle the bitmap returned */
-       npages++;
+       if (npages > ARRAY_SIZE(pages))
+               return -ERANGE;
 
        for (i = 0; i < npages; i++) {
                pages[i] = alloc_page(GFP_KERNEL);
@@ -3808,11 +3921,6 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
        args.acl_len = npages * PAGE_SIZE;
        args.acl_pgbase = 0;
 
-       /* Let decode_getfacl know not to fail if the ACL data is larger than
-        * the page we send as a guess */
-       if (buf == NULL)
-               res.acl_flags |= NFS4_ACL_LEN_REQUEST;
-
        dprintk("%s  buf %p buflen %zu npages %d args.acl_len %zu\n",
                __func__, buf, buflen, npages, args.acl_len);
        ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode),
@@ -3820,20 +3928,19 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
        if (ret)
                goto out_free;
 
-       acl_len = res.acl_len;
-       if (acl_len > args.acl_len)
-               nfs4_write_cached_acl(inode, NULL, 0, acl_len);
-       else
-               nfs4_write_cached_acl(inode, pages, res.acl_data_offset,
-                                     acl_len);
-       if (buf) {
+       /* Handle the case where the passed-in buffer is too short */
+       if (res.acl_flags & NFS4_ACL_TRUNC) {
+               /* Did the user only issue a request for the acl length? */
+               if (buf == NULL)
+                       goto out_ok;
                ret = -ERANGE;
-               if (acl_len > buflen)
-                       goto out_free;
-               _copy_from_pages(buf, pages, res.acl_data_offset,
-                               acl_len);
+               goto out_free;
        }
-       ret = acl_len;
+       nfs4_write_cached_acl(inode, pages, res.acl_data_offset, res.acl_len);
+       if (buf)
+               _copy_from_pages(buf, pages, res.acl_data_offset, res.acl_len);
+out_ok:
+       ret = res.acl_len;
 out_free:
        for (i = 0; i < npages; i++)
                if (pages[i])
@@ -3891,10 +3998,13 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
                .rpc_argp       = &arg,
                .rpc_resp       = &res,
        };
+       unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);
        int ret, i;
 
        if (!nfs4_server_supports_acls(server))
                return -EOPNOTSUPP;
+       if (npages > ARRAY_SIZE(pages))
+               return -ERANGE;
        i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
        if (i < 0)
                return i;
@@ -4012,6 +4122,36 @@ static void nfs4_init_boot_verifier(const struct nfs_client *clp,
        memcpy(bootverf->data, verf, sizeof(bootverf->data));
 }
 
+static unsigned int
+nfs4_init_nonuniform_client_string(const struct nfs_client *clp,
+                                  char *buf, size_t len)
+{
+       unsigned int result;
+
+       rcu_read_lock();
+       result = scnprintf(buf, len, "Linux NFSv4.0 %s/%s %s",
+                               clp->cl_ipaddr,
+                               rpc_peeraddr2str(clp->cl_rpcclient,
+                                                       RPC_DISPLAY_ADDR),
+                               rpc_peeraddr2str(clp->cl_rpcclient,
+                                                       RPC_DISPLAY_PROTO));
+       rcu_read_unlock();
+       return result;
+}
+
+static unsigned int
+nfs4_init_uniform_client_string(const struct nfs_client *clp,
+                               char *buf, size_t len)
+{
+       char *nodename = clp->cl_rpcclient->cl_nodename;
+
+       if (nfs4_client_id_uniquifier[0] != '\0')
+               nodename = nfs4_client_id_uniquifier;
+       return scnprintf(buf, len, "Linux NFSv%u.%u %s",
+                               clp->rpc_ops->version, clp->cl_minorversion,
+                               nodename);
+}
+
 /**
  * nfs4_proc_setclientid - Negotiate client ID
  * @clp: state data structure
@@ -4042,15 +4182,18 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
 
        /* nfs_client_id4 */
        nfs4_init_boot_verifier(clp, &sc_verifier);
-       rcu_read_lock();
-       setclientid.sc_name_len = scnprintf(setclientid.sc_name,
-                       sizeof(setclientid.sc_name), "%s/%s %s",
-                       clp->cl_ipaddr,
-                       rpc_peeraddr2str(clp->cl_rpcclient,
-                                               RPC_DISPLAY_ADDR),
-                       rpc_peeraddr2str(clp->cl_rpcclient,
-                                               RPC_DISPLAY_PROTO));
+       if (test_bit(NFS_CS_MIGRATION, &clp->cl_flags))
+               setclientid.sc_name_len =
+                               nfs4_init_uniform_client_string(clp,
+                                               setclientid.sc_name,
+                                               sizeof(setclientid.sc_name));
+       else
+               setclientid.sc_name_len =
+                               nfs4_init_nonuniform_client_string(clp,
+                                               setclientid.sc_name,
+                                               sizeof(setclientid.sc_name));
        /* cb_client4 */
+       rcu_read_lock();
        setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
                                sizeof(setclientid.sc_netid),
                                rpc_peeraddr2str(clp->cl_rpcclient,
@@ -4396,7 +4539,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
 
        if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
                return;
-       if ((calldata->lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) {
+       if (test_bit(NFS_LOCK_INITIALIZED, &calldata->lsp->ls_flags) == 0) {
                /* Note: exit _without_ running nfs4_locku_done */
                task->tk_action = NULL;
                return;
@@ -4404,9 +4547,11 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
        calldata->timestamp = jiffies;
        if (nfs4_setup_sequence(calldata->server,
                                &calldata->arg.seq_args,
-                               &calldata->res.seq_res, task))
-               return;
-       rpc_call_start(task);
+                               &calldata->res.seq_res,
+                               task) != 0)
+               nfs_release_seqid(calldata->arg.seqid);
+       else
+               rpc_call_start(task);
 }
 
 static const struct rpc_call_ops nfs4_locku_ops = {
@@ -4551,7 +4696,7 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
        /* Do we need to do an open_to_lock_owner? */
        if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) {
                if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0)
-                       return;
+                       goto out_release_lock_seqid;
                data->arg.open_stateid = &state->stateid;
                data->arg.new_lock_owner = 1;
                data->res.open_seqid = data->arg.open_seqid;
@@ -4560,10 +4705,15 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
        data->timestamp = jiffies;
        if (nfs4_setup_sequence(data->server,
                                &data->arg.seq_args,
-                               &data->res.seq_res, task))
+                               &data->res.seq_res,
+                               task) == 0) {
+               rpc_call_start(task);
                return;
-       rpc_call_start(task);
-       dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status);
+       }
+       nfs_release_seqid(data->arg.open_seqid);
+out_release_lock_seqid:
+       nfs_release_seqid(data->arg.lock_seqid);
+       dprintk("%s: done!, ret = %d\n", __func__, task->tk_status);
 }
 
 static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata)
@@ -4590,7 +4740,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)
        }
        if (data->rpc_status == 0) {
                nfs4_stateid_copy(&data->lsp->ls_stateid, &data->res.stateid);
-               data->lsp->ls_flags |= NFS_LOCK_INITIALIZED;
+               set_bit(NFS_LOCK_INITIALIZED, &data->lsp->ls_flags);
                renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp);
        }
 out:
@@ -4637,7 +4787,7 @@ static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_
        case -NFS4ERR_BAD_STATEID:
                lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
                if (new_lock_owner != 0 ||
-                  (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0)
+                  test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0)
                        nfs4_schedule_stateid_recovery(server, lsp->ls_state);
                break;
        case -NFS4ERR_STALE_STATEID:
@@ -4761,7 +4911,7 @@ static int nfs41_check_expired_locks(struct nfs4_state *state)
        struct nfs_server *server = NFS_SERVER(state->inode);
 
        list_for_each_entry(lsp, &state->lock_states, ls_locks) {
-               if (lsp->ls_flags & NFS_LOCK_INITIALIZED) {
+               if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
                        status = nfs41_test_stateid(server, &lsp->ls_stateid);
                        if (status != NFS_OK) {
                                /* Free the stateid unless the server
@@ -4769,7 +4919,7 @@ static int nfs41_check_expired_locks(struct nfs4_state *state)
                                if (status != -NFS4ERR_BAD_STATEID)
                                        nfs41_free_stateid(server,
                                                        &lsp->ls_stateid);
-                               lsp->ls_flags &= ~NFS_LOCK_INITIALIZED;
+                               clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags);
                                ret = status;
                        }
                }
@@ -5272,10 +5422,8 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
        };
 
        nfs4_init_boot_verifier(clp, &verifier);
-       args.id_len = scnprintf(args.id, sizeof(args.id),
-                               "%s/%s",
-                               clp->cl_ipaddr,
-                               clp->cl_rpcclient->cl_nodename);
+       args.id_len = nfs4_init_uniform_client_string(clp, args.id,
+                                                       sizeof(args.id));
        dprintk("NFS call  exchange_id auth=%s, '%.*s'\n",
                clp->cl_rpcclient->cl_auth->au_ops->au_name,
                args.id_len, args.id);
@@ -5396,6 +5544,8 @@ int nfs4_destroy_clientid(struct nfs_client *clp)
                goto out;
        if (clp->cl_exchange_flags == 0)
                goto out;
+       if (clp->cl_preserve_clid)
+               goto out;
        cred = nfs4_get_exchange_id_cred(clp);
        ret = nfs4_proc_destroy_clientid(clp, cred);
        if (cred)
@@ -6201,26 +6351,44 @@ nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
 static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
 {
        struct nfs4_layoutget *lgp = calldata;
-       struct nfs_server *server = NFS_SERVER(lgp->args.inode);
+       struct inode *inode = lgp->args.inode;
+       struct nfs_server *server = NFS_SERVER(inode);
+       struct pnfs_layout_hdr *lo;
+       struct nfs4_state *state = NULL;
 
        dprintk("--> %s\n", __func__);
 
        if (!nfs4_sequence_done(task, &lgp->res.seq_res))
-               return;
+               goto out;
 
        switch (task->tk_status) {
        case 0:
-               break;
+               goto out;
        case -NFS4ERR_LAYOUTTRYLATER:
        case -NFS4ERR_RECALLCONFLICT:
                task->tk_status = -NFS4ERR_DELAY;
-               /* Fall through */
-       default:
-               if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
-                       rpc_restart_call_prepare(task);
-                       return;
+               break;
+       case -NFS4ERR_EXPIRED:
+       case -NFS4ERR_BAD_STATEID:
+               spin_lock(&inode->i_lock);
+               lo = NFS_I(inode)->layout;
+               if (!lo || list_empty(&lo->plh_segs)) {
+                       spin_unlock(&inode->i_lock);
+                       /* If the open stateid was bad, then recover it. */
+                       state = lgp->args.ctx->state;
+               } else {
+                       LIST_HEAD(head);
+
+                       pnfs_mark_matching_lsegs_invalid(lo, &head, NULL);
+                       spin_unlock(&inode->i_lock);
+                       /* Mark the bad layout state as invalid, then
+                        * retry using the open stateid. */
+                       pnfs_free_lseg_list(&head);
                }
        }
+       if (nfs4_async_handle_error(task, server, state) == -EAGAIN)
+               rpc_restart_call_prepare(task);
+out:
        dprintk("<-- %s\n", __func__);
 }
 
@@ -6287,7 +6455,8 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = {
        .rpc_release = nfs4_layoutget_release,
 };
 
-void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
+struct pnfs_layout_segment *
+nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
 {
        struct nfs_server *server = NFS_SERVER(lgp->args.inode);
        size_t max_pages = max_response_pages(server);
@@ -6304,6 +6473,7 @@ void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
                .callback_data = lgp,
                .flags = RPC_TASK_ASYNC,
        };
+       struct pnfs_layout_segment *lseg = NULL;
        int status = 0;
 
        dprintk("--> %s\n", __func__);
@@ -6311,7 +6481,7 @@ void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
        lgp->args.layout.pages = nfs4_alloc_pages(max_pages, gfp_flags);
        if (!lgp->args.layout.pages) {
                nfs4_layoutget_release(lgp);
-               return;
+               return ERR_PTR(-ENOMEM);
        }
        lgp->args.layout.pglen = max_pages * PAGE_SIZE;
 
@@ -6320,15 +6490,17 @@ void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
        nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
-               return;
+               return ERR_CAST(task);
        status = nfs4_wait_for_completion_rpc_task(task);
        if (status == 0)
                status = task->tk_status;
        if (status == 0)
-               status = pnfs_layout_process(lgp);
+               lseg = pnfs_layout_process(lgp);
        rpc_put_task(task);
        dprintk("<-- %s status=%d\n", __func__, status);
-       return;
+       if (status)
+               return ERR_PTR(status);
+       return lseg;
 }
 
 static void
@@ -6347,7 +6519,6 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
 {
        struct nfs4_layoutreturn *lrp = calldata;
        struct nfs_server *server;
-       struct pnfs_layout_hdr *lo = lrp->args.layout;
 
        dprintk("--> %s\n", __func__);
 
@@ -6359,20 +6530,21 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
                rpc_restart_call_prepare(task);
                return;
        }
-       spin_lock(&lo->plh_inode->i_lock);
-       if (task->tk_status == 0 && lrp->res.lrs_present)
-               pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
-       lo->plh_block_lgets--;
-       spin_unlock(&lo->plh_inode->i_lock);
        dprintk("<-- %s\n", __func__);
 }
 
 static void nfs4_layoutreturn_release(void *calldata)
 {
        struct nfs4_layoutreturn *lrp = calldata;
+       struct pnfs_layout_hdr *lo = lrp->args.layout;
 
        dprintk("--> %s\n", __func__);
-       put_layout_hdr(lrp->args.layout);
+       spin_lock(&lo->plh_inode->i_lock);
+       if (lrp->res.lrs_present)
+               pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
+       lo->plh_block_lgets--;
+       spin_unlock(&lo->plh_inode->i_lock);
+       pnfs_put_layout_hdr(lrp->args.layout);
        kfree(calldata);
        dprintk("<-- %s\n", __func__);
 }
@@ -6546,7 +6718,7 @@ static void nfs4_layoutcommit_release(void *calldata)
                list_del_init(&lseg->pls_lc_list);
                if (test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT,
                                       &lseg->pls_flags))
-                       put_lseg(lseg);
+                       pnfs_put_lseg(lseg);
        }
 
        clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock);
@@ -6805,6 +6977,7 @@ static const struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
        .recover_lock   = nfs4_lock_reclaim,
        .establish_clid = nfs4_init_clientid,
        .get_clid_cred  = nfs4_get_setclientid_cred,
+       .detect_trunking = nfs40_discover_server_trunking,
 };
 
 #if defined(CONFIG_NFS_V4_1)
@@ -6816,6 +6989,7 @@ static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
        .establish_clid = nfs41_init_clientid,
        .get_clid_cred  = nfs4_get_exchange_id_cred,
        .reclaim_complete = nfs41_proc_reclaim_complete,
+       .detect_trunking = nfs41_discover_server_trunking,
 };
 #endif /* CONFIG_NFS_V4_1 */