@@ -1909,6 +1909,16 @@ gen_sessionid(struct nfsd4_session *ses)
19091909 */
19101910#define NFSD_MIN_HDR_SEQ_SZ (24 + 12 + 44)
19111911
1912+ static struct shrinker * nfsd_slot_shrinker ;
1913+ static DEFINE_SPINLOCK (nfsd_session_list_lock );
1914+ static LIST_HEAD (nfsd_session_list );
1915+ /* The sum of "target_slots-1" on every session. The shrinker can push this
1916+ * down, though it can take a little while for the memory to actually
1917+ * be freed. The "-1" is because we can never free slot 0 while the
1918+ * session is active.
1919+ */
1920+ static atomic_t nfsd_total_target_slots = ATOMIC_INIT (0 );
1921+
19121922static void
19131923free_session_slots (struct nfsd4_session * ses , int from )
19141924{
@@ -1930,8 +1940,11 @@ free_session_slots(struct nfsd4_session *ses, int from)
19301940 kfree (slot );
19311941 }
19321942 ses -> se_fchannel .maxreqs = from ;
1933- if (ses -> se_target_maxslots > from )
1934- ses -> se_target_maxslots = from ;
1943+ if (ses -> se_target_maxslots > from ) {
1944+ int new_target = from ?: 1 ;
1945+ atomic_sub (ses -> se_target_maxslots - new_target , & nfsd_total_target_slots );
1946+ ses -> se_target_maxslots = new_target ;
1947+ }
19351948}
19361949
19371950/**
@@ -1949,7 +1962,7 @@ free_session_slots(struct nfsd4_session *ses, int from)
19491962 * Return value:
19501963 * The number of slots that the target was reduced by.
19511964 */
1952- static int __maybe_unused
1965+ static int
19531966reduce_session_slots (struct nfsd4_session * ses , int dec )
19541967{
19551968 struct nfsd_net * nn = net_generic (ses -> se_client -> net ,
@@ -1962,6 +1975,7 @@ reduce_session_slots(struct nfsd4_session *ses, int dec)
19621975 return ret ;
19631976 ret = min (dec , ses -> se_target_maxslots - 1 );
19641977 ses -> se_target_maxslots -= ret ;
1978+ atomic_sub (ret , & nfsd_total_target_slots );
19651979 ses -> se_slot_gen += 1 ;
19661980 if (ses -> se_slot_gen == 0 ) {
19671981 int i ;
@@ -2021,6 +2035,7 @@ static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs,
20212035 fattrs -> maxreqs = i ;
20222036 memcpy (& new -> se_fchannel , fattrs , sizeof (struct nfsd4_channel_attrs ));
20232037 new -> se_target_maxslots = i ;
2038+ atomic_add (i - 1 , & nfsd_total_target_slots );
20242039 new -> se_cb_slot_avail = ~0U ;
20252040 new -> se_cb_highest_slot = min (battrs -> maxreqs - 1 ,
20262041 NFSD_BC_SLOT_TABLE_SIZE - 1 );
@@ -2145,6 +2160,36 @@ static void free_session(struct nfsd4_session *ses)
21452160 __free_session (ses );
21462161}
21472162
2163+ static unsigned long
2164+ nfsd_slot_count (struct shrinker * s , struct shrink_control * sc )
2165+ {
2166+ unsigned long cnt = atomic_read (& nfsd_total_target_slots );
2167+
2168+ return cnt ? cnt : SHRINK_EMPTY ;
2169+ }
2170+
2171+ static unsigned long
2172+ nfsd_slot_scan (struct shrinker * s , struct shrink_control * sc )
2173+ {
2174+ struct nfsd4_session * ses ;
2175+ unsigned long scanned = 0 ;
2176+ unsigned long freed = 0 ;
2177+
2178+ spin_lock (& nfsd_session_list_lock );
2179+ list_for_each_entry (ses , & nfsd_session_list , se_all_sessions ) {
2180+ freed += reduce_session_slots (ses , 1 );
2181+ scanned += 1 ;
2182+ if (scanned >= sc -> nr_to_scan ) {
2183+ /* Move starting point for next scan */
2184+ list_move (& nfsd_session_list , & ses -> se_all_sessions );
2185+ break ;
2186+ }
2187+ }
2188+ spin_unlock (& nfsd_session_list_lock );
2189+ sc -> nr_scanned = scanned ;
2190+ return freed ;
2191+ }
2192+
21482193static void init_session (struct svc_rqst * rqstp , struct nfsd4_session * new , struct nfs4_client * clp , struct nfsd4_create_session * cses )
21492194{
21502195 int idx ;
@@ -2169,6 +2214,10 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru
21692214 list_add (& new -> se_perclnt , & clp -> cl_sessions );
21702215 spin_unlock (& clp -> cl_lock );
21712216
2217+ spin_lock (& nfsd_session_list_lock );
2218+ list_add_tail (& new -> se_all_sessions , & nfsd_session_list );
2219+ spin_unlock (& nfsd_session_list_lock );
2220+
21722221 {
21732222 struct sockaddr * sa = svc_addr (rqstp );
21742223 /*
@@ -2238,6 +2287,9 @@ unhash_session(struct nfsd4_session *ses)
22382287 spin_lock (& ses -> se_client -> cl_lock );
22392288 list_del (& ses -> se_perclnt );
22402289 spin_unlock (& ses -> se_client -> cl_lock );
2290+ spin_lock (& nfsd_session_list_lock );
2291+ list_del (& ses -> se_all_sessions );
2292+ spin_unlock (& nfsd_session_list_lock );
22412293}
22422294
22432295/* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */
@@ -2373,8 +2425,12 @@ unhash_client_locked(struct nfs4_client *clp)
23732425 }
23742426 list_del_init (& clp -> cl_lru );
23752427 spin_lock (& clp -> cl_lock );
2376- list_for_each_entry (ses , & clp -> cl_sessions , se_perclnt )
2428+ spin_lock (& nfsd_session_list_lock );
2429+ list_for_each_entry (ses , & clp -> cl_sessions , se_perclnt ) {
23772430 list_del_init (& ses -> se_hash );
2431+ list_del_init (& ses -> se_all_sessions );
2432+ }
2433+ spin_unlock (& nfsd_session_list_lock );
23782434 spin_unlock (& clp -> cl_lock );
23792435}
23802436
@@ -4380,6 +4436,8 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
43804436 GFP_NOWAIT ))) {
43814437 s += 1 ;
43824438 session -> se_fchannel .maxreqs = s ;
4439+ atomic_add (s - session -> se_target_maxslots ,
4440+ & nfsd_total_target_slots );
43834441 session -> se_target_maxslots = s ;
43844442 } else {
43854443 kfree (slot );
@@ -8770,7 +8828,6 @@ nfs4_state_start_net(struct net *net)
87708828}
87718829
87728830/* initialization to perform when the nfsd service is started: */
8773-
87748831int
87758832nfs4_state_start (void )
87768833{
@@ -8780,6 +8837,15 @@ nfs4_state_start(void)
87808837 if (ret )
87818838 return ret ;
87828839
8840+ nfsd_slot_shrinker = shrinker_alloc (0 , "nfsd-DRC-slot" );
8841+ if (!nfsd_slot_shrinker ) {
8842+ rhltable_destroy (& nfs4_file_rhltable );
8843+ return - ENOMEM ;
8844+ }
8845+ nfsd_slot_shrinker -> count_objects = nfsd_slot_count ;
8846+ nfsd_slot_shrinker -> scan_objects = nfsd_slot_scan ;
8847+ shrinker_register (nfsd_slot_shrinker );
8848+
87838849 set_max_delegations ();
87848850 return 0 ;
87858851}
@@ -8821,6 +8887,7 @@ void
88218887nfs4_state_shutdown (void )
88228888{
88238889 rhltable_destroy (& nfs4_file_rhltable );
8890+ shrinker_free (nfsd_slot_shrinker );
88248891}
88258892
88268893static void
0 commit comments