xref: /openbmc/linux/drivers/md/persistent-data/dm-space-map-metadata.c (revision 26d0dfbb16fcb17d128a79dc70f3020ea6992af0)
13bd94003SHeinz Mauelshagen // SPDX-License-Identifier: GPL-2.0-only
23241b1d3SJoe Thornber /*
33241b1d3SJoe Thornber  * Copyright (C) 2011 Red Hat, Inc.
43241b1d3SJoe Thornber  *
53241b1d3SJoe Thornber  * This file is released under the GPL.
63241b1d3SJoe Thornber  */
73241b1d3SJoe Thornber 
83241b1d3SJoe Thornber #include "dm-space-map.h"
93241b1d3SJoe Thornber #include "dm-space-map-common.h"
103241b1d3SJoe Thornber #include "dm-space-map-metadata.h"
113241b1d3SJoe Thornber 
123241b1d3SJoe Thornber #include <linux/list.h>
133241b1d3SJoe Thornber #include <linux/slab.h>
143241b1d3SJoe Thornber #include <linux/device-mapper.h>
15fbc61291SJérémy Lefaure #include <linux/kernel.h>
163241b1d3SJoe Thornber 
173241b1d3SJoe Thornber #define DM_MSG_PREFIX "space map metadata"
183241b1d3SJoe Thornber 
193241b1d3SJoe Thornber /*----------------------------------------------------------------*/
203241b1d3SJoe Thornber 
213241b1d3SJoe Thornber /*
222fc48021SJoe Thornber  * An edge triggered threshold.
232fc48021SJoe Thornber  */
242fc48021SJoe Thornber struct threshold {
252fc48021SJoe Thornber 	bool threshold_set;
262fc48021SJoe Thornber 	bool value_set;
272fc48021SJoe Thornber 	dm_block_t threshold;
282fc48021SJoe Thornber 	dm_block_t current_value;
292fc48021SJoe Thornber 	dm_sm_threshold_fn fn;
302fc48021SJoe Thornber 	void *context;
312fc48021SJoe Thornber };
322fc48021SJoe Thornber 
threshold_init(struct threshold * t)332fc48021SJoe Thornber static void threshold_init(struct threshold *t)
342fc48021SJoe Thornber {
352fc48021SJoe Thornber 	t->threshold_set = false;
362fc48021SJoe Thornber 	t->value_set = false;
372fc48021SJoe Thornber }
382fc48021SJoe Thornber 
set_threshold(struct threshold * t,dm_block_t value,dm_sm_threshold_fn fn,void * context)392fc48021SJoe Thornber static void set_threshold(struct threshold *t, dm_block_t value,
402fc48021SJoe Thornber 			  dm_sm_threshold_fn fn, void *context)
412fc48021SJoe Thornber {
422fc48021SJoe Thornber 	t->threshold_set = true;
432fc48021SJoe Thornber 	t->threshold = value;
442fc48021SJoe Thornber 	t->fn = fn;
452fc48021SJoe Thornber 	t->context = context;
462fc48021SJoe Thornber }
472fc48021SJoe Thornber 
below_threshold(struct threshold * t,dm_block_t value)482fc48021SJoe Thornber static bool below_threshold(struct threshold *t, dm_block_t value)
492fc48021SJoe Thornber {
502fc48021SJoe Thornber 	return t->threshold_set && value <= t->threshold;
512fc48021SJoe Thornber }
522fc48021SJoe Thornber 
threshold_already_triggered(struct threshold * t)532fc48021SJoe Thornber static bool threshold_already_triggered(struct threshold *t)
542fc48021SJoe Thornber {
552fc48021SJoe Thornber 	return t->value_set && below_threshold(t, t->current_value);
562fc48021SJoe Thornber }
572fc48021SJoe Thornber 
check_threshold(struct threshold * t,dm_block_t value)582fc48021SJoe Thornber static void check_threshold(struct threshold *t, dm_block_t value)
592fc48021SJoe Thornber {
602fc48021SJoe Thornber 	if (below_threshold(t, value) &&
612fc48021SJoe Thornber 	    !threshold_already_triggered(t))
622fc48021SJoe Thornber 		t->fn(t->context);
632fc48021SJoe Thornber 
642fc48021SJoe Thornber 	t->value_set = true;
652fc48021SJoe Thornber 	t->current_value = value;
662fc48021SJoe Thornber }
672fc48021SJoe Thornber 
682fc48021SJoe Thornber /*----------------------------------------------------------------*/
692fc48021SJoe Thornber 
702fc48021SJoe Thornber /*
713241b1d3SJoe Thornber  * Space map interface.
723241b1d3SJoe Thornber  *
733241b1d3SJoe Thornber  * The low level disk format is written using the standard btree and
743241b1d3SJoe Thornber  * transaction manager.  This means that performing disk operations may
753241b1d3SJoe Thornber  * cause us to recurse into the space map in order to allocate new blocks.
763241b1d3SJoe Thornber  * For this reason we have a pool of pre-allocated blocks large enough to
773241b1d3SJoe Thornber  * service any metadata_ll_disk operation.
783241b1d3SJoe Thornber  */
793241b1d3SJoe Thornber 
803241b1d3SJoe Thornber /*
813241b1d3SJoe Thornber  * FIXME: we should calculate this based on the size of the device.
823241b1d3SJoe Thornber  * Only the metadata space map needs this functionality.
833241b1d3SJoe Thornber  */
843241b1d3SJoe Thornber #define MAX_RECURSIVE_ALLOCATIONS 1024
853241b1d3SJoe Thornber 
863241b1d3SJoe Thornber enum block_op_type {
873241b1d3SJoe Thornber 	BOP_INC,
883241b1d3SJoe Thornber 	BOP_DEC
893241b1d3SJoe Thornber };
903241b1d3SJoe Thornber 
913241b1d3SJoe Thornber struct block_op {
923241b1d3SJoe Thornber 	enum block_op_type type;
93be500ed7SJoe Thornber 	dm_block_t b;
94be500ed7SJoe Thornber 	dm_block_t e;
953241b1d3SJoe Thornber };
963241b1d3SJoe Thornber 
97cebc2de4SJoe Thornber struct bop_ring_buffer {
9886a3238cSHeinz Mauelshagen 	unsigned int begin;
9986a3238cSHeinz Mauelshagen 	unsigned int end;
100cebc2de4SJoe Thornber 	struct block_op bops[MAX_RECURSIVE_ALLOCATIONS + 1];
101cebc2de4SJoe Thornber };
102cebc2de4SJoe Thornber 
brb_init(struct bop_ring_buffer * brb)103cebc2de4SJoe Thornber static void brb_init(struct bop_ring_buffer *brb)
104cebc2de4SJoe Thornber {
105cebc2de4SJoe Thornber 	brb->begin = 0;
106cebc2de4SJoe Thornber 	brb->end = 0;
107cebc2de4SJoe Thornber }
108cebc2de4SJoe Thornber 
brb_empty(struct bop_ring_buffer * brb)109cebc2de4SJoe Thornber static bool brb_empty(struct bop_ring_buffer *brb)
110cebc2de4SJoe Thornber {
111cebc2de4SJoe Thornber 	return brb->begin == brb->end;
112cebc2de4SJoe Thornber }
113cebc2de4SJoe Thornber 
brb_next(struct bop_ring_buffer * brb,unsigned int old)11486a3238cSHeinz Mauelshagen static unsigned int brb_next(struct bop_ring_buffer *brb, unsigned int old)
115cebc2de4SJoe Thornber {
11686a3238cSHeinz Mauelshagen 	unsigned int r = old + 1;
1170ef0b471SHeinz Mauelshagen 
118fbc61291SJérémy Lefaure 	return r >= ARRAY_SIZE(brb->bops) ? 0 : r;
119cebc2de4SJoe Thornber }
120cebc2de4SJoe Thornber 
brb_push(struct bop_ring_buffer * brb,enum block_op_type type,dm_block_t b,dm_block_t e)121cebc2de4SJoe Thornber static int brb_push(struct bop_ring_buffer *brb,
122be500ed7SJoe Thornber 		    enum block_op_type type, dm_block_t b, dm_block_t e)
123cebc2de4SJoe Thornber {
124cebc2de4SJoe Thornber 	struct block_op *bop;
12586a3238cSHeinz Mauelshagen 	unsigned int next = brb_next(brb, brb->end);
126cebc2de4SJoe Thornber 
127cebc2de4SJoe Thornber 	/*
128cebc2de4SJoe Thornber 	 * We don't allow the last bop to be filled, this way we can
129cebc2de4SJoe Thornber 	 * differentiate between full and empty.
130cebc2de4SJoe Thornber 	 */
131cebc2de4SJoe Thornber 	if (next == brb->begin)
132cebc2de4SJoe Thornber 		return -ENOMEM;
133cebc2de4SJoe Thornber 
134cebc2de4SJoe Thornber 	bop = brb->bops + brb->end;
135cebc2de4SJoe Thornber 	bop->type = type;
136be500ed7SJoe Thornber 	bop->b = b;
137be500ed7SJoe Thornber 	bop->e = e;
138cebc2de4SJoe Thornber 
139cebc2de4SJoe Thornber 	brb->end = next;
140cebc2de4SJoe Thornber 
141cebc2de4SJoe Thornber 	return 0;
142cebc2de4SJoe Thornber }
143cebc2de4SJoe Thornber 
brb_peek(struct bop_ring_buffer * brb,struct block_op * result)14450dd842aSJoe Thornber static int brb_peek(struct bop_ring_buffer *brb, struct block_op *result)
145cebc2de4SJoe Thornber {
146cebc2de4SJoe Thornber 	struct block_op *bop;
147cebc2de4SJoe Thornber 
148cebc2de4SJoe Thornber 	if (brb_empty(brb))
149cebc2de4SJoe Thornber 		return -ENODATA;
150cebc2de4SJoe Thornber 
151cebc2de4SJoe Thornber 	bop = brb->bops + brb->begin;
152be500ed7SJoe Thornber 	memcpy(result, bop, sizeof(*result));
15350dd842aSJoe Thornber 	return 0;
15450dd842aSJoe Thornber }
15550dd842aSJoe Thornber 
brb_pop(struct bop_ring_buffer * brb)15650dd842aSJoe Thornber static int brb_pop(struct bop_ring_buffer *brb)
15750dd842aSJoe Thornber {
15850dd842aSJoe Thornber 	if (brb_empty(brb))
15950dd842aSJoe Thornber 		return -ENODATA;
16050dd842aSJoe Thornber 
161cebc2de4SJoe Thornber 	brb->begin = brb_next(brb, brb->begin);
162cebc2de4SJoe Thornber 
163cebc2de4SJoe Thornber 	return 0;
164cebc2de4SJoe Thornber }
165cebc2de4SJoe Thornber 
166cebc2de4SJoe Thornber /*----------------------------------------------------------------*/
167cebc2de4SJoe Thornber 
1683241b1d3SJoe Thornber struct sm_metadata {
1693241b1d3SJoe Thornber 	struct dm_space_map sm;
1703241b1d3SJoe Thornber 
1713241b1d3SJoe Thornber 	struct ll_disk ll;
1723241b1d3SJoe Thornber 	struct ll_disk old_ll;
1733241b1d3SJoe Thornber 
1743241b1d3SJoe Thornber 	dm_block_t begin;
1753241b1d3SJoe Thornber 
17686a3238cSHeinz Mauelshagen 	unsigned int recursion_count;
17786a3238cSHeinz Mauelshagen 	unsigned int allocated_this_transaction;
178cebc2de4SJoe Thornber 	struct bop_ring_buffer uncommitted;
1792fc48021SJoe Thornber 
1802fc48021SJoe Thornber 	struct threshold threshold;
1813241b1d3SJoe Thornber };
1823241b1d3SJoe Thornber 
add_bop(struct sm_metadata * smm,enum block_op_type type,dm_block_t b,dm_block_t e)183be500ed7SJoe Thornber static int add_bop(struct sm_metadata *smm, enum block_op_type type, dm_block_t b, dm_block_t e)
1843241b1d3SJoe Thornber {
185be500ed7SJoe Thornber 	int r = brb_push(&smm->uncommitted, type, b, e);
1860ef0b471SHeinz Mauelshagen 
187cebc2de4SJoe Thornber 	if (r) {
1883241b1d3SJoe Thornber 		DMERR("too many recursive allocations");
1893241b1d3SJoe Thornber 		return -ENOMEM;
1903241b1d3SJoe Thornber 	}
1913241b1d3SJoe Thornber 
1923241b1d3SJoe Thornber 	return 0;
1933241b1d3SJoe Thornber }
1943241b1d3SJoe Thornber 
commit_bop(struct sm_metadata * smm,struct block_op * op)1953241b1d3SJoe Thornber static int commit_bop(struct sm_metadata *smm, struct block_op *op)
1963241b1d3SJoe Thornber {
1973241b1d3SJoe Thornber 	int r = 0;
198be500ed7SJoe Thornber 	int32_t nr_allocations;
1993241b1d3SJoe Thornber 
2003241b1d3SJoe Thornber 	switch (op->type) {
2013241b1d3SJoe Thornber 	case BOP_INC:
202be500ed7SJoe Thornber 		r = sm_ll_inc(&smm->ll, op->b, op->e, &nr_allocations);
2033241b1d3SJoe Thornber 		break;
2043241b1d3SJoe Thornber 
2053241b1d3SJoe Thornber 	case BOP_DEC:
206be500ed7SJoe Thornber 		r = sm_ll_dec(&smm->ll, op->b, op->e, &nr_allocations);
2073241b1d3SJoe Thornber 		break;
2083241b1d3SJoe Thornber 	}
2093241b1d3SJoe Thornber 
2103241b1d3SJoe Thornber 	return r;
2113241b1d3SJoe Thornber }
2123241b1d3SJoe Thornber 
in(struct sm_metadata * smm)2133241b1d3SJoe Thornber static void in(struct sm_metadata *smm)
2143241b1d3SJoe Thornber {
2153241b1d3SJoe Thornber 	smm->recursion_count++;
2163241b1d3SJoe Thornber }
2173241b1d3SJoe Thornber 
apply_bops(struct sm_metadata * smm)2186096d91aSJoe Thornber static int apply_bops(struct sm_metadata *smm)
2193241b1d3SJoe Thornber {
2203241b1d3SJoe Thornber 	int r = 0;
2213241b1d3SJoe Thornber 
222cebc2de4SJoe Thornber 	while (!brb_empty(&smm->uncommitted)) {
223cebc2de4SJoe Thornber 		struct block_op bop;
224cebc2de4SJoe Thornber 
22550dd842aSJoe Thornber 		r = brb_peek(&smm->uncommitted, &bop);
226cebc2de4SJoe Thornber 		if (r) {
227cebc2de4SJoe Thornber 			DMERR("bug in bop ring buffer");
228cebc2de4SJoe Thornber 			break;
229cebc2de4SJoe Thornber 		}
230cebc2de4SJoe Thornber 
231cebc2de4SJoe Thornber 		r = commit_bop(smm, &bop);
2323241b1d3SJoe Thornber 		if (r)
2333241b1d3SJoe Thornber 			break;
23450dd842aSJoe Thornber 
23550dd842aSJoe Thornber 		brb_pop(&smm->uncommitted);
2363241b1d3SJoe Thornber 	}
2376096d91aSJoe Thornber 
2386096d91aSJoe Thornber 	return r;
2393241b1d3SJoe Thornber }
2403241b1d3SJoe Thornber 
out(struct sm_metadata * smm)2416096d91aSJoe Thornber static int out(struct sm_metadata *smm)
2426096d91aSJoe Thornber {
2436096d91aSJoe Thornber 	int r = 0;
2446096d91aSJoe Thornber 
2456096d91aSJoe Thornber 	/*
2466096d91aSJoe Thornber 	 * If we're not recursing then very bad things are happening.
2476096d91aSJoe Thornber 	 */
2486096d91aSJoe Thornber 	if (!smm->recursion_count) {
2496096d91aSJoe Thornber 		DMERR("lost track of recursion depth");
2506096d91aSJoe Thornber 		return -ENOMEM;
2516096d91aSJoe Thornber 	}
2526096d91aSJoe Thornber 
2536096d91aSJoe Thornber 	if (smm->recursion_count == 1)
254ae148243SZhangXiaoxu 		r = apply_bops(smm);
2556096d91aSJoe Thornber 
2563241b1d3SJoe Thornber 	smm->recursion_count--;
2573241b1d3SJoe Thornber 
2583241b1d3SJoe Thornber 	return r;
2593241b1d3SJoe Thornber }
2603241b1d3SJoe Thornber 
2613241b1d3SJoe Thornber /*
2623241b1d3SJoe Thornber  * When using the out() function above, we often want to combine an error
2633241b1d3SJoe Thornber  * code for the operation run in the recursive context with that from
2643241b1d3SJoe Thornber  * out().
2653241b1d3SJoe Thornber  */
combine_errors(int r1,int r2)2663241b1d3SJoe Thornber static int combine_errors(int r1, int r2)
2673241b1d3SJoe Thornber {
2683241b1d3SJoe Thornber 	return r1 ? r1 : r2;
2693241b1d3SJoe Thornber }
2703241b1d3SJoe Thornber 
recursing(struct sm_metadata * smm)2713241b1d3SJoe Thornber static int recursing(struct sm_metadata *smm)
2723241b1d3SJoe Thornber {
2733241b1d3SJoe Thornber 	return smm->recursion_count;
2743241b1d3SJoe Thornber }
2753241b1d3SJoe Thornber 
sm_metadata_destroy(struct dm_space_map * sm)2763241b1d3SJoe Thornber static void sm_metadata_destroy(struct dm_space_map *sm)
2773241b1d3SJoe Thornber {
2783241b1d3SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
2793241b1d3SJoe Thornber 
280*a6bba25fSMikulas Patocka 	kvfree(smm);
2813241b1d3SJoe Thornber }
2823241b1d3SJoe Thornber 
sm_metadata_get_nr_blocks(struct dm_space_map * sm,dm_block_t * count)2833241b1d3SJoe Thornber static int sm_metadata_get_nr_blocks(struct dm_space_map *sm, dm_block_t *count)
2843241b1d3SJoe Thornber {
2853241b1d3SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
2863241b1d3SJoe Thornber 
2873241b1d3SJoe Thornber 	*count = smm->ll.nr_blocks;
2883241b1d3SJoe Thornber 
2893241b1d3SJoe Thornber 	return 0;
2903241b1d3SJoe Thornber }
2913241b1d3SJoe Thornber 
sm_metadata_get_nr_free(struct dm_space_map * sm,dm_block_t * count)2923241b1d3SJoe Thornber static int sm_metadata_get_nr_free(struct dm_space_map *sm, dm_block_t *count)
2933241b1d3SJoe Thornber {
2943241b1d3SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
2953241b1d3SJoe Thornber 
2963241b1d3SJoe Thornber 	*count = smm->old_ll.nr_blocks - smm->old_ll.nr_allocated -
2973241b1d3SJoe Thornber 		 smm->allocated_this_transaction;
2983241b1d3SJoe Thornber 
2993241b1d3SJoe Thornber 	return 0;
3003241b1d3SJoe Thornber }
3013241b1d3SJoe Thornber 
sm_metadata_get_count(struct dm_space_map * sm,dm_block_t b,uint32_t * result)3023241b1d3SJoe Thornber static int sm_metadata_get_count(struct dm_space_map *sm, dm_block_t b,
3033241b1d3SJoe Thornber 				 uint32_t *result)
3043241b1d3SJoe Thornber {
305cebc2de4SJoe Thornber 	int r;
30686a3238cSHeinz Mauelshagen 	unsigned int i;
3073241b1d3SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
30886a3238cSHeinz Mauelshagen 	unsigned int adjustment = 0;
3093241b1d3SJoe Thornber 
3103241b1d3SJoe Thornber 	/*
3113241b1d3SJoe Thornber 	 * We may have some uncommitted adjustments to add.  This list
3123241b1d3SJoe Thornber 	 * should always be really short.
3133241b1d3SJoe Thornber 	 */
314cebc2de4SJoe Thornber 	for (i = smm->uncommitted.begin;
315cebc2de4SJoe Thornber 	     i != smm->uncommitted.end;
316cebc2de4SJoe Thornber 	     i = brb_next(&smm->uncommitted, i)) {
317cebc2de4SJoe Thornber 		struct block_op *op = smm->uncommitted.bops + i;
3183241b1d3SJoe Thornber 
319be500ed7SJoe Thornber 		if (b < op->b || b >= op->e)
3203241b1d3SJoe Thornber 			continue;
3213241b1d3SJoe Thornber 
3223241b1d3SJoe Thornber 		switch (op->type) {
3233241b1d3SJoe Thornber 		case BOP_INC:
3243241b1d3SJoe Thornber 			adjustment++;
3253241b1d3SJoe Thornber 			break;
3263241b1d3SJoe Thornber 
3273241b1d3SJoe Thornber 		case BOP_DEC:
3283241b1d3SJoe Thornber 			adjustment--;
3293241b1d3SJoe Thornber 			break;
3303241b1d3SJoe Thornber 		}
3313241b1d3SJoe Thornber 	}
3323241b1d3SJoe Thornber 
3333241b1d3SJoe Thornber 	r = sm_ll_lookup(&smm->ll, b, result);
3343241b1d3SJoe Thornber 	if (r)
3353241b1d3SJoe Thornber 		return r;
3363241b1d3SJoe Thornber 
3373241b1d3SJoe Thornber 	*result += adjustment;
3383241b1d3SJoe Thornber 
3393241b1d3SJoe Thornber 	return 0;
3403241b1d3SJoe Thornber }
3413241b1d3SJoe Thornber 
sm_metadata_count_is_more_than_one(struct dm_space_map * sm,dm_block_t b,int * result)3423241b1d3SJoe Thornber static int sm_metadata_count_is_more_than_one(struct dm_space_map *sm,
3433241b1d3SJoe Thornber 					      dm_block_t b, int *result)
3443241b1d3SJoe Thornber {
345cebc2de4SJoe Thornber 	int r, adjustment = 0;
34686a3238cSHeinz Mauelshagen 	unsigned int i;
3473241b1d3SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
3483241b1d3SJoe Thornber 	uint32_t rc;
3493241b1d3SJoe Thornber 
3503241b1d3SJoe Thornber 	/*
3513241b1d3SJoe Thornber 	 * We may have some uncommitted adjustments to add.  This list
3523241b1d3SJoe Thornber 	 * should always be really short.
3533241b1d3SJoe Thornber 	 */
354cebc2de4SJoe Thornber 	for (i = smm->uncommitted.begin;
355cebc2de4SJoe Thornber 	     i != smm->uncommitted.end;
356cebc2de4SJoe Thornber 	     i = brb_next(&smm->uncommitted, i)) {
357cebc2de4SJoe Thornber 
358cebc2de4SJoe Thornber 		struct block_op *op = smm->uncommitted.bops + i;
3593241b1d3SJoe Thornber 
360be500ed7SJoe Thornber 		if (b < op->b || b >= op->e)
3613241b1d3SJoe Thornber 			continue;
3623241b1d3SJoe Thornber 
3633241b1d3SJoe Thornber 		switch (op->type) {
3643241b1d3SJoe Thornber 		case BOP_INC:
3653241b1d3SJoe Thornber 			adjustment++;
3663241b1d3SJoe Thornber 			break;
3673241b1d3SJoe Thornber 
3683241b1d3SJoe Thornber 		case BOP_DEC:
3693241b1d3SJoe Thornber 			adjustment--;
3703241b1d3SJoe Thornber 			break;
3713241b1d3SJoe Thornber 		}
3723241b1d3SJoe Thornber 	}
3733241b1d3SJoe Thornber 
3743241b1d3SJoe Thornber 	if (adjustment > 1) {
3753241b1d3SJoe Thornber 		*result = 1;
3763241b1d3SJoe Thornber 		return 0;
3773241b1d3SJoe Thornber 	}
3783241b1d3SJoe Thornber 
3793241b1d3SJoe Thornber 	r = sm_ll_lookup_bitmap(&smm->ll, b, &rc);
3803241b1d3SJoe Thornber 	if (r)
3813241b1d3SJoe Thornber 		return r;
3823241b1d3SJoe Thornber 
3833241b1d3SJoe Thornber 	if (rc == 3)
3843241b1d3SJoe Thornber 		/*
3853241b1d3SJoe Thornber 		 * We err on the side of caution, and always return true.
3863241b1d3SJoe Thornber 		 */
3873241b1d3SJoe Thornber 		*result = 1;
3883241b1d3SJoe Thornber 	else
3893241b1d3SJoe Thornber 		*result = rc + adjustment > 1;
3903241b1d3SJoe Thornber 
3913241b1d3SJoe Thornber 	return 0;
3923241b1d3SJoe Thornber }
3933241b1d3SJoe Thornber 
sm_metadata_set_count(struct dm_space_map * sm,dm_block_t b,uint32_t count)3943241b1d3SJoe Thornber static int sm_metadata_set_count(struct dm_space_map *sm, dm_block_t b,
3953241b1d3SJoe Thornber 				 uint32_t count)
3963241b1d3SJoe Thornber {
3973241b1d3SJoe Thornber 	int r, r2;
398be500ed7SJoe Thornber 	int32_t nr_allocations;
3993241b1d3SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
4003241b1d3SJoe Thornber 
4013241b1d3SJoe Thornber 	if (smm->recursion_count) {
4023241b1d3SJoe Thornber 		DMERR("cannot recurse set_count()");
4033241b1d3SJoe Thornber 		return -EINVAL;
4043241b1d3SJoe Thornber 	}
4053241b1d3SJoe Thornber 
4063241b1d3SJoe Thornber 	in(smm);
407be500ed7SJoe Thornber 	r = sm_ll_insert(&smm->ll, b, count, &nr_allocations);
4083241b1d3SJoe Thornber 	r2 = out(smm);
4093241b1d3SJoe Thornber 
4103241b1d3SJoe Thornber 	return combine_errors(r, r2);
4113241b1d3SJoe Thornber }
4123241b1d3SJoe Thornber 
sm_metadata_inc_blocks(struct dm_space_map * sm,dm_block_t b,dm_block_t e)413be500ed7SJoe Thornber static int sm_metadata_inc_blocks(struct dm_space_map *sm, dm_block_t b, dm_block_t e)
4143241b1d3SJoe Thornber {
4153241b1d3SJoe Thornber 	int r, r2 = 0;
416be500ed7SJoe Thornber 	int32_t nr_allocations;
4173241b1d3SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
4183241b1d3SJoe Thornber 
419be500ed7SJoe Thornber 	if (recursing(smm)) {
420be500ed7SJoe Thornber 		r = add_bop(smm, BOP_INC, b, e);
421be500ed7SJoe Thornber 		if (r)
422be500ed7SJoe Thornber 			return r;
423be500ed7SJoe Thornber 	} else {
4243241b1d3SJoe Thornber 		in(smm);
425be500ed7SJoe Thornber 		r = sm_ll_inc(&smm->ll, b, e, &nr_allocations);
4263241b1d3SJoe Thornber 		r2 = out(smm);
4273241b1d3SJoe Thornber 	}
4283241b1d3SJoe Thornber 
4293241b1d3SJoe Thornber 	return combine_errors(r, r2);
4303241b1d3SJoe Thornber }
4313241b1d3SJoe Thornber 
sm_metadata_dec_blocks(struct dm_space_map * sm,dm_block_t b,dm_block_t e)432be500ed7SJoe Thornber static int sm_metadata_dec_blocks(struct dm_space_map *sm, dm_block_t b, dm_block_t e)
4333241b1d3SJoe Thornber {
4343241b1d3SJoe Thornber 	int r, r2 = 0;
435be500ed7SJoe Thornber 	int32_t nr_allocations;
4363241b1d3SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
4373241b1d3SJoe Thornber 
4383241b1d3SJoe Thornber 	if (recursing(smm))
439be500ed7SJoe Thornber 		r = add_bop(smm, BOP_DEC, b, e);
4403241b1d3SJoe Thornber 	else {
4413241b1d3SJoe Thornber 		in(smm);
442be500ed7SJoe Thornber 		r = sm_ll_dec(&smm->ll, b, e, &nr_allocations);
4433241b1d3SJoe Thornber 		r2 = out(smm);
4443241b1d3SJoe Thornber 	}
4453241b1d3SJoe Thornber 
4463241b1d3SJoe Thornber 	return combine_errors(r, r2);
4473241b1d3SJoe Thornber }
4483241b1d3SJoe Thornber 
sm_metadata_new_block_(struct dm_space_map * sm,dm_block_t * b)4493241b1d3SJoe Thornber static int sm_metadata_new_block_(struct dm_space_map *sm, dm_block_t *b)
4503241b1d3SJoe Thornber {
4513241b1d3SJoe Thornber 	int r, r2 = 0;
452be500ed7SJoe Thornber 	int32_t nr_allocations;
4533241b1d3SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
4543241b1d3SJoe Thornber 
4554feaef83SJoe Thornber 	/*
4564feaef83SJoe Thornber 	 * Any block we allocate has to be free in both the old and current ll.
4574feaef83SJoe Thornber 	 */
4584feaef83SJoe Thornber 	r = sm_ll_find_common_free_block(&smm->old_ll, &smm->ll, smm->begin, smm->ll.nr_blocks, b);
4595faafc77SJoe Thornber 	if (r == -ENOSPC) {
4605faafc77SJoe Thornber 		/*
4615faafc77SJoe Thornber 		 * There's no free block between smm->begin and the end of the metadata device.
4625faafc77SJoe Thornber 		 * We search before smm->begin in case something has been freed.
4635faafc77SJoe Thornber 		 */
4645faafc77SJoe Thornber 		r = sm_ll_find_common_free_block(&smm->old_ll, &smm->ll, 0, smm->begin, b);
4655faafc77SJoe Thornber 	}
4665faafc77SJoe Thornber 
4673241b1d3SJoe Thornber 	if (r)
4683241b1d3SJoe Thornber 		return r;
4693241b1d3SJoe Thornber 
4703241b1d3SJoe Thornber 	smm->begin = *b + 1;
4713241b1d3SJoe Thornber 
4723241b1d3SJoe Thornber 	if (recursing(smm))
473be500ed7SJoe Thornber 		r = add_bop(smm, BOP_INC, *b, *b + 1);
4743241b1d3SJoe Thornber 	else {
4753241b1d3SJoe Thornber 		in(smm);
476be500ed7SJoe Thornber 		r = sm_ll_inc(&smm->ll, *b, *b + 1, &nr_allocations);
4773241b1d3SJoe Thornber 		r2 = out(smm);
4783241b1d3SJoe Thornber 	}
4793241b1d3SJoe Thornber 
4803241b1d3SJoe Thornber 	if (!r)
4813241b1d3SJoe Thornber 		smm->allocated_this_transaction++;
4823241b1d3SJoe Thornber 
4833241b1d3SJoe Thornber 	return combine_errors(r, r2);
4843241b1d3SJoe Thornber }
4853241b1d3SJoe Thornber 
sm_metadata_new_block(struct dm_space_map * sm,dm_block_t * b)4863241b1d3SJoe Thornber static int sm_metadata_new_block(struct dm_space_map *sm, dm_block_t *b)
4873241b1d3SJoe Thornber {
4882fc48021SJoe Thornber 	dm_block_t count;
4892fc48021SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
4902fc48021SJoe Thornber 
4913241b1d3SJoe Thornber 	int r = sm_metadata_new_block_(sm, b);
4920ef0b471SHeinz Mauelshagen 
493f62b6b8fSMike Snitzer 	if (r) {
494c46985e2SMike Snitzer 		DMERR_LIMIT("unable to allocate new metadata block");
495f62b6b8fSMike Snitzer 		return r;
496f62b6b8fSMike Snitzer 	}
4972fc48021SJoe Thornber 
4982fc48021SJoe Thornber 	r = sm_metadata_get_nr_free(sm, &count);
499f62b6b8fSMike Snitzer 	if (r) {
500c46985e2SMike Snitzer 		DMERR_LIMIT("couldn't get free block count");
501f62b6b8fSMike Snitzer 		return r;
502f62b6b8fSMike Snitzer 	}
5032fc48021SJoe Thornber 
5042fc48021SJoe Thornber 	check_threshold(&smm->threshold, count);
5052fc48021SJoe Thornber 
5063241b1d3SJoe Thornber 	return r;
5073241b1d3SJoe Thornber }
5083241b1d3SJoe Thornber 
sm_metadata_commit(struct dm_space_map * sm)5093241b1d3SJoe Thornber static int sm_metadata_commit(struct dm_space_map *sm)
5103241b1d3SJoe Thornber {
5113241b1d3SJoe Thornber 	int r;
5123241b1d3SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
5133241b1d3SJoe Thornber 
5143241b1d3SJoe Thornber 	r = sm_ll_commit(&smm->ll);
5153241b1d3SJoe Thornber 	if (r)
5163241b1d3SJoe Thornber 		return r;
5173241b1d3SJoe Thornber 
5183241b1d3SJoe Thornber 	memcpy(&smm->old_ll, &smm->ll, sizeof(smm->old_ll));
5193241b1d3SJoe Thornber 	smm->allocated_this_transaction = 0;
5203241b1d3SJoe Thornber 
5213241b1d3SJoe Thornber 	return 0;
5223241b1d3SJoe Thornber }
5233241b1d3SJoe Thornber 
sm_metadata_register_threshold_callback(struct dm_space_map * sm,dm_block_t threshold,dm_sm_threshold_fn fn,void * context)5242fc48021SJoe Thornber static int sm_metadata_register_threshold_callback(struct dm_space_map *sm,
5252fc48021SJoe Thornber 						   dm_block_t threshold,
5262fc48021SJoe Thornber 						   dm_sm_threshold_fn fn,
5272fc48021SJoe Thornber 						   void *context)
5282fc48021SJoe Thornber {
5292fc48021SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
5302fc48021SJoe Thornber 
5312fc48021SJoe Thornber 	set_threshold(&smm->threshold, threshold, fn, context);
5322fc48021SJoe Thornber 
5332fc48021SJoe Thornber 	return 0;
5342fc48021SJoe Thornber }
5352fc48021SJoe Thornber 
sm_metadata_root_size(struct dm_space_map * sm,size_t * result)5363241b1d3SJoe Thornber static int sm_metadata_root_size(struct dm_space_map *sm, size_t *result)
5373241b1d3SJoe Thornber {
5383241b1d3SJoe Thornber 	*result = sizeof(struct disk_sm_root);
5393241b1d3SJoe Thornber 
5403241b1d3SJoe Thornber 	return 0;
5413241b1d3SJoe Thornber }
5423241b1d3SJoe Thornber 
sm_metadata_copy_root(struct dm_space_map * sm,void * where_le,size_t max)5433241b1d3SJoe Thornber static int sm_metadata_copy_root(struct dm_space_map *sm, void *where_le, size_t max)
5443241b1d3SJoe Thornber {
5453241b1d3SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
5463241b1d3SJoe Thornber 	struct disk_sm_root root_le;
5473241b1d3SJoe Thornber 
5483241b1d3SJoe Thornber 	root_le.nr_blocks = cpu_to_le64(smm->ll.nr_blocks);
5493241b1d3SJoe Thornber 	root_le.nr_allocated = cpu_to_le64(smm->ll.nr_allocated);
5503241b1d3SJoe Thornber 	root_le.bitmap_root = cpu_to_le64(smm->ll.bitmap_root);
5513241b1d3SJoe Thornber 	root_le.ref_count_root = cpu_to_le64(smm->ll.ref_count_root);
5523241b1d3SJoe Thornber 
5533241b1d3SJoe Thornber 	if (max < sizeof(root_le))
5543241b1d3SJoe Thornber 		return -ENOSPC;
5553241b1d3SJoe Thornber 
5563241b1d3SJoe Thornber 	memcpy(where_le, &root_le, sizeof(root_le));
5573241b1d3SJoe Thornber 
5583241b1d3SJoe Thornber 	return 0;
5593241b1d3SJoe Thornber }
5603241b1d3SJoe Thornber 
5611921c56dSJoe Thornber static int sm_metadata_extend(struct dm_space_map *sm, dm_block_t extra_blocks);
5621921c56dSJoe Thornber 
563b79af13eSBhumika Goyal static const struct dm_space_map ops = {
5643241b1d3SJoe Thornber 	.destroy = sm_metadata_destroy,
5653241b1d3SJoe Thornber 	.extend = sm_metadata_extend,
5663241b1d3SJoe Thornber 	.get_nr_blocks = sm_metadata_get_nr_blocks,
5673241b1d3SJoe Thornber 	.get_nr_free = sm_metadata_get_nr_free,
5683241b1d3SJoe Thornber 	.get_count = sm_metadata_get_count,
5693241b1d3SJoe Thornber 	.count_is_more_than_one = sm_metadata_count_is_more_than_one,
5703241b1d3SJoe Thornber 	.set_count = sm_metadata_set_count,
571be500ed7SJoe Thornber 	.inc_blocks = sm_metadata_inc_blocks,
572be500ed7SJoe Thornber 	.dec_blocks = sm_metadata_dec_blocks,
5733241b1d3SJoe Thornber 	.new_block = sm_metadata_new_block,
5743241b1d3SJoe Thornber 	.commit = sm_metadata_commit,
5753241b1d3SJoe Thornber 	.root_size = sm_metadata_root_size,
5767c3d3f2aSJoe Thornber 	.copy_root = sm_metadata_copy_root,
5772fc48021SJoe Thornber 	.register_threshold_callback = sm_metadata_register_threshold_callback
5783241b1d3SJoe Thornber };
5793241b1d3SJoe Thornber 
5803241b1d3SJoe Thornber /*----------------------------------------------------------------*/
5813241b1d3SJoe Thornber 
5823241b1d3SJoe Thornber /*
5833241b1d3SJoe Thornber  * When a new space map is created that manages its own space.  We use
5843241b1d3SJoe Thornber  * this tiny bootstrap allocator.
5853241b1d3SJoe Thornber  */
sm_bootstrap_destroy(struct dm_space_map * sm)5863241b1d3SJoe Thornber static void sm_bootstrap_destroy(struct dm_space_map *sm)
5873241b1d3SJoe Thornber {
5883241b1d3SJoe Thornber }
5893241b1d3SJoe Thornber 
sm_bootstrap_extend(struct dm_space_map * sm,dm_block_t extra_blocks)5903241b1d3SJoe Thornber static int sm_bootstrap_extend(struct dm_space_map *sm, dm_block_t extra_blocks)
5913241b1d3SJoe Thornber {
59288a488f6SJoe Thornber 	DMERR("bootstrap doesn't support extend");
5933241b1d3SJoe Thornber 
5943241b1d3SJoe Thornber 	return -EINVAL;
5953241b1d3SJoe Thornber }
5963241b1d3SJoe Thornber 
sm_bootstrap_get_nr_blocks(struct dm_space_map * sm,dm_block_t * count)5973241b1d3SJoe Thornber static int sm_bootstrap_get_nr_blocks(struct dm_space_map *sm, dm_block_t *count)
5983241b1d3SJoe Thornber {
5993241b1d3SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
6003241b1d3SJoe Thornber 
601c1c6156fSDan Carpenter 	*count = smm->ll.nr_blocks;
602c1c6156fSDan Carpenter 
603c1c6156fSDan Carpenter 	return 0;
6043241b1d3SJoe Thornber }
6053241b1d3SJoe Thornber 
sm_bootstrap_get_nr_free(struct dm_space_map * sm,dm_block_t * count)6063241b1d3SJoe Thornber static int sm_bootstrap_get_nr_free(struct dm_space_map *sm, dm_block_t *count)
6073241b1d3SJoe Thornber {
6083241b1d3SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
6093241b1d3SJoe Thornber 
6103241b1d3SJoe Thornber 	*count = smm->ll.nr_blocks - smm->begin;
6113241b1d3SJoe Thornber 
6123241b1d3SJoe Thornber 	return 0;
6133241b1d3SJoe Thornber }
6143241b1d3SJoe Thornber 
sm_bootstrap_get_count(struct dm_space_map * sm,dm_block_t b,uint32_t * result)6153241b1d3SJoe Thornber static int sm_bootstrap_get_count(struct dm_space_map *sm, dm_block_t b,
6163241b1d3SJoe Thornber 				  uint32_t *result)
6173241b1d3SJoe Thornber {
6183241b1d3SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
6193241b1d3SJoe Thornber 
62002717d98SJoe Thornber 	*result = (b < smm->begin) ? 1 : 0;
62102717d98SJoe Thornber 
62202717d98SJoe Thornber 	return 0;
6233241b1d3SJoe Thornber }
6243241b1d3SJoe Thornber 
sm_bootstrap_count_is_more_than_one(struct dm_space_map * sm,dm_block_t b,int * result)6253241b1d3SJoe Thornber static int sm_bootstrap_count_is_more_than_one(struct dm_space_map *sm,
6263241b1d3SJoe Thornber 					       dm_block_t b, int *result)
6273241b1d3SJoe Thornber {
6283241b1d3SJoe Thornber 	*result = 0;
6293241b1d3SJoe Thornber 
6303241b1d3SJoe Thornber 	return 0;
6313241b1d3SJoe Thornber }
6323241b1d3SJoe Thornber 
sm_bootstrap_set_count(struct dm_space_map * sm,dm_block_t b,uint32_t count)6333241b1d3SJoe Thornber static int sm_bootstrap_set_count(struct dm_space_map *sm, dm_block_t b,
6343241b1d3SJoe Thornber 				  uint32_t count)
6353241b1d3SJoe Thornber {
63688a488f6SJoe Thornber 	DMERR("bootstrap doesn't support set_count");
6373241b1d3SJoe Thornber 
6383241b1d3SJoe Thornber 	return -EINVAL;
6393241b1d3SJoe Thornber }
6403241b1d3SJoe Thornber 
sm_bootstrap_new_block(struct dm_space_map * sm,dm_block_t * b)6413241b1d3SJoe Thornber static int sm_bootstrap_new_block(struct dm_space_map *sm, dm_block_t *b)
6423241b1d3SJoe Thornber {
6433241b1d3SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
6443241b1d3SJoe Thornber 
6453241b1d3SJoe Thornber 	/*
6463241b1d3SJoe Thornber 	 * We know the entire device is unused.
6473241b1d3SJoe Thornber 	 */
6483241b1d3SJoe Thornber 	if (smm->begin == smm->ll.nr_blocks)
6493241b1d3SJoe Thornber 		return -ENOSPC;
6503241b1d3SJoe Thornber 
6513241b1d3SJoe Thornber 	*b = smm->begin++;
6523241b1d3SJoe Thornber 
6533241b1d3SJoe Thornber 	return 0;
6543241b1d3SJoe Thornber }
6553241b1d3SJoe Thornber 
sm_bootstrap_inc_blocks(struct dm_space_map * sm,dm_block_t b,dm_block_t e)656be500ed7SJoe Thornber static int sm_bootstrap_inc_blocks(struct dm_space_map *sm, dm_block_t b, dm_block_t e)
6573241b1d3SJoe Thornber {
658be500ed7SJoe Thornber 	int r;
6593241b1d3SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
6603241b1d3SJoe Thornber 
661be500ed7SJoe Thornber 	r = add_bop(smm, BOP_INC, b, e);
662be500ed7SJoe Thornber 	if (r)
663be500ed7SJoe Thornber 		return r;
664be500ed7SJoe Thornber 
665be500ed7SJoe Thornber 	return 0;
6663241b1d3SJoe Thornber }
6673241b1d3SJoe Thornber 
sm_bootstrap_dec_blocks(struct dm_space_map * sm,dm_block_t b,dm_block_t e)668be500ed7SJoe Thornber static int sm_bootstrap_dec_blocks(struct dm_space_map *sm, dm_block_t b, dm_block_t e)
6693241b1d3SJoe Thornber {
670be500ed7SJoe Thornber 	int r;
6713241b1d3SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
6723241b1d3SJoe Thornber 
673be500ed7SJoe Thornber 	r = add_bop(smm, BOP_DEC, b, e);
674be500ed7SJoe Thornber 	if (r)
675be500ed7SJoe Thornber 		return r;
676be500ed7SJoe Thornber 
677be500ed7SJoe Thornber 	return 0;
6783241b1d3SJoe Thornber }
6793241b1d3SJoe Thornber 
sm_bootstrap_commit(struct dm_space_map * sm)6803241b1d3SJoe Thornber static int sm_bootstrap_commit(struct dm_space_map *sm)
6813241b1d3SJoe Thornber {
6823241b1d3SJoe Thornber 	return 0;
6833241b1d3SJoe Thornber }
6843241b1d3SJoe Thornber 
sm_bootstrap_root_size(struct dm_space_map * sm,size_t * result)6853241b1d3SJoe Thornber static int sm_bootstrap_root_size(struct dm_space_map *sm, size_t *result)
6863241b1d3SJoe Thornber {
68788a488f6SJoe Thornber 	DMERR("bootstrap doesn't support root_size");
6883241b1d3SJoe Thornber 
6893241b1d3SJoe Thornber 	return -EINVAL;
6903241b1d3SJoe Thornber }
6913241b1d3SJoe Thornber 
sm_bootstrap_copy_root(struct dm_space_map * sm,void * where,size_t max)6923241b1d3SJoe Thornber static int sm_bootstrap_copy_root(struct dm_space_map *sm, void *where,
6933241b1d3SJoe Thornber 				  size_t max)
6943241b1d3SJoe Thornber {
69588a488f6SJoe Thornber 	DMERR("bootstrap doesn't support copy_root");
6963241b1d3SJoe Thornber 
6973241b1d3SJoe Thornber 	return -EINVAL;
6983241b1d3SJoe Thornber }
6993241b1d3SJoe Thornber 
700b79af13eSBhumika Goyal static const struct dm_space_map bootstrap_ops = {
7013241b1d3SJoe Thornber 	.destroy = sm_bootstrap_destroy,
7023241b1d3SJoe Thornber 	.extend = sm_bootstrap_extend,
7033241b1d3SJoe Thornber 	.get_nr_blocks = sm_bootstrap_get_nr_blocks,
7043241b1d3SJoe Thornber 	.get_nr_free = sm_bootstrap_get_nr_free,
7053241b1d3SJoe Thornber 	.get_count = sm_bootstrap_get_count,
7063241b1d3SJoe Thornber 	.count_is_more_than_one = sm_bootstrap_count_is_more_than_one,
7073241b1d3SJoe Thornber 	.set_count = sm_bootstrap_set_count,
708be500ed7SJoe Thornber 	.inc_blocks = sm_bootstrap_inc_blocks,
709be500ed7SJoe Thornber 	.dec_blocks = sm_bootstrap_dec_blocks,
7103241b1d3SJoe Thornber 	.new_block = sm_bootstrap_new_block,
7113241b1d3SJoe Thornber 	.commit = sm_bootstrap_commit,
7123241b1d3SJoe Thornber 	.root_size = sm_bootstrap_root_size,
7137c3d3f2aSJoe Thornber 	.copy_root = sm_bootstrap_copy_root,
7147c3d3f2aSJoe Thornber 	.register_threshold_callback = NULL
7153241b1d3SJoe Thornber };
7163241b1d3SJoe Thornber 
7173241b1d3SJoe Thornber /*----------------------------------------------------------------*/
7183241b1d3SJoe Thornber 
sm_metadata_extend(struct dm_space_map * sm,dm_block_t extra_blocks)7191921c56dSJoe Thornber static int sm_metadata_extend(struct dm_space_map *sm, dm_block_t extra_blocks)
7201921c56dSJoe Thornber {
721be500ed7SJoe Thornber 	int r;
7221921c56dSJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
7231921c56dSJoe Thornber 	dm_block_t old_len = smm->ll.nr_blocks;
7241921c56dSJoe Thornber 
7251921c56dSJoe Thornber 	/*
7261921c56dSJoe Thornber 	 * Flick into a mode where all blocks get allocated in the new area.
7271921c56dSJoe Thornber 	 */
7281921c56dSJoe Thornber 	smm->begin = old_len;
7297e664b3dSJoe Thornber 	memcpy(sm, &bootstrap_ops, sizeof(*sm));
7301921c56dSJoe Thornber 
7311921c56dSJoe Thornber 	/*
7321921c56dSJoe Thornber 	 * Extend.
7331921c56dSJoe Thornber 	 */
7341921c56dSJoe Thornber 	r = sm_ll_extend(&smm->ll, extra_blocks);
7357e664b3dSJoe Thornber 	if (r)
7367e664b3dSJoe Thornber 		goto out;
7371921c56dSJoe Thornber 
738fca02843SJoe Thornber 	/*
739fca02843SJoe Thornber 	 * We repeatedly increment then commit until the commit doesn't
740fca02843SJoe Thornber 	 * allocate any new blocks.
741fca02843SJoe Thornber 	 */
742fca02843SJoe Thornber 	do {
743be500ed7SJoe Thornber 		r = add_bop(smm, BOP_INC, old_len, smm->begin);
7447e664b3dSJoe Thornber 		if (r)
7457e664b3dSJoe Thornber 			goto out;
74650dd842aSJoe Thornber 
747fca02843SJoe Thornber 		old_len = smm->begin;
7487e664b3dSJoe Thornber 
7496096d91aSJoe Thornber 		r = apply_bops(smm);
7506096d91aSJoe Thornber 		if (r) {
7516096d91aSJoe Thornber 			DMERR("%s: apply_bops failed", __func__);
7526096d91aSJoe Thornber 			goto out;
7536096d91aSJoe Thornber 		}
7546096d91aSJoe Thornber 
755fca02843SJoe Thornber 		r = sm_ll_commit(&smm->ll);
756fca02843SJoe Thornber 		if (r)
757fca02843SJoe Thornber 			goto out;
758fca02843SJoe Thornber 
759fca02843SJoe Thornber 	} while (old_len != smm->begin);
7607e664b3dSJoe Thornber 
7617e664b3dSJoe Thornber out:
7621921c56dSJoe Thornber 	/*
7631921c56dSJoe Thornber 	 * Switch back to normal behaviour.
7641921c56dSJoe Thornber 	 */
7657e664b3dSJoe Thornber 	memcpy(sm, &ops, sizeof(*sm));
7661921c56dSJoe Thornber 	return r;
7671921c56dSJoe Thornber }
7681921c56dSJoe Thornber 
7691921c56dSJoe Thornber /*----------------------------------------------------------------*/
7701921c56dSJoe Thornber 
dm_sm_metadata_init(void)7713241b1d3SJoe Thornber struct dm_space_map *dm_sm_metadata_init(void)
7723241b1d3SJoe Thornber {
7733241b1d3SJoe Thornber 	struct sm_metadata *smm;
7743241b1d3SJoe Thornber 
775*a6bba25fSMikulas Patocka 	smm = kvmalloc(sizeof(*smm), GFP_KERNEL);
7763241b1d3SJoe Thornber 	if (!smm)
7773241b1d3SJoe Thornber 		return ERR_PTR(-ENOMEM);
7783241b1d3SJoe Thornber 
7793241b1d3SJoe Thornber 	memcpy(&smm->sm, &ops, sizeof(smm->sm));
7803241b1d3SJoe Thornber 
7813241b1d3SJoe Thornber 	return &smm->sm;
7823241b1d3SJoe Thornber }
7833241b1d3SJoe Thornber 
dm_sm_metadata_create(struct dm_space_map * sm,struct dm_transaction_manager * tm,dm_block_t nr_blocks,dm_block_t superblock)7843241b1d3SJoe Thornber int dm_sm_metadata_create(struct dm_space_map *sm,
7853241b1d3SJoe Thornber 			  struct dm_transaction_manager *tm,
7863241b1d3SJoe Thornber 			  dm_block_t nr_blocks,
7873241b1d3SJoe Thornber 			  dm_block_t superblock)
7883241b1d3SJoe Thornber {
7893241b1d3SJoe Thornber 	int r;
7903241b1d3SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
7913241b1d3SJoe Thornber 
7923241b1d3SJoe Thornber 	smm->begin = superblock + 1;
7933241b1d3SJoe Thornber 	smm->recursion_count = 0;
7943241b1d3SJoe Thornber 	smm->allocated_this_transaction = 0;
795cebc2de4SJoe Thornber 	brb_init(&smm->uncommitted);
7962fc48021SJoe Thornber 	threshold_init(&smm->threshold);
7973241b1d3SJoe Thornber 
7983241b1d3SJoe Thornber 	memcpy(&smm->sm, &bootstrap_ops, sizeof(smm->sm));
7993241b1d3SJoe Thornber 
8003241b1d3SJoe Thornber 	r = sm_ll_new_metadata(&smm->ll, tm);
801314c25c5SBenjamin Marzinski 	if (!r) {
8027d48935eSMike Snitzer 		if (nr_blocks > DM_SM_METADATA_MAX_BLOCKS)
8037d48935eSMike Snitzer 			nr_blocks = DM_SM_METADATA_MAX_BLOCKS;
8043241b1d3SJoe Thornber 		r = sm_ll_extend(&smm->ll, nr_blocks);
805314c25c5SBenjamin Marzinski 	}
806314c25c5SBenjamin Marzinski 	memcpy(&smm->sm, &ops, sizeof(smm->sm));
8073241b1d3SJoe Thornber 	if (r)
8083241b1d3SJoe Thornber 		return r;
8093241b1d3SJoe Thornber 
8103241b1d3SJoe Thornber 	/*
8113241b1d3SJoe Thornber 	 * Now we need to update the newly created data structures with the
8123241b1d3SJoe Thornber 	 * allocated blocks that they were built from.
8133241b1d3SJoe Thornber 	 */
814be500ed7SJoe Thornber 	r = add_bop(smm, BOP_INC, superblock, smm->begin);
8153241b1d3SJoe Thornber 	if (r)
8163241b1d3SJoe Thornber 		return r;
8173241b1d3SJoe Thornber 
8186096d91aSJoe Thornber 	r = apply_bops(smm);
8196096d91aSJoe Thornber 	if (r) {
8206096d91aSJoe Thornber 		DMERR("%s: apply_bops failed", __func__);
8216096d91aSJoe Thornber 		return r;
8226096d91aSJoe Thornber 	}
8236096d91aSJoe Thornber 
8243241b1d3SJoe Thornber 	return sm_metadata_commit(sm);
8253241b1d3SJoe Thornber }
8263241b1d3SJoe Thornber 
dm_sm_metadata_open(struct dm_space_map * sm,struct dm_transaction_manager * tm,void * root_le,size_t len)8273241b1d3SJoe Thornber int dm_sm_metadata_open(struct dm_space_map *sm,
8283241b1d3SJoe Thornber 			struct dm_transaction_manager *tm,
8293241b1d3SJoe Thornber 			void *root_le, size_t len)
8303241b1d3SJoe Thornber {
8313241b1d3SJoe Thornber 	int r;
8323241b1d3SJoe Thornber 	struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
8333241b1d3SJoe Thornber 
8343241b1d3SJoe Thornber 	r = sm_ll_open_metadata(&smm->ll, tm, root_le, len);
8353241b1d3SJoe Thornber 	if (r)
8363241b1d3SJoe Thornber 		return r;
8373241b1d3SJoe Thornber 
8383241b1d3SJoe Thornber 	smm->begin = 0;
8393241b1d3SJoe Thornber 	smm->recursion_count = 0;
8403241b1d3SJoe Thornber 	smm->allocated_this_transaction = 0;
841cebc2de4SJoe Thornber 	brb_init(&smm->uncommitted);
8422fc48021SJoe Thornber 	threshold_init(&smm->threshold);
8433241b1d3SJoe Thornber 
8443241b1d3SJoe Thornber 	memcpy(&smm->old_ll, &smm->ll, sizeof(smm->old_ll));
8453241b1d3SJoe Thornber 	return 0;
8463241b1d3SJoe Thornber }
847