diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-09 00:10:03 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-09 00:10:03 -0500 |
commit | 140dfc9299c33bbfc9350fa061f5ab65cb83df13 (patch) | |
tree | 09508691964e277f4835d30f7b9c3962e8cac596 /drivers/md/persistent-data | |
parent | f94784bdb114439eb3a5e62343826887bbf3f37c (diff) | |
parent | 1a71d6ffe18c0d0f03fc8531949cc8ed41d702ee (diff) |
Merge tag 'dm-3.19-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm
Pull device mapper updates from Mike Snitzer:
- Significant DM thin-provisioning performance improvements to meet
performance requirements that were requested by the Gluster
distributed filesystem.
Specifically, dm-thinp now takes care to aggregate IO that will be
issued to the same thinp block before issuing IO to the underlying
devices. This really helps improve performance on HW RAID6 devices
that have a writeback cache because it avoids RMW in the HW RAID
controller.
- Some stable fixes: fix leak in DM bufio if integrity profiles were
enabled, use memzero_explicit in DM crypt to avoid any potential for
information leak, and a DM cache fix to properly mark a cache block
dirty if it was promoted to the cache via the overwrite optimization.
- A few simple DM persistent data library fixes
- DM cache multiqueue policy block promotion improvements.
- DM cache discard improvements that take advantage of range
(multiblock) discard support in the DM bio-prison. This allows for
much more efficient bulk discard processing (e.g. when mkfs.xfs
discards the entire device).
- Some small optimizations in DM core and RCU deference cleanups
- DM core changes to suspend/resume code to introduce the new internal
suspend/resume interface that the DM thin-pool target now uses to
suspend/resume active thin devices when the thin-pool must
suspend/resume.
This avoids forcing userspace to track all active thin volumes in a
thin-pool when the thin-pool is suspended for the purposes of
metadata or data space resize.
* tag 'dm-3.19-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm: (49 commits)
dm crypt: use memzero_explicit for on-stack buffer
dm space map metadata: fix sm_bootstrap_get_count()
dm space map metadata: fix sm_bootstrap_get_nr_blocks()
dm bufio: fix memleak when using a dm_buffer's inline bio
dm cache: fix spurious cell_defer when dealing with partial block at end of device
dm cache: dirty flag was mistakenly being cleared when promoting via overwrite
dm cache: only use overwrite optimisation for promotion when in writeback mode
dm cache: discard block size must be a multiple of cache block size
dm cache: fix a harmless race when working out if a block is discarded
dm cache: when reloading a discard bitset allow for a different discard block size
dm cache: fix some issues with the new discard range support
dm array: if resizing the array is a noop set the new root to the old one
dm: use rcu_dereference_protected instead of rcu_dereference
dm thin: fix pool_io_hints to avoid looking at max_hw_sectors
dm thin: suspend/resume active thin devices when reloading thin-pool
dm: enhance internal suspend and resume interface
dm thin: do not allow thin device activation while pool is suspended
dm: add presuspend_undo hook to target_type
dm: return earlier from dm_blk_ioctl if target doesn't implement .ioctl
dm thin: remove stale 'trim' message in block comment above pool_message
...
Diffstat (limited to 'drivers/md/persistent-data')
-rw-r--r-- | drivers/md/persistent-data/dm-array.c | 4 | ||||
-rw-r--r-- | drivers/md/persistent-data/dm-space-map-metadata.c | 8 | ||||
-rw-r--r-- | drivers/md/persistent-data/dm-transaction-manager.c | 77 | ||||
-rw-r--r-- | drivers/md/persistent-data/dm-transaction-manager.h | 7 |
4 files changed, 91 insertions, 5 deletions
diff --git a/drivers/md/persistent-data/dm-array.c b/drivers/md/persistent-data/dm-array.c index 1d75b1dc1e2e..e64b61ad0ef3 100644 --- a/drivers/md/persistent-data/dm-array.c +++ b/drivers/md/persistent-data/dm-array.c | |||
@@ -645,8 +645,10 @@ static int array_resize(struct dm_array_info *info, dm_block_t root, | |||
645 | int r; | 645 | int r; |
646 | struct resize resize; | 646 | struct resize resize; |
647 | 647 | ||
648 | if (old_size == new_size) | 648 | if (old_size == new_size) { |
649 | *new_root = root; | ||
649 | return 0; | 650 | return 0; |
651 | } | ||
650 | 652 | ||
651 | resize.info = info; | 653 | resize.info = info; |
652 | resize.root = root; | 654 | resize.root = root; |
diff --git a/drivers/md/persistent-data/dm-space-map-metadata.c b/drivers/md/persistent-data/dm-space-map-metadata.c index 786b689bdfc7..e8a904298887 100644 --- a/drivers/md/persistent-data/dm-space-map-metadata.c +++ b/drivers/md/persistent-data/dm-space-map-metadata.c | |||
@@ -564,7 +564,9 @@ static int sm_bootstrap_get_nr_blocks(struct dm_space_map *sm, dm_block_t *count | |||
564 | { | 564 | { |
565 | struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); | 565 | struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); |
566 | 566 | ||
567 | return smm->ll.nr_blocks; | 567 | *count = smm->ll.nr_blocks; |
568 | |||
569 | return 0; | ||
568 | } | 570 | } |
569 | 571 | ||
570 | static int sm_bootstrap_get_nr_free(struct dm_space_map *sm, dm_block_t *count) | 572 | static int sm_bootstrap_get_nr_free(struct dm_space_map *sm, dm_block_t *count) |
@@ -581,7 +583,9 @@ static int sm_bootstrap_get_count(struct dm_space_map *sm, dm_block_t b, | |||
581 | { | 583 | { |
582 | struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); | 584 | struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); |
583 | 585 | ||
584 | return b < smm->begin ? 1 : 0; | 586 | *result = (b < smm->begin) ? 1 : 0; |
587 | |||
588 | return 0; | ||
585 | } | 589 | } |
586 | 590 | ||
587 | static int sm_bootstrap_count_is_more_than_one(struct dm_space_map *sm, | 591 | static int sm_bootstrap_count_is_more_than_one(struct dm_space_map *sm, |
diff --git a/drivers/md/persistent-data/dm-transaction-manager.c b/drivers/md/persistent-data/dm-transaction-manager.c index 3bc30a0ae3d6..9cb797d800cf 100644 --- a/drivers/md/persistent-data/dm-transaction-manager.c +++ b/drivers/md/persistent-data/dm-transaction-manager.c | |||
@@ -10,6 +10,8 @@ | |||
10 | #include "dm-persistent-data-internal.h" | 10 | #include "dm-persistent-data-internal.h" |
11 | 11 | ||
12 | #include <linux/export.h> | 12 | #include <linux/export.h> |
13 | #include <linux/mutex.h> | ||
14 | #include <linux/hash.h> | ||
13 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
14 | #include <linux/device-mapper.h> | 16 | #include <linux/device-mapper.h> |
15 | 17 | ||
@@ -17,6 +19,61 @@ | |||
17 | 19 | ||
18 | /*----------------------------------------------------------------*/ | 20 | /*----------------------------------------------------------------*/ |
19 | 21 | ||
22 | #define PREFETCH_SIZE 128 | ||
23 | #define PREFETCH_BITS 7 | ||
24 | #define PREFETCH_SENTINEL ((dm_block_t) -1ULL) | ||
25 | |||
26 | struct prefetch_set { | ||
27 | struct mutex lock; | ||
28 | dm_block_t blocks[PREFETCH_SIZE]; | ||
29 | }; | ||
30 | |||
31 | static unsigned prefetch_hash(dm_block_t b) | ||
32 | { | ||
33 | return hash_64(b, PREFETCH_BITS); | ||
34 | } | ||
35 | |||
36 | static void prefetch_wipe(struct prefetch_set *p) | ||
37 | { | ||
38 | unsigned i; | ||
39 | for (i = 0; i < PREFETCH_SIZE; i++) | ||
40 | p->blocks[i] = PREFETCH_SENTINEL; | ||
41 | } | ||
42 | |||
43 | static void prefetch_init(struct prefetch_set *p) | ||
44 | { | ||
45 | mutex_init(&p->lock); | ||
46 | prefetch_wipe(p); | ||
47 | } | ||
48 | |||
49 | static void prefetch_add(struct prefetch_set *p, dm_block_t b) | ||
50 | { | ||
51 | unsigned h = prefetch_hash(b); | ||
52 | |||
53 | mutex_lock(&p->lock); | ||
54 | if (p->blocks[h] == PREFETCH_SENTINEL) | ||
55 | p->blocks[h] = b; | ||
56 | |||
57 | mutex_unlock(&p->lock); | ||
58 | } | ||
59 | |||
60 | static void prefetch_issue(struct prefetch_set *p, struct dm_block_manager *bm) | ||
61 | { | ||
62 | unsigned i; | ||
63 | |||
64 | mutex_lock(&p->lock); | ||
65 | |||
66 | for (i = 0; i < PREFETCH_SIZE; i++) | ||
67 | if (p->blocks[i] != PREFETCH_SENTINEL) { | ||
68 | dm_bm_prefetch(bm, p->blocks[i]); | ||
69 | p->blocks[i] = PREFETCH_SENTINEL; | ||
70 | } | ||
71 | |||
72 | mutex_unlock(&p->lock); | ||
73 | } | ||
74 | |||
75 | /*----------------------------------------------------------------*/ | ||
76 | |||
20 | struct shadow_info { | 77 | struct shadow_info { |
21 | struct hlist_node hlist; | 78 | struct hlist_node hlist; |
22 | dm_block_t where; | 79 | dm_block_t where; |
@@ -37,6 +94,8 @@ struct dm_transaction_manager { | |||
37 | 94 | ||
38 | spinlock_t lock; | 95 | spinlock_t lock; |
39 | struct hlist_head buckets[DM_HASH_SIZE]; | 96 | struct hlist_head buckets[DM_HASH_SIZE]; |
97 | |||
98 | struct prefetch_set prefetches; | ||
40 | }; | 99 | }; |
41 | 100 | ||
42 | /*----------------------------------------------------------------*/ | 101 | /*----------------------------------------------------------------*/ |
@@ -117,6 +176,8 @@ static struct dm_transaction_manager *dm_tm_create(struct dm_block_manager *bm, | |||
117 | for (i = 0; i < DM_HASH_SIZE; i++) | 176 | for (i = 0; i < DM_HASH_SIZE; i++) |
118 | INIT_HLIST_HEAD(tm->buckets + i); | 177 | INIT_HLIST_HEAD(tm->buckets + i); |
119 | 178 | ||
179 | prefetch_init(&tm->prefetches); | ||
180 | |||
120 | return tm; | 181 | return tm; |
121 | } | 182 | } |
122 | 183 | ||
@@ -268,8 +329,14 @@ int dm_tm_read_lock(struct dm_transaction_manager *tm, dm_block_t b, | |||
268 | struct dm_block_validator *v, | 329 | struct dm_block_validator *v, |
269 | struct dm_block **blk) | 330 | struct dm_block **blk) |
270 | { | 331 | { |
271 | if (tm->is_clone) | 332 | if (tm->is_clone) { |
272 | return dm_bm_read_try_lock(tm->real->bm, b, v, blk); | 333 | int r = dm_bm_read_try_lock(tm->real->bm, b, v, blk); |
334 | |||
335 | if (r == -EWOULDBLOCK) | ||
336 | prefetch_add(&tm->real->prefetches, b); | ||
337 | |||
338 | return r; | ||
339 | } | ||
273 | 340 | ||
274 | return dm_bm_read_lock(tm->bm, b, v, blk); | 341 | return dm_bm_read_lock(tm->bm, b, v, blk); |
275 | } | 342 | } |
@@ -317,6 +384,12 @@ struct dm_block_manager *dm_tm_get_bm(struct dm_transaction_manager *tm) | |||
317 | return tm->bm; | 384 | return tm->bm; |
318 | } | 385 | } |
319 | 386 | ||
387 | void dm_tm_issue_prefetches(struct dm_transaction_manager *tm) | ||
388 | { | ||
389 | prefetch_issue(&tm->prefetches, tm->bm); | ||
390 | } | ||
391 | EXPORT_SYMBOL_GPL(dm_tm_issue_prefetches); | ||
392 | |||
320 | /*----------------------------------------------------------------*/ | 393 | /*----------------------------------------------------------------*/ |
321 | 394 | ||
322 | static int dm_tm_create_internal(struct dm_block_manager *bm, | 395 | static int dm_tm_create_internal(struct dm_block_manager *bm, |
diff --git a/drivers/md/persistent-data/dm-transaction-manager.h b/drivers/md/persistent-data/dm-transaction-manager.h index 2772ed2a781a..2e0d4d66fb1b 100644 --- a/drivers/md/persistent-data/dm-transaction-manager.h +++ b/drivers/md/persistent-data/dm-transaction-manager.h | |||
@@ -109,6 +109,13 @@ int dm_tm_ref(struct dm_transaction_manager *tm, dm_block_t b, | |||
109 | struct dm_block_manager *dm_tm_get_bm(struct dm_transaction_manager *tm); | 109 | struct dm_block_manager *dm_tm_get_bm(struct dm_transaction_manager *tm); |
110 | 110 | ||
111 | /* | 111 | /* |
112 | * If you're using a non-blocking clone the tm will build up a list of | ||
113 | * requested blocks that weren't in core. This call will request those | ||
114 | * blocks to be prefetched. | ||
115 | */ | ||
116 | void dm_tm_issue_prefetches(struct dm_transaction_manager *tm); | ||
117 | |||
118 | /* | ||
112 | * A little utility that ties the knot by producing a transaction manager | 119 | * A little utility that ties the knot by producing a transaction manager |
113 | * that has a space map managed by the transaction manager... | 120 | * that has a space map managed by the transaction manager... |
114 | * | 121 | * |