@@ -68,6 +68,8 @@ MODULE_LICENSE("Dual BSD/GPL");
6868static u64 srpt_service_guid ;
6969static DEFINE_SPINLOCK (srpt_dev_lock ); /* Protects srpt_dev_list. */
7070static LIST_HEAD (srpt_dev_list ); /* List of srpt_device structures. */
71+ static DEFINE_MUTEX (srpt_mc_mutex ); /* Protects srpt_memory_caches. */
72+ static DEFINE_XARRAY (srpt_memory_caches ); /* See also srpt_memory_cache_entry */
7173
7274static unsigned srp_max_req_size = DEFAULT_MAX_REQ_SIZE ;
7375module_param (srp_max_req_size , int , 0444 );
@@ -105,6 +107,63 @@ static void srpt_recv_done(struct ib_cq *cq, struct ib_wc *wc);
105107static void srpt_send_done (struct ib_cq * cq , struct ib_wc * wc );
106108static void srpt_process_wait_list (struct srpt_rdma_ch * ch );
107109
110+ /* Type of the entries in srpt_memory_caches. */
111+ struct srpt_memory_cache_entry {
112+ refcount_t ref ;
113+ struct kmem_cache * c ;
114+ };
115+
116+ static struct kmem_cache * srpt_cache_get (unsigned int object_size )
117+ {
118+ struct srpt_memory_cache_entry * e ;
119+ char name [32 ];
120+ void * res ;
121+
122+ guard (mutex )(& srpt_mc_mutex );
123+ e = xa_load (& srpt_memory_caches , object_size );
124+ if (e ) {
125+ refcount_inc (& e -> ref );
126+ return e -> c ;
127+ }
128+ snprintf (name , sizeof (name ), "srpt-%u" , object_size );
129+ e = kmalloc (sizeof (* e ), GFP_KERNEL );
130+ if (!e )
131+ return NULL ;
132+ refcount_set (& e -> ref , 1 );
133+ e -> c = kmem_cache_create (name , object_size , /*align=*/ 512 , 0 , NULL );
134+ if (!e -> c )
135+ goto free_entry ;
136+ res = xa_store (& srpt_memory_caches , object_size , e , GFP_KERNEL );
137+ if (xa_is_err (res ))
138+ goto destroy_cache ;
139+ return e -> c ;
140+
141+ destroy_cache :
142+ kmem_cache_destroy (e -> c );
143+
144+ free_entry :
145+ kfree (e );
146+ return NULL ;
147+ }
148+
149+ static void srpt_cache_put (struct kmem_cache * c )
150+ {
151+ struct srpt_memory_cache_entry * e = NULL ;
152+ unsigned long object_size ;
153+
154+ guard (mutex )(& srpt_mc_mutex );
155+ xa_for_each (& srpt_memory_caches , object_size , e )
156+ if (e -> c == c )
157+ break ;
158+ if (WARN_ON_ONCE (!e ))
159+ return ;
160+ if (!refcount_dec_and_test (& e -> ref ))
161+ return ;
162+ WARN_ON_ONCE (xa_erase (& srpt_memory_caches , object_size ) != e );
163+ kmem_cache_destroy (e -> c );
164+ kfree (e );
165+ }
166+
108167/*
109168 * The only allowed channel state changes are those that change the channel
110169 * state into a state with a higher numerical value. Hence the new > prev test.
@@ -2119,13 +2178,13 @@ static void srpt_release_channel_work(struct work_struct *w)
21192178 ch -> sport -> sdev , ch -> rq_size ,
21202179 ch -> rsp_buf_cache , DMA_TO_DEVICE );
21212180
2122- kmem_cache_destroy (ch -> rsp_buf_cache );
2181+ srpt_cache_put (ch -> rsp_buf_cache );
21232182
21242183 srpt_free_ioctx_ring ((struct srpt_ioctx * * )ch -> ioctx_recv_ring ,
21252184 sdev , ch -> rq_size ,
21262185 ch -> req_buf_cache , DMA_FROM_DEVICE );
21272186
2128- kmem_cache_destroy (ch -> req_buf_cache );
2187+ srpt_cache_put (ch -> req_buf_cache );
21292188
21302189 kref_put (& ch -> kref , srpt_free_ch );
21312190}
@@ -2245,8 +2304,7 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev,
22452304 INIT_LIST_HEAD (& ch -> cmd_wait_list );
22462305 ch -> max_rsp_size = ch -> sport -> port_attrib .srp_max_rsp_size ;
22472306
2248- ch -> rsp_buf_cache = kmem_cache_create ("srpt-rsp-buf" , ch -> max_rsp_size ,
2249- 512 , 0 , NULL );
2307+ ch -> rsp_buf_cache = srpt_cache_get (ch -> max_rsp_size );
22502308 if (!ch -> rsp_buf_cache )
22512309 goto free_ch ;
22522310
@@ -2280,8 +2338,7 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev,
22802338 alignment_offset = round_up (imm_data_offset , 512 ) -
22812339 imm_data_offset ;
22822340 req_sz = alignment_offset + imm_data_offset + srp_max_req_size ;
2283- ch -> req_buf_cache = kmem_cache_create ("srpt-req-buf" , req_sz ,
2284- 512 , 0 , NULL );
2341+ ch -> req_buf_cache = srpt_cache_get (req_sz );
22852342 if (!ch -> req_buf_cache )
22862343 goto free_rsp_ring ;
22872344
@@ -2478,15 +2535,15 @@ static int srpt_cm_req_recv(struct srpt_device *const sdev,
24782535 ch -> req_buf_cache , DMA_FROM_DEVICE );
24792536
24802537free_recv_cache :
2481- kmem_cache_destroy (ch -> req_buf_cache );
2538+ srpt_cache_put (ch -> req_buf_cache );
24822539
24832540free_rsp_ring :
24842541 srpt_free_ioctx_ring ((struct srpt_ioctx * * )ch -> ioctx_ring ,
24852542 ch -> sport -> sdev , ch -> rq_size ,
24862543 ch -> rsp_buf_cache , DMA_TO_DEVICE );
24872544
24882545free_rsp_cache :
2489- kmem_cache_destroy (ch -> rsp_buf_cache );
2546+ srpt_cache_put (ch -> rsp_buf_cache );
24902547
24912548free_ch :
24922549 if (rdma_cm_id )
@@ -3055,7 +3112,7 @@ static void srpt_free_srq(struct srpt_device *sdev)
30553112 srpt_free_ioctx_ring ((struct srpt_ioctx * * )sdev -> ioctx_ring , sdev ,
30563113 sdev -> srq_size , sdev -> req_buf_cache ,
30573114 DMA_FROM_DEVICE );
3058- kmem_cache_destroy (sdev -> req_buf_cache );
3115+ srpt_cache_put (sdev -> req_buf_cache );
30593116 sdev -> srq = NULL ;
30603117}
30613118
@@ -3082,8 +3139,7 @@ static int srpt_alloc_srq(struct srpt_device *sdev)
30823139 pr_debug ("create SRQ #wr= %d max_allow=%d dev= %s\n" , sdev -> srq_size ,
30833140 sdev -> device -> attrs .max_srq_wr , dev_name (& device -> dev ));
30843141
3085- sdev -> req_buf_cache = kmem_cache_create ("srpt-srq-req-buf" ,
3086- srp_max_req_size , 0 , 0 , NULL );
3142+ sdev -> req_buf_cache = srpt_cache_get (srp_max_req_size );
30873143 if (!sdev -> req_buf_cache )
30883144 goto free_srq ;
30893145
@@ -3105,7 +3161,7 @@ static int srpt_alloc_srq(struct srpt_device *sdev)
31053161 return 0 ;
31063162
31073163free_cache :
3108- kmem_cache_destroy (sdev -> req_buf_cache );
3164+ srpt_cache_put (sdev -> req_buf_cache );
31093165
31103166free_srq :
31113167 ib_destroy_srq (srq );
0 commit comments