diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-09 12:19:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-09 12:19:15 -0400 |
commit | bf97293eb878df3792d9de7213bd7b82135aea77 (patch) | |
tree | 16cb367bd78095b9eb8a54c800fcddfcccb618c7 /net/sunrpc | |
parent | 16d70e15295953b19ecf59e943723a181782b856 (diff) | |
parent | b1b3e136948a2bf4915326acb0d825d7d180753f (diff) |
Merge tag 'nfs-for-3.12-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust:
"Highlights include:
- Fix NFSv4 recovery so that it doesn't recover lost locks in cases
such as lease loss due to a network partition, where doing so may
result in data corruption. Add a kernel parameter to control
choice of legacy behaviour or not.
- Performance improvements when 2 processes are writing to the same
file.
- Flush data to disk when an RPCSEC_GSS session timeout is imminent.
- Implement NFSv4.1 SP4_MACH_CRED state protection to prevent other
NFS clients from being able to manipulate our lease and file
locking state.
- Allow sharing of RPCSEC_GSS caches between different rpc clients.
- Fix the broken NFSv4 security auto-negotiation between client and
server.
- Fix rmdir() to wait for outstanding sillyrename unlinks to complete
- Add a tracepoint framework for debugging NFSv4 state recovery
issues.
- Add tracing to the generic NFS layer.
- Add tracing for the SUNRPC socket connection state.
- Clean up the rpc_pipefs mount/umount event management.
- Merge more patches from Chuck in preparation for NFSv4 migration
support"
* tag 'nfs-for-3.12-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (107 commits)
NFSv4: use mach cred for SECINFO_NO_NAME w/ integrity
NFS: nfs_compare_super shouldn't check the auth flavour unless 'sec=' was set
NFSv4: Allow security autonegotiation for submounts
NFSv4: Disallow security negotiation for lookups when 'sec=' is specified
NFSv4: Fix security auto-negotiation
NFS: Clean up nfs_parse_security_flavors()
NFS: Clean up the auth flavour array mess
NFSv4.1 Use MDS auth flavor for data server connection
NFS: Don't check lock owner compatability unless file is locked (part 2)
NFS: Don't check lock owner compatibility in writes unless file is locked
nfs4: Map NFS4ERR_WRONG_CRED to EPERM
nfs4.1: Add SP4_MACH_CRED write and commit support
nfs4.1: Add SP4_MACH_CRED stateid support
nfs4.1: Add SP4_MACH_CRED secinfo support
nfs4.1: Add SP4_MACH_CRED cleanup support
nfs4.1: Add state protection handler
nfs4.1: Minimal SP4_MACH_CRED implementation
SUNRPC: Replace pointer values with task->tk_pid and rpc_clnt->cl_clid
SUNRPC: Add an identifier for struct rpc_clnt
SUNRPC: Ensure rpc_task->tk_pid is available for tracepoints
...
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/auth.c | 27 | ||||
-rw-r--r-- | net/sunrpc/auth_generic.c | 82 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 442 | ||||
-rw-r--r-- | net/sunrpc/auth_null.c | 6 | ||||
-rw-r--r-- | net/sunrpc/auth_unix.c | 6 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 157 | ||||
-rw-r--r-- | net/sunrpc/rpc_pipe.c | 193 | ||||
-rw-r--r-- | net/sunrpc/sched.c | 2 | ||||
-rw-r--r-- | net/sunrpc/stats.c | 2 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 13 |
10 files changed, 712 insertions, 218 deletions
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index ed2fdd210c0b..415159061cd0 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
@@ -250,11 +250,11 @@ rpcauth_list_flavors(rpc_authflavor_t *array, int size) | |||
250 | EXPORT_SYMBOL_GPL(rpcauth_list_flavors); | 250 | EXPORT_SYMBOL_GPL(rpcauth_list_flavors); |
251 | 251 | ||
252 | struct rpc_auth * | 252 | struct rpc_auth * |
253 | rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt) | 253 | rpcauth_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) |
254 | { | 254 | { |
255 | struct rpc_auth *auth; | 255 | struct rpc_auth *auth; |
256 | const struct rpc_authops *ops; | 256 | const struct rpc_authops *ops; |
257 | u32 flavor = pseudoflavor_to_flavor(pseudoflavor); | 257 | u32 flavor = pseudoflavor_to_flavor(args->pseudoflavor); |
258 | 258 | ||
259 | auth = ERR_PTR(-EINVAL); | 259 | auth = ERR_PTR(-EINVAL); |
260 | if (flavor >= RPC_AUTH_MAXFLAVOR) | 260 | if (flavor >= RPC_AUTH_MAXFLAVOR) |
@@ -269,7 +269,7 @@ rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt) | |||
269 | goto out; | 269 | goto out; |
270 | } | 270 | } |
271 | spin_unlock(&rpc_authflavor_lock); | 271 | spin_unlock(&rpc_authflavor_lock); |
272 | auth = ops->create(clnt, pseudoflavor); | 272 | auth = ops->create(args, clnt); |
273 | module_put(ops->owner); | 273 | module_put(ops->owner); |
274 | if (IS_ERR(auth)) | 274 | if (IS_ERR(auth)) |
275 | return auth; | 275 | return auth; |
@@ -343,6 +343,27 @@ out_nocache: | |||
343 | EXPORT_SYMBOL_GPL(rpcauth_init_credcache); | 343 | EXPORT_SYMBOL_GPL(rpcauth_init_credcache); |
344 | 344 | ||
345 | /* | 345 | /* |
346 | * Setup a credential key lifetime timeout notification | ||
347 | */ | ||
348 | int | ||
349 | rpcauth_key_timeout_notify(struct rpc_auth *auth, struct rpc_cred *cred) | ||
350 | { | ||
351 | if (!cred->cr_auth->au_ops->key_timeout) | ||
352 | return 0; | ||
353 | return cred->cr_auth->au_ops->key_timeout(auth, cred); | ||
354 | } | ||
355 | EXPORT_SYMBOL_GPL(rpcauth_key_timeout_notify); | ||
356 | |||
357 | bool | ||
358 | rpcauth_cred_key_to_expire(struct rpc_cred *cred) | ||
359 | { | ||
360 | if (!cred->cr_ops->crkey_to_expire) | ||
361 | return false; | ||
362 | return cred->cr_ops->crkey_to_expire(cred); | ||
363 | } | ||
364 | EXPORT_SYMBOL_GPL(rpcauth_cred_key_to_expire); | ||
365 | |||
366 | /* | ||
346 | * Destroy a list of credentials | 367 | * Destroy a list of credentials |
347 | */ | 368 | */ |
348 | static inline | 369 | static inline |
diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c index b6badafc6494..f6d84be49050 100644 --- a/net/sunrpc/auth_generic.c +++ b/net/sunrpc/auth_generic.c | |||
@@ -89,6 +89,7 @@ generic_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) | |||
89 | gcred->acred.uid = acred->uid; | 89 | gcred->acred.uid = acred->uid; |
90 | gcred->acred.gid = acred->gid; | 90 | gcred->acred.gid = acred->gid; |
91 | gcred->acred.group_info = acred->group_info; | 91 | gcred->acred.group_info = acred->group_info; |
92 | gcred->acred.ac_flags = 0; | ||
92 | if (gcred->acred.group_info != NULL) | 93 | if (gcred->acred.group_info != NULL) |
93 | get_group_info(gcred->acred.group_info); | 94 | get_group_info(gcred->acred.group_info); |
94 | gcred->acred.machine_cred = acred->machine_cred; | 95 | gcred->acred.machine_cred = acred->machine_cred; |
@@ -182,11 +183,78 @@ void rpc_destroy_generic_auth(void) | |||
182 | rpcauth_destroy_credcache(&generic_auth); | 183 | rpcauth_destroy_credcache(&generic_auth); |
183 | } | 184 | } |
184 | 185 | ||
186 | /* | ||
187 | * Test the the current time (now) against the underlying credential key expiry | ||
188 | * minus a timeout and setup notification. | ||
189 | * | ||
190 | * The normal case: | ||
191 | * If 'now' is before the key expiry minus RPC_KEY_EXPIRE_TIMEO, set | ||
192 | * the RPC_CRED_NOTIFY_TIMEOUT flag to setup the underlying credential | ||
193 | * rpc_credops crmatch routine to notify this generic cred when it's key | ||
194 | * expiration is within RPC_KEY_EXPIRE_TIMEO, and return 0. | ||
195 | * | ||
196 | * The error case: | ||
197 | * If the underlying cred lookup fails, return -EACCES. | ||
198 | * | ||
199 | * The 'almost' error case: | ||
200 | * If 'now' is within key expiry minus RPC_KEY_EXPIRE_TIMEO, but not within | ||
201 | * key expiry minus RPC_KEY_EXPIRE_FAIL, set the RPC_CRED_EXPIRE_SOON bit | ||
202 | * on the acred ac_flags and return 0. | ||
203 | */ | ||
204 | static int | ||
205 | generic_key_timeout(struct rpc_auth *auth, struct rpc_cred *cred) | ||
206 | { | ||
207 | struct auth_cred *acred = &container_of(cred, struct generic_cred, | ||
208 | gc_base)->acred; | ||
209 | struct rpc_cred *tcred; | ||
210 | int ret = 0; | ||
211 | |||
212 | |||
213 | /* Fast track for non crkey_timeout (no key) underlying credentials */ | ||
214 | if (test_bit(RPC_CRED_NO_CRKEY_TIMEOUT, &acred->ac_flags)) | ||
215 | return 0; | ||
216 | |||
217 | /* Fast track for the normal case */ | ||
218 | if (test_bit(RPC_CRED_NOTIFY_TIMEOUT, &acred->ac_flags)) | ||
219 | return 0; | ||
220 | |||
221 | /* lookup_cred either returns a valid referenced rpc_cred, or PTR_ERR */ | ||
222 | tcred = auth->au_ops->lookup_cred(auth, acred, 0); | ||
223 | if (IS_ERR(tcred)) | ||
224 | return -EACCES; | ||
225 | |||
226 | if (!tcred->cr_ops->crkey_timeout) { | ||
227 | set_bit(RPC_CRED_NO_CRKEY_TIMEOUT, &acred->ac_flags); | ||
228 | ret = 0; | ||
229 | goto out_put; | ||
230 | } | ||
231 | |||
232 | /* Test for the almost error case */ | ||
233 | ret = tcred->cr_ops->crkey_timeout(tcred); | ||
234 | if (ret != 0) { | ||
235 | set_bit(RPC_CRED_KEY_EXPIRE_SOON, &acred->ac_flags); | ||
236 | ret = 0; | ||
237 | } else { | ||
238 | /* In case underlying cred key has been reset */ | ||
239 | if (test_and_clear_bit(RPC_CRED_KEY_EXPIRE_SOON, | ||
240 | &acred->ac_flags)) | ||
241 | dprintk("RPC: UID %d Credential key reset\n", | ||
242 | tcred->cr_uid); | ||
243 | /* set up fasttrack for the normal case */ | ||
244 | set_bit(RPC_CRED_NOTIFY_TIMEOUT, &acred->ac_flags); | ||
245 | } | ||
246 | |||
247 | out_put: | ||
248 | put_rpccred(tcred); | ||
249 | return ret; | ||
250 | } | ||
251 | |||
185 | static const struct rpc_authops generic_auth_ops = { | 252 | static const struct rpc_authops generic_auth_ops = { |
186 | .owner = THIS_MODULE, | 253 | .owner = THIS_MODULE, |
187 | .au_name = "Generic", | 254 | .au_name = "Generic", |
188 | .lookup_cred = generic_lookup_cred, | 255 | .lookup_cred = generic_lookup_cred, |
189 | .crcreate = generic_create_cred, | 256 | .crcreate = generic_create_cred, |
257 | .key_timeout = generic_key_timeout, | ||
190 | }; | 258 | }; |
191 | 259 | ||
192 | static struct rpc_auth generic_auth = { | 260 | static struct rpc_auth generic_auth = { |
@@ -194,9 +262,23 @@ static struct rpc_auth generic_auth = { | |||
194 | .au_count = ATOMIC_INIT(0), | 262 | .au_count = ATOMIC_INIT(0), |
195 | }; | 263 | }; |
196 | 264 | ||
265 | static bool generic_key_to_expire(struct rpc_cred *cred) | ||
266 | { | ||
267 | struct auth_cred *acred = &container_of(cred, struct generic_cred, | ||
268 | gc_base)->acred; | ||
269 | bool ret; | ||
270 | |||
271 | get_rpccred(cred); | ||
272 | ret = test_bit(RPC_CRED_KEY_EXPIRE_SOON, &acred->ac_flags); | ||
273 | put_rpccred(cred); | ||
274 | |||
275 | return ret; | ||
276 | } | ||
277 | |||
197 | static const struct rpc_credops generic_credops = { | 278 | static const struct rpc_credops generic_credops = { |
198 | .cr_name = "Generic cred", | 279 | .cr_name = "Generic cred", |
199 | .crdestroy = generic_destroy_cred, | 280 | .crdestroy = generic_destroy_cred, |
200 | .crbind = generic_bind_cred, | 281 | .crbind = generic_bind_cred, |
201 | .crmatch = generic_match, | 282 | .crmatch = generic_match, |
283 | .crkey_to_expire = generic_key_to_expire, | ||
202 | }; | 284 | }; |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index fc2f78d6a9b4..30eb502135bb 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -51,6 +51,7 @@ | |||
51 | #include <linux/sunrpc/rpc_pipe_fs.h> | 51 | #include <linux/sunrpc/rpc_pipe_fs.h> |
52 | #include <linux/sunrpc/gss_api.h> | 52 | #include <linux/sunrpc/gss_api.h> |
53 | #include <asm/uaccess.h> | 53 | #include <asm/uaccess.h> |
54 | #include <linux/hashtable.h> | ||
54 | 55 | ||
55 | #include "../netns.h" | 56 | #include "../netns.h" |
56 | 57 | ||
@@ -62,6 +63,9 @@ static const struct rpc_credops gss_nullops; | |||
62 | #define GSS_RETRY_EXPIRED 5 | 63 | #define GSS_RETRY_EXPIRED 5 |
63 | static unsigned int gss_expired_cred_retry_delay = GSS_RETRY_EXPIRED; | 64 | static unsigned int gss_expired_cred_retry_delay = GSS_RETRY_EXPIRED; |
64 | 65 | ||
66 | #define GSS_KEY_EXPIRE_TIMEO 240 | ||
67 | static unsigned int gss_key_expire_timeo = GSS_KEY_EXPIRE_TIMEO; | ||
68 | |||
65 | #ifdef RPC_DEBUG | 69 | #ifdef RPC_DEBUG |
66 | # define RPCDBG_FACILITY RPCDBG_AUTH | 70 | # define RPCDBG_FACILITY RPCDBG_AUTH |
67 | #endif | 71 | #endif |
@@ -71,19 +75,33 @@ static unsigned int gss_expired_cred_retry_delay = GSS_RETRY_EXPIRED; | |||
71 | * using integrity (two 4-byte integers): */ | 75 | * using integrity (two 4-byte integers): */ |
72 | #define GSS_VERF_SLACK 100 | 76 | #define GSS_VERF_SLACK 100 |
73 | 77 | ||
78 | static DEFINE_HASHTABLE(gss_auth_hash_table, 16); | ||
79 | static DEFINE_SPINLOCK(gss_auth_hash_lock); | ||
80 | |||
81 | struct gss_pipe { | ||
82 | struct rpc_pipe_dir_object pdo; | ||
83 | struct rpc_pipe *pipe; | ||
84 | struct rpc_clnt *clnt; | ||
85 | const char *name; | ||
86 | struct kref kref; | ||
87 | }; | ||
88 | |||
74 | struct gss_auth { | 89 | struct gss_auth { |
75 | struct kref kref; | 90 | struct kref kref; |
91 | struct hlist_node hash; | ||
76 | struct rpc_auth rpc_auth; | 92 | struct rpc_auth rpc_auth; |
77 | struct gss_api_mech *mech; | 93 | struct gss_api_mech *mech; |
78 | enum rpc_gss_svc service; | 94 | enum rpc_gss_svc service; |
79 | struct rpc_clnt *client; | 95 | struct rpc_clnt *client; |
96 | struct net *net; | ||
80 | /* | 97 | /* |
81 | * There are two upcall pipes; dentry[1], named "gssd", is used | 98 | * There are two upcall pipes; dentry[1], named "gssd", is used |
82 | * for the new text-based upcall; dentry[0] is named after the | 99 | * for the new text-based upcall; dentry[0] is named after the |
83 | * mechanism (for example, "krb5") and exists for | 100 | * mechanism (for example, "krb5") and exists for |
84 | * backwards-compatibility with older gssd's. | 101 | * backwards-compatibility with older gssd's. |
85 | */ | 102 | */ |
86 | struct rpc_pipe *pipe[2]; | 103 | struct gss_pipe *gss_pipe[2]; |
104 | const char *target_name; | ||
87 | }; | 105 | }; |
88 | 106 | ||
89 | /* pipe_version >= 0 if and only if someone has a pipe open. */ | 107 | /* pipe_version >= 0 if and only if someone has a pipe open. */ |
@@ -294,7 +312,7 @@ static void put_pipe_version(struct net *net) | |||
294 | static void | 312 | static void |
295 | gss_release_msg(struct gss_upcall_msg *gss_msg) | 313 | gss_release_msg(struct gss_upcall_msg *gss_msg) |
296 | { | 314 | { |
297 | struct net *net = rpc_net_ns(gss_msg->auth->client); | 315 | struct net *net = gss_msg->auth->net; |
298 | if (!atomic_dec_and_test(&gss_msg->count)) | 316 | if (!atomic_dec_and_test(&gss_msg->count)) |
299 | return; | 317 | return; |
300 | put_pipe_version(net); | 318 | put_pipe_version(net); |
@@ -406,8 +424,8 @@ static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg) | |||
406 | } | 424 | } |
407 | 425 | ||
408 | static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg, | 426 | static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg, |
409 | struct rpc_clnt *clnt, | 427 | const char *service_name, |
410 | const char *service_name) | 428 | const char *target_name) |
411 | { | 429 | { |
412 | struct gss_api_mech *mech = gss_msg->auth->mech; | 430 | struct gss_api_mech *mech = gss_msg->auth->mech; |
413 | char *p = gss_msg->databuf; | 431 | char *p = gss_msg->databuf; |
@@ -417,8 +435,8 @@ static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg, | |||
417 | mech->gm_name, | 435 | mech->gm_name, |
418 | from_kuid(&init_user_ns, gss_msg->uid)); | 436 | from_kuid(&init_user_ns, gss_msg->uid)); |
419 | p += gss_msg->msg.len; | 437 | p += gss_msg->msg.len; |
420 | if (clnt->cl_principal) { | 438 | if (target_name) { |
421 | len = sprintf(p, "target=%s ", clnt->cl_principal); | 439 | len = sprintf(p, "target=%s ", target_name); |
422 | p += len; | 440 | p += len; |
423 | gss_msg->msg.len += len; | 441 | gss_msg->msg.len += len; |
424 | } | 442 | } |
@@ -439,21 +457,8 @@ static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg, | |||
439 | BUG_ON(gss_msg->msg.len > UPCALL_BUF_LEN); | 457 | BUG_ON(gss_msg->msg.len > UPCALL_BUF_LEN); |
440 | } | 458 | } |
441 | 459 | ||
442 | static void gss_encode_msg(struct gss_upcall_msg *gss_msg, | ||
443 | struct rpc_clnt *clnt, | ||
444 | const char *service_name) | ||
445 | { | ||
446 | struct net *net = rpc_net_ns(clnt); | ||
447 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
448 | |||
449 | if (sn->pipe_version == 0) | ||
450 | gss_encode_v0_msg(gss_msg); | ||
451 | else /* pipe_version == 1 */ | ||
452 | gss_encode_v1_msg(gss_msg, clnt, service_name); | ||
453 | } | ||
454 | |||
455 | static struct gss_upcall_msg * | 460 | static struct gss_upcall_msg * |
456 | gss_alloc_msg(struct gss_auth *gss_auth, struct rpc_clnt *clnt, | 461 | gss_alloc_msg(struct gss_auth *gss_auth, |
457 | kuid_t uid, const char *service_name) | 462 | kuid_t uid, const char *service_name) |
458 | { | 463 | { |
459 | struct gss_upcall_msg *gss_msg; | 464 | struct gss_upcall_msg *gss_msg; |
@@ -462,31 +467,36 @@ gss_alloc_msg(struct gss_auth *gss_auth, struct rpc_clnt *clnt, | |||
462 | gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); | 467 | gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); |
463 | if (gss_msg == NULL) | 468 | if (gss_msg == NULL) |
464 | return ERR_PTR(-ENOMEM); | 469 | return ERR_PTR(-ENOMEM); |
465 | vers = get_pipe_version(rpc_net_ns(clnt)); | 470 | vers = get_pipe_version(gss_auth->net); |
466 | if (vers < 0) { | 471 | if (vers < 0) { |
467 | kfree(gss_msg); | 472 | kfree(gss_msg); |
468 | return ERR_PTR(vers); | 473 | return ERR_PTR(vers); |
469 | } | 474 | } |
470 | gss_msg->pipe = gss_auth->pipe[vers]; | 475 | gss_msg->pipe = gss_auth->gss_pipe[vers]->pipe; |
471 | INIT_LIST_HEAD(&gss_msg->list); | 476 | INIT_LIST_HEAD(&gss_msg->list); |
472 | rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq"); | 477 | rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq"); |
473 | init_waitqueue_head(&gss_msg->waitqueue); | 478 | init_waitqueue_head(&gss_msg->waitqueue); |
474 | atomic_set(&gss_msg->count, 1); | 479 | atomic_set(&gss_msg->count, 1); |
475 | gss_msg->uid = uid; | 480 | gss_msg->uid = uid; |
476 | gss_msg->auth = gss_auth; | 481 | gss_msg->auth = gss_auth; |
477 | gss_encode_msg(gss_msg, clnt, service_name); | 482 | switch (vers) { |
483 | case 0: | ||
484 | gss_encode_v0_msg(gss_msg); | ||
485 | default: | ||
486 | gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name); | ||
487 | }; | ||
478 | return gss_msg; | 488 | return gss_msg; |
479 | } | 489 | } |
480 | 490 | ||
481 | static struct gss_upcall_msg * | 491 | static struct gss_upcall_msg * |
482 | gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cred *cred) | 492 | gss_setup_upcall(struct gss_auth *gss_auth, struct rpc_cred *cred) |
483 | { | 493 | { |
484 | struct gss_cred *gss_cred = container_of(cred, | 494 | struct gss_cred *gss_cred = container_of(cred, |
485 | struct gss_cred, gc_base); | 495 | struct gss_cred, gc_base); |
486 | struct gss_upcall_msg *gss_new, *gss_msg; | 496 | struct gss_upcall_msg *gss_new, *gss_msg; |
487 | kuid_t uid = cred->cr_uid; | 497 | kuid_t uid = cred->cr_uid; |
488 | 498 | ||
489 | gss_new = gss_alloc_msg(gss_auth, clnt, uid, gss_cred->gc_principal); | 499 | gss_new = gss_alloc_msg(gss_auth, uid, gss_cred->gc_principal); |
490 | if (IS_ERR(gss_new)) | 500 | if (IS_ERR(gss_new)) |
491 | return gss_new; | 501 | return gss_new; |
492 | gss_msg = gss_add_msg(gss_new); | 502 | gss_msg = gss_add_msg(gss_new); |
@@ -527,7 +537,7 @@ gss_refresh_upcall(struct rpc_task *task) | |||
527 | 537 | ||
528 | dprintk("RPC: %5u %s for uid %u\n", | 538 | dprintk("RPC: %5u %s for uid %u\n", |
529 | task->tk_pid, __func__, from_kuid(&init_user_ns, cred->cr_uid)); | 539 | task->tk_pid, __func__, from_kuid(&init_user_ns, cred->cr_uid)); |
530 | gss_msg = gss_setup_upcall(task->tk_client, gss_auth, cred); | 540 | gss_msg = gss_setup_upcall(gss_auth, cred); |
531 | if (PTR_ERR(gss_msg) == -EAGAIN) { | 541 | if (PTR_ERR(gss_msg) == -EAGAIN) { |
532 | /* XXX: warning on the first, under the assumption we | 542 | /* XXX: warning on the first, under the assumption we |
533 | * shouldn't normally hit this case on a refresh. */ | 543 | * shouldn't normally hit this case on a refresh. */ |
@@ -566,7 +576,7 @@ out: | |||
566 | static inline int | 576 | static inline int |
567 | gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | 577 | gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) |
568 | { | 578 | { |
569 | struct net *net = rpc_net_ns(gss_auth->client); | 579 | struct net *net = gss_auth->net; |
570 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | 580 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
571 | struct rpc_pipe *pipe; | 581 | struct rpc_pipe *pipe; |
572 | struct rpc_cred *cred = &gss_cred->gc_base; | 582 | struct rpc_cred *cred = &gss_cred->gc_base; |
@@ -583,7 +593,7 @@ retry: | |||
583 | timeout = 15 * HZ; | 593 | timeout = 15 * HZ; |
584 | if (!sn->gssd_running) | 594 | if (!sn->gssd_running) |
585 | timeout = HZ >> 2; | 595 | timeout = HZ >> 2; |
586 | gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred); | 596 | gss_msg = gss_setup_upcall(gss_auth, cred); |
587 | if (PTR_ERR(gss_msg) == -EAGAIN) { | 597 | if (PTR_ERR(gss_msg) == -EAGAIN) { |
588 | err = wait_event_interruptible_timeout(pipe_version_waitqueue, | 598 | err = wait_event_interruptible_timeout(pipe_version_waitqueue, |
589 | sn->pipe_version >= 0, timeout); | 599 | sn->pipe_version >= 0, timeout); |
@@ -797,83 +807,153 @@ gss_pipe_destroy_msg(struct rpc_pipe_msg *msg) | |||
797 | } | 807 | } |
798 | } | 808 | } |
799 | 809 | ||
800 | static void gss_pipes_dentries_destroy(struct rpc_auth *auth) | 810 | static void gss_pipe_dentry_destroy(struct dentry *dir, |
811 | struct rpc_pipe_dir_object *pdo) | ||
801 | { | 812 | { |
802 | struct gss_auth *gss_auth; | 813 | struct gss_pipe *gss_pipe = pdo->pdo_data; |
814 | struct rpc_pipe *pipe = gss_pipe->pipe; | ||
803 | 815 | ||
804 | gss_auth = container_of(auth, struct gss_auth, rpc_auth); | 816 | if (pipe->dentry != NULL) { |
805 | if (gss_auth->pipe[0]->dentry) | 817 | rpc_unlink(pipe->dentry); |
806 | rpc_unlink(gss_auth->pipe[0]->dentry); | 818 | pipe->dentry = NULL; |
807 | if (gss_auth->pipe[1]->dentry) | 819 | } |
808 | rpc_unlink(gss_auth->pipe[1]->dentry); | ||
809 | } | 820 | } |
810 | 821 | ||
811 | static int gss_pipes_dentries_create(struct rpc_auth *auth) | 822 | static int gss_pipe_dentry_create(struct dentry *dir, |
823 | struct rpc_pipe_dir_object *pdo) | ||
812 | { | 824 | { |
813 | int err; | 825 | struct gss_pipe *p = pdo->pdo_data; |
814 | struct gss_auth *gss_auth; | 826 | struct dentry *dentry; |
815 | struct rpc_clnt *clnt; | ||
816 | 827 | ||
817 | gss_auth = container_of(auth, struct gss_auth, rpc_auth); | 828 | dentry = rpc_mkpipe_dentry(dir, p->name, p->clnt, p->pipe); |
818 | clnt = gss_auth->client; | 829 | if (IS_ERR(dentry)) |
819 | 830 | return PTR_ERR(dentry); | |
820 | gss_auth->pipe[1]->dentry = rpc_mkpipe_dentry(clnt->cl_dentry, | 831 | p->pipe->dentry = dentry; |
821 | "gssd", | ||
822 | clnt, gss_auth->pipe[1]); | ||
823 | if (IS_ERR(gss_auth->pipe[1]->dentry)) | ||
824 | return PTR_ERR(gss_auth->pipe[1]->dentry); | ||
825 | gss_auth->pipe[0]->dentry = rpc_mkpipe_dentry(clnt->cl_dentry, | ||
826 | gss_auth->mech->gm_name, | ||
827 | clnt, gss_auth->pipe[0]); | ||
828 | if (IS_ERR(gss_auth->pipe[0]->dentry)) { | ||
829 | err = PTR_ERR(gss_auth->pipe[0]->dentry); | ||
830 | goto err_unlink_pipe_1; | ||
831 | } | ||
832 | return 0; | 832 | return 0; |
833 | } | ||
833 | 834 | ||
834 | err_unlink_pipe_1: | 835 | static const struct rpc_pipe_dir_object_ops gss_pipe_dir_object_ops = { |
835 | rpc_unlink(gss_auth->pipe[1]->dentry); | 836 | .create = gss_pipe_dentry_create, |
836 | return err; | 837 | .destroy = gss_pipe_dentry_destroy, |
838 | }; | ||
839 | |||
840 | static struct gss_pipe *gss_pipe_alloc(struct rpc_clnt *clnt, | ||
841 | const char *name, | ||
842 | const struct rpc_pipe_ops *upcall_ops) | ||
843 | { | ||
844 | struct gss_pipe *p; | ||
845 | int err = -ENOMEM; | ||
846 | |||
847 | p = kmalloc(sizeof(*p), GFP_KERNEL); | ||
848 | if (p == NULL) | ||
849 | goto err; | ||
850 | p->pipe = rpc_mkpipe_data(upcall_ops, RPC_PIPE_WAIT_FOR_OPEN); | ||
851 | if (IS_ERR(p->pipe)) { | ||
852 | err = PTR_ERR(p->pipe); | ||
853 | goto err_free_gss_pipe; | ||
854 | } | ||
855 | p->name = name; | ||
856 | p->clnt = clnt; | ||
857 | kref_init(&p->kref); | ||
858 | rpc_init_pipe_dir_object(&p->pdo, | ||
859 | &gss_pipe_dir_object_ops, | ||
860 | p); | ||
861 | return p; | ||
862 | err_free_gss_pipe: | ||
863 | kfree(p); | ||
864 | err: | ||
865 | return ERR_PTR(err); | ||
866 | } | ||
867 | |||
868 | struct gss_alloc_pdo { | ||
869 | struct rpc_clnt *clnt; | ||
870 | const char *name; | ||
871 | const struct rpc_pipe_ops *upcall_ops; | ||
872 | }; | ||
873 | |||
874 | static int gss_pipe_match_pdo(struct rpc_pipe_dir_object *pdo, void *data) | ||
875 | { | ||
876 | struct gss_pipe *gss_pipe; | ||
877 | struct gss_alloc_pdo *args = data; | ||
878 | |||
879 | if (pdo->pdo_ops != &gss_pipe_dir_object_ops) | ||
880 | return 0; | ||
881 | gss_pipe = container_of(pdo, struct gss_pipe, pdo); | ||
882 | if (strcmp(gss_pipe->name, args->name) != 0) | ||
883 | return 0; | ||
884 | if (!kref_get_unless_zero(&gss_pipe->kref)) | ||
885 | return 0; | ||
886 | return 1; | ||
837 | } | 887 | } |
838 | 888 | ||
839 | static void gss_pipes_dentries_destroy_net(struct rpc_clnt *clnt, | 889 | static struct rpc_pipe_dir_object *gss_pipe_alloc_pdo(void *data) |
840 | struct rpc_auth *auth) | 890 | { |
891 | struct gss_pipe *gss_pipe; | ||
892 | struct gss_alloc_pdo *args = data; | ||
893 | |||
894 | gss_pipe = gss_pipe_alloc(args->clnt, args->name, args->upcall_ops); | ||
895 | if (!IS_ERR(gss_pipe)) | ||
896 | return &gss_pipe->pdo; | ||
897 | return NULL; | ||
898 | } | ||
899 | |||
900 | static struct gss_pipe *gss_pipe_get(struct rpc_clnt *clnt, | ||
901 | const char *name, | ||
902 | const struct rpc_pipe_ops *upcall_ops) | ||
841 | { | 903 | { |
842 | struct net *net = rpc_net_ns(clnt); | 904 | struct net *net = rpc_net_ns(clnt); |
843 | struct super_block *sb; | 905 | struct rpc_pipe_dir_object *pdo; |
906 | struct gss_alloc_pdo args = { | ||
907 | .clnt = clnt, | ||
908 | .name = name, | ||
909 | .upcall_ops = upcall_ops, | ||
910 | }; | ||
844 | 911 | ||
845 | sb = rpc_get_sb_net(net); | 912 | pdo = rpc_find_or_alloc_pipe_dir_object(net, |
846 | if (sb) { | 913 | &clnt->cl_pipedir_objects, |
847 | if (clnt->cl_dentry) | 914 | gss_pipe_match_pdo, |
848 | gss_pipes_dentries_destroy(auth); | 915 | gss_pipe_alloc_pdo, |
849 | rpc_put_sb_net(net); | 916 | &args); |
850 | } | 917 | if (pdo != NULL) |
918 | return container_of(pdo, struct gss_pipe, pdo); | ||
919 | return ERR_PTR(-ENOMEM); | ||
851 | } | 920 | } |
852 | 921 | ||
853 | static int gss_pipes_dentries_create_net(struct rpc_clnt *clnt, | 922 | static void __gss_pipe_free(struct gss_pipe *p) |
854 | struct rpc_auth *auth) | ||
855 | { | 923 | { |
924 | struct rpc_clnt *clnt = p->clnt; | ||
856 | struct net *net = rpc_net_ns(clnt); | 925 | struct net *net = rpc_net_ns(clnt); |
857 | struct super_block *sb; | ||
858 | int err = 0; | ||
859 | 926 | ||
860 | sb = rpc_get_sb_net(net); | 927 | rpc_remove_pipe_dir_object(net, |
861 | if (sb) { | 928 | &clnt->cl_pipedir_objects, |
862 | if (clnt->cl_dentry) | 929 | &p->pdo); |
863 | err = gss_pipes_dentries_create(auth); | 930 | rpc_destroy_pipe_data(p->pipe); |
864 | rpc_put_sb_net(net); | 931 | kfree(p); |
865 | } | 932 | } |
866 | return err; | 933 | |
934 | static void __gss_pipe_release(struct kref *kref) | ||
935 | { | ||
936 | struct gss_pipe *p = container_of(kref, struct gss_pipe, kref); | ||
937 | |||
938 | __gss_pipe_free(p); | ||
939 | } | ||
940 | |||
941 | static void gss_pipe_free(struct gss_pipe *p) | ||
942 | { | ||
943 | if (p != NULL) | ||
944 | kref_put(&p->kref, __gss_pipe_release); | ||
867 | } | 945 | } |
868 | 946 | ||
869 | /* | 947 | /* |
870 | * NOTE: we have the opportunity to use different | 948 | * NOTE: we have the opportunity to use different |
871 | * parameters based on the input flavor (which must be a pseudoflavor) | 949 | * parameters based on the input flavor (which must be a pseudoflavor) |
872 | */ | 950 | */ |
873 | static struct rpc_auth * | 951 | static struct gss_auth * |
874 | gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | 952 | gss_create_new(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) |
875 | { | 953 | { |
954 | rpc_authflavor_t flavor = args->pseudoflavor; | ||
876 | struct gss_auth *gss_auth; | 955 | struct gss_auth *gss_auth; |
956 | struct gss_pipe *gss_pipe; | ||
877 | struct rpc_auth * auth; | 957 | struct rpc_auth * auth; |
878 | int err = -ENOMEM; /* XXX? */ | 958 | int err = -ENOMEM; /* XXX? */ |
879 | 959 | ||
@@ -883,12 +963,20 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | |||
883 | return ERR_PTR(err); | 963 | return ERR_PTR(err); |
884 | if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL))) | 964 | if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL))) |
885 | goto out_dec; | 965 | goto out_dec; |
966 | INIT_HLIST_NODE(&gss_auth->hash); | ||
967 | gss_auth->target_name = NULL; | ||
968 | if (args->target_name) { | ||
969 | gss_auth->target_name = kstrdup(args->target_name, GFP_KERNEL); | ||
970 | if (gss_auth->target_name == NULL) | ||
971 | goto err_free; | ||
972 | } | ||
886 | gss_auth->client = clnt; | 973 | gss_auth->client = clnt; |
974 | gss_auth->net = get_net(rpc_net_ns(clnt)); | ||
887 | err = -EINVAL; | 975 | err = -EINVAL; |
888 | gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor); | 976 | gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor); |
889 | if (!gss_auth->mech) { | 977 | if (!gss_auth->mech) { |
890 | dprintk("RPC: Pseudoflavor %d not found!\n", flavor); | 978 | dprintk("RPC: Pseudoflavor %d not found!\n", flavor); |
891 | goto err_free; | 979 | goto err_put_net; |
892 | } | 980 | } |
893 | gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor); | 981 | gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor); |
894 | if (gss_auth->service == 0) | 982 | if (gss_auth->service == 0) |
@@ -901,42 +989,41 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | |||
901 | atomic_set(&auth->au_count, 1); | 989 | atomic_set(&auth->au_count, 1); |
902 | kref_init(&gss_auth->kref); | 990 | kref_init(&gss_auth->kref); |
903 | 991 | ||
992 | err = rpcauth_init_credcache(auth); | ||
993 | if (err) | ||
994 | goto err_put_mech; | ||
904 | /* | 995 | /* |
905 | * Note: if we created the old pipe first, then someone who | 996 | * Note: if we created the old pipe first, then someone who |
906 | * examined the directory at the right moment might conclude | 997 | * examined the directory at the right moment might conclude |
907 | * that we supported only the old pipe. So we instead create | 998 | * that we supported only the old pipe. So we instead create |
908 | * the new pipe first. | 999 | * the new pipe first. |
909 | */ | 1000 | */ |
910 | gss_auth->pipe[1] = rpc_mkpipe_data(&gss_upcall_ops_v1, | 1001 | gss_pipe = gss_pipe_get(clnt, "gssd", &gss_upcall_ops_v1); |
911 | RPC_PIPE_WAIT_FOR_OPEN); | 1002 | if (IS_ERR(gss_pipe)) { |
912 | if (IS_ERR(gss_auth->pipe[1])) { | 1003 | err = PTR_ERR(gss_pipe); |
913 | err = PTR_ERR(gss_auth->pipe[1]); | 1004 | goto err_destroy_credcache; |
914 | goto err_put_mech; | ||
915 | } | 1005 | } |
1006 | gss_auth->gss_pipe[1] = gss_pipe; | ||
916 | 1007 | ||
917 | gss_auth->pipe[0] = rpc_mkpipe_data(&gss_upcall_ops_v0, | 1008 | gss_pipe = gss_pipe_get(clnt, gss_auth->mech->gm_name, |
918 | RPC_PIPE_WAIT_FOR_OPEN); | 1009 | &gss_upcall_ops_v0); |
919 | if (IS_ERR(gss_auth->pipe[0])) { | 1010 | if (IS_ERR(gss_pipe)) { |
920 | err = PTR_ERR(gss_auth->pipe[0]); | 1011 | err = PTR_ERR(gss_pipe); |
921 | goto err_destroy_pipe_1; | 1012 | goto err_destroy_pipe_1; |
922 | } | 1013 | } |
923 | err = gss_pipes_dentries_create_net(clnt, auth); | 1014 | gss_auth->gss_pipe[0] = gss_pipe; |
924 | if (err) | ||
925 | goto err_destroy_pipe_0; | ||
926 | err = rpcauth_init_credcache(auth); | ||
927 | if (err) | ||
928 | goto err_unlink_pipes; | ||
929 | 1015 | ||
930 | return auth; | 1016 | return gss_auth; |
931 | err_unlink_pipes: | ||
932 | gss_pipes_dentries_destroy_net(clnt, auth); | ||
933 | err_destroy_pipe_0: | ||
934 | rpc_destroy_pipe_data(gss_auth->pipe[0]); | ||
935 | err_destroy_pipe_1: | 1017 | err_destroy_pipe_1: |
936 | rpc_destroy_pipe_data(gss_auth->pipe[1]); | 1018 | gss_pipe_free(gss_auth->gss_pipe[1]); |
1019 | err_destroy_credcache: | ||
1020 | rpcauth_destroy_credcache(auth); | ||
937 | err_put_mech: | 1021 | err_put_mech: |
938 | gss_mech_put(gss_auth->mech); | 1022 | gss_mech_put(gss_auth->mech); |
1023 | err_put_net: | ||
1024 | put_net(gss_auth->net); | ||
939 | err_free: | 1025 | err_free: |
1026 | kfree(gss_auth->target_name); | ||
940 | kfree(gss_auth); | 1027 | kfree(gss_auth); |
941 | out_dec: | 1028 | out_dec: |
942 | module_put(THIS_MODULE); | 1029 | module_put(THIS_MODULE); |
@@ -946,10 +1033,11 @@ out_dec: | |||
946 | static void | 1033 | static void |
947 | gss_free(struct gss_auth *gss_auth) | 1034 | gss_free(struct gss_auth *gss_auth) |
948 | { | 1035 | { |
949 | gss_pipes_dentries_destroy_net(gss_auth->client, &gss_auth->rpc_auth); | 1036 | gss_pipe_free(gss_auth->gss_pipe[0]); |
950 | rpc_destroy_pipe_data(gss_auth->pipe[0]); | 1037 | gss_pipe_free(gss_auth->gss_pipe[1]); |
951 | rpc_destroy_pipe_data(gss_auth->pipe[1]); | ||
952 | gss_mech_put(gss_auth->mech); | 1038 | gss_mech_put(gss_auth->mech); |
1039 | put_net(gss_auth->net); | ||
1040 | kfree(gss_auth->target_name); | ||
953 | 1041 | ||
954 | kfree(gss_auth); | 1042 | kfree(gss_auth); |
955 | module_put(THIS_MODULE); | 1043 | module_put(THIS_MODULE); |
@@ -966,17 +1054,101 @@ gss_free_callback(struct kref *kref) | |||
966 | static void | 1054 | static void |
967 | gss_destroy(struct rpc_auth *auth) | 1055 | gss_destroy(struct rpc_auth *auth) |
968 | { | 1056 | { |
969 | struct gss_auth *gss_auth; | 1057 | struct gss_auth *gss_auth = container_of(auth, |
1058 | struct gss_auth, rpc_auth); | ||
970 | 1059 | ||
971 | dprintk("RPC: destroying GSS authenticator %p flavor %d\n", | 1060 | dprintk("RPC: destroying GSS authenticator %p flavor %d\n", |
972 | auth, auth->au_flavor); | 1061 | auth, auth->au_flavor); |
973 | 1062 | ||
1063 | if (hash_hashed(&gss_auth->hash)) { | ||
1064 | spin_lock(&gss_auth_hash_lock); | ||
1065 | hash_del(&gss_auth->hash); | ||
1066 | spin_unlock(&gss_auth_hash_lock); | ||
1067 | } | ||
1068 | |||
1069 | gss_pipe_free(gss_auth->gss_pipe[0]); | ||
1070 | gss_auth->gss_pipe[0] = NULL; | ||
1071 | gss_pipe_free(gss_auth->gss_pipe[1]); | ||
1072 | gss_auth->gss_pipe[1] = NULL; | ||
974 | rpcauth_destroy_credcache(auth); | 1073 | rpcauth_destroy_credcache(auth); |
975 | 1074 | ||
976 | gss_auth = container_of(auth, struct gss_auth, rpc_auth); | ||
977 | kref_put(&gss_auth->kref, gss_free_callback); | 1075 | kref_put(&gss_auth->kref, gss_free_callback); |
978 | } | 1076 | } |
979 | 1077 | ||
1078 | static struct gss_auth * | ||
1079 | gss_auth_find_or_add_hashed(struct rpc_auth_create_args *args, | ||
1080 | struct rpc_clnt *clnt, | ||
1081 | struct gss_auth *new) | ||
1082 | { | ||
1083 | struct gss_auth *gss_auth; | ||
1084 | unsigned long hashval = (unsigned long)clnt; | ||
1085 | |||
1086 | spin_lock(&gss_auth_hash_lock); | ||
1087 | hash_for_each_possible(gss_auth_hash_table, | ||
1088 | gss_auth, | ||
1089 | hash, | ||
1090 | hashval) { | ||
1091 | if (gss_auth->rpc_auth.au_flavor != args->pseudoflavor) | ||
1092 | continue; | ||
1093 | if (gss_auth->target_name != args->target_name) { | ||
1094 | if (gss_auth->target_name == NULL) | ||
1095 | continue; | ||
1096 | if (args->target_name == NULL) | ||
1097 | continue; | ||
1098 | if (strcmp(gss_auth->target_name, args->target_name)) | ||
1099 | continue; | ||
1100 | } | ||
1101 | if (!atomic_inc_not_zero(&gss_auth->rpc_auth.au_count)) | ||
1102 | continue; | ||
1103 | goto out; | ||
1104 | } | ||
1105 | if (new) | ||
1106 | hash_add(gss_auth_hash_table, &new->hash, hashval); | ||
1107 | gss_auth = new; | ||
1108 | out: | ||
1109 | spin_unlock(&gss_auth_hash_lock); | ||
1110 | return gss_auth; | ||
1111 | } | ||
1112 | |||
1113 | static struct gss_auth * | ||
1114 | gss_create_hashed(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) | ||
1115 | { | ||
1116 | struct gss_auth *gss_auth; | ||
1117 | struct gss_auth *new; | ||
1118 | |||
1119 | gss_auth = gss_auth_find_or_add_hashed(args, clnt, NULL); | ||
1120 | if (gss_auth != NULL) | ||
1121 | goto out; | ||
1122 | new = gss_create_new(args, clnt); | ||
1123 | if (IS_ERR(new)) | ||
1124 | return new; | ||
1125 | gss_auth = gss_auth_find_or_add_hashed(args, clnt, new); | ||
1126 | if (gss_auth != new) | ||
1127 | gss_destroy(&new->rpc_auth); | ||
1128 | out: | ||
1129 | return gss_auth; | ||
1130 | } | ||
1131 | |||
1132 | static struct rpc_auth * | ||
1133 | gss_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) | ||
1134 | { | ||
1135 | struct gss_auth *gss_auth; | ||
1136 | struct rpc_xprt *xprt = rcu_access_pointer(clnt->cl_xprt); | ||
1137 | |||
1138 | while (clnt != clnt->cl_parent) { | ||
1139 | struct rpc_clnt *parent = clnt->cl_parent; | ||
1140 | /* Find the original parent for this transport */ | ||
1141 | if (rcu_access_pointer(parent->cl_xprt) != xprt) | ||
1142 | break; | ||
1143 | clnt = parent; | ||
1144 | } | ||
1145 | |||
1146 | gss_auth = gss_create_hashed(args, clnt); | ||
1147 | if (IS_ERR(gss_auth)) | ||
1148 | return ERR_CAST(gss_auth); | ||
1149 | return &gss_auth->rpc_auth; | ||
1150 | } | ||
1151 | |||
980 | /* | 1152 | /* |
981 | * gss_destroying_context will cause the RPCSEC_GSS to send a NULL RPC call | 1153 | * gss_destroying_context will cause the RPCSEC_GSS to send a NULL RPC call |
982 | * to the server with the GSS control procedure field set to | 1154 | * to the server with the GSS control procedure field set to |
@@ -1126,10 +1298,32 @@ gss_cred_init(struct rpc_auth *auth, struct rpc_cred *cred) | |||
1126 | return err; | 1298 | return err; |
1127 | } | 1299 | } |
1128 | 1300 | ||
1301 | /* | ||
1302 | * Returns -EACCES if GSS context is NULL or will expire within the | ||
1303 | * timeout (miliseconds) | ||
1304 | */ | ||
1305 | static int | ||
1306 | gss_key_timeout(struct rpc_cred *rc) | ||
1307 | { | ||
1308 | struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); | ||
1309 | unsigned long now = jiffies; | ||
1310 | unsigned long expire; | ||
1311 | |||
1312 | if (gss_cred->gc_ctx == NULL) | ||
1313 | return -EACCES; | ||
1314 | |||
1315 | expire = gss_cred->gc_ctx->gc_expiry - (gss_key_expire_timeo * HZ); | ||
1316 | |||
1317 | if (time_after(now, expire)) | ||
1318 | return -EACCES; | ||
1319 | return 0; | ||
1320 | } | ||
1321 | |||
1129 | static int | 1322 | static int |
1130 | gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags) | 1323 | gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags) |
1131 | { | 1324 | { |
1132 | struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); | 1325 | struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); |
1326 | int ret; | ||
1133 | 1327 | ||
1134 | if (test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags)) | 1328 | if (test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags)) |
1135 | goto out; | 1329 | goto out; |
@@ -1142,11 +1336,26 @@ out: | |||
1142 | if (acred->principal != NULL) { | 1336 | if (acred->principal != NULL) { |
1143 | if (gss_cred->gc_principal == NULL) | 1337 | if (gss_cred->gc_principal == NULL) |
1144 | return 0; | 1338 | return 0; |
1145 | return strcmp(acred->principal, gss_cred->gc_principal) == 0; | 1339 | ret = strcmp(acred->principal, gss_cred->gc_principal) == 0; |
1340 | goto check_expire; | ||
1146 | } | 1341 | } |
1147 | if (gss_cred->gc_principal != NULL) | 1342 | if (gss_cred->gc_principal != NULL) |
1148 | return 0; | 1343 | return 0; |
1149 | return uid_eq(rc->cr_uid, acred->uid); | 1344 | ret = uid_eq(rc->cr_uid, acred->uid); |
1345 | |||
1346 | check_expire: | ||
1347 | if (ret == 0) | ||
1348 | return ret; | ||
1349 | |||
1350 | /* Notify acred users of GSS context expiration timeout */ | ||
1351 | if (test_bit(RPC_CRED_NOTIFY_TIMEOUT, &acred->ac_flags) && | ||
1352 | (gss_key_timeout(rc) != 0)) { | ||
1353 | /* test will now be done from generic cred */ | ||
1354 | test_and_clear_bit(RPC_CRED_NOTIFY_TIMEOUT, &acred->ac_flags); | ||
1355 | /* tell NFS layer that key will expire soon */ | ||
1356 | set_bit(RPC_CRED_KEY_EXPIRE_SOON, &acred->ac_flags); | ||
1357 | } | ||
1358 | return ret; | ||
1150 | } | 1359 | } |
1151 | 1360 | ||
1152 | /* | 1361 | /* |
@@ -1292,6 +1501,7 @@ gss_validate(struct rpc_task *task, __be32 *p) | |||
1292 | struct xdr_netobj mic; | 1501 | struct xdr_netobj mic; |
1293 | u32 flav,len; | 1502 | u32 flav,len; |
1294 | u32 maj_stat; | 1503 | u32 maj_stat; |
1504 | __be32 *ret = ERR_PTR(-EIO); | ||
1295 | 1505 | ||
1296 | dprintk("RPC: %5u %s\n", task->tk_pid, __func__); | 1506 | dprintk("RPC: %5u %s\n", task->tk_pid, __func__); |
1297 | 1507 | ||
@@ -1307,6 +1517,7 @@ gss_validate(struct rpc_task *task, __be32 *p) | |||
1307 | mic.data = (u8 *)p; | 1517 | mic.data = (u8 *)p; |
1308 | mic.len = len; | 1518 | mic.len = len; |
1309 | 1519 | ||
1520 | ret = ERR_PTR(-EACCES); | ||
1310 | maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic); | 1521 | maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic); |
1311 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) | 1522 | if (maj_stat == GSS_S_CONTEXT_EXPIRED) |
1312 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); | 1523 | clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags); |
@@ -1324,8 +1535,9 @@ gss_validate(struct rpc_task *task, __be32 *p) | |||
1324 | return p + XDR_QUADLEN(len); | 1535 | return p + XDR_QUADLEN(len); |
1325 | out_bad: | 1536 | out_bad: |
1326 | gss_put_ctx(ctx); | 1537 | gss_put_ctx(ctx); |
1327 | dprintk("RPC: %5u %s failed.\n", task->tk_pid, __func__); | 1538 | dprintk("RPC: %5u %s failed ret %ld.\n", task->tk_pid, __func__, |
1328 | return NULL; | 1539 | PTR_ERR(ret)); |
1540 | return ret; | ||
1329 | } | 1541 | } |
1330 | 1542 | ||
1331 | static void gss_wrap_req_encode(kxdreproc_t encode, struct rpc_rqst *rqstp, | 1543 | static void gss_wrap_req_encode(kxdreproc_t encode, struct rpc_rqst *rqstp, |
@@ -1657,8 +1869,6 @@ static const struct rpc_authops authgss_ops = { | |||
1657 | .destroy = gss_destroy, | 1869 | .destroy = gss_destroy, |
1658 | .lookup_cred = gss_lookup_cred, | 1870 | .lookup_cred = gss_lookup_cred, |
1659 | .crcreate = gss_create_cred, | 1871 | .crcreate = gss_create_cred, |
1660 | .pipes_create = gss_pipes_dentries_create, | ||
1661 | .pipes_destroy = gss_pipes_dentries_destroy, | ||
1662 | .list_pseudoflavors = gss_mech_list_pseudoflavors, | 1872 | .list_pseudoflavors = gss_mech_list_pseudoflavors, |
1663 | .info2flavor = gss_mech_info2flavor, | 1873 | .info2flavor = gss_mech_info2flavor, |
1664 | .flavor2info = gss_mech_flavor2info, | 1874 | .flavor2info = gss_mech_flavor2info, |
@@ -1675,6 +1885,7 @@ static const struct rpc_credops gss_credops = { | |||
1675 | .crvalidate = gss_validate, | 1885 | .crvalidate = gss_validate, |
1676 | .crwrap_req = gss_wrap_req, | 1886 | .crwrap_req = gss_wrap_req, |
1677 | .crunwrap_resp = gss_unwrap_resp, | 1887 | .crunwrap_resp = gss_unwrap_resp, |
1888 | .crkey_timeout = gss_key_timeout, | ||
1678 | }; | 1889 | }; |
1679 | 1890 | ||
1680 | static const struct rpc_credops gss_nullops = { | 1891 | static const struct rpc_credops gss_nullops = { |
@@ -1762,5 +1973,12 @@ module_param_named(expired_cred_retry_delay, | |||
1762 | MODULE_PARM_DESC(expired_cred_retry_delay, "Timeout (in seconds) until " | 1973 | MODULE_PARM_DESC(expired_cred_retry_delay, "Timeout (in seconds) until " |
1763 | "the RPC engine retries an expired credential"); | 1974 | "the RPC engine retries an expired credential"); |
1764 | 1975 | ||
1976 | module_param_named(key_expire_timeo, | ||
1977 | gss_key_expire_timeo, | ||
1978 | uint, 0644); | ||
1979 | MODULE_PARM_DESC(key_expire_timeo, "Time (in seconds) at the end of a " | ||
1980 | "credential keys lifetime where the NFS layer cleans up " | ||
1981 | "prior to key expiration"); | ||
1982 | |||
1765 | module_init(init_rpcsec_gss) | 1983 | module_init(init_rpcsec_gss) |
1766 | module_exit(exit_rpcsec_gss) | 1984 | module_exit(exit_rpcsec_gss) |
diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c index a5c36c01707b..f0ebe07978a2 100644 --- a/net/sunrpc/auth_null.c +++ b/net/sunrpc/auth_null.c | |||
@@ -18,7 +18,7 @@ static struct rpc_auth null_auth; | |||
18 | static struct rpc_cred null_cred; | 18 | static struct rpc_cred null_cred; |
19 | 19 | ||
20 | static struct rpc_auth * | 20 | static struct rpc_auth * |
21 | nul_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | 21 | nul_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) |
22 | { | 22 | { |
23 | atomic_inc(&null_auth.au_count); | 23 | atomic_inc(&null_auth.au_count); |
24 | return &null_auth; | 24 | return &null_auth; |
@@ -88,13 +88,13 @@ nul_validate(struct rpc_task *task, __be32 *p) | |||
88 | flavor = ntohl(*p++); | 88 | flavor = ntohl(*p++); |
89 | if (flavor != RPC_AUTH_NULL) { | 89 | if (flavor != RPC_AUTH_NULL) { |
90 | printk("RPC: bad verf flavor: %u\n", flavor); | 90 | printk("RPC: bad verf flavor: %u\n", flavor); |
91 | return NULL; | 91 | return ERR_PTR(-EIO); |
92 | } | 92 | } |
93 | 93 | ||
94 | size = ntohl(*p++); | 94 | size = ntohl(*p++); |
95 | if (size != 0) { | 95 | if (size != 0) { |
96 | printk("RPC: bad verf size: %u\n", size); | 96 | printk("RPC: bad verf size: %u\n", size); |
97 | return NULL; | 97 | return ERR_PTR(-EIO); |
98 | } | 98 | } |
99 | 99 | ||
100 | return p; | 100 | return p; |
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c index dc37021fc3e5..d5d692366294 100644 --- a/net/sunrpc/auth_unix.c +++ b/net/sunrpc/auth_unix.c | |||
@@ -33,7 +33,7 @@ static struct rpc_auth unix_auth; | |||
33 | static const struct rpc_credops unix_credops; | 33 | static const struct rpc_credops unix_credops; |
34 | 34 | ||
35 | static struct rpc_auth * | 35 | static struct rpc_auth * |
36 | unx_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | 36 | unx_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) |
37 | { | 37 | { |
38 | dprintk("RPC: creating UNIX authenticator for client %p\n", | 38 | dprintk("RPC: creating UNIX authenticator for client %p\n", |
39 | clnt); | 39 | clnt); |
@@ -192,13 +192,13 @@ unx_validate(struct rpc_task *task, __be32 *p) | |||
192 | flavor != RPC_AUTH_UNIX && | 192 | flavor != RPC_AUTH_UNIX && |
193 | flavor != RPC_AUTH_SHORT) { | 193 | flavor != RPC_AUTH_SHORT) { |
194 | printk("RPC: bad verf flavor: %u\n", flavor); | 194 | printk("RPC: bad verf flavor: %u\n", flavor); |
195 | return NULL; | 195 | return ERR_PTR(-EIO); |
196 | } | 196 | } |
197 | 197 | ||
198 | size = ntohl(*p++); | 198 | size = ntohl(*p++); |
199 | if (size > RPC_MAX_AUTH_SIZE) { | 199 | if (size > RPC_MAX_AUTH_SIZE) { |
200 | printk("RPC: giant verf size: %u\n", size); | 200 | printk("RPC: giant verf size: %u\n", size); |
201 | return NULL; | 201 | return ERR_PTR(-EIO); |
202 | } | 202 | } |
203 | task->tk_rqstp->rq_cred->cr_auth->au_rslack = (size >> 2) + 2; | 203 | task->tk_rqstp->rq_cred->cr_auth->au_rslack = (size >> 2) + 2; |
204 | p += (size >> 2); | 204 | p += (size >> 2); |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index ecbc4e3d83ad..77479606a971 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -102,12 +102,7 @@ static void rpc_unregister_client(struct rpc_clnt *clnt) | |||
102 | 102 | ||
103 | static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) | 103 | static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) |
104 | { | 104 | { |
105 | if (clnt->cl_dentry) { | 105 | rpc_remove_client_dir(clnt); |
106 | if (clnt->cl_auth && clnt->cl_auth->au_ops->pipes_destroy) | ||
107 | clnt->cl_auth->au_ops->pipes_destroy(clnt->cl_auth); | ||
108 | rpc_remove_client_dir(clnt->cl_dentry); | ||
109 | } | ||
110 | clnt->cl_dentry = NULL; | ||
111 | } | 106 | } |
112 | 107 | ||
113 | static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) | 108 | static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) |
@@ -123,10 +118,10 @@ static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) | |||
123 | } | 118 | } |
124 | 119 | ||
125 | static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb, | 120 | static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb, |
126 | struct rpc_clnt *clnt, | 121 | struct rpc_clnt *clnt) |
127 | const char *dir_name) | ||
128 | { | 122 | { |
129 | static uint32_t clntid; | 123 | static uint32_t clntid; |
124 | const char *dir_name = clnt->cl_program->pipe_dir_name; | ||
130 | char name[15]; | 125 | char name[15]; |
131 | struct dentry *dir, *dentry; | 126 | struct dentry *dir, *dentry; |
132 | 127 | ||
@@ -153,28 +148,35 @@ static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb, | |||
153 | } | 148 | } |
154 | 149 | ||
155 | static int | 150 | static int |
156 | rpc_setup_pipedir(struct rpc_clnt *clnt, const char *dir_name, | 151 | rpc_setup_pipedir(struct super_block *pipefs_sb, struct rpc_clnt *clnt) |
157 | struct super_block *pipefs_sb) | ||
158 | { | 152 | { |
159 | struct dentry *dentry; | 153 | struct dentry *dentry; |
160 | 154 | ||
161 | clnt->cl_dentry = NULL; | 155 | if (clnt->cl_program->pipe_dir_name != NULL) { |
162 | if (dir_name == NULL) | 156 | dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt); |
163 | return 0; | 157 | if (IS_ERR(dentry)) |
164 | dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name); | 158 | return PTR_ERR(dentry); |
165 | if (IS_ERR(dentry)) | 159 | } |
166 | return PTR_ERR(dentry); | ||
167 | clnt->cl_dentry = dentry; | ||
168 | return 0; | 160 | return 0; |
169 | } | 161 | } |
170 | 162 | ||
171 | static inline int rpc_clnt_skip_event(struct rpc_clnt *clnt, unsigned long event) | 163 | static int rpc_clnt_skip_event(struct rpc_clnt *clnt, unsigned long event) |
172 | { | 164 | { |
173 | if (((event == RPC_PIPEFS_MOUNT) && clnt->cl_dentry) || | 165 | if (clnt->cl_program->pipe_dir_name == NULL) |
174 | ((event == RPC_PIPEFS_UMOUNT) && !clnt->cl_dentry)) | ||
175 | return 1; | ||
176 | if ((event == RPC_PIPEFS_MOUNT) && atomic_read(&clnt->cl_count) == 0) | ||
177 | return 1; | 166 | return 1; |
167 | |||
168 | switch (event) { | ||
169 | case RPC_PIPEFS_MOUNT: | ||
170 | if (clnt->cl_pipedir_objects.pdh_dentry != NULL) | ||
171 | return 1; | ||
172 | if (atomic_read(&clnt->cl_count) == 0) | ||
173 | return 1; | ||
174 | break; | ||
175 | case RPC_PIPEFS_UMOUNT: | ||
176 | if (clnt->cl_pipedir_objects.pdh_dentry == NULL) | ||
177 | return 1; | ||
178 | break; | ||
179 | } | ||
178 | return 0; | 180 | return 0; |
179 | } | 181 | } |
180 | 182 | ||
@@ -186,18 +188,11 @@ static int __rpc_clnt_handle_event(struct rpc_clnt *clnt, unsigned long event, | |||
186 | 188 | ||
187 | switch (event) { | 189 | switch (event) { |
188 | case RPC_PIPEFS_MOUNT: | 190 | case RPC_PIPEFS_MOUNT: |
189 | dentry = rpc_setup_pipedir_sb(sb, clnt, | 191 | dentry = rpc_setup_pipedir_sb(sb, clnt); |
190 | clnt->cl_program->pipe_dir_name); | ||
191 | if (!dentry) | 192 | if (!dentry) |
192 | return -ENOENT; | 193 | return -ENOENT; |
193 | if (IS_ERR(dentry)) | 194 | if (IS_ERR(dentry)) |
194 | return PTR_ERR(dentry); | 195 | return PTR_ERR(dentry); |
195 | clnt->cl_dentry = dentry; | ||
196 | if (clnt->cl_auth->au_ops->pipes_create) { | ||
197 | err = clnt->cl_auth->au_ops->pipes_create(clnt->cl_auth); | ||
198 | if (err) | ||
199 | __rpc_clnt_remove_pipedir(clnt); | ||
200 | } | ||
201 | break; | 196 | break; |
202 | case RPC_PIPEFS_UMOUNT: | 197 | case RPC_PIPEFS_UMOUNT: |
203 | __rpc_clnt_remove_pipedir(clnt); | 198 | __rpc_clnt_remove_pipedir(clnt); |
@@ -230,8 +225,6 @@ static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event) | |||
230 | 225 | ||
231 | spin_lock(&sn->rpc_client_lock); | 226 | spin_lock(&sn->rpc_client_lock); |
232 | list_for_each_entry(clnt, &sn->all_clients, cl_clients) { | 227 | list_for_each_entry(clnt, &sn->all_clients, cl_clients) { |
233 | if (clnt->cl_program->pipe_dir_name == NULL) | ||
234 | continue; | ||
235 | if (rpc_clnt_skip_event(clnt, event)) | 228 | if (rpc_clnt_skip_event(clnt, event)) |
236 | continue; | 229 | continue; |
237 | spin_unlock(&sn->rpc_client_lock); | 230 | spin_unlock(&sn->rpc_client_lock); |
@@ -282,7 +275,10 @@ static void rpc_clnt_set_nodename(struct rpc_clnt *clnt, const char *nodename) | |||
282 | static int rpc_client_register(const struct rpc_create_args *args, | 275 | static int rpc_client_register(const struct rpc_create_args *args, |
283 | struct rpc_clnt *clnt) | 276 | struct rpc_clnt *clnt) |
284 | { | 277 | { |
285 | const struct rpc_program *program = args->program; | 278 | struct rpc_auth_create_args auth_args = { |
279 | .pseudoflavor = args->authflavor, | ||
280 | .target_name = args->client_name, | ||
281 | }; | ||
286 | struct rpc_auth *auth; | 282 | struct rpc_auth *auth; |
287 | struct net *net = rpc_net_ns(clnt); | 283 | struct net *net = rpc_net_ns(clnt); |
288 | struct super_block *pipefs_sb; | 284 | struct super_block *pipefs_sb; |
@@ -290,7 +286,7 @@ static int rpc_client_register(const struct rpc_create_args *args, | |||
290 | 286 | ||
291 | pipefs_sb = rpc_get_sb_net(net); | 287 | pipefs_sb = rpc_get_sb_net(net); |
292 | if (pipefs_sb) { | 288 | if (pipefs_sb) { |
293 | err = rpc_setup_pipedir(clnt, program->pipe_dir_name, pipefs_sb); | 289 | err = rpc_setup_pipedir(pipefs_sb, clnt); |
294 | if (err) | 290 | if (err) |
295 | goto out; | 291 | goto out; |
296 | } | 292 | } |
@@ -299,7 +295,7 @@ static int rpc_client_register(const struct rpc_create_args *args, | |||
299 | if (pipefs_sb) | 295 | if (pipefs_sb) |
300 | rpc_put_sb_net(net); | 296 | rpc_put_sb_net(net); |
301 | 297 | ||
302 | auth = rpcauth_create(args->authflavor, clnt); | 298 | auth = rpcauth_create(&auth_args, clnt); |
303 | if (IS_ERR(auth)) { | 299 | if (IS_ERR(auth)) { |
304 | dprintk("RPC: Couldn't create auth handle (flavor %u)\n", | 300 | dprintk("RPC: Couldn't create auth handle (flavor %u)\n", |
305 | args->authflavor); | 301 | args->authflavor); |
@@ -317,7 +313,27 @@ out: | |||
317 | return err; | 313 | return err; |
318 | } | 314 | } |
319 | 315 | ||
320 | static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt) | 316 | static DEFINE_IDA(rpc_clids); |
317 | |||
318 | static int rpc_alloc_clid(struct rpc_clnt *clnt) | ||
319 | { | ||
320 | int clid; | ||
321 | |||
322 | clid = ida_simple_get(&rpc_clids, 0, 0, GFP_KERNEL); | ||
323 | if (clid < 0) | ||
324 | return clid; | ||
325 | clnt->cl_clid = clid; | ||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static void rpc_free_clid(struct rpc_clnt *clnt) | ||
330 | { | ||
331 | ida_simple_remove(&rpc_clids, clnt->cl_clid); | ||
332 | } | ||
333 | |||
334 | static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, | ||
335 | struct rpc_xprt *xprt, | ||
336 | struct rpc_clnt *parent) | ||
321 | { | 337 | { |
322 | const struct rpc_program *program = args->program; | 338 | const struct rpc_program *program = args->program; |
323 | const struct rpc_version *version; | 339 | const struct rpc_version *version; |
@@ -343,16 +359,20 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru | |||
343 | clnt = kzalloc(sizeof(*clnt), GFP_KERNEL); | 359 | clnt = kzalloc(sizeof(*clnt), GFP_KERNEL); |
344 | if (!clnt) | 360 | if (!clnt) |
345 | goto out_err; | 361 | goto out_err; |
346 | clnt->cl_parent = clnt; | 362 | clnt->cl_parent = parent ? : clnt; |
363 | |||
364 | err = rpc_alloc_clid(clnt); | ||
365 | if (err) | ||
366 | goto out_no_clid; | ||
347 | 367 | ||
348 | rcu_assign_pointer(clnt->cl_xprt, xprt); | 368 | rcu_assign_pointer(clnt->cl_xprt, xprt); |
349 | clnt->cl_procinfo = version->procs; | 369 | clnt->cl_procinfo = version->procs; |
350 | clnt->cl_maxproc = version->nrprocs; | 370 | clnt->cl_maxproc = version->nrprocs; |
351 | clnt->cl_protname = program->name; | ||
352 | clnt->cl_prog = args->prognumber ? : program->number; | 371 | clnt->cl_prog = args->prognumber ? : program->number; |
353 | clnt->cl_vers = version->number; | 372 | clnt->cl_vers = version->number; |
354 | clnt->cl_stats = program->stats; | 373 | clnt->cl_stats = program->stats; |
355 | clnt->cl_metrics = rpc_alloc_iostats(clnt); | 374 | clnt->cl_metrics = rpc_alloc_iostats(clnt); |
375 | rpc_init_pipe_dir_head(&clnt->cl_pipedir_objects); | ||
356 | err = -ENOMEM; | 376 | err = -ENOMEM; |
357 | if (clnt->cl_metrics == NULL) | 377 | if (clnt->cl_metrics == NULL) |
358 | goto out_no_stats; | 378 | goto out_no_stats; |
@@ -372,12 +392,6 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru | |||
372 | 392 | ||
373 | clnt->cl_rtt = &clnt->cl_rtt_default; | 393 | clnt->cl_rtt = &clnt->cl_rtt_default; |
374 | rpc_init_rtt(&clnt->cl_rtt_default, clnt->cl_timeout->to_initval); | 394 | rpc_init_rtt(&clnt->cl_rtt_default, clnt->cl_timeout->to_initval); |
375 | clnt->cl_principal = NULL; | ||
376 | if (args->client_name) { | ||
377 | clnt->cl_principal = kstrdup(args->client_name, GFP_KERNEL); | ||
378 | if (!clnt->cl_principal) | ||
379 | goto out_no_principal; | ||
380 | } | ||
381 | 395 | ||
382 | atomic_set(&clnt->cl_count, 1); | 396 | atomic_set(&clnt->cl_count, 1); |
383 | 397 | ||
@@ -387,13 +401,15 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru | |||
387 | err = rpc_client_register(args, clnt); | 401 | err = rpc_client_register(args, clnt); |
388 | if (err) | 402 | if (err) |
389 | goto out_no_path; | 403 | goto out_no_path; |
404 | if (parent) | ||
405 | atomic_inc(&parent->cl_count); | ||
390 | return clnt; | 406 | return clnt; |
391 | 407 | ||
392 | out_no_path: | 408 | out_no_path: |
393 | kfree(clnt->cl_principal); | ||
394 | out_no_principal: | ||
395 | rpc_free_iostats(clnt->cl_metrics); | 409 | rpc_free_iostats(clnt->cl_metrics); |
396 | out_no_stats: | 410 | out_no_stats: |
411 | rpc_free_clid(clnt); | ||
412 | out_no_clid: | ||
397 | kfree(clnt); | 413 | kfree(clnt); |
398 | out_err: | 414 | out_err: |
399 | rpciod_down(); | 415 | rpciod_down(); |
@@ -479,7 +495,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) | |||
479 | if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT) | 495 | if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT) |
480 | xprt->resvport = 0; | 496 | xprt->resvport = 0; |
481 | 497 | ||
482 | clnt = rpc_new_client(args, xprt); | 498 | clnt = rpc_new_client(args, xprt, NULL); |
483 | if (IS_ERR(clnt)) | 499 | if (IS_ERR(clnt)) |
484 | return clnt; | 500 | return clnt; |
485 | 501 | ||
@@ -526,15 +542,12 @@ static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args, | |||
526 | goto out_err; | 542 | goto out_err; |
527 | args->servername = xprt->servername; | 543 | args->servername = xprt->servername; |
528 | 544 | ||
529 | new = rpc_new_client(args, xprt); | 545 | new = rpc_new_client(args, xprt, clnt); |
530 | if (IS_ERR(new)) { | 546 | if (IS_ERR(new)) { |
531 | err = PTR_ERR(new); | 547 | err = PTR_ERR(new); |
532 | goto out_err; | 548 | goto out_err; |
533 | } | 549 | } |
534 | 550 | ||
535 | atomic_inc(&clnt->cl_count); | ||
536 | new->cl_parent = clnt; | ||
537 | |||
538 | /* Turn off autobind on clones */ | 551 | /* Turn off autobind on clones */ |
539 | new->cl_autobind = 0; | 552 | new->cl_autobind = 0; |
540 | new->cl_softrtry = clnt->cl_softrtry; | 553 | new->cl_softrtry = clnt->cl_softrtry; |
@@ -561,7 +574,6 @@ struct rpc_clnt *rpc_clone_client(struct rpc_clnt *clnt) | |||
561 | .prognumber = clnt->cl_prog, | 574 | .prognumber = clnt->cl_prog, |
562 | .version = clnt->cl_vers, | 575 | .version = clnt->cl_vers, |
563 | .authflavor = clnt->cl_auth->au_flavor, | 576 | .authflavor = clnt->cl_auth->au_flavor, |
564 | .client_name = clnt->cl_principal, | ||
565 | }; | 577 | }; |
566 | return __rpc_clone_client(&args, clnt); | 578 | return __rpc_clone_client(&args, clnt); |
567 | } | 579 | } |
@@ -583,7 +595,6 @@ rpc_clone_client_set_auth(struct rpc_clnt *clnt, rpc_authflavor_t flavor) | |||
583 | .prognumber = clnt->cl_prog, | 595 | .prognumber = clnt->cl_prog, |
584 | .version = clnt->cl_vers, | 596 | .version = clnt->cl_vers, |
585 | .authflavor = flavor, | 597 | .authflavor = flavor, |
586 | .client_name = clnt->cl_principal, | ||
587 | }; | 598 | }; |
588 | return __rpc_clone_client(&args, clnt); | 599 | return __rpc_clone_client(&args, clnt); |
589 | } | 600 | } |
@@ -629,7 +640,7 @@ void rpc_shutdown_client(struct rpc_clnt *clnt) | |||
629 | might_sleep(); | 640 | might_sleep(); |
630 | 641 | ||
631 | dprintk_rcu("RPC: shutting down %s client for %s\n", | 642 | dprintk_rcu("RPC: shutting down %s client for %s\n", |
632 | clnt->cl_protname, | 643 | clnt->cl_program->name, |
633 | rcu_dereference(clnt->cl_xprt)->servername); | 644 | rcu_dereference(clnt->cl_xprt)->servername); |
634 | 645 | ||
635 | while (!list_empty(&clnt->cl_tasks)) { | 646 | while (!list_empty(&clnt->cl_tasks)) { |
@@ -649,17 +660,17 @@ static void | |||
649 | rpc_free_client(struct rpc_clnt *clnt) | 660 | rpc_free_client(struct rpc_clnt *clnt) |
650 | { | 661 | { |
651 | dprintk_rcu("RPC: destroying %s client for %s\n", | 662 | dprintk_rcu("RPC: destroying %s client for %s\n", |
652 | clnt->cl_protname, | 663 | clnt->cl_program->name, |
653 | rcu_dereference(clnt->cl_xprt)->servername); | 664 | rcu_dereference(clnt->cl_xprt)->servername); |
654 | if (clnt->cl_parent != clnt) | 665 | if (clnt->cl_parent != clnt) |
655 | rpc_release_client(clnt->cl_parent); | 666 | rpc_release_client(clnt->cl_parent); |
656 | rpc_clnt_remove_pipedir(clnt); | 667 | rpc_clnt_remove_pipedir(clnt); |
657 | rpc_unregister_client(clnt); | 668 | rpc_unregister_client(clnt); |
658 | rpc_free_iostats(clnt->cl_metrics); | 669 | rpc_free_iostats(clnt->cl_metrics); |
659 | kfree(clnt->cl_principal); | ||
660 | clnt->cl_metrics = NULL; | 670 | clnt->cl_metrics = NULL; |
661 | xprt_put(rcu_dereference_raw(clnt->cl_xprt)); | 671 | xprt_put(rcu_dereference_raw(clnt->cl_xprt)); |
662 | rpciod_down(); | 672 | rpciod_down(); |
673 | rpc_free_clid(clnt); | ||
663 | kfree(clnt); | 674 | kfree(clnt); |
664 | } | 675 | } |
665 | 676 | ||
@@ -720,7 +731,6 @@ struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old, | |||
720 | .prognumber = program->number, | 731 | .prognumber = program->number, |
721 | .version = vers, | 732 | .version = vers, |
722 | .authflavor = old->cl_auth->au_flavor, | 733 | .authflavor = old->cl_auth->au_flavor, |
723 | .client_name = old->cl_principal, | ||
724 | }; | 734 | }; |
725 | struct rpc_clnt *clnt; | 735 | struct rpc_clnt *clnt; |
726 | int err; | 736 | int err; |
@@ -1299,7 +1309,7 @@ call_start(struct rpc_task *task) | |||
1299 | struct rpc_clnt *clnt = task->tk_client; | 1309 | struct rpc_clnt *clnt = task->tk_client; |
1300 | 1310 | ||
1301 | dprintk("RPC: %5u call_start %s%d proc %s (%s)\n", task->tk_pid, | 1311 | dprintk("RPC: %5u call_start %s%d proc %s (%s)\n", task->tk_pid, |
1302 | clnt->cl_protname, clnt->cl_vers, | 1312 | clnt->cl_program->name, clnt->cl_vers, |
1303 | rpc_proc_name(task), | 1313 | rpc_proc_name(task), |
1304 | (RPC_IS_ASYNC(task) ? "async" : "sync")); | 1314 | (RPC_IS_ASYNC(task) ? "async" : "sync")); |
1305 | 1315 | ||
@@ -1423,9 +1433,9 @@ call_refreshresult(struct rpc_task *task) | |||
1423 | return; | 1433 | return; |
1424 | case -ETIMEDOUT: | 1434 | case -ETIMEDOUT: |
1425 | rpc_delay(task, 3*HZ); | 1435 | rpc_delay(task, 3*HZ); |
1426 | case -EKEYEXPIRED: | ||
1427 | case -EAGAIN: | 1436 | case -EAGAIN: |
1428 | status = -EACCES; | 1437 | status = -EACCES; |
1438 | case -EKEYEXPIRED: | ||
1429 | if (!task->tk_cred_retry) | 1439 | if (!task->tk_cred_retry) |
1430 | break; | 1440 | break; |
1431 | task->tk_cred_retry--; | 1441 | task->tk_cred_retry--; |
@@ -1912,7 +1922,7 @@ call_status(struct rpc_task *task) | |||
1912 | default: | 1922 | default: |
1913 | if (clnt->cl_chatty) | 1923 | if (clnt->cl_chatty) |
1914 | printk("%s: RPC call returned error %d\n", | 1924 | printk("%s: RPC call returned error %d\n", |
1915 | clnt->cl_protname, -status); | 1925 | clnt->cl_program->name, -status); |
1916 | rpc_exit(task, status); | 1926 | rpc_exit(task, status); |
1917 | } | 1927 | } |
1918 | } | 1928 | } |
@@ -1943,7 +1953,7 @@ call_timeout(struct rpc_task *task) | |||
1943 | if (clnt->cl_chatty) { | 1953 | if (clnt->cl_chatty) { |
1944 | rcu_read_lock(); | 1954 | rcu_read_lock(); |
1945 | printk(KERN_NOTICE "%s: server %s not responding, timed out\n", | 1955 | printk(KERN_NOTICE "%s: server %s not responding, timed out\n", |
1946 | clnt->cl_protname, | 1956 | clnt->cl_program->name, |
1947 | rcu_dereference(clnt->cl_xprt)->servername); | 1957 | rcu_dereference(clnt->cl_xprt)->servername); |
1948 | rcu_read_unlock(); | 1958 | rcu_read_unlock(); |
1949 | } | 1959 | } |
@@ -1959,7 +1969,7 @@ call_timeout(struct rpc_task *task) | |||
1959 | if (clnt->cl_chatty) { | 1969 | if (clnt->cl_chatty) { |
1960 | rcu_read_lock(); | 1970 | rcu_read_lock(); |
1961 | printk(KERN_NOTICE "%s: server %s not responding, still trying\n", | 1971 | printk(KERN_NOTICE "%s: server %s not responding, still trying\n", |
1962 | clnt->cl_protname, | 1972 | clnt->cl_program->name, |
1963 | rcu_dereference(clnt->cl_xprt)->servername); | 1973 | rcu_dereference(clnt->cl_xprt)->servername); |
1964 | rcu_read_unlock(); | 1974 | rcu_read_unlock(); |
1965 | } | 1975 | } |
@@ -1994,7 +2004,7 @@ call_decode(struct rpc_task *task) | |||
1994 | if (clnt->cl_chatty) { | 2004 | if (clnt->cl_chatty) { |
1995 | rcu_read_lock(); | 2005 | rcu_read_lock(); |
1996 | printk(KERN_NOTICE "%s: server %s OK\n", | 2006 | printk(KERN_NOTICE "%s: server %s OK\n", |
1997 | clnt->cl_protname, | 2007 | clnt->cl_program->name, |
1998 | rcu_dereference(clnt->cl_xprt)->servername); | 2008 | rcu_dereference(clnt->cl_xprt)->servername); |
1999 | rcu_read_unlock(); | 2009 | rcu_read_unlock(); |
2000 | } | 2010 | } |
@@ -2019,7 +2029,7 @@ call_decode(struct rpc_task *task) | |||
2019 | goto out_retry; | 2029 | goto out_retry; |
2020 | } | 2030 | } |
2021 | dprintk("RPC: %s: too small RPC reply size (%d bytes)\n", | 2031 | dprintk("RPC: %s: too small RPC reply size (%d bytes)\n", |
2022 | clnt->cl_protname, task->tk_status); | 2032 | clnt->cl_program->name, task->tk_status); |
2023 | task->tk_action = call_timeout; | 2033 | task->tk_action = call_timeout; |
2024 | goto out_retry; | 2034 | goto out_retry; |
2025 | } | 2035 | } |
@@ -2091,7 +2101,8 @@ rpc_verify_header(struct rpc_task *task) | |||
2091 | dprintk("RPC: %5u %s: XDR representation not a multiple of" | 2101 | dprintk("RPC: %5u %s: XDR representation not a multiple of" |
2092 | " 4 bytes: 0x%x\n", task->tk_pid, __func__, | 2102 | " 4 bytes: 0x%x\n", task->tk_pid, __func__, |
2093 | task->tk_rqstp->rq_rcv_buf.len); | 2103 | task->tk_rqstp->rq_rcv_buf.len); |
2094 | goto out_eio; | 2104 | error = -EIO; |
2105 | goto out_err; | ||
2095 | } | 2106 | } |
2096 | if ((len -= 3) < 0) | 2107 | if ((len -= 3) < 0) |
2097 | goto out_overflow; | 2108 | goto out_overflow; |
@@ -2100,6 +2111,7 @@ rpc_verify_header(struct rpc_task *task) | |||
2100 | if ((n = ntohl(*p++)) != RPC_REPLY) { | 2111 | if ((n = ntohl(*p++)) != RPC_REPLY) { |
2101 | dprintk("RPC: %5u %s: not an RPC reply: %x\n", | 2112 | dprintk("RPC: %5u %s: not an RPC reply: %x\n", |
2102 | task->tk_pid, __func__, n); | 2113 | task->tk_pid, __func__, n); |
2114 | error = -EIO; | ||
2103 | goto out_garbage; | 2115 | goto out_garbage; |
2104 | } | 2116 | } |
2105 | 2117 | ||
@@ -2118,7 +2130,8 @@ rpc_verify_header(struct rpc_task *task) | |||
2118 | dprintk("RPC: %5u %s: RPC call rejected, " | 2130 | dprintk("RPC: %5u %s: RPC call rejected, " |
2119 | "unknown error: %x\n", | 2131 | "unknown error: %x\n", |
2120 | task->tk_pid, __func__, n); | 2132 | task->tk_pid, __func__, n); |
2121 | goto out_eio; | 2133 | error = -EIO; |
2134 | goto out_err; | ||
2122 | } | 2135 | } |
2123 | if (--len < 0) | 2136 | if (--len < 0) |
2124 | goto out_overflow; | 2137 | goto out_overflow; |
@@ -2163,9 +2176,11 @@ rpc_verify_header(struct rpc_task *task) | |||
2163 | task->tk_pid, __func__, n); | 2176 | task->tk_pid, __func__, n); |
2164 | goto out_err; | 2177 | goto out_err; |
2165 | } | 2178 | } |
2166 | if (!(p = rpcauth_checkverf(task, p))) { | 2179 | p = rpcauth_checkverf(task, p); |
2167 | dprintk("RPC: %5u %s: auth check failed\n", | 2180 | if (IS_ERR(p)) { |
2168 | task->tk_pid, __func__); | 2181 | error = PTR_ERR(p); |
2182 | dprintk("RPC: %5u %s: auth check failed with %d\n", | ||
2183 | task->tk_pid, __func__, error); | ||
2169 | goto out_garbage; /* bad verifier, retry */ | 2184 | goto out_garbage; /* bad verifier, retry */ |
2170 | } | 2185 | } |
2171 | len = p - (__be32 *)iov->iov_base - 1; | 2186 | len = p - (__be32 *)iov->iov_base - 1; |
@@ -2218,8 +2233,6 @@ out_garbage: | |||
2218 | out_retry: | 2233 | out_retry: |
2219 | return ERR_PTR(-EAGAIN); | 2234 | return ERR_PTR(-EAGAIN); |
2220 | } | 2235 | } |
2221 | out_eio: | ||
2222 | error = -EIO; | ||
2223 | out_err: | 2236 | out_err: |
2224 | rpc_exit(task, error); | 2237 | rpc_exit(task, error); |
2225 | dprintk("RPC: %5u %s: call failed with error %d\n", task->tk_pid, | 2238 | dprintk("RPC: %5u %s: call failed with error %d\n", task->tk_pid, |
@@ -2291,7 +2304,7 @@ static void rpc_show_task(const struct rpc_clnt *clnt, | |||
2291 | printk(KERN_INFO "%5u %04x %6d %8p %8p %8ld %8p %sv%u %s a:%ps q:%s\n", | 2304 | printk(KERN_INFO "%5u %04x %6d %8p %8p %8ld %8p %sv%u %s a:%ps q:%s\n", |
2292 | task->tk_pid, task->tk_flags, task->tk_status, | 2305 | task->tk_pid, task->tk_flags, task->tk_status, |
2293 | clnt, task->tk_rqstp, task->tk_timeout, task->tk_ops, | 2306 | clnt, task->tk_rqstp, task->tk_timeout, task->tk_ops, |
2294 | clnt->cl_protname, clnt->cl_vers, rpc_proc_name(task), | 2307 | clnt->cl_program->name, clnt->cl_vers, rpc_proc_name(task), |
2295 | task->tk_action, rpc_waitq); | 2308 | task->tk_action, rpc_waitq); |
2296 | } | 2309 | } |
2297 | 2310 | ||
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 406859cc68aa..f94567b45bb3 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
@@ -409,7 +409,7 @@ rpc_show_info(struct seq_file *m, void *v) | |||
409 | rcu_read_lock(); | 409 | rcu_read_lock(); |
410 | seq_printf(m, "RPC server: %s\n", | 410 | seq_printf(m, "RPC server: %s\n", |
411 | rcu_dereference(clnt->cl_xprt)->servername); | 411 | rcu_dereference(clnt->cl_xprt)->servername); |
412 | seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname, | 412 | seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_program->name, |
413 | clnt->cl_prog, clnt->cl_vers); | 413 | clnt->cl_prog, clnt->cl_vers); |
414 | seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR)); | 414 | seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR)); |
415 | seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO)); | 415 | seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO)); |
@@ -480,23 +480,6 @@ static const struct dentry_operations rpc_dentry_operations = { | |||
480 | .d_delete = rpc_delete_dentry, | 480 | .d_delete = rpc_delete_dentry, |
481 | }; | 481 | }; |
482 | 482 | ||
483 | /* | ||
484 | * Lookup the data. This is trivial - if the dentry didn't already | ||
485 | * exist, we know it is negative. | ||
486 | */ | ||
487 | static struct dentry * | ||
488 | rpc_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) | ||
489 | { | ||
490 | if (dentry->d_name.len > NAME_MAX) | ||
491 | return ERR_PTR(-ENAMETOOLONG); | ||
492 | d_add(dentry, NULL); | ||
493 | return NULL; | ||
494 | } | ||
495 | |||
496 | static const struct inode_operations rpc_dir_inode_operations = { | ||
497 | .lookup = rpc_lookup, | ||
498 | }; | ||
499 | |||
500 | static struct inode * | 483 | static struct inode * |
501 | rpc_get_inode(struct super_block *sb, umode_t mode) | 484 | rpc_get_inode(struct super_block *sb, umode_t mode) |
502 | { | 485 | { |
@@ -509,7 +492,7 @@ rpc_get_inode(struct super_block *sb, umode_t mode) | |||
509 | switch (mode & S_IFMT) { | 492 | switch (mode & S_IFMT) { |
510 | case S_IFDIR: | 493 | case S_IFDIR: |
511 | inode->i_fop = &simple_dir_operations; | 494 | inode->i_fop = &simple_dir_operations; |
512 | inode->i_op = &rpc_dir_inode_operations; | 495 | inode->i_op = &simple_dir_inode_operations; |
513 | inc_nlink(inode); | 496 | inc_nlink(inode); |
514 | default: | 497 | default: |
515 | break; | 498 | break; |
@@ -901,6 +884,159 @@ rpc_unlink(struct dentry *dentry) | |||
901 | } | 884 | } |
902 | EXPORT_SYMBOL_GPL(rpc_unlink); | 885 | EXPORT_SYMBOL_GPL(rpc_unlink); |
903 | 886 | ||
887 | /** | ||
888 | * rpc_init_pipe_dir_head - initialise a struct rpc_pipe_dir_head | ||
889 | * @pdh: pointer to struct rpc_pipe_dir_head | ||
890 | */ | ||
891 | void rpc_init_pipe_dir_head(struct rpc_pipe_dir_head *pdh) | ||
892 | { | ||
893 | INIT_LIST_HEAD(&pdh->pdh_entries); | ||
894 | pdh->pdh_dentry = NULL; | ||
895 | } | ||
896 | EXPORT_SYMBOL_GPL(rpc_init_pipe_dir_head); | ||
897 | |||
898 | /** | ||
899 | * rpc_init_pipe_dir_object - initialise a struct rpc_pipe_dir_object | ||
900 | * @pdo: pointer to struct rpc_pipe_dir_object | ||
901 | * @pdo_ops: pointer to const struct rpc_pipe_dir_object_ops | ||
902 | * @pdo_data: pointer to caller-defined data | ||
903 | */ | ||
904 | void rpc_init_pipe_dir_object(struct rpc_pipe_dir_object *pdo, | ||
905 | const struct rpc_pipe_dir_object_ops *pdo_ops, | ||
906 | void *pdo_data) | ||
907 | { | ||
908 | INIT_LIST_HEAD(&pdo->pdo_head); | ||
909 | pdo->pdo_ops = pdo_ops; | ||
910 | pdo->pdo_data = pdo_data; | ||
911 | } | ||
912 | EXPORT_SYMBOL_GPL(rpc_init_pipe_dir_object); | ||
913 | |||
914 | static int | ||
915 | rpc_add_pipe_dir_object_locked(struct net *net, | ||
916 | struct rpc_pipe_dir_head *pdh, | ||
917 | struct rpc_pipe_dir_object *pdo) | ||
918 | { | ||
919 | int ret = 0; | ||
920 | |||
921 | if (pdh->pdh_dentry) | ||
922 | ret = pdo->pdo_ops->create(pdh->pdh_dentry, pdo); | ||
923 | if (ret == 0) | ||
924 | list_add_tail(&pdo->pdo_head, &pdh->pdh_entries); | ||
925 | return ret; | ||
926 | } | ||
927 | |||
928 | static void | ||
929 | rpc_remove_pipe_dir_object_locked(struct net *net, | ||
930 | struct rpc_pipe_dir_head *pdh, | ||
931 | struct rpc_pipe_dir_object *pdo) | ||
932 | { | ||
933 | if (pdh->pdh_dentry) | ||
934 | pdo->pdo_ops->destroy(pdh->pdh_dentry, pdo); | ||
935 | list_del_init(&pdo->pdo_head); | ||
936 | } | ||
937 | |||
938 | /** | ||
939 | * rpc_add_pipe_dir_object - associate a rpc_pipe_dir_object to a directory | ||
940 | * @net: pointer to struct net | ||
941 | * @pdh: pointer to struct rpc_pipe_dir_head | ||
942 | * @pdo: pointer to struct rpc_pipe_dir_object | ||
943 | * | ||
944 | */ | ||
945 | int | ||
946 | rpc_add_pipe_dir_object(struct net *net, | ||
947 | struct rpc_pipe_dir_head *pdh, | ||
948 | struct rpc_pipe_dir_object *pdo) | ||
949 | { | ||
950 | int ret = 0; | ||
951 | |||
952 | if (list_empty(&pdo->pdo_head)) { | ||
953 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
954 | |||
955 | mutex_lock(&sn->pipefs_sb_lock); | ||
956 | ret = rpc_add_pipe_dir_object_locked(net, pdh, pdo); | ||
957 | mutex_unlock(&sn->pipefs_sb_lock); | ||
958 | } | ||
959 | return ret; | ||
960 | } | ||
961 | EXPORT_SYMBOL_GPL(rpc_add_pipe_dir_object); | ||
962 | |||
963 | /** | ||
964 | * rpc_remove_pipe_dir_object - remove a rpc_pipe_dir_object from a directory | ||
965 | * @net: pointer to struct net | ||
966 | * @pdh: pointer to struct rpc_pipe_dir_head | ||
967 | * @pdo: pointer to struct rpc_pipe_dir_object | ||
968 | * | ||
969 | */ | ||
970 | void | ||
971 | rpc_remove_pipe_dir_object(struct net *net, | ||
972 | struct rpc_pipe_dir_head *pdh, | ||
973 | struct rpc_pipe_dir_object *pdo) | ||
974 | { | ||
975 | if (!list_empty(&pdo->pdo_head)) { | ||
976 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
977 | |||
978 | mutex_lock(&sn->pipefs_sb_lock); | ||
979 | rpc_remove_pipe_dir_object_locked(net, pdh, pdo); | ||
980 | mutex_unlock(&sn->pipefs_sb_lock); | ||
981 | } | ||
982 | } | ||
983 | EXPORT_SYMBOL_GPL(rpc_remove_pipe_dir_object); | ||
984 | |||
985 | /** | ||
986 | * rpc_find_or_alloc_pipe_dir_object | ||
987 | * @net: pointer to struct net | ||
988 | * @pdh: pointer to struct rpc_pipe_dir_head | ||
989 | * @match: match struct rpc_pipe_dir_object to data | ||
990 | * @alloc: allocate a new struct rpc_pipe_dir_object | ||
991 | * @data: user defined data for match() and alloc() | ||
992 | * | ||
993 | */ | ||
994 | struct rpc_pipe_dir_object * | ||
995 | rpc_find_or_alloc_pipe_dir_object(struct net *net, | ||
996 | struct rpc_pipe_dir_head *pdh, | ||
997 | int (*match)(struct rpc_pipe_dir_object *, void *), | ||
998 | struct rpc_pipe_dir_object *(*alloc)(void *), | ||
999 | void *data) | ||
1000 | { | ||
1001 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
1002 | struct rpc_pipe_dir_object *pdo; | ||
1003 | |||
1004 | mutex_lock(&sn->pipefs_sb_lock); | ||
1005 | list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head) { | ||
1006 | if (!match(pdo, data)) | ||
1007 | continue; | ||
1008 | goto out; | ||
1009 | } | ||
1010 | pdo = alloc(data); | ||
1011 | if (!pdo) | ||
1012 | goto out; | ||
1013 | rpc_add_pipe_dir_object_locked(net, pdh, pdo); | ||
1014 | out: | ||
1015 | mutex_unlock(&sn->pipefs_sb_lock); | ||
1016 | return pdo; | ||
1017 | } | ||
1018 | EXPORT_SYMBOL_GPL(rpc_find_or_alloc_pipe_dir_object); | ||
1019 | |||
1020 | static void | ||
1021 | rpc_create_pipe_dir_objects(struct rpc_pipe_dir_head *pdh) | ||
1022 | { | ||
1023 | struct rpc_pipe_dir_object *pdo; | ||
1024 | struct dentry *dir = pdh->pdh_dentry; | ||
1025 | |||
1026 | list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head) | ||
1027 | pdo->pdo_ops->create(dir, pdo); | ||
1028 | } | ||
1029 | |||
1030 | static void | ||
1031 | rpc_destroy_pipe_dir_objects(struct rpc_pipe_dir_head *pdh) | ||
1032 | { | ||
1033 | struct rpc_pipe_dir_object *pdo; | ||
1034 | struct dentry *dir = pdh->pdh_dentry; | ||
1035 | |||
1036 | list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head) | ||
1037 | pdo->pdo_ops->destroy(dir, pdo); | ||
1038 | } | ||
1039 | |||
904 | enum { | 1040 | enum { |
905 | RPCAUTH_info, | 1041 | RPCAUTH_info, |
906 | RPCAUTH_EOF | 1042 | RPCAUTH_EOF |
@@ -941,16 +1077,29 @@ struct dentry *rpc_create_client_dir(struct dentry *dentry, | |||
941 | const char *name, | 1077 | const char *name, |
942 | struct rpc_clnt *rpc_client) | 1078 | struct rpc_clnt *rpc_client) |
943 | { | 1079 | { |
944 | return rpc_mkdir_populate(dentry, name, S_IRUGO | S_IXUGO, NULL, | 1080 | struct dentry *ret; |
1081 | |||
1082 | ret = rpc_mkdir_populate(dentry, name, S_IRUGO | S_IXUGO, NULL, | ||
945 | rpc_clntdir_populate, rpc_client); | 1083 | rpc_clntdir_populate, rpc_client); |
1084 | if (!IS_ERR(ret)) { | ||
1085 | rpc_client->cl_pipedir_objects.pdh_dentry = ret; | ||
1086 | rpc_create_pipe_dir_objects(&rpc_client->cl_pipedir_objects); | ||
1087 | } | ||
1088 | return ret; | ||
946 | } | 1089 | } |
947 | 1090 | ||
948 | /** | 1091 | /** |
949 | * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir() | 1092 | * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir() |
950 | * @dentry: dentry for the pipe | 1093 | * @rpc_client: rpc_client for the pipe |
951 | */ | 1094 | */ |
952 | int rpc_remove_client_dir(struct dentry *dentry) | 1095 | int rpc_remove_client_dir(struct rpc_clnt *rpc_client) |
953 | { | 1096 | { |
1097 | struct dentry *dentry = rpc_client->cl_pipedir_objects.pdh_dentry; | ||
1098 | |||
1099 | if (dentry == NULL) | ||
1100 | return 0; | ||
1101 | rpc_destroy_pipe_dir_objects(&rpc_client->cl_pipedir_objects); | ||
1102 | rpc_client->cl_pipedir_objects.pdh_dentry = NULL; | ||
954 | return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate); | 1103 | return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate); |
955 | } | 1104 | } |
956 | 1105 | ||
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 93a7a4e94d80..ff3cc4bf4b24 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
@@ -258,7 +258,7 @@ static int rpc_wait_bit_killable(void *word) | |||
258 | return 0; | 258 | return 0; |
259 | } | 259 | } |
260 | 260 | ||
261 | #ifdef RPC_DEBUG | 261 | #if defined(RPC_DEBUG) || defined(RPC_TRACEPOINTS) |
262 | static void rpc_task_set_debuginfo(struct rpc_task *task) | 262 | static void rpc_task_set_debuginfo(struct rpc_task *task) |
263 | { | 263 | { |
264 | static atomic_t rpc_pid; | 264 | static atomic_t rpc_pid; |
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index 21b75cb08c03..54530490944e 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c | |||
@@ -188,7 +188,7 @@ void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) | |||
188 | 188 | ||
189 | seq_printf(seq, "\tRPC iostats version: %s ", RPC_IOSTATS_VERS); | 189 | seq_printf(seq, "\tRPC iostats version: %s ", RPC_IOSTATS_VERS); |
190 | seq_printf(seq, "p/v: %u/%u (%s)\n", | 190 | seq_printf(seq, "p/v: %u/%u (%s)\n", |
191 | clnt->cl_prog, clnt->cl_vers, clnt->cl_protname); | 191 | clnt->cl_prog, clnt->cl_vers, clnt->cl_program->name); |
192 | 192 | ||
193 | rcu_read_lock(); | 193 | rcu_read_lock(); |
194 | xprt = rcu_dereference(clnt->cl_xprt); | 194 | xprt = rcu_dereference(clnt->cl_xprt); |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index d6656d7768f4..ee03d35677d9 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -47,6 +47,8 @@ | |||
47 | #include <net/udp.h> | 47 | #include <net/udp.h> |
48 | #include <net/tcp.h> | 48 | #include <net/tcp.h> |
49 | 49 | ||
50 | #include <trace/events/sunrpc.h> | ||
51 | |||
50 | #include "sunrpc.h" | 52 | #include "sunrpc.h" |
51 | 53 | ||
52 | static void xs_close(struct rpc_xprt *xprt); | 54 | static void xs_close(struct rpc_xprt *xprt); |
@@ -665,8 +667,10 @@ static void xs_tcp_shutdown(struct rpc_xprt *xprt) | |||
665 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); | 667 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); |
666 | struct socket *sock = transport->sock; | 668 | struct socket *sock = transport->sock; |
667 | 669 | ||
668 | if (sock != NULL) | 670 | if (sock != NULL) { |
669 | kernel_sock_shutdown(sock, SHUT_WR); | 671 | kernel_sock_shutdown(sock, SHUT_WR); |
672 | trace_rpc_socket_shutdown(xprt, sock); | ||
673 | } | ||
670 | } | 674 | } |
671 | 675 | ||
672 | /** | 676 | /** |
@@ -811,6 +815,7 @@ static void xs_reset_transport(struct sock_xprt *transport) | |||
811 | 815 | ||
812 | sk->sk_no_check = 0; | 816 | sk->sk_no_check = 0; |
813 | 817 | ||
818 | trace_rpc_socket_close(&transport->xprt, sock); | ||
814 | sock_release(sock); | 819 | sock_release(sock); |
815 | } | 820 | } |
816 | 821 | ||
@@ -1492,6 +1497,7 @@ static void xs_tcp_state_change(struct sock *sk) | |||
1492 | sock_flag(sk, SOCK_ZAPPED), | 1497 | sock_flag(sk, SOCK_ZAPPED), |
1493 | sk->sk_shutdown); | 1498 | sk->sk_shutdown); |
1494 | 1499 | ||
1500 | trace_rpc_socket_state_change(xprt, sk->sk_socket); | ||
1495 | switch (sk->sk_state) { | 1501 | switch (sk->sk_state) { |
1496 | case TCP_ESTABLISHED: | 1502 | case TCP_ESTABLISHED: |
1497 | spin_lock(&xprt->transport_lock); | 1503 | spin_lock(&xprt->transport_lock); |
@@ -1896,6 +1902,7 @@ static int xs_local_setup_socket(struct sock_xprt *transport) | |||
1896 | xprt, xprt->address_strings[RPC_DISPLAY_ADDR]); | 1902 | xprt, xprt->address_strings[RPC_DISPLAY_ADDR]); |
1897 | 1903 | ||
1898 | status = xs_local_finish_connecting(xprt, sock); | 1904 | status = xs_local_finish_connecting(xprt, sock); |
1905 | trace_rpc_socket_connect(xprt, sock, status); | ||
1899 | switch (status) { | 1906 | switch (status) { |
1900 | case 0: | 1907 | case 0: |
1901 | dprintk("RPC: xprt %p connected to %s\n", | 1908 | dprintk("RPC: xprt %p connected to %s\n", |
@@ -2039,6 +2046,7 @@ static void xs_udp_setup_socket(struct work_struct *work) | |||
2039 | xprt->address_strings[RPC_DISPLAY_PORT]); | 2046 | xprt->address_strings[RPC_DISPLAY_PORT]); |
2040 | 2047 | ||
2041 | xs_udp_finish_connecting(xprt, sock); | 2048 | xs_udp_finish_connecting(xprt, sock); |
2049 | trace_rpc_socket_connect(xprt, sock, 0); | ||
2042 | status = 0; | 2050 | status = 0; |
2043 | out: | 2051 | out: |
2044 | xprt_clear_connecting(xprt); | 2052 | xprt_clear_connecting(xprt); |
@@ -2064,6 +2072,8 @@ static void xs_abort_connection(struct sock_xprt *transport) | |||
2064 | memset(&any, 0, sizeof(any)); | 2072 | memset(&any, 0, sizeof(any)); |
2065 | any.sa_family = AF_UNSPEC; | 2073 | any.sa_family = AF_UNSPEC; |
2066 | result = kernel_connect(transport->sock, &any, sizeof(any), 0); | 2074 | result = kernel_connect(transport->sock, &any, sizeof(any), 0); |
2075 | trace_rpc_socket_reset_connection(&transport->xprt, | ||
2076 | transport->sock, result); | ||
2067 | if (!result) | 2077 | if (!result) |
2068 | xs_sock_reset_connection_flags(&transport->xprt); | 2078 | xs_sock_reset_connection_flags(&transport->xprt); |
2069 | dprintk("RPC: AF_UNSPEC connect return code %d\n", result); | 2079 | dprintk("RPC: AF_UNSPEC connect return code %d\n", result); |
@@ -2194,6 +2204,7 @@ static void xs_tcp_setup_socket(struct work_struct *work) | |||
2194 | xprt->address_strings[RPC_DISPLAY_PORT]); | 2204 | xprt->address_strings[RPC_DISPLAY_PORT]); |
2195 | 2205 | ||
2196 | status = xs_tcp_finish_connecting(xprt, sock); | 2206 | status = xs_tcp_finish_connecting(xprt, sock); |
2207 | trace_rpc_socket_connect(xprt, sock, status); | ||
2197 | dprintk("RPC: %p connect status %d connected %d sock state %d\n", | 2208 | dprintk("RPC: %p connect status %d connected %d sock state %d\n", |
2198 | xprt, -status, xprt_connected(xprt), | 2209 | xprt, -status, xprt_connected(xprt), |
2199 | sock->sk->sk_state); | 2210 | sock->sk->sk_state); |