diff options
| author | Joe Thornber <ejt@redhat.com> | 2014-10-06 10:27:26 -0400 |
|---|---|---|
| committer | Mike Snitzer <snitzer@redhat.com> | 2014-11-10 15:25:26 -0500 |
| commit | 4646015d7e4ca5a4dc19427fb0a0aeff15a4fd91 (patch) | |
| tree | 5afe82e874f9eff6eeb70e77db458b22dcea3307 /drivers/md/persistent-data | |
| parent | e5cfc69a513cdc9d9e753c5ce07f0cc6b496bfd3 (diff) | |
dm transaction manager: add support for prefetching blocks of metadata
Introduce the dm_tm_issue_prefetches interface. If you're using a
non-blocking clone the tm will build up a list of requested blocks that
weren't in core. dm_tm_issue_prefetches will request those blocks to be
prefetched.
Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Diffstat (limited to 'drivers/md/persistent-data')
| -rw-r--r-- | drivers/md/persistent-data/dm-transaction-manager.c | 77 | ||||
| -rw-r--r-- | drivers/md/persistent-data/dm-transaction-manager.h | 7 |
2 files changed, 82 insertions, 2 deletions
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 | * |
