]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/nfs/nfs4proc.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / fs / nfs / nfs4proc.c
index 4435e5e1f904e3e5ba26f4eb578fc30c5f6d997b..0a07e353a9613f49d32508aa83d029c48f1055a6 100644 (file)
@@ -49,6 +49,8 @@
 #include <linux/mount.h>
 #include <linux/module.h>
 #include <linux/sunrpc/bc_xprt.h>
+#include <linux/xattr.h>
+#include <linux/utsname.h>
 
 #include "nfs4_fs.h"
 #include "delegation.h"
@@ -254,12 +256,13 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode,
                case -NFS4ERR_OPENMODE:
                        if (state == NULL)
                                break;
-                       nfs4_state_mark_reclaim_nograce(clp, state);
-                       goto do_state_recovery;
+                       nfs4_schedule_stateid_recovery(server, state);
+                       goto wait_on_recovery;
                case -NFS4ERR_STALE_STATEID:
                case -NFS4ERR_STALE_CLIENTID:
                case -NFS4ERR_EXPIRED:
-                       goto do_state_recovery;
+                       nfs4_schedule_lease_recovery(clp);
+                       goto wait_on_recovery;
 #if defined(CONFIG_NFS_V4_1)
                case -NFS4ERR_BADSESSION:
                case -NFS4ERR_BADSLOT:
@@ -270,7 +273,7 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode,
                case -NFS4ERR_SEQ_MISORDERED:
                        dprintk("%s ERROR: %d Reset session\n", __func__,
                                errorcode);
-                       nfs4_schedule_state_recovery(clp);
+                       nfs4_schedule_session_recovery(clp->cl_session);
                        exception->retry = 1;
                        break;
 #endif /* defined(CONFIG_NFS_V4_1) */
@@ -293,8 +296,7 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode,
        }
        /* We failed to handle the error */
        return nfs4_map_errors(ret);
-do_state_recovery:
-       nfs4_schedule_state_recovery(clp);
+wait_on_recovery:
        ret = nfs4_wait_clnt_recover(clp);
        if (ret == 0)
                exception->retry = 1;
@@ -355,9 +357,9 @@ nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *free_slot)
 }
 
 /*
- * Signal state manager thread if session is drained
+ * Signal state manager thread if session fore channel is drained
  */
-static void nfs41_check_drain_session_complete(struct nfs4_session *ses)
+static void nfs4_check_drain_fc_complete(struct nfs4_session *ses)
 {
        struct rpc_task *task;
 
@@ -371,8 +373,20 @@ static void nfs41_check_drain_session_complete(struct nfs4_session *ses)
        if (ses->fc_slot_table.highest_used_slotid != -1)
                return;
 
-       dprintk("%s COMPLETE: Session Drained\n", __func__);
-       complete(&ses->complete);
+       dprintk("%s COMPLETE: Session Fore Channel Drained\n", __func__);
+       complete(&ses->fc_slot_table.complete);
+}
+
+/*
+ * Signal state manager thread if session back channel is drained
+ */
+void nfs4_check_drain_bc_complete(struct nfs4_session *ses)
+{
+       if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state) ||
+           ses->bc_slot_table.highest_used_slotid != -1)
+               return;
+       dprintk("%s COMPLETE: Session Back Channel Drained\n", __func__);
+       complete(&ses->bc_slot_table.complete);
 }
 
 static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
@@ -389,7 +403,7 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
 
        spin_lock(&tbl->slot_tbl_lock);
        nfs4_free_slot(tbl, res->sr_slot);
-       nfs41_check_drain_session_complete(res->sr_session);
+       nfs4_check_drain_fc_complete(res->sr_session);
        spin_unlock(&tbl->slot_tbl_lock);
        res->sr_slot = NULL;
 }
@@ -421,8 +435,8 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *
                clp = res->sr_session->clp;
                do_renew_lease(clp, timestamp);
                /* Check sequence flags */
-               if (atomic_read(&clp->cl_count) > 1)
-                       nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags);
+               if (res->sr_status_flags != 0)
+                       nfs4_schedule_lease_recovery(clp);
                break;
        case -NFS4ERR_DELAY:
                /* The server detected a resend of the RPC call and
@@ -1241,14 +1255,13 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
                        case -NFS4ERR_BAD_HIGH_SLOT:
                        case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
                        case -NFS4ERR_DEADSESSION:
-                               nfs4_schedule_state_recovery(
-                                       server->nfs_client);
+                               nfs4_schedule_session_recovery(server->nfs_client->cl_session);
                                goto out;
                        case -NFS4ERR_STALE_CLIENTID:
                        case -NFS4ERR_STALE_STATEID:
                        case -NFS4ERR_EXPIRED:
                                /* Don't recall a delegation if it was lost */
-                               nfs4_schedule_state_recovery(server->nfs_client);
+                               nfs4_schedule_lease_recovery(server->nfs_client);
                                goto out;
                        case -ERESTARTSYS:
                                /*
@@ -1257,7 +1270,7 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
                                 */
                        case -NFS4ERR_ADMIN_REVOKED:
                        case -NFS4ERR_BAD_STATEID:
-                               nfs4_state_mark_reclaim_nograce(server->nfs_client, state);
+                               nfs4_schedule_stateid_recovery(server, state);
                        case -EKEYEXPIRED:
                                /*
                                 * User RPCSEC_GSS context has expired.
@@ -1573,7 +1586,7 @@ static int nfs4_recover_expired_lease(struct nfs_server *server)
                if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) &&
                    !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state))
                        break;
-               nfs4_schedule_state_recovery(clp);
+               nfs4_schedule_state_manager(clp);
                ret = -EIO;
        }
        return ret;
@@ -1826,6 +1839,8 @@ struct nfs4_closedata {
        struct nfs_closeres res;
        struct nfs_fattr fattr;
        unsigned long timestamp;
+       bool roc;
+       u32 roc_barrier;
 };
 
 static void nfs4_free_closedata(void *data)
@@ -1833,6 +1848,8 @@ static void nfs4_free_closedata(void *data)
        struct nfs4_closedata *calldata = data;
        struct nfs4_state_owner *sp = calldata->state->owner;
 
+       if (calldata->roc)
+               pnfs_roc_release(calldata->state->inode);
        nfs4_put_open_state(calldata->state);
        nfs_free_seqid(calldata->arg.seqid);
        nfs4_put_state_owner(sp);
@@ -1865,6 +1882,9 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
         */
        switch (task->tk_status) {
                case 0:
+                       if (calldata->roc)
+                               pnfs_roc_set_barrier(state->inode,
+                                                    calldata->roc_barrier);
                        nfs_set_open_stateid(state, &calldata->res.stateid, 0);
                        renew_lease(server, calldata->timestamp);
                        nfs4_close_clear_stateid_flags(state,
@@ -1917,8 +1937,15 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
                return;
        }
 
-       if (calldata->arg.fmode == 0)
+       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);
+                       return;
+               }
+       }
 
        nfs_fattr_init(calldata->res.fattr);
        calldata->timestamp = jiffies;
@@ -1946,7 +1973,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 path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait)
+int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc)
 {
        struct nfs_server *server = NFS_SERVER(state->inode);
        struct nfs4_closedata *calldata;
@@ -1981,11 +2008,12 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, i
        calldata->res.fattr = &calldata->fattr;
        calldata->res.seqid = calldata->arg.seqid;
        calldata->res.server = server;
+       calldata->roc = roc;
        path_get(path);
        calldata->path = *path;
 
-       msg.rpc_argp = &calldata->arg,
-       msg.rpc_resp = &calldata->res,
+       msg.rpc_argp = &calldata->arg;
+       msg.rpc_resp = &calldata->res;
        task_setup_data.callback_data = calldata;
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
@@ -1998,6 +2026,8 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, gfp_t gfp_mask, i
 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;
@@ -2486,6 +2516,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
                path = &ctx->path;
                fmode = ctx->mode;
        }
+       sattr->ia_mode &= ~current_umask();
        state = nfs4_do_open(dir, path, fmode, flags, sattr, cred);
        d_drop(dentry);
        if (IS_ERR(state)) {
@@ -2816,6 +2847,8 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
 {
        struct nfs4_exception exception = { };
        int err;
+
+       sattr->ia_mode &= ~current_umask();
        do {
                err = nfs4_handle_exception(NFS_SERVER(dir),
                                _nfs4_proc_mkdir(dir, dentry, sattr),
@@ -2916,6 +2949,8 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
 {
        struct nfs4_exception exception = { };
        int err;
+
+       sattr->ia_mode &= ~current_umask();
        do {
                err = nfs4_handle_exception(NFS_SERVER(dir),
                                _nfs4_proc_mknod(dir, dentry, sattr, rdev),
@@ -3142,7 +3177,7 @@ static void nfs4_renew_done(struct rpc_task *task, void *calldata)
        if (task->tk_status < 0) {
                /* Unless we're shutting down, schedule state recovery! */
                if (test_bit(NFS_CS_RENEWD, &clp->cl_res_state) != 0)
-                       nfs4_schedule_state_recovery(clp);
+                       nfs4_schedule_lease_recovery(clp);
                return;
        }
        do_renew_lease(clp, timestamp);
@@ -3216,6 +3251,35 @@ static void buf_to_pages(const void *buf, size_t buflen,
        }
 }
 
+static int buf_to_pages_noslab(const void *buf, size_t buflen,
+               struct page **pages, unsigned int *pgbase)
+{
+       struct page *newpage, **spages;
+       int rc = 0;
+       size_t len;
+       spages = pages;
+
+       do {
+               len = min_t(size_t, PAGE_CACHE_SIZE, buflen);
+               newpage = alloc_page(GFP_KERNEL);
+
+               if (newpage == NULL)
+                       goto unwind;
+               memcpy(page_address(newpage), buf, len);
+                buf += len;
+                buflen -= len;
+               *pages++ = newpage;
+               rc++;
+       } while (buflen != 0);
+
+       return rc;
+
+unwind:
+       for(; rc > 0; rc--)
+               __free_page(spages[rc-1]);
+       return -ENOMEM;
+}
+
 struct nfs4_cached_acl {
        int cached;
        size_t len;
@@ -3384,13 +3448,23 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
                .rpc_argp       = &arg,
                .rpc_resp       = &res,
        };
-       int ret;
+       int ret, i;
 
        if (!nfs4_server_supports_acls(server))
                return -EOPNOTSUPP;
+       i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
+       if (i < 0)
+               return i;
        nfs_inode_return_delegation(inode);
-       buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
        ret = nfs4_call_sync(server, &msg, &arg, &res, 1);
+
+       /*
+        * Free each page after tx, so the only ref left is
+        * held by the network stack
+        */
+       for (; i > 0; i--)
+               put_page(pages[i-1]);
+
        /*
         * Acl update can result in inode attribute update.
         * so mark the attribute cache invalid.
@@ -3428,12 +3502,13 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
                case -NFS4ERR_OPENMODE:
                        if (state == NULL)
                                break;
-                       nfs4_state_mark_reclaim_nograce(clp, state);
-                       goto do_state_recovery;
+                       nfs4_schedule_stateid_recovery(server, state);
+                       goto wait_on_recovery;
                case -NFS4ERR_STALE_STATEID:
                case -NFS4ERR_STALE_CLIENTID:
                case -NFS4ERR_EXPIRED:
-                       goto do_state_recovery;
+                       nfs4_schedule_lease_recovery(clp);
+                       goto wait_on_recovery;
 #if defined(CONFIG_NFS_V4_1)
                case -NFS4ERR_BADSESSION:
                case -NFS4ERR_BADSLOT:
@@ -3444,7 +3519,7 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
                case -NFS4ERR_SEQ_MISORDERED:
                        dprintk("%s ERROR %d, Reset session\n", __func__,
                                task->tk_status);
-                       nfs4_schedule_state_recovery(clp);
+                       nfs4_schedule_session_recovery(clp->cl_session);
                        task->tk_status = 0;
                        return -EAGAIN;
 #endif /* CONFIG_NFS_V4_1 */
@@ -3461,9 +3536,8 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
        }
        task->tk_status = nfs4_map_errors(task->tk_status);
        return 0;
-do_state_recovery:
+wait_on_recovery:
        rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL);
-       nfs4_schedule_state_recovery(clp);
        if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0)
                rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task);
        task->tk_status = 0;
@@ -3478,6 +3552,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
        struct nfs4_setclientid setclientid = {
                .sc_verifier = &sc_verifier,
                .sc_prog = program,
+               .sc_cb_ident = clp->cl_cb_ident,
        };
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID],
@@ -3517,7 +3592,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
                if (signalled())
                        break;
                if (loop++ & 1)
-                       ssleep(clp->cl_lease_time + 1);
+                       ssleep(clp->cl_lease_time / HZ + 1);
                else
                        if (++clp->cl_id_uniquifier == 0)
                                break;
@@ -3663,8 +3738,8 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
        data->rpc_status = 0;
 
        task_setup_data.callback_data = data;
-       msg.rpc_argp = &data->args,
-       msg.rpc_resp = &data->res,
+       msg.rpc_argp = &data->args;
+       msg.rpc_resp = &data->res;
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
@@ -3743,6 +3818,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock
                goto out;
        lsp = request->fl_u.nfs4_fl.owner;
        arg.lock_owner.id = lsp->ls_id.id;
+       arg.lock_owner.s_dev = server->s_dev;
        status = nfs4_call_sync(server, &msg, &arg, &res, 1);
        switch (status) {
                case 0:
@@ -3908,8 +3984,8 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
                return ERR_PTR(-ENOMEM);
        }
 
-       msg.rpc_argp = &data->arg,
-       msg.rpc_resp = &data->res,
+       msg.rpc_argp = &data->arg;
+       msg.rpc_resp = &data->res;
        task_setup_data.callback_data = data;
        return rpc_run_task(&task_setup_data);
 }
@@ -3988,6 +4064,7 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
        p->arg.lock_stateid = &lsp->ls_stateid;
        p->arg.lock_owner.clientid = server->nfs_client->cl_clientid;
        p->arg.lock_owner.id = lsp->ls_id.id;
+       p->arg.lock_owner.s_dev = server->s_dev;
        p->res.lock_seqid = p->arg.lock_seqid;
        p->lsp = lsp;
        p->server = server;
@@ -4071,7 +4148,7 @@ static void nfs4_lock_release(void *calldata)
                task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp,
                                data->arg.lock_seqid);
                if (!IS_ERR(task))
-                       rpc_put_task(task);
+                       rpc_put_task_async(task);
                dprintk("%s: cancelling lock!\n", __func__);
        } else
                nfs_free_seqid(data->arg.lock_seqid);
@@ -4095,23 +4172,18 @@ static const struct rpc_call_ops nfs4_recover_lock_ops = {
 
 static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_state *lsp, int new_lock_owner, int error)
 {
-       struct nfs_client *clp = server->nfs_client;
-       struct nfs4_state *state = lsp->ls_state;
-
        switch (error) {
        case -NFS4ERR_ADMIN_REVOKED:
        case -NFS4ERR_BAD_STATEID:
-       case -NFS4ERR_EXPIRED:
+               lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
                if (new_lock_owner != 0 ||
                   (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0)
-                       nfs4_state_mark_reclaim_nograce(clp, state);
-               lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
+                       nfs4_schedule_stateid_recovery(server, lsp->ls_state);
                break;
        case -NFS4ERR_STALE_STATEID:
-               if (new_lock_owner != 0 ||
-                   (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0)
-                       nfs4_state_mark_reclaim_reboot(clp, state);
                lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
+       case -NFS4ERR_EXPIRED:
+               nfs4_schedule_lease_recovery(server->nfs_client);
        };
 }
 
@@ -4145,8 +4217,8 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
                        data->arg.reclaim = NFS_LOCK_RECLAIM;
                task_setup_data.callback_ops = &nfs4_recover_lock_ops;
        }
-       msg.rpc_argp = &data->arg,
-       msg.rpc_resp = &data->res,
+       msg.rpc_argp = &data->arg;
+       msg.rpc_resp = &data->res;
        task_setup_data.callback_data = data;
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
@@ -4327,12 +4399,14 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
                        case -NFS4ERR_EXPIRED:
                        case -NFS4ERR_STALE_CLIENTID:
                        case -NFS4ERR_STALE_STATEID:
+                               nfs4_schedule_lease_recovery(server->nfs_client);
+                               goto out;
                        case -NFS4ERR_BADSESSION:
                        case -NFS4ERR_BADSLOT:
                        case -NFS4ERR_BAD_HIGH_SLOT:
                        case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
                        case -NFS4ERR_DEADSESSION:
-                               nfs4_schedule_state_recovery(server->nfs_client);
+                               nfs4_schedule_session_recovery(server->nfs_client->cl_session);
                                goto out;
                        case -ERESTARTSYS:
                                /*
@@ -4342,7 +4416,7 @@ int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
                        case -NFS4ERR_ADMIN_REVOKED:
                        case -NFS4ERR_BAD_STATEID:
                        case -NFS4ERR_OPENMODE:
-                               nfs4_state_mark_reclaim_nograce(server->nfs_client, state);
+                               nfs4_schedule_stateid_recovery(server, state);
                                err = 0;
                                goto out;
                        case -EKEYEXPIRED:
@@ -4392,48 +4466,43 @@ void nfs4_release_lockowner(const struct nfs4_lock_state *lsp)
                return;
        args->lock_owner.clientid = server->nfs_client->cl_clientid;
        args->lock_owner.id = lsp->ls_id.id;
+       args->lock_owner.s_dev = server->s_dev;
        msg.rpc_argp = args;
        rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, args);
 }
 
 #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
 
-int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf,
-               size_t buflen, int flags)
+static int nfs4_xattr_set_nfs4_acl(struct dentry *dentry, const char *key,
+                                  const void *buf, size_t buflen,
+                                  int flags, int type)
 {
-       struct inode *inode = dentry->d_inode;
-
-       if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0)
-               return -EOPNOTSUPP;
+       if (strcmp(key, "") != 0)
+               return -EINVAL;
 
-       return nfs4_proc_set_acl(inode, buf, buflen);
+       return nfs4_proc_set_acl(dentry->d_inode, buf, buflen);
 }
 
-/* The getxattr man page suggests returning -ENODATA for unknown attributes,
- * and that's what we'll do for e.g. user attributes that haven't been set.
- * But we'll follow ext2/ext3's lead by returning -EOPNOTSUPP for unsupported
- * attributes in kernel-managed attribute namespaces. */
-ssize_t nfs4_getxattr(struct dentry *dentry, const char *key, void *buf,
-               size_t buflen)
+static int nfs4_xattr_get_nfs4_acl(struct dentry *dentry, const char *key,
+                                  void *buf, size_t buflen, int type)
 {
-       struct inode *inode = dentry->d_inode;
-
-       if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0)
-               return -EOPNOTSUPP;
+       if (strcmp(key, "") != 0)
+               return -EINVAL;
 
-       return nfs4_proc_get_acl(inode, buf, buflen);
+       return nfs4_proc_get_acl(dentry->d_inode, buf, buflen);
 }
 
-ssize_t nfs4_listxattr(struct dentry *dentry, char *buf, size_t buflen)
+static size_t nfs4_xattr_list_nfs4_acl(struct dentry *dentry, char *list,
+                                      size_t list_len, const char *name,
+                                      size_t name_len, int type)
 {
-       size_t len = strlen(XATTR_NAME_NFSV4_ACL) + 1;
+       size_t len = sizeof(XATTR_NAME_NFSV4_ACL);
 
        if (!nfs4_server_supports_acls(NFS_SERVER(dentry->d_inode)))
                return 0;
-       if (buf && buflen < len)
-               return -ERANGE;
-       if (buf)
-               memcpy(buf, XATTR_NAME_NFSV4_ACL, len);
+
+       if (list && len <= list_len)
+               memcpy(list, XATTR_NAME_NFSV4_ACL, len);
        return len;
 }
 
@@ -4485,6 +4554,25 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
 }
 
 #ifdef CONFIG_NFS_V4_1
+/*
+ * Check the exchange flags returned by the server for invalid flags, having
+ * both PNFS and NON_PNFS flags set, and not having one of NON_PNFS, PNFS, or
+ * DS flags set.
+ */
+static int nfs4_check_cl_exchange_flags(u32 flags)
+{
+       if (flags & ~EXCHGID4_FLAG_MASK_R)
+               goto out_inval;
+       if ((flags & EXCHGID4_FLAG_USE_PNFS_MDS) &&
+           (flags & EXCHGID4_FLAG_USE_NON_PNFS))
+               goto out_inval;
+       if (!(flags & (EXCHGID4_FLAG_MASK_PNFS)))
+               goto out_inval;
+       return NFS_OK;
+out_inval:
+       return -NFS4ERR_INVAL;
+}
+
 /*
  * nfs4_proc_exchange_id()
  *
@@ -4498,7 +4586,7 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
        nfs4_verifier verifier;
        struct nfs41_exchange_id_args args = {
                .client = clp,
-               .flags = clp->cl_exchange_flags,
+               .flags = EXCHGID4_FLAG_SUPP_MOVED_REFER,
        };
        struct nfs41_exchange_id_res res = {
                .client = clp,
@@ -4515,34 +4603,21 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
        dprintk("--> %s\n", __func__);
        BUG_ON(clp == NULL);
 
-       /* Remove server-only flags */
-       args.flags &= ~EXCHGID4_FLAG_CONFIRMED_R;
-
        p = (u32 *)verifier.data;
        *p++ = htonl((u32)clp->cl_boot_time.tv_sec);
        *p = htonl((u32)clp->cl_boot_time.tv_nsec);
        args.verifier = &verifier;
 
-       while (1) {
-               args.id_len = scnprintf(args.id, sizeof(args.id),
-                                       "%s/%s %u",
-                                       clp->cl_ipaddr,
-                                       rpc_peeraddr2str(clp->cl_rpcclient,
-                                                        RPC_DISPLAY_ADDR),
-                                       clp->cl_id_uniquifier);
-
-               status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
-
-               if (status != -NFS4ERR_CLID_INUSE)
-                       break;
-
-               if (signalled())
-                       break;
-
-               if (++clp->cl_id_uniquifier == 0)
-                       break;
-       }
+       args.id_len = scnprintf(args.id, sizeof(args.id),
+                               "%s/%s.%s/%u",
+                               clp->cl_ipaddr,
+                               init_utsname()->nodename,
+                               init_utsname()->domainname,
+                               clp->cl_rpcclient->cl_auth->au_flavor);
 
+       status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
+       if (!status)
+               status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags);
        dprintk("<-- %s status= %d\n", __func__, status);
        return status;
 }
@@ -4776,17 +4851,17 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
        if (!session)
                return NULL;
 
-       init_completion(&session->complete);
-
        tbl = &session->fc_slot_table;
        tbl->highest_used_slotid = -1;
        spin_lock_init(&tbl->slot_tbl_lock);
        rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table");
+       init_completion(&tbl->complete);
 
        tbl = &session->bc_slot_table;
        tbl->highest_used_slotid = -1;
        spin_lock_init(&tbl->slot_tbl_lock);
        rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table");
+       init_completion(&tbl->complete);
 
        session->session_state = 1<<NFS4_SESSION_INITING;
 
@@ -4948,10 +5023,20 @@ int nfs4_proc_create_session(struct nfs_client *clp)
        int status;
        unsigned *ptr;
        struct nfs4_session *session = clp->cl_session;
+       long timeout = 0;
+       int err;
 
        dprintk("--> %s clp=%p session=%p\n", __func__, clp, session);
 
-       status = _nfs4_proc_create_session(clp);
+       do {
+               status = _nfs4_proc_create_session(clp);
+               if (status == -NFS4ERR_DELAY) {
+                       err = nfs4_delay(clp->cl_rpcclient, &timeout);
+                       if (err)
+                               status = err;
+               }
+       } while (status == -NFS4ERR_DELAY);
+
        if (status)
                goto out;
 
@@ -5060,7 +5145,7 @@ static int nfs41_sequence_handle_errors(struct rpc_task *task, struct nfs_client
                rpc_delay(task, NFS4_POLL_RETRY_MAX);
                return -EAGAIN;
        default:
-               nfs4_schedule_state_recovery(clp);
+               nfs4_schedule_lease_recovery(clp);
        }
        return 0;
 }
@@ -5147,7 +5232,7 @@ static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cr
        if (IS_ERR(task))
                ret = PTR_ERR(task);
        else
-               rpc_put_task(task);
+               rpc_put_task_async(task);
        dprintk("<-- %s status=%d\n", __func__, ret);
        return ret;
 }
@@ -5163,8 +5248,13 @@ static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
                goto out;
        }
        ret = rpc_wait_for_completion_task(task);
-       if (!ret)
+       if (!ret) {
+               struct nfs4_sequence_res *res = task->tk_msg.rpc_resp;
+
+               if (task->tk_status == 0)
+                       nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags);
                ret = task->tk_status;
+       }
        rpc_put_task(task);
 out:
        dprintk("<-- %s status=%d\n", __func__, ret);
@@ -5201,7 +5291,7 @@ static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nf
                rpc_delay(task, NFS4_POLL_RETRY_MAX);
                return -EAGAIN;
        default:
-               nfs4_schedule_state_recovery(clp);
+               nfs4_schedule_lease_recovery(clp);
        }
        return 0;
 }
@@ -5269,6 +5359,9 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp)
                status = PTR_ERR(task);
                goto out;
        }
+       status = nfs4_wait_for_completion_rpc_task(task);
+       if (status == 0)
+               status = task->tk_status;
        rpc_put_task(task);
        return 0;
 out:
@@ -5280,13 +5373,23 @@ static void
 nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs4_layoutget *lgp = calldata;
-       struct inode *ino = lgp->args.inode;
-       struct nfs_server *server = NFS_SERVER(ino);
+       struct nfs_server *server = NFS_SERVER(lgp->args.inode);
 
        dprintk("--> %s\n", __func__);
+       /* Note the is a race here, where a CB_LAYOUTRECALL can come in
+        * right now covering the LAYOUTGET we are about to send.
+        * However, that is not so catastrophic, and there seems
+        * to be no way to prevent it completely.
+        */
        if (nfs4_setup_sequence(server, &lgp->args.seq_args,
                                &lgp->res.seq_res, 0, task))
                return;
+       if (pnfs_choose_layoutget_stateid(&lgp->args.stateid,
+                                         NFS_I(lgp->args.inode)->layout,
+                                         lgp->args.ctx->state)) {
+               rpc_exit(task, NFS4_OK);
+               return;
+       }
        rpc_call_start(task);
 }
 
@@ -5313,7 +5416,6 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
                        return;
                }
        }
-       lgp->status = task->tk_status;
        dprintk("<-- %s\n", __func__);
 }
 
@@ -5322,7 +5424,6 @@ static void nfs4_layoutget_release(void *calldata)
        struct nfs4_layoutget *lgp = calldata;
 
        dprintk("--> %s\n", __func__);
-       put_layout_hdr(lgp->args.inode);
        if (lgp->res.layout.buf != NULL)
                free_page((unsigned long) lgp->res.layout.buf);
        put_nfs_open_context(lgp->args.ctx);
@@ -5367,13 +5468,10 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
        if (IS_ERR(task))
                return PTR_ERR(task);
        status = nfs4_wait_for_completion_rpc_task(task);
-       if (status != 0)
-               goto out;
-       status = lgp->status;
-       if (status != 0)
-               goto out;
-       status = pnfs_layout_process(lgp);
-out:
+       if (status == 0)
+               status = task->tk_status;
+       if (status == 0)
+               status = pnfs_layout_process(lgp);
        rpc_put_task(task);
        dprintk("<-- %s status=%d\n", __func__, status);
        return status;
@@ -5504,9 +5602,10 @@ static const struct inode_operations nfs4_file_inode_operations = {
        .permission     = nfs_permission,
        .getattr        = nfs_getattr,
        .setattr        = nfs_setattr,
-       .getxattr       = nfs4_getxattr,
-       .setxattr       = nfs4_setxattr,
-       .listxattr      = nfs4_listxattr,
+       .getxattr       = generic_getxattr,
+       .setxattr       = generic_setxattr,
+       .listxattr      = generic_listxattr,
+       .removexattr    = generic_removexattr,
 };
 
 const struct nfs_rpc_ops nfs_v4_clientops = {
@@ -5551,6 +5650,18 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
        .open_context   = nfs4_atomic_open,
 };
 
+static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
+       .prefix = XATTR_NAME_NFSV4_ACL,
+       .list   = nfs4_xattr_list_nfs4_acl,
+       .get    = nfs4_xattr_get_nfs4_acl,
+       .set    = nfs4_xattr_set_nfs4_acl,
+};
+
+const struct xattr_handler *nfs4_xattr_handlers[] = {
+       &nfs4_xattr_nfs4_acl_handler,
+       NULL
+};
+
 /*
  * Local variables:
  *  c-basic-offset: 8