xref: /onnv-gate/usr/src/lib/libparted/common/libparted/fs/ext2/ext2_meta.c (revision 9663:ace9a2ac3683)
1 /*
2     ext2_meta.c -- ext2 metadata mover
3     Copyright (C) 1998-2000, 2007 Free Software Foundation, Inc.
4 
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 3 of the License, or
8     (at your option) any later version.
9 
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include <config.h>
20 
21 #ifndef DISCOVER_ONLY
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include "ext2.h"
26 
ext2_metadata_push(struct ext2_fs * fs,blk_t newsize)27 int ext2_metadata_push(struct ext2_fs *fs, blk_t newsize)
28 {
29 	int   i;
30 	int   newgdblocks;
31 	blk_t newitoffset;
32 
33 	newgdblocks = ped_div_round_up (newsize
34                         - EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb),
35 			      EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb));
36 	newgdblocks = ped_div_round_up (newgdblocks
37                         * sizeof(struct ext2_group_desc),
38 			      fs->blocksize);
39 	newitoffset = newgdblocks + 3;
40 
41 	if (newitoffset <= fs->itoffset)
42 		return 1;
43 
44 	for (i=0;i<fs->numgroups;i++)
45 	{
46 		blk_t diff;
47 		blk_t j;
48 		blk_t fromblock;
49 		blk_t start;
50 
51 		start = (i * EXT2_SUPER_BLOCKS_PER_GROUP(fs->sb))
52 			+ EXT2_SUPER_FIRST_DATA_BLOCK(fs->sb);
53 
54 		if (EXT2_GROUP_INODE_TABLE(fs->gd[i]) >= start + newitoffset
55 		    && EXT2_GROUP_BLOCK_BITMAP(fs->gd[i]) >= start + newitoffset - 2
56 		    && EXT2_GROUP_INODE_BITMAP(fs->gd[i]) >= start + newitoffset - 1)
57 			continue;
58 
59 		diff = newitoffset - (EXT2_GROUP_INODE_TABLE(fs->gd[i]) - start);
60 
61 		/* inode table */
62 		fromblock = EXT2_GROUP_INODE_TABLE(fs->gd[i]) + fs->inodeblocks;
63 
64 		if (fs->opt_debug)
65 		{
66 			for (j=0;j<diff;j++)
67 				if (!ext2_get_block_state(fs, fromblock+j))
68 				{
69 					fprintf(stderr,
70 						"error: block relocator "
71 						"should have relocated "
72 						"%i\n",
73 						fromblock);
74 
75 					return 0;
76 				}
77 		}
78 
79 		for (j=0;j<diff;j++)
80 			if (!ext2_set_block_state(fs, fromblock+j, 1, 0))
81 				return 0;
82 
83 		if (!ext2_move_blocks(fs,
84 				      EXT2_GROUP_INODE_TABLE(fs->gd[i]),
85 				      fs->inodeblocks,
86 				      EXT2_GROUP_INODE_TABLE(fs->gd[i]) + diff))
87 			return 0;
88 		fs->gd[i].bg_inode_table = PED_CPU_TO_LE32 (
89 			EXT2_GROUP_INODE_TABLE(fs->gd[i]) + diff);
90 		fs->metadirty |= EXT2_META_GD;
91 
92 		if (fs->opt_safe)
93 			if (!ext2_sync(fs))
94 				return 0;
95 
96 		/* block bitmap and inode bitmap */
97 		fromblock = EXT2_GROUP_INODE_TABLE(fs->gd[i]);
98 		if (ext2_is_group_sparse(fs, i))
99 		{
100 			if (!ext2_copy_block(fs,
101 				EXT2_GROUP_INODE_BITMAP(fs->gd[i]),
102 				EXT2_GROUP_INODE_BITMAP(fs->gd[i]) + diff))
103 				return 0;
104 			fs->gd[i].bg_inode_bitmap = PED_CPU_TO_LE32 (
105 				EXT2_GROUP_INODE_BITMAP(fs->gd[i]) + diff);
106                         fs->metadirty |= EXT2_META_GD;
107 
108 			if (fs->opt_safe)
109 				if (!ext2_sync(fs))
110 					return 0;
111 
112 			if (!ext2_copy_block(fs,
113 				EXT2_GROUP_BLOCK_BITMAP(fs->gd[i]),
114 				EXT2_GROUP_BLOCK_BITMAP(fs->gd[i])+diff))
115 				return 0;
116 			fs->gd[i].bg_block_bitmap = PED_CPU_TO_LE32 (
117 				EXT2_GROUP_BLOCK_BITMAP(fs->gd[i]) + diff);
118 			fs->metadirty |= EXT2_META_GD;
119 
120 			if (fs->opt_safe)
121 				if (!ext2_sync(fs))
122 					return 0;
123 
124 			fromblock = EXT2_GROUP_BLOCK_BITMAP(fs->gd[i]);
125 		}
126 
127 		ext2_zero_blocks(fs, fromblock-diff, diff);
128 		for (j=0;j<diff;j++)
129 			if (!ext2_set_block_state(fs, fromblock+j-diff, 0, 0))
130 				return 0;
131 
132 		if (fs->opt_verbose)
133 			fprintf(stderr,
134 				"ext2_metadata_push: group %i/%i\r",
135 				i+1, fs->numgroups);
136 	}
137 
138 	fs->itoffset = newitoffset;
139 
140 	if (fs->opt_verbose)
141                 fputc ('\n', stderr);
142 
143 	return 1;
144 }
145 #endif /* !DISCOVER_ONLY */
146