Skip to content

Commit 92ee9b9

Browse files
damien-lemoalgregkh
authored andcommitted
null_blk: Fix zone size initialization
commit 0ebcdd7 upstream. For a null_blk device with zoned mode enabled is currently initialized with a number of zones equal to the device capacity divided by the zone size, without considering if the device capacity is a multiple of the zone size. If the zone size is not a divisor of the capacity, the zones end up not covering the entire capacity, potentially resulting is out of bounds accesses to the zone array. Fix this by adding one last smaller zone with a size equal to the remainder of the disk capacity divided by the zone size if the capacity is not a multiple of the zone size. For such smaller last zone, the zone capacity is also checked so that it does not exceed the smaller zone size. Reported-by: Naohiro Aota <[email protected]> Fixes: ca4b2a0 ("null_blk: add zone support") Cc: [email protected] Signed-off-by: Damien Le Moal <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: Johannes Thumshirn <[email protected]> Signed-off-by: Jens Axboe <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 2bbb320 commit 92ee9b9

1 file changed

Lines changed: 15 additions & 8 deletions

File tree

drivers/block/null_blk_zoned.c

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
#define CREATE_TRACE_POINTS
77
#include "null_blk_trace.h"
88

9-
/* zone_size in MBs to sectors. */
10-
#define ZONE_SIZE_SHIFT 11
9+
#define MB_TO_SECTS(mb) (((sector_t)mb * SZ_1M) >> SECTOR_SHIFT)
1110

1211
static inline unsigned int null_zone_no(struct nullb_device *dev, sector_t sect)
1312
{
@@ -16,7 +15,7 @@ static inline unsigned int null_zone_no(struct nullb_device *dev, sector_t sect)
1615

1716
int null_init_zoned_dev(struct nullb_device *dev, struct request_queue *q)
1817
{
19-
sector_t dev_size = (sector_t)dev->size * 1024 * 1024;
18+
sector_t dev_capacity_sects, zone_capacity_sects;
2019
sector_t sector = 0;
2120
unsigned int i;
2221

@@ -38,9 +37,13 @@ int null_init_zoned_dev(struct nullb_device *dev, struct request_queue *q)
3837
return -EINVAL;
3938
}
4039

41-
dev->zone_size_sects = dev->zone_size << ZONE_SIZE_SHIFT;
42-
dev->nr_zones = dev_size >>
43-
(SECTOR_SHIFT + ilog2(dev->zone_size_sects));
40+
zone_capacity_sects = MB_TO_SECTS(dev->zone_capacity);
41+
dev_capacity_sects = MB_TO_SECTS(dev->size);
42+
dev->zone_size_sects = MB_TO_SECTS(dev->zone_size);
43+
dev->nr_zones = dev_capacity_sects >> ilog2(dev->zone_size_sects);
44+
if (dev_capacity_sects & (dev->zone_size_sects - 1))
45+
dev->nr_zones++;
46+
4447
dev->zones = kvmalloc_array(dev->nr_zones, sizeof(struct blk_zone),
4548
GFP_KERNEL | __GFP_ZERO);
4649
if (!dev->zones)
@@ -101,8 +104,12 @@ int null_init_zoned_dev(struct nullb_device *dev, struct request_queue *q)
101104
struct blk_zone *zone = &dev->zones[i];
102105

103106
zone->start = zone->wp = sector;
104-
zone->len = dev->zone_size_sects;
105-
zone->capacity = dev->zone_capacity << ZONE_SIZE_SHIFT;
107+
if (zone->start + dev->zone_size_sects > dev_capacity_sects)
108+
zone->len = dev_capacity_sects - zone->start;
109+
else
110+
zone->len = dev->zone_size_sects;
111+
zone->capacity =
112+
min_t(sector_t, zone->len, zone_capacity_sects);
106113
zone->type = BLK_ZONE_TYPE_SEQWRITE_REQ;
107114
zone->cond = BLK_ZONE_COND_EMPTY;
108115

0 commit comments

Comments
 (0)