diff options
| -rw-r--r-- | fs/nfsd/nfs4state.c | 116 |
1 files changed, 49 insertions, 67 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f1262f73f08b..036d5f16fd7f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
| @@ -776,17 +776,15 @@ free_session_slots(struct nfsd4_session *ses) | |||
| 776 | * We don't actually need to cache the rpc and session headers, so we | 776 | * We don't actually need to cache the rpc and session headers, so we |
| 777 | * can allocate a little less for each slot: | 777 | * can allocate a little less for each slot: |
| 778 | */ | 778 | */ |
| 779 | static inline int slot_bytes(struct nfsd4_channel_attrs *ca) | 779 | static inline u32 slot_bytes(struct nfsd4_channel_attrs *ca) |
| 780 | { | 780 | { |
| 781 | return ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; | 781 | u32 size; |
| 782 | } | ||
| 783 | |||
| 784 | static int nfsd4_sanitize_slot_size(u32 size) | ||
| 785 | { | ||
| 786 | size -= NFSD_MIN_HDR_SEQ_SZ; /* We don't cache the rpc header */ | ||
| 787 | size = min_t(u32, size, NFSD_SLOT_CACHE_SIZE); | ||
| 788 | 782 | ||
| 789 | return size; | 783 | if (ca->maxresp_cached < NFSD_MIN_HDR_SEQ_SZ) |
| 784 | size = 0; | ||
| 785 | else | ||
| 786 | size = ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; | ||
| 787 | return size + sizeof(struct nfsd4_slot); | ||
| 790 | } | 788 | } |
| 791 | 789 | ||
| 792 | /* | 790 | /* |
| @@ -794,12 +792,12 @@ static int nfsd4_sanitize_slot_size(u32 size) | |||
| 794 | * re-negotiate active sessions and reduce their slot usage to make | 792 | * re-negotiate active sessions and reduce their slot usage to make |
| 795 | * room for new connections. For now we just fail the create session. | 793 | * room for new connections. For now we just fail the create session. |
| 796 | */ | 794 | */ |
| 797 | static int nfsd4_get_drc_mem(int slotsize, u32 num) | 795 | static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca) |
| 798 | { | 796 | { |
| 797 | u32 slotsize = slot_bytes(ca); | ||
| 798 | u32 num = ca->maxreqs; | ||
| 799 | int avail; | 799 | int avail; |
| 800 | 800 | ||
| 801 | num = min_t(u32, num, NFSD_MAX_SLOTS_PER_SESSION); | ||
| 802 | |||
| 803 | spin_lock(&nfsd_drc_lock); | 801 | spin_lock(&nfsd_drc_lock); |
| 804 | avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, | 802 | avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, |
| 805 | nfsd_drc_max_mem - nfsd_drc_mem_used); | 803 | nfsd_drc_max_mem - nfsd_drc_mem_used); |
| @@ -810,15 +808,19 @@ static int nfsd4_get_drc_mem(int slotsize, u32 num) | |||
| 810 | return num; | 808 | return num; |
| 811 | } | 809 | } |
| 812 | 810 | ||
| 813 | static void nfsd4_put_drc_mem(int slotsize, int num) | 811 | static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca) |
| 814 | { | 812 | { |
| 813 | int slotsize = slot_bytes(ca); | ||
| 814 | |||
| 815 | spin_lock(&nfsd_drc_lock); | 815 | spin_lock(&nfsd_drc_lock); |
| 816 | nfsd_drc_mem_used -= slotsize * num; | 816 | nfsd_drc_mem_used -= slotsize * ca->maxreqs; |
| 817 | spin_unlock(&nfsd_drc_lock); | 817 | spin_unlock(&nfsd_drc_lock); |
| 818 | } | 818 | } |
| 819 | 819 | ||
| 820 | static struct nfsd4_session *__alloc_session(int slotsize, int numslots) | 820 | static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *attrs) |
| 821 | { | 821 | { |
| 822 | int numslots = attrs->maxreqs; | ||
| 823 | int slotsize = slot_bytes(attrs); | ||
| 822 | struct nfsd4_session *new; | 824 | struct nfsd4_session *new; |
| 823 | int mem, i; | 825 | int mem, i; |
| 824 | 826 | ||
| @@ -831,8 +833,7 @@ static struct nfsd4_session *__alloc_session(int slotsize, int numslots) | |||
| 831 | return NULL; | 833 | return NULL; |
| 832 | /* allocate each struct nfsd4_slot and data cache in one piece */ | 834 | /* allocate each struct nfsd4_slot and data cache in one piece */ |
| 833 | for (i = 0; i < numslots; i++) { | 835 | for (i = 0; i < numslots; i++) { |
| 834 | mem = sizeof(struct nfsd4_slot) + slotsize; | 836 | new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL); |
| 835 | new->se_slots[i] = kzalloc(mem, GFP_KERNEL); | ||
| 836 | if (!new->se_slots[i]) | 837 | if (!new->se_slots[i]) |
| 837 | goto out_free; | 838 | goto out_free; |
| 838 | } | 839 | } |
| @@ -844,21 +845,6 @@ out_free: | |||
| 844 | return NULL; | 845 | return NULL; |
| 845 | } | 846 | } |
| 846 | 847 | ||
| 847 | static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, | ||
| 848 | struct nfsd4_channel_attrs *req, | ||
| 849 | int numslots, int slotsize, | ||
| 850 | struct nfsd_net *nn) | ||
| 851 | { | ||
| 852 | u32 maxrpc = nn->nfsd_serv->sv_max_mesg; | ||
| 853 | |||
| 854 | new->maxreqs = numslots; | ||
| 855 | new->maxresp_cached = min_t(u32, req->maxresp_cached, | ||
| 856 | slotsize + NFSD_MIN_HDR_SEQ_SZ); | ||
| 857 | new->maxreq_sz = min_t(u32, req->maxreq_sz, maxrpc); | ||
| 858 | new->maxresp_sz = min_t(u32, req->maxresp_sz, maxrpc); | ||
| 859 | new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND); | ||
| 860 | } | ||
| 861 | |||
| 862 | static void free_conn(struct nfsd4_conn *c) | 848 | static void free_conn(struct nfsd4_conn *c) |
| 863 | { | 849 | { |
| 864 | svc_xprt_put(c->cn_xprt); | 850 | svc_xprt_put(c->cn_xprt); |
| @@ -960,7 +946,6 @@ static void nfsd4_del_conns(struct nfsd4_session *s) | |||
| 960 | 946 | ||
| 961 | static void __free_session(struct nfsd4_session *ses) | 947 | static void __free_session(struct nfsd4_session *ses) |
| 962 | { | 948 | { |
| 963 | nfsd4_put_drc_mem(slot_bytes(&ses->se_fchannel), ses->se_fchannel.maxreqs); | ||
| 964 | free_session_slots(ses); | 949 | free_session_slots(ses); |
| 965 | kfree(ses); | 950 | kfree(ses); |
| 966 | } | 951 | } |
| @@ -971,35 +956,10 @@ static void free_session(struct nfsd4_session *ses) | |||
| 971 | 956 | ||
| 972 | lockdep_assert_held(&nn->client_lock); | 957 | lockdep_assert_held(&nn->client_lock); |
| 973 | nfsd4_del_conns(ses); | 958 | nfsd4_del_conns(ses); |
| 959 | nfsd4_put_drc_mem(&ses->se_fchannel); | ||
| 974 | __free_session(ses); | 960 | __free_session(ses); |
| 975 | } | 961 | } |
| 976 | 962 | ||
| 977 | static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan, | ||
| 978 | struct nfsd_net *nn) | ||
| 979 | { | ||
| 980 | struct nfsd4_session *new; | ||
| 981 | int numslots, slotsize; | ||
| 982 | /* | ||
| 983 | * Note decreasing slot size below client's request may | ||
| 984 | * make it difficult for client to function correctly, whereas | ||
| 985 | * decreasing the number of slots will (just?) affect | ||
| 986 | * performance. When short on memory we therefore prefer to | ||
| 987 | * decrease number of slots instead of their size. | ||
| 988 | */ | ||
| 989 | slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached); | ||
| 990 | numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs); | ||
| 991 | if (numslots < 1) | ||
| 992 | return NULL; | ||
| 993 | |||
| 994 | new = __alloc_session(slotsize, numslots); | ||
| 995 | if (!new) { | ||
| 996 | nfsd4_put_drc_mem(slotsize, numslots); | ||
| 997 | return NULL; | ||
| 998 | } | ||
| 999 | init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize, nn); | ||
| 1000 | return new; | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) | 963 | static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) |
| 1004 | { | 964 | { |
| 1005 | int idx; | 965 | int idx; |
| @@ -1022,7 +982,8 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru | |||
| 1022 | list_add(&new->se_perclnt, &clp->cl_sessions); | 982 | list_add(&new->se_perclnt, &clp->cl_sessions); |
| 1023 | spin_unlock(&clp->cl_lock); | 983 | spin_unlock(&clp->cl_lock); |
| 1024 | spin_unlock(&nn->client_lock); | 984 | spin_unlock(&nn->client_lock); |
| 1025 | 985 | memcpy(&new->se_fchannel, &cses->fore_channel, | |
| 986 | sizeof(struct nfsd4_channel_attrs)); | ||
| 1026 | if (cses->flags & SESSION4_BACK_CHAN) { | 987 | if (cses->flags & SESSION4_BACK_CHAN) { |
| 1027 | struct sockaddr *sa = svc_addr(rqstp); | 988 | struct sockaddr *sa = svc_addr(rqstp); |
| 1028 | /* | 989 | /* |
| @@ -1803,12 +1764,33 @@ nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, | |||
| 1803 | /* seqid, slotID, slotID, slotID, status */ \ | 1764 | /* seqid, slotID, slotID, slotID, status */ \ |
| 1804 | 5 ) * sizeof(__be32)) | 1765 | 5 ) * sizeof(__be32)) |
| 1805 | 1766 | ||
| 1806 | static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca) | 1767 | static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) |
| 1807 | { | 1768 | { |
| 1769 | u32 maxrpc = nn->nfsd_serv->sv_max_mesg; | ||
| 1770 | |||
| 1808 | if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ) | 1771 | if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ) |
| 1809 | return nfserr_toosmall; | 1772 | return nfserr_toosmall; |
| 1810 | if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ) | 1773 | if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ) |
| 1811 | return nfserr_toosmall; | 1774 | return nfserr_toosmall; |
| 1775 | ca->headerpadsz = 0; | ||
| 1776 | ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc); | ||
| 1777 | ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc); | ||
| 1778 | ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND); | ||
| 1779 | ca->maxresp_cached = min_t(u32, ca->maxresp_cached, | ||
| 1780 | NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ); | ||
| 1781 | ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION); | ||
| 1782 | / | ||
