Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dm: split discards further if target sets max_discard_granularity

The block core (bio_split_discard) will already split discards based
on the 'discard_granularity' and 'max_discard_sectors' queue_limits.
But the DM thin target also needs to ensure that it doesn't receive a
discard that spans a 'max_discard_sectors' boundary.

Introduce a dm_target 'max_discard_granularity' flag that if set will
cause DM core to split discard bios relative to 'max_discard_sectors'.
This treats 'discard_granularity' as a "min_discard_granularity" and
'max_discard_sectors' as a "max_discard_granularity".

Requested-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@kernel.org>

+27 -8
+19 -6
drivers/md/dm.c
··· 1162 1162 return ti->len - target_offset; 1163 1163 } 1164 1164 1165 - static sector_t max_io_len(struct dm_target *ti, sector_t sector) 1165 + static sector_t __max_io_len(struct dm_target *ti, sector_t sector, 1166 + unsigned int max_granularity) 1166 1167 { 1167 1168 sector_t target_offset = dm_target_offset(ti, sector); 1168 1169 sector_t len = max_io_len_target_boundary(ti, target_offset); ··· 1174 1173 * explains why stacked chunk_sectors based splitting via 1175 1174 * bio_split_to_limits() isn't possible here. 1176 1175 */ 1177 - if (!ti->max_io_len) 1176 + if (!max_granularity) 1178 1177 return len; 1179 1178 return min_t(sector_t, len, 1180 1179 min(queue_max_sectors(ti->table->md->queue), 1181 - blk_chunk_sectors_left(target_offset, ti->max_io_len))); 1180 + blk_chunk_sectors_left(target_offset, max_granularity))); 1181 + } 1182 + 1183 + static inline sector_t max_io_len(struct dm_target *ti, sector_t sector) 1184 + { 1185 + return __max_io_len(ti, sector, ti->max_io_len); 1182 1186 } 1183 1187 1184 1188 int dm_set_target_max_io_len(struct dm_target *ti, sector_t len) ··· 1571 1565 } 1572 1566 1573 1567 static void __send_changing_extent_only(struct clone_info *ci, struct dm_target *ti, 1574 - unsigned int num_bios) 1568 + unsigned int num_bios, 1569 + unsigned int max_granularity) 1575 1570 { 1576 1571 unsigned int len, bios; 1577 1572 1578 1573 len = min_t(sector_t, ci->sector_count, 1579 - max_io_len_target_boundary(ti, dm_target_offset(ti, ci->sector))); 1574 + __max_io_len(ti, ci->sector, max_granularity)); 1580 1575 1581 1576 atomic_add(num_bios, &ci->io->io_count); 1582 1577 bios = __send_duplicate_bios(ci, ti, num_bios, &len); ··· 1613 1606 struct dm_target *ti) 1614 1607 { 1615 1608 unsigned int num_bios = 0; 1609 + unsigned int max_granularity = 0; 1616 1610 1617 1611 switch (bio_op(ci->bio)) { 1618 1612 case REQ_OP_DISCARD: 1619 1613 num_bios = ti->num_discard_bios; 1614 + if (ti->max_discard_granularity) { 1615 + struct queue_limits *limits = 1616 + dm_get_queue_limits(ti->table->md); 1617 + max_granularity = limits->max_discard_sectors; 1618 + } 1620 1619 break; 1621 1620 case REQ_OP_SECURE_ERASE: 1622 1621 num_bios = ti->num_secure_erase_bios; ··· 1643 1630 if (unlikely(!num_bios)) 1644 1631 return BLK_STS_NOTSUPP; 1645 1632 1646 - __send_changing_extent_only(ci, ti, num_bios); 1633 + __send_changing_extent_only(ci, ti, num_bios, max_granularity); 1647 1634 return BLK_STS_OK; 1648 1635 } 1649 1636
+6
include/linux/device-mapper.h
··· 359 359 bool discards_supported:1; 360 360 361 361 /* 362 + * Set if this target requires that discards be split on both 363 + * 'discard_granularity' and 'max_discard_sectors' boundaries. 364 + */ 365 + bool max_discard_granularity:1; 366 + 367 + /* 362 368 * Set if we need to limit the number of in-flight bios when swapping. 363 369 */ 364 370 bool limit_swap_bios:1;
+2 -2
include/uapi/linux/dm-ioctl.h
··· 286 286 #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) 287 287 288 288 #define DM_VERSION_MAJOR 4 289 - #define DM_VERSION_MINOR 47 289 + #define DM_VERSION_MINOR 48 290 290 #define DM_VERSION_PATCHLEVEL 0 291 - #define DM_VERSION_EXTRA "-ioctl (2022-07-28)" 291 + #define DM_VERSION_EXTRA "-ioctl (2023-03-01)" 292 292 293 293 /* Status bits */ 294 294 #define DM_READONLY_FLAG (1 << 0) /* In/Out */