online.c revision df9c01b1449ccbaa9283486f0f6a50085043036b
1/* 2 * online.c --- Do on-line resizing of the ext3 filesystem 3 * 4 * Copyright (C) 2006 by Theodore Ts'o 5 * 6 * %Begin-Header% 7 * This file may be redistributed under the terms of the GNU Public 8 * License. 9 * %End-Header% 10 */ 11 12#include "resize2fs.h" 13#ifdef HAVE_SYS_IOCTL_H 14#include <sys/ioctl.h> 15#endif 16#include <sys/stat.h> 17#include <fcntl.h> 18 19extern char *program_name; 20 21errcode_t online_resize_fs(ext2_filsys fs, const char *mtpt, 22 blk_t *new_size, int flags EXT2FS_ATTR((unused))) 23{ 24#ifdef __linux__ 25 struct ext2_new_group_input input; 26 struct ext4_new_group_input input64; 27 struct ext2_super_block *sb = fs->super; 28 unsigned long new_desc_blocks; 29 ext2_filsys new_fs; 30 errcode_t retval; 31 double percent; 32 dgrp_t i; 33 blk_t size; 34 int fd, overhead; 35 int use_old_ioctl = 1; 36 37 printf(_("Filesystem at %s is mounted on %s; " 38 "on-line resizing required\n"), fs->device_name, mtpt); 39 40 if (*new_size < sb->s_blocks_count) { 41 printf(_("On-line shrinking from %u to %u not supported.\n"), 42 sb->s_blocks_count, *new_size); 43 exit(1); 44 } 45 46 /* 47 * If the number of descriptor blocks is going to increase, 48 * the on-line resizing inode must be present. 49 */ 50 new_desc_blocks = ext2fs_div_ceil( 51 ext2fs_div_ceil(*new_size - 52 fs->super->s_first_data_block, 53 EXT2_BLOCKS_PER_GROUP(fs->super)), 54 EXT2_DESC_PER_BLOCK(fs->super)); 55 printf("old desc_blocks = %lu, new_desc_blocks = %lu\n", 56 fs->desc_blocks, new_desc_blocks); 57 if (!(fs->super->s_feature_compat & 58 EXT2_FEATURE_COMPAT_RESIZE_INODE) && 59 new_desc_blocks != fs->desc_blocks) { 60 com_err(program_name, 0, 61 _("Filesystem does not support online resizing")); 62 exit(1); 63 } 64 65 fd = open(mtpt, O_RDONLY); 66 if (fd < 0) { 67 com_err(program_name, errno, 68 _("while trying to open mountpoint %s"), mtpt); 69 exit(1); 70 } 71 72 size=sb->s_blocks_count; 73 if (ioctl(fd, EXT2_IOC_GROUP_EXTEND, &size)) { 74 if (errno == EPERM) 75 com_err(program_name, 0, 76 _("Permission denied to resize filesystem")); 77 else if (errno == ENOTTY) 78 com_err(program_name, 0, 79 _("Kernel does not support online resizing")); 80 else 81 com_err(program_name, errno, 82 _("While checking for on-line resizing support")); 83 exit(1); 84 } 85 86 percent = (sb->s_r_blocks_count * 100.0) / sb->s_blocks_count; 87 88 retval = ext2fs_read_bitmaps(fs); 89 if (retval) 90 return retval; 91 92 retval = ext2fs_dup_handle(fs, &new_fs); 93 if (retval) 94 return retval; 95 96 retval = adjust_fs_info(new_fs, fs, *new_size); 97 if (retval) 98 return retval; 99 100 printf(_("Performing an on-line resize of %s to %u (%dk) blocks.\n"), 101 fs->device_name, *new_size, fs->blocksize / 1024); 102 103 size = fs->group_desc_count * sb->s_blocks_per_group + 104 sb->s_first_data_block; 105 if (size > *new_size) 106 size = *new_size; 107 108 if (ioctl(fd, EXT2_IOC_GROUP_EXTEND, &size)) { 109 com_err(program_name, errno, 110 _("While trying to extend the last group")); 111 exit(1); 112 } 113 114 for (i = fs->group_desc_count; 115 i < new_fs->group_desc_count; i++) { 116 117 overhead = (int) (2 + new_fs->inode_blocks_per_group); 118 119 if (ext2fs_bg_has_super(new_fs, new_fs->group_desc_count - 1)) 120 overhead += 1 + new_fs->desc_blocks + 121 new_fs->super->s_reserved_gdt_blocks; 122 123 input.group = i; 124 input.block_bitmap = new_fs->group_desc[i].bg_block_bitmap; 125 input.inode_bitmap = new_fs->group_desc[i].bg_inode_bitmap; 126 input.inode_table = new_fs->group_desc[i].bg_inode_table; 127 input.blocks_count = sb->s_blocks_per_group; 128 if (i == new_fs->group_desc_count-1) { 129 input.blocks_count = new_fs->super->s_blocks_count - 130 sb->s_first_data_block - 131 (i * sb->s_blocks_per_group); 132 } 133 input.reserved_blocks = (blk_t) (percent * input.blocks_count 134 / 100.0); 135 136#if 0 137 printf("new block bitmap is at 0x%04x\n", input.block_bitmap); 138 printf("new inode bitmap is at 0x%04x\n", input.inode_bitmap); 139 printf("new inode table is at 0x%04x-0x%04x\n", 140 input.inode_table, 141 input.inode_table + new_fs->inode_blocks_per_group-1); 142 printf("new group has %u blocks\n", input.blocks_count); 143 printf("new group will reserve %d blocks\n", 144 input.reserved_blocks); 145 printf("new group has %d free blocks\n", 146 new_fs->group_desc[i].bg_free_blocks_count); 147 printf("new group has %d free inodes (%d blocks)\n", 148 new_fs->group_desc[i].bg_free_inodes_count, 149 new_fs->inode_blocks_per_group); 150 printf("Adding group #%d\n", input.group); 151#endif 152 153 if (use_old_ioctl && 154 ioctl(fd, EXT2_IOC_GROUP_ADD, &input) == 0) 155 continue; 156 else 157 use_old_ioctl = 1; 158 159 input64.group = input.group; 160 input64.block_bitmap = input.block_bitmap; 161 input64.inode_bitmap = input.inode_bitmap; 162 input64.inode_table = input.inode_table; 163 input64.blocks_count = input.blocks_count; 164 input64.reserved_blocks = input.reserved_blocks; 165 input64.unused = input.unused; 166 167 if (ioctl(fd, EXT4_IOC_GROUP_ADD, &input64) < 0) { 168 com_err(program_name, errno, 169 _("While trying to add group #%d"), 170 input.group); 171 exit(1); 172 } 173 } 174 175 ext2fs_free(new_fs); 176 close(fd); 177 178 return 0; 179#else 180 printf(_("Filesystem at %s is mounted on %s, and on-line resizing is " 181 "not supported on this system.\n"), fs->device_name, mtpt); 182 exit(1); 183#endif 184} 185