Files
reiserfsprogs/resize_reiserfs/resize_reiserfs.c
T

258 lines
6.1 KiB
C

/*
* Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
*/
/*
* Written by Alexander Zarochentcev.
*
* FS resize utility
*
*/
#include "resize.h"
int opt_force = 0;
int opt_verbose = 1; /* now "verbose" option is default */
int opt_nowrite = 0;
int opt_safe = 0;
#if 0
/* Given a file descriptor and an offset, check whether the offset is
a valid offset for the file - return 0 if it isn't valid or 1 if it
is */
int valid_offset( int fd, loff_t offset )
{
char ch;
if (lseek64 (fd, offset, 0) < 0)
return 0;
if (read (fd, &ch, 1) < 1)
return 0;
return 1;
}
#endif
/* calculate the new fs size (in blocks) from old fs size and the string
representation of new size */
static unsigned long calc_new_fs_size(unsigned long count, int bs,
char *bytes_str)
{
long long int bytes;
unsigned long blocks;
int c;
bytes = atoll(bytes_str);
c = bytes_str[strlen(bytes_str) - 1];
switch (c) {
case 'G':
case 'g':
bytes *= 1024;
case 'M':
case 'm':
bytes *= 1024;
case 'K':
case 'k':
bytes *= 1024;
}
blocks = bytes / bs;
if (bytes_str[0] == '+' || bytes_str[0] == '-')
return (count + blocks);
return blocks;
}
/* print some fs parameters */
static void sb_report(struct reiserfs_super_block * sb1,
struct reiserfs_super_block * sb2)
{
printf(
"ReiserFS report:\n"
"blocksize %d\n"
"block count %d (%d)\n"
"free blocks %d (%d)\n"
"bitmap block count %d (%d)\n",
rs_blocksize(sb1),
rs_block_count(sb1), rs_block_count(sb2),
rs_free_blocks(sb1), rs_free_blocks(sb2),
rs_bmap_nr(sb1), rs_bmap_nr(sb2));
};
/* conditional bwrite */
static int bwrite_cond (struct buffer_head * bh)
{
if(!opt_nowrite) {
mark_buffer_uptodate(bh,1);
mark_buffer_dirty(bh);
bwrite(bh);
}
return 0;
}
/* the first one of the mainest functions */
int expand_fs (reiserfs_filsys_t fs, unsigned long block_count_new) {
int block_r, block_r_new;
unsigned int bmap_nr_new, bmap_nr_old;
int i;
reiserfs_bitmap_t bmp;
struct reiserfs_super_block * rs = fs->s_rs;
reiserfs_reopen(fs, O_RDWR);
set_state (fs->s_rs, REISERFS_ERROR_FS);
bwrite_cond(SB_BUFFER_WITH_SB(fs));
bmp = reiserfs_create_bitmap(rs_block_count(rs));
if (!bmp)
die ("cannot create bitmap\n");
reiserfs_fetch_disk_bitmap(bmp, fs);
reiserfs_free_bitmap_blocks(fs);
if (reiserfs_expand_bitmap(bmp, block_count_new))
die ("cannot expand bitmap\n");
/* clean bits in old bitmap tail */
for (i = rs_block_count(rs);
i < rs_bmap_nr(rs) * rs_blocksize(rs) * 8 && i < block_count_new;
i++) {
reiserfs_bitmap_clear_bit(bmp, i);
}
/* count used bits in last bitmap block */
block_r = rs_block_count(rs) - ((rs_bmap_nr(rs) - 1) * rs_blocksize(rs) * 8);
/* count bitmap blocks in new fs */
bmap_nr_new = (block_count_new - 1) / (rs_blocksize(rs) * 8) + 1;
block_r_new = block_count_new - (bmap_nr_new - 1) * rs_blocksize(rs) * 8;
bmap_nr_old = rs_bmap_nr(rs);
/* update super block buffer*/
set_free_blocks (rs, rs_free_blocks(rs) + block_count_new
- rs_block_count(rs) - (bmap_nr_new - rs_bmap_nr(rs)));
set_block_count (rs, block_count_new);
set_bmap_nr (rs, bmap_nr_new);
reiserfs_read_bitmap_blocks(fs);
for (i = bmap_nr_old; i < bmap_nr_new; i++) /* fix new bitmap blocks */
reiserfs_bitmap_set_bit(bmp, SB_AP_BITMAP(fs)[i]->b_blocknr);
reiserfs_flush_bitmap(bmp, fs);
return 0;
}
int main(int argc, char *argv[]) {
char * bytes_count_str = NULL;
char * devname;
reiserfs_filsys_t fs;
struct reiserfs_super_block * rs;
int c;
int error;
struct reiserfs_super_block *sb_old;
unsigned long block_count_new;
print_banner ("resize_reiserfs");
while ((c = getopt(argc, argv, "fvcqs:")) != EOF) {
switch (c) {
case 's' :
if (!optarg)
die("%s: Missing argument to -s option", argv[0]);
bytes_count_str = optarg;
break;
case 'f':
opt_force = 1;
break;
case 'v':
opt_verbose++;
break;
case 'n':
/* no nowrite option at this moment */
/* opt_nowrite = 1; */
break;
case 'c':
opt_safe = 1;
break;
case 'q':
opt_verbose = 0;
break;
default:
print_usage_and_exit ();
}
}
if (optind == argc )
print_usage_and_exit();
devname = argv[optind];
fs = reiserfs_open(devname, O_RDONLY, &error, 0);
if (!fs)
die ("%s: can not open '%s': %s", argv[0], devname, strerror(error));
if (no_reiserfs_found (fs)) {
die ("resize_reiserfs: no reiserfs found on the device");
}
if (!spread_bitmaps (fs)) {
die ("resize_reiserfs: cannot resize reiserfs in old (not spread bitmap) format.\n");
}
rs = fs->s_rs;
if(bytes_count_str) { /* new fs size is specified by user */
block_count_new = calc_new_fs_size(rs_block_count(rs), fs->s_blocksize, bytes_count_str);
} else { /* use whole device */
block_count_new = count_blocks(devname, fs->s_blocksize, -1);
}
if (is_mounted (devname)) {
reiserfs_close(fs);
return resize_fs_online(devname, block_count_new);
}
if (rs_state(rs) != REISERFS_VALID_FS)
die ("%s: the file system isn't in valid state\n", argv[0]);
if(!valid_offset(fs->s_dev, (loff_t) block_count_new * fs->s_blocksize - 1))
die ("%s: %s too small", argv[0], devname);
sb_old = 0; /* Needed to keep idiot compiler from issuing false warning */
/* save SB for reporting */
if(opt_verbose) {
sb_old = getmem(SB_SIZE);
memcpy(sb_old, SB_DISK_SUPER_BLOCK(fs), SB_SIZE);
}
if (block_count_new == SB_BLOCK_COUNT(fs))
die ("%s: Calculated fs size is the same as the previous one.", argv[0]);
if (block_count_new > SB_BLOCK_COUNT(fs))
expand_fs(fs, block_count_new);
else
shrink_fs(fs, block_count_new);
if(opt_verbose) {
sb_report(rs, sb_old);
freemem(sb_old);
}
set_state (rs, REISERFS_VALID_FS);
bwrite_cond(SB_BUFFER_WITH_SB(fs));
if (opt_verbose) {
printf("\nSyncing..");
fflush(stdout);
}
reiserfs_close (fs);
if (opt_verbose)
printf("done\n");
return 0;
}