]>
Commit | Line | Data |
---|---|---|
1b6bf175 TT |
1 | /* |
2 | * e2fsck.c - superblock checks | |
3 | * | |
4 | * Copyright (C) 1993, 1994, 1995, 1996, 1997 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 | ||
1b6bf175 TT |
12 | #ifdef HAVE_ERRNO_H |
13 | #include <errno.h> | |
14 | #endif | |
1b6bf175 | 15 | |
54be2ccc | 16 | #ifndef EXT2_SKIP_UUID |
1b6bf175 | 17 | #include "uuid/uuid.h" |
54be2ccc | 18 | #endif |
1b6bf175 TT |
19 | #include "e2fsck.h" |
20 | #include "problem.h" | |
1b6bf175 TT |
21 | |
22 | #define MIN_CHECK 1 | |
23 | #define MAX_CHECK 2 | |
24 | ||
25 | static void check_super_value(e2fsck_t ctx, const char *descr, | |
26 | unsigned long value, int flags, | |
7f813ba3 | 27 | unsigned long min_val, unsigned long max_val) |
1b6bf175 TT |
28 | { |
29 | struct problem_context pctx; | |
30 | ||
7f813ba3 TT |
31 | if (((flags & MIN_CHECK) && (value < min_val)) || |
32 | ((flags & MAX_CHECK) && (value > max_val))) { | |
1b6bf175 TT |
33 | clear_problem_context(&pctx); |
34 | pctx.num = value; | |
35 | pctx.str = descr; | |
36 | fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx); | |
08b21301 | 37 | ctx->flags |= E2F_FLAG_ABORT; /* never get here! */ |
1b6bf175 TT |
38 | } |
39 | } | |
40 | ||
4313932c TT |
41 | /* |
42 | * This routine may get stubbed out in special compilations of the | |
43 | * e2fsck code.. | |
44 | */ | |
45 | #ifndef EXT2_SPECIAL_DEVICE_SIZE | |
46 | errcode_t e2fsck_get_device_size(e2fsck_t ctx) | |
47 | { | |
48 | return (ext2fs_get_device_size(ctx->filesystem_name, | |
49 | EXT2_BLOCK_SIZE(ctx->fs->super), | |
50 | &ctx->num_blocks)); | |
51 | } | |
4313932c TT |
52 | #endif |
53 | ||
80bfaa3e TT |
54 | /* |
55 | * helper function to release an inode | |
56 | */ | |
57 | struct process_block_struct { | |
8394902e TT |
58 | e2fsck_t ctx; |
59 | char *buf; | |
80bfaa3e | 60 | struct problem_context *pctx; |
8394902e TT |
61 | int truncating; |
62 | int truncate_offset; | |
54434927 | 63 | e2_blkcnt_t truncate_block; |
8394902e TT |
64 | int truncated_blocks; |
65 | int abort; | |
66 | errcode_t errcode; | |
80bfaa3e TT |
67 | }; |
68 | ||
69 | static int release_inode_block(ext2_filsys fs, | |
70 | blk_t *block_nr, | |
54434927 TT |
71 | e2_blkcnt_t blockcnt, |
72 | blk_t ref_blk EXT2FS_ATTR((unused)), | |
73 | int ref_offset EXT2FS_ATTR((unused)), | |
80bfaa3e TT |
74 | void *priv_data) |
75 | { | |
76 | struct process_block_struct *pb; | |
8394902e TT |
77 | e2fsck_t ctx; |
78 | struct problem_context *pctx; | |
79 | blk_t blk = *block_nr; | |
80 | int retval = 0; | |
80bfaa3e TT |
81 | |
82 | pb = (struct process_block_struct *) priv_data; | |
83 | ctx = pb->ctx; | |
84 | pctx = pb->pctx; | |
85 | ||
86 | pctx->blk = blk; | |
87 | pctx->blkcount = blockcnt; | |
88 | ||
89 | if (HOLE_BLKADDR(blk)) | |
90 | return 0; | |
91 | ||
92 | if ((blk < fs->super->s_first_data_block) || | |
93 | (blk >= fs->super->s_blocks_count)) { | |
94 | fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, pctx); | |
53ef44c4 | 95 | return_abort: |
80bfaa3e TT |
96 | pb->abort = 1; |
97 | return BLOCK_ABORT; | |
98 | } | |
99 | ||
100 | if (!ext2fs_test_block_bitmap(fs->block_map, blk)) { | |
101 | fix_problem(ctx, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK, pctx); | |
53ef44c4 | 102 | goto return_abort; |
8394902e TT |
103 | } |
104 | ||
105 | /* | |
106 | * If we are deleting an orphan, then we leave the fields alone. | |
107 | * If we are truncating an orphan, then update the inode fields | |
108 | * and clean up any partial block data. | |
109 | */ | |
110 | if (pb->truncating) { | |
111 | /* | |
112 | * We only remove indirect blocks if they are | |
113 | * completely empty. | |
114 | */ | |
115 | if (blockcnt < 0) { | |
116 | int i, limit; | |
53ef44c4 | 117 | blk_t *bp; |
8394902e TT |
118 | |
119 | pb->errcode = io_channel_read_blk(fs->io, blk, 1, | |
120 | pb->buf); | |
121 | if (pb->errcode) | |
53ef44c4 | 122 | goto return_abort; |
8394902e TT |
123 | |
124 | limit = fs->blocksize >> 2; | |
53ef44c4 TT |
125 | for (i = 0, bp = (blk_t *) pb->buf; |
126 | i < limit; i++, bp++) | |
127 | if (*bp) | |
8394902e TT |
128 | return 0; |
129 | } | |
130 | /* | |
131 | * We don't remove direct blocks until we've reached | |
132 | * the truncation block. | |
133 | */ | |
134 | if (blockcnt >= 0 && blockcnt < pb->truncate_block) | |
135 | return 0; | |
136 | /* | |
137 | * If part of the last block needs truncating, we do | |
138 | * it here. | |
139 | */ | |
140 | if ((blockcnt == pb->truncate_block) && pb->truncate_offset) { | |
141 | pb->errcode = io_channel_read_blk(fs->io, blk, 1, | |
142 | pb->buf); | |
143 | if (pb->errcode) | |
53ef44c4 | 144 | goto return_abort; |
8394902e TT |
145 | memset(pb->buf + pb->truncate_offset, 0, |
146 | fs->blocksize - pb->truncate_offset); | |
147 | pb->errcode = io_channel_write_blk(fs->io, blk, 1, | |
148 | pb->buf); | |
149 | if (pb->errcode) | |
53ef44c4 | 150 | goto return_abort; |
8394902e TT |
151 | } |
152 | pb->truncated_blocks++; | |
153 | *block_nr = 0; | |
154 | retval |= BLOCK_CHANGED; | |
80bfaa3e TT |
155 | } |
156 | ||
0684a4f3 | 157 | ext2fs_block_alloc_stats(fs, blk, -1); |
8394902e | 158 | return retval; |
80bfaa3e TT |
159 | } |
160 | ||
161 | /* | |
162 | * This function releases an inode. Returns 1 if an inconsistency was | |
8394902e TT |
163 | * found. If the inode has a link count, then it is being truncated and |
164 | * not deleted. | |
80bfaa3e | 165 | */ |
86c627ec | 166 | static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, |
721edd0e | 167 | struct ext2_inode *inode, char *block_buf, |
80bfaa3e TT |
168 | struct problem_context *pctx) |
169 | { | |
0684a4f3 | 170 | struct process_block_struct pb; |
8394902e | 171 | ext2_filsys fs = ctx->fs; |
80bfaa3e | 172 | errcode_t retval; |
0684a4f3 | 173 | __u32 count; |
80bfaa3e | 174 | |
42475e28 TT |
175 | if (!ext2fs_inode_has_valid_blocks(inode)) |
176 | return 0; | |
177 | ||
8394902e | 178 | pb.buf = block_buf + 3 * ctx->fs->blocksize; |
80bfaa3e TT |
179 | pb.ctx = ctx; |
180 | pb.abort = 0; | |
8394902e | 181 | pb.errcode = 0; |
80bfaa3e | 182 | pb.pctx = pctx; |
8394902e TT |
183 | if (inode->i_links_count) { |
184 | pb.truncating = 1; | |
54434927 | 185 | pb.truncate_block = (e2_blkcnt_t) |
8394902e TT |
186 | ((((long long)inode->i_size_high << 32) + |
187 | inode->i_size + fs->blocksize - 1) / | |
188 | fs->blocksize); | |
189 | pb.truncate_offset = inode->i_size % fs->blocksize; | |
190 | } else { | |
191 | pb.truncating = 0; | |
192 | pb.truncate_block = 0; | |
193 | pb.truncate_offset = 0; | |
194 | } | |
195 | pb.truncated_blocks = 0; | |
54434927 | 196 | retval = ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_DEPTH_TRAVERSE, |
8394902e | 197 | block_buf, release_inode_block, &pb); |
80bfaa3e | 198 | if (retval) { |
8394902e | 199 | com_err("release_inode_blocks", retval, |
80bfaa3e TT |
200 | _("while calling ext2fs_block_iterate for inode %d"), |
201 | ino); | |
202 | return 1; | |
203 | } | |
204 | if (pb.abort) | |
205 | return 1; | |
206 | ||
8394902e TT |
207 | /* Refresh the inode since ext2fs_block_iterate may have changed it */ |
208 | e2fsck_read_inode(ctx, ino, inode, "release_inode_blocks"); | |
209 | ||
210 | if (pb.truncated_blocks) | |
211 | inode->i_blocks -= pb.truncated_blocks * | |
212 | (fs->blocksize / 512); | |
213 | ||
0684a4f3 TT |
214 | if (inode->i_file_acl) { |
215 | retval = ext2fs_adjust_ea_refcount(fs, inode->i_file_acl, | |
216 | block_buf, -1, &count); | |
217 | if (retval == EXT2_ET_BAD_EA_BLOCK_NUM) { | |
218 | retval = 0; | |
219 | count = 1; | |
220 | } | |
221 | if (retval) { | |
222 | com_err("release_inode_blocks", retval, | |
223 | _("while calling ext2fs_adjust_ea_refocunt for inode %d"), | |
224 | ino); | |
225 | return 1; | |
226 | } | |
227 | if (count == 0) | |
228 | ext2fs_block_alloc_stats(fs, inode->i_file_acl, -1); | |
229 | inode->i_file_acl = 0; | |
230 | } | |
80bfaa3e TT |
231 | return 0; |
232 | } | |
233 | ||
234 | /* | |
235 | * This function releases all of the orphan inodes. It returns 1 if | |
236 | * it hit some error, and 0 on success. | |
237 | */ | |
238 | static int release_orphan_inodes(e2fsck_t ctx) | |
239 | { | |
240 | ext2_filsys fs = ctx->fs; | |
86c627ec | 241 | ext2_ino_t ino, next_ino; |
80bfaa3e TT |
242 | struct ext2_inode inode; |
243 | struct problem_context pctx; | |
244 | char *block_buf; | |
245 | ||
246 | if ((ino = fs->super->s_last_orphan) == 0) | |
247 | return 0; | |
248 | ||
25c63ba0 TT |
249 | /* |
250 | * Win or lose, we won't be using the head of the orphan inode | |
251 | * list again. | |
252 | */ | |
253 | fs->super->s_last_orphan = 0; | |
254 | ext2fs_mark_super_dirty(fs); | |
eb4ab510 TT |
255 | |
256 | /* | |
257 | * If the filesystem contains errors, don't run the orphan | |
258 | * list, since the orphan list can't be trusted; and we're | |
259 | * going to be running a full e2fsck run anyway... | |
260 | */ | |
261 | if (fs->super->s_state & EXT2_ERROR_FS) | |
262 | return 0; | |
25c63ba0 | 263 | |
80bfaa3e TT |
264 | if ((ino < EXT2_FIRST_INODE(fs->super)) || |
265 | (ino > fs->super->s_inodes_count)) { | |
266 | clear_problem_context(&pctx); | |
53ef44c4 | 267 | pctx.ino = ino; |
80bfaa3e TT |
268 | fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_HEAD_INODE, &pctx); |
269 | return 1; | |
270 | } | |
271 | ||
8394902e | 272 | block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4, |
9b565759 | 273 | "block iterate buffer"); |
80bfaa3e TT |
274 | e2fsck_read_bitmaps(ctx); |
275 | ||
276 | while (ino) { | |
8394902e | 277 | e2fsck_read_inode(ctx, ino, &inode, "release_orphan_inodes"); |
80bfaa3e | 278 | clear_problem_context(&pctx); |
ecf1b776 | 279 | pctx.ino = ino; |
80bfaa3e | 280 | pctx.inode = &inode; |
f0b8c87d TT |
281 | pctx.str = inode.i_links_count ? _("Truncating") : |
282 | _("Clearing"); | |
80bfaa3e | 283 | |
8394902e | 284 | fix_problem(ctx, PR_0_ORPHAN_CLEAR_INODE, &pctx); |
ecf1b776 | 285 | |
80bfaa3e TT |
286 | next_ino = inode.i_dtime; |
287 | if (next_ino && | |
99a2cc96 TT |
288 | ((next_ino < EXT2_FIRST_INODE(fs->super)) || |
289 | (next_ino > fs->super->s_inodes_count))) { | |
290 | pctx.ino = next_ino; | |
80bfaa3e | 291 | fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx); |
53ef44c4 | 292 | goto return_abort; |
80bfaa3e TT |
293 | } |
294 | ||
8394902e | 295 | if (release_inode_blocks(ctx, ino, &inode, block_buf, &pctx)) |
53ef44c4 | 296 | goto return_abort; |
ecf1b776 | 297 | |
8394902e | 298 | if (!inode.i_links_count) { |
0684a4f3 TT |
299 | ext2fs_inode_alloc_stats2(fs, ino, -1, |
300 | LINUX_S_ISDIR(inode.i_mode)); | |
8394902e | 301 | inode.i_dtime = time(0); |
eb16f861 ST |
302 | } else { |
303 | inode.i_dtime = 0; | |
8394902e TT |
304 | } |
305 | e2fsck_write_inode(ctx, ino, &inode, "delete_file"); | |
80bfaa3e TT |
306 | ino = next_ino; |
307 | } | |
c4e3d3f3 | 308 | ext2fs_free_mem(&block_buf); |
80bfaa3e | 309 | return 0; |
53ef44c4 | 310 | return_abort: |
c4e3d3f3 | 311 | ext2fs_free_mem(&block_buf); |
80bfaa3e TT |
312 | return 1; |
313 | } | |
314 | ||
315 | ||
1b6bf175 TT |
316 | void check_super_block(e2fsck_t ctx) |
317 | { | |
318 | ext2_filsys fs = ctx->fs; | |
319 | blk_t first_block, last_block; | |
5dd8f963 | 320 | struct ext2_super_block *sb = fs->super; |
1b6bf175 | 321 | blk_t blocks_per_group = fs->super->s_blocks_per_group; |
b21bf267 | 322 | blk_t bpg_max; |
78cf0547 | 323 | int inodes_per_block; |
b21bf267 | 324 | int ipg_max; |
7f813ba3 | 325 | dgrp_t i; |
1b6bf175 TT |
326 | blk_t should_be; |
327 | struct problem_context pctx; | |
e75cfc5d | 328 | struct ext2_inode inode; |
2a77a784 | 329 | __u32 free_blocks = 0, free_inodes = 0; |
b21bf267 AD |
330 | |
331 | inodes_per_block = EXT2_INODES_PER_BLOCK(fs->super); | |
332 | ipg_max = inodes_per_block * (blocks_per_group - 4); | |
333 | if (ipg_max > EXT2_MAX_INODES_PER_GROUP(sb)) | |
334 | ipg_max = EXT2_MAX_INODES_PER_GROUP(sb); | |
335 | bpg_max = 8 * EXT2_BLOCK_SIZE(sb); | |
336 | if (bpg_max > EXT2_MAX_BLOCKS_PER_GROUP(sb)) | |
337 | bpg_max = EXT2_MAX_BLOCKS_PER_GROUP(sb); | |
1b6bf175 | 338 | |
54dc7ca2 | 339 | ctx->invalid_inode_bitmap_flag = (int *) e2fsck_allocate_memory(ctx, |
f8188fff | 340 | sizeof(int) * fs->group_desc_count, "invalid_inode_bitmap"); |
54dc7ca2 | 341 | ctx->invalid_block_bitmap_flag = (int *) e2fsck_allocate_memory(ctx, |
f8188fff | 342 | sizeof(int) * fs->group_desc_count, "invalid_block_bitmap"); |
54dc7ca2 | 343 | ctx->invalid_inode_table_flag = (int *) e2fsck_allocate_memory(ctx, |
f8188fff | 344 | sizeof(int) * fs->group_desc_count, "invalid_inode_table"); |
b21bf267 | 345 | |
1b6bf175 TT |
346 | clear_problem_context(&pctx); |
347 | ||
348 | /* | |
349 | * Verify the super block constants... | |
350 | */ | |
5dd8f963 | 351 | check_super_value(ctx, "inodes_count", sb->s_inodes_count, |
1b6bf175 | 352 | MIN_CHECK, 1, 0); |
5dd8f963 | 353 | check_super_value(ctx, "blocks_count", sb->s_blocks_count, |
1b6bf175 | 354 | MIN_CHECK, 1, 0); |
5dd8f963 TT |
355 | check_super_value(ctx, "first_data_block", sb->s_first_data_block, |
356 | MAX_CHECK, 0, sb->s_blocks_count); | |
5dd8f963 | 357 | check_super_value(ctx, "log_block_size", sb->s_log_block_size, |
31e29a12 TT |
358 | MIN_CHECK | MAX_CHECK, 0, |
359 | EXT2_MAX_BLOCK_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE); | |
932a489c AD |
360 | check_super_value(ctx, "log_frag_size", sb->s_log_frag_size, |
361 | MIN_CHECK | MAX_CHECK, 0, sb->s_log_block_size); | |
5dd8f963 | 362 | check_super_value(ctx, "frags_per_group", sb->s_frags_per_group, |
ef059870 | 363 | MIN_CHECK | MAX_CHECK, sb->s_blocks_per_group, |
b21bf267 | 364 | bpg_max); |
5dd8f963 | 365 | check_super_value(ctx, "blocks_per_group", sb->s_blocks_per_group, |
b21bf267 | 366 | MIN_CHECK | MAX_CHECK, 8, bpg_max); |
5dd8f963 | 367 | check_super_value(ctx, "inodes_per_group", sb->s_inodes_per_group, |
b21bf267 | 368 | MIN_CHECK | MAX_CHECK, inodes_per_block, ipg_max); |
5dd8f963 | 369 | check_super_value(ctx, "r_blocks_count", sb->s_r_blocks_count, |
424cd2be | 370 | MAX_CHECK, 0, sb->s_blocks_count / 4); |
1b6bf175 | 371 | |
f8188fff | 372 | if (!ctx->num_blocks) { |
4313932c | 373 | pctx.errcode = e2fsck_get_device_size(ctx); |
f8188fff TT |
374 | if (pctx.errcode && pctx.errcode != EXT2_ET_UNIMPLEMENTED) { |
375 | fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx); | |
08b21301 TT |
376 | ctx->flags |= E2F_FLAG_ABORT; |
377 | return; | |
378 | } | |
f8188fff | 379 | if ((pctx.errcode != EXT2_ET_UNIMPLEMENTED) && |
5dd8f963 TT |
380 | (ctx->num_blocks < sb->s_blocks_count)) { |
381 | pctx.blk = sb->s_blocks_count; | |
f8188fff TT |
382 | pctx.blk2 = ctx->num_blocks; |
383 | if (fix_problem(ctx, PR_0_FS_SIZE_WRONG, &pctx)) { | |
384 | ctx->flags |= E2F_FLAG_ABORT; | |
385 | return; | |
386 | } | |
387 | } | |
1b6bf175 TT |
388 | } |
389 | ||
54434927 | 390 | if (sb->s_log_block_size != (__u32) sb->s_log_frag_size) { |
5dd8f963 TT |
391 | pctx.blk = EXT2_BLOCK_SIZE(sb); |
392 | pctx.blk2 = EXT2_FRAG_SIZE(sb); | |
1b6bf175 | 393 | fix_problem(ctx, PR_0_NO_FRAGMENTS, &pctx); |
08b21301 TT |
394 | ctx->flags |= E2F_FLAG_ABORT; |
395 | return; | |
1b6bf175 TT |
396 | } |
397 | ||
5dd8f963 TT |
398 | should_be = sb->s_frags_per_group >> |
399 | (sb->s_log_block_size - sb->s_log_frag_size); | |
400 | if (sb->s_blocks_per_group != should_be) { | |
401 | pctx.blk = sb->s_blocks_per_group; | |
1b6bf175 TT |
402 | pctx.blk2 = should_be; |
403 | fix_problem(ctx, PR_0_BLOCKS_PER_GROUP, &pctx); | |
08b21301 TT |
404 | ctx->flags |= E2F_FLAG_ABORT; |
405 | return; | |
1b6bf175 TT |
406 | } |
407 | ||
5dd8f963 TT |
408 | should_be = (sb->s_log_block_size == 0) ? 1 : 0; |
409 | if (sb->s_first_data_block != should_be) { | |
410 | pctx.blk = sb->s_first_data_block; | |
1b6bf175 TT |
411 | pctx.blk2 = should_be; |
412 | fix_problem(ctx, PR_0_FIRST_DATA_BLOCK, &pctx); | |
08b21301 TT |
413 | ctx->flags |= E2F_FLAG_ABORT; |
414 | return; | |
1b6bf175 TT |
415 | } |
416 | ||
5dd8f963 TT |
417 | should_be = sb->s_inodes_per_group * fs->group_desc_count; |
418 | if (sb->s_inodes_count != should_be) { | |
419 | pctx.ino = sb->s_inodes_count; | |
d4b0ce03 TT |
420 | pctx.ino2 = should_be; |
421 | if (fix_problem(ctx, PR_0_INODE_COUNT_WRONG, &pctx)) { | |
5dd8f963 | 422 | sb->s_inodes_count = should_be; |
d4b0ce03 TT |
423 | ext2fs_mark_super_dirty(fs); |
424 | } | |
425 | } | |
426 | ||
1b6bf175 TT |
427 | /* |
428 | * Verify the group descriptors.... | |
429 | */ | |
430 | first_block = fs->super->s_first_data_block; | |
431 | last_block = first_block + blocks_per_group; | |
432 | ||
433 | for (i = 0; i < fs->group_desc_count; i++) { | |
434 | pctx.group = i; | |
435 | ||
436 | if (i == fs->group_desc_count - 1) | |
437 | last_block = fs->super->s_blocks_count; | |
438 | if ((fs->group_desc[i].bg_block_bitmap < first_block) || | |
439 | (fs->group_desc[i].bg_block_bitmap >= last_block)) { | |
440 | pctx.blk = fs->group_desc[i].bg_block_bitmap; | |
24bfb443 | 441 | if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx)) |
1b6bf175 | 442 | fs->group_desc[i].bg_block_bitmap = 0; |
24bfb443 TT |
443 | } |
444 | if (fs->group_desc[i].bg_block_bitmap == 0) { | |
445 | ctx->invalid_block_bitmap_flag[i]++; | |
446 | ctx->invalid_bitmaps++; | |
1b6bf175 TT |
447 | } |
448 | if ((fs->group_desc[i].bg_inode_bitmap < first_block) || | |
449 | (fs->group_desc[i].bg_inode_bitmap >= last_block)) { | |
450 | pctx.blk = fs->group_desc[i].bg_inode_bitmap; | |
24bfb443 | 451 | if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx)) |
1b6bf175 | 452 | fs->group_desc[i].bg_inode_bitmap = 0; |
24bfb443 TT |
453 | } |
454 | if (fs->group_desc[i].bg_inode_bitmap == 0) { | |
455 | ctx->invalid_inode_bitmap_flag[i]++; | |
456 | ctx->invalid_bitmaps++; | |
1b6bf175 TT |
457 | } |
458 | if ((fs->group_desc[i].bg_inode_table < first_block) || | |
459 | ((fs->group_desc[i].bg_inode_table + | |
460 | fs->inode_blocks_per_group - 1) >= last_block)) { | |
461 | pctx.blk = fs->group_desc[i].bg_inode_table; | |
24bfb443 | 462 | if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx)) |
1b6bf175 | 463 | fs->group_desc[i].bg_inode_table = 0; |
24bfb443 TT |
464 | } |
465 | if (fs->group_desc[i].bg_inode_table == 0) { | |
466 | ctx->invalid_inode_table_flag[i]++; | |
467 | ctx->invalid_bitmaps++; | |
1b6bf175 | 468 | } |
2a77a784 TT |
469 | free_blocks += fs->group_desc[i].bg_free_blocks_count; |
470 | free_inodes += fs->group_desc[i].bg_free_inodes_count; | |
1b6bf175 TT |
471 | first_block += fs->super->s_blocks_per_group; |
472 | last_block += fs->super->s_blocks_per_group; | |
473 | } | |
474 | /* | |
475 | * If we have invalid bitmaps, set the error state of the | |
476 | * filesystem. | |
477 | */ | |
478 | if (ctx->invalid_bitmaps && !(ctx->options & E2F_OPT_READONLY)) { | |
479 | fs->super->s_state &= ~EXT2_VALID_FS; | |
480 | ext2fs_mark_super_dirty(fs); | |
481 | } | |
482 | ||
4ea0a110 TT |
483 | clear_problem_context(&pctx); |
484 | ||
54be2ccc | 485 | #ifndef EXT2_SKIP_UUID |
1b6bf175 TT |
486 | /* |
487 | * If the UUID field isn't assigned, assign it. | |
488 | */ | |
5dd8f963 | 489 | if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(sb->s_uuid)) { |
1b6bf175 | 490 | if (fix_problem(ctx, PR_0_ADD_UUID, &pctx)) { |
5dd8f963 | 491 | uuid_generate(sb->s_uuid); |
1b6bf175 | 492 | ext2fs_mark_super_dirty(fs); |
299d7424 | 493 | fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; |
1b6bf175 TT |
494 | } |
495 | } | |
54be2ccc | 496 | #endif |
2a77a784 TT |
497 | |
498 | /* | |
499 | * Update the global counts from the block group counts. This | |
500 | * is needed for an experimental patch which eliminates | |
501 | * locking the entire filesystem when allocating blocks or | |
502 | * inodes; if the filesystem is not unmounted cleanly, the | |
503 | * global counts may not be accurate. | |
504 | */ | |
505 | if (!(ctx->options & E2F_OPT_READONLY) && | |
506 | ((free_blocks != fs->super->s_free_blocks_count) || | |
507 | (free_inodes != fs->super->s_free_inodes_count))) { | |
508 | fs->super->s_free_blocks_count = free_blocks; | |
509 | fs->super->s_free_inodes_count = free_inodes; | |
510 | ext2fs_mark_super_dirty(fs); | |
511 | } | |
4ea0a110 TT |
512 | |
513 | /* | |
514 | * For the Hurd, check to see if the filetype option is set, | |
515 | * since it doesn't support it. | |
516 | */ | |
80bfaa3e TT |
517 | if (!(ctx->options & E2F_OPT_READONLY) && |
518 | fs->super->s_creator_os == EXT2_OS_HURD && | |
4ea0a110 TT |
519 | (fs->super->s_feature_incompat & |
520 | EXT2_FEATURE_INCOMPAT_FILETYPE)) { | |
521 | if (fix_problem(ctx, PR_0_HURD_CLEAR_FILETYPE, &pctx)) { | |
522 | fs->super->s_feature_incompat &= | |
523 | ~EXT2_FEATURE_INCOMPAT_FILETYPE; | |
524 | ext2fs_mark_super_dirty(fs); | |
525 | ||
526 | } | |
527 | } | |
80bfaa3e | 528 | |
7b59f1ef TT |
529 | /* |
530 | * If we have any of the compatibility flags set, we need to have a | |
531 | * revision 1 filesystem. Most kernels will not check the flags on | |
532 | * a rev 0 filesystem and we may have corruption issues because of | |
533 | * the incompatible changes to the filesystem. | |
534 | */ | |
535 | if (!(ctx->options & E2F_OPT_READONLY) && | |
536 | fs->super->s_rev_level == EXT2_GOOD_OLD_REV && | |
537 | (fs->super->s_feature_compat || | |
538 | fs->super->s_feature_ro_compat || | |
539 | fs->super->s_feature_incompat) && | |
540 | fix_problem(ctx, PR_0_FS_REV_LEVEL, &pctx)) { | |
a917d1cc | 541 | ext2fs_update_dynamic_rev(fs); |
7b59f1ef TT |
542 | ext2fs_mark_super_dirty(fs); |
543 | } | |
544 | ||
e75cfc5d TT |
545 | /* |
546 | * If the resize inode feature isn't set, then | |
547 | * s_reserved_gdt_blocks must be zero, and the resize inode | |
548 | * must be cleared. | |
549 | */ | |
550 | if (!(fs->super->s_feature_compat & | |
551 | EXT2_FEATURE_COMPAT_RESIZE_INODE)) { | |
552 | if (fs->super->s_reserved_gdt_blocks) { | |
553 | pctx.num = fs->super->s_reserved_gdt_blocks; | |
554 | if (fix_problem(ctx, PR_0_NONZERO_RESERVED_GDT_BLOCKS, | |
555 | &pctx)) { | |
556 | fs->super->s_reserved_gdt_blocks = 0; | |
557 | ext2fs_mark_super_dirty(fs); | |
558 | } | |
559 | } | |
560 | e2fsck_read_inode(ctx, EXT2_RESIZE_INO, &inode, | |
561 | "check_resize"); | |
562 | for (i=0; i < EXT2_N_BLOCKS; i++) { | |
563 | if (inode.i_block[i]) | |
564 | break; | |
565 | } | |
566 | pctx.ino = EXT2_RESIZE_INO; | |
567 | if ((i < EXT2_N_BLOCKS) && | |
568 | fix_problem(ctx, PR_0_CLEAR_RESIZE_INODE, &pctx)) { | |
569 | for (i=0; i < EXT2_N_BLOCKS; i++) { | |
570 | inode.i_block[i] = 0; | |
571 | } | |
572 | inode.i_blocks = 0; | |
573 | e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode, | |
574 | "clear_resize"); | |
575 | } | |
576 | } | |
577 | ||
80bfaa3e TT |
578 | /* |
579 | * Clean up any orphan inodes, if present. | |
580 | */ | |
581 | if (!(ctx->options & E2F_OPT_READONLY) && release_orphan_inodes(ctx)) { | |
582 | fs->super->s_state &= ~EXT2_VALID_FS; | |
7b59f1ef | 583 | ext2fs_mark_super_dirty(fs); |
80bfaa3e TT |
584 | } |
585 | ||
773fd8a1 TT |
586 | /* |
587 | * Move the ext3 journal file, if necessary. | |
588 | */ | |
589 | e2fsck_move_ext3_journal(ctx); | |
1b6bf175 TT |
590 | return; |
591 | } |