Files
reiserfsprogs/utils/fsck/uobjectid.c
T

396 lines
8.6 KiB
C

/*
* Copyright 1996-2004 by Hans Reiser, licensing governed by
* reiserfsprogs/README
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "fsck.h"
#include "misc/malloc.h"
/* when --check fsck builds a map of objectids of files it finds in the tree
when --rebuild-tree - fsck builds map of objectids it inserts into tree */
#define ALLOC_SIZE 1024
#define MAX_ID (~(__u32)0)
/* 2 bytes for the counter */
#define BM_SIZE (ALLOC_SIZE - sizeof(__u16))
#define BM_INTERVAL (BM_SIZE * 8)
#define INDEX_COUNT (MAX_ID / BM_INTERVAL)
#define id_map_interval(map, id) (map->index + (id / BM_INTERVAL))
#define id_map_local_count(interval) (interval + BM_SIZE)
/*
typedef struct sb_id_map {
__u32 * m_begin;
__u32 m_size, m_used_slot_count;
} sb_id_map_t;
*/
id_map_t *id_map_init() {
id_map_t *map;
__u32 i;
map = misc_getmem(sizeof(id_map_t));
map->index = misc_malloc(INDEX_COUNT * sizeof(void *));
for (i = 0; i < INDEX_COUNT; i++) {
if (map->index[i] != (void *)0)
map->index[i] = (void *)0;
}
id_map_mark(map, 0);
id_map_mark(map, 1);
/* id == 0 should not be there, just for convinient usage */
map->count--;
return map;
}
void id_map_free(id_map_t *map) {
__u32 i;
for (i = 0; i < INDEX_COUNT; i++) {
if (map->index[i] != (void *)0 && map->index[i] != (void *)1)
misc_freemem(map->index[i]);
}
misc_freemem(map->index);
misc_freemem(map);
}
int id_map_test(id_map_t *map, __u32 id) {
void **interval = id_map_interval(map, id);
if (*interval == (void *)0)
return 0;
if (*interval == (void *)1)
return 1;
return misc_test_bit(id % BM_INTERVAL, *interval);
}
int id_map_mark(id_map_t *map, __u32 id) {
void **interval = id_map_interval(map, id);
if (*interval == (void *)0)
*interval = misc_getmem(ALLOC_SIZE);
if (*interval == (void *)1)
return 1;
if (misc_test_bit(id % BM_INTERVAL, *interval))
return 1;
misc_set_bit(id % BM_INTERVAL, *interval);
(*(__u16 *)id_map_local_count(*interval))++;
map->count++;
if ((*(__u16 *)id_map_local_count(*interval)) == BM_INTERVAL) {
/* Dealloc fully used bitmap */
misc_freemem(*interval);
*interval = (void *)1;
}
if (map->last_used < (id / BM_INTERVAL))
map->last_used = id / BM_INTERVAL;
return 0;
}
/* call this for proper_id_map only!! */
__u32 id_map_alloc(id_map_t *map) {
__u32 i, zero_count;
__u32 id = 0, first = ~(__u32)0;
for (i = 0, zero_count = 0; zero_count < 10 && i < INDEX_COUNT - 1; i++) {
if (map->index[i] == (void *)0) {
if (zero_count == 0)
first = i;
zero_count++;
} else if (map->index[i] != (void *)1)
break;
}
if (map->index[i] != (void *)1 && map->index[i] != (void *)0) {
id = misc_find_first_zero_bit(map->index[i], BM_INTERVAL);
if (id >= BM_INTERVAL)
misc_die ("Id is out of interval size, interval looks corrupted.");
id += i * BM_INTERVAL;
} else if (first != ~(__u32)0) {
id = first * BM_INTERVAL;
if (id == 0)
id = 2;
} else
misc_die ("%s: No more free objectid is available.", __FUNCTION__);
id_map_mark(map, id);
return id;
}
/* this could be used if some more sofisticated flushing will be needed. */
/*
static void sb_id_map_pack(sb_id_map_t *map) {
map->m_begin[1] = map->m_begin[map->m_used_slot_count - 1];
memset(map->m_begin + 2, 0, map->m_used_slot_count - 2);
map->m_used_slot_count = 2;
}*/
static __u32 id_map_next_bound(id_map_t *map, __u32 start) {
__u32 index = start / BM_INTERVAL;
__u32 offset = 0;
int look_for;
if (map->index[index] == (void *)0)
look_for = 1;
else if (map->index[index] == (void *)1)
look_for = 0;
else {
offset = start % BM_INTERVAL;
look_for = !misc_test_bit(offset, map->index[index]);
offset++;
}
start_again:
if (look_for) {
while (index < INDEX_COUNT && map->index[index] == (void *)0) {
index++;
}
if (index == INDEX_COUNT)
return 0;
if (map->index[index] == (void *)1)
return index * BM_INTERVAL;
offset = misc_find_next_set_bit(map->index[index],
BM_INTERVAL, offset);
if (offset >= BM_INTERVAL) {
offset = 0;
index++;
goto start_again;
}
} else {
while (index < INDEX_COUNT && map->index[index] == (void *)1)
index++;
if (index == INDEX_COUNT)
return 0;
if (map->index[index] == (void *)0)
return index * BM_INTERVAL;
offset = misc_find_next_zero_bit(map->index[index],
BM_INTERVAL, offset);
if (offset >= BM_INTERVAL) {
offset = 0;
index++;
goto start_again;
}
}
return index * BM_INTERVAL + offset;
}
void id_map_flush(struct id_map * map, reiserfs_filsys_t * fs) {
int size, max, i;
__u32 id, prev_id;
__u32 * sb_objectid_map;
size = reiserfs_super_size (fs->fs_ondisk_sb);
sb_objectid_map = (__u32 *)((char *)(fs->fs_ondisk_sb) + size);
max = ((fs->fs_blocksize - size) >> 3 << 1);
reiserfs_sb_set_mapmax (fs->fs_ondisk_sb, max);
id = 1;
sb_objectid_map[0] = cpu_to_le32(0);
for (i = 1; i < max - 1; i++) {
id = id_map_next_bound(map, id);
sb_objectid_map[i] = cpu_to_le32(id);
if (id == 0) {
if (i % 2) {
misc_die ("%s: Used interval is not closed "
"on flushing.", __FUNCTION__);
}
break;
}
}
if (map->index[map->last_used] == (void *)0) {
misc_die ("Object id map looks corrupted - last "
"used interval cannot be zeroed.");
}
i++;
if (i == max) {
if (id == 0) {
misc_die ("Objectid interval does not contain "
"any set bit what is expected.");
}
if (map->index[map->last_used] == (void *)1) {
prev_id = BM_INTERVAL - 1;
} else {
prev_id = ~(__u32)0;
if (id < map->last_used * BM_INTERVAL)
id = 0;
else
id %= BM_INTERVAL;
if (misc_test_bit(id, map->index[map->last_used]))
prev_id = id;
while ((id = misc_find_next_set_bit(map->index[map->last_used],
BM_INTERVAL, (id + 1))) != BM_INTERVAL)
{
prev_id = id;
}
if (prev_id == ~(__u32)0) {
misc_die ("Objectid interval does not contain "
"any set bit what is expected.");
}
prev_id++;
}
sb_objectid_map[max - 1] =
cpu_to_le32(prev_id + map->last_used * BM_INTERVAL);
} else {
i--;
memset(sb_objectid_map + i, 0, (max - i) * sizeof (__u32));
}
reiserfs_sb_set_mapcur (fs->fs_ondisk_sb, i);
}
void fetch_objectid_map (struct id_map * map,
reiserfs_filsys_t * fs)
{
__u32 i, j, sb_size;
__u32 * sb_objectid_map;
sb_size = reiserfs_super_size (fs->fs_ondisk_sb);
sb_objectid_map = (__u32 *)((char *)(fs->fs_ondisk_sb) + sb_size);
if (map == NULL)
misc_die ("Not map given");
for (i = 0; i < reiserfs_sb_get_mapcur(fs->fs_ondisk_sb); i+=2) {
for (j = sb_objectid_map[i]; j < sb_objectid_map[i + 1]; j++) {
id_map_mark(map, j);
if (j == 0)
map->count--;
}
}
}
#define OBJMAP_START_MAGIC 375331
#define OBJMAP_END_MAGIC 7700472
void reiserfs_objectid_map_save (FILE * fp, struct id_map * id_map) {
__u32 v, count;
v = OBJMAP_START_MAGIC;
fwrite (&v, 4, 1, fp);
v = 0;
count = 0;
/* Write 0. */
fwrite (&v, 4, 1, fp);
count++;
while ((v = id_map_next_bound(id_map, v))) {
fwrite (&v, 4, 1, fp);
count++;
}
fwrite (&count, 4, 1, fp);
v = OBJMAP_END_MAGIC;
fwrite (&v, 4, 1, fp);
}
struct id_map * reiserfs_objectid_map_load (FILE * fp) {
__u32 v, count, i, prev, next;
struct id_map * id_map;
int skip, odd;
id_map = id_map_init();
fread (&v, 4, 1, fp);
if (v != OBJMAP_START_MAGIC) {
reiserfs_warning (stderr, "reiserfs_objectid_map_load: no "
"objectid map begin magic found");
goto error;
}
count = 0;
skip = 0;
odd = 0;
prev = 0;
while (1) {
if (skip) {
skip = 0;
v = next;
} else if (fread(&v, 4, 1, fp) != 1) {
reiserfs_warning (stderr, "%s: failed to read the given",
__FUNCTION__);
goto error;
}
if (v == count) {
/* Check if the magic goes after. */
if (fread(&next, 4, 1, fp) != 1) {
reiserfs_warning (stderr, "%s: failed to read the given",
__FUNCTION__);
goto error;
}
if (next != OBJMAP_END_MAGIC)
skip = 1;
else break;
}
if (odd) {
for (i = prev; i < v; i++) {
id_map_mark(id_map, i);
if (i == 0)
id_map->count--;
}
}
prev = v;
odd = odd ? 0 : 1;
count++;
}
return id_map;
error:
fflush (stderr);
id_map_free(id_map);
return NULL;
}