Commit b90ebc3d authored by Akinobu Mita's avatar Akinobu Mita Committed by James Bottomley

[SCSI] scsi_debug: fix logical block provisioning support

provisioning map (map_storep) is a bitmap accessed by bitops.

So the allocation size should be a multiple of sizeof(unsigned long) and
also the bitmap should be cleared by using bitmap_clear() instead of
memset().

Otherwise it will cause problem on big-endian architecture if the number of
bits is not a multiple of BITS_PER_LONG.

I tried testing the logical block provisioning support in scsi_debug,
but it didn't work as I expected.

For example, load scsi_debug module with UNMAP command supported
and fill the storage with random data.

        # modprobe scsi_debug lbpu=1
        # dd if=/dev/urandom of=/dev/sdb

Then, try to unmap LBA 0, but Get LBA status reports:

        # sg_unmap --lba=0 --num=1 /dev/sdb
        # sg_get_lba_status --lba=0 /dev/sdb
        descriptor LBA: 0x0000000000000000  blocks: 16384  mapped

This is unexpected result.  Because UNMAP command to LBA 0 finished
without any errors, but Get LBA status shows that LBA 0 is still mapped.

This problem is due to the wrong translation between LBA and index of
provisioning map.  Fix it by using correct translation functions.
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 cc34a8e6
...@@ -1997,24 +1997,39 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, ...@@ -1997,24 +1997,39 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
return ret; return ret;
} }
static unsigned int map_state(sector_t lba, unsigned int *num) static unsigned long lba_to_map_index(sector_t lba)
{
if (scsi_debug_unmap_alignment) {
lba += scsi_debug_unmap_granularity -
scsi_debug_unmap_alignment;
}
do_div(lba, scsi_debug_unmap_granularity);
return lba;
}
static sector_t map_index_to_lba(unsigned long index)
{ {
unsigned int granularity, alignment, mapped; return index * scsi_debug_unmap_granularity -
sector_t block, next, end; scsi_debug_unmap_alignment;
}
granularity = scsi_debug_unmap_granularity; static unsigned int map_state(sector_t lba, unsigned int *num)
alignment = granularity - scsi_debug_unmap_alignment; {
block = lba + alignment; sector_t end;
do_div(block, granularity); unsigned int mapped;
unsigned long index;
unsigned long next;
mapped = test_bit(block, map_storep); index = lba_to_map_index(lba);
mapped = test_bit(index, map_storep);
if (mapped) if (mapped)
next = find_next_zero_bit(map_storep, map_size, block); next = find_next_zero_bit(map_storep, map_size, index);
else else
next = find_next_bit(map_storep, map_size, block); next = find_next_bit(map_storep, map_size, index);
end = next * granularity - scsi_debug_unmap_alignment; end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
*num = end - lba; *num = end - lba;
return mapped; return mapped;
...@@ -2022,48 +2037,37 @@ static unsigned int map_state(sector_t lba, unsigned int *num) ...@@ -2022,48 +2037,37 @@ static unsigned int map_state(sector_t lba, unsigned int *num)
static void map_region(sector_t lba, unsigned int len) static void map_region(sector_t lba, unsigned int len)
{ {
unsigned int granularity, alignment;
sector_t end = lba + len; sector_t end = lba + len;
granularity = scsi_debug_unmap_granularity;
alignment = granularity - scsi_debug_unmap_alignment;
while (lba < end) { while (lba < end) {
sector_t block, rem; unsigned long index = lba_to_map_index(lba);
block = lba + alignment;
rem = do_div(block, granularity);
if (block < map_size) if (index < map_size)
set_bit(block, map_storep); set_bit(index, map_storep);
lba += granularity - rem; lba = map_index_to_lba(index + 1);
} }
} }
static void unmap_region(sector_t lba, unsigned int len) static void unmap_region(sector_t lba, unsigned int len)
{ {
unsigned int granularity, alignment;
sector_t end = lba + len; sector_t end = lba + len;
granularity = scsi_debug_unmap_granularity;
alignment = granularity - scsi_debug_unmap_alignment;
while (lba < end) { while (lba < end) {
sector_t block, rem; unsigned long index = lba_to_map_index(lba);
block = lba + alignment;
rem = do_div(block, granularity);
if (rem == 0 && lba + granularity < end && block < map_size) { if (lba == map_index_to_lba(index) &&
clear_bit(block, map_storep); lba + scsi_debug_unmap_granularity <= end &&
if (scsi_debug_lbprz) index < map_size) {
clear_bit(index, map_storep);
if (scsi_debug_lbprz) {
memset(fake_storep + memset(fake_storep +
lba * scsi_debug_sector_size, 0, lba * scsi_debug_sector_size, 0,
scsi_debug_sector_size * scsi_debug_sector_size *
scsi_debug_unmap_granularity); scsi_debug_unmap_granularity);
}
} }
lba += granularity - rem; lba = map_index_to_lba(index + 1);
} }
} }
...@@ -3402,8 +3406,6 @@ static int __init scsi_debug_init(void) ...@@ -3402,8 +3406,6 @@ static int __init scsi_debug_init(void)
/* Logical Block Provisioning */ /* Logical Block Provisioning */
if (scsi_debug_lbp()) { if (scsi_debug_lbp()) {
unsigned int map_bytes;
scsi_debug_unmap_max_blocks = scsi_debug_unmap_max_blocks =
clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU); clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU);
...@@ -3422,9 +3424,8 @@ static int __init scsi_debug_init(void) ...@@ -3422,9 +3424,8 @@ static int __init scsi_debug_init(void)
return -EINVAL; return -EINVAL;
} }
map_size = (sdebug_store_sectors / scsi_debug_unmap_granularity); map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
map_bytes = map_size >> 3; map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long));
map_storep = vmalloc(map_bytes);
printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n", printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n",
map_size); map_size);
...@@ -3435,7 +3436,7 @@ static int __init scsi_debug_init(void) ...@@ -3435,7 +3436,7 @@ static int __init scsi_debug_init(void)
goto free_vm; goto free_vm;
} }
memset(map_storep, 0x0, map_bytes); bitmap_zero(map_storep, map_size);
/* Map first 1KB for partition table */ /* Map first 1KB for partition table */
if (scsi_debug_num_parts) if (scsi_debug_num_parts)
......
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