aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/nfsd/nfs4state.c211
1 files changed, 89 insertions, 122 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index ebddcc173ed8..f86476c23b2f 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -533,94 +533,6 @@ gen_sessionid(struct nfsd4_session *ses)
533 */ 533 */
534#define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44) 534#define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44)
535 535
536/*
537 * Give the client the number of ca_maxresponsesize_cached slots it
538 * requests, of size bounded by NFSD_SLOT_CACHE_SIZE,
539 * NFSD_MAX_MEM_PER_SESSION, and nfsd_drc_max_mem. Do not allow more
540 * than NFSD_MAX_SLOTS_PER_SESSION.
541 *
542 * If we run out of reserved DRC memory we should (up to a point)
543 * re-negotiate active sessions and reduce their slot usage to make
544 * rooom for new connections. For now we just fail the create session.
545 */
546static int set_forechannel_drc_size(struct nfsd4_channel_attrs *fchan)
547{
548 int mem, size = fchan->maxresp_cached;
549
550 if (fchan->maxreqs < 1)
551 return nfserr_inval;
552
553 if (size < NFSD_MIN_HDR_SEQ_SZ)
554 size = NFSD_MIN_HDR_SEQ_SZ;
555 size -= NFSD_MIN_HDR_SEQ_SZ;
556 if (size > NFSD_SLOT_CACHE_SIZE)
557 size = NFSD_SLOT_CACHE_SIZE;
558
559 /* bound the maxreqs by NFSD_MAX_MEM_PER_SESSION */
560 mem = fchan->maxreqs * size;
561 if (mem > NFSD_MAX_MEM_PER_SESSION) {
562 fchan->maxreqs = NFSD_MAX_MEM_PER_SESSION / size;
563 if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION)
564 fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION;
565 mem = fchan->maxreqs * size;
566 }
567
568 spin_lock(&nfsd_drc_lock);
569 /* bound the total session drc memory ussage */
570 if (mem + nfsd_drc_mem_used > nfsd_drc_max_mem) {
571 fchan->maxreqs = (nfsd_drc_max_mem - nfsd_drc_mem_used) / size;
572 mem = fchan->maxreqs * size;
573 }
574 nfsd_drc_mem_used += mem;
575 spin_unlock(&nfsd_drc_lock);
576
577 if (fchan->maxreqs == 0)
578 return nfserr_jukebox;
579
580 fchan->maxresp_cached = size + NFSD_MIN_HDR_SEQ_SZ;
581 return 0;
582}
583
584/*
585 * fchan holds the client values on input, and the server values on output
586 * sv_max_mesg is the maximum payload plus one page for overhead.
587 */
588static int init_forechannel_attrs(struct svc_rqst *rqstp,
589 struct nfsd4_channel_attrs *session_fchan,
590 struct nfsd4_channel_attrs *fchan)
591{
592 int status = 0;
593 __u32 maxcount = nfsd_serv->sv_max_mesg;
594
595 /* headerpadsz set to zero in encode routine */
596
597 /* Use the client's max request and max response size if possible */
598 if (fchan->maxreq_sz > maxcount)
599 fchan->maxreq_sz = maxcount;
600 session_fchan->maxreq_sz = fchan->maxreq_sz;
601
602 if (fchan->maxresp_sz > maxcount)
603 fchan->maxresp_sz = maxcount;
604 session_fchan->maxresp_sz = fchan->maxresp_sz;
605
606 /* Use the client's maxops if possible */
607 if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND)
608 fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND;
609 session_fchan->maxops = fchan->maxops;
610
611 /* FIXME: Error means no more DRC pages so the server should
612 * recover pages from existing sessions. For now fail session
613 * creation.
614 */
615 status = set_forechannel_drc_size(fchan);
616
617 session_fchan->maxresp_cached = fchan->maxresp_cached;
618 session_fchan->maxreqs = fchan->maxreqs;
619
620 dprintk("%s status %d\n", __func__, status);
621 return status;
622}
623
624static void 536static void
625free_session_slots(struct nfsd4_session *ses) 537free_session_slots(struct nfsd4_session *ses)
626{ 538{
@@ -639,63 +551,118 @@ static inline int slot_bytes(struct nfsd4_channel_attrs *ca)
639 return ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; 551 return ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
640} 552}
641 553
642static __be32 alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses) 554static int nfsd4_sanitize_slot_size(u32 size)
643{ 555{
644 struct nfsd4_session *new, tmp; 556 size -= NFSD_MIN_HDR_SEQ_SZ; /* We don't cache the rpc header */
645 struct nfsd4_slot *sp; 557 size = min_t(u32, size, NFSD_SLOT_CACHE_SIZE);
646 int idx, slotsize, cachesize, i;
647 int status;
648 558
649 memset(&tmp, 0, sizeof(tmp)); 559 return size;
560}
650 561
651 /* FIXME: For now, we just accept the client back channel attributes. */ 562/*
652 tmp.se_bchannel = cses->back_channel; 563 * XXX: If we run out of reserved DRC memory we could (up to a point)
653 status = init_forechannel_attrs(rqstp, &tmp.se_fchannel, 564 * re-negotiate active sessions and reduce their slot usage to make
654 &cses->fore_channel); 565 * rooom for new connections. For now we just fail the create session.
655 if (status) 566 */
656 goto out; 567static int nfsd4_get_drc_mem(int slotsize, u32 num)
568{
569 int avail;
657 570
658 BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *) 571 num = min_t(u32, num, NFSD_MAX_SLOTS_PER_SESSION);
659 + sizeof(struct nfsd4_session) > PAGE_SIZE);
660 572
661 status = nfserr_jukebox; 573 spin_lock(&nfsd_drc_lock);
662 /* allocate struct nfsd4_session and slot table pointers in one piece */ 574 avail = min_t(int, NFSD_MAX_MEM_PER_SESSION,
663 slotsize = tmp.se_fchannel.maxreqs * sizeof(struct nfsd4_slot *); 575 nfsd_drc_max_mem - nfsd_drc_mem_used);
664 new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); 576 num = min_t(int, num, avail / slotsize);
665 if (!new) 577 nfsd_drc_mem_used += num * slotsize;
666 goto out; 578 spin_unlock(&nfsd_drc_lock);
579
580 return num;
581}
582
583static void nfsd4_put_drc_mem(int slotsize, int num)
584{
585 spin_lock(&nfsd_drc_lock);
586 nfsd_drc_mem_used -= slotsize * num;
587 spin_unlock(&nfsd_drc_lock);
588}
589
590static struct nfsd4_session *alloc_session(int slotsize, int numslots)
591{
592 struct nfsd4_session *new;
593 int mem, i;
667 594
668 memcpy(new, &tmp, sizeof(*new)); 595 BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *)
596 + sizeof(struct nfsd4_session) > PAGE_SIZE);
597 mem = numslots * sizeof(struct nfsd4_slot *);
669 598
599 new = kzalloc(sizeof(*new) + mem, GFP_KERNEL);
600 if (!new)
601 return NULL;
670 /* allocate each struct nfsd4_slot and data cache in one piece */ 602 /* allocate each struct nfsd4_slot and data cache in one piece */
671 cachesize = slot_bytes(&new->se_fchannel); 603 for (i = 0; i < numslots; i++) {
672 for (i = 0; i < new->se_fchannel.maxreqs; i++) { 604 mem = sizeof(struct nfsd4_slot) + slotsize;
673 sp = kzalloc(sizeof(*sp) + cachesize, GFP_KERNEL); 605 new->se_slots[i] = kzalloc(mem, GFP_KERNEL);
674 if (!sp) 606 if (!new->se_slots[i])
675 goto out_free; 607 goto out_free;
676 new->se_slots[i] = sp;
677 } 608 }
609 return new;
610out_free:
611 while (i--)
612 kfree(new->se_slots[i]);
613 kfree(new);
614 return NULL;
615}
616
617static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4_channel_attrs *req, int numslots, int slotsize)
618{
619 u32 maxrpc = nfsd_serv->sv_max_mesg;
620
621 new->maxreqs = numslots;
622 new->maxresp_cached = slotsize + NFSD_MIN_HDR_SEQ_SZ;
623 new->maxreq_sz = min_t(u32, req->maxreq_sz, maxrpc);
624 new->maxresp_sz = min_t(u32, req->maxresp_sz, maxrpc);
625 new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND);
626}
627
628static __be32 alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses)
629{
630 struct nfsd4_session *new;
631 struct nfsd4_channel_attrs *fchan = &cses->fore_channel;
632 int numslots, slotsize;
633 int idx;
634
635 /*
636 * Note decreasing slot size below client's request may
637 * make it difficult for client to function correctly, whereas
638 * decreasing the number of slots will (just?) affect
639 * performance. When short on memory we therefore prefer to
640 * decrease number of slots instead of their size.
641 */
642 slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached);
643 numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs);
644
645 new = alloc_session(slotsize, numslots);
646 if (!new) {
647 nfsd4_put_drc_mem(slotsize, fchan->maxreqs);
648 return nfserr_jukebox;
649 }
650 init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize);
678 651
679 new->se_client = clp; 652 new->se_client = clp;
680 gen_sessionid(new); 653 gen_sessionid(new);
681 idx = hash_sessionid(&new->se_sessionid);
682 memcpy(clp->cl_sessionid.data, new->se_sessionid.data, 654 memcpy(clp->cl_sessionid.data, new->se_sessionid.data,
683 NFS4_MAX_SESSIONID_LEN); 655 NFS4_MAX_SESSIONID_LEN);
684 656
685 new->se_flags = cses->flags; 657 new->se_flags = cses->flags;
686 kref_init(&new->se_ref); 658 kref_init(&new->se_ref);
659 idx = hash_sessionid(&new->se_sessionid);
687 spin_lock(&client_lock); 660 spin_lock(&client_lock);
688 list_add(&new->se_hash, &sessionid_hashtbl[idx]); 661 list_add(&new->se_hash, &sessionid_hashtbl[idx]);
689 list_add(&new->se_perclnt, &clp->cl_sessions); 662 list_add(&new->se_perclnt, &clp->cl_sessions);
690 spin_unlock(&client_lock); 663 spin_unlock(&client_lock);
691 664
692 status = nfs_ok; 665 return nfs_ok;
693out:
694 return status;
695out_free:
696 free_session_slots(new);
697 kfree(new);
698 goto out;
699} 666}
700 667
701/* caller must hold client_lock */ 668/* caller must hold client_lock */