/* * Copyright 2000-2004 by Hans Reiser, licensing governed by * reiserfsprogs/README */ #ifdef HAVE_CONFIG_H # include #endif #include "reiserfs/libreiserfs.h" #include "misc/malloc.h" #include "misc/device.h" #include #include #include #include #include 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); }