blob: 2c760a9c2dff3ec8e36226e65cde349efb3a1494 [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
43#include <et/com_err.h>
44#include "e2fsck.h"
Theodore Ts'o21c84b71997-04-29 16:15:03 +000045#include "problem.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000046
Theodore Ts'o50e1e101997-04-26 13:58:21 +000047#ifdef NO_INLINE_FUNCS
48#define _INLINE_
49#else
50#define _INLINE_ inline
51#endif
52
Theodore Ts'o3839e651997-04-26 13:21:57 +000053/* Files counts */
54int fs_directory_count = 0;
55int fs_regular_count = 0;
56int fs_blockdev_count = 0;
57int fs_chardev_count = 0;
58int fs_links_count = 0;
59int fs_symlinks_count = 0;
60int fs_fast_symlinks_count = 0;
61int fs_fifo_count = 0;
62int fs_total_count = 0;
63int fs_badblocks_count = 0;
64int fs_sockets_count = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +000065int fs_ind_count = 0;
66int fs_dind_count = 0;
67int fs_tind_count = 0;
Theodore Ts'o74becf31997-04-26 14:37:06 +000068int fs_fragmented = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +000069
Theodore Ts'of3db3561997-04-26 13:34:30 +000070ext2fs_inode_bitmap inode_used_map = 0; /* Inodes which are in use */
71ext2fs_inode_bitmap inode_bad_map = 0; /* Inodes which are bad in some way */
72ext2fs_inode_bitmap inode_dir_map = 0; /* Inodes which are directories */
Theodore Ts'o21c84b71997-04-29 16:15:03 +000073ext2fs_inode_bitmap inode_bb_map = 0; /* Inodes which are in bad blocks */
Theodore Ts'o3839e651997-04-26 13:21:57 +000074
Theodore Ts'of3db3561997-04-26 13:34:30 +000075ext2fs_block_bitmap block_found_map = 0;
76ext2fs_block_bitmap block_dup_map = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +000077ext2fs_block_bitmap block_illegal_map = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +000078
Theodore Ts'o21c84b71997-04-29 16:15:03 +000079ext2_icount_t inode_link_info = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +000080
81static int process_block(ext2_filsys fs, blk_t *blocknr,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000082 int blockcnt, blk_t ref_blk,
83 int ref_offset, void *private);
Theodore Ts'o3839e651997-04-26 13:21:57 +000084static int process_bad_block(ext2_filsys fs, blk_t *block_nr,
Theodore Ts'o21c84b71997-04-29 16:15:03 +000085 int blockcnt, blk_t ref_blk,
86 int ref_offset, void *private);
87static void check_blocks(ext2_filsys fs, struct problem_context *pctx,
Theodore Ts'o3839e651997-04-26 13:21:57 +000088 char *block_buf);
89static void mark_table_blocks(ext2_filsys fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +000090static void alloc_bad_map(ext2_filsys fs);
Theodore Ts'o21c84b71997-04-29 16:15:03 +000091static void alloc_bb_map(ext2_filsys fs);
Theodore Ts'of3db3561997-04-26 13:34:30 +000092static void handle_fs_bad_blocks(ext2_filsys fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +000093static void process_inodes(ext2_filsys fs, char *block_buf);
94static int process_inode_cmp(const void *a, const void *b);
Theodore Ts'of3db3561997-04-26 13:34:30 +000095static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan,
96 dgrp_t group, void * private);
Theodore Ts'o21c84b71997-04-29 16:15:03 +000097/* static char *describe_illegal_block(ext2_filsys fs, blk_t block); */
Theodore Ts'o3839e651997-04-26 13:21:57 +000098
99struct process_block_struct {
100 ino_t ino;
Theodore Ts'o74becf31997-04-26 14:37:06 +0000101 int is_dir:1, clear:1, suppress:1, fragmented:1;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000102 int num_blocks;
103 int last_block;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000104 int num_illegal_blocks;
Theodore Ts'o74becf31997-04-26 14:37:06 +0000105 blk_t previous_block;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000106 struct ext2_inode *inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000107 struct problem_context *pctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000108};
109
110struct process_inode_block {
111 ino_t ino;
112 struct ext2_inode inode;
113};
114
115/*
116 * For pass1_check_directory and pass1_get_blocks
117 */
118ino_t stashed_ino;
119struct ext2_inode *stashed_inode;
120
121/*
122 * For the inodes to process list.
123 */
124static struct process_inode_block *inodes_to_process;
125static int process_inode_count;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000126int process_inode_size = 256;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000127
128/*
Theodore Ts'of3db3561997-04-26 13:34:30 +0000129 * Free all memory allocated by pass1 in preparation for restarting
130 * things.
131 */
132static void unwind_pass1(ext2_filsys fs)
133{
134 ext2fs_free_inode_bitmap(inode_used_map); inode_used_map = 0;
135 ext2fs_free_inode_bitmap(inode_dir_map); inode_dir_map = 0;
136 ext2fs_free_block_bitmap(block_found_map); block_found_map = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000137 ext2fs_free_icount(inode_link_info); inode_link_info = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000138 free(inodes_to_process);inodes_to_process = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000139 ext2fs_free_dblist(fs->dblist); fs->dblist = 0;
140 free_dir_info(fs);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000141 if (block_dup_map) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000142 ext2fs_free_block_bitmap(block_dup_map); block_dup_map = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000143 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000144 if (inode_bb_map) {
145 ext2fs_free_inode_bitmap(inode_bb_map); inode_bb_map = 0;
146 }
147 if (inode_bad_map) {
148 ext2fs_free_inode_bitmap(inode_bad_map); inode_bad_map = 0;
149 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000150
151 /* Clear statistic counters */
152 fs_directory_count = 0;
153 fs_regular_count = 0;
154 fs_blockdev_count = 0;
155 fs_chardev_count = 0;
156 fs_links_count = 0;
157 fs_symlinks_count = 0;
158 fs_fast_symlinks_count = 0;
159 fs_fifo_count = 0;
160 fs_total_count = 0;
161 fs_badblocks_count = 0;
162 fs_sockets_count = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000163 fs_ind_count = 0;
164 fs_dind_count = 0;
165 fs_tind_count = 0;
Theodore Ts'o74becf31997-04-26 14:37:06 +0000166 fs_fragmented = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000167}
168
Theodore Ts'o3839e651997-04-26 13:21:57 +0000169void pass1(ext2_filsys fs)
170{
171 ino_t ino;
172 struct ext2_inode inode;
173 ext2_inode_scan scan;
174 char *block_buf;
175 errcode_t retval;
176 struct resource_track rtrack;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000177 unsigned char frag, fsize;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000178 struct problem_context pctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000179
180 init_resource_track(&rtrack);
181
182 if (!preen)
183 printf("Pass 1: Checking inodes, blocks, and sizes\n");
184
185#ifdef MTRACE
186 mtrace_print("Pass 1");
187#endif
188
189 /*
190 * Allocate bitmaps structures
191 */
Theodore Ts'of3db3561997-04-26 13:34:30 +0000192 retval = ext2fs_allocate_inode_bitmap(fs, "in-use inode map",
193 &inode_used_map);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000194 if (retval) {
195 com_err("ext2fs_allocate_inode_bitmap", retval,
196 "while allocating inode_used_map");
197 fatal_error(0);
198 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000199 retval = ext2fs_allocate_inode_bitmap(fs, "directory inode map",
200 &inode_dir_map);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000201 if (retval) {
202 com_err("ext2fs_allocate_inode_bitmap", retval,
203 "while allocating inode_dir_map");
204 fatal_error(0);
205 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000206 retval = ext2fs_allocate_block_bitmap(fs, "in-use block map",
207 &block_found_map);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000208 if (retval) {
209 com_err("ext2fs_allocate_block_bitmap", retval,
210 "while allocating block_found_map");
211 fatal_error(0);
212 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000213 retval = ext2fs_allocate_block_bitmap(fs, "illegal block map",
214 &block_illegal_map);
215 if (retval) {
216 com_err("ext2fs_allocate_block_bitmap", retval,
217 "while allocating block_illegal_map");
218 fatal_error(0);
219 }
Theodore Ts'o521e3681997-04-29 17:48:10 +0000220 retval = ext2fs_create_icount2(fs, 0, 0, 0, &inode_link_info);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000221 if (retval) {
222 com_err("ext2fs_create_icount", retval,
223 "while creating inode_link_info");
224 fatal_error(0);
225 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000226 inodes_to_process = allocate_memory(process_inode_size *
227 sizeof(struct process_inode_block),
228 "array of inodes to process");
229 process_inode_count = 0;
230
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000231 retval = ext2fs_init_dblist(fs, 0);
232 if (retval) {
233 com_err(program_name, retval,
234 "while allocating directory block information");
235 fatal_error(0);
236 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000237
238 mark_table_blocks(fs);
239 block_buf = allocate_memory(fs->blocksize * 3, "block interate buffer");
240 fs->get_blocks = pass1_get_blocks;
241 fs->check_directory = pass1_check_directory;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000242 fs->read_inode = pass1_read_inode;
243 fs->write_inode = pass1_write_inode;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000244 ehandler_operation("doing inode scan");
245 retval = ext2fs_open_inode_scan(fs, inode_buffer_blocks, &scan);
246 if (retval) {
247 com_err(program_name, retval, "while opening inode scan");
248 fatal_error(0);
249 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000250 ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000251 retval = ext2fs_get_next_inode(scan, &ino, &inode);
252 if (retval) {
253 com_err(program_name, retval, "while starting inode scan");
254 fatal_error(0);
255 }
256 stashed_inode = &inode;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000257 ext2fs_set_inode_callback(scan, scan_callback, block_buf);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000258 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000259 while (ino) {
260 stashed_ino = ino;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000261 if (inode.i_links_count)
262 retval = ext2fs_icount_store(inode_link_info, ino,
263 inode.i_links_count);
264 if (retval) {
265 com_err("ext2fs_icount_fetch", retval,
266 "while adding inode %u", ino);
267 fatal_error(0);
268 }
269 pctx.ino = ino;
270 pctx.inode = &inode;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000271 if (ino == EXT2_BAD_INO) {
272 struct process_block_struct pb;
273
274 pb.ino = EXT2_BAD_INO;
275 pb.num_blocks = pb.last_block = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000276 pb.num_illegal_blocks = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000277 pb.suppress = 0; pb.clear = 0; pb.is_dir = 0;
Theodore Ts'o74becf31997-04-26 14:37:06 +0000278 pb.fragmented = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000279 pb.inode = &inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000280 pb.pctx = &pctx;
281 retval = ext2fs_block_iterate2(fs, ino, 0, block_buf,
282 process_bad_block, &pb);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000283 if (retval)
284 com_err(program_name, retval, "while calling e2fsc_block_interate in pass 1");
285
Theodore Ts'of3db3561997-04-26 13:34:30 +0000286 ext2fs_mark_inode_bitmap(inode_used_map, ino);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000287 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000288 goto next;
289 }
290 if (ino == EXT2_ROOT_INO) {
291 /*
292 * Make sure the root inode is a directory; if
293 * not, offer to clear it. It will be
294 * regnerated in pass #3.
295 */
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000296 if (!LINUX_S_ISDIR(inode.i_mode)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000297 if (fix_problem(fs, PR_1_ROOT_NO_DIR, &pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000298 inode.i_dtime = time(0);
299 inode.i_links_count = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000300 ext2fs_icount_store(inode_link_info,
301 ino, 0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000302 e2fsck_write_inode(fs, ino, &inode,
303 "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000304 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000305 }
306 /*
307 * If dtime is set, offer to clear it. mke2fs
308 * version 0.2b created filesystems with the
309 * dtime field set for the root and lost+found
310 * directories. We won't worry about
311 * /lost+found, since that can be regenerated
312 * easily. But we will fix the root directory
313 * as a special case.
314 */
315 if (inode.i_dtime && inode.i_links_count) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000316 if (fix_problem(fs, PR_1_ROOT_DTIME, &pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000317 inode.i_dtime = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000318 e2fsck_write_inode(fs, ino, &inode,
319 "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000320 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000321 }
322 }
Theodore Ts'o5c576471997-04-29 15:29:49 +0000323 if (ino == EXT2_BOOT_LOADER_INO) {
324 ext2fs_mark_inode_bitmap(inode_used_map, ino);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000325 check_blocks(fs, &pctx, block_buf);
Theodore Ts'o5c576471997-04-29 15:29:49 +0000326 goto next;
327 }
Theodore Ts'o7f88b041997-04-26 14:48:50 +0000328 if ((ino != EXT2_ROOT_INO) &&
329 (ino < EXT2_FIRST_INODE(fs->super))) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000330 ext2fs_mark_inode_bitmap(inode_used_map, ino);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000331 if (inode.i_mode != 0) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000332 if (fix_problem(fs,
333 PR_1_RESERVED_BAD_MODE, &pctx)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000334 inode.i_mode = 0;
335 e2fsck_write_inode(fs, ino, &inode,
336 "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000337 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000338 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000339 check_blocks(fs, &pctx, block_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000340 goto next;
341 }
342 /*
343 * This code assumes that deleted inodes have
344 * i_links_count set to 0.
345 */
346 if (!inode.i_links_count) {
347 if (!inode.i_dtime && inode.i_mode) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000348 if (fix_problem(fs,
349 PR_1_ZERO_DTIME, &pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000350 inode.i_dtime = time(0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000351 e2fsck_write_inode(fs, ino, &inode,
352 "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000353 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000354 }
355 goto next;
356 }
357 /*
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000358 * n.b. 0.3c ext2fs code didn't clear i_links_count for
Theodore Ts'o3839e651997-04-26 13:21:57 +0000359 * deleted files. Oops.
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000360 *
361 * Since all new ext2 implementations get this right,
362 * we now assume that the case of non-zero
363 * i_links_count and non-zero dtime means that we
364 * should keep the file, not delete it.
Theodore Ts'o3839e651997-04-26 13:21:57 +0000365 *
Theodore Ts'o3839e651997-04-26 13:21:57 +0000366 */
367 if (inode.i_dtime) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000368 if (fix_problem(fs, PR_1_SET_DTIME, &pctx)) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000369 inode.i_dtime = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000370 e2fsck_write_inode(fs, ino, &inode, "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000371 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000372 }
373
Theodore Ts'of3db3561997-04-26 13:34:30 +0000374 ext2fs_mark_inode_bitmap(inode_used_map, ino);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000375 switch (fs->super->s_creator_os) {
376 case EXT2_OS_LINUX:
377 frag = inode.osd2.linux2.l_i_frag;
378 fsize = inode.osd2.linux2.l_i_fsize;
379 break;
380 case EXT2_OS_HURD:
381 frag = inode.osd2.hurd2.h_i_frag;
382 fsize = inode.osd2.hurd2.h_i_fsize;
383 break;
384 case EXT2_OS_MASIX:
385 frag = inode.osd2.masix2.m_i_frag;
386 fsize = inode.osd2.masix2.m_i_fsize;
387 break;
388 default:
389 frag = fsize = 0;
390 }
391
392 if (inode.i_faddr || frag || fsize
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000393 || inode.i_file_acl || inode.i_dir_acl) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000394 if (!inode_bad_map)
395 alloc_bad_map(fs);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000396 ext2fs_mark_inode_bitmap(inode_bad_map, ino);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000397 }
398
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000399 if (LINUX_S_ISDIR(inode.i_mode)) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000400 ext2fs_mark_inode_bitmap(inode_dir_map, ino);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000401 add_dir_info(fs, ino, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000402 fs_directory_count++;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000403 } else if (LINUX_S_ISREG (inode.i_mode))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000404 fs_regular_count++;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000405 else if (LINUX_S_ISCHR (inode.i_mode))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000406 fs_chardev_count++;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000407 else if (LINUX_S_ISBLK (inode.i_mode))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000408 fs_blockdev_count++;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000409 else if (LINUX_S_ISLNK (inode.i_mode)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000410 fs_symlinks_count++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000411 if (!inode.i_blocks) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000412 fs_fast_symlinks_count++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000413 goto next;
414 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000415 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000416 else if (LINUX_S_ISFIFO (inode.i_mode))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000417 fs_fifo_count++;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000418 else if (LINUX_S_ISSOCK (inode.i_mode))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000419 fs_sockets_count++;
420 else {
421 if (!inode_bad_map)
422 alloc_bad_map(fs);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000423 ext2fs_mark_inode_bitmap(inode_bad_map, ino);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000424 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000425 if (inode.i_block[EXT2_IND_BLOCK])
426 fs_ind_count++;
427 if (inode.i_block[EXT2_DIND_BLOCK])
428 fs_dind_count++;
429 if (inode.i_block[EXT2_TIND_BLOCK])
430 fs_tind_count++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000431 if (inode.i_block[EXT2_IND_BLOCK] ||
432 inode.i_block[EXT2_DIND_BLOCK] ||
433 inode.i_block[EXT2_TIND_BLOCK]) {
434 inodes_to_process[process_inode_count].ino = ino;
435 inodes_to_process[process_inode_count].inode = inode;
436 process_inode_count++;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000437 } else
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000438 check_blocks(fs, &pctx, block_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000439
440 if (process_inode_count >= process_inode_size)
441 process_inodes(fs, block_buf);
442 next:
443 retval = ext2fs_get_next_inode(scan, &ino, &inode);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000444 if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
445 if (!inode_bb_map)
446 alloc_bb_map(fs);
447 ext2fs_mark_inode_bitmap(inode_bb_map, ino);
448 ext2fs_mark_inode_bitmap(inode_used_map, ino);
449 goto next;
450 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000451 if (retval) {
452 com_err(program_name, retval,
453 "while doing inode scan");
454 fatal_error(0);
455 }
456 }
457 process_inodes(fs, block_buf);
458 ext2fs_close_inode_scan(scan);
459 ehandler_operation(0);
460
Theodore Ts'of3db3561997-04-26 13:34:30 +0000461 if (invalid_bitmaps)
462 handle_fs_bad_blocks(fs);
463
464 if (restart_e2fsck) {
465 unwind_pass1(fs);
466 goto endit;
467 }
468
Theodore Ts'o3839e651997-04-26 13:21:57 +0000469 if (block_dup_map) {
470 if (preen) {
471 printf("Duplicate or bad blocks in use!\n");
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000472 preenhalt(fs);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000473 }
474 pass1_dupblocks(fs, block_buf);
475 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000476 free(inodes_to_process);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000477endit:
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000478 fs->get_blocks = 0;
479 fs->check_directory = 0;
480 fs->read_inode = 0;
481 fs->write_inode = 0;
482
Theodore Ts'o3839e651997-04-26 13:21:57 +0000483 free(block_buf);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000484 ext2fs_free_block_bitmap(block_illegal_map);
485 block_illegal_map = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000486
Theodore Ts'o3839e651997-04-26 13:21:57 +0000487 if (tflag > 1) {
488 printf("Pass 1: ");
489 print_resource_track(&rtrack);
490 }
491}
492
493/*
Theodore Ts'of3db3561997-04-26 13:34:30 +0000494 * When the inode_scan routines call this callback at the end of the
495 * glock group, call process_inodes.
496 */
497static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan,
498 dgrp_t group, void * private)
499{
500 process_inodes(fs, (char *) private);
501 return 0;
502}
503
504/*
Theodore Ts'o3839e651997-04-26 13:21:57 +0000505 * Process the inodes in the "inodes to process" list.
506 */
507static void process_inodes(ext2_filsys fs, char *block_buf)
508{
509 int i;
510 struct ext2_inode *old_stashed_inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000511 ino_t old_stashed_ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000512 const char *old_operation;
513 char buf[80];
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000514 struct problem_context pctx;
515
Theodore Ts'o3839e651997-04-26 13:21:57 +0000516#if 0
Theodore Ts'of3db3561997-04-26 13:34:30 +0000517 printf("begin process_inodes: ");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000518#endif
519 old_operation = ehandler_operation(0);
520 old_stashed_inode = stashed_inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000521 old_stashed_ino = stashed_ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000522 qsort(inodes_to_process, process_inode_count,
523 sizeof(struct process_inode_block), process_inode_cmp);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000524 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000525 for (i=0; i < process_inode_count; i++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000526 pctx.inode = stashed_inode = &inodes_to_process[i].inode;
527 pctx.ino = stashed_ino = inodes_to_process[i].ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000528
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000529#if 0
530 printf("%u ", pctx.ino);
531#endif
532 sprintf(buf, "reading indirect blocks of inode %lu", pctx.ino);
533 ehandler_operation(buf);
534 check_blocks(fs, &pctx, block_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000535 }
536 stashed_inode = old_stashed_inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000537 stashed_ino = old_stashed_ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000538 process_inode_count = 0;
539#if 0
Theodore Ts'of3db3561997-04-26 13:34:30 +0000540 printf("end process inodes\n");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000541#endif
542 ehandler_operation(old_operation);
543}
544
545static int process_inode_cmp(const void *a, const void *b)
546{
547 const struct process_inode_block *ib_a =
548 (const struct process_inode_block *) a;
549 const struct process_inode_block *ib_b =
550 (const struct process_inode_block *) b;
551
552 return (ib_a->inode.i_block[EXT2_IND_BLOCK] -
553 ib_b->inode.i_block[EXT2_IND_BLOCK]);
554}
555
Theodore Ts'o3839e651997-04-26 13:21:57 +0000556/*
557 * This procedure will allocate the inode bad map table
558 */
559static void alloc_bad_map(ext2_filsys fs)
560{
561 errcode_t retval;
562
Theodore Ts'of3db3561997-04-26 13:34:30 +0000563 retval = ext2fs_allocate_inode_bitmap(fs, "bad inode map",
564 &inode_bad_map);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000565 if (retval) {
566 com_err("ext2fs_allocate_inode_bitmap", retval,
567 "while allocating inode_bad_map");
568 fatal_error(0);
569 }
570}
571
572/*
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000573 * This procedure will allocate the inode "bb" (badblock) map table
574 */
575static void alloc_bb_map(ext2_filsys fs)
576{
577 errcode_t retval;
578
579 retval = ext2fs_allocate_inode_bitmap(fs, "inode in bad block map",
580 &inode_bb_map);
581 if (retval) {
582 com_err("ext2fs_allocate_inode_bitmap", retval,
583 "while allocating inode in bad block map");
584 fatal_error(0);
585 }
586}
587
588/*
Theodore Ts'o3839e651997-04-26 13:21:57 +0000589 * Marks a block as in use, setting the dup_map if it's been set
590 * already. Called by process_block and process_bad_block.
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000591 *
592 * WARNING: Assumes checks have already been done to make sure block
593 * is valid. This is true in both process_block and process_bad_block.
Theodore Ts'o3839e651997-04-26 13:21:57 +0000594 */
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000595static _INLINE_ void mark_block_used(ext2_filsys fs, blk_t block)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000596{
597 errcode_t retval;
598
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000599 if (ext2fs_fast_test_block_bitmap(block_found_map, block)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000600 if (!block_dup_map) {
601 retval = ext2fs_allocate_block_bitmap(fs,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000602 "multiply claimed block map", &block_dup_map);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000603 if (retval) {
604 com_err("ext2fs_allocate_block_bitmap", retval,
605 "while allocating block_dup_map");
606 fatal_error(0);
607 }
608 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000609 ext2fs_fast_mark_block_bitmap(block_dup_map, block);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000610 } else {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000611 ext2fs_fast_mark_block_bitmap(block_found_map, block);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000612 }
613}
614
615/*
616 * This subroutine is called on each inode to account for all of the
617 * blocks used by that inode.
618 */
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000619static void check_blocks(ext2_filsys fs, struct problem_context *pctx,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000620 char *block_buf)
621{
622 struct process_block_struct pb;
623 errcode_t retval;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000624 ino_t ino = pctx->ino;
625 struct ext2_inode *inode = pctx->inode;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000626
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000627 if (!ext2fs_inode_has_valid_blocks(pctx->inode))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000628 return;
629
630 pb.ino = ino;
631 pb.num_blocks = pb.last_block = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000632 pb.num_illegal_blocks = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000633 pb.suppress = 0; pb.clear = 0;
Theodore Ts'o74becf31997-04-26 14:37:06 +0000634 pb.fragmented = 0;
635 pb.previous_block = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000636 pb.is_dir = LINUX_S_ISDIR(pctx->inode->i_mode);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000637 pb.inode = inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000638 pb.pctx = pctx;
639 retval = ext2fs_block_iterate2(fs, ino,
640 pb.is_dir ? BLOCK_FLAG_HOLE : 0,
641 block_buf, process_block, &pb);
642 reset_problem_latch(PR_LATCH_BLOCK);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000643 if (retval)
644 com_err(program_name, retval,
645 "while calling ext2fs_block_iterate in check_blocks");
646
Theodore Ts'o74becf31997-04-26 14:37:06 +0000647 if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group)
648 fs_fragmented++;
649
Theodore Ts'of3db3561997-04-26 13:34:30 +0000650 if (pb.clear) {
651 e2fsck_read_inode(fs, ino, inode, "check_blocks");
652 if (retval) {
653 com_err("check_blocks", retval,
654 "while reading to be cleared inode %d", ino);
655 fatal_error(0);
656 }
657 inode->i_links_count = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000658 ext2fs_icount_store(inode_link_info, ino, 0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000659 inode->i_dtime = time(0);
660 e2fsck_write_inode(fs, ino, inode, "check_blocks");
661 ext2fs_unmark_inode_bitmap(inode_dir_map, ino);
662 ext2fs_unmark_inode_bitmap(inode_used_map, ino);
663 /*
664 * The inode was probably partially accounted for
665 * before processing was aborted, so we need to
666 * restart the pass 1 scan.
667 */
668 restart_e2fsck++;
669 return;
670 }
671
Theodore Ts'o3839e651997-04-26 13:21:57 +0000672 pb.num_blocks *= (fs->blocksize / 512);
673#if 0
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000674 printf("inode %u, i_size = %lu, last_block = %lu, i_blocks=%lu, num_blocks = %lu\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +0000675 ino, inode->i_size, pb.last_block, inode->i_blocks,
676 pb.num_blocks);
677#endif
678 if (!pb.num_blocks && pb.is_dir) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000679 if (fix_problem(fs, PR_1_ZERO_LENGTH_DIR, pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000680 inode->i_links_count = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000681 ext2fs_icount_store(inode_link_info, ino, 0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000682 inode->i_dtime = time(0);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000683 e2fsck_write_inode(fs, ino, inode, "check_blocks");
684 ext2fs_unmark_inode_bitmap(inode_dir_map, ino);
685 ext2fs_unmark_inode_bitmap(inode_used_map, ino);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000686 fs_directory_count--;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000687 pb.is_dir = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000688 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000689 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000690 if ((pb.is_dir && (inode->i_size !=
691 (pb.last_block + 1) * fs->blocksize)) ||
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000692 (inode->i_size < pb.last_block * fs->blocksize)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000693 pctx->num = (pb.last_block+1) * fs->blocksize;
694 if (fix_problem(fs, PR_1_BAD_I_SIZE, pctx)) {
695 inode->i_size = pctx->num;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000696 e2fsck_write_inode(fs, ino, inode, "check_blocks");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000697 }
698 pctx->num = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000699 }
700 if (pb.num_blocks != inode->i_blocks) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000701 pctx->num = pb.num_blocks;
702 if (fix_problem(fs, PR_1_BAD_I_BLOCKS, pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000703 inode->i_blocks = pb.num_blocks;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000704 e2fsck_write_inode(fs, ino, inode, "check_blocks");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000705 }
706 pctx->num = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000707 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000708}
709
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000710#if 0
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000711/*
712 * Helper function called by process block when an illegal block is
713 * found. It returns a description about why the block is illegal
714 */
715static char *describe_illegal_block(ext2_filsys fs, blk_t block)
716{
717 blk_t super;
718 int i;
719 static char problem[80];
720
721 super = fs->super->s_first_data_block;
722 strcpy(problem, "PROGRAMMING ERROR: Unknown reason for illegal block");
723 if (block < super) {
724 sprintf(problem, "< FIRSTBLOCK (%u)", super);
725 return(problem);
726 } else if (block >= fs->super->s_blocks_count) {
727 sprintf(problem, "> BLOCKS (%u)", fs->super->s_blocks_count);
728 return(problem);
729 }
730 for (i = 0; i < fs->group_desc_count; i++) {
731 if (block == super) {
732 sprintf(problem, "is the superblock in group %d", i);
733 break;
734 }
735 if (block > super &&
736 block <= (super + fs->desc_blocks)) {
737 sprintf(problem, "is in the group descriptors "
738 "of group %d", i);
739 break;
740 }
741 if (block == fs->group_desc[i].bg_block_bitmap) {
742 sprintf(problem, "is the block bitmap of group %d", i);
743 break;
744 }
745 if (block == fs->group_desc[i].bg_inode_bitmap) {
746 sprintf(problem, "is the inode bitmap of group %d", i);
747 break;
748 }
749 if (block >= fs->group_desc[i].bg_inode_table &&
750 (block < fs->group_desc[i].bg_inode_table
751 + fs->inode_blocks_per_group)) {
752 sprintf(problem, "is in the inode table of group %d",
753 i);
754 break;
755 }
756 super += fs->super->s_blocks_per_group;
757 }
758 return(problem);
759}
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000760#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +0000761
762/*
763 * This is a helper function for check_blocks().
764 */
765int process_block(ext2_filsys fs,
766 blk_t *block_nr,
767 int blockcnt,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000768 blk_t ref_block,
769 int ref_offset,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000770 void *private)
771{
772 struct process_block_struct *p;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000773 struct problem_context *pctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000774 blk_t blk = *block_nr;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000775 int ret_code = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000776 int problem = 0;
777 errcode_t retval;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000778
Theodore Ts'o3839e651997-04-26 13:21:57 +0000779 p = (struct process_block_struct *) private;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000780 pctx = p->pctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000781
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000782 if (blk == 0) {
783 if (p->is_dir == 0) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000784 /*
785 * Should never happen, since only directories
786 * get called with BLOCK_FLAG_HOLE
787 */
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000788 printf("process_block() called with blk == 0, "
Theodore Ts'o5c576471997-04-29 15:29:49 +0000789 "blockcnt=%d, inode %lu???\n",
790 blockcnt, p->ino);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000791 return 0;
792 }
793 if (blockcnt < 0)
794 return 0;
795 if (blockcnt * fs->blocksize < p->inode->i_size) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000796#if 0
797 printf("Missing block (#%d) in directory inode %lu!\n",
798 blockcnt, p->ino);
799#endif
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000800 goto mark_dir;
801 }
802 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000803 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000804
805#if 0
806 printf("Process_block, inode %lu, block %u, #%d\n", p->ino, blk,
807 blockcnt);
808#endif
809
Theodore Ts'o74becf31997-04-26 14:37:06 +0000810 /*
811 * Simplistic fragmentation check. We merely require that the
812 * file be contiguous. (Which can never be true for really
813 * big files that are greater than a block group.)
814 */
815 if (p->previous_block) {
816 if (p->previous_block+1 != blk)
817 p->fragmented = 1;
818 }
819 p->previous_block = blk;
820
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000821 if (blk < fs->super->s_first_data_block ||
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000822 blk >= fs->super->s_blocks_count)
823 problem = PR_1_ILLEGAL_BLOCK_NUM;
Theodore Ts'o521e3681997-04-29 17:48:10 +0000824#if 0
825 else
826 if (ext2fs_test_block_bitmap(block_illegal_map, blk))
827 problem = PR_1_BLOCK_OVERLAPS_METADATA;
828#endif
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000829
830 if (problem) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000831 p->num_illegal_blocks++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000832 if (!p->suppress && (p->num_illegal_blocks % 12) == 0) {
833 if (fix_problem(fs, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000834 p->clear = 1;
835 return BLOCK_ABORT;
836 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000837 if (ask("Suppress messages", 0)) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000838 p->suppress = 1;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000839 suppress_latch_group(PR_LATCH_BLOCK, 1);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000840 }
841 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000842 pctx->blk = blk;
843 pctx->blkcount = blockcnt;
844 if (fix_problem(fs, problem, pctx)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000845 blk = *block_nr = 0;
846 ret_code = BLOCK_CHANGED;
847 goto mark_dir;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000848 } else
Theodore Ts'o3839e651997-04-26 13:21:57 +0000849 return 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000850 pctx->blk = 0;
851 pctx->blkcount = -1;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000852 }
853
854 mark_block_used(fs, blk);
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000855 p->num_blocks++;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000856 if (blockcnt >= 0)
857 p->last_block = blockcnt;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000858mark_dir:
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000859 if (p->is_dir && (blockcnt >= 0)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000860 retval = ext2fs_add_dir_block(fs->dblist, p->ino,
861 blk, blockcnt);
862 if (retval) {
863 com_err(program_name, retval,
864 "while adding to directory block list");
865 fatal_error(0);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000866 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000867 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000868 return ret_code;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000869}
870
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000871static void bad_block_indirect(ext2_filsys fs, blk_t blk)
Theodore Ts'of3db3561997-04-26 13:34:30 +0000872{
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000873 printf("Bad block %u used as bad block indirect block?!?\n", blk);
874 preenhalt(fs);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000875 printf("\nThis inconsistency can not be fixed with "
876 "e2fsck; to fix it, use\n"
877 """dumpe2fs -b"" to dump out the bad block "
878 "list and ""e2fsck -L filename""\n"
879 "to read it back in again.\n");
880 if (ask("Continue", 0))
881 return;
882 fatal_error(0);
883}
884
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000885static int bad_primary_block(ext2_filsys fs, blk_t *block_nr)
886{
887 printf("\nIf the block is really bad, the filesystem can not be "
888 "fixed.\n");
889 preenhalt(fs);
890 printf("You can clear the this block from the bad block list\n");
891 printf("and hope that block is really OK, but there are no "
892 "guarantees.\n\n");
893 if (ask("Clear (and hope for the best)", 1)) {
894 *block_nr = 0;
895 return 1;
896 }
897 ext2fs_unmark_valid(fs);
898 return 0;
899}
900
Theodore Ts'o3839e651997-04-26 13:21:57 +0000901int process_bad_block(ext2_filsys fs,
902 blk_t *block_nr,
903 int blockcnt,
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000904 blk_t ref_block,
905 int ref_offset,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000906 void *private)
907{
908 struct process_block_struct *p;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000909 blk_t blk = *block_nr;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000910 int first_block;
911 int i;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000912 struct problem_context *pctx;
913
Theodore Ts'o3839e651997-04-26 13:21:57 +0000914 if (!blk)
915 return 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000916
Theodore Ts'o3839e651997-04-26 13:21:57 +0000917 p = (struct process_block_struct *) private;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000918 pctx = p->pctx;
919
920 pctx->blk = blk;
921 pctx->blkcount = blockcnt;
922
Theodore Ts'o3839e651997-04-26 13:21:57 +0000923
924 if ((blk < fs->super->s_first_data_block) ||
925 (blk >= fs->super->s_blocks_count)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000926 if (fix_problem(fs, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000927 *block_nr = 0;
928 return BLOCK_CHANGED;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000929 } else
Theodore Ts'o3839e651997-04-26 13:21:57 +0000930 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000931 }
932
933 if (blockcnt < 0) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000934 if (ext2fs_test_block_bitmap(block_found_map, blk))
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000935 bad_block_indirect(fs, blk);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000936 else
937 mark_block_used(fs, blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000938 return 0;
939 }
940#if 0
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000941 printf ("DEBUG: Marking %u as bad.\n", blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000942#endif
943 fs_badblocks_count++;
944 /*
945 * If the block is not used, then mark it as used and return.
946 * If it is already marked as found, this must mean that
947 * there's an overlap between the filesystem table blocks
948 * (bitmaps and inode table) and the bad block list.
949 */
Theodore Ts'of3db3561997-04-26 13:34:30 +0000950 if (!ext2fs_test_block_bitmap(block_found_map, blk)) {
951 ext2fs_mark_block_bitmap(block_found_map, blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000952 return 0;
953 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000954 /*
955 * Try to find the where the filesystem block was used...
956 */
957 first_block = fs->super->s_first_data_block;
958
959 for (i = 0; i < fs->group_desc_count; i++ ) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000960 pctx->group = i;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000961 if (blk == first_block) {
962 if (i == 0) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000963 printf("The primary superblock (%u) is "
964 "on the bad block list.\n", blk);
965 if (bad_primary_block(fs, block_nr))
966 return BLOCK_CHANGED;
967 return 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000968 }
969 if (!preen)
970 printf("Warning: Group %d's superblock "
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000971 "(%u) is bad.\n", i, blk);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000972 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000973 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000974 if ((blk > first_block) &&
975 (blk <= first_block + fs->desc_blocks)) {
976 if (i == 0) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000977 printf("Block %u in the primary group "
978 "descriptors is on the bad block "
979 "list\n", blk);
980 if (bad_primary_block(fs, block_nr))
981 return BLOCK_CHANGED;
982 return 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000983 }
984 if (!preen)
985 printf("Warning: Group %d's copy of the "
986 "group descriptors has a bad "
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000987 "block (%u).\n", i, blk);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000988 return 0;
989 }
990 if (blk == fs->group_desc[i].bg_block_bitmap) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000991 if (fix_problem(fs, PR_1_BB_BAD_BLOCK, pctx)) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000992 invalid_block_bitmap[i]++;
993 invalid_bitmaps++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000994 }
Theodore Ts'of3db3561997-04-26 13:34:30 +0000995 return 0;
996 }
997 if (blk == fs->group_desc[i].bg_inode_bitmap) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000998 if (fix_problem(fs, PR_1_IB_BAD_BLOCK, pctx)) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000999 invalid_inode_bitmap[i]++;
1000 invalid_bitmaps++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001001 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001002 return 0;
1003 }
1004 if ((blk >= fs->group_desc[i].bg_inode_table) &&
1005 (blk < (fs->group_desc[i].bg_inode_table +
1006 fs->inode_blocks_per_group))) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001007 /*
1008 * If there are bad blocks in the inode table,
1009 * the inode scan code will try to do
1010 * something reasonable automatically.
1011 */
Theodore Ts'of3db3561997-04-26 13:34:30 +00001012 return 0;
1013 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001014 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001015 /*
1016 * If we've gotten to this point, then the only
1017 * possibility is that the bad block inode meta data
1018 * is using a bad block.
1019 */
1020 if ((blk == p->inode->i_block[EXT2_IND_BLOCK]) ||
1021 p->inode->i_block[EXT2_DIND_BLOCK]) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001022 bad_block_indirect(fs, blk);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001023 return 0;
1024 }
1025
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001026 printf("Programming error? block #%u claimed for no reason "
Theodore Ts'of3db3561997-04-26 13:34:30 +00001027 "in process_bad_block.\n", blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001028 return 0;
1029}
1030
Theodore Ts'of3db3561997-04-26 13:34:30 +00001031static void new_table_block(ext2_filsys fs, blk_t first_block, int group,
Theodore Ts'o3839e651997-04-26 13:21:57 +00001032 const char *name, int num, blk_t *new_block)
1033{
1034 errcode_t retval;
1035 blk_t old_block = *new_block;
1036 int i;
1037 char *buf;
1038
1039 retval = ext2fs_get_free_blocks(fs, first_block,
1040 first_block + fs->super->s_blocks_per_group,
1041 num, block_found_map, new_block);
1042 if (retval) {
1043 printf("Could not allocate %d block(s) for %s: %s\n",
1044 num, name, error_message(retval));
1045 ext2fs_unmark_valid(fs);
1046 return;
1047 }
1048 buf = malloc(fs->blocksize);
1049 if (!buf) {
1050 printf("Could not allocate block buffer for relocating %s\n",
1051 name);
1052 ext2fs_unmark_valid(fs);
1053 return;
1054 }
1055 ext2fs_mark_super_dirty(fs);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001056 printf("Relocating group %d's %s ", group, name);
1057 if (old_block)
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001058 printf("from %u ", old_block);
1059 printf("to %u...\n", *new_block);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001060 for (i = 0; i < num; i++) {
Theodore Ts'of3db3561997-04-26 13:34:30 +00001061 ext2fs_mark_block_bitmap(block_found_map, (*new_block)+i);
1062 if (old_block) {
1063 retval = io_channel_read_blk(fs->io, old_block + i,
1064 1, buf);
1065 if (retval)
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001066 printf("Warning: could not read block %u "
Theodore Ts'of3db3561997-04-26 13:34:30 +00001067 "of %s: %s\n",
1068 old_block + i, name,
1069 error_message(retval));
1070 } else
1071 memset(buf, 0, fs->blocksize);
1072
Theodore Ts'o3839e651997-04-26 13:21:57 +00001073 retval = io_channel_write_blk(fs->io, (*new_block) + i,
1074 1, buf);
1075 if (retval)
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001076 printf("Warning: could not write block %u for %s: %s\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +00001077 (*new_block) + i, name, error_message(retval));
Theodore Ts'o3839e651997-04-26 13:21:57 +00001078 }
1079 free(buf);
1080}
1081
1082/*
Theodore Ts'of3db3561997-04-26 13:34:30 +00001083 * This routine gets called at the end of pass 1 if bad blocks are
1084 * detected in the superblock, group descriptors, inode_bitmaps, or
1085 * block bitmaps. At this point, all of the blocks have been mapped
1086 * out, so we can try to allocate new block(s) to replace the bad
1087 * blocks.
Theodore Ts'o3839e651997-04-26 13:21:57 +00001088 */
Theodore Ts'of3db3561997-04-26 13:34:30 +00001089static void handle_fs_bad_blocks(ext2_filsys fs)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001090{
Theodore Ts'of3db3561997-04-26 13:34:30 +00001091 int i;
1092 int first_block = fs->super->s_first_data_block;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001093
1094 for (i = 0; i < fs->group_desc_count; i++) {
Theodore Ts'of3db3561997-04-26 13:34:30 +00001095 if (invalid_block_bitmap[i]) {
1096 new_table_block(fs, first_block, i, "block bitmap", 1,
Theodore Ts'o3839e651997-04-26 13:21:57 +00001097 &fs->group_desc[i].bg_block_bitmap);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001098 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001099 if (invalid_inode_bitmap[i]) {
1100 new_table_block(fs, first_block, i, "inode bitmap", 1,
Theodore Ts'o3839e651997-04-26 13:21:57 +00001101 &fs->group_desc[i].bg_inode_bitmap);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001102 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001103 if (invalid_inode_table[i]) {
1104 new_table_block(fs, first_block, i, "inode table",
1105 fs->inode_blocks_per_group,
Theodore Ts'o3839e651997-04-26 13:21:57 +00001106 &fs->group_desc[i].bg_inode_table);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001107 restart_e2fsck++;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001108 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001109 first_block += fs->super->s_blocks_per_group;
1110 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001111 invalid_bitmaps = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001112}
1113
1114/*
1115 * This routine marks all blocks which are used by the superblock,
1116 * group descriptors, inode bitmaps, and block bitmaps.
1117 */
1118static void mark_table_blocks(ext2_filsys fs)
1119{
Theodore Ts'of3db3561997-04-26 13:34:30 +00001120 blk_t block, b;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001121 int i,j;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001122 struct problem_context pctx;
1123
1124 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001125
1126 block = fs->super->s_first_data_block;
1127 for (i = 0; i < fs->group_desc_count; i++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001128 pctx.group = i;
1129 /*
1130 * Mark the blocks used for the inode table
1131 */
1132 if (fs->group_desc[i].bg_inode_table) {
1133 for (j = 0, b = fs->group_desc[i].bg_inode_table;
1134 j < fs->inode_blocks_per_group;
1135 j++, b++) {
1136 if (ext2fs_test_block_bitmap(block_found_map,
1137 b)) {
1138 pctx.blk = b;
1139 if (fix_problem(fs,
1140 PR_1_ITABLE_CONFLICT, &pctx)) {
1141 invalid_inode_table[i]++;
1142 invalid_bitmaps++;
1143 }
1144 } else {
1145 ext2fs_mark_block_bitmap(block_found_map,
1146 b);
1147 ext2fs_mark_block_bitmap(block_illegal_map,
1148 b);
1149 }
1150 }
1151 }
1152
Theodore Ts'o3839e651997-04-26 13:21:57 +00001153 /*
1154 * Mark block used for the block bitmap
1155 */
Theodore Ts'of3db3561997-04-26 13:34:30 +00001156 if (fs->group_desc[i].bg_block_bitmap) {
1157 if (ext2fs_test_block_bitmap(block_found_map,
1158 fs->group_desc[i].bg_block_bitmap)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001159 pctx.blk = fs->group_desc[i].bg_block_bitmap;
1160 if (fix_problem(fs, PR_1_BB_CONFLICT, &pctx)) {
Theodore Ts'of3db3561997-04-26 13:34:30 +00001161 invalid_block_bitmap[i]++;
1162 invalid_bitmaps++;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001163 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001164 } else {
Theodore Ts'of3db3561997-04-26 13:34:30 +00001165 ext2fs_mark_block_bitmap(block_found_map,
1166 fs->group_desc[i].bg_block_bitmap);
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001167 ext2fs_mark_block_bitmap(block_illegal_map,
1168 fs->group_desc[i].bg_block_bitmap);
1169 }
1170
Theodore Ts'of3db3561997-04-26 13:34:30 +00001171 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001172 /*
1173 * Mark block used for the inode bitmap
1174 */
Theodore Ts'of3db3561997-04-26 13:34:30 +00001175 if (fs->group_desc[i].bg_inode_bitmap) {
1176 if (ext2fs_test_block_bitmap(block_found_map,
1177 fs->group_desc[i].bg_inode_bitmap)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001178 pctx.blk = fs->group_desc[i].bg_inode_bitmap;
1179 if (fix_problem(fs, PR_1_IB_CONFLICT, &pctx)) {
Theodore Ts'of3db3561997-04-26 13:34:30 +00001180 invalid_inode_bitmap[i]++;
1181 invalid_bitmaps++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001182 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001183 } else {
Theodore Ts'of3db3561997-04-26 13:34:30 +00001184 ext2fs_mark_block_bitmap(block_found_map,
1185 fs->group_desc[i].bg_inode_bitmap);
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001186 ext2fs_mark_block_bitmap(block_illegal_map,
1187 fs->group_desc[i].bg_inode_bitmap);
1188 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001189 }
Theodore Ts'o521e3681997-04-29 17:48:10 +00001190
1191 if (ext2fs_bg_has_super(fs, i)) {
1192 /*
1193 * Mark this group's copy of the superblock
1194 */
1195 ext2fs_mark_block_bitmap(block_found_map, block);
1196 ext2fs_mark_block_bitmap(block_illegal_map, block);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001197
Theodore Ts'o521e3681997-04-29 17:48:10 +00001198 /*
1199 * Mark this group's copy of the descriptors
1200 */
1201 for (j = 0; j < fs->desc_blocks; j++) {
1202 ext2fs_mark_block_bitmap(block_found_map,
1203 block + j + 1);
1204 ext2fs_mark_block_bitmap(block_illegal_map,
1205 block + j + 1);
1206 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001207 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001208 block += fs->super->s_blocks_per_group;
1209 }
1210}
1211
1212/*
1213 * This subroutines short circuits ext2fs_get_blocks and
1214 * ext2fs_check_directory; we use them since we already have the inode
1215 * structure, so there's no point in letting the ext2fs library read
1216 * the inode again.
1217 */
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001218errcode_t pass1_get_blocks(ext2_filsys fs, ino_t ino, blk_t *blocks)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001219{
1220 int i;
1221
Theodore Ts'o521e3681997-04-29 17:48:10 +00001222 if (ino != stashed_ino)
1223 return EXT2_ET_CALLBACK_NOTHANDLED;
1224
1225 for (i=0; i < EXT2_N_BLOCKS; i++)
1226 blocks[i] = stashed_inode->i_block[i];
1227 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001228}
1229
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001230errcode_t pass1_read_inode(ext2_filsys fs, ino_t ino, struct ext2_inode *inode)
1231{
1232 if (ino != stashed_ino)
1233 return EXT2_ET_CALLBACK_NOTHANDLED;
1234 *inode = *stashed_inode;
1235 return 0;
1236}
1237
1238errcode_t pass1_write_inode(ext2_filsys fs, ino_t ino,
1239 struct ext2_inode *inode)
1240{
1241 if (ino == stashed_ino)
1242 *stashed_inode = *inode;
1243 return EXT2_ET_CALLBACK_NOTHANDLED;
1244}
1245
1246errcode_t pass1_check_directory(ext2_filsys fs, ino_t ino)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001247{
1248 if (ino == stashed_ino) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001249 if (!LINUX_S_ISDIR(stashed_inode->i_mode))
Theodore Ts'o3839e651997-04-26 13:21:57 +00001250 return ENOTDIR;
1251 return 0;
1252 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00001253 printf("INTERNAL ERROR: pass1_check_directory: unexpected inode #%lu\n",
Theodore Ts'o3839e651997-04-26 13:21:57 +00001254 ino);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001255 printf("\t(was expecting %lu)\n", stashed_ino);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001256 exit(FSCK_ERROR);
1257}