diff options
author | Benny Halevy <bhalevy@panasas.com> | 2009-04-01 09:22:29 -0400 |
---|---|---|
committer | Benny Halevy <bhalevy@panasas.com> | 2009-06-17 15:23:57 -0400 |
commit | 99fe60d062cfecf382c036065b3278b82b6c5eff (patch) | |
tree | b4451fc4bb42c0915c4f736cc5fdae9e818b55d4 /fs/nfs | |
parent | 938e10109115a71cc69d475122f21cf75e5046cd (diff) |
nfs41: exchange_id operation
Implement the exchange_id operation conforming to
http://tools.ietf.org/html/draft-ietf-nfsv4-minorversion1-26
Unlike NFSv4.0, NFSv4.1 requires machine credentials. RPC_AUTH_GSS machine
credentials will be passed into the kernel at mount time to be available for
the exchange_id operation.
RPC_AUTH_UNIX root mounts can use the UNIX root credential. Store the root
credential in the nfs_client struct.
Without a credential, NFSv4.1 state renewal fails.
[nfs41: establish clientid via exchange id only if cred != NULL]
Signed-off-by: Andy Adamson<andros@umich.edu>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[nfsd41: move nfstime4 from under CONFIG_NFS_V4_1]
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[nfs41: do not wait a lease time in exchange id]
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>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
[nfs41: Ignoring impid in decode_exchange_id is missing a READ_BUF]
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
[nfs41: fix Xcode_exchange_id's xdr Xcoding pointer type]
[nfs41: get rid of unused struct nfs41_exchange_id_res members]
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r-- | fs/nfs/nfs4proc.c | 61 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 139 |
2 files changed, 200 insertions, 0 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index dc0feb5837b1..6f384e290753 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <linux/smp_lock.h> | 48 | #include <linux/smp_lock.h> |
49 | #include <linux/namei.h> | 49 | #include <linux/namei.h> |
50 | #include <linux/mount.h> | 50 | #include <linux/mount.h> |
51 | #include <linux/module.h> | ||
51 | 52 | ||
52 | #include "nfs4_fs.h" | 53 | #include "nfs4_fs.h" |
53 | #include "delegation.h" | 54 | #include "delegation.h" |
@@ -433,11 +434,13 @@ static int nfs41_setup_sequence(struct nfs4_session *session, | |||
433 | spin_unlock(&tbl->slot_tbl_lock); | 434 | spin_unlock(&tbl->slot_tbl_lock); |
434 | 435 | ||
435 | slot = tbl->slots + slotid; | 436 | slot = tbl->slots + slotid; |
437 | args->sa_session = session; | ||
436 | args->sa_slotid = slotid; | 438 | args->sa_slotid = slotid; |
437 | args->sa_cache_this = cache_reply; | 439 | args->sa_cache_this = cache_reply; |
438 | 440 | ||
439 | dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr); | 441 | dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr); |
440 | 442 | ||
443 | res->sr_session = session; | ||
441 | res->sr_slotid = slotid; | 444 | res->sr_slotid = slotid; |
442 | res->sr_renewal_time = jiffies; | 445 | res->sr_renewal_time = jiffies; |
443 | /* | 446 | /* |
@@ -4128,6 +4131,64 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
4128 | } | 4131 | } |
4129 | 4132 | ||
4130 | #ifdef CONFIG_NFS_V4_1 | 4133 | #ifdef CONFIG_NFS_V4_1 |
4134 | /* | ||
4135 | * nfs4_proc_exchange_id() | ||
4136 | * | ||
4137 | * Since the clientid has expired, all compounds using sessions | ||
4138 | * associated with the stale clientid will be returning | ||
4139 | * NFS4ERR_BADSESSION in the sequence operation, and will therefore | ||
4140 | * be in some phase of session reset. | ||
4141 | */ | ||
4142 | static int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | ||
4143 | { | ||
4144 | nfs4_verifier verifier; | ||
4145 | struct nfs41_exchange_id_args args = { | ||
4146 | .client = clp, | ||
4147 | .flags = clp->cl_exchange_flags, | ||
4148 | }; | ||
4149 | struct nfs41_exchange_id_res res = { | ||
4150 | .client = clp, | ||
4151 | }; | ||
4152 | int status; | ||
4153 | struct rpc_message msg = { | ||
4154 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_EXCHANGE_ID], | ||
4155 | .rpc_argp = &args, | ||
4156 | .rpc_resp = &res, | ||
4157 | .rpc_cred = cred, | ||
4158 | }; | ||
4159 | __be32 *p; | ||
4160 | |||
4161 | dprintk("--> %s\n", __func__); | ||
4162 | BUG_ON(clp == NULL); | ||
4163 | p = (u32 *)verifier.data; | ||
4164 | *p++ = htonl((u32)clp->cl_boot_time.tv_sec); | ||
4165 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); | ||
4166 | args.verifier = &verifier; | ||
4167 | |||
4168 | while (1) { | ||
4169 | args.id_len = scnprintf(args.id, sizeof(args.id), | ||
4170 | "%s/%s %u", | ||
4171 | clp->cl_ipaddr, | ||
4172 | rpc_peeraddr2str(clp->cl_rpcclient, | ||
4173 | RPC_DISPLAY_ADDR), | ||
4174 | clp->cl_id_uniquifier); | ||
4175 | |||
4176 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | ||
4177 | |||
4178 | if (status != NFS4ERR_CLID_INUSE) | ||
4179 | break; | ||
4180 | |||
4181 | if (signalled()) | ||
4182 | break; | ||
4183 | |||
4184 | if (++clp->cl_id_uniquifier == 0) | ||
4185 | break; | ||
4186 | } | ||
4187 | |||
4188 | dprintk("<-- %s status= %d\n", __func__, status); | ||
4189 | return status; | ||
4190 | } | ||
4191 | |||
4131 | /* Destroy the slot table */ | 4192 | /* Destroy the slot table */ |
4132 | static void nfs4_destroy_slot_table(struct nfs4_session *session) | 4193 | static void nfs4_destroy_slot_table(struct nfs4_session *session) |
4133 | { | 4194 | { |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 5b944cd57218..783c4214dccd 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -246,6 +246,27 @@ static int nfs4_stat_to_errno(int); | |||
246 | (0) | 246 | (0) |
247 | 247 | ||
248 | #if defined(CONFIG_NFS_V4_1) | 248 | #if defined(CONFIG_NFS_V4_1) |
249 | #define encode_exchange_id_maxsz (op_encode_hdr_maxsz + \ | ||
250 | encode_verifier_maxsz + \ | ||
251 | 1 /* co_ownerid.len */ + \ | ||
252 | XDR_QUADLEN(NFS4_EXCHANGE_ID_LEN) + \ | ||
253 | 1 /* flags */ + \ | ||
254 | 1 /* spa_how */ + \ | ||
255 | 0 /* SP4_NONE (for now) */ + \ | ||
256 | 1 /* zero implemetation id array */) | ||
257 | #define decode_exchange_id_maxsz (op_decode_hdr_maxsz + \ | ||
258 | 2 /* eir_clientid */ + \ | ||
259 | 1 /* eir_sequenceid */ + \ | ||
260 | 1 /* eir_flags */ + \ | ||
261 | 1 /* spr_how */ + \ | ||
262 | 0 /* SP4_NONE (for now) */ + \ | ||
263 | 2 /* eir_server_owner.so_minor_id */ + \ | ||
264 | /* eir_server_owner.so_major_id<> */ \ | ||
265 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \ | ||
266 | /* eir_server_scope<> */ \ | ||
267 | XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \ | ||
268 | 1 /* eir_server_impl_id array length */ + \ | ||
269 | 0 /* ignored eir_server_impl_id contents */) | ||
249 | #define encode_sequence_maxsz 0 /* stub */ | 270 | #define encode_sequence_maxsz 0 /* stub */ |
250 | #define decode_sequence_maxsz 0 /* stub */ | 271 | #define decode_sequence_maxsz 0 /* stub */ |
251 | #else /* CONFIG_NFS_V4_1 */ | 272 | #else /* CONFIG_NFS_V4_1 */ |
@@ -594,6 +615,14 @@ static int nfs4_stat_to_errno(int); | |||
594 | decode_putfh_maxsz + \ | 615 | decode_putfh_maxsz + \ |
595 | decode_lookup_maxsz + \ | 616 | decode_lookup_maxsz + \ |
596 | decode_fs_locations_maxsz) | 617 | decode_fs_locations_maxsz) |
618 | #if defined(CONFIG_NFS_V4_1) | ||
619 | #define NFS4_enc_exchange_id_sz \ | ||
620 | (compound_encode_hdr_maxsz + \ | ||
621 | encode_exchange_id_maxsz) | ||
622 | #define NFS4_dec_exchange_id_sz \ | ||
623 | (compound_decode_hdr_maxsz + \ | ||
624 | decode_exchange_id_maxsz) | ||
625 | #endif /* CONFIG_NFS_V4_1 */ | ||
597 | 626 | ||
598 | static const umode_t nfs_type2fmt[] = { | 627 | static const umode_t nfs_type2fmt[] = { |
599 | [NF4BAD] = 0, | 628 | [NF4BAD] = 0, |
@@ -1455,7 +1484,29 @@ static void encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *state | |||
1455 | hdr->replen += decode_delegreturn_maxsz; | 1484 | hdr->replen += decode_delegreturn_maxsz; |
1456 | } | 1485 | } |
1457 | 1486 | ||
1487 | #if defined(CONFIG_NFS_V4_1) | ||
1458 | /* NFSv4.1 operations */ | 1488 | /* NFSv4.1 operations */ |
1489 | static void encode_exchange_id(struct xdr_stream *xdr, | ||
1490 | struct nfs41_exchange_id_args *args, | ||
1491 | struct compound_hdr *hdr) | ||
1492 | { | ||
1493 | __be32 *p; | ||
1494 | |||
1495 | RESERVE_SPACE(4 + sizeof(args->verifier->data)); | ||
1496 | WRITE32(OP_EXCHANGE_ID); | ||
1497 | WRITEMEM(args->verifier->data, sizeof(args->verifier->data)); | ||
1498 | |||
1499 | encode_string(xdr, args->id_len, args->id); | ||
1500 | |||
1501 | RESERVE_SPACE(12); | ||
1502 | WRITE32(args->flags); | ||
1503 | WRITE32(0); /* zero length state_protect4_a */ | ||
1504 | WRITE32(0); /* zero length implementation id array */ | ||
1505 | hdr->nops++; | ||
1506 | hdr->replen += decode_exchange_id_maxsz; | ||
1507 | } | ||
1508 | #endif /* CONFIG_NFS_V4_1 */ | ||
1509 | |||
1459 | static void encode_sequence(struct xdr_stream *xdr, | 1510 | static void encode_sequence(struct xdr_stream *xdr, |
1460 | const struct nfs4_sequence_args *args, | 1511 | const struct nfs4_sequence_args *args, |
1461 | struct compound_hdr *hdr) | 1512 | struct compound_hdr *hdr) |
@@ -2162,6 +2213,26 @@ static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs | |||
2162 | return 0; | 2213 | return 0; |
2163 | } | 2214 | } |
2164 | 2215 | ||
2216 | #if defined(CONFIG_NFS_V4_1) | ||
2217 | /* | ||
2218 | * EXCHANGE_ID request | ||
2219 | */ | ||
2220 | static int nfs4_xdr_enc_exchange_id(struct rpc_rqst *req, uint32_t *p, | ||
2221 | struct nfs41_exchange_id_args *args) | ||
2222 | { | ||
2223 | struct xdr_stream xdr; | ||
2224 | struct compound_hdr hdr = { | ||
2225 | .minorversion = args->client->cl_minorversion, | ||
2226 | }; | ||
2227 | |||
2228 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); | ||
2229 | encode_compound_hdr(&xdr, req, &hdr); | ||
2230 | encode_exchange_id(&xdr, args, &hdr); | ||
2231 | encode_nops(&hdr); | ||
2232 | return 0; | ||
2233 | } | ||
2234 | #endif /* CONFIG_NFS_V4_1 */ | ||
2235 | |||
2165 | /* | 2236 | /* |
2166 | * START OF "GENERIC" DECODE ROUTINES. | 2237 | * START OF "GENERIC" DECODE ROUTINES. |
2167 | * These may look a little ugly since they are imported from a "generic" | 2238 | * These may look a little ugly since they are imported from a "generic" |
@@ -3877,6 +3948,52 @@ static int decode_delegreturn(struct xdr_stream *xdr) | |||
3877 | return decode_op_hdr(xdr, OP_DELEGRETURN); | 3948 | return decode_op_hdr(xdr, OP_DELEGRETURN); |
3878 | } | 3949 | } |
3879 | 3950 | ||
3951 | #if defined(CONFIG_NFS_V4_1) | ||
3952 | static int decode_exchange_id(struct xdr_stream *xdr, | ||
3953 | struct nfs41_exchange_id_res *res) | ||
3954 | { | ||
3955 | __be32 *p; | ||
3956 | uint32_t dummy; | ||
3957 | int status; | ||
3958 | struct nfs_client *clp = res->client; | ||
3959 | |||
3960 | status = decode_op_hdr(xdr, OP_EXCHANGE_ID); | ||
3961 | if (status) | ||
3962 | return status; | ||
3963 | |||
3964 | READ_BUF(8); | ||
3965 | READ64(clp->cl_ex_clid); | ||
3966 | READ_BUF(12); | ||
3967 | READ32(clp->cl_seqid); | ||
3968 | READ32(clp->cl_exchange_flags); | ||
3969 | |||
3970 | /* We ask for SP4_NONE */ | ||
3971 | READ32(dummy); | ||
3972 | if (dummy != SP4_NONE) | ||
3973 | return -EIO; | ||
3974 | |||
3975 | /* Throw away minor_id */ | ||
3976 | READ_BUF(8); | ||
3977 | |||
3978 | /* Throw away Major id */ | ||
3979 | READ_BUF(4); | ||
3980 | READ32(dummy); | ||
3981 | READ_BUF(dummy); | ||
3982 | |||
3983 | /* Throw away server_scope */ | ||
3984 | READ_BUF(4); | ||
3985 | READ32(dummy); | ||
3986 | READ_BUF(dummy); | ||
3987 | |||
3988 | /* Throw away Implementation id array */ | ||
3989 | READ_BUF(4); | ||
3990 | READ32(dummy); | ||
3991 | READ_BUF(dummy); | ||
3992 | |||
3993 | return 0; | ||
3994 | } | ||
3995 | #endif /* CONFIG_NFS_V4_1 */ | ||
3996 | |||
3880 | static int decode_sequence(struct xdr_stream *xdr, | 3997 | static int decode_sequence(struct xdr_stream *xdr, |
3881 | struct nfs4_sequence_res *res, | 3998 | struct nfs4_sequence_res *res, |
3882 | struct rpc_rqst *rqstp) | 3999 | struct rpc_rqst *rqstp) |
@@ -4774,6 +4891,25 @@ out: | |||
4774 | return status; | 4891 | return status; |
4775 | } | 4892 | } |
4776 | 4893 | ||
4894 | #if defined(CONFIG_NFS_V4_1) | ||
4895 | /* | ||
4896 | * EXCHANGE_ID request | ||
4897 | */ | ||
4898 | static int nfs4_xdr_dec_exchange_id(struct rpc_rqst *rqstp, uint32_t *p, | ||
4899 | void *res) | ||
4900 | { | ||
4901 | struct xdr_stream xdr; | ||
4902 | struct compound_hdr hdr; | ||
4903 | int status; | ||
4904 | |||
4905 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
4906 | status = decode_compound_hdr(&xdr, &hdr); | ||
4907 | if (!status) | ||
4908 | status = decode_exchange_id(&xdr, res); | ||
4909 | return status; | ||
4910 | } | ||
4911 | #endif /* CONFIG_NFS_V4_1 */ | ||
4912 | |||
4777 | __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) | 4913 | __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus) |
4778 | { | 4914 | { |
4779 | uint32_t bitmap[2] = {0}; | 4915 | uint32_t bitmap[2] = {0}; |
@@ -4943,6 +5079,9 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
4943 | PROC(GETACL, enc_getacl, dec_getacl), | 5079 | PROC(GETACL, enc_getacl, dec_getacl), |
4944 | PROC(SETACL, enc_setacl, dec_setacl), | 5080 | PROC(SETACL, enc_setacl, dec_setacl), |
4945 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), | 5081 | PROC(FS_LOCATIONS, enc_fs_locations, dec_fs_locations), |
5082 | #if defined(CONFIG_NFS_V4_1) | ||
5083 | PROC(EXCHANGE_ID, enc_exchange_id, dec_exchange_id), | ||
5084 | #endif /* CONFIG_NFS_V4_1 */ | ||
4946 | }; | 5085 | }; |
4947 | 5086 | ||
4948 | struct rpc_version nfs_version4 = { | 5087 | struct rpc_version nfs_version4 = { |