summaryrefslogtreecommitdiff
path: root/resize/online.c
blob: 7701150dc7c859aeb8a5559afbc72f3834331ce5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
 * online.c --- Do on-line resizing of the ext3 filesystem
 *
 * Copyright (C) 2006 by Theodore Ts'o 
 * 
 * %Begin-Header%
 * This file may be redistributed under the terms of the GNU Public
 * License.
 * %End-Header%
 */

#include "resize2fs.h"
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
#include <sys/stat.h>
#include <fcntl.h>

extern char *program_name;

errcode_t online_resize_fs(ext2_filsys fs, const char *mtpt, 
			   blk_t *new_size, int flags)
{
	struct ext2_new_group_input input;
	struct ext2_super_block *sb = fs->super;
	ext2_filsys 		new_fs;
	errcode_t 		retval;
	dgrp_t			i;
	blk_t			size;
	int			fd, r_frac, overhead;

	printf(_("Filesystem at %s is mounted on %s; "
		 "on-line resizing required\n"), fs->device_name, mtpt);

	if (*new_size < sb->s_blocks_count) {
		printf(_("On-line shrinking from %u to %u not supported.\n"),
		       sb->s_blocks_count, *new_size);
		exit(1);
	}

	fd = open(mtpt, O_RDONLY);
	if (fd < 0) {
		com_err(program_name, errno, 
			_("while trying to open mountpoint %s"), mtpt);
		exit(1);
	}

	size=sb->s_blocks_count;
	if (ioctl(fd, EXT2_IOC_GROUP_EXTEND, &size)) {
		if (errno == EPERM)
			com_err(program_name, 0, 
				_("Permission denied to resize filesystem"));
		else if (errno == ENOTTY)
			com_err(program_name, 0, 
			_("Filesystem does not support online resizing"));
		else 
			com_err(program_name, errno, 
			_("While checking for on-line resizing support"));
		exit(1);
	}

	r_frac = ((100 * sb->s_r_blocks_count) + sb->s_blocks_count-1) /
		sb->s_blocks_count;

	retval = ext2fs_read_bitmaps(fs);
	if (retval)
		return retval;

	retval = ext2fs_dup_handle(fs, &new_fs);
	if (retval)
		return retval;

	retval = adjust_fs_info(new_fs, fs, *new_size);
	if (retval)
		return retval;

	printf(_("Performing an on-line resize of %s to %d (%dk) blocks.\n"), 
	       fs->device_name, *new_size, fs->blocksize / 1024);

	size = fs->group_desc_count * sb->s_blocks_per_group + 
		sb->s_first_data_block;
	if (size > *new_size)
		size = *new_size;

	if (ioctl(fd, EXT2_IOC_GROUP_EXTEND, &size)) {
		com_err(program_name, errno, 
			_("While trying to extend the last group"));
		exit(1);
	}

	for (i = fs->group_desc_count;
	     i < new_fs->group_desc_count; i++) {

		overhead = (int) (2 + new_fs->inode_blocks_per_group);

		if (ext2fs_bg_has_super(new_fs, new_fs->group_desc_count - 1))
			overhead += 1 + new_fs->desc_blocks + 
				new_fs->super->s_reserved_gdt_blocks;

		input.group = i;
		input.block_bitmap = new_fs->group_desc[i].bg_block_bitmap;
		input.inode_bitmap = new_fs->group_desc[i].bg_inode_bitmap;
		input.inode_table = new_fs->group_desc[i].bg_inode_table;
		input.blocks_count = sb->s_blocks_per_group;
		if (i == new_fs->group_desc_count-1) {
			input.blocks_count = new_fs->super->s_blocks_count -
				sb->s_first_data_block - 
				(i * sb->s_blocks_per_group);
		}
		input.reserved_blocks = e2p_percent(r_frac, 
						    input.blocks_count);

#if 0
		printf("new block bitmap is at 0x%04x\n", input.block_bitmap);
		printf("new inode bitmap is at 0x%04x\n", input.inode_bitmap);
		printf("new inode table is at 0x%04x-0x%04x\n", 
		       input.inode_table,
		       input.inode_table + new_fs->inode_blocks_per_group-1);
		printf("new group has %d blocks\n", input.blocks_count);
		printf("new group will reserve %d blocks\n", 
		       input.reserved_blocks);
		printf("new group has %d free blocks\n", 
		       new_fs->group_desc[i].bg_free_blocks_count);
		printf("new group has %d free inodes (%d blocks)\n",
		       new_fs->group_desc[i].bg_free_inodes_count, 
		       new_fs->inode_blocks_per_group);
		printf("Adding group #%d\n", input.group);
#endif

		if (ioctl(fd, EXT2_IOC_GROUP_ADD, &input) < 0) {
			com_err(program_name, errno, 
				_("While trying to add group #%d"), 
				input.group);
			exit(1);
		}
	}

	ext2fs_free(new_fs);
	close(fd);

	return 0;
}