aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4state.c
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2013-04-08 16:44:14 -0400
committerJ. Bruce Fields <bfields@redhat.com>2013-04-09 16:43:44 -0400
commit55c760cfc40d75b4d8a17d56580ec306db2ab14f (patch)
tree36adf820afe85ed7644654c9f505c95cb0f774c3 /fs/nfsd/nfs4state.c
parent373cd4098a6392395af63af220d989df00b444f7 (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.c116
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 */
779static inline int slot_bytes(struct nfsd4_channel_attrs *ca) 779static 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
784static 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 */
797static int nfsd4_get_drc_mem(int slotsize, u32 num) 795static 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
813static void nfsd4_put_drc_mem(int slotsize, int num) 811static 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
820static struct nfsd4_session *__alloc_session(int slotsize, int numslots) 820static 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
847static 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
862static void free_conn(struct nfsd4_conn *c) 848static 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
961static void __free_session(struct nfsd4_session *ses) 947static 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
977static 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
1003static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) 963static 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
1806static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca) 1767static __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);
1907out_free_session: 1887out_free_session:
1908 __free_session(new); 1888 __free_session(new);
1889out_release_drc_mem:
1890 nfsd4_put_drc_mem(&cr_ses->fore_channel);
1909 return status; 1891 return status;
1910} 1892}
1911 1893