]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - drivers/md/dm.c
Merge branches 'pm-sleep', 'pm-cpuidle', 'pm-cpufreq', 'pm-devfreq' and 'pm-avs'
[linux.git] / drivers / md / dm.c
index 1a5e328c443a997a48e36a0397afbe27ee8c8e4b..e8f9661a10a197176ac68c8a93764e87e9d9b2f8 100644 (file)
@@ -440,14 +440,48 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
        return dm_get_geometry(md, geo);
 }
 
+#ifdef CONFIG_BLK_DEV_ZONED
+int dm_report_zones_cb(struct blk_zone *zone, unsigned int idx, void *data)
+{
+       struct dm_report_zones_args *args = data;
+       sector_t sector_diff = args->tgt->begin - args->start;
+
+       /*
+        * Ignore zones beyond the target range.
+        */
+       if (zone->start >= args->start + args->tgt->len)
+               return 0;
+
+       /*
+        * Remap the start sector and write pointer position of the zone
+        * to match its position in the target range.
+        */
+       zone->start += sector_diff;
+       if (zone->type != BLK_ZONE_TYPE_CONVENTIONAL) {
+               if (zone->cond == BLK_ZONE_COND_FULL)
+                       zone->wp = zone->start + zone->len;
+               else if (zone->cond == BLK_ZONE_COND_EMPTY)
+                       zone->wp = zone->start;
+               else
+                       zone->wp += sector_diff;
+       }
+
+       args->next_sector = zone->start + zone->len;
+       return args->orig_cb(zone, args->zone_idx++, args->orig_data);
+}
+EXPORT_SYMBOL_GPL(dm_report_zones_cb);
+
 static int dm_blk_report_zones(struct gendisk *disk, sector_t sector,
-                              struct blk_zone *zones, unsigned int *nr_zones)
+               unsigned int nr_zones, report_zones_cb cb, void *data)
 {
-#ifdef CONFIG_BLK_DEV_ZONED
        struct mapped_device *md = disk->private_data;
-       struct dm_target *tgt;
        struct dm_table *map;
        int srcu_idx, ret;
+       struct dm_report_zones_args args = {
+               .next_sector = sector,
+               .orig_data = data,
+               .orig_cb = cb,
+       };
 
        if (dm_suspended_md(md))
                return -EAGAIN;
@@ -456,38 +490,30 @@ static int dm_blk_report_zones(struct gendisk *disk, sector_t sector,
        if (!map)
                return -EIO;
 
-       tgt = dm_table_find_target(map, sector);
-       if (!tgt) {
-               ret = -EIO;
-               goto out;
-       }
+       do {
+               struct dm_target *tgt;
 
-       /*
-        * If we are executing this, we already know that the block device
-        * is a zoned device and so each target should have support for that
-        * type of drive. A missing report_zones method means that the target
-        * driver has a problem.
-        */
-       if (WARN_ON(!tgt->type->report_zones)) {
-               ret = -EIO;
-               goto out;
-       }
+               tgt = dm_table_find_target(map, args.next_sector);
+               if (WARN_ON_ONCE(!tgt->type->report_zones)) {
+                       ret = -EIO;
+                       goto out;
+               }
 
-       /*
-        * blkdev_report_zones() will loop and call this again to cover all the
-        * zones of the target, eventually moving on to the next target.
-        * So there is no need to loop here trying to fill the entire array
-        * of zones.
-        */
-       ret = tgt->type->report_zones(tgt, sector, zones, nr_zones);
+               args.tgt = tgt;
+               ret = tgt->type->report_zones(tgt, &args, nr_zones);
+               if (ret < 0)
+                       goto out;
+       } while (args.zone_idx < nr_zones &&
+                args.next_sector < get_capacity(disk));
 
+       ret = args.zone_idx;
 out:
        dm_put_live_table(md, srcu_idx);
        return ret;
-#else
-       return -ENOTSUPP;
-#endif
 }
+#else
+#define dm_blk_report_zones            NULL
+#endif /* CONFIG_BLK_DEV_ZONED */
 
 static int dm_prepare_ioctl(struct mapped_device *md, int *srcu_idx,
                            struct block_device **bdev)
@@ -1174,7 +1200,8 @@ static size_t dm_dax_copy_to_iter(struct dax_device *dax_dev, pgoff_t pgoff,
 
 /*
  * A target may call dm_accept_partial_bio only from the map routine.  It is
- * allowed for all bio types except REQ_PREFLUSH and REQ_OP_ZONE_RESET.
+ * allowed for all bio types except REQ_PREFLUSH, REQ_OP_ZONE_RESET,
+ * REQ_OP_ZONE_OPEN, REQ_OP_ZONE_CLOSE and REQ_OP_ZONE_FINISH.
  *
  * dm_accept_partial_bio informs the dm that the target only wants to process
  * additional n_sectors sectors of the bio and the rest of the data should be
@@ -1212,54 +1239,6 @@ void dm_accept_partial_bio(struct bio *bio, unsigned n_sectors)
 }
 EXPORT_SYMBOL_GPL(dm_accept_partial_bio);
 
-/*
- * The zone descriptors obtained with a zone report indicate
- * zone positions within the underlying device of the target. The zone
- * descriptors must be remapped to match their position within the dm device.
- * The caller target should obtain the zones information using
- * blkdev_report_zones() to ensure that remapping for partition offset is
- * already handled.
- */
-void dm_remap_zone_report(struct dm_target *ti, sector_t start,
-                         struct blk_zone *zones, unsigned int *nr_zones)
-{
-#ifdef CONFIG_BLK_DEV_ZONED
-       struct blk_zone *zone;
-       unsigned int nrz = *nr_zones;
-       int i;
-
-       /*
-        * Remap the start sector and write pointer position of the zones in
-        * the array. Since we may have obtained from the target underlying
-        * device more zones that the target size, also adjust the number
-        * of zones.
-        */
-       for (i = 0; i < nrz; i++) {
-               zone = zones + i;
-               if (zone->start >= start + ti->len) {
-                       memset(zone, 0, sizeof(struct blk_zone) * (nrz - i));
-                       break;
-               }
-
-               zone->start = zone->start + ti->begin - start;
-               if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL)
-                       continue;
-
-               if (zone->cond == BLK_ZONE_COND_FULL)
-                       zone->wp = zone->start + zone->len;
-               else if (zone->cond == BLK_ZONE_COND_EMPTY)
-                       zone->wp = zone->start;
-               else
-                       zone->wp = zone->wp + ti->begin - start;
-       }
-
-       *nr_zones = i;
-#else /* !CONFIG_BLK_DEV_ZONED */
-       *nr_zones = 0;
-#endif
-}
-EXPORT_SYMBOL_GPL(dm_remap_zone_report);
-
 static blk_qc_t __map_bio(struct dm_target_io *tio)
 {
        int r;
@@ -1627,7 +1606,7 @@ static blk_qc_t __split_and_process_bio(struct mapped_device *md,
                ci.sector_count = 0;
                error = __send_empty_flush(&ci);
                /* dec_pending submits any data associated with flush */
-       } else if (bio_op(bio) == REQ_OP_ZONE_RESET) {
+       } else if (op_is_zone_mgmt(bio_op(bio))) {
                ci.bio = bio;
                ci.sector_count = 0;
                error = __split_and_process_non_flush(&ci);