From: Jörn Engel Date: Thu, 15 Mar 2012 19:05:12 +0000 (-0400) Subject: target: Use array_zalloc for tpg_lun_list X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=4a5a75f32dcbcd0b2685f74fd4ede26edf8765a9;p=linux-beck.git target: Use array_zalloc for tpg_lun_list Turns an order-10 allocation into slab-sized ones, thereby preventing allocation failures with memory fragmentation. This likely saves memory as well, as the slab allocator can pack objects more tightly than the buddy allocator. Signed-off-by: Joern Engel Signed-off-by: Nicholas Bellinger --- diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 5cfaa4b6da42..fd7f17c303a7 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -1429,7 +1429,7 @@ struct se_lun *core_get_lun_from_tpg(struct se_portal_group *tpg, u32 unpacked_l spin_unlock(&tpg->tpg_lun_lock); return NULL; } - lun = &tpg->tpg_lun_list[unpacked_lun]; + lun = tpg->tpg_lun_list[unpacked_lun]; if (lun->lun_status != TRANSPORT_LUN_STATUS_FREE) { pr_err("%s Logical Unit Number: %u is not free on" @@ -1462,7 +1462,7 @@ static struct se_lun *core_dev_get_lun(struct se_portal_group *tpg, u32 unpacked spin_unlock(&tpg->tpg_lun_lock); return NULL; } - lun = &tpg->tpg_lun_list[unpacked_lun]; + lun = tpg->tpg_lun_list[unpacked_lun]; if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) { pr_err("%s Logical Unit Number: %u is not active on" diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index f3ea385737d5..146fe47f11c1 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -163,7 +163,7 @@ void core_tpg_add_node_to_devs( spin_lock(&tpg->tpg_lun_lock); for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - lun = &tpg->tpg_lun_list[i]; + lun = tpg->tpg_lun_list[i]; if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) continue; @@ -222,6 +222,34 @@ static int core_set_queue_depth_for_node( return 0; } +void array_free(void *array, int n) +{ + void **a = array; + int i; + + for (i = 0; i < n; i++) + kfree(a[i]); + kfree(a); +} + +static void *array_zalloc(int n, size_t size, gfp_t flags) +{ + void **a; + int i; + + a = kzalloc(n * sizeof(void*), flags); + if (!a) + return NULL; + for (i = 0; i < n; i++) { + a[i] = kzalloc(size, flags); + if (!a[i]) { + array_free(a, n); + return NULL; + } + } + return a; +} + /* core_create_device_list_for_node(): * * @@ -336,7 +364,7 @@ void core_tpg_clear_object_luns(struct se_portal_group *tpg) spin_lock(&tpg->tpg_lun_lock); for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - lun = &tpg->tpg_lun_list[i]; + lun = tpg->tpg_lun_list[i]; if ((lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) || (lun->lun_se_dev == NULL)) @@ -661,8 +689,8 @@ int core_tpg_register( struct se_lun *lun; u32 i; - se_tpg->tpg_lun_list = kzalloc((sizeof(struct se_lun) * - TRANSPORT_MAX_LUNS_PER_TPG), GFP_KERNEL); + se_tpg->tpg_lun_list = array_zalloc(TRANSPORT_MAX_LUNS_PER_TPG, + sizeof(struct se_lun), GFP_KERNEL); if (!se_tpg->tpg_lun_list) { pr_err("Unable to allocate struct se_portal_group->" "tpg_lun_list\n"); @@ -670,7 +698,7 @@ int core_tpg_register( } for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { - lun = &se_tpg->tpg_lun_list[i]; + lun = se_tpg->tpg_lun_list[i]; lun->unpacked_lun = i; lun->lun_status = TRANSPORT_LUN_STATUS_FREE; atomic_set(&lun->lun_acl_count, 0); @@ -756,7 +784,7 @@ int core_tpg_deregister(struct se_portal_group *se_tpg) core_tpg_release_virtual_lun0(se_tpg); se_tpg->se_tpg_fabric_ptr = NULL; - kfree(se_tpg->tpg_lun_list); + array_free(se_tpg->tpg_lun_list, TRANSPORT_MAX_LUNS_PER_TPG); return 0; } EXPORT_SYMBOL(core_tpg_deregister); @@ -777,7 +805,7 @@ struct se_lun *core_tpg_pre_addlun( } spin_lock(&tpg->tpg_lun_lock); - lun = &tpg->tpg_lun_list[unpacked_lun]; + lun = tpg->tpg_lun_list[unpacked_lun]; if (lun->lun_status == TRANSPORT_LUN_STATUS_ACTIVE) { pr_err("TPG Logical Unit Number: %u is already active" " on %s Target Portal Group: %u, ignoring request.\n", @@ -835,7 +863,7 @@ struct se_lun *core_tpg_pre_dellun( } spin_lock(&tpg->tpg_lun_lock); - lun = &tpg->tpg_lun_list[unpacked_lun]; + lun = tpg->tpg_lun_list[unpacked_lun]; if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) { pr_err("%s Logical Unit Number: %u is not active on" " Target Portal Group: %u, ignoring request.\n", diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index e5e6ff98f0fa..8c9ff1b14396 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -62,4 +62,6 @@ int transport_set_vpd_ident(struct t10_vpd *, unsigned char *); void *transport_kmap_data_sg(struct se_cmd *); void transport_kunmap_data_sg(struct se_cmd *); +void array_free(void *array, int n); + #endif /* TARGET_CORE_BACKEND_H */ diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index c3334094c668..fc918a7b7d70 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -934,7 +934,7 @@ struct se_portal_group { struct list_head se_tpg_node; /* linked list for initiator ACL list */ struct list_head acl_node_list; - struct se_lun *tpg_lun_list; + struct se_lun **tpg_lun_list; struct se_lun tpg_virt_lun0; /* List of TCM sessions associated wth this TPG */ struct list_head tpg_sess_list;