|
@@ -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)
|
|
@@ -150,6 +152,7 @@ static int nfs4_map_errors(int err)
|
|
|
case -NFS4ERR_RECALLCONFLICT:
|
|
|
return -EREMOTEIO;
|
|
|
case -NFS4ERR_WRONGSEC:
|
|
|
+ case -NFS4ERR_WRONG_CRED:
|
|
|
return -EPERM;
|
|
|
case -NFS4ERR_BADOWNER:
|
|
|
case -NFS4ERR_BADNAME:
|
|
@@ -433,6 +436,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 +464,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 +605,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 +691,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 +733,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 +744,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 +760,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 +793,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 +803,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 +847,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 +856,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 +870,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 +878,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 +1019,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 +1189,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 +1526,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 +1611,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 +1653,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 +1681,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 +1841,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 +1994,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 +2044,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 +2087,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 +2299,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 +2413,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 +2491,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
|
|
|
*/
|
|
@@ -2511,10 +2616,13 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
|
|
|
};
|
|
|
int status = -ENOMEM;
|
|
|
|
|
|
+ nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_CLEANUP,
|
|
|
+ &task_setup_data.rpc_client, &msg);
|
|
|
+
|
|
|
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 +2798,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 +2814,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;
|
|
@@ -2772,18 +2884,27 @@ static int nfs4_do_find_root_sec(struct nfs_server *server,
|
|
|
* @server: initialized nfs_server handle
|
|
|
* @fhandle: we fill in the pseudo-fs root file handle
|
|
|
* @info: we fill in an FSINFO struct
|
|
|
+ * @auth_probe: probe the auth flavours
|
|
|
*
|
|
|
* Returns zero on success, or a negative errno.
|
|
|
*/
|
|
|
int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle,
|
|
|
- struct nfs_fsinfo *info)
|
|
|
+ struct nfs_fsinfo *info,
|
|
|
+ bool auth_probe)
|
|
|
{
|
|
|
int status;
|
|
|
|
|
|
- status = nfs4_lookup_root(server, fhandle, info);
|
|
|
- if ((status == -NFS4ERR_WRONGSEC) &&
|
|
|
- !(server->flags & NFS_MOUNT_SECFLAVOUR))
|
|
|
+ switch (auth_probe) {
|
|
|
+ case false:
|
|
|
+ status = nfs4_lookup_root(server, fhandle, info);
|
|
|
+ if (status != -NFS4ERR_WRONGSEC)
|
|
|
+ break;
|
|
|
+ /* Did user force a 'sec=' mount option? */
|
|
|
+ if (server->flags & NFS_MOUNT_SECFLAVOUR)
|
|
|
+ break;
|
|
|
+ default:
|
|
|
status = nfs4_do_find_root_sec(server, fhandle, info);
|
|
|
+ }
|
|
|
|
|
|
if (status == 0)
|
|
|
status = nfs4_server_capabilities(server, fhandle);
|
|
@@ -2899,8 +3020,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 +3062,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 +3142,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;
|
|
@@ -3031,7 +3154,9 @@ static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir,
|
|
|
err = -EPERM;
|
|
|
if (client != *clnt)
|
|
|
goto out;
|
|
|
-
|
|
|
+ /* No security negotiation if the user specified 'sec=' */
|
|
|
+ if (NFS_SERVER(dir)->flags & NFS_MOUNT_SECFLAVOUR)
|
|
|
+ goto out;
|
|
|
client = nfs4_create_sec_client(client, dir, name);
|
|
|
if (IS_ERR(client))
|
|
|
return PTR_ERR(client);
|
|
@@ -3134,8 +3259,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;
|
|
@@ -3188,8 +3314,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;
|
|
@@ -3253,8 +3380,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;
|
|
@@ -3268,7 +3396,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);
|
|
|
}
|
|
@@ -3283,7 +3411,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;
|
|
@@ -3301,7 +3430,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)
|
|
@@ -3315,7 +3444,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;
|
|
@@ -3361,9 +3491,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;
|
|
@@ -3525,9 +3656,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);
|
|
|
|
|
@@ -3564,8 +3695,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);
|
|
@@ -3618,9 +3750,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;
|
|
@@ -3672,8 +3805,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);
|
|
|
|
|
@@ -3741,6 +3875,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;
|
|
|
|
|
@@ -3859,6 +3994,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;
|
|
@@ -3902,24 +4038,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;
|
|
@@ -3985,18 +4126,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)
|
|
@@ -4011,6 +4156,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;
|
|
@@ -4033,7 +4179,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 {
|
|
@@ -4062,6 +4208,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)
|
|
@@ -4319,6 +4466,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);
|
|
@@ -4398,8 +4546,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;
|
|
@@ -4452,8 +4601,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;
|
|
@@ -4505,9 +4655,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;
|
|
@@ -4630,11 +4781,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));
|
|
|
}
|
|
@@ -4660,10 +4811,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);
|
|
@@ -4724,6 +4879,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;
|
|
|
}
|
|
@@ -4751,6 +4907,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;
|
|
|
}
|
|
@@ -4772,6 +4929,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:
|
|
@@ -4793,7 +4951,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;
|
|
@@ -4805,12 +4962,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,
|
|
|
};
|
|
@@ -4835,7 +4989,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;
|
|
@@ -4875,6 +5029,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:
|
|
@@ -4949,8 +5104,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;
|
|
@@ -5087,6 +5243,9 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
|
|
|
.flags = RPC_TASK_ASYNC,
|
|
|
};
|
|
|
|
|
|
+ nfs4_state_protect(NFS_SERVER(lsp->ls_state->inode)->nfs_client,
|
|
|
+ NFS_SP4_MACH_CRED_CLEANUP, &task_setup_data.rpc_client, &msg);
|
|
|
+
|
|
|
/* Ensure this is an unlock - when canceling a lock, the
|
|
|
* canceled lock is passed in, and it won't be an unlock.
|
|
|
*/
|
|
@@ -5098,7 +5257,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;
|
|
@@ -5148,6 +5307,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;
|
|
|
}
|
|
|
|
|
@@ -5333,7 +5493,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;
|
|
@@ -5371,6 +5531,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);
|
|
@@ -5389,10 +5550,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;
|
|
@@ -5428,6 +5594,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. */
|
|
@@ -5515,6 +5682,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),
|
|
@@ -5597,8 +5765,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;
|
|
@@ -5607,6 +5790,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,
|
|
|
};
|
|
|
|
|
@@ -5619,14 +5804,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;
|
|
@@ -5781,14 +5969,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 = {
|
|
@@ -5803,10 +6000,25 @@ 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);
|
|
|
+
|
|
|
+ nfs4_state_protect(NFS_SERVER(dir)->nfs_client,
|
|
|
+ NFS_SP4_MACH_CRED_SECINFO, &clnt, &msg);
|
|
|
+
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
@@ -5816,8 +6028,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;
|
|
@@ -5881,6 +6108,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)) {
|
|
@@ -5909,16 +6137,124 @@ out:
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * nfs4_proc_exchange_id()
|
|
|
+ * Minimum set of SP4_MACH_CRED operations from RFC 5661 in the enforce map
|
|
|
+ * and operations we'd like to see to enable certain features in the allow map
|
|
|
+ */
|
|
|
+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)
|
|
|
+ },
|
|
|
+ .allow.u.words = {
|
|
|
+ [0] = 1 << (OP_CLOSE) |
|
|
|
+ 1 << (OP_LOCKU),
|
|
|
+ [1] = 1 << (OP_SECINFO - 32) |
|
|
|
+ 1 << (OP_SECINFO_NO_NAME - 32) |
|
|
|
+ 1 << (OP_TEST_STATEID - 32) |
|
|
|
+ 1 << (OP_FREE_STATEID - 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (test_bit(OP_CLOSE, sp->allow.u.longs) &&
|
|
|
+ test_bit(OP_LOCKU, sp->allow.u.longs)) {
|
|
|
+ dfprintk(MOUNT, " cleanup mode enabled\n");
|
|
|
+ set_bit(NFS_SP4_MACH_CRED_CLEANUP, &clp->cl_sp4_flags);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (test_bit(OP_SECINFO, sp->allow.u.longs) &&
|
|
|
+ test_bit(OP_SECINFO_NO_NAME, sp->allow.u.longs)) {
|
|
|
+ dfprintk(MOUNT, " secinfo mode enabled\n");
|
|
|
+ set_bit(NFS_SP4_MACH_CRED_SECINFO, &clp->cl_sp4_flags);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (test_bit(OP_TEST_STATEID, sp->allow.u.longs) &&
|
|
|
+ test_bit(OP_FREE_STATEID, sp->allow.u.longs)) {
|
|
|
+ dfprintk(MOUNT, " stateid mode enabled\n");
|
|
|
+ set_bit(NFS_SP4_MACH_CRED_STATEID, &clp->cl_sp4_flags);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (test_bit(OP_WRITE, sp->allow.u.longs)) {
|
|
|
+ dfprintk(MOUNT, " write mode enabled\n");
|
|
|
+ set_bit(NFS_SP4_MACH_CRED_WRITE, &clp->cl_sp4_flags);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (test_bit(OP_COMMIT, sp->allow.u.longs)) {
|
|
|
+ dfprintk(MOUNT, " commit mode enabled\n");
|
|
|
+ set_bit(NFS_SP4_MACH_CRED_COMMIT, &clp->cl_sp4_flags);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ 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 = {
|
|
@@ -5965,10 +6301,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);
|
|
@@ -6015,6 +6371,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)
|
|
|
{
|
|
@@ -6026,6 +6411,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);
|
|
@@ -6063,7 +6449,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);
|
|
@@ -6155,7 +6541,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);
|
|
@@ -6289,6 +6675,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 */
|
|
@@ -6352,6 +6739,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. "
|
|
@@ -6401,6 +6789,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)
|
|
@@ -6458,7 +6847,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;
|
|
@@ -6553,6 +6942,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;
|
|
@@ -6600,7 +6990,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;
|
|
@@ -6791,7 +7181,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);
|
|
@@ -6802,6 +7192,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);
|
|
@@ -6874,7 +7268,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,
|
|
@@ -6882,11 +7276,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;
|
|
@@ -7063,7 +7458,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);
|
|
@@ -7073,15 +7468,21 @@ 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)
|
|
|
+ struct nfs_fsinfo *info,
|
|
|
+ struct nfs4_secinfo_flavors *flavors, bool use_integrity)
|
|
|
{
|
|
|
struct nfs41_secinfo_no_name_args args = {
|
|
|
.style = SECINFO_STYLE_CURRENT_FH,
|
|
@@ -7094,7 +7495,23 @@ _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);
|
|
|
+ struct rpc_clnt *clnt = server->client;
|
|
|
+ int status;
|
|
|
+
|
|
|
+ if (use_integrity) {
|
|
|
+ clnt = server->nfs_client->cl_rpcclient;
|
|
|
+ msg.rpc_cred = nfs4_get_clid_cred(server->nfs_client);
|
|
|
+ }
|
|
|
+
|
|
|
+ dprintk("--> %s\n", __func__);
|
|
|
+ status = nfs4_call_sync(clnt, server, &msg, &args.seq_args,
|
|
|
+ &res.seq_res, 0);
|
|
|
+ dprintk("<-- %s status=%d\n", __func__, status);
|
|
|
+
|
|
|
+ if (msg.rpc_cred)
|
|
|
+ put_rpccred(msg.rpc_cred);
|
|
|
+
|
|
|
+ return status;
|
|
|
}
|
|
|
|
|
|
static int
|
|
@@ -7104,7 +7521,24 @@ nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
|
|
|
struct nfs4_exception exception = { };
|
|
|
int err;
|
|
|
do {
|
|
|
- err = _nfs41_proc_secinfo_no_name(server, fhandle, info, flavors);
|
|
|
+ /* first try using integrity protection */
|
|
|
+ err = -NFS4ERR_WRONGSEC;
|
|
|
+
|
|
|
+ /* try to use integrity protection with machine cred */
|
|
|
+ if (_nfs4_is_integrity_protected(server->nfs_client))
|
|
|
+ err = _nfs41_proc_secinfo_no_name(server, fhandle, info,
|
|
|
+ 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 = _nfs41_proc_secinfo_no_name(server, fhandle, info,
|
|
|
+ flavors, false);
|
|
|
+
|
|
|
switch (err) {
|
|
|
case 0:
|
|
|
case -NFS4ERR_WRONGSEC:
|
|
@@ -7174,11 +7608,15 @@ static int _nfs41_test_stateid(struct nfs_server *server,
|
|
|
.rpc_resp = &res,
|
|
|
.rpc_cred = cred,
|
|
|
};
|
|
|
+ struct rpc_clnt *rpc_client = server->client;
|
|
|
+
|
|
|
+ nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
|
|
|
+ &rpc_client, &msg);
|
|
|
|
|
|
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,
|
|
|
+ status = nfs4_call_sync_sequence(rpc_client, server, &msg,
|
|
|
&args.seq_args, &res.seq_res);
|
|
|
if (status != NFS_OK) {
|
|
|
dprintk("NFS reply test_stateid: failed, %d\n", status);
|
|
@@ -7247,7 +7685,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,
|
|
@@ -7270,6 +7708,9 @@ static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server,
|
|
|
};
|
|
|
struct nfs_free_stateid_data *data;
|
|
|
|
|
|
+ nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
|
|
|
+ &task_setup.rpc_client, &msg);
|
|
|
+
|
|
|
dprintk("NFS call free_stateid %p\n", stateid);
|
|
|
data = kmalloc(sizeof(*data), GFP_NOFS);
|
|
|
if (!data)
|
|
@@ -7281,7 +7722,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);
|
|
|
|
|
@@ -7357,7 +7798,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,
|
|
|
};
|
|
|
|
|
@@ -7368,7 +7808,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,
|
|
|
};
|
|
@@ -7380,7 +7819,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)
|
|
@@ -7390,7 +7828,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 */
|
|
|
|
|
@@ -7414,10 +7851,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,
|
|
@@ -7432,10 +7871,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,
|
|
@@ -7451,10 +7892,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,
|
|
@@ -7471,7 +7914,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,
|