diff options
author | Bryan Schumaker <bjschuma@netapp.com> | 2011-06-02 14:59:07 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-07-12 13:40:27 -0400 |
commit | fca78d6d2c77f87d7dbee89bbe4836a44da881e2 (patch) | |
tree | 5378bd6ad0917cf11ad7f7b739b71794df230c85 /fs | |
parent | 6382a44138e7aa40bf52170e7afc014443a24806 (diff) |
NFS: Add SECINFO_NO_NAME procedure
If the client is using NFS v4.1, then we can use SECINFO_NO_NAME to find
the secflavor for the initial mount. If the server doesn't support
SECINFO_NO_NAME then I fall back on the "guess and check" method used
for v4.0 mounts.
Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/internal.h | 3 | ||||
-rw-r--r-- | fs/nfs/namespace.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 84 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 68 |
5 files changed, 157 insertions, 2 deletions
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 2a55347a2daa..fc017eadfe08 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
@@ -277,6 +277,9 @@ extern void nfs_sb_deactive(struct super_block *sb); | |||
277 | extern char *nfs_path(char **p, struct dentry *dentry, | 277 | extern char *nfs_path(char **p, struct dentry *dentry, |
278 | char *buffer, ssize_t buflen); | 278 | char *buffer, ssize_t buflen); |
279 | extern struct vfsmount *nfs_d_automount(struct path *path); | 279 | extern struct vfsmount *nfs_d_automount(struct path *path); |
280 | #ifdef CONFIG_NFS_V4 | ||
281 | rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *); | ||
282 | #endif | ||
280 | 283 | ||
281 | /* getroot.c */ | 284 | /* getroot.c */ |
282 | extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *, | 285 | extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *, |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 1f063bacd285..8102391bb374 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
@@ -119,7 +119,7 @@ Elong: | |||
119 | } | 119 | } |
120 | 120 | ||
121 | #ifdef CONFIG_NFS_V4 | 121 | #ifdef CONFIG_NFS_V4 |
122 | static rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors) | 122 | rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors) |
123 | { | 123 | { |
124 | struct gss_api_mech *mech; | 124 | struct gss_api_mech *mech; |
125 | struct xdr_netobj oid; | 125 | struct xdr_netobj oid; |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index b47f0d4710fa..c30aed2c70f4 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -67,6 +67,8 @@ struct nfs4_minor_version_ops { | |||
67 | int cache_reply); | 67 | int cache_reply); |
68 | int (*validate_stateid)(struct nfs_delegation *, | 68 | int (*validate_stateid)(struct nfs_delegation *, |
69 | const nfs4_stateid *); | 69 | const nfs4_stateid *); |
70 | int (*find_root_sec)(struct nfs_server *, struct nfs_fh *, | ||
71 | struct nfs_fsinfo *); | ||
70 | const struct nfs4_state_recovery_ops *reboot_recovery_ops; | 72 | const struct nfs4_state_recovery_ops *reboot_recovery_ops; |
71 | const struct nfs4_state_recovery_ops *nograce_recovery_ops; | 73 | const struct nfs4_state_recovery_ops *nograce_recovery_ops; |
72 | const struct nfs4_state_maintenance_ops *state_renewal_ops; | 74 | const struct nfs4_state_maintenance_ops *state_renewal_ops; |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 5f4912f72282..892bff53f61d 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -2251,13 +2251,14 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2251 | static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, | 2251 | static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, |
2252 | struct nfs_fsinfo *info) | 2252 | struct nfs_fsinfo *info) |
2253 | { | 2253 | { |
2254 | int minor_version = server->nfs_client->cl_minorversion; | ||
2254 | int status = nfs4_lookup_root(server, fhandle, info); | 2255 | int status = nfs4_lookup_root(server, fhandle, info); |
2255 | if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR)) | 2256 | if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR)) |
2256 | /* | 2257 | /* |
2257 | * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM | 2258 | * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM |
2258 | * by nfs4_map_errors() as this function exits. | 2259 | * by nfs4_map_errors() as this function exits. |
2259 | */ | 2260 | */ |
2260 | status = nfs4_find_root_sec(server, fhandle, info); | 2261 | status = nfs_v4_minor_ops[minor_version]->find_root_sec(server, fhandle, info); |
2261 | if (status == 0) | 2262 | if (status == 0) |
2262 | status = nfs4_server_capabilities(server, fhandle); | 2263 | status = nfs4_server_capabilities(server, fhandle); |
2263 | if (status == 0) | 2264 | if (status == 0) |
@@ -5935,6 +5936,85 @@ out: | |||
5935 | rpc_put_task(task); | 5936 | rpc_put_task(task); |
5936 | return status; | 5937 | return status; |
5937 | } | 5938 | } |
5939 | |||
5940 | static int | ||
5941 | _nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle, | ||
5942 | struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors) | ||
5943 | { | ||
5944 | struct nfs41_secinfo_no_name_args args = { | ||
5945 | .style = SECINFO_STYLE_CURRENT_FH, | ||
5946 | }; | ||
5947 | struct nfs4_secinfo_res res = { | ||
5948 | .flavors = flavors, | ||
5949 | }; | ||
5950 | struct rpc_message msg = { | ||
5951 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SECINFO_NO_NAME], | ||
5952 | .rpc_argp = &args, | ||
5953 | .rpc_resp = &res, | ||
5954 | }; | ||
5955 | return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); | ||
5956 | } | ||
5957 | |||
5958 | static int | ||
5959 | nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle, | ||
5960 | struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors) | ||
5961 | { | ||
5962 | struct nfs4_exception exception = { }; | ||
5963 | int err; | ||
5964 | do { | ||
5965 | err = _nfs41_proc_secinfo_no_name(server, fhandle, info, flavors); | ||
5966 | switch (err) { | ||
5967 | case 0: | ||
5968 | case -NFS4ERR_WRONGSEC: | ||
5969 | case -NFS4ERR_NOTSUPP: | ||
5970 | break; | ||
5971 | default: | ||
5972 | err = nfs4_handle_exception(server, err, &exception); | ||
5973 | } | ||
5974 | } while (exception.retry); | ||
5975 | return err; | ||
5976 | } | ||
5977 | |||
5978 | static int | ||
5979 | nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, | ||
5980 | struct nfs_fsinfo *info) | ||
5981 | { | ||
5982 | int err; | ||
5983 | struct page *page; | ||
5984 | rpc_authflavor_t flavor; | ||
5985 | struct nfs4_secinfo_flavors *flavors; | ||
5986 | |||
5987 | page = alloc_page(GFP_KERNEL); | ||
5988 | if (!page) { | ||
5989 | err = -ENOMEM; | ||
5990 | goto out; | ||
5991 | } | ||
5992 | |||
5993 | flavors = page_address(page); | ||
5994 | err = nfs41_proc_secinfo_no_name(server, fhandle, info, flavors); | ||
5995 | |||
5996 | /* | ||
5997 | * Fall back on "guess and check" method if | ||
5998 | * the server doesn't support SECINFO_NO_NAME | ||
5999 | */ | ||
6000 | if (err == -NFS4ERR_WRONGSEC || err == -NFS4ERR_NOTSUPP) { | ||
6001 | err = nfs4_find_root_sec(server, fhandle, info); | ||
6002 | goto out_freepage; | ||
6003 | } | ||
6004 | if (err) | ||
6005 | goto out_freepage; | ||
6006 | |||
6007 | flavor = nfs_find_best_sec(flavors); | ||
6008 | if (err == 0) | ||
6009 | err = nfs4_lookup_root_sec(server, fhandle, info, flavor); | ||
6010 | |||
6011 | out_freepage: | ||
6012 | put_page(page); | ||
6013 | if (err == -EACCES) | ||
6014 | return -EPERM; | ||
6015 | out: | ||
6016 | return err; | ||
6017 | } | ||
5938 | #endif /* CONFIG_NFS_V4_1 */ | 6018 | #endif /* CONFIG_NFS_V4_1 */ |
5939 | 6019 | ||
5940 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { | 6020 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { |
@@ -5996,6 +6076,7 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = { | |||
5996 | .minor_version = 0, | 6076 | .minor_version = 0, |
5997 | .call_sync = _nfs4_call_sync, | 6077 | .call_sync = _nfs4_call_sync, |
5998 | .validate_stateid = nfs4_validate_delegation_stateid, | 6078 | .validate_stateid = nfs4_validate_delegation_stateid, |
6079 | .find_root_sec = nfs4_find_root_sec, | ||
5999 | .reboot_recovery_ops = &nfs40_reboot_recovery_ops, | 6080 | .reboot_recovery_ops = &nfs40_reboot_recovery_ops, |
6000 | .nograce_recovery_ops = &nfs40_nograce_recovery_ops, | 6081 | .nograce_recovery_ops = &nfs40_nograce_recovery_ops, |
6001 | .state_renewal_ops = &nfs40_state_renewal_ops, | 6082 | .state_renewal_ops = &nfs40_state_renewal_ops, |
@@ -6006,6 +6087,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { | |||
6006 | .minor_version = 1, | 6087 | .minor_version = 1, |
6007 | .call_sync = _nfs4_call_sync_session, | 6088 | .call_sync = _nfs4_call_sync_session, |
6008 | .validate_stateid = nfs41_validate_delegation_stateid, | 6089 | .validate_stateid = nfs41_validate_delegation_stateid, |
6090 | .find_root_sec = nfs41_find_root_sec, | ||
6009 | .reboot_recovery_ops = &nfs41_reboot_recovery_ops, | 6091 | .reboot_recovery_ops = &nfs41_reboot_recovery_ops, |
6010 | .nograce_recovery_ops = &nfs41_nograce_recovery_ops, | 6092 | .nograce_recovery_ops = &nfs41_nograce_recovery_ops, |
6011 | .state_renewal_ops = &nfs41_state_renewal_ops, | 6093 | .state_renewal_ops = &nfs41_state_renewal_ops, |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 1555c74dd336..c8c069a6319b 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -343,6 +343,8 @@ static int nfs4_stat_to_errno(int); | |||
343 | 1 /* FIXME: opaque lrf_body always empty at the moment */) | 343 | 1 /* FIXME: opaque lrf_body always empty at the moment */) |
344 | #define decode_layoutreturn_maxsz (op_decode_hdr_maxsz + \ | 344 | #define decode_layoutreturn_maxsz (op_decode_hdr_maxsz + \ |
345 | 1 + decode_stateid_maxsz) | 345 | 1 + decode_stateid_maxsz) |
346 | #define encode_secinfo_no_name_maxsz (op_encode_hdr_maxsz + 1) | ||
347 | #define decode_secinfo_no_name_maxsz decode_secinfo_maxsz | ||
346 | #else /* CONFIG_NFS_V4_1 */ | 348 | #else /* CONFIG_NFS_V4_1 */ |
347 | #define encode_sequence_maxsz 0 | 349 | #define encode_sequence_maxsz 0 |
348 | #define decode_sequence_maxsz 0 | 350 | #define decode_sequence_maxsz 0 |
@@ -772,6 +774,14 @@ static int nfs4_stat_to_errno(int); | |||
772 | decode_sequence_maxsz + \ | 774 | decode_sequence_maxsz + \ |
773 | decode_putfh_maxsz + \ | 775 | decode_putfh_maxsz + \ |
774 | decode_layoutreturn_maxsz) | 776 | decode_layoutreturn_maxsz) |
777 | #define NFS4_enc_secinfo_no_name_sz (compound_encode_hdr_maxsz + \ | ||
778 | encode_sequence_maxsz + \ | ||
779 | encode_putrootfh_maxsz +\ | ||
780 | encode_secinfo_no_name_maxsz) | ||
781 | #define NFS4_dec_secinfo_no_name_sz (compound_decode_hdr_maxsz + \ | ||
782 | decode_sequence_maxsz + \ | ||
783 | decode_putrootfh_maxsz + \ | ||
784 | decode_secinfo_no_name_maxsz) | ||
775 | 785 | ||
776 | const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH + | 786 | const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH + |
777 | compound_encode_hdr_maxsz + | 787 | compound_encode_hdr_maxsz + |
@@ -1938,6 +1948,20 @@ encode_layoutreturn(struct xdr_stream *xdr, | |||
1938 | hdr->nops++; | 1948 | hdr->nops++; |
1939 | hdr->replen += decode_layoutreturn_maxsz; | 1949 | hdr->replen += decode_layoutreturn_maxsz; |
1940 | } | 1950 | } |
1951 | |||
1952 | static int | ||
1953 | encode_secinfo_no_name(struct xdr_stream *xdr, | ||
1954 | const struct nfs41_secinfo_no_name_args *args, | ||
1955 | struct compound_hdr *hdr) | ||
1956 | { | ||
1957 | __be32 *p; | ||
1958 | p = reserve_space(xdr, 8); | ||
1959 | *p++ = cpu_to_be32(OP_SECINFO_NO_NAME); | ||
1960 | *p++ = cpu_to_be32(args->style); | ||
1961 | hdr->nops++; | ||
1962 | hdr->replen += decode_secinfo_no_name_maxsz; | ||
1963 | return 0; | ||
1964 | } | ||
1941 | #endif /* CONFIG_NFS_V4_1 */ | 1965 | #endif /* CONFIG_NFS_V4_1 */ |
1942 | 1966 | ||
1943 | /* | 1967 | /* |
@@ -2790,6 +2814,25 @@ static void nfs4_xdr_enc_layoutreturn(struct rpc_rqst *req, | |||
2790 | encode_layoutreturn(xdr, args, &hdr); | 2814 | encode_layoutreturn(xdr, args, &hdr); |
2791 | encode_nops(&hdr); | 2815 | encode_nops(&hdr); |
2792 | } | 2816 | } |
2817 | |||
2818 | /* | ||
2819 | * Encode SECINFO_NO_NAME request | ||
2820 | */ | ||
2821 | static int nfs4_xdr_enc_secinfo_no_name(struct rpc_rqst *req, | ||
2822 | struct xdr_stream *xdr, | ||
2823 | struct nfs41_secinfo_no_name_args *args) | ||
2824 | { | ||
2825 | struct compound_hdr hdr = { | ||
2826 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), | ||
2827 | }; | ||
2828 | |||
2829 | encode_compound_hdr(xdr, req, &hdr); | ||
2830 | encode_sequence(xdr, &args->seq_args, &hdr); | ||
2831 | encode_putrootfh(xdr, &hdr); | ||
2832 | encode_secinfo_no_name(xdr, args, &hdr); | ||
2833 | encode_nops(&hdr); | ||
2834 | return 0; | ||
2835 | } | ||
2793 | #endif /* CONFIG_NFS_V4_1 */ | 2836 | #endif /* CONFIG_NFS_V4_1 */ |
2794 | 2837 | ||
2795 | static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) | 2838 | static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) |
@@ -6467,6 +6510,30 @@ static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp, | |||
6467 | out: | 6510 | out: |
6468 | return status; | 6511 | return status; |
6469 | } | 6512 | } |
6513 | |||
6514 | /* | ||
6515 | * Decode SECINFO_NO_NAME response | ||
6516 | */ | ||
6517 | static int nfs4_xdr_dec_secinfo_no_name(struct rpc_rqst *rqstp, | ||
6518 | struct xdr_stream *xdr, | ||
6519 | struct nfs4_secinfo_res *res) | ||
6520 | { | ||
6521 | struct compound_hdr hdr; | ||
6522 | int status; | ||
6523 | |||
6524 | status = decode_compound_hdr(xdr, &hdr); | ||
6525 | if (status) | ||
6526 | goto out; | ||
6527 | status = decode_sequence(xdr, &res->seq_res, rqstp); | ||
6528 | if (status) | ||
6529 | goto out; | ||
6530 | status = decode_putrootfh(xdr); | ||
6531 | if (status) | ||
6532 | goto out; | ||
6533 | status = decode_secinfo(xdr, res); | ||
6534 | out: | ||
6535 | return status; | ||
6536 | } | ||
6470 | #endif /* CONFIG_NFS_V4_1 */ | 6537 | #endif /* CONFIG_NFS_V4_1 */ |
6471 | 6538 | ||
6472 | /** | 6539 | /** |
@@ -6669,6 +6736,7 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
6669 | PROC(LAYOUTGET, enc_layoutget, dec_layoutget), | 6736 | PROC(LAYOUTGET, enc_layoutget, dec_layoutget), |
6670 | PROC(LAYOUTCOMMIT, enc_layoutcommit, dec_layoutcommit), | 6737 | PROC(LAYOUTCOMMIT, enc_layoutcommit, dec_layoutcommit), |
6671 | PROC(LAYOUTRETURN, enc_layoutreturn, dec_layoutreturn), | 6738 | PROC(LAYOUTRETURN, enc_layoutreturn, dec_layoutreturn), |
6739 | PROC(SECINFO_NO_NAME, enc_secinfo_no_name, dec_secinfo_no_name), | ||
6672 | #endif /* CONFIG_NFS_V4_1 */ | 6740 | #endif /* CONFIG_NFS_V4_1 */ |
6673 | }; | 6741 | }; |
6674 | 6742 | ||