/* * Space map interface. * * The low level disk format is written using the standard btree and * transaction manager. This means that performing disk operations may * cause us to recurse into the space map in order to allocate new blocks. * For this reason we have a pool of pre-allocated blocks large enough to * service any metadata_ll_disk operation.
*/
/* * FIXME: we should calculate this based on the size of the device. * Only the metadata space map needs this functionality.
*/ #define MAX_RECURSIVE_ALLOCATIONS 1024
staticint apply_bops(struct sm_metadata *smm)
{ int r = 0;
while (!brb_empty(&smm->uncommitted)) { struct block_op bop;
r = brb_peek(&smm->uncommitted, &bop); if (r) {
DMERR("bug in bop ring buffer"); break;
}
r = commit_bop(smm, &bop); if (r) break;
brb_pop(&smm->uncommitted);
}
return r;
}
staticint out(struct sm_metadata *smm)
{ int r = 0;
/* * If we're not recursing then very bad things are happening.
*/ if (!smm->recursion_count) {
DMERR("lost track of recursion depth"); return -ENOMEM;
}
if (smm->recursion_count == 1)
r = apply_bops(smm);
smm->recursion_count--;
return r;
}
/* * When using the out() function above, we often want to combine an error * code for the operation run in the recursive context with that from * out().
*/ staticint combine_errors(int r1, int r2)
{ return r1 ? r1 : r2;
}
/* * We may have some uncommitted adjustments to add. This list * should always be really short.
*/ for (i = smm->uncommitted.begin;
i != smm->uncommitted.end;
i = brb_next(&smm->uncommitted, i)) { struct block_op *op = smm->uncommitted.bops + i;
if (b < op->b || b >= op->e) continue;
switch (op->type) { case BOP_INC:
adjustment++; break;
case BOP_DEC:
adjustment--; break;
}
}
r = sm_ll_lookup(&smm->ll, b, result); if (r) return r;
/* * We may have some uncommitted adjustments to add. This list * should always be really short.
*/ for (i = smm->uncommitted.begin;
i != smm->uncommitted.end;
i = brb_next(&smm->uncommitted, i)) {
struct block_op *op = smm->uncommitted.bops + i;
if (b < op->b || b >= op->e) continue;
switch (op->type) { case BOP_INC:
adjustment++; break;
case BOP_DEC:
adjustment--; break;
}
}
if (adjustment > 1) {
*result = 1; return 0;
}
r = sm_ll_lookup_bitmap(&smm->ll, b, &rc); if (r) return r;
if (rc == 3) /* * We err on the side of caution, and always return true.
*/
*result = 1; else
*result = rc + adjustment > 1;
/* * Any block we allocate has to be free in both the old and current ll.
*/
r = sm_ll_find_common_free_block(&smm->old_ll, &smm->ll, smm->begin, smm->ll.nr_blocks, b); if (r == -ENOSPC) { /* * There's no free block between smm->begin and the end of the metadata device. * We search before smm->begin in case something has been freed.
*/
r = sm_ll_find_common_free_block(&smm->old_ll, &smm->ll, 0, smm->begin, b);
}
if (r) return r;
smm->begin = *b + 1;
if (recursing(smm))
r = add_bop(smm, BOP_INC, *b, *b + 1); else {
in(smm);
r = sm_ll_inc(&smm->ll, *b, *b + 1, &nr_allocations);
r2 = out(smm);
}
/* * When a new space map is created that manages its own space. We use * this tiny bootstrap allocator.
*/ staticvoid sm_bootstrap_destroy(struct dm_space_map *sm)
{
}
/* * Flick into a mode where all blocks get allocated in the new area.
*/
smm->begin = old_len;
memcpy(sm, &bootstrap_ops, sizeof(*sm));
/* * Extend.
*/
r = sm_ll_extend(&smm->ll, extra_blocks); if (r) goto out;
/* * We repeatedly increment then commit until the commit doesn't * allocate any new blocks.
*/ do {
r = add_bop(smm, BOP_INC, old_len, smm->begin); if (r) goto out;
old_len = smm->begin;
r = apply_bops(smm); if (r) {
DMERR("%s: apply_bops failed", __func__); goto out;
}
r = sm_ll_commit(&smm->ll); if (r) goto out;
} while (old_len != smm->begin);
out: /* * Switch back to normal behaviour.
*/
memcpy(sm, &ops, sizeof(*sm)); return r;
}
r = sm_ll_new_metadata(&smm->ll, tm); if (!r) { if (nr_blocks > DM_SM_METADATA_MAX_BLOCKS)
nr_blocks = DM_SM_METADATA_MAX_BLOCKS;
r = sm_ll_extend(&smm->ll, nr_blocks);
}
memcpy(&smm->sm, &ops, sizeof(smm->sm)); if (r) return r;
/* * Now we need to update the newly created data structures with the * allocated blocks that they were built from.
*/
r = add_bop(smm, BOP_INC, superblock, smm->begin); if (r) return r;
r = apply_bops(smm); if (r) {
DMERR("%s: apply_bops failed", __func__); return r;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.