Commit 66261da169263f90c431741886b90b0982dda981
Committed by
David S. Miller
1 parent
b319109396
rds: tcp: cleanup if kmem_cache_alloc fails in rds_tcp_conn_alloc()
If kmem_cache_alloc() fails in the middle of the for() loop, cleanup anything that might have been allocated so far. Signed-off-by: Sowmini Varadhan <sowmini.varadhan@oracle.com> Acked-by: Santosh Shilimkar <santosh.shilimkar@oracle.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 1 changed file with 26 additions and 20 deletions Side-by-side Diff
net/rds/tcp.c
... | ... | @@ -270,16 +270,33 @@ |
270 | 270 | return -EADDRNOTAVAIL; |
271 | 271 | } |
272 | 272 | |
273 | +static void rds_tcp_conn_free(void *arg) | |
274 | +{ | |
275 | + struct rds_tcp_connection *tc = arg; | |
276 | + unsigned long flags; | |
277 | + | |
278 | + rdsdebug("freeing tc %p\n", tc); | |
279 | + | |
280 | + spin_lock_irqsave(&rds_tcp_conn_lock, flags); | |
281 | + if (!tc->t_tcp_node_detached) | |
282 | + list_del(&tc->t_tcp_node); | |
283 | + spin_unlock_irqrestore(&rds_tcp_conn_lock, flags); | |
284 | + | |
285 | + kmem_cache_free(rds_tcp_conn_slab, tc); | |
286 | +} | |
287 | + | |
273 | 288 | static int rds_tcp_conn_alloc(struct rds_connection *conn, gfp_t gfp) |
274 | 289 | { |
275 | 290 | struct rds_tcp_connection *tc; |
276 | - int i; | |
291 | + int i, j; | |
292 | + int ret = 0; | |
277 | 293 | |
278 | 294 | for (i = 0; i < RDS_MPATH_WORKERS; i++) { |
279 | 295 | tc = kmem_cache_alloc(rds_tcp_conn_slab, gfp); |
280 | - if (!tc) | |
281 | - return -ENOMEM; | |
282 | - | |
296 | + if (!tc) { | |
297 | + ret = -ENOMEM; | |
298 | + break; | |
299 | + } | |
283 | 300 | mutex_init(&tc->t_conn_path_lock); |
284 | 301 | tc->t_sock = NULL; |
285 | 302 | tc->t_tinc = NULL; |
... | ... | @@ -296,22 +313,11 @@ |
296 | 313 | rdsdebug("rds_conn_path [%d] tc %p\n", i, |
297 | 314 | conn->c_path[i].cp_transport_data); |
298 | 315 | } |
299 | - | |
300 | - return 0; | |
301 | -} | |
302 | - | |
303 | -static void rds_tcp_conn_free(void *arg) | |
304 | -{ | |
305 | - struct rds_tcp_connection *tc = arg; | |
306 | - unsigned long flags; | |
307 | - rdsdebug("freeing tc %p\n", tc); | |
308 | - | |
309 | - spin_lock_irqsave(&rds_tcp_conn_lock, flags); | |
310 | - if (!tc->t_tcp_node_detached) | |
311 | - list_del(&tc->t_tcp_node); | |
312 | - spin_unlock_irqrestore(&rds_tcp_conn_lock, flags); | |
313 | - | |
314 | - kmem_cache_free(rds_tcp_conn_slab, tc); | |
316 | + if (ret) { | |
317 | + for (j = 0; j < i; j++) | |
318 | + rds_tcp_conn_free(conn->c_path[j].cp_transport_data); | |
319 | + } | |
320 | + return ret; | |
315 | 321 | } |
316 | 322 | |
317 | 323 | static bool list_has_conn(struct list_head *list, struct rds_connection *conn) |