diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-30 14:28:08 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-30 14:28:08 -0400 |
commit | 8728f986fe29d872dc5dc72941088eb9cb8bc723 (patch) | |
tree | b0742c9c396bc8e4fddfbe1da57777270a803970 /net/sunrpc | |
parent | e72859b87f57826f41e07a87bbaed65ed1133f85 (diff) | |
parent | 721ccfb79b6f74f4052de70236d24047e73682d4 (diff) |
Merge tag 'nfs-for-3.10-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client bugfixes and cleanups from Trond Myklebust:
- NLM: stable fix for NFSv2/v3 blocking locks
- NFSv4.x: stable fixes for the delegation recall error handling code
- NFSv4.x: Security flavour negotiation fixes and cleanups by Chuck
Lever
- SUNRPC: A number of RPCSEC_GSS fixes and cleanups also from Chuck
- NFSv4.x assorted state management and reboot recovery bugfixes
- NFSv4.1: In cases where we have already looked up a file, and hold a
valid filehandle, use the new open-by-filehandle operation instead of
opening by name.
- Allow the NFSv4.1 callback thread to freeze
- NFSv4.x: ensure that file unlock waits for readahead to complete
- NFSv4.1: ensure that the RPC layer doesn't override the NFS session
table size negotiation by limiting the number of slots.
- NFSv4.x: Fix SETATTR spec compatibility issues
* tag 'nfs-for-3.10-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (67 commits)
NFSv4: Warn once about servers that incorrectly apply open mode to setattr
NFSv4: Servers should only check SETATTR stateid open mode on size change
NFSv4: Don't recheck permissions on open in case of recovery cached open
NFSv4.1: Don't do a delegated open for NFS4_OPEN_CLAIM_DELEG_CUR_FH modes
NFSv4.1: Use the more efficient open_noattr call for open-by-filehandle
NFS: Retry SETCLIENTID with AUTH_SYS instead of AUTH_NONE
NFSv4: Ensure that we clear the NFS_OPEN_STATE flag when appropriate
LOCKD: Ensure that nlmclnt_block resets block->b_status after a server reboot
NFSv4: Ensure the LOCK call cannot use the delegation stateid
NFSv4: Use the open stateid if the delegation has the wrong mode
nfs: Send atime and mtime as a 64bit value
NFSv4: Record the OPEN create mode used in the nfs4_opendata structure
NFSv4.1: Set the RPC_CLNT_CREATE_INFINITE_SLOTS flag for NFSv4.1 transports
SUNRPC: Allow rpc_create() to request that TCP slots be unlimited
SUNRPC: Fix a livelock problem in the xprt->backlog queue
NFSv4: Fix handling of revoked delegations by setattr
NFSv4 release the sequence id in the return on close case
nfs: remove unnecessary check for NULL inode->i_flock from nfs_delegation_claim_locks
NFS: Ensure that NFS file unlock waits for readahead to complete
NFS: Add functionality to allow waiting on all outstanding reads to complete
...
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/Kconfig | 2 | ||||
-rw-r--r-- | net/sunrpc/auth.c | 75 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 3 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_krb5_mech.c | 6 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/gss_mech_switch.c | 119 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/svcauth_gss.c | 4 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 43 | ||||
-rw-r--r-- | net/sunrpc/xprt.c | 61 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 14 |
9 files changed, 275 insertions, 52 deletions
diff --git a/net/sunrpc/Kconfig b/net/sunrpc/Kconfig index 516fe2caac2c..241b54f30204 100644 --- a/net/sunrpc/Kconfig +++ b/net/sunrpc/Kconfig | |||
@@ -3,6 +3,7 @@ config SUNRPC | |||
3 | 3 | ||
4 | config SUNRPC_GSS | 4 | config SUNRPC_GSS |
5 | tristate | 5 | tristate |
6 | select OID_REGISTRY | ||
6 | 7 | ||
7 | config SUNRPC_BACKCHANNEL | 8 | config SUNRPC_BACKCHANNEL |
8 | bool | 9 | bool |
@@ -24,7 +25,6 @@ config SUNRPC_XPRT_RDMA | |||
24 | config SUNRPC_SWAP | 25 | config SUNRPC_SWAP |
25 | bool | 26 | bool |
26 | depends on SUNRPC | 27 | depends on SUNRPC |
27 | select NETVM | ||
28 | 28 | ||
29 | config RPCSEC_GSS_KRB5 | 29 | config RPCSEC_GSS_KRB5 |
30 | tristate "Secure RPC: Kerberos V mechanism" | 30 | tristate "Secure RPC: Kerberos V mechanism" |
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index f5294047df77..ed2fdd210c0b 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
@@ -82,7 +82,7 @@ MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size"); | |||
82 | 82 | ||
83 | static u32 | 83 | static u32 |
84 | pseudoflavor_to_flavor(u32 flavor) { | 84 | pseudoflavor_to_flavor(u32 flavor) { |
85 | if (flavor >= RPC_AUTH_MAXFLAVOR) | 85 | if (flavor > RPC_AUTH_MAXFLAVOR) |
86 | return RPC_AUTH_GSS; | 86 | return RPC_AUTH_GSS; |
87 | return flavor; | 87 | return flavor; |
88 | } | 88 | } |
@@ -124,6 +124,79 @@ rpcauth_unregister(const struct rpc_authops *ops) | |||
124 | EXPORT_SYMBOL_GPL(rpcauth_unregister); | 124 | EXPORT_SYMBOL_GPL(rpcauth_unregister); |
125 | 125 | ||
126 | /** | 126 | /** |
127 | * rpcauth_get_pseudoflavor - check if security flavor is supported | ||
128 | * @flavor: a security flavor | ||
129 | * @info: a GSS mech OID, quality of protection, and service value | ||
130 | * | ||
131 | * Verifies that an appropriate kernel module is available or already loaded. | ||
132 | * Returns an equivalent pseudoflavor, or RPC_AUTH_MAXFLAVOR if "flavor" is | ||
133 | * not supported locally. | ||
134 | */ | ||
135 | rpc_authflavor_t | ||
136 | rpcauth_get_pseudoflavor(rpc_authflavor_t flavor, struct rpcsec_gss_info *info) | ||
137 | { | ||
138 | const struct rpc_authops *ops; | ||
139 | rpc_authflavor_t pseudoflavor; | ||
140 | |||
141 | ops = auth_flavors[flavor]; | ||
142 | if (ops == NULL) | ||
143 | request_module("rpc-auth-%u", flavor); | ||
144 | spin_lock(&rpc_authflavor_lock); | ||
145 | ops = auth_flavors[flavor]; | ||
146 | if (ops == NULL || !try_module_get(ops->owner)) { | ||
147 | spin_unlock(&rpc_authflavor_lock); | ||
148 | return RPC_AUTH_MAXFLAVOR; | ||
149 | } | ||
150 | spin_unlock(&rpc_authflavor_lock); | ||
151 | |||
152 | pseudoflavor = flavor; | ||
153 | if (ops->info2flavor != NULL) | ||
154 | pseudoflavor = ops->info2flavor(info); | ||
155 | |||
156 | module_put(ops->owner); | ||
157 | return pseudoflavor; | ||
158 | } | ||
159 | EXPORT_SYMBOL_GPL(rpcauth_get_pseudoflavor); | ||
160 | |||
161 | /** | ||
162 | * rpcauth_get_gssinfo - find GSS tuple matching a GSS pseudoflavor | ||
163 | * @pseudoflavor: GSS pseudoflavor to match | ||
164 | * @info: rpcsec_gss_info structure to fill in | ||
165 | * | ||
166 | * Returns zero and fills in "info" if pseudoflavor matches a | ||
167 | * supported mechanism. | ||
168 | */ | ||
169 | int | ||
170 | rpcauth_get_gssinfo(rpc_authflavor_t pseudoflavor, struct rpcsec_gss_info *info) | ||
171 | { | ||
172 | rpc_authflavor_t flavor = pseudoflavor_to_flavor(pseudoflavor); | ||
173 | const struct rpc_authops *ops; | ||
174 | int result; | ||
175 | |||
176 | if (flavor >= RPC_AUTH_MAXFLAVOR) | ||
177 | return -EINVAL; | ||
178 | |||
179 | ops = auth_flavors[flavor]; | ||
180 | if (ops == NULL) | ||
181 | request_module("rpc-auth-%u", flavor); | ||
182 | spin_lock(&rpc_authflavor_lock); | ||
183 | ops = auth_flavors[flavor]; | ||
184 | if (ops == NULL || !try_module_get(ops->owner)) { | ||
185 | spin_unlock(&rpc_authflavor_lock); | ||
186 | return -ENOENT; | ||
187 | } | ||
188 | spin_unlock(&rpc_authflavor_lock); | ||
189 | |||
190 | result = -ENOENT; | ||
191 | if (ops->flavor2info != NULL) | ||
192 | result = ops->flavor2info(pseudoflavor, info); | ||
193 | |||
194 | module_put(ops->owner); | ||
195 | return result; | ||
196 | } | ||
197 | EXPORT_SYMBOL_GPL(rpcauth_get_gssinfo); | ||
198 | |||
199 | /** | ||
127 | * rpcauth_list_flavors - discover registered flavors and pseudoflavors | 200 | * rpcauth_list_flavors - discover registered flavors and pseudoflavors |
128 | * @array: array to fill in | 201 | * @array: array to fill in |
129 | * @size: size of "array" | 202 | * @size: size of "array" |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 5257d2982ba5..51415b07174e 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -1641,6 +1641,8 @@ static const struct rpc_authops authgss_ops = { | |||
1641 | .pipes_create = gss_pipes_dentries_create, | 1641 | .pipes_create = gss_pipes_dentries_create, |
1642 | .pipes_destroy = gss_pipes_dentries_destroy, | 1642 | .pipes_destroy = gss_pipes_dentries_destroy, |
1643 | .list_pseudoflavors = gss_mech_list_pseudoflavors, | 1643 | .list_pseudoflavors = gss_mech_list_pseudoflavors, |
1644 | .info2flavor = gss_mech_info2flavor, | ||
1645 | .flavor2info = gss_mech_flavor2info, | ||
1644 | }; | 1646 | }; |
1645 | 1647 | ||
1646 | static const struct rpc_credops gss_credops = { | 1648 | static const struct rpc_credops gss_credops = { |
@@ -1733,6 +1735,7 @@ static void __exit exit_rpcsec_gss(void) | |||
1733 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ | 1735 | rcu_barrier(); /* Wait for completion of call_rcu()'s */ |
1734 | } | 1736 | } |
1735 | 1737 | ||
1738 | MODULE_ALIAS("rpc-auth-6"); | ||
1736 | MODULE_LICENSE("GPL"); | 1739 | MODULE_LICENSE("GPL"); |
1737 | module_param_named(expired_cred_retry_delay, | 1740 | module_param_named(expired_cred_retry_delay, |
1738 | gss_expired_cred_retry_delay, | 1741 | gss_expired_cred_retry_delay, |
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c index d3611f11a8df..33255ff889c0 100644 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c | |||
@@ -729,16 +729,19 @@ static const struct gss_api_ops gss_kerberos_ops = { | |||
729 | static struct pf_desc gss_kerberos_pfs[] = { | 729 | static struct pf_desc gss_kerberos_pfs[] = { |
730 | [0] = { | 730 | [0] = { |
731 | .pseudoflavor = RPC_AUTH_GSS_KRB5, | 731 | .pseudoflavor = RPC_AUTH_GSS_KRB5, |
732 | .qop = GSS_C_QOP_DEFAULT, | ||
732 | .service = RPC_GSS_SVC_NONE, | 733 | .service = RPC_GSS_SVC_NONE, |
733 | .name = "krb5", | 734 | .name = "krb5", |
734 | }, | 735 | }, |
735 | [1] = { | 736 | [1] = { |
736 | .pseudoflavor = RPC_AUTH_GSS_KRB5I, | 737 | .pseudoflavor = RPC_AUTH_GSS_KRB5I, |
738 | .qop = GSS_C_QOP_DEFAULT, | ||
737 | .service = RPC_GSS_SVC_INTEGRITY, | 739 | .service = RPC_GSS_SVC_INTEGRITY, |
738 | .name = "krb5i", | 740 | .name = "krb5i", |
739 | }, | 741 | }, |
740 | [2] = { | 742 | [2] = { |
741 | .pseudoflavor = RPC_AUTH_GSS_KRB5P, | 743 | .pseudoflavor = RPC_AUTH_GSS_KRB5P, |
744 | .qop = GSS_C_QOP_DEFAULT, | ||
742 | .service = RPC_GSS_SVC_PRIVACY, | 745 | .service = RPC_GSS_SVC_PRIVACY, |
743 | .name = "krb5p", | 746 | .name = "krb5p", |
744 | }, | 747 | }, |
@@ -750,11 +753,12 @@ MODULE_ALIAS("rpc-auth-gss-krb5p"); | |||
750 | MODULE_ALIAS("rpc-auth-gss-390003"); | 753 | MODULE_ALIAS("rpc-auth-gss-390003"); |
751 | MODULE_ALIAS("rpc-auth-gss-390004"); | 754 | MODULE_ALIAS("rpc-auth-gss-390004"); |
752 | MODULE_ALIAS("rpc-auth-gss-390005"); | 755 | MODULE_ALIAS("rpc-auth-gss-390005"); |
756 | MODULE_ALIAS("rpc-auth-gss-1.2.840.113554.1.2.2"); | ||
753 | 757 | ||
754 | static struct gss_api_mech gss_kerberos_mech = { | 758 | static struct gss_api_mech gss_kerberos_mech = { |
755 | .gm_name = "krb5", | 759 | .gm_name = "krb5", |
756 | .gm_owner = THIS_MODULE, | 760 | .gm_owner = THIS_MODULE, |
757 | .gm_oid = {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"}, | 761 | .gm_oid = { 9, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }, |
758 | .gm_ops = &gss_kerberos_ops, | 762 | .gm_ops = &gss_kerberos_ops, |
759 | .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs), | 763 | .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs), |
760 | .gm_pfs = gss_kerberos_pfs, | 764 | .gm_pfs = gss_kerberos_pfs, |
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c index f0f4eee63a35..79881d6e68a1 100644 --- a/net/sunrpc/auth_gss/gss_mech_switch.c +++ b/net/sunrpc/auth_gss/gss_mech_switch.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/types.h> | 36 | #include <linux/types.h> |
37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
38 | #include <linux/module.h> | 38 | #include <linux/module.h> |
39 | #include <linux/oid_registry.h> | ||
39 | #include <linux/sunrpc/msg_prot.h> | 40 | #include <linux/sunrpc/msg_prot.h> |
40 | #include <linux/sunrpc/gss_asn1.h> | 41 | #include <linux/sunrpc/gss_asn1.h> |
41 | #include <linux/sunrpc/auth_gss.h> | 42 | #include <linux/sunrpc/auth_gss.h> |
@@ -102,8 +103,13 @@ out: | |||
102 | return status; | 103 | return status; |
103 | } | 104 | } |
104 | 105 | ||
105 | int | 106 | /** |
106 | gss_mech_register(struct gss_api_mech *gm) | 107 | * gss_mech_register - register a GSS mechanism |
108 | * @gm: GSS mechanism handle | ||
109 | * | ||
110 | * Returns zero if successful, or a negative errno. | ||
111 | */ | ||
112 | int gss_mech_register(struct gss_api_mech *gm) | ||
107 | { | 113 | { |
108 | int status; | 114 | int status; |
109 | 115 | ||
@@ -116,11 +122,14 @@ gss_mech_register(struct gss_api_mech *gm) | |||
116 | dprintk("RPC: registered gss mechanism %s\n", gm->gm_name); | 122 | dprintk("RPC: registered gss mechanism %s\n", gm->gm_name); |
117 | return 0; | 123 | return 0; |
118 | } | 124 | } |
119 | |||
120 | EXPORT_SYMBOL_GPL(gss_mech_register); | 125 | EXPORT_SYMBOL_GPL(gss_mech_register); |
121 | 126 | ||
122 | void | 127 | /** |
123 | gss_mech_unregister(struct gss_api_mech *gm) | 128 | * gss_mech_unregister - release a GSS mechanism |
129 | * @gm: GSS mechanism handle | ||
130 | * | ||
131 | */ | ||
132 | void gss_mech_unregister(struct gss_api_mech *gm) | ||
124 | { | 133 | { |
125 | spin_lock(®istered_mechs_lock); | 134 | spin_lock(®istered_mechs_lock); |
126 | list_del(&gm->gm_list); | 135 | list_del(&gm->gm_list); |
@@ -128,18 +137,14 @@ gss_mech_unregister(struct gss_api_mech *gm) | |||
128 | dprintk("RPC: unregistered gss mechanism %s\n", gm->gm_name); | 137 | dprintk("RPC: unregistered gss mechanism %s\n", gm->gm_name); |
129 | gss_mech_free(gm); | 138 | gss_mech_free(gm); |
130 | } | 139 | } |
131 | |||
132 | EXPORT_SYMBOL_GPL(gss_mech_unregister); | 140 | EXPORT_SYMBOL_GPL(gss_mech_unregister); |
133 | 141 | ||
134 | struct gss_api_mech * | 142 | static struct gss_api_mech *gss_mech_get(struct gss_api_mech *gm) |
135 | gss_mech_get(struct gss_api_mech *gm) | ||
136 | { | 143 | { |
137 | __module_get(gm->gm_owner); | 144 | __module_get(gm->gm_owner); |
138 | return gm; | 145 | return gm; |
139 | } | 146 | } |
140 | 147 | ||
141 | EXPORT_SYMBOL_GPL(gss_mech_get); | ||
142 | |||
143 | static struct gss_api_mech * | 148 | static struct gss_api_mech * |
144 | _gss_mech_get_by_name(const char *name) | 149 | _gss_mech_get_by_name(const char *name) |
145 | { | 150 | { |
@@ -169,12 +174,16 @@ struct gss_api_mech * gss_mech_get_by_name(const char *name) | |||
169 | } | 174 | } |
170 | return gm; | 175 | return gm; |
171 | } | 176 | } |
172 | EXPORT_SYMBOL_GPL(gss_mech_get_by_name); | ||
173 | 177 | ||
174 | struct gss_api_mech * | 178 | static struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj) |
175 | gss_mech_get_by_OID(struct xdr_netobj *obj) | ||
176 | { | 179 | { |
177 | struct gss_api_mech *pos, *gm = NULL; | 180 | struct gss_api_mech *pos, *gm = NULL; |
181 | char buf[32]; | ||
182 | |||
183 | if (sprint_oid(obj->data, obj->len, buf, sizeof(buf)) < 0) | ||
184 | return NULL; | ||
185 | dprintk("RPC: %s(%s)\n", __func__, buf); | ||
186 | request_module("rpc-auth-gss-%s", buf); | ||
178 | 187 | ||
179 | spin_lock(®istered_mechs_lock); | 188 | spin_lock(®istered_mechs_lock); |
180 | list_for_each_entry(pos, ®istered_mechs, gm_list) { | 189 | list_for_each_entry(pos, ®istered_mechs, gm_list) { |
@@ -188,11 +197,8 @@ gss_mech_get_by_OID(struct xdr_netobj *obj) | |||
188 | } | 197 | } |
189 | spin_unlock(®istered_mechs_lock); | 198 | spin_unlock(®istered_mechs_lock); |
190 | return gm; | 199 | return gm; |
191 | |||
192 | } | 200 | } |
193 | 201 | ||
194 | EXPORT_SYMBOL_GPL(gss_mech_get_by_OID); | ||
195 | |||
196 | static inline int | 202 | static inline int |
197 | mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor) | 203 | mech_supports_pseudoflavor(struct gss_api_mech *gm, u32 pseudoflavor) |
198 | { | 204 | { |
@@ -237,8 +243,6 @@ gss_mech_get_by_pseudoflavor(u32 pseudoflavor) | |||
237 | return gm; | 243 | return gm; |
238 | } | 244 | } |
239 | 245 | ||
240 | EXPORT_SYMBOL_GPL(gss_mech_get_by_pseudoflavor); | ||
241 | |||
242 | /** | 246 | /** |
243 | * gss_mech_list_pseudoflavors - Discover registered GSS pseudoflavors | 247 | * gss_mech_list_pseudoflavors - Discover registered GSS pseudoflavors |
244 | * @array: array to fill in | 248 | * @array: array to fill in |
@@ -268,19 +272,82 @@ int gss_mech_list_pseudoflavors(rpc_authflavor_t *array_ptr, int size) | |||
268 | return i; | 272 | return i; |
269 | } | 273 | } |
270 | 274 | ||
271 | u32 | 275 | /** |
272 | gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service) | 276 | * gss_svc_to_pseudoflavor - map a GSS service number to a pseudoflavor |
277 | * @gm: GSS mechanism handle | ||
278 | * @qop: GSS quality-of-protection value | ||
279 | * @service: GSS service value | ||
280 | * | ||
281 | * Returns a matching security flavor, or RPC_AUTH_MAXFLAVOR if none is found. | ||
282 | */ | ||
283 | rpc_authflavor_t gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 qop, | ||
284 | u32 service) | ||
273 | { | 285 | { |
274 | int i; | 286 | int i; |
275 | 287 | ||
276 | for (i = 0; i < gm->gm_pf_num; i++) { | 288 | for (i = 0; i < gm->gm_pf_num; i++) { |
277 | if (gm->gm_pfs[i].service == service) { | 289 | if (gm->gm_pfs[i].qop == qop && |
290 | gm->gm_pfs[i].service == service) { | ||
278 | return gm->gm_pfs[i].pseudoflavor; | 291 | return gm->gm_pfs[i].pseudoflavor; |
279 | } | 292 | } |
280 | } | 293 | } |
281 | return RPC_AUTH_MAXFLAVOR; /* illegal value */ | 294 | return RPC_AUTH_MAXFLAVOR; |
295 | } | ||
296 | |||
297 | /** | ||
298 | * gss_mech_info2flavor - look up a pseudoflavor given a GSS tuple | ||
299 | * @info: a GSS mech OID, quality of protection, and service value | ||
300 | * | ||
301 | * Returns a matching pseudoflavor, or RPC_AUTH_MAXFLAVOR if the tuple is | ||
302 | * not supported. | ||
303 | */ | ||
304 | rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *info) | ||
305 | { | ||
306 | rpc_authflavor_t pseudoflavor; | ||
307 | struct gss_api_mech *gm; | ||
308 | |||
309 | gm = gss_mech_get_by_OID(&info->oid); | ||
310 | if (gm == NULL) | ||
311 | return RPC_AUTH_MAXFLAVOR; | ||
312 | |||
313 | pseudoflavor = gss_svc_to_pseudoflavor(gm, info->qop, info->service); | ||
314 | |||
315 | gss_mech_put(gm); | ||
316 | return pseudoflavor; | ||
317 | } | ||
318 | |||
319 | /** | ||
320 | * gss_mech_flavor2info - look up a GSS tuple for a given pseudoflavor | ||
321 | * @pseudoflavor: GSS pseudoflavor to match | ||
322 | * @info: rpcsec_gss_info structure to fill in | ||
323 | * | ||
324 | * Returns zero and fills in "info" if pseudoflavor matches a | ||
325 | * supported mechanism. Otherwise a negative errno is returned. | ||
326 | */ | ||
327 | int gss_mech_flavor2info(rpc_authflavor_t pseudoflavor, | ||
328 | struct rpcsec_gss_info *info) | ||
329 | { | ||
330 | struct gss_api_mech *gm; | ||
331 | int i; | ||
332 | |||
333 | gm = gss_mech_get_by_pseudoflavor(pseudoflavor); | ||
334 | if (gm == NULL) | ||
335 | return -ENOENT; | ||
336 | |||
337 | for (i = 0; i < gm->gm_pf_num; i++) { | ||
338 | if (gm->gm_pfs[i].pseudoflavor == pseudoflavor) { | ||
339 | memcpy(info->oid.data, gm->gm_oid.data, gm->gm_oid.len); | ||
340 | info->oid.len = gm->gm_oid.len; | ||
341 | info->qop = gm->gm_pfs[i].qop; | ||
342 | info->service = gm->gm_pfs[i].service; | ||
343 | gss_mech_put(gm); | ||
344 | return 0; | ||
345 | } | ||
346 | } | ||
347 | |||
348 | gss_mech_put(gm); | ||
349 | return -ENOENT; | ||
282 | } | 350 | } |
283 | EXPORT_SYMBOL_GPL(gss_svc_to_pseudoflavor); | ||
284 | 351 | ||
285 | u32 | 352 | u32 |
286 | gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor) | 353 | gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor) |
@@ -294,8 +361,6 @@ gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor) | |||
294 | return 0; | 361 | return 0; |
295 | } | 362 | } |
296 | 363 | ||
297 | EXPORT_SYMBOL_GPL(gss_pseudoflavor_to_service); | ||
298 | |||
299 | char * | 364 | char * |
300 | gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service) | 365 | gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service) |
301 | { | 366 | { |
@@ -308,8 +373,6 @@ gss_service_to_auth_domain_name(struct gss_api_mech *gm, u32 service) | |||
308 | return NULL; | 373 | return NULL; |
309 | } | 374 | } |
310 | 375 | ||
311 | EXPORT_SYMBOL_GPL(gss_service_to_auth_domain_name); | ||
312 | |||
313 | void | 376 | void |
314 | gss_mech_put(struct gss_api_mech * gm) | 377 | gss_mech_put(struct gss_api_mech * gm) |
315 | { | 378 | { |
@@ -317,8 +380,6 @@ gss_mech_put(struct gss_api_mech * gm) | |||
317 | module_put(gm->gm_owner); | 380 | module_put(gm->gm_owner); |
318 | } | 381 | } |
319 | 382 | ||
320 | EXPORT_SYMBOL_GPL(gss_mech_put); | ||
321 | |||
322 | /* The mech could probably be determined from the token instead, but it's just | 383 | /* The mech could probably be determined from the token instead, but it's just |
323 | * as easy for now to pass it in. */ | 384 | * as easy for now to pass it in. */ |
324 | int | 385 | int |
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 5ead60550895..c3ba570222dc 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c | |||
@@ -1220,7 +1220,9 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
1220 | svcdata->rsci = rsci; | 1220 | svcdata->rsci = rsci; |
1221 | cache_get(&rsci->h); | 1221 | cache_get(&rsci->h); |
1222 | rqstp->rq_cred.cr_flavor = gss_svc_to_pseudoflavor( | 1222 | rqstp->rq_cred.cr_flavor = gss_svc_to_pseudoflavor( |
1223 | rsci->mechctx->mech_type, gc->gc_svc); | 1223 | rsci->mechctx->mech_type, |
1224 | GSS_C_QOP_DEFAULT, | ||
1225 | gc->gc_svc); | ||
1224 | ret = SVC_OK; | 1226 | ret = SVC_OK; |
1225 | goto out; | 1227 | goto out; |
1226 | } | 1228 | } |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index d5f35f15af98..d259fa966927 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -411,6 +411,8 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) | |||
411 | }; | 411 | }; |
412 | char servername[48]; | 412 | char servername[48]; |
413 | 413 | ||
414 | if (args->flags & RPC_CLNT_CREATE_INFINITE_SLOTS) | ||
415 | xprtargs.flags |= XPRT_CREATE_INFINITE_SLOTS; | ||
414 | /* | 416 | /* |
415 | * If the caller chooses not to specify a hostname, whip | 417 | * If the caller chooses not to specify a hostname, whip |
416 | * up a string representation of the passed-in address. | 418 | * up a string representation of the passed-in address. |
@@ -1301,6 +1303,8 @@ call_reserve(struct rpc_task *task) | |||
1301 | xprt_reserve(task); | 1303 | xprt_reserve(task); |
1302 | } | 1304 | } |
1303 | 1305 | ||
1306 | static void call_retry_reserve(struct rpc_task *task); | ||
1307 | |||
1304 | /* | 1308 | /* |
1305 | * 1b. Grok the result of xprt_reserve() | 1309 | * 1b. Grok the result of xprt_reserve() |
1306 | */ | 1310 | */ |
@@ -1342,7 +1346,7 @@ call_reserveresult(struct rpc_task *task) | |||
1342 | case -ENOMEM: | 1346 | case -ENOMEM: |
1343 | rpc_delay(task, HZ >> 2); | 1347 | rpc_delay(task, HZ >> 2); |
1344 | case -EAGAIN: /* woken up; retry */ | 1348 | case -EAGAIN: /* woken up; retry */ |
1345 | task->tk_action = call_reserve; | 1349 | task->tk_action = call_retry_reserve; |
1346 | return; | 1350 | return; |
1347 | case -EIO: /* probably a shutdown */ | 1351 | case -EIO: /* probably a shutdown */ |
1348 | break; | 1352 | break; |
@@ -1355,6 +1359,19 @@ call_reserveresult(struct rpc_task *task) | |||
1355 | } | 1359 | } |
1356 | 1360 | ||
1357 | /* | 1361 | /* |
1362 | * 1c. Retry reserving an RPC call slot | ||
1363 | */ | ||
1364 | static void | ||
1365 | call_retry_reserve(struct rpc_task *task) | ||
1366 | { | ||
1367 | dprint_status(task); | ||
1368 | |||
1369 | task->tk_status = 0; | ||
1370 | task->tk_action = call_reserveresult; | ||
1371 | xprt_retry_reserve(task); | ||
1372 | } | ||
1373 | |||
1374 | /* | ||
1358 | * 2. Bind and/or refresh the credentials | 1375 | * 2. Bind and/or refresh the credentials |
1359 | */ | 1376 | */ |
1360 | static void | 1377 | static void |
@@ -1639,22 +1656,26 @@ call_connect_status(struct rpc_task *task) | |||
1639 | 1656 | ||
1640 | dprint_status(task); | 1657 | dprint_status(task); |
1641 | 1658 | ||
1642 | task->tk_status = 0; | ||
1643 | if (status >= 0 || status == -EAGAIN) { | ||
1644 | clnt->cl_stats->netreconn++; | ||
1645 | task->tk_action = call_transmit; | ||
1646 | return; | ||
1647 | } | ||
1648 | |||
1649 | trace_rpc_connect_status(task, status); | 1659 | trace_rpc_connect_status(task, status); |
1650 | switch (status) { | 1660 | switch (status) { |
1651 | /* if soft mounted, test if we've timed out */ | 1661 | /* if soft mounted, test if we've timed out */ |
1652 | case -ETIMEDOUT: | 1662 | case -ETIMEDOUT: |
1653 | task->tk_action = call_timeout; | 1663 | task->tk_action = call_timeout; |
1654 | break; | 1664 | return; |
1655 | default: | 1665 | case -ECONNREFUSED: |
1656 | rpc_exit(task, -EIO); | 1666 | case -ECONNRESET: |
1667 | case -ENETUNREACH: | ||
1668 | if (RPC_IS_SOFTCONN(task)) | ||
1669 | break; | ||
1670 | /* retry with existing socket, after a delay */ | ||
1671 | case 0: | ||
1672 | case -EAGAIN: | ||
1673 | task->tk_status = 0; | ||
1674 | clnt->cl_stats->netreconn++; | ||
1675 | task->tk_action = call_transmit; | ||
1676 | return; | ||
1657 | } | 1677 | } |
1678 | rpc_exit(task, status); | ||
1658 | } | 1679 | } |
1659 | 1680 | ||
1660 | /* | 1681 | /* |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index b7478d5e7ffd..745fca3cfd36 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
@@ -948,6 +948,34 @@ void xprt_transmit(struct rpc_task *task) | |||
948 | spin_unlock_bh(&xprt->transport_lock); | 948 | spin_unlock_bh(&xprt->transport_lock); |
949 | } | 949 | } |
950 | 950 | ||
951 | static void xprt_add_backlog(struct rpc_xprt *xprt, struct rpc_task *task) | ||
952 | { | ||
953 | set_bit(XPRT_CONGESTED, &xprt->state); | ||
954 | rpc_sleep_on(&xprt->backlog, task, NULL); | ||
955 | } | ||
956 | |||
957 | static void xprt_wake_up_backlog(struct rpc_xprt *xprt) | ||
958 | { | ||
959 | if (rpc_wake_up_next(&xprt->backlog) == NULL) | ||
960 | clear_bit(XPRT_CONGESTED, &xprt->state); | ||
961 | } | ||
962 | |||
963 | static bool xprt_throttle_congested(struct rpc_xprt *xprt, struct rpc_task *task) | ||
964 | { | ||
965 | bool ret = false; | ||
966 | |||
967 | if (!test_bit(XPRT_CONGESTED, &xprt->state)) | ||
968 | goto out; | ||
969 | spin_lock(&xprt->reserve_lock); | ||
970 | if (test_bit(XPRT_CONGESTED, &xprt->state)) { | ||
971 | rpc_sleep_on(&xprt->backlog, task, NULL); | ||
972 | ret = true; | ||
973 | } | ||
974 | spin_unlock(&xprt->reserve_lock); | ||
975 | out: | ||
976 | return ret; | ||
977 | } | ||
978 | |||
951 | static struct rpc_rqst *xprt_dynamic_alloc_slot(struct rpc_xprt *xprt, gfp_t gfp_flags) | 979 | static struct rpc_rqst *xprt_dynamic_alloc_slot(struct rpc_xprt *xprt, gfp_t gfp_flags) |
952 | { | 980 | { |
953 | struct rpc_rqst *req = ERR_PTR(-EAGAIN); | 981 | struct rpc_rqst *req = ERR_PTR(-EAGAIN); |
@@ -992,7 +1020,7 @@ void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task) | |||
992 | task->tk_status = -ENOMEM; | 1020 | task->tk_status = -ENOMEM; |
993 | break; | 1021 | break; |
994 | case -EAGAIN: | 1022 | case -EAGAIN: |
995 | rpc_sleep_on(&xprt->backlog, task, NULL); | 1023 | xprt_add_backlog(xprt, task); |
996 | dprintk("RPC: waiting for request slot\n"); | 1024 | dprintk("RPC: waiting for request slot\n"); |
997 | default: | 1025 | default: |
998 | task->tk_status = -EAGAIN; | 1026 | task->tk_status = -EAGAIN; |
@@ -1028,7 +1056,7 @@ static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req) | |||
1028 | memset(req, 0, sizeof(*req)); /* mark unused */ | 1056 | memset(req, 0, sizeof(*req)); /* mark unused */ |
1029 | list_add(&req->rq_list, &xprt->free); | 1057 | list_add(&req->rq_list, &xprt->free); |
1030 | } | 1058 | } |
1031 | rpc_wake_up_next(&xprt->backlog); | 1059 | xprt_wake_up_backlog(xprt); |
1032 | spin_unlock(&xprt->reserve_lock); | 1060 | spin_unlock(&xprt->reserve_lock); |
1033 | } | 1061 | } |
1034 | 1062 | ||
@@ -1092,7 +1120,8 @@ EXPORT_SYMBOL_GPL(xprt_free); | |||
1092 | * xprt_reserve - allocate an RPC request slot | 1120 | * xprt_reserve - allocate an RPC request slot |
1093 | * @task: RPC task requesting a slot allocation | 1121 | * @task: RPC task requesting a slot allocation |
1094 | * | 1122 | * |
1095 | * If no more slots are available, place the task on the transport's | 1123 | * If the transport is marked as being congested, or if no more |
1124 | * slots are available, place the task on the transport's | ||
1096 | * backlog queue. | 1125 | * backlog queue. |
1097 | */ | 1126 | */ |
1098 | void xprt_reserve(struct rpc_task *task) | 1127 | void xprt_reserve(struct rpc_task *task) |
@@ -1107,6 +1136,32 @@ void xprt_reserve(struct rpc_task *task) | |||
1107 | task->tk_status = -EAGAIN; | 1136 | task->tk_status = -EAGAIN; |
1108 | rcu_read_lock(); | 1137 | rcu_read_lock(); |
1109 | xprt = rcu_dereference(task->tk_client->cl_xprt); | 1138 | xprt = rcu_dereference(task->tk_client->cl_xprt); |
1139 | if (!xprt_throttle_congested(xprt, task)) | ||
1140 | xprt->ops->alloc_slot(xprt, task); | ||
1141 | rcu_read_unlock(); | ||
1142 | } | ||
1143 | |||
1144 | /** | ||
1145 | * xprt_retry_reserve - allocate an RPC request slot | ||
1146 | * @task: RPC task requesting a slot allocation | ||
1147 | * | ||
1148 | * If no more slots are available, place the task on the transport's | ||
1149 | * backlog queue. | ||
1150 | * Note that the only difference with xprt_reserve is that we now | ||
1151 | * ignore the value of the XPRT_CONGESTED flag. | ||
1152 | */ | ||
1153 | void xprt_retry_reserve(struct rpc_task *task) | ||
1154 | { | ||
1155 | struct rpc_xprt *xprt; | ||
1156 | |||
1157 | task->tk_status = 0; | ||
1158 | if (task->tk_rqstp != NULL) | ||
1159 | return; | ||
1160 | |||
1161 | task->tk_timeout = 0; | ||
1162 | task->tk_status = -EAGAIN; | ||
1163 | rcu_read_lock(); | ||
1164 | xprt = rcu_dereference(task->tk_client->cl_xprt); | ||
1110 | xprt->ops->alloc_slot(xprt, task); | 1165 | xprt->ops->alloc_slot(xprt, task); |
1111 | rcu_read_unlock(); | 1166 | rcu_read_unlock(); |
1112 | } | 1167 | } |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 3d02130828da..9c2825827dec 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -2207,10 +2207,6 @@ static void xs_tcp_setup_socket(struct work_struct *work) | |||
2207 | */ | 2207 | */ |
2208 | xs_tcp_force_close(xprt); | 2208 | xs_tcp_force_close(xprt); |
2209 | break; | 2209 | break; |
2210 | case -ECONNREFUSED: | ||
2211 | case -ECONNRESET: | ||
2212 | case -ENETUNREACH: | ||
2213 | /* retry with existing socket, after a delay */ | ||
2214 | case 0: | 2210 | case 0: |
2215 | case -EINPROGRESS: | 2211 | case -EINPROGRESS: |
2216 | case -EALREADY: | 2212 | case -EALREADY: |
@@ -2221,6 +2217,10 @@ static void xs_tcp_setup_socket(struct work_struct *work) | |||
2221 | /* Happens, for instance, if the user specified a link | 2217 | /* Happens, for instance, if the user specified a link |
2222 | * local IPv6 address without a scope-id. | 2218 | * local IPv6 address without a scope-id. |
2223 | */ | 2219 | */ |
2220 | case -ECONNREFUSED: | ||
2221 | case -ECONNRESET: | ||
2222 | case -ENETUNREACH: | ||
2223 | /* retry with existing socket, after a delay */ | ||
2224 | goto out; | 2224 | goto out; |
2225 | } | 2225 | } |
2226 | out_eagain: | 2226 | out_eagain: |
@@ -2767,9 +2767,13 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args) | |||
2767 | struct rpc_xprt *xprt; | 2767 | struct rpc_xprt *xprt; |
2768 | struct sock_xprt *transport; | 2768 | struct sock_xprt *transport; |
2769 | struct rpc_xprt *ret; | 2769 | struct rpc_xprt *ret; |
2770 | unsigned int max_slot_table_size = xprt_max_tcp_slot_table_entries; | ||
2771 | |||
2772 | if (args->flags & XPRT_CREATE_INFINITE_SLOTS) | ||
2773 | max_slot_table_size = RPC_MAX_SLOT_TABLE_LIMIT; | ||
2770 | 2774 | ||
2771 | xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries, | 2775 | xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries, |
2772 | xprt_max_tcp_slot_table_entries); | 2776 | max_slot_table_size); |
2773 | if (IS_ERR(xprt)) | 2777 | if (IS_ERR(xprt)) |
2774 | return xprt; | 2778 | return xprt; |
2775 | transport = container_of(xprt, struct sock_xprt, xprt); | 2779 | transport = container_of(xprt, struct sock_xprt, xprt); |