Back to home page

LXR

 
 

    


0001 /*
0002  * Zoned block device handling
0003  *
0004  * Copyright (c) 2015, Hannes Reinecke
0005  * Copyright (c) 2015, SUSE Linux GmbH
0006  *
0007  * Copyright (c) 2016, Damien Le Moal
0008  * Copyright (c) 2016, Western Digital
0009  */
0010 
0011 #include <linux/kernel.h>
0012 #include <linux/module.h>
0013 #include <linux/rbtree.h>
0014 #include <linux/blkdev.h>
0015 
0016 static inline sector_t blk_zone_start(struct request_queue *q,
0017                       sector_t sector)
0018 {
0019     sector_t zone_mask = blk_queue_zone_sectors(q) - 1;
0020 
0021     return sector & ~zone_mask;
0022 }
0023 
0024 /*
0025  * Check that a zone report belongs to the partition.
0026  * If yes, fix its start sector and write pointer, copy it in the
0027  * zone information array and return true. Return false otherwise.
0028  */
0029 static bool blkdev_report_zone(struct block_device *bdev,
0030                    struct blk_zone *rep,
0031                    struct blk_zone *zone)
0032 {
0033     sector_t offset = get_start_sect(bdev);
0034 
0035     if (rep->start < offset)
0036         return false;
0037 
0038     rep->start -= offset;
0039     if (rep->start + rep->len > bdev->bd_part->nr_sects)
0040         return false;
0041 
0042     if (rep->type == BLK_ZONE_TYPE_CONVENTIONAL)
0043         rep->wp = rep->start + rep->len;
0044     else
0045         rep->wp -= offset;
0046     memcpy(zone, rep, sizeof(struct blk_zone));
0047 
0048     return true;
0049 }
0050 
0051 /**
0052  * blkdev_report_zones - Get zones information
0053  * @bdev:   Target block device
0054  * @sector: Sector from which to report zones
0055  * @zones:  Array of zone structures where to return the zones information
0056  * @nr_zones:   Number of zone structures in the zone array
0057  * @gfp_mask:   Memory allocation flags (for bio_alloc)
0058  *
0059  * Description:
0060  *    Get zone information starting from the zone containing @sector.
0061  *    The number of zone information reported may be less than the number
0062  *    requested by @nr_zones. The number of zones actually reported is
0063  *    returned in @nr_zones.
0064  */
0065 int blkdev_report_zones(struct block_device *bdev,
0066             sector_t sector,
0067             struct blk_zone *zones,
0068             unsigned int *nr_zones,
0069             gfp_t gfp_mask)
0070 {
0071     struct request_queue *q = bdev_get_queue(bdev);
0072     struct blk_zone_report_hdr *hdr;
0073     unsigned int nrz = *nr_zones;
0074     struct page *page;
0075     unsigned int nr_rep;
0076     size_t rep_bytes;
0077     unsigned int nr_pages;
0078     struct bio *bio;
0079     struct bio_vec *bv;
0080     unsigned int i, n, nz;
0081     unsigned int ofst;
0082     void *addr;
0083     int ret;
0084 
0085     if (!q)
0086         return -ENXIO;
0087 
0088     if (!blk_queue_is_zoned(q))
0089         return -EOPNOTSUPP;
0090 
0091     if (!nrz)
0092         return 0;
0093 
0094     if (sector > bdev->bd_part->nr_sects) {
0095         *nr_zones = 0;
0096         return 0;
0097     }
0098 
0099     /*
0100      * The zone report has a header. So make room for it in the
0101      * payload. Also make sure that the report fits in a single BIO
0102      * that will not be split down the stack.
0103      */
0104     rep_bytes = sizeof(struct blk_zone_report_hdr) +
0105         sizeof(struct blk_zone) * nrz;
0106     rep_bytes = (rep_bytes + PAGE_SIZE - 1) & PAGE_MASK;
0107     if (rep_bytes > (queue_max_sectors(q) << 9))
0108         rep_bytes = queue_max_sectors(q) << 9;
0109 
0110     nr_pages = min_t(unsigned int, BIO_MAX_PAGES,
0111              rep_bytes >> PAGE_SHIFT);
0112     nr_pages = min_t(unsigned int, nr_pages,
0113              queue_max_segments(q));
0114 
0115     bio = bio_alloc(gfp_mask, nr_pages);
0116     if (!bio)
0117         return -ENOMEM;
0118 
0119     bio->bi_bdev = bdev;
0120     bio->bi_iter.bi_sector = blk_zone_start(q, sector);
0121     bio_set_op_attrs(bio, REQ_OP_ZONE_REPORT, 0);
0122 
0123     for (i = 0; i < nr_pages; i++) {
0124         page = alloc_page(gfp_mask);
0125         if (!page) {
0126             ret = -ENOMEM;
0127             goto out;
0128         }
0129         if (!bio_add_page(bio, page, PAGE_SIZE, 0)) {
0130             __free_page(page);
0131             break;
0132         }
0133     }
0134 
0135     if (i == 0)
0136         ret = -ENOMEM;
0137     else
0138         ret = submit_bio_wait(bio);
0139     if (ret)
0140         goto out;
0141 
0142     /*
0143      * Process the report result: skip the header and go through the
0144      * reported zones to fixup and fixup the zone information for
0145      * partitions. At the same time, return the zone information into
0146      * the zone array.
0147      */
0148     n = 0;
0149     nz = 0;
0150     nr_rep = 0;
0151     bio_for_each_segment_all(bv, bio, i) {
0152 
0153         if (!bv->bv_page)
0154             break;
0155 
0156         addr = kmap_atomic(bv->bv_page);
0157 
0158         /* Get header in the first page */
0159         ofst = 0;
0160         if (!nr_rep) {
0161             hdr = (struct blk_zone_report_hdr *) addr;
0162             nr_rep = hdr->nr_zones;
0163             ofst = sizeof(struct blk_zone_report_hdr);
0164         }
0165 
0166         /* Fixup and report zones */
0167         while (ofst < bv->bv_len &&
0168                n < nr_rep && nz < nrz) {
0169             if (blkdev_report_zone(bdev, addr + ofst, &zones[nz]))
0170                 nz++;
0171             ofst += sizeof(struct blk_zone);
0172             n++;
0173         }
0174 
0175         kunmap_atomic(addr);
0176 
0177         if (n >= nr_rep || nz >= nrz)
0178             break;
0179 
0180     }
0181 
0182     *nr_zones = nz;
0183 out:
0184     bio_for_each_segment_all(bv, bio, i)
0185         __free_page(bv->bv_page);
0186     bio_put(bio);
0187 
0188     return ret;
0189 }
0190 EXPORT_SYMBOL_GPL(blkdev_report_zones);
0191 
0192 /**
0193  * blkdev_reset_zones - Reset zones write pointer
0194  * @bdev:   Target block device
0195  * @sector: Start sector of the first zone to reset
0196  * @nr_sectors: Number of sectors, at least the length of one zone
0197  * @gfp_mask:   Memory allocation flags (for bio_alloc)
0198  *
0199  * Description:
0200  *    Reset the write pointer of the zones contained in the range
0201  *    @sector..@sector+@nr_sectors. Specifying the entire disk sector range
0202  *    is valid, but the specified range should not contain conventional zones.
0203  */
0204 int blkdev_reset_zones(struct block_device *bdev,
0205                sector_t sector, sector_t nr_sectors,
0206                gfp_t gfp_mask)
0207 {
0208     struct request_queue *q = bdev_get_queue(bdev);
0209     sector_t zone_sectors;
0210     sector_t end_sector = sector + nr_sectors;
0211     struct bio *bio;
0212     int ret;
0213 
0214     if (!q)
0215         return -ENXIO;
0216 
0217     if (!blk_queue_is_zoned(q))
0218         return -EOPNOTSUPP;
0219 
0220     if (end_sector > bdev->bd_part->nr_sects)
0221         /* Out of range */
0222         return -EINVAL;
0223 
0224     /* Check alignment (handle eventual smaller last zone) */
0225     zone_sectors = blk_queue_zone_sectors(q);
0226     if (sector & (zone_sectors - 1))
0227         return -EINVAL;
0228 
0229     if ((nr_sectors & (zone_sectors - 1)) &&
0230         end_sector != bdev->bd_part->nr_sects)
0231         return -EINVAL;
0232 
0233     while (sector < end_sector) {
0234 
0235         bio = bio_alloc(gfp_mask, 0);
0236         bio->bi_iter.bi_sector = sector;
0237         bio->bi_bdev = bdev;
0238         bio_set_op_attrs(bio, REQ_OP_ZONE_RESET, 0);
0239 
0240         ret = submit_bio_wait(bio);
0241         bio_put(bio);
0242 
0243         if (ret)
0244             return ret;
0245 
0246         sector += zone_sectors;
0247 
0248         /* This may take a while, so be nice to others */
0249         cond_resched();
0250 
0251     }
0252 
0253     return 0;
0254 }
0255 EXPORT_SYMBOL_GPL(blkdev_reset_zones);
0256 
0257 /**
0258  * BLKREPORTZONE ioctl processing.
0259  * Called from blkdev_ioctl.
0260  */
0261 int blkdev_report_zones_ioctl(struct block_device *bdev, fmode_t mode,
0262                   unsigned int cmd, unsigned long arg)
0263 {
0264     void __user *argp = (void __user *)arg;
0265     struct request_queue *q;
0266     struct blk_zone_report rep;
0267     struct blk_zone *zones;
0268     int ret;
0269 
0270     if (!argp)
0271         return -EINVAL;
0272 
0273     q = bdev_get_queue(bdev);
0274     if (!q)
0275         return -ENXIO;
0276 
0277     if (!blk_queue_is_zoned(q))
0278         return -ENOTTY;
0279 
0280     if (!capable(CAP_SYS_ADMIN))
0281         return -EACCES;
0282 
0283     if (copy_from_user(&rep, argp, sizeof(struct blk_zone_report)))
0284         return -EFAULT;
0285 
0286     if (!rep.nr_zones)
0287         return -EINVAL;
0288 
0289     zones = kcalloc(rep.nr_zones, sizeof(struct blk_zone), GFP_KERNEL);
0290     if (!zones)
0291         return -ENOMEM;
0292 
0293     ret = blkdev_report_zones(bdev, rep.sector,
0294                   zones, &rep.nr_zones,
0295                   GFP_KERNEL);
0296     if (ret)
0297         goto out;
0298 
0299     if (copy_to_user(argp, &rep, sizeof(struct blk_zone_report))) {
0300         ret = -EFAULT;
0301         goto out;
0302     }
0303 
0304     if (rep.nr_zones) {
0305         if (copy_to_user(argp + sizeof(struct blk_zone_report), zones,
0306                  sizeof(struct blk_zone) * rep.nr_zones))
0307             ret = -EFAULT;
0308     }
0309 
0310  out:
0311     kfree(zones);
0312 
0313     return ret;
0314 }
0315 
0316 /**
0317  * BLKRESETZONE ioctl processing.
0318  * Called from blkdev_ioctl.
0319  */
0320 int blkdev_reset_zones_ioctl(struct block_device *bdev, fmode_t mode,
0321                  unsigned int cmd, unsigned long arg)
0322 {
0323     void __user *argp = (void __user *)arg;
0324     struct request_queue *q;
0325     struct blk_zone_range zrange;
0326 
0327     if (!argp)
0328         return -EINVAL;
0329 
0330     q = bdev_get_queue(bdev);
0331     if (!q)
0332         return -ENXIO;
0333 
0334     if (!blk_queue_is_zoned(q))
0335         return -ENOTTY;
0336 
0337     if (!capable(CAP_SYS_ADMIN))
0338         return -EACCES;
0339 
0340     if (!(mode & FMODE_WRITE))
0341         return -EBADF;
0342 
0343     if (copy_from_user(&zrange, argp, sizeof(struct blk_zone_range)))
0344         return -EFAULT;
0345 
0346     return blkdev_reset_zones(bdev, zrange.sector, zrange.nr_sectors,
0347                   GFP_KERNEL);
0348 }