diff options
| -rw-r--r-- | Documentation/device-mapper/cache.txt | 12 | ||||
| -rw-r--r-- | drivers/md/dm-cache-target.c | 225 |
2 files changed, 233 insertions, 4 deletions
diff --git a/Documentation/device-mapper/cache.txt b/Documentation/device-mapper/cache.txt index ff6639f72536..fc9d2dfb9415 100644 --- a/Documentation/device-mapper/cache.txt +++ b/Documentation/device-mapper/cache.txt | |||
| @@ -244,12 +244,22 @@ The message format is: | |||
| 244 | E.g. | 244 | E.g. |
| 245 | dmsetup message my_cache 0 sequential_threshold 1024 | 245 | dmsetup message my_cache 0 sequential_threshold 1024 |
| 246 | 246 | ||
| 247 | |||
| 248 | Invalidation is removing an entry from the cache without writing it | ||
| 249 | back. Cache blocks can be invalidated via the invalidate_cblocks | ||
| 250 | message, which takes an arbitrary number of cblock ranges. | ||
| 251 | |||
| 252 | invalidate_cblocks [<cblock>|<cblock begin>-<cblock end>]* | ||
| 253 | |||
| 254 | E.g. | ||
| 255 | dmsetup message my_cache 0 invalidate_cblocks 2345 3456-4567 5678-6789 | ||
| 256 | |||
| 247 | Examples | 257 | Examples |
| 248 | ======== | 258 | ======== |
| 249 | 259 | ||
| 250 | The test suite can be found here: | 260 | The test suite can be found here: |
| 251 | 261 | ||
| 252 | https://github.com/jthornber/thinp-test-suite | 262 | https://github.com/jthornber/device-mapper-test-suite |
| 253 | 263 | ||
| 254 | dmsetup create my_cache --table '0 41943040 cache /dev/mapper/metadata \ | 264 | dmsetup create my_cache --table '0 41943040 cache /dev/mapper/metadata \ |
| 255 | /dev/mapper/ssd /dev/mapper/origin 512 1 writeback default 0' | 265 | /dev/mapper/ssd /dev/mapper/origin 512 1 writeback default 0' |
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 8c0217753cc5..41e664b474f1 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c | |||
| @@ -150,6 +150,25 @@ struct cache_stats { | |||
| 150 | atomic_t discard_count; | 150 | atomic_t discard_count; |
| 151 | }; | 151 | }; |
| 152 | 152 | ||
| 153 | /* | ||
| 154 | * Defines a range of cblocks, begin to (end - 1) are in the range. end is | ||
| 155 | * the one-past-the-end value. | ||
| 156 | */ | ||
| 157 | struct cblock_range { | ||
| 158 | dm_cblock_t begin; | ||
| 159 | dm_cblock_t end; | ||
| 160 | }; | ||
| 161 | |||
| 162 | struct invalidation_request { | ||
| 163 | struct list_head list; | ||
| 164 | struct cblock_range *cblocks; | ||
| 165 | |||
| 166 | atomic_t complete; | ||
| 167 | int err; | ||
| 168 | |||
| 169 | wait_queue_head_t result_wait; | ||
| 170 | }; | ||
| 171 | |||
| 153 | struct cache { | 172 | struct cache { |
| 154 | struct dm_target *ti; | 173 | struct dm_target *ti; |
| 155 | struct dm_target_callbacks callbacks; | 174 | struct dm_target_callbacks callbacks; |
| @@ -241,6 +260,7 @@ struct cache { | |||
| 241 | 260 | ||
| 242 | bool need_tick_bio:1; | 261 | bool need_tick_bio:1; |
| 243 | bool sized:1; | 262 | bool sized:1; |
| 263 | bool invalidate:1; | ||
| 244 | bool commit_requested:1; | 264 | bool commit_requested:1; |
| 245 | bool loaded_mappings:1; | 265 | bool loaded_mappings:1; |
| 246 | bool loaded_discards:1; | 266 | bool loaded_discards:1; |
| @@ -251,6 +271,12 @@ struct cache { | |||
| 251 | struct cache_features features; | 271 | struct cache_features features; |
| 252 | 272 | ||
| 253 | struct cache_stats stats; | 273 | struct cache_stats stats; |
| 274 | |||
| 275 | /* | ||
| 276 | * Invalidation fields. | ||
| 277 | */ | ||
| 278 | spinlock_t invalidation_lock; | ||
| 279 | struct list_head invalidation_requests; | ||
| 254 | }; | 280 | }; |
| 255 | 281 | ||
| 256 | struct per_bio_data { | 282 | struct per_bio_data { |
| @@ -283,6 +309,7 @@ struct dm_cache_migration { | |||
| 283 | bool demote:1; | 309 | bool demote:1; |
| 284 | bool promote:1; | 310 | bool promote:1; |
| 285 | bool requeue_holder:1; | 311 | bool requeue_holder:1; |
| 312 | bool invalidate:1; | ||
| 286 | 313 | ||
| 287 | struct dm_bio_prison_cell *old_ocell; | 314 | struct dm_bio_prison_cell *old_ocell; |
| 288 | struct dm_bio_prison_cell *new_ocell; | 315 | struct dm_bio_prison_cell *new_ocell; |
| @@ -904,8 +931,11 @@ static void migration_success_post_commit(struct dm_cache_migration *mg) | |||
| 904 | list_add_tail(&mg->list, &cache->quiesced_migrations); | 931 | list_add_tail(&mg->list, &cache->quiesced_migrations); |
| 905 | spin_unlock_irqrestore(&cache->lock, flags); | 932 | spin_unlock_irqrestore(&cache->lock, flags); |
| 906 | 933 | ||
| 907 | } else | 934 | } else { |
| 935 | if (mg->invalidate) | ||
| 936 | policy_remove_mapping(cache->policy, mg->old_oblock); | ||
| 908 | cleanup_migration(mg); | 937 | cleanup_migration(mg); |
| 938 | } | ||
| 909 | 939 | ||
| 910 | } else { | 940 | } else { |
| 911 | if (mg->requeue_holder) | 941 | if (mg->requeue_holder) |
| @@ -1115,6 +1145,7 @@ static void promote(struct cache *cache, struct prealloc *structs, | |||
| 1115 | mg->demote = false; | 1145 | mg->demote = false; |
| 1116 | mg->promote = true; | 1146 | mg->promote = true; |
| 1117 | mg->requeue_holder = true; | 1147 | mg->requeue_holder = true; |
| 1148 | mg->invalidate = false; | ||
| 1118 | mg->cache = cache; | 1149 | mg->cache = cache; |
| 1119 | mg->new_oblock = oblock; | 1150 | mg->new_oblock = oblock; |
| 1120 | mg->cblock = cblock; | 1151 | mg->cblock = cblock; |
| @@ -1137,6 +1168,7 @@ static void writeback(struct cache *cache, struct prealloc *structs, | |||
| 1137 | mg->demote = false; | 1168 | mg->demote = false; |
| 1138 | mg->promote = false; | 1169 | mg->promote = false; |
| 1139 | mg->requeue_holder = true; | 1170 | mg->requeue_holder = true; |
| 1171 | mg->invalidate = false; | ||
| 1140 | mg->cache = cache; | 1172 | mg->cache = cache; |
| 1141 | mg->old_oblock = oblock; | 1173 | mg->old_oblock = oblock; |
| 1142 | mg->cblock = cblock; | 1174 | mg->cblock = cblock; |
| @@ -1161,6 +1193,7 @@ static void demote_then_promote(struct cache *cache, struct prealloc *structs, | |||
| 1161 | mg->demote = true; | 1193 | mg->demote = true; |
| 1162 | mg->promote = true; | 1194 | mg->promote = true; |
| 1163 | mg->requeue_holder = true; | 1195 | mg->requeue_holder = true; |
| 1196 | mg->invalidate = false; | ||
| 1164 | mg->cache = cache; | 1197 | mg->cache = cache; |
| 1165 | mg->old_oblock = old_oblock; | 1198 | mg->old_oblock = old_oblock; |
| 1166 | mg->new_oblock = new_oblock; | 1199 | mg->new_oblock = new_oblock; |
| @@ -1188,6 +1221,7 @@ static void invalidate(struct cache *cache, struct prealloc *structs, | |||
| 1188 | mg->demote = true; | 1221 | mg->demote = true; |
| 1189 | mg->promote = false; | 1222 | mg->promote = false; |
| 1190 | mg->requeue_holder = true; | 1223 | mg->requeue_holder = true; |
| 1224 | mg->invalidate = true; | ||
| 1191 | mg->cache = cache; | 1225 | mg->cache = cache; |
| 1192 | mg->old_oblock = oblock; | 1226 | mg->old_oblock = oblock; |
| 1193 | mg->cblock = cblock; | 1227 | mg->cblock = cblock; |
| @@ -1525,6 +1559,58 @@ static void writeback_some_dirty_blocks(struct cache *cache) | |||
| 1525 | } | 1559 | } |
| 1526 | 1560 | ||
| 1527 | /*---------------------------------------------------------------- | 1561 | /*---------------------------------------------------------------- |
| 1562 | * Invalidations. | ||
| 1563 | * Dropping something from the cache *without* writing back. | ||
| 1564 | *--------------------------------------------------------------*/ | ||
| 1565 | |||
| 1566 | static void process_invalidation_request(struct cache *cache, struct invalidation_request *req) | ||
| 1567 | { | ||
| 1568 | int r = 0; | ||
| 1569 | uint64_t begin = from_cblock(req->cblocks->begin); | ||
| 1570 | uint64_t end = from_cblock(req->cblocks->end); | ||
| 1571 | |||
| 1572 | while (begin != end) { | ||
| 1573 | r = policy_remove_cblock(cache->policy, to_cblock(begin)); | ||
| 1574 | if (!r) { | ||
| 1575 | r = dm_cache_remove_mapping(cache->cmd, to_cblock(begin)); | ||
| 1576 | if (r) | ||
| 1577 | break; | ||
| 1578 | |||
| 1579 | } else if (r == -ENODATA) { | ||
| 1580 | /* harmless, already unmapped */ | ||
| 1581 | r = 0; | ||
| 1582 | |||
| 1583 | } else { | ||
| 1584 | DMERR("policy_remove_cblock failed"); | ||
| 1585 | break; | ||
| 1586 | } | ||
| 1587 | |||
| 1588 | begin++; | ||
| 1589 | } | ||
| 1590 | |||
| 1591 | cache->commit_requested = true; | ||
| 1592 | |||
| 1593 | req->err = r; | ||
| 1594 | atomic_set(&req->complete, 1); | ||
| 1595 | |||
| 1596 | wake_up(&req->result_wait); | ||
| 1597 | } | ||
| 1598 | |||
| 1599 | static void process_invalidation_requests(struct cache *cache) | ||
| 1600 | { | ||
| 1601 | struct list_head list; | ||
| 1602 | struct invalidation_request *req, *tmp; | ||
| 1603 | |||
| 1604 | INIT_LIST_HEAD(&list); | ||
| 1605 | spin_lock(&cache->invalidation_lock); | ||
| 1606 | list_splice_init(&cache->invalidation_requests, &list); | ||
| 1607 | spin_unlock(&cache->invalidation_lock); | ||
| 1608 | |||
| 1609 | list_for_each_entry_safe (req, tmp, &list, list) | ||
| 1610 | process_invalidation_request(cache, req); | ||
| 1611 | } | ||
| 1612 | |||
| 1613 | /*---------------------------------------------------------------- | ||
| 1528 | * Main worker loop | 1614 | * Main worker loop |
| 1529 | *--------------------------------------------------------------*/ | 1615 | *--------------------------------------------------------------*/ |
| 1530 | static bool is_quiescing(struct cache *cache) | 1616 | static bool is_quiescing(struct cache *cache) |
| @@ -1593,7 +1679,8 @@ static int more_work(struct cache *cache) | |||
| 1593 | !bio_list_empty(&cache->deferred_writethrough_bios) || | 1679 | !bio_list_empty(&cache->deferred_writethrough_bios) || |
| 1594 | !list_empty(&cache->quiesced_migrations) || | 1680 | !list_empty(&cache->quiesced_migrations) || |
| 1595 | !list_empty(&cache->completed_migrations) || | 1681 | !list_empty(&cache->completed_migrations) || |
| 1596 | !list_empty(&cache->need_commit_migrations); | 1682 | !list_empty(&cache->need_commit_migrations) || |
| 1683 | cache->invalidate; | ||
| 1597 | } | 1684 | } |
| 1598 | 1685 | ||
| 1599 | static void do_worker(struct work_struct *ws) | 1686 | static void do_worker(struct work_struct *ws) |
| @@ -1605,6 +1692,7 @@ static void do_worker(struct work_struct *ws) | |||
| 1605 | writeback_some_dirty_blocks(cache); | 1692 | writeback_some_dirty_blocks(cache); |
| 1606 | process_deferred_writethrough_bios(cache); | 1693 | process_deferred_writethrough_bios(cache); |
| 1607 | process_deferred_bios(cache); | 1694 | process_deferred_bios(cache); |
| 1695 | process_invalidation_requests(cache); | ||
| 1608 | } | 1696 | } |
| 1609 | 1697 | ||
| 1610 | process_migrations(cache, &cache->quiesced_migrations, issue_copy); | 1698 | process_migrations(cache, &cache->quiesced_migrations, issue_copy); |
| @@ -2271,6 +2359,7 @@ static int cache_create(struct cache_args *ca, struct cache **result) | |||
| 2271 | 2359 | ||
| 2272 | cache->need_tick_bio = true; | 2360 | cache->need_tick_bio = true; |
| 2273 | cache->sized = false; | 2361 | cache->sized = false; |
| 2362 | cache->invalidate = false; | ||
| 2274 | cache->commit_requested = false; | 2363 | cache->commit_requested = false; |
| 2275 | cache->loaded_mappings = false; | 2364 | cache->loaded_mappings = false; |
| 2276 | cache->loaded_discards = false; | 2365 | cache->loaded_discards = false; |
| @@ -2284,6 +2373,9 @@ static int cache_create(struct cache_args *ca, struct cache **result) | |||
| 2284 | atomic_set(&cache->stats.commit_count, 0); | 2373 | atomic_set(&cache->stats.commit_count, 0); |
| 2285 | atomic_set(&cache->stats.discard_count, 0); | 2374 | atomic_set(&cache->stats.discard_count, 0); |
| 2286 | 2375 | ||
| 2376 | spin_lock_init(&cache->invalidation_lock); | ||
| 2377 | INIT_LIST_HEAD(&cache->invalidation_requests); | ||
| 2378 | |||
| 2287 | *result = cache; | 2379 | *result = cache; |
| 2288 | return 0; | 2380 | return 0; |
| 2289 | 2381 | ||
| @@ -2833,7 +2925,128 @@ err: | |||
| 2833 | } | 2925 | } |
| 2834 | 2926 | ||
| 2835 | /* | 2927 | /* |
| 2836 | * Supports <key> <value>. | 2928 | * A cache block range can take two forms: |
| 2929 | * | ||
| 2930 | * i) A single cblock, eg. '3456' | ||
| 2931 | * ii) A begin and end cblock with dots between, eg. 123-234 | ||
| 2932 | */ | ||
| 2933 | static int parse_cblock_range(struct cache *cache, const char *str, | ||
| 2934 | struct cblock_range *result) | ||
| 2935 | { | ||
| 2936 | char dummy; | ||
| 2937 | uint64_t b, e; | ||
| 2938 | int r; | ||
| 2939 | |||
| 2940 | /* | ||
| 2941 | * Try and parse form (ii) first. | ||
| 2942 | */ | ||
| 2943 | r = sscanf(str, "%llu-%llu%c", &b, &e, &dummy); | ||
| 2944 | if (r < 0) | ||
| 2945 | return r; | ||
| 2946 | |||
| 2947 | if (r == 2) { | ||
| 2948 | result->begin = to_cblock(b); | ||
| 2949 | result->end = to_cblock(e); | ||
| 2950 | return 0; | ||
| 2951 | } | ||
| 2952 | |||
| 2953 | /* | ||
| 2954 | * That didn't work, try form (i). | ||
| 2955 | */ | ||
| 2956 | r = sscanf(str, "%llu%c", &b, &dummy); | ||
| 2957 | if (r < 0) | ||
| 2958 | return r; | ||
| 2959 | |||
| 2960 | if (r == 1) { | ||
| 2961 | result->begin = to_cblock(b); | ||
| 2962 | result->end = to_cblock(from_cblock(result->begin) + 1u); | ||
| 2963 | return 0; | ||
| 2964 | } | ||
| 2965 | |||
| 2966 | DMERR("invalid cblock range '%s'", str); | ||
| 2967 | return -EINVAL; | ||
| 2968 | } | ||
| 2969 | |||
| 2970 | static int validate_cblock_range(struct cache *cache, struct cblock_range *range) | ||
| 2971 | { | ||
| 2972 | uint64_t b = from_cblock(range->begin); | ||
| 2973 | uint64_t e = from_cblock(range->end); | ||
| 2974 | uint64_t n = from_cblock(cache->cache_size); | ||
| 2975 | |||
| 2976 | if (b >= n) { | ||
| 2977 | DMERR("begin cblock out of range: %llu >= %llu", b, n); | ||
| 2978 | return -EINVAL; | ||
| 2979 | } | ||
| 2980 | |||
| 2981 | if (e > n) { | ||
| 2982 | DMERR("end cblock out of range: %llu > %llu", e, n); | ||
| 2983 | return -EINVAL; | ||
| 2984 | } | ||
| 2985 | |||
| 2986 | if (b >= e) { | ||
| 2987 | DMERR("invalid cblock range: %llu >= %llu", b, e); | ||
| 2988 | return -EINVAL; | ||
| 2989 | } | ||
| 2990 | |||
| 2991 | return 0; | ||
| 2992 | } | ||
| 2993 | |||
| 2994 | static int request_invalidation(struct cache *cache, struct cblock_range *range) | ||
| 2995 | { | ||
| 2996 | struct invalidation_request req; | ||
| 2997 | |||
| 2998 | INIT_LIST_HEAD(&req.list); | ||
| 2999 | req.cblocks = range; | ||
| 3000 | atomic_set(&req.complete, 0); | ||
| 3001 | req.err = 0; | ||
| 3002 | init_waitqueue_head(&req.result_wait); | ||
| 3003 | |||
| 3004 | spin_lock(&cache->invalidation_lock); | ||
| 3005 | list_add(&req.list, &cache->invalidation_requests); | ||
| 3006 | spin_unlock(&cache->invalidation_lock); | ||
| 3007 | wake_worker(cache); | ||
| 3008 | |||
| 3009 | wait_event(req.result_wait, atomic_read(&req.complete)); | ||
| 3010 | return req.err; | ||
| 3011 | } | ||
| 3012 | |||
| 3013 | static int process_invalidate_cblocks_message(struct cache *cache, unsigned count, | ||
| 3014 | const char **cblock_ranges) | ||
| 3015 | { | ||
| 3016 | int r = 0; | ||
| 3017 | unsigned i; | ||
| 3018 | struct cblock_range range; | ||
| 3019 | |||
| 3020 | if (!passthrough_mode(&cache->features)) { | ||
| 3021 | DMERR("cache has to be in passthrough mode for invalidation"); | ||
| 3022 | return -EPERM; | ||
| 3023 | } | ||
| 3024 | |||
| 3025 | for (i = 0; i < count; i++) { | ||
| 3026 | r = parse_cblock_range(cache, cblock_ranges[i], &range); | ||
| 3027 | if (r) | ||
| 3028 | break; | ||
| 3029 | |||
| 3030 | r = validate_cblock_range(cache, &range); | ||
| 3031 | if (r) | ||
| 3032 | break; | ||
| 3033 | |||
| 3034 | /* | ||
| 3035 | * Pass begin and end origin blocks to the worker and wake it. | ||
| 3036 | */ | ||
| 3037 | r = request_invalidation(cache, &range); | ||
| 3038 | if (r) | ||
| 3039 | break; | ||
| 3040 | } | ||
| 3041 | |||
| 3042 | return r; | ||
| 3043 | } | ||
| 3044 | |||
| 3045 | /* | ||
| 3046 | * Supports | ||
| 3047 | * "<key> <value>" | ||
| 3048 | * and | ||
| 3049 | * "invalidate_cblocks [(<begin>)|(<begin>-<end>)]* | ||
| 2837 | * | 3050 | * |
| 2838 | * The key migration_threshold is supported by the cache target core. | 3051 | * The key migration_threshold is supported by the cache target core. |
| 2839 | */ | 3052 | */ |
| @@ -2841,6 +3054,12 @@ static int cache_message(struct dm_target *ti, unsigned argc, char **argv) | |||
| 2841 | { | 3054 | { |
| 2842 | struct cache *cache = ti->private; | 3055 | struct cache *cache = ti->private; |
| 2843 | 3056 | ||
| 3057 | if (!argc) | ||
| 3058 | return -EINVAL; | ||
| 3059 | |||
| 3060 | if (!strcmp(argv[0], "invalidate_cblocks")) | ||
| 3061 | return process_invalidate_cblocks_message(cache, argc - 1, (const char **) argv + 1); | ||
| 3062 | |||
| 2844 | if (argc != 2) | 3063 | if (argc != 2) |
| 2845 | return -EINVAL; | 3064 | return -EINVAL; |
| 2846 | 3065 | ||
