diff options
| author | Heinz Mauelshagen <mauelshagen@redhat.com> | 2013-03-01 17:45:52 -0500 |
|---|---|---|
| committer | Alasdair G Kergon <agk@redhat.com> | 2013-03-01 17:45:52 -0500 |
| commit | 8735a8134786fa4ef36dee65d7fa779b99ba5fe3 (patch) | |
| tree | 0049cda7a855a2ba7d3e0c4628d983a8466fafbc | |
| parent | f283635281132af7bc7b90af3c105b8c0f73b9c7 (diff) | |
dm cache: add cleaner policy
A simple cache policy that writes back all data to the origin.
This is used to decommission a dm cache by emptying it.
Signed-off-by: Heinz Mauelshagen <mauelshagen@redhat.com>
Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
| -rw-r--r-- | Documentation/device-mapper/cache-policies.txt | 5 | ||||
| -rw-r--r-- | drivers/md/Kconfig | 8 | ||||
| -rw-r--r-- | drivers/md/Makefile | 2 | ||||
| -rw-r--r-- | drivers/md/dm-cache-policy-cleaner.c | 464 |
4 files changed, 479 insertions, 0 deletions
diff --git a/Documentation/device-mapper/cache-policies.txt b/Documentation/device-mapper/cache-policies.txt index 731879f97b80..d7c440b444cc 100644 --- a/Documentation/device-mapper/cache-policies.txt +++ b/Documentation/device-mapper/cache-policies.txt | |||
| @@ -53,6 +53,11 @@ since spindles tend to have good bandwidth. The io_tracker counts | |||
| 53 | contiguous I/Os to try to spot when the io is in one of these sequential | 53 | contiguous I/Os to try to spot when the io is in one of these sequential |
| 54 | modes. | 54 | modes. |
| 55 | 55 | ||
| 56 | cleaner | ||
| 57 | ------- | ||
| 58 | |||
| 59 | The cleaner writes back all dirty blocks in a cache to decommission it. | ||
| 60 | |||
| 56 | Examples | 61 | Examples |
| 57 | ======== | 62 | ======== |
| 58 | 63 | ||
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 1a96cbc7afda..e30b490055aa 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig | |||
| @@ -291,6 +291,14 @@ config DM_CACHE_MQ | |||
| 291 | This is meant to be a general purpose policy. It prioritises | 291 | This is meant to be a general purpose policy. It prioritises |
| 292 | reads over writes. | 292 | reads over writes. |
| 293 | 293 | ||
| 294 | config DM_CACHE_CLEANER | ||
| 295 | tristate "Cleaner Cache Policy (EXPERIMENTAL)" | ||
| 296 | depends on DM_CACHE | ||
| 297 | default y | ||
| 298 | ---help--- | ||
| 299 | A simple cache policy that writes back all data to the | ||
| 300 | origin. Used when decommissioning a dm-cache. | ||
| 301 | |||
| 294 | config DM_MIRROR | 302 | config DM_MIRROR |
| 295 | tristate "Mirror target" | 303 | tristate "Mirror target" |
| 296 | depends on BLK_DEV_DM | 304 | depends on BLK_DEV_DM |
diff --git a/drivers/md/Makefile b/drivers/md/Makefile index adc8710c2408..7ceeaefc0e95 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile | |||
| @@ -13,6 +13,7 @@ dm-log-userspace-y \ | |||
| 13 | dm-thin-pool-y += dm-thin.o dm-thin-metadata.o | 13 | dm-thin-pool-y += dm-thin.o dm-thin-metadata.o |
| 14 | dm-cache-y += dm-cache-target.o dm-cache-metadata.o dm-cache-policy.o | 14 | dm-cache-y += dm-cache-target.o dm-cache-metadata.o dm-cache-policy.o |
| 15 | dm-cache-mq-y += dm-cache-policy-mq.o | 15 | dm-cache-mq-y += dm-cache-policy-mq.o |
| 16 | dm-cache-cleaner-y += dm-cache-policy-cleaner.o | ||
| 16 | md-mod-y += md.o bitmap.o | 17 | md-mod-y += md.o bitmap.o |
| 17 | raid456-y += raid5.o | 18 | raid456-y += raid5.o |
| 18 | 19 | ||
| @@ -48,6 +49,7 @@ obj-$(CONFIG_DM_THIN_PROVISIONING) += dm-thin-pool.o | |||
| 48 | obj-$(CONFIG_DM_VERITY) += dm-verity.o | 49 | obj-$(CONFIG_DM_VERITY) += dm-verity.o |
| 49 | obj-$(CONFIG_DM_CACHE) += dm-cache.o | 50 | obj-$(CONFIG_DM_CACHE) += dm-cache.o |
| 50 | obj-$(CONFIG_DM_CACHE_MQ) += dm-cache-mq.o | 51 | obj-$(CONFIG_DM_CACHE_MQ) += dm-cache-mq.o |
| 52 | obj-$(CONFIG_DM_CACHE_CLEANER) += dm-cache-cleaner.o | ||
| 51 | 53 | ||
| 52 | ifeq ($(CONFIG_DM_UEVENT),y) | 54 | ifeq ($(CONFIG_DM_UEVENT),y) |
| 53 | dm-mod-objs += dm-uevent.o | 55 | dm-mod-objs += dm-uevent.o |
diff --git a/drivers/md/dm-cache-policy-cleaner.c b/drivers/md/dm-cache-policy-cleaner.c new file mode 100644 index 000000000000..cc05d70b3cb8 --- /dev/null +++ b/drivers/md/dm-cache-policy-cleaner.c | |||
| @@ -0,0 +1,464 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 Red Hat. All rights reserved. | ||
| 3 | * | ||
| 4 | * writeback cache policy supporting flushing out dirty cache blocks. | ||
| 5 | * | ||
| 6 | * This file is released under the GPL. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include "dm-cache-policy.h" | ||
| 10 | #include "dm.h" | ||
| 11 | |||
| 12 | #include <linux/hash.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/slab.h> | ||
| 15 | #include <linux/vmalloc.h> | ||
| 16 | |||
| 17 | /*----------------------------------------------------------------*/ | ||
| 18 | |||
| 19 | #define DM_MSG_PREFIX "cache cleaner" | ||
| 20 | #define CLEANER_VERSION "1.0.0" | ||
| 21 | |||
| 22 | /* Cache entry struct. */ | ||
| 23 | struct wb_cache_entry { | ||
| 24 | struct list_head list; | ||
| 25 | struct hlist_node hlist; | ||
| 26 | |||
| 27 | dm_oblock_t oblock; | ||
| 28 | dm_cblock_t cblock; | ||
| 29 | bool dirty:1; | ||
| 30 | bool pending:1; | ||
| 31 | }; | ||
| 32 | |||
| 33 | struct hash { | ||
| 34 | struct hlist_head *table; | ||
| 35 | dm_block_t hash_bits; | ||
| 36 | unsigned nr_buckets; | ||
| 37 | }; | ||
| 38 | |||
| 39 | struct policy { | ||
| 40 | struct dm_cache_policy policy; | ||
| 41 | spinlock_t lock; | ||
| 42 | |||
| 43 | struct list_head free; | ||
| 44 | struct list_head clean; | ||
| 45 | struct list_head clean_pending; | ||
| 46 | struct list_head dirty; | ||
| 47 | |||
| 48 | /* | ||
| 49 | * We know exactly how many cblocks will be needed, | ||
| 50 | * so we can allocate them up front. | ||
| 51 | */ | ||
| 52 | dm_cblock_t cache_size, nr_cblocks_allocated; | ||
| 53 | struct wb_cache_entry *cblocks; | ||
| 54 | struct hash chash; | ||
| 55 | }; | ||
| 56 | |||
| 57 | /*----------------------------------------------------------------------------*/ | ||
| 58 | |||
| 59 | /* | ||
| 60 | * Low-level functions. | ||
| 61 | */ | ||
| 62 | static unsigned next_power(unsigned n, unsigned min) | ||
| 63 | { | ||
| 64 | return roundup_pow_of_two(max(n, min)); | ||
| 65 | } | ||
| 66 | |||
| 67 | static struct policy *to_policy(struct dm_cache_policy *p) | ||
| 68 | { | ||
| 69 | return container_of(p, struct policy, policy); | ||
| 70 | } | ||
| 71 | |||
| 72 | static struct list_head *list_pop(struct list_head *q) | ||
| 73 | { | ||
| 74 | struct list_head *r = q->next; | ||
| 75 | |||
| 76 | list_del(r); | ||
| 77 | |||
| 78 | return r; | ||
| 79 | } | ||
| 80 | |||
| 81 | /*----------------------------------------------------------------------------*/ | ||
| 82 | |||
| 83 | /* Allocate/free various resources. */ | ||
| 84 | static int alloc_hash(struct hash *hash, unsigned elts) | ||
| 85 | { | ||
| 86 | hash->nr_buckets = next_power(elts >> 4, 16); | ||
| 87 | hash->hash_bits = ffs(hash->nr_buckets) - 1; | ||
| 88 | hash->table = vzalloc(sizeof(*hash->table) * hash->nr_buckets); | ||
| 89 | |||
| 90 | return hash->table ? 0 : -ENOMEM; | ||
| 91 | } | ||
| 92 | |||
| 93 | static void free_hash(struct hash *hash) | ||
| 94 | { | ||
| 95 | vfree(hash->table); | ||
| 96 | } | ||
| 97 | |||
| 98 | static int alloc_cache_blocks_with_hash(struct policy *p, dm_cblock_t cache_size) | ||
| 99 | { | ||
| 100 | int r = -ENOMEM; | ||
| 101 | |||
| 102 | p->cblocks = vzalloc(sizeof(*p->cblocks) * from_cblock(cache_size)); | ||
| 103 | if (p->cblocks) { | ||
| 104 | unsigned u = from_cblock(cache_size); | ||
| 105 | |||
| 106 | while (u--) | ||
| 107 | list_add(&p->cblocks[u].list, &p->free); | ||
| 108 | |||
| 109 | p->nr_cblocks_allocated = 0; | ||
| 110 | |||
| 111 | /* Cache entries hash. */ | ||
| 112 | r = alloc_hash(&p->chash, from_cblock(cache_size)); | ||
| 113 | if (r) | ||
| 114 | vfree(p->cblocks); | ||
| 115 | } | ||
| 116 | |||
| 117 | return r; | ||
| 118 | } | ||
| 119 | |||
| 120 | static void free_cache_blocks_and_hash(struct policy *p) | ||
| 121 | { | ||
| 122 | free_hash(&p->chash); | ||
| 123 | vfree(p->cblocks); | ||
| 124 | } | ||
| 125 | |||
| 126 | static struct wb_cache_entry *alloc_cache_entry(struct policy *p) | ||
| 127 | { | ||
| 128 | struct wb_cache_entry *e; | ||
| 129 | |||
| 130 | BUG_ON(from_cblock(p->nr_cblocks_allocated) >= from_cblock(p->cache_size)); | ||
| 131 | |||
| 132 | e = list_entry(list_pop(&p->free), struct wb_cache_entry, list); | ||
