Commit 65f72f2a authored by Akinobu Mita's avatar Akinobu Mita Committed by James Bottomley

[SCSI] scsi_debug: avoid partial copying PI from prot_sglist to dif_storep

If data integrity support is enabled, prot_verify_write() is called in
response to WRITE commands and it verifies protection info from
prot_sglist by comparing against data sglist, and copies protection info
to dif_storep.

When multiple blocks are transfered by a WRITE command, it verifies and
copies these blocks one by one.  So if it fails to verify protection
info in the middle of blocks, the actual data transfer to fake_storep
isn't proceeded at all although protection info for some blocks are
already copied to dif_storep.  Therefore, it breaks the data integrity
between fake_storep and dif_storep.

This fixes it by ensuring that copying protection info to dif_storep is
done after all blocks are successfully verified.  Reusing dif_copy_prot()
with supporting the opposite direction simplifies this fix.
Signed-off-by: default avatarAkinobu Mita <akinobu.mita@gmail.com>
Acked-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent bb8c063c
...@@ -1790,7 +1790,7 @@ static int dif_verify(struct sd_dif_tuple *sdt, const void *data, ...@@ -1790,7 +1790,7 @@ static int dif_verify(struct sd_dif_tuple *sdt, const void *data,
} }
static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector, static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
unsigned int sectors) unsigned int sectors, bool read)
{ {
unsigned int i, resid; unsigned int i, resid;
struct scatterlist *psgl; struct scatterlist *psgl;
...@@ -1809,10 +1809,18 @@ static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector, ...@@ -1809,10 +1809,18 @@ static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
rest = start + len - dif_store_end; rest = start + len - dif_store_end;
paddr = kmap_atomic(sg_page(psgl)) + psgl->offset; paddr = kmap_atomic(sg_page(psgl)) + psgl->offset;
memcpy(paddr, start, len - rest);
if (rest) if (read)
memcpy(paddr + len - rest, dif_storep, rest); memcpy(paddr, start, len - rest);
else
memcpy(start, paddr, len - rest);
if (rest) {
if (read)
memcpy(paddr + len - rest, dif_storep, rest);
else
memcpy(dif_storep, paddr + len - rest, rest);
}
sector += len / sizeof(*dif_storep); sector += len / sizeof(*dif_storep);
resid -= len; resid -= len;
...@@ -1845,7 +1853,7 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, ...@@ -1845,7 +1853,7 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
ei_lba++; ei_lba++;
} }
dif_copy_prot(SCpnt, start_sec, sectors); dif_copy_prot(SCpnt, start_sec, sectors, true);
dix_reads++; dix_reads++;
return 0; return 0;
...@@ -1928,15 +1936,12 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, ...@@ -1928,15 +1936,12 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
{ {
int i, j, ret; int i, j, ret;
struct sd_dif_tuple *sdt; struct sd_dif_tuple *sdt;
struct scatterlist *dsgl = scsi_sglist(SCpnt); struct scatterlist *dsgl;
struct scatterlist *psgl = scsi_prot_sglist(SCpnt); struct scatterlist *psgl = scsi_prot_sglist(SCpnt);
void *daddr, *paddr; void *daddr, *paddr;
sector_t tmp_sec = start_sec; sector_t sector = start_sec;
sector_t sector;
int ppage_offset; int ppage_offset;
sector = do_div(tmp_sec, sdebug_store_sectors);
BUG_ON(scsi_sg_count(SCpnt) == 0); BUG_ON(scsi_sg_count(SCpnt) == 0);
BUG_ON(scsi_prot_sg_count(SCpnt) == 0); BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
...@@ -1964,25 +1969,13 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, ...@@ -1964,25 +1969,13 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
sdt = paddr + ppage_offset; sdt = paddr + ppage_offset;
ret = dif_verify(sdt, daddr + j, start_sec, ei_lba); ret = dif_verify(sdt, daddr + j, sector, ei_lba);
if (ret) { if (ret) {
dump_sector(daddr + j, scsi_debug_sector_size); dump_sector(daddr + j, scsi_debug_sector_size);
goto out; goto out;
} }
/* Would be great to copy this in bigger
* chunks. However, for the sake of
* correctness we need to verify each sector
* before writing it to "stable" storage
*/
memcpy(dif_storep + sector, sdt, sizeof(*sdt));
sector++; sector++;
if (sector == sdebug_store_sectors)
sector = 0; /* Force wrap */
start_sec++;
ei_lba++; ei_lba++;
ppage_offset += sizeof(struct sd_dif_tuple); ppage_offset += sizeof(struct sd_dif_tuple);
} }
...@@ -1991,6 +1984,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, ...@@ -1991,6 +1984,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
kunmap_atomic(daddr); kunmap_atomic(daddr);
} }
dif_copy_prot(SCpnt, start_sec, sectors, false);
dix_writes++; dix_writes++;
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment