diff options
author | Andy Adamson <andros@netapp.com> | 2009-04-01 09:22:36 -0400 |
---|---|---|
committer | Benny Halevy <bhalevy@panasas.com> | 2009-06-17 15:25:04 -0400 |
commit | fc01cea963a246742ff15e118ce5259e3091352c (patch) | |
tree | bf2bd0fdb99910aa8045d53574504e49c577bbf0 | |
parent | 8328d59f380e26477b9c1ede99e33d021365bcd1 (diff) |
nfs41: sequence operation
Implement the sequence operation conforming to
http://tools.ietf.org/html/draft-ietf-nfsv4-minorversion1-26
Check returned sessionid, slotid and slot sequenceid in decode_sequence.
If the server returns different values for sessionID, slotID or slot sequence
number than what was sent, the server is looney tunes.
Pass the sequence operation status to nfs41_sequence_done in order to
determine when to increment the slot sequence ID.
Free slot is separated from sequence done.
Signed-off-by: Rahul Iyer <iyer@netapp.com>
Signed-off-by: Ricardo Labiaga <ricardo.labiaga@netapp.com>
Signed-off-by: Andy Adamson<andros@umich.edu>
[nfs41: sequence res use slotid]
Signed-off-by: Andy Adamson <andros@netapp.com>
[nfs41: deref slot table in decode_sequence only for minorversion!=0]
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[nfs41: nfs4_call_sync]
[nfs41: remove SEQ4_STATUS_USE_TK_STATUS]
[nfs41: return ESERVERFAULT in decode_sequence]
[no sr_session, no sr_flags]
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[nfs41: use nfs4_call_sync_sequence to renew session lease]
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[nfs41: remove nfs4_call_sync_sequence forward definition]
Signed-off-by: Andy Adamson <andros@netapp.com>
[nfs41: use struct nfs_client for nfs41_proc_async_sequence]
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[nfs41: pass *session in seq_args and seq_res]
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[nfs41 nfs41_sequence_call_done update error checking]
[nfs41 nfs41_sequence_done update error checking]
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[nfs41: remove switch on error from nfs41_sequence_call_done]
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/nfs4proc.c | 92 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 127 |
2 files changed, 214 insertions, 5 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 5fe208b486d4..17768095f0cc 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -4567,6 +4567,98 @@ int nfs4_proc_destroy_session(struct nfs4_session *session) | |||
4567 | return status; | 4567 | return status; |
4568 | } | 4568 | } |
4569 | 4569 | ||
4570 | /* | ||
4571 | * Renew the cl_session lease. | ||
4572 | */ | ||
4573 | static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | ||
4574 | { | ||
4575 | struct nfs4_sequence_args args; | ||
4576 | struct nfs4_sequence_res res; | ||
4577 | |||
4578 | struct rpc_message msg = { | ||
4579 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | ||
4580 | .rpc_argp = &args, | ||
4581 | .rpc_resp = &res, | ||
4582 | .rpc_cred = cred, | ||
4583 | }; | ||
4584 | |||
4585 | args.sa_cache_this = 0; | ||
4586 | |||
4587 | return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args, | ||
4588 | &res, 0); | ||
4589 | } | ||
4590 | |||
4591 | void nfs41_sequence_call_done(struct rpc_task *task, void *data) | ||
4592 | { | ||
4593 | struct nfs_client *clp = (struct nfs_client *)data; | ||
4594 | |||
4595 | nfs41_sequence_done(clp, task->tk_msg.rpc_resp, task->tk_status); | ||
4596 | |||
4597 | if (task->tk_status < 0) { | ||
4598 | dprintk("%s ERROR %d\n", __func__, task->tk_status); | ||
4599 | |||
4600 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) | ||
4601 | == -EAGAIN) { | ||
4602 | rpc_restart_call(task); | ||
4603 | return; | ||
4604 | } | ||
4605 | } | ||
4606 | nfs41_sequence_free_slot(clp, task->tk_msg.rpc_resp); | ||
4607 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); | ||
4608 | |||
4609 | put_rpccred(task->tk_msg.rpc_cred); | ||
4610 | kfree(task->tk_msg.rpc_argp); | ||
4611 | kfree(task->tk_msg.rpc_resp); | ||
4612 | |||
4613 | dprintk("<-- %s\n", __func__); | ||
4614 | } | ||
4615 | |||
4616 | static void nfs41_sequence_prepare(struct rpc_task *task, void *data) | ||
4617 | { | ||
4618 | struct nfs_client *clp; | ||
4619 | struct nfs4_sequence_args *args; | ||
4620 | struct nfs4_sequence_res *res; | ||
4621 | |||
4622 | clp = (struct nfs_client *)data; | ||
4623 | args = task->tk_msg.rpc_argp; | ||
4624 | res = task->tk_msg.rpc_resp; | ||
4625 | |||
4626 | if (nfs4_setup_sequence(clp, args, res, 0, task)) | ||
4627 | return; | ||
4628 | rpc_call_start(task); | ||
4629 | } | ||
4630 | |||
4631 | static const struct rpc_call_ops nfs41_sequence_ops = { | ||
4632 | .rpc_call_done = nfs41_sequence_call_done, | ||
4633 | .rpc_call_prepare = nfs41_sequence_prepare, | ||
4634 | }; | ||
4635 | |||
4636 | static int nfs41_proc_async_sequence(struct nfs_client *clp, | ||
4637 | struct rpc_cred *cred) | ||
4638 | { | ||
4639 | struct nfs4_sequence_args *args; | ||
4640 | struct nfs4_sequence_res *res; | ||
4641 | struct rpc_message msg = { | ||
4642 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | ||
4643 | .rpc_cred = cred, | ||
4644 | }; | ||
4645 | |||
4646 | args = kzalloc(sizeof(*args), GFP_KERNEL); | ||
4647 | if (!args) | ||
4648 | return -ENOMEM; | ||
4649 | res = kzalloc(sizeof(*res), GFP_KERNEL); | ||
4650 | if (!res) { | ||
4651 | kfree(args); | ||
4652 | return -ENOMEM; | ||
4653 | } | ||
4654 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
4655 | msg.rpc_argp = args; | ||
4656 | msg.rpc_resp = res; | ||
4657 | |||
4658 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | ||
4659 | &nfs41_sequence_ops, (void *)clp); | ||
4660 | } | ||
4661 | |||
4570 | #endif /* CONFIG_NFS_V4_1 */ | 4662 | #endif /* CONFIG_NFS_V4_1 */ |
4571 | 4663 | ||
4572 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { | 4664 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index a81e49648ccb..617273e7d47f 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -296,8 +296,10 @@ static int nfs4_stat_to_errno(int); | |||
296 | decode_channel_attrs_maxsz) | 296 | decode_channel_attrs_maxsz) |
297 | #define encode_destroy_session_maxsz (op_encode_hdr_maxsz + 4) | 297 | #define encode_destroy_session_maxsz (op_encode_hdr_maxsz + 4) |
298 | #define decode_destroy_session_maxsz (op_decode_hdr_maxsz) | 298 | #define decode_destroy_session_maxsz (op_decode_hdr_maxsz) |
299 | #define encode_sequence_maxsz 0 /* stub */ | 299 | #define encode_sequence_maxsz (op_encode_hdr_maxsz + \ |
300 | #define decode_sequence_maxsz 0 /* stub */ | 300 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 4) |
301 | #define decode_sequence_maxsz (op_decode_hdr_maxsz + \ | ||
302 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5) | ||
301 | #else /* CONFIG_NFS_V4_1 */ | 303 | #else /* CONFIG_NFS_V4_1 */ |
302 | #define encode_sequence_maxsz 0 | 304 | #define encode_sequence_maxsz 0 |
303 | #define decode_sequence_maxsz 0 | 305 | #define decode_sequence_maxsz 0 |
@@ -661,6 +663,12 @@ static int nfs4_stat_to_errno(int); | |||
661 | encode_destroy_session_maxsz) | 663 | encode_destroy_session_maxsz) |
662 | #define NFS4_dec_destroy_session_sz (compound_decode_hdr_maxsz + \ | 664 | #define NFS4_dec_destroy_session_sz (compound_decode_hdr_maxsz + \ |
663 | decode_destroy_session_maxsz) | 665 | decode_destroy_session_maxsz) |
666 | #define NFS4_enc_sequence_sz \ | ||
667 | (compound_decode_hdr_maxsz + \ | ||
668 | encode_sequence_maxsz) | ||
669 | #define NFS4_dec_sequence_sz \ | ||
670 | (compound_decode_hdr_maxsz + \ | ||
671 | decode_sequence_maxsz) | ||
664 | #define NFS4_enc_get_lease_time_sz (compound_encode_hdr_maxsz + \ | 672 | #define NFS4_enc_get_lease_time_sz (compound_encode_hdr_maxsz + \ |
665 | encode_sequence_maxsz + \ | 673 | encode_sequence_maxsz + \ |
666 | encode_putrootfh_maxsz + \ | 674 | encode_putrootfh_maxsz + \ |
@@ -1635,11 +1643,39 @@ static void encode_sequence(struct xdr_stream *xdr, | |||
1635 | { | 1643 | { |
1636 | #if defined(CONFIG_NFS_V4_1) | 1644 | #if defined(CONFIG_NFS_V4_1) |
1637 | struct nfs4_session *session = args->sa_session; | 1645 | struct nfs4_session *session = args->sa_session; |
1646 | struct nfs4_slot_table *tp; | ||
1647 | struct nfs4_slot *slot; | ||
1648 | __be32 *p; | ||
1638 | 1649 | ||
1639 | if (!session) | 1650 | if (!session) |
1640 | return; | 1651 | return; |
1641 | 1652 | ||
1642 | /* stub */ | 1653 | tp = &session->fc_slot_table; |
1654 | |||
1655 | WARN_ON(args->sa_slotid == NFS4_MAX_SLOT_TABLE); | ||
1656 | slot = tp->slots + args->sa_slotid; | ||
1657 | |||
1658 | RESERVE_SPACE(4); | ||
1659 | WRITE32(OP_SEQUENCE); | ||
1660 | |||
1661 | /* | ||
1662 | * Sessionid + seqid + slotid + max slotid + cache_this | ||
1663 | */ | ||
1664 | dprintk("%s: sessionid=%u:%u:%u:%u seqid=%d slotid=%d " | ||
1665 | "max_slotid=%d cache_this=%d\n", | ||
1666 | __func__, | ||
1667 | ((u32 *)session->sess_id.data)[0], | ||
1668 | ((u32 *)session->sess_id.data)[1], | ||
1669 | ((u32 *)session->sess_id.data)[2], | ||
1670 | ((u32 *)session->sess_id.data)[3], | ||
1671 | slot->seq_nr, args->sa_slotid, | ||
1672 | tp->highest_used_slotid, args->sa_cache_this); | ||
1673 | RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 16); | ||
1674 | WRITEMEM(session->sess_id.data, NFS4_MAX_SESSIONID_LEN); | ||
1675 | WRITE32(slot->seq_nr); | ||
1676 | WRITE32(args->sa_slotid); | ||
1677 | WRITE32(tp->highest_used_slotid); | ||
1678 | WRITE32(args->sa_cache_this); | ||
1643 | hdr->nops++; | 1679 | hdr->nops++; |
1644 | hdr->replen += decode_sequence_maxsz; | 1680 | hdr->replen += decode_sequence_maxsz; |
1645 | #endif /* CONFIG_NFS_V4_1 */ | 1681 | #endif /* CONFIG_NFS_V4_1 */ |
@@ -2391,6 +2427,24 @@ static int nfs4_xdr_enc_destroy_session(struct rpc_rqst *req, uint32_t *p, | |||
2391 | } | 2427 | } |
2392 | 2428 | ||
2393 | /* | 2429 | /* |
2430 | * a SEQUENCE request | ||
2431 | */ | ||
2432 | static int nfs4_xdr_enc_sequence(struct rpc_rqst *req, uint32_t *p, | ||
2433 | struct nfs4_sequence_args *args) | ||
2434 | { | ||
2435 | struct xdr_stream xdr; | ||
2436 | struct compound_hdr hdr = { | ||
2437 | .minorversion = nfs4_xdr_minorversion(args), | ||
2438 | }; | ||
2439 | |||
2440 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2441 | encode_compound_hdr(&xdr, req, &hdr); | ||
2442 | encode_sequence(&xdr, args, &hdr); | ||
2443 | encode_nops(&hdr); | ||
2444 | return 0; | ||
2445 | } | ||
2446 | |||
2447 | /* | ||
2394 | * a GET_LEASE_TIME request | 2448 | * a GET_LEASE_TIME request |
2395 | */ | 2449 | */ |
2396 | static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p, | 2450 | static int nfs4_xdr_enc_get_lease_time(struct rpc_rqst *req, uint32_t *p, |
@@ -4236,13 +4290,58 @@ static int decode_sequence(struct xdr_stream *xdr, | |||
4236 | struct rpc_rqst *rqstp) | 4290 | struct rpc_rqst *rqstp) |
4237 | { | 4291 | { |
4238 | #if defined(CONFIG_NFS_V4_1) | 4292 | #if defined(CONFIG_NFS_V4_1) |
4293 | struct nfs4_slot *slot; | ||
4294 | struct nfs4_sessionid id; | ||
4295 | u32 dummy; | ||
4296 | int status; | ||
4297 | __be32 *p; | ||
4298 | |||
4239 | if (!res->sr_session) | 4299 | if (!res->sr_session) |
4240 | return 0; | 4300 | return 0; |
4241 | 4301 | ||
4242 | /* stub */ | 4302 | status = decode_op_hdr(xdr, OP_SEQUENCE); |
4243 | #endif /* CONFIG_NFS_V4_1 */ | 4303 | if (status) |
4304 | goto out_err; | ||
4244 | 4305 | ||
4306 | /* | ||
4307 | * If the server returns different values for sessionID, slotID or | ||
4308 | * sequence number, the server is looney tunes. | ||
4309 | */ | ||
4310 | status = -ESERVERFAULT; | ||
4311 | |||
4312 | slot = &res->sr_session->fc_slot_table.slots[res->sr_slotid]; | ||
4313 | READ_BUF(NFS4_MAX_SESSIONID_LEN + 20); | ||
4314 | COPYMEM(id.data, NFS4_MAX_SESSIONID_LEN); | ||
4315 | if (memcmp(id.data, res->sr_session->sess_id.data, | ||
4316 | NFS4_MAX_SESSIONID_LEN)) { | ||
4317 | dprintk("%s Invalid session id\n", __func__); | ||
4318 | goto out_err; | ||
4319 | } | ||
4320 | /* seqid */ | ||
4321 | READ32(dummy); | ||
4322 | if (dummy != slot->seq_nr) { | ||
4323 | dprintk("%s Invalid sequence number\n", __func__); | ||
4324 | goto out_err; | ||
4325 | } | ||
4326 | /* slot id */ | ||
4327 | READ32(dummy); | ||
4328 | if (dummy != res->sr_slotid) { | ||
4329 | dprintk("%s Invalid slot id\n", __func__); | ||
4330 | goto out_err; | ||
4331 | } | ||
4332 | /* highest slot id - currently not processed */ | ||
4333 | READ32(dummy); | ||
4334 | /* target highest slot id - currently not processed */ | ||
4335 | READ32(dummy); | ||
4336 | /* result flags - currently not processed */ | ||
4337 | READ32(dummy); | ||
4338 | status = 0; | ||
4339 | out_err: | ||
4340 | res->sr_status = status; | ||
4341 | return status; | ||
4342 | #else /* CONFIG_NFS_V4_1 */ | ||
4245 | return 0; | 4343 | return 0; |
4344 | #endif /* CONFIG_NFS_V4_1 */ | ||
4246 | } | 4345 | } |
4247 | 4346 | ||
4248 | /* | 4347 | /* |
@@ -5181,6 +5280,23 @@ static int nfs4_xdr_dec_destroy_session(struct rpc_rqst *rqstp, uint32_t *p, | |||
5181 | } | 5280 | } |
5182 | 5281 | ||
5183 | /* | 5282 | /* |
5283 | * a SEQUENCE request | ||
5284 | */ | ||
5285 | static int nfs4_xdr_dec_sequence(struct rpc_rqst *rqstp, uint32_t *p, | ||
5286 | struct nfs4_sequence_res *res) | ||
5287 | { | ||
5288 | struct xdr_stream xdr; | ||
5289 | struct compound_hdr hdr; | ||
5290 | int status; | ||
5291 | |||
5292 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
5293 | status = decode_compound_hdr(&xdr, &hdr); | ||
5294 | if (!status) | ||
5295 | status = decode_sequence(&xdr, res, rqstp); | ||
5296 | return status; | ||
5297 | } | ||
5298 | |||
5299 | /* | ||
5184 | * a GET_LEASE_TIME request | 5300 | * a GET_LEASE_TIME request |
5185 | */ | 5301 | */ |
5186 | static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp, uint32_t *p, | 5302 | static int nfs4_xdr_dec_get_lease_time(struct rpc_rqst *rqstp, uint32_t *p, |
@@ -5375,6 +5491,7 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
5375 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), | 5491 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), |
5376 | PROC(CREATE_SESSION, enc_create_session, dec_create_session), | 5492 | PROC(CREATE_SESSION, enc_create_session, dec_create_session), |
5377 | PROC(DESTROY_SESSION, enc_destroy_session, dec_destroy_session), | 5493 | PROC(DESTROY_SESSION, enc_destroy_session, dec_destroy_session), |
5494 | PROC(SEQUENCE, enc_sequence, dec_sequence), | ||
5378 | PROC(GET_LEASE_TIME, enc_get_lease_time, dec_get_lease_time), | 5495 | PROC(GET_LEASE_TIME, enc_get_lease_time, dec_get_lease_time), |
5379 | #endif /* CONFIG_NFS_V4_1 */ | 5496 | #endif /* CONFIG_NFS_V4_1 */ |
5380 | }; | 5497 | }; |