diff options
author | Akinobu Mita <akinobu.mita@gmail.com> | 2013-09-18 08:27:26 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2013-10-25 04:58:12 -0400 |
commit | 65f72f2a2fe89f072d6a88e5cd69a64270b9c436 (patch) | |
tree | 05da71cdc92fcb9ea0888fdd2316c340ac89baf9 | |
parent | bb8c063c6afcd930b8da944927144f2982609638 (diff) |
[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: Akinobu Mita <akinobu.mita@gmail.com>
Acked-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r-- | drivers/scsi/scsi_debug.c | 40 |
1 files changed, 17 insertions, 23 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 99e74d75cf08..43369e9071f7 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c | |||
@@ -1790,7 +1790,7 @@ static int dif_verify(struct sd_dif_tuple *sdt, const void *data, | |||
1790 | } | 1790 | } |
1791 | 1791 | ||
1792 | static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector, | 1792 | static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector, |
1793 | unsigned int sectors) | 1793 | unsigned int sectors, bool read) |
1794 | { | 1794 | { |
1795 | unsigned int i, resid; | 1795 | unsigned int i, resid; |
1796 | struct scatterlist *psgl; | 1796 | struct scatterlist *psgl; |
@@ -1809,10 +1809,18 @@ static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector, | |||
1809 | rest = start + len - dif_store_end; | 1809 | rest = start + len - dif_store_end; |
1810 | 1810 | ||
1811 | paddr = kmap_atomic(sg_page(psgl)) + psgl->offset; | 1811 | paddr = kmap_atomic(sg_page(psgl)) + psgl->offset; |
1812 | memcpy(paddr, start, len - rest); | ||
1813 | 1812 | ||
1814 | if (rest) | 1813 | if (read) |
1815 | memcpy(paddr + len - rest, dif_storep, rest); | 1814 | memcpy(paddr, start, len - rest); |
1815 | else | ||
1816 | memcpy(start, paddr, len - rest); | ||
1817 | |||
1818 | if (rest) { | ||
1819 | if (read) | ||
1820 | memcpy(paddr + len - rest, dif_storep, rest); | ||
1821 | else | ||
1822 | memcpy(dif_storep, paddr + len - rest, rest); | ||
1823 | } | ||
1816 | 1824 | ||
1817 | sector += len / sizeof(*dif_storep); | 1825 | sector += len / sizeof(*dif_storep); |
1818 | resid -= len; | 1826 | resid -= len; |
@@ -1845,7 +1853,7 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, | |||
1845 | ei_lba++; | 1853 | ei_lba++; |
1846 | } | 1854 | } |
1847 | 1855 | ||
1848 | dif_copy_prot(SCpnt, start_sec, sectors); | 1856 | dif_copy_prot(SCpnt, start_sec, sectors, true); |
1849 | dix_reads++; | 1857 | dix_reads++; |
1850 | 1858 | ||
1851 | return 0; | 1859 | return 0; |
@@ -1928,15 +1936,12 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, | |||
1928 | { | 1936 | { |
1929 | int i, j, ret; | 1937 | int i, j, ret; |
1930 | struct sd_dif_tuple *sdt; | 1938 | struct sd_dif_tuple *sdt; |
1931 | struct scatterlist *dsgl = scsi_sglist(SCpnt); | 1939 | struct scatterlist *dsgl; |
1932 | struct scatterlist *psgl = scsi_prot_sglist(SCpnt); | 1940 | struct scatterlist *psgl = scsi_prot_sglist(SCpnt); |
1933 | void *daddr, *paddr; | 1941 | void *daddr, *paddr; |
1934 | sector_t tmp_sec = start_sec; | 1942 | sector_t sector = start_sec; |
1935 | sector_t sector; | ||
1936 | int ppage_offset; | 1943 | int ppage_offset; |
1937 | 1944 | ||
1938 | sector = do_div(tmp_sec, sdebug_store_sectors); | ||
1939 | |||
1940 | BUG_ON(scsi_sg_count(SCpnt) == 0); | 1945 | BUG_ON(scsi_sg_count(SCpnt) == 0); |
1941 | BUG_ON(scsi_prot_sg_count(SCpnt) == 0); | 1946 | BUG_ON(scsi_prot_sg_count(SCpnt) == 0); |
1942 | 1947 | ||
@@ -1964,25 +1969,13 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, | |||
1964 | 1969 | ||
1965 | sdt = paddr + ppage_offset; | 1970 | sdt = paddr + ppage_offset; |
1966 | 1971 | ||
1967 | ret = dif_verify(sdt, daddr + j, start_sec, ei_lba); | 1972 | ret = dif_verify(sdt, daddr + j, sector, ei_lba); |
1968 | if (ret) { | 1973 | if (ret) { |
1969 | dump_sector(daddr + j, scsi_debug_sector_size); | 1974 | dump_sector(daddr + j, scsi_debug_sector_size); |
1970 | goto out; | 1975 | goto out; |
1971 | } | 1976 | } |
1972 | 1977 | ||
1973 | /* Would be great to copy this in bigger | ||
1974 | * chunks. However, for the sake of | ||
1975 | * correctness we need to verify each sector | ||
1976 | * before writing it to "stable" storage | ||
1977 | */ | ||
1978 | memcpy(dif_storep + sector, sdt, sizeof(*sdt)); | ||
1979 | |||
1980 | sector++; | 1978 | sector++; |
1981 | |||
1982 | if (sector == sdebug_store_sectors) | ||
1983 | sector = 0; /* Force wrap */ | ||
1984 | |||
1985 | start_sec++; | ||
1986 | ei_lba++; | 1979 | ei_lba++; |
1987 | ppage_offset += sizeof(struct sd_dif_tuple); | 1980 | ppage_offset += sizeof(struct sd_dif_tuple); |
1988 | } | 1981 | } |
@@ -1991,6 +1984,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, | |||
1991 | kunmap_atomic(daddr); | 1984 | kunmap_atomic(daddr); |
1992 | } | 1985 | } |
1993 | 1986 | ||
1987 | dif_copy_prot(SCpnt, start_sec, sectors, false); | ||
1994 | dix_writes++; | 1988 | dix_writes++; |
1995 | 1989 | ||
1996 | return 0; | 1990 | return 0; |