Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+49 -67
+49 -67
fs/nfsd/nfs4state.c
··· 776 776 * We don't actually need to cache the rpc and session headers, so we 777 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; 782 - } 781 + u32 size; 783 782 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 - 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 /* ··· 792 794 * re-negotiate active sessions and reduce their slot usage to make 793 795 * room for new connections. For now we just fail the create session. 794 796 */ 795 - static int nfsd4_get_drc_mem(int slotsize, u32 num) 797 + static u32 nfsd4_get_drc_mem(struct nfsd4_channel_attrs *ca) 796 798 { 799 + u32 slotsize = slot_bytes(ca); 800 + u32 num = ca->maxreqs; 797 801 int avail; 798 - 799 - num = min_t(u32, num, NFSD_MAX_SLOTS_PER_SESSION); 800 802 801 803 spin_lock(&nfsd_drc_lock); 802 804 avail = min((unsigned long)NFSD_MAX_MEM_PER_SESSION, ··· 808 810 return num; 809 811 } 810 812 811 - static void nfsd4_put_drc_mem(int slotsize, int num) 813 + static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca) 812 814 { 815 + int slotsize = slot_bytes(ca); 816 + 813 817 spin_lock(&nfsd_drc_lock); 814 - nfsd_drc_mem_used -= slotsize * num; 818 + nfsd_drc_mem_used -= slotsize * ca->maxreqs; 815 819 spin_unlock(&nfsd_drc_lock); 816 820 } 817 821 818 - static struct nfsd4_session *__alloc_session(int slotsize, int numslots) 822 + static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *attrs) 819 823 { 824 + int numslots = attrs->maxreqs; 825 + int slotsize = slot_bytes(attrs); 820 826 struct nfsd4_session *new; 821 827 int mem, i; 822 828 ··· 833 831 return NULL; 834 832 /* allocate each struct nfsd4_slot and data cache in one piece */ 835 833 for (i = 0; i < numslots; i++) { 836 - mem = sizeof(struct nfsd4_slot) + slotsize; 837 - new->se_slots[i] = kzalloc(mem, GFP_KERNEL); 834 + new->se_slots[i] = kzalloc(slotsize, GFP_KERNEL); 838 835 if (!new->se_slots[i]) 839 836 goto out_free; 840 837 } ··· 843 842 kfree(new->se_slots[i]); 844 843 kfree(new); 845 844 return NULL; 846 - } 847 - 848 - static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, 849 - struct nfsd4_channel_attrs *req, 850 - int numslots, int slotsize, 851 - struct nfsd_net *nn) 852 - { 853 - u32 maxrpc = nn->nfsd_serv->sv_max_mesg; 854 - 855 - new->maxreqs = numslots; 856 - new->maxresp_cached = min_t(u32, req->maxresp_cached, 857 - slotsize + NFSD_MIN_HDR_SEQ_SZ); 858 - new->maxreq_sz = min_t(u32, req->maxreq_sz, maxrpc); 859 - new->maxresp_sz = min_t(u32, req->maxresp_sz, maxrpc); 860 - new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND); 861 845 } 862 846 863 847 static void free_conn(struct nfsd4_conn *c) ··· 946 960 947 961 static void __free_session(struct nfsd4_session *ses) 948 962 { 949 - nfsd4_put_drc_mem(slot_bytes(&ses->se_fchannel), ses->se_fchannel.maxreqs); 950 963 free_session_slots(ses); 951 964 kfree(ses); 952 965 } ··· 956 971 957 972 lockdep_assert_held(&nn->client_lock); 958 973 nfsd4_del_conns(ses); 974 + nfsd4_put_drc_mem(&ses->se_fchannel); 959 975 __free_session(ses); 960 - } 961 - 962 - static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan, 963 - struct nfsd_net *nn) 964 - { 965 - struct nfsd4_session *new; 966 - int numslots, slotsize; 967 - /* 968 - * Note decreasing slot size below client's request may 969 - * make it difficult for client to function correctly, whereas 970 - * decreasing the number of slots will (just?) affect 971 - * performance. When short on memory we therefore prefer to 972 - * decrease number of slots instead of their size. 973 - */ 974 - slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached); 975 - numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs); 976 - if (numslots < 1) 977 - return NULL; 978 - 979 - new = __alloc_session(slotsize, numslots); 980 - if (!new) { 981 - nfsd4_put_drc_mem(slotsize, numslots); 982 - return NULL; 983 - } 984 - init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize, nn); 985 - return new; 986 976 } 987 977 988 978 static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) ··· 982 1022 list_add(&new->se_perclnt, &clp->cl_sessions); 983 1023 spin_unlock(&clp->cl_lock); 984 1024 spin_unlock(&nn->client_lock); 985 - 1025 + memcpy(&new->se_fchannel, &cses->fore_channel, 1026 + sizeof(struct nfsd4_channel_attrs)); 986 1027 if (cses->flags & SESSION4_BACK_CHAN) { 987 1028 struct sockaddr *sa = svc_addr(rqstp); 988 1029 /* ··· 1764 1803 /* seqid, slotID, slotID, slotID, status */ \ 1765 1804 5 ) * sizeof(__be32)) 1766 1805 1767 - static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca) 1806 + static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfsd_net *nn) 1768 1807 { 1808 + u32 maxrpc = nn->nfsd_serv->sv_max_mesg; 1809 + 1769 1810 if (ca->maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ) 1770 1811 return nfserr_toosmall; 1771 1812 if (ca->maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ) 1772 1813 return nfserr_toosmall; 1814 + ca->headerpadsz = 0; 1815 + ca->maxreq_sz = min_t(u32, ca->maxreq_sz, maxrpc); 1816 + ca->maxresp_sz = min_t(u32, ca->maxresp_sz, maxrpc); 1817 + ca->maxops = min_t(u32, ca->maxops, NFSD_MAX_OPS_PER_COMPOUND); 1818 + ca->maxresp_cached = min_t(u32, ca->maxresp_cached, 1819 + NFSD_SLOT_CACHE_SIZE + NFSD_MIN_HDR_SEQ_SZ); 1820 + ca->maxreqs = min_t(u32, ca->maxreqs, NFSD_MAX_SLOTS_PER_SESSION); 1821 + /* 1822 + * Note decreasing slot size below client's request may make it 1823 + * difficult for client to function correctly, whereas 1824 + * decreasing the number of slots will (just?) affect 1825 + * performance. When short on memory we therefore prefer to 1826 + * decrease number of slots instead of their size. Clients that 1827 + * request larger slots than they need will get poor results: 1828 + */ 1829 + ca->maxreqs = nfsd4_get_drc_mem(ca); 1830 + if (!ca->maxreqs) 1831 + return nfserr_jukebox; 1832 + 1773 1833 return nfs_ok; 1774 1834 } 1775 1835 ··· 1809 1827 1810 1828 if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) 1811 1829 return nfserr_inval; 1812 - status = check_forechannel_attrs(&cr_ses->fore_channel); 1830 + status = check_forechannel_attrs(&cr_ses->fore_channel, nn); 1813 1831 if (status) 1814 1832 return status; 1815 - new = alloc_session(&cr_ses->fore_channel, nn); 1816 - if (!new) 1817 - return nfserr_jukebox; 1818 1833 status = nfserr_jukebox; 1834 + new = alloc_session(&cr_ses->fore_channel); 1835 + if (!new) 1836 + goto out_release_drc_mem; 1819 1837 conn = alloc_conn_from_crses(rqstp, cr_ses); 1820 1838 if (!conn) 1821 1839 goto out_free_session; ··· 1874 1892 1875 1893 memcpy(cr_ses->sessionid.data, new->se_sessionid.data, 1876 1894 NFS4_MAX_SESSIONID_LEN); 1877 - memcpy(&cr_ses->fore_channel, &new->se_fchannel, 1878 - sizeof(struct nfsd4_channel_attrs)); 1879 1895 cs_slot->sl_seqid++; 1880 1896 cr_ses->seqid = cs_slot->sl_seqid; 1881 1897 ··· 1886 1906 free_conn(conn); 1887 1907 out_free_session: 1888 1908 __free_session(new); 1909 + out_release_drc_mem: 1910 + nfsd4_put_drc_mem(&cr_ses->fore_channel); 1889 1911 return status; 1890 1912 } 1891 1913