blob: 7ba9c6389649f5349eab24939b723f96a9d4086e [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
2 * pass1.c -- pass #1 of e2fsck: sequential scan of the inode table
3 *
Theodore Ts'o21c84b71997-04-29 16:15:03 +00004 * 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%
Theodore Ts'o3839e651997-04-26 13:21:57 +000010 *
11 * Pass 1 of e2fsck iterates over all the inodes in the filesystems,
12 * and applies the following tests to each inode:
13 *
14 * - The mode field of the inode must be legal.
15 * - The size and block count fields of the inode are correct.
16 * - A data block must not be used by another inode
17 *
18 * Pass 1 also gathers the collects the following information:
19 *
20 * - A bitmap of which inodes are in use. (inode_used_map)
21 * - A bitmap of which inodes are directories. (inode_dir_map)
22 * - A bitmap of which inodes have bad fields. (inode_bad_map)
Theodore Ts'o21c84b71997-04-29 16:15:03 +000023 * - A bitmap of which inodes are in bad blocks. (inode_bb_map)
Theodore Ts'o3839e651997-04-26 13:21:57 +000024 * - A bitmap of which blocks are in use. (block_found_map)
25 * - A bitmap of which blocks are in use by two inodes (block_dup_map)
26 * - The data blocks of the directory inodes. (dir_map)
27 *
28 * Pass 1 is designed to stash away enough information so that the
29 * other passes should not need to read in the inode information
30 * during the normal course of a filesystem check. (Althogh if an
31 * inconsistency is detected, other passes may need to read in an
32 * inode to fix it.)
33 *
34 * Note that pass 1B will be invoked if there are any duplicate blocks
35 * found.
36 */
37
38#include <time.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000039#ifdef HAVE_ERRNO_H
40#include <errno.h>
41#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000042
Theodore Ts'o3839e651997-04-26 13:21:57 +000043#include "e2fsck.h"
Theodore Ts'o21c84b71997-04-29 16:15:03 +000044#include "problem.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000045
Theodore Ts'o50e1e101997-04-26 13:58:21 +000046#ifdef NO_INLINE_FUNCS
47#define _INLINE_
48#else
49#define _INLINE_ inline
50#endif
51
Theodore Ts'o3839e651997-04-26 13:21:57 +000052static int process_block(ext2_filsys fs, blk_t *blocknr,
Theodore Ts'o246501c1998-03-24 16:22:38 +000053 blkcnt_t blockcnt, blk_t ref_blk,
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +000054 int ref_offset, void *priv_data);
Theodore Ts'o3839e651997-04-26 13:21:57 +000055static int process_bad_block(ext2_filsys fs, blk_t *block_nr,
Theodore Ts'o246501c1998-03-24 16:22:38 +000056 blkcnt_t blockcnt, blk_t ref_blk,
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +000057 int ref_offset, void *priv_data);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000058static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
Theodore Ts'o3839e651997-04-26 13:21:57 +000059 char *block_buf);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000060static void mark_table_blocks(e2fsck_t ctx);
61static void alloc_bad_map(e2fsck_t ctx);
62static void alloc_bb_map(e2fsck_t ctx);
63static void handle_fs_bad_blocks(e2fsck_t ctx);
64static void process_inodes(e2fsck_t ctx, char *block_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +000065static int process_inode_cmp(const void *a, const void *b);
Theodore Ts'of3db3561997-04-26 13:34:30 +000066static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan,
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +000067 dgrp_t group, void * priv_data);
Theodore Ts'o21c84b71997-04-29 16:15:03 +000068/* static char *describe_illegal_block(ext2_filsys fs, blk_t block); */
Theodore Ts'o3839e651997-04-26 13:21:57 +000069
70struct process_block_struct {
Theodore Ts'o246501c1998-03-24 16:22:38 +000071 ino_t ino;
72 int is_dir:1, clear:1, suppress:1, fragmented:1;
73 blk_t num_blocks;
74 blkcnt_t last_block;
75 int num_illegal_blocks;
76 blk_t previous_block;
Theodore Ts'of3db3561997-04-26 13:34:30 +000077 struct ext2_inode *inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000078 struct problem_context *pctx;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000079 e2fsck_t ctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +000080};
81
82struct process_inode_block {
83 ino_t ino;
84 struct ext2_inode inode;
85};
86
Theodore Ts'of8188ff1997-11-14 05:23:04 +000087struct scan_callback_struct {
88 e2fsck_t ctx;
89 char *block_buf;
90};
91
Theodore Ts'o3839e651997-04-26 13:21:57 +000092/*
Theodore Ts'o3839e651997-04-26 13:21:57 +000093 * For the inodes to process list.
94 */
95static struct process_inode_block *inodes_to_process;
96static int process_inode_count;
Theodore Ts'o3839e651997-04-26 13:21:57 +000097
Theodore Ts'o246501c1998-03-24 16:22:38 +000098#define EXT2_BPP(bits) (1UL << ((bits) - 2))
99
100#define EXT2_MAX_SIZE(bits) \
101 (((EXT2_NDIR_BLOCKS + EXT2_BPP(bits) + \
102 EXT2_BPP(bits) * EXT2_BPP(bits) + \
103 EXT2_BPP(bits) * EXT2_BPP(bits) * EXT2_BPP(bits)) * \
104 (1UL << bits)) - 1)
105
106static long long ext2_max_sizes[] = {
107EXT2_MAX_SIZE(10), EXT2_MAX_SIZE(11), EXT2_MAX_SIZE(12), EXT2_MAX_SIZE(13)
108};
109
110#undef EXT2_BPP
111
Theodore Ts'o3839e651997-04-26 13:21:57 +0000112/*
Theodore Ts'of3db3561997-04-26 13:34:30 +0000113 * Free all memory allocated by pass1 in preparation for restarting
114 * things.
115 */
116static void unwind_pass1(ext2_filsys fs)
117{
Theodore Ts'o08b21301997-11-03 19:42:40 +0000118 ext2fs_free_mem((void **) &inodes_to_process);
119 inodes_to_process = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000120}
121
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000122/*
123 * Check to make sure a device inode is real. Returns 1 if the device
124 * checks out, 0 if not.
125 */
126int e2fsck_pass1_check_device_inode(struct ext2_inode *inode)
127{
128 int i;
129
Theodore Ts'o7fdfabd1997-11-24 11:51:17 +0000130 /*
131 * We should be able to do the test below all the time, but
132 * because the kernel doesn't forcibly clear the device
133 * inode's additional i_block fields, there are some rare
134 * occasions when a legitimate device inode will have non-zero
135 * additional i_block fields. So for now, we only complain
136 * when the immutable flag is set, which should never happen
137 * for devices. (And that's when the problem is caused, since
138 * you can't set or clear immutable flags for devices.) Once
139 * the kernel has been fixed we can change this...
140 */
141 if (inode->i_flags & EXT2_IMMUTABLE_FL) {
142 for (i=4; i < EXT2_N_BLOCKS; i++)
143 if (inode->i_block[i])
144 return 0;
145 }
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000146 return 1;
147}
148
Theodore Ts'o08b21301997-11-03 19:42:40 +0000149void e2fsck_pass1(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000150{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000151 ext2_filsys fs = ctx->fs;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000152 ino_t ino;
153 struct ext2_inode inode;
154 ext2_inode_scan scan;
155 char *block_buf;
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000156#ifdef RESOURCE_TRACK
Theodore Ts'o3839e651997-04-26 13:21:57 +0000157 struct resource_track rtrack;
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000158#endif
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000159 unsigned char frag, fsize;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000160 struct problem_context pctx;
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000161 struct scan_callback_struct scan_struct;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000162
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000163#ifdef RESOURCE_TRACK
Theodore Ts'o3839e651997-04-26 13:21:57 +0000164 init_resource_track(&rtrack);
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000165#endif
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000166 clear_problem_context(&pctx);
167
168 if (!(ctx->options & E2F_OPT_PREEN))
169 fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000170
171#ifdef MTRACE
172 mtrace_print("Pass 1");
173#endif
174
175 /*
176 * Allocate bitmaps structures
177 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000178 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, "in-use inode map",
179 &ctx->inode_used_map);
180 if (pctx.errcode) {
181 pctx.num = 1;
182 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000183 ctx->flags |= E2F_FLAG_ABORT;
184 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000185 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000186 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, "directory inode map",
187 &ctx->inode_dir_map);
188 if (pctx.errcode) {
189 pctx.num = 2;
190 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000191 ctx->flags |= E2F_FLAG_ABORT;
192 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000193 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000194 pctx.errcode = ext2fs_allocate_block_bitmap(fs, "in-use block map",
195 &ctx->block_found_map);
196 if (pctx.errcode) {
197 pctx.num = 1;
198 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000199 ctx->flags |= E2F_FLAG_ABORT;
200 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000201 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000202 pctx.errcode = ext2fs_allocate_block_bitmap(fs, "illegal block map",
203 &ctx->block_illegal_map);
204 if (pctx.errcode) {
205 pctx.num = 2;
206 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000207 ctx->flags |= E2F_FLAG_ABORT;
208 return;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000209 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000210 pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0,
211 &ctx->inode_link_info);
212 if (pctx.errcode) {
213 fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000214 ctx->flags |= E2F_FLAG_ABORT;
215 return;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000216 }
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000217 inodes_to_process = (struct process_inode_block *)
218 e2fsck_allocate_memory(ctx,
219 (ctx->process_inode_size *
220 sizeof(struct process_inode_block)),
221 "array of inodes to process");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000222 process_inode_count = 0;
223
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000224 pctx.errcode = ext2fs_init_dblist(fs, 0);
225 if (pctx.errcode) {
226 fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000227 ctx->flags |= E2F_FLAG_ABORT;
228 return;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000229 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000230
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000231 mark_table_blocks(ctx);
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000232 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
233 "block interate buffer");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000234 fs->get_blocks = pass1_get_blocks;
235 fs->check_directory = pass1_check_directory;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000236 fs->read_inode = pass1_read_inode;
237 fs->write_inode = pass1_write_inode;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000238 ehandler_operation("doing inode scan");
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000239 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
240 &scan);
241 if (pctx.errcode) {
242 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000243 ctx->flags |= E2F_FLAG_ABORT;
244 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000245 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000246 ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000247 pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
248 if (pctx.errcode) {
249 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000250 ctx->flags |= E2F_FLAG_ABORT;
251 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000252 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000253 ctx->stashed_inode = &inode;
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000254 scan_struct.ctx = ctx;
255 scan_struct.block_buf = block_buf;
256 ext2fs_set_inode_callback(scan, scan_callback, &scan_struct);
257 if (ctx->progress)
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000258 if ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count))
259 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000260 while (ino) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000261 pctx.ino = ino;
262 pctx.inode = &inode;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000263 ctx->stashed_ino = ino;
264 if (inode.i_links_count) {
265 pctx.errcode = ext2fs_icount_store(ctx->inode_link_info,
266 ino, inode.i_links_count);
267 if (pctx.errcode) {
268 pctx.num = inode.i_links_count;
269 fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000270 ctx->flags |= E2F_FLAG_ABORT;
271 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000272 }
273 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000274 if (ino == EXT2_BAD_INO) {
275 struct process_block_struct pb;
276
277 pb.ino = EXT2_BAD_INO;
278 pb.num_blocks = pb.last_block = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000279 pb.num_illegal_blocks = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000280 pb.suppress = 0; pb.clear = 0; pb.is_dir = 0;
Theodore Ts'o74becf31997-04-26 14:37:06 +0000281 pb.fragmented = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000282 pb.inode = &inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000283 pb.pctx = &pctx;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000284 pb.ctx = ctx;
285 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0,
286 block_buf, process_bad_block, &pb);
287 if (pctx.errcode) {
288 fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000289 ctx->flags |= E2F_FLAG_ABORT;
290 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000291 }
292 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000293 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000294 goto next;
295 }
296 if (ino == EXT2_ROOT_INO) {
297 /*
298 * Make sure the root inode is a directory; if
299 * not, offer to clear it. It will be
300 * regnerated in pass #3.
301 */
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000302 if (!LINUX_S_ISDIR(inode.i_mode)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000303 if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000304 inode.i_dtime = time(0);
305 inode.i_links_count = 0;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000306 ext2fs_icount_store(ctx->inode_link_info,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000307 ino, 0);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000308 e2fsck_write_inode(ctx, ino, &inode,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000309 "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000310 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000311 }
312 /*
313 * If dtime is set, offer to clear it. mke2fs
314 * version 0.2b created filesystems with the
315 * dtime field set for the root and lost+found
316 * directories. We won't worry about
317 * /lost+found, since that can be regenerated
318 * easily. But we will fix the root directory
319 * as a special case.
320 */
321 if (inode.i_dtime && inode.i_links_count) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000322 if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000323 inode.i_dtime = 0;
Theodore Ts'o08b21301997-11-03 19:42:40 +0000324 e2fsck_write_inode(ctx, ino, &inode,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000325 "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000326 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000327 }
328 }
Theodore Ts'o5c576471997-04-29 15:29:49 +0000329 if (ino == EXT2_BOOT_LOADER_INO) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000330 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
331 check_blocks(ctx, &pctx, block_buf);
Theodore Ts'o5c576471997-04-29 15:29:49 +0000332 goto next;
333 }
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000334 if ((ino != EXT2_ROOT_INO) &&
335 (ino < EXT2_FIRST_INODE(fs->super))) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000336 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000337 if (inode.i_mode != 0) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000338 if (fix_problem(ctx,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000339 PR_1_RESERVED_BAD_MODE, &pctx)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000340 inode.i_mode = 0;
Theodore Ts'o08b21301997-11-03 19:42:40 +0000341 e2fsck_write_inode(ctx, ino, &inode,
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000342 "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000343 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000344 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000345 check_blocks(ctx, &pctx, block_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000346 goto next;
347 }
348 /*
349 * This code assumes that deleted inodes have
350 * i_links_count set to 0.
351 */
352 if (!inode.i_links_count) {
353 if (!inode.i_dtime && inode.i_mode) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000354 if (fix_problem(ctx,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000355 PR_1_ZERO_DTIME, &pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000356 inode.i_dtime = time(0);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000357 e2fsck_write_inode(ctx, ino, &inode,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000358 "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000359 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000360 }
361 goto next;
362 }
363 /*
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000364 * n.b. 0.3c ext2fs code didn't clear i_links_count for
Theodore Ts'o3839e651997-04-26 13:21:57 +0000365 * deleted files. Oops.
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000366 *
367 * Since all new ext2 implementations get this right,
368 * we now assume that the case of non-zero
369 * i_links_count and non-zero dtime means that we
370 * should keep the file, not delete it.
Theodore Ts'o3839e651997-04-26 13:21:57 +0000371 *
Theodore Ts'o3839e651997-04-26 13:21:57 +0000372 */
373 if (inode.i_dtime) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000374 if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000375 inode.i_dtime = 0;
Theodore Ts'o08b21301997-11-03 19:42:40 +0000376 e2fsck_write_inode(ctx, ino, &inode, "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000377 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000378 }
379
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000380 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000381 switch (fs->super->s_creator_os) {
382 case EXT2_OS_LINUX:
383 frag = inode.osd2.linux2.l_i_frag;
384 fsize = inode.osd2.linux2.l_i_fsize;
385 break;
386 case EXT2_OS_HURD:
387 frag = inode.osd2.hurd2.h_i_frag;
388 fsize = inode.osd2.hurd2.h_i_fsize;
389 break;
390 case EXT2_OS_MASIX:
391 frag = inode.osd2.masix2.m_i_frag;
392 fsize = inode.osd2.masix2.m_i_fsize;
393 break;
394 default:
395 frag = fsize = 0;
396 }
397
398 if (inode.i_faddr || frag || fsize
Theodore Ts'o246501c1998-03-24 16:22:38 +0000399 || inode.i_file_acl ||
400 (LINUX_S_ISDIR(inode.i_mode) && inode.i_dir_acl)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000401 if (!ctx->inode_bad_map)
402 alloc_bad_map(ctx);
403 ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000404 }
405
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000406 if (LINUX_S_ISDIR(inode.i_mode)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000407 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000408 e2fsck_add_dir_info(ctx, ino, 0);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000409 ctx->fs_directory_count++;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000410 } else if (LINUX_S_ISREG (inode.i_mode))
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000411 ctx->fs_regular_count++;
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000412 else if (LINUX_S_ISCHR (inode.i_mode) &&
413 e2fsck_pass1_check_device_inode(&inode))
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000414 ctx->fs_chardev_count++;
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000415 else if (LINUX_S_ISBLK (inode.i_mode) &&
416 e2fsck_pass1_check_device_inode(&inode))
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000417 ctx->fs_blockdev_count++;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000418 else if (LINUX_S_ISLNK (inode.i_mode)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000419 ctx->fs_symlinks_count++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000420 if (!inode.i_blocks) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000421 ctx->fs_fast_symlinks_count++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000422 goto next;
423 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000424 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000425 else if (LINUX_S_ISFIFO (inode.i_mode))
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000426 ctx->fs_fifo_count++;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000427 else if (LINUX_S_ISSOCK (inode.i_mode))
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000428 ctx->fs_sockets_count++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000429 else {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000430 if (!ctx->inode_bad_map)
431 alloc_bad_map(ctx);
432 ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000433 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000434 if (inode.i_block[EXT2_IND_BLOCK])
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000435 ctx->fs_ind_count++;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000436 if (inode.i_block[EXT2_DIND_BLOCK])
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000437 ctx->fs_dind_count++;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000438 if (inode.i_block[EXT2_TIND_BLOCK])
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000439 ctx->fs_tind_count++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000440 if (inode.i_block[EXT2_IND_BLOCK] ||
441 inode.i_block[EXT2_DIND_BLOCK] ||
442 inode.i_block[EXT2_TIND_BLOCK]) {
443 inodes_to_process[process_inode_count].ino = ino;
444 inodes_to_process[process_inode_count].inode = inode;
445 process_inode_count++;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000446 } else
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000447 check_blocks(ctx, &pctx, block_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000448
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000449 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +0000450 return;
451
452 if (process_inode_count >= ctx->process_inode_size) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000453 process_inodes(ctx, block_buf);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000454
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000455 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +0000456 return;
457 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000458 next:
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000459 pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
Theodore Ts'o2df1f6a1998-02-27 05:03:48 +0000460 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
461 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000462 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
463 if (!ctx->inode_bb_map)
464 alloc_bb_map(ctx);
465 ext2fs_mark_inode_bitmap(ctx->inode_bb_map, ino);
466 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000467 goto next;
468 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000469 if (pctx.errcode) {
470 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000471 ctx->flags |= E2F_FLAG_ABORT;
472 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000473 }
474 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000475 process_inodes(ctx, block_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000476 ext2fs_close_inode_scan(scan);
477 ehandler_operation(0);
478
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000479 if (ctx->invalid_bitmaps)
480 handle_fs_bad_blocks(ctx);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000481
Theodore Ts'o08b21301997-11-03 19:42:40 +0000482 if (ctx->flags & E2F_FLAG_RESTART) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000483 unwind_pass1(fs);
484 goto endit;
485 }
486
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000487 if (ctx->block_dup_map) {
488 if (ctx->options & E2F_OPT_PREEN) {
489 clear_problem_context(&pctx);
490 fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000491 }
Theodore Ts'o08b21301997-11-03 19:42:40 +0000492 e2fsck_pass1_dupblocks(ctx, block_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000493 }
Theodore Ts'o08b21301997-11-03 19:42:40 +0000494 ext2fs_free_mem((void **) &inodes_to_process);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000495endit:
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000496 fs->get_blocks = 0;
497 fs->check_directory = 0;
498 fs->read_inode = 0;
499 fs->write_inode = 0;
500
Theodore Ts'o08b21301997-11-03 19:42:40 +0000501 ext2fs_free_mem((void **) &block_buf);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000502 ext2fs_free_block_bitmap(ctx->block_illegal_map);
503 ctx->block_illegal_map = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000504
Theodore Ts'o246501c1998-03-24 16:22:38 +0000505 if (ctx->large_files &&
506 !(fs->super->s_feature_ro_compat &
507 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
508 if (fix_problem(ctx, PR_1_FEATURE_LARGE_FILES, &pctx)) {
509 fs->super->s_feature_ro_compat |=
510 EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
511 ext2fs_mark_super_dirty(fs);
512 }
513 } else if (!ctx->large_files &&
514 (fs->super->s_feature_ro_compat &
515 EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
516 if (fs->flags & EXT2_FLAG_RW) {
517 fs->super->s_feature_ro_compat &=
518 ~EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
519 ext2fs_mark_super_dirty(fs);
520 }
521 }
522
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000523#ifdef RESOURCE_TRACK
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000524 if (ctx->options & E2F_OPT_TIME2)
525 print_resource_track("Pass 1", &rtrack);
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000526#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000527}
528
529/*
Theodore Ts'of3db3561997-04-26 13:34:30 +0000530 * When the inode_scan routines call this callback at the end of the
531 * glock group, call process_inodes.
532 */
533static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan,
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000534 dgrp_t group, void * priv_data)
Theodore Ts'of3db3561997-04-26 13:34:30 +0000535{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000536 struct scan_callback_struct *scan_struct;
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000537 e2fsck_t ctx;
538
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000539 scan_struct = (struct scan_callback_struct *) priv_data;
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000540 ctx = scan_struct->ctx;
541
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000542 process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf);
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000543
544 if (ctx->progress)
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000545 if ((ctx->progress)(ctx, 1, group+1,
546 ctx->fs->group_desc_count))
547 return EXT2_ET_CANCEL_REQUESTED;
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000548
Theodore Ts'of3db3561997-04-26 13:34:30 +0000549 return 0;
550}
551
552/*
Theodore Ts'o3839e651997-04-26 13:21:57 +0000553 * Process the inodes in the "inodes to process" list.
554 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000555static void process_inodes(e2fsck_t ctx, char *block_buf)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000556{
557 int i;
558 struct ext2_inode *old_stashed_inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000559 ino_t old_stashed_ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000560 const char *old_operation;
561 char buf[80];
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000562 struct problem_context pctx;
563
Theodore Ts'o3839e651997-04-26 13:21:57 +0000564#if 0
Theodore Ts'of3db3561997-04-26 13:34:30 +0000565 printf("begin process_inodes: ");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000566#endif
567 old_operation = ehandler_operation(0);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000568 old_stashed_inode = ctx->stashed_inode;
569 old_stashed_ino = ctx->stashed_ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000570 qsort(inodes_to_process, process_inode_count,
571 sizeof(struct process_inode_block), process_inode_cmp);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000572 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000573 for (i=0; i < process_inode_count; i++) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000574 pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode;
575 pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000576
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000577#if 0
578 printf("%u ", pctx.ino);
579#endif
580 sprintf(buf, "reading indirect blocks of inode %lu", pctx.ino);
581 ehandler_operation(buf);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000582 check_blocks(ctx, &pctx, block_buf);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000583 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o2df1f6a1998-02-27 05:03:48 +0000584 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000585 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000586 ctx->stashed_inode = old_stashed_inode;
587 ctx->stashed_ino = old_stashed_ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000588 process_inode_count = 0;
589#if 0
Theodore Ts'of3db3561997-04-26 13:34:30 +0000590 printf("end process inodes\n");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000591#endif
592 ehandler_operation(old_operation);
593}
594
595static int process_inode_cmp(const void *a, const void *b)
596{
597 const struct process_inode_block *ib_a =
598 (const struct process_inode_block *) a;
599 const struct process_inode_block *ib_b =
600 (const struct process_inode_block *) b;
601
602 return (ib_a->inode.i_block[EXT2_IND_BLOCK] -
603 ib_b->inode.i_block[EXT2_IND_BLOCK]);
604}
605
Theodore Ts'o3839e651997-04-26 13:21:57 +0000606/*
607 * This procedure will allocate the inode bad map table
608 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000609static void alloc_bad_map(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000610{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000611 struct problem_context pctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000612
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000613 clear_problem_context(&pctx);
614
615 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs, "bad inode map",
616 &ctx->inode_bad_map);
617 if (pctx.errcode) {
618 pctx.num = 3;
619 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000620 /* Should never get here */
621 ctx->flags |= E2F_FLAG_ABORT;
622 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000623 }
624}
625
626/*
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000627 * This procedure will allocate the inode "bb" (badblock) map table
628 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000629static void alloc_bb_map(e2fsck_t ctx)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000630{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000631 struct problem_context pctx;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000632
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000633 clear_problem_context(&pctx);
634 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
635 "inode in bad block map",
636 &ctx->inode_bb_map);
637 if (pctx.errcode) {
638 pctx.num = 4;
639 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000640 /* Should never get here */
641 ctx->flags |= E2F_FLAG_ABORT;
642 return;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000643 }
644}
645
646/*
Theodore Ts'o3839e651997-04-26 13:21:57 +0000647 * Marks a block as in use, setting the dup_map if it's been set
648 * already. Called by process_block and process_bad_block.
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000649 *
650 * WARNING: Assumes checks have already been done to make sure block
651 * is valid. This is true in both process_block and process_bad_block.
Theodore Ts'o3839e651997-04-26 13:21:57 +0000652 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000653static _INLINE_ void mark_block_used(e2fsck_t ctx, blk_t block)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000654{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000655 struct problem_context pctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000656
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000657 clear_problem_context(&pctx);
658
659 if (ext2fs_fast_test_block_bitmap(ctx->block_found_map, block)) {
660 if (!ctx->block_dup_map) {
661 pctx.errcode = ext2fs_allocate_block_bitmap(ctx->fs,
662 "multiply claimed block map",
663 &ctx->block_dup_map);
664 if (pctx.errcode) {
665 pctx.num = 3;
666 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR,
667 &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000668 /* Should never get here */
669 ctx->flags |= E2F_FLAG_ABORT;
670 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000671 }
672 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000673 ext2fs_fast_mark_block_bitmap(ctx->block_dup_map, block);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000674 } else {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000675 ext2fs_fast_mark_block_bitmap(ctx->block_found_map, block);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000676 }
677}
678
679/*
680 * This subroutine is called on each inode to account for all of the
681 * blocks used by that inode.
682 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000683static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000684 char *block_buf)
685{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000686 ext2_filsys fs = ctx->fs;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000687 struct process_block_struct pb;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000688 ino_t ino = pctx->ino;
689 struct ext2_inode *inode = pctx->inode;
Theodore Ts'o246501c1998-03-24 16:22:38 +0000690 int bad_size = 0;
691 __u64 size;
692 struct ext2fs_sb *sb;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000693
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000694 if (!ext2fs_inode_has_valid_blocks(pctx->inode))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000695 return;
696
697 pb.ino = ino;
698 pb.num_blocks = pb.last_block = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000699 pb.num_illegal_blocks = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000700 pb.suppress = 0; pb.clear = 0;
Theodore Ts'o74becf31997-04-26 14:37:06 +0000701 pb.fragmented = 0;
702 pb.previous_block = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000703 pb.is_dir = LINUX_S_ISDIR(pctx->inode->i_mode);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000704 pb.inode = inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000705 pb.pctx = pctx;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000706 pb.ctx = ctx;
707 pctx->ino = ino;
708 pctx->errcode = ext2fs_block_iterate2(fs, ino,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000709 pb.is_dir ? BLOCK_FLAG_HOLE : 0,
710 block_buf, process_block, &pb);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000711 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +0000712 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000713 end_problem_latch(ctx, PR_LATCH_BLOCK);
714 if (pctx->errcode)
715 fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000716
Theodore Ts'o74becf31997-04-26 14:37:06 +0000717 if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group)
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000718 ctx->fs_fragmented++;
Theodore Ts'o74becf31997-04-26 14:37:06 +0000719
Theodore Ts'of3db3561997-04-26 13:34:30 +0000720 if (pb.clear) {
Theodore Ts'o08b21301997-11-03 19:42:40 +0000721 e2fsck_read_inode(ctx, ino, inode, "check_blocks");
Theodore Ts'of3db3561997-04-26 13:34:30 +0000722 inode->i_links_count = 0;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000723 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000724 inode->i_dtime = time(0);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000725 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000726 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
727 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000728 /*
729 * The inode was probably partially accounted for
730 * before processing was aborted, so we need to
731 * restart the pass 1 scan.
732 */
Theodore Ts'o08b21301997-11-03 19:42:40 +0000733 ctx->flags |= E2F_FLAG_RESTART;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000734 return;
735 }
736
Theodore Ts'o3839e651997-04-26 13:21:57 +0000737 pb.num_blocks *= (fs->blocksize / 512);
738#if 0
Theodore Ts'o246501c1998-03-24 16:22:38 +0000739 printf("inode %u, i_size = %lu, last_block = %lld, i_blocks=%lu, num_blocks = %lu\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000740 ino, inode->i_size, pb.last_block, inode->i_blocks,
741 pb.num_blocks);
742#endif
743 if (!pb.num_blocks && pb.is_dir) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000744 if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000745 inode->i_links_count = 0;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000746 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000747 inode->i_dtime = time(0);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000748 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000749 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
750 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
751 ctx->fs_directory_count--;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000752 pb.is_dir = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000753 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000754 }
Theodore Ts'o246501c1998-03-24 16:22:38 +0000755 if (pb.is_dir) {
756 int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super);
757 if ((nblock > (pb.last_block + 1)) ||
758 ((inode->i_size & (fs->blocksize-1)) != 0))
759 bad_size = 1;
760 else if (nblock < (pb.last_block + 1)) {
761 sb = (struct ext2fs_sb *) fs->super;
762 if (((pb.last_block + 1) - nblock) >
763 sb->s_prealloc_dir_blocks)
764 bad_size = 1;
765 }
766 } else {
767 size = inode->i_size + ((__u64) inode->i_size_high << 32);
768 if ((size < pb.last_block * fs->blocksize))
769 bad_size = 1;
770 else if (size > ext2_max_sizes[fs->super->s_log_block_size])
771 bad_size = 1;
772 }
773 if (bad_size) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000774 pctx->num = (pb.last_block+1) * fs->blocksize;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000775 if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000776 inode->i_size = pctx->num;
Theodore Ts'o246501c1998-03-24 16:22:38 +0000777 if (!pb.is_dir)
778 inode->i_size_high = pctx->num >> 32;
Theodore Ts'o08b21301997-11-03 19:42:40 +0000779 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000780 }
781 pctx->num = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000782 }
Theodore Ts'o246501c1998-03-24 16:22:38 +0000783 if (!pb.is_dir && inode->i_size_high)
784 ctx->large_files++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000785 if (pb.num_blocks != inode->i_blocks) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000786 pctx->num = pb.num_blocks;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000787 if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000788 inode->i_blocks = pb.num_blocks;
Theodore Ts'o08b21301997-11-03 19:42:40 +0000789 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000790 }
791 pctx->num = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000792 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000793}
794
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000795#if 0
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000796/*
797 * Helper function called by process block when an illegal block is
798 * found. It returns a description about why the block is illegal
799 */
800static char *describe_illegal_block(ext2_filsys fs, blk_t block)
801{
802 blk_t super;
803 int i;
804 static char problem[80];
805
806 super = fs->super->s_first_data_block;
807 strcpy(problem, "PROGRAMMING ERROR: Unknown reason for illegal block");
808 if (block < super) {
809 sprintf(problem, "< FIRSTBLOCK (%u)", super);
810 return(problem);
811 } else if (block >= fs->super->s_blocks_count) {
812 sprintf(problem, "> BLOCKS (%u)", fs->super->s_blocks_count);
813 return(problem);
814 }
815 for (i = 0; i < fs->group_desc_count; i++) {
816 if (block == super) {
817 sprintf(problem, "is the superblock in group %d", i);
818 break;
819 }
820 if (block > super &&
821 block <= (super + fs->desc_blocks)) {
822 sprintf(problem, "is in the group descriptors "
823 "of group %d", i);
824 break;
825 }
826 if (block == fs->group_desc[i].bg_block_bitmap) {
827 sprintf(problem, "is the block bitmap of group %d", i);
828 break;
829 }
830 if (block == fs->group_desc[i].bg_inode_bitmap) {
831 sprintf(problem, "is the inode bitmap of group %d", i);
832 break;
833 }
834 if (block >= fs->group_desc[i].bg_inode_table &&
835 (block < fs->group_desc[i].bg_inode_table
836 + fs->inode_blocks_per_group)) {
837 sprintf(problem, "is in the inode table of group %d",
838 i);
839 break;
840 }
841 super += fs->super->s_blocks_per_group;
842 }
843 return(problem);
844}
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000845#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000846
847/*
848 * This is a helper function for check_blocks().
849 */
850int process_block(ext2_filsys fs,
851 blk_t *block_nr,
Theodore Ts'o246501c1998-03-24 16:22:38 +0000852 blkcnt_t blockcnt,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000853 blk_t ref_block,
854 int ref_offset,
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000855 void *priv_data)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000856{
857 struct process_block_struct *p;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000858 struct problem_context *pctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000859 blk_t blk = *block_nr;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000860 int ret_code = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000861 int problem = 0;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000862 e2fsck_t ctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000863
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000864 p = (struct process_block_struct *) priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000865 pctx = p->pctx;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000866 ctx = p->ctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000867
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000868 if (blk == 0) {
869 if (p->is_dir == 0) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000870 /*
871 * Should never happen, since only directories
872 * get called with BLOCK_FLAG_HOLE
873 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000874#if DEBUG_E2FSCK
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000875 printf("process_block() called with blk == 0, "
Theodore Ts'o5c576471997-04-29 15:29:49 +0000876 "blockcnt=%d, inode %lu???\n",
877 blockcnt, p->ino);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000878#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000879 return 0;
880 }
881 if (blockcnt < 0)
882 return 0;
883 if (blockcnt * fs->blocksize < p->inode->i_size) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000884#if 0
885 printf("Missing block (#%d) in directory inode %lu!\n",
886 blockcnt, p->ino);
887#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000888 goto mark_dir;
889 }
890 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000891 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000892
893#if 0
894 printf("Process_block, inode %lu, block %u, #%d\n", p->ino, blk,
895 blockcnt);
896#endif
897
Theodore Ts'o74becf31997-04-26 14:37:06 +0000898 /*
899 * Simplistic fragmentation check. We merely require that the
900 * file be contiguous. (Which can never be true for really
901 * big files that are greater than a block group.)
902 */
903 if (p->previous_block) {
904 if (p->previous_block+1 != blk)
905 p->fragmented = 1;
906 }
907 p->previous_block = blk;
908
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000909 if (blk < fs->super->s_first_data_block ||
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000910 blk >= fs->super->s_blocks_count)
911 problem = PR_1_ILLEGAL_BLOCK_NUM;
Theodore Ts'o521e3681997-04-29 17:48:10 +0000912#if 0
913 else
914 if (ext2fs_test_block_bitmap(block_illegal_map, blk))
915 problem = PR_1_BLOCK_OVERLAPS_METADATA;
916#endif
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000917
918 if (problem) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000919 p->num_illegal_blocks++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000920 if (!p->suppress && (p->num_illegal_blocks % 12) == 0) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000921 if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000922 p->clear = 1;
923 return BLOCK_ABORT;
924 }
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000925 if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000926 p->suppress = 1;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000927 set_latch_flags(PR_LATCH_BLOCK,
928 PRL_SUPPRESS, 0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000929 }
930 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000931 pctx->blk = blk;
932 pctx->blkcount = blockcnt;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000933 if (fix_problem(ctx, problem, pctx)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000934 blk = *block_nr = 0;
935 ret_code = BLOCK_CHANGED;
936 goto mark_dir;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000937 } else
Theodore Ts'o3839e651997-04-26 13:21:57 +0000938 return 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000939 pctx->blk = 0;
940 pctx->blkcount = -1;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000941 }
942
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000943 mark_block_used(ctx, blk);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000944 p->num_blocks++;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000945 if (blockcnt >= 0)
946 p->last_block = blockcnt;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000947mark_dir:
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000948 if (p->is_dir && (blockcnt >= 0)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000949 pctx->errcode = ext2fs_add_dir_block(fs->dblist, p->ino,
950 blk, blockcnt);
951 if (pctx->errcode) {
952 pctx->blk = blk;
953 pctx->num = blockcnt;
954 fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000955 /* Should never get here */
956 ctx->flags |= E2F_FLAG_ABORT;
957 return BLOCK_ABORT;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000958 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000959 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000960 return ret_code;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000961}
962
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000963static void bad_block_indirect(e2fsck_t ctx, blk_t blk)
Theodore Ts'of3db3561997-04-26 13:34:30 +0000964{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000965 struct problem_context pctx;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000966
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000967 clear_problem_context(&pctx);
968 /*
969 * Prompt to see if we should continue or not.
970 */
971 if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, &pctx))
Theodore Ts'o08b21301997-11-03 19:42:40 +0000972 ctx->flags |= E2F_FLAG_ABORT;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000973}
974
Theodore Ts'o3839e651997-04-26 13:21:57 +0000975int process_bad_block(ext2_filsys fs,
976 blk_t *block_nr,
Theodore Ts'o246501c1998-03-24 16:22:38 +0000977 blkcnt_t blockcnt,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000978 blk_t ref_block,
979 int ref_offset,
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000980 void *priv_data)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000981{
982 struct process_block_struct *p;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000983 blk_t blk = *block_nr;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000984 int first_block;
985 int i;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000986 struct problem_context *pctx;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000987 e2fsck_t ctx;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000988
Theodore Ts'o3839e651997-04-26 13:21:57 +0000989 if (!blk)
990 return 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000991
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000992 p = (struct process_block_struct *) priv_data;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000993 ctx = p->ctx;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000994 pctx = p->pctx;
995
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000996 pctx->ino = EXT2_BAD_INO;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000997 pctx->blk = blk;
998 pctx->blkcount = blockcnt;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000999
1000 if ((blk < fs->super->s_first_data_block) ||
1001 (blk >= fs->super->s_blocks_count)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001002 if (fix_problem(ctx, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +00001003 *block_nr = 0;
1004 return BLOCK_CHANGED;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001005 } else
Theodore Ts'o3839e651997-04-26 13:21:57 +00001006 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001007 }
1008
1009 if (blockcnt < 0) {
Theodore Ts'o08b21301997-11-03 19:42:40 +00001010 if (ext2fs_test_block_bitmap(ctx->block_found_map, blk)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001011 bad_block_indirect(ctx, blk);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +00001012 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +00001013 return BLOCK_ABORT;
1014 } else
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001015 mark_block_used(ctx, blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001016 return 0;
1017 }
1018#if 0
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001019 printf ("DEBUG: Marking %u as bad.\n", blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001020#endif
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001021 ctx->fs_badblocks_count++;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001022 /*
1023 * If the block is not used, then mark it as used and return.
1024 * If it is already marked as found, this must mean that
1025 * there's an overlap between the filesystem table blocks
1026 * (bitmaps and inode table) and the bad block list.
1027 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001028 if (!ext2fs_test_block_bitmap(ctx->block_found_map, blk)) {
1029 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001030 return 0;
1031 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001032 /*
1033 * Try to find the where the filesystem block was used...
1034 */
1035 first_block = fs->super->s_first_data_block;
1036
1037 for (i = 0; i < fs->group_desc_count; i++ ) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001038 pctx->group = i;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001039 pctx->blk = blk;
Theodore Ts'o8039c481997-11-19 21:39:13 +00001040 if (!ext2fs_bg_has_super(fs, i))
1041 goto skip_super;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001042 if (blk == first_block) {
1043 if (i == 0) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001044 if (fix_problem(ctx,
1045 PR_1_BAD_PRIMARY_SUPERBLOCK,
1046 pctx)) {
1047 *block_nr = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001048 return BLOCK_CHANGED;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001049 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001050 return 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001051 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001052 fix_problem(ctx, PR_1_BAD_SUPERBLOCK, pctx);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001053 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001054 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001055 if ((blk > first_block) &&
1056 (blk <= first_block + fs->desc_blocks)) {
1057 if (i == 0) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001058 pctx->blk = *block_nr;
1059 if (fix_problem(ctx,
1060 PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR, pctx)) {
1061 *block_nr = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001062 return BLOCK_CHANGED;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001063 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001064 return 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001065 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001066 fix_problem(ctx, PR_1_BAD_GROUP_DESCRIPTORS, pctx);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001067 return 0;
1068 }
Theodore Ts'o8039c481997-11-19 21:39:13 +00001069 skip_super:
Theodore Ts'of3db3561997-04-26 13:34:30 +00001070 if (blk == fs->group_desc[i].bg_block_bitmap) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001071 if (fix_problem(ctx, PR_1_BB_BAD_BLOCK, pctx)) {
1072 ctx->invalid_block_bitmap_flag[i]++;
1073 ctx->invalid_bitmaps++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001074 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001075 return 0;
1076 }
1077 if (blk == fs->group_desc[i].bg_inode_bitmap) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001078 if (fix_problem(ctx, PR_1_IB_BAD_BLOCK, pctx)) {
1079 ctx->invalid_inode_bitmap_flag[i]++;
1080 ctx->invalid_bitmaps++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001081 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001082 return 0;
1083 }
1084 if ((blk >= fs->group_desc[i].bg_inode_table) &&
1085 (blk < (fs->group_desc[i].bg_inode_table +
1086 fs->inode_blocks_per_group))) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001087 /*
1088 * If there are bad blocks in the inode table,
1089 * the inode scan code will try to do
1090 * something reasonable automatically.
1091 */
Theodore Ts'of3db3561997-04-26 13:34:30 +00001092 return 0;
1093 }
Theodore Ts'o8039c481997-11-19 21:39:13 +00001094 first_block += fs->super->s_blocks_per_group;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001095 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001096 /*
1097 * If we've gotten to this point, then the only
1098 * possibility is that the bad block inode meta data
1099 * is using a bad block.
1100 */
1101 if ((blk == p->inode->i_block[EXT2_IND_BLOCK]) ||
1102 p->inode->i_block[EXT2_DIND_BLOCK]) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001103 bad_block_indirect(ctx, blk);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +00001104 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +00001105 return BLOCK_ABORT;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001106 return 0;
1107 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001108
1109 pctx->group = -1;
1110
1111 /* Warn user that the block wasn't claimed */
1112 fix_problem(ctx, PR_1_PROGERR_CLAIMED_BLOCK, pctx);
1113
Theodore Ts'o3839e651997-04-26 13:21:57 +00001114 return 0;
1115}
1116
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001117static void new_table_block(e2fsck_t ctx, blk_t first_block, int group,
Theodore Ts'o3839e651997-04-26 13:21:57 +00001118 const char *name, int num, blk_t *new_block)
1119{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001120 ext2_filsys fs = ctx->fs;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001121 blk_t old_block = *new_block;
1122 int i;
1123 char *buf;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001124 struct problem_context pctx;
1125
1126 clear_problem_context(&pctx);
1127
1128 pctx.group = group;
1129 pctx.blk = old_block;
1130 pctx.str = name;
1131
1132 pctx.errcode = ext2fs_get_free_blocks(fs, first_block,
Theodore Ts'o3839e651997-04-26 13:21:57 +00001133 first_block + fs->super->s_blocks_per_group,
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001134 num, ctx->block_found_map, new_block);
1135 if (pctx.errcode) {
1136 pctx.num = num;
1137 fix_problem(ctx, PR_1_RELOC_BLOCK_ALLOCATE, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001138 ext2fs_unmark_valid(fs);
1139 return;
1140 }
Theodore Ts'o08b21301997-11-03 19:42:40 +00001141 pctx.errcode = ext2fs_get_mem(fs->blocksize, (void **) &buf);
1142 if (pctx.errcode) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001143 fix_problem(ctx, PR_1_RELOC_MEMORY_ALLOCATE, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001144 ext2fs_unmark_valid(fs);
1145 return;
1146 }
1147 ext2fs_mark_super_dirty(fs);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001148 pctx.blk2 = *new_block;
1149 fix_problem(ctx, (old_block ? PR_1_RELOC_FROM_TO :
1150 PR_1_RELOC_TO), &pctx);
1151 pctx.blk2 = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001152 for (i = 0; i < num; i++) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001153 pctx.blk = i;
1154 ext2fs_mark_block_bitmap(ctx->block_found_map, (*new_block)+i);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001155 if (old_block) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001156 pctx.errcode = io_channel_read_blk(fs->io,
1157 old_block + i, 1, buf);
1158 if (pctx.errcode)
1159 fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001160 } else
1161 memset(buf, 0, fs->blocksize);
1162
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001163 pctx.blk = (*new_block) + i;
1164 pctx.errcode = io_channel_write_blk(fs->io, pctx.blk,
Theodore Ts'o3839e651997-04-26 13:21:57 +00001165 1, buf);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001166 if (pctx.errcode)
1167 fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001168 }
Theodore Ts'o08b21301997-11-03 19:42:40 +00001169 ext2fs_free_mem((void **) &buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001170}
1171
1172/*
Theodore Ts'of3db3561997-04-26 13:34:30 +00001173 * This routine gets called at the end of pass 1 if bad blocks are
1174 * detected in the superblock, group descriptors, inode_bitmaps, or
1175 * block bitmaps. At this point, all of the blocks have been mapped
1176 * out, so we can try to allocate new block(s) to replace the bad
1177 * blocks.
Theodore Ts'o3839e651997-04-26 13:21:57 +00001178 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001179static void handle_fs_bad_blocks(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001180{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001181 ext2_filsys fs = ctx->fs;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001182 int i;
1183 int first_block = fs->super->s_first_data_block;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001184
1185 for (i = 0; i < fs->group_desc_count; i++) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001186 if (ctx->invalid_block_bitmap_flag[i]) {
1187 new_table_block(ctx, first_block, i, "block bitmap",
1188 1, &fs->group_desc[i].bg_block_bitmap);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001189 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001190 if (ctx->invalid_inode_bitmap_flag[i]) {
1191 new_table_block(ctx, first_block, i, "inode bitmap",
1192 1, &fs->group_desc[i].bg_inode_bitmap);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001193 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001194 if (ctx->invalid_inode_table_flag[i]) {
1195 new_table_block(ctx, first_block, i, "inode table",
Theodore Ts'of3db3561997-04-26 13:34:30 +00001196 fs->inode_blocks_per_group,
Theodore Ts'o3839e651997-04-26 13:21:57 +00001197 &fs->group_desc[i].bg_inode_table);
Theodore Ts'o08b21301997-11-03 19:42:40 +00001198 ctx->flags |= E2F_FLAG_RESTART;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001199 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001200 first_block += fs->super->s_blocks_per_group;
1201 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001202 ctx->invalid_bitmaps = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001203}
1204
1205/*
1206 * This routine marks all blocks which are used by the superblock,
1207 * group descriptors, inode bitmaps, and block bitmaps.
1208 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001209static void mark_table_blocks(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001210{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001211 ext2_filsys fs = ctx->fs;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001212 blk_t block, b;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001213 int i,j;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001214 struct problem_context pctx;
1215
1216 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001217
1218 block = fs->super->s_first_data_block;
1219 for (i = 0; i < fs->group_desc_count; i++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001220 pctx.group = i;
Theodore Ts'oda2e97f1997-06-12 04:28:07 +00001221
1222 if (ext2fs_bg_has_super(fs, i)) {
1223 /*
1224 * Mark this group's copy of the superblock
1225 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001226 ext2fs_mark_block_bitmap(ctx->block_found_map, block);
1227 ext2fs_mark_block_bitmap(ctx->block_illegal_map,
1228 block);
Theodore Ts'oda2e97f1997-06-12 04:28:07 +00001229
1230 /*
1231 * Mark this group's copy of the descriptors
1232 */
1233 for (j = 0; j < fs->desc_blocks; j++) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001234 ext2fs_mark_block_bitmap(ctx->block_found_map,
Theodore Ts'oda2e97f1997-06-12 04:28:07 +00001235 block + j + 1);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001236 ext2fs_mark_block_bitmap(ctx->block_illegal_map,
Theodore Ts'oda2e97f1997-06-12 04:28:07 +00001237 block + j + 1);
1238 }
1239 }
1240
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001241 /*
1242 * Mark the blocks used for the inode table
1243 */
1244 if (fs->group_desc[i].bg_inode_table) {
1245 for (j = 0, b = fs->group_desc[i].bg_inode_table;
1246 j < fs->inode_blocks_per_group;
1247 j++, b++) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001248 if (ext2fs_test_block_bitmap(ctx->block_found_map,
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001249 b)) {
1250 pctx.blk = b;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001251 if (fix_problem(ctx,
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001252 PR_1_ITABLE_CONFLICT, &pctx)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001253 ctx->invalid_inode_table_flag[i]++;
1254 ctx->invalid_bitmaps++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001255 }
1256 } else {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001257 ext2fs_mark_block_bitmap(ctx->block_found_map,
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001258 b);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001259 ext2fs_mark_block_bitmap(ctx->block_illegal_map,
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001260 b);
1261 }
1262 }
1263 }
1264
Theodore Ts'o3839e651997-04-26 13:21:57 +00001265 /*
1266 * Mark block used for the block bitmap
1267 */
Theodore Ts'of3db3561997-04-26 13:34:30 +00001268 if (fs->group_desc[i].bg_block_bitmap) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001269 if (ext2fs_test_block_bitmap(ctx->block_found_map,
Theodore Ts'of3db3561997-04-26 13:34:30 +00001270 fs->group_desc[i].bg_block_bitmap)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001271 pctx.blk = fs->group_desc[i].bg_block_bitmap;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001272 if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) {
1273 ctx->invalid_block_bitmap_flag[i]++;
1274 ctx->invalid_bitmaps++;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001275 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001276 } else {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001277 ext2fs_mark_block_bitmap(ctx->block_found_map,
Theodore Ts'of3db3561997-04-26 13:34:30 +00001278 fs->group_desc[i].bg_block_bitmap);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001279 ext2fs_mark_block_bitmap(ctx->block_illegal_map,
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001280 fs->group_desc[i].bg_block_bitmap);
1281 }
1282
Theodore Ts'of3db3561997-04-26 13:34:30 +00001283 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001284 /*
1285 * Mark block used for the inode bitmap
1286 */
Theodore Ts'of3db3561997-04-26 13:34:30 +00001287 if (fs->group_desc[i].bg_inode_bitmap) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001288 if (ext2fs_test_block_bitmap(ctx->block_found_map,
Theodore Ts'of3db3561997-04-26 13:34:30 +00001289 fs->group_desc[i].bg_inode_bitmap)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001290 pctx.blk = fs->group_desc[i].bg_inode_bitmap;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001291 if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) {
1292 ctx->invalid_inode_bitmap_flag[i]++;
1293 ctx->invalid_bitmaps++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001294 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001295 } else {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001296 ext2fs_mark_block_bitmap(ctx->block_found_map,
Theodore Ts'of3db3561997-04-26 13:34:30 +00001297 fs->group_desc[i].bg_inode_bitmap);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001298 ext2fs_mark_block_bitmap(ctx->block_illegal_map,
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001299 fs->group_desc[i].bg_inode_bitmap);
1300 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001301 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001302 block += fs->super->s_blocks_per_group;
1303 }
1304}
1305
1306/*
1307 * This subroutines short circuits ext2fs_get_blocks and
1308 * ext2fs_check_directory; we use them since we already have the inode
1309 * structure, so there's no point in letting the ext2fs library read
1310 * the inode again.
1311 */
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001312errcode_t pass1_get_blocks(ext2_filsys fs, ino_t ino, blk_t *blocks)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001313{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00001314 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001315 int i;
1316
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001317 if (ino != ctx->stashed_ino)
Theodore Ts'o521e3681997-04-29 17:48:10 +00001318 return EXT2_ET_CALLBACK_NOTHANDLED;
1319
1320 for (i=0; i < EXT2_N_BLOCKS; i++)
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001321 blocks[i] = ctx->stashed_inode->i_block[i];
Theodore Ts'o521e3681997-04-29 17:48:10 +00001322 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001323}
1324
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001325errcode_t pass1_read_inode(ext2_filsys fs, ino_t ino, struct ext2_inode *inode)
1326{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00001327 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001328
1329 if (ino != ctx->stashed_ino)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001330 return EXT2_ET_CALLBACK_NOTHANDLED;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001331 *inode = *ctx->stashed_inode;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001332 return 0;
1333}
1334
1335errcode_t pass1_write_inode(ext2_filsys fs, ino_t ino,
1336 struct ext2_inode *inode)
1337{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00001338 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001339
1340 if (ino == ctx->stashed_ino)
1341 *ctx->stashed_inode = *inode;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001342 return EXT2_ET_CALLBACK_NOTHANDLED;
1343}
1344
1345errcode_t pass1_check_directory(ext2_filsys fs, ino_t ino)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001346{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00001347 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001348
1349 if (ino != ctx->stashed_ino)
1350 return EXT2_ET_CALLBACK_NOTHANDLED;
1351
1352 if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode))
Theodore Ts'o291c9041997-10-31 06:17:08 +00001353 return EXT2_ET_NO_DIRECTORY;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001354 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001355}