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