On Wed, Apr 6, 2022 at 8:07 AM Christoph Hellwig <hch@xxxxxx> wrote: > > Add a helper to query the number of sectors support per each discard bio > based on the block device and use this helper to stop various places from > poking into the request_queue to see if discard is supported and if so how > much. This mirrors what is done e.g. for write zeroes as well. > > Signed-off-by: Christoph Hellwig <hch@xxxxxx> > --- > block/blk-core.c | 2 +- > block/blk-lib.c | 2 +- > block/ioctl.c | 3 +-- > drivers/block/drbd/drbd_main.c | 2 +- > drivers/block/drbd/drbd_nl.c | 12 +++++++----- > drivers/block/drbd/drbd_receiver.c | 5 ++--- > drivers/block/loop.c | 9 +++------ > drivers/block/rnbd/rnbd-srv-dev.h | 6 +----- > drivers/block/xen-blkback/xenbus.c | 2 +- > drivers/md/bcache/request.c | 4 ++-- > drivers/md/bcache/super.c | 2 +- > drivers/md/bcache/sysfs.c | 2 +- > drivers/md/dm-cache-target.c | 9 +-------- > drivers/md/dm-clone-target.c | 9 +-------- > drivers/md/dm-io.c | 2 +- > drivers/md/dm-log-writes.c | 3 +-- > drivers/md/dm-raid.c | 9 ++------- > drivers/md/dm-table.c | 4 +--- > drivers/md/dm-thin.c | 9 +-------- > drivers/md/dm.c | 2 +- > drivers/md/md-linear.c | 4 ++-- > drivers/md/raid0.c | 2 +- > drivers/md/raid1.c | 6 +++--- > drivers/md/raid10.c | 8 ++++---- > drivers/md/raid5-cache.c | 2 +- > drivers/target/target_core_device.c | 8 +++----- > fs/btrfs/extent-tree.c | 4 ++-- > fs/btrfs/ioctl.c | 2 +- > fs/exfat/file.c | 2 +- > fs/exfat/super.c | 10 +++------- > fs/ext4/ioctl.c | 10 +++------- > fs/ext4/super.c | 10 +++------- > fs/f2fs/f2fs.h | 3 +-- > fs/f2fs/segment.c | 6 ++---- > fs/fat/file.c | 2 +- > fs/fat/inode.c | 10 +++------- > fs/gfs2/rgrp.c | 2 +- > fs/jbd2/journal.c | 7 ++----- > fs/jfs/ioctl.c | 2 +- > fs/jfs/super.c | 8 ++------ > fs/nilfs2/ioctl.c | 2 +- > fs/ntfs3/file.c | 2 +- > fs/ntfs3/super.c | 2 +- > fs/ocfs2/ioctl.c | 2 +- > fs/xfs/xfs_discard.c | 2 +- > fs/xfs/xfs_super.c | 12 ++++-------- > include/linux/blkdev.h | 5 +++++ > mm/swapfile.c | 17 ++--------------- > 48 files changed, 87 insertions(+), 163 deletions(-) > > diff --git a/block/blk-core.c b/block/blk-core.c > index 937bb6b863317..b5c3a8049134c 100644 > --- a/block/blk-core.c > +++ b/block/blk-core.c > @@ -820,7 +820,7 @@ void submit_bio_noacct(struct bio *bio) > > switch (bio_op(bio)) { > case REQ_OP_DISCARD: > - if (!blk_queue_discard(q)) > + if (!bdev_max_discard_sectors(bdev)) > goto not_supported; > break; > case REQ_OP_SECURE_ERASE: > diff --git a/block/blk-lib.c b/block/blk-lib.c > index 2ae32a722851c..8b4b66d3a9bfc 100644 > --- a/block/blk-lib.c > +++ b/block/blk-lib.c > @@ -53,7 +53,7 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, > return -EOPNOTSUPP; > op = REQ_OP_SECURE_ERASE; > } else { > - if (!blk_queue_discard(q)) > + if (!bdev_max_discard_sectors(bdev)) > return -EOPNOTSUPP; > op = REQ_OP_DISCARD; > } > diff --git a/block/ioctl.c b/block/ioctl.c > index ad3771b268b81..c2cd3ba5290ce 100644 > --- a/block/ioctl.c > +++ b/block/ioctl.c > @@ -87,14 +87,13 @@ static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode, > { > uint64_t range[2]; > uint64_t start, len; > - struct request_queue *q = bdev_get_queue(bdev); > struct inode *inode = bdev->bd_inode; > int err; > > if (!(mode & FMODE_WRITE)) > return -EBADF; > > - if (!blk_queue_discard(q)) > + if (!bdev_max_discard_sectors(bdev)) > return -EOPNOTSUPP; > > if (copy_from_user(range, (void __user *)arg, sizeof(range))) > diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c > index 9d43aadde19ad..8fd89a1b0b7b3 100644 > --- a/drivers/block/drbd/drbd_main.c > +++ b/drivers/block/drbd/drbd_main.c > @@ -942,7 +942,7 @@ int drbd_send_sizes(struct drbd_peer_device *peer_device, int trigger_reply, enu > cpu_to_be32(bdev_alignment_offset(bdev)); > p->qlim->io_min = cpu_to_be32(bdev_io_min(bdev)); > p->qlim->io_opt = cpu_to_be32(bdev_io_opt(bdev)); > - p->qlim->discard_enabled = blk_queue_discard(q); > + p->qlim->discard_enabled = !!bdev_max_discard_sectors(bdev); > p->qlim->write_same_capable = 0; > put_ldev(device); > } else { > diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c > index 40bb0b356a6d6..8e28e0a8e5e41 100644 > --- a/drivers/block/drbd/drbd_nl.c > +++ b/drivers/block/drbd/drbd_nl.c > @@ -1210,7 +1210,7 @@ static void decide_on_discard_support(struct drbd_device *device, > first_peer_device(device)->connection; > struct request_queue *q = device->rq_queue; > > - if (bdev && !blk_queue_discard(bdev->backing_bdev->bd_disk->queue)) > + if (bdev && !bdev_max_discard_sectors(bdev->backing_bdev)) > goto not_supported; > > if (connection->cstate >= C_CONNECTED && > @@ -1439,14 +1439,15 @@ static bool write_ordering_changed(struct disk_conf *a, struct disk_conf *b) > static void sanitize_disk_conf(struct drbd_device *device, struct disk_conf *disk_conf, > struct drbd_backing_dev *nbc) > { > - struct request_queue * const q = nbc->backing_bdev->bd_disk->queue; > + struct block_device *bdev = nbc->backing_bdev; > + struct request_queue *q = bdev->bd_disk->queue; > > if (disk_conf->al_extents < DRBD_AL_EXTENTS_MIN) > disk_conf->al_extents = DRBD_AL_EXTENTS_MIN; > if (disk_conf->al_extents > drbd_al_extents_max(nbc)) > disk_conf->al_extents = drbd_al_extents_max(nbc); > > - if (!blk_queue_discard(q)) { > + if (!bdev_max_discard_sectors(bdev)) { > if (disk_conf->rs_discard_granularity) { > disk_conf->rs_discard_granularity = 0; /* disable feature */ > drbd_info(device, "rs_discard_granularity feature disabled\n"); > @@ -1455,6 +1456,7 @@ static void sanitize_disk_conf(struct drbd_device *device, struct disk_conf *dis > > if (disk_conf->rs_discard_granularity) { > int orig_value = disk_conf->rs_discard_granularity; > + sector_t discard_size = bdev_max_discard_sectors(bdev) << 9; > int remainder; > > if (q->limits.discard_granularity > disk_conf->rs_discard_granularity) > @@ -1463,8 +1465,8 @@ static void sanitize_disk_conf(struct drbd_device *device, struct disk_conf *dis > remainder = disk_conf->rs_discard_granularity % q->limits.discard_granularity; > disk_conf->rs_discard_granularity += remainder; > > - if (disk_conf->rs_discard_granularity > q->limits.max_discard_sectors << 9) > - disk_conf->rs_discard_granularity = q->limits.max_discard_sectors << 9; > + if (disk_conf->rs_discard_granularity > discard_size) > + disk_conf->rs_discard_granularity = discard_size; > > if (disk_conf->rs_discard_granularity != orig_value) > drbd_info(device, "rs_discard_granularity changed to %d\n", > diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c > index 08da922f81d1d..8a4a47da56fe9 100644 > --- a/drivers/block/drbd/drbd_receiver.c > +++ b/drivers/block/drbd/drbd_receiver.c > @@ -1524,7 +1524,7 @@ int drbd_issue_discard_or_zero_out(struct drbd_device *device, sector_t start, u > granularity = max(q->limits.discard_granularity >> 9, 1U); > alignment = (bdev_discard_alignment(bdev) >> 9) % granularity; > > - max_discard_sectors = min(q->limits.max_discard_sectors, (1U << 22)); > + max_discard_sectors = min(bdev_max_discard_sectors(bdev), (1U << 22)); > max_discard_sectors -= max_discard_sectors % granularity; > if (unlikely(!max_discard_sectors)) > goto zero_out; > @@ -1575,11 +1575,10 @@ int drbd_issue_discard_or_zero_out(struct drbd_device *device, sector_t start, u > > static bool can_do_reliable_discards(struct drbd_device *device) > { > - struct request_queue *q = bdev_get_queue(device->ldev->backing_bdev); > struct disk_conf *dc; > bool can_do; > > - if (!blk_queue_discard(q)) > + if (!bdev_max_discard_sectors(device->ldev->backing_bdev)) > return false; > > rcu_read_lock(); > diff --git a/drivers/block/loop.c b/drivers/block/loop.c > index 8d800d46e4985..4b919b75205a7 100644 > --- a/drivers/block/loop.c > +++ b/drivers/block/loop.c > @@ -314,15 +314,12 @@ static int lo_fallocate(struct loop_device *lo, struct request *rq, loff_t pos, > > mode |= FALLOC_FL_KEEP_SIZE; > > - if (!blk_queue_discard(lo->lo_queue)) { > - ret = -EOPNOTSUPP; > - goto out; > - } > + if (!bdev_max_discard_sectors(lo->lo_device)) > + return -EOPNOTSUPP; > > ret = file->f_op->fallocate(file, mode, pos, blk_rq_bytes(rq)); > if (unlikely(ret && ret != -EINVAL && ret != -EOPNOTSUPP)) > - ret = -EIO; > - out: > + return -EIO; > return ret; > } > > diff --git a/drivers/block/rnbd/rnbd-srv-dev.h b/drivers/block/rnbd/rnbd-srv-dev.h > index 2c3df02b5e8ec..1f7e1c8fd4d9b 100644 > --- a/drivers/block/rnbd/rnbd-srv-dev.h > +++ b/drivers/block/rnbd/rnbd-srv-dev.h > @@ -49,11 +49,7 @@ static inline int rnbd_dev_get_secure_discard(const struct rnbd_dev *dev) > > static inline int rnbd_dev_get_max_discard_sects(const struct rnbd_dev *dev) > { > - if (!blk_queue_discard(bdev_get_queue(dev->bdev))) > - return 0; > - > - return blk_queue_get_max_sectors(bdev_get_queue(dev->bdev), > - REQ_OP_DISCARD); > + return bdev_max_discard_sectors(dev->bdev); > } > > static inline int rnbd_dev_get_discard_granularity(const struct rnbd_dev *dev) > diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c > index 8b691fe50475f..83cd08041e6b3 100644 > --- a/drivers/block/xen-blkback/xenbus.c > +++ b/drivers/block/xen-blkback/xenbus.c > @@ -583,7 +583,7 @@ static void xen_blkbk_discard(struct xenbus_transaction xbt, struct backend_info > if (!xenbus_read_unsigned(dev->nodename, "discard-enable", 1)) > return; > > - if (blk_queue_discard(q)) { > + if (bdev_max_discard_sectors(bdev)) { > err = xenbus_printf(xbt, dev->nodename, > "discard-granularity", "%u", > q->limits.discard_granularity); > diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c > index fdd0194f84dd0..e27f67f06a428 100644 > --- a/drivers/md/bcache/request.c > +++ b/drivers/md/bcache/request.c > @@ -1005,7 +1005,7 @@ static void cached_dev_write(struct cached_dev *dc, struct search *s) > bio_get(s->iop.bio); > > if (bio_op(bio) == REQ_OP_DISCARD && > - !blk_queue_discard(bdev_get_queue(dc->bdev))) > + !bdev_max_discard_sectors(dc->bdev)) > goto insert_data; > > /* I/O request sent to backing device */ > @@ -1115,7 +1115,7 @@ static void detached_dev_do_request(struct bcache_device *d, struct bio *bio, > bio->bi_private = ddip; > > if ((bio_op(bio) == REQ_OP_DISCARD) && > - !blk_queue_discard(bdev_get_queue(dc->bdev))) > + !bdev_max_discard_sectors(dc->bdev)) > bio->bi_end_io(bio); > else > submit_bio_noacct(bio); > diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c > index bf3de149d3c9f..296f200b2e208 100644 > --- a/drivers/md/bcache/super.c > +++ b/drivers/md/bcache/super.c > @@ -2350,7 +2350,7 @@ static int register_cache(struct cache_sb *sb, struct cache_sb_disk *sb_disk, > ca->bdev->bd_holder = ca; > ca->sb_disk = sb_disk; > > - if (blk_queue_discard(bdev_get_queue(bdev))) > + if (bdev_max_discard_sectors((bdev))) > ca->discard = CACHE_DISCARD(&ca->sb); > > ret = cache_alloc(ca); > diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c > index d1029d71ff3bc..c6f677059214d 100644 > --- a/drivers/md/bcache/sysfs.c > +++ b/drivers/md/bcache/sysfs.c > @@ -1151,7 +1151,7 @@ STORE(__bch_cache) > if (attr == &sysfs_discard) { > bool v = strtoul_or_return(buf); > > - if (blk_queue_discard(bdev_get_queue(ca->bdev))) > + if (bdev_max_discard_sectors(ca->bdev)) > ca->discard = v; > > if (v != CACHE_DISCARD(&ca->sb)) { > diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c > index 780a61bc6cc03..28c5de8eca4a0 100644 > --- a/drivers/md/dm-cache-target.c > +++ b/drivers/md/dm-cache-target.c > @@ -3329,13 +3329,6 @@ static int cache_iterate_devices(struct dm_target *ti, > return r; > } > > -static bool origin_dev_supports_discard(struct block_device *origin_bdev) > -{ > - struct request_queue *q = bdev_get_queue(origin_bdev); > - > - return blk_queue_discard(q); > -} > - > /* > * If discard_passdown was enabled verify that the origin device > * supports discards. Disable discard_passdown if not. > @@ -3349,7 +3342,7 @@ static void disable_passdown_if_not_supported(struct cache *cache) > if (!cache->features.discard_passdown) > return; > > - if (!origin_dev_supports_discard(origin_bdev)) > + if (!bdev_max_discard_sectors(origin_bdev)) > reason = "discard unsupported"; > > else if (origin_limits->max_discard_sectors < cache->sectors_per_block) > diff --git a/drivers/md/dm-clone-target.c b/drivers/md/dm-clone-target.c > index 128316a73d016..811b0a5379d03 100644 > --- a/drivers/md/dm-clone-target.c > +++ b/drivers/md/dm-clone-target.c > @@ -2016,13 +2016,6 @@ static void clone_resume(struct dm_target *ti) > do_waker(&clone->waker.work); > } > > -static bool bdev_supports_discards(struct block_device *bdev) > -{ > - struct request_queue *q = bdev_get_queue(bdev); > - > - return (q && blk_queue_discard(q)); > -} > - > /* > * If discard_passdown was enabled verify that the destination device supports > * discards. Disable discard_passdown if not. > @@ -2036,7 +2029,7 @@ static void disable_passdown_if_not_supported(struct clone *clone) > if (!test_bit(DM_CLONE_DISCARD_PASSDOWN, &clone->flags)) > return; > > - if (!bdev_supports_discards(dest_dev)) > + if (!bdev_max_discard_sectors(dest_dev)) > reason = "discard unsupported"; > else if (dest_limits->max_discard_sectors < clone->region_size) > reason = "max discard sectors smaller than a region"; > diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c > index 5762366333a27..e4b95eaeec8c7 100644 > --- a/drivers/md/dm-io.c > +++ b/drivers/md/dm-io.c > @@ -311,7 +311,7 @@ static void do_region(int op, int op_flags, unsigned region, > * Reject unsupported discard and write same requests. > */ > if (op == REQ_OP_DISCARD) > - special_cmd_max_sectors = q->limits.max_discard_sectors; > + special_cmd_max_sectors = bdev_max_discard_sectors(where->bdev); > else if (op == REQ_OP_WRITE_ZEROES) > special_cmd_max_sectors = q->limits.max_write_zeroes_sectors; > if ((op == REQ_OP_DISCARD || op == REQ_OP_WRITE_ZEROES) && > diff --git a/drivers/md/dm-log-writes.c b/drivers/md/dm-log-writes.c > index c9d036d6bb2ee..e194226c89e54 100644 > --- a/drivers/md/dm-log-writes.c > +++ b/drivers/md/dm-log-writes.c > @@ -866,9 +866,8 @@ static int log_writes_message(struct dm_target *ti, unsigned argc, char **argv, > static void log_writes_io_hints(struct dm_target *ti, struct queue_limits *limits) > { > struct log_writes_c *lc = ti->private; > - struct request_queue *q = bdev_get_queue(lc->dev->bdev); > > - if (!q || !blk_queue_discard(q)) { > + if (!bdev_max_discard_sectors(lc->dev->bdev)) { > lc->device_supports_discard = false; > limits->discard_granularity = lc->sectorsize; > limits->max_discard_sectors = (UINT_MAX >> SECTOR_SHIFT); > diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c > index 2b26435a6946e..9526ccbedafba 100644 > --- a/drivers/md/dm-raid.c > +++ b/drivers/md/dm-raid.c > @@ -2963,13 +2963,8 @@ static void configure_discard_support(struct raid_set *rs) > raid456 = rs_is_raid456(rs); > > for (i = 0; i < rs->raid_disks; i++) { > - struct request_queue *q; > - > - if (!rs->dev[i].rdev.bdev) > - continue; > - > - q = bdev_get_queue(rs->dev[i].rdev.bdev); > - if (!q || !blk_queue_discard(q)) > + if (!rs->dev[i].rdev.bdev || > + !bdev_max_discard_sectors(rs->dev[i].rdev.bdev)) > return; > > if (raid456) { > diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c > index d46839faa0ca5..4297c38328a9b 100644 > --- a/drivers/md/dm-table.c > +++ b/drivers/md/dm-table.c > @@ -1888,9 +1888,7 @@ static bool dm_table_supports_nowait(struct dm_table *t) > static int device_not_discard_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 !blk_queue_discard(q); > + return !bdev_max_discard_sectors(dev->bdev); > } > > static bool dm_table_supports_discards(struct dm_table *t) > diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c > index 4d25d0e270313..cd333a3e4c33b 100644 > --- a/drivers/md/dm-thin.c > +++ b/drivers/md/dm-thin.c > @@ -2802,13 +2802,6 @@ static void requeue_bios(struct pool *pool) > /*---------------------------------------------------------------- > * Binding of control targets to a pool object > *--------------------------------------------------------------*/ > -static bool data_dev_supports_discard(struct pool_c *pt) > -{ > - struct request_queue *q = bdev_get_queue(pt->data_dev->bdev); > - > - return blk_queue_discard(q); > -} > - > static bool is_factor(sector_t block_size, uint32_t n) > { > return !sector_div(block_size, n); > @@ -2828,7 +2821,7 @@ static void disable_passdown_if_not_supported(struct pool_c *pt) > if (!pt->adjusted_pf.discard_passdown) > return; > > - if (!data_dev_supports_discard(pt)) > + if (!bdev_max_discard_sectors(pt->data_dev->bdev)) > reason = "discard unsupported"; > > else if (data_limits->max_discard_sectors < pool->sectors_per_block) > diff --git a/drivers/md/dm.c b/drivers/md/dm.c > index 3c5fad7c4ee68..ba75933cc22ca 100644 > --- a/drivers/md/dm.c > +++ b/drivers/md/dm.c > @@ -982,7 +982,7 @@ static void clone_endio(struct bio *bio) > > if (unlikely(error == BLK_STS_TARGET)) { > if (bio_op(bio) == REQ_OP_DISCARD && > - !q->limits.max_discard_sectors) > + !bdev_max_discard_sectors(bio->bi_bdev)) > disable_discard(md); > else if (bio_op(bio) == REQ_OP_WRITE_ZEROES && > !q->limits.max_write_zeroes_sectors) > diff --git a/drivers/md/md-linear.c b/drivers/md/md-linear.c > index 0f55b079371b1..4dd5afff72844 100644 > --- a/drivers/md/md-linear.c > +++ b/drivers/md/md-linear.c > @@ -97,7 +97,7 @@ static struct linear_conf *linear_conf(struct mddev *mddev, int raid_disks) > conf->array_sectors += rdev->sectors; > cnt++; > > - if (blk_queue_discard(bdev_get_queue(rdev->bdev))) > + if (bdev_max_discard_sectors(rdev->bdev)) > discard_supported = true; > } > if (cnt != raid_disks) { > @@ -252,7 +252,7 @@ static bool linear_make_request(struct mddev *mddev, struct bio *bio) > start_sector + data_offset; > > if (unlikely((bio_op(bio) == REQ_OP_DISCARD) && > - !blk_queue_discard(bio->bi_bdev->bd_disk->queue))) { > + !bdev_max_discard_sectors(bio->bi_bdev))) { > /* Just ignore it */ > bio_endio(bio); > } else { > diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c > index b21e101183f44..02ac3ab213c72 100644 > --- a/drivers/md/raid0.c > +++ b/drivers/md/raid0.c > @@ -412,7 +412,7 @@ static int raid0_run(struct mddev *mddev) > rdev_for_each(rdev, mddev) { > disk_stack_limits(mddev->gendisk, rdev->bdev, > rdev->data_offset << 9); > - if (blk_queue_discard(bdev_get_queue(rdev->bdev))) > + if (bdev_max_discard_sectors(rdev->bdev)) > discard_supported = true; > } > if (!discard_supported) > diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c > index d81b896855f9f..39b9cb4d54ee0 100644 > --- a/drivers/md/raid1.c > +++ b/drivers/md/raid1.c > @@ -802,7 +802,7 @@ static void flush_bio_list(struct r1conf *conf, struct bio *bio) > if (test_bit(Faulty, &rdev->flags)) { > bio_io_error(bio); > } else if (unlikely((bio_op(bio) == REQ_OP_DISCARD) && > - !blk_queue_discard(bio->bi_bdev->bd_disk->queue))) > + !bdev_max_discard_sectors(bio->bi_bdev))) > /* Just ignore it */ > bio_endio(bio); > else > @@ -1826,7 +1826,7 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev) > break; > } > } > - if (mddev->queue && blk_queue_discard(bdev_get_queue(rdev->bdev))) > + if (mddev->queue && bdev_max_discard_sectors(rdev->bdev)) > blk_queue_flag_set(QUEUE_FLAG_DISCARD, mddev->queue); > print_conf(conf); > return err; > @@ -3141,7 +3141,7 @@ static int raid1_run(struct mddev *mddev) > continue; > disk_stack_limits(mddev->gendisk, rdev->bdev, > rdev->data_offset << 9); > - if (blk_queue_discard(bdev_get_queue(rdev->bdev))) > + if (bdev_max_discard_sectors(rdev->bdev)) > discard_supported = true; > } > > diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c > index 7816c8b2e8087..eaa86c6a35a55 100644 > --- a/drivers/md/raid10.c > +++ b/drivers/md/raid10.c > @@ -888,7 +888,7 @@ static void flush_pending_writes(struct r10conf *conf) > if (test_bit(Faulty, &rdev->flags)) { > bio_io_error(bio); > } else if (unlikely((bio_op(bio) == REQ_OP_DISCARD) && > - !blk_queue_discard(bio->bi_bdev->bd_disk->queue))) > + !bdev_max_discard_sectors(bio->bi_bdev))) > /* Just ignore it */ > bio_endio(bio); > else > @@ -1083,7 +1083,7 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule) > if (test_bit(Faulty, &rdev->flags)) { > bio_io_error(bio); > } else if (unlikely((bio_op(bio) == REQ_OP_DISCARD) && > - !blk_queue_discard(bio->bi_bdev->bd_disk->queue))) > + !bdev_max_discard_sectors(bio->bi_bdev))) > /* Just ignore it */ > bio_endio(bio); > else > @@ -2144,7 +2144,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev) > rcu_assign_pointer(p->rdev, rdev); > break; > } > - if (mddev->queue && blk_queue_discard(bdev_get_queue(rdev->bdev))) > + if (mddev->queue && bdev_max_discard_sectors(rdev->bdev)) > blk_queue_flag_set(QUEUE_FLAG_DISCARD, mddev->queue); > > print_conf(conf); > @@ -4141,7 +4141,7 @@ static int raid10_run(struct mddev *mddev) > > disk->head_position = 0; > > - if (blk_queue_discard(bdev_get_queue(rdev->bdev))) > + if (bdev_max_discard_sectors(rdev->bdev)) > discard_supported = true; > first = 0; > } > diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c > index a7d50ff9020a8..c3cbf9a574a39 100644 > --- a/drivers/md/raid5-cache.c > +++ b/drivers/md/raid5-cache.c > @@ -1318,7 +1318,7 @@ static void r5l_write_super_and_discard_space(struct r5l_log *log, > > r5l_write_super(log, end); > > - if (!blk_queue_discard(bdev_get_queue(bdev))) > + if (!bdev_max_discard_sectors(bdev)) > return; > > mddev = log->rdev->mddev; > diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c > index 16e775bcf4a7c..7d510e4231713 100644 > --- a/drivers/target/target_core_device.c > +++ b/drivers/target/target_core_device.c > @@ -829,9 +829,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) > } > > /* > - * Check if the underlying struct block_device request_queue supports > - * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM > - * in ATA and we need to set TPE=1 > + * Check if the underlying struct block_device request_queue supports disard. > */ > bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib, > struct block_device *bdev) > @@ -839,11 +837,11 @@ bool target_configure_unmap_from_queue(struct se_dev_attrib *attrib, > struct request_queue *q = bdev_get_queue(bdev); > int block_size = bdev_logical_block_size(bdev); > > - if (!blk_queue_discard(q)) > + if (!bdev_max_discard_sectors(bdev)) > return false; > > attrib->max_unmap_lba_count = > - q->limits.max_discard_sectors >> (ilog2(block_size) - 9); > + bdev_max_discard_sectors(bdev) >> (ilog2(block_size) - 9); > /* > * Currently hardcoded to 1 in Linux/SCSI code.. > */ > diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c > index f477035a2ac23..efd8deb3ab7e8 100644 > --- a/fs/btrfs/extent-tree.c > +++ b/fs/btrfs/extent-tree.c > @@ -1291,7 +1291,7 @@ static int do_discard_extent(struct btrfs_io_stripe *stripe, u64 *bytes) > ret = btrfs_reset_device_zone(dev_replace->tgtdev, phys, len, > &discarded); > discarded += src_disc; > - } else if (blk_queue_discard(bdev_get_queue(stripe->dev->bdev))) { > + } else if (bdev_max_discard_sectors(stripe->dev->bdev)) { > ret = btrfs_issue_discard(dev->bdev, phys, len, &discarded); > } else { > ret = 0; > @@ -5987,7 +5987,7 @@ static int btrfs_trim_free_extents(struct btrfs_device *device, u64 *trimmed) > *trimmed = 0; > > /* Discard not supported = nothing to do. */ > - if (!blk_queue_discard(bdev_get_queue(device->bdev))) > + if (!bdev_max_discard_sectors(device->bdev)) > return 0; > > /* Not writable = nothing to do. */ > diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c > index 238cee5b5254d..fc7953755fd8b 100644 > --- a/fs/btrfs/ioctl.c > +++ b/fs/btrfs/ioctl.c > @@ -501,7 +501,7 @@ static noinline int btrfs_ioctl_fitrim(struct btrfs_fs_info *fs_info, > if (!device->bdev) > continue; > q = bdev_get_queue(device->bdev); > - if (blk_queue_discard(q)) { > + if (bdev_max_discard_sectors(device->bdev)) { > num_devices++; > minlen = min_t(u64, q->limits.discard_granularity, > minlen); > diff --git a/fs/exfat/file.c b/fs/exfat/file.c > index 2f51300592366..765e4f63dd18d 100644 > --- a/fs/exfat/file.c > +++ b/fs/exfat/file.c > @@ -358,7 +358,7 @@ static int exfat_ioctl_fitrim(struct inode *inode, unsigned long arg) > if (!capable(CAP_SYS_ADMIN)) > return -EPERM; > > - if (!blk_queue_discard(q)) > + if (!bdev_max_discard_sectors(inode->i_sb->s_bdev)) > return -EOPNOTSUPP; > > if (copy_from_user(&range, (struct fstrim_range __user *)arg, sizeof(range))) > diff --git a/fs/exfat/super.c b/fs/exfat/super.c > index 8ca21e7917d16..be0788ecaf20e 100644 > --- a/fs/exfat/super.c > +++ b/fs/exfat/super.c > @@ -627,13 +627,9 @@ static int exfat_fill_super(struct super_block *sb, struct fs_context *fc) > if (opts->allow_utime == (unsigned short)-1) > opts->allow_utime = ~opts->fs_dmask & 0022; > > - if (opts->discard) { > - struct request_queue *q = bdev_get_queue(sb->s_bdev); > - > - if (!blk_queue_discard(q)) { > - exfat_warn(sb, "mounting with \"discard\" option, but the device does not support discard"); > - opts->discard = 0; > - } > + if (opts->discard && !bdev_max_discard_sectors(sb->s_bdev)) { > + exfat_warn(sb, "mounting with \"discard\" option, but the device does not support discard"); > + opts->discard = 0; > } > > sb->s_flags |= SB_NODIRATIME; > diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c > index 992229ca2d830..6e3b9eea126f4 100644 > --- a/fs/ext4/ioctl.c > +++ b/fs/ext4/ioctl.c > @@ -1044,7 +1044,6 @@ static int ext4_ioctl_checkpoint(struct file *filp, unsigned long arg) > __u32 flags = 0; > unsigned int flush_flags = 0; > struct super_block *sb = file_inode(filp)->i_sb; > - struct request_queue *q; > > if (copy_from_user(&flags, (__u32 __user *)arg, > sizeof(__u32))) > @@ -1065,10 +1064,8 @@ static int ext4_ioctl_checkpoint(struct file *filp, unsigned long arg) > if (flags & ~EXT4_IOC_CHECKPOINT_FLAG_VALID) > return -EINVAL; > > - q = bdev_get_queue(EXT4_SB(sb)->s_journal->j_dev); > - if (!q) > - return -ENXIO; > - if ((flags & JBD2_JOURNAL_FLUSH_DISCARD) && !blk_queue_discard(q)) > + if ((flags & JBD2_JOURNAL_FLUSH_DISCARD) && > + !bdev_max_discard_sectors(EXT4_SB(sb)->s_journal->j_dev)) > return -EOPNOTSUPP; > > if (flags & EXT4_IOC_CHECKPOINT_FLAG_DRY_RUN) > @@ -1393,14 +1390,13 @@ static long __ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) > > case FITRIM: > { > - struct request_queue *q = bdev_get_queue(sb->s_bdev); > struct fstrim_range range; > int ret = 0; > > if (!capable(CAP_SYS_ADMIN)) > return -EPERM; > > - if (!blk_queue_discard(q)) > + if (!bdev_max_discard_sectors(sb->s_bdev)) > return -EOPNOTSUPP; > > /* > diff --git a/fs/ext4/super.c b/fs/ext4/super.c > index 81749eaddf4c1..93f4e4e9e2631 100644 > --- a/fs/ext4/super.c > +++ b/fs/ext4/super.c > @@ -5458,13 +5458,9 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb) > goto failed_mount9; > } > > - if (test_opt(sb, DISCARD)) { > - struct request_queue *q = bdev_get_queue(sb->s_bdev); > - if (!blk_queue_discard(q)) > - ext4_msg(sb, KERN_WARNING, > - "mounting with \"discard\" option, but " > - "the device does not support discard"); > - } > + if (test_opt(sb, DISCARD) && !bdev_max_discard_sectors(sb->s_bdev)) > + ext4_msg(sb, KERN_WARNING, > + "mounting with \"discard\" option, but the device does not support discard"); > > if (es->s_error_count) > mod_timer(&sbi->s_err_report, jiffies + 300*HZ); /* 5 minutes */ > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h > index cd1e65bcf0b04..0ea9a5fa7c1dd 100644 > --- a/fs/f2fs/f2fs.h > +++ b/fs/f2fs/f2fs.h > @@ -4381,8 +4381,7 @@ static inline bool f2fs_hw_should_discard(struct f2fs_sb_info *sbi) > > static inline bool f2fs_bdev_support_discard(struct block_device *bdev) > { > - return blk_queue_discard(bdev_get_queue(bdev)) || > - bdev_is_zoned(bdev); > + return bdev_max_discard_sectors(bdev) || bdev_is_zoned(bdev); > } > > static inline bool f2fs_hw_support_discard(struct f2fs_sb_info *sbi) > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c > index 22dfeb9915290..71f09adbcba86 100644 > --- a/fs/f2fs/segment.c > +++ b/fs/f2fs/segment.c > @@ -1196,9 +1196,8 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi, > unsigned int *issued) > { > struct block_device *bdev = dc->bdev; > - struct request_queue *q = bdev_get_queue(bdev); > unsigned int max_discard_blocks = > - SECTOR_TO_BLOCK(q->limits.max_discard_sectors); > + SECTOR_TO_BLOCK(bdev_max_discard_sectors(bdev)); > struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; > struct list_head *wait_list = (dpolicy->type == DPOLICY_FSTRIM) ? > &(dcc->fstrim_list) : &(dcc->wait_list); > @@ -1375,9 +1374,8 @@ static void __update_discard_tree_range(struct f2fs_sb_info *sbi, > struct discard_cmd *dc; > struct discard_info di = {0}; > struct rb_node **insert_p = NULL, *insert_parent = NULL; > - struct request_queue *q = bdev_get_queue(bdev); > unsigned int max_discard_blocks = > - SECTOR_TO_BLOCK(q->limits.max_discard_sectors); > + SECTOR_TO_BLOCK(bdev_max_discard_sectors(bdev)); > block_t end = lstart + len; > > dc = (struct discard_cmd *)f2fs_lookup_rb_tree_ret(&dcc->root, > diff --git a/fs/fat/file.c b/fs/fat/file.c > index a5a309fcc7faf..e4c7d10e80129 100644 > --- a/fs/fat/file.c > +++ b/fs/fat/file.c > @@ -133,7 +133,7 @@ static int fat_ioctl_fitrim(struct inode *inode, unsigned long arg) > if (!capable(CAP_SYS_ADMIN)) > return -EPERM; > > - if (!blk_queue_discard(q)) > + if (!bdev_max_discard_sectors(sb->s_bdev)) > return -EOPNOTSUPP; > > user_range = (struct fstrim_range __user *)arg; > diff --git a/fs/fat/inode.c b/fs/fat/inode.c > index bf6051bdf1d1d..3d1afb95a925a 100644 > --- a/fs/fat/inode.c > +++ b/fs/fat/inode.c > @@ -1872,13 +1872,9 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, > goto out_fail; > } > > - if (sbi->options.discard) { > - struct request_queue *q = bdev_get_queue(sb->s_bdev); > - if (!blk_queue_discard(q)) > - fat_msg(sb, KERN_WARNING, > - "mounting with \"discard\" option, but " > - "the device does not support discard"); > - } > + if (sbi->options.discard && !bdev_max_discard_sectors(sb->s_bdev)) > + fat_msg(sb, KERN_WARNING, > + "mounting with \"discard\" option, but the device does not support discard"); > > fat_set_state(sb, 1, 0); > return 0; > diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c > index 801ad9f4f2bef..7f20ac9133bc6 100644 > --- a/fs/gfs2/rgrp.c > +++ b/fs/gfs2/rgrp.c > @@ -1405,7 +1405,7 @@ int gfs2_fitrim(struct file *filp, void __user *argp) > if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) > return -EROFS; > > - if (!blk_queue_discard(q)) > + if (!bdev_max_discard_sectors(sdp->sd_vfs->s_bdev)) > return -EOPNOTSUPP; > > if (copy_from_user(&r, argp, sizeof(r))) > diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c > index fcacafa4510d1..19d226cd4ff4d 100644 > --- a/fs/jbd2/journal.c > +++ b/fs/jbd2/journal.c > @@ -1762,7 +1762,6 @@ static int __jbd2_journal_erase(journal_t *journal, unsigned int flags) > unsigned long block, log_offset; /* logical */ > unsigned long long phys_block, block_start, block_stop; /* physical */ > loff_t byte_start, byte_stop, byte_count; > - struct request_queue *q = bdev_get_queue(journal->j_dev); > > /* flags must be set to either discard or zeroout */ > if ((flags & ~JBD2_JOURNAL_FLUSH_VALID) || !flags || > @@ -1770,10 +1769,8 @@ static int __jbd2_journal_erase(journal_t *journal, unsigned int flags) > (flags & JBD2_JOURNAL_FLUSH_ZEROOUT))) > return -EINVAL; > > - if (!q) > - return -ENXIO; > - > - if ((flags & JBD2_JOURNAL_FLUSH_DISCARD) && !blk_queue_discard(q)) > + if ((flags & JBD2_JOURNAL_FLUSH_DISCARD) && > + !bdev_max_discard_sectors(journal->j_dev)) > return -EOPNOTSUPP; > > /* > diff --git a/fs/jfs/ioctl.c b/fs/jfs/ioctl.c > index 03a845ab4f009..357ae6e5c36ec 100644 > --- a/fs/jfs/ioctl.c > +++ b/fs/jfs/ioctl.c > @@ -117,7 +117,7 @@ long jfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) > if (!capable(CAP_SYS_ADMIN)) > return -EPERM; > > - if (!blk_queue_discard(q)) { > + if (!bdev_max_discard_sectors(sb->s_bdev)) { > jfs_warn("FITRIM not supported on device"); > return -EOPNOTSUPP; > } > diff --git a/fs/jfs/super.c b/fs/jfs/super.c > index f1a13a74cddf3..85d4f44f2ac4d 100644 > --- a/fs/jfs/super.c > +++ b/fs/jfs/super.c > @@ -372,19 +372,16 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, > } > > case Opt_discard: > - { > - struct request_queue *q = bdev_get_queue(sb->s_bdev); > /* if set to 1, even copying files will cause > * trimming :O > * -> user has more control over the online trimming > */ > sbi->minblks_trim = 64; > - if (blk_queue_discard(q)) > + if (bdev_max_discard_sectors(sb->s_bdev)) > *flag |= JFS_DISCARD; > else > pr_err("JFS: discard option not supported on device\n"); > break; > - } > > case Opt_nodiscard: > *flag &= ~JFS_DISCARD; > @@ -392,10 +389,9 @@ static int parse_options(char *options, struct super_block *sb, s64 *newLVSize, > > case Opt_discard_minblk: > { > - struct request_queue *q = bdev_get_queue(sb->s_bdev); > char *minblks_trim = args[0].from; > int rc; > - if (blk_queue_discard(q)) { > + if (bdev_max_discard_sectors(sb->s_bdev)) { > *flag |= JFS_DISCARD; > rc = kstrtouint(minblks_trim, 0, > &sbi->minblks_trim); > diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c > index fec194a666f4b..52b73f558fcb1 100644 > --- a/fs/nilfs2/ioctl.c > +++ b/fs/nilfs2/ioctl.c > @@ -1059,7 +1059,7 @@ static int nilfs_ioctl_trim_fs(struct inode *inode, void __user *argp) > if (!capable(CAP_SYS_ADMIN)) > return -EPERM; > > - if (!blk_queue_discard(q)) > + if (!bdev_max_discard_sectors(nilfs->ns_bdev)) > return -EOPNOTSUPP; > > if (copy_from_user(&range, argp, sizeof(range))) > diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c > index 787b53b984ee1..e763236169331 100644 > --- a/fs/ntfs3/file.c > +++ b/fs/ntfs3/file.c > @@ -28,7 +28,7 @@ static int ntfs_ioctl_fitrim(struct ntfs_sb_info *sbi, unsigned long arg) > if (!capable(CAP_SYS_ADMIN)) > return -EPERM; > > - if (!blk_queue_discard(q)) > + if (!bdev_max_discard_sectors(sbi->sb->s_bdev)) > return -EOPNOTSUPP; > > user_range = (struct fstrim_range __user *)arg; > diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c > index cd30e81abbce0..c734085bcce4a 100644 > --- a/fs/ntfs3/super.c > +++ b/fs/ntfs3/super.c > @@ -913,7 +913,7 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc) > } > > rq = bdev_get_queue(bdev); > - if (blk_queue_discard(rq) && rq->limits.discard_granularity) { > + if (bdev_max_discard_sectors(bdev) && rq->limits.discard_granularity) { > sbi->discard_granularity = rq->limits.discard_granularity; > sbi->discard_granularity_mask_inv = > ~(u64)(sbi->discard_granularity - 1); > diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c > index f59461d85da45..9b78ef103ada6 100644 > --- a/fs/ocfs2/ioctl.c > +++ b/fs/ocfs2/ioctl.c > @@ -910,7 +910,7 @@ long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) > if (!capable(CAP_SYS_ADMIN)) > return -EPERM; > > - if (!blk_queue_discard(q)) > + if (!bdev_max_discard_sectors(sb->s_bdev)) > return -EOPNOTSUPP; > > if (copy_from_user(&range, argp, sizeof(range))) > diff --git a/fs/xfs/xfs_discard.c b/fs/xfs/xfs_discard.c > index 0191de8ce9ced..a4e6609d616b7 100644 > --- a/fs/xfs/xfs_discard.c > +++ b/fs/xfs/xfs_discard.c > @@ -162,7 +162,7 @@ xfs_ioc_trim( > > if (!capable(CAP_SYS_ADMIN)) > return -EPERM; > - if (!blk_queue_discard(q)) > + if (!bdev_max_discard_sectors(mp->m_ddev_targp->bt_bdev)) > return -EOPNOTSUPP; > > /* > diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c > index 54be9d64093ed..a276b8111f636 100644 > --- a/fs/xfs/xfs_super.c > +++ b/fs/xfs/xfs_super.c > @@ -1608,14 +1608,10 @@ xfs_fs_fill_super(. > goto out_filestream_unmount; > }> > - if (xfs_has_discard(mp)) { > - struct request_queue *q = bdev_get_queue(sb->s_bdev); > - > - if (!blk_queue_discard(q)) { > - xfs_warn(mp, "mounting with \"discard\" option, but " > - "the device does not support discard"); > - mp->m_features &= ~XFS_FEAT_DISCARD; > - } > + if (xfs_has_discard(mp) && !bdev_max_discard_sectors(sb->s_bdev)) { > + xfs_warn(mp, > + "mounting with \"discard\" option, but the device does not support discard"); > + mp->m_features &= ~XFS_FEAT_DISCARD; > } > > if (xfs_has_reflink(mp)) { > diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h > index 34b1cfd067421..ce16247d3afab 100644 > --- a/include/linux/blkdev.h > +++ b/include/linux/blkdev.h > @@ -1254,6 +1254,11 @@ bdev_zone_write_granularity(struct block_device *bdev) > int bdev_alignment_offset(struct block_device *bdev); > unsigned int bdev_discard_alignment(struct block_device *bdev); > > +static inline unsigned int bdev_max_discard_sectors(struct block_device *bdev) > +{ > + return bdev_get_queue(bdev)->limits.max_discard_sectors; > +} > + So this patch replaces checking for blk_queue_discard(q) with checking whether bdev_max_discard_sectors() is nonzero. That doesn't seem to be equivalent for callers like drivers/md/raid0.c:raid0_run() which clear the QUEUE_FLAG_DISCARD flag without zeroing out max_discard_sectors, for example. Should a test for the QUEUE_FLAG_DISCARD flag be added here? If I'm misreading things, could you please document that bdev_max_discard_sectors() != 0 implies that discard is supported? Thanks, Andreas > static inline unsigned int bdev_write_zeroes_sectors(struct block_device *bdev) > { > struct request_queue *q = bdev_get_queue(bdev); > diff --git a/mm/swapfile.c b/mm/swapfile.c > index 4069f17a82c8e..5d9cedf9e7b84 100644 > --- a/mm/swapfile.c > +++ b/mm/swapfile.c > @@ -2957,20 +2957,6 @@ static int setup_swap_map_and_extents(struct swap_info_struct *p, > return nr_extents; > } > > -/* > - * Helper to sys_swapon determining if a given swap > - * backing device queue supports DISCARD operations. > - */ > -static bool swap_discardable(struct swap_info_struct *si) > -{ > - struct request_queue *q = bdev_get_queue(si->bdev); > - > - if (!blk_queue_discard(q)) > - return false; > - > - return true; > -} > - > SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) > { > struct swap_info_struct *p; > @@ -3132,7 +3118,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) > sizeof(long), > GFP_KERNEL); > > - if (p->bdev && (swap_flags & SWAP_FLAG_DISCARD) && swap_discardable(p)) { > + if ((swap_flags & SWAP_FLAG_DISCARD) && > + p->bdev && bdev_max_discard_sectors(p->bdev)) { > /* > * When discard is enabled for swap with no particular > * policy flagged, we set all swap discard flags here in > -- > 2.30.2 > -- dm-devel mailing list dm-devel@xxxxxxxxxx https://listman.redhat.com/mailman/listinfo/dm-devel