diff options
Diffstat (limited to 'e2fsprogs/e2fsck/super.c')
-rw-r--r-- | e2fsprogs/e2fsck/super.c | 713 |
1 files changed, 713 insertions, 0 deletions
diff --git a/e2fsprogs/e2fsck/super.c b/e2fsprogs/e2fsck/super.c new file mode 100644 index 000000000..294cd80e4 --- /dev/null +++ b/e2fsprogs/e2fsck/super.c | |||
@@ -0,0 +1,713 @@ | |||
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 | |||
12 | #ifdef HAVE_ERRNO_H | ||
13 | #include <errno.h> | ||
14 | #endif | ||
15 | |||
16 | #ifndef EXT2_SKIP_UUID | ||
17 | #include "uuid/uuid.h" | ||
18 | #endif | ||
19 | #include "e2fsck.h" | ||
20 | #include "problem.h" | ||
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, | ||
27 | unsigned long min_val, unsigned long max_val) | ||
28 | { | ||
29 | struct problem_context pctx; | ||
30 | |||
31 | if (((flags & MIN_CHECK) && (value < min_val)) || | ||
32 | ((flags & MAX_CHECK) && (value > max_val))) { | ||
33 | clear_problem_context(&pctx); | ||
34 | pctx.num = value; | ||
35 | pctx.str = descr; | ||
36 | fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx); | ||
37 | ctx->flags |= E2F_FLAG_ABORT; /* never get here! */ | ||
38 | } | ||
39 | } | ||
40 | |||
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 | } | ||
52 | #endif | ||
53 | |||
54 | /* | ||
55 | * helper function to release an inode | ||
56 | */ | ||
57 | struct process_block_struct { | ||
58 | e2fsck_t ctx; | ||
59 | char *buf; | ||
60 | struct problem_context *pctx; | ||
61 | int truncating; | ||
62 | int truncate_offset; | ||
63 | e2_blkcnt_t truncate_block; | ||
64 | int truncated_blocks; | ||
65 | int abort; | ||
66 | errcode_t errcode; | ||
67 | }; | ||
68 | |||
69 | static int release_inode_block(ext2_filsys fs, | ||
70 | blk_t *block_nr, | ||
71 | e2_blkcnt_t blockcnt, | ||
72 | blk_t ref_blk EXT2FS_ATTR((unused)), | ||
73 | int ref_offset EXT2FS_ATTR((unused)), | ||
74 | void *priv_data) | ||
75 | { | ||
76 | struct process_block_struct *pb; | ||
77 | e2fsck_t ctx; | ||
78 | struct problem_context *pctx; | ||
79 | blk_t blk = *block_nr; | ||
80 | int retval = 0; | ||
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); | ||
95 | return_abort: | ||
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); | ||
102 | goto return_abort; | ||
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; | ||
117 | blk_t *bp; | ||
118 | |||
119 | pb->errcode = io_channel_read_blk(fs->io, blk, 1, | ||
120 | pb->buf); | ||
121 | if (pb->errcode) | ||
122 | goto return_abort; | ||
123 | |||
124 | limit = fs->blocksize >> 2; | ||
125 | for (i = 0, bp = (blk_t *) pb->buf; | ||
126 | i < limit; i++, bp++) | ||
127 | if (*bp) | ||
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) | ||
144 | goto return_abort; | ||
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) | ||
150 | goto return_abort; | ||
151 | } | ||
152 | pb->truncated_blocks++; | ||
153 | *block_nr = 0; | ||
154 | retval |= BLOCK_CHANGED; | ||
155 | } | ||
156 | |||
157 | ext2fs_block_alloc_stats(fs, blk, -1); | ||
158 | return retval; | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * This function releases an inode. Returns 1 if an inconsistency was | ||
163 | * found. If the inode has a link count, then it is being truncated and | ||
164 | * not deleted. | ||
165 | */ | ||
166 | static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, | ||
167 | struct ext2_inode *inode, char *block_buf, | ||
168 | struct problem_context *pctx) | ||
169 | { | ||
170 | struct process_block_struct pb; | ||
171 | ext2_filsys fs = ctx->fs; | ||
172 | errcode_t retval; | ||
173 | __u32 count; | ||
174 | |||
175 | if (!ext2fs_inode_has_valid_blocks(inode)) | ||
176 | return 0; | ||
177 | |||
178 | pb.buf = block_buf + 3 * ctx->fs->blocksize; | ||
179 | pb.ctx = ctx; | ||
180 | pb.abort = 0; | ||
181 | pb.errcode = 0; | ||
182 | pb.pctx = pctx; | ||
183 | if (inode->i_links_count) { | ||
184 | pb.truncating = 1; | ||
185 | pb.truncate_block = (e2_blkcnt_t) | ||
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; | ||
196 | retval = ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_DEPTH_TRAVERSE, | ||
197 | block_buf, release_inode_block, &pb); | ||
198 | if (retval) { | ||
199 | com_err("release_inode_blocks", retval, | ||
200 | _("while calling ext2fs_block_iterate for inode %d"), | ||
201 | ino); | ||
202 | return 1; | ||
203 | } | ||
204 | if (pb.abort) | ||
205 | return 1; | ||
206 | |||
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 | |||
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 | } | ||
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; | ||
241 | ext2_ino_t ino, next_ino; | ||
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 | |||
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); | ||
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; | ||
263 | |||
264 | if ((ino < EXT2_FIRST_INODE(fs->super)) || | ||
265 | (ino > fs->super->s_inodes_count)) { | ||
266 | clear_problem_context(&pctx); | ||
267 | pctx.ino = ino; | ||
268 | fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_HEAD_INODE, &pctx); | ||
269 | return 1; | ||
270 | } | ||
271 | |||
272 | block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4, | ||
273 | "block iterate buffer"); | ||
274 | e2fsck_read_bitmaps(ctx); | ||
275 | |||
276 | while (ino) { | ||
277 | e2fsck_read_inode(ctx, ino, &inode, "release_orphan_inodes"); | ||
278 | clear_problem_context(&pctx); | ||
279 | pctx.ino = ino; | ||
280 | pctx.inode = &inode; | ||
281 | pctx.str = inode.i_links_count ? _("Truncating") : | ||
282 | _("Clearing"); | ||
283 | |||
284 | fix_problem(ctx, PR_0_ORPHAN_CLEAR_INODE, &pctx); | ||
285 | |||
286 | next_ino = inode.i_dtime; | ||
287 | if (next_ino && | ||
288 | ((next_ino < EXT2_FIRST_INODE(fs->super)) || | ||
289 | (next_ino > fs->super->s_inodes_count))) { | ||
290 | pctx.ino = next_ino; | ||
291 | fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx); | ||
292 | goto return_abort; | ||
293 | } | ||
294 | |||
295 | if (release_inode_blocks(ctx, ino, &inode, block_buf, &pctx)) | ||
296 | goto return_abort; | ||
297 | |||
298 | if (!inode.i_links_count) { | ||
299 | ext2fs_inode_alloc_stats2(fs, ino, -1, | ||
300 | LINUX_S_ISDIR(inode.i_mode)); | ||
301 | inode.i_dtime = time(0); | ||
302 | } else { | ||
303 | inode.i_dtime = 0; | ||
304 | } | ||
305 | e2fsck_write_inode(ctx, ino, &inode, "delete_file"); | ||
306 | ino = next_ino; | ||
307 | } | ||
308 | ext2fs_free_mem(&block_buf); | ||
309 | return 0; | ||
310 | return_abort: | ||
311 | ext2fs_free_mem(&block_buf); | ||
312 | return 1; | ||
313 | } | ||
314 | |||
315 | /* | ||
316 | * Check the resize inode to make sure it is sane. We check both for | ||
317 | * the case where on-line resizing is not enabled (in which case the | ||
318 | * resize inode should be cleared) as well as the case where on-line | ||
319 | * resizing is enabled. | ||
320 | */ | ||
321 | void check_resize_inode(e2fsck_t ctx) | ||
322 | { | ||
323 | ext2_filsys fs = ctx->fs; | ||
324 | struct ext2_inode inode; | ||
325 | struct problem_context pctx; | ||
326 | int i, j, gdt_off, ind_off; | ||
327 | blk_t blk, pblk, expect; | ||
328 | __u32 *dind_buf = 0, *ind_buf; | ||
329 | errcode_t retval; | ||
330 | |||
331 | clear_problem_context(&pctx); | ||
332 | |||
333 | /* | ||
334 | * If the resize inode feature isn't set, then | ||
335 | * s_reserved_gdt_blocks must be zero. | ||
336 | */ | ||
337 | if (!(fs->super->s_feature_compat & | ||
338 | EXT2_FEATURE_COMPAT_RESIZE_INODE)) { | ||
339 | if (fs->super->s_reserved_gdt_blocks) { | ||
340 | pctx.num = fs->super->s_reserved_gdt_blocks; | ||
341 | if (fix_problem(ctx, PR_0_NONZERO_RESERVED_GDT_BLOCKS, | ||
342 | &pctx)) { | ||
343 | fs->super->s_reserved_gdt_blocks = 0; | ||
344 | ext2fs_mark_super_dirty(fs); | ||
345 | } | ||
346 | } | ||
347 | } | ||
348 | |||
349 | /* Read the resizde inode */ | ||
350 | pctx.ino = EXT2_RESIZE_INO; | ||
351 | retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode); | ||
352 | if (retval) { | ||
353 | if (fs->super->s_feature_compat & | ||
354 | EXT2_FEATURE_COMPAT_RESIZE_INODE) | ||
355 | ctx->flags |= E2F_FLAG_RESIZE_INODE; | ||
356 | return; | ||
357 | } | ||
358 | |||
359 | /* | ||
360 | * If the resize inode feature isn't set, check to make sure | ||
361 | * the resize inode is cleared; then we're done. | ||
362 | */ | ||
363 | if (!(fs->super->s_feature_compat & | ||
364 | EXT2_FEATURE_COMPAT_RESIZE_INODE)) { | ||
365 | for (i=0; i < EXT2_N_BLOCKS; i++) { | ||
366 | if (inode.i_block[i]) | ||
367 | break; | ||
368 | } | ||
369 | if ((i < EXT2_N_BLOCKS) && | ||
370 | fix_problem(ctx, PR_0_CLEAR_RESIZE_INODE, &pctx)) { | ||
371 | memset(&inode, 0, sizeof(inode)); | ||
372 | e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode, | ||
373 | "clear_resize"); | ||
374 | } | ||
375 | return; | ||
376 | } | ||
377 | |||
378 | /* | ||
379 | * The resize inode feature is enabled; check to make sure the | ||
380 | * only block in use is the double indirect block | ||
381 | */ | ||
382 | blk = inode.i_block[EXT2_DIND_BLOCK]; | ||
383 | for (i=0; i < EXT2_N_BLOCKS; i++) { | ||
384 | if (i != EXT2_DIND_BLOCK && inode.i_block[i]) | ||
385 | break; | ||
386 | } | ||
387 | if ((i < EXT2_N_BLOCKS) || !blk || !inode.i_links_count || | ||
388 | !(inode.i_mode & LINUX_S_IFREG) || | ||
389 | (blk < fs->super->s_first_data_block || | ||
390 | blk >= fs->super->s_blocks_count)) { | ||
391 | resize_inode_invalid: | ||
392 | if (fix_problem(ctx, PR_0_RESIZE_INODE_INVALID, &pctx)) { | ||
393 | memset(&inode, 0, sizeof(inode)); | ||
394 | e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode, | ||
395 | "clear_resize"); | ||
396 | ctx->flags |= E2F_FLAG_RESIZE_INODE; | ||
397 | } | ||
398 | if (!(ctx->options & E2F_OPT_READONLY)) { | ||
399 | fs->super->s_state &= ~EXT2_VALID_FS; | ||
400 | ext2fs_mark_super_dirty(fs); | ||
401 | } | ||
402 | goto cleanup; | ||
403 | } | ||
404 | dind_buf = (__u32 *) e2fsck_allocate_memory(ctx, fs->blocksize * 2, | ||
405 | "resize dind buffer"); | ||
406 | ind_buf = (__u32 *) ((char *) dind_buf + fs->blocksize); | ||
407 | |||
408 | retval = ext2fs_read_ind_block(fs, blk, dind_buf); | ||
409 | if (retval) | ||
410 | goto resize_inode_invalid; | ||
411 | |||
412 | gdt_off = fs->desc_blocks; | ||
413 | pblk = fs->super->s_first_data_block + 1 + fs->desc_blocks; | ||
414 | for (i = 0; i < fs->super->s_reserved_gdt_blocks / 4; | ||
415 | i++, gdt_off++, pblk++) { | ||
416 | gdt_off %= fs->blocksize/4; | ||
417 | if (dind_buf[gdt_off] != pblk) | ||
418 | goto resize_inode_invalid; | ||
419 | retval = ext2fs_read_ind_block(fs, pblk, ind_buf); | ||
420 | if (retval) | ||
421 | goto resize_inode_invalid; | ||
422 | ind_off = 0; | ||
423 | for (j = 1; j < fs->group_desc_count; j++) { | ||
424 | if (!ext2fs_bg_has_super(fs, j)) | ||
425 | continue; | ||
426 | expect = pblk + (j * fs->super->s_blocks_per_group); | ||
427 | if (ind_buf[ind_off] != expect) | ||
428 | goto resize_inode_invalid; | ||
429 | ind_off++; | ||
430 | } | ||
431 | } | ||
432 | |||
433 | cleanup: | ||
434 | if (dind_buf) | ||
435 | ext2fs_free_mem(&dind_buf); | ||
436 | |||
437 | } | ||
438 | |||
439 | void check_super_block(e2fsck_t ctx) | ||
440 | { | ||
441 | ext2_filsys fs = ctx->fs; | ||
442 | blk_t first_block, last_block; | ||
443 | struct ext2_super_block *sb = fs->super; | ||
444 | struct ext2_group_desc *gd; | ||
445 | blk_t blocks_per_group = fs->super->s_blocks_per_group; | ||
446 | blk_t bpg_max; | ||
447 | int inodes_per_block; | ||
448 | int ipg_max; | ||
449 | int inode_size; | ||
450 | dgrp_t i; | ||
451 | blk_t should_be; | ||
452 | struct problem_context pctx; | ||
453 | __u32 free_blocks = 0, free_inodes = 0; | ||
454 | |||
455 | inodes_per_block = EXT2_INODES_PER_BLOCK(fs->super); | ||
456 | ipg_max = inodes_per_block * (blocks_per_group - 4); | ||
457 | if (ipg_max > EXT2_MAX_INODES_PER_GROUP(sb)) | ||
458 | ipg_max = EXT2_MAX_INODES_PER_GROUP(sb); | ||
459 | bpg_max = 8 * EXT2_BLOCK_SIZE(sb); | ||
460 | if (bpg_max > EXT2_MAX_BLOCKS_PER_GROUP(sb)) | ||
461 | bpg_max = EXT2_MAX_BLOCKS_PER_GROUP(sb); | ||
462 | |||
463 | ctx->invalid_inode_bitmap_flag = (int *) e2fsck_allocate_memory(ctx, | ||
464 | sizeof(int) * fs->group_desc_count, "invalid_inode_bitmap"); | ||
465 | ctx->invalid_block_bitmap_flag = (int *) e2fsck_allocate_memory(ctx, | ||
466 | sizeof(int) * fs->group_desc_count, "invalid_block_bitmap"); | ||
467 | ctx->invalid_inode_table_flag = (int *) e2fsck_allocate_memory(ctx, | ||
468 | sizeof(int) * fs->group_desc_count, "invalid_inode_table"); | ||
469 | |||
470 | clear_problem_context(&pctx); | ||
471 | |||
472 | /* | ||
473 | * Verify the super block constants... | ||
474 | */ | ||
475 | check_super_value(ctx, "inodes_count", sb->s_inodes_count, | ||
476 | MIN_CHECK, 1, 0); | ||
477 | check_super_value(ctx, "blocks_count", sb->s_blocks_count, | ||
478 | MIN_CHECK, 1, 0); | ||
479 | check_super_value(ctx, "first_data_block", sb->s_first_data_block, | ||
480 | MAX_CHECK, 0, sb->s_blocks_count); | ||
481 | check_super_value(ctx, "log_block_size", sb->s_log_block_size, | ||
482 | MIN_CHECK | MAX_CHECK, 0, | ||
483 | EXT2_MAX_BLOCK_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE); | ||
484 | check_super_value(ctx, "log_frag_size", sb->s_log_frag_size, | ||
485 | MIN_CHECK | MAX_CHECK, 0, sb->s_log_block_size); | ||
486 | check_super_value(ctx, "frags_per_group", sb->s_frags_per_group, | ||
487 | MIN_CHECK | MAX_CHECK, sb->s_blocks_per_group, | ||
488 | bpg_max); | ||
489 | check_super_value(ctx, "blocks_per_group", sb->s_blocks_per_group, | ||
490 | MIN_CHECK | MAX_CHECK, 8, bpg_max); | ||
491 | check_super_value(ctx, "inodes_per_group", sb->s_inodes_per_group, | ||
492 | MIN_CHECK | MAX_CHECK, inodes_per_block, ipg_max); | ||
493 | check_super_value(ctx, "r_blocks_count", sb->s_r_blocks_count, | ||
494 | MAX_CHECK, 0, sb->s_blocks_count / 2); | ||
495 | check_super_value(ctx, "reserved_gdt_blocks", | ||
496 | sb->s_reserved_gdt_blocks, MAX_CHECK, 0, | ||
497 | fs->blocksize/4); | ||
498 | inode_size = EXT2_INODE_SIZE(sb); | ||
499 | check_super_value(ctx, "inode_size", | ||
500 | inode_size, MIN_CHECK | MAX_CHECK, | ||
501 | EXT2_GOOD_OLD_INODE_SIZE, fs->blocksize); | ||
502 | if (inode_size & (inode_size - 1)) { | ||
503 | pctx.num = inode_size; | ||
504 | pctx.str = "inode_size"; | ||
505 | fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx); | ||
506 | ctx->flags |= E2F_FLAG_ABORT; /* never get here! */ | ||
507 | return; | ||
508 | } | ||
509 | |||
510 | if (!ctx->num_blocks) { | ||
511 | pctx.errcode = e2fsck_get_device_size(ctx); | ||
512 | if (pctx.errcode && pctx.errcode != EXT2_ET_UNIMPLEMENTED) { | ||
513 | fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx); | ||
514 | ctx->flags |= E2F_FLAG_ABORT; | ||
515 | return; | ||
516 | } | ||
517 | if ((pctx.errcode != EXT2_ET_UNIMPLEMENTED) && | ||
518 | (ctx->num_blocks < sb->s_blocks_count)) { | ||
519 | pctx.blk = sb->s_blocks_count; | ||
520 | pctx.blk2 = ctx->num_blocks; | ||
521 | if (fix_problem(ctx, PR_0_FS_SIZE_WRONG, &pctx)) { | ||
522 | ctx->flags |= E2F_FLAG_ABORT; | ||
523 | return; | ||
524 | } | ||
525 | } | ||
526 | } | ||
527 | |||
528 | if (sb->s_log_block_size != (__u32) sb->s_log_frag_size) { | ||
529 | pctx.blk = EXT2_BLOCK_SIZE(sb); | ||
530 | pctx.blk2 = EXT2_FRAG_SIZE(sb); | ||
531 | fix_problem(ctx, PR_0_NO_FRAGMENTS, &pctx); | ||
532 | ctx->flags |= E2F_FLAG_ABORT; | ||
533 | return; | ||
534 | } | ||
535 | |||
536 | should_be = sb->s_frags_per_group >> | ||
537 | (sb->s_log_block_size - sb->s_log_frag_size); | ||
538 | if (sb->s_blocks_per_group != should_be) { | ||
539 | pctx.blk = sb->s_blocks_per_group; | ||
540 | pctx.blk2 = should_be; | ||
541 | fix_problem(ctx, PR_0_BLOCKS_PER_GROUP, &pctx); | ||
542 | ctx->flags |= E2F_FLAG_ABORT; | ||
543 | return; | ||
544 | } | ||
545 | |||
546 | should_be = (sb->s_log_block_size == 0) ? 1 : 0; | ||
547 | if (sb->s_first_data_block != should_be) { | ||
548 | pctx.blk = sb->s_first_data_block; | ||
549 | pctx.blk2 = should_be; | ||
550 | fix_problem(ctx, PR_0_FIRST_DATA_BLOCK, &pctx); | ||
551 | ctx->flags |= E2F_FLAG_ABORT; | ||
552 | return; | ||
553 | } | ||
554 | |||
555 | should_be = sb->s_inodes_per_group * fs->group_desc_count; | ||
556 | if (sb->s_inodes_count != should_be) { | ||
557 | pctx.ino = sb->s_inodes_count; | ||
558 | pctx.ino2 = should_be; | ||
559 | if (fix_problem(ctx, PR_0_INODE_COUNT_WRONG, &pctx)) { | ||
560 | sb->s_inodes_count = should_be; | ||
561 | ext2fs_mark_super_dirty(fs); | ||
562 | } | ||
563 | } | ||
564 | |||
565 | /* | ||
566 | * Verify the group descriptors.... | ||
567 | */ | ||
568 | first_block = sb->s_first_data_block; | ||
569 | last_block = first_block + blocks_per_group; | ||
570 | |||
571 | for (i = 0, gd=fs->group_desc; i < fs->group_desc_count; i++, gd++) { | ||
572 | pctx.group = i; | ||
573 | |||
574 | if (i == fs->group_desc_count - 1) | ||
575 | last_block = sb->s_blocks_count; | ||
576 | if ((gd->bg_block_bitmap < first_block) || | ||
577 | (gd->bg_block_bitmap >= last_block)) { | ||
578 | pctx.blk = gd->bg_block_bitmap; | ||
579 | if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx)) | ||
580 | gd->bg_block_bitmap = 0; | ||
581 | } | ||
582 | if (gd->bg_block_bitmap == 0) { | ||
583 | ctx->invalid_block_bitmap_flag[i]++; | ||
584 | ctx->invalid_bitmaps++; | ||
585 | } | ||
586 | if ((gd->bg_inode_bitmap < first_block) || | ||
587 | (gd->bg_inode_bitmap >= last_block)) { | ||
588 | pctx.blk = gd->bg_inode_bitmap; | ||
589 | if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx)) | ||
590 | gd->bg_inode_bitmap = 0; | ||
591 | } | ||
592 | if (gd->bg_inode_bitmap == 0) { | ||
593 | ctx->invalid_inode_bitmap_flag[i]++; | ||
594 | ctx->invalid_bitmaps++; | ||
595 | } | ||
596 | if ((gd->bg_inode_table < first_block) || | ||
597 | ((gd->bg_inode_table + | ||
598 | fs->inode_blocks_per_group - 1) >= last_block)) { | ||
599 | pctx.blk = gd->bg_inode_table; | ||
600 | if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx)) | ||
601 | gd->bg_inode_table = 0; | ||
602 | } | ||
603 | if (gd->bg_inode_table == 0) { | ||
604 | ctx->invalid_inode_table_flag[i]++; | ||
605 | ctx->invalid_bitmaps++; | ||
606 | } | ||
607 | free_blocks += gd->bg_free_blocks_count; | ||
608 | free_inodes += gd->bg_free_inodes_count; | ||
609 | first_block += sb->s_blocks_per_group; | ||
610 | last_block += sb->s_blocks_per_group; | ||
611 | |||
612 | if ((gd->bg_free_blocks_count > sb->s_blocks_per_group) || | ||
613 | (gd->bg_free_inodes_count > sb->s_inodes_per_group) || | ||
614 | (gd->bg_used_dirs_count > sb->s_inodes_per_group)) | ||
615 | ext2fs_unmark_valid(fs); | ||
616 | |||
617 | } | ||
618 | |||
619 | /* | ||
620 | * Update the global counts from the block group counts. This | ||
621 | * is needed for an experimental patch which eliminates | ||
622 | * locking the entire filesystem when allocating blocks or | ||
623 | * inodes; if the filesystem is not unmounted cleanly, the | ||
624 | * global counts may not be accurate. | ||
625 | */ | ||
626 | if ((free_blocks != sb->s_free_blocks_count) || | ||
627 | (free_inodes != sb->s_free_inodes_count)) { | ||
628 | if (ctx->options & E2F_OPT_READONLY) | ||
629 | ext2fs_unmark_valid(fs); | ||
630 | else { | ||
631 | sb->s_free_blocks_count = free_blocks; | ||
632 | sb->s_free_inodes_count = free_inodes; | ||
633 | ext2fs_mark_super_dirty(fs); | ||
634 | } | ||
635 | } | ||
636 | |||
637 | if ((sb->s_free_blocks_count > sb->s_blocks_count) || | ||
638 | (sb->s_free_inodes_count > sb->s_inodes_count)) | ||
639 | ext2fs_unmark_valid(fs); | ||
640 | |||
641 | |||
642 | /* | ||
643 | * If we have invalid bitmaps, set the error state of the | ||
644 | * filesystem. | ||
645 | */ | ||
646 | if (ctx->invalid_bitmaps && !(ctx->options & E2F_OPT_READONLY)) { | ||
647 | sb->s_state &= ~EXT2_VALID_FS; | ||
648 | ext2fs_mark_super_dirty(fs); | ||
649 | } | ||
650 | |||
651 | clear_problem_context(&pctx); | ||
652 | |||
653 | #ifndef EXT2_SKIP_UUID | ||
654 | /* | ||
655 | * If the UUID field isn't assigned, assign it. | ||
656 | */ | ||
657 | if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(sb->s_uuid)) { | ||
658 | if (fix_problem(ctx, PR_0_ADD_UUID, &pctx)) { | ||
659 | uuid_generate(sb->s_uuid); | ||
660 | ext2fs_mark_super_dirty(fs); | ||
661 | fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; | ||
662 | } | ||
663 | } | ||
664 | #endif | ||
665 | |||
666 | /* | ||
667 | * For the Hurd, check to see if the filetype option is set, | ||
668 | * since it doesn't support it. | ||
669 | */ | ||
670 | if (!(ctx->options & E2F_OPT_READONLY) && | ||
671 | fs->super->s_creator_os == EXT2_OS_HURD && | ||
672 | (fs->super->s_feature_incompat & | ||
673 | EXT2_FEATURE_INCOMPAT_FILETYPE)) { | ||
674 | if (fix_problem(ctx, PR_0_HURD_CLEAR_FILETYPE, &pctx)) { | ||
675 | fs->super->s_feature_incompat &= | ||
676 | ~EXT2_FEATURE_INCOMPAT_FILETYPE; | ||
677 | ext2fs_mark_super_dirty(fs); | ||
678 | |||
679 | } | ||
680 | } | ||
681 | |||
682 | /* | ||
683 | * If we have any of the compatibility flags set, we need to have a | ||
684 | * revision 1 filesystem. Most kernels will not check the flags on | ||
685 | * a rev 0 filesystem and we may have corruption issues because of | ||
686 | * the incompatible changes to the filesystem. | ||
687 | */ | ||
688 | if (!(ctx->options & E2F_OPT_READONLY) && | ||
689 | fs->super->s_rev_level == EXT2_GOOD_OLD_REV && | ||
690 | (fs->super->s_feature_compat || | ||
691 | fs->super->s_feature_ro_compat || | ||
692 | fs->super->s_feature_incompat) && | ||
693 | fix_problem(ctx, PR_0_FS_REV_LEVEL, &pctx)) { | ||
694 | ext2fs_update_dynamic_rev(fs); | ||
695 | ext2fs_mark_super_dirty(fs); | ||
696 | } | ||
697 | |||
698 | check_resize_inode(ctx); | ||
699 | |||
700 | /* | ||
701 | * Clean up any orphan inodes, if present. | ||
702 | */ | ||
703 | if (!(ctx->options & E2F_OPT_READONLY) && release_orphan_inodes(ctx)) { | ||
704 | fs->super->s_state &= ~EXT2_VALID_FS; | ||
705 | ext2fs_mark_super_dirty(fs); | ||
706 | } | ||
707 | |||
708 | /* | ||
709 | * Move the ext3 journal file, if necessary. | ||
710 | */ | ||
711 | e2fsck_move_ext3_journal(ctx); | ||
712 | return; | ||
713 | } | ||