aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4callback.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfs4callback.c')
-rw-r--r--fs/nfsd/nfs4callback.c247
1 files changed, 155 insertions, 92 deletions
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 290289bd44f7..3fd23f7aceca 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -140,8 +140,10 @@ struct nfs4_cb_compound_hdr {
140 int status; 140 int status;
141 u32 ident; 141 u32 ident;
142 u32 nops; 142 u32 nops;
143 __be32 *nops_p;
144 u32 minorversion;
143 u32 taglen; 145 u32 taglen;
144 char * tag; 146 char *tag;
145}; 147};
146 148
147static struct { 149static struct {
@@ -201,33 +203,39 @@ nfs_cb_stat_to_errno(int stat)
201 * XDR encode 203 * XDR encode
202 */ 204 */
203 205
204static int 206static void
205encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) 207encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr)
206{ 208{
207 __be32 * p; 209 __be32 * p;
208 210
209 RESERVE_SPACE(16); 211 RESERVE_SPACE(16);
210 WRITE32(0); /* tag length is always 0 */ 212 WRITE32(0); /* tag length is always 0 */
211 WRITE32(NFS4_MINOR_VERSION); 213 WRITE32(hdr->minorversion);
212 WRITE32(hdr->ident); 214 WRITE32(hdr->ident);
215 hdr->nops_p = p;
213 WRITE32(hdr->nops); 216 WRITE32(hdr->nops);
214 return 0;
215} 217}
216 218
217static int 219static void encode_cb_nops(struct nfs4_cb_compound_hdr *hdr)
218encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec) 220{
221 *hdr->nops_p = htonl(hdr->nops);
222}
223
224static void
225encode_cb_recall(struct xdr_stream *xdr, struct nfs4_delegation *dp,
226 struct nfs4_cb_compound_hdr *hdr)
219{ 227{
220 __be32 *p; 228 __be32 *p;
221 int len = cb_rec->cbr_fh.fh_size; 229 int len = dp->dl_fh.fh_size;
222 230
223 RESERVE_SPACE(12+sizeof(cb_rec->cbr_stateid) + len); 231 RESERVE_SPACE(12+sizeof(dp->dl_stateid) + len);
224 WRITE32(OP_CB_RECALL); 232 WRITE32(OP_CB_RECALL);
225 WRITE32(cb_rec->cbr_stateid.si_generation); 233 WRITE32(dp->dl_stateid.si_generation);
226 WRITEMEM(&cb_rec->cbr_stateid.si_opaque, sizeof(stateid_opaque_t)); 234 WRITEMEM(&dp->dl_stateid.si_opaque, sizeof(stateid_opaque_t));
227 WRITE32(cb_rec->cbr_trunc); 235 WRITE32(0); /* truncate optimization not implemented */
228 WRITE32(len); 236 WRITE32(len);
229 WRITEMEM(&cb_rec->cbr_fh.fh_base, len); 237 WRITEMEM(&dp->dl_fh.fh_base, len);
230 return 0; 238 hdr->nops++;
231} 239}
232 240
233static int 241static int
@@ -241,17 +249,18 @@ nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p)
241} 249}
242 250
243static int 251static int
244nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_cb_recall *args) 252nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_delegation *args)
245{ 253{
246 struct xdr_stream xdr; 254 struct xdr_stream xdr;
247 struct nfs4_cb_compound_hdr hdr = { 255 struct nfs4_cb_compound_hdr hdr = {
248 .ident = args->cbr_ident, 256 .ident = args->dl_ident,
249 .nops = 1,
250 }; 257 };
251 258
252 xdr_init_encode(&xdr, &req->rq_snd_buf, p); 259 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
253 encode_cb_compound_hdr(&xdr, &hdr); 260 encode_cb_compound_hdr(&xdr, &hdr);
254 return (encode_cb_recall(&xdr, args)); 261 encode_cb_recall(&xdr, args, &hdr);
262 encode_cb_nops(&hdr);
263 return 0;
255} 264}
256 265
257 266
@@ -358,18 +367,21 @@ static struct rpc_program cb_program = {
358 .pipe_dir_name = "/nfsd4_cb", 367 .pipe_dir_name = "/nfsd4_cb",
359}; 368};
360 369
370static int max_cb_time(void)
371{
372 return max(NFSD_LEASE_TIME/10, (time_t)1) * HZ;
373}
374
361/* Reference counting, callback cleanup, etc., all look racy as heck. 375/* Reference counting, callback cleanup, etc., all look racy as heck.
362 * And why is cb_set an atomic? */ 376 * And why is cb_set an atomic? */
363 377
364static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp) 378int setup_callback_client(struct nfs4_client *clp)
365{ 379{
366 struct sockaddr_in addr; 380 struct sockaddr_in addr;
367 struct nfs4_callback *cb = &clp->cl_callback; 381 struct nfs4_cb_conn *cb = &clp->cl_cb_conn;
368 struct rpc_timeout timeparms = { 382 struct rpc_timeout timeparms = {
369 .to_initval = (NFSD_LEASE_TIME/4) * HZ, 383 .to_initval = max_cb_time(),
370 .to_retries = 5, 384 .to_retries = 0,
371 .to_maxval = (NFSD_LEASE_TIME/2) * HZ,
372 .to_exponential = 1,
373 }; 385 };
374 struct rpc_create_args args = { 386 struct rpc_create_args args = {
375 .protocol = IPPROTO_TCP, 387 .protocol = IPPROTO_TCP,
@@ -386,7 +398,7 @@ static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp)
386 struct rpc_clnt *client; 398 struct rpc_clnt *client;
387 399
388 if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) 400 if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5))
389 return ERR_PTR(-EINVAL); 401 return -EINVAL;
390 402
391 /* Initialize address */ 403 /* Initialize address */
392 memset(&addr, 0, sizeof(addr)); 404 memset(&addr, 0, sizeof(addr));
@@ -396,48 +408,77 @@ static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp)
396 408
397 /* Create RPC client */ 409 /* Create RPC client */
398 client = rpc_create(&args); 410 client = rpc_create(&args);
399 if (IS_ERR(client)) 411 if (IS_ERR(client)) {
400 dprintk("NFSD: couldn't create callback client: %ld\n", 412 dprintk("NFSD: couldn't create callback client: %ld\n",
401 PTR_ERR(client)); 413 PTR_ERR(client));
402 return client; 414 return PTR_ERR(client);
415 }
416 cb->cb_client = client;
417 return 0;
418
419}
420
421static void warn_no_callback_path(struct nfs4_client *clp, int reason)
422{
423 dprintk("NFSD: warning: no callback path to client %.*s: error %d\n",
424 (int)clp->cl_name.len, clp->cl_name.data, reason);
425}
426
427static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata)
428{
429 struct nfs4_client *clp = calldata;
430
431 if (task->tk_status)
432 warn_no_callback_path(clp, task->tk_status);
433 else
434 atomic_set(&clp->cl_cb_conn.cb_set, 1);
435 put_nfs4_client(clp);
436}
437
438static const struct rpc_call_ops nfsd4_cb_probe_ops = {
439 .rpc_call_done = nfsd4_cb_probe_done,
440};
403 441
442static struct rpc_cred *lookup_cb_cred(struct nfs4_cb_conn *cb)
443{
444 struct auth_cred acred = {
445 .machine_cred = 1
446 };
447
448 /*
449 * Note in the gss case this doesn't actually have to wait for a
450 * gss upcall (or any calls to the client); this just creates a
451 * non-uptodate cred which the rpc state machine will fill in with
452 * a refresh_upcall later.
453 */
454 return rpcauth_lookup_credcache(cb->cb_client->cl_auth, &acred,
455 RPCAUTH_LOOKUP_NEW);
404} 456}
405 457
406static int do_probe_callback(void *data) 458void do_probe_callback(struct nfs4_client *clp)
407{ 459{
408 struct nfs4_client *clp = data; 460 struct nfs4_cb_conn *cb = &clp->cl_cb_conn;
409 struct nfs4_callback *cb = &clp->cl_callback;
410 struct rpc_message msg = { 461 struct rpc_message msg = {
411 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], 462 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
412 .rpc_argp = clp, 463 .rpc_argp = clp,
413 }; 464 };
414 struct rpc_clnt *client; 465 struct rpc_cred *cred;
415 int status; 466 int status;
416 467
417 client = setup_callback_client(clp); 468 cred = lookup_cb_cred(cb);
418 if (IS_ERR(client)) { 469 if (IS_ERR(cred)) {
419 status = PTR_ERR(client); 470 status = PTR_ERR(cred);
420 dprintk("NFSD: couldn't create callback client: %d\n", 471 goto out;
421 status); 472 }
422 goto out_err; 473 cb->cb_cred = cred;
474 msg.rpc_cred = cb->cb_cred;
475 status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_SOFT,
476 &nfsd4_cb_probe_ops, (void *)clp);
477out:
478 if (status) {
479 warn_no_callback_path(clp, status);
480 put_nfs4_client(clp);
423 } 481 }
424
425 status = rpc_call_sync(client, &msg, RPC_TASK_SOFT);
426
427 if (status)
428 goto out_release_client;
429
430 cb->cb_client = client;
431 atomic_set(&cb->cb_set, 1);
432 put_nfs4_client(clp);
433 return 0;
434out_release_client:
435 rpc_shutdown_client(client);
436out_err:
437 dprintk("NFSD: warning: no callback path to client %.*s: error %d\n",
438 (int)clp->cl_name.len, clp->cl_name.data, status);
439 put_nfs4_client(clp);
440 return 0;
441} 482}
442 483
443/* 484/*
@@ -446,21 +487,65 @@ out_err:
446void 487void
447nfsd4_probe_callback(struct nfs4_client *clp) 488nfsd4_probe_callback(struct nfs4_client *clp)
448{ 489{
449 struct task_struct *t; 490 int status;
450 491
451 BUG_ON(atomic_read(&clp->cl_callback.cb_set)); 492 BUG_ON(atomic_read(&clp->cl_cb_conn.cb_set));
493
494 status = setup_callback_client(clp);
495 if (status) {
496 warn_no_callback_path(clp, status);
497 return;
498 }
452 499
453 /* the task holds a reference to the nfs4_client struct */ 500 /* the task holds a reference to the nfs4_client struct */
454 atomic_inc(&clp->cl_count); 501 atomic_inc(&clp->cl_count);
455 502
456 t = kthread_run(do_probe_callback, clp, "nfs4_cb_probe"); 503 do_probe_callback(clp);
504}
457 505
458 if (IS_ERR(t)) 506static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
459 atomic_dec(&clp->cl_count); 507{
508 struct nfs4_delegation *dp = calldata;
509 struct nfs4_client *clp = dp->dl_client;
460 510
461 return; 511 switch (task->tk_status) {
512 case -EIO:
513 /* Network partition? */
514 atomic_set(&clp->cl_cb_conn.cb_set, 0);
515 warn_no_callback_path(clp, task->tk_status);
516 case -EBADHANDLE:
517 case -NFS4ERR_BAD_STATEID:
518 /* Race: client probably got cb_recall
519 * before open reply granting delegation */
520 break;
521 default:
522 /* success, or error we can't handle */
523 return;
524 }
525 if (dp->dl_retries--) {
526 rpc_delay(task, 2*HZ);
527 task->tk_status = 0;
528 rpc_restart_call(task);
529 } else {
530 atomic_set(&clp->cl_cb_conn.cb_set, 0);
531 warn_no_callback_path(clp, task->tk_status);
532 }
533}
534
535static void nfsd4_cb_recall_release(void *calldata)
536{
537 struct nfs4_delegation *dp = calldata;
538 struct nfs4_client *clp = dp->dl_client;
539
540 nfs4_put_delegation(dp);
541 put_nfs4_client(clp);
462} 542}
463 543
544static const struct rpc_call_ops nfsd4_cb_recall_ops = {
545 .rpc_call_done = nfsd4_cb_recall_done,
546 .rpc_release = nfsd4_cb_recall_release,
547};
548
464/* 549/*
465 * called with dp->dl_count inc'ed. 550 * called with dp->dl_count inc'ed.
466 */ 551 */
@@ -468,41 +553,19 @@ void
468nfsd4_cb_recall(struct nfs4_delegation *dp) 553nfsd4_cb_recall(struct nfs4_delegation *dp)
469{ 554{
470 struct nfs4_client *clp = dp->dl_client; 555 struct nfs4_client *clp = dp->dl_client;
471 struct rpc_clnt *clnt = clp->cl_callback.cb_client; 556 struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client;
472 struct nfs4_cb_recall *cbr = &dp->dl_recall;
473 struct rpc_message msg = { 557 struct rpc_message msg = {
474 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], 558 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL],
475 .rpc_argp = cbr, 559 .rpc_argp = dp,
560 .rpc_cred = clp->cl_cb_conn.cb_cred
476 }; 561 };
477 int retries = 1; 562 int status;
478 int status = 0; 563
479 564 dp->dl_retries = 1;
480 cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */ 565 status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT,
481 cbr->cbr_dp = dp; 566 &nfsd4_cb_recall_ops, dp);
482 567 if (status) {
483 status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT); 568 put_nfs4_client(clp);
484 while (retries--) { 569 nfs4_put_delegation(dp);
485 switch (status) {
486 case -EIO:
487 /* Network partition? */
488 atomic_set(&clp->cl_callback.cb_set, 0);
489 case -EBADHANDLE:
490 case -NFS4ERR_BAD_STATEID:
491 /* Race: client probably got cb_recall
492 * before open reply granting delegation */
493 break;
494 default:
495 goto out_put_cred;
496 }
497 ssleep(2);
498 status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT);
499 } 570 }
500out_put_cred:
501 /*
502 * Success or failure, now we're either waiting for lease expiration
503 * or deleg_return.
504 */
505 put_nfs4_client(clp);
506 nfs4_put_delegation(dp);
507 return;
508} 571}