blob: 34f15c62634e711bbf2ed167033fe6421b05f2a9 [file] [log] [blame]
/*
* Copyright 2000-2004 by Hans Reiser, licensing governed by
* reiserfsprogs/README
*/
/*
* 2000/10/26 - Initial version.
*/
#include "includes.h"
#include <assert.h>
/* create clean bitmap */
reiserfs_bitmap_t * reiserfs_create_bitmap (unsigned int bit_count)
{
reiserfs_bitmap_t * bm;
bm = getmem (sizeof (*bm));
if (!bm)
return 0;
bm->bm_bit_size = bit_count;
bm->bm_byte_size = ((unsigned long long)bit_count + 7) / 8;
bm->bm_set_bits = 0;
bm->bm_map = getmem (bm->bm_byte_size);
if (!bm->bm_map) {
freemem (bm);
return 0;
}
return bm;
}
/* Expand existing bitmap. Return non-zero if can't. FIXME: it is
assumed that bit_count is new number of blocks to be addressed */
int reiserfs_expand_bitmap (reiserfs_bitmap_t * bm, unsigned int bit_count)
{
unsigned int byte_count = ((bit_count + 7) / 8);
char * new_map;
new_map = expandmem (bm->bm_map, bm->bm_byte_size,
byte_count - bm->bm_byte_size);
if (!new_map) {
return 1;
}
bm->bm_map = new_map;
bm->bm_byte_size = byte_count;
bm->bm_bit_size = bit_count;
bm->bm_dirty = 1;
return 0;
}
void reiserfs_shrink_bitmap (reiserfs_bitmap_t * bm, unsigned int bit_count)
{
unsigned long i;
assert (bm->bm_bit_size >= bit_count);
bm->bm_byte_size = (bit_count + 7) / 8;
bm->bm_bit_size = bit_count;
bm->bm_set_bits = 0;
bm->bm_dirty = 1;
for (i = 0; i < bm->bm_bit_size; i++) {
if (reiserfs_bitmap_test_bit(bm, i))
bm->bm_set_bits++;
}
}
/* bitmap destructor */
void reiserfs_delete_bitmap (reiserfs_bitmap_t * bm)
{
freemem(bm->bm_map);
bm->bm_map = NULL; /* to not reuse bitmap handle */
bm->bm_bit_size = 0;
bm->bm_byte_size = 0;
freemem(bm);
}
void reiserfs_bitmap_copy (reiserfs_bitmap_t * to, reiserfs_bitmap_t * from)
{
assert (to->bm_byte_size == from->bm_byte_size);
memcpy (to->bm_map, from->bm_map, from->bm_byte_size);
to->bm_bit_size = from->bm_bit_size;
to->bm_set_bits = from->bm_set_bits;
to->bm_dirty = 1;
}
int reiserfs_bitmap_compare (reiserfs_bitmap_t * bm1, reiserfs_bitmap_t * bm2)
{
unsigned long i, diff;
unsigned long int bytes, bits;
assert (bm1->bm_byte_size == bm2->bm_byte_size &&
bm1->bm_bit_size == bm2->bm_bit_size);
diff = 0;
/* compare full bytes */
bytes = bm1->bm_bit_size / 8;
bits = bytes * 8;
if (memcmp (bm1->bm_map, bm2->bm_map, bytes)) {
for (i = 0; i < bits; i ++)
if (reiserfs_bitmap_test_bit(bm1, i) != reiserfs_bitmap_test_bit(bm2, i))
diff ++;
}
/* compare last byte of bitmap which can be used partially */
bits = bm1->bm_bit_size % 8;
for (i = bm1->bm_bit_size / 8 * 8; i < bm1->bm_bit_size / 8 * 8 + bits; i ++)
if (reiserfs_bitmap_test_bit(bm1, i) != reiserfs_bitmap_test_bit(bm2, i))
diff ++;
/* int mask;
mask = 255 >> (8 - bits);
if ((bm1->bm_map [bytes] & mask) != (bm2->bm_map [bytes] & mask)) {
diff ++;
}
}*/
return diff;
}
/*
Does X | Y for every bit of the bitmap `to`, where
X - bit of the `to` bitmap,
Y - `from` bitmap.
Save result in the `to` bitmap.
*/
void reiserfs_bitmap_disjunction (reiserfs_bitmap_t * to,
reiserfs_bitmap_t * from)
{
unsigned int i;
assert (to->bm_byte_size == from->bm_byte_size &&
to->bm_bit_size == from->bm_bit_size);
for (i = 0; i < to->bm_bit_size; i++) {
if (misc_test_bit(i, from->bm_map) && !misc_test_bit(i, to->bm_map)) {
misc_set_bit(i, to->bm_map);
to->bm_set_bits ++;
to->bm_dirty = 1;
}
}
}
/*
Does X & !Y for every bit of the bitmap `base`, where
X - bit of the `base` bitmap,
Y - `exclude` bitmap.
Save result in the `base` bitmap.
*/
void reiserfs_bitmap_delta (reiserfs_bitmap_t * base, reiserfs_bitmap_t * exclude) {
unsigned int i;
assert (base->bm_byte_size == exclude->bm_byte_size &&
base->bm_bit_size == exclude->bm_bit_size);
for (i = 0; i < base->bm_bit_size; i++) {
if (misc_test_bit(i, exclude->bm_map) && misc_test_bit(i, base->bm_map)) {
misc_clear_bit(i, base->bm_map);
base->bm_set_bits --;
base->bm_dirty = 1;
}
}
}
void reiserfs_bitmap_set_bit (reiserfs_bitmap_t * bm, unsigned int bit_number)
{
assert(bit_number < bm->bm_bit_size);
if (misc_test_bit (bit_number, bm->bm_map))
return;
misc_set_bit(bit_number, bm->bm_map);
bm->bm_set_bits ++;
bm->bm_dirty = 1;
}
void reiserfs_bitmap_clear_bit (reiserfs_bitmap_t * bm, unsigned int bit_number)
{
assert(bit_number < bm->bm_bit_size);
if (!misc_test_bit (bit_number, bm->bm_map))
return;
misc_clear_bit (bit_number, bm->bm_map);
bm->bm_set_bits --;
bm->bm_dirty = 1;
}
int reiserfs_bitmap_test_bit (reiserfs_bitmap_t * bm, unsigned int bit_number)
{
if (bit_number >= bm->bm_bit_size)
printf ("bit %u, bitsize %lu\n", bit_number, bm->bm_bit_size);
assert(bit_number < bm->bm_bit_size);
return misc_test_bit(bit_number, bm->bm_map);
}
unsigned int reiserfs_bitmap_zeros (reiserfs_bitmap_t * bm) {
return bm->bm_bit_size - bm->bm_set_bits;
}
unsigned int reiserfs_bitmap_ones (reiserfs_bitmap_t * bm) {
return bm->bm_set_bits;
}
int reiserfs_bitmap_find_zero_bit (reiserfs_bitmap_t * bm, unsigned long * first)
{
unsigned long bit_nr = *first;
assert(*first < bm->bm_bit_size);
bit_nr = misc_find_next_zero_bit(bm->bm_map, bm->bm_bit_size, *first);
if (bit_nr >= bm->bm_bit_size) { /* search failed */
return 1;
}
*first = bit_nr;
return 0;
}
/* read every bitmap block and copy their content into bitmap 'bm' */
static int reiserfs_fetch_ondisk_bitmap (reiserfs_bitmap_t * bm, reiserfs_filsys_t * fs)
{
unsigned int last_byte_unused_bits;
unsigned long block, to_copy;
struct buffer_head * bh;
unsigned int i;
int copied;
int ret = 0;
char * p;
to_copy = (get_sb_block_count (fs->fs_ondisk_sb) + 7) / 8;
/*reiserfs_warning (stderr, "Fetching on-disk bitmap..");*/
assert (bm->bm_byte_size == to_copy);
copied = fs->fs_blocksize;
p = bm->bm_map;
block = fs->fs_super_bh->b_blocknr + 1;
while (to_copy) {
bh = bread (fs->fs_dev, block, fs->fs_blocksize);
if (!bh) {
reiserfs_warning (stderr, "reiserfs_fetch_ondisk_bitmap: "
"bread failed reading bitmap (%lu)\n", block);
bh = getblk (fs->fs_dev, block, fs->fs_blocksize);
if (!bh) {
reiserfs_exit (1, "reiserfs_fetch_ondisk_bitmap: "
"getblk failed");
}
memset (bh->b_data, 0xff, bh->b_size);
mark_buffer_uptodate (bh, 1);
}
if (to_copy < fs->fs_blocksize) {
for (i = to_copy; i < fs->fs_blocksize; i++) {
if (bh->b_data[i] != (char)0xff) {
ret = 1;
break;
}
}
copied = to_copy;
}
memcpy (p, bh->b_data, copied);
brelse (bh);
p += copied;
to_copy -= copied;
/* next bitmap block */
if (spread_bitmaps (fs))
block = (block / (fs->fs_blocksize * 8) + 1) * (fs->fs_blocksize * 8);
else
block ++;
}
/* on disk bitmap has bits out of SB_BLOCK_COUNT set to 1, where as
reiserfs_bitmap_t has those bits set to 0 */
last_byte_unused_bits = bm->bm_byte_size * 8 - bm->bm_bit_size;
for (i = 0; i < last_byte_unused_bits; i ++) {
if (misc_test_bit (bm->bm_bit_size + i, bm->bm_map) == 0)
ret = 1;
else
misc_clear_bit (bm->bm_bit_size + i, bm->bm_map);
}
bm->bm_set_bits = 0;
/* FIXME: optimize that */
for (i = 0; i < bm->bm_bit_size; i ++)
if (reiserfs_bitmap_test_bit (bm, i))
bm->bm_set_bits ++;
bm->bm_dirty = 0;
return ret;
}
/* copy bitmap 'bm' to buffers which hold on-disk bitmap if bitmap was ever
changed and return 1. Otherwise - return 0 */
int reiserfs_flush_to_ondisk_bitmap (reiserfs_bitmap_t * bm, reiserfs_filsys_t * fs)
{
unsigned int last_byte_unused_bits, i;
unsigned long to_copy, copied, block;
struct buffer_head * bh;
char * p;
/* make sure that the device is big enough */
bh = bread (fs->fs_dev, bm->bm_bit_size - 1, fs->fs_blocksize);
if (!bh) {
reiserfs_warning (stderr, "reiserfs_flush_to_ondisk_bitmap: bread failed for block %lu\n",
bm->bm_bit_size - 1);
/*
bh = getblk (fs->fs_dev, bm->bm_bit_size - 1, fs->fs_blocksize);
if (!bh)
reiserfs_panic ("reiserfs_flush_to_ondisk_bitmap: getblk failed");
mark_buffer_uptodate (bh, 1);
mark_buffer_dirty (bh);
bwrite (bh);*/
}
brelse (bh);
if (!bm->bm_dirty)
return 0;
to_copy = bm->bm_byte_size;
copied = fs->fs_blocksize;
p = bm->bm_map;
block = fs->fs_super_bh->b_blocknr + 1;
while (to_copy) {
/* we bread to make sure that filesystem contains enough blocks */
bh = getblk (fs->fs_dev, block, fs->fs_blocksize);
if (!bh) {
reiserfs_exit (1, "Getblk failed for (%lu)\n", block);
}
memset (bh->b_data, 0xff, bh->b_size);
mark_buffer_uptodate (bh, 1);
if (to_copy < fs->fs_blocksize)
copied = to_copy;
memcpy (bh->b_data, p, copied);
if (copied == to_copy) {
/* set unused bits of last byte of a bitmap to 1 */
last_byte_unused_bits = bm->bm_byte_size * 8 - bm->bm_bit_size;
for (i = 0; i < last_byte_unused_bits; i ++)
misc_set_bit ((bm->bm_bit_size % (fs->fs_blocksize * 8)) + i, bh->b_data);
}
mark_buffer_dirty (bh);
brelse (bh);
p += copied;
to_copy -= copied;
/* next bitmap block */
if (spread_bitmaps (fs))
block = (block / (fs->fs_blocksize * 8) + 1) * (fs->fs_blocksize * 8);
else
block ++;
}
return 1;
}
void reiserfs_bitmap_zero (reiserfs_bitmap_t * bm)
{
memset (bm->bm_map, 0, bm->bm_byte_size);
bm->bm_set_bits = 0;
bm->bm_dirty = 1;
}
void reiserfs_bitmap_fill (reiserfs_bitmap_t * bm)
{
memset (bm->bm_map, 0xff, bm->bm_byte_size);
bm->bm_set_bits = bm->bm_bit_size;
bm->bm_dirty = 1;
}
/* format of bitmap saved in a file:
magic number (32 bits)
bm_bit_size (32 bits)
number of ranges of used and free blocks (32 bits)
number of contiguously used block, .. of free blocks, used, free, etc
magic number (32 bits) */
#define BITMAP_START_MAGIC 374031
#define BITMAP_END_MAGIC 7786472
FILE * open_file (char * filename, char * option)
{
FILE * fp = fopen (filename, option);
if (!fp) {
reiserfs_warning (stderr, "open_file: could not open file %s\n", filename);
return 0;
}
reiserfs_warning (stderr, "Temp file opened by fsck: \"%s\" .. \n", filename);
return fp;
}
void close_file (FILE * fp)
{
fclose (fp);
/*reiserfs_warning (stderr, "done\n"); fflush (stderr);*/
}
void reiserfs_bitmap_save (FILE * fp, reiserfs_bitmap_t * bm)
{
// FILE * fp;
__u32 v;
int zeros;
int count;
unsigned int i;
int extents;
long position;
/* fp = fopen (filename, "w+");
if (!fp) {
reiserfs_warning (stderr, "reiserfs_bitmap_save: could not save bitmap in %s: %s",
filename, strerror(errno));
return;
}*/
// reiserfs_warning (stderr, "Saving bitmap in \"%s\" .. ", filename); fflush (stderr);
v = BITMAP_START_MAGIC;
fwrite (&v, 4, 1, fp);
v = bm->bm_bit_size;
fwrite (&v, 4, 1, fp);
/*printf ("SAVE: bit_size - %d\n", v);*/
position = ftell(fp);
if (fseek (fp, 4, SEEK_CUR)) {
reiserfs_warning (stderr, "reiserfs_bitmap_save: fseek failed: %s\n", strerror(errno));
// fclose (fp);
return;
}
zeros = 0;
count = 0;
extents = 0;
for (i = 0; i < v; i ++) {
if (reiserfs_bitmap_test_bit (bm, i)) {
if (zeros) {
/* previous bit was not set, write amount of not set
bits, switch to count set bits */
fwrite (&count, 4, 1, fp);
/*printf ("SAVE: Free %d\n", count);*/
extents ++;
count = 1;
zeros = 0;
} else {
/* one more zero bit appeared */
count ++;
}
} else {
/* zero bit found */
if (zeros) {
count ++;
} else {
/* previous bit was set, write amount of set bits,
switch to count not set bits */
fwrite (&count, 4, 1, fp);
/*printf ("SAVE: Used %d\n", count);*/
extents ++;
count = 1;
zeros = 1;
}
}
}
fwrite (&count, 4, 1, fp);
extents ++;
/*
if (zeros)
printf ("SAVE: Free %d\n", count);
else
printf ("SAVE: Used %d\n", count);
*/
v = BITMAP_END_MAGIC;
fwrite (&v, 4, 1, fp);
if (fseek (fp, position, SEEK_SET)) {
reiserfs_warning (stderr, "reiserfs_bitmap_save: fseek failed: %s", strerror(errno));
return;
}
fwrite (&extents, 4, 1, fp);
if (fseek (fp, 0, SEEK_END)) {
reiserfs_warning (stderr, "reiserfs_bitmap_save: fseek failed: %s", strerror(errno));
return;
}
}
/* format of fsck dump file:
after pass0
magic number (32 bits)
passed stage number
bitmap of leaves
bitmap of good_unfm
bitmap of bad_unfm
magic number (32 bits) */
#define FSCK_DUMP_START_MAGIC 374033
#define FSCK_DUMP_END_MAGIC 7786470
void reiserfs_begin_stage_info_save(FILE * file, unsigned long stage)
{
__u32 v = FSCK_DUMP_START_MAGIC;
fwrite (&v, 4, 1, file);
fwrite (&stage, 4, 1, file);
}
void reiserfs_end_stage_info_save(FILE * file)
{
__u32 v = FSCK_DUMP_END_MAGIC;
fwrite (&v, 4, 1, file);
}
/*return last passed stage*/
int is_stage_magic_correct (FILE * fp)
{
__u32 v;
if (fseek (fp, -4, SEEK_END)) {
reiserfs_warning (stderr, "is_stage_magic_correct: fseek failed: %s\n",
strerror(errno));
return -1;
}
fread (&v, 4, 1, fp);
if (v != FSCK_DUMP_END_MAGIC) {
reiserfs_warning (stderr, "is_stage_magic_correct: no magic found\n");
return -1;
}
if (fseek (fp, 0, SEEK_SET)) {
reiserfs_warning (stderr, "is_stage_magic_correct: fseek failed: %s\n",
strerror(errno));
return -1;
}
fread (&v, 4, 1, fp);
if (v != FSCK_DUMP_START_MAGIC) {
reiserfs_warning (stderr, "is_stage_magic_correct: no magic found\n");
return -1;
}
fread (&v, 4, 1, fp);
if (v != PASS_0_DONE && v != PASS_1_DONE && v != TREE_IS_BUILT && v != SEMANTIC_DONE && v != LOST_FOUND_DONE) {
reiserfs_warning (stderr, "is_stage_magic_correct: wrong pass found");
return -1;
}
return (__u16)v;
}
reiserfs_bitmap_t * reiserfs_bitmap_load (FILE * fp)
{
// FILE * fp;
__u32 v;
int count;
int i, j;
int extents;
int bit;
reiserfs_bitmap_t * bm;
/* fp = fopen (filename, "r");
if (!fp) {
reiserfs_warning (stderr, "reiserfs_bitmap_load: fopen failed: %s\n", strerror(errno));
return 0;
}*/
fread (&v, 4, 1, fp);
if (v != BITMAP_START_MAGIC) {
reiserfs_warning (stderr, "reiserfs_bitmap_load: "
"no bitmap start magic found");
// fclose (fp);
return 0;
}
/* read bit size of bitmap */
fread (&v, 4, 1, fp);
bm = reiserfs_create_bitmap (v);
if (!bm) {
reiserfs_warning (stderr, "reiserfs_bitmap_load: creation failed");
// fclose (fp);
return 0;
}
/*printf ("LOAD: bit_size - %d\n", v);*/
fread (&extents, 4, 1, fp);
/*printf ("LOAD: extents - %d\n", extents);*/
bit = 0;
for (i = 0; i < extents; i ++) {
fread (&count, 4, 1, fp);
/*
if (i % 2)
printf ("LOAD: Free %d\n", count);
else
printf ("LOAD: Used %d\n", count);
*/
for (j = 0; j < count; j ++, bit ++)
if (i % 2 == 0) {
reiserfs_bitmap_set_bit (bm, bit);
}
}
fread (&v, 4, 1, fp);
/*printf ("LOAD: Endmagic %d\n", v);*/
// fclose (fp);
if (v != BITMAP_END_MAGIC) {
reiserfs_warning (stderr, "reiserfs_bitmap_load: "
"no bitmap end magic found");
return 0;
}
/* reiserfs_warning (stderr, "%d bits set - done\n", reiserfs_bitmap_ones (bm));*/
fflush (stderr);
return bm;
}
void reiserfs_bitmap_invert (reiserfs_bitmap_t * bm)
{
unsigned int i;
/*reiserfs_warning (stderr, "Bitmap inverting..");fflush (stderr);*/
for (i = 0; i < bm->bm_bit_size; i ++) {
if (reiserfs_bitmap_test_bit (bm, i))
reiserfs_bitmap_clear_bit (bm, i);
else
reiserfs_bitmap_set_bit (bm, i);
}
/*reiserfs_warning (stderr, "done\n");*/
}
void reiserfs_free_ondisk_bitmap (reiserfs_filsys_t * fs)
{
if (fs->fs_bitmap2) {
reiserfs_delete_bitmap (fs->fs_bitmap2);
fs->fs_bitmap2 = 0;
}
}
/* read bitmap blocks */
int reiserfs_open_ondisk_bitmap (reiserfs_filsys_t * fs)
{
unsigned int blocks = get_sb_block_count(fs->fs_ondisk_sb) ;
unsigned int bmap_nr = reiserfs_bmap_nr(blocks, fs->fs_blocksize);
if (fs->fs_bitmap2)
reiserfs_panic ("bitmap is initiaized already");
fs->fs_bitmap2 = reiserfs_create_bitmap (blocks);
if (!fs->fs_bitmap2)
return -1;
if (reiserfs_bmap_over(bmap_nr)) {
if (get_sb_bmap_nr(fs->fs_ondisk_sb) != 0) {
reiserfs_warning (stderr, "%s: large file system has "
"incorrect bitmap count %u. Should be 0 "
"to indicate overflow.\nPlease re-run with "
"--rebuild-sb to fix it.\n", __FUNCTION__,
get_sb_bmap_nr(fs->fs_ondisk_sb));
return -1;
}
} else if (bmap_nr != get_sb_bmap_nr (fs->fs_ondisk_sb)) {
reiserfs_warning (stderr, "%s: wrong either bitmaps number,\n",
__FUNCTION__);
reiserfs_warning (stderr, "count of blocks or blocksize, run with "
"--rebuild-sb to fix it\n");
return -1;
}
return reiserfs_fetch_ondisk_bitmap (fs->fs_bitmap2, fs);
}
int reiserfs_create_ondisk_bitmap (reiserfs_filsys_t * fs)
{
if (fs->fs_bitmap2)
reiserfs_panic ("bitmap is initiaized already");
fs->fs_bitmap2 = reiserfs_create_bitmap (get_sb_block_count (fs->fs_ondisk_sb));
if (!fs->fs_bitmap2)
return 0;
return 1;
}
void reiserfs_close_ondisk_bitmap (reiserfs_filsys_t * fs)
{
if (!fs->fs_bitmap2)
return;
reiserfs_flush_to_ondisk_bitmap (fs->fs_bitmap2, fs);
reiserfs_free_ondisk_bitmap (fs);
}