OSDN Git Service

Merge tag 'for-4.17/dm-changes' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 6 Apr 2018 18:50:19 +0000 (11:50 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 6 Apr 2018 18:50:19 +0000 (11:50 -0700)
Pull device mapper updates from Mike Snitzer:

 - DM core passthrough ioctl fix to retain reference to DM table, and
   that table's block devices, while issuing the ioctl to one of those
   block devices.

 - DM core passthrough ioctl fix to _not_ override the fmode_t used to
   issue the ioctl. Overriding by using the fmode_t that the block
   device was originally open with during DM table load is a liability.

 - Add DM core support for secure erase forwarding and update the DM
   linear and DM striped targets to support them.

 - A DM core 4.16 stable fix to allow abnormal IO (e.g. discard, write
   same, write zeroes) for targets that make use of the non-splitting IO
   variant (as is done for multipath or thinp when layered directly on
   NVMe).

 - Allow DM targets to return a payload in response to a DM message that
   they are sent. This is useful for DM targets that would like to
   provide statistics data in response to DM messages.

 - Update DM bufio to support non-power-of-2 block sizes. Numerous other
   related changes prepare the DM bufio code for this support.

 - Fix DM crypt to use a bounded amount of memory across the entire
   system. This is to avoid OOM that can otherwise occur in response to
   certain pathological IO workloads (e.g. discarding a large DM crypt
   device).

 - Add a 'check_at_most_once' feature to the DM verity target to allow
   verity to be used on mobile devices that have very limited resources.

 - Fix the DM integrity target to fail early if a keyed algorithm (e.g.
   HMAC) is to be used but the key isn't set.

 - Add non-power-of-2 support to the DM unstripe target.

 - Eliminate the use of a Variable Length Array in the DM stripe target.

 - Update the DM log-writes target to record metadata (REQ_META flag).

 - DM raid fixes for its nosync status and some variable range issues.

* tag 'for-4.17/dm-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm: (28 commits)
  dm: remove fmode_t argument from .prepare_ioctl hook
  dm: hold DM table for duration of ioctl rather than use blkdev_get
  dm raid: fix parse_raid_params() variable range issue
  dm verity: make verity_for_io_block static
  dm verity: add 'check_at_most_once' option to only validate hashes once
  dm bufio: don't embed a bio in the dm_buffer structure
  dm bufio: support non-power-of-two block sizes
  dm bufio: use slab cache for dm_buffer structure allocations
  dm bufio: reorder fields in dm_buffer structure
  dm bufio: relax alignment constraint on slab cache
  dm bufio: remove code that merges slab caches
  dm bufio: get rid of slab cache name allocations
  dm bufio: move dm-bufio.h to include/linux/
  dm bufio: delete outdated comment
  dm: add support for secure erase forwarding
  dm: backfill abnormal IO support to non-splitting IO submission
  dm raid: fix nosync status
  dm mpath: use DM_MAPIO_SUBMITTED instead of magic number 0 in process_queued_bios()
  dm stripe: get rid of a Variable Length Array (VLA)
  dm log writes: record metadata flag for better flags record
  ...

1  2 
drivers/md/dm-table.c
drivers/md/dm.c
include/linux/device-mapper.h

diff --combined drivers/md/dm-table.c
@@@ -1846,6 -1846,34 +1846,34 @@@ static bool dm_table_supports_discards(
        return true;
  }
  
+ static int device_not_secure_erase_capable(struct dm_target *ti,
+                                          struct dm_dev *dev, sector_t start,
+                                          sector_t len, void *data)
+ {
+       struct request_queue *q = bdev_get_queue(dev->bdev);
+       return q && !blk_queue_secure_erase(q);
+ }
+ static bool dm_table_supports_secure_erase(struct dm_table *t)
+ {
+       struct dm_target *ti;
+       unsigned int i;
+       for (i = 0; i < dm_table_get_num_targets(t); i++) {
+               ti = dm_table_get_target(t, i);
+               if (!ti->num_secure_erase_bios)
+                       return false;
+               if (!ti->type->iterate_devices ||
+                   ti->type->iterate_devices(ti, device_not_secure_erase_capable, NULL))
+                       return false;
+       }
+       return true;
+ }
  void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
                               struct queue_limits *limits)
  {
        q->limits = *limits;
  
        if (!dm_table_supports_discards(t)) {
 -              queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q);
 +              blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q);
                /* Must also clear discard limits... */
                q->limits.max_discard_sectors = 0;
                q->limits.max_hw_discard_sectors = 0;
                q->limits.discard_alignment = 0;
                q->limits.discard_misaligned = 0;
        } else
 -              queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q);
 +              blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
  
 -              queue_flag_set_unlocked(QUEUE_FLAG_SECERASE, q);
+       if (dm_table_supports_secure_erase(t))
++              blk_queue_flag_set(QUEUE_FLAG_SECERASE, q);
        if (dm_table_supports_flush(t, (1UL << QUEUE_FLAG_WC))) {
                wc = true;
                if (dm_table_supports_flush(t, (1UL << QUEUE_FLAG_FUA)))
        blk_queue_write_cache(q, wc, fua);
  
        if (dm_table_supports_dax(t))
 -              queue_flag_set_unlocked(QUEUE_FLAG_DAX, q);
 +              blk_queue_flag_set(QUEUE_FLAG_DAX, q);
        if (dm_table_supports_dax_write_cache(t))
                dax_write_cache(t->md->dax_dev, true);
  
        /* Ensure that all underlying devices are non-rotational. */
        if (dm_table_all_devices_attribute(t, device_is_nonrot))
 -              queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q);
 +              blk_queue_flag_set(QUEUE_FLAG_NONROT, q);
        else
 -              queue_flag_clear_unlocked(QUEUE_FLAG_NONROT, q);
 +              blk_queue_flag_clear(QUEUE_FLAG_NONROT, q);
  
        if (!dm_table_supports_write_same(t))
                q->limits.max_write_same_sectors = 0;
                q->limits.max_write_zeroes_sectors = 0;
  
        if (dm_table_all_devices_attribute(t, queue_supports_sg_merge))
 -              queue_flag_clear_unlocked(QUEUE_FLAG_NO_SG_MERGE, q);
 +              blk_queue_flag_clear(QUEUE_FLAG_NO_SG_MERGE, q);
        else
 -              queue_flag_set_unlocked(QUEUE_FLAG_NO_SG_MERGE, q);
 +              blk_queue_flag_set(QUEUE_FLAG_NO_SG_MERGE, q);
  
        dm_table_verify_integrity(t);
  
         * have it set.
         */
        if (blk_queue_add_random(q) && dm_table_all_devices_attribute(t, device_is_not_random))
 -              queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, q);
 +              blk_queue_flag_clear(QUEUE_FLAG_ADD_RANDOM, q);
  }
  
  unsigned int dm_table_get_num_targets(struct dm_table *t)
diff --combined drivers/md/dm.c
@@@ -458,67 -458,56 +458,56 @@@ static int dm_blk_getgeo(struct block_d
        return dm_get_geometry(md, geo);
  }
  
- static char *_dm_claim_ptr = "I belong to device-mapper";
- static int dm_get_bdev_for_ioctl(struct mapped_device *md,
-                                struct block_device **bdev,
-                                fmode_t *mode)
+ static int dm_prepare_ioctl(struct mapped_device *md, int *srcu_idx,
+                           struct block_device **bdev)
+       __acquires(md->io_barrier)
  {
        struct dm_target *tgt;
        struct dm_table *map;
-       int srcu_idx, r, r2;
+       int r;
  
  retry:
        r = -ENOTTY;
-       map = dm_get_live_table(md, &srcu_idx);
+       map = dm_get_live_table(md, srcu_idx);
        if (!map || !dm_table_get_size(map))
-               goto out;
+               return r;
  
        /* We only support devices that have a single target */
        if (dm_table_get_num_targets(map) != 1)
-               goto out;
+               return r;
  
        tgt = dm_table_get_target(map, 0);
        if (!tgt->type->prepare_ioctl)
-               goto out;
-       if (dm_suspended_md(md)) {
-               r = -EAGAIN;
-               goto out;
-       }
-       r = tgt->type->prepare_ioctl(tgt, bdev, mode);
-       if (r < 0)
-               goto out;
-       bdgrab(*bdev);
-       r2 = blkdev_get(*bdev, *mode, _dm_claim_ptr);
-       if (r2 < 0) {
-               r = r2;
-               goto out;
-       }
+               return r;
  
-       dm_put_live_table(md, srcu_idx);
-       return r;
+       if (dm_suspended_md(md))
+               return -EAGAIN;
  
- out:
-       dm_put_live_table(md, srcu_idx);
+       r = tgt->type->prepare_ioctl(tgt, bdev);
        if (r == -ENOTCONN && !fatal_signal_pending(current)) {
+               dm_put_live_table(md, *srcu_idx);
                msleep(10);
                goto retry;
        }
        return r;
  }
  
+ static void dm_unprepare_ioctl(struct mapped_device *md, int srcu_idx)
+       __releases(md->io_barrier)
+ {
+       dm_put_live_table(md, srcu_idx);
+ }
  static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
                        unsigned int cmd, unsigned long arg)
  {
        struct mapped_device *md = bdev->bd_disk->private_data;
-       int r;
+       int r, srcu_idx;
  
-       r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
+       r = dm_prepare_ioctl(md, &srcu_idx, &bdev);
        if (r < 0)
-               return r;
+               goto out;
  
        if (r > 0) {
                /*
  
        r =  __blkdev_driver_ioctl(bdev, mode, cmd, arg);
  out:
-       blkdev_put(bdev, mode);
+       dm_unprepare_ioctl(md, srcu_idx);
        return r;
  }
  
@@@ -710,6 -699,8 +699,8 @@@ static void dm_put_live_table_fast(stru
        rcu_read_unlock();
  }
  
+ static char *_dm_claim_ptr = "I belong to device-mapper";
  /*
   * Open a table device so we can use it as a map destination.
   */
@@@ -1414,6 -1405,11 +1405,11 @@@ static unsigned get_num_discard_bios(st
        return ti->num_discard_bios;
  }
  
+ static unsigned get_num_secure_erase_bios(struct dm_target *ti)
+ {
+       return ti->num_secure_erase_bios;
+ }
  static unsigned get_num_write_same_bios(struct dm_target *ti)
  {
        return ti->num_write_same_bios;
@@@ -1467,6 -1463,11 +1463,11 @@@ static int __send_discard(struct clone_
                                           is_split_required_for_discard);
  }
  
+ static int __send_secure_erase(struct clone_info *ci, struct dm_target *ti)
+ {
+       return __send_changing_extent_only(ci, ti, get_num_secure_erase_bios, NULL);
+ }
  static int __send_write_same(struct clone_info *ci, struct dm_target *ti)
  {
        return __send_changing_extent_only(ci, ti, get_num_write_same_bios, NULL);
@@@ -1477,6 -1478,25 +1478,25 @@@ static int __send_write_zeroes(struct c
        return __send_changing_extent_only(ci, ti, get_num_write_zeroes_bios, NULL);
  }
  
+ static bool __process_abnormal_io(struct clone_info *ci, struct dm_target *ti,
+                                 int *result)
+ {
+       struct bio *bio = ci->bio;
+       if (bio_op(bio) == REQ_OP_DISCARD)
+               *result = __send_discard(ci, ti);
+       else if (bio_op(bio) == REQ_OP_SECURE_ERASE)
+               *result = __send_secure_erase(ci, ti);
+       else if (bio_op(bio) == REQ_OP_WRITE_SAME)
+               *result = __send_write_same(ci, ti);
+       else if (bio_op(bio) == REQ_OP_WRITE_ZEROES)
+               *result = __send_write_zeroes(ci, ti);
+       else
+               return false;
+       return true;
+ }
  /*
   * Select the correct strategy for processing a non-flush bio.
   */
@@@ -1491,12 -1511,8 +1511,8 @@@ static int __split_and_process_non_flus
        if (!dm_target_is_valid(ti))
                return -EIO;
  
-       if (unlikely(bio_op(bio) == REQ_OP_DISCARD))
-               return __send_discard(ci, ti);
-       else if (unlikely(bio_op(bio) == REQ_OP_WRITE_SAME))
-               return __send_write_same(ci, ti);
-       else if (unlikely(bio_op(bio) == REQ_OP_WRITE_ZEROES))
-               return __send_write_zeroes(ci, ti);
+       if (unlikely(__process_abnormal_io(ci, ti, &r)))
+               return r;
  
        if (bio_op(bio) == REQ_OP_ZONE_REPORT)
                len = ci->sector_count;
@@@ -1617,9 -1633,12 +1633,12 @@@ static blk_qc_t __process_bio(struct ma
                        goto out;
                }
  
-               tio = alloc_tio(&ci, ti, 0, GFP_NOIO);
                ci.bio = bio;
                ci.sector_count = bio_sectors(bio);
+               if (unlikely(__process_abnormal_io(&ci, ti, &error)))
+                       goto out;
+               tio = alloc_tio(&ci, ti, 0, GFP_NOIO);
                ret = __clone_and_map_simple_bio(&ci, tio, NULL);
        }
  out:
@@@ -1848,7 -1867,7 +1867,7 @@@ static struct mapped_device *alloc_dev(
        INIT_LIST_HEAD(&md->table_devices);
        spin_lock_init(&md->uevent_lock);
  
 -      md->queue = blk_alloc_queue_node(GFP_KERNEL, numa_node_id);
 +      md->queue = blk_alloc_queue_node(GFP_KERNEL, numa_node_id, NULL);
        if (!md->queue)
                goto bad;
        md->queue->queuedata = md;
@@@ -3015,20 -3034,19 +3034,19 @@@ static int dm_pr_reserve(struct block_d
  {
        struct mapped_device *md = bdev->bd_disk->private_data;
        const struct pr_ops *ops;
-       fmode_t mode;
-       int r;
+       int r, srcu_idx;
  
-       r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
+       r = dm_prepare_ioctl(md, &srcu_idx, &bdev);
        if (r < 0)
-               return r;
+               goto out;
  
        ops = bdev->bd_disk->fops->pr_ops;
        if (ops && ops->pr_reserve)
                r = ops->pr_reserve(bdev, key, type, flags);
        else
                r = -EOPNOTSUPP;
-       blkdev_put(bdev, mode);
+ out:
+       dm_unprepare_ioctl(md, srcu_idx);
        return r;
  }
  
@@@ -3036,20 -3054,19 +3054,19 @@@ static int dm_pr_release(struct block_d
  {
        struct mapped_device *md = bdev->bd_disk->private_data;
        const struct pr_ops *ops;
-       fmode_t mode;
-       int r;
+       int r, srcu_idx;
  
-       r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
+       r = dm_prepare_ioctl(md, &srcu_idx, &bdev);
        if (r < 0)
-               return r;
+               goto out;
  
        ops = bdev->bd_disk->fops->pr_ops;
        if (ops && ops->pr_release)
                r = ops->pr_release(bdev, key, type);
        else
                r = -EOPNOTSUPP;
-       blkdev_put(bdev, mode);
+ out:
+       dm_unprepare_ioctl(md, srcu_idx);
        return r;
  }
  
@@@ -3058,20 -3075,19 +3075,19 @@@ static int dm_pr_preempt(struct block_d
  {
        struct mapped_device *md = bdev->bd_disk->private_data;
        const struct pr_ops *ops;
-       fmode_t mode;
-       int r;
+       int r, srcu_idx;
  
-       r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
+       r = dm_prepare_ioctl(md, &srcu_idx, &bdev);
        if (r < 0)
-               return r;
+               goto out;
  
        ops = bdev->bd_disk->fops->pr_ops;
        if (ops && ops->pr_preempt)
                r = ops->pr_preempt(bdev, old_key, new_key, type, abort);
        else
                r = -EOPNOTSUPP;
-       blkdev_put(bdev, mode);
+ out:
+       dm_unprepare_ioctl(md, srcu_idx);
        return r;
  }
  
@@@ -3079,20 -3095,19 +3095,19 @@@ static int dm_pr_clear(struct block_dev
  {
        struct mapped_device *md = bdev->bd_disk->private_data;
        const struct pr_ops *ops;
-       fmode_t mode;
-       int r;
+       int r, srcu_idx;
  
-       r = dm_get_bdev_for_ioctl(md, &bdev, &mode);
+       r = dm_prepare_ioctl(md, &srcu_idx, &bdev);
        if (r < 0)
-               return r;
+               goto out;
  
        ops = bdev->bd_disk->fops->pr_ops;
        if (ops && ops->pr_clear)
                r = ops->pr_clear(bdev, key);
        else
                r = -EOPNOTSUPP;
-       blkdev_put(bdev, mode);
+ out:
+       dm_unprepare_ioctl(md, srcu_idx);
        return r;
  }
  
@@@ -87,10 -87,10 +87,10 @@@ typedef void (*dm_resume_fn) (struct dm
  typedef void (*dm_status_fn) (struct dm_target *ti, status_type_t status_type,
                              unsigned status_flags, char *result, unsigned maxlen);
  
- typedef int (*dm_message_fn) (struct dm_target *ti, unsigned argc, char **argv);
+ typedef int (*dm_message_fn) (struct dm_target *ti, unsigned argc, char **argv,
+                             char *result, unsigned maxlen);
  
- typedef int (*dm_prepare_ioctl_fn) (struct dm_target *ti,
-                           struct block_device **bdev, fmode_t *mode);
+ typedef int (*dm_prepare_ioctl_fn) (struct dm_target *ti, struct block_device **bdev);
  
  /*
   * These iteration functions are typically used to check (and combine)
@@@ -267,6 -267,12 +267,12 @@@ struct dm_target 
        unsigned num_discard_bios;
  
        /*
+        * The number of secure erase bios that will be submitted to the target.
+        * The bio number can be accessed with dm_bio_get_target_bio_nr.
+        */
+       unsigned num_secure_erase_bios;
+       /*
         * The number of WRITE SAME bios that will be submitted to the target.
         * The bio number can be accessed with dm_bio_get_target_bio_nr.
         */
@@@ -542,6 -548,8 +548,6 @@@ do {                                                                       
  #define DMEMIT(x...) sz += ((sz >= maxlen) ? \
                          0 : scnprintf(result + sz, maxlen - sz, x))
  
 -#define SECTOR_SHIFT 9
 -
  /*
   * Definitions of return values from target end_io function.
   */