diff options
author | Akinobu Mita <akinobu.mita@gmail.com> | 2013-04-16 09:11:58 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2013-05-02 18:45:56 -0400 |
commit | b90ebc3d5c41c9164ae04efd2e4f8204c2a186f1 (patch) | |
tree | b74225a28bb0322c6cb755349abc7a8299198c2c /drivers/scsi | |
parent | cc34a8e663b2908b9ab487dab8456d117a1e0b93 (diff) |
[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: Akinobu Mita <akinobu.mita@gmail.com>
Acked-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/scsi_debug.c | 81 |
1 files changed, 41 insertions, 40 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 4b5d3887ff47..154d9870dc5a 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c | |||
@@ -1997,24 +1997,39 @@ out: | |||
1997 | return ret; | 1997 | return ret; |
1998 | } | 1998 | } |
1999 | 1999 | ||
2000 | static unsigned int map_state(sector_t lba, unsigned int *num) | 2000 | static unsigned long lba_to_map_index(sector_t lba) |
2001 | { | ||
2002 | if (scsi_debug_unmap_alignment) { | ||
2003 | lba += scsi_debug_unmap_granularity - | ||
2004 | scsi_debug_unmap_alignment; | ||
2005 | } | ||
2006 | do_div(lba, scsi_debug_unmap_granularity); | ||
2007 | |||
2008 | return lba; | ||
2009 | } | ||
2010 | |||
2011 | static sector_t map_index_to_lba(unsigned long index) | ||
2001 | { | 2012 | { |
2002 | unsigned int granularity, alignment, mapped; | 2013 | return index * scsi_debug_unmap_granularity - |
2003 | sector_t block, next, end; | 2014 | scsi_debug_unmap_alignment; |
2015 | } | ||
2004 | 2016 | ||
2005 | granularity = scsi_debug_unmap_granularity; | 2017 | static unsigned int map_state(sector_t lba, unsigned int *num) |
2006 | alignment = granularity - scsi_debug_unmap_alignment; | 2018 | { |
2007 | block = lba + alignment; | 2019 | sector_t end; |
2008 | do_div(block, granularity); | 2020 | unsigned int mapped; |
2021 | unsigned long index; | ||
2022 | unsigned long next; | ||
2009 | 2023 | ||
2010 | mapped = test_bit(block, map_storep); | 2024 | index = lba_to_map_index(lba); |
2025 | mapped = test_bit(index, map_storep); | ||
2011 | 2026 | ||
2012 | if (mapped) | 2027 | if (mapped) |
2013 | next = find_next_zero_bit(map_storep, map_size, block); | 2028 | next = find_next_zero_bit(map_storep, map_size, index); |
2014 | else | 2029 | else |
2015 | next = find_next_bit(map_storep, map_size, block); | 2030 | next = find_next_bit(map_storep, map_size, index); |
2016 | 2031 | ||
2017 | end = next * granularity - scsi_debug_unmap_alignment; | 2032 | end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next)); |
2018 | *num = end - lba; | 2033 | *num = end - lba; |
2019 | 2034 | ||
2020 | return mapped; | 2035 | return mapped; |
@@ -2022,48 +2037,37 @@ static unsigned int map_state(sector_t lba, unsigned int *num) | |||
2022 | 2037 | ||
2023 | static void map_region(sector_t lba, unsigned int len) | 2038 | static void map_region(sector_t lba, unsigned int len) |
2024 | { | 2039 | { |
2025 | unsigned int granularity, alignment; | ||
2026 | sector_t end = lba + len; | 2040 | sector_t end = lba + len; |
2027 | 2041 | ||
2028 | granularity = scsi_debug_unmap_granularity; | ||
2029 | alignment = granularity - scsi_debug_unmap_alignment; | ||
2030 | |||
2031 | while (lba < end) { | 2042 | while (lba < end) { |
2032 | sector_t block, rem; | 2043 | unsigned long index = lba_to_map_index(lba); |
2033 | |||
2034 | block = lba + alignment; | ||
2035 | rem = do_div(block, granularity); | ||
2036 | 2044 | ||
2037 | if (block < map_size) | 2045 | if (index < map_size) |
2038 | set_bit(block, map_storep); | 2046 | set_bit(index, map_storep); |
2039 | 2047 | ||
2040 | lba += granularity - rem; | 2048 | lba = map_index_to_lba(index + 1); |
2041 | } | 2049 | } |
2042 | } | 2050 | } |
2043 | 2051 | ||
2044 | static void unmap_region(sector_t lba, unsigned int len) | 2052 | static void unmap_region(sector_t lba, unsigned int len) |
2045 | { | 2053 | { |
2046 | unsigned int granularity, alignment; | ||
2047 | sector_t end = lba + len; | 2054 | sector_t end = lba + len; |
2048 | 2055 | ||
2049 | granularity = scsi_debug_unmap_granularity; | ||
2050 | alignment = granularity - scsi_debug_unmap_alignment; | ||
2051 | |||
2052 | while (lba < end) { | 2056 | while (lba < end) { |
2053 | sector_t block, rem; | 2057 | unsigned long index = lba_to_map_index(lba); |
2054 | |||
2055 | block = lba + alignment; | ||
2056 | rem = do_div(block, granularity); | ||
2057 | 2058 | ||
2058 | if (rem == 0 && lba + granularity < end && block < map_size) { | 2059 | if (lba == map_index_to_lba(index) && |
2059 | clear_bit(block, map_storep); | 2060 | lba + scsi_debug_unmap_granularity <= end && |
2060 | if (scsi_debug_lbprz) | 2061 | index < map_size) { |
2062 | clear_bit(index, map_storep); | ||
2063 | if (scsi_debug_lbprz) { | ||
2061 | memset(fake_storep + | 2064 | memset(fake_storep + |
2062 | lba * scsi_debug_sector_size, 0, | 2065 | lba * scsi_debug_sector_size, 0, |
2063 | scsi_debug_sector_size * | 2066 | scsi_debug_sector_size * |
2064 | scsi_debug_unmap_granularity); | 2067 | scsi_debug_unmap_granularity); |
2068 | } | ||
2065 | } | 2069 | } |
2066 | lba += granularity - rem; | 2070 | lba = map_index_to_lba(index + 1); |
2067 | } | 2071 | } |
2068 | } | 2072 | } |
2069 | 2073 | ||
@@ -3402,8 +3406,6 @@ static int __init scsi_debug_init(void) | |||
3402 | 3406 | ||
3403 | /* Logical Block Provisioning */ | 3407 | /* Logical Block Provisioning */ |
3404 | if (scsi_debug_lbp()) { | 3408 | if (scsi_debug_lbp()) { |
3405 | unsigned int map_bytes; | ||
3406 | |||
3407 | scsi_debug_unmap_max_blocks = | 3409 | scsi_debug_unmap_max_blocks = |
3408 | clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU); | 3410 | clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU); |
3409 | 3411 | ||
@@ -3422,9 +3424,8 @@ static int __init scsi_debug_init(void) | |||
3422 | return -EINVAL; | 3424 | return -EINVAL; |
3423 | } | 3425 | } |
3424 | 3426 | ||
3425 | map_size = (sdebug_store_sectors / scsi_debug_unmap_granularity); | 3427 | map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; |
3426 | map_bytes = map_size >> 3; | 3428 | map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long)); |
3427 | map_storep = vmalloc(map_bytes); | ||
3428 | 3429 | ||
3429 | printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n", | 3430 | printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n", |
3430 | map_size); | 3431 | map_size); |
@@ -3435,7 +3436,7 @@ static int __init scsi_debug_init(void) | |||
3435 | goto free_vm; | 3436 | goto free_vm; |
3436 | } | 3437 | } |
3437 | 3438 | ||
3438 | memset(map_storep, 0x0, map_bytes); | 3439 | bitmap_zero(map_storep, map_size); |
3439 | 3440 | ||
3440 | /* Map first 1KB for partition table */ | 3441 | /* Map first 1KB for partition table */ |
3441 | if (scsi_debug_num_parts) | 3442 | if (scsi_debug_num_parts) |