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 <joern@logfs.org>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
This commit is contained in:
Jörn Engel 2012-03-15 15:05:12 -04:00 committed by Nicholas Bellinger
parent b168fe8cfe
commit 4a5a75f32d
4 changed files with 41 additions and 11 deletions

View File

@ -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); spin_unlock(&tpg->tpg_lun_lock);
return NULL; return NULL;
} }
lun = &tpg->tpg_lun_list[unpacked_lun]; lun = tpg->tpg_lun_list[unpacked_lun];
if (lun->lun_status != TRANSPORT_LUN_STATUS_FREE) { if (lun->lun_status != TRANSPORT_LUN_STATUS_FREE) {
pr_err("%s Logical Unit Number: %u is not free on" 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); spin_unlock(&tpg->tpg_lun_lock);
return NULL; return NULL;
} }
lun = &tpg->tpg_lun_list[unpacked_lun]; lun = tpg->tpg_lun_list[unpacked_lun];
if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) { if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) {
pr_err("%s Logical Unit Number: %u is not active on" pr_err("%s Logical Unit Number: %u is not active on"

View File

@ -163,7 +163,7 @@ void core_tpg_add_node_to_devs(
spin_lock(&tpg->tpg_lun_lock); spin_lock(&tpg->tpg_lun_lock);
for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { 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) if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE)
continue; continue;
@ -222,6 +222,34 @@ static int core_set_queue_depth_for_node(
return 0; 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(): /* 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); spin_lock(&tpg->tpg_lun_lock);
for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { 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) || if ((lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) ||
(lun->lun_se_dev == NULL)) (lun->lun_se_dev == NULL))
@ -661,8 +689,8 @@ int core_tpg_register(
struct se_lun *lun; struct se_lun *lun;
u32 i; u32 i;
se_tpg->tpg_lun_list = kzalloc((sizeof(struct se_lun) * se_tpg->tpg_lun_list = array_zalloc(TRANSPORT_MAX_LUNS_PER_TPG,
TRANSPORT_MAX_LUNS_PER_TPG), GFP_KERNEL); sizeof(struct se_lun), GFP_KERNEL);
if (!se_tpg->tpg_lun_list) { if (!se_tpg->tpg_lun_list) {
pr_err("Unable to allocate struct se_portal_group->" pr_err("Unable to allocate struct se_portal_group->"
"tpg_lun_list\n"); "tpg_lun_list\n");
@ -670,7 +698,7 @@ int core_tpg_register(
} }
for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) { 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->unpacked_lun = i;
lun->lun_status = TRANSPORT_LUN_STATUS_FREE; lun->lun_status = TRANSPORT_LUN_STATUS_FREE;
atomic_set(&lun->lun_acl_count, 0); 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); core_tpg_release_virtual_lun0(se_tpg);
se_tpg->se_tpg_fabric_ptr = NULL; 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; return 0;
} }
EXPORT_SYMBOL(core_tpg_deregister); EXPORT_SYMBOL(core_tpg_deregister);
@ -777,7 +805,7 @@ struct se_lun *core_tpg_pre_addlun(
} }
spin_lock(&tpg->tpg_lun_lock); 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) { if (lun->lun_status == TRANSPORT_LUN_STATUS_ACTIVE) {
pr_err("TPG Logical Unit Number: %u is already active" pr_err("TPG Logical Unit Number: %u is already active"
" on %s Target Portal Group: %u, ignoring request.\n", " 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); 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) { if (lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE) {
pr_err("%s Logical Unit Number: %u is not active on" pr_err("%s Logical Unit Number: %u is not active on"
" Target Portal Group: %u, ignoring request.\n", " Target Portal Group: %u, ignoring request.\n",

View File

@ -62,4 +62,6 @@ int transport_set_vpd_ident(struct t10_vpd *, unsigned char *);
void *transport_kmap_data_sg(struct se_cmd *); void *transport_kmap_data_sg(struct se_cmd *);
void transport_kunmap_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 */ #endif /* TARGET_CORE_BACKEND_H */

View File

@ -934,7 +934,7 @@ struct se_portal_group {
struct list_head se_tpg_node; struct list_head se_tpg_node;
/* linked list for initiator ACL list */ /* linked list for initiator ACL list */
struct list_head acl_node_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; struct se_lun tpg_virt_lun0;
/* List of TCM sessions associated wth this TPG */ /* List of TCM sessions associated wth this TPG */
struct list_head tpg_sess_list; struct list_head tpg_sess_list;