|
@@ -303,15 +303,19 @@ do_state_recovery:
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-static void renew_lease(const struct nfs_server *server, unsigned long timestamp)
|
|
|
|
|
|
+static void do_renew_lease(struct nfs_client *clp, unsigned long timestamp)
|
|
{
|
|
{
|
|
- struct nfs_client *clp = server->nfs_client;
|
|
|
|
spin_lock(&clp->cl_lock);
|
|
spin_lock(&clp->cl_lock);
|
|
if (time_before(clp->cl_last_renewal,timestamp))
|
|
if (time_before(clp->cl_last_renewal,timestamp))
|
|
clp->cl_last_renewal = timestamp;
|
|
clp->cl_last_renewal = timestamp;
|
|
spin_unlock(&clp->cl_lock);
|
|
spin_unlock(&clp->cl_lock);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void renew_lease(const struct nfs_server *server, unsigned long timestamp)
|
|
|
|
+{
|
|
|
|
+ do_renew_lease(server->nfs_client, timestamp);
|
|
|
|
+}
|
|
|
|
+
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -356,7 +360,7 @@ static void nfs41_check_drain_session_complete(struct nfs4_session *ses)
|
|
{
|
|
{
|
|
struct rpc_task *task;
|
|
struct rpc_task *task;
|
|
|
|
|
|
- if (!test_bit(NFS4CLNT_SESSION_DRAINING, &ses->clp->cl_state)) {
|
|
|
|
|
|
+ if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
|
|
task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq);
|
|
task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq);
|
|
if (task)
|
|
if (task)
|
|
rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
|
|
rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
|
|
@@ -370,12 +374,11 @@ static void nfs41_check_drain_session_complete(struct nfs4_session *ses)
|
|
complete(&ses->complete);
|
|
complete(&ses->complete);
|
|
}
|
|
}
|
|
|
|
|
|
-static void nfs41_sequence_free_slot(const struct nfs_client *clp,
|
|
|
|
- struct nfs4_sequence_res *res)
|
|
|
|
|
|
+static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
|
|
{
|
|
{
|
|
struct nfs4_slot_table *tbl;
|
|
struct nfs4_slot_table *tbl;
|
|
|
|
|
|
- tbl = &clp->cl_session->fc_slot_table;
|
|
|
|
|
|
+ tbl = &res->sr_session->fc_slot_table;
|
|
if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) {
|
|
if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) {
|
|
/* just wake up the next guy waiting since
|
|
/* just wake up the next guy waiting since
|
|
* we may have not consumed a slot after all */
|
|
* we may have not consumed a slot after all */
|
|
@@ -385,18 +388,17 @@ static void nfs41_sequence_free_slot(const struct nfs_client *clp,
|
|
|
|
|
|
spin_lock(&tbl->slot_tbl_lock);
|
|
spin_lock(&tbl->slot_tbl_lock);
|
|
nfs4_free_slot(tbl, res->sr_slotid);
|
|
nfs4_free_slot(tbl, res->sr_slotid);
|
|
- nfs41_check_drain_session_complete(clp->cl_session);
|
|
|
|
|
|
+ nfs41_check_drain_session_complete(res->sr_session);
|
|
spin_unlock(&tbl->slot_tbl_lock);
|
|
spin_unlock(&tbl->slot_tbl_lock);
|
|
res->sr_slotid = NFS4_MAX_SLOT_TABLE;
|
|
res->sr_slotid = NFS4_MAX_SLOT_TABLE;
|
|
}
|
|
}
|
|
|
|
|
|
-static void nfs41_sequence_done(struct nfs_client *clp,
|
|
|
|
- struct nfs4_sequence_res *res,
|
|
|
|
- int rpc_status)
|
|
|
|
|
|
+static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
|
|
{
|
|
{
|
|
unsigned long timestamp;
|
|
unsigned long timestamp;
|
|
struct nfs4_slot_table *tbl;
|
|
struct nfs4_slot_table *tbl;
|
|
struct nfs4_slot *slot;
|
|
struct nfs4_slot *slot;
|
|
|
|
+ struct nfs_client *clp;
|
|
|
|
|
|
/*
|
|
/*
|
|
* sr_status remains 1 if an RPC level error occurred. The server
|
|
* sr_status remains 1 if an RPC level error occurred. The server
|
|
@@ -411,25 +413,51 @@ static void nfs41_sequence_done(struct nfs_client *clp,
|
|
if (res->sr_slotid == NFS4_MAX_SLOT_TABLE)
|
|
if (res->sr_slotid == NFS4_MAX_SLOT_TABLE)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
|
|
+ tbl = &res->sr_session->fc_slot_table;
|
|
|
|
+ slot = tbl->slots + res->sr_slotid;
|
|
|
|
+
|
|
/* Check the SEQUENCE operation status */
|
|
/* Check the SEQUENCE operation status */
|
|
- if (res->sr_status == 0) {
|
|
|
|
- tbl = &clp->cl_session->fc_slot_table;
|
|
|
|
- slot = tbl->slots + res->sr_slotid;
|
|
|
|
|
|
+ switch (res->sr_status) {
|
|
|
|
+ case 0:
|
|
/* Update the slot's sequence and clientid lease timer */
|
|
/* Update the slot's sequence and clientid lease timer */
|
|
++slot->seq_nr;
|
|
++slot->seq_nr;
|
|
timestamp = res->sr_renewal_time;
|
|
timestamp = res->sr_renewal_time;
|
|
- spin_lock(&clp->cl_lock);
|
|
|
|
- if (time_before(clp->cl_last_renewal, timestamp))
|
|
|
|
- clp->cl_last_renewal = timestamp;
|
|
|
|
- spin_unlock(&clp->cl_lock);
|
|
|
|
|
|
+ clp = res->sr_session->clp;
|
|
|
|
+ do_renew_lease(clp, timestamp);
|
|
/* Check sequence flags */
|
|
/* Check sequence flags */
|
|
if (atomic_read(&clp->cl_count) > 1)
|
|
if (atomic_read(&clp->cl_count) > 1)
|
|
nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags);
|
|
nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags);
|
|
|
|
+ break;
|
|
|
|
+ case -NFS4ERR_DELAY:
|
|
|
|
+ /* The server detected a resend of the RPC call and
|
|
|
|
+ * returned NFS4ERR_DELAY as per Section 2.10.6.2
|
|
|
|
+ * of RFC5661.
|
|
|
|
+ */
|
|
|
|
+ dprintk("%s: slot=%d seq=%d: Operation in progress\n",
|
|
|
|
+ __func__, res->sr_slotid, slot->seq_nr);
|
|
|
|
+ goto out_retry;
|
|
|
|
+ default:
|
|
|
|
+ /* Just update the slot sequence no. */
|
|
|
|
+ ++slot->seq_nr;
|
|
}
|
|
}
|
|
out:
|
|
out:
|
|
/* The session may be reset by one of the error handlers. */
|
|
/* The session may be reset by one of the error handlers. */
|
|
dprintk("%s: Error %d free the slot \n", __func__, res->sr_status);
|
|
dprintk("%s: Error %d free the slot \n", __func__, res->sr_status);
|
|
- nfs41_sequence_free_slot(clp, res);
|
|
|
|
|
|
+ nfs41_sequence_free_slot(res);
|
|
|
|
+ return 1;
|
|
|
|
+out_retry:
|
|
|
|
+ if (!rpc_restart_call(task))
|
|
|
|
+ goto out;
|
|
|
|
+ rpc_delay(task, NFS4_POLL_RETRY_MAX);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int nfs4_sequence_done(struct rpc_task *task,
|
|
|
|
+ struct nfs4_sequence_res *res)
|
|
|
|
+{
|
|
|
|
+ if (res->sr_session == NULL)
|
|
|
|
+ return 1;
|
|
|
|
+ return nfs41_sequence_done(task, res);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -480,12 +508,11 @@ static int nfs41_setup_sequence(struct nfs4_session *session,
|
|
if (res->sr_slotid != NFS4_MAX_SLOT_TABLE)
|
|
if (res->sr_slotid != NFS4_MAX_SLOT_TABLE)
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
- memset(res, 0, sizeof(*res));
|
|
|
|
res->sr_slotid = NFS4_MAX_SLOT_TABLE;
|
|
res->sr_slotid = NFS4_MAX_SLOT_TABLE;
|
|
tbl = &session->fc_slot_table;
|
|
tbl = &session->fc_slot_table;
|
|
|
|
|
|
spin_lock(&tbl->slot_tbl_lock);
|
|
spin_lock(&tbl->slot_tbl_lock);
|
|
- if (test_bit(NFS4CLNT_SESSION_DRAINING, &session->clp->cl_state) &&
|
|
|
|
|
|
+ if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) &&
|
|
!rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) {
|
|
!rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) {
|
|
/*
|
|
/*
|
|
* The state manager will wait until the slot table is empty.
|
|
* The state manager will wait until the slot table is empty.
|
|
@@ -525,6 +552,7 @@ static int nfs41_setup_sequence(struct nfs4_session *session,
|
|
res->sr_session = session;
|
|
res->sr_session = session;
|
|
res->sr_slotid = slotid;
|
|
res->sr_slotid = slotid;
|
|
res->sr_renewal_time = jiffies;
|
|
res->sr_renewal_time = jiffies;
|
|
|
|
+ res->sr_status_flags = 0;
|
|
/*
|
|
/*
|
|
* sr_status is only set in decode_sequence, and so will remain
|
|
* sr_status is only set in decode_sequence, and so will remain
|
|
* set to 1 if an rpc level failure occurs.
|
|
* set to 1 if an rpc level failure occurs.
|
|
@@ -533,33 +561,33 @@ static int nfs41_setup_sequence(struct nfs4_session *session,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
-int nfs4_setup_sequence(struct nfs_client *clp,
|
|
|
|
|
|
+int nfs4_setup_sequence(const struct nfs_server *server,
|
|
struct nfs4_sequence_args *args,
|
|
struct nfs4_sequence_args *args,
|
|
struct nfs4_sequence_res *res,
|
|
struct nfs4_sequence_res *res,
|
|
int cache_reply,
|
|
int cache_reply,
|
|
struct rpc_task *task)
|
|
struct rpc_task *task)
|
|
{
|
|
{
|
|
|
|
+ struct nfs4_session *session = nfs4_get_session(server);
|
|
int ret = 0;
|
|
int ret = 0;
|
|
|
|
|
|
|
|
+ if (session == NULL) {
|
|
|
|
+ args->sa_session = NULL;
|
|
|
|
+ res->sr_session = NULL;
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
dprintk("--> %s clp %p session %p sr_slotid %d\n",
|
|
dprintk("--> %s clp %p session %p sr_slotid %d\n",
|
|
- __func__, clp, clp->cl_session, res->sr_slotid);
|
|
|
|
|
|
+ __func__, session->clp, session, res->sr_slotid);
|
|
|
|
|
|
- if (!nfs4_has_session(clp))
|
|
|
|
- goto out;
|
|
|
|
- ret = nfs41_setup_sequence(clp->cl_session, args, res, cache_reply,
|
|
|
|
|
|
+ ret = nfs41_setup_sequence(session, args, res, cache_reply,
|
|
task);
|
|
task);
|
|
- if (ret && ret != -EAGAIN) {
|
|
|
|
- /* terminate rpc task */
|
|
|
|
- task->tk_status = ret;
|
|
|
|
- task->tk_action = NULL;
|
|
|
|
- }
|
|
|
|
out:
|
|
out:
|
|
dprintk("<-- %s status=%d\n", __func__, ret);
|
|
dprintk("<-- %s status=%d\n", __func__, ret);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
struct nfs41_call_sync_data {
|
|
struct nfs41_call_sync_data {
|
|
- struct nfs_client *clp;
|
|
|
|
|
|
+ const struct nfs_server *seq_server;
|
|
struct nfs4_sequence_args *seq_args;
|
|
struct nfs4_sequence_args *seq_args;
|
|
struct nfs4_sequence_res *seq_res;
|
|
struct nfs4_sequence_res *seq_res;
|
|
int cache_reply;
|
|
int cache_reply;
|
|
@@ -569,9 +597,9 @@ static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
|
|
{
|
|
{
|
|
struct nfs41_call_sync_data *data = calldata;
|
|
struct nfs41_call_sync_data *data = calldata;
|
|
|
|
|
|
- dprintk("--> %s data->clp->cl_session %p\n", __func__,
|
|
|
|
- data->clp->cl_session);
|
|
|
|
- if (nfs4_setup_sequence(data->clp, data->seq_args,
|
|
|
|
|
|
+ dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server);
|
|
|
|
+
|
|
|
|
+ if (nfs4_setup_sequence(data->seq_server, data->seq_args,
|
|
data->seq_res, data->cache_reply, task))
|
|
data->seq_res, data->cache_reply, task))
|
|
return;
|
|
return;
|
|
rpc_call_start(task);
|
|
rpc_call_start(task);
|
|
@@ -587,7 +615,7 @@ static void nfs41_call_sync_done(struct rpc_task *task, void *calldata)
|
|
{
|
|
{
|
|
struct nfs41_call_sync_data *data = calldata;
|
|
struct nfs41_call_sync_data *data = calldata;
|
|
|
|
|
|
- nfs41_sequence_done(data->clp, data->seq_res, task->tk_status);
|
|
|
|
|
|
+ nfs41_sequence_done(task, data->seq_res);
|
|
}
|
|
}
|
|
|
|
|
|
struct rpc_call_ops nfs41_call_sync_ops = {
|
|
struct rpc_call_ops nfs41_call_sync_ops = {
|
|
@@ -600,8 +628,7 @@ struct rpc_call_ops nfs41_call_priv_sync_ops = {
|
|
.rpc_call_done = nfs41_call_sync_done,
|
|
.rpc_call_done = nfs41_call_sync_done,
|
|
};
|
|
};
|
|
|
|
|
|
-static int nfs4_call_sync_sequence(struct nfs_client *clp,
|
|
|
|
- struct rpc_clnt *clnt,
|
|
|
|
|
|
+static int nfs4_call_sync_sequence(struct nfs_server *server,
|
|
struct rpc_message *msg,
|
|
struct rpc_message *msg,
|
|
struct nfs4_sequence_args *args,
|
|
struct nfs4_sequence_args *args,
|
|
struct nfs4_sequence_res *res,
|
|
struct nfs4_sequence_res *res,
|
|
@@ -611,13 +638,13 @@ static int nfs4_call_sync_sequence(struct nfs_client *clp,
|
|
int ret;
|
|
int ret;
|
|
struct rpc_task *task;
|
|
struct rpc_task *task;
|
|
struct nfs41_call_sync_data data = {
|
|
struct nfs41_call_sync_data data = {
|
|
- .clp = clp,
|
|
|
|
|
|
+ .seq_server = server,
|
|
.seq_args = args,
|
|
.seq_args = args,
|
|
.seq_res = res,
|
|
.seq_res = res,
|
|
.cache_reply = cache_reply,
|
|
.cache_reply = cache_reply,
|
|
};
|
|
};
|
|
struct rpc_task_setup task_setup = {
|
|
struct rpc_task_setup task_setup = {
|
|
- .rpc_client = clnt,
|
|
|
|
|
|
+ .rpc_client = server->client,
|
|
.rpc_message = msg,
|
|
.rpc_message = msg,
|
|
.callback_ops = &nfs41_call_sync_ops,
|
|
.callback_ops = &nfs41_call_sync_ops,
|
|
.callback_data = &data
|
|
.callback_data = &data
|
|
@@ -642,10 +669,15 @@ int _nfs4_call_sync_session(struct nfs_server *server,
|
|
struct nfs4_sequence_res *res,
|
|
struct nfs4_sequence_res *res,
|
|
int cache_reply)
|
|
int cache_reply)
|
|
{
|
|
{
|
|
- return nfs4_call_sync_sequence(server->nfs_client, server->client,
|
|
|
|
- msg, args, res, cache_reply, 0);
|
|
|
|
|
|
+ return nfs4_call_sync_sequence(server, msg, args, res, cache_reply, 0);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#else
|
|
|
|
+static int nfs4_sequence_done(struct rpc_task *task,
|
|
|
|
+ struct nfs4_sequence_res *res)
|
|
|
|
+{
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
#endif /* CONFIG_NFS_V4_1 */
|
|
#endif /* CONFIG_NFS_V4_1 */
|
|
|
|
|
|
int _nfs4_call_sync(struct nfs_server *server,
|
|
int _nfs4_call_sync(struct nfs_server *server,
|
|
@@ -659,18 +691,9 @@ int _nfs4_call_sync(struct nfs_server *server,
|
|
}
|
|
}
|
|
|
|
|
|
#define nfs4_call_sync(server, msg, args, res, cache_reply) \
|
|
#define nfs4_call_sync(server, msg, args, res, cache_reply) \
|
|
- (server)->nfs_client->cl_call_sync((server), (msg), &(args)->seq_args, \
|
|
|
|
|
|
+ (server)->nfs_client->cl_mvops->call_sync((server), (msg), &(args)->seq_args, \
|
|
&(res)->seq_res, (cache_reply))
|
|
&(res)->seq_res, (cache_reply))
|
|
|
|
|
|
-static void nfs4_sequence_done(const struct nfs_server *server,
|
|
|
|
- struct nfs4_sequence_res *res, int rpc_status)
|
|
|
|
-{
|
|
|
|
-#ifdef CONFIG_NFS_V4_1
|
|
|
|
- if (nfs4_has_session(server->nfs_client))
|
|
|
|
- nfs41_sequence_done(server->nfs_client, res, rpc_status);
|
|
|
|
-#endif /* CONFIG_NFS_V4_1 */
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
|
|
static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
|
|
{
|
|
{
|
|
struct nfs_inode *nfsi = NFS_I(dir);
|
|
struct nfs_inode *nfsi = NFS_I(dir);
|
|
@@ -745,19 +768,14 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
|
|
p->o_arg.server = server;
|
|
p->o_arg.server = server;
|
|
p->o_arg.bitmask = server->attr_bitmask;
|
|
p->o_arg.bitmask = server->attr_bitmask;
|
|
p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
|
|
p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
|
|
- if (flags & O_EXCL) {
|
|
|
|
- if (nfs4_has_persistent_session(server->nfs_client)) {
|
|
|
|
- /* GUARDED */
|
|
|
|
- p->o_arg.u.attrs = &p->attrs;
|
|
|
|
- memcpy(&p->attrs, attrs, sizeof(p->attrs));
|
|
|
|
- } else { /* EXCLUSIVE4_1 */
|
|
|
|
- u32 *s = (u32 *) p->o_arg.u.verifier.data;
|
|
|
|
- s[0] = jiffies;
|
|
|
|
- s[1] = current->pid;
|
|
|
|
- }
|
|
|
|
- } else if (flags & O_CREAT) {
|
|
|
|
|
|
+ if (flags & O_CREAT) {
|
|
|
|
+ u32 *s;
|
|
|
|
+
|
|
p->o_arg.u.attrs = &p->attrs;
|
|
p->o_arg.u.attrs = &p->attrs;
|
|
memcpy(&p->attrs, attrs, sizeof(p->attrs));
|
|
memcpy(&p->attrs, attrs, sizeof(p->attrs));
|
|
|
|
+ s = (u32 *) p->o_arg.u.verifier.data;
|
|
|
|
+ s[0] = jiffies;
|
|
|
|
+ s[1] = current->pid;
|
|
}
|
|
}
|
|
p->c_arg.fh = &p->o_res.fh;
|
|
p->c_arg.fh = &p->o_res.fh;
|
|
p->c_arg.stateid = &p->o_res.stateid;
|
|
p->c_arg.stateid = &p->o_res.stateid;
|
|
@@ -1255,8 +1273,6 @@ static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata)
|
|
struct nfs4_opendata *data = calldata;
|
|
struct nfs4_opendata *data = calldata;
|
|
|
|
|
|
data->rpc_status = task->tk_status;
|
|
data->rpc_status = task->tk_status;
|
|
- if (RPC_ASSASSINATED(task))
|
|
|
|
- return;
|
|
|
|
if (data->rpc_status == 0) {
|
|
if (data->rpc_status == 0) {
|
|
memcpy(data->o_res.stateid.data, data->c_res.stateid.data,
|
|
memcpy(data->o_res.stateid.data, data->c_res.stateid.data,
|
|
sizeof(data->o_res.stateid.data));
|
|
sizeof(data->o_res.stateid.data));
|
|
@@ -1356,13 +1372,13 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
|
|
}
|
|
}
|
|
/* Update sequence id. */
|
|
/* Update sequence id. */
|
|
data->o_arg.id = sp->so_owner_id.id;
|
|
data->o_arg.id = sp->so_owner_id.id;
|
|
- data->o_arg.clientid = sp->so_client->cl_clientid;
|
|
|
|
|
|
+ data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid;
|
|
if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
|
|
if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
|
|
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
|
|
task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
|
|
nfs_copy_fh(&data->o_res.fh, data->o_arg.fh);
|
|
nfs_copy_fh(&data->o_res.fh, data->o_arg.fh);
|
|
}
|
|
}
|
|
data->timestamp = jiffies;
|
|
data->timestamp = jiffies;
|
|
- if (nfs4_setup_sequence(data->o_arg.server->nfs_client,
|
|
|
|
|
|
+ if (nfs4_setup_sequence(data->o_arg.server,
|
|
&data->o_arg.seq_args,
|
|
&data->o_arg.seq_args,
|
|
&data->o_res.seq_res, 1, task))
|
|
&data->o_res.seq_res, 1, task))
|
|
return;
|
|
return;
|
|
@@ -1385,11 +1401,9 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata)
|
|
|
|
|
|
data->rpc_status = task->tk_status;
|
|
data->rpc_status = task->tk_status;
|
|
|
|
|
|
- nfs4_sequence_done(data->o_arg.server, &data->o_res.seq_res,
|
|
|
|
- task->tk_status);
|
|
|
|
-
|
|
|
|
- if (RPC_ASSASSINATED(task))
|
|
|
|
|
|
+ if (!nfs4_sequence_done(task, &data->o_res.seq_res))
|
|
return;
|
|
return;
|
|
|
|
+
|
|
if (task->tk_status == 0) {
|
|
if (task->tk_status == 0) {
|
|
switch (data->o_res.f_attr->mode & S_IFMT) {
|
|
switch (data->o_res.f_attr->mode & S_IFMT) {
|
|
case S_IFREG:
|
|
case S_IFREG:
|
|
@@ -1773,7 +1787,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
|
|
if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) {
|
|
if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) {
|
|
/* Use that stateid */
|
|
/* Use that stateid */
|
|
} else if (state != NULL) {
|
|
} else if (state != NULL) {
|
|
- nfs4_copy_stateid(&arg.stateid, state, current->files);
|
|
|
|
|
|
+ nfs4_copy_stateid(&arg.stateid, state, current->files, current->tgid);
|
|
} else
|
|
} else
|
|
memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid));
|
|
memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid));
|
|
|
|
|
|
@@ -1838,8 +1852,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
|
|
struct nfs4_state *state = calldata->state;
|
|
struct nfs4_state *state = calldata->state;
|
|
struct nfs_server *server = NFS_SERVER(calldata->inode);
|
|
struct nfs_server *server = NFS_SERVER(calldata->inode);
|
|
|
|
|
|
- nfs4_sequence_done(server, &calldata->res.seq_res, task->tk_status);
|
|
|
|
- if (RPC_ASSASSINATED(task))
|
|
|
|
|
|
+ if (!nfs4_sequence_done(task, &calldata->res.seq_res))
|
|
return;
|
|
return;
|
|
/* hmm. we are done with the inode, and in the process of freeing
|
|
/* hmm. we are done with the inode, and in the process of freeing
|
|
* the state_owner. we keep this around to process errors
|
|
* the state_owner. we keep this around to process errors
|
|
@@ -1903,7 +1916,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
|
|
|
|
|
|
nfs_fattr_init(calldata->res.fattr);
|
|
nfs_fattr_init(calldata->res.fattr);
|
|
calldata->timestamp = jiffies;
|
|
calldata->timestamp = jiffies;
|
|
- if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client,
|
|
|
|
|
|
+ if (nfs4_setup_sequence(NFS_SERVER(calldata->inode),
|
|
&calldata->arg.seq_args, &calldata->res.seq_res,
|
|
&calldata->arg.seq_args, &calldata->res.seq_res,
|
|
1, task))
|
|
1, task))
|
|
return;
|
|
return;
|
|
@@ -2648,7 +2661,8 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
|
|
{
|
|
{
|
|
struct nfs_removeres *res = task->tk_msg.rpc_resp;
|
|
struct nfs_removeres *res = task->tk_msg.rpc_resp;
|
|
|
|
|
|
- nfs4_sequence_done(res->server, &res->seq_res, task->tk_status);
|
|
|
|
|
|
+ if (!nfs4_sequence_done(task, &res->seq_res))
|
|
|
|
+ return 0;
|
|
if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN)
|
|
if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN)
|
|
return 0;
|
|
return 0;
|
|
update_changeattr(dir, &res->cinfo);
|
|
update_changeattr(dir, &res->cinfo);
|
|
@@ -3093,7 +3107,8 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
|
|
|
|
|
|
dprintk("--> %s\n", __func__);
|
|
dprintk("--> %s\n", __func__);
|
|
|
|
|
|
- nfs4_sequence_done(server, &data->res.seq_res, task->tk_status);
|
|
|
|
|
|
+ if (!nfs4_sequence_done(task, &data->res.seq_res))
|
|
|
|
+ return -EAGAIN;
|
|
|
|
|
|
if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) {
|
|
if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) {
|
|
nfs_restart_rpc(task, server->nfs_client);
|
|
nfs_restart_rpc(task, server->nfs_client);
|
|
@@ -3116,8 +3131,8 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
|
|
{
|
|
{
|
|
struct inode *inode = data->inode;
|
|
struct inode *inode = data->inode;
|
|
|
|
|
|
- nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res,
|
|
|
|
- task->tk_status);
|
|
|
|
|
|
+ if (!nfs4_sequence_done(task, &data->res.seq_res))
|
|
|
|
+ return -EAGAIN;
|
|
|
|
|
|
if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) {
|
|
if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) {
|
|
nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client);
|
|
nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client);
|
|
@@ -3145,8 +3160,9 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data)
|
|
{
|
|
{
|
|
struct inode *inode = data->inode;
|
|
struct inode *inode = data->inode;
|
|
|
|
|
|
- nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res,
|
|
|
|
- task->tk_status);
|
|
|
|
|
|
+ if (!nfs4_sequence_done(task, &data->res.seq_res))
|
|
|
|
+ return -EAGAIN;
|
|
|
|
+
|
|
if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) {
|
|
if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) {
|
|
nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client);
|
|
nfs_restart_rpc(task, NFS_SERVER(inode)->nfs_client);
|
|
return -EAGAIN;
|
|
return -EAGAIN;
|
|
@@ -3196,10 +3212,7 @@ static void nfs4_renew_done(struct rpc_task *task, void *calldata)
|
|
nfs4_schedule_state_recovery(clp);
|
|
nfs4_schedule_state_recovery(clp);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
- spin_lock(&clp->cl_lock);
|
|
|
|
- if (time_before(clp->cl_last_renewal,timestamp))
|
|
|
|
- clp->cl_last_renewal = timestamp;
|
|
|
|
- spin_unlock(&clp->cl_lock);
|
|
|
|
|
|
+ do_renew_lease(clp, timestamp);
|
|
}
|
|
}
|
|
|
|
|
|
static const struct rpc_call_ops nfs4_renew_ops = {
|
|
static const struct rpc_call_ops nfs4_renew_ops = {
|
|
@@ -3240,10 +3253,7 @@ int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred)
|
|
status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
|
|
status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
|
|
if (status < 0)
|
|
if (status < 0)
|
|
return status;
|
|
return status;
|
|
- spin_lock(&clp->cl_lock);
|
|
|
|
- if (time_before(clp->cl_last_renewal,now))
|
|
|
|
- clp->cl_last_renewal = now;
|
|
|
|
- spin_unlock(&clp->cl_lock);
|
|
|
|
|
|
+ do_renew_lease(clp, now);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -3464,9 +3474,11 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
|
|
}
|
|
}
|
|
|
|
|
|
static int
|
|
static int
|
|
-_nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs_client *clp, struct nfs4_state *state)
|
|
|
|
|
|
+nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state)
|
|
{
|
|
{
|
|
- if (!clp || task->tk_status >= 0)
|
|
|
|
|
|
+ struct nfs_client *clp = server->nfs_client;
|
|
|
|
+
|
|
|
|
+ if (task->tk_status >= 0)
|
|
return 0;
|
|
return 0;
|
|
switch(task->tk_status) {
|
|
switch(task->tk_status) {
|
|
case -NFS4ERR_ADMIN_REVOKED:
|
|
case -NFS4ERR_ADMIN_REVOKED:
|
|
@@ -3498,8 +3510,7 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
|
|
return -EAGAIN;
|
|
return -EAGAIN;
|
|
#endif /* CONFIG_NFS_V4_1 */
|
|
#endif /* CONFIG_NFS_V4_1 */
|
|
case -NFS4ERR_DELAY:
|
|
case -NFS4ERR_DELAY:
|
|
- if (server)
|
|
|
|
- nfs_inc_server_stats(server, NFSIOS_DELAY);
|
|
|
|
|
|
+ nfs_inc_server_stats(server, NFSIOS_DELAY);
|
|
case -NFS4ERR_GRACE:
|
|
case -NFS4ERR_GRACE:
|
|
case -EKEYEXPIRED:
|
|
case -EKEYEXPIRED:
|
|
rpc_delay(task, NFS4_POLL_RETRY_MAX);
|
|
rpc_delay(task, NFS4_POLL_RETRY_MAX);
|
|
@@ -3520,12 +3531,6 @@ do_state_recovery:
|
|
return -EAGAIN;
|
|
return -EAGAIN;
|
|
}
|
|
}
|
|
|
|
|
|
-static int
|
|
|
|
-nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state)
|
|
|
|
-{
|
|
|
|
- return _nfs4_async_handle_error(task, server, server->nfs_client, state);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
|
|
int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
|
|
unsigned short port, struct rpc_cred *cred,
|
|
unsigned short port, struct rpc_cred *cred,
|
|
struct nfs4_setclientid_res *res)
|
|
struct nfs4_setclientid_res *res)
|
|
@@ -3641,8 +3646,8 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
|
|
{
|
|
{
|
|
struct nfs4_delegreturndata *data = calldata;
|
|
struct nfs4_delegreturndata *data = calldata;
|
|
|
|
|
|
- nfs4_sequence_done(data->res.server, &data->res.seq_res,
|
|
|
|
- task->tk_status);
|
|
|
|
|
|
+ if (!nfs4_sequence_done(task, &data->res.seq_res))
|
|
|
|
+ return;
|
|
|
|
|
|
switch (task->tk_status) {
|
|
switch (task->tk_status) {
|
|
case -NFS4ERR_STALE_STATEID:
|
|
case -NFS4ERR_STALE_STATEID:
|
|
@@ -3672,7 +3677,7 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)
|
|
|
|
|
|
d_data = (struct nfs4_delegreturndata *)data;
|
|
d_data = (struct nfs4_delegreturndata *)data;
|
|
|
|
|
|
- if (nfs4_setup_sequence(d_data->res.server->nfs_client,
|
|
|
|
|
|
+ if (nfs4_setup_sequence(d_data->res.server,
|
|
&d_data->args.seq_args,
|
|
&d_data->args.seq_args,
|
|
&d_data->res.seq_res, 1, task))
|
|
&d_data->res.seq_res, 1, task))
|
|
return;
|
|
return;
|
|
@@ -3892,9 +3897,7 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
|
|
{
|
|
{
|
|
struct nfs4_unlockdata *calldata = data;
|
|
struct nfs4_unlockdata *calldata = data;
|
|
|
|
|
|
- nfs4_sequence_done(calldata->server, &calldata->res.seq_res,
|
|
|
|
- task->tk_status);
|
|
|
|
- if (RPC_ASSASSINATED(task))
|
|
|
|
|
|
+ if (!nfs4_sequence_done(task, &calldata->res.seq_res))
|
|
return;
|
|
return;
|
|
switch (task->tk_status) {
|
|
switch (task->tk_status) {
|
|
case 0:
|
|
case 0:
|
|
@@ -3927,7 +3930,7 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data)
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
calldata->timestamp = jiffies;
|
|
calldata->timestamp = jiffies;
|
|
- if (nfs4_setup_sequence(calldata->server->nfs_client,
|
|
|
|
|
|
+ if (nfs4_setup_sequence(calldata->server,
|
|
&calldata->arg.seq_args,
|
|
&calldata->arg.seq_args,
|
|
&calldata->res.seq_res, 1, task))
|
|
&calldata->res.seq_res, 1, task))
|
|
return;
|
|
return;
|
|
@@ -4082,7 +4085,8 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
|
|
} else
|
|
} else
|
|
data->arg.new_lock_owner = 0;
|
|
data->arg.new_lock_owner = 0;
|
|
data->timestamp = jiffies;
|
|
data->timestamp = jiffies;
|
|
- if (nfs4_setup_sequence(data->server->nfs_client, &data->arg.seq_args,
|
|
|
|
|
|
+ if (nfs4_setup_sequence(data->server,
|
|
|
|
+ &data->arg.seq_args,
|
|
&data->res.seq_res, 1, task))
|
|
&data->res.seq_res, 1, task))
|
|
return;
|
|
return;
|
|
rpc_call_start(task);
|
|
rpc_call_start(task);
|
|
@@ -4101,12 +4105,10 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)
|
|
|
|
|
|
dprintk("%s: begin!\n", __func__);
|
|
dprintk("%s: begin!\n", __func__);
|
|
|
|
|
|
- nfs4_sequence_done(data->server, &data->res.seq_res,
|
|
|
|
- task->tk_status);
|
|
|
|
|
|
+ if (!nfs4_sequence_done(task, &data->res.seq_res))
|
|
|
|
+ return;
|
|
|
|
|
|
data->rpc_status = task->tk_status;
|
|
data->rpc_status = task->tk_status;
|
|
- if (RPC_ASSASSINATED(task))
|
|
|
|
- goto out;
|
|
|
|
if (data->arg.new_lock_owner != 0) {
|
|
if (data->arg.new_lock_owner != 0) {
|
|
if (data->rpc_status == 0)
|
|
if (data->rpc_status == 0)
|
|
nfs_confirm_seqid(&data->lsp->ls_seqid, 0);
|
|
nfs_confirm_seqid(&data->lsp->ls_seqid, 0);
|
|
@@ -4424,6 +4426,34 @@ out:
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void nfs4_release_lockowner_release(void *calldata)
|
|
|
|
+{
|
|
|
|
+ kfree(calldata);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const struct rpc_call_ops nfs4_release_lockowner_ops = {
|
|
|
|
+ .rpc_release = nfs4_release_lockowner_release,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+void nfs4_release_lockowner(const struct nfs4_lock_state *lsp)
|
|
|
|
+{
|
|
|
|
+ struct nfs_server *server = lsp->ls_state->owner->so_server;
|
|
|
|
+ struct nfs_release_lockowner_args *args;
|
|
|
|
+ struct rpc_message msg = {
|
|
|
|
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER],
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ if (server->nfs_client->cl_mvops->minor_version != 0)
|
|
|
|
+ return;
|
|
|
|
+ args = kmalloc(sizeof(*args), GFP_NOFS);
|
|
|
|
+ if (!args)
|
|
|
|
+ return;
|
|
|
|
+ args->lock_owner.clientid = server->nfs_client->cl_clientid;
|
|
|
|
+ args->lock_owner.id = lsp->ls_id.id;
|
|
|
|
+ msg.rpc_argp = args;
|
|
|
|
+ rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, args);
|
|
|
|
+}
|
|
|
|
+
|
|
#define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
|
|
#define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
|
|
|
|
|
|
int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf,
|
|
int nfs4_setxattr(struct dentry *dentry, const char *key, const void *buf,
|
|
@@ -4611,7 +4641,8 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata)
|
|
(struct nfs4_get_lease_time_data *)calldata;
|
|
(struct nfs4_get_lease_time_data *)calldata;
|
|
|
|
|
|
dprintk("--> %s\n", __func__);
|
|
dprintk("--> %s\n", __func__);
|
|
- nfs41_sequence_done(data->clp, &data->res->lr_seq_res, task->tk_status);
|
|
|
|
|
|
+ if (!nfs41_sequence_done(task, &data->res->lr_seq_res))
|
|
|
|
+ return;
|
|
switch (task->tk_status) {
|
|
switch (task->tk_status) {
|
|
case -NFS4ERR_DELAY:
|
|
case -NFS4ERR_DELAY:
|
|
case -NFS4ERR_GRACE:
|
|
case -NFS4ERR_GRACE:
|
|
@@ -4805,13 +4836,6 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
|
|
if (!session)
|
|
if (!session)
|
|
return NULL;
|
|
return NULL;
|
|
|
|
|
|
- /*
|
|
|
|
- * The create session reply races with the server back
|
|
|
|
- * channel probe. Mark the client NFS_CS_SESSION_INITING
|
|
|
|
- * so that the client back channel can find the
|
|
|
|
- * nfs_client struct
|
|
|
|
- */
|
|
|
|
- clp->cl_cons_state = NFS_CS_SESSION_INITING;
|
|
|
|
init_completion(&session->complete);
|
|
init_completion(&session->complete);
|
|
|
|
|
|
tbl = &session->fc_slot_table;
|
|
tbl = &session->fc_slot_table;
|
|
@@ -4824,6 +4848,8 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
|
|
spin_lock_init(&tbl->slot_tbl_lock);
|
|
spin_lock_init(&tbl->slot_tbl_lock);
|
|
rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table");
|
|
rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table");
|
|
|
|
|
|
|
|
+ session->session_state = 1<<NFS4_SESSION_INITING;
|
|
|
|
+
|
|
session->clp = clp;
|
|
session->clp = clp;
|
|
return session;
|
|
return session;
|
|
}
|
|
}
|
|
@@ -5040,6 +5066,10 @@ int nfs4_init_session(struct nfs_server *server)
|
|
if (!nfs4_has_session(clp))
|
|
if (!nfs4_has_session(clp))
|
|
return 0;
|
|
return 0;
|
|
|
|
|
|
|
|
+ session = clp->cl_session;
|
|
|
|
+ if (!test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state))
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
rsize = server->rsize;
|
|
rsize = server->rsize;
|
|
if (rsize == 0)
|
|
if (rsize == 0)
|
|
rsize = NFS_MAX_FILE_IO_SIZE;
|
|
rsize = NFS_MAX_FILE_IO_SIZE;
|
|
@@ -5047,7 +5077,6 @@ int nfs4_init_session(struct nfs_server *server)
|
|
if (wsize == 0)
|
|
if (wsize == 0)
|
|
wsize = NFS_MAX_FILE_IO_SIZE;
|
|
wsize = NFS_MAX_FILE_IO_SIZE;
|
|
|
|
|
|
- session = clp->cl_session;
|
|
|
|
session->fc_attrs.max_rqst_sz = wsize + nfs41_maxwrite_overhead;
|
|
session->fc_attrs.max_rqst_sz = wsize + nfs41_maxwrite_overhead;
|
|
session->fc_attrs.max_resp_sz = rsize + nfs41_maxread_overhead;
|
|
session->fc_attrs.max_resp_sz = rsize + nfs41_maxread_overhead;
|
|
|
|
|
|
@@ -5060,69 +5089,70 @@ int nfs4_init_session(struct nfs_server *server)
|
|
/*
|
|
/*
|
|
* Renew the cl_session lease.
|
|
* Renew the cl_session lease.
|
|
*/
|
|
*/
|
|
-static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
|
|
|
|
-{
|
|
|
|
|
|
+struct nfs4_sequence_data {
|
|
|
|
+ struct nfs_client *clp;
|
|
struct nfs4_sequence_args args;
|
|
struct nfs4_sequence_args args;
|
|
struct nfs4_sequence_res res;
|
|
struct nfs4_sequence_res res;
|
|
-
|
|
|
|
- struct rpc_message msg = {
|
|
|
|
- .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE],
|
|
|
|
- .rpc_argp = &args,
|
|
|
|
- .rpc_resp = &res,
|
|
|
|
- .rpc_cred = cred,
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- args.sa_cache_this = 0;
|
|
|
|
-
|
|
|
|
- return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args,
|
|
|
|
- &res, args.sa_cache_this, 1);
|
|
|
|
-}
|
|
|
|
|
|
+};
|
|
|
|
|
|
static void nfs41_sequence_release(void *data)
|
|
static void nfs41_sequence_release(void *data)
|
|
{
|
|
{
|
|
- struct nfs_client *clp = (struct nfs_client *)data;
|
|
|
|
|
|
+ struct nfs4_sequence_data *calldata = data;
|
|
|
|
+ struct nfs_client *clp = calldata->clp;
|
|
|
|
|
|
if (atomic_read(&clp->cl_count) > 1)
|
|
if (atomic_read(&clp->cl_count) > 1)
|
|
nfs4_schedule_state_renewal(clp);
|
|
nfs4_schedule_state_renewal(clp);
|
|
nfs_put_client(clp);
|
|
nfs_put_client(clp);
|
|
|
|
+ kfree(calldata);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int nfs41_sequence_handle_errors(struct rpc_task *task, struct nfs_client *clp)
|
|
|
|
+{
|
|
|
|
+ switch(task->tk_status) {
|
|
|
|
+ case -NFS4ERR_DELAY:
|
|
|
|
+ case -EKEYEXPIRED:
|
|
|
|
+ rpc_delay(task, NFS4_POLL_RETRY_MAX);
|
|
|
|
+ return -EAGAIN;
|
|
|
|
+ default:
|
|
|
|
+ nfs4_schedule_state_recovery(clp);
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static void nfs41_sequence_call_done(struct rpc_task *task, void *data)
|
|
static void nfs41_sequence_call_done(struct rpc_task *task, void *data)
|
|
{
|
|
{
|
|
- struct nfs_client *clp = (struct nfs_client *)data;
|
|
|
|
|
|
+ struct nfs4_sequence_data *calldata = data;
|
|
|
|
+ struct nfs_client *clp = calldata->clp;
|
|
|
|
|
|
- nfs41_sequence_done(clp, task->tk_msg.rpc_resp, task->tk_status);
|
|
|
|
|
|
+ if (!nfs41_sequence_done(task, task->tk_msg.rpc_resp))
|
|
|
|
+ return;
|
|
|
|
|
|
if (task->tk_status < 0) {
|
|
if (task->tk_status < 0) {
|
|
dprintk("%s ERROR %d\n", __func__, task->tk_status);
|
|
dprintk("%s ERROR %d\n", __func__, task->tk_status);
|
|
if (atomic_read(&clp->cl_count) == 1)
|
|
if (atomic_read(&clp->cl_count) == 1)
|
|
goto out;
|
|
goto out;
|
|
|
|
|
|
- if (_nfs4_async_handle_error(task, NULL, clp, NULL)
|
|
|
|
- == -EAGAIN) {
|
|
|
|
- nfs_restart_rpc(task, clp);
|
|
|
|
|
|
+ if (nfs41_sequence_handle_errors(task, clp) == -EAGAIN) {
|
|
|
|
+ rpc_restart_call_prepare(task);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred);
|
|
dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred);
|
|
out:
|
|
out:
|
|
- kfree(task->tk_msg.rpc_argp);
|
|
|
|
- kfree(task->tk_msg.rpc_resp);
|
|
|
|
-
|
|
|
|
dprintk("<-- %s\n", __func__);
|
|
dprintk("<-- %s\n", __func__);
|
|
}
|
|
}
|
|
|
|
|
|
static void nfs41_sequence_prepare(struct rpc_task *task, void *data)
|
|
static void nfs41_sequence_prepare(struct rpc_task *task, void *data)
|
|
{
|
|
{
|
|
- struct nfs_client *clp;
|
|
|
|
|
|
+ struct nfs4_sequence_data *calldata = data;
|
|
|
|
+ struct nfs_client *clp = calldata->clp;
|
|
struct nfs4_sequence_args *args;
|
|
struct nfs4_sequence_args *args;
|
|
struct nfs4_sequence_res *res;
|
|
struct nfs4_sequence_res *res;
|
|
|
|
|
|
- clp = (struct nfs_client *)data;
|
|
|
|
args = task->tk_msg.rpc_argp;
|
|
args = task->tk_msg.rpc_argp;
|
|
res = task->tk_msg.rpc_resp;
|
|
res = task->tk_msg.rpc_resp;
|
|
|
|
|
|
- if (nfs4_setup_sequence(clp, args, res, 0, task))
|
|
|
|
|
|
+ if (nfs41_setup_sequence(clp->cl_session, args, res, 0, task))
|
|
return;
|
|
return;
|
|
rpc_call_start(task);
|
|
rpc_call_start(task);
|
|
}
|
|
}
|
|
@@ -5133,32 +5163,67 @@ static const struct rpc_call_ops nfs41_sequence_ops = {
|
|
.rpc_release = nfs41_sequence_release,
|
|
.rpc_release = nfs41_sequence_release,
|
|
};
|
|
};
|
|
|
|
|
|
-static int nfs41_proc_async_sequence(struct nfs_client *clp,
|
|
|
|
- struct rpc_cred *cred)
|
|
|
|
|
|
+static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
|
|
{
|
|
{
|
|
- struct nfs4_sequence_args *args;
|
|
|
|
- struct nfs4_sequence_res *res;
|
|
|
|
|
|
+ struct nfs4_sequence_data *calldata;
|
|
struct rpc_message msg = {
|
|
struct rpc_message msg = {
|
|
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE],
|
|
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE],
|
|
.rpc_cred = cred,
|
|
.rpc_cred = cred,
|
|
};
|
|
};
|
|
|
|
+ struct rpc_task_setup task_setup_data = {
|
|
|
|
+ .rpc_client = clp->cl_rpcclient,
|
|
|
|
+ .rpc_message = &msg,
|
|
|
|
+ .callback_ops = &nfs41_sequence_ops,
|
|
|
|
+ .flags = RPC_TASK_ASYNC | RPC_TASK_SOFT,
|
|
|
|
+ };
|
|
|
|
|
|
if (!atomic_inc_not_zero(&clp->cl_count))
|
|
if (!atomic_inc_not_zero(&clp->cl_count))
|
|
- return -EIO;
|
|
|
|
- args = kzalloc(sizeof(*args), GFP_NOFS);
|
|
|
|
- res = kzalloc(sizeof(*res), GFP_NOFS);
|
|
|
|
- if (!args || !res) {
|
|
|
|
- kfree(args);
|
|
|
|
- kfree(res);
|
|
|
|
|
|
+ return ERR_PTR(-EIO);
|
|
|
|
+ calldata = kmalloc(sizeof(*calldata), GFP_NOFS);
|
|
|
|
+ if (calldata == NULL) {
|
|
nfs_put_client(clp);
|
|
nfs_put_client(clp);
|
|
- return -ENOMEM;
|
|
|
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
}
|
|
}
|
|
- res->sr_slotid = NFS4_MAX_SLOT_TABLE;
|
|
|
|
- msg.rpc_argp = args;
|
|
|
|
- msg.rpc_resp = res;
|
|
|
|
|
|
+ calldata->res.sr_slotid = NFS4_MAX_SLOT_TABLE;
|
|
|
|
+ msg.rpc_argp = &calldata->args;
|
|
|
|
+ msg.rpc_resp = &calldata->res;
|
|
|
|
+ calldata->clp = clp;
|
|
|
|
+ task_setup_data.callback_data = calldata;
|
|
|
|
|
|
- return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT,
|
|
|
|
- &nfs41_sequence_ops, (void *)clp);
|
|
|
|
|
|
+ return rpc_run_task(&task_setup_data);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cred)
|
|
|
|
+{
|
|
|
|
+ struct rpc_task *task;
|
|
|
|
+ int ret = 0;
|
|
|
|
+
|
|
|
|
+ task = _nfs41_proc_sequence(clp, cred);
|
|
|
|
+ if (IS_ERR(task))
|
|
|
|
+ ret = PTR_ERR(task);
|
|
|
|
+ else
|
|
|
|
+ rpc_put_task(task);
|
|
|
|
+ dprintk("<-- %s status=%d\n", __func__, ret);
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
|
|
|
|
+{
|
|
|
|
+ struct rpc_task *task;
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ task = _nfs41_proc_sequence(clp, cred);
|
|
|
|
+ if (IS_ERR(task)) {
|
|
|
|
+ ret = PTR_ERR(task);
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+ ret = rpc_wait_for_completion_task(task);
|
|
|
|
+ if (!ret)
|
|
|
|
+ ret = task->tk_status;
|
|
|
|
+ rpc_put_task(task);
|
|
|
|
+out:
|
|
|
|
+ dprintk("<-- %s status=%d\n", __func__, ret);
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
struct nfs4_reclaim_complete_data {
|
|
struct nfs4_reclaim_complete_data {
|
|
@@ -5172,13 +5237,31 @@ static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data)
|
|
struct nfs4_reclaim_complete_data *calldata = data;
|
|
struct nfs4_reclaim_complete_data *calldata = data;
|
|
|
|
|
|
rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
|
|
rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
|
|
- if (nfs4_setup_sequence(calldata->clp, &calldata->arg.seq_args,
|
|
|
|
|
|
+ if (nfs41_setup_sequence(calldata->clp->cl_session,
|
|
|
|
+ &calldata->arg.seq_args,
|
|
&calldata->res.seq_res, 0, task))
|
|
&calldata->res.seq_res, 0, task))
|
|
return;
|
|
return;
|
|
|
|
|
|
rpc_call_start(task);
|
|
rpc_call_start(task);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nfs_client *clp)
|
|
|
|
+{
|
|
|
|
+ switch(task->tk_status) {
|
|
|
|
+ case 0:
|
|
|
|
+ case -NFS4ERR_COMPLETE_ALREADY:
|
|
|
|
+ case -NFS4ERR_WRONG_CRED: /* What to do here? */
|
|
|
|
+ break;
|
|
|
|
+ case -NFS4ERR_DELAY:
|
|
|
|
+ case -EKEYEXPIRED:
|
|
|
|
+ rpc_delay(task, NFS4_POLL_RETRY_MAX);
|
|
|
|
+ return -EAGAIN;
|
|
|
|
+ default:
|
|
|
|
+ nfs4_schedule_state_recovery(clp);
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data)
|
|
static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data)
|
|
{
|
|
{
|
|
struct nfs4_reclaim_complete_data *calldata = data;
|
|
struct nfs4_reclaim_complete_data *calldata = data;
|
|
@@ -5186,32 +5269,13 @@ static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data)
|
|
struct nfs4_sequence_res *res = &calldata->res.seq_res;
|
|
struct nfs4_sequence_res *res = &calldata->res.seq_res;
|
|
|
|
|
|
dprintk("--> %s\n", __func__);
|
|
dprintk("--> %s\n", __func__);
|
|
- nfs41_sequence_done(clp, res, task->tk_status);
|
|
|
|
- switch (task->tk_status) {
|
|
|
|
- case 0:
|
|
|
|
- case -NFS4ERR_COMPLETE_ALREADY:
|
|
|
|
- break;
|
|
|
|
- case -NFS4ERR_BADSESSION:
|
|
|
|
- case -NFS4ERR_DEADSESSION:
|
|
|
|
- /*
|
|
|
|
- * Handle the session error, but do not retry the operation, as
|
|
|
|
- * we have no way of telling whether the clientid had to be
|
|
|
|
- * reset before we got our reply. If reset, a new wave of
|
|
|
|
- * reclaim operations will follow, containing their own reclaim
|
|
|
|
- * complete. We don't want our retry to get on the way of
|
|
|
|
- * recovery by incorrectly indicating to the server that we're
|
|
|
|
- * done reclaiming state since the process had to be restarted.
|
|
|
|
- */
|
|
|
|
- _nfs4_async_handle_error(task, NULL, clp, NULL);
|
|
|
|
- break;
|
|
|
|
- default:
|
|
|
|
- if (_nfs4_async_handle_error(
|
|
|
|
- task, NULL, clp, NULL) == -EAGAIN) {
|
|
|
|
- rpc_restart_call_prepare(task);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ if (!nfs41_sequence_done(task, res))
|
|
|
|
+ return;
|
|
|
|
|
|
|
|
+ if (nfs41_reclaim_complete_handle_errors(task, clp) == -EAGAIN) {
|
|
|
|
+ rpc_restart_call_prepare(task);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
dprintk("<-- %s\n", __func__);
|
|
dprintk("<-- %s\n", __func__);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -5325,28 +5389,30 @@ struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {
|
|
};
|
|
};
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-/*
|
|
|
|
- * Per minor version reboot and network partition recovery ops
|
|
|
|
- */
|
|
|
|
-
|
|
|
|
-struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[] = {
|
|
|
|
- &nfs40_reboot_recovery_ops,
|
|
|
|
-#if defined(CONFIG_NFS_V4_1)
|
|
|
|
- &nfs41_reboot_recovery_ops,
|
|
|
|
-#endif
|
|
|
|
|
|
+static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
|
|
|
|
+ .minor_version = 0,
|
|
|
|
+ .call_sync = _nfs4_call_sync,
|
|
|
|
+ .validate_stateid = nfs4_validate_delegation_stateid,
|
|
|
|
+ .reboot_recovery_ops = &nfs40_reboot_recovery_ops,
|
|
|
|
+ .nograce_recovery_ops = &nfs40_nograce_recovery_ops,
|
|
|
|
+ .state_renewal_ops = &nfs40_state_renewal_ops,
|
|
};
|
|
};
|
|
|
|
|
|
-struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[] = {
|
|
|
|
- &nfs40_nograce_recovery_ops,
|
|
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
- &nfs41_nograce_recovery_ops,
|
|
|
|
-#endif
|
|
|
|
|
|
+static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
|
|
|
|
+ .minor_version = 1,
|
|
|
|
+ .call_sync = _nfs4_call_sync_session,
|
|
|
|
+ .validate_stateid = nfs41_validate_delegation_stateid,
|
|
|
|
+ .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
|
|
|
|
+ .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
|
|
|
|
+ .state_renewal_ops = &nfs41_state_renewal_ops,
|
|
};
|
|
};
|
|
|
|
+#endif
|
|
|
|
|
|
-struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[] = {
|
|
|
|
- &nfs40_state_renewal_ops,
|
|
|
|
|
|
+const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {
|
|
|
|
+ [0] = &nfs_v4_0_minor_ops,
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
- &nfs41_state_renewal_ops,
|
|
|
|
|
|
+ [1] = &nfs_v4_1_minor_ops,
|
|
#endif
|
|
#endif
|
|
};
|
|
};
|
|
|
|
|