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 /* The current method of adding one block group at a time to a 97 * mounted filesystem means it is impossible to accomodate the 98 * flex_bg allocation method of placing the metadata together 99 * in a single block group. For now we "fix" this issue by 100 * using the traditional layout for new block groups, where 101 * each block group is self-contained and contains its own 102 * bitmap blocks and inode tables. This means we don't get 103 * the layout advantages of flex_bg in the new block groups, 104 * but at least it allows on-line resizing to function. 105 */ 106 new_fs->super->s_feature_incompat &= ~EXT4_FEATURE_INCOMPAT_FLEX_BG; 107 retval = adjust_fs_info(new_fs, fs, 0, *new_size); 108 if (retval) 109 return retval; 110 111 printf(_("Performing an on-line resize of %s to %u (%dk) blocks.\n"), 112 fs->device_name, *new_size, fs->blocksize / 1024); 113 114 size = fs->group_desc_count * sb->s_blocks_per_group + 115 sb->s_first_data_block; 116 if (size > *new_size) 117 size = *new_size; 118 119 if (ioctl(fd, EXT2_IOC_GROUP_EXTEND, &size)) { 120 com_err(program_name, errno, 121 _("While trying to extend the last group")); 122 exit(1); 123 } 124 125 for (i = fs->group_desc_count; 126 i < new_fs->group_desc_count; i++) { 127 128 overhead = (int) (2 + new_fs->inode_blocks_per_group); 129 130 if (ext2fs_bg_has_super(new_fs, new_fs->group_desc_count - 1)) 131 overhead += 1 + new_fs->desc_blocks + 132 new_fs->super->s_reserved_gdt_blocks; 133 134 input.group = i; 135 input.block_bitmap = new_fs->group_desc[i].bg_block_bitmap; 136 input.inode_bitmap = new_fs->group_desc[i].bg_inode_bitmap; 137 input.inode_table = new_fs->group_desc[i].bg_inode_table; 138 input.blocks_count = sb->s_blocks_per_group; 139 if (i == new_fs->group_desc_count-1) { 140 input.blocks_count = new_fs->super->s_blocks_count - 141 sb->s_first_data_block - 142 (i * sb->s_blocks_per_group); 143 } 144 input.reserved_blocks = (blk_t) (percent * input.blocks_count 145 / 100.0); 146 147#if 0 148 printf("new block bitmap is at 0x%04x\n", input.block_bitmap); 149 printf("new inode bitmap is at 0x%04x\n", input.inode_bitmap); 150 printf("new inode table is at 0x%04x-0x%04x\n", 151 input.inode_table, 152 input.inode_table + new_fs->inode_blocks_per_group-1); 153 printf("new group has %u blocks\n", input.blocks_count); 154 printf("new group will reserve %d blocks\n", 155 input.reserved_blocks); 156 printf("new group has %d free blocks\n", 157 new_fs->group_desc[i].bg_free_blocks_count); 158 printf("new group has %d free inodes (%d blocks)\n", 159 new_fs->group_desc[i].bg_free_inodes_count, 160 new_fs->inode_blocks_per_group); 161 printf("Adding group #%d\n", input.group); 162#endif 163 164 if (use_old_ioctl && 165 ioctl(fd, EXT2_IOC_GROUP_ADD, &input) == 0) 166 continue; 167 else 168 use_old_ioctl = 0; 169 170 input64.group = input.group; 171 input64.block_bitmap = input.block_bitmap; 172 input64.inode_bitmap = input.inode_bitmap; 173 input64.inode_table = input.inode_table; 174 input64.blocks_count = input.blocks_count; 175 input64.reserved_blocks = input.reserved_blocks; 176 input64.unused = input.unused; 177 178 if (ioctl(fd, EXT4_IOC_GROUP_ADD, &input64) < 0) { 179 com_err(program_name, errno, 180 _("While trying to add group #%d"), 181 input.group); 182 exit(1); 183 } 184 } 185 186 ext2fs_free(new_fs); 187 close(fd); 188 189 return 0; 190#else 191 printf(_("Filesystem at %s is mounted on %s, and on-line resizing is " 192 "not supported on this system.\n"), fs->device_name, mtpt); 193 exit(1); 194#endif 195} 196