diff options
author | J. Bruce Fields <bfields@redhat.com> | 2013-04-08 16:44:14 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2013-04-09 16:43:44 -0400 |
commit | 55c760cfc40d75b4d8a17d56580ec306db2ab14f (patch) | |
tree | 36adf820afe85ed7644654c9f505c95cb0f774c3 /fs/nfsd/nfs4state.c | |
parent | 373cd4098a6392395af63af220d989df00b444f7 (diff) |
nfsd4: fix forechannel attribute negotiation
Negotiation of the 4.1 session forechannel attributes is a mess. Fix:
- Move it all into check_forechannel_attrs instead of spreading
it between that, alloc_session, and init_forechannel_attrs.
- set a minimum "slotsize" so that our drc memory limits apply
even for small maxresponsesize_cached. This also fixes some
bugs when slotsize becomes <= 0.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-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 | /* | ||
1783 | * Note decreasing slot size below client's request may make it | ||
1784 | * difficult for client to function correctly, whereas | ||
1785 | * decreasing the number of slots will (just?) affect | ||
1786 | * performance. When short on memory we therefore prefer to | ||
1787 | * decrease number of slots instead of their size. Clients that | ||
1788 | * request larger slots than they need will get poor results: | ||
1789 | */ | ||
1790 | ca->maxreqs = nfsd4_get_drc_mem(ca); | ||
1791 | if (!ca->maxreqs) | ||
1792 | return nfserr_jukebox; | ||
1793 | |||
1812 | return nfs_ok; | 1794 | return nfs_ok; |
1813 | } | 1795 | } |
1814 | 1796 | ||
@@ -1827,13 +1809,13 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1827 | 1809 | ||
1828 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) | 1810 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) |
1829 | return nfserr_inval; | 1811 | return nfserr_inval; |
1830 | status = check_forechannel_attrs(&cr_ses->fore_channel); | 1812 | status = check_forechannel_attrs(&cr_ses->fore_channel, nn); |
1831 | if (status) | 1813 | if (status) |
1832 | return status; | 1814 | return status; |
1833 | new = alloc_session(&cr_ses->fore_channel, nn); | ||
1834 | if (!new) | ||
1835 | return nfserr_jukebox; | ||
1836 | status = nfserr_jukebox; | 1815 | status = nfserr_jukebox; |
1816 | new = alloc_session(&cr_ses->fore_channel); | ||
1817 | if (!new) | ||
1818 | goto out_release_drc_mem; | ||
1837 | conn = alloc_conn_from_crses(rqstp, cr_ses); | 1819 | conn = alloc_conn_from_crses(rqstp, cr_ses); |
1838 | if (!conn) | 1820 | if (!conn) |
1839 | goto out_free_session; | 1821 | goto out_free_session; |
@@ -1892,8 +1874,6 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1892 | 1874 | ||
1893 | memcpy(cr_ses->sessionid.data, new->se_sessionid.data, | 1875 | memcpy(cr_ses->sessionid.data, new->se_sessionid.data, |
1894 | NFS4_MAX_SESSIONID_LEN); | 1876 | NFS4_MAX_SESSIONID_LEN); |
1895 | memcpy(&cr_ses->fore_channel, &new->se_fchannel, | ||
1896 | sizeof(struct nfsd4_channel_attrs)); | ||
1897 | cs_slot->sl_seqid++; | 1877 | cs_slot->sl_seqid++; |
1898 | cr_ses->seqid = cs_slot->sl_seqid; | 1878 | cr_ses->seqid = cs_slot->sl_seqid; |
1899 | 1879 | ||
@@ -1906,6 +1886,8 @@ out_free_conn: | |||
1906 | free_conn(conn); | 1886 | free_conn(conn); |
1907 | out_free_session: | 1887 | out_free_session: |
1908 | __free_session(new); | 1888 | __free_session(new); |
1889 | out_release_drc_mem: | ||
1890 | nfsd4_put_drc_mem(&cr_ses->fore_channel); | ||
1909 | return status; | 1891 | return status; |
1910 | } | 1892 | } |
1911 | 1893 | ||