diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 685 |
1 files changed, 319 insertions, 366 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 980a216a48c8..2153f9bdbebd 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -55,6 +55,7 @@ | |||
55 | #include <linux/lockd/bind.h> | 55 | #include <linux/lockd/bind.h> |
56 | #include <linux/module.h> | 56 | #include <linux/module.h> |
57 | #include <linux/sunrpc/svcauth_gss.h> | 57 | #include <linux/sunrpc/svcauth_gss.h> |
58 | #include <linux/sunrpc/clnt.h> | ||
58 | 59 | ||
59 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 60 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
60 | 61 | ||
@@ -413,36 +414,65 @@ gen_sessionid(struct nfsd4_session *ses) | |||
413 | } | 414 | } |
414 | 415 | ||
415 | /* | 416 | /* |
416 | * Give the client the number of slots it requests bound by | 417 | * The protocol defines ca_maxresponssize_cached to include the size of |
417 | * NFSD_MAX_SLOTS_PER_SESSION and by sv_drc_max_pages. | 418 | * the rpc header, but all we need to cache is the data starting after |
419 | * the end of the initial SEQUENCE operation--the rest we regenerate | ||
420 | * each time. Therefore we can advertise a ca_maxresponssize_cached | ||
421 | * value that is the number of bytes in our cache plus a few additional | ||
422 | * bytes. In order to stay on the safe side, and not promise more than | ||
423 | * we can cache, those additional bytes must be the minimum possible: 24 | ||
424 | * bytes of rpc header (xid through accept state, with AUTH_NULL | ||
425 | * verifier), 12 for the compound header (with zero-length tag), and 44 | ||
426 | * for the SEQUENCE op response: | ||
427 | */ | ||
428 | #define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) | ||
429 | |||
430 | /* | ||
431 | * Give the client the number of ca_maxresponsesize_cached slots it | ||
432 | * requests, of size bounded by NFSD_SLOT_CACHE_SIZE, | ||
433 | * NFSD_MAX_MEM_PER_SESSION, and nfsd_drc_max_mem. Do not allow more | ||
434 | * than NFSD_MAX_SLOTS_PER_SESSION. | ||
418 | * | 435 | * |
419 | * If we run out of pages (sv_drc_pages_used == sv_drc_max_pages) we | 436 | * If we run out of reserved DRC memory we should (up to a point) |
420 | * should (up to a point) re-negotiate active sessions and reduce their | 437 | * re-negotiate active sessions and reduce their slot usage to make |
421 | * slot usage to make rooom for new connections. For now we just fail the | 438 | * rooom for new connections. For now we just fail the create session. |
422 | * create session. | ||
423 | */ | 439 | */ |
424 | static int set_forechannel_maxreqs(struct nfsd4_channel_attrs *fchan) | 440 | static int set_forechannel_drc_size(struct nfsd4_channel_attrs *fchan) |
425 | { | 441 | { |
426 | int status = 0, np = fchan->maxreqs * NFSD_PAGES_PER_SLOT; | 442 | int mem, size = fchan->maxresp_cached; |
427 | 443 | ||
428 | if (fchan->maxreqs < 1) | 444 | if (fchan->maxreqs < 1) |
429 | return nfserr_inval; | 445 | return nfserr_inval; |
430 | else if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) | ||
431 | fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION; | ||
432 | 446 | ||
433 | spin_lock(&nfsd_serv->sv_lock); | 447 | if (size < NFSD_MIN_HDR_SEQ_SZ) |
434 | if (np + nfsd_serv->sv_drc_pages_used > nfsd_serv->sv_drc_max_pages) | 448 | size = NFSD_MIN_HDR_SEQ_SZ; |
435 | np = nfsd_serv->sv_drc_max_pages - nfsd_serv->sv_drc_pages_used; | 449 | size -= NFSD_MIN_HDR_SEQ_SZ; |
436 | nfsd_serv->sv_drc_pages_used += np; | 450 | if (size > NFSD_SLOT_CACHE_SIZE) |
437 | spin_unlock(&nfsd_serv->sv_lock); | 451 | size = NFSD_SLOT_CACHE_SIZE; |
452 | |||
453 | /* bound the maxreqs by NFSD_MAX_MEM_PER_SESSION */ | ||
454 | mem = fchan->maxreqs * size; | ||
455 | if (mem > NFSD_MAX_MEM_PER_SESSION) { | ||
456 | fchan->maxreqs = NFSD_MAX_MEM_PER_SESSION / size; | ||
457 | if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) | ||
458 | fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION; | ||
459 | mem = fchan->maxreqs * size; | ||
460 | } | ||
438 | 461 | ||
439 | if (np <= 0) { | 462 | spin_lock(&nfsd_drc_lock); |
440 | status = nfserr_resource; | 463 | /* bound the total session drc memory ussage */ |
441 | fchan->maxreqs = 0; | 464 | if (mem + nfsd_drc_mem_used > nfsd_drc_max_mem) { |
442 | } else | 465 | fchan->maxreqs = (nfsd_drc_max_mem - nfsd_drc_mem_used) / size; |
443 | fchan->maxreqs = np / NFSD_PAGES_PER_SLOT; | 466 | mem = fchan->maxreqs * size; |
467 | } | ||
468 | nfsd_drc_mem_used += mem; | ||
469 | spin_unlock(&nfsd_drc_lock); | ||
444 | 470 | ||
445 | return status; | 471 | if (fchan->maxreqs == 0) |
472 | return nfserr_serverfault; | ||
473 | |||
474 | fchan->maxresp_cached = size + NFSD_MIN_HDR_SEQ_SZ; | ||
475 | return 0; | ||
446 | } | 476 | } |
447 | 477 | ||
448 | /* | 478 | /* |
@@ -466,36 +496,41 @@ static int init_forechannel_attrs(struct svc_rqst *rqstp, | |||
466 | fchan->maxresp_sz = maxcount; | 496 | fchan->maxresp_sz = maxcount; |
467 | session_fchan->maxresp_sz = fchan->maxresp_sz; | 497 | session_fchan->maxresp_sz = fchan->maxresp_sz; |
468 | 498 | ||
469 | /* Set the max response cached size our default which is | ||
470 | * a multiple of PAGE_SIZE and small */ | ||
471 | session_fchan->maxresp_cached = NFSD_PAGES_PER_SLOT * PAGE_SIZE; | ||
472 | fchan->maxresp_cached = session_fchan->maxresp_cached; | ||
473 | |||
474 | /* Use the client's maxops if possible */ | 499 | /* Use the client's maxops if possible */ |
475 | if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND) | 500 | if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND) |
476 | fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND; | 501 | fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND; |
477 | session_fchan->maxops = fchan->maxops; | 502 | session_fchan->maxops = fchan->maxops; |
478 | 503 | ||
479 | /* try to use the client requested number of slots */ | ||
480 | if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) | ||
481 | fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION; | ||
482 | |||
483 | /* FIXME: Error means no more DRC pages so the server should | 504 | /* FIXME: Error means no more DRC pages so the server should |
484 | * recover pages from existing sessions. For now fail session | 505 | * recover pages from existing sessions. For now fail session |
485 | * creation. | 506 | * creation. |
486 | */ | 507 | */ |
487 | status = set_forechannel_maxreqs(fchan); | 508 | status = set_forechannel_drc_size(fchan); |
488 | 509 | ||
510 | session_fchan->maxresp_cached = fchan->maxresp_cached; | ||
489 | session_fchan->maxreqs = fchan->maxreqs; | 511 | session_fchan->maxreqs = fchan->maxreqs; |
512 | |||
513 | dprintk("%s status %d\n", __func__, status); | ||
490 | return status; | 514 | return status; |
491 | } | 515 | } |
492 | 516 | ||
517 | static void | ||
518 | free_session_slots(struct nfsd4_session *ses) | ||
519 | { | ||
520 | int i; | ||
521 | |||
522 | for (i = 0; i < ses->se_fchannel.maxreqs; i++) | ||
523 | kfree(ses->se_slots[i]); | ||
524 | } | ||
525 | |||
493 | static int | 526 | static int |
494 | alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, | 527 | alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, |
495 | struct nfsd4_create_session *cses) | 528 | struct nfsd4_create_session *cses) |
496 | { | 529 | { |
497 | struct nfsd4_session *new, tmp; | 530 | struct nfsd4_session *new, tmp; |
498 | int idx, status = nfserr_resource, slotsize; | 531 | struct nfsd4_slot *sp; |
532 | int idx, slotsize, cachesize, i; | ||
533 | int status; | ||
499 | 534 | ||
500 | memset(&tmp, 0, sizeof(tmp)); | 535 | memset(&tmp, 0, sizeof(tmp)); |
501 | 536 | ||
@@ -506,14 +541,27 @@ alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, | |||
506 | if (status) | 541 | if (status) |
507 | goto out; | 542 | goto out; |
508 | 543 | ||
509 | /* allocate struct nfsd4_session and slot table in one piece */ | 544 | BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot) |
510 | slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot); | 545 | + sizeof(struct nfsd4_session) > PAGE_SIZE); |
546 | |||
547 | status = nfserr_serverfault; | ||
548 | /* allocate struct nfsd4_session and slot table pointers in one piece */ | ||
549 | slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot *); | ||
511 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); | 550 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); |
512 | if (!new) | 551 | if (!new) |
513 | goto out; | 552 | goto out; |
514 | 553 | ||
515 | memcpy(new, &tmp, sizeof(*new)); | 554 | memcpy(new, &tmp, sizeof(*new)); |
516 | 555 | ||
556 | /* allocate each struct nfsd4_slot and data cache in one piece */ | ||
557 | cachesize = new->se_fchannel.maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; | ||
558 | for (i = 0; i < new->se_fchannel.maxreqs; i++) { | ||
559 | sp = kzalloc(sizeof(*sp) + cachesize, GFP_KERNEL); | ||
560 | if (!sp) | ||
561 | goto out_free; | ||
562 | new->se_slots[i] = sp; | ||
563 | } | ||
564 | |||
517 | new->se_client = clp; | 565 | new->se_client = clp; |
518 | gen_sessionid(new); | 566 | gen_sessionid(new); |
519 | idx = hash_sessionid(&new->se_sessionid); | 567 | idx = hash_sessionid(&new->se_sessionid); |
@@ -530,6 +578,10 @@ alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, | |||
530 | status = nfs_ok; | 578 | status = nfs_ok; |
531 | out: | 579 | out: |
532 | return status; | 580 | return status; |
581 | out_free: | ||
582 | free_session_slots(new); | ||
583 | kfree(new); | ||
584 | goto out; | ||
533 | } | 585 | } |
534 | 586 | ||
535 | /* caller must hold sessionid_lock */ | 587 | /* caller must hold sessionid_lock */ |
@@ -572,19 +624,16 @@ release_session(struct nfsd4_session *ses) | |||
572 | nfsd4_put_session(ses); | 624 | nfsd4_put_session(ses); |
573 | } | 625 | } |
574 | 626 | ||
575 | static void nfsd4_release_respages(struct page **respages, short resused); | ||
576 | |||
577 | void | 627 | void |
578 | free_session(struct kref *kref) | 628 | free_session(struct kref *kref) |
579 | { | 629 | { |
580 | struct nfsd4_session *ses; | 630 | struct nfsd4_session *ses; |
581 | int i; | ||
582 | 631 | ||
583 | ses = container_of(kref, struct nfsd4_session, se_ref); | 632 | ses = container_of(kref, struct nfsd4_session, se_ref); |
584 | for (i = 0; i < ses->se_fchannel.maxreqs; i++) { | 633 | spin_lock(&nfsd_drc_lock); |
585 | struct nfsd4_cache_entry *e = &ses->se_slots[i].sl_cache_entry; | 634 | nfsd_drc_mem_used -= ses->se_fchannel.maxreqs * NFSD_SLOT_CACHE_SIZE; |
586 | nfsd4_release_respages(e->ce_respages, e->ce_resused); | 635 | spin_unlock(&nfsd_drc_lock); |
587 | } | 636 | free_session_slots(ses); |
588 | kfree(ses); | 637 | kfree(ses); |
589 | } | 638 | } |
590 | 639 | ||
@@ -647,18 +696,14 @@ shutdown_callback_client(struct nfs4_client *clp) | |||
647 | clp->cl_cb_conn.cb_client = NULL; | 696 | clp->cl_cb_conn.cb_client = NULL; |
648 | rpc_shutdown_client(clnt); | 697 | rpc_shutdown_client(clnt); |
649 | } | 698 | } |
650 | if (clp->cl_cb_conn.cb_cred) { | ||
651 | put_rpccred(clp->cl_cb_conn.cb_cred); | ||
652 | clp->cl_cb_conn.cb_cred = NULL; | ||
653 | } | ||
654 | } | 699 | } |
655 | 700 | ||
656 | static inline void | 701 | static inline void |
657 | free_client(struct nfs4_client *clp) | 702 | free_client(struct nfs4_client *clp) |
658 | { | 703 | { |
659 | shutdown_callback_client(clp); | 704 | shutdown_callback_client(clp); |
660 | nfsd4_release_respages(clp->cl_slot.sl_cache_entry.ce_respages, | 705 | if (clp->cl_cb_xprt) |
661 | clp->cl_slot.sl_cache_entry.ce_resused); | 706 | svc_xprt_put(clp->cl_cb_xprt); |
662 | if (clp->cl_cred.cr_group_info) | 707 | if (clp->cl_cred.cr_group_info) |
663 | put_group_info(clp->cl_cred.cr_group_info); | 708 | put_group_info(clp->cl_cred.cr_group_info); |
664 | kfree(clp->cl_principal); | 709 | kfree(clp->cl_principal); |
@@ -714,25 +759,6 @@ expire_client(struct nfs4_client *clp) | |||
714 | put_nfs4_client(clp); | 759 | put_nfs4_client(clp); |
715 | } | 760 | } |
716 | 761 | ||
717 | static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir) | ||
718 | { | ||
719 | struct nfs4_client *clp; | ||
720 | |||
721 | clp = alloc_client(name); | ||
722 | if (clp == NULL) | ||
723 | return NULL; | ||
724 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | ||
725 | atomic_set(&clp->cl_count, 1); | ||
726 | atomic_set(&clp->cl_cb_conn.cb_set, 0); | ||
727 | INIT_LIST_HEAD(&clp->cl_idhash); | ||
728 | INIT_LIST_HEAD(&clp->cl_strhash); | ||
729 | INIT_LIST_HEAD(&clp->cl_openowners); | ||
730 | INIT_LIST_HEAD(&clp->cl_delegations); | ||
731 | INIT_LIST_HEAD(&clp->cl_sessions); | ||
732 | INIT_LIST_HEAD(&clp->cl_lru); | ||
733 | return clp; | ||
734 | } | ||
735 | |||
736 | static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) | 762 | static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) |
737 | { | 763 | { |
738 | memcpy(target->cl_verifier.data, source->data, | 764 | memcpy(target->cl_verifier.data, source->data, |
@@ -795,6 +821,46 @@ static void gen_confirm(struct nfs4_client *clp) | |||
795 | *p++ = i++; | 821 | *p++ = i++; |
796 | } | 822 | } |
797 | 823 | ||
824 | static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, | ||
825 | struct svc_rqst *rqstp, nfs4_verifier *verf) | ||
826 | { | ||
827 | struct nfs4_client *clp; | ||
828 | struct sockaddr *sa = svc_addr(rqstp); | ||
829 | char *princ; | ||
830 | |||
831 | clp = alloc_client(name); | ||
832 | if (clp == NULL) | ||
833 | return NULL; | ||
834 | |||
835 | princ = svc_gss_principal(rqstp); | ||
836 | if (princ) { | ||
837 | clp->cl_principal = kstrdup(princ, GFP_KERNEL); | ||
838 | if (clp->cl_principal == NULL) { | ||
839 | free_client(clp); | ||
840 | return NULL; | ||
841 | } | ||
842 | } | ||
843 | |||
844 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | ||
845 | atomic_set(&clp->cl_count, 1); | ||
846 | atomic_set(&clp->cl_cb_conn.cb_set, 0); | ||
847 | INIT_LIST_HEAD(&clp->cl_idhash); | ||
848 | INIT_LIST_HEAD(&clp->cl_strhash); | ||
849 | INIT_LIST_HEAD(&clp->cl_openowners); | ||
850 | INIT_LIST_HEAD(&clp->cl_delegations); | ||
851 | INIT_LIST_HEAD(&clp->cl_sessions); | ||
852 | INIT_LIST_HEAD(&clp->cl_lru); | ||
853 | clear_bit(0, &clp->cl_cb_slot_busy); | ||
854 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); | ||
855 | copy_verf(clp, verf); | ||
856 | rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); | ||
857 | clp->cl_flavor = rqstp->rq_flavor; | ||
858 | copy_cred(&clp->cl_cred, &rqstp->rq_cred); | ||
859 | gen_confirm(clp); | ||
860 | |||
861 | return clp; | ||
862 | } | ||
863 | |||
798 | static int check_name(struct xdr_netobj name) | 864 | static int check_name(struct xdr_netobj name) |
799 | { | 865 | { |
800 | if (name.len == 0) | 866 | if (name.len == 0) |
@@ -902,93 +968,40 @@ find_unconfirmed_client_by_str(const char *dname, unsigned int hashval, | |||
902 | return NULL; | 968 | return NULL; |
903 | } | 969 | } |
904 | 970 | ||
905 | /* a helper function for parse_callback */ | ||
906 | static int | ||
907 | parse_octet(unsigned int *lenp, char **addrp) | ||
908 | { | ||
909 | unsigned int len = *lenp; | ||
910 | char *p = *addrp; | ||
911 | int n = -1; | ||
912 | char c; | ||
913 | |||
914 | for (;;) { | ||
915 | if (!len) | ||
916 | break; | ||
917 | len--; | ||
918 | c = *p++; | ||
919 | if (c == '.') | ||
920 | break; | ||
921 | if ((c < '0') || (c > '9')) { | ||
922 | n = -1; | ||
923 | break; | ||
924 | } | ||
925 | if (n < 0) | ||
926 | n = 0; | ||
927 | n = (n * 10) + (c - '0'); | ||
928 | if (n > 255) { | ||
929 | n = -1; | ||
930 | break; | ||
931 | } | ||
932 | } | ||
933 | *lenp = len; | ||
934 | *addrp = p; | ||
935 | return n; | ||
936 | } | ||
937 | |||
938 | /* parse and set the setclientid ipv4 callback address */ | ||
939 | static int | ||
940 | parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigned short *cbportp) | ||
941 | { | ||
942 | int temp = 0; | ||
943 | u32 cbaddr = 0; | ||
944 | u16 cbport = 0; | ||
945 | u32 addrlen = addr_len; | ||
946 | char *addr = addr_val; | ||
947 | int i, shift; | ||
948 | |||
949 | /* ipaddress */ | ||
950 | shift = 24; | ||
951 | for(i = 4; i > 0 ; i--) { | ||
952 | if ((temp = parse_octet(&addrlen, &addr)) < 0) { | ||
953 | return 0; | ||
954 | } | ||
955 | cbaddr |= (temp << shift); | ||
956 | if (shift > 0) | ||
957 | shift -= 8; | ||
958 | } | ||
959 | *cbaddrp = cbaddr; | ||
960 | |||
961 | /* port */ | ||
962 | shift = 8; | ||
963 | for(i = 2; i > 0 ; i--) { | ||
964 | if ((temp = parse_octet(&addrlen, &addr)) < 0) { | ||
965 | return 0; | ||
966 | } | ||
967 | cbport |= (temp << shift); | ||
968 | if (shift > 0) | ||
969 | shift -= 8; | ||
970 | } | ||
971 | *cbportp = cbport; | ||
972 | return 1; | ||
973 | } | ||
974 | |||
975 | static void | 971 | static void |
976 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) | 972 | gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, u32 scopeid) |
977 | { | 973 | { |
978 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; | 974 | struct nfs4_cb_conn *cb = &clp->cl_cb_conn; |
979 | 975 | unsigned short expected_family; | |
980 | /* Currently, we only support tcp for the callback channel */ | 976 | |
981 | if ((se->se_callback_netid_len != 3) || memcmp((char *)se->se_callback_netid_val, "tcp", 3)) | 977 | /* Currently, we only support tcp and tcp6 for the callback channel */ |
978 | if (se->se_callback_netid_len == 3 && | ||
979 | !memcmp(se->se_callback_netid_val, "tcp", 3)) | ||
980 | expected_family = AF_INET; | ||
981 | else if (se->se_callback_netid_len == 4 && | ||
982 | !memcmp(se->se_callback_netid_val, "tcp6", 4)) | ||
983 | expected_family = AF_INET6; | ||
984 | else | ||
982 | goto out_err; | 985 | goto out_err; |
983 | 986 | ||
984 | if ( !(parse_ipv4(se->se_callback_addr_len, se->se_callback_addr_val, | 987 | cb->cb_addrlen = rpc_uaddr2sockaddr(se->se_callback_addr_val, |
985 | &cb->cb_addr, &cb->cb_port))) | 988 | se->se_callback_addr_len, |
989 | (struct sockaddr *) &cb->cb_addr, | ||
990 | sizeof(cb->cb_addr)); | ||
991 | |||
992 | if (!cb->cb_addrlen || cb->cb_addr.ss_family != expected_family) | ||
986 | goto out_err; | 993 | goto out_err; |
994 | |||
995 | if (cb->cb_addr.ss_family == AF_INET6) | ||
996 | ((struct sockaddr_in6 *) &cb->cb_addr)->sin6_scope_id = scopeid; | ||
997 | |||
987 | cb->cb_minorversion = 0; | 998 | cb->cb_minorversion = 0; |
988 | cb->cb_prog = se->se_callback_prog; | 999 | cb->cb_prog = se->se_callback_prog; |
989 | cb->cb_ident = se->se_callback_ident; | 1000 | cb->cb_ident = se->se_callback_ident; |
990 | return; | 1001 | return; |
991 | out_err: | 1002 | out_err: |
1003 | cb->cb_addr.ss_family = AF_UNSPEC; | ||
1004 | cb->cb_addrlen = 0; | ||
992 | dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " | 1005 | dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " |
993 | "will not receive delegations\n", | 1006 | "will not receive delegations\n", |
994 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); | 1007 | clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); |
@@ -996,175 +1009,87 @@ out_err: | |||
996 | return; | 1009 | return; |
997 | } | 1010 | } |
998 | 1011 | ||
999 | void | ||
1000 | nfsd4_set_statp(struct svc_rqst *rqstp, __be32 *statp) | ||
1001 | { | ||
1002 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | ||
1003 | |||
1004 | resp->cstate.statp = statp; | ||
1005 | } | ||
1006 | |||
1007 | /* | 1012 | /* |
1008 | * Dereference the result pages. | 1013 | * Cache a reply. nfsd4_check_drc_limit() has bounded the cache size. |
1009 | */ | 1014 | */ |
1010 | static void | 1015 | void |
1011 | nfsd4_release_respages(struct page **respages, short resused) | 1016 | nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) |
1012 | { | 1017 | { |
1013 | int i; | 1018 | struct nfsd4_slot *slot = resp->cstate.slot; |
1019 | unsigned int base; | ||
1014 | 1020 | ||
1015 | dprintk("--> %s\n", __func__); | 1021 | dprintk("--> %s slot %p\n", __func__, slot); |
1016 | for (i = 0; i < resused; i++) { | ||
1017 | if (!respages[i]) | ||
1018 | continue; | ||
1019 | put_page(respages[i]); | ||
1020 | respages[i] = NULL; | ||
1021 | } | ||
1022 | } | ||
1023 | 1022 | ||
1024 | static void | 1023 | slot->sl_opcnt = resp->opcnt; |
1025 | nfsd4_copy_pages(struct page **topages, struct page **frompages, short count) | 1024 | slot->sl_status = resp->cstate.status; |
1026 | { | ||
1027 | int i; | ||
1028 | 1025 | ||
1029 | for (i = 0; i < count; i++) { | 1026 | if (nfsd4_not_cached(resp)) { |
1030 | topages[i] = frompages[i]; | 1027 | slot->sl_datalen = 0; |
1031 | if (!topages[i]) | 1028 | return; |
1032 | continue; | ||
1033 | get_page(topages[i]); | ||
1034 | } | 1029 | } |
1030 | slot->sl_datalen = (char *)resp->p - (char *)resp->cstate.datap; | ||
1031 | base = (char *)resp->cstate.datap - | ||
1032 | (char *)resp->xbuf->head[0].iov_base; | ||
1033 | if (read_bytes_from_xdr_buf(resp->xbuf, base, slot->sl_data, | ||
1034 | slot->sl_datalen)) | ||
1035 | WARN("%s: sessions DRC could not cache compound\n", __func__); | ||
1036 | return; | ||
1035 | } | 1037 | } |
1036 | 1038 | ||
1037 | /* | 1039 | /* |
1038 | * Cache the reply pages up to NFSD_PAGES_PER_SLOT + 1, clearing the previous | 1040 | * Encode the replay sequence operation from the slot values. |
1039 | * pages. We add a page to NFSD_PAGES_PER_SLOT for the case where the total | 1041 | * If cachethis is FALSE encode the uncached rep error on the next |
1040 | * length of the XDR response is less than se_fmaxresp_cached | 1042 | * operation which sets resp->p and increments resp->opcnt for |
1041 | * (NFSD_PAGES_PER_SLOT * PAGE_SIZE) but the xdr_buf pages is used for a | 1043 | * nfs4svc_encode_compoundres. |
1042 | * of the reply (e.g. readdir). | ||
1043 | * | 1044 | * |
1044 | * Store the base and length of the rq_req.head[0] page | ||
1045 | * of the NFSv4.1 data, just past the rpc header. | ||
1046 | */ | 1045 | */ |
1047 | void | 1046 | static __be32 |
1048 | nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) | 1047 | nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, |
1048 | struct nfsd4_compoundres *resp) | ||
1049 | { | 1049 | { |
1050 | struct nfsd4_cache_entry *entry = &resp->cstate.slot->sl_cache_entry; | 1050 | struct nfsd4_op *op; |
1051 | struct svc_rqst *rqstp = resp->rqstp; | 1051 | struct nfsd4_slot *slot = resp->cstate.slot; |
1052 | struct nfsd4_compoundargs *args = rqstp->rq_argp; | ||
1053 | struct nfsd4_op *op = &args->ops[resp->opcnt]; | ||
1054 | struct kvec *resv = &rqstp->rq_res.head[0]; | ||
1055 | |||
1056 | dprintk("--> %s entry %p\n", __func__, entry); | ||
1057 | |||
1058 | /* Don't cache a failed OP_SEQUENCE. */ | ||
1059 | if (resp->opcnt == 1 && op->opnum == OP_SEQUENCE && resp->cstate.status) | ||
1060 | return; | ||
1061 | 1052 | ||
1062 | nfsd4_release_respages(entry->ce_respages, entry->ce_resused); | 1053 | dprintk("--> %s resp->opcnt %d cachethis %u \n", __func__, |
1063 | entry->ce_opcnt = resp->opcnt; | 1054 | resp->opcnt, resp->cstate.slot->sl_cachethis); |
1064 | entry->ce_status = resp->cstate.status; | ||
1065 | 1055 | ||
1066 | /* | 1056 | /* Encode the replayed sequence operation */ |
1067 | * Don't need a page to cache just the sequence operation - the slot | 1057 | op = &args->ops[resp->opcnt - 1]; |
1068 | * does this for us! | 1058 | nfsd4_encode_operation(resp, op); |
1069 | */ | ||
1070 | 1059 | ||
1071 | if (nfsd4_not_cached(resp)) { | 1060 | /* Return nfserr_retry_uncached_rep in next operation. */ |
1072 | entry->ce_resused = 0; | 1061 | if (args->opcnt > 1 && slot->sl_cachethis == 0) { |
1073 | entry->ce_rpchdrlen = 0; | 1062 | op = &args->ops[resp->opcnt++]; |
1074 | dprintk("%s Just cache SEQUENCE. ce_cachethis %d\n", __func__, | 1063 | op->status = nfserr_retry_uncached_rep; |
1075 | resp->cstate.slot->sl_cache_entry.ce_cachethis); | 1064 | nfsd4_encode_operation(resp, op); |
1076 | return; | ||
1077 | } | ||
1078 | entry->ce_resused = rqstp->rq_resused; | ||
1079 | if (entry->ce_resused > NFSD_PAGES_PER_SLOT + 1) | ||
1080 | entry->ce_resused = NFSD_PAGES_PER_SLOT + 1; | ||
1081 | nfsd4_copy_pages(entry->ce_respages, rqstp->rq_respages, | ||
1082 | entry->ce_resused); | ||
1083 | entry->ce_datav.iov_base = resp->cstate.statp; | ||
1084 | entry->ce_datav.iov_len = resv->iov_len - ((char *)resp->cstate.statp - | ||
1085 | (char *)page_address(rqstp->rq_respages[0])); | ||
1086 | /* Current request rpc header length*/ | ||
1087 | entry->ce_rpchdrlen = (char *)resp->cstate.statp - | ||
1088 | (char *)page_address(rqstp->rq_respages[0]); | ||
1089 | } | ||
1090 | |||
1091 | /* | ||
1092 | * We keep the rpc header, but take the nfs reply from the replycache. | ||
1093 | */ | ||
1094 | static int | ||
1095 | nfsd41_copy_replay_data(struct nfsd4_compoundres *resp, | ||
1096 | struct nfsd4_cache_entry *entry) | ||
1097 | { | ||
1098 | struct svc_rqst *rqstp = resp->rqstp; | ||
1099 | struct kvec *resv = &resp->rqstp->rq_res.head[0]; | ||
1100 | int len; | ||
1101 | |||
1102 | /* Current request rpc header length*/ | ||
1103 | len = (char *)resp->cstate.statp - | ||
1104 | (char *)page_address(rqstp->rq_respages[0]); | ||
1105 | if (entry->ce_datav.iov_len + len > PAGE_SIZE) { | ||
1106 | dprintk("%s v41 cached reply too large (%Zd).\n", __func__, | ||
1107 | entry->ce_datav.iov_len); | ||
1108 | return 0; | ||
1109 | } | 1065 | } |
1110 | /* copy the cached reply nfsd data past the current rpc header */ | 1066 | return op->status; |
1111 | memcpy((char *)resv->iov_base + len, entry->ce_datav.iov_base, | ||
1112 | entry->ce_datav.iov_len); | ||
1113 | resv->iov_len = len + entry->ce_datav.iov_len; | ||
1114 | return 1; | ||
1115 | } | 1067 | } |
1116 | 1068 | ||
1117 | /* | 1069 | /* |
1118 | * Keep the first page of the replay. Copy the NFSv4.1 data from the first | 1070 | * The sequence operation is not cached because we can use the slot and |
1119 | * cached page. Replace any futher replay pages from the cache. | 1071 | * session values. |
1120 | */ | 1072 | */ |
1121 | __be32 | 1073 | __be32 |
1122 | nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, | 1074 | nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, |
1123 | struct nfsd4_sequence *seq) | 1075 | struct nfsd4_sequence *seq) |
1124 | { | 1076 | { |
1125 | struct nfsd4_cache_entry *entry = &resp->cstate.slot->sl_cache_entry; | 1077 | struct nfsd4_slot *slot = resp->cstate.slot; |
1126 | __be32 status; | 1078 | __be32 status; |
1127 | 1079 | ||
1128 | dprintk("--> %s entry %p\n", __func__, entry); | 1080 | dprintk("--> %s slot %p\n", __func__, slot); |
1129 | |||
1130 | /* | ||
1131 | * If this is just the sequence operation, we did not keep | ||
1132 | * a page in the cache entry because we can just use the | ||
1133 | * slot info stored in struct nfsd4_sequence that was checked | ||
1134 | * against the slot in nfsd4_sequence(). | ||
1135 | * | ||
1136 | * This occurs when seq->cachethis is FALSE, or when the client | ||
1137 | * session inactivity timer fires and a solo sequence operation | ||
1138 | * is sent (lease renewal). | ||
1139 | */ | ||
1140 | if (seq && nfsd4_not_cached(resp)) { | ||
1141 | seq->maxslots = resp->cstate.session->se_fchannel.maxreqs; | ||
1142 | return nfs_ok; | ||
1143 | } | ||
1144 | |||
1145 | if (!nfsd41_copy_replay_data(resp, entry)) { | ||
1146 | /* | ||
1147 | * Not enough room to use the replay rpc header, send the | ||
1148 | * cached header. Release all the allocated result pages. | ||
1149 | */ | ||
1150 | svc_free_res_pages(resp->rqstp); | ||
1151 | nfsd4_copy_pages(resp->rqstp->rq_respages, entry->ce_respages, | ||
1152 | entry->ce_resused); | ||
1153 | } else { | ||
1154 | /* Release all but the first allocated result page */ | ||
1155 | 1081 | ||
1156 | resp->rqstp->rq_resused--; | 1082 | /* Either returns 0 or nfserr_retry_uncached */ |
1157 | svc_free_res_pages(resp->rqstp); | 1083 | status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp); |
1084 | if (status == nfserr_retry_uncached_rep) | ||
1085 | return status; | ||
1158 | 1086 | ||
1159 | nfsd4_copy_pages(&resp->rqstp->rq_respages[1], | 1087 | /* The sequence operation has been encoded, cstate->datap set. */ |
1160 | &entry->ce_respages[1], | 1088 | memcpy(resp->cstate.datap, slot->sl_data, slot->sl_datalen); |
1161 | entry->ce_resused - 1); | ||
1162 | } | ||
1163 | 1089 | ||
1164 | resp->rqstp->rq_resused = entry->ce_resused; | 1090 | resp->opcnt = slot->sl_opcnt; |
1165 | resp->opcnt = entry->ce_opcnt; | 1091 | resp->p = resp->cstate.datap + XDR_QUADLEN(slot->sl_datalen); |
1166 | resp->cstate.iovlen = entry->ce_datav.iov_len + entry->ce_rpchdrlen; | 1092 | status = slot->sl_status; |
1167 | status = entry->ce_status; | ||
1168 | 1093 | ||
1169 | return status; | 1094 | return status; |
1170 | } | 1095 | } |
@@ -1194,13 +1119,15 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1194 | int status; | 1119 | int status; |
1195 | unsigned int strhashval; | 1120 | unsigned int strhashval; |
1196 | char dname[HEXDIR_LEN]; | 1121 | char dname[HEXDIR_LEN]; |
1122 | char addr_str[INET6_ADDRSTRLEN]; | ||
1197 | nfs4_verifier verf = exid->verifier; | 1123 | nfs4_verifier verf = exid->verifier; |
1198 | u32 ip_addr = svc_addr_in(rqstp)->sin_addr.s_addr; | 1124 | struct sockaddr *sa = svc_addr(rqstp); |
1199 | 1125 | ||
1126 | rpc_ntop(sa, addr_str, sizeof(addr_str)); | ||
1200 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " | 1127 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " |
1201 | " ip_addr=%u flags %x, spa_how %d\n", | 1128 | "ip_addr=%s flags %x, spa_how %d\n", |
1202 | __func__, rqstp, exid, exid->clname.len, exid->clname.data, | 1129 | __func__, rqstp, exid, exid->clname.len, exid->clname.data, |
1203 | ip_addr, exid->flags, exid->spa_how); | 1130 | addr_str, exid->flags, exid->spa_how); |
1204 | 1131 | ||
1205 | if (!check_name(exid->clname) || (exid->flags & ~EXCHGID4_FLAG_MASK_A)) | 1132 | if (!check_name(exid->clname) || (exid->flags & ~EXCHGID4_FLAG_MASK_A)) |
1206 | return nfserr_inval; | 1133 | return nfserr_inval; |
@@ -1281,28 +1208,23 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1281 | 1208 | ||
1282 | out_new: | 1209 | out_new: |
1283 | /* Normal case */ | 1210 | /* Normal case */ |
1284 | new = create_client(exid->clname, dname); | 1211 | new = create_client(exid->clname, dname, rqstp, &verf); |
1285 | if (new == NULL) { | 1212 | if (new == NULL) { |
1286 | status = nfserr_resource; | 1213 | status = nfserr_serverfault; |
1287 | goto out; | 1214 | goto out; |
1288 | } | 1215 | } |
1289 | 1216 | ||
1290 | copy_verf(new, &verf); | ||
1291 | copy_cred(&new->cl_cred, &rqstp->rq_cred); | ||
1292 | new->cl_addr = ip_addr; | ||
1293 | gen_clid(new); | 1217 | gen_clid(new); |
1294 | gen_confirm(new); | ||
1295 | add_to_unconfirmed(new, strhashval); | 1218 | add_to_unconfirmed(new, strhashval); |
1296 | out_copy: | 1219 | out_copy: |
1297 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; | 1220 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; |
1298 | exid->clientid.cl_id = new->cl_clientid.cl_id; | 1221 | exid->clientid.cl_id = new->cl_clientid.cl_id; |
1299 | 1222 | ||
1300 | new->cl_slot.sl_seqid = 0; | ||
1301 | exid->seqid = 1; | 1223 | exid->seqid = 1; |
1302 | nfsd4_set_ex_flags(new, exid); | 1224 | nfsd4_set_ex_flags(new, exid); |
1303 | 1225 | ||
1304 | dprintk("nfsd4_exchange_id seqid %d flags %x\n", | 1226 | dprintk("nfsd4_exchange_id seqid %d flags %x\n", |
1305 | new->cl_slot.sl_seqid, new->cl_exchange_flags); | 1227 | new->cl_cs_slot.sl_seqid, new->cl_exchange_flags); |
1306 | status = nfs_ok; | 1228 | status = nfs_ok; |
1307 | 1229 | ||
1308 | out: | 1230 | out: |
@@ -1313,40 +1235,60 @@ error: | |||
1313 | } | 1235 | } |
1314 | 1236 | ||
1315 | static int | 1237 | static int |
1316 | check_slot_seqid(u32 seqid, struct nfsd4_slot *slot) | 1238 | check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) |
1317 | { | 1239 | { |
1318 | dprintk("%s enter. seqid %d slot->sl_seqid %d\n", __func__, seqid, | 1240 | dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, |
1319 | slot->sl_seqid); | 1241 | slot_seqid); |
1320 | 1242 | ||
1321 | /* The slot is in use, and no response has been sent. */ | 1243 | /* The slot is in use, and no response has been sent. */ |
1322 | if (slot->sl_inuse) { | 1244 | if (slot_inuse) { |
1323 | if (seqid == slot->sl_seqid) | 1245 | if (seqid == slot_seqid) |
1324 | return nfserr_jukebox; | 1246 | return nfserr_jukebox; |
1325 | else | 1247 | else |
1326 | return nfserr_seq_misordered; | 1248 | return nfserr_seq_misordered; |
1327 | } | 1249 | } |
1328 | /* Normal */ | 1250 | /* Normal */ |
1329 | if (likely(seqid == slot->sl_seqid + 1)) | 1251 | if (likely(seqid == slot_seqid + 1)) |
1330 | return nfs_ok; | 1252 | return nfs_ok; |
1331 | /* Replay */ | 1253 | /* Replay */ |
1332 | if (seqid == slot->sl_seqid) | 1254 | if (seqid == slot_seqid) |
1333 | return nfserr_replay_cache; | 1255 | return nfserr_replay_cache; |
1334 | /* Wraparound */ | 1256 | /* Wraparound */ |
1335 | if (seqid == 1 && (slot->sl_seqid + 1) == 0) | 1257 | if (seqid == 1 && (slot_seqid + 1) == 0) |
1336 | return nfs_ok; | 1258 | return nfs_ok; |
1337 | /* Misordered replay or misordered new request */ | 1259 | /* Misordered replay or misordered new request */ |
1338 | return nfserr_seq_misordered; | 1260 | return nfserr_seq_misordered; |
1339 | } | 1261 | } |
1340 | 1262 | ||
1263 | /* | ||
1264 | * Cache the create session result into the create session single DRC | ||
1265 | * slot cache by saving the xdr structure. sl_seqid has been set. | ||
1266 | * Do this for solo or embedded create session operations. | ||
1267 | */ | ||
1268 | static void | ||
1269 | nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, | ||
1270 | struct nfsd4_clid_slot *slot, int nfserr) | ||
1271 | { | ||
1272 | slot->sl_status = nfserr; | ||
1273 | memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); | ||
1274 | } | ||
1275 | |||
1276 | static __be32 | ||
1277 | nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, | ||
1278 | struct nfsd4_clid_slot *slot) | ||
1279 | { | ||
1280 | memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses)); | ||
1281 | return slot->sl_status; | ||
1282 | } | ||
1283 | |||
1341 | __be32 | 1284 | __be32 |
1342 | nfsd4_create_session(struct svc_rqst *rqstp, | 1285 | nfsd4_create_session(struct svc_rqst *rqstp, |
1343 | struct nfsd4_compound_state *cstate, | 1286 | struct nfsd4_compound_state *cstate, |
1344 | struct nfsd4_create_session *cr_ses) | 1287 | struct nfsd4_create_session *cr_ses) |
1345 | { | 1288 | { |
1346 | u32 ip_addr = svc_addr_in(rqstp)->sin_addr.s_addr; | 1289 | struct sockaddr *sa = svc_addr(rqstp); |
1347 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | ||
1348 | struct nfs4_client *conf, *unconf; | 1290 | struct nfs4_client *conf, *unconf; |
1349 | struct nfsd4_slot *slot = NULL; | 1291 | struct nfsd4_clid_slot *cs_slot = NULL; |
1350 | int status = 0; | 1292 | int status = 0; |
1351 | 1293 | ||
1352 | nfs4_lock_state(); | 1294 | nfs4_lock_state(); |
@@ -1354,40 +1296,38 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1354 | conf = find_confirmed_client(&cr_ses->clientid); | 1296 | conf = find_confirmed_client(&cr_ses->clientid); |
1355 | 1297 | ||
1356 | if (conf) { | 1298 | if (conf) { |
1357 | slot = &conf->cl_slot; | 1299 | cs_slot = &conf->cl_cs_slot; |
1358 | status = check_slot_seqid(cr_ses->seqid, slot); | 1300 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1359 | if (status == nfserr_replay_cache) { | 1301 | if (status == nfserr_replay_cache) { |
1360 | dprintk("Got a create_session replay! seqid= %d\n", | 1302 | dprintk("Got a create_session replay! seqid= %d\n", |
1361 | slot->sl_seqid); | 1303 | cs_slot->sl_seqid); |
1362 | cstate->slot = slot; | ||
1363 | cstate->status = status; | ||
1364 | /* Return the cached reply status */ | 1304 | /* Return the cached reply status */ |
1365 | status = nfsd4_replay_cache_entry(resp, NULL); | 1305 | status = nfsd4_replay_create_session(cr_ses, cs_slot); |
1366 | goto out; | 1306 | goto out; |
1367 | } else if (cr_ses->seqid != conf->cl_slot.sl_seqid + 1) { | 1307 | } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) { |
1368 | status = nfserr_seq_misordered; | 1308 | status = nfserr_seq_misordered; |
1369 | dprintk("Sequence misordered!\n"); | 1309 | dprintk("Sequence misordered!\n"); |
1370 | dprintk("Expected seqid= %d but got seqid= %d\n", | 1310 | dprintk("Expected seqid= %d but got seqid= %d\n", |
1371 | slot->sl_seqid, cr_ses->seqid); | 1311 | cs_slot->sl_seqid, cr_ses->seqid); |
1372 | goto out; | 1312 | goto out; |
1373 | } | 1313 | } |
1374 | conf->cl_slot.sl_seqid++; | 1314 | cs_slot->sl_seqid++; |
1375 | } else if (unconf) { | 1315 | } else if (unconf) { |
1376 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || | 1316 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || |
1377 | (ip_addr != unconf->cl_addr)) { | 1317 | !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { |
1378 | status = nfserr_clid_inuse; | 1318 | status = nfserr_clid_inuse; |
1379 | goto out; | 1319 | goto out; |
1380 | } | 1320 | } |
1381 | 1321 | ||
1382 | slot = &unconf->cl_slot; | 1322 | cs_slot = &unconf->cl_cs_slot; |
1383 | status = check_slot_seqid(cr_ses->seqid, slot); | 1323 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1384 | if (status) { | 1324 | if (status) { |
1385 | /* an unconfirmed replay returns misordered */ | 1325 | /* an unconfirmed replay returns misordered */ |
1386 | status = nfserr_seq_misordered; | 1326 | status = nfserr_seq_misordered; |
1387 | goto out; | 1327 | goto out_cache; |
1388 | } | 1328 | } |
1389 | 1329 | ||
1390 | slot->sl_seqid++; /* from 0 to 1 */ | 1330 | cs_slot->sl_seqid++; /* from 0 to 1 */ |
1391 | move_to_confirmed(unconf); | 1331 | move_to_confirmed(unconf); |
1392 | 1332 | ||
1393 | /* | 1333 | /* |
@@ -1396,6 +1336,19 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1396 | cr_ses->flags &= ~SESSION4_PERSIST; | 1336 | cr_ses->flags &= ~SESSION4_PERSIST; |
1397 | cr_ses->flags &= ~SESSION4_RDMA; | 1337 | cr_ses->flags &= ~SESSION4_RDMA; |
1398 | 1338 | ||
1339 | if (cr_ses->flags & SESSION4_BACK_CHAN) { | ||
1340 | unconf->cl_cb_xprt = rqstp->rq_xprt; | ||
1341 | svc_xprt_get(unconf->cl_cb_xprt); | ||
1342 | rpc_copy_addr( | ||
1343 | (struct sockaddr *)&unconf->cl_cb_conn.cb_addr, | ||
1344 | sa); | ||
1345 | unconf->cl_cb_conn.cb_addrlen = svc_addr_len(sa); | ||
1346 | unconf->cl_cb_conn.cb_minorversion = | ||
1347 | cstate->minorversion; | ||
1348 | unconf->cl_cb_conn.cb_prog = cr_ses->callback_prog; | ||
1349 | unconf->cl_cb_seq_nr = 1; | ||
1350 | nfsd4_probe_callback(unconf); | ||
1351 | } | ||
1399 | conf = unconf; | 1352 | conf = unconf; |
1400 | } else { | 1353 | } else { |
1401 | status = nfserr_stale_clientid; | 1354 | status = nfserr_stale_clientid; |
@@ -1408,12 +1361,11 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1408 | 1361 | ||
1409 | memcpy(cr_ses->sessionid.data, conf->cl_sessionid.data, | 1362 | memcpy(cr_ses->sessionid.data, conf->cl_sessionid.data, |
1410 | NFS4_MAX_SESSIONID_LEN); | 1363 | NFS4_MAX_SESSIONID_LEN); |
1411 | cr_ses->seqid = slot->sl_seqid; | 1364 | cr_ses->seqid = cs_slot->sl_seqid; |
1412 | 1365 | ||
1413 | slot->sl_inuse = true; | 1366 | out_cache: |
1414 | cstate->slot = slot; | 1367 | /* cache solo and embedded create sessions under the state lock */ |
1415 | /* Ensure a page is used for the cache */ | 1368 | nfsd4_cache_create_session(cr_ses, cs_slot, status); |
1416 | slot->sl_cache_entry.ce_cachethis = 1; | ||
1417 | out: | 1369 | out: |
1418 | nfs4_unlock_state(); | 1370 | nfs4_unlock_state(); |
1419 | dprintk("%s returns %d\n", __func__, ntohl(status)); | 1371 | dprintk("%s returns %d\n", __func__, ntohl(status)); |
@@ -1478,18 +1430,23 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1478 | if (seq->slotid >= session->se_fchannel.maxreqs) | 1430 | if (seq->slotid >= session->se_fchannel.maxreqs) |
1479 | goto out; | 1431 | goto out; |
1480 | 1432 | ||
1481 | slot = &session->se_slots[seq->slotid]; | 1433 | slot = session->se_slots[seq->slotid]; |
1482 | dprintk("%s: slotid %d\n", __func__, seq->slotid); | 1434 | dprintk("%s: slotid %d\n", __func__, seq->slotid); |
1483 | 1435 | ||
1484 | status = check_slot_seqid(seq->seqid, slot); | 1436 | /* We do not negotiate the number of slots yet, so set the |
1437 | * maxslots to the session maxreqs which is used to encode | ||
1438 | * sr_highest_slotid and the sr_target_slot id to maxslots */ | ||
1439 | seq->maxslots = session->se_fchannel.maxreqs; | ||
1440 | |||
1441 | status = check_slot_seqid(seq->seqid, slot->sl_seqid, slot->sl_inuse); | ||
1485 | if (status == nfserr_replay_cache) { | 1442 | if (status == nfserr_replay_cache) { |
1486 | cstate->slot = slot; | 1443 | cstate->slot = slot; |
1487 | cstate->session = session; | 1444 | cstate->session = session; |
1488 | /* Return the cached reply status and set cstate->status | 1445 | /* Return the cached reply status and set cstate->status |
1489 | * for nfsd4_svc_encode_compoundres processing */ | 1446 | * for nfsd4_proc_compound processing */ |
1490 | status = nfsd4_replay_cache_entry(resp, seq); | 1447 | status = nfsd4_replay_cache_entry(resp, seq); |
1491 | cstate->status = nfserr_replay_cache; | 1448 | cstate->status = nfserr_replay_cache; |
1492 | goto replay_cache; | 1449 | goto out; |
1493 | } | 1450 | } |
1494 | if (status) | 1451 | if (status) |
1495 | goto out; | 1452 | goto out; |
@@ -1497,23 +1454,23 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
1497 | /* Success! bump slot seqid */ | 1454 | /* Success! bump slot seqid */ |
1498 | slot->sl_inuse = true; | 1455 | slot->sl_inuse = true; |
1499 | slot->sl_seqid = seq->seqid; | 1456 | slot->sl_seqid = seq->seqid; |
1500 | slot->sl_cache_entry.ce_cachethis = seq->cachethis; | 1457 | slot->sl_cachethis = seq->cachethis; |
1501 | /* Always set the cache entry cachethis for solo sequence */ | ||
1502 | if (nfsd4_is_solo_sequence(resp)) | ||
1503 | slot->sl_cache_entry.ce_cachethis = 1; | ||
1504 | 1458 | ||
1505 | cstate->slot = slot; | 1459 | cstate->slot = slot; |
1506 | cstate->session = session; | 1460 | cstate->session = session; |
1507 | 1461 | ||
1508 | replay_cache: | 1462 | /* Hold a session reference until done processing the compound: |
1509 | /* Renew the clientid on success and on replay. | ||
1510 | * Hold a session reference until done processing the compound: | ||
1511 | * nfsd4_put_session called only if the cstate slot is set. | 1463 | * nfsd4_put_session called only if the cstate slot is set. |
1512 | */ | 1464 | */ |
1513 | renew_client(session->se_client); | ||
1514 | nfsd4_get_session(session); | 1465 | nfsd4_get_session(session); |
1515 | out: | 1466 | out: |
1516 | spin_unlock(&sessionid_lock); | 1467 | spin_unlock(&sessionid_lock); |
1468 | /* Renew the clientid on success and on replay */ | ||
1469 | if (cstate->session) { | ||
1470 | nfs4_lock_state(); | ||
1471 | renew_client(session->se_client); | ||
1472 | nfs4_unlock_state(); | ||
1473 | } | ||
1517 | dprintk("%s: return %d\n", __func__, ntohl(status)); | 1474 | dprintk("%s: return %d\n", __func__, ntohl(status)); |
1518 | return status; | 1475 | return status; |
1519 | } | 1476 | } |
@@ -1522,7 +1479,7 @@ __be32 | |||
1522 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 1479 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
1523 | struct nfsd4_setclientid *setclid) | 1480 | struct nfsd4_setclientid *setclid) |
1524 | { | 1481 | { |
1525 | struct sockaddr_in *sin = svc_addr_in(rqstp); | 1482 | struct sockaddr *sa = svc_addr(rqstp); |
1526 | struct xdr_netobj clname = { | 1483 | struct xdr_netobj clname = { |
1527 | .len = setclid->se_namelen, | 1484 | .len = setclid->se_namelen, |
1528 | .data = setclid->se_name, | 1485 | .data = setclid->se_name, |
@@ -1531,7 +1488,6 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1531 | unsigned int strhashval; | 1488 | unsigned int strhashval; |
1532 | struct nfs4_client *conf, *unconf, *new; | 1489 | struct nfs4_client *conf, *unconf, *new; |
1533 | __be32 status; | 1490 | __be32 status; |
1534 | char *princ; | ||
1535 | char dname[HEXDIR_LEN]; | 1491 | char dname[HEXDIR_LEN]; |
1536 | 1492 | ||
1537 | if (!check_name(clname)) | 1493 | if (!check_name(clname)) |
@@ -1554,8 +1510,11 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1554 | /* RFC 3530 14.2.33 CASE 0: */ | 1510 | /* RFC 3530 14.2.33 CASE 0: */ |
1555 | status = nfserr_clid_inuse; | 1511 | status = nfserr_clid_inuse; |
1556 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { | 1512 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { |
1557 | dprintk("NFSD: setclientid: string in use by client" | 1513 | char addr_str[INET6_ADDRSTRLEN]; |
1558 | " at %pI4\n", &conf->cl_addr); | 1514 | rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str, |
1515 | sizeof(addr_str)); | ||
1516 | dprintk("NFSD: setclientid: string in use by client " | ||
1517 | "at %s\n", addr_str); | ||
1559 | goto out; | 1518 | goto out; |
1560 | } | 1519 | } |
1561 | } | 1520 | } |
@@ -1573,7 +1532,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1573 | */ | 1532 | */ |
1574 | if (unconf) | 1533 | if (unconf) |
1575 | expire_client(unconf); | 1534 | expire_client(unconf); |
1576 | new = create_client(clname, dname); | 1535 | new = create_client(clname, dname, rqstp, &clverifier); |
1577 | if (new == NULL) | 1536 | if (new == NULL) |
1578 | goto out; | 1537 | goto out; |
1579 | gen_clid(new); | 1538 | gen_clid(new); |
@@ -1590,7 +1549,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1590 | */ | 1549 | */ |
1591 | expire_client(unconf); | 1550 | expire_client(unconf); |
1592 | } | 1551 | } |
1593 | new = create_client(clname, dname); | 1552 | new = create_client(clname, dname, rqstp, &clverifier); |
1594 | if (new == NULL) | 1553 | if (new == NULL) |
1595 | goto out; | 1554 | goto out; |
1596 | copy_clid(new, conf); | 1555 | copy_clid(new, conf); |
@@ -1600,7 +1559,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1600 | * probable client reboot; state will be removed if | 1559 | * probable client reboot; state will be removed if |
1601 | * confirmed. | 1560 | * confirmed. |
1602 | */ | 1561 | */ |
1603 | new = create_client(clname, dname); | 1562 | new = create_client(clname, dname, rqstp, &clverifier); |
1604 | if (new == NULL) | 1563 | if (new == NULL) |
1605 | goto out; | 1564 | goto out; |
1606 | gen_clid(new); | 1565 | gen_clid(new); |
@@ -1611,25 +1570,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
1611 | * confirmed. | 1570 | * confirmed. |
1612 | */ | 1571 | */ |
1613 | expire_client(unconf); | 1572 | expire_client(unconf); |
1614 | new = create_client(clname, dname); | 1573 | new = create_client(clname, dname, rqstp, &clverifier); |
1615 | if (new == NULL) | 1574 | if (new == NULL) |
1616 | goto out; | 1575 | goto out; |
1617 | gen_clid(new); | 1576 | gen_clid(new); |
1618 | } | 1577 | } |
1619 | copy_verf(new, &clverifier); | 1578 | gen_callback(new, setclid, rpc_get_scope_id(sa)); |
1620 | new->cl_addr = sin->sin_addr.s_addr; | ||
1621 | new->cl_flavor = rqstp->rq_flavor; | ||
1622 | princ = svc_gss_principal(rqstp); | ||
1623 | if (princ) { | ||
1624 | new->cl_principal = kstrdup(princ, GFP_KERNEL); | ||
1625 | if (new->cl_principal == NULL) { | ||
1626 | free_client(new); | ||
1627 | goto out; | ||
1628 | } | ||
1629 | } | ||
1630 | copy_cred(&new->cl_cred, &rqstp->rq_cred); | ||
1631 | gen_confirm(new); | ||
1632 | gen_callback(new, setclid); | ||
1633 | add_to_unconfirmed(new, strhashval); | 1579 | add_to_unconfirmed(new, strhashval); |
1634 | setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; | 1580 | setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; |
1635 | setclid->se_clientid.cl_id = new->cl_clientid.cl_id; | 1581 | setclid->se_clientid.cl_id = new->cl_clientid.cl_id; |
@@ -1651,7 +1597,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
1651 | struct nfsd4_compound_state *cstate, | 1597 | struct nfsd4_compound_state *cstate, |
1652 | struct nfsd4_setclientid_confirm *setclientid_confirm) | 1598 | struct nfsd4_setclientid_confirm *setclientid_confirm) |
1653 | { | 1599 | { |
1654 | struct sockaddr_in *sin = svc_addr_in(rqstp); | 1600 | struct sockaddr *sa = svc_addr(rqstp); |
1655 | struct nfs4_client *conf, *unconf; | 1601 | struct nfs4_client *conf, *unconf; |
1656 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; | 1602 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; |
1657 | clientid_t * clid = &setclientid_confirm->sc_clientid; | 1603 | clientid_t * clid = &setclientid_confirm->sc_clientid; |
@@ -1670,9 +1616,9 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
1670 | unconf = find_unconfirmed_client(clid); | 1616 | unconf = find_unconfirmed_client(clid); |
1671 | 1617 | ||
1672 | status = nfserr_clid_inuse; | 1618 | status = nfserr_clid_inuse; |
1673 | if (conf && conf->cl_addr != sin->sin_addr.s_addr) | 1619 | if (conf && !rpc_cmp_addr((struct sockaddr *) &conf->cl_addr, sa)) |
1674 | goto out; | 1620 | goto out; |
1675 | if (unconf && unconf->cl_addr != sin->sin_addr.s_addr) | 1621 | if (unconf && !rpc_cmp_addr((struct sockaddr *) &unconf->cl_addr, sa)) |
1676 | goto out; | 1622 | goto out; |
1677 | 1623 | ||
1678 | /* | 1624 | /* |
@@ -2163,7 +2109,7 @@ int nfsd_change_deleg_cb(struct file_lock **onlist, int arg) | |||
2163 | return -EAGAIN; | 2109 | return -EAGAIN; |
2164 | } | 2110 | } |
2165 | 2111 | ||
2166 | static struct lock_manager_operations nfsd_lease_mng_ops = { | 2112 | static const struct lock_manager_operations nfsd_lease_mng_ops = { |
2167 | .fl_break = nfsd_break_deleg_cb, | 2113 | .fl_break = nfsd_break_deleg_cb, |
2168 | .fl_release_private = nfsd_release_deleg_cb, | 2114 | .fl_release_private = nfsd_release_deleg_cb, |
2169 | .fl_copy_lock = nfsd_copy_lock_deleg_cb, | 2115 | .fl_copy_lock = nfsd_copy_lock_deleg_cb, |
@@ -3368,7 +3314,7 @@ nfs4_transform_lock_offset(struct file_lock *lock) | |||
3368 | 3314 | ||
3369 | /* Hack!: For now, we're defining this just so we can use a pointer to it | 3315 | /* Hack!: For now, we're defining this just so we can use a pointer to it |
3370 | * as a unique cookie to identify our (NFSv4's) posix locks. */ | 3316 | * as a unique cookie to identify our (NFSv4's) posix locks. */ |
3371 | static struct lock_manager_operations nfsd_posix_mng_ops = { | 3317 | static const struct lock_manager_operations nfsd_posix_mng_ops = { |
3372 | }; | 3318 | }; |
3373 | 3319 | ||
3374 | static inline void | 3320 | static inline void |
@@ -4072,7 +4018,7 @@ set_max_delegations(void) | |||
4072 | 4018 | ||
4073 | /* initialization to perform when the nfsd service is started: */ | 4019 | /* initialization to perform when the nfsd service is started: */ |
4074 | 4020 | ||
4075 | static void | 4021 | static int |
4076 | __nfs4_state_start(void) | 4022 | __nfs4_state_start(void) |
4077 | { | 4023 | { |
4078 | unsigned long grace_time; | 4024 | unsigned long grace_time; |
@@ -4084,19 +4030,26 @@ __nfs4_state_start(void) | |||
4084 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", | 4030 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", |
4085 | grace_time/HZ); | 4031 | grace_time/HZ); |
4086 | laundry_wq = create_singlethread_workqueue("nfsd4"); | 4032 | laundry_wq = create_singlethread_workqueue("nfsd4"); |
4033 | if (laundry_wq == NULL) | ||
4034 | return -ENOMEM; | ||
4087 | queue_delayed_work(laundry_wq, &laundromat_work, grace_time); | 4035 | queue_delayed_work(laundry_wq, &laundromat_work, grace_time); |
4088 | set_max_delegations(); | 4036 | set_max_delegations(); |
4037 | return set_callback_cred(); | ||
4089 | } | 4038 | } |
4090 | 4039 | ||
4091 | void | 4040 | int |
4092 | nfs4_state_start(void) | 4041 | nfs4_state_start(void) |
4093 | { | 4042 | { |
4043 | int ret; | ||
4044 | |||
4094 | if (nfs4_init) | 4045 | if (nfs4_init) |
4095 | return; | 4046 | return 0; |
4096 | nfsd4_load_reboot_recovery_data(); | 4047 | nfsd4_load_reboot_recovery_data(); |
4097 | __nfs4_state_start(); | 4048 | ret = __nfs4_state_start(); |
4049 | if (ret) | ||
4050 | return ret; | ||
4098 | nfs4_init = 1; | 4051 | nfs4_init = 1; |
4099 | return; | 4052 | return 0; |
4100 | } | 4053 | } |
4101 | 4054 | ||
4102 | time_t | 4055 | time_t |