]> Git Repo - linux.git/blobdiff - drivers/md/dm-target.c
dm error: Add support for zoned block devices
[linux.git] / drivers / md / dm-target.c
index 27e2992ff249271edfb30629936c28ff541a81a0..0c4efb0bef8a90ae668b02b2ea2f6557a1348180 100644 (file)
@@ -116,8 +116,62 @@ EXPORT_SYMBOL(dm_unregister_target);
  * io-err: always fails an io, useful for bringing
  * up LVs that have holes in them.
  */
+struct io_err_c {
+       struct dm_dev *dev;
+       sector_t start;
+};
+
+static int io_err_get_args(struct dm_target *tt, unsigned int argc, char **args)
+{
+       unsigned long long start;
+       struct io_err_c *ioec;
+       char dummy;
+       int ret;
+
+       ioec = kmalloc(sizeof(*ioec), GFP_KERNEL);
+       if (!ioec) {
+               tt->error = "Cannot allocate io_err context";
+               return -ENOMEM;
+       }
+
+       ret = -EINVAL;
+       if (sscanf(args[1], "%llu%c", &start, &dummy) != 1 ||
+           start != (sector_t)start) {
+               tt->error = "Invalid device sector";
+               goto bad;
+       }
+       ioec->start = start;
+
+       ret = dm_get_device(tt, args[0], dm_table_get_mode(tt->table), &ioec->dev);
+       if (ret) {
+               tt->error = "Device lookup failed";
+               goto bad;
+       }
+
+       tt->private = ioec;
+
+       return 0;
+
+bad:
+       kfree(ioec);
+
+       return ret;
+}
+
 static int io_err_ctr(struct dm_target *tt, unsigned int argc, char **args)
 {
+       /*
+        * If we have arguments, assume it is the path to the backing
+        * block device and its mapping start sector (same as dm-linear).
+        * In this case, get the device so that we can get its limits.
+        */
+       if (argc == 2) {
+               int ret = io_err_get_args(tt, argc, args);
+
+               if (ret)
+                       return ret;
+       }
+
        /*
         * Return error for discards instead of -EOPNOTSUPP
         */
@@ -129,7 +183,12 @@ static int io_err_ctr(struct dm_target *tt, unsigned int argc, char **args)
 
 static void io_err_dtr(struct dm_target *tt)
 {
-       /* empty */
+       struct io_err_c *ioec = tt->private;
+
+       if (ioec) {
+               dm_put_device(tt, ioec->dev);
+               kfree(ioec);
+       }
 }
 
 static int io_err_map(struct dm_target *tt, struct bio *bio)
@@ -149,6 +208,45 @@ static void io_err_release_clone_rq(struct request *clone,
 {
 }
 
+#ifdef CONFIG_BLK_DEV_ZONED
+static sector_t io_err_map_sector(struct dm_target *ti, sector_t bi_sector)
+{
+       struct io_err_c *ioec = ti->private;
+
+       return ioec->start + dm_target_offset(ti, bi_sector);
+}
+
+static int io_err_report_zones(struct dm_target *ti,
+               struct dm_report_zones_args *args, unsigned int nr_zones)
+{
+       struct io_err_c *ioec = ti->private;
+
+       /*
+        * This should never be called when we do not have a backing device
+        * as that mean the target is not a zoned one.
+        */
+       if (WARN_ON_ONCE(!ioec))
+               return -EIO;
+
+       return dm_report_zones(ioec->dev->bdev, ioec->start,
+                              io_err_map_sector(ti, args->next_sector),
+                              args, nr_zones);
+}
+#else
+#define io_err_report_zones NULL
+#endif
+
+static int io_err_iterate_devices(struct dm_target *ti,
+                                 iterate_devices_callout_fn fn, void *data)
+{
+       struct io_err_c *ioec = ti->private;
+
+       if (!ioec)
+               return 0;
+
+       return fn(ti, ioec->dev, ioec->start, ti->len, data);
+}
+
 static void io_err_io_hints(struct dm_target *ti, struct queue_limits *limits)
 {
        limits->max_discard_sectors = UINT_MAX;
@@ -165,15 +263,17 @@ static long io_err_dax_direct_access(struct dm_target *ti, pgoff_t pgoff,
 
 static struct target_type error_target = {
        .name = "error",
-       .version = {1, 6, 0},
-       .features = DM_TARGET_WILDCARD,
+       .version = {1, 7, 0},
+       .features = DM_TARGET_WILDCARD | DM_TARGET_ZONED_HM,
        .ctr  = io_err_ctr,
        .dtr  = io_err_dtr,
        .map  = io_err_map,
        .clone_and_map_rq = io_err_clone_and_map_rq,
        .release_clone_rq = io_err_release_clone_rq,
+       .iterate_devices = io_err_iterate_devices,
        .io_hints = io_err_io_hints,
        .direct_access = io_err_dax_direct_access,
+       .report_zones = io_err_report_zones,
 };
 
 int __init dm_target_init(void)
This page took 0.037858 seconds and 4 git commands to generate.