mirror of
git://sourceware.org/git/lvm2.git
synced 2024-12-22 17:35:59 +03:00
180 lines
3.9 KiB
C
180 lines
3.9 KiB
C
/*
|
|
* dm-table.c
|
|
*
|
|
* Copyright (C) 2001 Sistina Software
|
|
*
|
|
* This software is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2, or (at
|
|
* your option) any later version.
|
|
*
|
|
* This software is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with GNU CC; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
/*
|
|
* Changelog
|
|
*
|
|
* 16/08/2001 - First version [Joe Thornber]
|
|
*/
|
|
|
|
#include "dm.h"
|
|
|
|
static int _alloc_targets(struct mapped_device *md, int num);
|
|
|
|
static inline ulong _round_up(ulong n, ulong size)
|
|
{
|
|
ulong r = n % size;
|
|
return n + (r ? (size - r) : 0);
|
|
}
|
|
|
|
static inline ulong _div_up(ulong n, ulong size)
|
|
{
|
|
return _round_up(n, size) / size;
|
|
}
|
|
|
|
static offset_t _high(struct mapped_device *md, int l, int n)
|
|
{
|
|
while (1) {
|
|
if (n >= md->counts[l])
|
|
return (offset_t) -1;
|
|
|
|
if (l == md->depth - 1)
|
|
return md->index[l][((n + 1) * KEYS_PER_NODE) - 1];
|
|
|
|
l++;
|
|
n = (n + 1) * (KEYS_PER_NODE + 1) - 1;
|
|
}
|
|
}
|
|
|
|
static int _setup_btree_index(int l, struct mapped_device *md)
|
|
{
|
|
int n, c, cn;
|
|
|
|
for (n = 0, cn = 0; n < md->counts[l]; n++) {
|
|
offset_t *k = md->index[l] + (n * KEYS_PER_NODE);
|
|
|
|
for (c = 0; c < KEYS_PER_NODE; c++)
|
|
k[c] = _high(md, l + 1, cn++);
|
|
cn++;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void dm_free_table(struct mapped_device *md)
|
|
{
|
|
int i;
|
|
for (i = 0; i < md->depth; i++)
|
|
vfree(md->index[i]);
|
|
|
|
vfree(md->targets);
|
|
vfree(md->contexts);
|
|
|
|
md->num_targets = 0;
|
|
md->num_allocated = 0;
|
|
}
|
|
|
|
int dm_start_table(struct mapped_device *md)
|
|
{
|
|
set_bit(DM_LOADING, &md->state);
|
|
|
|
dm_free_table(md);
|
|
if (!_alloc_targets(md, 2)) /* FIXME: increase once debugged 256 ? */
|
|
return -ENOMEM;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int dm_add_entry(struct mapped_device *md, offset_t high,
|
|
dm_map_fn target, void *context)
|
|
{
|
|
if (md->num_targets >= md->num_targets &&
|
|
!_alloc_targets(md, md->num_allocated * 2))
|
|
return -ENOMEM;
|
|
|
|
md->highs[md->num_targets] = high;
|
|
md->targets[md->num_targets] = target;
|
|
md->contexts[md->num_targets] = context;
|
|
|
|
md->num_targets++;
|
|
return 0;
|
|
}
|
|
|
|
int dm_complete_table(struct mapped_device *md)
|
|
{
|
|
int n, i;
|
|
|
|
clear_bit(DM_LOADING, &md->state);
|
|
|
|
/* how many indexes will the btree have ? */
|
|
for (n = _div_up(md->num_targets, KEYS_PER_NODE), i = 1; n != 1; i++)
|
|
n = _div_up(n, KEYS_PER_NODE + 1);
|
|
|
|
md->depth = i;
|
|
md->counts[md->depth - 1] = _div_up(md->num_targets, KEYS_PER_NODE);
|
|
|
|
while (--i)
|
|
md->counts[i - 1] = _div_up(md->counts[i], KEYS_PER_NODE + 1);
|
|
|
|
for (i = 0; i < md->depth; i++) {
|
|
size_t s = NODE_SIZE * md->counts[i];
|
|
md->index[i] = vmalloc(s);
|
|
memset(md->index[i], -1, s);
|
|
}
|
|
|
|
/* bottom layer is easy */
|
|
md->index[md->depth - 1] = md->highs;
|
|
|
|
/* fill in higher levels */
|
|
for (i = md->depth - 1; i; i--)
|
|
_setup_btree_index(i - 1, md);
|
|
|
|
set_bit(DM_LOADED, &md->state);
|
|
return 1;
|
|
}
|
|
|
|
static int _alloc_targets(struct mapped_device *md, int num)
|
|
{
|
|
offset_t *n_highs;
|
|
dm_map_fn *n_targets;
|
|
void **n_contexts;
|
|
|
|
if (!(n_highs = vmalloc(sizeof(*n_highs) * num)))
|
|
return 0;
|
|
|
|
if (!(n_targets = vmalloc(sizeof(*n_targets) * num))) {
|
|
vfree(n_highs);
|
|
return 0;
|
|
}
|
|
|
|
if (!(n_contexts = vmalloc(sizeof(*n_contexts) * num))) {
|
|
vfree(n_highs);
|
|
vfree(n_targets);
|
|
return 0;
|
|
}
|
|
|
|
memcpy(n_highs, md->highs, sizeof(*n_highs) * md->num_targets);
|
|
memcpy(n_targets, md->targets, sizeof(*n_targets) * md->num_targets);
|
|
memcpy(n_contexts, md->contexts,
|
|
sizeof(*n_contexts) * md->num_targets);
|
|
|
|
vfree(md->highs);
|
|
vfree(md->targets);
|
|
vfree(md->contexts);
|
|
|
|
md->num_allocated = num;
|
|
md->highs = n_highs;
|
|
md->targets = n_targets;
|
|
md->contexts = n_contexts;
|
|
|
|
return 1;
|
|
}
|