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