提交 3185ad9c 编写于 作者: D Damien Le Moal 提交者: Yang Yingliang

null_blk: Fix zone size initialization

stable inclusion
from linux-4.19.165
commit 1344c5564d84ce01fdf844a6c77fa4be92b8039a

--------------------------------

commit 0ebcdd70 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: NNaohiro Aota <naohiro.aota@wdc.com>
Fixes: ca4b2a01 ("null_blk: add zone support")
Cc: stable@vger.kernel.org
Signed-off-by: NDamien Le Moal <damien.lemoal@wdc.com>
Reviewed-by: NChristoph Hellwig <hch@lst.de>
Reviewed-by: NJohannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: NJens Axboe <axboe@kernel.dk>
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
Signed-off-by: NCheng Jian <cj.chengjian@huawei.com>
上级 3b952359
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/sizes.h>
#include "null_blk.h" #include "null_blk.h"
/* zone_size in MBs to sectors. */ #define MB_TO_SECTS(mb) (((sector_t)mb * SZ_1M) >> SECTOR_SHIFT)
#define ZONE_SIZE_SHIFT 11
static inline unsigned int null_zone_no(struct nullb_device *dev, sector_t sect) static inline unsigned int null_zone_no(struct nullb_device *dev, sector_t sect)
{ {
...@@ -12,7 +12,7 @@ static inline unsigned int null_zone_no(struct nullb_device *dev, sector_t sect) ...@@ -12,7 +12,7 @@ static inline unsigned int null_zone_no(struct nullb_device *dev, sector_t sect)
int null_zone_init(struct nullb_device *dev) int null_zone_init(struct nullb_device *dev)
{ {
sector_t dev_size = (sector_t)dev->size * 1024 * 1024; sector_t dev_capacity_sects;
sector_t sector = 0; sector_t sector = 0;
unsigned int i; unsigned int i;
...@@ -21,9 +21,12 @@ int null_zone_init(struct nullb_device *dev) ...@@ -21,9 +21,12 @@ int null_zone_init(struct nullb_device *dev)
return -EINVAL; return -EINVAL;
} }
dev->zone_size_sects = dev->zone_size << ZONE_SIZE_SHIFT; dev_capacity_sects = MB_TO_SECTS(dev->size);
dev->nr_zones = dev_size >> dev->zone_size_sects = MB_TO_SECTS(dev->zone_size);
(SECTOR_SHIFT + ilog2(dev->zone_size_sects)); dev->nr_zones = dev_capacity_sects >> ilog2(dev->zone_size_sects);
if (dev_capacity_sects & (dev->zone_size_sects - 1))
dev->nr_zones++;
dev->zones = kvmalloc_array(dev->nr_zones, sizeof(struct blk_zone), dev->zones = kvmalloc_array(dev->nr_zones, sizeof(struct blk_zone),
GFP_KERNEL | __GFP_ZERO); GFP_KERNEL | __GFP_ZERO);
if (!dev->zones) if (!dev->zones)
...@@ -33,7 +36,10 @@ int null_zone_init(struct nullb_device *dev) ...@@ -33,7 +36,10 @@ int null_zone_init(struct nullb_device *dev)
struct blk_zone *zone = &dev->zones[i]; struct blk_zone *zone = &dev->zones[i];
zone->start = zone->wp = sector; zone->start = zone->wp = sector;
zone->len = dev->zone_size_sects; if (zone->start + dev->zone_size_sects > dev_capacity_sects)
zone->len = dev_capacity_sects - zone->start;
else
zone->len = dev->zone_size_sects;
zone->type = BLK_ZONE_TYPE_SEQWRITE_REQ; zone->type = BLK_ZONE_TYPE_SEQWRITE_REQ;
zone->cond = BLK_ZONE_COND_EMPTY; zone->cond = BLK_ZONE_COND_EMPTY;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册