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

dm thin: generate event when metadata threshold passed

Generate a dm event when the amount of remaining thin pool metadata
space falls below a certain level.

The threshold is taken to be a quarter of the size of the metadata
device with a minimum threshold of 4MB.

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

authored by

Joe Thornber and committed by
Alasdair G Kergon
ac8c3f3d 2fc48021

+58
+14
drivers/md/dm-thin-metadata.c
··· 1696 1696 dm_bm_set_read_only(pmd->bm); 1697 1697 up_write(&pmd->root_lock); 1698 1698 } 1699 + 1700 + int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd, 1701 + dm_block_t threshold, 1702 + dm_sm_threshold_fn fn, 1703 + void *context) 1704 + { 1705 + int r; 1706 + 1707 + down_write(&pmd->root_lock); 1708 + r = dm_sm_register_threshold_callback(pmd->metadata_sm, threshold, fn, context); 1709 + up_write(&pmd->root_lock); 1710 + 1711 + return r; 1712 + }
+6
drivers/md/dm-thin-metadata.h
··· 8 8 #define DM_THIN_METADATA_H 9 9 10 10 #include "persistent-data/dm-block-manager.h" 11 + #include "persistent-data/dm-space-map.h" 11 12 12 13 #define THIN_METADATA_BLOCK_SIZE 4096 13 14 ··· 193 192 * that nothing is changing. 194 193 */ 195 194 void dm_pool_metadata_read_only(struct dm_pool_metadata *pmd); 195 + 196 + int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd, 197 + dm_block_t threshold, 198 + dm_sm_threshold_fn fn, 199 + void *context); 196 200 197 201 /*----------------------------------------------------------------*/ 198 202
+38
drivers/md/dm-thin.c
··· 1281 1281 bio_io_error(bio); 1282 1282 } 1283 1283 1284 + /* 1285 + * FIXME: should we also commit due to size of transaction, measured in 1286 + * metadata blocks? 1287 + */ 1284 1288 static int need_commit_due_to_time(struct pool *pool) 1285 1289 { 1286 1290 return jiffies < pool->last_commit_jiffies || ··· 1913 1909 return r; 1914 1910 } 1915 1911 1912 + static void metadata_low_callback(void *context) 1913 + { 1914 + struct pool *pool = context; 1915 + 1916 + DMWARN("%s: reached low water mark for metadata device: sending event.", 1917 + dm_device_name(pool->pool_md)); 1918 + 1919 + dm_table_event(pool->ti->table); 1920 + } 1921 + 1916 1922 static sector_t get_metadata_dev_size(struct block_device *bdev) 1917 1923 { 1918 1924 sector_t metadata_dev_size = i_size_read(bdev->bd_inode) >> SECTOR_SHIFT; ··· 1944 1930 sector_div(metadata_dev_size, THIN_METADATA_BLOCK_SIZE >> SECTOR_SHIFT); 1945 1931 1946 1932 return metadata_dev_size; 1933 + } 1934 + 1935 + /* 1936 + * When a metadata threshold is crossed a dm event is triggered, and 1937 + * userland should respond by growing the metadata device. We could let 1938 + * userland set the threshold, like we do with the data threshold, but I'm 1939 + * not sure they know enough to do this well. 1940 + */ 1941 + static dm_block_t calc_metadata_threshold(struct pool_c *pt) 1942 + { 1943 + /* 1944 + * 4M is ample for all ops with the possible exception of thin 1945 + * device deletion which is harmless if it fails (just retry the 1946 + * delete after you've grown the device). 1947 + */ 1948 + dm_block_t quarter = get_metadata_dev_size_in_blocks(pt->metadata_dev->bdev) / 4; 1949 + return min((dm_block_t)1024ULL /* 4M */, quarter); 1947 1950 } 1948 1951 1949 1952 /* ··· 2095 2064 ti->discard_zeroes_data_unsupported = true; 2096 2065 } 2097 2066 ti->private = pt; 2067 + 2068 + r = dm_pool_register_metadata_threshold(pt->pool->pmd, 2069 + calc_metadata_threshold(pt), 2070 + metadata_low_callback, 2071 + pool); 2072 + if (r) 2073 + goto out_free_pt; 2098 2074 2099 2075 pt->callbacks.congested_fn = pool_is_congested; 2100 2076 dm_table_add_target_callbacks(ti->table, &pt->callbacks);