aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@citi.umich.edu>2007-07-27 18:06:50 -0400
committerJ. Bruce Fields <bfields@citi.umich.edu>2007-10-09 18:31:56 -0400
commit2b47eece1fa519a81c8b802af77a8b8aa44baa10 (patch)
treeb06263ca61a05cfaca7311bcfe542a44502c817c /fs/nfsd
parentc9b6cbe56d3ac471e6cd72a59ec9e324b3417016 (diff)
knfsd: spawn kernel thread to probe callback channel
We want to allow gss on the callback channel, so people using krb5 can still get the benefits of delegations. But looking up the rpc credential can take some time in that case. And we shouldn't delay the response to setclientid_confirm while we wait. It may be inefficient, but for now the simplest solution is just to spawn a new thread as necessary for the purpose. (Thanks to Adrian Bunk for catching a missing static here.) Signed-off-by: "J. Bruce Fields" <bfields@citi.umich.edu> Cc: Adrian Bunk <bunk@kernel.org>
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/nfs4callback.c71
1 files changed, 34 insertions, 37 deletions
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 31d6633c7fe4..c17a5202ee3f 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -39,6 +39,7 @@
39#include <linux/errno.h> 39#include <linux/errno.h>
40#include <linux/delay.h> 40#include <linux/delay.h>
41#include <linux/sched.h> 41#include <linux/sched.h>
42#include <linux/kthread.h>
42#include <linux/sunrpc/xdr.h> 43#include <linux/sunrpc/xdr.h>
43#include <linux/sunrpc/svc.h> 44#include <linux/sunrpc/svc.h>
44#include <linux/sunrpc/clnt.h> 45#include <linux/sunrpc/clnt.h>
@@ -365,6 +366,35 @@ nfsd4_lookupcred(struct nfs4_client *clp, int taskflags)
365 return ret; 366 return ret;
366} 367}
367 368
369/* Reference counting, callback cleanup, etc., all look racy as heck.
370 * And why is cb_set an atomic? */
371
372static int do_probe_callback(void *data)
373{
374 struct nfs4_client *clp = data;
375 struct nfs4_callback *cb = &clp->cl_callback;
376 struct rpc_message msg = {
377 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
378 .rpc_argp = clp,
379 };
380 int status;
381
382 msg.rpc_cred = nfsd4_lookupcred(clp, 0);
383 if (IS_ERR(msg.rpc_cred))
384 goto out;
385 status = rpc_call_sync(cb->cb_client, &msg, RPC_TASK_SOFT);
386 put_rpccred(msg.rpc_cred);
387
388 if (status) {
389 rpc_shutdown_client(cb->cb_client);
390 cb->cb_client = NULL;
391 } else
392 atomic_set(&cb->cb_set, 1);
393out:
394 put_nfs4_client(clp);
395 return 0;
396}
397
368/* 398/*
369 * Set up the callback client and put a NFSPROC4_CB_NULL on the wire... 399 * Set up the callback client and put a NFSPROC4_CB_NULL on the wire...
370 */ 400 */
@@ -390,11 +420,7 @@ nfsd4_probe_callback(struct nfs4_client *clp)
390 .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */ 420 .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
391 .flags = (RPC_CLNT_CREATE_NOPING), 421 .flags = (RPC_CLNT_CREATE_NOPING),
392 }; 422 };
393 struct rpc_message msg = { 423 struct task_struct *t;
394 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
395 .rpc_argp = clp,
396 };
397 int status;
398 424
399 if (atomic_read(&cb->cb_set)) 425 if (atomic_read(&cb->cb_set))
400 return; 426 return;
@@ -426,16 +452,11 @@ nfsd4_probe_callback(struct nfs4_client *clp)
426 /* the task holds a reference to the nfs4_client struct */ 452 /* the task holds a reference to the nfs4_client struct */
427 atomic_inc(&clp->cl_count); 453 atomic_inc(&clp->cl_count);
428 454
429 msg.rpc_cred = nfsd4_lookupcred(clp,0); 455 t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe");
430 if (IS_ERR(msg.rpc_cred))
431 goto out_release_clp;
432 status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL);
433 put_rpccred(msg.rpc_cred);
434 456
435 if (status != 0) { 457 if (IS_ERR(t))
436 dprintk("NFSD: asynchronous NFSPROC4_CB_NULL failed!\n");
437 goto out_release_clp; 458 goto out_release_clp;
438 } 459
439 return; 460 return;
440 461
441out_release_clp: 462out_release_clp:
@@ -447,30 +468,6 @@ out_err:
447 (int)clp->cl_name.len, clp->cl_name.data); 468 (int)clp->cl_name.len, clp->cl_name.data);
448} 469}
449 470
450static void
451nfs4_cb_null(struct rpc_task *task, void *dummy)
452{
453 struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp;
454 struct nfs4_callback *cb = &clp->cl_callback;
455 __be32 addr = htonl(cb->cb_addr);
456
457 dprintk("NFSD: nfs4_cb_null task->tk_status %d\n", task->tk_status);
458
459 if (task->tk_status < 0) {
460 dprintk("NFSD: callback establishment to client %.*s failed\n",
461 (int)clp->cl_name.len, clp->cl_name.data);
462 goto out;
463 }
464 atomic_set(&cb->cb_set, 1);
465 dprintk("NFSD: callback set to client %u.%u.%u.%u\n", NIPQUAD(addr));
466out:
467 put_nfs4_client(clp);
468}
469
470static const struct rpc_call_ops nfs4_cb_null_ops = {
471 .rpc_call_done = nfs4_cb_null,
472};
473
474/* 471/*
475 * called with dp->dl_count inc'ed. 472 * called with dp->dl_count inc'ed.
476 * nfs4_lock_state() may or may not have been called. 473 * nfs4_lock_state() may or may not have been called.