Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.20 116 lines 2.8 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2#include <linux/vmalloc.h> 3#include "null_blk.h" 4 5/* zone_size in MBs to sectors. */ 6#define ZONE_SIZE_SHIFT 11 7 8static inline unsigned int null_zone_no(struct nullb_device *dev, sector_t sect) 9{ 10 return sect >> ilog2(dev->zone_size_sects); 11} 12 13int null_zone_init(struct nullb_device *dev) 14{ 15 sector_t dev_size = (sector_t)dev->size * 1024 * 1024; 16 sector_t sector = 0; 17 unsigned int i; 18 19 if (!is_power_of_2(dev->zone_size)) { 20 pr_err("null_blk: zone_size must be power-of-two\n"); 21 return -EINVAL; 22 } 23 24 dev->zone_size_sects = dev->zone_size << ZONE_SIZE_SHIFT; 25 dev->nr_zones = dev_size >> 26 (SECTOR_SHIFT + ilog2(dev->zone_size_sects)); 27 dev->zones = kvmalloc_array(dev->nr_zones, sizeof(struct blk_zone), 28 GFP_KERNEL | __GFP_ZERO); 29 if (!dev->zones) 30 return -ENOMEM; 31 32 for (i = 0; i < dev->nr_zones; i++) { 33 struct blk_zone *zone = &dev->zones[i]; 34 35 zone->start = zone->wp = sector; 36 zone->len = dev->zone_size_sects; 37 zone->type = BLK_ZONE_TYPE_SEQWRITE_REQ; 38 zone->cond = BLK_ZONE_COND_EMPTY; 39 40 sector += dev->zone_size_sects; 41 } 42 43 return 0; 44} 45 46void null_zone_exit(struct nullb_device *dev) 47{ 48 kvfree(dev->zones); 49} 50 51int null_zone_report(struct gendisk *disk, sector_t sector, 52 struct blk_zone *zones, unsigned int *nr_zones, 53 gfp_t gfp_mask) 54{ 55 struct nullb *nullb = disk->private_data; 56 struct nullb_device *dev = nullb->dev; 57 unsigned int zno, nrz = 0; 58 59 if (!dev->zoned) 60 /* Not a zoned null device */ 61 return -EOPNOTSUPP; 62 63 zno = null_zone_no(dev, sector); 64 if (zno < dev->nr_zones) { 65 nrz = min_t(unsigned int, *nr_zones, dev->nr_zones - zno); 66 memcpy(zones, &dev->zones[zno], nrz * sizeof(struct blk_zone)); 67 } 68 69 *nr_zones = nrz; 70 71 return 0; 72} 73 74void null_zone_write(struct nullb_cmd *cmd, sector_t sector, 75 unsigned int nr_sectors) 76{ 77 struct nullb_device *dev = cmd->nq->dev; 78 unsigned int zno = null_zone_no(dev, sector); 79 struct blk_zone *zone = &dev->zones[zno]; 80 81 switch (zone->cond) { 82 case BLK_ZONE_COND_FULL: 83 /* Cannot write to a full zone */ 84 cmd->error = BLK_STS_IOERR; 85 break; 86 case BLK_ZONE_COND_EMPTY: 87 case BLK_ZONE_COND_IMP_OPEN: 88 /* Writes must be at the write pointer position */ 89 if (sector != zone->wp) { 90 cmd->error = BLK_STS_IOERR; 91 break; 92 } 93 94 if (zone->cond == BLK_ZONE_COND_EMPTY) 95 zone->cond = BLK_ZONE_COND_IMP_OPEN; 96 97 zone->wp += nr_sectors; 98 if (zone->wp == zone->start + zone->len) 99 zone->cond = BLK_ZONE_COND_FULL; 100 break; 101 default: 102 /* Invalid zone condition */ 103 cmd->error = BLK_STS_IOERR; 104 break; 105 } 106} 107 108void null_zone_reset(struct nullb_cmd *cmd, sector_t sector) 109{ 110 struct nullb_device *dev = cmd->nq->dev; 111 unsigned int zno = null_zone_no(dev, sector); 112 struct blk_zone *zone = &dev->zones[zno]; 113 114 zone->cond = BLK_ZONE_COND_EMPTY; 115 zone->wp = zone->start; 116}