diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-02-19 00:01:02 -0500 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-02-19 20:58:12 -0500 |
commit | 6e5459353de4ac80924e94fafa8b3e31a086c5dd (patch) | |
tree | 18066f37c9070b23b30754052d113b2f6fb9022c /drivers/target/iscsi | |
parent | 05b9689245c1b2f0dea38c1cb4882810ce3adda8 (diff) |
iscsi-target: Enforce individual network portal export once per TargetName
This patch enforces individual network portal export on a once per TargetName
basis, thus preventing a network portal from being exported multiple times
across multiple TargetPortalGroups in a single TargetName instance.
This is done in iscsit_tpg_check_network_portal() by walking tiqn->tiqn_tpg_list
and tpg->tpg_gnp_list using iscsit_check_np_match() looking for an existing
network portal mapping from iscsit_tpg_add_network_portal() context, but only
when no pre-existing tpg_np_parent pointer is present.
Reported-by: Andy Grover <agrover@redhat.com>
Tested-by: Andy Grover <agrover@redhat.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target/iscsi')
-rw-r--r-- | drivers/target/iscsi/iscsi_target_tpg.c | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index de9ea32b6104..ee8f8c66248d 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c | |||
@@ -422,6 +422,35 @@ struct iscsi_tpg_np *iscsit_tpg_locate_child_np( | |||
422 | return NULL; | 422 | return NULL; |
423 | } | 423 | } |
424 | 424 | ||
425 | static bool iscsit_tpg_check_network_portal( | ||
426 | struct iscsi_tiqn *tiqn, | ||
427 | struct __kernel_sockaddr_storage *sockaddr, | ||
428 | int network_transport) | ||
429 | { | ||
430 | struct iscsi_portal_group *tpg; | ||
431 | struct iscsi_tpg_np *tpg_np; | ||
432 | struct iscsi_np *np; | ||
433 | bool match = false; | ||
434 | |||
435 | spin_lock(&tiqn->tiqn_tpg_lock); | ||
436 | list_for_each_entry(tpg, &tiqn->tiqn_tpg_list, tpg_list) { | ||
437 | |||
438 | spin_lock(&tpg->tpg_np_lock); | ||
439 | list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, tpg_np_list) { | ||
440 | np = tpg_np->tpg_np; | ||
441 | |||
442 | match = iscsit_check_np_match(sockaddr, np, | ||
443 | network_transport); | ||
444 | if (match == true) | ||
445 | break; | ||
446 | } | ||
447 | spin_unlock(&tpg->tpg_np_lock); | ||
448 | } | ||
449 | spin_unlock(&tiqn->tiqn_tpg_lock); | ||
450 | |||
451 | return match; | ||
452 | } | ||
453 | |||
425 | struct iscsi_tpg_np *iscsit_tpg_add_network_portal( | 454 | struct iscsi_tpg_np *iscsit_tpg_add_network_portal( |
426 | struct iscsi_portal_group *tpg, | 455 | struct iscsi_portal_group *tpg, |
427 | struct __kernel_sockaddr_storage *sockaddr, | 456 | struct __kernel_sockaddr_storage *sockaddr, |
@@ -432,6 +461,16 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal( | |||
432 | struct iscsi_np *np; | 461 | struct iscsi_np *np; |
433 | struct iscsi_tpg_np *tpg_np; | 462 | struct iscsi_tpg_np *tpg_np; |
434 | 463 | ||
464 | if (!tpg_np_parent) { | ||
465 | if (iscsit_tpg_check_network_portal(tpg->tpg_tiqn, sockaddr, | ||
466 | network_transport) == true) { | ||
467 | pr_err("Network Portal: %s already exists on a" | ||
468 | " different TPG on %s\n", ip_str, | ||
469 | tpg->tpg_tiqn->tiqn); | ||
470 | return ERR_PTR(-EEXIST); | ||
471 | } | ||
472 | } | ||
473 | |||
435 | tpg_np = kzalloc(sizeof(struct iscsi_tpg_np), GFP_KERNEL); | 474 | tpg_np = kzalloc(sizeof(struct iscsi_tpg_np), GFP_KERNEL); |
436 | if (!tpg_np) { | 475 | if (!tpg_np) { |
437 | pr_err("Unable to allocate memory for" | 476 | pr_err("Unable to allocate memory for" |