cxlflash: Fix to avoid invalid port_sel value
authorManoj Kumar <kumarmn@us.ibm.com>
Wed, 21 Oct 2015 20:10:31 +0000 (15:10 -0500)
committerJames Bottomley <JBottomley@Odin.com>
Fri, 30 Oct 2015 07:57:21 +0000 (16:57 +0900)
If two concurrent MANAGE_LUN ioctls are issued with the same
WWID parameter, it would result in an incorrect value of port_sel.

This is because port_sel is modified without any locks being
held. If the first caller stalls after the return from
find_and_create_lun(), the value of port_sel will be set
incorrectly to indicate a single port, though in this case
it should have been set to both ports.

To fix, use the global mutex to serialize the lookup of the
WWID and the subsequent modification of port_sel.

Signed-off-by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com>
Signed-off-by: Manoj N. Kumar <manoj@linux.vnet.ibm.com>
Reviewed-by: Brian King <brking@linux.vnet.ibm.com>
Reviewed-by: Tomas Henzl <thenzl@redhat.com>
Signed-off-by: James Bottomley <JBottomley@Odin.com>
drivers/scsi/cxlflash/lunmgt.c

index d98ad0ff64c18e403c41fd8d069c0b3a41651e51..8c372fc73e1f6c7888d003c76bf20d1cdbac7126 100644 (file)
@@ -120,7 +120,8 @@ static struct glun_info *lookup_global(u8 *wwid)
  *
  * The LUN is kept both in a local list (per adapter) and in a global list
  * (across all adapters). Certain attributes of the LUN are local to the
- * adapter (such as index, port selection mask etc.).
+ * adapter (such as index, port selection mask, etc.).
+ *
  * The block allocation map is shared across all adapters (i.e. associated
  * wih the global list). Since different attributes are associated with
  * the per adapter and global entries, allocate two separate structures for each
@@ -128,6 +129,8 @@ static struct glun_info *lookup_global(u8 *wwid)
  *
  * Keep a pointer back from the local to the global entry.
  *
+ * This routine assumes the caller holds the global mutex.
+ *
  * Return: Found/Allocated local lun_info structure on success, NULL on failure
  */
 static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid)
@@ -137,7 +140,6 @@ static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid)
        struct Scsi_Host *shost = sdev->host;
        struct cxlflash_cfg *cfg = shost_priv(shost);
 
-       mutex_lock(&global.mutex);
        if (unlikely(!wwid))
                goto out;
 
@@ -169,7 +171,6 @@ static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid)
        list_add(&gli->list, &global.gluns);
 
 out:
-       mutex_unlock(&global.mutex);
        pr_debug("%s: returning %p\n", __func__, lli);
        return lli;
 }
@@ -235,6 +236,7 @@ int cxlflash_manage_lun(struct scsi_device *sdev,
        u64 flags = manage->hdr.flags;
        u32 chan = sdev->channel;
 
+       mutex_lock(&global.mutex);
        lli = find_and_create_lun(sdev, manage->wwid);
        pr_debug("%s: ENTER: WWID = %016llX%016llX, flags = %016llX li = %p\n",
                 __func__, get_unaligned_le64(&manage->wwid[0]),
@@ -261,6 +263,7 @@ int cxlflash_manage_lun(struct scsi_device *sdev,
        }
 
 out:
+       mutex_unlock(&global.mutex);
        pr_debug("%s: returning rc=%d\n", __func__, rc);
        return rc;
 }