]> Git Repo - linux.git/commitdiff
Merge tag 'for-5.14/dm-changes' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <[email protected]>
Thu, 1 Jul 2021 01:19:39 +0000 (18:19 -0700)
committerLinus Torvalds <[email protected]>
Thu, 1 Jul 2021 01:19:39 +0000 (18:19 -0700)
Pull device mapper updates from Mike Snitzer:

 - Various DM persistent-data library improvements and fixes that
   benefit both the DM thinp and cache targets.

 - A few small DM kcopyd efficiency improvements.

 - Significant zoned related block core, DM core and DM zoned target
   changes that culminate with adding zoned append emulation (which is
   required to properly fix DM crypt's zoned support).

 - Various DM writecache target changes that improve efficiency. Adds an
   optional "metadata_only" feature that only promotes bios flagged with
   REQ_META. But the most significant improvement is writecache's
   ability to pause writeback, for a confiurable time, if/when the
   working set is larger than the cache (and the cache is full) -- this
   ensures performance is no worse than the slower origin device.

* tag 'for-5.14/dm-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm: (35 commits)
  dm writecache: make writeback pause configurable
  dm writecache: pause writeback if cache full and origin being written directly
  dm io tracker: factor out IO tracker
  dm btree remove: assign new_root only when removal succeeds
  dm zone: fix dm_revalidate_zones() memory allocation
  dm ps io affinity: remove redundant continue statement
  dm writecache: add optional "metadata_only" parameter
  dm writecache: add "cleaner" and "max_age" to Documentation
  dm writecache: write at least 4k when committing
  dm writecache: flush origin device when writing and cache is full
  dm writecache: have ssd writeback wait if the kcopyd workqueue is busy
  dm writecache: use list_move instead of list_del/list_add in writecache_writeback()
  dm writecache: commit just one block, not a full page
  dm writecache: remove unused gfp_t argument from wc_add_block()
  dm crypt: Fix zoned block device support
  dm: introduce zone append emulation
  dm: rearrange core declarations for extended use from dm-zone.c
  block: introduce BIO_ZONE_WRITE_LOCKED bio flag
  block: introduce bio zone helpers
  block: improve handling of all zones reset operation
  ...

1  2 
drivers/md/dm.c
include/linux/blk_types.h
include/linux/blkdev.h

diff --combined drivers/md/dm.c
index a57aba553ebb2e1fd3b727bbaace96c2757c36c7,420a12b42708858bd5aeb70766ab50899e5c8bf4..2c5f9e58521179af3bf5ed2dd9ed0940cb2d0cc4
@@@ -74,38 -74,6 +74,6 @@@ struct clone_info 
        unsigned sector_count;
  };
  
- /*
-  * One of these is allocated per clone bio.
-  */
- #define DM_TIO_MAGIC 7282014
- struct dm_target_io {
-       unsigned magic;
-       struct dm_io *io;
-       struct dm_target *ti;
-       unsigned target_bio_nr;
-       unsigned *len_ptr;
-       bool inside_dm_io;
-       struct bio clone;
- };
- /*
-  * One of these is allocated per original bio.
-  * It contains the first clone used for that original.
-  */
- #define DM_IO_MAGIC 5191977
- struct dm_io {
-       unsigned magic;
-       struct mapped_device *md;
-       blk_status_t status;
-       atomic_t io_count;
-       struct bio *orig_bio;
-       unsigned long start_time;
-       spinlock_t endio_lock;
-       struct dm_stats_aux stats_aux;
-       /* last member of dm_target_io is 'struct bio' */
-       struct dm_target_io tio;
- };
  #define DM_TARGET_IO_BIO_OFFSET (offsetof(struct dm_target_io, clone))
  #define DM_IO_BIO_OFFSET \
        (offsetof(struct dm_target_io, clone) + offsetof(struct dm_io, tio))
@@@ -137,19 -105,6 +105,6 @@@ EXPORT_SYMBOL_GPL(dm_bio_get_target_bio
  
  #define MINOR_ALLOCED ((void *)-1)
  
- /*
-  * Bits for the md->flags field.
-  */
- #define DMF_BLOCK_IO_FOR_SUSPEND 0
- #define DMF_SUSPENDED 1
- #define DMF_FROZEN 2
- #define DMF_FREEING 3
- #define DMF_DELETING 4
- #define DMF_NOFLUSH_SUSPENDING 5
- #define DMF_DEFERRED_REMOVE 6
- #define DMF_SUSPENDED_INTERNALLY 7
- #define DMF_POST_SUSPENDING 8
  #define DM_NUMA_NODE NUMA_NO_NODE
  static int dm_numa_node = DM_NUMA_NODE;
  
@@@ -444,84 -399,6 +399,6 @@@ static int dm_blk_getgeo(struct block_d
        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,
-               unsigned int nr_zones, report_zones_cb cb, void *data)
- {
-       struct mapped_device *md = disk->private_data;
-       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;
-       map = dm_get_live_table(md, &srcu_idx);
-       if (!map) {
-               ret = -EIO;
-               goto out;
-       }
-       do {
-               struct dm_target *tgt;
-               tgt = dm_table_find_target(map, args.next_sector);
-               if (WARN_ON_ONCE(!tgt->type->report_zones)) {
-                       ret = -EIO;
-                       goto out;
-               }
-               args.tgt = tgt;
-               ret = tgt->type->report_zones(tgt, &args,
-                                             nr_zones - args.zone_idx);
-               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
- #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)
  {
@@@ -903,7 -780,7 +780,7 @@@ static int __noflush_suspending(struct 
   * Decrements the number of outstanding ios that a bio has been
   * cloned into, completing the original io if necc.
   */
static void dec_pending(struct dm_io *io, blk_status_t error)
void dm_io_dec_pending(struct dm_io *io, blk_status_t error)
  {
        unsigned long flags;
        blk_status_t io_error;
        }
  
        if (atomic_dec_and_test(&io->io_count)) {
+               bio = io->orig_bio;
                if (io->status == BLK_STS_DM_REQUEUE) {
                        /*
                         * Target requested pushing back the I/O.
                         */
                        spin_lock_irqsave(&md->deferred_lock, flags);
-                       if (__noflush_suspending(md))
+                       if (__noflush_suspending(md) &&
+                           !WARN_ON_ONCE(dm_is_zone_write(md, bio))) {
                                /* NOTE early return due to BLK_STS_DM_REQUEUE below */
-                               bio_list_add_head(&md->deferred, io->orig_bio);
-                       else
-                               /* noflush suspend was interrupted. */
+                               bio_list_add_head(&md->deferred, bio);
+                       } else {
+                               /*
+                                * noflush suspend was interrupted or this is
+                                * a write to a zoned target.
+                                */
                                io->status = BLK_STS_IOERR;
+                       }
                        spin_unlock_irqrestore(&md->deferred_lock, flags);
                }
  
                io_error = io->status;
-               bio = io->orig_bio;
                end_io_acct(io);
                free_io(md, io);
  
@@@ -994,7 -876,6 +876,6 @@@ static void clone_endio(struct bio *bio
        struct dm_io *io = tio->io;
        struct mapped_device *md = tio->io->md;
        dm_endio_fn endio = tio->ti->type->end_io;
-       struct bio *orig_bio = io->orig_bio;
        struct request_queue *q = bio->bi_bdev->bd_disk->queue;
  
        if (unlikely(error == BLK_STS_TARGET)) {
                        disable_write_zeroes(md);
        }
  
-       /*
-        * For zone-append bios get offset in zone of the written
-        * sector and add that to the original bio sector pos.
-        */
-       if (bio_op(orig_bio) == REQ_OP_ZONE_APPEND) {
-               sector_t written_sector = bio->bi_iter.bi_sector;
-               struct request_queue *q = orig_bio->bi_bdev->bd_disk->queue;
-               u64 mask = (u64)blk_queue_zone_sectors(q) - 1;
-               orig_bio->bi_iter.bi_sector += written_sector & mask;
-       }
+       if (blk_queue_is_zoned(q))
+               dm_zone_endio(io, bio);
  
        if (endio) {
                int r = endio(tio->ti, bio, &error);
                switch (r) {
                case DM_ENDIO_REQUEUE:
-                       error = BLK_STS_DM_REQUEUE;
+                       /*
+                        * Requeuing writes to a sequential zone of a zoned
+                        * target will break the sequential write pattern:
+                        * fail such IO.
+                        */
+                       if (WARN_ON_ONCE(dm_is_zone_write(md, bio)))
+                               error = BLK_STS_IOERR;
+                       else
+                               error = BLK_STS_DM_REQUEUE;
                        fallthrough;
                case DM_ENDIO_DONE:
                        break;
        }
  
        free_tio(tio);
-       dec_pending(io, error);
+       dm_io_dec_pending(io, error);
  }
  
  /*
@@@ -1237,8 -1117,8 +1117,8 @@@ static int dm_dax_zero_page_range(struc
  
  /*
   * A target may call dm_accept_partial_bio only from the map routine.  It is
-  * 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.
+  * allowed for all bio types except REQ_PREFLUSH, REQ_OP_ZONE_* zone management
+  * operations and REQ_OP_ZONE_APPEND (zone append writes).
   *
   * 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
@@@ -1268,9 -1148,13 +1148,13 @@@ void dm_accept_partial_bio(struct bio *
  {
        struct dm_target_io *tio = container_of(bio, struct dm_target_io, clone);
        unsigned bi_size = bio->bi_iter.bi_size >> SECTOR_SHIFT;
        BUG_ON(bio->bi_opf & REQ_PREFLUSH);
+       BUG_ON(op_is_zone_mgmt(bio_op(bio)));
+       BUG_ON(bio_op(bio) == REQ_OP_ZONE_APPEND);
        BUG_ON(bi_size > *tio->len_ptr);
        BUG_ON(n_sectors > bi_size);
        *tio->len_ptr -= bi_size - n_sectors;
        bio->bi_iter.bi_size = n_sectors << SECTOR_SHIFT;
  }
@@@ -1308,7 -1192,7 +1192,7 @@@ static blk_qc_t __map_bio(struct dm_tar
         * anything, the target has assumed ownership of
         * this io.
         */
-       atomic_inc(&io->io_count);
+       dm_io_inc_pending(io);
        sector = clone->bi_iter.bi_sector;
  
        if (unlikely(swap_bios_limit(ti, clone))) {
                down(&md->swap_bios_semaphore);
        }
  
-       r = ti->type->map(ti, clone);
+       /*
+        * Check if the IO needs a special mapping due to zone append emulation
+        * on zoned target. In this case, dm_zone_map_bio() calls the target
+        * map operation.
+        */
+       if (dm_emulate_zone_append(io->md))
+               r = dm_zone_map_bio(tio);
+       else
+               r = ti->type->map(ti, clone);
        switch (r) {
        case DM_MAPIO_SUBMITTED:
                break;
                        up(&md->swap_bios_semaphore);
                }
                free_tio(tio);
-               dec_pending(io, BLK_STS_IOERR);
+               dm_io_dec_pending(io, BLK_STS_IOERR);
                break;
        case DM_MAPIO_REQUEUE:
                if (unlikely(swap_bios_limit(ti, clone))) {
                        up(&md->swap_bios_semaphore);
                }
                free_tio(tio);
-               dec_pending(io, BLK_STS_DM_REQUEUE);
+               dm_io_dec_pending(io, BLK_STS_DM_REQUEUE);
                break;
        default:
                DMWARN("unimplemented target map return value: %d", r);
@@@ -1631,7 -1524,7 +1524,7 @@@ static blk_qc_t __split_and_process_bio
  
        if (bio->bi_opf & REQ_PREFLUSH) {
                error = __send_empty_flush(&ci);
-               /* dec_pending submits any data associated with flush */
+               /* dm_io_dec_pending submits any data associated with flush */
        } else if (op_is_zone_mgmt(bio_op(bio))) {
                ci.bio = bio;
                ci.sector_count = 0;
        }
  
        /* drop the extra reference count */
-       dec_pending(ci.io, errno_to_blk_status(error));
+       dm_io_dec_pending(ci.io, errno_to_blk_status(error));
        return ret;
  }
  
@@@ -1801,13 -1694,13 +1694,13 @@@ static void cleanup_mapped_device(struc
                md->disk->private_data = NULL;
                spin_unlock(&_minor_lock);
                del_gendisk(md->disk);
 -              put_disk(md->disk);
        }
  
 -      if (md->queue) {
 +      if (md->queue)
                dm_queue_destroy_keyslot_manager(md->queue);
 -              blk_cleanup_queue(md->queue);
 -      }
 +
 +      if (md->disk)
 +              blk_cleanup_disk(md->disk);
  
        cleanup_srcu_struct(&md->io_barrier);
  
        mutex_destroy(&md->swap_bios_lock);
  
        dm_mq_cleanup_mapped_device(md);
+       dm_cleanup_zoned_dev(md);
  }
  
  /*
@@@ -1869,10 -1763,13 +1763,10 @@@ static struct mapped_device *alloc_dev(
         * established. If request-based table is loaded: blk-mq will
         * override accordingly.
         */
 -      md->queue = blk_alloc_queue(numa_node_id);
 -      if (!md->queue)
 -              goto bad;
 -
 -      md->disk = alloc_disk_node(1, md->numa_node_id);
 +      md->disk = blk_alloc_disk(md->numa_node_id);
        if (!md->disk)
                goto bad;
 +      md->queue = md->disk->queue;
  
        init_waitqueue_head(&md->wait);
        INIT_WORK(&md->work, dm_wq_work);
  
        md->disk->major = _major;
        md->disk->first_minor = minor;
 +      md->disk->minors = 1;
        md->disk->fops = &dm_blk_dops;
        md->disk->queue = md->queue;
        md->disk->private_data = md;
@@@ -2060,11 -1956,16 +1954,16 @@@ static struct dm_table *__bind(struct m
                goto out;
        }
  
+       ret = dm_table_set_restrictions(t, q, limits);
+       if (ret) {
+               old_map = ERR_PTR(ret);
+               goto out;
+       }
        old_map = rcu_dereference_protected(md->map, lockdep_is_held(&md->suspend_lock));
        rcu_assign_pointer(md->map, (void *)t);
        md->immutable_target_type = dm_table_get_immutable_target_type(t);
  
-       dm_table_set_restrictions(t, q, limits);
        if (old_map)
                dm_sync_table(md);
  
@@@ -2183,7 -2084,10 +2082,10 @@@ int dm_setup_md_queue(struct mapped_dev
                DMERR("Cannot calculate initial queue limits");
                return r;
        }
-       dm_table_set_restrictions(t, md->queue, &limits);
+       r = dm_table_set_restrictions(t, md->queue, &limits);
+       if (r)
+               return r;
        blk_register_queue(md->disk);
  
        return 0;
@@@ -2326,7 -2230,7 +2228,7 @@@ static bool md_in_flight_bios(struct ma
        return sum != 0;
  }
  
 -static int dm_wait_for_bios_completion(struct mapped_device *md, long task_state)
 +static int dm_wait_for_bios_completion(struct mapped_device *md, unsigned int task_state)
  {
        int r = 0;
        DEFINE_WAIT(wait);
        return r;
  }
  
 -static int dm_wait_for_completion(struct mapped_device *md, long task_state)
 +static int dm_wait_for_completion(struct mapped_device *md, unsigned int task_state)
  {
        int r = 0;
  
@@@ -2476,7 -2380,7 +2378,7 @@@ static void unlock_fs(struct mapped_dev
   * are being added to md->deferred list.
   */
  static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
 -                      unsigned suspend_flags, long task_state,
 +                      unsigned suspend_flags, unsigned int task_state,
                        int dmf_suspended_flag)
  {
        bool do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG;
index fd3860d18d7ed7da0fd9508a49c6f87d5f85cefb,e5cf12f102a217e4fcd9fc81a9452e1941021745..b05f2fd495fcd1a7f4bbcd03d6a8dfed531316c7
@@@ -29,6 -29,7 +29,6 @@@ struct block_device 
        int                     bd_openers;
        struct inode *          bd_inode;       /* will die */
        struct super_block *    bd_super;
 -      struct mutex            bd_mutex;       /* open/close mutex */
        void *                  bd_claiming;
        struct device           bd_device;
        void *                  bd_holder;
@@@ -39,6 -40,9 +39,6 @@@
  #endif
        struct kobject          *bd_holder_dir;
        u8                      bd_partno;
 -      /* number of times partitions within this device have been opened. */
 -      unsigned                bd_part_count;
 -
        spinlock_t              bd_size_lock; /* for bd_inode->i_size updates */
        struct gendisk *        bd_disk;
        struct backing_dev_info *bd_bdi;
@@@ -300,6 -304,7 +300,7 @@@ enum 
        BIO_CGROUP_ACCT,        /* has been accounted to a cgroup */
        BIO_TRACKED,            /* set if bio goes through the rq_qos path */
        BIO_REMAPPED,
+       BIO_ZONE_WRITE_LOCKED,  /* Owns a zoned device zone write lock */
        BIO_FLAG_LAST
  };
  
diff --combined include/linux/blkdev.h
index d66d0da7252991ab731130d395e18b6bd36710ec,2db0f376f5d9fc13122f3c26f2b19b09932a21c6..103acc5228e761982ffe298b85dc236667a6b0bd
@@@ -25,7 -25,6 +25,7 @@@
  #include <linux/scatterlist.h>
  #include <linux/blkzoned.h>
  #include <linux/pm.h>
 +#include <linux/sbitmap.h>
  
  struct module;
  struct scsi_ioctl_command;
@@@ -494,9 -493,6 +494,9 @@@ struct request_queue 
  
        atomic_t                nr_active_requests_shared_sbitmap;
  
 +      struct sbitmap_queue    sched_bitmap_tags;
 +      struct sbitmap_queue    sched_breserved_tags;
 +
        struct list_head        icq_list;
  #ifdef CONFIG_BLK_CGROUP
        DECLARE_BITMAP          (blkcg_pols, BLKCG_MAX_POLS);
@@@ -1012,6 -1008,18 +1012,18 @@@ static inline unsigned int blk_rq_stats
  /* Helper to convert BLK_ZONE_ZONE_XXX to its string format XXX */
  const char *blk_zone_cond_str(enum blk_zone_cond zone_cond);
  
+ static inline unsigned int bio_zone_no(struct bio *bio)
+ {
+       return blk_queue_zone_no(bdev_get_queue(bio->bi_bdev),
+                                bio->bi_iter.bi_sector);
+ }
+ static inline unsigned int bio_zone_is_seq(struct bio *bio)
+ {
+       return blk_queue_zone_is_seq(bdev_get_queue(bio->bi_bdev),
+                                    bio->bi_iter.bi_sector);
+ }
  static inline unsigned int blk_rq_zone_no(struct request *rq)
  {
        return blk_queue_zone_no(rq->q, blk_rq_pos(rq));
@@@ -1213,6 -1221,7 +1225,6 @@@ static inline int blk_rq_map_sg(struct 
  extern void blk_dump_rq_flags(struct request *, char *);
  
  bool __must_check blk_get_queue(struct request_queue *);
 -struct request_queue *blk_alloc_queue(int node_id);
  extern void blk_put_queue(struct request_queue *);
  extern void blk_set_queue_dying(struct request_queue *);
  
This page took 0.097277 seconds and 4 git commands to generate.