iscsi-target: Enforce individual network portal export once per TargetName
authorNicholas Bellinger <nab@linux-iscsi.org>
Tue, 19 Feb 2013 05:01:02 +0000 (21:01 -0800)
committerNicholas Bellinger <nab@linux-iscsi.org>
Wed, 20 Feb 2013 01:58:12 +0000 (17:58 -0800)
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>
drivers/target/iscsi/iscsi_target_tpg.c

index de9ea32b61046287eedacbc4c97c5368d5964217..ee8f8c66248d22dc1777536ca6323124b79cb69f 100644 (file)
@@ -422,6 +422,35 @@ struct iscsi_tpg_np *iscsit_tpg_locate_child_np(
        return NULL;
 }
 
+static bool iscsit_tpg_check_network_portal(
+       struct iscsi_tiqn *tiqn,
+       struct __kernel_sockaddr_storage *sockaddr,
+       int network_transport)
+{
+       struct iscsi_portal_group *tpg;
+       struct iscsi_tpg_np *tpg_np;
+       struct iscsi_np *np;
+       bool match = false;
+
+       spin_lock(&tiqn->tiqn_tpg_lock);
+       list_for_each_entry(tpg, &tiqn->tiqn_tpg_list, tpg_list) {
+
+               spin_lock(&tpg->tpg_np_lock);
+               list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, tpg_np_list) {
+                       np = tpg_np->tpg_np;
+
+                       match = iscsit_check_np_match(sockaddr, np,
+                                               network_transport);
+                       if (match == true)
+                               break;
+               }
+               spin_unlock(&tpg->tpg_np_lock);
+       }
+       spin_unlock(&tiqn->tiqn_tpg_lock);
+
+       return match;
+}
+
 struct iscsi_tpg_np *iscsit_tpg_add_network_portal(
        struct iscsi_portal_group *tpg,
        struct __kernel_sockaddr_storage *sockaddr,
@@ -432,6 +461,16 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal(
        struct iscsi_np *np;
        struct iscsi_tpg_np *tpg_np;
 
+       if (!tpg_np_parent) {
+               if (iscsit_tpg_check_network_portal(tpg->tpg_tiqn, sockaddr,
+                               network_transport) == true) {
+                       pr_err("Network Portal: %s already exists on a"
+                               " different TPG on %s\n", ip_str,
+                               tpg->tpg_tiqn->tiqn);
+                       return ERR_PTR(-EEXIST);
+               }
+       }
+
        tpg_np = kzalloc(sizeof(struct iscsi_tpg_np), GFP_KERNEL);
        if (!tpg_np) {
                pr_err("Unable to allocate memory for"