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

dm thin: always return -ENOSPC if no_free_space is set

If pool has 'no_free_space' set it means a previous allocation already
determined the pool has no free space (and failed that allocation with
-ENOSPC). By always returning -ENOSPC if 'no_free_space' is set, we do
not allow the pool to oscillate between allocating blocks and then not.

But a side-effect of this determinism is that if a user wants to be able
to allocate new blocks they'll need to reload the pool's table (to clear
the 'no_free_space' flag). This reload will happen automatically if the
pool's data volume is resized. But if the user takes action to free a
lot of space by deleting snapshot volumes, etc the pool will no longer
allow data allocations to continue without an intervening table reload.

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

+32 -26
+32 -26
drivers/md/dm-thin.c
··· 918 918 unsigned long flags; 919 919 struct pool *pool = tc->pool; 920 920 921 + /* 922 + * Once no_free_space is set we must not allow allocation to succeed. 923 + * Otherwise it is difficult to explain, debug, test and support. 924 + */ 925 + if (pool->no_free_space) 926 + return -ENOSPC; 927 + 921 928 r = dm_pool_get_free_block_count(pool->pmd, &free_blocks); 922 929 if (r) 923 930 return r; ··· 939 932 } 940 933 941 934 if (!free_blocks) { 942 - if (pool->no_free_space) 935 + /* 936 + * Try to commit to see if that will free up some 937 + * more space. 938 + */ 939 + (void) commit_or_fallback(pool); 940 + 941 + r = dm_pool_get_free_block_count(pool->pmd, &free_blocks); 942 + if (r) 943 + return r; 944 + 945 + /* 946 + * If we still have no space we set a flag to avoid 947 + * doing all this checking and return -ENOSPC. This 948 + * flag serves as a latch that disallows allocations from 949 + * this pool until the admin takes action (e.g. resize or 950 + * table reload). 951 + */ 952 + if (!free_blocks) { 953 + DMWARN("%s: no free space available.", 954 + dm_device_name(pool->pool_md)); 955 + spin_lock_irqsave(&pool->lock, flags); 956 + pool->no_free_space = 1; 957 + spin_unlock_irqrestore(&pool->lock, flags); 943 958 return -ENOSPC; 944 - else { 945 - /* 946 - * Try to commit to see if that will free up some 947 - * more space. 948 - */ 949 - (void) commit_or_fallback(pool); 950 - 951 - r = dm_pool_get_free_block_count(pool->pmd, &free_blocks); 952 - if (r) 953 - return r; 954 - 955 - /* 956 - * If we still have no space we set a flag to avoid 957 - * doing all this checking and return -ENOSPC. 958 - */ 959 - if (!free_blocks) { 960 - DMWARN("%s: no free space available.", 961 - dm_device_name(pool->pool_md)); 962 - spin_lock_irqsave(&pool->lock, flags); 963 - pool->no_free_space = 1; 964 - spin_unlock_irqrestore(&pool->lock, flags); 965 - return -ENOSPC; 966 - } 967 959 } 968 960 } 969 961 ··· 2701 2695 .name = "thin-pool", 2702 2696 .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE | 2703 2697 DM_TARGET_IMMUTABLE, 2704 - .version = {1, 8, 0}, 2698 + .version = {1, 9, 0}, 2705 2699 .module = THIS_MODULE, 2706 2700 .ctr = pool_ctr, 2707 2701 .dtr = pool_dtr, ··· 2988 2982 2989 2983 static struct target_type thin_target = { 2990 2984 .name = "thin", 2991 - .version = {1, 8, 0}, 2985 + .version = {1, 9, 0}, 2992 2986 .module = THIS_MODULE, 2993 2987 .ctr = thin_ctr, 2994 2988 .dtr = thin_dtr,