Files
reiserfsprogs/libreiserfs/filesystem.c
T

481 lines
12 KiB
C

/*
* Copyright 2000-2004 by Hans Reiser, licensing governed by
* reiserfsprogs/README
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "reiserfs/libreiserfs.h"
#include "misc/malloc.h"
#include "misc/device.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
int reiserfs_fs_blksize_check (unsigned int blocksize)
{
return ((((blocksize & -blocksize) == blocksize)
&& (blocksize >= 512) && (blocksize <= 8192)));
}
reiserfs_blktype_t reiserfs_fs_block(reiserfs_filsys_t *fs,
unsigned long block)
{
if (block < fs->fs_super_bh->b_blocknr ||
block >= reiserfs_sb_get_blocks (fs->fs_ondisk_sb))
{
return BT_INVAL;
}
if (block == fs->fs_super_bh->b_blocknr)
return BT_SUPER;
if (reiserfs_journal_block (fs, block))
return BT_JOURNAL;
if (reiserfs_bitmap_block(fs, block))
return BT_BITMAP;
return BT_UNKNOWN;
}
/* read super block. fixme: only 4k blocks, pre-journaled format
is refused. Journal and bitmap are to be opened separately.
skip_check is set to 1 if checks of openned SB should be omitted.*/
reiserfs_filsys_t * reiserfs_fs_open (char * filename, int flags,
int *error, void * vp, int check)
{
reiserfs_filsys_t * fs;
reiserfs_bh_t * bh;
reiserfs_sb_t * sb;
int fd, i;
if (error)
*error = 0;
fd = open (filename, flags
#if defined(O_LARGEFILE)
| O_LARGEFILE
#endif
);
if (fd == -1) {
if (error)
*error = errno;
return 0;
}
fs = misc_getmem (sizeof (*fs));
fs->fs_dev = fd;
fs->fs_vp = vp;
strncpy(fs->fs_file_name, filename, sizeof(fs->fs_file_name));
/* reiserfs super block is either in 16-th or in 2-nd 4k block of the
device */
for (i = 2; i < 17; i += 14) {
bh = reiserfs_buffer_read (fd, i, 4096);
if (!bh) {
reiserfs_warning (stderr, "reiserfs_fs_open: reiserfs_buffer_read "
"failed reading block %d\n", i);
} else {
sb = (reiserfs_sb_t *)bh->b_data;
if (reiserfs_super_magic(sb))
goto found;
/* reiserfs signature is not found at the i-th 4k block */
reiserfs_buffer_close (bh);
}
}
reiserfs_warning(stderr, "\nreiserfs_fs_open: the reiserfs superblock "
"cannot be found on %s.\n", filename);
misc_freemem (fs);
close (fd);
fs = NULL;
return fs;
found:
if (!reiserfs_fs_blksize_check(reiserfs_sb_get_blksize(sb))) {
reiserfs_warning(stderr, "reiserfs_fs_open: a superblock with "
"wrong parameters was found in the block (%d).\n", i);
misc_freemem (fs);
close (fd);
reiserfs_buffer_close(bh);
return NULL;
}
if (check) {
/* A few checks of found super block. */
reiserfs_bh_t *tmp_bh;
tmp_bh = reiserfs_buffer_read (fd, reiserfs_sb_get_blocks(sb) - 1,
reiserfs_sb_get_blksize(sb));
if (!tmp_bh) {
reiserfs_warning (stderr, "\n%s: Your partition is not big enough "
"to contain the \nfilesystem of (%lu) blocks as "
"was specified in the found super block.\n",
__FUNCTION__, reiserfs_sb_get_blocks(sb) - 1);
misc_freemem (fs);
close (fd);
reiserfs_buffer_close(bh);
return NULL;
}
reiserfs_buffer_close(tmp_bh);
}
fs->fs_blocksize = reiserfs_sb_get_blksize (sb);
/* check block size on the filesystem */
if (fs->fs_blocksize != 4096) {
i = bh->b_blocknr * 4096 / fs->fs_blocksize;
reiserfs_buffer_close (bh);
bh = reiserfs_buffer_read (fd, i, fs->fs_blocksize);
if (!bh) {
reiserfs_warning (stderr, "reiserfs_fs_open: reiserfs_buffer_read "
"failed reading block %d, size %d\n",
i, fs->fs_blocksize);
misc_freemem (fs);
return 0;
}
sb = (reiserfs_sb_t *)bh->b_data;
}
fs->hash = reiserfs_hash_func (reiserfs_sb_get_hash (sb));
fs->fs_super_bh = bh;
fs->fs_ondisk_sb = sb;
fs->fs_flags = flags; /* O_RDONLY or O_RDWR */
fs->fs_format = reiserfs_super_format (sb);
/*reiserfs_read_bitmap_blocks(fs);*/
if (flags & O_RDWR)
fs->fs_dirt = 1;
else
fs->fs_dirt = 0;
return fs;
}
/* creates buffer for super block and fills it up with fields which are
constant for given size and version of a filesystem */
reiserfs_filsys_t * reiserfs_fs_create (char * filename,
int version,
unsigned long block_count,
int block_size,
int default_journal,
int new_format)
{
reiserfs_filsys_t * fs;
unsigned long bmap_nr;
if (misc_device_count_blocks (filename, block_size) < block_count) {
reiserfs_warning (stderr, "reiserfs_fs_create: no enough "
"blocks on device\n");
return 0;
}
if (!reiserfs_journal_fits (REISERFS_DISK_OFFSET_IN_BYTES / block_size,
block_size, block_count, 0))
{
reiserfs_warning (stderr, "reiserfs_fs_create: can not create that "
"small (%d blocks) filesystem\n", block_count);
return 0;
}
fs = misc_getmem (sizeof (*fs));
if (!fs) {
reiserfs_warning (stderr, "reiserfs_fs_create: misc_getmem failed\n");
return 0;
}
fs->fs_dev = open (filename, O_RDWR
#if defined(O_LARGEFILE)
| O_LARGEFILE
#endif
);
if (fs->fs_dev == -1) {
reiserfs_warning (stderr, "reiserfs_fs_create: could not open %s: %s\n",
filename, strerror(errno));
misc_freemem (fs);
return 0;
}
fs->fs_blocksize = block_size;
sprintf(fs->fs_file_name, filename);
fs->fs_format = version;
if (new_format)
fs->fs_super_bh = reiserfs_buffer_open (fs->fs_dev,
REISERFS_DISK_OFFSET_IN_BYTES / block_size, block_size);
else
fs->fs_super_bh = reiserfs_buffer_open (fs->fs_dev,
REISERFS_OLD_DISK_OFFSET_IN_BYTES / block_size, block_size);
if (!fs->fs_super_bh) {
reiserfs_warning (stderr, "reiserfs_fs_create: "
"reiserfs_buffer_open failed\n");
return 0;
}
reiserfs_buffer_mkuptodate (fs->fs_super_bh, 1);
fs->fs_ondisk_sb = (reiserfs_sb_t *)fs->fs_super_bh->b_data;
memset (fs->fs_ondisk_sb, 0, block_size);
/* fill super block fields which are constant for given version
and block count */
reiserfs_sb_set_blocks (fs->fs_ondisk_sb, block_count);
/* sb_free_blocks */
/* sb_root_block */
/* sb_journal_1st_block */
/* sb_journal_dev */
/* sb_orig_journal_size */
/* sb_joural_magic */
/* sb_journal magic_F */
/* sb_mount_id */
/* sb_not_used0 */
/* sb_generation_number */
reiserfs_sb_set_blksize (fs->fs_ondisk_sb, block_size);
switch (version) {
case REISERFS_FORMAT_3_5:
reiserfs_sb_set_mapmax (fs->fs_ondisk_sb,
(block_size - REISERFS_SB_SIZE_V1) / sizeof(__u32) / 2 * 2);
/* sb_oid_cursize */
/* sb_state */
memcpy (fs->fs_ondisk_sb->s_v1.s_magic,
REISERFS_3_5_SUPER_MAGIC_STRING,
strlen (REISERFS_3_5_SUPER_MAGIC_STRING));
break;
case REISERFS_FORMAT_3_6:
reiserfs_sb_set_mapmax (fs->fs_ondisk_sb,
(block_size - REISERFS_SB_SIZE) / sizeof(__u32) / 2 * 2);
/* sb_oid_cursize */
/* sb_state */
memcpy (fs->fs_ondisk_sb->s_v1.s_magic,
REISERFS_3_6_SUPER_MAGIC_STRING,
strlen (REISERFS_3_6_SUPER_MAGIC_STRING));
break;
}
if (!default_journal)
memcpy (fs->fs_ondisk_sb->s_v1.s_magic,
REISERFS_JR_SUPER_MAGIC_STRING,
strlen (REISERFS_JR_SUPER_MAGIC_STRING));
/* sb_fsck_state */
/* sb_hash_function_code */
/* sb_tree_height */
bmap_nr = reiserfs_bmap_nr(block_count, block_size);
reiserfs_sb_set_version (fs->fs_ondisk_sb, version);
reiserfs_sb_set_bmaps (fs->fs_ondisk_sb,
reiserfs_bmap_over(bmap_nr) ? 0 : bmap_nr);
/* sb_not_used1 */
reiserfs_buffer_mkdirty (fs->fs_super_bh);
fs->fs_dirt = 1;
return fs;
}
/* flush bitmap, reiserfs_buffer_close super block, flush all dirty buffers,
close and open again the device, read super block */
static void reiserfs_only_reopen (reiserfs_filsys_t * fs, int flag)
{
unsigned long super_block;
/* reiserfs_bitmap_flush (fs->fs_bitmap2, fs);*/
super_block = fs->fs_super_bh->b_blocknr;
reiserfs_buffer_close (fs->fs_super_bh);
reiserfs_buffer_flush_all(fs->fs_dev);
reiserfs_buffer_invalidate_all (fs->fs_dev);
if (close (fs->fs_dev))
misc_die ("reiserfs_fs_reopen: closed failed: %s", strerror(errno));
fs->fs_dev = open (fs->fs_file_name, flag
#if defined(O_LARGEFILE)
| O_LARGEFILE
#endif
);
if (fs->fs_dev == -1)
misc_die ("reiserfs_fs_reopen: could not reopen device: %s",
strerror(errno));
fs->fs_super_bh = reiserfs_buffer_read (fs->fs_dev, super_block,
fs->fs_blocksize);
if (!fs->fs_super_bh)
misc_die ("reiserfs_fs_reopen: reading super block failed");
fs->fs_ondisk_sb = (reiserfs_sb_t *)fs->fs_super_bh->b_data;
fs->fs_flags = flag; /* O_RDONLY or O_RDWR */
if (flag & O_RDWR)
fs->fs_dirt = 1;
else
fs->fs_dirt = 0;
}
void reiserfs_fs_reopen (reiserfs_filsys_t * fs, int flag)
{
reiserfs_only_reopen (fs, flag);
reiserfs_journal_reopen (fs, flag);
}
int reiserfs_fs_rw (reiserfs_filsys_t * fs)
{
if ((fs->fs_flags) & O_RDWR)
return 1;
return 0;
}
/* flush all changes made on a filesystem */
void reiserfs_fs_flush (reiserfs_filsys_t * fs)
{
if (fs->fs_dirt) {
reiserfs_journal_flush (fs);
reiserfs_buffer_flush_all(fs->fs_dev);
}
fs->fs_dirt = 0;
}
/* free all memory involved into manipulating with filesystem */
void reiserfs_fs_free (reiserfs_filsys_t * fs)
{
reiserfs_journal_free (fs);
reiserfs_bitmap_free (fs);
/* release super block and memory used by filesystem handler */
reiserfs_buffer_close (fs->fs_super_bh);
fs->fs_super_bh = 0;
reiserfs_buffer_free_all ();
misc_freemem (fs);
}
/* this closes everything: journal. bitmap and the fs itself */
void reiserfs_fs_close (reiserfs_filsys_t * fs)
{
reiserfs_journal_close (fs);
reiserfs_bitmap_close (fs);
reiserfs_fs_flush (fs);
fsync(fs->fs_dev);
reiserfs_fs_free (fs);
}
void reiserfs_print_bmap_block (FILE * fp, int i, unsigned long block,
char * map, int blocks, int silent,
int blocksize)
{
int j, k;
int bits = blocksize * 8;
int zeros = 0, ones = 0;
reiserfs_warning (fp, "#%d: block %lu: ", i, block);
blocks = blocksize * 8;
if (misc_test_bit (0, map)) {
/* first block addressed by this bitmap block is used */
ones ++;
if (!silent)
reiserfs_warning (fp, "Busy (%d-", i * bits);
for (j = 1; j < blocks; j ++) {
while (misc_test_bit (j, map)) {
ones ++;
if (j == blocks - 1) {
if (!silent)
reiserfs_warning (fp, "%d)\n", j + i * bits);
goto end;
}
j++;
}
if (!silent)
reiserfs_warning (fp, "%d) Free(%d-",
j - 1 + i * bits, j + i * bits);
while (!misc_test_bit (j, map)) {
zeros ++;
if (j == blocks - 1) {
if (!silent)
reiserfs_warning (fp, "%d)\n", j + i * bits);
goto end;
}
j++;
}
if (!silent)
reiserfs_warning (fp, "%d) Busy(%d-",
j - 1 + i * bits, j + i * bits);
j --;
end:
/* to make gcc 3.2 do not sware here */;
}
} else {
/* first block addressed by this bitmap is free */
zeros ++;
if (!silent)
reiserfs_warning (fp, "Free (%d-", i * bits);
for (j = 1; j < blocks; j ++) {
k = 0;
while (!misc_test_bit (j, map)) {
k ++;
if (j == blocks - 1) {
if (!silent)
reiserfs_warning (fp, "%d)\n", j + i * bits);
zeros += k;
goto end2;
}
j++;
}
zeros += k;
if (!silent)
reiserfs_warning (fp, "%d) Busy(%d-",
j - 1 + i * bits, j + i * bits);
k = 0;
while (misc_test_bit (j, map)) {
ones ++;
if (j == blocks - 1) {
if (!silent)
reiserfs_warning (fp, "%d)\n", j + i * bits);
ones += k;
goto end2;
}
j++;
}
ones += k;
if (!silent)
reiserfs_warning (fp, "%d) Free(%d-",
j - 1 + i * bits, j + i * bits);
j --;
end2:
/* to make gcc 3.2 do not sware here */;
}
}
reiserfs_warning (fp, "used %d, free %d\n", ones, zeros);
}