History

dm: handle REQ_OP_ZONE_RESET_ALL

This commit implements processing of the REQ_OP_ZONE_RESET_ALL operation for zoned mapped devices. Given that this operation always has a BIO sector of 0 and a 0 size, processing through the regular BIO __split_and_process_bio() function does not work because this function would always select the first target. Instead, handling of this operation is implemented using the function __send_zone_reset_all(). Similarly to the __send_empty_flush() function, the new __send_zone_reset_all() function manually goes through all targets of a mapped device table doing the following: 1) If the target can natively support REQ_OP_ZONE_RESET_ALL, __send_duplicate_bios() is used to forward the reset all operation to the target. This case is handled with the __send_zone_reset_all_native() function. 2) For other targets, the function __send_zone_reset_all_emulated() is executed to emulate the execution of REQ_OP_ZONE_RESET_ALL using regular REQ_OP_ZONE_RESET operations. Targets that can natively support REQ_OP_ZONE_RESET_ALL are identified using the new target field zone_reset_all_supported. This boolean is set to true in for targets that have reliable zone limits, that is, targets that map all sequential write required zones of their zoned device(s). Setting this field is handled in dm_set_zones_restrictions() and device_get_zone_resource_limits(). For targets with unreliable zone limits, REQ_OP_ZONE_RESET_ALL must be emulated (case 2 above). This is implemented with __send_zone_reset_all_emulated() and is similar to the block layer function blkdev_zone_reset_all_emulated(): first a report zones is done for the zones of the target to identify zones that need reset, that is, any sequential write required zone that is not already empty. This is done using a bitmap and the function dm_zone_get_reset_bitmap() which sets to 1 the bit corresponding to a zone that needs reset. Next, this zone bitmap is inspected and a clone BIO modified to use the REQ_OP_ZONE_RESET operation issued for any zone with its bit set in the zone bitmap. This implementation is more efficient than what the block layer does with blkdev_zone_reset_all_emulated(), which is always used for DM zoned devices currently: as we can natively use REQ_OP_ZONE_RESET_ALL on targets mapping all sequential write required zones, resetting all zones of a zoned mapped device can be much faster compared to always emulating this operation using regular per-zone reset. In the worst case, this implementation is as-efficient as the block layer emulation. This reduction in the time it takes to reset all zones of a zoned mapped device depends directly on the mapped device targets mapping (reliable zone limits or not).

Damien Le Moal committed 2 years ago

Commit 81e77061 parent ae7e9654 files · +190 −5Browse files

Unified · Split

4 files
  1. drivers/md/dm-zone.c +48 −2
  2. drivers/md/dm.c +132 −3
  3. drivers/md/dm.h +3 −0
  4. include/linux/device-mapper.h +7 −0
drivers/md/dm-zone.c+48−2
@@ -292,10 +292,12 @@ static int device_get_zone_resource_limits(struct dm_target *ti, · 291 unmodified lines
292 292
293 /*293 /*
294 * If the target does not map all sequential zones, the limits294 * If the target does not map all sequential zones, the limits
295 * will not be reliable.295 * will not be reliable and we cannot use REQ_OP_ZONE_RESET_ALL.
296 */296 */
297 if (zc.target_nr_seq_zones < zc.total_nr_seq_zones)297 if (zc.target_nr_seq_zones < zc.total_nr_seq_zones) {
298 zlim->reliable_limits = false;298 zlim->reliable_limits = false;
299 ti->zone_reset_all_supported = false;
300 }
299 301
300 /*302 /*
301 * If the target maps less sequential zones than the limit values, then303 * If the target maps less sequential zones than the limit values, then
@@ -353,6 +355,14 @@ int dm_set_zones_restrictions(struct dm_table *t, struct request_queue *q, · 51 unmodified lines
353 for (unsigned int i = 0; i < t->num_targets; i++) {355 for (unsigned int i = 0; i < t->num_targets; i++) {
354 struct dm_target *ti = dm_table_get_target(t, i);356 struct dm_target *ti = dm_table_get_target(t, i);
355 357
358 /*
359 * Assume that the target can accept REQ_OP_ZONE_RESET_ALL.
360 * device_get_zone_resource_limits() may adjust this if one of
361 * the device used by the target does not have all its
362 * sequential write required zones mapped.
363 */
364 ti->zone_reset_all_supported = true;
365
356 if (!ti->type->iterate_devices ||366 if (!ti->type->iterate_devices ||
357 ti->type->iterate_devices(ti,367 ti->type->iterate_devices(ti,
358 device_get_zone_resource_limits, &zlim)) {368 device_get_zone_resource_limits, &zlim)) {
@@ -420,3 +430,39 @@ void dm_zone_endio(struct dm_io *io, struct bio *clone) · 61 unmodified lines
420 430
421 return;431 return;
422}432}
433
434static int dm_zone_need_reset_cb(struct blk_zone *zone, unsigned int idx,
435 void *data)
436{
437 /*
438 * For an all-zones reset, ignore conventional, empty, read-only
439 * and offline zones.
440 */
441 switch (zone->cond) {
442 case BLK_ZONE_COND_NOT_WP:
443 case BLK_ZONE_COND_EMPTY:
444 case BLK_ZONE_COND_READONLY:
445 case BLK_ZONE_COND_OFFLINE:
446 return 0;
447 default:
448 set_bit(idx, (unsigned long *)data);
449 return 0;
450 }
451}
452
453int dm_zone_get_reset_bitmap(struct mapped_device *md, struct dm_table *t,
454 sector_t sector, unsigned int nr_zones,
455 unsigned long *need_reset)
456{
457 int ret;
458
459 ret = dm_blk_do_report_zones(md, t, sector, nr_zones,
460 dm_zone_need_reset_cb, need_reset);
461 if (ret != nr_zones) {
462 DMERR("Get %s zone reset bitmap failed\n",
463 md->disk->disk_name);
464 return -EIO;
465 }
466
467 return 0;
468}
drivers/md/dm.c+132−3
@@ -1606,6 +1606,7 @@ static bool is_abnormal_io(struct bio *bio) · 1605 unmodified lines
1606 case REQ_OP_DISCARD:1606 case REQ_OP_DISCARD:
1607 case REQ_OP_SECURE_ERASE:1607 case REQ_OP_SECURE_ERASE:
1608 case REQ_OP_WRITE_ZEROES:1608 case REQ_OP_WRITE_ZEROES:
1609 case REQ_OP_ZONE_RESET_ALL:
1609 return true;1610 return true;
1610 default:1611 default:
1611 return false;1612 return false;
@@ -1774,6 +1775,119 @@ static inline bool dm_zone_plug_bio(struct mapped_device *md, struct bio *bio) · 162 unmodified lines
1774{1775{
1775 return dm_emulate_zone_append(md) && blk_zone_plug_bio(bio, 0);1776 return dm_emulate_zone_append(md) && blk_zone_plug_bio(bio, 0);
1776}1777}
1778
1779static blk_status_t __send_zone_reset_all_emulated(struct clone_info *ci,
1780 struct dm_target *ti)
1781{
1782 struct bio_list blist = BIO_EMPTY_LIST;
1783 struct mapped_device *md = ci->io->md;
1784 unsigned int zone_sectors = md->disk->queue->limits.chunk_sectors;
1785 unsigned long *need_reset;
1786 unsigned int i, nr_zones, nr_reset;
1787 unsigned int num_bios = 0;
1788 blk_status_t sts = BLK_STS_OK;
1789 sector_t sector = ti->begin;
1790 struct bio *clone;
1791 int ret;
1792
1793 nr_zones = ti->len >> ilog2(zone_sectors);
1794 need_reset = bitmap_zalloc(nr_zones, GFP_NOIO);
1795 if (!need_reset)
1796 return BLK_STS_RESOURCE;
1797
1798 ret = dm_zone_get_reset_bitmap(md, ci->map, ti->begin,
1799 nr_zones, need_reset);
1800 if (ret) {
1801 sts = BLK_STS_IOERR;
1802 goto free_bitmap;
1803 }
1804
1805 /* If we have no zone to reset, we are done. */
1806 nr_reset = bitmap_weight(need_reset, nr_zones);
1807 if (!nr_reset)
1808 goto free_bitmap;
1809
1810 atomic_add(nr_zones, &ci->io->io_count);
1811
1812 for (i = 0; i < nr_zones; i++) {
1813
1814 if (!test_bit(i, need_reset)) {
1815 sector += zone_sectors;
1816 continue;
1817 }
1818
1819 if (bio_list_empty(&blist)) {
1820 /* This may take a while, so be nice to others */
1821 if (num_bios)
1822 cond_resched();
1823
1824 /*
1825 * We may need to reset thousands of zones, so let's
1826 * not go crazy with the clone allocation.
1827 */
1828 alloc_multiple_bios(&blist, ci, ti, min(nr_reset, 32),
1829 NULL, GFP_NOIO);
1830 }
1831
1832 /* Get a clone and change it to a regular reset operation. */
1833 clone = bio_list_pop(&blist);
1834 clone->bi_opf &= ~REQ_OP_MASK;
1835 clone->bi_opf |= REQ_OP_ZONE_RESET | REQ_SYNC;
1836 clone->bi_iter.bi_sector = sector;
1837 clone->bi_iter.bi_size = 0;
1838 __map_bio(clone);
1839
1840 sector += zone_sectors;
1841 num_bios++;
1842 nr_reset--;
1843 }
1844
1845 WARN_ON_ONCE(!bio_list_empty(&blist));
1846 atomic_sub(nr_zones - num_bios, &ci->io->io_count);
1847 ci->sector_count = 0;
1848
1849free_bitmap:
1850 bitmap_free(need_reset);
1851
1852 return sts;
1853}
1854
1855static void __send_zone_reset_all_native(struct clone_info *ci,
1856 struct dm_target *ti)
1857{
1858 unsigned int bios;
1859
1860 atomic_add(1, &ci->io->io_count);
1861 bios = __send_duplicate_bios(ci, ti, 1, NULL, GFP_NOIO);
1862 atomic_sub(1 - bios, &ci->io->io_count);
1863
1864 ci->sector_count = 0;
1865}
1866
1867static blk_status_t __send_zone_reset_all(struct clone_info *ci)
1868{
1869 struct dm_table *t = ci->map;
1870 blk_status_t sts = BLK_STS_OK;
1871
1872 for (unsigned int i = 0; i < t->num_targets; i++) {
1873 struct dm_target *ti = dm_table_get_target(t, i);
1874
1875 if (ti->zone_reset_all_supported) {
1876 __send_zone_reset_all_native(ci, ti);
1877 continue;
1878 }
1879
1880 sts = __send_zone_reset_all_emulated(ci, ti);
1881 if (sts != BLK_STS_OK)
1882 break;
1883 }
1884
1885 /* Release the reference that alloc_io() took for submission. */
1886 atomic_sub(1, &ci->io->io_count);
1887
1888 return sts;
1889}
1890
1777#else1891#else
1778static inline bool dm_zone_bio_needs_split(struct mapped_device *md,1892static inline bool dm_zone_bio_needs_split(struct mapped_device *md,
1779 struct bio *bio)1893 struct bio *bio)
@@ -1784,6 +1898,10 @@ static inline bool dm_zone_plug_bio(struct mapped_device *md, struct bio *bio) · 4 unmodified lines
1784{1898{
1785 return false;1899 return false;
1786}1900}
1901static blk_status_t __send_zone_reset_all(struct clone_info *ci)
1902{
1903 return BLK_STS_NOTSUPP;
1904}
1787#endif1905#endif
1788 1906
1789/*1907/*
@@ -1797,9 +1915,14 @@ static void dm_split_and_process_bio(struct mapped_device *md, · 7 unmodified lines
1797 blk_status_t error = BLK_STS_OK;1915 blk_status_t error = BLK_STS_OK;
1798 bool is_abnormal, need_split;1916 bool is_abnormal, need_split;
1799 1917
1800 need_split = is_abnormal = is_abnormal_io(bio);1918 is_abnormal = is_abnormal_io(bio);
1801 if (static_branch_unlikely(&zoned_enabled))1919 if (static_branch_unlikely(&zoned_enabled)) {
1802 need_split = is_abnormal || dm_zone_bio_needs_split(md, bio);1920 /* Special case REQ_OP_ZONE_RESET_ALL as it cannot be split. */
1921 need_split = (bio_op(bio) != REQ_OP_ZONE_RESET_ALL) &&
1922 (is_abnormal || dm_zone_bio_needs_split(md, bio));
1923 } else {
1924 need_split = is_abnormal;
1925 }
1803 1926
1804 if (unlikely(need_split)) {1927 if (unlikely(need_split)) {
1805 /*1928 /*
@@ -1840,6 +1963,12 @@ static void dm_split_and_process_bio(struct mapped_device *md, · 34 unmodified lines
1840 goto out;1963 goto out;
1841 }1964 }
1842 1965
1966 if (static_branch_unlikely(&zoned_enabled) &&
1967 (bio_op(bio) == REQ_OP_ZONE_RESET_ALL)) {
1968 error = __send_zone_reset_all(&ci);
1969 goto out;
1970 }
1971
1843 error = __split_and_process_bio(&ci);1972 error = __split_and_process_bio(&ci);
1844 if (error || !ci.sector_count)1973 if (error || !ci.sector_count)
1845 goto out;1974 goto out;
drivers/md/dm.h+3−0
@@ -110,6 +110,9 @@ int dm_blk_report_zones(struct gendisk *disk, sector_t sector, · 109 unmodified lines
110 unsigned int nr_zones, report_zones_cb cb, void *data);110 unsigned int nr_zones, report_zones_cb cb, void *data);
111bool dm_is_zone_write(struct mapped_device *md, struct bio *bio);111bool dm_is_zone_write(struct mapped_device *md, struct bio *bio);
112int dm_zone_map_bio(struct dm_target_io *io);112int dm_zone_map_bio(struct dm_target_io *io);
113int dm_zone_get_reset_bitmap(struct mapped_device *md, struct dm_table *t,
114 sector_t sector, unsigned int nr_zones,
115 unsigned long *need_reset);
113#else116#else
114#define dm_blk_report_zones NULL117#define dm_blk_report_zones NULL
115static inline bool dm_is_zone_write(struct mapped_device *md, struct bio *bio)118static inline bool dm_is_zone_write(struct mapped_device *md, struct bio *bio)
include/linux/device-mapper.h+7−0
@@ -357,6 +357,13 @@ struct dm_target { · 356 unmodified lines
357 */357 */
358 bool discards_supported:1;358 bool discards_supported:1;
359 359
360 /*
361 * Automatically set by dm-core if this target supports
362 * REQ_OP_ZONE_RESET_ALL. Otherwise, this operation will be emulated
363 * using REQ_OP_ZONE_RESET. Target drivers must not set this manually.
364 */
365 bool zone_reset_all_supported:1;
366
360 /*367 /*
361 * Set if this target requires that discards be split on368 * Set if this target requires that discards be split on
362 * 'max_discard_sectors' boundaries.369 * 'max_discard_sectors' boundaries.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t