All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/5] scsi_debug: bug fixes and cleanups for data integrity support
@ 2013-05-19 13:42 Akinobu Mita
  2013-05-19 13:42 ` [PATCH v2 1/5] scsi_debug: fix invalid address passed to kunmap_atomic() Akinobu Mita
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Akinobu Mita @ 2013-05-19 13:42 UTC (permalink / raw)
  To: linux-scsi
  Cc: Akinobu Mita, James E.J. Bottomley, Douglas Gilbert, Martin K. Petersen

This patch set includes bug fixes which I hit when I was tried testing
the data integrity support in scsi_debug on x86_32.

And it also includes cleanups which helps increasing readability and
further bug fixing in data integrity support.

* Changes from v1
- Split the patch "fix data integrity support on highmem machine" into
  two separate patches.
- Add new cleanup patch "reduce duplication between prot_verify_read and
  prot_verify_write".

Cc: "James E.J. Bottomley" <JBottomley@parallels.com>
Cc: Douglas Gilbert <dgilbert@interlog.com>
Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: linux-scsi@vger.kernel.org

Akinobu Mita (5):
  scsi_debug: fix invalid address passed to kunmap_atomic()
  scsi_debug: fix incorrectly nested kmap_atomic()
  scsi_debug: fix NULL pointer dereference with parameters dif=0 dix=1
  scsi_debug: simplify offset calculation for dif_storep
  scsi_debug: reduce duplication between prot_verify_read and
    prot_verify_write

 drivers/scsi/scsi_debug.c | 164 +++++++++++++++++++---------------------------
 1 file changed, 66 insertions(+), 98 deletions(-)

-- 
1.8.1.4


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 1/5] scsi_debug: fix invalid address passed to kunmap_atomic()
  2013-05-19 13:42 [PATCH v2 0/5] scsi_debug: bug fixes and cleanups for data integrity support Akinobu Mita
@ 2013-05-19 13:42 ` Akinobu Mita
  2013-05-19 13:42 ` [PATCH v2 2/5] scsi_debug: fix incorrectly nested kmap_atomic() Akinobu Mita
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Akinobu Mita @ 2013-05-19 13:42 UTC (permalink / raw)
  To: linux-scsi
  Cc: Akinobu Mita, James E.J. Bottomley, Douglas Gilbert, Martin K. Petersen

In the function prot_verify_write(), the kmap address 'daddr' is
incremented in the loop for each data page.  Finally 'daddr' reaches
the next page boundary in the end of the loop, and the invalid address
is passed to kunmap_atomic().

Fix it by passing original value to kunmap_atomic().

Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Cc: "James E.J. Bottomley" <JBottomley@parallels.com>
Cc: Douglas Gilbert <dgilbert@interlog.com>
Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: linux-scsi@vger.kernel.org
Acked-by: Douglas Gilbert <dgilbert@interlog.com>
---

* New patch from v2
- Splitted from the patch "fix data integrity support on highmem machine" in v1

 drivers/scsi/scsi_debug.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 0a537a0..caf6a94 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -1981,7 +1981,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
 			ppage_offset += sizeof(struct sd_dif_tuple);
 		}
 
-		kunmap_atomic(daddr);
+		kunmap_atomic(daddr - dsgl->length);
 	}
 
 	kunmap_atomic(paddr);
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v2 2/5] scsi_debug: fix incorrectly nested kmap_atomic()
  2013-05-19 13:42 [PATCH v2 0/5] scsi_debug: bug fixes and cleanups for data integrity support Akinobu Mita
  2013-05-19 13:42 ` [PATCH v2 1/5] scsi_debug: fix invalid address passed to kunmap_atomic() Akinobu Mita
@ 2013-05-19 13:42 ` Akinobu Mita
  2013-05-19 13:42 ` [PATCH v2 3/5] scsi_debug: fix NULL pointer dereference with parameters dif=0 dix=1 Akinobu Mita
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Akinobu Mita @ 2013-05-19 13:42 UTC (permalink / raw)
  To: linux-scsi
  Cc: Akinobu Mita, James E.J. Bottomley, Douglas Gilbert, Martin K. Petersen

In the function prot_verify_write(), kmap_atomic()/kunmap_atomic() for
data page and kmap_atomic()/kunmap_atomic() for protection information
page are not nested each other.

It worked perfectly before commit 3e4d3af501cccdc8a8cca41bdbe57d54ad7e7e73
("mm: stack based kmap_atomic()").  Because the kmap_atomic slot KM_IRQ0
was used for data page and the slot KM_IRQ1 was used for protection page.

But KM_types are gone and kmap_atomic() is using stack based implementation.
So two different kmap_atomic() usages must be strictly nested now.

This change ensures kmap_atomic() usage is strictly nested.

Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Cc: "James E.J. Bottomley" <JBottomley@parallels.com>
Cc: Douglas Gilbert <dgilbert@interlog.com>
Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: linux-scsi@vger.kernel.org
Acked-by: Douglas Gilbert <dgilbert@interlog.com>
---

* New patch from v2
- Splitted from the patch "fix data integrity support on highmem machine" in v1

 drivers/scsi/scsi_debug.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index caf6a94..0a428b6 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -1891,12 +1891,12 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
 	BUG_ON(scsi_sg_count(SCpnt) == 0);
 	BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
 
-	paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
 	ppage_offset = 0;
 
 	/* For each data page */
 	scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) {
 		daddr = kmap_atomic(sg_page(dsgl)) + dsgl->offset;
+		paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
 
 		/* For each sector-sized chunk in data page */
 		for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) {
@@ -1981,19 +1981,18 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
 			ppage_offset += sizeof(struct sd_dif_tuple);
 		}
 
+		kunmap_atomic(paddr);
 		kunmap_atomic(daddr - dsgl->length);
 	}
 
-	kunmap_atomic(paddr);
-
 	dix_writes++;
 
 	return 0;
 
 out:
 	dif_errors++;
-	kunmap_atomic(daddr);
 	kunmap_atomic(paddr);
+	kunmap_atomic(daddr);
 	return ret;
 }
 
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v2 3/5] scsi_debug: fix NULL pointer dereference with parameters dif=0 dix=1
  2013-05-19 13:42 [PATCH v2 0/5] scsi_debug: bug fixes and cleanups for data integrity support Akinobu Mita
  2013-05-19 13:42 ` [PATCH v2 1/5] scsi_debug: fix invalid address passed to kunmap_atomic() Akinobu Mita
  2013-05-19 13:42 ` [PATCH v2 2/5] scsi_debug: fix incorrectly nested kmap_atomic() Akinobu Mita
@ 2013-05-19 13:42 ` Akinobu Mita
  2013-05-19 13:42 ` [PATCH v2 4/5] scsi_debug: simplify offset calculation for dif_storep Akinobu Mita
  2013-05-19 13:42 ` [PATCH v2 5/5] scsi_debug: reduce duplication between prot_verify_read and prot_verify_write Akinobu Mita
  4 siblings, 0 replies; 6+ messages in thread
From: Akinobu Mita @ 2013-05-19 13:42 UTC (permalink / raw)
  To: linux-scsi
  Cc: Akinobu Mita, James E.J. Bottomley, Douglas Gilbert, Martin K. Petersen

The protection info dif_storep is allocated only when parameter dif is
not zero.  But it will be accessed when reading or writing to the storage
installed with parameter dix is not zero.

So kernel crashes if scsi_debug module is loaded with parameters dix=1 and
dif=0.

This fixes it by making dif_storep available if parameter dix is not zero
instead of checking if parameter dif is not zero.

Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Cc: "James E.J. Bottomley" <JBottomley@parallels.com>
Cc: Douglas Gilbert <dgilbert@interlog.com>
Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: linux-scsi@vger.kernel.org
Acked-by: Douglas Gilbert <dgilbert@interlog.com>
Acked-by: "Martin K. Petersen" <martin.petersen@oracle.com>
---

* No changes from v1

 drivers/scsi/scsi_debug.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 0a428b6..631e9ab 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -3373,7 +3373,7 @@ static int __init scsi_debug_init(void)
 	if (scsi_debug_num_parts > 0)
 		sdebug_build_parts(fake_storep, sz);
 
-	if (scsi_debug_dif) {
+	if (scsi_debug_dix) {
 		int dif_size;
 
 		dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple);
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v2 4/5] scsi_debug: simplify offset calculation for dif_storep
  2013-05-19 13:42 [PATCH v2 0/5] scsi_debug: bug fixes and cleanups for data integrity support Akinobu Mita
                   ` (2 preceding siblings ...)
  2013-05-19 13:42 ` [PATCH v2 3/5] scsi_debug: fix NULL pointer dereference with parameters dif=0 dix=1 Akinobu Mita
@ 2013-05-19 13:42 ` Akinobu Mita
  2013-05-19 13:42 ` [PATCH v2 5/5] scsi_debug: reduce duplication between prot_verify_read and prot_verify_write Akinobu Mita
  4 siblings, 0 replies; 6+ messages in thread
From: Akinobu Mita @ 2013-05-19 13:42 UTC (permalink / raw)
  To: linux-scsi
  Cc: Akinobu Mita, James E.J. Bottomley, Douglas Gilbert, Martin K. Petersen

dif_storep is declared as pointer to unsigned char type.  But it is
actually used to store vmalloced array of struct sd_dif_tuple.

This changes the type of dif_storep to the pointer to struct sd_dif_tuple.
It simplifies offset calculation for dif_storep and enables to remove
hardcoded size of struct sd_dif_tuple.

Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Cc: "James E.J. Bottomley" <JBottomley@parallels.com>
Cc: Douglas Gilbert <dgilbert@interlog.com>
Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: linux-scsi@vger.kernel.org
Acked-by: Douglas Gilbert <dgilbert@interlog.com>
---

* No changes from v1

 drivers/scsi/scsi_debug.c | 18 +++++++-----------
 1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 631e9ab..152ead6 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -258,7 +258,7 @@ struct sdebug_queued_cmd {
 static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
 
 static unsigned char * fake_storep;	/* ramdisk storage */
-static unsigned char *dif_storep;	/* protection info */
+static struct sd_dif_tuple *dif_storep;	/* protection info */
 static void *map_storep;		/* provisioning map */
 
 static unsigned long map_size;
@@ -277,11 +277,6 @@ static char sdebug_proc_name[] = "scsi_debug";
 
 static struct bus_type pseudo_lld_bus;
 
-static inline sector_t dif_offset(sector_t sector)
-{
-	return sector << 3;
-}
-
 static struct device_driver sdebug_driverfs_driver = {
 	.name 		= sdebug_proc_name,
 	.bus		= &pseudo_lld_bus,
@@ -1727,7 +1722,7 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
 
 	start_sec = do_div(tmp_sec, sdebug_store_sectors);
 
-	sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec));
+	sdt = dif_storep + start_sec;
 
 	for (i = 0 ; i < sectors ; i++) {
 		u16 csum;
@@ -1782,16 +1777,17 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
 		ei_lba++;
 	}
 
-	resid = sectors * 8; /* Bytes of protection data to copy into sgl */
+	/* Bytes of protection data to copy into sgl */
+	resid = sectors * sizeof(*dif_storep);
 	sector = start_sec;
 
 	scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) {
 		int len = min(psgl->length, resid);
 
 		paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
-		memcpy(paddr, dif_storep + dif_offset(sector), len);
+		memcpy(paddr, dif_storep + sector, len);
 
-		sector += len >> 3;
+		sector += len / sizeof(*dif_storep);
 		if (sector >= sdebug_store_sectors) {
 			/* Force wrap */
 			tmp_sec = sector;
@@ -1968,7 +1964,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
 			 * correctness we need to verify each sector
 			 * before writing it to "stable" storage
 			 */
-			memcpy(dif_storep + dif_offset(sector), sdt, 8);
+			memcpy(dif_storep + sector, sdt, sizeof(*sdt));
 
 			sector++;
 
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v2 5/5] scsi_debug: reduce duplication between prot_verify_read and prot_verify_write
  2013-05-19 13:42 [PATCH v2 0/5] scsi_debug: bug fixes and cleanups for data integrity support Akinobu Mita
                   ` (3 preceding siblings ...)
  2013-05-19 13:42 ` [PATCH v2 4/5] scsi_debug: simplify offset calculation for dif_storep Akinobu Mita
@ 2013-05-19 13:42 ` Akinobu Mita
  4 siblings, 0 replies; 6+ messages in thread
From: Akinobu Mita @ 2013-05-19 13:42 UTC (permalink / raw)
  To: linux-scsi
  Cc: Akinobu Mita, James E.J. Bottomley, Douglas Gilbert, Martin K. Petersen

In order to reduce code duplication between prot_verify_read() and
prot_verify_write(), this moves common code into the new functions.

Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Cc: "James E.J. Bottomley" <JBottomley@parallels.com>
Cc: Douglas Gilbert <dgilbert@interlog.com>
Cc: "Martin K. Petersen" <martin.petersen@oracle.com>
Cc: linux-scsi@vger.kernel.org
---

* New patch from v2

 drivers/scsi/scsi_debug.c | 135 +++++++++++++++++++---------------------------
 1 file changed, 54 insertions(+), 81 deletions(-)

diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 152ead6..bd14e12 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -1710,6 +1710,50 @@ static int do_device_access(struct scsi_cmnd *scmd,
 	return ret;
 }
 
+static u16 dif_compute_csum(const void *buf, int len)
+{
+	u16 csum;
+
+	switch (scsi_debug_guard) {
+	case 1:
+		csum = ip_compute_csum(buf, len);
+		break;
+	case 0:
+		csum = cpu_to_be16(crc_t10dif(buf, len));
+		break;
+	default:
+		BUG();
+	}
+	return csum;
+}
+
+static int dif_verify(struct sd_dif_tuple *sdt, u16 csum, sector_t sector,
+		      u32 ei_lba)
+{
+	if (sdt->guard_tag != csum) {
+		pr_err("%s: GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
+			__func__,
+			(unsigned long)sector,
+			be16_to_cpu(sdt->guard_tag),
+			be16_to_cpu(csum));
+		return 0x01;
+	}
+	if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
+	    be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
+		pr_err("%s: REF check failed on sector %lu\n",
+			__func__, (unsigned long)sector);
+		return 0x03;
+	}
+	if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
+	    be32_to_cpu(sdt->ref_tag) != ei_lba) {
+		pr_err("%s: REF check failed on sector %lu\n",
+			__func__, (unsigned long)sector);
+			dif_errors++;
+		return 0x03;
+	}
+	return 0;
+}
+
 static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
 			    unsigned int sectors, u32 ei_lba)
 {
@@ -1726,52 +1770,21 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
 
 	for (i = 0 ; i < sectors ; i++) {
 		u16 csum;
+		int ret;
 
 		if (sdt[i].app_tag == 0xffff)
 			continue;
 
 		sector = start_sec + i;
 
-		switch (scsi_debug_guard) {
-		case 1:
-			csum = ip_compute_csum(fake_storep +
-					       sector * scsi_debug_sector_size,
-					       scsi_debug_sector_size);
-			break;
-		case 0:
-			csum = crc_t10dif(fake_storep +
-					  sector * scsi_debug_sector_size,
-					  scsi_debug_sector_size);
-			csum = cpu_to_be16(csum);
-			break;
-		default:
-			BUG();
-		}
+		csum = dif_compute_csum(fake_storep +
+					sector * scsi_debug_sector_size,
+					scsi_debug_sector_size);
 
-		if (sdt[i].guard_tag != csum) {
-			printk(KERN_ERR "%s: GUARD check failed on sector %lu" \
-			       " rcvd 0x%04x, data 0x%04x\n", __func__,
-			       (unsigned long)sector,
-			       be16_to_cpu(sdt[i].guard_tag),
-			       be16_to_cpu(csum));
+		ret = dif_verify(&sdt[i], csum, sector, ei_lba);
+		if (ret) {
 			dif_errors++;
-			return 0x01;
-		}
-
-		if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
-		    be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {
-			printk(KERN_ERR "%s: REF check failed on sector %lu\n",
-			       __func__, (unsigned long)sector);
-			dif_errors++;
-			return 0x03;
-		}
-
-		if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
-		    be32_to_cpu(sdt[i].ref_tag) != ei_lba) {
-			printk(KERN_ERR "%s: REF check failed on sector %lu\n",
-			       __func__, (unsigned long)sector);
-			dif_errors++;
-			return 0x03;
+			return ret;
 		}
 
 		ei_lba++;
@@ -1911,50 +1924,10 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
 
 			sdt = paddr + ppage_offset;
 
-			switch (scsi_debug_guard) {
-			case 1:
-				csum = ip_compute_csum(daddr,
-						       scsi_debug_sector_size);
-				break;
-			case 0:
-				csum = cpu_to_be16(crc_t10dif(daddr,
-						      scsi_debug_sector_size));
-				break;
-			default:
-				BUG();
-				ret = 0;
-				goto out;
-			}
-
-			if (sdt->guard_tag != csum) {
-				printk(KERN_ERR
-				       "%s: GUARD check failed on sector %lu " \
-				       "rcvd 0x%04x, calculated 0x%04x\n",
-				       __func__, (unsigned long)sector,
-				       be16_to_cpu(sdt->guard_tag),
-				       be16_to_cpu(csum));
-				ret = 0x01;
-				dump_sector(daddr, scsi_debug_sector_size);
-				goto out;
-			}
-
-			if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
-			    be32_to_cpu(sdt->ref_tag)
-			    != (start_sec & 0xffffffff)) {
-				printk(KERN_ERR
-				       "%s: REF check failed on sector %lu\n",
-				       __func__, (unsigned long)sector);
-				ret = 0x03;
-				dump_sector(daddr, scsi_debug_sector_size);
-				goto out;
-			}
+			csum = dif_compute_csum(daddr, scsi_debug_sector_size);
 
-			if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
-			    be32_to_cpu(sdt->ref_tag) != ei_lba) {
-				printk(KERN_ERR
-				       "%s: REF check failed on sector %lu\n",
-				       __func__, (unsigned long)sector);
-				ret = 0x03;
+			ret = dif_verify(sdt, csum, start_sec, ei_lba);
+			if (ret) {
 				dump_sector(daddr, scsi_debug_sector_size);
 				goto out;
 			}
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2013-05-19 13:42 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-05-19 13:42 [PATCH v2 0/5] scsi_debug: bug fixes and cleanups for data integrity support Akinobu Mita
2013-05-19 13:42 ` [PATCH v2 1/5] scsi_debug: fix invalid address passed to kunmap_atomic() Akinobu Mita
2013-05-19 13:42 ` [PATCH v2 2/5] scsi_debug: fix incorrectly nested kmap_atomic() Akinobu Mita
2013-05-19 13:42 ` [PATCH v2 3/5] scsi_debug: fix NULL pointer dereference with parameters dif=0 dix=1 Akinobu Mita
2013-05-19 13:42 ` [PATCH v2 4/5] scsi_debug: simplify offset calculation for dif_storep Akinobu Mita
2013-05-19 13:42 ` [PATCH v2 5/5] scsi_debug: reduce duplication between prot_verify_read and prot_verify_write Akinobu Mita

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.