diff options
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r-- | fs/nfs/nfs4proc.c | 1287 |
1 files changed, 1238 insertions, 49 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4674f8092da8..57dabb8a048e 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -48,11 +48,14 @@ | |||
48 | #include <linux/smp_lock.h> | 48 | #include <linux/smp_lock.h> |
49 | #include <linux/namei.h> | 49 | #include <linux/namei.h> |
50 | #include <linux/mount.h> | 50 | #include <linux/mount.h> |
51 | #include <linux/module.h> | ||
52 | #include <linux/sunrpc/bc_xprt.h> | ||
51 | 53 | ||
52 | #include "nfs4_fs.h" | 54 | #include "nfs4_fs.h" |
53 | #include "delegation.h" | 55 | #include "delegation.h" |
54 | #include "internal.h" | 56 | #include "internal.h" |
55 | #include "iostat.h" | 57 | #include "iostat.h" |
58 | #include "callback.h" | ||
56 | 59 | ||
57 | #define NFSDBG_FACILITY NFSDBG_PROC | 60 | #define NFSDBG_FACILITY NFSDBG_PROC |
58 | 61 | ||
@@ -247,7 +250,25 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode, | |||
247 | ret = nfs4_wait_clnt_recover(clp); | 250 | ret = nfs4_wait_clnt_recover(clp); |
248 | if (ret == 0) | 251 | if (ret == 0) |
249 | exception->retry = 1; | 252 | exception->retry = 1; |
253 | #if !defined(CONFIG_NFS_V4_1) | ||
250 | break; | 254 | break; |
255 | #else /* !defined(CONFIG_NFS_V4_1) */ | ||
256 | if (!nfs4_has_session(server->nfs_client)) | ||
257 | break; | ||
258 | /* FALLTHROUGH */ | ||
259 | case -NFS4ERR_BADSESSION: | ||
260 | case -NFS4ERR_BADSLOT: | ||
261 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
262 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
263 | case -NFS4ERR_DEADSESSION: | ||
264 | case -NFS4ERR_SEQ_FALSE_RETRY: | ||
265 | case -NFS4ERR_SEQ_MISORDERED: | ||
266 | dprintk("%s ERROR: %d Reset session\n", __func__, | ||
267 | errorcode); | ||
268 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
269 | exception->retry = 1; | ||
270 | /* FALLTHROUGH */ | ||
271 | #endif /* !defined(CONFIG_NFS_V4_1) */ | ||
251 | case -NFS4ERR_FILE_OPEN: | 272 | case -NFS4ERR_FILE_OPEN: |
252 | case -NFS4ERR_GRACE: | 273 | case -NFS4ERR_GRACE: |
253 | case -NFS4ERR_DELAY: | 274 | case -NFS4ERR_DELAY: |
@@ -271,6 +292,353 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp | |||
271 | spin_unlock(&clp->cl_lock); | 292 | spin_unlock(&clp->cl_lock); |
272 | } | 293 | } |
273 | 294 | ||
295 | #if defined(CONFIG_NFS_V4_1) | ||
296 | |||
297 | /* | ||
298 | * nfs4_free_slot - free a slot and efficiently update slot table. | ||
299 | * | ||
300 | * freeing a slot is trivially done by clearing its respective bit | ||
301 | * in the bitmap. | ||
302 | * If the freed slotid equals highest_used_slotid we want to update it | ||
303 | * so that the server would be able to size down the slot table if needed, | ||
304 | * otherwise we know that the highest_used_slotid is still in use. | ||
305 | * When updating highest_used_slotid there may be "holes" in the bitmap | ||
306 | * so we need to scan down from highest_used_slotid to 0 looking for the now | ||
307 | * highest slotid in use. | ||
308 | * If none found, highest_used_slotid is set to -1. | ||
309 | */ | ||
310 | static void | ||
311 | nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid) | ||
312 | { | ||
313 | int slotid = free_slotid; | ||
314 | |||
315 | spin_lock(&tbl->slot_tbl_lock); | ||
316 | /* clear used bit in bitmap */ | ||
317 | __clear_bit(slotid, tbl->used_slots); | ||
318 | |||
319 | /* update highest_used_slotid when it is freed */ | ||
320 | if (slotid == tbl->highest_used_slotid) { | ||
321 | slotid = find_last_bit(tbl->used_slots, tbl->max_slots); | ||
322 | if (slotid >= 0 && slotid < tbl->max_slots) | ||
323 | tbl->highest_used_slotid = slotid; | ||
324 | else | ||
325 | tbl->highest_used_slotid = -1; | ||
326 | } | ||
327 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | ||
328 | spin_unlock(&tbl->slot_tbl_lock); | ||
329 | dprintk("%s: free_slotid %u highest_used_slotid %d\n", __func__, | ||
330 | free_slotid, tbl->highest_used_slotid); | ||
331 | } | ||
332 | |||
333 | void nfs41_sequence_free_slot(const struct nfs_client *clp, | ||
334 | struct nfs4_sequence_res *res) | ||
335 | { | ||
336 | struct nfs4_slot_table *tbl; | ||
337 | |||
338 | if (!nfs4_has_session(clp)) { | ||
339 | dprintk("%s: No session\n", __func__); | ||
340 | return; | ||
341 | } | ||
342 | tbl = &clp->cl_session->fc_slot_table; | ||
343 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) { | ||
344 | dprintk("%s: No slot\n", __func__); | ||
345 | /* just wake up the next guy waiting since | ||
346 | * we may have not consumed a slot after all */ | ||
347 | rpc_wake_up_next(&tbl->slot_tbl_waitq); | ||
348 | return; | ||
349 | } | ||
350 | nfs4_free_slot(tbl, res->sr_slotid); | ||
351 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
352 | } | ||
353 | |||
354 | static void nfs41_sequence_done(struct nfs_client *clp, | ||
355 | struct nfs4_sequence_res *res, | ||
356 | int rpc_status) | ||
357 | { | ||
358 | unsigned long timestamp; | ||
359 | struct nfs4_slot_table *tbl; | ||
360 | struct nfs4_slot *slot; | ||
361 | |||
362 | /* | ||
363 | * sr_status remains 1 if an RPC level error occurred. The server | ||
364 | * may or may not have processed the sequence operation.. | ||
365 | * Proceed as if the server received and processed the sequence | ||
366 | * operation. | ||
367 | */ | ||
368 | if (res->sr_status == 1) | ||
369 | res->sr_status = NFS_OK; | ||
370 | |||
371 | /* -ERESTARTSYS can result in skipping nfs41_sequence_setup */ | ||
372 | if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) | ||
373 | goto out; | ||
374 | |||
375 | tbl = &clp->cl_session->fc_slot_table; | ||
376 | slot = tbl->slots + res->sr_slotid; | ||
377 | |||
378 | if (res->sr_status == 0) { | ||
379 | /* Update the slot's sequence and clientid lease timer */ | ||
380 | ++slot->seq_nr; | ||
381 | timestamp = res->sr_renewal_time; | ||
382 | spin_lock(&clp->cl_lock); | ||
383 | if (time_before(clp->cl_last_renewal, timestamp)) | ||
384 | clp->cl_last_renewal = timestamp; | ||
385 | spin_unlock(&clp->cl_lock); | ||
386 | return; | ||
387 | } | ||
388 | out: | ||
389 | /* The session may be reset by one of the error handlers. */ | ||
390 | dprintk("%s: Error %d free the slot \n", __func__, res->sr_status); | ||
391 | nfs41_sequence_free_slot(clp, res); | ||
392 | } | ||
393 | |||
394 | /* | ||
395 | * nfs4_find_slot - efficiently look for a free slot | ||
396 | * | ||
397 | * nfs4_find_slot looks for an unset bit in the used_slots bitmap. | ||
398 | * If found, we mark the slot as used, update the highest_used_slotid, | ||
399 | * and respectively set up the sequence operation args. | ||
400 | * The slot number is returned if found, or NFS4_MAX_SLOT_TABLE otherwise. | ||
401 | * | ||
402 | * Note: must be called with under the slot_tbl_lock. | ||
403 | */ | ||
404 | static u8 | ||
405 | nfs4_find_slot(struct nfs4_slot_table *tbl, struct rpc_task *task) | ||
406 | { | ||
407 | int slotid; | ||
408 | u8 ret_id = NFS4_MAX_SLOT_TABLE; | ||
409 | BUILD_BUG_ON((u8)NFS4_MAX_SLOT_TABLE != (int)NFS4_MAX_SLOT_TABLE); | ||
410 | |||
411 | dprintk("--> %s used_slots=%04lx highest_used=%d max_slots=%d\n", | ||
412 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, | ||
413 | tbl->max_slots); | ||
414 | slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slots); | ||
415 | if (slotid >= tbl->max_slots) | ||
416 | goto out; | ||
417 | __set_bit(slotid, tbl->used_slots); | ||
418 | if (slotid > tbl->highest_used_slotid) | ||
419 | tbl->highest_used_slotid = slotid; | ||
420 | ret_id = slotid; | ||
421 | out: | ||
422 | dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d \n", | ||
423 | __func__, tbl->used_slots[0], tbl->highest_used_slotid, ret_id); | ||
424 | return ret_id; | ||
425 | } | ||
426 | |||
427 | static int nfs4_recover_session(struct nfs4_session *session) | ||
428 | { | ||
429 | struct nfs_client *clp = session->clp; | ||
430 | int ret; | ||
431 | |||
432 | for (;;) { | ||
433 | ret = nfs4_wait_clnt_recover(clp); | ||
434 | if (ret != 0) | ||
435 | return ret; | ||
436 | if (!test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) | ||
437 | break; | ||
438 | nfs4_schedule_state_manager(clp); | ||
439 | } | ||
440 | return 0; | ||
441 | } | ||
442 | |||
443 | static int nfs41_setup_sequence(struct nfs4_session *session, | ||
444 | struct nfs4_sequence_args *args, | ||
445 | struct nfs4_sequence_res *res, | ||
446 | int cache_reply, | ||
447 | struct rpc_task *task) | ||
448 | { | ||
449 | struct nfs4_slot *slot; | ||
450 | struct nfs4_slot_table *tbl; | ||
451 | int status = 0; | ||
452 | u8 slotid; | ||
453 | |||
454 | dprintk("--> %s\n", __func__); | ||
455 | /* slot already allocated? */ | ||
456 | if (res->sr_slotid != NFS4_MAX_SLOT_TABLE) | ||
457 | return 0; | ||
458 | |||
459 | memset(res, 0, sizeof(*res)); | ||
460 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
461 | tbl = &session->fc_slot_table; | ||
462 | |||
463 | spin_lock(&tbl->slot_tbl_lock); | ||
464 | if (test_bit(NFS4CLNT_SESSION_SETUP, &session->clp->cl_state)) { | ||
465 | if (tbl->highest_used_slotid != -1) { | ||
466 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | ||
467 | spin_unlock(&tbl->slot_tbl_lock); | ||
468 | dprintk("<-- %s: Session reset: draining\n", __func__); | ||
469 | return -EAGAIN; | ||
470 | } | ||
471 | |||
472 | /* The slot table is empty; start the reset thread */ | ||
473 | dprintk("%s Session Reset\n", __func__); | ||
474 | spin_unlock(&tbl->slot_tbl_lock); | ||
475 | status = nfs4_recover_session(session); | ||
476 | if (status) | ||
477 | return status; | ||
478 | spin_lock(&tbl->slot_tbl_lock); | ||
479 | } | ||
480 | |||
481 | slotid = nfs4_find_slot(tbl, task); | ||
482 | if (slotid == NFS4_MAX_SLOT_TABLE) { | ||
483 | rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL); | ||
484 | spin_unlock(&tbl->slot_tbl_lock); | ||
485 | dprintk("<-- %s: no free slots\n", __func__); | ||
486 | return -EAGAIN; | ||
487 | } | ||
488 | spin_unlock(&tbl->slot_tbl_lock); | ||
489 | |||
490 | slot = tbl->slots + slotid; | ||
491 | args->sa_session = session; | ||
492 | args->sa_slotid = slotid; | ||
493 | args->sa_cache_this = cache_reply; | ||
494 | |||
495 | dprintk("<-- %s slotid=%d seqid=%d\n", __func__, slotid, slot->seq_nr); | ||
496 | |||
497 | res->sr_session = session; | ||
498 | res->sr_slotid = slotid; | ||
499 | res->sr_renewal_time = jiffies; | ||
500 | /* | ||
501 | * sr_status is only set in decode_sequence, and so will remain | ||
502 | * set to 1 if an rpc level failure occurs. | ||
503 | */ | ||
504 | res->sr_status = 1; | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | int nfs4_setup_sequence(struct nfs_client *clp, | ||
509 | struct nfs4_sequence_args *args, | ||
510 | struct nfs4_sequence_res *res, | ||
511 | int cache_reply, | ||
512 | struct rpc_task *task) | ||
513 | { | ||
514 | int ret = 0; | ||
515 | |||
516 | dprintk("--> %s clp %p session %p sr_slotid %d\n", | ||
517 | __func__, clp, clp->cl_session, res->sr_slotid); | ||
518 | |||
519 | if (!nfs4_has_session(clp)) | ||
520 | goto out; | ||
521 | ret = nfs41_setup_sequence(clp->cl_session, args, res, cache_reply, | ||
522 | task); | ||
523 | if (ret != -EAGAIN) { | ||
524 | /* terminate rpc task */ | ||
525 | task->tk_status = ret; | ||
526 | task->tk_action = NULL; | ||
527 | } | ||
528 | out: | ||
529 | dprintk("<-- %s status=%d\n", __func__, ret); | ||
530 | return ret; | ||
531 | } | ||
532 | |||
533 | struct nfs41_call_sync_data { | ||
534 | struct nfs_client *clp; | ||
535 | struct nfs4_sequence_args *seq_args; | ||
536 | struct nfs4_sequence_res *seq_res; | ||
537 | int cache_reply; | ||
538 | }; | ||
539 | |||
540 | static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata) | ||
541 | { | ||
542 | struct nfs41_call_sync_data *data = calldata; | ||
543 | |||
544 | dprintk("--> %s data->clp->cl_session %p\n", __func__, | ||
545 | data->clp->cl_session); | ||
546 | if (nfs4_setup_sequence(data->clp, data->seq_args, | ||
547 | data->seq_res, data->cache_reply, task)) | ||
548 | return; | ||
549 | rpc_call_start(task); | ||
550 | } | ||
551 | |||
552 | static void nfs41_call_sync_done(struct rpc_task *task, void *calldata) | ||
553 | { | ||
554 | struct nfs41_call_sync_data *data = calldata; | ||
555 | |||
556 | nfs41_sequence_done(data->clp, data->seq_res, task->tk_status); | ||
557 | nfs41_sequence_free_slot(data->clp, data->seq_res); | ||
558 | } | ||
559 | |||
560 | struct rpc_call_ops nfs41_call_sync_ops = { | ||
561 | .rpc_call_prepare = nfs41_call_sync_prepare, | ||
562 | .rpc_call_done = nfs41_call_sync_done, | ||
563 | }; | ||
564 | |||
565 | static int nfs4_call_sync_sequence(struct nfs_client *clp, | ||
566 | struct rpc_clnt *clnt, | ||
567 | struct rpc_message *msg, | ||
568 | struct nfs4_sequence_args *args, | ||
569 | struct nfs4_sequence_res *res, | ||
570 | int cache_reply) | ||
571 | { | ||
572 | int ret; | ||
573 | struct rpc_task *task; | ||
574 | struct nfs41_call_sync_data data = { | ||
575 | .clp = clp, | ||
576 | .seq_args = args, | ||
577 | .seq_res = res, | ||
578 | .cache_reply = cache_reply, | ||
579 | }; | ||
580 | struct rpc_task_setup task_setup = { | ||
581 | .rpc_client = clnt, | ||
582 | .rpc_message = msg, | ||
583 | .callback_ops = &nfs41_call_sync_ops, | ||
584 | .callback_data = &data | ||
585 | }; | ||
586 | |||
587 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
588 | task = rpc_run_task(&task_setup); | ||
589 | if (IS_ERR(task)) | ||
590 | ret = PTR_ERR(task); | ||
591 | else { | ||
592 | ret = task->tk_status; | ||
593 | rpc_put_task(task); | ||
594 | } | ||
595 | return ret; | ||
596 | } | ||
597 | |||
598 | int _nfs4_call_sync_session(struct nfs_server *server, | ||
599 | struct rpc_message *msg, | ||
600 | struct nfs4_sequence_args *args, | ||
601 | struct nfs4_sequence_res *res, | ||
602 | int cache_reply) | ||
603 | { | ||
604 | return nfs4_call_sync_sequence(server->nfs_client, server->client, | ||
605 | msg, args, res, cache_reply); | ||
606 | } | ||
607 | |||
608 | #endif /* CONFIG_NFS_V4_1 */ | ||
609 | |||
610 | int _nfs4_call_sync(struct nfs_server *server, | ||
611 | struct rpc_message *msg, | ||
612 | struct nfs4_sequence_args *args, | ||
613 | struct nfs4_sequence_res *res, | ||
614 | int cache_reply) | ||
615 | { | ||
616 | args->sa_session = res->sr_session = NULL; | ||
617 | return rpc_call_sync(server->client, msg, 0); | ||
618 | } | ||
619 | |||
620 | #define nfs4_call_sync(server, msg, args, res, cache_reply) \ | ||
621 | (server)->nfs_client->cl_call_sync((server), (msg), &(args)->seq_args, \ | ||
622 | &(res)->seq_res, (cache_reply)) | ||
623 | |||
624 | static void nfs4_sequence_done(const struct nfs_server *server, | ||
625 | struct nfs4_sequence_res *res, int rpc_status) | ||
626 | { | ||
627 | #ifdef CONFIG_NFS_V4_1 | ||
628 | if (nfs4_has_session(server->nfs_client)) | ||
629 | nfs41_sequence_done(server->nfs_client, res, rpc_status); | ||
630 | #endif /* CONFIG_NFS_V4_1 */ | ||
631 | } | ||
632 | |||
633 | /* no restart, therefore free slot here */ | ||
634 | static void nfs4_sequence_done_free_slot(const struct nfs_server *server, | ||
635 | struct nfs4_sequence_res *res, | ||
636 | int rpc_status) | ||
637 | { | ||
638 | nfs4_sequence_done(server, res, rpc_status); | ||
639 | nfs4_sequence_free_slot(server->nfs_client, res); | ||
640 | } | ||
641 | |||
274 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | 642 | static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) |
275 | { | 643 | { |
276 | struct nfs_inode *nfsi = NFS_I(dir); | 644 | struct nfs_inode *nfsi = NFS_I(dir); |
@@ -343,6 +711,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path, | |||
343 | p->o_arg.server = server; | 711 | p->o_arg.server = server; |
344 | p->o_arg.bitmask = server->attr_bitmask; | 712 | p->o_arg.bitmask = server->attr_bitmask; |
345 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; | 713 | p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; |
714 | p->o_res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
346 | if (flags & O_EXCL) { | 715 | if (flags & O_EXCL) { |
347 | u32 *s = (u32 *) p->o_arg.u.verifier.data; | 716 | u32 *s = (u32 *) p->o_arg.u.verifier.data; |
348 | s[0] = jiffies; | 717 | s[0] = jiffies; |
@@ -929,6 +1298,10 @@ static void nfs4_open_prepare(struct rpc_task *task, void *calldata) | |||
929 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); | 1298 | nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); |
930 | } | 1299 | } |
931 | data->timestamp = jiffies; | 1300 | data->timestamp = jiffies; |
1301 | if (nfs4_setup_sequence(data->o_arg.server->nfs_client, | ||
1302 | &data->o_arg.seq_args, | ||
1303 | &data->o_res.seq_res, 1, task)) | ||
1304 | return; | ||
932 | rpc_call_start(task); | 1305 | rpc_call_start(task); |
933 | return; | 1306 | return; |
934 | out_no_action: | 1307 | out_no_action: |
@@ -941,6 +1314,10 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) | |||
941 | struct nfs4_opendata *data = calldata; | 1314 | struct nfs4_opendata *data = calldata; |
942 | 1315 | ||
943 | data->rpc_status = task->tk_status; | 1316 | data->rpc_status = task->tk_status; |
1317 | |||
1318 | nfs4_sequence_done_free_slot(data->o_arg.server, &data->o_res.seq_res, | ||
1319 | task->tk_status); | ||
1320 | |||
944 | if (RPC_ASSASSINATED(task)) | 1321 | if (RPC_ASSASSINATED(task)) |
945 | return; | 1322 | return; |
946 | if (task->tk_status == 0) { | 1323 | if (task->tk_status == 0) { |
@@ -1269,7 +1646,7 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, | |||
1269 | } else | 1646 | } else |
1270 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); | 1647 | memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); |
1271 | 1648 | ||
1272 | status = rpc_call_sync(server->client, &msg, 0); | 1649 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
1273 | if (status == 0 && state != NULL) | 1650 | if (status == 0 && state != NULL) |
1274 | renew_lease(server, timestamp); | 1651 | renew_lease(server, timestamp); |
1275 | return status; | 1652 | return status; |
@@ -1318,6 +1695,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1318 | struct nfs4_state *state = calldata->state; | 1695 | struct nfs4_state *state = calldata->state; |
1319 | struct nfs_server *server = NFS_SERVER(calldata->inode); | 1696 | struct nfs_server *server = NFS_SERVER(calldata->inode); |
1320 | 1697 | ||
1698 | nfs4_sequence_done(server, &calldata->res.seq_res, task->tk_status); | ||
1321 | if (RPC_ASSASSINATED(task)) | 1699 | if (RPC_ASSASSINATED(task)) |
1322 | return; | 1700 | return; |
1323 | /* hmm. we are done with the inode, and in the process of freeing | 1701 | /* hmm. we are done with the inode, and in the process of freeing |
@@ -1336,10 +1714,11 @@ static void nfs4_close_done(struct rpc_task *task, void *data) | |||
1336 | break; | 1714 | break; |
1337 | default: | 1715 | default: |
1338 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { | 1716 | if (nfs4_async_handle_error(task, server, state) == -EAGAIN) { |
1339 | rpc_restart_call(task); | 1717 | nfs4_restart_rpc(task, server->nfs_client); |
1340 | return; | 1718 | return; |
1341 | } | 1719 | } |
1342 | } | 1720 | } |
1721 | nfs4_sequence_free_slot(server->nfs_client, &calldata->res.seq_res); | ||
1343 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); | 1722 | nfs_refresh_inode(calldata->inode, calldata->res.fattr); |
1344 | } | 1723 | } |
1345 | 1724 | ||
@@ -1380,6 +1759,10 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1380 | calldata->arg.fmode = FMODE_WRITE; | 1759 | calldata->arg.fmode = FMODE_WRITE; |
1381 | } | 1760 | } |
1382 | calldata->timestamp = jiffies; | 1761 | calldata->timestamp = jiffies; |
1762 | if (nfs4_setup_sequence((NFS_SERVER(calldata->inode))->nfs_client, | ||
1763 | &calldata->arg.seq_args, &calldata->res.seq_res, | ||
1764 | 1, task)) | ||
1765 | return; | ||
1383 | rpc_call_start(task); | 1766 | rpc_call_start(task); |
1384 | } | 1767 | } |
1385 | 1768 | ||
@@ -1419,13 +1802,15 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1419 | }; | 1802 | }; |
1420 | int status = -ENOMEM; | 1803 | int status = -ENOMEM; |
1421 | 1804 | ||
1422 | calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); | 1805 | calldata = kzalloc(sizeof(*calldata), GFP_KERNEL); |
1423 | if (calldata == NULL) | 1806 | if (calldata == NULL) |
1424 | goto out; | 1807 | goto out; |
1425 | calldata->inode = state->inode; | 1808 | calldata->inode = state->inode; |
1426 | calldata->state = state; | 1809 | calldata->state = state; |
1427 | calldata->arg.fh = NFS_FH(state->inode); | 1810 | calldata->arg.fh = NFS_FH(state->inode); |
1428 | calldata->arg.stateid = &state->open_stateid; | 1811 | calldata->arg.stateid = &state->open_stateid; |
1812 | if (nfs4_has_session(server->nfs_client)) | ||
1813 | memset(calldata->arg.stateid->data, 0, 4); /* clear seqid */ | ||
1429 | /* Serialization for the sequence id */ | 1814 | /* Serialization for the sequence id */ |
1430 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); | 1815 | calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); |
1431 | if (calldata->arg.seqid == NULL) | 1816 | if (calldata->arg.seqid == NULL) |
@@ -1435,6 +1820,7 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait) | |||
1435 | calldata->res.fattr = &calldata->fattr; | 1820 | calldata->res.fattr = &calldata->fattr; |
1436 | calldata->res.seqid = calldata->arg.seqid; | 1821 | calldata->res.seqid = calldata->arg.seqid; |
1437 | calldata->res.server = server; | 1822 | calldata->res.server = server; |
1823 | calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
1438 | calldata->path.mnt = mntget(path->mnt); | 1824 | calldata->path.mnt = mntget(path->mnt); |
1439 | calldata->path.dentry = dget(path->dentry); | 1825 | calldata->path.dentry = dget(path->dentry); |
1440 | 1826 | ||
@@ -1584,15 +1970,18 @@ void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) | |||
1584 | 1970 | ||
1585 | static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) | 1971 | static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) |
1586 | { | 1972 | { |
1973 | struct nfs4_server_caps_arg args = { | ||
1974 | .fhandle = fhandle, | ||
1975 | }; | ||
1587 | struct nfs4_server_caps_res res = {}; | 1976 | struct nfs4_server_caps_res res = {}; |
1588 | struct rpc_message msg = { | 1977 | struct rpc_message msg = { |
1589 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS], | 1978 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS], |
1590 | .rpc_argp = fhandle, | 1979 | .rpc_argp = &args, |
1591 | .rpc_resp = &res, | 1980 | .rpc_resp = &res, |
1592 | }; | 1981 | }; |
1593 | int status; | 1982 | int status; |
1594 | 1983 | ||
1595 | status = rpc_call_sync(server->client, &msg, 0); | 1984 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
1596 | if (status == 0) { | 1985 | if (status == 0) { |
1597 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); | 1986 | memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); |
1598 | if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) | 1987 | if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) |
@@ -1606,6 +1995,7 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f | |||
1606 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; | 1995 | server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; |
1607 | server->acl_bitmask = res.acl_bitmask; | 1996 | server->acl_bitmask = res.acl_bitmask; |
1608 | } | 1997 | } |
1998 | |||
1609 | return status; | 1999 | return status; |
1610 | } | 2000 | } |
1611 | 2001 | ||
@@ -1637,8 +2027,15 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | |||
1637 | .rpc_argp = &args, | 2027 | .rpc_argp = &args, |
1638 | .rpc_resp = &res, | 2028 | .rpc_resp = &res, |
1639 | }; | 2029 | }; |
2030 | int status; | ||
2031 | |||
1640 | nfs_fattr_init(info->fattr); | 2032 | nfs_fattr_init(info->fattr); |
1641 | return rpc_call_sync(server->client, &msg, 0); | 2033 | status = nfs4_recover_expired_lease(server); |
2034 | if (!status) | ||
2035 | status = nfs4_check_client_ready(server->nfs_client); | ||
2036 | if (!status) | ||
2037 | status = nfs4_call_sync(server, &msg, &args, &res, 0); | ||
2038 | return status; | ||
1642 | } | 2039 | } |
1643 | 2040 | ||
1644 | static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, | 2041 | static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, |
@@ -1728,7 +2125,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, | |||
1728 | }; | 2125 | }; |
1729 | 2126 | ||
1730 | nfs_fattr_init(fattr); | 2127 | nfs_fattr_init(fattr); |
1731 | return rpc_call_sync(server->client, &msg, 0); | 2128 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
1732 | } | 2129 | } |
1733 | 2130 | ||
1734 | static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) | 2131 | static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) |
@@ -1812,7 +2209,7 @@ static int _nfs4_proc_lookupfh(struct nfs_server *server, const struct nfs_fh *d | |||
1812 | nfs_fattr_init(fattr); | 2209 | nfs_fattr_init(fattr); |
1813 | 2210 | ||
1814 | dprintk("NFS call lookupfh %s\n", name->name); | 2211 | dprintk("NFS call lookupfh %s\n", name->name); |
1815 | status = rpc_call_sync(server->client, &msg, 0); | 2212 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
1816 | dprintk("NFS reply lookupfh: %d\n", status); | 2213 | dprintk("NFS reply lookupfh: %d\n", status); |
1817 | return status; | 2214 | return status; |
1818 | } | 2215 | } |
@@ -1898,7 +2295,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry | |||
1898 | args.access |= NFS4_ACCESS_EXECUTE; | 2295 | args.access |= NFS4_ACCESS_EXECUTE; |
1899 | } | 2296 | } |
1900 | nfs_fattr_init(&fattr); | 2297 | nfs_fattr_init(&fattr); |
1901 | status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 2298 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
1902 | if (!status) { | 2299 | if (!status) { |
1903 | entry->mask = 0; | 2300 | entry->mask = 0; |
1904 | if (res.access & NFS4_ACCESS_READ) | 2301 | if (res.access & NFS4_ACCESS_READ) |
@@ -1957,13 +2354,14 @@ static int _nfs4_proc_readlink(struct inode *inode, struct page *page, | |||
1957 | .pglen = pglen, | 2354 | .pglen = pglen, |
1958 | .pages = &page, | 2355 | .pages = &page, |
1959 | }; | 2356 | }; |
2357 | struct nfs4_readlink_res res; | ||
1960 | struct rpc_message msg = { | 2358 | struct rpc_message msg = { |
1961 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK], | 2359 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK], |
1962 | .rpc_argp = &args, | 2360 | .rpc_argp = &args, |
1963 | .rpc_resp = NULL, | 2361 | .rpc_resp = &res, |
1964 | }; | 2362 | }; |
1965 | 2363 | ||
1966 | return rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 2364 | return nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0); |
1967 | } | 2365 | } |
1968 | 2366 | ||
1969 | static int nfs4_proc_readlink(struct inode *inode, struct page *page, | 2367 | static int nfs4_proc_readlink(struct inode *inode, struct page *page, |
@@ -2057,7 +2455,7 @@ static int _nfs4_proc_remove(struct inode *dir, struct qstr *name) | |||
2057 | int status; | 2455 | int status; |
2058 | 2456 | ||
2059 | nfs_fattr_init(&res.dir_attr); | 2457 | nfs_fattr_init(&res.dir_attr); |
2060 | status = rpc_call_sync(server->client, &msg, 0); | 2458 | status = nfs4_call_sync(server, &msg, &args, &res, 1); |
2061 | if (status == 0) { | 2459 | if (status == 0) { |
2062 | update_changeattr(dir, &res.cinfo); | 2460 | update_changeattr(dir, &res.cinfo); |
2063 | nfs_post_op_update_inode(dir, &res.dir_attr); | 2461 | nfs_post_op_update_inode(dir, &res.dir_attr); |
@@ -2092,8 +2490,10 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) | |||
2092 | { | 2490 | { |
2093 | struct nfs_removeres *res = task->tk_msg.rpc_resp; | 2491 | struct nfs_removeres *res = task->tk_msg.rpc_resp; |
2094 | 2492 | ||
2493 | nfs4_sequence_done(res->server, &res->seq_res, task->tk_status); | ||
2095 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) | 2494 | if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN) |
2096 | return 0; | 2495 | return 0; |
2496 | nfs4_sequence_free_slot(res->server->nfs_client, &res->seq_res); | ||
2097 | update_changeattr(dir, &res->cinfo); | 2497 | update_changeattr(dir, &res->cinfo); |
2098 | nfs_post_op_update_inode(dir, &res->dir_attr); | 2498 | nfs_post_op_update_inode(dir, &res->dir_attr); |
2099 | return 1; | 2499 | return 1; |
@@ -2125,7 +2525,7 @@ static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, | |||
2125 | 2525 | ||
2126 | nfs_fattr_init(res.old_fattr); | 2526 | nfs_fattr_init(res.old_fattr); |
2127 | nfs_fattr_init(res.new_fattr); | 2527 | nfs_fattr_init(res.new_fattr); |
2128 | status = rpc_call_sync(server->client, &msg, 0); | 2528 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
2129 | 2529 | ||
2130 | if (!status) { | 2530 | if (!status) { |
2131 | update_changeattr(old_dir, &res.old_cinfo); | 2531 | update_changeattr(old_dir, &res.old_cinfo); |
@@ -2174,7 +2574,7 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr * | |||
2174 | 2574 | ||
2175 | nfs_fattr_init(res.fattr); | 2575 | nfs_fattr_init(res.fattr); |
2176 | nfs_fattr_init(res.dir_attr); | 2576 | nfs_fattr_init(res.dir_attr); |
2177 | status = rpc_call_sync(server->client, &msg, 0); | 2577 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
2178 | if (!status) { | 2578 | if (!status) { |
2179 | update_changeattr(dir, &res.cinfo); | 2579 | update_changeattr(dir, &res.cinfo); |
2180 | nfs_post_op_update_inode(dir, res.dir_attr); | 2580 | nfs_post_op_update_inode(dir, res.dir_attr); |
@@ -2235,7 +2635,8 @@ static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir, | |||
2235 | 2635 | ||
2236 | static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) | 2636 | static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data) |
2237 | { | 2637 | { |
2238 | int status = rpc_call_sync(NFS_CLIENT(dir), &data->msg, 0); | 2638 | int status = nfs4_call_sync(NFS_SERVER(dir), &data->msg, |
2639 | &data->arg, &data->res, 1); | ||
2239 | if (status == 0) { | 2640 | if (status == 0) { |
2240 | update_changeattr(dir, &data->res.dir_cinfo); | 2641 | update_changeattr(dir, &data->res.dir_cinfo); |
2241 | nfs_post_op_update_inode(dir, data->res.dir_fattr); | 2642 | nfs_post_op_update_inode(dir, data->res.dir_fattr); |
@@ -2344,7 +2745,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, | |||
2344 | (unsigned long long)cookie); | 2745 | (unsigned long long)cookie); |
2345 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); | 2746 | nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args); |
2346 | res.pgbase = args.pgbase; | 2747 | res.pgbase = args.pgbase; |
2347 | status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0); | 2748 | status = nfs4_call_sync(NFS_SERVER(dir), &msg, &args, &res, 0); |
2348 | if (status == 0) | 2749 | if (status == 0) |
2349 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); | 2750 | memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE); |
2350 | 2751 | ||
@@ -2422,14 +2823,17 @@ static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2422 | .fh = fhandle, | 2823 | .fh = fhandle, |
2423 | .bitmask = server->attr_bitmask, | 2824 | .bitmask = server->attr_bitmask, |
2424 | }; | 2825 | }; |
2826 | struct nfs4_statfs_res res = { | ||
2827 | .fsstat = fsstat, | ||
2828 | }; | ||
2425 | struct rpc_message msg = { | 2829 | struct rpc_message msg = { |
2426 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS], | 2830 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS], |
2427 | .rpc_argp = &args, | 2831 | .rpc_argp = &args, |
2428 | .rpc_resp = fsstat, | 2832 | .rpc_resp = &res, |
2429 | }; | 2833 | }; |
2430 | 2834 | ||
2431 | nfs_fattr_init(fsstat->fattr); | 2835 | nfs_fattr_init(fsstat->fattr); |
2432 | return rpc_call_sync(server->client, &msg, 0); | 2836 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
2433 | } | 2837 | } |
2434 | 2838 | ||
2435 | static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) | 2839 | static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) |
@@ -2451,13 +2855,16 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, | |||
2451 | .fh = fhandle, | 2855 | .fh = fhandle, |
2452 | .bitmask = server->attr_bitmask, | 2856 | .bitmask = server->attr_bitmask, |
2453 | }; | 2857 | }; |
2858 | struct nfs4_fsinfo_res res = { | ||
2859 | .fsinfo = fsinfo, | ||
2860 | }; | ||
2454 | struct rpc_message msg = { | 2861 | struct rpc_message msg = { |
2455 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO], | 2862 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO], |
2456 | .rpc_argp = &args, | 2863 | .rpc_argp = &args, |
2457 | .rpc_resp = fsinfo, | 2864 | .rpc_resp = &res, |
2458 | }; | 2865 | }; |
2459 | 2866 | ||
2460 | return rpc_call_sync(server->client, &msg, 0); | 2867 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
2461 | } | 2868 | } |
2462 | 2869 | ||
2463 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) | 2870 | static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) |
@@ -2486,10 +2893,13 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle | |||
2486 | .fh = fhandle, | 2893 | .fh = fhandle, |
2487 | .bitmask = server->attr_bitmask, | 2894 | .bitmask = server->attr_bitmask, |
2488 | }; | 2895 | }; |
2896 | struct nfs4_pathconf_res res = { | ||
2897 | .pathconf = pathconf, | ||
2898 | }; | ||
2489 | struct rpc_message msg = { | 2899 | struct rpc_message msg = { |
2490 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF], | 2900 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF], |
2491 | .rpc_argp = &args, | 2901 | .rpc_argp = &args, |
2492 | .rpc_resp = pathconf, | 2902 | .rpc_resp = &res, |
2493 | }; | 2903 | }; |
2494 | 2904 | ||
2495 | /* None of the pathconf attributes are mandatory to implement */ | 2905 | /* None of the pathconf attributes are mandatory to implement */ |
@@ -2499,7 +2909,7 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle | |||
2499 | } | 2909 | } |
2500 | 2910 | ||
2501 | nfs_fattr_init(pathconf->fattr); | 2911 | nfs_fattr_init(pathconf->fattr); |
2502 | return rpc_call_sync(server->client, &msg, 0); | 2912 | return nfs4_call_sync(server, &msg, &args, &res, 0); |
2503 | } | 2913 | } |
2504 | 2914 | ||
2505 | static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | 2915 | static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, |
@@ -2520,8 +2930,13 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data) | |||
2520 | { | 2930 | { |
2521 | struct nfs_server *server = NFS_SERVER(data->inode); | 2931 | struct nfs_server *server = NFS_SERVER(data->inode); |
2522 | 2932 | ||
2933 | dprintk("--> %s\n", __func__); | ||
2934 | |||
2935 | /* nfs4_sequence_free_slot called in the read rpc_call_done */ | ||
2936 | nfs4_sequence_done(server, &data->res.seq_res, task->tk_status); | ||
2937 | |||
2523 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { | 2938 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { |
2524 | rpc_restart_call(task); | 2939 | nfs4_restart_rpc(task, server->nfs_client); |
2525 | return -EAGAIN; | 2940 | return -EAGAIN; |
2526 | } | 2941 | } |
2527 | 2942 | ||
@@ -2541,8 +2956,12 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2541 | { | 2956 | { |
2542 | struct inode *inode = data->inode; | 2957 | struct inode *inode = data->inode; |
2543 | 2958 | ||
2959 | /* slot is freed in nfs_writeback_done */ | ||
2960 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | ||
2961 | task->tk_status); | ||
2962 | |||
2544 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { | 2963 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { |
2545 | rpc_restart_call(task); | 2964 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
2546 | return -EAGAIN; | 2965 | return -EAGAIN; |
2547 | } | 2966 | } |
2548 | if (task->tk_status >= 0) { | 2967 | if (task->tk_status >= 0) { |
@@ -2567,10 +2986,14 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data) | |||
2567 | { | 2986 | { |
2568 | struct inode *inode = data->inode; | 2987 | struct inode *inode = data->inode; |
2569 | 2988 | ||
2989 | nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res, | ||
2990 | task->tk_status); | ||
2570 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { | 2991 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) { |
2571 | rpc_restart_call(task); | 2992 | nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client); |
2572 | return -EAGAIN; | 2993 | return -EAGAIN; |
2573 | } | 2994 | } |
2995 | nfs4_sequence_free_slot(NFS_SERVER(inode)->nfs_client, | ||
2996 | &data->res.seq_res); | ||
2574 | nfs_refresh_inode(inode, data->res.fattr); | 2997 | nfs_refresh_inode(inode, data->res.fattr); |
2575 | return 0; | 2998 | return 0; |
2576 | } | 2999 | } |
@@ -2603,6 +3026,9 @@ static void nfs4_renew_done(struct rpc_task *task, void *data) | |||
2603 | if (time_before(clp->cl_last_renewal,timestamp)) | 3026 | if (time_before(clp->cl_last_renewal,timestamp)) |
2604 | clp->cl_last_renewal = timestamp; | 3027 | clp->cl_last_renewal = timestamp; |
2605 | spin_unlock(&clp->cl_lock); | 3028 | spin_unlock(&clp->cl_lock); |
3029 | dprintk("%s calling put_rpccred on rpc_cred %p\n", __func__, | ||
3030 | task->tk_msg.rpc_cred); | ||
3031 | put_rpccred(task->tk_msg.rpc_cred); | ||
2606 | } | 3032 | } |
2607 | 3033 | ||
2608 | static const struct rpc_call_ops nfs4_renew_ops = { | 3034 | static const struct rpc_call_ops nfs4_renew_ops = { |
@@ -2742,12 +3168,14 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
2742 | .acl_pages = pages, | 3168 | .acl_pages = pages, |
2743 | .acl_len = buflen, | 3169 | .acl_len = buflen, |
2744 | }; | 3170 | }; |
2745 | size_t resp_len = buflen; | 3171 | struct nfs_getaclres res = { |
3172 | .acl_len = buflen, | ||
3173 | }; | ||
2746 | void *resp_buf; | 3174 | void *resp_buf; |
2747 | struct rpc_message msg = { | 3175 | struct rpc_message msg = { |
2748 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], | 3176 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL], |
2749 | .rpc_argp = &args, | 3177 | .rpc_argp = &args, |
2750 | .rpc_resp = &resp_len, | 3178 | .rpc_resp = &res, |
2751 | }; | 3179 | }; |
2752 | struct page *localpage = NULL; | 3180 | struct page *localpage = NULL; |
2753 | int ret; | 3181 | int ret; |
@@ -2761,26 +3189,26 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu | |||
2761 | return -ENOMEM; | 3189 | return -ENOMEM; |
2762 | args.acl_pages[0] = localpage; | 3190 | args.acl_pages[0] = localpage; |
2763 | args.acl_pgbase = 0; | 3191 | args.acl_pgbase = 0; |
2764 | resp_len = args.acl_len = PAGE_SIZE; | 3192 | args.acl_len = PAGE_SIZE; |
2765 | } else { | 3193 | } else { |
2766 | resp_buf = buf; | 3194 | resp_buf = buf; |
2767 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); | 3195 | buf_to_pages(buf, buflen, args.acl_pages, &args.acl_pgbase); |
2768 | } | 3196 | } |
2769 | ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 3197 | ret = nfs4_call_sync(NFS_SERVER(inode), &msg, &args, &res, 0); |
2770 | if (ret) | 3198 | if (ret) |
2771 | goto out_free; | 3199 | goto out_free; |
2772 | if (resp_len > args.acl_len) | 3200 | if (res.acl_len > args.acl_len) |
2773 | nfs4_write_cached_acl(inode, NULL, resp_len); | 3201 | nfs4_write_cached_acl(inode, NULL, res.acl_len); |
2774 | else | 3202 | else |
2775 | nfs4_write_cached_acl(inode, resp_buf, resp_len); | 3203 | nfs4_write_cached_acl(inode, resp_buf, res.acl_len); |
2776 | if (buf) { | 3204 | if (buf) { |
2777 | ret = -ERANGE; | 3205 | ret = -ERANGE; |
2778 | if (resp_len > buflen) | 3206 | if (res.acl_len > buflen) |
2779 | goto out_free; | 3207 | goto out_free; |
2780 | if (localpage) | 3208 | if (localpage) |
2781 | memcpy(buf, resp_buf, resp_len); | 3209 | memcpy(buf, resp_buf, res.acl_len); |
2782 | } | 3210 | } |
2783 | ret = resp_len; | 3211 | ret = res.acl_len; |
2784 | out_free: | 3212 | out_free: |
2785 | if (localpage) | 3213 | if (localpage) |
2786 | __free_page(localpage); | 3214 | __free_page(localpage); |
@@ -2827,10 +3255,11 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
2827 | .acl_pages = pages, | 3255 | .acl_pages = pages, |
2828 | .acl_len = buflen, | 3256 | .acl_len = buflen, |
2829 | }; | 3257 | }; |
3258 | struct nfs_setaclres res; | ||
2830 | struct rpc_message msg = { | 3259 | struct rpc_message msg = { |
2831 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL], | 3260 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL], |
2832 | .rpc_argp = &arg, | 3261 | .rpc_argp = &arg, |
2833 | .rpc_resp = NULL, | 3262 | .rpc_resp = &res, |
2834 | }; | 3263 | }; |
2835 | int ret; | 3264 | int ret; |
2836 | 3265 | ||
@@ -2838,7 +3267,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl | |||
2838 | return -EOPNOTSUPP; | 3267 | return -EOPNOTSUPP; |
2839 | nfs_inode_return_delegation(inode); | 3268 | nfs_inode_return_delegation(inode); |
2840 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); | 3269 | buf_to_pages(buf, buflen, arg.acl_pages, &arg.acl_pgbase); |
2841 | ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0); | 3270 | ret = nfs4_call_sync(server, &msg, &arg, &res, 1); |
2842 | nfs_access_zap_cache(inode); | 3271 | nfs_access_zap_cache(inode); |
2843 | nfs_zap_acl_cache(inode); | 3272 | nfs_zap_acl_cache(inode); |
2844 | return ret; | 3273 | return ret; |
@@ -2857,10 +3286,8 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen | |||
2857 | } | 3286 | } |
2858 | 3287 | ||
2859 | static int | 3288 | static int |
2860 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) | 3289 | _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs_client *clp, struct nfs4_state *state) |
2861 | { | 3290 | { |
2862 | struct nfs_client *clp = server->nfs_client; | ||
2863 | |||
2864 | if (!clp || task->tk_status >= 0) | 3291 | if (!clp || task->tk_status >= 0) |
2865 | return 0; | 3292 | return 0; |
2866 | switch(task->tk_status) { | 3293 | switch(task->tk_status) { |
@@ -2879,8 +3306,23 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
2879 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); | 3306 | rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task); |
2880 | task->tk_status = 0; | 3307 | task->tk_status = 0; |
2881 | return -EAGAIN; | 3308 | return -EAGAIN; |
3309 | #if defined(CONFIG_NFS_V4_1) | ||
3310 | case -NFS4ERR_BADSESSION: | ||
3311 | case -NFS4ERR_BADSLOT: | ||
3312 | case -NFS4ERR_BAD_HIGH_SLOT: | ||
3313 | case -NFS4ERR_DEADSESSION: | ||
3314 | case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: | ||
3315 | case -NFS4ERR_SEQ_FALSE_RETRY: | ||
3316 | case -NFS4ERR_SEQ_MISORDERED: | ||
3317 | dprintk("%s ERROR %d, Reset session\n", __func__, | ||
3318 | task->tk_status); | ||
3319 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
3320 | task->tk_status = 0; | ||
3321 | return -EAGAIN; | ||
3322 | #endif /* CONFIG_NFS_V4_1 */ | ||
2882 | case -NFS4ERR_DELAY: | 3323 | case -NFS4ERR_DELAY: |
2883 | nfs_inc_server_stats(server, NFSIOS_DELAY); | 3324 | if (server) |
3325 | nfs_inc_server_stats(server, NFSIOS_DELAY); | ||
2884 | case -NFS4ERR_GRACE: | 3326 | case -NFS4ERR_GRACE: |
2885 | rpc_delay(task, NFS4_POLL_RETRY_MAX); | 3327 | rpc_delay(task, NFS4_POLL_RETRY_MAX); |
2886 | task->tk_status = 0; | 3328 | task->tk_status = 0; |
@@ -2893,6 +3335,12 @@ nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, | |||
2893 | return 0; | 3335 | return 0; |
2894 | } | 3336 | } |
2895 | 3337 | ||
3338 | static int | ||
3339 | nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state) | ||
3340 | { | ||
3341 | return _nfs4_async_handle_error(task, server, server->nfs_client, state); | ||
3342 | } | ||
3343 | |||
2896 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) | 3344 | int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short port, struct rpc_cred *cred) |
2897 | { | 3345 | { |
2898 | nfs4_verifier sc_verifier; | 3346 | nfs4_verifier sc_verifier; |
@@ -3000,6 +3448,10 @@ struct nfs4_delegreturndata { | |||
3000 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | 3448 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) |
3001 | { | 3449 | { |
3002 | struct nfs4_delegreturndata *data = calldata; | 3450 | struct nfs4_delegreturndata *data = calldata; |
3451 | |||
3452 | nfs4_sequence_done_free_slot(data->res.server, &data->res.seq_res, | ||
3453 | task->tk_status); | ||
3454 | |||
3003 | data->rpc_status = task->tk_status; | 3455 | data->rpc_status = task->tk_status; |
3004 | if (data->rpc_status == 0) | 3456 | if (data->rpc_status == 0) |
3005 | renew_lease(data->res.server, data->timestamp); | 3457 | renew_lease(data->res.server, data->timestamp); |
@@ -3010,7 +3462,25 @@ static void nfs4_delegreturn_release(void *calldata) | |||
3010 | kfree(calldata); | 3462 | kfree(calldata); |
3011 | } | 3463 | } |
3012 | 3464 | ||
3465 | #if defined(CONFIG_NFS_V4_1) | ||
3466 | static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data) | ||
3467 | { | ||
3468 | struct nfs4_delegreturndata *d_data; | ||
3469 | |||
3470 | d_data = (struct nfs4_delegreturndata *)data; | ||
3471 | |||
3472 | if (nfs4_setup_sequence(d_data->res.server->nfs_client, | ||
3473 | &d_data->args.seq_args, | ||
3474 | &d_data->res.seq_res, 1, task)) | ||
3475 | return; | ||
3476 | rpc_call_start(task); | ||
3477 | } | ||
3478 | #endif /* CONFIG_NFS_V4_1 */ | ||
3479 | |||
3013 | static const struct rpc_call_ops nfs4_delegreturn_ops = { | 3480 | static const struct rpc_call_ops nfs4_delegreturn_ops = { |
3481 | #if defined(CONFIG_NFS_V4_1) | ||
3482 | .rpc_call_prepare = nfs4_delegreturn_prepare, | ||
3483 | #endif /* CONFIG_NFS_V4_1 */ | ||
3014 | .rpc_call_done = nfs4_delegreturn_done, | 3484 | .rpc_call_done = nfs4_delegreturn_done, |
3015 | .rpc_release = nfs4_delegreturn_release, | 3485 | .rpc_release = nfs4_delegreturn_release, |
3016 | }; | 3486 | }; |
@@ -3032,7 +3502,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
3032 | }; | 3502 | }; |
3033 | int status = 0; | 3503 | int status = 0; |
3034 | 3504 | ||
3035 | data = kmalloc(sizeof(*data), GFP_KERNEL); | 3505 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
3036 | if (data == NULL) | 3506 | if (data == NULL) |
3037 | return -ENOMEM; | 3507 | return -ENOMEM; |
3038 | data->args.fhandle = &data->fh; | 3508 | data->args.fhandle = &data->fh; |
@@ -3042,6 +3512,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
3042 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); | 3512 | memcpy(&data->stateid, stateid, sizeof(data->stateid)); |
3043 | data->res.fattr = &data->fattr; | 3513 | data->res.fattr = &data->fattr; |
3044 | data->res.server = server; | 3514 | data->res.server = server; |
3515 | data->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
3045 | nfs_fattr_init(data->res.fattr); | 3516 | nfs_fattr_init(data->res.fattr); |
3046 | data->timestamp = jiffies; | 3517 | data->timestamp = jiffies; |
3047 | data->rpc_status = 0; | 3518 | data->rpc_status = 0; |
@@ -3127,7 +3598,7 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock | |||
3127 | goto out; | 3598 | goto out; |
3128 | lsp = request->fl_u.nfs4_fl.owner; | 3599 | lsp = request->fl_u.nfs4_fl.owner; |
3129 | arg.lock_owner.id = lsp->ls_id.id; | 3600 | arg.lock_owner.id = lsp->ls_id.id; |
3130 | status = rpc_call_sync(server->client, &msg, 0); | 3601 | status = nfs4_call_sync(server, &msg, &arg, &res, 1); |
3131 | switch (status) { | 3602 | switch (status) { |
3132 | case 0: | 3603 | case 0: |
3133 | request->fl_type = F_UNLCK; | 3604 | request->fl_type = F_UNLCK; |
@@ -3187,13 +3658,14 @@ static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl, | |||
3187 | struct nfs4_unlockdata *p; | 3658 | struct nfs4_unlockdata *p; |
3188 | struct inode *inode = lsp->ls_state->inode; | 3659 | struct inode *inode = lsp->ls_state->inode; |
3189 | 3660 | ||
3190 | p = kmalloc(sizeof(*p), GFP_KERNEL); | 3661 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
3191 | if (p == NULL) | 3662 | if (p == NULL) |
3192 | return NULL; | 3663 | return NULL; |
3193 | p->arg.fh = NFS_FH(inode); | 3664 | p->arg.fh = NFS_FH(inode); |
3194 | p->arg.fl = &p->fl; | 3665 | p->arg.fl = &p->fl; |
3195 | p->arg.seqid = seqid; | 3666 | p->arg.seqid = seqid; |
3196 | p->res.seqid = seqid; | 3667 | p->res.seqid = seqid; |
3668 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
3197 | p->arg.stateid = &lsp->ls_stateid; | 3669 | p->arg.stateid = &lsp->ls_stateid; |
3198 | p->lsp = lsp; | 3670 | p->lsp = lsp; |
3199 | atomic_inc(&lsp->ls_count); | 3671 | atomic_inc(&lsp->ls_count); |
@@ -3217,6 +3689,8 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3217 | { | 3689 | { |
3218 | struct nfs4_unlockdata *calldata = data; | 3690 | struct nfs4_unlockdata *calldata = data; |
3219 | 3691 | ||
3692 | nfs4_sequence_done(calldata->server, &calldata->res.seq_res, | ||
3693 | task->tk_status); | ||
3220 | if (RPC_ASSASSINATED(task)) | 3694 | if (RPC_ASSASSINATED(task)) |
3221 | return; | 3695 | return; |
3222 | switch (task->tk_status) { | 3696 | switch (task->tk_status) { |
@@ -3233,8 +3707,11 @@ static void nfs4_locku_done(struct rpc_task *task, void *data) | |||
3233 | break; | 3707 | break; |
3234 | default: | 3708 | default: |
3235 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) | 3709 | if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN) |
3236 | rpc_restart_call(task); | 3710 | nfs4_restart_rpc(task, |
3711 | calldata->server->nfs_client); | ||
3237 | } | 3712 | } |
3713 | nfs4_sequence_free_slot(calldata->server->nfs_client, | ||
3714 | &calldata->res.seq_res); | ||
3238 | } | 3715 | } |
3239 | 3716 | ||
3240 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) | 3717 | static void nfs4_locku_prepare(struct rpc_task *task, void *data) |
@@ -3249,6 +3726,10 @@ static void nfs4_locku_prepare(struct rpc_task *task, void *data) | |||
3249 | return; | 3726 | return; |
3250 | } | 3727 | } |
3251 | calldata->timestamp = jiffies; | 3728 | calldata->timestamp = jiffies; |
3729 | if (nfs4_setup_sequence(calldata->server->nfs_client, | ||
3730 | &calldata->arg.seq_args, | ||
3731 | &calldata->res.seq_res, 1, task)) | ||
3732 | return; | ||
3252 | rpc_call_start(task); | 3733 | rpc_call_start(task); |
3253 | } | 3734 | } |
3254 | 3735 | ||
@@ -3341,6 +3822,7 @@ struct nfs4_lockdata { | |||
3341 | unsigned long timestamp; | 3822 | unsigned long timestamp; |
3342 | int rpc_status; | 3823 | int rpc_status; |
3343 | int cancelled; | 3824 | int cancelled; |
3825 | struct nfs_server *server; | ||
3344 | }; | 3826 | }; |
3345 | 3827 | ||
3346 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | 3828 | static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, |
@@ -3366,7 +3848,9 @@ static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl, | |||
3366 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; | 3848 | p->arg.lock_owner.clientid = server->nfs_client->cl_clientid; |
3367 | p->arg.lock_owner.id = lsp->ls_id.id; | 3849 | p->arg.lock_owner.id = lsp->ls_id.id; |
3368 | p->res.lock_seqid = p->arg.lock_seqid; | 3850 | p->res.lock_seqid = p->arg.lock_seqid; |
3851 | p->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
3369 | p->lsp = lsp; | 3852 | p->lsp = lsp; |
3853 | p->server = server; | ||
3370 | atomic_inc(&lsp->ls_count); | 3854 | atomic_inc(&lsp->ls_count); |
3371 | p->ctx = get_nfs_open_context(ctx); | 3855 | p->ctx = get_nfs_open_context(ctx); |
3372 | memcpy(&p->fl, fl, sizeof(p->fl)); | 3856 | memcpy(&p->fl, fl, sizeof(p->fl)); |
@@ -3396,6 +3880,9 @@ static void nfs4_lock_prepare(struct rpc_task *task, void *calldata) | |||
3396 | } else | 3880 | } else |
3397 | data->arg.new_lock_owner = 0; | 3881 | data->arg.new_lock_owner = 0; |
3398 | data->timestamp = jiffies; | 3882 | data->timestamp = jiffies; |
3883 | if (nfs4_setup_sequence(data->server->nfs_client, &data->arg.seq_args, | ||
3884 | &data->res.seq_res, 1, task)) | ||
3885 | return; | ||
3399 | rpc_call_start(task); | 3886 | rpc_call_start(task); |
3400 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); | 3887 | dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status); |
3401 | } | 3888 | } |
@@ -3406,6 +3893,9 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata) | |||
3406 | 3893 | ||
3407 | dprintk("%s: begin!\n", __func__); | 3894 | dprintk("%s: begin!\n", __func__); |
3408 | 3895 | ||
3896 | nfs4_sequence_done_free_slot(data->server, &data->res.seq_res, | ||
3897 | task->tk_status); | ||
3898 | |||
3409 | data->rpc_status = task->tk_status; | 3899 | data->rpc_status = task->tk_status; |
3410 | if (RPC_ASSASSINATED(task)) | 3900 | if (RPC_ASSASSINATED(task)) |
3411 | goto out; | 3901 | goto out; |
@@ -3706,10 +4196,13 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
3706 | .page = page, | 4196 | .page = page, |
3707 | .bitmask = bitmask, | 4197 | .bitmask = bitmask, |
3708 | }; | 4198 | }; |
4199 | struct nfs4_fs_locations_res res = { | ||
4200 | .fs_locations = fs_locations, | ||
4201 | }; | ||
3709 | struct rpc_message msg = { | 4202 | struct rpc_message msg = { |
3710 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS], | 4203 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS], |
3711 | .rpc_argp = &args, | 4204 | .rpc_argp = &args, |
3712 | .rpc_resp = fs_locations, | 4205 | .rpc_resp = &res, |
3713 | }; | 4206 | }; |
3714 | int status; | 4207 | int status; |
3715 | 4208 | ||
@@ -3717,24 +4210,720 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name, | |||
3717 | nfs_fattr_init(&fs_locations->fattr); | 4210 | nfs_fattr_init(&fs_locations->fattr); |
3718 | fs_locations->server = server; | 4211 | fs_locations->server = server; |
3719 | fs_locations->nlocations = 0; | 4212 | fs_locations->nlocations = 0; |
3720 | status = rpc_call_sync(server->client, &msg, 0); | 4213 | status = nfs4_call_sync(server, &msg, &args, &res, 0); |
3721 | nfs_fixup_referral_attributes(&fs_locations->fattr); | 4214 | nfs_fixup_referral_attributes(&fs_locations->fattr); |
3722 | dprintk("%s: returned status = %d\n", __func__, status); | 4215 | dprintk("%s: returned status = %d\n", __func__, status); |
3723 | return status; | 4216 | return status; |
3724 | } | 4217 | } |
3725 | 4218 | ||
3726 | struct nfs4_state_recovery_ops nfs4_reboot_recovery_ops = { | 4219 | #ifdef CONFIG_NFS_V4_1 |
4220 | /* | ||
4221 | * nfs4_proc_exchange_id() | ||
4222 | * | ||
4223 | * Since the clientid has expired, all compounds using sessions | ||
4224 | * associated with the stale clientid will be returning | ||
4225 | * NFS4ERR_BADSESSION in the sequence operation, and will therefore | ||
4226 | * be in some phase of session reset. | ||
4227 | */ | ||
4228 | static int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) | ||
4229 | { | ||
4230 | nfs4_verifier verifier; | ||
4231 | struct nfs41_exchange_id_args args = { | ||
4232 | .client = clp, | ||
4233 | .flags = clp->cl_exchange_flags, | ||
4234 | }; | ||
4235 | struct nfs41_exchange_id_res res = { | ||
4236 | .client = clp, | ||
4237 | }; | ||
4238 | int status; | ||
4239 | struct rpc_message msg = { | ||
4240 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_EXCHANGE_ID], | ||
4241 | .rpc_argp = &args, | ||
4242 | .rpc_resp = &res, | ||
4243 | .rpc_cred = cred, | ||
4244 | }; | ||
4245 | __be32 *p; | ||
4246 | |||
4247 | dprintk("--> %s\n", __func__); | ||
4248 | BUG_ON(clp == NULL); | ||
4249 | |||
4250 | p = (u32 *)verifier.data; | ||
4251 | *p++ = htonl((u32)clp->cl_boot_time.tv_sec); | ||
4252 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); | ||
4253 | args.verifier = &verifier; | ||
4254 | |||
4255 | while (1) { | ||
4256 | args.id_len = scnprintf(args.id, sizeof(args.id), | ||
4257 | "%s/%s %u", | ||
4258 | clp->cl_ipaddr, | ||
4259 | rpc_peeraddr2str(clp->cl_rpcclient, | ||
4260 | RPC_DISPLAY_ADDR), | ||
4261 | clp->cl_id_uniquifier); | ||
4262 | |||
4263 | status = rpc_call_sync(clp->cl_rpcclient, &msg, 0); | ||
4264 | |||
4265 | if (status != NFS4ERR_CLID_INUSE) | ||
4266 | break; | ||
4267 | |||
4268 | if (signalled()) | ||
4269 | break; | ||
4270 | |||
4271 | if (++clp->cl_id_uniquifier == 0) | ||
4272 | break; | ||
4273 | } | ||
4274 | |||
4275 | dprintk("<-- %s status= %d\n", __func__, status); | ||
4276 | return status; | ||
4277 | } | ||
4278 | |||
4279 | struct nfs4_get_lease_time_data { | ||
4280 | struct nfs4_get_lease_time_args *args; | ||
4281 | struct nfs4_get_lease_time_res *res; | ||
4282 | struct nfs_client *clp; | ||
4283 | }; | ||
4284 | |||
4285 | static void nfs4_get_lease_time_prepare(struct rpc_task *task, | ||
4286 | void *calldata) | ||
4287 | { | ||
4288 | int ret; | ||
4289 | struct nfs4_get_lease_time_data *data = | ||
4290 | (struct nfs4_get_lease_time_data *)calldata; | ||
4291 | |||
4292 | dprintk("--> %s\n", __func__); | ||
4293 | /* just setup sequence, do not trigger session recovery | ||
4294 | since we're invoked within one */ | ||
4295 | ret = nfs41_setup_sequence(data->clp->cl_session, | ||
4296 | &data->args->la_seq_args, | ||
4297 | &data->res->lr_seq_res, 0, task); | ||
4298 | |||
4299 | BUG_ON(ret == -EAGAIN); | ||
4300 | rpc_call_start(task); | ||
4301 | dprintk("<-- %s\n", __func__); | ||
4302 | } | ||
4303 | |||
4304 | /* | ||
4305 | * Called from nfs4_state_manager thread for session setup, so don't recover | ||
4306 | * from sequence operation or clientid errors. | ||
4307 | */ | ||
4308 | static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata) | ||
4309 | { | ||
4310 | struct nfs4_get_lease_time_data *data = | ||
4311 | (struct nfs4_get_lease_time_data *)calldata; | ||
4312 | |||
4313 | dprintk("--> %s\n", __func__); | ||
4314 | nfs41_sequence_done(data->clp, &data->res->lr_seq_res, task->tk_status); | ||
4315 | switch (task->tk_status) { | ||
4316 | case -NFS4ERR_DELAY: | ||
4317 | case -NFS4ERR_GRACE: | ||
4318 | dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status); | ||
4319 | rpc_delay(task, NFS4_POLL_RETRY_MIN); | ||
4320 | task->tk_status = 0; | ||
4321 | nfs4_restart_rpc(task, data->clp); | ||
4322 | return; | ||
4323 | } | ||
4324 | nfs41_sequence_free_slot(data->clp, &data->res->lr_seq_res); | ||
4325 | dprintk("<-- %s\n", __func__); | ||
4326 | } | ||
4327 | |||
4328 | struct rpc_call_ops nfs4_get_lease_time_ops = { | ||
4329 | .rpc_call_prepare = nfs4_get_lease_time_prepare, | ||
4330 | .rpc_call_done = nfs4_get_lease_time_done, | ||
4331 | }; | ||
4332 | |||
4333 | int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo) | ||
4334 | { | ||
4335 | struct rpc_task *task; | ||
4336 | struct nfs4_get_lease_time_args args; | ||
4337 | struct nfs4_get_lease_time_res res = { | ||
4338 | .lr_fsinfo = fsinfo, | ||
4339 | }; | ||
4340 | struct nfs4_get_lease_time_data data = { | ||
4341 | .args = &args, | ||
4342 | .res = &res, | ||
4343 | .clp = clp, | ||
4344 | }; | ||
4345 | struct rpc_message msg = { | ||
4346 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GET_LEASE_TIME], | ||
4347 | .rpc_argp = &args, | ||
4348 | .rpc_resp = &res, | ||
4349 | }; | ||
4350 | struct rpc_task_setup task_setup = { | ||
4351 | .rpc_client = clp->cl_rpcclient, | ||
4352 | .rpc_message = &msg, | ||
4353 | .callback_ops = &nfs4_get_lease_time_ops, | ||
4354 | .callback_data = &data | ||
4355 | }; | ||
4356 | int status; | ||
4357 | |||
4358 | res.lr_seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
4359 | dprintk("--> %s\n", __func__); | ||
4360 | task = rpc_run_task(&task_setup); | ||
4361 | |||
4362 | if (IS_ERR(task)) | ||
4363 | status = PTR_ERR(task); | ||
4364 | else { | ||
4365 | status = task->tk_status; | ||
4366 | rpc_put_task(task); | ||
4367 | } | ||
4368 | dprintk("<-- %s return %d\n", __func__, status); | ||
4369 | |||
4370 | return status; | ||
4371 | } | ||
4372 | |||
4373 | /* | ||
4374 | * Reset a slot table | ||
4375 | */ | ||
4376 | static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, int max_slots, | ||
4377 | int old_max_slots, int ivalue) | ||
4378 | { | ||
4379 | int i; | ||
4380 | int ret = 0; | ||
4381 | |||
4382 | dprintk("--> %s: max_reqs=%u, tbl %p\n", __func__, max_slots, tbl); | ||
4383 | |||
4384 | /* | ||
4385 | * Until we have dynamic slot table adjustment, insist | ||
4386 | * upon the same slot table size | ||
4387 | */ | ||
4388 | if (max_slots != old_max_slots) { | ||
4389 | dprintk("%s reset slot table does't match old\n", | ||
4390 | __func__); | ||
4391 | ret = -EINVAL; /*XXX NFS4ERR_REQ_TOO_BIG ? */ | ||
4392 | goto out; | ||
4393 | } | ||
4394 | spin_lock(&tbl->slot_tbl_lock); | ||
4395 | for (i = 0; i < max_slots; ++i) | ||
4396 | tbl->slots[i].seq_nr = ivalue; | ||
4397 | tbl->highest_used_slotid = -1; | ||
4398 | spin_unlock(&tbl->slot_tbl_lock); | ||
4399 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | ||
4400 | tbl, tbl->slots, tbl->max_slots); | ||
4401 | out: | ||
4402 | dprintk("<-- %s: return %d\n", __func__, ret); | ||
4403 | return ret; | ||
4404 | } | ||
4405 | |||
4406 | /* | ||
4407 | * Reset the forechannel and backchannel slot tables | ||
4408 | */ | ||
4409 | static int nfs4_reset_slot_tables(struct nfs4_session *session) | ||
4410 | { | ||
4411 | int status; | ||
4412 | |||
4413 | status = nfs4_reset_slot_table(&session->fc_slot_table, | ||
4414 | session->fc_attrs.max_reqs, | ||
4415 | session->fc_slot_table.max_slots, | ||
4416 | 1); | ||
4417 | if (status) | ||
4418 | return status; | ||
4419 | |||
4420 | status = nfs4_reset_slot_table(&session->bc_slot_table, | ||
4421 | session->bc_attrs.max_reqs, | ||
4422 | session->bc_slot_table.max_slots, | ||
4423 | 0); | ||
4424 | return status; | ||
4425 | } | ||
4426 | |||
4427 | /* Destroy the slot table */ | ||
4428 | static void nfs4_destroy_slot_tables(struct nfs4_session *session) | ||
4429 | { | ||
4430 | if (session->fc_slot_table.slots != NULL) { | ||
4431 | kfree(session->fc_slot_table.slots); | ||
4432 | session->fc_slot_table.slots = NULL; | ||
4433 | } | ||
4434 | if (session->bc_slot_table.slots != NULL) { | ||
4435 | kfree(session->bc_slot_table.slots); | ||
4436 | session->bc_slot_table.slots = NULL; | ||
4437 | } | ||
4438 | return; | ||
4439 | } | ||
4440 | |||
4441 | /* | ||
4442 | * Initialize slot table | ||
4443 | */ | ||
4444 | static int nfs4_init_slot_table(struct nfs4_slot_table *tbl, | ||
4445 | int max_slots, int ivalue) | ||
4446 | { | ||
4447 | int i; | ||
4448 | struct nfs4_slot *slot; | ||
4449 | int ret = -ENOMEM; | ||
4450 | |||
4451 | BUG_ON(max_slots > NFS4_MAX_SLOT_TABLE); | ||
4452 | |||
4453 | dprintk("--> %s: max_reqs=%u\n", __func__, max_slots); | ||
4454 | |||
4455 | slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_KERNEL); | ||
4456 | if (!slot) | ||
4457 | goto out; | ||
4458 | for (i = 0; i < max_slots; ++i) | ||
4459 | slot[i].seq_nr = ivalue; | ||
4460 | ret = 0; | ||
4461 | |||
4462 | spin_lock(&tbl->slot_tbl_lock); | ||
4463 | if (tbl->slots != NULL) { | ||
4464 | spin_unlock(&tbl->slot_tbl_lock); | ||
4465 | dprintk("%s: slot table already initialized. tbl=%p slots=%p\n", | ||
4466 | __func__, tbl, tbl->slots); | ||
4467 | WARN_ON(1); | ||
4468 | goto out_free; | ||
4469 | } | ||
4470 | tbl->max_slots = max_slots; | ||
4471 | tbl->slots = slot; | ||
4472 | tbl->highest_used_slotid = -1; /* no slot is currently used */ | ||
4473 | spin_unlock(&tbl->slot_tbl_lock); | ||
4474 | dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__, | ||
4475 | tbl, tbl->slots, tbl->max_slots); | ||
4476 | out: | ||
4477 | dprintk("<-- %s: return %d\n", __func__, ret); | ||
4478 | return ret; | ||
4479 | |||
4480 | out_free: | ||
4481 | kfree(slot); | ||
4482 | goto out; | ||
4483 | } | ||
4484 | |||
4485 | /* | ||
4486 | * Initialize the forechannel and backchannel tables | ||
4487 | */ | ||
4488 | static int nfs4_init_slot_tables(struct nfs4_session *session) | ||
4489 | { | ||
4490 | int status; | ||
4491 | |||
4492 | status = nfs4_init_slot_table(&session->fc_slot_table, | ||
4493 | session->fc_attrs.max_reqs, 1); | ||
4494 | if (status) | ||
4495 | return status; | ||
4496 | |||
4497 | status = nfs4_init_slot_table(&session->bc_slot_table, | ||
4498 | session->bc_attrs.max_reqs, 0); | ||
4499 | if (status) | ||
4500 | nfs4_destroy_slot_tables(session); | ||
4501 | |||
4502 | return status; | ||
4503 | } | ||
4504 | |||
4505 | struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | ||
4506 | { | ||
4507 | struct nfs4_session *session; | ||
4508 | struct nfs4_slot_table *tbl; | ||
4509 | |||
4510 | session = kzalloc(sizeof(struct nfs4_session), GFP_KERNEL); | ||
4511 | if (!session) | ||
4512 | return NULL; | ||
4513 | |||
4514 | set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state); | ||
4515 | /* | ||
4516 | * The create session reply races with the server back | ||
4517 | * channel probe. Mark the client NFS_CS_SESSION_INITING | ||
4518 | * so that the client back channel can find the | ||
4519 | * nfs_client struct | ||
4520 | */ | ||
4521 | clp->cl_cons_state = NFS_CS_SESSION_INITING; | ||
4522 | |||
4523 | tbl = &session->fc_slot_table; | ||
4524 | spin_lock_init(&tbl->slot_tbl_lock); | ||
4525 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table"); | ||
4526 | |||
4527 | tbl = &session->bc_slot_table; | ||
4528 | spin_lock_init(&tbl->slot_tbl_lock); | ||
4529 | rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table"); | ||
4530 | |||
4531 | session->clp = clp; | ||
4532 | return session; | ||
4533 | } | ||
4534 | |||
4535 | void nfs4_destroy_session(struct nfs4_session *session) | ||
4536 | { | ||
4537 | nfs4_proc_destroy_session(session); | ||
4538 | dprintk("%s Destroy backchannel for xprt %p\n", | ||
4539 | __func__, session->clp->cl_rpcclient->cl_xprt); | ||
4540 | xprt_destroy_backchannel(session->clp->cl_rpcclient->cl_xprt, | ||
4541 | NFS41_BC_MIN_CALLBACKS); | ||
4542 | nfs4_destroy_slot_tables(session); | ||
4543 | kfree(session); | ||
4544 | } | ||
4545 | |||
4546 | /* | ||
4547 | * Initialize the values to be used by the client in CREATE_SESSION | ||
4548 | * If nfs4_init_session set the fore channel request and response sizes, | ||
4549 | * use them. | ||
4550 | * | ||
4551 | * Set the back channel max_resp_sz_cached to zero to force the client to | ||
4552 | * always set csa_cachethis to FALSE because the current implementation | ||
4553 | * of the back channel DRC only supports caching the CB_SEQUENCE operation. | ||
4554 | */ | ||
4555 | static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args) | ||
4556 | { | ||
4557 | struct nfs4_session *session = args->client->cl_session; | ||
4558 | unsigned int mxrqst_sz = session->fc_attrs.max_rqst_sz, | ||
4559 | mxresp_sz = session->fc_attrs.max_resp_sz; | ||
4560 | |||
4561 | if (mxrqst_sz == 0) | ||
4562 | mxrqst_sz = NFS_MAX_FILE_IO_SIZE; | ||
4563 | if (mxresp_sz == 0) | ||
4564 | mxresp_sz = NFS_MAX_FILE_IO_SIZE; | ||
4565 | /* Fore channel attributes */ | ||
4566 | args->fc_attrs.headerpadsz = 0; | ||
4567 | args->fc_attrs.max_rqst_sz = mxrqst_sz; | ||
4568 | args->fc_attrs.max_resp_sz = mxresp_sz; | ||
4569 | args->fc_attrs.max_resp_sz_cached = mxresp_sz; | ||
4570 | args->fc_attrs.max_ops = NFS4_MAX_OPS; | ||
4571 | args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs; | ||
4572 | |||
4573 | dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u " | ||
4574 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", | ||
4575 | __func__, | ||
4576 | args->fc_attrs.max_rqst_sz, args->fc_attrs.max_resp_sz, | ||
4577 | args->fc_attrs.max_resp_sz_cached, args->fc_attrs.max_ops, | ||
4578 | args->fc_attrs.max_reqs); | ||
4579 | |||
4580 | /* Back channel attributes */ | ||
4581 | args->bc_attrs.headerpadsz = 0; | ||
4582 | args->bc_attrs.max_rqst_sz = PAGE_SIZE; | ||
4583 | args->bc_attrs.max_resp_sz = PAGE_SIZE; | ||
4584 | args->bc_attrs.max_resp_sz_cached = 0; | ||
4585 | args->bc_attrs.max_ops = NFS4_MAX_BACK_CHANNEL_OPS; | ||
4586 | args->bc_attrs.max_reqs = 1; | ||
4587 | |||
4588 | dprintk("%s: Back Channel : max_rqst_sz=%u max_resp_sz=%u " | ||
4589 | "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n", | ||
4590 | __func__, | ||
4591 | args->bc_attrs.max_rqst_sz, args->bc_attrs.max_resp_sz, | ||
4592 | args->bc_attrs.max_resp_sz_cached, args->bc_attrs.max_ops, | ||
4593 | args->bc_attrs.max_reqs); | ||
4594 | } | ||
4595 | |||
4596 | static int _verify_channel_attr(char *chan, char *attr_name, u32 sent, u32 rcvd) | ||
4597 | { | ||
4598 | if (rcvd <= sent) | ||
4599 | return 0; | ||
4600 | printk(KERN_WARNING "%s: Session INVALID: %s channel %s increased. " | ||
4601 | "sent=%u rcvd=%u\n", __func__, chan, attr_name, sent, rcvd); | ||
4602 | return -EINVAL; | ||
4603 | } | ||
4604 | |||
4605 | #define _verify_fore_channel_attr(_name_) \ | ||
4606 | _verify_channel_attr("fore", #_name_, \ | ||
4607 | args->fc_attrs._name_, \ | ||
4608 | session->fc_attrs._name_) | ||
4609 | |||
4610 | #define _verify_back_channel_attr(_name_) \ | ||
4611 | _verify_channel_attr("back", #_name_, \ | ||
4612 | args->bc_attrs._name_, \ | ||
4613 | session->bc_attrs._name_) | ||
4614 | |||
4615 | /* | ||
4616 | * The server is not allowed to increase the fore channel header pad size, | ||
4617 | * maximum response size, or maximum number of operations. | ||
4618 | * | ||
4619 | * The back channel attributes are only negotiatied down: We send what the | ||
4620 | * (back channel) server insists upon. | ||
4621 | */ | ||
4622 | static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args, | ||
4623 | struct nfs4_session *session) | ||
4624 | { | ||
4625 | int ret = 0; | ||
4626 | |||
4627 | ret |= _verify_fore_channel_attr(headerpadsz); | ||
4628 | ret |= _verify_fore_channel_attr(max_resp_sz); | ||
4629 | ret |= _verify_fore_channel_attr(max_ops); | ||
4630 | |||
4631 | ret |= _verify_back_channel_attr(headerpadsz); | ||
4632 | ret |= _verify_back_channel_attr(max_rqst_sz); | ||
4633 | ret |= _verify_back_channel_attr(max_resp_sz); | ||
4634 | ret |= _verify_back_channel_attr(max_resp_sz_cached); | ||
4635 | ret |= _verify_back_channel_attr(max_ops); | ||
4636 | ret |= _verify_back_channel_attr(max_reqs); | ||
4637 | |||
4638 | return ret; | ||
4639 | } | ||
4640 | |||
4641 | static int _nfs4_proc_create_session(struct nfs_client *clp) | ||
4642 | { | ||
4643 | struct nfs4_session *session = clp->cl_session; | ||
4644 | struct nfs41_create_session_args args = { | ||
4645 | .client = clp, | ||
4646 | .cb_program = NFS4_CALLBACK, | ||
4647 | }; | ||
4648 | struct nfs41_create_session_res res = { | ||
4649 | .client = clp, | ||
4650 | }; | ||
4651 | struct rpc_message msg = { | ||
4652 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE_SESSION], | ||
4653 | .rpc_argp = &args, | ||
4654 | .rpc_resp = &res, | ||
4655 | }; | ||
4656 | int status; | ||
4657 | |||
4658 | nfs4_init_channel_attrs(&args); | ||
4659 | args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN); | ||
4660 | |||
4661 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); | ||
4662 | |||
4663 | if (!status) | ||
4664 | /* Verify the session's negotiated channel_attrs values */ | ||
4665 | status = nfs4_verify_channel_attrs(&args, session); | ||
4666 | if (!status) { | ||
4667 | /* Increment the clientid slot sequence id */ | ||
4668 | clp->cl_seqid++; | ||
4669 | } | ||
4670 | |||
4671 | return status; | ||
4672 | } | ||
4673 | |||
4674 | /* | ||
4675 | * Issues a CREATE_SESSION operation to the server. | ||
4676 | * It is the responsibility of the caller to verify the session is | ||
4677 | * expired before calling this routine. | ||
4678 | */ | ||
4679 | int nfs4_proc_create_session(struct nfs_client *clp, int reset) | ||
4680 | { | ||
4681 | int status; | ||
4682 | unsigned *ptr; | ||
4683 | struct nfs_fsinfo fsinfo; | ||
4684 | struct nfs4_session *session = clp->cl_session; | ||
4685 | |||
4686 | dprintk("--> %s clp=%p session=%p\n", __func__, clp, session); | ||
4687 | |||
4688 | status = _nfs4_proc_create_session(clp); | ||
4689 | if (status) | ||
4690 | goto out; | ||
4691 | |||
4692 | /* Init or reset the fore channel */ | ||
4693 | if (reset) | ||
4694 | status = nfs4_reset_slot_tables(session); | ||
4695 | else | ||
4696 | status = nfs4_init_slot_tables(session); | ||
4697 | dprintk("fore channel slot table initialization returned %d\n", status); | ||
4698 | if (status) | ||
4699 | goto out; | ||
4700 | |||
4701 | ptr = (unsigned *)&session->sess_id.data[0]; | ||
4702 | dprintk("%s client>seqid %d sessionid %u:%u:%u:%u\n", __func__, | ||
4703 | clp->cl_seqid, ptr[0], ptr[1], ptr[2], ptr[3]); | ||
4704 | |||
4705 | if (reset) | ||
4706 | /* Lease time is aleady set */ | ||
4707 | goto out; | ||
4708 | |||
4709 | /* Get the lease time */ | ||
4710 | status = nfs4_proc_get_lease_time(clp, &fsinfo); | ||
4711 | if (status == 0) { | ||
4712 | /* Update lease time and schedule renewal */ | ||
4713 | spin_lock(&clp->cl_lock); | ||
4714 | clp->cl_lease_time = fsinfo.lease_time * HZ; | ||
4715 | clp->cl_last_renewal = jiffies; | ||
4716 | clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); | ||
4717 | spin_unlock(&clp->cl_lock); | ||
4718 | |||
4719 | nfs4_schedule_state_renewal(clp); | ||
4720 | } | ||
4721 | out: | ||
4722 | dprintk("<-- %s\n", __func__); | ||
4723 | return status; | ||
4724 | } | ||
4725 | |||
4726 | /* | ||
4727 | * Issue the over-the-wire RPC DESTROY_SESSION. | ||
4728 | * The caller must serialize access to this routine. | ||
4729 | */ | ||
4730 | int nfs4_proc_destroy_session(struct nfs4_session *session) | ||
4731 | { | ||
4732 | int status = 0; | ||
4733 | struct rpc_message msg; | ||
4734 | |||
4735 | dprintk("--> nfs4_proc_destroy_session\n"); | ||
4736 | |||
4737 | /* session is still being setup */ | ||
4738 | if (session->clp->cl_cons_state != NFS_CS_READY) | ||
4739 | return status; | ||
4740 | |||
4741 | msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DESTROY_SESSION]; | ||
4742 | msg.rpc_argp = session; | ||
4743 | msg.rpc_resp = NULL; | ||
4744 | msg.rpc_cred = NULL; | ||
4745 | status = rpc_call_sync(session->clp->cl_rpcclient, &msg, 0); | ||
4746 | |||
4747 | if (status) | ||
4748 | printk(KERN_WARNING | ||
4749 | "Got error %d from the server on DESTROY_SESSION. " | ||
4750 | "Session has been destroyed regardless...\n", status); | ||
4751 | |||
4752 | dprintk("<-- nfs4_proc_destroy_session\n"); | ||
4753 | return status; | ||
4754 | } | ||
4755 | |||
4756 | /* | ||
4757 | * Renew the cl_session lease. | ||
4758 | */ | ||
4759 | static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred) | ||
4760 | { | ||
4761 | struct nfs4_sequence_args args; | ||
4762 | struct nfs4_sequence_res res; | ||
4763 | |||
4764 | struct rpc_message msg = { | ||
4765 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | ||
4766 | .rpc_argp = &args, | ||
4767 | .rpc_resp = &res, | ||
4768 | .rpc_cred = cred, | ||
4769 | }; | ||
4770 | |||
4771 | args.sa_cache_this = 0; | ||
4772 | |||
4773 | return nfs4_call_sync_sequence(clp, clp->cl_rpcclient, &msg, &args, | ||
4774 | &res, 0); | ||
4775 | } | ||
4776 | |||
4777 | void nfs41_sequence_call_done(struct rpc_task *task, void *data) | ||
4778 | { | ||
4779 | struct nfs_client *clp = (struct nfs_client *)data; | ||
4780 | |||
4781 | nfs41_sequence_done(clp, task->tk_msg.rpc_resp, task->tk_status); | ||
4782 | |||
4783 | if (task->tk_status < 0) { | ||
4784 | dprintk("%s ERROR %d\n", __func__, task->tk_status); | ||
4785 | |||
4786 | if (_nfs4_async_handle_error(task, NULL, clp, NULL) | ||
4787 | == -EAGAIN) { | ||
4788 | nfs4_restart_rpc(task, clp); | ||
4789 | return; | ||
4790 | } | ||
4791 | } | ||
4792 | nfs41_sequence_free_slot(clp, task->tk_msg.rpc_resp); | ||
4793 | dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred); | ||
4794 | |||
4795 | put_rpccred(task->tk_msg.rpc_cred); | ||
4796 | kfree(task->tk_msg.rpc_argp); | ||
4797 | kfree(task->tk_msg.rpc_resp); | ||
4798 | |||
4799 | dprintk("<-- %s\n", __func__); | ||
4800 | } | ||
4801 | |||
4802 | static void nfs41_sequence_prepare(struct rpc_task *task, void *data) | ||
4803 | { | ||
4804 | struct nfs_client *clp; | ||
4805 | struct nfs4_sequence_args *args; | ||
4806 | struct nfs4_sequence_res *res; | ||
4807 | |||
4808 | clp = (struct nfs_client *)data; | ||
4809 | args = task->tk_msg.rpc_argp; | ||
4810 | res = task->tk_msg.rpc_resp; | ||
4811 | |||
4812 | if (nfs4_setup_sequence(clp, args, res, 0, task)) | ||
4813 | return; | ||
4814 | rpc_call_start(task); | ||
4815 | } | ||
4816 | |||
4817 | static const struct rpc_call_ops nfs41_sequence_ops = { | ||
4818 | .rpc_call_done = nfs41_sequence_call_done, | ||
4819 | .rpc_call_prepare = nfs41_sequence_prepare, | ||
4820 | }; | ||
4821 | |||
4822 | static int nfs41_proc_async_sequence(struct nfs_client *clp, | ||
4823 | struct rpc_cred *cred) | ||
4824 | { | ||
4825 | struct nfs4_sequence_args *args; | ||
4826 | struct nfs4_sequence_res *res; | ||
4827 | struct rpc_message msg = { | ||
4828 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE], | ||
4829 | .rpc_cred = cred, | ||
4830 | }; | ||
4831 | |||
4832 | args = kzalloc(sizeof(*args), GFP_KERNEL); | ||
4833 | if (!args) | ||
4834 | return -ENOMEM; | ||
4835 | res = kzalloc(sizeof(*res), GFP_KERNEL); | ||
4836 | if (!res) { | ||
4837 | kfree(args); | ||
4838 | return -ENOMEM; | ||
4839 | } | ||
4840 | res->sr_slotid = NFS4_MAX_SLOT_TABLE; | ||
4841 | msg.rpc_argp = args; | ||
4842 | msg.rpc_resp = res; | ||
4843 | |||
4844 | return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT, | ||
4845 | &nfs41_sequence_ops, (void *)clp); | ||
4846 | } | ||
4847 | |||
4848 | #endif /* CONFIG_NFS_V4_1 */ | ||
4849 | |||
4850 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { | ||
3727 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, | 4851 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, |
3728 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, | 4852 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, |
3729 | .recover_open = nfs4_open_reclaim, | 4853 | .recover_open = nfs4_open_reclaim, |
3730 | .recover_lock = nfs4_lock_reclaim, | 4854 | .recover_lock = nfs4_lock_reclaim, |
4855 | .establish_clid = nfs4_init_clientid, | ||
4856 | .get_clid_cred = nfs4_get_setclientid_cred, | ||
3731 | }; | 4857 | }; |
3732 | 4858 | ||
3733 | struct nfs4_state_recovery_ops nfs4_nograce_recovery_ops = { | 4859 | #if defined(CONFIG_NFS_V4_1) |
4860 | struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = { | ||
4861 | .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT, | ||
4862 | .state_flag_bit = NFS_STATE_RECLAIM_REBOOT, | ||
4863 | .recover_open = nfs4_open_reclaim, | ||
4864 | .recover_lock = nfs4_lock_reclaim, | ||
4865 | .establish_clid = nfs4_proc_exchange_id, | ||
4866 | .get_clid_cred = nfs4_get_exchange_id_cred, | ||
4867 | }; | ||
4868 | #endif /* CONFIG_NFS_V4_1 */ | ||
4869 | |||
4870 | struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = { | ||
3734 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, | 4871 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, |
3735 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | 4872 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, |
3736 | .recover_open = nfs4_open_expired, | 4873 | .recover_open = nfs4_open_expired, |
3737 | .recover_lock = nfs4_lock_expired, | 4874 | .recover_lock = nfs4_lock_expired, |
4875 | .establish_clid = nfs4_init_clientid, | ||
4876 | .get_clid_cred = nfs4_get_setclientid_cred, | ||
4877 | }; | ||
4878 | |||
4879 | #if defined(CONFIG_NFS_V4_1) | ||
4880 | struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = { | ||
4881 | .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, | ||
4882 | .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, | ||
4883 | .recover_open = nfs4_open_expired, | ||
4884 | .recover_lock = nfs4_lock_expired, | ||
4885 | .establish_clid = nfs4_proc_exchange_id, | ||
4886 | .get_clid_cred = nfs4_get_exchange_id_cred, | ||
4887 | }; | ||
4888 | #endif /* CONFIG_NFS_V4_1 */ | ||
4889 | |||
4890 | struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = { | ||
4891 | .sched_state_renewal = nfs4_proc_async_renew, | ||
4892 | .get_state_renewal_cred_locked = nfs4_get_renew_cred_locked, | ||
4893 | .renew_lease = nfs4_proc_renew, | ||
4894 | }; | ||
4895 | |||
4896 | #if defined(CONFIG_NFS_V4_1) | ||
4897 | struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = { | ||
4898 | .sched_state_renewal = nfs41_proc_async_sequence, | ||
4899 | .get_state_renewal_cred_locked = nfs4_get_machine_cred_locked, | ||
4900 | .renew_lease = nfs4_proc_sequence, | ||
4901 | }; | ||
4902 | #endif | ||
4903 | |||
4904 | /* | ||
4905 | * Per minor version reboot and network partition recovery ops | ||
4906 | */ | ||
4907 | |||
4908 | struct nfs4_state_recovery_ops *nfs4_reboot_recovery_ops[] = { | ||
4909 | &nfs40_reboot_recovery_ops, | ||
4910 | #if defined(CONFIG_NFS_V4_1) | ||
4911 | &nfs41_reboot_recovery_ops, | ||
4912 | #endif | ||
4913 | }; | ||
4914 | |||
4915 | struct nfs4_state_recovery_ops *nfs4_nograce_recovery_ops[] = { | ||
4916 | &nfs40_nograce_recovery_ops, | ||
4917 | #if defined(CONFIG_NFS_V4_1) | ||
4918 | &nfs41_nograce_recovery_ops, | ||
4919 | #endif | ||
4920 | }; | ||
4921 | |||
4922 | struct nfs4_state_maintenance_ops *nfs4_state_renewal_ops[] = { | ||
4923 | &nfs40_state_renewal_ops, | ||
4924 | #if defined(CONFIG_NFS_V4_1) | ||
4925 | &nfs41_state_renewal_ops, | ||
4926 | #endif | ||
3738 | }; | 4927 | }; |
3739 | 4928 | ||
3740 | static const struct inode_operations nfs4_file_inode_operations = { | 4929 | static const struct inode_operations nfs4_file_inode_operations = { |