A zoned block device maintains a write pointer within a zone, and reads beyond the write pointer are undefined. Fill data buffer returned above the write pointer with 0xFF. Signed-off-by: Ajay Joshi <ajay.joshi@xxxxxxx> Reviewed-by: Damien Le Moal <damien.lemoal@xxxxxxx> Reviewed-by: Matias Bjørling <matias.bjorling@xxxxxxx> --- drivers/block/null_blk.h | 7 +++++++ drivers/block/null_blk_main.c | 26 +++++++++++++++++++++++++- drivers/block/null_blk_zoned.c | 18 ++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/drivers/block/null_blk.h b/drivers/block/null_blk.h index 34b22d6523ba..fa82c4d96c8a 100644 --- a/drivers/block/null_blk.h +++ b/drivers/block/null_blk.h @@ -94,6 +94,8 @@ int null_zone_report(struct gendisk *disk, sector_t sector, void null_zone_write(struct nullb_cmd *cmd, sector_t sector, unsigned int nr_sectors); void null_zone_reset(struct nullb_cmd *cmd, sector_t sector); +size_t null_zone_valid_read_len(struct nullb *nullb, + sector_t sector, unsigned int len); #else static inline int null_zone_init(struct nullb_device *dev) { @@ -112,5 +114,10 @@ static inline void null_zone_write(struct nullb_cmd *cmd, sector_t sector, { } static inline void null_zone_reset(struct nullb_cmd *cmd, sector_t sector) {} +static inline size_t null_zone_valid_read_len(struct nullb *nullb, + sector_t sector, unsigned int len) +{ + return len; +} #endif /* CONFIG_BLK_DEV_ZONED */ #endif /* __NULL_BLK_H */ diff --git a/drivers/block/null_blk_main.c b/drivers/block/null_blk_main.c index 99328ded60d1..ce66f4e6268a 100644 --- a/drivers/block/null_blk_main.c +++ b/drivers/block/null_blk_main.c @@ -996,6 +996,16 @@ static int copy_from_nullb(struct nullb *nullb, struct page *dest, return 0; } +static void nullb_fill_pattern(struct nullb *nullb, + struct page *page, unsigned int len, unsigned int off) +{ + void *dst; + + dst = kmap_atomic(page); + memset(dst + off, 0xFF, len); + kunmap_atomic(dst); +} + static void null_handle_discard(struct nullb *nullb, sector_t sector, size_t n) { size_t temp; @@ -1037,9 +1047,23 @@ static int null_transfer(struct nullb *nullb, struct page *page, bool is_fua) { int err = 0; + struct nullb_device *dev = nullb->dev; + unsigned int valid_len = len; if (!is_write) { - err = copy_from_nullb(nullb, page, off, sector, len); + if (dev->zoned) + valid_len = null_zone_valid_read_len(nullb, + sector, len); + + if (valid_len) { + err = copy_from_nullb(nullb, page, off, + sector, valid_len); + off += valid_len; + len -= valid_len; + } + + if (len) + nullb_fill_pattern(nullb, page, len, off); flush_dcache_page(page); } else { flush_dcache_page(page); diff --git a/drivers/block/null_blk_zoned.c b/drivers/block/null_blk_zoned.c index fca0c97ff1aa..20a3c08e628c 100644 --- a/drivers/block/null_blk_zoned.c +++ b/drivers/block/null_blk_zoned.c @@ -85,6 +85,24 @@ int null_zone_report(struct gendisk *disk, sector_t sector, return 0; } +size_t null_zone_valid_read_len(struct nullb *nullb, + sector_t sector, unsigned int len) +{ + struct nullb_device *dev = nullb->dev; + struct blk_zone *zone = &dev->zones[null_zone_no(dev, sector)]; + unsigned int nr_sectors = len >> SECTOR_SHIFT; + + /* Read must be below the write pointer position */ + if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL || + sector + nr_sectors <= zone->wp) + return len; + + if (sector > zone->wp) + return 0; + + return (zone->wp - sector) << SECTOR_SHIFT; +} + void null_zone_write(struct nullb_cmd *cmd, sector_t sector, unsigned int nr_sectors) { -- 2.19.1