xref: /linux/drivers/md/persistent-data/dm-transaction-manager.c (revision e5451c8f8330e03ad3cfa16048b4daf961af434f)
13241b1d3SJoe Thornber /*
23241b1d3SJoe Thornber  * Copyright (C) 2011 Red Hat, Inc.
33241b1d3SJoe Thornber  *
43241b1d3SJoe Thornber  * This file is released under the GPL.
53241b1d3SJoe Thornber  */
63241b1d3SJoe Thornber #include "dm-transaction-manager.h"
73241b1d3SJoe Thornber #include "dm-space-map.h"
83241b1d3SJoe Thornber #include "dm-space-map-disk.h"
93241b1d3SJoe Thornber #include "dm-space-map-metadata.h"
103241b1d3SJoe Thornber #include "dm-persistent-data-internal.h"
113241b1d3SJoe Thornber 
121944ce60SPaul Gortmaker #include <linux/export.h>
134646015dSJoe Thornber #include <linux/mutex.h>
144646015dSJoe Thornber #include <linux/hash.h>
153241b1d3SJoe Thornber #include <linux/slab.h>
163241b1d3SJoe Thornber #include <linux/device-mapper.h>
173241b1d3SJoe Thornber 
183241b1d3SJoe Thornber #define DM_MSG_PREFIX "transaction manager"
193241b1d3SJoe Thornber 
203241b1d3SJoe Thornber /*----------------------------------------------------------------*/
213241b1d3SJoe Thornber 
224646015dSJoe Thornber #define PREFETCH_SIZE 128
234646015dSJoe Thornber #define PREFETCH_BITS 7
244646015dSJoe Thornber #define PREFETCH_SENTINEL ((dm_block_t) -1ULL)
254646015dSJoe Thornber 
264646015dSJoe Thornber struct prefetch_set {
274646015dSJoe Thornber 	struct mutex lock;
284646015dSJoe Thornber 	dm_block_t blocks[PREFETCH_SIZE];
294646015dSJoe Thornber };
304646015dSJoe Thornber 
314646015dSJoe Thornber static unsigned prefetch_hash(dm_block_t b)
324646015dSJoe Thornber {
334646015dSJoe Thornber 	return hash_64(b, PREFETCH_BITS);
344646015dSJoe Thornber }
354646015dSJoe Thornber 
364646015dSJoe Thornber static void prefetch_wipe(struct prefetch_set *p)
374646015dSJoe Thornber {
384646015dSJoe Thornber 	unsigned i;
394646015dSJoe Thornber 	for (i = 0; i < PREFETCH_SIZE; i++)
404646015dSJoe Thornber 		p->blocks[i] = PREFETCH_SENTINEL;
414646015dSJoe Thornber }
424646015dSJoe Thornber 
434646015dSJoe Thornber static void prefetch_init(struct prefetch_set *p)
444646015dSJoe Thornber {
454646015dSJoe Thornber 	mutex_init(&p->lock);
464646015dSJoe Thornber 	prefetch_wipe(p);
474646015dSJoe Thornber }
484646015dSJoe Thornber 
494646015dSJoe Thornber static void prefetch_add(struct prefetch_set *p, dm_block_t b)
504646015dSJoe Thornber {
514646015dSJoe Thornber 	unsigned h = prefetch_hash(b);
524646015dSJoe Thornber 
534646015dSJoe Thornber 	mutex_lock(&p->lock);
544646015dSJoe Thornber 	if (p->blocks[h] == PREFETCH_SENTINEL)
554646015dSJoe Thornber 		p->blocks[h] = b;
564646015dSJoe Thornber 
574646015dSJoe Thornber 	mutex_unlock(&p->lock);
584646015dSJoe Thornber }
594646015dSJoe Thornber 
604646015dSJoe Thornber static void prefetch_issue(struct prefetch_set *p, struct dm_block_manager *bm)
614646015dSJoe Thornber {
624646015dSJoe Thornber 	unsigned i;
634646015dSJoe Thornber 
644646015dSJoe Thornber 	mutex_lock(&p->lock);
654646015dSJoe Thornber 
664646015dSJoe Thornber 	for (i = 0; i < PREFETCH_SIZE; i++)
674646015dSJoe Thornber 		if (p->blocks[i] != PREFETCH_SENTINEL) {
684646015dSJoe Thornber 			dm_bm_prefetch(bm, p->blocks[i]);
694646015dSJoe Thornber 			p->blocks[i] = PREFETCH_SENTINEL;
704646015dSJoe Thornber 		}
714646015dSJoe Thornber 
724646015dSJoe Thornber 	mutex_unlock(&p->lock);
734646015dSJoe Thornber }
744646015dSJoe Thornber 
754646015dSJoe Thornber /*----------------------------------------------------------------*/
764646015dSJoe Thornber 
773241b1d3SJoe Thornber struct shadow_info {
783241b1d3SJoe Thornber 	struct hlist_node hlist;
793241b1d3SJoe Thornber 	dm_block_t where;
803241b1d3SJoe Thornber };
813241b1d3SJoe Thornber 
823241b1d3SJoe Thornber /*
833241b1d3SJoe Thornber  * It would be nice if we scaled with the size of transaction.
843241b1d3SJoe Thornber  */
85df855798SAndrew Morton #define DM_HASH_SIZE 256
86df855798SAndrew Morton #define DM_HASH_MASK (DM_HASH_SIZE - 1)
873241b1d3SJoe Thornber 
883241b1d3SJoe Thornber struct dm_transaction_manager {
893241b1d3SJoe Thornber 	int is_clone;
903241b1d3SJoe Thornber 	struct dm_transaction_manager *real;
913241b1d3SJoe Thornber 
923241b1d3SJoe Thornber 	struct dm_block_manager *bm;
933241b1d3SJoe Thornber 	struct dm_space_map *sm;
943241b1d3SJoe Thornber 
953241b1d3SJoe Thornber 	spinlock_t lock;
96df855798SAndrew Morton 	struct hlist_head buckets[DM_HASH_SIZE];
974646015dSJoe Thornber 
984646015dSJoe Thornber 	struct prefetch_set prefetches;
993241b1d3SJoe Thornber };
1003241b1d3SJoe Thornber 
1013241b1d3SJoe Thornber /*----------------------------------------------------------------*/
1023241b1d3SJoe Thornber 
1033241b1d3SJoe Thornber static int is_shadow(struct dm_transaction_manager *tm, dm_block_t b)
1043241b1d3SJoe Thornber {
1053241b1d3SJoe Thornber 	int r = 0;
106df855798SAndrew Morton 	unsigned bucket = dm_hash_block(b, DM_HASH_MASK);
1073241b1d3SJoe Thornber 	struct shadow_info *si;
1083241b1d3SJoe Thornber 
1093241b1d3SJoe Thornber 	spin_lock(&tm->lock);
110b67bfe0dSSasha Levin 	hlist_for_each_entry(si, tm->buckets + bucket, hlist)
1113241b1d3SJoe Thornber 		if (si->where == b) {
1123241b1d3SJoe Thornber 			r = 1;
1133241b1d3SJoe Thornber 			break;
1143241b1d3SJoe Thornber 		}
1153241b1d3SJoe Thornber 	spin_unlock(&tm->lock);
1163241b1d3SJoe Thornber 
1173241b1d3SJoe Thornber 	return r;
1183241b1d3SJoe Thornber }
1193241b1d3SJoe Thornber 
1203241b1d3SJoe Thornber /*
1213241b1d3SJoe Thornber  * This can silently fail if there's no memory.  We're ok with this since
1223241b1d3SJoe Thornber  * creating redundant shadows causes no harm.
1233241b1d3SJoe Thornber  */
1243241b1d3SJoe Thornber static void insert_shadow(struct dm_transaction_manager *tm, dm_block_t b)
1253241b1d3SJoe Thornber {
1263241b1d3SJoe Thornber 	unsigned bucket;
1273241b1d3SJoe Thornber 	struct shadow_info *si;
1283241b1d3SJoe Thornber 
1293241b1d3SJoe Thornber 	si = kmalloc(sizeof(*si), GFP_NOIO);
1303241b1d3SJoe Thornber 	if (si) {
1313241b1d3SJoe Thornber 		si->where = b;
132df855798SAndrew Morton 		bucket = dm_hash_block(b, DM_HASH_MASK);
1333241b1d3SJoe Thornber 		spin_lock(&tm->lock);
1343241b1d3SJoe Thornber 		hlist_add_head(&si->hlist, tm->buckets + bucket);
1353241b1d3SJoe Thornber 		spin_unlock(&tm->lock);
1363241b1d3SJoe Thornber 	}
1373241b1d3SJoe Thornber }
1383241b1d3SJoe Thornber 
1393241b1d3SJoe Thornber static void wipe_shadow_table(struct dm_transaction_manager *tm)
1403241b1d3SJoe Thornber {
1413241b1d3SJoe Thornber 	struct shadow_info *si;
142b67bfe0dSSasha Levin 	struct hlist_node *tmp;
1433241b1d3SJoe Thornber 	struct hlist_head *bucket;
1443241b1d3SJoe Thornber 	int i;
1453241b1d3SJoe Thornber 
1463241b1d3SJoe Thornber 	spin_lock(&tm->lock);
147df855798SAndrew Morton 	for (i = 0; i < DM_HASH_SIZE; i++) {
1483241b1d3SJoe Thornber 		bucket = tm->buckets + i;
149b67bfe0dSSasha Levin 		hlist_for_each_entry_safe(si, tmp, bucket, hlist)
1503241b1d3SJoe Thornber 			kfree(si);
1513241b1d3SJoe Thornber 
1523241b1d3SJoe Thornber 		INIT_HLIST_HEAD(bucket);
1533241b1d3SJoe Thornber 	}
1543241b1d3SJoe Thornber 
1553241b1d3SJoe Thornber 	spin_unlock(&tm->lock);
1563241b1d3SJoe Thornber }
1573241b1d3SJoe Thornber 
1583241b1d3SJoe Thornber /*----------------------------------------------------------------*/
1593241b1d3SJoe Thornber 
1603241b1d3SJoe Thornber static struct dm_transaction_manager *dm_tm_create(struct dm_block_manager *bm,
1613241b1d3SJoe Thornber 						   struct dm_space_map *sm)
1623241b1d3SJoe Thornber {
1633241b1d3SJoe Thornber 	int i;
1643241b1d3SJoe Thornber 	struct dm_transaction_manager *tm;
1653241b1d3SJoe Thornber 
1663241b1d3SJoe Thornber 	tm = kmalloc(sizeof(*tm), GFP_KERNEL);
1673241b1d3SJoe Thornber 	if (!tm)
1683241b1d3SJoe Thornber 		return ERR_PTR(-ENOMEM);
1693241b1d3SJoe Thornber 
1703241b1d3SJoe Thornber 	tm->is_clone = 0;
1713241b1d3SJoe Thornber 	tm->real = NULL;
1723241b1d3SJoe Thornber 	tm->bm = bm;
1733241b1d3SJoe Thornber 	tm->sm = sm;
1743241b1d3SJoe Thornber 
1753241b1d3SJoe Thornber 	spin_lock_init(&tm->lock);
176df855798SAndrew Morton 	for (i = 0; i < DM_HASH_SIZE; i++)
1773241b1d3SJoe Thornber 		INIT_HLIST_HEAD(tm->buckets + i);
1783241b1d3SJoe Thornber 
1794646015dSJoe Thornber 	prefetch_init(&tm->prefetches);
1804646015dSJoe Thornber 
1813241b1d3SJoe Thornber 	return tm;
1823241b1d3SJoe Thornber }
1833241b1d3SJoe Thornber 
1843241b1d3SJoe Thornber struct dm_transaction_manager *dm_tm_create_non_blocking_clone(struct dm_transaction_manager *real)
1853241b1d3SJoe Thornber {
1863241b1d3SJoe Thornber 	struct dm_transaction_manager *tm;
1873241b1d3SJoe Thornber 
1883241b1d3SJoe Thornber 	tm = kmalloc(sizeof(*tm), GFP_KERNEL);
1893241b1d3SJoe Thornber 	if (tm) {
1903241b1d3SJoe Thornber 		tm->is_clone = 1;
1913241b1d3SJoe Thornber 		tm->real = real;
1923241b1d3SJoe Thornber 	}
1933241b1d3SJoe Thornber 
1943241b1d3SJoe Thornber 	return tm;
1953241b1d3SJoe Thornber }
1963241b1d3SJoe Thornber EXPORT_SYMBOL_GPL(dm_tm_create_non_blocking_clone);
1973241b1d3SJoe Thornber 
1983241b1d3SJoe Thornber void dm_tm_destroy(struct dm_transaction_manager *tm)
1993241b1d3SJoe Thornber {
20025d7cd6fSMike Snitzer 	if (!tm->is_clone)
20125d7cd6fSMike Snitzer 		wipe_shadow_table(tm);
20225d7cd6fSMike Snitzer 
2033241b1d3SJoe Thornber 	kfree(tm);
2043241b1d3SJoe Thornber }
2053241b1d3SJoe Thornber EXPORT_SYMBOL_GPL(dm_tm_destroy);
2063241b1d3SJoe Thornber 
2073241b1d3SJoe Thornber int dm_tm_pre_commit(struct dm_transaction_manager *tm)
2083241b1d3SJoe Thornber {
2093241b1d3SJoe Thornber 	int r;
2103241b1d3SJoe Thornber 
2113241b1d3SJoe Thornber 	if (tm->is_clone)
2123241b1d3SJoe Thornber 		return -EWOULDBLOCK;
2133241b1d3SJoe Thornber 
2143241b1d3SJoe Thornber 	r = dm_sm_commit(tm->sm);
2153241b1d3SJoe Thornber 	if (r < 0)
2163241b1d3SJoe Thornber 		return r;
2173241b1d3SJoe Thornber 
218a9d45396SJoe Thornber 	return dm_bm_flush(tm->bm);
2193241b1d3SJoe Thornber }
2203241b1d3SJoe Thornber EXPORT_SYMBOL_GPL(dm_tm_pre_commit);
2213241b1d3SJoe Thornber 
2223241b1d3SJoe Thornber int dm_tm_commit(struct dm_transaction_manager *tm, struct dm_block *root)
2233241b1d3SJoe Thornber {
2243241b1d3SJoe Thornber 	if (tm->is_clone)
2253241b1d3SJoe Thornber 		return -EWOULDBLOCK;
2263241b1d3SJoe Thornber 
2273241b1d3SJoe Thornber 	wipe_shadow_table(tm);
228a9d45396SJoe Thornber 	dm_bm_unlock(root);
2293241b1d3SJoe Thornber 
230a9d45396SJoe Thornber 	return dm_bm_flush(tm->bm);
2313241b1d3SJoe Thornber }
2323241b1d3SJoe Thornber EXPORT_SYMBOL_GPL(dm_tm_commit);
2333241b1d3SJoe Thornber 
2343241b1d3SJoe Thornber int dm_tm_new_block(struct dm_transaction_manager *tm,
2353241b1d3SJoe Thornber 		    struct dm_block_validator *v,
2363241b1d3SJoe Thornber 		    struct dm_block **result)
2373241b1d3SJoe Thornber {
2383241b1d3SJoe Thornber 	int r;
2393241b1d3SJoe Thornber 	dm_block_t new_block;
2403241b1d3SJoe Thornber 
2413241b1d3SJoe Thornber 	if (tm->is_clone)
2423241b1d3SJoe Thornber 		return -EWOULDBLOCK;
2433241b1d3SJoe Thornber 
2443241b1d3SJoe Thornber 	r = dm_sm_new_block(tm->sm, &new_block);
2453241b1d3SJoe Thornber 	if (r < 0)
2463241b1d3SJoe Thornber 		return r;
2473241b1d3SJoe Thornber 
2483241b1d3SJoe Thornber 	r = dm_bm_write_lock_zero(tm->bm, new_block, v, result);
2493241b1d3SJoe Thornber 	if (r < 0) {
2503241b1d3SJoe Thornber 		dm_sm_dec_block(tm->sm, new_block);
2513241b1d3SJoe Thornber 		return r;
2523241b1d3SJoe Thornber 	}
2533241b1d3SJoe Thornber 
2543241b1d3SJoe Thornber 	/*
2553241b1d3SJoe Thornber 	 * New blocks count as shadows in that they don't need to be
2563241b1d3SJoe Thornber 	 * shadowed again.
2573241b1d3SJoe Thornber 	 */
2583241b1d3SJoe Thornber 	insert_shadow(tm, new_block);
2593241b1d3SJoe Thornber 
2603241b1d3SJoe Thornber 	return 0;
2613241b1d3SJoe Thornber }
2623241b1d3SJoe Thornber 
2633241b1d3SJoe Thornber static int __shadow_block(struct dm_transaction_manager *tm, dm_block_t orig,
2643241b1d3SJoe Thornber 			  struct dm_block_validator *v,
2653241b1d3SJoe Thornber 			  struct dm_block **result)
2663241b1d3SJoe Thornber {
2673241b1d3SJoe Thornber 	int r;
2683241b1d3SJoe Thornber 	dm_block_t new;
2693241b1d3SJoe Thornber 	struct dm_block *orig_block;
2703241b1d3SJoe Thornber 
2713241b1d3SJoe Thornber 	r = dm_sm_new_block(tm->sm, &new);
2723241b1d3SJoe Thornber 	if (r < 0)
2733241b1d3SJoe Thornber 		return r;
2743241b1d3SJoe Thornber 
2753241b1d3SJoe Thornber 	r = dm_sm_dec_block(tm->sm, orig);
2763241b1d3SJoe Thornber 	if (r < 0)
2773241b1d3SJoe Thornber 		return r;
2783241b1d3SJoe Thornber 
2793241b1d3SJoe Thornber 	r = dm_bm_read_lock(tm->bm, orig, v, &orig_block);
2803241b1d3SJoe Thornber 	if (r < 0)
2813241b1d3SJoe Thornber 		return r;
2823241b1d3SJoe Thornber 
2833c9ad9bdSJoe Thornber 	/*
2843c9ad9bdSJoe Thornber 	 * It would be tempting to use dm_bm_unlock_move here, but some
2853c9ad9bdSJoe Thornber 	 * code, such as the space maps, keeps using the old data structures
2863c9ad9bdSJoe Thornber 	 * secure in the knowledge they won't be changed until the next
2873c9ad9bdSJoe Thornber 	 * transaction.  Using unlock_move would force a synchronous read
2883c9ad9bdSJoe Thornber 	 * since the old block would no longer be in the cache.
2893c9ad9bdSJoe Thornber 	 */
2903c9ad9bdSJoe Thornber 	r = dm_bm_write_lock_zero(tm->bm, new, v, result);
2913c9ad9bdSJoe Thornber 	if (r) {
2923241b1d3SJoe Thornber 		dm_bm_unlock(orig_block);
2933241b1d3SJoe Thornber 		return r;
2943241b1d3SJoe Thornber 	}
2953241b1d3SJoe Thornber 
2963c9ad9bdSJoe Thornber 	memcpy(dm_block_data(*result), dm_block_data(orig_block),
2973c9ad9bdSJoe Thornber 	       dm_bm_block_size(tm->bm));
2983c9ad9bdSJoe Thornber 
2993c9ad9bdSJoe Thornber 	dm_bm_unlock(orig_block);
3003c9ad9bdSJoe Thornber 	return r;
3013241b1d3SJoe Thornber }
3023241b1d3SJoe Thornber 
3033241b1d3SJoe Thornber int dm_tm_shadow_block(struct dm_transaction_manager *tm, dm_block_t orig,
3043241b1d3SJoe Thornber 		       struct dm_block_validator *v, struct dm_block **result,
3053241b1d3SJoe Thornber 		       int *inc_children)
3063241b1d3SJoe Thornber {
3073241b1d3SJoe Thornber 	int r;
3083241b1d3SJoe Thornber 
3093241b1d3SJoe Thornber 	if (tm->is_clone)
3103241b1d3SJoe Thornber 		return -EWOULDBLOCK;
3113241b1d3SJoe Thornber 
3123241b1d3SJoe Thornber 	r = dm_sm_count_is_more_than_one(tm->sm, orig, inc_children);
3133241b1d3SJoe Thornber 	if (r < 0)
3143241b1d3SJoe Thornber 		return r;
3153241b1d3SJoe Thornber 
3163241b1d3SJoe Thornber 	if (is_shadow(tm, orig) && !*inc_children)
3173241b1d3SJoe Thornber 		return dm_bm_write_lock(tm->bm, orig, v, result);
3183241b1d3SJoe Thornber 
3193241b1d3SJoe Thornber 	r = __shadow_block(tm, orig, v, result);
3203241b1d3SJoe Thornber 	if (r < 0)
3213241b1d3SJoe Thornber 		return r;
3223241b1d3SJoe Thornber 	insert_shadow(tm, dm_block_location(*result));
3233241b1d3SJoe Thornber 
3243241b1d3SJoe Thornber 	return r;
3253241b1d3SJoe Thornber }
326cc8394d8SJoe Thornber EXPORT_SYMBOL_GPL(dm_tm_shadow_block);
3273241b1d3SJoe Thornber 
3283241b1d3SJoe Thornber int dm_tm_read_lock(struct dm_transaction_manager *tm, dm_block_t b,
3293241b1d3SJoe Thornber 		    struct dm_block_validator *v,
3303241b1d3SJoe Thornber 		    struct dm_block **blk)
3313241b1d3SJoe Thornber {
3324646015dSJoe Thornber 	if (tm->is_clone) {
3334646015dSJoe Thornber 		int r = dm_bm_read_try_lock(tm->real->bm, b, v, blk);
3344646015dSJoe Thornber 
3354646015dSJoe Thornber 		if (r == -EWOULDBLOCK)
3364646015dSJoe Thornber 			prefetch_add(&tm->real->prefetches, b);
3374646015dSJoe Thornber 
3384646015dSJoe Thornber 		return r;
3394646015dSJoe Thornber 	}
3403241b1d3SJoe Thornber 
3413241b1d3SJoe Thornber 	return dm_bm_read_lock(tm->bm, b, v, blk);
3423241b1d3SJoe Thornber }
343cc8394d8SJoe Thornber EXPORT_SYMBOL_GPL(dm_tm_read_lock);
3443241b1d3SJoe Thornber 
345*4c7da06fSMikulas Patocka void dm_tm_unlock(struct dm_transaction_manager *tm, struct dm_block *b)
3463241b1d3SJoe Thornber {
347*4c7da06fSMikulas Patocka 	dm_bm_unlock(b);
3483241b1d3SJoe Thornber }
3493241b1d3SJoe Thornber EXPORT_SYMBOL_GPL(dm_tm_unlock);
3503241b1d3SJoe Thornber 
3513241b1d3SJoe Thornber void dm_tm_inc(struct dm_transaction_manager *tm, dm_block_t b)
3523241b1d3SJoe Thornber {
3533241b1d3SJoe Thornber 	/*
3543241b1d3SJoe Thornber 	 * The non-blocking clone doesn't support this.
3553241b1d3SJoe Thornber 	 */
3563241b1d3SJoe Thornber 	BUG_ON(tm->is_clone);
3573241b1d3SJoe Thornber 
3583241b1d3SJoe Thornber 	dm_sm_inc_block(tm->sm, b);
3593241b1d3SJoe Thornber }
3603241b1d3SJoe Thornber EXPORT_SYMBOL_GPL(dm_tm_inc);
3613241b1d3SJoe Thornber 
3623241b1d3SJoe Thornber void dm_tm_dec(struct dm_transaction_manager *tm, dm_block_t b)
3633241b1d3SJoe Thornber {
3643241b1d3SJoe Thornber 	/*
3653241b1d3SJoe Thornber 	 * The non-blocking clone doesn't support this.
3663241b1d3SJoe Thornber 	 */
3673241b1d3SJoe Thornber 	BUG_ON(tm->is_clone);
3683241b1d3SJoe Thornber 
3693241b1d3SJoe Thornber 	dm_sm_dec_block(tm->sm, b);
3703241b1d3SJoe Thornber }
3713241b1d3SJoe Thornber EXPORT_SYMBOL_GPL(dm_tm_dec);
3723241b1d3SJoe Thornber 
3733241b1d3SJoe Thornber int dm_tm_ref(struct dm_transaction_manager *tm, dm_block_t b,
3743241b1d3SJoe Thornber 	      uint32_t *result)
3753241b1d3SJoe Thornber {
3763241b1d3SJoe Thornber 	if (tm->is_clone)
3773241b1d3SJoe Thornber 		return -EWOULDBLOCK;
3783241b1d3SJoe Thornber 
3793241b1d3SJoe Thornber 	return dm_sm_get_count(tm->sm, b, result);
3803241b1d3SJoe Thornber }
3813241b1d3SJoe Thornber 
3823241b1d3SJoe Thornber struct dm_block_manager *dm_tm_get_bm(struct dm_transaction_manager *tm)
3833241b1d3SJoe Thornber {
3843241b1d3SJoe Thornber 	return tm->bm;
3853241b1d3SJoe Thornber }
3863241b1d3SJoe Thornber 
3874646015dSJoe Thornber void dm_tm_issue_prefetches(struct dm_transaction_manager *tm)
3884646015dSJoe Thornber {
3894646015dSJoe Thornber 	prefetch_issue(&tm->prefetches, tm->bm);
3904646015dSJoe Thornber }
3914646015dSJoe Thornber EXPORT_SYMBOL_GPL(dm_tm_issue_prefetches);
3924646015dSJoe Thornber 
3933241b1d3SJoe Thornber /*----------------------------------------------------------------*/
3943241b1d3SJoe Thornber 
3953241b1d3SJoe Thornber static int dm_tm_create_internal(struct dm_block_manager *bm,
3963241b1d3SJoe Thornber 				 dm_block_t sb_location,
3973241b1d3SJoe Thornber 				 struct dm_transaction_manager **tm,
3983241b1d3SJoe Thornber 				 struct dm_space_map **sm,
399384ef0e6SJoe Thornber 				 int create,
400384ef0e6SJoe Thornber 				 void *sm_root, size_t sm_len)
4013241b1d3SJoe Thornber {
4023241b1d3SJoe Thornber 	int r;
4033241b1d3SJoe Thornber 
4043caf6d73SJoe Thornber 	*sm = dm_sm_metadata_init();
4053caf6d73SJoe Thornber 	if (IS_ERR(*sm))
4063caf6d73SJoe Thornber 		return PTR_ERR(*sm);
4073241b1d3SJoe Thornber 
4083caf6d73SJoe Thornber 	*tm = dm_tm_create(bm, *sm);
4093241b1d3SJoe Thornber 	if (IS_ERR(*tm)) {
4103caf6d73SJoe Thornber 		dm_sm_destroy(*sm);
4113241b1d3SJoe Thornber 		return PTR_ERR(*tm);
4123241b1d3SJoe Thornber 	}
4133241b1d3SJoe Thornber 
4143241b1d3SJoe Thornber 	if (create) {
4153caf6d73SJoe Thornber 		r = dm_sm_metadata_create(*sm, *tm, dm_bm_nr_blocks(bm),
4163241b1d3SJoe Thornber 					  sb_location);
4173241b1d3SJoe Thornber 		if (r) {
4183241b1d3SJoe Thornber 			DMERR("couldn't create metadata space map");
419384ef0e6SJoe Thornber 			goto bad;
4203241b1d3SJoe Thornber 		}
4213241b1d3SJoe Thornber 
4223241b1d3SJoe Thornber 	} else {
423384ef0e6SJoe Thornber 		r = dm_sm_metadata_open(*sm, *tm, sm_root, sm_len);
4243241b1d3SJoe Thornber 		if (r) {
4253241b1d3SJoe Thornber 			DMERR("couldn't open metadata space map");
426384ef0e6SJoe Thornber 			goto bad;
4273241b1d3SJoe Thornber 		}
42862662303SMike Snitzer 	}
4293241b1d3SJoe Thornber 
4303241b1d3SJoe Thornber 	return 0;
4313241b1d3SJoe Thornber 
432384ef0e6SJoe Thornber bad:
4333241b1d3SJoe Thornber 	dm_tm_destroy(*tm);
434384ef0e6SJoe Thornber 	dm_sm_destroy(*sm);
4353241b1d3SJoe Thornber 	return r;
4363241b1d3SJoe Thornber }
4373241b1d3SJoe Thornber 
4383241b1d3SJoe Thornber int dm_tm_create_with_sm(struct dm_block_manager *bm, dm_block_t sb_location,
4393241b1d3SJoe Thornber 			 struct dm_transaction_manager **tm,
440384ef0e6SJoe Thornber 			 struct dm_space_map **sm)
4413241b1d3SJoe Thornber {
442384ef0e6SJoe Thornber 	return dm_tm_create_internal(bm, sb_location, tm, sm, 1, NULL, 0);
4433241b1d3SJoe Thornber }
4443241b1d3SJoe Thornber EXPORT_SYMBOL_GPL(dm_tm_create_with_sm);
4453241b1d3SJoe Thornber 
4463241b1d3SJoe Thornber int dm_tm_open_with_sm(struct dm_block_manager *bm, dm_block_t sb_location,
447384ef0e6SJoe Thornber 		       void *sm_root, size_t root_len,
4483241b1d3SJoe Thornber 		       struct dm_transaction_manager **tm,
449384ef0e6SJoe Thornber 		       struct dm_space_map **sm)
4503241b1d3SJoe Thornber {
451384ef0e6SJoe Thornber 	return dm_tm_create_internal(bm, sb_location, tm, sm, 0, sm_root, root_len);
4523241b1d3SJoe Thornber }
4533241b1d3SJoe Thornber EXPORT_SYMBOL_GPL(dm_tm_open_with_sm);
4543241b1d3SJoe Thornber 
4553241b1d3SJoe Thornber /*----------------------------------------------------------------*/
456