blob: 4832f6973f79f9e498ba618368a8002e2e0818e4 [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'o21c84b71997-04-29 16:15:03 +000053 int 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'o21c84b71997-04-29 16:15:03 +000056 int 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 {
71 ino_t ino;
Theodore Ts'o74becf31997-04-26 14:37:06 +000072 int is_dir:1, clear:1, suppress:1, fragmented:1;
Theodore Ts'o3839e651997-04-26 13:21:57 +000073 int num_blocks;
74 int last_block;
Theodore Ts'of3db3561997-04-26 13:34:30 +000075 int num_illegal_blocks;
Theodore Ts'o74becf31997-04-26 14:37:06 +000076 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
98/*
Theodore Ts'of3db3561997-04-26 13:34:30 +000099 * Free all memory allocated by pass1 in preparation for restarting
100 * things.
101 */
102static void unwind_pass1(ext2_filsys fs)
103{
Theodore Ts'o08b21301997-11-03 19:42:40 +0000104 ext2fs_free_mem((void **) &inodes_to_process);
105 inodes_to_process = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000106}
107
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000108/*
109 * Check to make sure a device inode is real. Returns 1 if the device
110 * checks out, 0 if not.
111 */
112int e2fsck_pass1_check_device_inode(struct ext2_inode *inode)
113{
114 int i;
115
Theodore Ts'o7fdfabd1997-11-24 11:51:17 +0000116 /*
117 * We should be able to do the test below all the time, but
118 * because the kernel doesn't forcibly clear the device
119 * inode's additional i_block fields, there are some rare
120 * occasions when a legitimate device inode will have non-zero
121 * additional i_block fields. So for now, we only complain
122 * when the immutable flag is set, which should never happen
123 * for devices. (And that's when the problem is caused, since
124 * you can't set or clear immutable flags for devices.) Once
125 * the kernel has been fixed we can change this...
126 */
127 if (inode->i_flags & EXT2_IMMUTABLE_FL) {
128 for (i=4; i < EXT2_N_BLOCKS; i++)
129 if (inode->i_block[i])
130 return 0;
131 }
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000132 return 1;
133}
134
Theodore Ts'o08b21301997-11-03 19:42:40 +0000135void e2fsck_pass1(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000136{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000137 ext2_filsys fs = ctx->fs;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000138 ino_t ino;
139 struct ext2_inode inode;
140 ext2_inode_scan scan;
141 char *block_buf;
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000142#ifdef RESOURCE_TRACK
Theodore Ts'o3839e651997-04-26 13:21:57 +0000143 struct resource_track rtrack;
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000144#endif
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000145 unsigned char frag, fsize;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000146 struct problem_context pctx;
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000147 struct scan_callback_struct scan_struct;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000148
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000149#ifdef RESOURCE_TRACK
Theodore Ts'o3839e651997-04-26 13:21:57 +0000150 init_resource_track(&rtrack);
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000151#endif
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000152 clear_problem_context(&pctx);
153
154 if (!(ctx->options & E2F_OPT_PREEN))
155 fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000156
157#ifdef MTRACE
158 mtrace_print("Pass 1");
159#endif
160
161 /*
162 * Allocate bitmaps structures
163 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000164 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, "in-use inode map",
165 &ctx->inode_used_map);
166 if (pctx.errcode) {
167 pctx.num = 1;
168 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000169 ctx->flags |= E2F_FLAG_ABORT;
170 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000171 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000172 pctx.errcode = ext2fs_allocate_inode_bitmap(fs, "directory inode map",
173 &ctx->inode_dir_map);
174 if (pctx.errcode) {
175 pctx.num = 2;
176 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000177 ctx->flags |= E2F_FLAG_ABORT;
178 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000179 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000180 pctx.errcode = ext2fs_allocate_block_bitmap(fs, "in-use block map",
181 &ctx->block_found_map);
182 if (pctx.errcode) {
183 pctx.num = 1;
184 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000185 ctx->flags |= E2F_FLAG_ABORT;
186 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000187 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000188 pctx.errcode = ext2fs_allocate_block_bitmap(fs, "illegal block map",
189 &ctx->block_illegal_map);
190 if (pctx.errcode) {
191 pctx.num = 2;
192 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000193 ctx->flags |= E2F_FLAG_ABORT;
194 return;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000195 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000196 pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0,
197 &ctx->inode_link_info);
198 if (pctx.errcode) {
199 fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000200 ctx->flags |= E2F_FLAG_ABORT;
201 return;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000202 }
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000203 inodes_to_process = (struct process_inode_block *)
204 e2fsck_allocate_memory(ctx,
205 (ctx->process_inode_size *
206 sizeof(struct process_inode_block)),
207 "array of inodes to process");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000208 process_inode_count = 0;
209
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000210 pctx.errcode = ext2fs_init_dblist(fs, 0);
211 if (pctx.errcode) {
212 fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000213 ctx->flags |= E2F_FLAG_ABORT;
214 return;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000215 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000216
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000217 mark_table_blocks(ctx);
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000218 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
219 "block interate buffer");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000220 fs->get_blocks = pass1_get_blocks;
221 fs->check_directory = pass1_check_directory;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000222 fs->read_inode = pass1_read_inode;
223 fs->write_inode = pass1_write_inode;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000224 ehandler_operation("doing inode scan");
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000225 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
226 &scan);
227 if (pctx.errcode) {
228 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000229 ctx->flags |= E2F_FLAG_ABORT;
230 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000231 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000232 ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000233 pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
234 if (pctx.errcode) {
235 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000236 ctx->flags |= E2F_FLAG_ABORT;
237 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000238 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000239 ctx->stashed_inode = &inode;
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000240 scan_struct.ctx = ctx;
241 scan_struct.block_buf = block_buf;
242 ext2fs_set_inode_callback(scan, scan_callback, &scan_struct);
243 if (ctx->progress)
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000244 if ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count))
245 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000246 while (ino) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000247 pctx.ino = ino;
248 pctx.inode = &inode;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000249 ctx->stashed_ino = ino;
250 if (inode.i_links_count) {
251 pctx.errcode = ext2fs_icount_store(ctx->inode_link_info,
252 ino, inode.i_links_count);
253 if (pctx.errcode) {
254 pctx.num = inode.i_links_count;
255 fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000256 ctx->flags |= E2F_FLAG_ABORT;
257 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000258 }
259 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000260 if (ino == EXT2_BAD_INO) {
261 struct process_block_struct pb;
262
263 pb.ino = EXT2_BAD_INO;
264 pb.num_blocks = pb.last_block = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000265 pb.num_illegal_blocks = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000266 pb.suppress = 0; pb.clear = 0; pb.is_dir = 0;
Theodore Ts'o74becf31997-04-26 14:37:06 +0000267 pb.fragmented = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000268 pb.inode = &inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000269 pb.pctx = &pctx;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000270 pb.ctx = ctx;
271 pctx.errcode = ext2fs_block_iterate2(fs, ino, 0,
272 block_buf, process_bad_block, &pb);
273 if (pctx.errcode) {
274 fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000275 ctx->flags |= E2F_FLAG_ABORT;
276 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000277 }
278 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000279 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000280 goto next;
281 }
282 if (ino == EXT2_ROOT_INO) {
283 /*
284 * Make sure the root inode is a directory; if
285 * not, offer to clear it. It will be
286 * regnerated in pass #3.
287 */
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000288 if (!LINUX_S_ISDIR(inode.i_mode)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000289 if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000290 inode.i_dtime = time(0);
291 inode.i_links_count = 0;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000292 ext2fs_icount_store(ctx->inode_link_info,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000293 ino, 0);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000294 e2fsck_write_inode(ctx, ino, &inode,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000295 "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000296 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000297 }
298 /*
299 * If dtime is set, offer to clear it. mke2fs
300 * version 0.2b created filesystems with the
301 * dtime field set for the root and lost+found
302 * directories. We won't worry about
303 * /lost+found, since that can be regenerated
304 * easily. But we will fix the root directory
305 * as a special case.
306 */
307 if (inode.i_dtime && inode.i_links_count) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000308 if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000309 inode.i_dtime = 0;
Theodore Ts'o08b21301997-11-03 19:42:40 +0000310 e2fsck_write_inode(ctx, ino, &inode,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000311 "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000312 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000313 }
314 }
Theodore Ts'o5c576471997-04-29 15:29:49 +0000315 if (ino == EXT2_BOOT_LOADER_INO) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000316 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
317 check_blocks(ctx, &pctx, block_buf);
Theodore Ts'o5c576471997-04-29 15:29:49 +0000318 goto next;
319 }
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000320 if ((ino != EXT2_ROOT_INO) &&
321 (ino < EXT2_FIRST_INODE(fs->super))) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000322 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000323 if (inode.i_mode != 0) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000324 if (fix_problem(ctx,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000325 PR_1_RESERVED_BAD_MODE, &pctx)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000326 inode.i_mode = 0;
Theodore Ts'o08b21301997-11-03 19:42:40 +0000327 e2fsck_write_inode(ctx, ino, &inode,
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000328 "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000329 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000330 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000331 check_blocks(ctx, &pctx, block_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000332 goto next;
333 }
334 /*
335 * This code assumes that deleted inodes have
336 * i_links_count set to 0.
337 */
338 if (!inode.i_links_count) {
339 if (!inode.i_dtime && inode.i_mode) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000340 if (fix_problem(ctx,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000341 PR_1_ZERO_DTIME, &pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000342 inode.i_dtime = time(0);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000343 e2fsck_write_inode(ctx, ino, &inode,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000344 "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000345 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000346 }
347 goto next;
348 }
349 /*
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000350 * n.b. 0.3c ext2fs code didn't clear i_links_count for
Theodore Ts'o3839e651997-04-26 13:21:57 +0000351 * deleted files. Oops.
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000352 *
353 * Since all new ext2 implementations get this right,
354 * we now assume that the case of non-zero
355 * i_links_count and non-zero dtime means that we
356 * should keep the file, not delete it.
Theodore Ts'o3839e651997-04-26 13:21:57 +0000357 *
Theodore Ts'o3839e651997-04-26 13:21:57 +0000358 */
359 if (inode.i_dtime) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000360 if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000361 inode.i_dtime = 0;
Theodore Ts'o08b21301997-11-03 19:42:40 +0000362 e2fsck_write_inode(ctx, ino, &inode, "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000363 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000364 }
365
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000366 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000367 switch (fs->super->s_creator_os) {
368 case EXT2_OS_LINUX:
369 frag = inode.osd2.linux2.l_i_frag;
370 fsize = inode.osd2.linux2.l_i_fsize;
371 break;
372 case EXT2_OS_HURD:
373 frag = inode.osd2.hurd2.h_i_frag;
374 fsize = inode.osd2.hurd2.h_i_fsize;
375 break;
376 case EXT2_OS_MASIX:
377 frag = inode.osd2.masix2.m_i_frag;
378 fsize = inode.osd2.masix2.m_i_fsize;
379 break;
380 default:
381 frag = fsize = 0;
382 }
383
384 if (inode.i_faddr || frag || fsize
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000385 || inode.i_file_acl || inode.i_dir_acl) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000386 if (!ctx->inode_bad_map)
387 alloc_bad_map(ctx);
388 ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000389 }
390
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000391 if (LINUX_S_ISDIR(inode.i_mode)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000392 ext2fs_mark_inode_bitmap(ctx->inode_dir_map, ino);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000393 e2fsck_add_dir_info(ctx, ino, 0);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000394 ctx->fs_directory_count++;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000395 } else if (LINUX_S_ISREG (inode.i_mode))
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000396 ctx->fs_regular_count++;
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000397 else if (LINUX_S_ISCHR (inode.i_mode) &&
398 e2fsck_pass1_check_device_inode(&inode))
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000399 ctx->fs_chardev_count++;
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000400 else if (LINUX_S_ISBLK (inode.i_mode) &&
401 e2fsck_pass1_check_device_inode(&inode))
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000402 ctx->fs_blockdev_count++;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000403 else if (LINUX_S_ISLNK (inode.i_mode)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000404 ctx->fs_symlinks_count++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000405 if (!inode.i_blocks) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000406 ctx->fs_fast_symlinks_count++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000407 goto next;
408 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000409 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000410 else if (LINUX_S_ISFIFO (inode.i_mode))
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000411 ctx->fs_fifo_count++;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000412 else if (LINUX_S_ISSOCK (inode.i_mode))
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000413 ctx->fs_sockets_count++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000414 else {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000415 if (!ctx->inode_bad_map)
416 alloc_bad_map(ctx);
417 ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000418 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000419 if (inode.i_block[EXT2_IND_BLOCK])
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000420 ctx->fs_ind_count++;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000421 if (inode.i_block[EXT2_DIND_BLOCK])
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000422 ctx->fs_dind_count++;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000423 if (inode.i_block[EXT2_TIND_BLOCK])
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000424 ctx->fs_tind_count++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000425 if (inode.i_block[EXT2_IND_BLOCK] ||
426 inode.i_block[EXT2_DIND_BLOCK] ||
427 inode.i_block[EXT2_TIND_BLOCK]) {
428 inodes_to_process[process_inode_count].ino = ino;
429 inodes_to_process[process_inode_count].inode = inode;
430 process_inode_count++;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000431 } else
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000432 check_blocks(ctx, &pctx, block_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000433
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000434 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +0000435 return;
436
437 if (process_inode_count >= ctx->process_inode_size) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000438 process_inodes(ctx, block_buf);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000439
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000440 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +0000441 return;
442 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000443 next:
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000444 pctx.errcode = ext2fs_get_next_inode(scan, &ino, &inode);
445 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
446 if (!ctx->inode_bb_map)
447 alloc_bb_map(ctx);
448 ext2fs_mark_inode_bitmap(ctx->inode_bb_map, ino);
449 ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000450 goto next;
451 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000452 if (pctx.errcode) {
453 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000454 ctx->flags |= E2F_FLAG_ABORT;
455 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000456 }
457 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000458 process_inodes(ctx, block_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000459 ext2fs_close_inode_scan(scan);
460 ehandler_operation(0);
461
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000462 if (ctx->invalid_bitmaps)
463 handle_fs_bad_blocks(ctx);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000464
Theodore Ts'o08b21301997-11-03 19:42:40 +0000465 if (ctx->flags & E2F_FLAG_RESTART) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000466 unwind_pass1(fs);
467 goto endit;
468 }
469
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000470 if (ctx->block_dup_map) {
471 if (ctx->options & E2F_OPT_PREEN) {
472 clear_problem_context(&pctx);
473 fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000474 }
Theodore Ts'o08b21301997-11-03 19:42:40 +0000475 e2fsck_pass1_dupblocks(ctx, block_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000476 }
Theodore Ts'o08b21301997-11-03 19:42:40 +0000477 ext2fs_free_mem((void **) &inodes_to_process);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000478endit:
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000479 fs->get_blocks = 0;
480 fs->check_directory = 0;
481 fs->read_inode = 0;
482 fs->write_inode = 0;
483
Theodore Ts'o08b21301997-11-03 19:42:40 +0000484 ext2fs_free_mem((void **) &block_buf);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000485 ext2fs_free_block_bitmap(ctx->block_illegal_map);
486 ctx->block_illegal_map = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000487
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000488#ifdef RESOURCE_TRACK
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000489 if (ctx->options & E2F_OPT_TIME2)
490 print_resource_track("Pass 1", &rtrack);
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000491#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000492}
493
494/*
Theodore Ts'of3db3561997-04-26 13:34:30 +0000495 * When the inode_scan routines call this callback at the end of the
496 * glock group, call process_inodes.
497 */
498static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan,
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000499 dgrp_t group, void * priv_data)
Theodore Ts'of3db3561997-04-26 13:34:30 +0000500{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000501 struct scan_callback_struct *scan_struct;
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000502 e2fsck_t ctx;
503
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000504 scan_struct = (struct scan_callback_struct *) priv_data;
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000505 ctx = scan_struct->ctx;
506
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000507 process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf);
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000508
509 if (ctx->progress)
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000510 if ((ctx->progress)(ctx, 1, group+1,
511 ctx->fs->group_desc_count))
512 return EXT2_ET_CANCEL_REQUESTED;
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000513
Theodore Ts'of3db3561997-04-26 13:34:30 +0000514 return 0;
515}
516
517/*
Theodore Ts'o3839e651997-04-26 13:21:57 +0000518 * Process the inodes in the "inodes to process" list.
519 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000520static void process_inodes(e2fsck_t ctx, char *block_buf)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000521{
522 int i;
523 struct ext2_inode *old_stashed_inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000524 ino_t old_stashed_ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000525 const char *old_operation;
526 char buf[80];
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000527 struct problem_context pctx;
528
Theodore Ts'o3839e651997-04-26 13:21:57 +0000529#if 0
Theodore Ts'of3db3561997-04-26 13:34:30 +0000530 printf("begin process_inodes: ");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000531#endif
532 old_operation = ehandler_operation(0);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000533 old_stashed_inode = ctx->stashed_inode;
534 old_stashed_ino = ctx->stashed_ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000535 qsort(inodes_to_process, process_inode_count,
536 sizeof(struct process_inode_block), process_inode_cmp);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000537 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000538 for (i=0; i < process_inode_count; i++) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000539 pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode;
540 pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000541
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000542#if 0
543 printf("%u ", pctx.ino);
544#endif
545 sprintf(buf, "reading indirect blocks of inode %lu", pctx.ino);
546 ehandler_operation(buf);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000547 check_blocks(ctx, &pctx, block_buf);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000548
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000549 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +0000550 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000551 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000552 ctx->stashed_inode = old_stashed_inode;
553 ctx->stashed_ino = old_stashed_ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000554 process_inode_count = 0;
555#if 0
Theodore Ts'of3db3561997-04-26 13:34:30 +0000556 printf("end process inodes\n");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000557#endif
558 ehandler_operation(old_operation);
559}
560
561static int process_inode_cmp(const void *a, const void *b)
562{
563 const struct process_inode_block *ib_a =
564 (const struct process_inode_block *) a;
565 const struct process_inode_block *ib_b =
566 (const struct process_inode_block *) b;
567
568 return (ib_a->inode.i_block[EXT2_IND_BLOCK] -
569 ib_b->inode.i_block[EXT2_IND_BLOCK]);
570}
571
Theodore Ts'o3839e651997-04-26 13:21:57 +0000572/*
573 * This procedure will allocate the inode bad map table
574 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000575static void alloc_bad_map(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000576{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000577 struct problem_context pctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000578
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000579 clear_problem_context(&pctx);
580
581 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs, "bad inode map",
582 &ctx->inode_bad_map);
583 if (pctx.errcode) {
584 pctx.num = 3;
585 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000586 /* Should never get here */
587 ctx->flags |= E2F_FLAG_ABORT;
588 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000589 }
590}
591
592/*
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000593 * This procedure will allocate the inode "bb" (badblock) map table
594 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000595static void alloc_bb_map(e2fsck_t ctx)
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000596{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000597 struct problem_context pctx;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000598
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000599 clear_problem_context(&pctx);
600 pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
601 "inode in bad block map",
602 &ctx->inode_bb_map);
603 if (pctx.errcode) {
604 pctx.num = 4;
605 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000606 /* Should never get here */
607 ctx->flags |= E2F_FLAG_ABORT;
608 return;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000609 }
610}
611
612/*
Theodore Ts'o3839e651997-04-26 13:21:57 +0000613 * Marks a block as in use, setting the dup_map if it's been set
614 * already. Called by process_block and process_bad_block.
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000615 *
616 * WARNING: Assumes checks have already been done to make sure block
617 * is valid. This is true in both process_block and process_bad_block.
Theodore Ts'o3839e651997-04-26 13:21:57 +0000618 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000619static _INLINE_ void mark_block_used(e2fsck_t ctx, blk_t block)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000620{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000621 struct problem_context pctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000622
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000623 clear_problem_context(&pctx);
624
625 if (ext2fs_fast_test_block_bitmap(ctx->block_found_map, block)) {
626 if (!ctx->block_dup_map) {
627 pctx.errcode = ext2fs_allocate_block_bitmap(ctx->fs,
628 "multiply claimed block map",
629 &ctx->block_dup_map);
630 if (pctx.errcode) {
631 pctx.num = 3;
632 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR,
633 &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000634 /* Should never get here */
635 ctx->flags |= E2F_FLAG_ABORT;
636 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000637 }
638 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000639 ext2fs_fast_mark_block_bitmap(ctx->block_dup_map, block);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000640 } else {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000641 ext2fs_fast_mark_block_bitmap(ctx->block_found_map, block);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000642 }
643}
644
645/*
646 * This subroutine is called on each inode to account for all of the
647 * blocks used by that inode.
648 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000649static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000650 char *block_buf)
651{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000652 ext2_filsys fs = ctx->fs;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000653 struct process_block_struct pb;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000654 ino_t ino = pctx->ino;
655 struct ext2_inode *inode = pctx->inode;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000656
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000657 if (!ext2fs_inode_has_valid_blocks(pctx->inode))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000658 return;
659
660 pb.ino = ino;
661 pb.num_blocks = pb.last_block = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000662 pb.num_illegal_blocks = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000663 pb.suppress = 0; pb.clear = 0;
Theodore Ts'o74becf31997-04-26 14:37:06 +0000664 pb.fragmented = 0;
665 pb.previous_block = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000666 pb.is_dir = LINUX_S_ISDIR(pctx->inode->i_mode);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000667 pb.inode = inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000668 pb.pctx = pctx;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000669 pb.ctx = ctx;
670 pctx->ino = ino;
671 pctx->errcode = ext2fs_block_iterate2(fs, ino,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000672 pb.is_dir ? BLOCK_FLAG_HOLE : 0,
673 block_buf, process_block, &pb);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000674 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +0000675 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000676 end_problem_latch(ctx, PR_LATCH_BLOCK);
677 if (pctx->errcode)
678 fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000679
Theodore Ts'o74becf31997-04-26 14:37:06 +0000680 if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group)
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000681 ctx->fs_fragmented++;
Theodore Ts'o74becf31997-04-26 14:37:06 +0000682
Theodore Ts'of3db3561997-04-26 13:34:30 +0000683 if (pb.clear) {
Theodore Ts'o08b21301997-11-03 19:42:40 +0000684 e2fsck_read_inode(ctx, ino, inode, "check_blocks");
Theodore Ts'of3db3561997-04-26 13:34:30 +0000685 inode->i_links_count = 0;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000686 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000687 inode->i_dtime = time(0);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000688 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000689 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
690 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000691 /*
692 * The inode was probably partially accounted for
693 * before processing was aborted, so we need to
694 * restart the pass 1 scan.
695 */
Theodore Ts'o08b21301997-11-03 19:42:40 +0000696 ctx->flags |= E2F_FLAG_RESTART;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000697 return;
698 }
699
Theodore Ts'o3839e651997-04-26 13:21:57 +0000700 pb.num_blocks *= (fs->blocksize / 512);
701#if 0
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000702 printf("inode %u, i_size = %lu, last_block = %lu, i_blocks=%lu, num_blocks = %lu\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000703 ino, inode->i_size, pb.last_block, inode->i_blocks,
704 pb.num_blocks);
705#endif
706 if (!pb.num_blocks && pb.is_dir) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000707 if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000708 inode->i_links_count = 0;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000709 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000710 inode->i_dtime = time(0);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000711 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000712 ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
713 ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
714 ctx->fs_directory_count--;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000715 pb.is_dir = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000716 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000717 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000718 if ((pb.is_dir && (inode->i_size !=
719 (pb.last_block + 1) * fs->blocksize)) ||
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000720 (inode->i_size < pb.last_block * fs->blocksize)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000721 pctx->num = (pb.last_block+1) * fs->blocksize;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000722 if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000723 inode->i_size = pctx->num;
Theodore Ts'o08b21301997-11-03 19:42:40 +0000724 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000725 }
726 pctx->num = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000727 }
728 if (pb.num_blocks != inode->i_blocks) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000729 pctx->num = pb.num_blocks;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000730 if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000731 inode->i_blocks = pb.num_blocks;
Theodore Ts'o08b21301997-11-03 19:42:40 +0000732 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000733 }
734 pctx->num = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000735 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000736}
737
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000738#if 0
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000739/*
740 * Helper function called by process block when an illegal block is
741 * found. It returns a description about why the block is illegal
742 */
743static char *describe_illegal_block(ext2_filsys fs, blk_t block)
744{
745 blk_t super;
746 int i;
747 static char problem[80];
748
749 super = fs->super->s_first_data_block;
750 strcpy(problem, "PROGRAMMING ERROR: Unknown reason for illegal block");
751 if (block < super) {
752 sprintf(problem, "< FIRSTBLOCK (%u)", super);
753 return(problem);
754 } else if (block >= fs->super->s_blocks_count) {
755 sprintf(problem, "> BLOCKS (%u)", fs->super->s_blocks_count);
756 return(problem);
757 }
758 for (i = 0; i < fs->group_desc_count; i++) {
759 if (block == super) {
760 sprintf(problem, "is the superblock in group %d", i);
761 break;
762 }
763 if (block > super &&
764 block <= (super + fs->desc_blocks)) {
765 sprintf(problem, "is in the group descriptors "
766 "of group %d", i);
767 break;
768 }
769 if (block == fs->group_desc[i].bg_block_bitmap) {
770 sprintf(problem, "is the block bitmap of group %d", i);
771 break;
772 }
773 if (block == fs->group_desc[i].bg_inode_bitmap) {
774 sprintf(problem, "is the inode bitmap of group %d", i);
775 break;
776 }
777 if (block >= fs->group_desc[i].bg_inode_table &&
778 (block < fs->group_desc[i].bg_inode_table
779 + fs->inode_blocks_per_group)) {
780 sprintf(problem, "is in the inode table of group %d",
781 i);
782 break;
783 }
784 super += fs->super->s_blocks_per_group;
785 }
786 return(problem);
787}
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000788#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000789
790/*
791 * This is a helper function for check_blocks().
792 */
793int process_block(ext2_filsys fs,
794 blk_t *block_nr,
795 int blockcnt,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000796 blk_t ref_block,
797 int ref_offset,
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000798 void *priv_data)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000799{
800 struct process_block_struct *p;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000801 struct problem_context *pctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000802 blk_t blk = *block_nr;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000803 int ret_code = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000804 int problem = 0;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000805 e2fsck_t ctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000806
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000807 p = (struct process_block_struct *) priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000808 pctx = p->pctx;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000809 ctx = p->ctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000810
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000811 if (blk == 0) {
812 if (p->is_dir == 0) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000813 /*
814 * Should never happen, since only directories
815 * get called with BLOCK_FLAG_HOLE
816 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000817#if DEBUG_E2FSCK
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000818 printf("process_block() called with blk == 0, "
Theodore Ts'o5c576471997-04-29 15:29:49 +0000819 "blockcnt=%d, inode %lu???\n",
820 blockcnt, p->ino);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000821#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000822 return 0;
823 }
824 if (blockcnt < 0)
825 return 0;
826 if (blockcnt * fs->blocksize < p->inode->i_size) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000827#if 0
828 printf("Missing block (#%d) in directory inode %lu!\n",
829 blockcnt, p->ino);
830#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000831 goto mark_dir;
832 }
833 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000834 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000835
836#if 0
837 printf("Process_block, inode %lu, block %u, #%d\n", p->ino, blk,
838 blockcnt);
839#endif
840
Theodore Ts'o74becf31997-04-26 14:37:06 +0000841 /*
842 * Simplistic fragmentation check. We merely require that the
843 * file be contiguous. (Which can never be true for really
844 * big files that are greater than a block group.)
845 */
846 if (p->previous_block) {
847 if (p->previous_block+1 != blk)
848 p->fragmented = 1;
849 }
850 p->previous_block = blk;
851
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000852 if (blk < fs->super->s_first_data_block ||
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000853 blk >= fs->super->s_blocks_count)
854 problem = PR_1_ILLEGAL_BLOCK_NUM;
Theodore Ts'o521e3681997-04-29 17:48:10 +0000855#if 0
856 else
857 if (ext2fs_test_block_bitmap(block_illegal_map, blk))
858 problem = PR_1_BLOCK_OVERLAPS_METADATA;
859#endif
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000860
861 if (problem) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000862 p->num_illegal_blocks++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000863 if (!p->suppress && (p->num_illegal_blocks % 12) == 0) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000864 if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000865 p->clear = 1;
866 return BLOCK_ABORT;
867 }
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000868 if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000869 p->suppress = 1;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000870 set_latch_flags(PR_LATCH_BLOCK,
871 PRL_SUPPRESS, 0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000872 }
873 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000874 pctx->blk = blk;
875 pctx->blkcount = blockcnt;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000876 if (fix_problem(ctx, problem, pctx)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000877 blk = *block_nr = 0;
878 ret_code = BLOCK_CHANGED;
879 goto mark_dir;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000880 } else
Theodore Ts'o3839e651997-04-26 13:21:57 +0000881 return 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000882 pctx->blk = 0;
883 pctx->blkcount = -1;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000884 }
885
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000886 mark_block_used(ctx, blk);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000887 p->num_blocks++;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000888 if (blockcnt >= 0)
889 p->last_block = blockcnt;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000890mark_dir:
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000891 if (p->is_dir && (blockcnt >= 0)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000892 pctx->errcode = ext2fs_add_dir_block(fs->dblist, p->ino,
893 blk, blockcnt);
894 if (pctx->errcode) {
895 pctx->blk = blk;
896 pctx->num = blockcnt;
897 fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000898 /* Should never get here */
899 ctx->flags |= E2F_FLAG_ABORT;
900 return BLOCK_ABORT;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000901 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000902 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000903 return ret_code;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000904}
905
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000906static void bad_block_indirect(e2fsck_t ctx, blk_t blk)
Theodore Ts'of3db3561997-04-26 13:34:30 +0000907{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000908 struct problem_context pctx;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000909
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000910 clear_problem_context(&pctx);
911 /*
912 * Prompt to see if we should continue or not.
913 */
914 if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, &pctx))
Theodore Ts'o08b21301997-11-03 19:42:40 +0000915 ctx->flags |= E2F_FLAG_ABORT;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000916}
917
Theodore Ts'o3839e651997-04-26 13:21:57 +0000918int process_bad_block(ext2_filsys fs,
919 blk_t *block_nr,
920 int blockcnt,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000921 blk_t ref_block,
922 int ref_offset,
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000923 void *priv_data)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000924{
925 struct process_block_struct *p;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000926 blk_t blk = *block_nr;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000927 int first_block;
928 int i;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000929 struct problem_context *pctx;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000930 e2fsck_t ctx;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000931
Theodore Ts'o3839e651997-04-26 13:21:57 +0000932 if (!blk)
933 return 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000934
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000935 p = (struct process_block_struct *) priv_data;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000936 ctx = p->ctx;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000937 pctx = p->pctx;
938
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000939 pctx->ino = EXT2_BAD_INO;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000940 pctx->blk = blk;
941 pctx->blkcount = blockcnt;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000942
943 if ((blk < fs->super->s_first_data_block) ||
944 (blk >= fs->super->s_blocks_count)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000945 if (fix_problem(ctx, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000946 *block_nr = 0;
947 return BLOCK_CHANGED;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000948 } else
Theodore Ts'o3839e651997-04-26 13:21:57 +0000949 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000950 }
951
952 if (blockcnt < 0) {
Theodore Ts'o08b21301997-11-03 19:42:40 +0000953 if (ext2fs_test_block_bitmap(ctx->block_found_map, blk)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000954 bad_block_indirect(ctx, blk);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000955 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +0000956 return BLOCK_ABORT;
957 } else
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000958 mark_block_used(ctx, blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000959 return 0;
960 }
961#if 0
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000962 printf ("DEBUG: Marking %u as bad.\n", blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000963#endif
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000964 ctx->fs_badblocks_count++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000965 /*
966 * If the block is not used, then mark it as used and return.
967 * If it is already marked as found, this must mean that
968 * there's an overlap between the filesystem table blocks
969 * (bitmaps and inode table) and the bad block list.
970 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000971 if (!ext2fs_test_block_bitmap(ctx->block_found_map, blk)) {
972 ext2fs_mark_block_bitmap(ctx->block_found_map, blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000973 return 0;
974 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000975 /*
976 * Try to find the where the filesystem block was used...
977 */
978 first_block = fs->super->s_first_data_block;
979
980 for (i = 0; i < fs->group_desc_count; i++ ) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000981 pctx->group = i;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000982 pctx->blk = blk;
Theodore Ts'o8039c481997-11-19 21:39:13 +0000983 if (!ext2fs_bg_has_super(fs, i))
984 goto skip_super;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000985 if (blk == first_block) {
986 if (i == 0) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000987 if (fix_problem(ctx,
988 PR_1_BAD_PRIMARY_SUPERBLOCK,
989 pctx)) {
990 *block_nr = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000991 return BLOCK_CHANGED;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000992 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000993 return 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000994 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000995 fix_problem(ctx, PR_1_BAD_SUPERBLOCK, pctx);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000996 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000997 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000998 if ((blk > first_block) &&
999 (blk <= first_block + fs->desc_blocks)) {
1000 if (i == 0) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001001 pctx->blk = *block_nr;
1002 if (fix_problem(ctx,
1003 PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR, pctx)) {
1004 *block_nr = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001005 return BLOCK_CHANGED;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001006 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001007 return 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001008 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001009 fix_problem(ctx, PR_1_BAD_GROUP_DESCRIPTORS, pctx);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001010 return 0;
1011 }
Theodore Ts'o8039c481997-11-19 21:39:13 +00001012 skip_super:
Theodore Ts'of3db3561997-04-26 13:34:30 +00001013 if (blk == fs->group_desc[i].bg_block_bitmap) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001014 if (fix_problem(ctx, PR_1_BB_BAD_BLOCK, pctx)) {
1015 ctx->invalid_block_bitmap_flag[i]++;
1016 ctx->invalid_bitmaps++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001017 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001018 return 0;
1019 }
1020 if (blk == fs->group_desc[i].bg_inode_bitmap) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001021 if (fix_problem(ctx, PR_1_IB_BAD_BLOCK, pctx)) {
1022 ctx->invalid_inode_bitmap_flag[i]++;
1023 ctx->invalid_bitmaps++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001024 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001025 return 0;
1026 }
1027 if ((blk >= fs->group_desc[i].bg_inode_table) &&
1028 (blk < (fs->group_desc[i].bg_inode_table +
1029 fs->inode_blocks_per_group))) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001030 /*
1031 * If there are bad blocks in the inode table,
1032 * the inode scan code will try to do
1033 * something reasonable automatically.
1034 */
Theodore Ts'of3db3561997-04-26 13:34:30 +00001035 return 0;
1036 }
Theodore Ts'o8039c481997-11-19 21:39:13 +00001037 first_block += fs->super->s_blocks_per_group;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001038 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001039 /*
1040 * If we've gotten to this point, then the only
1041 * possibility is that the bad block inode meta data
1042 * is using a bad block.
1043 */
1044 if ((blk == p->inode->i_block[EXT2_IND_BLOCK]) ||
1045 p->inode->i_block[EXT2_DIND_BLOCK]) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001046 bad_block_indirect(ctx, blk);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +00001047 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +00001048 return BLOCK_ABORT;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001049 return 0;
1050 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001051
1052 pctx->group = -1;
1053
1054 /* Warn user that the block wasn't claimed */
1055 fix_problem(ctx, PR_1_PROGERR_CLAIMED_BLOCK, pctx);
1056
Theodore Ts'o3839e651997-04-26 13:21:57 +00001057 return 0;
1058}
1059
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001060static void new_table_block(e2fsck_t ctx, blk_t first_block, int group,
Theodore Ts'o3839e651997-04-26 13:21:57 +00001061 const char *name, int num, blk_t *new_block)
1062{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001063 ext2_filsys fs = ctx->fs;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001064 blk_t old_block = *new_block;
1065 int i;
1066 char *buf;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001067 struct problem_context pctx;
1068
1069 clear_problem_context(&pctx);
1070
1071 pctx.group = group;
1072 pctx.blk = old_block;
1073 pctx.str = name;
1074
1075 pctx.errcode = ext2fs_get_free_blocks(fs, first_block,
Theodore Ts'o3839e651997-04-26 13:21:57 +00001076 first_block + fs->super->s_blocks_per_group,
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001077 num, ctx->block_found_map, new_block);
1078 if (pctx.errcode) {
1079 pctx.num = num;
1080 fix_problem(ctx, PR_1_RELOC_BLOCK_ALLOCATE, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001081 ext2fs_unmark_valid(fs);
1082 return;
1083 }
Theodore Ts'o08b21301997-11-03 19:42:40 +00001084 pctx.errcode = ext2fs_get_mem(fs->blocksize, (void **) &buf);
1085 if (pctx.errcode) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001086 fix_problem(ctx, PR_1_RELOC_MEMORY_ALLOCATE, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001087 ext2fs_unmark_valid(fs);
1088 return;
1089 }
1090 ext2fs_mark_super_dirty(fs);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001091 pctx.blk2 = *new_block;
1092 fix_problem(ctx, (old_block ? PR_1_RELOC_FROM_TO :
1093 PR_1_RELOC_TO), &pctx);
1094 pctx.blk2 = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001095 for (i = 0; i < num; i++) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001096 pctx.blk = i;
1097 ext2fs_mark_block_bitmap(ctx->block_found_map, (*new_block)+i);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001098 if (old_block) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001099 pctx.errcode = io_channel_read_blk(fs->io,
1100 old_block + i, 1, buf);
1101 if (pctx.errcode)
1102 fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001103 } else
1104 memset(buf, 0, fs->blocksize);
1105
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001106 pctx.blk = (*new_block) + i;
1107 pctx.errcode = io_channel_write_blk(fs->io, pctx.blk,
Theodore Ts'o3839e651997-04-26 13:21:57 +00001108 1, buf);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001109 if (pctx.errcode)
1110 fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001111 }
Theodore Ts'o08b21301997-11-03 19:42:40 +00001112 ext2fs_free_mem((void **) &buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001113}
1114
1115/*
Theodore Ts'of3db3561997-04-26 13:34:30 +00001116 * This routine gets called at the end of pass 1 if bad blocks are
1117 * detected in the superblock, group descriptors, inode_bitmaps, or
1118 * block bitmaps. At this point, all of the blocks have been mapped
1119 * out, so we can try to allocate new block(s) to replace the bad
1120 * blocks.
Theodore Ts'o3839e651997-04-26 13:21:57 +00001121 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001122static void handle_fs_bad_blocks(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001123{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001124 ext2_filsys fs = ctx->fs;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001125 int i;
1126 int first_block = fs->super->s_first_data_block;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001127
1128 for (i = 0; i < fs->group_desc_count; i++) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001129 if (ctx->invalid_block_bitmap_flag[i]) {
1130 new_table_block(ctx, first_block, i, "block bitmap",
1131 1, &fs->group_desc[i].bg_block_bitmap);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001132 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001133 if (ctx->invalid_inode_bitmap_flag[i]) {
1134 new_table_block(ctx, first_block, i, "inode bitmap",
1135 1, &fs->group_desc[i].bg_inode_bitmap);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001136 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001137 if (ctx->invalid_inode_table_flag[i]) {
1138 new_table_block(ctx, first_block, i, "inode table",
Theodore Ts'of3db3561997-04-26 13:34:30 +00001139 fs->inode_blocks_per_group,
Theodore Ts'o3839e651997-04-26 13:21:57 +00001140 &fs->group_desc[i].bg_inode_table);
Theodore Ts'o08b21301997-11-03 19:42:40 +00001141 ctx->flags |= E2F_FLAG_RESTART;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001142 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001143 first_block += fs->super->s_blocks_per_group;
1144 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001145 ctx->invalid_bitmaps = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001146}
1147
1148/*
1149 * This routine marks all blocks which are used by the superblock,
1150 * group descriptors, inode bitmaps, and block bitmaps.
1151 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001152static void mark_table_blocks(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001153{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001154 ext2_filsys fs = ctx->fs;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001155 blk_t block, b;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001156 int i,j;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001157 struct problem_context pctx;
1158
1159 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001160
1161 block = fs->super->s_first_data_block;
1162 for (i = 0; i < fs->group_desc_count; i++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001163 pctx.group = i;
Theodore Ts'oda2e97f1997-06-12 04:28:07 +00001164
1165 if (ext2fs_bg_has_super(fs, i)) {
1166 /*
1167 * Mark this group's copy of the superblock
1168 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001169 ext2fs_mark_block_bitmap(ctx->block_found_map, block);
1170 ext2fs_mark_block_bitmap(ctx->block_illegal_map,
1171 block);
Theodore Ts'oda2e97f1997-06-12 04:28:07 +00001172
1173 /*
1174 * Mark this group's copy of the descriptors
1175 */
1176 for (j = 0; j < fs->desc_blocks; j++) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001177 ext2fs_mark_block_bitmap(ctx->block_found_map,
Theodore Ts'oda2e97f1997-06-12 04:28:07 +00001178 block + j + 1);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001179 ext2fs_mark_block_bitmap(ctx->block_illegal_map,
Theodore Ts'oda2e97f1997-06-12 04:28:07 +00001180 block + j + 1);
1181 }
1182 }
1183
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001184 /*
1185 * Mark the blocks used for the inode table
1186 */
1187 if (fs->group_desc[i].bg_inode_table) {
1188 for (j = 0, b = fs->group_desc[i].bg_inode_table;
1189 j < fs->inode_blocks_per_group;
1190 j++, b++) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001191 if (ext2fs_test_block_bitmap(ctx->block_found_map,
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001192 b)) {
1193 pctx.blk = b;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001194 if (fix_problem(ctx,
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001195 PR_1_ITABLE_CONFLICT, &pctx)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001196 ctx->invalid_inode_table_flag[i]++;
1197 ctx->invalid_bitmaps++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001198 }
1199 } else {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001200 ext2fs_mark_block_bitmap(ctx->block_found_map,
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001201 b);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001202 ext2fs_mark_block_bitmap(ctx->block_illegal_map,
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001203 b);
1204 }
1205 }
1206 }
1207
Theodore Ts'o3839e651997-04-26 13:21:57 +00001208 /*
1209 * Mark block used for the block bitmap
1210 */
Theodore Ts'of3db3561997-04-26 13:34:30 +00001211 if (fs->group_desc[i].bg_block_bitmap) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001212 if (ext2fs_test_block_bitmap(ctx->block_found_map,
Theodore Ts'of3db3561997-04-26 13:34:30 +00001213 fs->group_desc[i].bg_block_bitmap)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001214 pctx.blk = fs->group_desc[i].bg_block_bitmap;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001215 if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) {
1216 ctx->invalid_block_bitmap_flag[i]++;
1217 ctx->invalid_bitmaps++;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001218 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001219 } else {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001220 ext2fs_mark_block_bitmap(ctx->block_found_map,
Theodore Ts'of3db3561997-04-26 13:34:30 +00001221 fs->group_desc[i].bg_block_bitmap);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001222 ext2fs_mark_block_bitmap(ctx->block_illegal_map,
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001223 fs->group_desc[i].bg_block_bitmap);
1224 }
1225
Theodore Ts'of3db3561997-04-26 13:34:30 +00001226 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001227 /*
1228 * Mark block used for the inode bitmap
1229 */
Theodore Ts'of3db3561997-04-26 13:34:30 +00001230 if (fs->group_desc[i].bg_inode_bitmap) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001231 if (ext2fs_test_block_bitmap(ctx->block_found_map,
Theodore Ts'of3db3561997-04-26 13:34:30 +00001232 fs->group_desc[i].bg_inode_bitmap)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001233 pctx.blk = fs->group_desc[i].bg_inode_bitmap;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001234 if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) {
1235 ctx->invalid_inode_bitmap_flag[i]++;
1236 ctx->invalid_bitmaps++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001237 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001238 } else {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001239 ext2fs_mark_block_bitmap(ctx->block_found_map,
Theodore Ts'of3db3561997-04-26 13:34:30 +00001240 fs->group_desc[i].bg_inode_bitmap);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001241 ext2fs_mark_block_bitmap(ctx->block_illegal_map,
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001242 fs->group_desc[i].bg_inode_bitmap);
1243 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001244 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001245 block += fs->super->s_blocks_per_group;
1246 }
1247}
1248
1249/*
1250 * This subroutines short circuits ext2fs_get_blocks and
1251 * ext2fs_check_directory; we use them since we already have the inode
1252 * structure, so there's no point in letting the ext2fs library read
1253 * the inode again.
1254 */
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001255errcode_t pass1_get_blocks(ext2_filsys fs, ino_t ino, blk_t *blocks)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001256{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00001257 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001258 int i;
1259
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001260 if (ino != ctx->stashed_ino)
Theodore Ts'o521e3681997-04-29 17:48:10 +00001261 return EXT2_ET_CALLBACK_NOTHANDLED;
1262
1263 for (i=0; i < EXT2_N_BLOCKS; i++)
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001264 blocks[i] = ctx->stashed_inode->i_block[i];
Theodore Ts'o521e3681997-04-29 17:48:10 +00001265 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001266}
1267
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001268errcode_t pass1_read_inode(ext2_filsys fs, ino_t ino, struct ext2_inode *inode)
1269{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00001270 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001271
1272 if (ino != ctx->stashed_ino)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001273 return EXT2_ET_CALLBACK_NOTHANDLED;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001274 *inode = *ctx->stashed_inode;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001275 return 0;
1276}
1277
1278errcode_t pass1_write_inode(ext2_filsys fs, ino_t ino,
1279 struct ext2_inode *inode)
1280{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00001281 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001282
1283 if (ino == ctx->stashed_ino)
1284 *ctx->stashed_inode = *inode;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001285 return EXT2_ET_CALLBACK_NOTHANDLED;
1286}
1287
1288errcode_t pass1_check_directory(ext2_filsys fs, ino_t ino)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001289{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00001290 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001291
1292 if (ino != ctx->stashed_ino)
1293 return EXT2_ET_CALLBACK_NOTHANDLED;
1294
1295 if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode))
Theodore Ts'o291c9041997-10-31 06:17:08 +00001296 return EXT2_ET_NO_DIRECTORY;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001297 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001298}