Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4646015d authored by Joe Thornber's avatar Joe Thornber Committed by Mike Snitzer
Browse files

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: default avatarJoe Thornber <ejt@redhat.com>
Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
parent e5cfc69a
Loading
Loading
Loading
Loading
+75 −2
Original line number Original line Diff line number Diff line
@@ -10,6 +10,8 @@
#include "dm-persistent-data-internal.h"
#include "dm-persistent-data-internal.h"


#include <linux/export.h>
#include <linux/export.h>
#include <linux/mutex.h>
#include <linux/hash.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/device-mapper.h>
#include <linux/device-mapper.h>


@@ -17,6 +19,61 @@


/*----------------------------------------------------------------*/
/*----------------------------------------------------------------*/


#define PREFETCH_SIZE 128
#define PREFETCH_BITS 7
#define PREFETCH_SENTINEL ((dm_block_t) -1ULL)

struct prefetch_set {
	struct mutex lock;
	dm_block_t blocks[PREFETCH_SIZE];
};

static unsigned prefetch_hash(dm_block_t b)
{
	return hash_64(b, PREFETCH_BITS);
}

static void prefetch_wipe(struct prefetch_set *p)
{
	unsigned i;
	for (i = 0; i < PREFETCH_SIZE; i++)
		p->blocks[i] = PREFETCH_SENTINEL;
}

static void prefetch_init(struct prefetch_set *p)
{
	mutex_init(&p->lock);
	prefetch_wipe(p);
}

static void prefetch_add(struct prefetch_set *p, dm_block_t b)
{
	unsigned h = prefetch_hash(b);

	mutex_lock(&p->lock);
	if (p->blocks[h] == PREFETCH_SENTINEL)
		p->blocks[h] = b;

	mutex_unlock(&p->lock);
}

static void prefetch_issue(struct prefetch_set *p, struct dm_block_manager *bm)
{
	unsigned i;

	mutex_lock(&p->lock);

	for (i = 0; i < PREFETCH_SIZE; i++)
		if (p->blocks[i] != PREFETCH_SENTINEL) {
			dm_bm_prefetch(bm, p->blocks[i]);
			p->blocks[i] = PREFETCH_SENTINEL;
		}

	mutex_unlock(&p->lock);
}

/*----------------------------------------------------------------*/

struct shadow_info {
struct shadow_info {
	struct hlist_node hlist;
	struct hlist_node hlist;
	dm_block_t where;
	dm_block_t where;
@@ -37,6 +94,8 @@ struct dm_transaction_manager {


	spinlock_t lock;
	spinlock_t lock;
	struct hlist_head buckets[DM_HASH_SIZE];
	struct hlist_head buckets[DM_HASH_SIZE];

	struct prefetch_set prefetches;
};
};


/*----------------------------------------------------------------*/
/*----------------------------------------------------------------*/
@@ -117,6 +176,8 @@ static struct dm_transaction_manager *dm_tm_create(struct dm_block_manager *bm,
	for (i = 0; i < DM_HASH_SIZE; i++)
	for (i = 0; i < DM_HASH_SIZE; i++)
		INIT_HLIST_HEAD(tm->buckets + i);
		INIT_HLIST_HEAD(tm->buckets + i);


	prefetch_init(&tm->prefetches);

	return tm;
	return tm;
}
}


@@ -268,8 +329,14 @@ int dm_tm_read_lock(struct dm_transaction_manager *tm, dm_block_t b,
		    struct dm_block_validator *v,
		    struct dm_block_validator *v,
		    struct dm_block **blk)
		    struct dm_block **blk)
{
{
	if (tm->is_clone)
	if (tm->is_clone) {
		return dm_bm_read_try_lock(tm->real->bm, b, v, blk);
		int r = dm_bm_read_try_lock(tm->real->bm, b, v, blk);

		if (r == -EWOULDBLOCK)
			prefetch_add(&tm->real->prefetches, b);

		return r;
	}


	return dm_bm_read_lock(tm->bm, b, v, blk);
	return dm_bm_read_lock(tm->bm, b, v, blk);
}
}
@@ -317,6 +384,12 @@ struct dm_block_manager *dm_tm_get_bm(struct dm_transaction_manager *tm)
	return tm->bm;
	return tm->bm;
}
}


void dm_tm_issue_prefetches(struct dm_transaction_manager *tm)
{
	prefetch_issue(&tm->prefetches, tm->bm);
}
EXPORT_SYMBOL_GPL(dm_tm_issue_prefetches);

/*----------------------------------------------------------------*/
/*----------------------------------------------------------------*/


static int dm_tm_create_internal(struct dm_block_manager *bm,
static int dm_tm_create_internal(struct dm_block_manager *bm,
+7 −0
Original line number Original line Diff line number Diff line
@@ -108,6 +108,13 @@ int dm_tm_ref(struct dm_transaction_manager *tm, dm_block_t b,


struct dm_block_manager *dm_tm_get_bm(struct dm_transaction_manager *tm);
struct dm_block_manager *dm_tm_get_bm(struct dm_transaction_manager *tm);


/*
 * If you're using a non-blocking clone the tm will build up a list of
 * requested blocks that weren't in core.  This call will request those
 * blocks to be prefetched.
 */
void dm_tm_issue_prefetches(struct dm_transaction_manager *tm);

/*
/*
 * A little utility that ties the knot by producing a transaction manager
 * A little utility that ties the knot by producing a transaction manager
 * that has a space map managed by the transaction manager...
 * that has a space map managed by the transaction manager...