blob: dddf7a2538f6c76f2ea547ed465fbab04efb080b [file] [log] [blame]
/*
* Copyright 1996-2002 Hans Reiser
*/
#include "fsck.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
FIXME: objectid gets into map when stat data item
*/
#if 0
/* is it marked used in super block's objectid map. fixme: binary search could
be used here */
int is_objectid_used (reiserfs_filsys_t * fs, __u32 objectid)
{
__u32 * objectid_map;
int i = 0;
objectid_map = (__u32 *)((char *)(fs->fs_ondisk_sb) + (sb_size(fs)));
while (i < get_sb_oid_cursize (fs->fs_ondisk_sb)) {
if (objectid == le32_to_cpu (objectid_map[i])) {
return 1; /* objectid is used */
}
if (objectid > le32_to_cpu(objectid_map[i]) &&
objectid < le32_to_cpu(objectid_map[i+1])) {
return 1; /* objectid is used */
}
if (objectid < le32_to_cpu(objectid_map[i]))
break;
i += 2;
}
/* objectid is free */
return 0;
}
#endif
/* true objectid map */
/* increase area by MAP_SIZE bytes */
static void grow_id_map (struct id_map * map)
{
/*
if (map->m_page_count && ((map->m_page_count % 5) == 0)) {
fsck_log ("grow_id_map: objectid map expanded: used %lu, %d blocks\n",
map->m_used_slots_count, map->m_page_count);
}
*/
map->m_begin = expandmem (map->m_begin, map->m_page_count * MAP_SIZE, MAP_SIZE);
map->m_page_count ++;
}
static void try_to_shrink_id_map (struct id_map * map)
{
if (map->m_used_slots_count * sizeof(__u32) <= (map->m_page_count - 1) * MAP_SIZE) {
/*
if (map->m_page_count && ((map->m_page_count % 5) == 0))
fsck_log ("shrink_id_map: objectid map shrinked: used %lu, %d blocks\n",
map->m_used_slots_count, map->m_page_count);
*/
map->m_begin = expandmem (map->m_begin, map->m_page_count * MAP_SIZE,
-MAP_SIZE);
map->m_page_count--;
}
}
/* ubin_search_id is used to find id in the map (or proper place to
insert the new id). if smth goes wrong or ubin_search_id stops
working properly check_id_search_result should help to find raised
problems */
static void check_id_search_result(struct id_map * map, int res, __u32 pos,
__u32 id)
{
if (res != POSITION_FOUND && res != POSITION_NOT_FOUND)
die("check_id_search_result: get wrong result from ubin_search (%d)", res);
if (res == 1 && le32_to_cpu (map->m_begin[pos]) != id)
die("check_id_search_result: wrong id found %u %u", id, le32_to_cpu(map->m_begin[pos]));
if (res == 1)
{
if (pos > map->m_used_slots_count)
die("check_id_search_result: get bad position (%u), used %u",
pos, map->m_used_slots_count);
if (pos >= 0 && pos <= map->m_used_slots_count && le32_to_cpu(map->m_begin[pos - 1]) >= id)
die("check_id_search_result: previous id (%u) not less than (%u)",
le32_to_cpu(map->m_begin[pos - 1]), id);
if (pos >= 0 && pos < map->m_used_slots_count && le32_to_cpu(map->m_begin[pos]) < id)
die("check_id_search_result: found id (%u) not much than (%u)",
le32_to_cpu(map->m_begin[pos]), id);
}
}
/* */
struct id_map * init_id_map (void)
{
struct id_map * map;
map = getmem (sizeof (struct id_map));
map->m_begin = NULL;
map->m_used_slots_count = 0;
map->m_page_count = 0;
mark_objectid_really_used (map, 1);
return map;
}
/* free whole map */
void free_id_map (struct id_map * map)
{
freemem (map->m_begin);
freemem (map);
}
/* return 1 if id is marked used, 0 otherwise */
int is_objectid_really_used (struct id_map * map, __u32 id, __u32 * ppos)
{
int res;
__u32 le_id = cpu_to_le32 (id);
*ppos = 0;
if (map->m_begin == NULL)
return 0;
/* smth exists in the map, find proper place to insert or this id */
res = reiserfs_bin_search (&le_id, map->m_begin, map->m_used_slots_count,
sizeof (__u32), ppos, comp_ids);
#if 1
check_id_search_result (map, res, *ppos, id);
#endif
/* *ppos is position in objectid map of the element which is equal id
or position of an element which is smallest and greater than id */
if (res == POSITION_NOT_FOUND)
/* id is not found in the map. if returned position is odd -
id is marked used */
return (*ppos % 2);
/* if returned position is odd - id is marked free */
return !(*ppos % 2);
}
static void check_objectid_map (struct id_map * map, int pos)
{
/* check only previous id, current and 2 next ones,
if not specified to check evth */
int count = 3;
int i;
int first = pos;
if (first == 0) {
first = 1;
} else if (first == -1) {
count = map->m_used_slots_count - 1;
first = 1;
}
if (first + count > map->m_used_slots_count)
count = map->m_used_slots_count - first;
for (i = first; i < first + count; i ++)
if (le32_to_cpu(map->m_begin [i - 1]) >= le32_to_cpu(map->m_begin [i]))
die ("check_objectid_map: map corrupted");
}
int __mark_objectid_really_used(struct id_map *map, __u32 id, __u32 pos) {
map->objectids_marked ++;
if (pos % 2 == 0){
/* id not found in the map. why? is_id_used() knows */
if (map->m_begin == NULL)
/* map is empty */
grow_id_map (map);
/* id + 1 is used, change id + 1 to id and exit */
if ( id + 1 == le32_to_cpu (map->m_begin[pos]) ) {
/* we can mark id as used w/o expanding of id map */
map->m_begin[pos] = cpu_to_le32 (id);
check_objectid_map (map, pos);
return 0;
}
if (map->m_page_count * MAP_SIZE == map->m_used_slots_count * sizeof(__u32))
/* fixme: do not grow too much */
grow_id_map (map);
if (map->m_used_slots_count - pos > 0)
memmove (map->m_begin + pos + 2, map->m_begin + pos, (map->m_used_slots_count - pos) * sizeof (__u32));
map->m_used_slots_count += 2;
map->m_begin[pos] = cpu_to_le32 (id);
map->m_begin[pos+1] = cpu_to_le32 (id + 1);
check_objectid_map (map, pos);
return 0;
}
/* id found in the map. pos is odd position () */
map->m_begin[pos] = cpu_to_le32 (id + 1);
/* if end id of current interval == start id of next interval we
eliminated a sequence of unused objectids */
if (pos + 1 < map->m_used_slots_count &&
map->m_begin[pos + 1] == map->m_begin[pos]) { /* safe, both are le */
memmove (map->m_begin + pos, map->m_begin + pos + 2, (map->m_used_slots_count - pos - 2) * sizeof (__u32));
map->m_used_slots_count -= 2;
try_to_shrink_id_map (map);
}
check_objectid_map (map, pos);
return 0;
}
/* returns 1 objectid is marked used already, 0 otherwise */
int mark_objectid_really_used (struct id_map * map, __u32 id)
{
__u32 pos;
/* check whether id is used and get place if used or place to insert if not */
if (is_objectid_really_used (map, id, &pos) == 1)
return 1;
return __mark_objectid_really_used(map, id, pos) ;
}
static __u32 get_free_id (reiserfs_filsys_t * fs)
{
struct id_map * map;
map = proper_id_map (fs);
/* If map is not NULL return the second element (first position in
the map). This allocates the first unused objectid. That is to
say, the first entry on the objectid map is the first unused
objectid. */
if (map->m_begin == NULL) {
fprintf (stderr, "get_free_id: hmm, 1 is allocated as objectid\n");
return 1;
}
return (le32_to_cpu (map->m_begin[1]));
}
__u32 get_unused_objectid (reiserfs_filsys_t * fs)
{
__u32 objectid;
objectid = get_free_id (fs);
if (mark_objectid_really_used (proper_id_map (fs), objectid))
die ("get_unused_objectid: could not mark %lu used",
( long unsigned ) objectid);
return objectid;
}
#define objectid_map(fs) ((char *)((char *)((fs)->s_rs) + sb_size (fs)))
#if 0
/* returns 0 if on-disk objectid map matches to the correct one, 1
otherwise */
int compare_id_maps (reiserfs_filsys_t * fs)
{
struct id_map * map;
int disk_size;
map = proper_id_map (fs);
disk_size = rs_objectid_map_size (fs->s_rs);
if (disk_size != map->m_used_slots_count ||
memcmp ((char *)((char *)((fs)->s_rs) + sb_size (fs)), map->m_begin, sizeof(__u32) * disk_size)) {
fprintf (stderr, "Objectid maps mismatch\n");
return 1;
}
return 0;
}
/* copy objectid map into buffer containing super block */
void correct_objectid_map (reiserfs_filsys_t * fs)
{
struct id_map * map;
int size, disk_max;
map = proper_id_map (fs);
size = map->m_used_slots_count;
disk_max = rs_objectid_map_max_size (fs->s_rs);
if (disk_max < size) {
size = disk_max;
} else {
memset (fu_objectid_map (fs) + size, 0, (disk_max - size) * sizeof (__u32));
}
memcpy (fu_objectid_map (fs), map->m_begin, size * sizeof (__u32));
set_objectid_map_size (fs->s_rs, size);
mark_buffer_dirty (SB_BUFFER_WITH_SB (fs));
/*
if (fs->fu_job->verbose)
fprintf (stderr, "Objectid map corrected\n");
*/
}
#endif
/* print the map of objectids */
void print_objectid_list (__u32 *map, int count)
{
int i;
for (i = 0; i < count ; i += 2)
printf ("\n[%u-%u]", le32_to_cpu(map[i]),le32_to_cpu(map[i+1]));
}
#if 0
/* print on-disk map of objectids */
void print_disk_objectid_list (void)
{
int i;
__u32 * objectid_map = (__u32 *)((char *)SB_DISK_SUPER_BLOCK (&g_sb) + (sb_size(&g_sb)));
printf ("\n on-disk id map. used:%lu", SB_OBJECTID_MAP_SIZE(&g_sb));
for (i = 0; i < SB_OBJECTID_MAP_SIZE(&g_sb); i += 2)
printf ("\n[%u-%u]", objectid_map[i], objectid_map[i + 1] - 1);
}
#endif
void flush_objectid_map (struct id_map * map, reiserfs_filsys_t * fs)
{
int size, max;
int sb_size;
__u32 * sb_objectid_map;
sb_size = reiserfs_super_block_size (fs->fs_ondisk_sb);
sb_objectid_map = (__u32 *)((char *)(fs->fs_ondisk_sb) + sb_size);
max = ((fs->fs_blocksize - sb_size) >> 3 << 1);
set_sb_oid_maxsize (fs->fs_ondisk_sb, max);
if (map->m_used_slots_count > max)
size = max;
else
size = map->m_used_slots_count;
check_objectid_map (map, -1);
memcpy (sb_objectid_map, map->m_begin, size * sizeof (__u32));
memset (sb_objectid_map + size, 0, (max - size) * sizeof (__u32));
set_sb_oid_cursize (fs->fs_ondisk_sb, size);
if (size == max)
sb_objectid_map [max - 1] = map->m_begin [map->m_used_slots_count - 1];
// check_objectid_map (map);
}
void fetch_objectid_map (struct id_map * map, reiserfs_filsys_t * fs)
{
int sb_size;
__u32 * sb_objectid_map;
sb_size = reiserfs_super_block_size (fs->fs_ondisk_sb);
sb_objectid_map = (__u32 *)((char *)(fs->fs_ondisk_sb) + sb_size);
if (map->m_page_count != 1)
die ("fetch_objectid_map: can not fetch long map");
grow_id_map (map);
memcpy (map->m_begin, sb_objectid_map, get_sb_oid_cursize (fs->fs_ondisk_sb) * sizeof (__u32));
map->m_used_slots_count = get_sb_oid_cursize (fs->fs_ondisk_sb);
}
#define OBJMAP_START_MAGIC 375331
#define OBJMAP_END_MAGIC 7700472
void reiserfs_objectid_map_save (FILE * fp, struct id_map * id_map)
{
__u32 v;
int i;
v = OBJMAP_START_MAGIC;
fwrite (&v, 4, 1, fp);
v = id_map->m_used_slots_count;
fwrite (&v, 4, 1, fp);
for (i = 0; i < id_map->m_page_count - 1; i++) {
fwrite ((char *)id_map->m_begin + MAP_SIZE * i, 4, 1, fp);
}
for (i = 0; i < id_map->m_used_slots_count * sizeof(__u32) - (id_map->m_page_count - 1) * MAP_SIZE; i++) {
fwrite ((char *)id_map->m_begin + MAP_SIZE * (id_map->m_page_count - 1) + i, 4, 1, fp);
}
v = OBJMAP_END_MAGIC;
fwrite (&v, 4, 1, fp);
}
struct id_map * reiserfs_objectid_map_load (FILE * fp)
{
__u32 v;
int i;
struct id_map * id_map;
fread (&v, 4, 1, fp);
if (v != OBJMAP_START_MAGIC) {
reiserfs_warning (stderr, "reiserfs_objectid_map_load: no objectid map begin magic found");
return 0;
}
/* read bit size of objectid map */
fread (&v, 4, 1, fp);
id_map = init_id_map ();
id_map->m_used_slots_count = v;
id_map->m_page_count = v / MAP_SIZE + 1;
id_map->m_begin = expandmem (id_map->m_begin, 0, id_map->m_page_count * MAP_SIZE);
for (i = 0; i < id_map->m_page_count - 1; i++) {
fread ((char *)id_map->m_begin + MAP_SIZE * i, 4, 1, fp);
}
for (i = 0; i < id_map->m_used_slots_count * sizeof(__u32) - (id_map->m_page_count - 1) * MAP_SIZE; i++) {
fread ((char *)id_map->m_begin + MAP_SIZE * (id_map->m_page_count - 1) + i, 4, 1, fp);
}
fread (&v, 4, 1, fp);
if (v != OBJMAP_END_MAGIC) {
reiserfs_warning (stderr, "reiserfs_objectid_map_load: no objectid map end magic found");
return 0;
}
fflush (stderr);
return id_map;
}