nfs4.1: Minimal SP4_MACH_CRED implementation
[linux-2.6-block.git] / fs / nfs / nfs4proc.c
index cf11799297c42d50dc33aca126e6da11f033ce4b..ab6ee1dffd7b872b1b9bab2cb6201a6570a9aeb8 100644 (file)
@@ -66,6 +66,8 @@
 #include "nfs4session.h"
 #include "fscache.h"
 
+#include "nfs4trace.h"
+
 #define NFSDBG_FACILITY                NFSDBG_PROC
 
 #define NFS4_POLL_RETRY_MIN    (HZ/10)
@@ -433,6 +435,20 @@ wait_on_recovery:
        return ret;
 }
 
+/*
+ * Return 'true' if 'clp' is using an rpc_client that is integrity protected
+ * or 'false' otherwise.
+ */
+static bool _nfs4_is_integrity_protected(struct nfs_client *clp)
+{
+       rpc_authflavor_t flavor = clp->cl_rpcclient->cl_auth->au_flavor;
+
+       if (flavor == RPC_AUTH_GSS_KRB5I ||
+           flavor == RPC_AUTH_GSS_KRB5P)
+               return true;
+
+       return false;
+}
 
 static void do_renew_lease(struct nfs_client *clp, unsigned long timestamp)
 {
@@ -447,6 +463,88 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp
        do_renew_lease(server->nfs_client, timestamp);
 }
 
+struct nfs4_call_sync_data {
+       const struct nfs_server *seq_server;
+       struct nfs4_sequence_args *seq_args;
+       struct nfs4_sequence_res *seq_res;
+};
+
+static void nfs4_init_sequence(struct nfs4_sequence_args *args,
+                              struct nfs4_sequence_res *res, int cache_reply)
+{
+       args->sa_slot = NULL;
+       args->sa_cache_this = cache_reply;
+       args->sa_privileged = 0;
+
+       res->sr_slot = NULL;
+}
+
+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)
+{
+       struct nfs4_slot_table *tbl = server->nfs_client->cl_slot_tbl;
+       struct nfs4_slot *slot;
+
+       /* slot already allocated? */
+       if (res->sr_slot != NULL)
+               goto out_start;
+
+       spin_lock(&tbl->slot_tbl_lock);
+       if (nfs4_slot_tbl_draining(tbl) && !args->sa_privileged)
+               goto out_sleep;
+
+       slot = nfs4_alloc_slot(tbl);
+       if (IS_ERR(slot)) {
+               if (slot == ERR_PTR(-ENOMEM))
+                       task->tk_timeout = HZ >> 2;
+               goto out_sleep;
+       }
+       spin_unlock(&tbl->slot_tbl_lock);
+
+       args->sa_slot = slot;
+       res->sr_slot = slot;
+
+out_start:
+       rpc_call_start(task);
+       return 0;
+
+out_sleep:
+       if (args->sa_privileged)
+               rpc_sleep_on_priority(&tbl->slot_tbl_waitq, task,
+                               NULL, RPC_PRIORITY_PRIVILEGED);
+       else
+               rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
+       spin_unlock(&tbl->slot_tbl_lock);
+       return -EAGAIN;
+}
+
+static int nfs40_sequence_done(struct rpc_task *task,
+                              struct nfs4_sequence_res *res)
+{
+       struct nfs4_slot *slot = res->sr_slot;
+       struct nfs4_slot_table *tbl;
+
+       if (!RPC_WAS_SENT(task))
+               goto out;
+
+       tbl = slot->table;
+       spin_lock(&tbl->slot_tbl_lock);
+       if (!nfs41_wake_and_assign_slot(tbl, slot))
+               nfs4_free_slot(tbl, slot);
+       spin_unlock(&tbl->slot_tbl_lock);
+
+       res->sr_slot = NULL;
+out:
+       return 1;
+}
+
 #if defined(CONFIG_NFS_V4_1)
 
 static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
@@ -506,6 +604,7 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *
                interrupted = true;
        }
 
+       trace_nfs4_sequence_done(session, res);
        /* Check the SEQUENCE operation status */
        switch (res->sr_status) {
        case 0:
@@ -591,25 +690,11 @@ static int nfs4_sequence_done(struct rpc_task *task,
 {
        if (res->sr_slot == NULL)
                return 1;
+       if (!res->sr_slot->table->session)
+               return nfs40_sequence_done(task, res);
        return nfs41_sequence_done(task, res);
 }
 
-static void nfs41_init_sequence(struct nfs4_sequence_args *args,
-               struct nfs4_sequence_res *res, int cache_reply)
-{
-       args->sa_slot = NULL;
-       args->sa_cache_this = 0;
-       args->sa_privileged = 0;
-       if (cache_reply)
-               args->sa_cache_this = 1;
-       res->sr_slot = NULL;
-}
-
-static void nfs4_set_sequence_privileged(struct nfs4_sequence_args *args)
-{
-       args->sa_privileged = 1;
-}
-
 int nfs41_setup_sequence(struct nfs4_session *session,
                                struct nfs4_sequence_args *args,
                                struct nfs4_sequence_res *res,
@@ -647,7 +732,7 @@ int nfs41_setup_sequence(struct nfs4_session *session,
 
        args->sa_slot = slot;
 
-       dprintk("<-- %s slotid=%d seqid=%d\n", __func__,
+       dprintk("<-- %s slotid=%u seqid=%u\n", __func__,
                        slot->slot_nr, slot->seq_nr);
 
        res->sr_slot = slot;
@@ -658,6 +743,7 @@ int nfs41_setup_sequence(struct nfs4_session *session,
         * set to 1 if an rpc level failure occurs.
         */
        res->sr_status = 1;
+       trace_nfs4_setup_sequence(session, args);
 out_success:
        rpc_call_start(task);
        return 0;
@@ -673,38 +759,30 @@ out_sleep:
 }
 EXPORT_SYMBOL_GPL(nfs41_setup_sequence);
 
-int nfs4_setup_sequence(const struct nfs_server *server,
-                       struct nfs4_sequence_args *args,
-                       struct nfs4_sequence_res *res,
-                       struct rpc_task *task)
+static int nfs4_setup_sequence(const struct nfs_server *server,
+                              struct nfs4_sequence_args *args,
+                              struct nfs4_sequence_res *res,
+                              struct rpc_task *task)
 {
        struct nfs4_session *session = nfs4_get_session(server);
        int ret = 0;
 
-       if (session == NULL) {
-               rpc_call_start(task);
-               goto out;
-       }
+       if (!session)
+               return nfs40_setup_sequence(server, args, res, task);
 
-       dprintk("--> %s clp %p session %p sr_slot %d\n",
+       dprintk("--> %s clp %p session %p sr_slot %u\n",
                __func__, session->clp, session, res->sr_slot ?
-                       res->sr_slot->slot_nr : -1);
+                       res->sr_slot->slot_nr : NFS4_NO_SLOT);
 
        ret = nfs41_setup_sequence(session, args, res, task);
-out:
+
        dprintk("<-- %s status=%d\n", __func__, ret);
        return ret;
 }
 
-struct nfs41_call_sync_data {
-       const struct nfs_server *seq_server;
-       struct nfs4_sequence_args *seq_args;
-       struct nfs4_sequence_res *seq_res;
-};
-
 static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
 {
-       struct nfs41_call_sync_data *data = calldata;
+       struct nfs4_call_sync_data *data = calldata;
        struct nfs4_session *session = nfs4_get_session(data->seq_server);
 
        dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server);
@@ -714,7 +792,7 @@ static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
 
 static void nfs41_call_sync_done(struct rpc_task *task, void *calldata)
 {
-       struct nfs41_call_sync_data *data = calldata;
+       struct nfs4_call_sync_data *data = calldata;
 
        nfs41_sequence_done(task, data->seq_res);
 }
@@ -724,6 +802,42 @@ static const struct rpc_call_ops nfs41_call_sync_ops = {
        .rpc_call_done = nfs41_call_sync_done,
 };
 
+#else  /* !CONFIG_NFS_V4_1 */
+
+static int nfs4_setup_sequence(const struct nfs_server *server,
+                              struct nfs4_sequence_args *args,
+                              struct nfs4_sequence_res *res,
+                              struct rpc_task *task)
+{
+       return nfs40_setup_sequence(server, args, res, task);
+}
+
+static int nfs4_sequence_done(struct rpc_task *task,
+                              struct nfs4_sequence_res *res)
+{
+       return nfs40_sequence_done(task, res);
+}
+
+#endif /* !CONFIG_NFS_V4_1 */
+
+static void nfs40_call_sync_prepare(struct rpc_task *task, void *calldata)
+{
+       struct nfs4_call_sync_data *data = calldata;
+       nfs4_setup_sequence(data->seq_server,
+                               data->seq_args, data->seq_res, task);
+}
+
+static void nfs40_call_sync_done(struct rpc_task *task, void *calldata)
+{
+       struct nfs4_call_sync_data *data = calldata;
+       nfs4_sequence_done(task, data->seq_res);
+}
+
+static const struct rpc_call_ops nfs40_call_sync_ops = {
+       .rpc_call_prepare = nfs40_call_sync_prepare,
+       .rpc_call_done = nfs40_call_sync_done,
+};
+
 static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
                                   struct nfs_server *server,
                                   struct rpc_message *msg,
@@ -732,7 +846,8 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
 {
        int ret;
        struct rpc_task *task;
-       struct nfs41_call_sync_data data = {
+       struct nfs_client *clp = server->nfs_client;
+       struct nfs4_call_sync_data data = {
                .seq_server = server,
                .seq_args = args,
                .seq_res = res,
@@ -740,7 +855,7 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
        struct rpc_task_setup task_setup = {
                .rpc_client = clnt,
                .rpc_message = msg,
-               .callback_ops = &nfs41_call_sync_ops,
+               .callback_ops = clp->cl_mvops->call_sync_ops,
                .callback_data = &data
        };
 
@@ -754,35 +869,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
        return ret;
 }
 
-#else
-static
-void nfs41_init_sequence(struct nfs4_sequence_args *args,
-               struct nfs4_sequence_res *res, int cache_reply)
-{
-}
-
-static void nfs4_set_sequence_privileged(struct nfs4_sequence_args *args)
-{
-}
-
-
-static int nfs4_sequence_done(struct rpc_task *task,
-                              struct nfs4_sequence_res *res)
-{
-       return 1;
-}
-#endif /* CONFIG_NFS_V4_1 */
-
-static
-int _nfs4_call_sync(struct rpc_clnt *clnt,
-                   struct nfs_server *server,
-                   struct rpc_message *msg,
-                   struct nfs4_sequence_args *args,
-                   struct nfs4_sequence_res *res)
-{
-       return rpc_call_sync(clnt, msg, 0);
-}
-
 static
 int nfs4_call_sync(struct rpc_clnt *clnt,
                   struct nfs_server *server,
@@ -791,9 +877,8 @@ int nfs4_call_sync(struct rpc_clnt *clnt,
                   struct nfs4_sequence_res *res,
                   int cache_reply)
 {
-       nfs41_init_sequence(args, res, cache_reply);
-       return server->nfs_client->cl_mvops->call_sync(clnt, server, msg,
-                                               args, res);
+       nfs4_init_sequence(args, res, cache_reply);
+       return nfs4_call_sync_sequence(clnt, server, msg, args, res);
 }
 
 static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
@@ -933,7 +1018,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
                p->o_arg.fh = NFS_FH(dentry->d_inode);
        }
        if (attrs != NULL && attrs->ia_valid != 0) {
-               __be32 verf[2];
+               __u32 verf[2];
 
                p->o_arg.u.attrs = &p->attrs;
                memcpy(&p->attrs, attrs, sizeof(p->attrs));
@@ -1103,7 +1188,7 @@ static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stat
                goto no_delegation;
 
        spin_lock(&deleg_cur->lock);
-       if (nfsi->delegation != deleg_cur ||
+       if (rcu_dereference(nfsi->delegation) != deleg_cur ||
           test_bit(NFS_DELEGATION_RETURNING, &deleg_cur->flags) ||
            (deleg_cur->type & fmode) != fmode)
                goto no_delegation_unlock;
@@ -1440,6 +1525,7 @@ static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state
        int err;
        do {
                err = _nfs4_do_open_reclaim(ctx, state);
+               trace_nfs4_open_reclaim(ctx, 0, err);
                if (nfs4_clear_cap_atomic_open_v1(server, err, &exception))
                        continue;
                if (err != -NFS4ERR_DELAY)
@@ -1524,10 +1610,20 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
        return nfs4_handle_delegation_recall_error(server, state, stateid, err);
 }
 
+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->o_arg.seq_args,
+                               &data->o_res.seq_res, task);
+}
+
 static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata)
 {
        struct nfs4_opendata *data = calldata;
 
+       nfs40_sequence_done(task, &data->o_res.seq_res);
+
        data->rpc_status = task->tk_status;
        if (data->rpc_status == 0) {
                nfs4_stateid_copy(&data->o_res.stateid, &data->c_res.stateid);
@@ -1556,6 +1652,7 @@ out_free:
 }
 
 static const struct rpc_call_ops nfs4_open_confirm_ops = {
+       .rpc_call_prepare = nfs4_open_confirm_prepare,
        .rpc_call_done = nfs4_open_confirm_done,
        .rpc_release = nfs4_open_confirm_release,
 };
@@ -1583,6 +1680,7 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data)
        };
        int status;
 
+       nfs4_init_sequence(&data->o_arg.seq_args, &data->o_res.seq_res, 1);
        kref_get(&data->kref);
        data->rpc_done = 0;
        data->rpc_status = 0;
@@ -1742,7 +1840,7 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
        };
        int status;
 
-       nfs41_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1);
+       nfs4_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1);
        kref_get(&data->kref);
        data->rpc_done = 0;
        data->rpc_status = 0;
@@ -1895,6 +1993,7 @@ static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state
 
        do {
                err = _nfs4_open_expired(ctx, state);
+               trace_nfs4_open_expired(ctx, 0, err);
                if (nfs4_clear_cap_atomic_open_v1(server, err, &exception))
                        continue;
                switch (err) {
@@ -1944,6 +2043,7 @@ static void nfs41_clear_delegation_stateid(struct nfs4_state *state)
                cred = get_rpccred(delegation->cred);
                rcu_read_unlock();
                status = nfs41_test_stateid(server, stateid, cred);
+               trace_nfs4_test_delegation_stateid(state, NULL, status);
        } else
                rcu_read_unlock();
 
@@ -1986,6 +2086,7 @@ static int nfs41_check_open_stateid(struct nfs4_state *state)
                return -NFS4ERR_BAD_STATEID;
 
        status = nfs41_test_stateid(server, stateid, cred);
+       trace_nfs4_test_open_stateid(state, NULL, status);
        if (status != NFS_OK) {
                /* Free the stateid unless the server explicitly
                 * informs us the stateid is unrecognized. */
@@ -2197,6 +2298,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
        do {
                status = _nfs4_do_open(dir, ctx, flags, sattr, label);
                res = ctx->state;
+               trace_nfs4_open_file(ctx, flags, status);
                if (status == 0)
                        break;
                /* NOTE: BAD_SEQID means the server and client disagree about the
@@ -2310,6 +2412,7 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
        int err;
        do {
                err = _nfs4_do_setattr(inode, cred, fattr, sattr, state, ilabel, olabel);
+               trace_nfs4_setattr(inode, err);
                switch (err) {
                case -NFS4ERR_OPENMODE:
                        if (!(sattr->ia_valid & ATTR_SIZE)) {
@@ -2387,6 +2490,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
        dprintk("%s: begin!\n", __func__);
        if (!nfs4_sequence_done(task, &calldata->res.seq_res))
                return;
+       trace_nfs4_close(state, &calldata->arg, &calldata->res, task->tk_status);
         /* hmm. we are done with the inode, and in the process of freeing
         * the state_owner. we keep this around to process errors
         */
@@ -2514,7 +2618,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
        calldata = kzalloc(sizeof(*calldata), gfp_mask);
        if (calldata == NULL)
                goto out;
-       nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 1);
+       nfs4_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 1);
        calldata->inode = state->inode;
        calldata->state = state;
        calldata->arg.fh = NFS_FH(state->inode);
@@ -2690,6 +2794,7 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
        int err;
        do {
                err = _nfs4_lookup_root(server, fhandle, info);
+               trace_nfs4_lookup_root(server, fhandle, info->fattr, err);
                switch (err) {
                case 0:
                case -NFS4ERR_WRONGSEC:
@@ -2705,10 +2810,13 @@ out:
 static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
                                struct nfs_fsinfo *info, rpc_authflavor_t flavor)
 {
+       struct rpc_auth_create_args auth_args = {
+               .pseudoflavor = flavor,
+       };
        struct rpc_auth *auth;
        int ret;
 
-       auth = rpcauth_create(flavor, server->client);
+       auth = rpcauth_create(&auth_args, server->client);
        if (IS_ERR(auth)) {
                ret = -EACCES;
                goto out;
@@ -2899,8 +3007,9 @@ static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(server,
-                               _nfs4_proc_getattr(server, fhandle, fattr, label),
+               err = _nfs4_proc_getattr(server, fhandle, fattr, label);
+               trace_nfs4_getattr(server, fhandle, fattr, err);
+               err = nfs4_handle_exception(server, err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -2940,10 +3049,10 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
        
        /* Deal with open(O_TRUNC) */
        if (sattr->ia_valid & ATTR_OPEN)
-               sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
+               sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME);
 
        /* Optimization: if the end result is no change, don't RPC */
-       if ((sattr->ia_valid & ~(ATTR_FILE)) == 0)
+       if ((sattr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0)
                return 0;
 
        /* Search for an existing open(O_WRITE) file */
@@ -3020,6 +3129,7 @@ static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir,
        int err;
        do {
                err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr, label);
+               trace_nfs4_lookup(dir, name, err);
                switch (err) {
                case -NFS4ERR_BADNAME:
                        err = -ENOENT;
@@ -3136,8 +3246,9 @@ static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(inode),
-                               _nfs4_proc_access(inode, entry),
+               err = _nfs4_proc_access(inode, entry);
+               trace_nfs4_access(inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -3190,8 +3301,9 @@ static int nfs4_proc_readlink(struct inode *inode, struct page *page,
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(inode),
-                               _nfs4_proc_readlink(inode, page, pgbase, pglen),
+               err = _nfs4_proc_readlink(inode, page, pgbase, pglen);
+               trace_nfs4_readlink(inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -3255,8 +3367,9 @@ static int nfs4_proc_remove(struct inode *dir, struct qstr *name)
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dir),
-                               _nfs4_proc_remove(dir, name),
+               err = _nfs4_proc_remove(dir, name);
+               trace_nfs4_remove(dir, name, err);
+               err = nfs4_handle_exception(NFS_SERVER(dir), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -3270,7 +3383,7 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
 
        res->server = server;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
-       nfs41_init_sequence(&args->seq_args, &res->seq_res, 1);
+       nfs4_init_sequence(&args->seq_args, &res->seq_res, 1);
 
        nfs_fattr_init(res->dir_attr);
 }
@@ -3285,7 +3398,8 @@ static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlin
 
 static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
 {
-       struct nfs_removeres *res = task->tk_msg.rpc_resp;
+       struct nfs_unlinkdata *data = task->tk_calldata;
+       struct nfs_removeres *res = &data->res;
 
        if (!nfs4_sequence_done(task, &res->seq_res))
                return 0;
@@ -3303,7 +3417,7 @@ static void nfs4_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
 
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME];
        res->server = server;
-       nfs41_init_sequence(&arg->seq_args, &res->seq_res, 1);
+       nfs4_init_sequence(&arg->seq_args, &res->seq_res, 1);
 }
 
 static void nfs4_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data)
@@ -3317,7 +3431,8 @@ static void nfs4_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renam
 static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
                                 struct inode *new_dir)
 {
-       struct nfs_renameres *res = task->tk_msg.rpc_resp;
+       struct nfs_renamedata *data = task->tk_calldata;
+       struct nfs_renameres *res = &data->res;
 
        if (!nfs4_sequence_done(task, &res->seq_res))
                return 0;
@@ -3363,9 +3478,10 @@ static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(old_dir),
-                               _nfs4_proc_rename(old_dir, old_name,
-                                       new_dir, new_name),
+               err = _nfs4_proc_rename(old_dir, old_name,
+                                       new_dir, new_name);
+               trace_nfs4_rename(old_dir, old_name, new_dir, new_name, err);
+               err = nfs4_handle_exception(NFS_SERVER(old_dir), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -3527,9 +3643,9 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
        label = nfs4_label_init_security(dir, dentry, sattr, &l);
 
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dir),
-                               _nfs4_proc_symlink(dir, dentry, page,
-                                                       len, sattr, label),
+               err = _nfs4_proc_symlink(dir, dentry, page, len, sattr, label);
+               trace_nfs4_symlink(dir, &dentry->d_name, err);
+               err = nfs4_handle_exception(NFS_SERVER(dir), err,
                                &exception);
        } while (exception.retry);
 
@@ -3566,8 +3682,9 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
 
        sattr->ia_mode &= ~current_umask();
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dir),
-                               _nfs4_proc_mkdir(dir, dentry, sattr, label),
+               err = _nfs4_proc_mkdir(dir, dentry, sattr, label);
+               trace_nfs4_mkdir(dir, &dentry->d_name, err);
+               err = nfs4_handle_exception(NFS_SERVER(dir), err,
                                &exception);
        } while (exception.retry);
        nfs4_label_release_security(label);
@@ -3620,9 +3737,10 @@ static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dentry->d_inode),
-                               _nfs4_proc_readdir(dentry, cred, cookie,
-                                       pages, count, plus),
+               err = _nfs4_proc_readdir(dentry, cred, cookie,
+                               pages, count, plus);
+               trace_nfs4_readdir(dentry->d_inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(dentry->d_inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -3674,8 +3792,9 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
 
        sattr->ia_mode &= ~current_umask();
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dir),
-                               _nfs4_proc_mknod(dir, dentry, sattr, label, rdev),
+               err = _nfs4_proc_mknod(dir, dentry, sattr, label, rdev);
+               trace_nfs4_mknod(dir, &dentry->d_name, err);
+               err = nfs4_handle_exception(NFS_SERVER(dir), err,
                                &exception);
        } while (exception.retry);
 
@@ -3743,6 +3862,7 @@ static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, str
 
        do {
                err = _nfs4_do_fsinfo(server, fhandle, fsinfo);
+               trace_nfs4_fsinfo(server, fhandle, fsinfo->fattr, err);
                if (err == 0) {
                        struct nfs_client *clp = server->nfs_client;
 
@@ -3861,6 +3981,7 @@ static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_read_data *data)
 {
        struct nfs_server *server = NFS_SERVER(data->header->inode);
 
+       trace_nfs4_read(data, task->tk_status);
        if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) {
                rpc_restart_call_prepare(task);
                return -EAGAIN;
@@ -3904,24 +4025,29 @@ static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message
        data->timestamp   = jiffies;
        data->read_done_cb = nfs4_read_done_cb;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ];
-       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
+       nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
 }
 
-static void nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
+static int nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
 {
        if (nfs4_setup_sequence(NFS_SERVER(data->header->inode),
                        &data->args.seq_args,
                        &data->res.seq_res,
                        task))
-               return;
-       nfs4_set_rw_stateid(&data->args.stateid, data->args.context,
-                       data->args.lock_context, FMODE_READ);
+               return 0;
+       if (nfs4_set_rw_stateid(&data->args.stateid, data->args.context,
+                               data->args.lock_context, FMODE_READ) == -EIO)
+               return -EIO;
+       if (unlikely(test_bit(NFS_CONTEXT_BAD, &data->args.context->flags)))
+               return -EIO;
+       return 0;
 }
 
 static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data)
 {
        struct inode *inode = data->header->inode;
        
+       trace_nfs4_write(data, task->tk_status);
        if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) {
                rpc_restart_call_prepare(task);
                return -EAGAIN;
@@ -3987,18 +4113,22 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
        data->timestamp   = jiffies;
 
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE];
-       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
+       nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
 }
 
-static void nfs4_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
+static int nfs4_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
 {
        if (nfs4_setup_sequence(NFS_SERVER(data->header->inode),
                        &data->args.seq_args,
                        &data->res.seq_res,
                        task))
-               return;
-       nfs4_set_rw_stateid(&data->args.stateid, data->args.context,
-                       data->args.lock_context, FMODE_WRITE);
+               return 0;
+       if (nfs4_set_rw_stateid(&data->args.stateid, data->args.context,
+                               data->args.lock_context, FMODE_WRITE) == -EIO)
+               return -EIO;
+       if (unlikely(test_bit(NFS_CONTEXT_BAD, &data->args.context->flags)))
+               return -EIO;
+       return 0;
 }
 
 static void nfs4_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data)
@@ -4013,6 +4143,7 @@ static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_commit_data *da
 {
        struct inode *inode = data->inode;
 
+       trace_nfs4_commit(data, task->tk_status);
        if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) {
                rpc_restart_call_prepare(task);
                return -EAGAIN;
@@ -4035,7 +4166,7 @@ static void nfs4_proc_commit_setup(struct nfs_commit_data *data, struct rpc_mess
                data->commit_done_cb = nfs4_commit_done_cb;
        data->res.server = server;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT];
-       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
+       nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
 }
 
 struct nfs4_renewdata {
@@ -4064,6 +4195,7 @@ static void nfs4_renew_done(struct rpc_task *task, void *calldata)
        struct nfs_client *clp = data->client;
        unsigned long timestamp = data->timestamp;
 
+       trace_nfs4_renew_async(clp, task->tk_status);
        if (task->tk_status < 0) {
                /* Unless we're shutting down, schedule state recovery! */
                if (test_bit(NFS_CS_RENEWD, &clp->cl_res_state) == 0)
@@ -4321,6 +4453,7 @@ static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bufl
        ssize_t ret;
        do {
                ret = __nfs4_get_acl_uncached(inode, buf, buflen);
+               trace_nfs4_get_acl(inode, ret);
                if (ret >= 0)
                        break;
                ret = nfs4_handle_exception(NFS_SERVER(inode), ret, &exception);
@@ -4400,8 +4533,9 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(inode),
-                               __nfs4_proc_set_acl(inode, buf, buflen),
+               err = __nfs4_proc_set_acl(inode, buf, buflen);
+               trace_nfs4_set_acl(inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -4454,8 +4588,9 @@ static int nfs4_get_security_label(struct inode *inode, void *buf,
                return -EOPNOTSUPP;
 
        do {
-               err = nfs4_handle_exception(NFS_SERVER(inode),
-                               _nfs4_get_security_label(inode, buf, buflen),
+               err = _nfs4_get_security_label(inode, buf, buflen);
+               trace_nfs4_get_security_label(inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -4507,9 +4642,10 @@ static int nfs4_do_set_security_label(struct inode *inode,
        int err;
 
        do {
-               err = nfs4_handle_exception(NFS_SERVER(inode),
-                               _nfs4_do_set_security_label(inode, ilabel,
-                               fattr, olabel),
+               err = _nfs4_do_set_security_label(inode, ilabel,
+                               fattr, olabel);
+               trace_nfs4_set_security_label(inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -4632,11 +4768,11 @@ static void nfs4_init_boot_verifier(const struct nfs_client *clp,
                /* An impossible timestamp guarantees this value
                 * will never match a generated boot time. */
                verf[0] = 0;
-               verf[1] = (__be32)(NSEC_PER_SEC + 1);
+               verf[1] = cpu_to_be32(NSEC_PER_SEC + 1);
        } else {
                struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
-               verf[0] = (__be32)nn->boot_time.tv_sec;
-               verf[1] = (__be32)nn->boot_time.tv_nsec;
+               verf[0] = cpu_to_be32(nn->boot_time.tv_sec);
+               verf[1] = cpu_to_be32(nn->boot_time.tv_nsec);
        }
        memcpy(bootverf->data, verf, sizeof(bootverf->data));
 }
@@ -4662,10 +4798,14 @@ 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;
+       const 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/%s",
+                               clp->rpc_ops->version,
+                               clp->cl_minorversion,
+                               nfs4_client_id_uniquifier,
+                               nodename);
        return scnprintf(buf, len, "Linux NFSv%u.%u %s",
                                clp->rpc_ops->version, clp->cl_minorversion,
                                nodename);
@@ -4726,6 +4866,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
                clp->cl_rpcclient->cl_auth->au_ops->au_name,
                setclientid.sc_name_len, setclientid.sc_name);
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_setclientid(clp, status);
        dprintk("NFS reply setclientid: %d\n", status);
        return status;
 }
@@ -4753,6 +4894,7 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
                clp->cl_rpcclient->cl_auth->au_ops->au_name,
                clp->cl_clientid);
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_setclientid_confirm(clp, status);
        dprintk("NFS reply setclientid_confirm: %d\n", status);
        return status;
 }
@@ -4774,6 +4916,7 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
        if (!nfs4_sequence_done(task, &data->res.seq_res))
                return;
 
+       trace_nfs4_delegreturn_exit(&data->args, &data->res, task->tk_status);
        switch (task->tk_status) {
        case -NFS4ERR_STALE_STATEID:
        case -NFS4ERR_EXPIRED:
@@ -4795,7 +4938,6 @@ static void nfs4_delegreturn_release(void *calldata)
        kfree(calldata);
 }
 
-#if defined(CONFIG_NFS_V4_1)
 static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)
 {
        struct nfs4_delegreturndata *d_data;
@@ -4807,12 +4949,9 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)
                        &d_data->res.seq_res,
                        task);
 }
-#endif /* CONFIG_NFS_V4_1 */
 
 static const struct rpc_call_ops nfs4_delegreturn_ops = {
-#if defined(CONFIG_NFS_V4_1)
        .rpc_call_prepare = nfs4_delegreturn_prepare,
-#endif /* CONFIG_NFS_V4_1 */
        .rpc_call_done = nfs4_delegreturn_done,
        .rpc_release = nfs4_delegreturn_release,
 };
@@ -4837,7 +4976,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
        data = kzalloc(sizeof(*data), GFP_NOFS);
        if (data == NULL)
                return -ENOMEM;
-       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
+       nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
        data->args.fhandle = &data->fh;
        data->args.stateid = &data->stateid;
        data->args.bitmask = server->cache_consistency_bitmask;
@@ -4877,6 +5016,7 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4
        int err;
        do {
                err = _nfs4_proc_delegreturn(inode, cred, stateid, issync);
+               trace_nfs4_delegreturn(inode, err);
                switch (err) {
                        case -NFS4ERR_STALE_STATEID:
                        case -NFS4ERR_EXPIRED:
@@ -4951,8 +5091,9 @@ static int nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *
        int err;
 
        do {
-               err = nfs4_handle_exception(NFS_SERVER(state->inode),
-                               _nfs4_proc_getlk(state, cmd, request),
+               err = _nfs4_proc_getlk(state, cmd, request);
+               trace_nfs4_get_lock(request, state, cmd, err);
+               err = nfs4_handle_exception(NFS_SERVER(state->inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -5100,7 +5241,7 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
                return ERR_PTR(-ENOMEM);
        }
 
-       nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
+       nfs4_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
        msg.rpc_argp = &data->arg;
        msg.rpc_resp = &data->res;
        task_setup_data.callback_data = data;
@@ -5150,6 +5291,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
        rpc_put_task(task);
 out:
        request->fl_flags = fl_flags;
+       trace_nfs4_unlock(request, state, F_SETLK, status);
        return status;
 }
 
@@ -5335,7 +5477,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
                return -ENOMEM;
        if (IS_SETLKW(cmd))
                data->arg.block = 1;
-       nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
+       nfs4_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
        msg.rpc_argp = &data->arg;
        msg.rpc_resp = &data->res;
        task_setup_data.callback_data = data;
@@ -5373,6 +5515,7 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request
                if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
                        return 0;
                err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM);
+               trace_nfs4_lock_reclaim(request, state, F_SETLK, err);
                if (err != -NFS4ERR_DELAY)
                        break;
                nfs4_handle_exception(server, err, &exception);
@@ -5391,10 +5534,15 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
        err = nfs4_set_lock_state(state, request);
        if (err != 0)
                return err;
+       if (!recover_lost_locks) {
+               set_bit(NFS_LOCK_LOST, &request->fl_u.nfs4_fl.owner->ls_flags);
+               return 0;
+       }
        do {
                if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
                        return 0;
                err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_EXPIRED);
+               trace_nfs4_lock_expired(request, state, F_SETLK, err);
                switch (err) {
                default:
                        goto out;
@@ -5430,6 +5578,7 @@ static int nfs41_check_expired_locks(struct nfs4_state *state)
                        status = nfs41_test_stateid(server,
                                        &lsp->ls_stateid,
                                        cred);
+                       trace_nfs4_test_lock_stateid(state, lsp, status);
                        if (status != NFS_OK) {
                                /* Free the stateid unless the server
                                 * informs us the stateid is unrecognized. */
@@ -5517,6 +5666,7 @@ static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *
 
        do {
                err = _nfs4_proc_setlk(state, cmd, request);
+               trace_nfs4_set_lock(request, state, cmd, err);
                if (err == -NFS4ERR_DENIED)
                        err = -EAGAIN;
                err = nfs4_handle_exception(NFS_SERVER(state->inode),
@@ -5599,8 +5749,23 @@ struct nfs_release_lockowner_data {
        struct nfs4_lock_state *lsp;
        struct nfs_server *server;
        struct nfs_release_lockowner_args args;
+       struct nfs4_sequence_args seq_args;
+       struct nfs4_sequence_res seq_res;
 };
 
+static void nfs4_release_lockowner_prepare(struct rpc_task *task, void *calldata)
+{
+       struct nfs_release_lockowner_data *data = calldata;
+       nfs40_setup_sequence(data->server,
+                               &data->seq_args, &data->seq_res, task);
+}
+
+static void nfs4_release_lockowner_done(struct rpc_task *task, void *calldata)
+{
+       struct nfs_release_lockowner_data *data = calldata;
+       nfs40_sequence_done(task, &data->seq_res);
+}
+
 static void nfs4_release_lockowner_release(void *calldata)
 {
        struct nfs_release_lockowner_data *data = calldata;
@@ -5609,6 +5774,8 @@ static void nfs4_release_lockowner_release(void *calldata)
 }
 
 static const struct rpc_call_ops nfs4_release_lockowner_ops = {
+       .rpc_call_prepare = nfs4_release_lockowner_prepare,
+       .rpc_call_done = nfs4_release_lockowner_done,
        .rpc_release = nfs4_release_lockowner_release,
 };
 
@@ -5621,14 +5788,17 @@ static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_st
 
        if (server->nfs_client->cl_mvops->minor_version != 0)
                return -EINVAL;
+
        data = kmalloc(sizeof(*data), GFP_NOFS);
        if (!data)
                return -ENOMEM;
+       nfs4_init_sequence(&data->seq_args, &data->seq_res, 0);
        data->lsp = lsp;
        data->server = server;
        data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
        data->args.lock_owner.id = lsp->ls_seqid.owner_id;
        data->args.lock_owner.s_dev = server->s_dev;
+
        msg.rpc_argp = &data->args;
        rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data);
        return 0;
@@ -5783,14 +5953,23 @@ int nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dir),
-                               _nfs4_proc_fs_locations(client, dir, name, fs_locations, page),
+               err = _nfs4_proc_fs_locations(client, dir, name,
+                               fs_locations, page);
+               trace_nfs4_get_fs_locations(dir, name, err);
+               err = nfs4_handle_exception(NFS_SERVER(dir), err,
                                &exception);
        } while (exception.retry);
        return err;
 }
 
-static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors)
+/**
+ * If 'use_integrity' is true and the state managment nfs_client
+ * cl_rpcclient is using krb5i/p, use the integrity protected cl_rpcclient
+ * and the machine credential as per RFC3530bis and RFC5661 Security
+ * Considerations sections. Otherwise, just use the user cred with the
+ * filesystem's rpc_client.
+ */
+static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors, bool use_integrity)
 {
        int status;
        struct nfs4_secinfo_arg args = {
@@ -5805,10 +5984,21 @@ static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
+       struct rpc_clnt *clnt = NFS_SERVER(dir)->client;
+
+       if (use_integrity) {
+               clnt = NFS_SERVER(dir)->nfs_client->cl_rpcclient;
+               msg.rpc_cred = nfs4_get_clid_cred(NFS_SERVER(dir)->nfs_client);
+       }
 
        dprintk("NFS call  secinfo %s\n", name->name);
-       status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0);
+       status = nfs4_call_sync(clnt, NFS_SERVER(dir), &msg, &args.seq_args,
+                               &res.seq_res, 0);
        dprintk("NFS reply  secinfo: %d\n", status);
+
+       if (msg.rpc_cred)
+               put_rpccred(msg.rpc_cred);
+
        return status;
 }
 
@@ -5818,8 +6008,23 @@ int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name,
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dir),
-                               _nfs4_proc_secinfo(dir, name, flavors),
+               err = -NFS4ERR_WRONGSEC;
+
+               /* try to use integrity protection with machine cred */
+               if (_nfs4_is_integrity_protected(NFS_SERVER(dir)->nfs_client))
+                       err = _nfs4_proc_secinfo(dir, name, flavors, true);
+
+               /*
+                * if unable to use integrity protection, or SECINFO with
+                * integrity protection returns NFS4ERR_WRONGSEC (which is
+                * disallowed by spec, but exists in deployed servers) use
+                * the current filesystem's rpc_client and the user cred.
+                */
+               if (err == -NFS4ERR_WRONGSEC)
+                       err = _nfs4_proc_secinfo(dir, name, flavors, false);
+
+               trace_nfs4_secinfo(dir, name, err);
+               err = nfs4_handle_exception(NFS_SERVER(dir), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -5883,6 +6088,7 @@ int nfs4_proc_bind_conn_to_session(struct nfs_client *clp, struct rpc_cred *cred
        }
 
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_bind_conn_to_session(clp, status);
        if (status == 0) {
                if (memcmp(res.session->sess_id.data,
                    clp->cl_session->sess_id.data, NFS4_MAX_SESSIONID_LEN)) {
@@ -5911,16 +6117,87 @@ out:
 }
 
 /*
- * nfs4_proc_exchange_id()
+ * Minimum set of SP4_MACH_CRED operations from RFC 5661
+ */
+static const struct nfs41_state_protection nfs4_sp4_mach_cred_request = {
+       .how = SP4_MACH_CRED,
+       .enforce.u.words = {
+               [1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) |
+                     1 << (OP_EXCHANGE_ID - 32) |
+                     1 << (OP_CREATE_SESSION - 32) |
+                     1 << (OP_DESTROY_SESSION - 32) |
+                     1 << (OP_DESTROY_CLIENTID - 32)
+       }
+};
+
+/*
+ * Select the state protection mode for client `clp' given the server results
+ * from exchange_id in `sp'.
  *
- * Returns zero, a negative errno, or a negative NFS4ERR status code.
+ * Returns 0 on success, negative errno otherwise.
+ */
+static int nfs4_sp4_select_mode(struct nfs_client *clp,
+                                struct nfs41_state_protection *sp)
+{
+       static const u32 supported_enforce[NFS4_OP_MAP_NUM_WORDS] = {
+               [1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) |
+                     1 << (OP_EXCHANGE_ID - 32) |
+                     1 << (OP_CREATE_SESSION - 32) |
+                     1 << (OP_DESTROY_SESSION - 32) |
+                     1 << (OP_DESTROY_CLIENTID - 32)
+       };
+       unsigned int i;
+
+       if (sp->how == SP4_MACH_CRED) {
+               /* Print state protect result */
+               dfprintk(MOUNT, "Server SP4_MACH_CRED support:\n");
+               for (i = 0; i <= LAST_NFS4_OP; i++) {
+                       if (test_bit(i, sp->enforce.u.longs))
+                               dfprintk(MOUNT, "  enforce op %d\n", i);
+                       if (test_bit(i, sp->allow.u.longs))
+                               dfprintk(MOUNT, "  allow op %d\n", i);
+               }
+
+               /* make sure nothing is on enforce list that isn't supported */
+               for (i = 0; i < NFS4_OP_MAP_NUM_WORDS; i++) {
+                       if (sp->enforce.u.words[i] & ~supported_enforce[i]) {
+                               dfprintk(MOUNT, "sp4_mach_cred: disabled\n");
+                               return -EINVAL;
+                       }
+               }
+
+               /*
+                * Minimal mode - state operations are allowed to use machine
+                * credential.  Note this already happens by default, so the
+                * client doesn't have to do anything more than the negotiation.
+                *
+                * NOTE: we don't care if EXCHANGE_ID is in the list -
+                *       we're already using the machine cred for exchange_id
+                *       and will never use a different cred.
+                */
+               if (test_bit(OP_BIND_CONN_TO_SESSION, sp->enforce.u.longs) &&
+                   test_bit(OP_CREATE_SESSION, sp->enforce.u.longs) &&
+                   test_bit(OP_DESTROY_SESSION, sp->enforce.u.longs) &&
+                   test_bit(OP_DESTROY_CLIENTID, sp->enforce.u.longs)) {
+                       dfprintk(MOUNT, "sp4_mach_cred:\n");
+                       dfprintk(MOUNT, "  minimal mode enabled\n");
+                       set_bit(NFS_SP4_MACH_CRED_MINIMAL, &clp->cl_sp4_flags);
+               } else {
+                       dfprintk(MOUNT, "sp4_mach_cred: disabled\n");
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * _nfs4_proc_exchange_id()
  *
- * Since the clientid has expired, all compounds using sessions
- * associated with the stale clientid will be returning
- * NFS4ERR_BADSESSION in the sequence operation, and will therefore
- * be in some phase of session reset.
+ * Wrapper for EXCHANGE_ID operation.
  */
-int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
+static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
+       u32 sp4_how)
 {
        nfs4_verifier verifier;
        struct nfs41_exchange_id_args args = {
@@ -5967,10 +6244,30 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
                goto out_server_scope;
        }
 
+       switch (sp4_how) {
+       case SP4_NONE:
+               args.state_protect.how = SP4_NONE;
+               break;
+
+       case SP4_MACH_CRED:
+               args.state_protect = nfs4_sp4_mach_cred_request;
+               break;
+
+       default:
+               /* unsupported! */
+               WARN_ON_ONCE(1);
+               status = -EINVAL;
+               goto out_server_scope;
+       }
+
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_exchange_id(clp, status);
        if (status == 0)
                status = nfs4_check_cl_exchange_flags(res.flags);
 
+       if (status == 0)
+               status = nfs4_sp4_select_mode(clp, &res.state_protect);
+
        if (status == 0) {
                clp->cl_clientid = res.clientid;
                clp->cl_exchange_flags = (res.flags & ~EXCHGID4_FLAG_CONFIRMED_R);
@@ -6017,6 +6314,35 @@ out:
        return status;
 }
 
+/*
+ * nfs4_proc_exchange_id()
+ *
+ * Returns zero, a negative errno, or a negative NFS4ERR status code.
+ *
+ * Since the clientid has expired, all compounds using sessions
+ * associated with the stale clientid will be returning
+ * NFS4ERR_BADSESSION in the sequence operation, and will therefore
+ * be in some phase of session reset.
+ *
+ * Will attempt to negotiate SP4_MACH_CRED if krb5i / krb5p auth is used.
+ */
+int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
+{
+       rpc_authflavor_t authflavor = clp->cl_rpcclient->cl_auth->au_flavor;
+       int status;
+
+       /* try SP4_MACH_CRED if krb5i/p */
+       if (authflavor == RPC_AUTH_GSS_KRB5I ||
+           authflavor == RPC_AUTH_GSS_KRB5P) {
+               status = _nfs4_proc_exchange_id(clp, cred, SP4_MACH_CRED);
+               if (!status)
+                       return 0;
+       }
+
+       /* try SP4_NONE */
+       return _nfs4_proc_exchange_id(clp, cred, SP4_NONE);
+}
+
 static int _nfs4_proc_destroy_clientid(struct nfs_client *clp,
                struct rpc_cred *cred)
 {
@@ -6028,6 +6354,7 @@ static int _nfs4_proc_destroy_clientid(struct nfs_client *clp,
        int status;
 
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_destroy_clientid(clp, status);
        if (status)
                dprintk("NFS: Got error %d from the server %s on "
                        "DESTROY_CLIENTID.", status, clp->cl_hostname);
@@ -6065,7 +6392,7 @@ int nfs4_destroy_clientid(struct nfs_client *clp)
                goto out;
        if (clp->cl_preserve_clid)
                goto out;
-       cred = nfs4_get_exchange_id_cred(clp);
+       cred = nfs4_get_clid_cred(clp);
        ret = nfs4_proc_destroy_clientid(clp, cred);
        if (cred)
                put_rpccred(cred);
@@ -6157,7 +6484,7 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
        };
        int status;
 
-       nfs41_init_sequence(&args.la_seq_args, &res.lr_seq_res, 0);
+       nfs4_init_sequence(&args.la_seq_args, &res.lr_seq_res, 0);
        nfs4_set_sequence_privileged(&args.la_seq_args);
        dprintk("--> %s\n", __func__);
        task = rpc_run_task(&task_setup);
@@ -6291,6 +6618,7 @@ static int _nfs4_proc_create_session(struct nfs_client *clp,
        args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN);
 
        status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_create_session(clp, status);
 
        if (!status) {
                /* Verify the session's negotiated channel_attrs values */
@@ -6354,6 +6682,7 @@ int nfs4_proc_destroy_session(struct nfs4_session *session,
                return status;
 
        status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_destroy_session(session->clp, status);
 
        if (status)
                dprintk("NFS: Got error %d from the server on DESTROY_SESSION. "
@@ -6403,6 +6732,7 @@ static void nfs41_sequence_call_done(struct rpc_task *task, void *data)
        if (!nfs41_sequence_done(task, task->tk_msg.rpc_resp))
                return;
 
+       trace_nfs4_sequence(clp, task->tk_status);
        if (task->tk_status < 0) {
                dprintk("%s ERROR %d\n", __func__, task->tk_status);
                if (atomic_read(&clp->cl_count) == 1)
@@ -6460,7 +6790,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp,
                nfs_put_client(clp);
                return ERR_PTR(-ENOMEM);
        }
-       nfs41_init_sequence(&calldata->args, &calldata->res, 0);
+       nfs4_init_sequence(&calldata->args, &calldata->res, 0);
        if (is_privileged)
                nfs4_set_sequence_privileged(&calldata->args);
        msg.rpc_argp = &calldata->args;
@@ -6555,6 +6885,7 @@ static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data)
        if (!nfs41_sequence_done(task, res))
                return;
 
+       trace_nfs4_reclaim_complete(clp, task->tk_status);
        if (nfs41_reclaim_complete_handle_errors(task, clp) == -EAGAIN) {
                rpc_restart_call_prepare(task);
                return;
@@ -6602,7 +6933,7 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp,
        calldata->clp = clp;
        calldata->arg.one_fs = 0;
 
-       nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 0);
+       nfs4_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 0);
        nfs4_set_sequence_privileged(&calldata->arg.seq_args);
        msg.rpc_argp = &calldata->arg;
        msg.rpc_resp = &calldata->res;
@@ -6793,7 +7124,7 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
 
        lgp->res.layoutp = &lgp->args.layout;
        lgp->res.seq_res.sr_slot = NULL;
-       nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
+       nfs4_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
 
        /* nfs4_layoutget_release calls pnfs_put_layout_hdr */
        pnfs_get_layout_hdr(NFS_I(inode)->layout);
@@ -6804,6 +7135,10 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
        status = nfs4_wait_for_completion_rpc_task(task);
        if (status == 0)
                status = task->tk_status;
+       trace_nfs4_layoutget(lgp->args.ctx,
+                       &lgp->args.range,
+                       &lgp->res.range,
+                       status);
        /* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */
        if (status == 0 && lgp->res.layoutp->len)
                lseg = pnfs_layout_process(lgp);
@@ -6876,7 +7211,7 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp)
                .rpc_cred = lrp->cred,
        };
        struct rpc_task_setup task_setup_data = {
-               .rpc_client = lrp->clp->cl_rpcclient,
+               .rpc_client = NFS_SERVER(lrp->args.inode)->client,
                .rpc_message = &msg,
                .callback_ops = &nfs4_layoutreturn_call_ops,
                .callback_data = lrp,
@@ -6884,11 +7219,12 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp)
        int status;
 
        dprintk("--> %s\n", __func__);
-       nfs41_init_sequence(&lrp->args.seq_args, &lrp->res.seq_res, 1);
+       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;
+       trace_nfs4_layoutreturn(lrp->args.inode, status);
        dprintk("<-- %s status=%d\n", __func__, status);
        rpc_put_task(task);
        return status;
@@ -7065,7 +7401,7 @@ nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)
                data->args.lastbytewritten,
                data->args.inode->i_ino);
 
-       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
+       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);
@@ -7075,12 +7411,17 @@ nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)
        if (status != 0)
                goto out;
        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;
 }
 
+/**
+ * Use the state managment nfs_client cl_rpcclient, which uses krb5i (if
+ * possible) as per RFC3530bis and RFC5661 Security Considerations sections
+ */
 static int
 _nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
                    struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors)
@@ -7096,7 +7437,8 @@ _nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
-       return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
+       return nfs4_call_sync(server->nfs_client->cl_rpcclient, server, &msg,
+                               &args.seq_args, &res.seq_res, 0);
 }
 
 static int
@@ -7178,7 +7520,7 @@ static int _nfs41_test_stateid(struct nfs_server *server,
        };
 
        dprintk("NFS call  test_stateid %p\n", stateid);
-       nfs41_init_sequence(&args.seq_args, &res.seq_res, 0);
+       nfs4_init_sequence(&args.seq_args, &res.seq_res, 0);
        nfs4_set_sequence_privileged(&args.seq_args);
        status = nfs4_call_sync_sequence(server->client, server, &msg,
                        &args.seq_args, &res.seq_res);
@@ -7249,7 +7591,7 @@ static void nfs41_free_stateid_release(void *calldata)
        kfree(calldata);
 }
 
-const struct rpc_call_ops nfs41_free_stateid_ops = {
+static const struct rpc_call_ops nfs41_free_stateid_ops = {
        .rpc_call_prepare = nfs41_free_stateid_prepare,
        .rpc_call_done = nfs41_free_stateid_done,
        .rpc_release = nfs41_free_stateid_release,
@@ -7283,7 +7625,7 @@ static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server,
 
        msg.rpc_argp = &data->args;
        msg.rpc_resp = &data->res;
-       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
+       nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
        if (privileged)
                nfs4_set_sequence_privileged(&data->args.seq_args);
 
@@ -7359,7 +7701,6 @@ static const struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
        .recover_open   = nfs4_open_reclaim,
        .recover_lock   = nfs4_lock_reclaim,
        .establish_clid = nfs4_init_clientid,
-       .get_clid_cred  = nfs4_get_setclientid_cred,
        .detect_trunking = nfs40_discover_server_trunking,
 };
 
@@ -7370,7 +7711,6 @@ static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
        .recover_open   = nfs4_open_reclaim,
        .recover_lock   = nfs4_lock_reclaim,
        .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,
 };
@@ -7382,7 +7722,6 @@ static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {
        .recover_open   = nfs4_open_expired,
        .recover_lock   = nfs4_lock_expired,
        .establish_clid = nfs4_init_clientid,
-       .get_clid_cred  = nfs4_get_setclientid_cred,
 };
 
 #if defined(CONFIG_NFS_V4_1)
@@ -7392,7 +7731,6 @@ static const struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = {
        .recover_open   = nfs41_open_expired,
        .recover_lock   = nfs41_lock_expired,
        .establish_clid = nfs41_init_clientid,
-       .get_clid_cred  = nfs4_get_exchange_id_cred,
 };
 #endif /* CONFIG_NFS_V4_1 */
 
@@ -7416,10 +7754,12 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
                | NFS_CAP_ATOMIC_OPEN
                | NFS_CAP_CHANGE_ATTR
                | NFS_CAP_POSIX_LOCK,
-       .call_sync = _nfs4_call_sync,
+       .init_client = nfs40_init_client,
+       .shutdown_client = nfs40_shutdown_client,
        .match_stateid = nfs4_match_stateid,
        .find_root_sec = nfs4_find_root_sec,
        .free_lock_state = nfs4_release_lockowner,
+       .call_sync_ops = &nfs40_call_sync_ops,
        .reboot_recovery_ops = &nfs40_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs40_nograce_recovery_ops,
        .state_renewal_ops = &nfs40_state_renewal_ops,
@@ -7434,10 +7774,12 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
                | NFS_CAP_POSIX_LOCK
                | NFS_CAP_STATEID_NFSV41
                | NFS_CAP_ATOMIC_OPEN_V1,
-       .call_sync = nfs4_call_sync_sequence,
+       .init_client = nfs41_init_client,
+       .shutdown_client = nfs41_shutdown_client,
        .match_stateid = nfs41_match_stateid,
        .find_root_sec = nfs41_find_root_sec,
        .free_lock_state = nfs41_free_lock_state,
+       .call_sync_ops = &nfs41_call_sync_ops,
        .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
        .state_renewal_ops = &nfs41_state_renewal_ops,
@@ -7453,10 +7795,12 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
                | NFS_CAP_POSIX_LOCK
                | NFS_CAP_STATEID_NFSV41
                | NFS_CAP_ATOMIC_OPEN_V1,
-       .call_sync = nfs4_call_sync_sequence,
+       .init_client = nfs41_init_client,
+       .shutdown_client = nfs41_shutdown_client,
        .match_stateid = nfs41_match_stateid,
        .find_root_sec = nfs41_find_root_sec,
        .free_lock_state = nfs41_free_lock_state,
+       .call_sync_ops = &nfs41_call_sync_ops,
        .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
        .state_renewal_ops = &nfs41_state_renewal_ops,
@@ -7473,7 +7817,7 @@ const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {
 #endif
 };
 
-const struct inode_operations nfs4_dir_inode_operations = {
+static const struct inode_operations nfs4_dir_inode_operations = {
        .create         = nfs_create,
        .lookup         = nfs_lookup,
        .atomic_open    = nfs_atomic_open,