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

Configure Feed

Select the types of activity you want to include in your feed.

dm thin: fix discard support for data devices

The discard limits that get established for a thin-pool or thin device
may be incompatible with the pool's data device. Avoid this by checking
the discard limits of the pool's data device. If an incompatibility is
found then the pool's 'discard passdown' feature is disabled.

Change thin_io_hints to ensure that a thin device always uses the same
queue limits as its pool device.

Introduce requested_pf to track whether or not the table line originally
contained the no_discard_passdown flag and use this directly for table
output. We prepare the correct setting for discard_passdown directly in
bind_control_target (called from pool_io_hints) and store it in
adjusted_pf rather than waiting until we have access to pool->pf in
pool_preresume.

Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>

authored by

Mike Snitzer and committed by
Alasdair G Kergon
0424caa1 9bc142dd

+57 -30
+57 -30
drivers/md/dm-thin.c
··· 580 580 struct dm_target_callbacks callbacks; 581 581 582 582 dm_block_t low_water_blocks; 583 - struct pool_features pf; 583 + struct pool_features requested_pf; /* Features requested during table load */ 584 + struct pool_features adjusted_pf; /* Features used after adjusting for constituent devices */ 584 585 }; 585 586 586 587 /* ··· 1849 1848 1850 1849 /* 1851 1850 * If discard_passdown was enabled verify that the data device 1852 - * supports discards. Disable discard_passdown if not; otherwise 1853 - * -EOPNOTSUPP will be returned. 1851 + * supports discards. Disable discard_passdown if not. 1854 1852 */ 1855 - static void disable_passdown_if_not_supported(struct pool_c *pt, 1856 - struct pool_features *pf) 1853 + static void disable_passdown_if_not_supported(struct pool_c *pt) 1857 1854 { 1855 + struct pool *pool = pt->pool; 1856 + struct block_device *data_bdev = pt->data_dev->bdev; 1857 + struct queue_limits *data_limits = &bdev_get_queue(data_bdev)->limits; 1858 + sector_t block_size = pool->sectors_per_block << SECTOR_SHIFT; 1859 + const char *reason = NULL; 1858 1860 char buf[BDEVNAME_SIZE]; 1859 1861 1860 - if (!pf->discard_passdown || data_dev_supports_discard(pt)) 1862 + if (!pt->adjusted_pf.discard_passdown) 1861 1863 return; 1862 1864 1863 - DMWARN("Discard unsupported by data device (%s): Disabling discard passdown.", 1864 - bdevname(pt->data_dev->bdev, buf)); 1865 + if (!data_dev_supports_discard(pt)) 1866 + reason = "discard unsupported"; 1865 1867 1866 - pf->discard_passdown = false; 1868 + else if (data_limits->max_discard_sectors < pool->sectors_per_block) 1869 + reason = "max discard sectors smaller than a block"; 1870 + 1871 + else if (data_limits->discard_granularity > block_size) 1872 + reason = "discard granularity larger than a block"; 1873 + 1874 + else if (block_size & (data_limits->discard_granularity - 1)) 1875 + reason = "discard granularity not a factor of block size"; 1876 + 1877 + if (reason) { 1878 + DMWARN("Data device (%s) %s: Disabling discard passdown.", bdevname(data_bdev, buf), reason); 1879 + pt->adjusted_pf.discard_passdown = false; 1880 + } 1867 1881 } 1868 1882 1869 1883 static int bind_control_target(struct pool *pool, struct dm_target *ti) ··· 1889 1873 * We want to make sure that degraded pools are never upgraded. 1890 1874 */ 1891 1875 enum pool_mode old_mode = pool->pf.mode; 1892 - enum pool_mode new_mode = pt->pf.mode; 1876 + enum pool_mode new_mode = pt->adjusted_pf.mode; 1893 1877 1894 1878 if (old_mode > new_mode) 1895 1879 new_mode = old_mode; 1896 1880 1897 1881 pool->ti = ti; 1898 1882 pool->low_water_blocks = pt->low_water_blocks; 1899 - pool->pf = pt->pf; 1883 + pool->pf = pt->adjusted_pf; 1900 1884 1901 - disable_passdown_if_not_supported(pt, &pool->pf); 1902 1885 set_pool_mode(pool, new_mode); 1903 1886 1904 1887 return 0; ··· 2286 2271 pt->metadata_dev = metadata_dev; 2287 2272 pt->data_dev = data_dev; 2288 2273 pt->low_water_blocks = low_water_blocks; 2289 - pt->pf = pf; 2274 + pt->adjusted_pf = pt->requested_pf = pf; 2290 2275 ti->num_flush_requests = 1; 2291 2276 2292 2277 /* ··· 2733 2718 format_dev_t(buf2, pt->data_dev->bdev->bd_dev), 2734 2719 (unsigned long)pool->sectors_per_block, 2735 2720 (unsigned long long)pt->low_water_blocks); 2736 - emit_flags(&pt->pf, result, sz, maxlen); 2721 + emit_flags(&pt->requested_pf, result, sz, maxlen); 2737 2722 break; 2738 2723 } 2739 2724 ··· 2762 2747 return min(max_size, q->merge_bvec_fn(q, bvm, biovec)); 2763 2748 } 2764 2749 2765 - static void set_discard_limits(struct pool *pool, struct queue_limits *limits) 2750 + static void set_discard_limits(struct pool_c *pt, struct queue_limits *limits) 2766 2751 { 2767 - /* 2768 - * FIXME: these limits may be incompatible with the pool's data device 2769 - */ 2752 + struct pool *pool = pt->pool; 2753 + struct queue_limits *data_limits; 2754 + 2770 2755 limits->max_discard_sectors = pool->sectors_per_block; 2771 2756 2772 2757 /* 2773 - * This is just a hint, and not enforced. We have to cope with 2774 - * bios that cover a block partially. A discard that spans a block 2775 - * boundary is not sent to this target. 2758 + * discard_granularity is just a hint, and not enforced. 2776 2759 */ 2777 - limits->discard_granularity = pool->sectors_per_block << SECTOR_SHIFT; 2760 + if (pt->adjusted_pf.discard_passdown) { 2761 + data_limits = &bdev_get_queue(pt->data_dev->bdev)->limits; 2762 + limits->discard_granularity = data_limits->discard_granularity; 2763 + } else 2764 + limits->discard_granularity = pool->sectors_per_block << SECTOR_SHIFT; 2778 2765 } 2779 2766 2780 2767 static void pool_io_hints(struct dm_target *ti, struct queue_limits *limits) ··· 2786 2769 2787 2770 blk_limits_io_min(limits, 0); 2788 2771 blk_limits_io_opt(limits, pool->sectors_per_block << SECTOR_SHIFT); 2789 - if (pool->pf.discard_enabled) 2790 - set_discard_limits(pool, limits); 2772 + 2773 + /* 2774 + * pt->adjusted_pf is a staging area for the actual features to use. 2775 + * They get transferred to the live pool in bind_control_target() 2776 + * called from pool_preresume(). 2777 + */ 2778 + if (!pt->adjusted_pf.discard_enabled) 2779 + return; 2780 + 2781 + disable_passdown_if_not_supported(pt); 2782 + 2783 + set_discard_limits(pt, limits); 2791 2784 } 2792 2785 2793 2786 static struct target_type pool_target = { 2794 2787 .name = "thin-pool", 2795 2788 .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE | 2796 2789 DM_TARGET_IMMUTABLE, 2797 - .version = {1, 3, 0}, 2790 + .version = {1, 4, 0}, 2798 2791 .module = THIS_MODULE, 2799 2792 .ctr = pool_ctr, 2800 2793 .dtr = pool_dtr, ··· 3083 3056 return 0; 3084 3057 } 3085 3058 3059 + /* 3060 + * A thin device always inherits its queue limits from its pool. 3061 + */ 3086 3062 static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits) 3087 3063 { 3088 3064 struct thin_c *tc = ti->private; 3089 - struct pool *pool = tc->pool; 3090 3065 3091 - blk_limits_io_min(limits, 0); 3092 - blk_limits_io_opt(limits, pool->sectors_per_block << SECTOR_SHIFT); 3093 - set_discard_limits(pool, limits); 3066 + *limits = bdev_get_queue(tc->pool_dev->bdev)->limits; 3094 3067 } 3095 3068 3096 3069 static struct target_type thin_target = { 3097 3070 .name = "thin", 3098 - .version = {1, 3, 0}, 3071 + .version = {1, 4, 0}, 3099 3072 .module = THIS_MODULE, 3100 3073 .ctr = thin_ctr, 3101 3074 .dtr = thin_dtr,