blob: ef04b6fc733fd943faaa0401b501b9c4ae0ee2af [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
Theodore Ts'oefc6f622008-08-27 23:07:54 -04003 *
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'oefc6f622008-08-27 23:07:54 -040010 *
Theodore Ts'o3839e651997-04-26 13:21:57 +000011 * 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)
Theodore Ts'oaa4115a1999-10-21 19:33:18 +000022 * - A bitmap of which inodes are regular files. (inode_reg_map)
Theodore Ts'o3839e651997-04-26 13:21:57 +000023 * - A bitmap of which inodes have bad fields. (inode_bad_map)
Theodore Ts'o21c84b71997-04-29 16:15:03 +000024 * - A bitmap of which inodes are in bad blocks. (inode_bb_map)
Theodore Ts'oaa4115a1999-10-21 19:33:18 +000025 * - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
Theodore Ts'o3839e651997-04-26 13:21:57 +000026 * - A bitmap of which blocks are in use. (block_found_map)
27 * - A bitmap of which blocks are in use by two inodes (block_dup_map)
28 * - The data blocks of the directory inodes. (dir_map)
29 *
30 * Pass 1 is designed to stash away enough information so that the
31 * other passes should not need to read in the inode information
32 * during the normal course of a filesystem check. (Althogh if an
33 * inconsistency is detected, other passes may need to read in an
34 * inode to fix it.)
35 *
36 * Note that pass 1B will be invoked if there are any duplicate blocks
37 * found.
38 */
39
Matthias Andreeb969b1b2003-12-28 13:04:35 +010040#define _GNU_SOURCE 1 /* get strnlen() */
Theodore Ts'o3e699062002-10-13 23:56:28 -040041#include <string.h>
Theodore Ts'o3839e651997-04-26 13:21:57 +000042#include <time.h>
Theodore Ts'o50e1e101997-04-26 13:58:21 +000043#ifdef HAVE_ERRNO_H
44#include <errno.h>
45#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +000046
Theodore Ts'o3839e651997-04-26 13:21:57 +000047#include "e2fsck.h"
Theodore Ts'o342d8472001-07-02 11:54:09 -040048#include <ext2fs/ext2_ext_attr.h>
49
Theodore Ts'o21c84b71997-04-29 16:15:03 +000050#include "problem.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000051
Theodore Ts'o50e1e101997-04-26 13:58:21 +000052#ifdef NO_INLINE_FUNCS
53#define _INLINE_
54#else
55#define _INLINE_ inline
56#endif
57
JP Abgralle0ed7402014-03-19 19:08:39 -070058static int process_block(ext2_filsys fs, blk64_t *blocknr,
59 e2_blkcnt_t blockcnt, blk64_t ref_blk,
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +000060 int ref_offset, void *priv_data);
JP Abgralle0ed7402014-03-19 19:08:39 -070061static int process_bad_block(ext2_filsys fs, blk64_t *block_nr,
62 e2_blkcnt_t blockcnt, blk64_t ref_blk,
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +000063 int ref_offset, void *priv_data);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000064static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
Theodore Ts'o3839e651997-04-26 13:21:57 +000065 char *block_buf);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000066static void mark_table_blocks(e2fsck_t ctx);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000067static void alloc_bb_map(e2fsck_t ctx);
Theodore Ts'oaa4115a1999-10-21 19:33:18 +000068static void alloc_imagic_map(e2fsck_t ctx);
Theodore Ts'ofdbdea02001-06-02 04:26:26 +000069static void mark_inode_bad(e2fsck_t ctx, ino_t ino);
Theodore Ts'o890a2f92015-07-14 22:50:51 -040070static void add_encrypted_dir(e2fsck_t ctx, ino_t ino);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000071static void handle_fs_bad_blocks(e2fsck_t ctx);
72static void process_inodes(e2fsck_t ctx, char *block_buf);
Theodore Ts'o4c77fe51998-04-30 17:35:59 +000073static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b);
Theodore Ts'of3db3561997-04-26 13:34:30 +000074static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan,
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +000075 dgrp_t group, void * priv_data);
Theodore Ts'oefc6f622008-08-27 23:07:54 -040076static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
Theodore Ts'oe8a3ee62001-07-07 11:12:50 -040077 char *block_buf, int adjust_sign);
JP Abgralle0ed7402014-03-19 19:08:39 -070078/* static char *describe_illegal_block(ext2_filsys fs, blk64_t block); */
Theodore Ts'o3839e651997-04-26 13:21:57 +000079
80struct process_block_struct {
Theodore Ts'o86c627e2001-01-11 15:12:14 +000081 ext2_ino_t ino;
Matthias Andree83e692e2004-03-30 04:17:14 +020082 unsigned is_dir:1, is_reg:1, clear:1, suppress:1,
Theodore Ts'o000ba402003-11-21 10:41:58 -050083 fragmented:1, compressed:1, bbcheck:1;
Eric Sandeen65d71892010-03-30 11:42:51 -050084 blk64_t num_blocks;
JP Abgralle0ed7402014-03-19 19:08:39 -070085 blk64_t max_blocks;
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +000086 e2_blkcnt_t last_block;
JP Abgralle0ed7402014-03-19 19:08:39 -070087 e2_blkcnt_t last_init_lblock;
Theodore Ts'o4dbe79b2009-11-28 09:35:37 -050088 e2_blkcnt_t last_db_block;
Theodore Ts'o246501c1998-03-24 16:22:38 +000089 int num_illegal_blocks;
JP Abgralle0ed7402014-03-19 19:08:39 -070090 blk64_t previous_block;
Theodore Ts'of3db3561997-04-26 13:34:30 +000091 struct ext2_inode *inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +000092 struct problem_context *pctx;
Theodore Ts'o000ba402003-11-21 10:41:58 -050093 ext2fs_block_bitmap fs_meta_blocks;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000094 e2fsck_t ctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +000095};
96
97struct process_inode_block {
Theodore Ts'o86c627e2001-01-11 15:12:14 +000098 ext2_ino_t ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +000099 struct ext2_inode inode;
100};
101
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000102struct scan_callback_struct {
103 e2fsck_t ctx;
104 char *block_buf;
105};
106
Theodore Ts'o3839e651997-04-26 13:21:57 +0000107/*
Theodore Ts'o3839e651997-04-26 13:21:57 +0000108 * For the inodes to process list.
109 */
110static struct process_inode_block *inodes_to_process;
111static int process_inode_count;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000112
Theodore Ts'o7823dd62002-05-17 23:37:42 -0400113static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE -
114 EXT2_MIN_BLOCK_LOG_SIZE + 1];
Theodore Ts'o246501c1998-03-24 16:22:38 +0000115
Theodore Ts'o3839e651997-04-26 13:21:57 +0000116/*
Theodore Ts'of3db3561997-04-26 13:34:30 +0000117 * Free all memory allocated by pass1 in preparation for restarting
118 * things.
119 */
Theodore Ts'o54434922003-12-07 01:28:50 -0500120static void unwind_pass1(ext2_filsys fs EXT2FS_ATTR((unused)))
Theodore Ts'of3db3561997-04-26 13:34:30 +0000121{
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400122 ext2fs_free_mem(&inodes_to_process);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000123 inodes_to_process = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000124}
125
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000126/*
127 * Check to make sure a device inode is real. Returns 1 if the device
128 * checks out, 0 if not.
Theodore Ts'o1dde43f1998-11-14 04:18:28 +0000129 *
130 * Note: this routine is now also used to check FIFO's and Sockets,
131 * since they have the same requirement; the i_block fields should be
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400132 * zero.
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000133 */
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400134int e2fsck_pass1_check_device_inode(ext2_filsys fs EXT2FS_ATTR((unused)),
Theodore Ts'of954ba02007-05-22 20:53:01 -0400135 struct ext2_inode *inode)
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000136{
137 int i;
138
Theodore Ts'o7fdfabd1997-11-24 11:51:17 +0000139 /*
Theodore Ts'o441ab1e2007-03-31 18:56:09 -0400140 * If the index flag is set, then this is a bogus
141 * device/fifo/socket
Theodore Ts'oa40ecbb2001-08-13 06:15:36 -0400142 */
Theodore Ts'o441ab1e2007-03-31 18:56:09 -0400143 if (inode->i_flags & EXT2_INDEX_FL)
Theodore Ts'o53abed02001-08-27 12:18:16 -0400144 return 0;
Theodore Ts'obcf9c5d2002-05-21 09:14:17 -0400145
Theodore Ts'oa40ecbb2001-08-13 06:15:36 -0400146 /*
Theodore Ts'o7fdfabd1997-11-24 11:51:17 +0000147 * We should be able to do the test below all the time, but
148 * because the kernel doesn't forcibly clear the device
149 * inode's additional i_block fields, there are some rare
150 * occasions when a legitimate device inode will have non-zero
151 * additional i_block fields. So for now, we only complain
152 * when the immutable flag is set, which should never happen
153 * for devices. (And that's when the problem is caused, since
154 * you can't set or clear immutable flags for devices.) Once
155 * the kernel has been fixed we can change this...
156 */
Theodore Ts'o01fbc702000-04-03 13:57:21 +0000157 if (inode->i_flags & (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)) {
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400158 for (i=4; i < EXT2_N_BLOCKS; i++)
Theodore Ts'o7fdfabd1997-11-24 11:51:17 +0000159 if (inode->i_block[i])
160 return 0;
161 }
Theodore Ts'o7cf73dc1997-08-14 17:17:16 +0000162 return 1;
163}
164
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +0000165/*
Andreas Dilger67052a82001-08-04 00:51:18 -0600166 * Check to make sure a symlink inode is real. Returns 1 if the symlink
167 * checks out, 0 if not.
168 */
Theodore Ts'o7cadc572008-03-13 23:05:00 -0400169int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino,
170 struct ext2_inode *inode, char *buf)
Andreas Dilger67052a82001-08-04 00:51:18 -0600171{
Theodore Ts'o54434922003-12-07 01:28:50 -0500172 unsigned int len;
Theodore Ts'od007cb42001-08-04 20:39:39 -0400173 int i;
JP Abgralle0ed7402014-03-19 19:08:39 -0700174 blk64_t blocks;
Theodore Ts'o7cadc572008-03-13 23:05:00 -0400175 ext2_extent_handle_t handle;
176 struct ext2_extent_info info;
177 struct ext2fs_extent extent;
Andreas Dilger67052a82001-08-04 00:51:18 -0600178
Theodore Ts'obcf9c5d2002-05-21 09:14:17 -0400179 if ((inode->i_size_high || inode->i_size == 0) ||
180 (inode->i_flags & EXT2_INDEX_FL))
Andreas Dilger67052a82001-08-04 00:51:18 -0600181 return 0;
182
Theodore Ts'o7cadc572008-03-13 23:05:00 -0400183 if (inode->i_flags & EXT4_EXTENTS_FL) {
184 if (inode->i_size > fs->blocksize)
185 return 0;
number965284b239a2009-05-19 13:34:12 -0700186 if (ext2fs_extent_open2(fs, ino, inode, &handle))
Theodore Ts'o7cadc572008-03-13 23:05:00 -0400187 return 0;
188 i = 0;
189 if (ext2fs_extent_get_info(handle, &info) ||
190 (info.num_entries != 1) ||
191 (info.max_depth != 0))
192 goto exit_extent;
193 if (ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent) ||
194 (extent.e_lblk != 0) ||
195 (extent.e_len != 1) ||
196 (extent.e_pblk < fs->super->s_first_data_block) ||
JP Abgralle0ed7402014-03-19 19:08:39 -0700197 (extent.e_pblk >= ext2fs_blocks_count(fs->super)))
Theodore Ts'o7cadc572008-03-13 23:05:00 -0400198 goto exit_extent;
199 i = 1;
200 exit_extent:
201 ext2fs_extent_free(handle);
202 return i;
203 }
204
JP Abgralle0ed7402014-03-19 19:08:39 -0700205 blocks = ext2fs_inode_data_blocks2(fs, inode);
Theodore Ts'o0684a4f2002-08-17 10:19:44 -0400206 if (blocks) {
Andreas Dilgerb94a0522002-05-18 13:16:30 -0600207 if ((inode->i_size >= fs->blocksize) ||
Theodore Ts'o0684a4f2002-08-17 10:19:44 -0400208 (blocks != fs->blocksize >> 9) ||
Theodore Ts'od007cb42001-08-04 20:39:39 -0400209 (inode->i_block[0] < fs->super->s_first_data_block) ||
JP Abgralle0ed7402014-03-19 19:08:39 -0700210 (inode->i_block[0] >= ext2fs_blocks_count(fs->super)))
Andreas Dilger67052a82001-08-04 00:51:18 -0600211 return 0;
212
213 for (i = 1; i < EXT2_N_BLOCKS; i++)
214 if (inode->i_block[i])
215 return 0;
Andreas Dilgerb94a0522002-05-18 13:16:30 -0600216
JP Abgralle0ed7402014-03-19 19:08:39 -0700217 if (io_channel_read_blk64(fs->io, inode->i_block[0], 1, buf))
Andreas Dilger67052a82001-08-04 00:51:18 -0600218 return 0;
219
Theodore Ts'o890a2f92015-07-14 22:50:51 -0400220 if (inode->i_flags & EXT4_ENCRYPT_FL) {
221 len = ext2fs_le32_to_cpu(*((__u32 *)buf)) + 4;
222 } else {
223 len = strnlen(buf, fs->blocksize);
224 }
Andreas Dilgerb94a0522002-05-18 13:16:30 -0600225 if (len == fs->blocksize)
226 return 0;
Andreas Dilgerb94a0522002-05-18 13:16:30 -0600227 } else {
228 if (inode->i_size >= sizeof(inode->i_block))
229 return 0;
230
231 len = strnlen((char *)inode->i_block, sizeof(inode->i_block));
232 if (len == sizeof(inode->i_block))
Andreas Dilger67052a82001-08-04 00:51:18 -0600233 return 0;
234 }
Andreas Dilgerb94a0522002-05-18 13:16:30 -0600235 if (len != inode->i_size)
Theodore Ts'o890a2f92015-07-14 22:50:51 -0400236 if ((inode->i_flags & EXT4_ENCRYPT_FL) == 0)
237 return 0;
Andreas Dilger67052a82001-08-04 00:51:18 -0600238 return 1;
239}
240
241/*
Theodore Ts'o01fbc702000-04-03 13:57:21 +0000242 * If the immutable (or append-only) flag is set on the inode, offer
243 * to clear it.
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +0000244 */
Theodore Ts'obcf9c5d2002-05-21 09:14:17 -0400245#define BAD_SPECIAL_FLAGS (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +0000246static void check_immutable(e2fsck_t ctx, struct problem_context *pctx)
247{
Andreas Dilgerb94a0522002-05-18 13:16:30 -0600248 if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS))
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +0000249 return;
250
251 if (!fix_problem(ctx, PR_1_SET_IMMUTABLE, pctx))
252 return;
253
Andreas Dilgerb94a0522002-05-18 13:16:30 -0600254 pctx->inode->i_flags &= ~BAD_SPECIAL_FLAGS;
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +0000255 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
256}
257
Theodore Ts'od647a1e2000-05-27 14:40:09 +0000258/*
259 * If device, fifo or socket, check size is zero -- if not offer to
260 * clear it
261 */
262static void check_size(e2fsck_t ctx, struct problem_context *pctx)
263{
264 struct ext2_inode *inode = pctx->inode;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400265
JP Abgralle0ed7402014-03-19 19:08:39 -0700266 if (EXT2_I_SIZE(inode) == 0)
Theodore Ts'od647a1e2000-05-27 14:40:09 +0000267 return;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400268
Theodore Ts'o85645a6f2001-08-13 06:11:39 -0400269 if (!fix_problem(ctx, PR_1_SET_NONZSIZE, pctx))
Theodore Ts'od647a1e2000-05-27 14:40:09 +0000270 return;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400271
Theodore Ts'od647a1e2000-05-27 14:40:09 +0000272 inode->i_size = 0;
Theodore Ts'ofdbdea02001-06-02 04:26:26 +0000273 inode->i_size_high = 0;
Theodore Ts'od647a1e2000-05-27 14:40:09 +0000274 e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1");
275}
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400276
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500277static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
278{
279 struct ext2_super_block *sb = ctx->fs->super;
280 struct ext2_inode_large *inode;
281 struct ext2_ext_attr_entry *entry;
JP Abgralle0ed7402014-03-19 19:08:39 -0700282 char *start;
Kalpak Shah1a8c2c42007-05-08 01:07:30 -0400283 unsigned int storage_size, remain;
JP Abgralle0ed7402014-03-19 19:08:39 -0700284 problem_t problem = 0;
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500285
286 inode = (struct ext2_inode_large *) pctx->inode;
287 storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE -
288 inode->i_extra_isize;
289 start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
290 inode->i_extra_isize + sizeof(__u32);
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500291 entry = (struct ext2_ext_attr_entry *) start;
292
293 /* scan all entry's headers first */
294
295 /* take finish entry 0UL into account */
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400296 remain = storage_size - sizeof(__u32);
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500297
298 while (!EXT2_EXT_IS_LAST_ENTRY(entry)) {
Andreas Dilgerfefaef32008-02-02 01:16:32 -0700299 __u32 hash;
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500300
301 /* header eats this space */
302 remain -= sizeof(struct ext2_ext_attr_entry);
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400303
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500304 /* is attribute name valid? */
305 if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain) {
306 pctx->num = entry->e_name_len;
307 problem = PR_1_ATTR_NAME_LEN;
308 goto fix;
309 }
310
311 /* attribute len eats this space */
312 remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len);
313
314 /* check value size */
JP Abgralle0ed7402014-03-19 19:08:39 -0700315 if (entry->e_value_size > remain) {
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500316 pctx->num = entry->e_value_size;
317 problem = PR_1_ATTR_VALUE_SIZE;
318 goto fix;
319 }
320
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500321 /* e_value_block must be 0 in inode's ea */
322 if (entry->e_value_block != 0) {
323 pctx->num = entry->e_value_block;
324 problem = PR_1_ATTR_VALUE_BLOCK;
325 goto fix;
326 }
Andreas Dilgerfefaef32008-02-02 01:16:32 -0700327
328 hash = ext2fs_ext_attr_hash_entry(entry,
329 start + entry->e_value_offs);
330
331 /* e_hash may be 0 in older inode's ea */
332 if (entry->e_hash != 0 && entry->e_hash != hash) {
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500333 pctx->num = entry->e_hash;
334 problem = PR_1_ATTR_HASH;
335 goto fix;
336 }
337
338 remain -= entry->e_value_size;
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500339
340 entry = EXT2_EXT_ATTR_NEXT(entry);
341 }
342fix:
343 /*
344 * it seems like a corruption. it's very unlikely we could repair
345 * EA(s) in automatic fashion -bzzz
346 */
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500347 if (problem == 0 || !fix_problem(ctx, problem, pctx))
348 return;
349
Andreas Dilgerfefaef32008-02-02 01:16:32 -0700350 /* simply remove all possible EA(s) */
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500351 *((__u32 *)start) = 0UL;
Dmitry V. Levinda938f22007-10-20 22:10:26 +0400352 e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode,
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500353 EXT2_INODE_SIZE(sb), "pass1");
354}
355
356static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
357{
358 struct ext2_super_block *sb = ctx->fs->super;
359 struct ext2_inode_large *inode;
360 __u32 *eamagic;
361 int min, max;
362
363 inode = (struct ext2_inode_large *) pctx->inode;
364 if (EXT2_INODE_SIZE(sb) == EXT2_GOOD_OLD_INODE_SIZE) {
365 /* this isn't large inode. so, nothing to check */
366 return;
367 }
368
369#if 0
370 printf("inode #%u, i_extra_size %d\n", pctx->ino,
371 inode->i_extra_isize);
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400372#endif
JP Abgralle0ed7402014-03-19 19:08:39 -0700373 /* i_extra_isize must cover i_extra_isize + i_checksum_hi at least */
374 min = sizeof(inode->i_extra_isize) + sizeof(inode->i_checksum_hi);
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500375 max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400376 /*
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500377 * For now we will allow i_extra_isize to be 0, but really
378 * implementations should never allow i_extra_isize to be 0
379 */
380 if (inode->i_extra_isize &&
381 (inode->i_extra_isize < min || inode->i_extra_isize > max)) {
382 if (!fix_problem(ctx, PR_1_EXTRA_ISIZE, pctx))
383 return;
384 inode->i_extra_isize = min;
385 e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode,
386 EXT2_INODE_SIZE(sb), "pass1");
387 return;
388 }
389
390 eamagic = (__u32 *) (((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE +
391 inode->i_extra_isize);
392 if (*eamagic == EXT2_EXT_ATTR_MAGIC) {
393 /* it seems inode has an extended attribute(s) in body */
394 check_ea_in_inode(ctx, pctx);
395 }
396}
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +0000397
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400398/*
Theodore Ts'ofbc3f902007-04-02 10:08:59 -0400399 * Check to see if the inode might really be a directory, despite i_mode
400 *
401 * This is a lot of complexity for something for which I'm not really
402 * convinced happens frequently in the wild. If for any reason this
403 * causes any problems, take this code out.
404 * [tytso:20070331.0827EDT]
405 */
406static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx,
407 char *buf)
408{
409 struct ext2_inode *inode = pctx->inode;
Theodore Ts'ofbc3f902007-04-02 10:08:59 -0400410 struct ext2_dir_entry *dirent;
Theodore Ts'oe94bc632007-04-14 09:29:02 -0400411 errcode_t retval;
JP Abgralle0ed7402014-03-19 19:08:39 -0700412 blk64_t blk;
Theodore Ts'o03fa6f82008-11-16 10:03:00 -0500413 unsigned int i, rec_len, not_device = 0;
Nick Dokos1ec42a02010-02-05 10:35:17 -0500414 int extent_fs;
Theodore Ts'ofbc3f902007-04-02 10:08:59 -0400415
Nick Dokos1ec42a02010-02-05 10:35:17 -0500416 /*
417 * If the mode looks OK, we believe it. If the first block in
418 * the i_block array is 0, this cannot be a directory. If the
419 * inode is extent-mapped, it is still the case that the latter
420 * cannot be 0 - the magic number in the extent header would make
421 * it nonzero.
422 */
Theodore Ts'ofbc3f902007-04-02 10:08:59 -0400423 if (LINUX_S_ISDIR(inode->i_mode) || LINUX_S_ISREG(inode->i_mode) ||
Theodore Ts'o0eeb1542007-04-14 12:01:39 -0400424 LINUX_S_ISLNK(inode->i_mode) || inode->i_block[0] == 0)
Theodore Ts'ofbc3f902007-04-02 10:08:59 -0400425 return;
426
Nick Dokos1ec42a02010-02-05 10:35:17 -0500427 /*
428 * Check the block numbers in the i_block array for validity:
429 * zero blocks are skipped (but the first one cannot be zero -
430 * see above), other blocks are checked against the first and
431 * max data blocks (from the the superblock) and against the
432 * block bitmap. Any invalid block found means this cannot be
433 * a directory.
434 *
435 * If there are non-zero blocks past the fourth entry, then
436 * this cannot be a device file: we remember that for the next
437 * check.
438 *
439 * For extent mapped files, we don't do any sanity checking:
440 * just try to get the phys block of logical block 0 and run
441 * with it.
442 */
Theodore Ts'ofbc3f902007-04-02 10:08:59 -0400443
JP Abgralle0ed7402014-03-19 19:08:39 -0700444 extent_fs = (ctx->fs->super->s_feature_incompat &
445 EXT3_FEATURE_INCOMPAT_EXTENTS);
Nick Dokos1ec42a02010-02-05 10:35:17 -0500446 if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) {
447 /* extent mapped */
JP Abgralle0ed7402014-03-19 19:08:39 -0700448 if (ext2fs_bmap2(ctx->fs, pctx->ino, inode, 0, 0, 0, 0,
Nick Dokos1ec42a02010-02-05 10:35:17 -0500449 &blk))
450 return;
451 /* device files are never extent mapped */
452 not_device++;
453 } else {
454 for (i=0; i < EXT2_N_BLOCKS; i++) {
455 blk = inode->i_block[i];
456 if (!blk)
457 continue;
458 if (i >= 4)
459 not_device++;
460
461 if (blk < ctx->fs->super->s_first_data_block ||
JP Abgralle0ed7402014-03-19 19:08:39 -0700462 blk >= ext2fs_blocks_count(ctx->fs->super) ||
463 ext2fs_fast_test_block_bitmap2(ctx->block_found_map,
464 blk))
Nick Dokos1ec42a02010-02-05 10:35:17 -0500465 return; /* Invalid block, can't be dir */
466 }
467 blk = inode->i_block[0];
Theodore Ts'ofbc3f902007-04-02 10:08:59 -0400468 }
469
Nick Dokos1ec42a02010-02-05 10:35:17 -0500470 /*
471 * If the mode says this is a device file and the i_links_count field
472 * is sane and we have not ruled it out as a device file previously,
473 * we declare it a device file, not a directory.
474 */
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400475 if ((LINUX_S_ISCHR(inode->i_mode) || LINUX_S_ISBLK(inode->i_mode)) &&
Theodore Ts'ofbc3f902007-04-02 10:08:59 -0400476 (inode->i_links_count == 1) && !not_device)
477 return;
478
Nick Dokos1ec42a02010-02-05 10:35:17 -0500479 /* read the first block */
JP Abgralle0ed7402014-03-19 19:08:39 -0700480 ehandler_operation(_("reading directory block"));
481 retval = ext2fs_read_dir_block3(ctx->fs, blk, buf, 0);
Theodore Ts'oe94bc632007-04-14 09:29:02 -0400482 ehandler_operation(0);
483 if (retval)
Theodore Ts'ofbc3f902007-04-02 10:08:59 -0400484 return;
485
486 dirent = (struct ext2_dir_entry *) buf;
Theodore Ts'o8a480352009-06-21 21:07:38 -0400487 retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
488 if (retval)
489 return;
Theodore Ts'ofbc3f902007-04-02 10:08:59 -0400490 if (((dirent->name_len & 0xFF) != 1) ||
491 (dirent->name[0] != '.') ||
492 (dirent->inode != pctx->ino) ||
Theodore Ts'o5dd77db2008-08-25 21:08:19 -0400493 (rec_len < 12) ||
494 (rec_len % 4) ||
495 (rec_len >= ctx->fs->blocksize - 12))
Theodore Ts'ofbc3f902007-04-02 10:08:59 -0400496 return;
497
Theodore Ts'o5dd77db2008-08-25 21:08:19 -0400498 dirent = (struct ext2_dir_entry *) (buf + rec_len);
Theodore Ts'o8a480352009-06-21 21:07:38 -0400499 retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len);
500 if (retval)
501 return;
Theodore Ts'ofbc3f902007-04-02 10:08:59 -0400502 if (((dirent->name_len & 0xFF) != 2) ||
503 (dirent->name[0] != '.') ||
504 (dirent->name[1] != '.') ||
Theodore Ts'o5dd77db2008-08-25 21:08:19 -0400505 (rec_len < 12) ||
506 (rec_len % 4))
Theodore Ts'ofbc3f902007-04-02 10:08:59 -0400507 return;
508
509 if (fix_problem(ctx, PR_1_TREAT_AS_DIRECTORY, pctx)) {
510 inode->i_mode = (inode->i_mode & 07777) | LINUX_S_IFDIR;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400511 e2fsck_write_inode_full(ctx, pctx->ino, inode,
512 EXT2_INODE_SIZE(ctx->fs->super),
Theodore Ts'ofbc3f902007-04-02 10:08:59 -0400513 "check_is_really_dir");
514 }
515}
516
JP Abgralle0ed7402014-03-19 19:08:39 -0700517void e2fsck_setup_tdb_icount(e2fsck_t ctx, int flags,
518 ext2_icount_t *ret)
Theodore Ts'o34b9f792007-04-06 18:43:11 -0400519{
Theodore Ts'of954ba02007-05-22 20:53:01 -0400520 unsigned int threshold;
Theodore Ts'o34b9f792007-04-06 18:43:11 -0400521 ext2_ino_t num_dirs;
522 errcode_t retval;
Theodore Ts'of954ba02007-05-22 20:53:01 -0400523 char *tdb_dir;
524 int enable;
Theodore Ts'o34b9f792007-04-06 18:43:11 -0400525
526 *ret = 0;
527
528 profile_get_string(ctx->profile, "scratch_files", "directory", 0, 0,
529 &tdb_dir);
Theodore Ts'of954ba02007-05-22 20:53:01 -0400530 profile_get_uint(ctx->profile, "scratch_files",
531 "numdirs_threshold", 0, 0, &threshold);
Theodore Ts'o34b9f792007-04-06 18:43:11 -0400532 profile_get_boolean(ctx->profile, "scratch_files",
533 "icount", 0, 1, &enable);
534
535 retval = ext2fs_get_num_dirs(ctx->fs, &num_dirs);
536 if (retval)
537 num_dirs = 1024; /* Guess */
538
539 if (!enable || !tdb_dir || access(tdb_dir, W_OK) ||
540 (threshold && num_dirs <= threshold))
541 return;
542
543 retval = ext2fs_create_icount_tdb(ctx->fs, tdb_dir, flags, ret);
544 if (retval)
545 *ret = 0;
546}
547
Theodore Ts'o08b21301997-11-03 19:42:40 +0000548void e2fsck_pass1(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000549{
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +0000550 int i;
Theodore Ts'o31e29a12002-05-17 10:53:07 -0400551 __u64 max_sizes;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000552 ext2_filsys fs = ctx->fs;
JP Abgralle0ed7402014-03-19 19:08:39 -0700553 ext2_ino_t ino = 0;
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500554 struct ext2_inode *inode;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000555 ext2_inode_scan scan;
556 char *block_buf;
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000557#ifdef RESOURCE_TRACK
Theodore Ts'o3839e651997-04-26 13:21:57 +0000558 struct resource_track rtrack;
Theodore Ts'o8bf191e1997-10-20 01:38:32 +0000559#endif
Theodore Ts'o1e3472c1997-04-29 14:53:37 +0000560 unsigned char frag, fsize;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000561 struct problem_context pctx;
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000562 struct scan_callback_struct scan_struct;
Theodore Ts'o5dd8f962001-01-01 15:51:50 +0000563 struct ext2_super_block *sb = ctx->fs->super;
Theodore Ts'oe94bc632007-04-14 09:29:02 -0400564 const char *old_op;
JP Abgralle0ed7402014-03-19 19:08:39 -0700565 unsigned int save_type;
Theodore Ts'o15d482b2007-08-20 21:31:11 -0400566 int imagic_fs, extent_fs;
Theodore Ts'obe93ef02002-10-31 18:38:55 -0500567 int busted_fs_time = 0;
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500568 int inode_size;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400569
Theodore Ts'o6d96b002007-08-03 20:07:09 -0400570 init_resource_track(&rtrack, ctx->fs->io);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000571 clear_problem_context(&pctx);
572
573 if (!(ctx->options & E2F_OPT_PREEN))
574 fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000575
Theodore Ts'o3214a452002-07-23 12:00:00 -0400576 if ((fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
577 !(ctx->options & E2F_OPT_NO)) {
Theodore Ts'ob7a00562002-07-20 00:28:07 -0400578 if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50))
579 ctx->dirs_to_hash = 0;
580 }
581
Theodore Ts'o3839e651997-04-26 13:21:57 +0000582#ifdef MTRACE
583 mtrace_print("Pass 1");
584#endif
585
Andreas Dilger932a4892002-05-16 03:20:07 -0600586#define EXT2_BPP(bits) (1ULL << ((bits) - 2))
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +0000587
Andreas Dilger932a4892002-05-16 03:20:07 -0600588 for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) {
589 max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i);
590 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i);
591 max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i);
JP Abgralle0ed7402014-03-19 19:08:39 -0700592 max_sizes = (max_sizes * (1UL << i));
Theodore Ts'o7823dd62002-05-17 23:37:42 -0400593 ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes;
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +0000594 }
595#undef EXT2_BPP
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +0000596
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +0000597 imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES);
Theodore Ts'o15d482b2007-08-20 21:31:11 -0400598 extent_fs = (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS);
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +0000599
Theodore Ts'o3839e651997-04-26 13:21:57 +0000600 /*
601 * Allocate bitmaps structures
602 */
JP Abgralle0ed7402014-03-19 19:08:39 -0700603 pctx.errcode = e2fsck_allocate_inode_bitmap(fs, _("in-use inode map"),
604 EXT2FS_BMAP64_RBTREE,
605 "inode_used_map",
606 &ctx->inode_used_map);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000607 if (pctx.errcode) {
608 pctx.num = 1;
609 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000610 ctx->flags |= E2F_FLAG_ABORT;
611 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000612 }
JP Abgralle0ed7402014-03-19 19:08:39 -0700613 pctx.errcode = e2fsck_allocate_inode_bitmap(fs,
614 _("directory inode map"),
615 EXT2FS_BMAP64_AUTODIR,
616 "inode_dir_map", &ctx->inode_dir_map);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000617 if (pctx.errcode) {
618 pctx.num = 2;
619 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000620 ctx->flags |= E2F_FLAG_ABORT;
621 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000622 }
JP Abgralle0ed7402014-03-19 19:08:39 -0700623 pctx.errcode = e2fsck_allocate_inode_bitmap(fs,
624 _("regular file inode map"), EXT2FS_BMAP64_RBTREE,
625 "inode_reg_map", &ctx->inode_reg_map);
Theodore Ts'oaa4115a1999-10-21 19:33:18 +0000626 if (pctx.errcode) {
627 pctx.num = 6;
628 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
629 ctx->flags |= E2F_FLAG_ABORT;
630 return;
631 }
JP Abgralle0ed7402014-03-19 19:08:39 -0700632 pctx.errcode = e2fsck_allocate_subcluster_bitmap(fs,
633 _("in-use block map"), EXT2FS_BMAP64_RBTREE,
634 "block_found_map", &ctx->block_found_map);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000635 if (pctx.errcode) {
636 pctx.num = 1;
637 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000638 ctx->flags |= E2F_FLAG_ABORT;
639 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000640 }
Theodore Ts'o34b9f792007-04-06 18:43:11 -0400641 e2fsck_setup_tdb_icount(ctx, 0, &ctx->inode_link_info);
JP Abgralle0ed7402014-03-19 19:08:39 -0700642 if (!ctx->inode_link_info) {
643 e2fsck_set_bitmap_type(fs, EXT2FS_BMAP64_RBTREE,
644 "inode_link_info", &save_type);
Theodore Ts'o34b9f792007-04-06 18:43:11 -0400645 pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0,
646 &ctx->inode_link_info);
JP Abgralle0ed7402014-03-19 19:08:39 -0700647 fs->default_bitmap_type = save_type;
648 }
649
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000650 if (pctx.errcode) {
651 fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000652 ctx->flags |= E2F_FLAG_ABORT;
653 return;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000654 }
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500655 inode_size = EXT2_INODE_SIZE(fs->super);
656 inode = (struct ext2_inode *)
657 e2fsck_allocate_memory(ctx, inode_size, "scratch inode");
658
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000659 inodes_to_process = (struct process_inode_block *)
660 e2fsck_allocate_memory(ctx,
661 (ctx->process_inode_size *
662 sizeof(struct process_inode_block)),
663 "array of inodes to process");
Theodore Ts'o3839e651997-04-26 13:21:57 +0000664 process_inode_count = 0;
665
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000666 pctx.errcode = ext2fs_init_dblist(fs, 0);
667 if (pctx.errcode) {
668 fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000669 ctx->flags |= E2F_FLAG_ABORT;
Brian Behlendorf9d45b6e2007-03-28 11:57:20 -0400670 ext2fs_free_mem(&inode);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000671 return;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000672 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000673
Theodore Ts'o9cbfb8d2000-07-04 19:51:22 +0000674 /*
675 * If the last orphan field is set, clear it, since the pass1
676 * processing will automatically find and clear the orphans.
677 * In the future, we may want to try using the last_orphan
678 * linked list ourselves, but for now, we clear it so that the
679 * ext3 mount code won't get confused.
680 */
681 if (!(ctx->options & E2F_OPT_READONLY)) {
682 if (fs->super->s_last_orphan) {
683 fs->super->s_last_orphan = 0;
684 ext2fs_mark_super_dirty(fs);
685 }
686 }
687
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000688 mark_table_blocks(ctx);
JP Abgralle0ed7402014-03-19 19:08:39 -0700689 pctx.errcode = ext2fs_convert_subcluster_bitmap(fs,
690 &ctx->block_found_map);
691 if (pctx.errcode) {
692 fix_problem(ctx, PR_1_CONVERT_SUBCLUSTER, &pctx);
693 ctx->flags |= E2F_FLAG_ABORT;
694 ext2fs_free_mem(&inode);
695 return;
696 }
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000697 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3,
698 "block interate buffer");
Theodore Ts'oe72a9ba1999-06-25 15:40:18 +0000699 e2fsck_use_inode_shortcuts(ctx, 1);
Theodore Ts'oe94bc632007-04-14 09:29:02 -0400700 old_op = ehandler_operation(_("opening inode scan"));
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400701 pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks,
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000702 &scan);
Theodore Ts'oe94bc632007-04-14 09:29:02 -0400703 ehandler_operation(old_op);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000704 if (pctx.errcode) {
705 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000706 ctx->flags |= E2F_FLAG_ABORT;
Brian Behlendorf9d45b6e2007-03-28 11:57:20 -0400707 ext2fs_free_mem(&block_buf);
708 ext2fs_free_mem(&inode);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000709 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000710 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000711 ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0);
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500712 ctx->stashed_inode = inode;
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000713 scan_struct.ctx = ctx;
714 scan_struct.block_buf = block_buf;
715 ext2fs_set_inode_callback(scan, scan_callback, &scan_struct);
716 if (ctx->progress)
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +0000717 if ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count))
718 return;
Theodore Ts'o4147d9f2005-04-06 14:55:53 -0400719 if ((fs->super->s_wtime < fs->super->s_inodes_count) ||
720 (fs->super->s_mtime < fs->super->s_inodes_count))
Theodore Ts'obe93ef02002-10-31 18:38:55 -0500721 busted_fs_time = 1;
722
JP Abgralle0ed7402014-03-19 19:08:39 -0700723 if ((fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) &&
724 fs->super->s_mmp_block > fs->super->s_first_data_block &&
725 fs->super->s_mmp_block < ext2fs_blocks_count(fs->super))
726 ext2fs_mark_block_bitmap2(ctx->block_found_map,
727 fs->super->s_mmp_block);
728
Theodore Ts'od237a782002-10-03 01:09:35 -0400729 while (1) {
JP Abgralle0ed7402014-03-19 19:08:39 -0700730 if (ino % (fs->super->s_inodes_per_group * 4) == 1) {
731 if (e2fsck_mmp_update(fs))
732 fatal_error(ctx, 0);
733 }
Theodore Ts'oe94bc632007-04-14 09:29:02 -0400734 old_op = ehandler_operation(_("getting next inode from scan"));
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400735 pctx.errcode = ext2fs_get_next_inode_full(scan, &ino,
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500736 inode, inode_size);
Theodore Ts'oe94bc632007-04-14 09:29:02 -0400737 ehandler_operation(old_op);
Theodore Ts'od237a782002-10-03 01:09:35 -0400738 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
739 return;
740 if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
741 if (!ctx->inode_bb_map)
742 alloc_bb_map(ctx);
JP Abgralle0ed7402014-03-19 19:08:39 -0700743 ext2fs_mark_inode_bitmap2(ctx->inode_bb_map, ino);
744 ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
Theodore Ts'od237a782002-10-03 01:09:35 -0400745 continue;
746 }
747 if (pctx.errcode) {
748 fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
749 ctx->flags |= E2F_FLAG_ABORT;
750 return;
751 }
752 if (!ino)
753 break;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000754 pctx.ino = ino;
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500755 pctx.inode = inode;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000756 ctx->stashed_ino = ino;
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500757 if (inode->i_links_count) {
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400758 pctx.errcode = ext2fs_icount_store(ctx->inode_link_info,
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500759 ino, inode->i_links_count);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000760 if (pctx.errcode) {
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500761 pctx.num = inode->i_links_count;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000762 fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000763 ctx->flags |= E2F_FLAG_ABORT;
764 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000765 }
766 }
Eric Sandeendfc870c2008-04-01 15:18:44 -0400767
768 /*
769 * Test for incorrect extent flag settings.
770 *
771 * On big-endian machines we must be careful:
772 * When the inode is read, the i_block array is not swapped
773 * if the extent flag is set. Therefore if we are testing
774 * for or fixing a wrongly-set flag, we must potentially
775 * (un)swap before testing, or after fixing.
776 */
777
778 /*
779 * In this case the extents flag was set when read, so
780 * extent_header_verify is ok. If the inode is cleared,
781 * no need to swap... so no extra swapping here.
782 */
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400783 if ((inode->i_flags & EXT4_EXTENTS_FL) && !extent_fs &&
Theodore Ts'o15d482b2007-08-20 21:31:11 -0400784 (inode->i_links_count || (ino == EXT2_BAD_INO) ||
785 (ino == EXT2_ROOT_INO) || (ino == EXT2_JOURNAL_INO))) {
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400786 if ((ext2fs_extent_header_verify(inode->i_block,
Theodore Ts'o15d482b2007-08-20 21:31:11 -0400787 sizeof(inode->i_block)) == 0) &&
788 fix_problem(ctx, PR_1_EXTENT_FEATURE, &pctx)) {
789 sb->s_feature_incompat |= EXT3_FEATURE_INCOMPAT_EXTENTS;
790 ext2fs_mark_super_dirty(fs);
791 extent_fs = 1;
792 } else if (fix_problem(ctx, PR_1_EXTENTS_SET, &pctx)) {
793 clear_inode:
794 e2fsck_clear_inode(ctx, ino, inode, 0, "pass1");
795 if (ino == EXT2_BAD_INO)
JP Abgralle0ed7402014-03-19 19:08:39 -0700796 ext2fs_mark_inode_bitmap2(ctx->inode_used_map,
Theodore Ts'o15d482b2007-08-20 21:31:11 -0400797 ino);
798 continue;
799 }
800 }
801
Eric Sandeendfc870c2008-04-01 15:18:44 -0400802 /*
803 * For big-endian machines:
804 * If the inode didn't have the extents flag set when it
805 * was read, then the i_blocks array was swapped. To test
806 * as an extents header, we must swap it back first.
807 * IF we then set the extents flag, the entire i_block
808 * array must be un/re-swapped to make it proper extents data.
809 */
Theodore Ts'o15d482b2007-08-20 21:31:11 -0400810 if (extent_fs && !(inode->i_flags & EXT4_EXTENTS_FL) &&
811 (inode->i_links_count || (ino == EXT2_BAD_INO) ||
812 (ino == EXT2_ROOT_INO) || (ino == EXT2_JOURNAL_INO)) &&
813 (LINUX_S_ISREG(inode->i_mode) ||
Eric Sandeendfc870c2008-04-01 15:18:44 -0400814 LINUX_S_ISDIR(inode->i_mode))) {
815 void *ehp;
816#ifdef WORDS_BIGENDIAN
817 __u32 tmp_block[EXT2_N_BLOCKS];
818
819 for (i = 0; i < EXT2_N_BLOCKS; i++)
820 tmp_block[i] = ext2fs_swab32(inode->i_block[i]);
821 ehp = tmp_block;
822#else
823 ehp = inode->i_block;
824#endif
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400825 if ((ext2fs_extent_header_verify(ehp,
Eric Sandeendfc870c2008-04-01 15:18:44 -0400826 sizeof(inode->i_block)) == 0) &&
827 (fix_problem(ctx, PR_1_UNSET_EXTENT_FL, &pctx))) {
Theodore Ts'o15d482b2007-08-20 21:31:11 -0400828 inode->i_flags |= EXT4_EXTENTS_FL;
Eric Sandeendfc870c2008-04-01 15:18:44 -0400829#ifdef WORDS_BIGENDIAN
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400830 memcpy(inode->i_block, tmp_block,
Eric Sandeendfc870c2008-04-01 15:18:44 -0400831 sizeof(inode->i_block));
832#endif
Theodore Ts'o15d482b2007-08-20 21:31:11 -0400833 e2fsck_write_inode(ctx, ino, inode, "pass1");
834 }
835 }
836
Theodore Ts'o3839e651997-04-26 13:21:57 +0000837 if (ino == EXT2_BAD_INO) {
838 struct process_block_struct pb;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400839
JP Abgralle0ed7402014-03-19 19:08:39 -0700840 if ((inode->i_mode || inode->i_uid || inode->i_gid ||
841 inode->i_links_count || inode->i_file_acl) &&
842 fix_problem(ctx, PR_1_INVALID_BAD_INODE, &pctx)) {
843 memset(inode, 0, sizeof(struct ext2_inode));
844 e2fsck_write_inode(ctx, ino, inode,
845 "clear bad inode");
846 }
847
Theodore Ts'o000ba402003-11-21 10:41:58 -0500848 pctx.errcode = ext2fs_copy_bitmap(ctx->block_found_map,
849 &pb.fs_meta_blocks);
850 if (pctx.errcode) {
851 pctx.num = 4;
852 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
853 ctx->flags |= E2F_FLAG_ABORT;
854 return;
855 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000856 pb.ino = EXT2_BAD_INO;
857 pb.num_blocks = pb.last_block = 0;
Theodore Ts'o4dbe79b2009-11-28 09:35:37 -0500858 pb.last_db_block = -1;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000859 pb.num_illegal_blocks = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000860 pb.suppress = 0; pb.clear = 0; pb.is_dir = 0;
Theodore Ts'o000ba402003-11-21 10:41:58 -0500861 pb.is_reg = 0; pb.fragmented = 0; pb.bbcheck = 0;
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500862 pb.inode = inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000863 pb.pctx = &pctx;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000864 pb.ctx = ctx;
JP Abgralle0ed7402014-03-19 19:08:39 -0700865 pctx.errcode = ext2fs_block_iterate3(fs, ino, 0,
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000866 block_buf, process_bad_block, &pb);
Theodore Ts'o000ba402003-11-21 10:41:58 -0500867 ext2fs_free_block_bitmap(pb.fs_meta_blocks);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000868 if (pctx.errcode) {
869 fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000870 ctx->flags |= E2F_FLAG_ABORT;
871 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000872 }
Theodore Ts'o000ba402003-11-21 10:41:58 -0500873 if (pb.bbcheck)
874 if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK_PROMPT, &pctx)) {
875 ctx->flags |= E2F_FLAG_ABORT;
876 return;
877 }
JP Abgralle0ed7402014-03-19 19:08:39 -0700878 ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000879 clear_problem_context(&pctx);
Theodore Ts'od237a782002-10-03 01:09:35 -0400880 continue;
Theodore Ts'oa9ca2012001-01-12 21:53:25 +0000881 } else if (ino == EXT2_ROOT_INO) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000882 /*
883 * Make sure the root inode is a directory; if
884 * not, offer to clear it. It will be
885 * regnerated in pass #3.
886 */
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500887 if (!LINUX_S_ISDIR(inode->i_mode)) {
Theodore Ts'o15d482b2007-08-20 21:31:11 -0400888 if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx))
889 goto clear_inode;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000890 }
891 /*
892 * If dtime is set, offer to clear it. mke2fs
893 * version 0.2b created filesystems with the
894 * dtime field set for the root and lost+found
895 * directories. We won't worry about
896 * /lost+found, since that can be regenerated
897 * easily. But we will fix the root directory
898 * as a special case.
899 */
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500900 if (inode->i_dtime && inode->i_links_count) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000901 if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) {
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500902 inode->i_dtime = 0;
903 e2fsck_write_inode(ctx, ino, inode,
Theodore Ts'of3db3561997-04-26 13:34:30 +0000904 "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000905 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000906 }
Theodore Ts'oa9ca2012001-01-12 21:53:25 +0000907 } else if (ino == EXT2_JOURNAL_INO) {
JP Abgralle0ed7402014-03-19 19:08:39 -0700908 ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
Theodore Ts'of18996c2001-01-03 16:57:24 +0000909 if (fs->super->s_journal_inum == EXT2_JOURNAL_INO) {
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500910 if (!LINUX_S_ISREG(inode->i_mode) &&
Theodore Ts'oa9ca2012001-01-12 21:53:25 +0000911 fix_problem(ctx, PR_1_JOURNAL_BAD_MODE,
912 &pctx)) {
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500913 inode->i_mode = LINUX_S_IFREG;
914 e2fsck_write_inode(ctx, ino, inode,
Theodore Ts'oa9ca2012001-01-12 21:53:25 +0000915 "pass1");
916 }
Theodore Ts'of18996c2001-01-03 16:57:24 +0000917 check_blocks(ctx, &pctx, block_buf);
Theodore Ts'od237a782002-10-03 01:09:35 -0400918 continue;
Theodore Ts'of18996c2001-01-03 16:57:24 +0000919 }
JP Abgralle0ed7402014-03-19 19:08:39 -0700920 if ((inode->i_links_count ||
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500921 inode->i_blocks || inode->i_block[0]) &&
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400922 fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR,
Theodore Ts'of18996c2001-01-03 16:57:24 +0000923 &pctx)) {
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500924 memset(inode, 0, inode_size);
Theodore Ts'oa9ca2012001-01-12 21:53:25 +0000925 ext2fs_icount_store(ctx->inode_link_info,
926 ino, 0);
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400927 e2fsck_write_inode_full(ctx, ino, inode,
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500928 inode_size, "pass1");
Theodore Ts'of18996c2001-01-03 16:57:24 +0000929 }
JP Abgralle0ed7402014-03-19 19:08:39 -0700930 } else if ((ino == EXT4_USR_QUOTA_INO) ||
931 (ino == EXT4_GRP_QUOTA_INO)) {
932 ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
933 if ((fs->super->s_feature_ro_compat &
934 EXT4_FEATURE_RO_COMPAT_QUOTA) &&
935 ((fs->super->s_usr_quota_inum == ino) ||
936 (fs->super->s_grp_quota_inum == ino))) {
937 if (!LINUX_S_ISREG(inode->i_mode) &&
938 fix_problem(ctx, PR_1_QUOTA_BAD_MODE,
939 &pctx)) {
940 inode->i_mode = LINUX_S_IFREG;
941 e2fsck_write_inode(ctx, ino, inode,
942 "pass1");
943 }
944 check_blocks(ctx, &pctx, block_buf);
945 continue;
946 }
947 if ((inode->i_links_count ||
948 inode->i_blocks || inode->i_block[0]) &&
949 fix_problem(ctx, PR_1_QUOTA_INODE_NOT_CLEAR,
950 &pctx)) {
951 memset(inode, 0, inode_size);
952 ext2fs_icount_store(ctx->inode_link_info,
953 ino, 0);
954 e2fsck_write_inode_full(ctx, ino, inode,
955 inode_size, "pass1");
956 }
Theodore Ts'oa9ca2012001-01-12 21:53:25 +0000957 } else if (ino < EXT2_FIRST_INODE(fs->super)) {
JP Abgralle0ed7402014-03-19 19:08:39 -0700958 problem_t problem = 0;
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400959
JP Abgralle0ed7402014-03-19 19:08:39 -0700960 ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
Theodore Ts'o53ef44c2001-01-06 05:55:58 +0000961 if (ino == EXT2_BOOT_LOADER_INO) {
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500962 if (LINUX_S_ISDIR(inode->i_mode))
Theodore Ts'ob09a4b02000-10-24 21:16:09 +0000963 problem = PR_1_RESERVED_BAD_MODE;
Theodore Ts'ob1f204f2001-08-30 16:42:09 -0400964 } else if (ino == EXT2_RESIZE_INO) {
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500965 if (inode->i_mode &&
966 !LINUX_S_ISREG(inode->i_mode))
Theodore Ts'ob1f204f2001-08-30 16:42:09 -0400967 problem = PR_1_RESERVED_BAD_MODE;
Theodore Ts'o53ef44c2001-01-06 05:55:58 +0000968 } else {
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500969 if (inode->i_mode != 0)
Theodore Ts'ob09a4b02000-10-24 21:16:09 +0000970 problem = PR_1_RESERVED_BAD_MODE;
Theodore Ts'ob09a4b02000-10-24 21:16:09 +0000971 }
972 if (problem) {
973 if (fix_problem(ctx, problem, &pctx)) {
Theodore Ts'ocebe48a2005-03-21 13:15:45 -0500974 inode->i_mode = 0;
975 e2fsck_write_inode(ctx, ino, inode,
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000976 "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +0000977 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000978 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000979 check_blocks(ctx, &pctx, block_buf);
Theodore Ts'od237a782002-10-03 01:09:35 -0400980 continue;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000981 }
JP Abgralle0ed7402014-03-19 19:08:39 -0700982
Theodore Ts'o3839e651997-04-26 13:21:57 +0000983 /*
Theodore Ts'o21afac02001-05-14 12:47:41 +0000984 * Check for inodes who might have been part of the
985 * orphaned list linked list. They should have gotten
986 * dealt with by now, unless the list had somehow been
987 * corrupted.
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400988 *
Theodore Ts'o21afac02001-05-14 12:47:41 +0000989 * FIXME: In the future, inodes which are still in use
990 * (and which are therefore) pending truncation should
991 * be handled specially. Right now we just clear the
992 * dtime field, and the normal e2fsck handling of
993 * inodes where i_size and the inode blocks are
994 * inconsistent is to fix i_size, instead of releasing
995 * the extra blocks. This won't catch the inodes that
996 * was at the end of the orphan list, but it's better
997 * than nothing. The right answer is that there
998 * shouldn't be any bugs in the orphan list handling. :-)
999 */
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001000 if (inode->i_dtime && !busted_fs_time &&
1001 inode->i_dtime < ctx->fs->super->s_inodes_count) {
Theodore Ts'o21afac02001-05-14 12:47:41 +00001002 if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) {
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001003 inode->i_dtime = inode->i_links_count ?
Theodore Ts'o1f3ad142005-04-14 14:07:53 -04001004 0 : ctx->now;
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001005 e2fsck_write_inode(ctx, ino, inode,
Theodore Ts'o21afac02001-05-14 12:47:41 +00001006 "pass1");
1007 }
1008 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001009
Theodore Ts'o21afac02001-05-14 12:47:41 +00001010 /*
Theodore Ts'o3839e651997-04-26 13:21:57 +00001011 * This code assumes that deleted inodes have
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001012 * i_links_count set to 0.
Theodore Ts'o3839e651997-04-26 13:21:57 +00001013 */
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001014 if (!inode->i_links_count) {
1015 if (!inode->i_dtime && inode->i_mode) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001016 if (fix_problem(ctx,
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001017 PR_1_ZERO_DTIME, &pctx)) {
Theodore Ts'o1f3ad142005-04-14 14:07:53 -04001018 inode->i_dtime = ctx->now;
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001019 e2fsck_write_inode(ctx, ino, inode,
Theodore Ts'of3db3561997-04-26 13:34:30 +00001020 "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001021 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001022 }
Theodore Ts'od237a782002-10-03 01:09:35 -04001023 continue;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001024 }
1025 /*
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001026 * n.b. 0.3c ext2fs code didn't clear i_links_count for
Theodore Ts'o3839e651997-04-26 13:21:57 +00001027 * deleted files. Oops.
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001028 *
1029 * Since all new ext2 implementations get this right,
1030 * we now assume that the case of non-zero
1031 * i_links_count and non-zero dtime means that we
1032 * should keep the file, not delete it.
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001033 *
Theodore Ts'o3839e651997-04-26 13:21:57 +00001034 */
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001035 if (inode->i_dtime) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001036 if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) {
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001037 inode->i_dtime = 0;
1038 e2fsck_write_inode(ctx, ino, inode, "pass1");
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001039 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001040 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001041
JP Abgralle0ed7402014-03-19 19:08:39 -07001042 ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001043 switch (fs->super->s_creator_os) {
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001044 case EXT2_OS_HURD:
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001045 frag = inode->osd2.hurd2.h_i_frag;
1046 fsize = inode->osd2.hurd2.h_i_fsize;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001047 break;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00001048 default:
1049 frag = fsize = 0;
1050 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001051
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001052 if (inode->i_faddr || frag || fsize ||
1053 (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl))
Theodore Ts'ofdbdea02001-06-02 04:26:26 +00001054 mark_inode_bad(ctx, ino);
Theodore Ts'o911ec622009-04-23 21:31:16 -04001055 if (!(fs->super->s_feature_incompat &
1056 EXT4_FEATURE_INCOMPAT_64BIT) &&
1057 inode->osd2.linux2.l_i_file_acl_high != 0)
1058 mark_inode_bad(ctx, ino);
Theodore Ts'o5d171192006-11-11 06:32:03 -05001059 if ((fs->super->s_creator_os == EXT2_OS_LINUX) &&
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001060 !(fs->super->s_feature_ro_compat &
Theodore Ts'o5d171192006-11-11 06:32:03 -05001061 EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
1062 (inode->osd2.linux2.l_i_blocks_hi != 0))
1063 mark_inode_bad(ctx, ino);
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001064 if (inode->i_flags & EXT2_IMAGIC_FL) {
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +00001065 if (imagic_fs) {
1066 if (!ctx->inode_imagic_map)
1067 alloc_imagic_map(ctx);
JP Abgralle0ed7402014-03-19 19:08:39 -07001068 ext2fs_mark_inode_bitmap2(ctx->inode_imagic_map,
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +00001069 ino);
1070 } else {
1071 if (fix_problem(ctx, PR_1_SET_IMAGIC, &pctx)) {
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001072 inode->i_flags &= ~EXT2_IMAGIC_FL;
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +00001073 e2fsck_write_inode(ctx, ino,
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001074 inode, "pass1");
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +00001075 }
1076 }
Theodore Ts'oaa4115a1999-10-21 19:33:18 +00001077 }
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001078
1079 check_inode_extra_space(ctx, &pctx);
Theodore Ts'ofbc3f902007-04-02 10:08:59 -04001080 check_is_really_dir(ctx, &pctx, block_buf);
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001081
Eric Sandeendfc870c2008-04-01 15:18:44 -04001082 /*
JP Abgralle0ed7402014-03-19 19:08:39 -07001083 * ext2fs_inode_has_valid_blocks2 does not actually look
Eric Sandeendfc870c2008-04-01 15:18:44 -04001084 * at i_block[] values, so not endian-sensitive here.
1085 */
Theodore Ts'ocb23cad2008-03-24 08:17:24 -04001086 if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL) &&
1087 LINUX_S_ISLNK(inode->i_mode) &&
JP Abgralle0ed7402014-03-19 19:08:39 -07001088 !ext2fs_inode_has_valid_blocks2(fs, inode) &&
Theodore Ts'ocb23cad2008-03-24 08:17:24 -04001089 fix_problem(ctx, PR_1_FAST_SYMLINK_EXTENT_FL, &pctx)) {
1090 inode->i_flags &= ~EXT4_EXTENTS_FL;
1091 e2fsck_write_inode(ctx, ino, inode, "pass1");
1092 }
1093
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001094 if (LINUX_S_ISDIR(inode->i_mode)) {
JP Abgralle0ed7402014-03-19 19:08:39 -07001095 ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino);
Theodore Ts'o08b21301997-11-03 19:42:40 +00001096 e2fsck_add_dir_info(ctx, ino, 0);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001097 ctx->fs_directory_count++;
Theodore Ts'o890a2f92015-07-14 22:50:51 -04001098 if (inode->i_flags & EXT4_ENCRYPT_FL)
1099 add_encrypted_dir(ctx, ino);
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001100 } else if (LINUX_S_ISREG (inode->i_mode)) {
JP Abgralle0ed7402014-03-19 19:08:39 -07001101 ext2fs_mark_inode_bitmap2(ctx->inode_reg_map, ino);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001102 ctx->fs_regular_count++;
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001103 } else if (LINUX_S_ISCHR (inode->i_mode) &&
1104 e2fsck_pass1_check_device_inode(fs, inode)) {
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +00001105 check_immutable(ctx, &pctx);
Theodore Ts'od647a1e2000-05-27 14:40:09 +00001106 check_size(ctx, &pctx);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001107 ctx->fs_chardev_count++;
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001108 } else if (LINUX_S_ISBLK (inode->i_mode) &&
1109 e2fsck_pass1_check_device_inode(fs, inode)) {
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +00001110 check_immutable(ctx, &pctx);
Theodore Ts'od647a1e2000-05-27 14:40:09 +00001111 check_size(ctx, &pctx);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001112 ctx->fs_blockdev_count++;
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001113 } else if (LINUX_S_ISLNK (inode->i_mode) &&
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001114 e2fsck_pass1_check_symlink(fs, ino, inode,
Theodore Ts'o7cadc572008-03-13 23:05:00 -04001115 block_buf)) {
Theodore Ts'ofd77b2c2001-07-27 22:10:01 -04001116 check_immutable(ctx, &pctx);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001117 ctx->fs_symlinks_count++;
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001118 if (ext2fs_inode_data_blocks(fs, inode) == 0) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001119 ctx->fs_fast_symlinks_count++;
Theodore Ts'o0684a4f2002-08-17 10:19:44 -04001120 check_blocks(ctx, &pctx, block_buf);
Theodore Ts'od237a782002-10-03 01:09:35 -04001121 continue;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001122 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001123 }
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001124 else if (LINUX_S_ISFIFO (inode->i_mode) &&
1125 e2fsck_pass1_check_device_inode(fs, inode)) {
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +00001126 check_immutable(ctx, &pctx);
Theodore Ts'od647a1e2000-05-27 14:40:09 +00001127 check_size(ctx, &pctx);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001128 ctx->fs_fifo_count++;
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001129 } else if ((LINUX_S_ISSOCK (inode->i_mode)) &&
1130 e2fsck_pass1_check_device_inode(fs, inode)) {
Theodore Ts'o6fdc7a31999-11-10 13:34:40 +00001131 check_immutable(ctx, &pctx);
Theodore Ts'od647a1e2000-05-27 14:40:09 +00001132 check_size(ctx, &pctx);
1133 ctx->fs_sockets_count++;
Theodore Ts'ofdbdea02001-06-02 04:26:26 +00001134 } else
1135 mark_inode_bad(ctx, ino);
Theodore Ts'o8da6d1a2008-08-14 09:48:07 -04001136 if (!(inode->i_flags & EXT4_EXTENTS_FL)) {
1137 if (inode->i_block[EXT2_IND_BLOCK])
1138 ctx->fs_ind_count++;
1139 if (inode->i_block[EXT2_DIND_BLOCK])
1140 ctx->fs_dind_count++;
1141 if (inode->i_block[EXT2_TIND_BLOCK])
1142 ctx->fs_tind_count++;
1143 }
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001144 if (!(inode->i_flags & EXT4_EXTENTS_FL) &&
1145 (inode->i_block[EXT2_IND_BLOCK] ||
1146 inode->i_block[EXT2_DIND_BLOCK] ||
1147 inode->i_block[EXT2_TIND_BLOCK] ||
JP Abgralle0ed7402014-03-19 19:08:39 -07001148 ext2fs_file_acl_block(fs, inode))) {
Theodore Ts'o3839e651997-04-26 13:21:57 +00001149 inodes_to_process[process_inode_count].ino = ino;
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001150 inodes_to_process[process_inode_count].inode = *inode;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001151 process_inode_count++;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001152 } else
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001153 check_blocks(ctx, &pctx, block_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001154
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +00001155 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +00001156 return;
1157
1158 if (process_inode_count >= ctx->process_inode_size) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001159 process_inodes(ctx, block_buf);
Theodore Ts'o08b21301997-11-03 19:42:40 +00001160
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +00001161 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +00001162 return;
1163 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001164 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001165 process_inodes(ctx, block_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001166 ext2fs_close_inode_scan(scan);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001167
Theodore Ts'oe8a3ee62001-07-07 11:12:50 -04001168 /*
1169 * If any extended attribute blocks' reference counts need to
1170 * be adjusted, either up (ctx->refcount_extra), or down
1171 * (ctx->refcount), then fix them.
1172 */
1173 if (ctx->refcount) {
1174 adjust_extattr_refcount(ctx, ctx->refcount, block_buf, -1);
1175 ea_refcount_free(ctx->refcount);
1176 ctx->refcount = 0;
1177 }
1178 if (ctx->refcount_extra) {
1179 adjust_extattr_refcount(ctx, ctx->refcount_extra,
1180 block_buf, +1);
1181 ea_refcount_free(ctx->refcount_extra);
1182 ctx->refcount_extra = 0;
1183 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001184
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001185 if (ctx->invalid_bitmaps)
1186 handle_fs_bad_blocks(ctx);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001187
Theodore Ts'o24ceb242001-07-26 09:02:56 -04001188 /* We don't need the block_ea_map any more */
1189 if (ctx->block_ea_map) {
1190 ext2fs_free_block_bitmap(ctx->block_ea_map);
1191 ctx->block_ea_map = 0;
1192 }
1193
Theodore Ts'oc3ffaf82004-12-24 01:42:22 -05001194 if (ctx->flags & E2F_FLAG_RESIZE_INODE) {
1195 ext2fs_block_bitmap save_bmap;
Theodore Ts'oc3ffaf82004-12-24 01:42:22 -05001196
1197 save_bmap = fs->block_map;
1198 fs->block_map = ctx->block_found_map;
1199 clear_problem_context(&pctx);
1200 pctx.errcode = ext2fs_create_resize_inode(fs);
1201 if (pctx.errcode) {
Theodore Ts'oa6217f52010-05-12 18:58:53 -04001202 if (!fix_problem(ctx, PR_1_RESIZE_INODE_CREATE,
1203 &pctx)) {
1204 ctx->flags |= E2F_FLAG_ABORT;
1205 return;
1206 }
1207 pctx.errcode = 0;
Theodore Ts'oc3ffaf82004-12-24 01:42:22 -05001208 }
Theodore Ts'oa6217f52010-05-12 18:58:53 -04001209 if (!pctx.errcode) {
1210 e2fsck_read_inode(ctx, EXT2_RESIZE_INO, inode,
1211 "recreate inode");
1212 inode->i_mtime = ctx->now;
1213 e2fsck_write_inode(ctx, EXT2_RESIZE_INO, inode,
1214 "recreate inode");
1215 }
Theodore Ts'oc3ffaf82004-12-24 01:42:22 -05001216 fs->block_map = save_bmap;
1217 ctx->flags &= ~E2F_FLAG_RESIZE_INODE;
1218 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001219
Theodore Ts'o08b21301997-11-03 19:42:40 +00001220 if (ctx->flags & E2F_FLAG_RESTART) {
Theodore Ts'oaa4115a1999-10-21 19:33:18 +00001221 /*
1222 * Only the master copy of the superblock and block
1223 * group descriptors are going to be written during a
1224 * restart, so set the superblock to be used to be the
1225 * master superblock.
1226 */
1227 ctx->use_superblock = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +00001228 unwind_pass1(fs);
1229 goto endit;
1230 }
1231
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001232 if (ctx->block_dup_map) {
1233 if (ctx->options & E2F_OPT_PREEN) {
1234 clear_problem_context(&pctx);
1235 fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001236 }
Theodore Ts'o08b21301997-11-03 19:42:40 +00001237 e2fsck_pass1_dupblocks(ctx, block_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001238 }
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -04001239 ext2fs_free_mem(&inodes_to_process);
Theodore Ts'of3db3561997-04-26 13:34:30 +00001240endit:
Theodore Ts'oe72a9ba1999-06-25 15:40:18 +00001241 e2fsck_use_inode_shortcuts(ctx, 0);
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001242
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -04001243 ext2fs_free_mem(&block_buf);
Theodore Ts'ocebe48a2005-03-21 13:15:45 -05001244 ext2fs_free_mem(&inode);
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001245
Ken Chen9facd072009-05-28 09:55:10 -04001246 print_resource_track(ctx, _("Pass 1"), &rtrack, ctx->fs->io);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001247}
1248
1249/*
Theodore Ts'of3db3561997-04-26 13:34:30 +00001250 * When the inode_scan routines call this callback at the end of the
1251 * glock group, call process_inodes.
1252 */
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001253static errcode_t scan_callback(ext2_filsys fs,
Theodore Ts'o54434922003-12-07 01:28:50 -05001254 ext2_inode_scan scan EXT2FS_ATTR((unused)),
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00001255 dgrp_t group, void * priv_data)
Theodore Ts'of3db3561997-04-26 13:34:30 +00001256{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00001257 struct scan_callback_struct *scan_struct;
Theodore Ts'of8188ff1997-11-14 05:23:04 +00001258 e2fsck_t ctx;
1259
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00001260 scan_struct = (struct scan_callback_struct *) priv_data;
Theodore Ts'of8188ff1997-11-14 05:23:04 +00001261 ctx = scan_struct->ctx;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001262
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00001263 process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf);
Theodore Ts'of8188ff1997-11-14 05:23:04 +00001264
1265 if (ctx->progress)
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +00001266 if ((ctx->progress)(ctx, 1, group+1,
1267 ctx->fs->group_desc_count))
1268 return EXT2_ET_CANCEL_REQUESTED;
Theodore Ts'of8188ff1997-11-14 05:23:04 +00001269
Theodore Ts'of3db3561997-04-26 13:34:30 +00001270 return 0;
1271}
1272
1273/*
Theodore Ts'o3839e651997-04-26 13:21:57 +00001274 * Process the inodes in the "inodes to process" list.
1275 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001276static void process_inodes(e2fsck_t ctx, char *block_buf)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001277{
1278 int i;
1279 struct ext2_inode *old_stashed_inode;
Theodore Ts'o86c627e2001-01-11 15:12:14 +00001280 ext2_ino_t old_stashed_ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001281 const char *old_operation;
1282 char buf[80];
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001283 struct problem_context pctx;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001284
Theodore Ts'o3839e651997-04-26 13:21:57 +00001285#if 0
Theodore Ts'of3db3561997-04-26 13:34:30 +00001286 printf("begin process_inodes: ");
Theodore Ts'o3839e651997-04-26 13:21:57 +00001287#endif
Theodore Ts'o86a63e91999-11-23 13:52:48 +00001288 if (process_inode_count == 0)
1289 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001290 old_operation = ehandler_operation(0);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001291 old_stashed_inode = ctx->stashed_inode;
1292 old_stashed_ino = ctx->stashed_ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001293 qsort(inodes_to_process, process_inode_count,
1294 sizeof(struct process_inode_block), process_inode_cmp);
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001295 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001296 for (i=0; i < process_inode_count; i++) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001297 pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode;
1298 pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001299
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001300#if 0
1301 printf("%u ", pctx.ino);
1302#endif
Theodore Ts'o86c627e2001-01-11 15:12:14 +00001303 sprintf(buf, _("reading indirect blocks of inode %u"),
Theodore Ts'o0c4a0722000-02-07 03:11:03 +00001304 pctx.ino);
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001305 ehandler_operation(buf);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001306 check_blocks(ctx, &pctx, block_buf);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +00001307 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o2df1f6a1998-02-27 05:03:48 +00001308 break;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001309 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001310 ctx->stashed_inode = old_stashed_inode;
1311 ctx->stashed_ino = old_stashed_ino;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001312 process_inode_count = 0;
1313#if 0
Theodore Ts'of3db3561997-04-26 13:34:30 +00001314 printf("end process inodes\n");
Theodore Ts'o3839e651997-04-26 13:21:57 +00001315#endif
1316 ehandler_operation(old_operation);
1317}
1318
Theodore Ts'o4c77fe51998-04-30 17:35:59 +00001319static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001320{
1321 const struct process_inode_block *ib_a =
1322 (const struct process_inode_block *) a;
1323 const struct process_inode_block *ib_b =
1324 (const struct process_inode_block *) b;
Theodore Ts'ob5acdb62001-07-07 22:27:40 -04001325 int ret;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001326
Theodore Ts'ob5acdb62001-07-07 22:27:40 -04001327 ret = (ib_a->inode.i_block[EXT2_IND_BLOCK] -
1328 ib_b->inode.i_block[EXT2_IND_BLOCK]);
1329 if (ret == 0)
JP Abgralle0ed7402014-03-19 19:08:39 -07001330 /*
1331 * We only call process_inodes() for non-extent
1332 * inodes, so it's OK to pass NULL to
1333 * ext2fs_file_acl_block() here.
1334 */
1335 ret = ext2fs_file_acl_block(0, &(ib_a->inode)) -
1336 ext2fs_file_acl_block(0, &(ib_b->inode));
Theodore Ts'o0eeec8a2008-09-12 09:10:39 -04001337 if (ret == 0)
1338 ret = ib_a->ino - ib_b->ino;
Theodore Ts'ob5acdb62001-07-07 22:27:40 -04001339 return ret;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001340}
1341
Theodore Ts'o3839e651997-04-26 13:21:57 +00001342/*
Theodore Ts'ofdbdea02001-06-02 04:26:26 +00001343 * Mark an inode as being bad in some what
Theodore Ts'o3839e651997-04-26 13:21:57 +00001344 */
Theodore Ts'ofdbdea02001-06-02 04:26:26 +00001345static void mark_inode_bad(e2fsck_t ctx, ino_t ino)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001346{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001347 struct problem_context pctx;
Theodore Ts'ofdbdea02001-06-02 04:26:26 +00001348
1349 if (!ctx->inode_bad_map) {
1350 clear_problem_context(&pctx);
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001351
JP Abgralle0ed7402014-03-19 19:08:39 -07001352 pctx.errcode = e2fsck_allocate_inode_bitmap(ctx->fs,
1353 _("bad inode map"), EXT2FS_BMAP64_RBTREE,
1354 "inode_bad_map", &ctx->inode_bad_map);
Theodore Ts'ofdbdea02001-06-02 04:26:26 +00001355 if (pctx.errcode) {
1356 pctx.num = 3;
1357 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
1358 /* Should never get here */
1359 ctx->flags |= E2F_FLAG_ABORT;
1360 return;
1361 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00001362 }
JP Abgralle0ed7402014-03-19 19:08:39 -07001363 ext2fs_mark_inode_bitmap2(ctx->inode_bad_map, ino);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001364}
1365
Theodore Ts'o890a2f92015-07-14 22:50:51 -04001366static void add_encrypted_dir(e2fsck_t ctx, ino_t ino)
1367{
1368 struct problem_context pctx;
1369
1370 if (!ctx->encrypted_dirs) {
1371 pctx.errcode = ext2fs_u32_list_create(&ctx->encrypted_dirs, 0);
1372 if (pctx.errcode)
1373 goto error;
1374 }
1375 pctx.errcode = ext2fs_u32_list_add(ctx->encrypted_dirs, ino);
1376 if (pctx.errcode == 0)
1377 return;
1378error:
1379 fix_problem(ctx, PR_1_ALLOCATE_ENCRYPTED_DIRLIST, &pctx);
1380 /* Should never get here */
1381 ctx->flags |= E2F_FLAG_ABORT;
1382}
Theodore Ts'ofdbdea02001-06-02 04:26:26 +00001383
Theodore Ts'o3839e651997-04-26 13:21:57 +00001384/*
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001385 * This procedure will allocate the inode "bb" (badblock) map table
1386 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001387static void alloc_bb_map(e2fsck_t ctx)
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001388{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001389 struct problem_context pctx;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001390
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001391 clear_problem_context(&pctx);
JP Abgralle0ed7402014-03-19 19:08:39 -07001392 pctx.errcode = e2fsck_allocate_inode_bitmap(ctx->fs,
1393 _("inode in bad block map"), EXT2FS_BMAP64_RBTREE,
1394 "inode_bb_map", &ctx->inode_bb_map);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001395 if (pctx.errcode) {
1396 pctx.num = 4;
1397 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +00001398 /* Should never get here */
1399 ctx->flags |= E2F_FLAG_ABORT;
1400 return;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00001401 }
1402}
1403
1404/*
Theodore Ts'oaa4115a1999-10-21 19:33:18 +00001405 * This procedure will allocate the inode imagic table
1406 */
1407static void alloc_imagic_map(e2fsck_t ctx)
1408{
1409 struct problem_context pctx;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001410
Theodore Ts'oaa4115a1999-10-21 19:33:18 +00001411 clear_problem_context(&pctx);
JP Abgralle0ed7402014-03-19 19:08:39 -07001412 pctx.errcode = e2fsck_allocate_inode_bitmap(ctx->fs,
1413 _("imagic inode map"), EXT2FS_BMAP64_RBTREE,
1414 "inode_imagic_map", &ctx->inode_imagic_map);
Theodore Ts'oaa4115a1999-10-21 19:33:18 +00001415 if (pctx.errcode) {
1416 pctx.num = 5;
1417 fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
1418 /* Should never get here */
1419 ctx->flags |= E2F_FLAG_ABORT;
1420 return;
1421 }
1422}
1423
1424/*
Theodore Ts'o3839e651997-04-26 13:21:57 +00001425 * Marks a block as in use, setting the dup_map if it's been set
1426 * already. Called by process_block and process_bad_block.
Theodore Ts'o50e1e101997-04-26 13:58:21 +00001427 *
1428 * WARNING: Assumes checks have already been done to make sure block
1429 * is valid. This is true in both process_block and process_bad_block.
Theodore Ts'o3839e651997-04-26 13:21:57 +00001430 */
JP Abgralle0ed7402014-03-19 19:08:39 -07001431static _INLINE_ void mark_block_used(e2fsck_t ctx, blk64_t block)
Theodore Ts'o3839e651997-04-26 13:21:57 +00001432{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001433 struct problem_context pctx;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001434
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001435 clear_problem_context(&pctx);
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001436
JP Abgralle0ed7402014-03-19 19:08:39 -07001437 if (ext2fs_fast_test_block_bitmap2(ctx->block_found_map, block)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001438 if (!ctx->block_dup_map) {
JP Abgralle0ed7402014-03-19 19:08:39 -07001439 pctx.errcode = e2fsck_allocate_block_bitmap(ctx->fs,
1440 _("multiply claimed block map"),
1441 EXT2FS_BMAP64_RBTREE, "block_dup_map",
1442 &ctx->block_dup_map);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001443 if (pctx.errcode) {
1444 pctx.num = 3;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001445 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR,
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001446 &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +00001447 /* Should never get here */
1448 ctx->flags |= E2F_FLAG_ABORT;
1449 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +00001450 }
1451 }
JP Abgralle0ed7402014-03-19 19:08:39 -07001452 ext2fs_fast_mark_block_bitmap2(ctx->block_dup_map, block);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001453 } else {
JP Abgralle0ed7402014-03-19 19:08:39 -07001454 ext2fs_fast_mark_block_bitmap2(ctx->block_found_map, block);
Theodore Ts'o3839e651997-04-26 13:21:57 +00001455 }
1456}
1457
JP Abgralle0ed7402014-03-19 19:08:39 -07001458static _INLINE_ void mark_blocks_used(e2fsck_t ctx, blk64_t block,
1459 unsigned int num)
1460{
1461 if (ext2fs_test_block_bitmap_range2(ctx->block_found_map, block, num))
1462 ext2fs_mark_block_bitmap_range2(ctx->block_found_map, block, num);
1463 else
1464 while (num--)
1465 mark_block_used(ctx, block++);
1466}
1467
Theodore Ts'o3839e651997-04-26 13:21:57 +00001468/*
Theodore Ts'oe8a3ee62001-07-07 11:12:50 -04001469 * Adjust the extended attribute block's reference counts at the end
1470 * of pass 1, either by subtracting out references for EA blocks that
1471 * are still referenced in ctx->refcount, or by adding references for
1472 * EA blocks that had extra references as accounted for in
1473 * ctx->refcount_extra.
1474 */
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001475static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
Theodore Ts'oe8a3ee62001-07-07 11:12:50 -04001476 char *block_buf, int adjust_sign)
1477{
1478 struct ext2_ext_attr_header *header;
1479 struct problem_context pctx;
1480 ext2_filsys fs = ctx->fs;
JP Abgralle0ed7402014-03-19 19:08:39 -07001481 blk64_t blk;
Theodore Ts'oe8a3ee62001-07-07 11:12:50 -04001482 __u32 should_be;
1483 int count;
1484
1485 clear_problem_context(&pctx);
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001486
Theodore Ts'oe8a3ee62001-07-07 11:12:50 -04001487 ea_refcount_intr_begin(refcount);
1488 while (1) {
1489 if ((blk = ea_refcount_intr_next(refcount, &count)) == 0)
1490 break;
1491 pctx.blk = blk;
JP Abgralle0ed7402014-03-19 19:08:39 -07001492 pctx.errcode = ext2fs_read_ext_attr2(fs, blk, block_buf);
Theodore Ts'oe8a3ee62001-07-07 11:12:50 -04001493 if (pctx.errcode) {
1494 fix_problem(ctx, PR_1_EXTATTR_READ_ABORT, &pctx);
1495 return;
1496 }
1497 header = (struct ext2_ext_attr_header *) block_buf;
1498 pctx.blkcount = header->h_refcount;
1499 should_be = header->h_refcount + adjust_sign * count;
1500 pctx.num = should_be;
1501 if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) {
1502 header->h_refcount = should_be;
JP Abgralle0ed7402014-03-19 19:08:39 -07001503 pctx.errcode = ext2fs_write_ext_attr2(fs, blk,
Theodore Ts'oe8a3ee62001-07-07 11:12:50 -04001504 block_buf);
1505 if (pctx.errcode) {
Theodore Ts'oa6217f52010-05-12 18:58:53 -04001506 fix_problem(ctx, PR_1_EXTATTR_WRITE_ABORT,
1507 &pctx);
Theodore Ts'oe8a3ee62001-07-07 11:12:50 -04001508 continue;
1509 }
1510 }
1511 }
1512}
1513
1514/*
Theodore Ts'o342d8472001-07-02 11:54:09 -04001515 * Handle processing the extended attribute blocks
1516 */
1517static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
1518 char *block_buf)
1519{
1520 ext2_filsys fs = ctx->fs;
1521 ext2_ino_t ino = pctx->ino;
1522 struct ext2_inode *inode = pctx->inode;
JP Abgralle0ed7402014-03-19 19:08:39 -07001523 blk64_t blk;
Theodore Ts'o55fd07e2001-07-19 16:31:25 -04001524 char * end;
Theodore Ts'oe8a3ee62001-07-07 11:12:50 -04001525 struct ext2_ext_attr_header *header;
Theodore Ts'o55fd07e2001-07-19 16:31:25 -04001526 struct ext2_ext_attr_entry *entry;
Theodore Ts'o342d8472001-07-02 11:54:09 -04001527 int count;
Theodore Ts'o86bc90f2007-04-04 21:42:42 -04001528 region_t region = 0;
Brian Behlendorf5469d762007-03-28 11:41:40 -04001529
JP Abgralle0ed7402014-03-19 19:08:39 -07001530 blk = ext2fs_file_acl_block(fs, inode);
Theodore Ts'o342d8472001-07-02 11:54:09 -04001531 if (blk == 0)
1532 return 0;
1533
1534 /*
1535 * If the Extended attribute flag isn't set, then a non-zero
1536 * file acl means that the inode is corrupted.
1537 *
1538 * Or if the extended attribute block is an invalid block,
1539 * then the inode is also corrupted.
1540 */
1541 if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) ||
1542 (blk < fs->super->s_first_data_block) ||
JP Abgralle0ed7402014-03-19 19:08:39 -07001543 (blk >= ext2fs_blocks_count(fs->super))) {
Theodore Ts'o342d8472001-07-02 11:54:09 -04001544 mark_inode_bad(ctx, ino);
1545 return 0;
1546 }
1547
1548 /* If ea bitmap hasn't been allocated, create it */
1549 if (!ctx->block_ea_map) {
JP Abgralle0ed7402014-03-19 19:08:39 -07001550 pctx->errcode = e2fsck_allocate_block_bitmap(fs,
1551 _("ext attr block map"),
1552 EXT2FS_BMAP64_RBTREE, "block_ea_map",
1553 &ctx->block_ea_map);
Theodore Ts'o342d8472001-07-02 11:54:09 -04001554 if (pctx->errcode) {
1555 pctx->num = 2;
1556 fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, pctx);
1557 ctx->flags |= E2F_FLAG_ABORT;
1558 return 0;
1559 }
1560 }
1561
1562 /* Create the EA refcount structure if necessary */
1563 if (!ctx->refcount) {
1564 pctx->errcode = ea_refcount_create(0, &ctx->refcount);
1565 if (pctx->errcode) {
1566 pctx->num = 1;
1567 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
1568 ctx->flags |= E2F_FLAG_ABORT;
1569 return 0;
1570 }
1571 }
1572
Theodore Ts'ob5acdb62001-07-07 22:27:40 -04001573#if 0
1574 /* Debugging text */
1575 printf("Inode %u has EA block %u\n", ino, blk);
1576#endif
1577
Theodore Ts'o342d8472001-07-02 11:54:09 -04001578 /* Have we seen this EA block before? */
JP Abgralle0ed7402014-03-19 19:08:39 -07001579 if (ext2fs_fast_test_block_bitmap2(ctx->block_ea_map, blk)) {
Theodore Ts'o342d8472001-07-02 11:54:09 -04001580 if (ea_refcount_decrement(ctx->refcount, blk, 0) == 0)
1581 return 1;
1582 /* Ooops, this EA was referenced more than it stated */
1583 if (!ctx->refcount_extra) {
1584 pctx->errcode = ea_refcount_create(0,
1585 &ctx->refcount_extra);
1586 if (pctx->errcode) {
1587 pctx->num = 2;
1588 fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
1589 ctx->flags |= E2F_FLAG_ABORT;
Theodore Ts'o55fd07e2001-07-19 16:31:25 -04001590 return 0;
Theodore Ts'o342d8472001-07-02 11:54:09 -04001591 }
1592 }
1593 ea_refcount_increment(ctx->refcount_extra, blk, 0);
1594 return 1;
1595 }
Brian Behlendorf5469d762007-03-28 11:41:40 -04001596
Theodore Ts'o342d8472001-07-02 11:54:09 -04001597 /*
1598 * OK, we haven't seen this EA block yet. So we need to
1599 * validate it
1600 */
1601 pctx->blk = blk;
JP Abgralle0ed7402014-03-19 19:08:39 -07001602 pctx->errcode = ext2fs_read_ext_attr2(fs, blk, block_buf);
Theodore Ts'o342d8472001-07-02 11:54:09 -04001603 if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx))
1604 goto clear_extattr;
Theodore Ts'o342d8472001-07-02 11:54:09 -04001605 header = (struct ext2_ext_attr_header *) block_buf;
JP Abgralle0ed7402014-03-19 19:08:39 -07001606 pctx->blk = ext2fs_file_acl_block(fs, inode);
Theodore Ts'o0684a4f2002-08-17 10:19:44 -04001607 if (((ctx->ext_attr_ver == 1) &&
1608 (header->h_magic != EXT2_EXT_ATTR_MAGIC_v1)) ||
1609 ((ctx->ext_attr_ver == 2) &&
1610 (header->h_magic != EXT2_EXT_ATTR_MAGIC))) {
1611 if (fix_problem(ctx, PR_1_BAD_EA_BLOCK, pctx))
1612 goto clear_extattr;
1613 }
Theodore Ts'o0d634672002-05-22 00:22:38 -04001614
Theodore Ts'o55fd07e2001-07-19 16:31:25 -04001615 if (header->h_blocks != 1) {
1616 if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx))
1617 goto clear_extattr;
1618 }
1619
1620 region = region_create(0, fs->blocksize);
1621 if (!region) {
Theodore Ts'oa6217f52010-05-12 18:58:53 -04001622 fix_problem(ctx, PR_1_EA_ALLOC_REGION_ABORT, pctx);
Theodore Ts'o55fd07e2001-07-19 16:31:25 -04001623 ctx->flags |= E2F_FLAG_ABORT;
1624 return 0;
1625 }
1626 if (region_allocate(region, 0, sizeof(struct ext2_ext_attr_header))) {
1627 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
Theodore Ts'o342d8472001-07-02 11:54:09 -04001628 goto clear_extattr;
1629 }
Brian Behlendorf5469d762007-03-28 11:41:40 -04001630
Theodore Ts'o55fd07e2001-07-19 16:31:25 -04001631 entry = (struct ext2_ext_attr_entry *)(header+1);
1632 end = block_buf + fs->blocksize;
1633 while ((char *)entry < end && *(__u32 *)entry) {
Andreas Dilgerfefaef32008-02-02 01:16:32 -07001634 __u32 hash;
1635
Theodore Ts'o55fd07e2001-07-19 16:31:25 -04001636 if (region_allocate(region, (char *)entry - (char *)header,
1637 EXT2_EXT_ATTR_LEN(entry->e_name_len))) {
1638 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
1639 goto clear_extattr;
Andreas Dilgerfefaef32008-02-02 01:16:32 -07001640 break;
Theodore Ts'o55fd07e2001-07-19 16:31:25 -04001641 }
Theodore Ts'o0684a4f2002-08-17 10:19:44 -04001642 if ((ctx->ext_attr_ver == 1 &&
Theodore Ts'o0d634672002-05-22 00:22:38 -04001643 (entry->e_name_len == 0 || entry->e_name_index != 0)) ||
Theodore Ts'o0684a4f2002-08-17 10:19:44 -04001644 (ctx->ext_attr_ver == 2 &&
Theodore Ts'o0d634672002-05-22 00:22:38 -04001645 entry->e_name_index == 0)) {
Theodore Ts'o55fd07e2001-07-19 16:31:25 -04001646 if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx))
1647 goto clear_extattr;
Andreas Dilgerfefaef32008-02-02 01:16:32 -07001648 break;
Theodore Ts'o55fd07e2001-07-19 16:31:25 -04001649 }
1650 if (entry->e_value_block != 0) {
1651 if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
1652 goto clear_extattr;
1653 }
Andreas Dilgera34c6ff2007-06-22 02:22:38 -04001654 if (entry->e_value_offs + entry->e_value_size > fs->blocksize) {
1655 if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx))
1656 goto clear_extattr;
1657 break;
1658 }
Theodore Ts'o14fe1c32001-07-25 19:48:24 -04001659 if (entry->e_value_size &&
1660 region_allocate(region, entry->e_value_offs,
1661 EXT2_EXT_ATTR_SIZE(entry->e_value_size))) {
Theodore Ts'o55fd07e2001-07-19 16:31:25 -04001662 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
1663 goto clear_extattr;
1664 }
Andreas Dilgerfefaef32008-02-02 01:16:32 -07001665
1666 hash = ext2fs_ext_attr_hash_entry(entry, block_buf +
1667 entry->e_value_offs);
1668
1669 if (entry->e_hash != hash) {
1670 pctx->num = entry->e_hash;
1671 if (fix_problem(ctx, PR_1_ATTR_HASH, pctx))
1672 goto clear_extattr;
1673 entry->e_hash = hash;
1674 }
1675
Theodore Ts'o55fd07e2001-07-19 16:31:25 -04001676 entry = EXT2_EXT_ATTR_NEXT(entry);
1677 }
1678 if (region_allocate(region, (char *)entry - (char *)header, 4)) {
1679 if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx))
1680 goto clear_extattr;
1681 }
1682 region_free(region);
Theodore Ts'o342d8472001-07-02 11:54:09 -04001683
1684 count = header->h_refcount - 1;
1685 if (count)
1686 ea_refcount_store(ctx->refcount, blk, count);
1687 mark_block_used(ctx, blk);
JP Abgralle0ed7402014-03-19 19:08:39 -07001688 ext2fs_fast_mark_block_bitmap2(ctx->block_ea_map, blk);
Theodore Ts'o342d8472001-07-02 11:54:09 -04001689 return 1;
1690
1691clear_extattr:
Brian Behlendorf5469d762007-03-28 11:41:40 -04001692 if (region)
1693 region_free(region);
JP Abgralle0ed7402014-03-19 19:08:39 -07001694 ext2fs_file_acl_block_set(fs, inode, 0);
Theodore Ts'o342d8472001-07-02 11:54:09 -04001695 e2fsck_write_inode(ctx, ino, inode, "check_ext_attr");
1696 return 0;
1697}
1698
Theodore Ts'o503f9e72002-06-26 16:52:10 -04001699/* Returns 1 if bad htree, 0 if OK */
1700static int handle_htree(e2fsck_t ctx, struct problem_context *pctx,
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001701 ext2_ino_t ino, struct ext2_inode *inode,
Theodore Ts'o503f9e72002-06-26 16:52:10 -04001702 char *block_buf)
1703{
1704 struct ext2_dx_root_info *root;
1705 ext2_filsys fs = ctx->fs;
1706 errcode_t retval;
JP Abgralle0ed7402014-03-19 19:08:39 -07001707 blk64_t blk;
Theodore Ts'o503f9e72002-06-26 16:52:10 -04001708
1709 if ((!LINUX_S_ISDIR(inode->i_mode) &&
1710 fix_problem(ctx, PR_1_HTREE_NODIR, pctx)) ||
1711 (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
1712 fix_problem(ctx, PR_1_HTREE_SET, pctx)))
1713 return 1;
1714
JP Abgralle0ed7402014-03-19 19:08:39 -07001715 pctx->errcode = ext2fs_bmap2(fs, ino, inode, 0, 0, 0, 0, &blk);
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001716
1717 if ((pctx->errcode) ||
1718 (blk == 0) ||
1719 (blk < fs->super->s_first_data_block) ||
JP Abgralle0ed7402014-03-19 19:08:39 -07001720 (blk >= ext2fs_blocks_count(fs->super))) {
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001721 if (fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
1722 return 1;
1723 else
1724 return 0;
1725 }
Theodore Ts'o503f9e72002-06-26 16:52:10 -04001726
JP Abgralle0ed7402014-03-19 19:08:39 -07001727 retval = io_channel_read_blk64(fs->io, blk, 1, block_buf);
Theodore Ts'o503f9e72002-06-26 16:52:10 -04001728 if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
1729 return 1;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001730
Theodore Ts'o503f9e72002-06-26 16:52:10 -04001731 /* XXX should check that beginning matches a directory */
1732 root = (struct ext2_dx_root_info *) (block_buf + 24);
1733
1734 if ((root->reserved_zero || root->info_length < 8) &&
1735 fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
1736 return 1;
1737
1738 pctx->num = root->hash_version;
1739 if ((root->hash_version != EXT2_HASH_LEGACY) &&
1740 (root->hash_version != EXT2_HASH_HALF_MD4) &&
Theodore Ts'of044b4d2002-08-17 13:32:21 -04001741 (root->hash_version != EXT2_HASH_TEA) &&
Theodore Ts'o503f9e72002-06-26 16:52:10 -04001742 fix_problem(ctx, PR_1_HTREE_HASHV, pctx))
1743 return 1;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001744
Theodore Ts'o503f9e72002-06-26 16:52:10 -04001745 if ((root->unused_flags & EXT2_HASH_FLAG_INCOMPAT) &&
1746 fix_problem(ctx, PR_1_HTREE_INCOMPAT, pctx))
1747 return 1;
1748
1749 pctx->num = root->indirect_levels;
1750 if ((root->indirect_levels > 1) &&
1751 fix_problem(ctx, PR_1_HTREE_DEPTH, pctx))
1752 return 1;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04001753
Theodore Ts'o503f9e72002-06-26 16:52:10 -04001754 return 0;
1755}
Theodore Ts'o342d8472001-07-02 11:54:09 -04001756
Theodore Ts'oe3df15a2007-09-15 14:10:47 -04001757void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino,
1758 struct ext2_inode *inode, int restart_flag,
1759 const char *source)
1760{
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001761 inode->i_flags = 0;
Theodore Ts'oe3df15a2007-09-15 14:10:47 -04001762 inode->i_links_count = 0;
1763 ext2fs_icount_store(ctx->inode_link_info, ino, 0);
1764 inode->i_dtime = ctx->now;
1765
JP Abgralle0ed7402014-03-19 19:08:39 -07001766 ext2fs_unmark_inode_bitmap2(ctx->inode_dir_map, ino);
1767 ext2fs_unmark_inode_bitmap2(ctx->inode_used_map, ino);
Theodore Ts'oe3df15a2007-09-15 14:10:47 -04001768 if (ctx->inode_reg_map)
JP Abgralle0ed7402014-03-19 19:08:39 -07001769 ext2fs_unmark_inode_bitmap2(ctx->inode_reg_map, ino);
Theodore Ts'oe3df15a2007-09-15 14:10:47 -04001770 if (ctx->inode_bad_map)
JP Abgralle0ed7402014-03-19 19:08:39 -07001771 ext2fs_unmark_inode_bitmap2(ctx->inode_bad_map, ino);
Theodore Ts'oe3df15a2007-09-15 14:10:47 -04001772
1773 /*
1774 * If the inode was partially accounted for before processing
1775 * was aborted, we need to restart the pass 1 scan.
1776 */
1777 ctx->flags |= restart_flag;
1778
JP Abgralle0ed7402014-03-19 19:08:39 -07001779 if (ino == EXT2_BAD_INO)
1780 memset(inode, 0, sizeof(struct ext2_inode));
1781
Theodore Ts'oe3df15a2007-09-15 14:10:47 -04001782 e2fsck_write_inode(ctx, ino, inode, source);
1783}
1784
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001785static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx,
Theodore Ts'od5a8f9a2008-06-02 20:12:34 -04001786 struct process_block_struct *pb,
JP Abgralle0ed7402014-03-19 19:08:39 -07001787 blk64_t start_block, blk64_t end_block,
1788 blk64_t eof_block,
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001789 ext2_extent_handle_t ehandle)
1790{
1791 struct ext2fs_extent extent;
JP Abgralle0ed7402014-03-19 19:08:39 -07001792 blk64_t blk, last_lblk;
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001793 e2_blkcnt_t blockcnt;
Theodore Ts'o2acad6b2008-06-07 11:04:10 -04001794 unsigned int i;
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001795 int is_dir, is_leaf;
JP Abgralle0ed7402014-03-19 19:08:39 -07001796 problem_t problem;
Theodore Ts'o11de9262008-05-30 15:23:24 -04001797 struct ext2_extent_info info;
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001798
Theodore Ts'o11de9262008-05-30 15:23:24 -04001799 pctx->errcode = ext2fs_extent_get_info(ehandle, &info);
1800 if (pctx->errcode)
1801 return;
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001802
1803 pctx->errcode = ext2fs_extent_get(ehandle, EXT2_EXTENT_FIRST_SIB,
1804 &extent);
Theodore Ts'o11de9262008-05-30 15:23:24 -04001805 while (!pctx->errcode && info.num_entries-- > 0) {
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001806 is_leaf = extent.e_flags & EXT2_EXTENT_FLAGS_LEAF;
1807 is_dir = LINUX_S_ISDIR(pctx->inode->i_mode);
JP Abgralle0ed7402014-03-19 19:08:39 -07001808 last_lblk = extent.e_lblk + extent.e_len - 1;
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001809
1810 problem = 0;
Theodore Ts'oe6238d32010-05-14 18:03:14 -04001811 if (extent.e_pblk == 0 ||
1812 extent.e_pblk < ctx->fs->super->s_first_data_block ||
JP Abgralle0ed7402014-03-19 19:08:39 -07001813 extent.e_pblk >= ext2fs_blocks_count(ctx->fs->super))
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001814 problem = PR_1_EXTENT_BAD_START_BLK;
Theodore Ts'od5a8f9a2008-06-02 20:12:34 -04001815 else if (extent.e_lblk < start_block)
1816 problem = PR_1_OUT_OF_ORDER_EXTENTS;
JP Abgralle0ed7402014-03-19 19:08:39 -07001817 else if ((end_block && last_lblk > end_block) &&
1818 (!(extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT &&
1819 last_lblk > eof_block)))
1820 problem = PR_1_EXTENT_END_OUT_OF_BOUNDS;
1821 else if (is_leaf && extent.e_len == 0)
1822 problem = PR_1_EXTENT_LENGTH_ZERO;
Eric Sandeen7a1eac22008-04-01 20:38:58 -05001823 else if (is_leaf &&
1824 (extent.e_pblk + extent.e_len) >
JP Abgralle0ed7402014-03-19 19:08:39 -07001825 ext2fs_blocks_count(ctx->fs->super))
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001826 problem = PR_1_EXTENT_ENDS_BEYOND;
JP Abgralle0ed7402014-03-19 19:08:39 -07001827 else if (is_leaf && is_dir &&
1828 ((extent.e_lblk + extent.e_len) >
1829 (1 << (21 - ctx->fs->super->s_log_block_size))))
1830 problem = PR_1_TOOBIG_DIR;
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001831
1832 if (problem) {
JP Abgralle0ed7402014-03-19 19:08:39 -07001833report_problem:
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001834 pctx->blk = extent.e_pblk;
1835 pctx->blk2 = extent.e_lblk;
1836 pctx->num = extent.e_len;
JP Abgralle0ed7402014-03-19 19:08:39 -07001837 pctx->blkcount = extent.e_lblk + extent.e_len;
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001838 if (fix_problem(ctx, problem, pctx)) {
Theodore Ts'o19f433a2010-03-17 13:32:52 -04001839 e2fsck_read_bitmaps(ctx);
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001840 pctx->errcode =
1841 ext2fs_extent_delete(ehandle, 0);
1842 if (pctx->errcode) {
Theodore Ts'o7518c172008-12-25 22:42:38 -05001843 pctx->str = "ext2fs_extent_delete";
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001844 return;
1845 }
JP Abgralle0ed7402014-03-19 19:08:39 -07001846 ext2fs_extent_fix_parents(ehandle);
Theodore Ts'o73e5abc2008-05-28 04:54:44 -04001847 pctx->errcode = ext2fs_extent_get(ehandle,
1848 EXT2_EXTENT_CURRENT,
1849 &extent);
1850 if (pctx->errcode == EXT2_ET_NO_CURRENT_NODE) {
1851 pctx->errcode = 0;
1852 break;
1853 }
1854 continue;
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001855 }
1856 goto next;
1857 }
1858
1859 if (!is_leaf) {
JP Abgralle0ed7402014-03-19 19:08:39 -07001860 blk64_t lblk = extent.e_lblk;
1861
Theodore Ts'o7518c172008-12-25 22:42:38 -05001862 blk = extent.e_pblk;
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001863 pctx->errcode = ext2fs_extent_get(ehandle,
1864 EXT2_EXTENT_DOWN, &extent);
1865 if (pctx->errcode) {
Theodore Ts'o7518c172008-12-25 22:42:38 -05001866 pctx->str = "EXT2_EXTENT_DOWN";
1867 problem = PR_1_EXTENT_HEADER_INVALID;
1868 if (pctx->errcode == EXT2_ET_EXTENT_HEADER_BAD)
1869 goto report_problem;
1870 return;
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001871 }
JP Abgralle0ed7402014-03-19 19:08:39 -07001872 /* The next extent should match this index's logical start */
1873 if (extent.e_lblk != lblk) {
1874 struct ext2_extent_info e_info;
1875
1876 ext2fs_extent_get_info(ehandle, &e_info);
1877 pctx->blk = lblk;
1878 pctx->blk2 = extent.e_lblk;
1879 pctx->num = e_info.curr_level - 1;
1880 problem = PR_1_EXTENT_INDEX_START_INVALID;
1881 if (fix_problem(ctx, problem, pctx))
1882 ext2fs_extent_fix_parents(ehandle);
1883 }
1884 scan_extent_node(ctx, pctx, pb, extent.e_lblk,
1885 last_lblk, eof_block, ehandle);
Theodore Ts'o7518c172008-12-25 22:42:38 -05001886 if (pctx->errcode)
1887 return;
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001888 pctx->errcode = ext2fs_extent_get(ehandle,
1889 EXT2_EXTENT_UP, &extent);
1890 if (pctx->errcode) {
Theodore Ts'o7518c172008-12-25 22:42:38 -05001891 pctx->str = "EXT2_EXTENT_UP";
1892 return;
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001893 }
Theodore Ts'o7518c172008-12-25 22:42:38 -05001894 mark_block_used(ctx, blk);
1895 pb->num_blocks++;
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001896 goto next;
1897 }
1898
Theodore Ts'o63b5e352008-08-10 22:43:24 -04001899 if ((pb->previous_block != 0) &&
1900 (pb->previous_block+1 != extent.e_pblk)) {
Theodore Ts'o100d4702008-12-08 22:00:13 -05001901 if (ctx->options & E2F_OPT_FRAGCHECK) {
1902 char type = '?';
1903
1904 if (pb->is_dir)
1905 type = 'd';
1906 else if (pb->is_reg)
1907 type = 'f';
1908
1909 printf(("%6lu(%c): expecting %6lu "
1910 "actual extent "
Theodore Ts'o63b5e352008-08-10 22:43:24 -04001911 "phys %6lu log %lu len %lu\n"),
Theodore Ts'o100d4702008-12-08 22:00:13 -05001912 (unsigned long) pctx->ino, type,
Theodore Ts'o63b5e352008-08-10 22:43:24 -04001913 (unsigned long) pb->previous_block+1,
1914 (unsigned long) extent.e_pblk,
1915 (unsigned long) extent.e_lblk,
1916 (unsigned long) extent.e_len);
Theodore Ts'o100d4702008-12-08 22:00:13 -05001917 }
Theodore Ts'o63b5e352008-08-10 22:43:24 -04001918 pb->fragmented = 1;
1919 }
JP Abgralle0ed7402014-03-19 19:08:39 -07001920 while (is_dir && (++pb->last_db_block <
1921 (e2_blkcnt_t) extent.e_lblk)) {
1922 pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist,
1923 pb->ino, 0,
1924 pb->last_db_block);
Theodore Ts'o4607ef72009-11-29 00:06:10 -05001925 if (pctx->errcode) {
1926 pctx->blk = 0;
1927 pctx->num = pb->last_db_block;
1928 goto failed_add_dir_block;
1929 }
1930 }
JP Abgralle0ed7402014-03-19 19:08:39 -07001931 if (!ctx->fs->cluster_ratio_bits) {
1932 mark_blocks_used(ctx, extent.e_pblk, extent.e_len);
1933 pb->num_blocks += extent.e_len;
1934 }
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001935 for (blk = extent.e_pblk, blockcnt = extent.e_lblk, i = 0;
1936 i < extent.e_len;
1937 blk++, blockcnt++, i++) {
JP Abgralle0ed7402014-03-19 19:08:39 -07001938 if (ctx->fs->cluster_ratio_bits &&
1939 !(pb->previous_block &&
1940 (EXT2FS_B2C(ctx->fs, blk) ==
1941 EXT2FS_B2C(ctx->fs, pb->previous_block)) &&
1942 (blk & EXT2FS_CLUSTER_MASK(ctx->fs)) ==
1943 ((unsigned) blockcnt & EXT2FS_CLUSTER_MASK(ctx->fs)))) {
1944 mark_block_used(ctx, blk);
1945 pb->num_blocks++;
1946 }
1947
1948 pb->previous_block = blk;
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001949
1950 if (is_dir) {
JP Abgralle0ed7402014-03-19 19:08:39 -07001951 pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist, pctx->ino, blk, blockcnt);
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001952 if (pctx->errcode) {
1953 pctx->blk = blk;
1954 pctx->num = blockcnt;
Theodore Ts'o4607ef72009-11-29 00:06:10 -05001955 failed_add_dir_block:
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001956 fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
1957 /* Should never get here */
1958 ctx->flags |= E2F_FLAG_ABORT;
1959 return;
1960 }
1961 }
1962 }
Theodore Ts'o4607ef72009-11-29 00:06:10 -05001963 if (is_dir && extent.e_len > 0)
1964 pb->last_db_block = blockcnt - 1;
Theodore Ts'o63b5e352008-08-10 22:43:24 -04001965 pb->previous_block = extent.e_pblk + extent.e_len - 1;
JP Abgralle0ed7402014-03-19 19:08:39 -07001966 start_block = pb->last_block = last_lblk;
1967 if (is_leaf && !is_dir &&
1968 !(extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT))
1969 pb->last_init_lblock = last_lblk;
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001970 next:
1971 pctx->errcode = ext2fs_extent_get(ehandle,
1972 EXT2_EXTENT_NEXT_SIB,
1973 &extent);
1974 }
1975 if (pctx->errcode == EXT2_ET_EXTENT_NO_NEXT)
1976 pctx->errcode = 0;
1977}
1978
1979static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx,
Theodore Ts'o2acad6b2008-06-07 11:04:10 -04001980 struct process_block_struct *pb)
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001981{
Theodore Ts'o8da6d1a2008-08-14 09:48:07 -04001982 struct ext2_extent_info info;
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001983 struct ext2_inode *inode = pctx->inode;
1984 ext2_extent_handle_t ehandle;
1985 ext2_filsys fs = ctx->fs;
1986 ext2_ino_t ino = pctx->ino;
Theodore Ts'o8da6d1a2008-08-14 09:48:07 -04001987 errcode_t retval;
JP Abgralle0ed7402014-03-19 19:08:39 -07001988 blk64_t eof_lblk;
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001989
number965284b239a2009-05-19 13:34:12 -07001990 pctx->errcode = ext2fs_extent_open2(fs, ino, inode, &ehandle);
Theodore Ts'o0a68b182009-05-17 08:42:52 -04001991 if (pctx->errcode) {
1992 if (fix_problem(ctx, PR_1_READ_EXTENT, pctx))
1993 e2fsck_clear_inode(ctx, ino, inode, 0,
1994 "check_blocks_extents");
Theodore Ts'o15d482b2007-08-20 21:31:11 -04001995 pctx->errcode = 0;
1996 return;
1997 }
1998
Theodore Ts'o8da6d1a2008-08-14 09:48:07 -04001999 retval = ext2fs_extent_get_info(ehandle, &info);
2000 if (retval == 0) {
2001 if (info.max_depth >= MAX_EXTENT_DEPTH_COUNT)
2002 info.max_depth = MAX_EXTENT_DEPTH_COUNT-1;
2003 ctx->extent_depth_count[info.max_depth]++;
2004 }
2005
JP Abgralle0ed7402014-03-19 19:08:39 -07002006 eof_lblk = ((EXT2_I_SIZE(inode) + fs->blocksize - 1) >>
2007 EXT2_BLOCK_SIZE_BITS(fs->super)) - 1;
2008 scan_extent_node(ctx, pctx, pb, 0, 0, eof_lblk, ehandle);
Theodore Ts'o7518c172008-12-25 22:42:38 -05002009 if (pctx->errcode &&
2010 fix_problem(ctx, PR_1_EXTENT_ITERATE_FAILURE, pctx)) {
2011 pb->num_blocks = 0;
2012 inode->i_blocks = 0;
2013 e2fsck_clear_inode(ctx, ino, inode, E2F_FLAG_RESTART,
2014 "check_blocks_extents");
2015 pctx->errcode = 0;
2016 }
Theodore Ts'o15d482b2007-08-20 21:31:11 -04002017 ext2fs_extent_free(ehandle);
2018}
2019
Theodore Ts'o342d8472001-07-02 11:54:09 -04002020/*
Theodore Ts'o3839e651997-04-26 13:21:57 +00002021 * This subroutine is called on each inode to account for all of the
2022 * blocks used by that inode.
2023 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002024static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
Theodore Ts'o3839e651997-04-26 13:21:57 +00002025 char *block_buf)
2026{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002027 ext2_filsys fs = ctx->fs;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002028 struct process_block_struct pb;
Theodore Ts'o86c627e2001-01-11 15:12:14 +00002029 ext2_ino_t ino = pctx->ino;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002030 struct ext2_inode *inode = pctx->inode;
JP Abgralle0ed7402014-03-19 19:08:39 -07002031 unsigned bad_size = 0;
Theodore Ts'o503f9e72002-06-26 16:52:10 -04002032 int dirty_inode = 0;
Eric Sandeen7c1e0902008-07-06 23:02:47 -05002033 int extent_fs;
Theodore Ts'o246501c1998-03-24 16:22:38 +00002034 __u64 size;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002035
Theodore Ts'o3839e651997-04-26 13:21:57 +00002036 pb.ino = ino;
Theodore Ts'o0684a4f2002-08-17 10:19:44 -04002037 pb.num_blocks = 0;
2038 pb.last_block = -1;
JP Abgralle0ed7402014-03-19 19:08:39 -07002039 pb.last_init_lblock = -1;
Theodore Ts'o4dbe79b2009-11-28 09:35:37 -05002040 pb.last_db_block = -1;
Theodore Ts'of3db3561997-04-26 13:34:30 +00002041 pb.num_illegal_blocks = 0;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002042 pb.suppress = 0; pb.clear = 0;
Theodore Ts'o74becf31997-04-26 14:37:06 +00002043 pb.fragmented = 0;
Theodore Ts'o19178752000-02-11 15:55:07 +00002044 pb.compressed = 0;
Theodore Ts'o74becf31997-04-26 14:37:06 +00002045 pb.previous_block = 0;
Andreas Dilgerb94a0522002-05-18 13:16:30 -06002046 pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
Theodore Ts'oda307042002-05-21 21:19:14 -04002047 pb.is_reg = LINUX_S_ISREG(inode->i_mode);
2048 pb.max_blocks = 1 << (31 - fs->super->s_log_block_size);
Theodore Ts'of3db3561997-04-26 13:34:30 +00002049 pb.inode = inode;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002050 pb.pctx = pctx;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002051 pb.ctx = ctx;
2052 pctx->ino = ino;
Theodore Ts'o0684a4f2002-08-17 10:19:44 -04002053 pctx->errcode = 0;
Theodore Ts'o19178752000-02-11 15:55:07 +00002054
Eric Sandeen7c1e0902008-07-06 23:02:47 -05002055 extent_fs = (ctx->fs->super->s_feature_incompat &
2056 EXT3_FEATURE_INCOMPAT_EXTENTS);
2057
Theodore Ts'o19178752000-02-11 15:55:07 +00002058 if (inode->i_flags & EXT2_COMPRBLK_FL) {
Theodore Ts'of5ae75e2001-01-01 14:52:52 +00002059 if (fs->super->s_feature_incompat &
2060 EXT2_FEATURE_INCOMPAT_COMPRESSION)
Theodore Ts'o19178752000-02-11 15:55:07 +00002061 pb.compressed = 1;
2062 else {
2063 if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) {
2064 inode->i_flags &= ~EXT2_COMPRBLK_FL;
Theodore Ts'o503f9e72002-06-26 16:52:10 -04002065 dirty_inode++;
Theodore Ts'o19178752000-02-11 15:55:07 +00002066 }
2067 }
2068 }
2069
JP Abgralle0ed7402014-03-19 19:08:39 -07002070 if (ext2fs_file_acl_block(fs, inode) &&
2071 check_ext_attr(ctx, pctx, block_buf)) {
Andreas Dilgerfefaef32008-02-02 01:16:32 -07002072 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
2073 goto out;
Theodore Ts'odc71f232005-03-20 16:57:10 -05002074 pb.num_blocks++;
Andreas Dilgerfefaef32008-02-02 01:16:32 -07002075 }
Theodore Ts'odc71f232005-03-20 16:57:10 -05002076
JP Abgralle0ed7402014-03-19 19:08:39 -07002077 if (ext2fs_inode_has_valid_blocks2(fs, inode)) {
Eric Sandeen7c1e0902008-07-06 23:02:47 -05002078 if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL))
Theodore Ts'o2acad6b2008-06-07 11:04:10 -04002079 check_blocks_extents(ctx, pctx, &pb);
JP Abgralle0ed7402014-03-19 19:08:39 -07002080 else {
2081 pctx->errcode = ext2fs_block_iterate3(fs, ino,
Theodore Ts'o15d482b2007-08-20 21:31:11 -04002082 pb.is_dir ? BLOCK_FLAG_HOLE : 0,
2083 block_buf, process_block, &pb);
JP Abgralle0ed7402014-03-19 19:08:39 -07002084 /*
2085 * We do not have uninitialized extents in non extent
2086 * files.
2087 */
2088 pb.last_init_lblock = pb.last_block;
2089 }
Theodore Ts'o15d482b2007-08-20 21:31:11 -04002090 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002091 end_problem_latch(ctx, PR_LATCH_BLOCK);
Theodore Ts'oda307042002-05-21 21:19:14 -04002092 end_problem_latch(ctx, PR_LATCH_TOOBIG);
Theodore Ts'o0684a4f2002-08-17 10:19:44 -04002093 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
2094 goto out;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002095 if (pctx->errcode)
2096 fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +00002097
Theodore Ts'oce44d8c2008-12-08 21:33:11 -05002098 if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group) {
2099 if (LINUX_S_ISDIR(inode->i_mode))
2100 ctx->fs_fragmented_dir++;
2101 else
2102 ctx->fs_fragmented++;
2103 }
Theodore Ts'o74becf31997-04-26 14:37:06 +00002104
Theodore Ts'of3db3561997-04-26 13:34:30 +00002105 if (pb.clear) {
Theodore Ts'oe3df15a2007-09-15 14:10:47 -04002106 e2fsck_clear_inode(ctx, ino, inode, E2F_FLAG_RESTART,
2107 "check_blocks");
2108 return;
Theodore Ts'of3db3561997-04-26 13:34:30 +00002109 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002110
Theodore Ts'o8fdc9982002-06-25 23:26:34 -04002111 if (inode->i_flags & EXT2_INDEX_FL) {
Theodore Ts'o503f9e72002-06-26 16:52:10 -04002112 if (handle_htree(ctx, pctx, ino, inode, block_buf)) {
2113 inode->i_flags &= ~EXT2_INDEX_FL;
2114 dirty_inode++;
2115 } else {
Theodore Ts'o8fdc9982002-06-25 23:26:34 -04002116#ifdef ENABLE_HTREE
2117 e2fsck_add_dx_dir(ctx, ino, pb.last_block+1);
2118#endif
Theodore Ts'o503f9e72002-06-26 16:52:10 -04002119 }
Theodore Ts'o8fdc9982002-06-25 23:26:34 -04002120 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002121
Theodore Ts'o3839e651997-04-26 13:21:57 +00002122 if (!pb.num_blocks && pb.is_dir) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002123 if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) {
Theodore Ts'oe3df15a2007-09-15 14:10:47 -04002124 e2fsck_clear_inode(ctx, ino, inode, 0, "check_blocks");
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002125 ctx->fs_directory_count--;
Theodore Ts'oe3df15a2007-09-15 14:10:47 -04002126 return;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002127 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00002128 }
Theodore Ts'o0684a4f2002-08-17 10:19:44 -04002129
JP Abgralle0ed7402014-03-19 19:08:39 -07002130 if (ino == EXT2_ROOT_INO || ino >= EXT2_FIRST_INODE(ctx->fs->super)) {
2131 quota_data_add(ctx->qctx, inode, ino,
2132 pb.num_blocks * fs->blocksize);
2133 quota_data_inodes(ctx->qctx, inode, ino, +1);
2134 }
2135
Theodore Ts'o1ca10592008-04-09 11:39:11 -04002136 if (!(fs->super->s_feature_ro_compat &
2137 EXT4_FEATURE_RO_COMPAT_HUGE_FILE) ||
2138 !(inode->i_flags & EXT4_HUGE_FILE_FL))
2139 pb.num_blocks *= (fs->blocksize / 512);
JP Abgralle0ed7402014-03-19 19:08:39 -07002140 pb.num_blocks *= EXT2FS_CLUSTER_RATIO(fs);
Theodore Ts'o0684a4f2002-08-17 10:19:44 -04002141#if 0
JP Abgralle0ed7402014-03-19 19:08:39 -07002142 printf("inode %u, i_size = %u, last_block = %lld, i_blocks=%llu, num_blocks = %llu\n",
2143 ino, inode->i_size, pb.last_block, ext2fs_inode_i_blocks(fs, inode),
Theodore Ts'o0684a4f2002-08-17 10:19:44 -04002144 pb.num_blocks);
2145#endif
Theodore Ts'o246501c1998-03-24 16:22:38 +00002146 if (pb.is_dir) {
2147 int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super);
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002148 if (inode->i_size & (fs->blocksize - 1))
Theodore Ts'o2cd12332008-03-13 00:58:54 -04002149 bad_size = 5;
2150 else if (nblock > (pb.last_block + 1))
Theodore Ts'o246501c1998-03-24 16:22:38 +00002151 bad_size = 1;
2152 else if (nblock < (pb.last_block + 1)) {
Theodore Ts'o246501c1998-03-24 16:22:38 +00002153 if (((pb.last_block + 1) - nblock) >
Theodore Ts'o5dd8f962001-01-01 15:51:50 +00002154 fs->super->s_prealloc_dir_blocks)
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +00002155 bad_size = 2;
Theodore Ts'o246501c1998-03-24 16:22:38 +00002156 }
2157 } else {
Theodore Ts'o9f0288d2007-08-03 20:43:37 -04002158 e2_blkcnt_t blkpg = ctx->blocks_per_page;
2159
Theodore Ts'o4f489282003-01-22 18:28:15 -05002160 size = EXT2_I_SIZE(inode);
JP Abgralle0ed7402014-03-19 19:08:39 -07002161 if ((pb.last_init_lblock >= 0) &&
Theodore Ts'o9f0288d2007-08-03 20:43:37 -04002162 /* allow allocated blocks to end of PAGE_SIZE */
JP Abgralle0ed7402014-03-19 19:08:39 -07002163 (size < (__u64)pb.last_init_lblock * fs->blocksize) &&
2164 (pb.last_init_lblock / blkpg * blkpg != pb.last_init_lblock ||
2165 size < (__u64)(pb.last_init_lblock & ~(blkpg-1)) *
2166 fs->blocksize))
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +00002167 bad_size = 3;
Eric Sandeen7c1e0902008-07-06 23:02:47 -05002168 else if (!(extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) &&
2169 size > ext2_max_sizes[fs->super->s_log_block_size])
2170 /* too big for a direct/indirect-mapped file */
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +00002171 bad_size = 4;
Eric Sandeen7c1e0902008-07-06 23:02:47 -05002172 else if ((extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) &&
Theodore Ts'o3ec7be42008-08-17 09:41:38 -04002173 size >
Theodore Ts'o03fa6f82008-11-16 10:03:00 -05002174 ((1ULL << (32 + EXT2_BLOCK_SIZE_BITS(fs->super))) - 1))
Eric Sandeen7c1e0902008-07-06 23:02:47 -05002175 /* too big for an extent-based file - 32bit ee_block */
2176 bad_size = 6;
Theodore Ts'o246501c1998-03-24 16:22:38 +00002177 }
Theodore Ts'o0684a4f2002-08-17 10:19:44 -04002178 /* i_size for symlinks is checked elsewhere */
2179 if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002180 pctx->num = (pb.last_block+1) * fs->blocksize;
Theodore Ts'o3ec7be42008-08-17 09:41:38 -04002181 pctx->group = bad_size;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002182 if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002183 inode->i_size = pctx->num;
Theodore Ts'o0684a4f2002-08-17 10:19:44 -04002184 if (!LINUX_S_ISDIR(inode->i_mode))
Theodore Ts'o246501c1998-03-24 16:22:38 +00002185 inode->i_size_high = pctx->num >> 32;
Theodore Ts'o503f9e72002-06-26 16:52:10 -04002186 dirty_inode++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002187 }
2188 pctx->num = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002189 }
Darrick J. Wong3b6c0932013-12-10 17:18:27 -08002190 if (LINUX_S_ISREG(inode->i_mode) &&
JP Abgralle0ed7402014-03-19 19:08:39 -07002191 ext2fs_needs_large_file_feature(EXT2_I_SIZE(inode)))
Theodore Ts'o246501c1998-03-24 16:22:38 +00002192 ctx->large_files++;
Theodore Ts'o8a8f3652009-10-12 21:59:37 -04002193 if ((pb.num_blocks != ext2fs_inode_i_blocks(fs, inode)) ||
Theodore Ts'o1ca10592008-04-09 11:39:11 -04002194 ((fs->super->s_feature_ro_compat &
2195 EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
2196 (inode->i_flags & EXT4_HUGE_FILE_FL) &&
2197 (inode->osd2.linux2.l_i_blocks_hi != 0))) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002198 pctx->num = pb.num_blocks;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002199 if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +00002200 inode->i_blocks = pb.num_blocks;
JP Abgralle0ed7402014-03-19 19:08:39 -07002201 inode->osd2.linux2.l_i_blocks_hi = pb.num_blocks >> 32;
Theodore Ts'o503f9e72002-06-26 16:52:10 -04002202 dirty_inode++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002203 }
2204 pctx->num = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002205 }
Theodore Ts'oa49249d2009-11-28 09:44:08 -05002206
2207 if (ctx->dirs_to_hash && pb.is_dir &&
2208 !(inode->i_flags & EXT2_INDEX_FL) &&
2209 ((inode->i_size / fs->blocksize) >= 3))
2210 ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
2211
Theodore Ts'o503f9e72002-06-26 16:52:10 -04002212out:
2213 if (dirty_inode)
2214 e2fsck_write_inode(ctx, ino, inode, "check_blocks");
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002215}
2216
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002217#if 0
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002218/*
2219 * Helper function called by process block when an illegal block is
2220 * found. It returns a description about why the block is illegal
2221 */
JP Abgralle0ed7402014-03-19 19:08:39 -07002222static char *describe_illegal_block(ext2_filsys fs, blk64_t block)
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002223{
JP Abgralle0ed7402014-03-19 19:08:39 -07002224 blk64_t super;
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002225 int i;
2226 static char problem[80];
2227
2228 super = fs->super->s_first_data_block;
2229 strcpy(problem, "PROGRAMMING ERROR: Unknown reason for illegal block");
2230 if (block < super) {
2231 sprintf(problem, "< FIRSTBLOCK (%u)", super);
2232 return(problem);
JP Abgralle0ed7402014-03-19 19:08:39 -07002233 } else if (block >= ext2fs_blocks_count(fs->super)) {
2234 sprintf(problem, "> BLOCKS (%u)", ext2fs_blocks_count(fs->super));
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002235 return(problem);
2236 }
2237 for (i = 0; i < fs->group_desc_count; i++) {
2238 if (block == super) {
2239 sprintf(problem, "is the superblock in group %d", i);
2240 break;
2241 }
2242 if (block > super &&
2243 block <= (super + fs->desc_blocks)) {
2244 sprintf(problem, "is in the group descriptors "
2245 "of group %d", i);
2246 break;
2247 }
JP Abgralle0ed7402014-03-19 19:08:39 -07002248 if (block == ext2fs_block_bitmap_loc(fs, i)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002249 sprintf(problem, "is the block bitmap of group %d", i);
2250 break;
2251 }
JP Abgralle0ed7402014-03-19 19:08:39 -07002252 if (block == ext2fs_inode_bitmap_loc(fs, i)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002253 sprintf(problem, "is the inode bitmap of group %d", i);
2254 break;
2255 }
JP Abgralle0ed7402014-03-19 19:08:39 -07002256 if (block >= ext2fs_inode_table_loc(fs, i) &&
2257 (block < ext2fs_inode_table_loc(fs, i)
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002258 + fs->inode_blocks_per_group)) {
2259 sprintf(problem, "is in the inode table of group %d",
2260 i);
2261 break;
2262 }
2263 super += fs->super->s_blocks_per_group;
2264 }
2265 return(problem);
2266}
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002267#endif
Theodore Ts'o3839e651997-04-26 13:21:57 +00002268
2269/*
2270 * This is a helper function for check_blocks().
2271 */
Theodore Ts'o53ef44c2001-01-06 05:55:58 +00002272static int process_block(ext2_filsys fs,
JP Abgralle0ed7402014-03-19 19:08:39 -07002273 blk64_t *block_nr,
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +00002274 e2_blkcnt_t blockcnt,
JP Abgralle0ed7402014-03-19 19:08:39 -07002275 blk64_t ref_block EXT2FS_ATTR((unused)),
Theodore Ts'o54434922003-12-07 01:28:50 -05002276 int ref_offset EXT2FS_ATTR((unused)),
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00002277 void *priv_data)
Theodore Ts'o3839e651997-04-26 13:21:57 +00002278{
2279 struct process_block_struct *p;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002280 struct problem_context *pctx;
JP Abgralle0ed7402014-03-19 19:08:39 -07002281 blk64_t blk = *block_nr;
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002282 int ret_code = 0;
JP Abgralle0ed7402014-03-19 19:08:39 -07002283 problem_t problem = 0;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002284 e2fsck_t ctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002285
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00002286 p = (struct process_block_struct *) priv_data;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002287 pctx = p->pctx;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002288 ctx = p->ctx;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002289
Theodore Ts'o19178752000-02-11 15:55:07 +00002290 if (p->compressed && (blk == EXT2FS_COMPRESSED_BLKADDR)) {
2291 /* todo: Check that the comprblk_fl is high, that the
2292 blkaddr pattern looks right (all non-holes up to
2293 first EXT2FS_COMPRESSED_BLKADDR, then all
2294 EXT2FS_COMPRESSED_BLKADDR up to end of cluster),
2295 that the feature_incompat bit is high, and that the
2296 inode is a regular file. If we're doing a "full
2297 check" (a concept introduced to e2fsck by e2compr,
2298 meaning that we look at data blocks as well as
2299 metadata) then call some library routine that
2300 checks the compressed data. I'll have to think
2301 about this, because one particularly important
2302 problem to be able to fix is to recalculate the
2303 cluster size if necessary. I think that perhaps
2304 we'd better do most/all e2compr-specific checks
2305 separately, after the non-e2compr checks. If not
2306 doing a full check, it may be useful to test that
2307 the personality is linux; e.g. if it isn't then
2308 perhaps this really is just an illegal block. */
2309 return 0;
2310 }
Andreas Dilgerb94a0522002-05-18 13:16:30 -06002311
Theodore Ts'o4dbe79b2009-11-28 09:35:37 -05002312 if (blk == 0)
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002313 return 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002314
2315#if 0
2316 printf("Process_block, inode %lu, block %u, #%d\n", p->ino, blk,
2317 blockcnt);
2318#endif
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002319
Theodore Ts'o74becf31997-04-26 14:37:06 +00002320 /*
2321 * Simplistic fragmentation check. We merely require that the
2322 * file be contiguous. (Which can never be true for really
2323 * big files that are greater than a block group.)
2324 */
Theodore Ts'o63b5e352008-08-10 22:43:24 -04002325 if (!HOLE_BLKADDR(p->previous_block) && p->ino != EXT2_RESIZE_INO) {
2326 if (p->previous_block+1 != blk) {
Theodore Ts'o100d4702008-12-08 22:00:13 -05002327 if (ctx->options & E2F_OPT_FRAGCHECK) {
2328 char type = '?';
2329
2330 if (p->is_dir)
2331 type = 'd';
2332 else if (p->is_reg)
2333 type = 'f';
2334
2335 printf(_("%6lu(%c): expecting %6lu "
2336 "got phys %6lu (blkcnt %lld)\n"),
2337 (unsigned long) pctx->ino, type,
Theodore Ts'o63b5e352008-08-10 22:43:24 -04002338 (unsigned long) p->previous_block+1,
2339 (unsigned long) blk,
Theodore Ts'of4e2c992008-08-12 22:11:02 -04002340 blockcnt);
Theodore Ts'o100d4702008-12-08 22:00:13 -05002341 }
Theodore Ts'o74becf31997-04-26 14:37:06 +00002342 p->fragmented = 1;
Theodore Ts'o63b5e352008-08-10 22:43:24 -04002343 }
Theodore Ts'o74becf31997-04-26 14:37:06 +00002344 }
Theodore Ts'o503f9e72002-06-26 16:52:10 -04002345
Theodore Ts'o8421fb62004-07-26 20:11:49 -04002346 if (p->is_dir && blockcnt > (1 << (21 - fs->super->s_log_block_size)))
Theodore Ts'oda307042002-05-21 21:19:14 -04002347 problem = PR_1_TOOBIG_DIR;
2348 if (p->is_reg && p->num_blocks+1 >= p->max_blocks)
2349 problem = PR_1_TOOBIG_REG;
2350 if (!p->is_dir && !p->is_reg && blockcnt > 0)
2351 problem = PR_1_TOOBIG_SYMLINK;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002352
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002353 if (blk < fs->super->s_first_data_block ||
JP Abgralle0ed7402014-03-19 19:08:39 -07002354 blk >= ext2fs_blocks_count(fs->super))
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002355 problem = PR_1_ILLEGAL_BLOCK_NUM;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002356
2357 if (problem) {
Theodore Ts'of3db3561997-04-26 13:34:30 +00002358 p->num_illegal_blocks++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002359 if (!p->suppress && (p->num_illegal_blocks % 12) == 0) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002360 if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) {
Theodore Ts'of3db3561997-04-26 13:34:30 +00002361 p->clear = 1;
2362 return BLOCK_ABORT;
2363 }
Theodore Ts'of8188ff1997-11-14 05:23:04 +00002364 if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) {
Theodore Ts'of3db3561997-04-26 13:34:30 +00002365 p->suppress = 1;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002366 set_latch_flags(PR_LATCH_BLOCK,
2367 PRL_SUPPRESS, 0);
Theodore Ts'of3db3561997-04-26 13:34:30 +00002368 }
2369 }
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002370 pctx->blk = blk;
2371 pctx->blkcount = blockcnt;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002372 if (fix_problem(ctx, problem, pctx)) {
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002373 blk = *block_nr = 0;
2374 ret_code = BLOCK_CHANGED;
2375 goto mark_dir;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002376 } else
Theodore Ts'o3839e651997-04-26 13:21:57 +00002377 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002378 }
2379
Theodore Ts'od323f8f2004-12-15 14:39:16 -05002380 if (p->ino == EXT2_RESIZE_INO) {
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002381 /*
Theodore Ts'oc3ffaf82004-12-24 01:42:22 -05002382 * The resize inode has already be sanity checked
2383 * during pass #0 (the superblock checks). All we
2384 * have to do is mark the double indirect block as
2385 * being in use; all of the other blocks are handled
2386 * by mark_table_blocks()).
2387 */
2388 if (blockcnt == BLOCK_COUNT_DIND)
Theodore Ts'od323f8f2004-12-15 14:39:16 -05002389 mark_block_used(ctx, blk);
JP Abgralle0ed7402014-03-19 19:08:39 -07002390 p->num_blocks++;
2391 } else if (!(ctx->fs->cluster_ratio_bits &&
2392 p->previous_block &&
2393 (EXT2FS_B2C(ctx->fs, blk) ==
2394 EXT2FS_B2C(ctx->fs, p->previous_block)) &&
2395 (blk & EXT2FS_CLUSTER_MASK(ctx->fs)) ==
2396 ((unsigned) blockcnt & EXT2FS_CLUSTER_MASK(ctx->fs)))) {
Theodore Ts'od323f8f2004-12-15 14:39:16 -05002397 mark_block_used(ctx, blk);
JP Abgralle0ed7402014-03-19 19:08:39 -07002398 p->num_blocks++;
2399 }
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00002400 if (blockcnt >= 0)
2401 p->last_block = blockcnt;
JP Abgralle0ed7402014-03-19 19:08:39 -07002402 p->previous_block = blk;
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002403mark_dir:
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00002404 if (p->is_dir && (blockcnt >= 0)) {
Theodore Ts'o4dbe79b2009-11-28 09:35:37 -05002405 while (++p->last_db_block < blockcnt) {
JP Abgralle0ed7402014-03-19 19:08:39 -07002406 pctx->errcode = ext2fs_add_dir_block2(fs->dblist,
2407 p->ino, 0,
2408 p->last_db_block);
Theodore Ts'o4dbe79b2009-11-28 09:35:37 -05002409 if (pctx->errcode) {
2410 pctx->blk = 0;
2411 pctx->num = p->last_db_block;
2412 goto failed_add_dir_block;
2413 }
2414 }
JP Abgralle0ed7402014-03-19 19:08:39 -07002415 pctx->errcode = ext2fs_add_dir_block2(fs->dblist, p->ino,
2416 blk, blockcnt);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002417 if (pctx->errcode) {
2418 pctx->blk = blk;
2419 pctx->num = blockcnt;
Theodore Ts'o4dbe79b2009-11-28 09:35:37 -05002420 failed_add_dir_block:
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002421 fix_problem(ctx, PR_1_ADD_DBLOCK, pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +00002422 /* Should never get here */
2423 ctx->flags |= E2F_FLAG_ABORT;
2424 return BLOCK_ABORT;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002425 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00002426 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002427 return ret_code;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002428}
2429
Theodore Ts'o53ef44c2001-01-06 05:55:58 +00002430static int process_bad_block(ext2_filsys fs,
JP Abgralle0ed7402014-03-19 19:08:39 -07002431 blk64_t *block_nr,
Theodore Ts'o9d1bd3d1998-06-10 20:45:22 +00002432 e2_blkcnt_t blockcnt,
JP Abgralle0ed7402014-03-19 19:08:39 -07002433 blk64_t ref_block EXT2FS_ATTR((unused)),
Theodore Ts'o54434922003-12-07 01:28:50 -05002434 int ref_offset EXT2FS_ATTR((unused)),
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00002435 void *priv_data)
Theodore Ts'o3839e651997-04-26 13:21:57 +00002436{
2437 struct process_block_struct *p;
JP Abgralle0ed7402014-03-19 19:08:39 -07002438 blk64_t blk = *block_nr;
2439 blk64_t first_block;
Theodore Ts'o54434922003-12-07 01:28:50 -05002440 dgrp_t i;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002441 struct problem_context *pctx;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002442 e2fsck_t ctx;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002443
Theodore Ts'o19178752000-02-11 15:55:07 +00002444 /*
2445 * Note: This function processes blocks for the bad blocks
2446 * inode, which is never compressed. So we don't use HOLE_BLKADDR().
2447 */
2448
Theodore Ts'o3839e651997-04-26 13:21:57 +00002449 if (!blk)
2450 return 0;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002451
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00002452 p = (struct process_block_struct *) priv_data;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002453 ctx = p->ctx;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002454 pctx = p->pctx;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002455
Theodore Ts'of8188ff1997-11-14 05:23:04 +00002456 pctx->ino = EXT2_BAD_INO;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002457 pctx->blk = blk;
2458 pctx->blkcount = blockcnt;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002459
2460 if ((blk < fs->super->s_first_data_block) ||
JP Abgralle0ed7402014-03-19 19:08:39 -07002461 (blk >= ext2fs_blocks_count(fs->super))) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002462 if (fix_problem(ctx, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +00002463 *block_nr = 0;
2464 return BLOCK_CHANGED;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002465 } else
Theodore Ts'o3839e651997-04-26 13:21:57 +00002466 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002467 }
2468
2469 if (blockcnt < 0) {
JP Abgralle0ed7402014-03-19 19:08:39 -07002470 if (ext2fs_test_block_bitmap2(p->fs_meta_blocks, blk)) {
Theodore Ts'o000ba402003-11-21 10:41:58 -05002471 p->bbcheck = 1;
2472 if (fix_problem(ctx, PR_1_BB_FS_BLOCK, pctx)) {
2473 *block_nr = 0;
2474 return BLOCK_CHANGED;
2475 }
JP Abgralle0ed7402014-03-19 19:08:39 -07002476 } else if (ext2fs_test_block_bitmap2(ctx->block_found_map,
Theodore Ts'o000ba402003-11-21 10:41:58 -05002477 blk)) {
2478 p->bbcheck = 1;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002479 if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK,
Theodore Ts'o000ba402003-11-21 10:41:58 -05002480 pctx)) {
2481 *block_nr = 0;
2482 return BLOCK_CHANGED;
2483 }
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +00002484 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +00002485 return BLOCK_ABORT;
2486 } else
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002487 mark_block_used(ctx, blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +00002488 return 0;
2489 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002490#if 0
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002491 printf ("DEBUG: Marking %u as bad.\n", blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +00002492#endif
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002493 ctx->fs_badblocks_count++;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002494 /*
2495 * If the block is not used, then mark it as used and return.
2496 * If it is already marked as found, this must mean that
2497 * there's an overlap between the filesystem table blocks
2498 * (bitmaps and inode table) and the bad block list.
2499 */
JP Abgralle0ed7402014-03-19 19:08:39 -07002500 if (!ext2fs_test_block_bitmap2(ctx->block_found_map, blk)) {
2501 ext2fs_mark_block_bitmap2(ctx->block_found_map, blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +00002502 return 0;
2503 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00002504 /*
2505 * Try to find the where the filesystem block was used...
2506 */
2507 first_block = fs->super->s_first_data_block;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002508
Theodore Ts'of3db3561997-04-26 13:34:30 +00002509 for (i = 0; i < fs->group_desc_count; i++ ) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002510 pctx->group = i;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002511 pctx->blk = blk;
Theodore Ts'o8039c481997-11-19 21:39:13 +00002512 if (!ext2fs_bg_has_super(fs, i))
2513 goto skip_super;
Theodore Ts'of3db3561997-04-26 13:34:30 +00002514 if (blk == first_block) {
2515 if (i == 0) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002516 if (fix_problem(ctx,
2517 PR_1_BAD_PRIMARY_SUPERBLOCK,
2518 pctx)) {
2519 *block_nr = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002520 return BLOCK_CHANGED;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002521 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002522 return 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +00002523 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002524 fix_problem(ctx, PR_1_BAD_SUPERBLOCK, pctx);
Theodore Ts'of3db3561997-04-26 13:34:30 +00002525 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002526 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00002527 if ((blk > first_block) &&
2528 (blk <= first_block + fs->desc_blocks)) {
2529 if (i == 0) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002530 pctx->blk = *block_nr;
2531 if (fix_problem(ctx,
2532 PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR, pctx)) {
2533 *block_nr = 0;
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002534 return BLOCK_CHANGED;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002535 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002536 return 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +00002537 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002538 fix_problem(ctx, PR_1_BAD_GROUP_DESCRIPTORS, pctx);
Theodore Ts'of3db3561997-04-26 13:34:30 +00002539 return 0;
2540 }
Theodore Ts'o8039c481997-11-19 21:39:13 +00002541 skip_super:
JP Abgralle0ed7402014-03-19 19:08:39 -07002542 if (blk == ext2fs_block_bitmap_loc(fs, i)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002543 if (fix_problem(ctx, PR_1_BB_BAD_BLOCK, pctx)) {
2544 ctx->invalid_block_bitmap_flag[i]++;
2545 ctx->invalid_bitmaps++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002546 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00002547 return 0;
2548 }
JP Abgralle0ed7402014-03-19 19:08:39 -07002549 if (blk == ext2fs_inode_bitmap_loc(fs, i)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002550 if (fix_problem(ctx, PR_1_IB_BAD_BLOCK, pctx)) {
2551 ctx->invalid_inode_bitmap_flag[i]++;
2552 ctx->invalid_bitmaps++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002553 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00002554 return 0;
2555 }
JP Abgralle0ed7402014-03-19 19:08:39 -07002556 if ((blk >= ext2fs_inode_table_loc(fs, i)) &&
2557 (blk < (ext2fs_inode_table_loc(fs, i) +
Theodore Ts'of3db3561997-04-26 13:34:30 +00002558 fs->inode_blocks_per_group))) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002559 /*
2560 * If there are bad blocks in the inode table,
2561 * the inode scan code will try to do
2562 * something reasonable automatically.
2563 */
Theodore Ts'of3db3561997-04-26 13:34:30 +00002564 return 0;
2565 }
Theodore Ts'o8039c481997-11-19 21:39:13 +00002566 first_block += fs->super->s_blocks_per_group;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002567 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00002568 /*
2569 * If we've gotten to this point, then the only
2570 * possibility is that the bad block inode meta data
2571 * is using a bad block.
2572 */
2573 if ((blk == p->inode->i_block[EXT2_IND_BLOCK]) ||
Theodore Ts'o000ba402003-11-21 10:41:58 -05002574 (blk == p->inode->i_block[EXT2_DIND_BLOCK]) ||
2575 (blk == p->inode->i_block[EXT2_TIND_BLOCK])) {
2576 p->bbcheck = 1;
2577 if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, pctx)) {
2578 *block_nr = 0;
2579 return BLOCK_CHANGED;
2580 }
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +00002581 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +00002582 return BLOCK_ABORT;
Theodore Ts'of3db3561997-04-26 13:34:30 +00002583 return 0;
2584 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002585
2586 pctx->group = -1;
2587
2588 /* Warn user that the block wasn't claimed */
2589 fix_problem(ctx, PR_1_PROGERR_CLAIMED_BLOCK, pctx);
2590
Theodore Ts'o3839e651997-04-26 13:21:57 +00002591 return 0;
2592}
2593
JP Abgralle0ed7402014-03-19 19:08:39 -07002594static void new_table_block(e2fsck_t ctx, blk64_t first_block, dgrp_t group,
2595 const char *name, int num, blk64_t *new_block)
Theodore Ts'o3839e651997-04-26 13:21:57 +00002596{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002597 ext2_filsys fs = ctx->fs;
Theodore Ts'o617446e2009-08-18 22:27:42 -04002598 dgrp_t last_grp;
JP Abgralle0ed7402014-03-19 19:08:39 -07002599 blk64_t old_block = *new_block;
2600 blk64_t last_block;
2601 dgrp_t flexbg;
2602 unsigned flexbg_size;
2603 int i, is_flexbg;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002604 char *buf;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002605 struct problem_context pctx;
2606
2607 clear_problem_context(&pctx);
2608
2609 pctx.group = group;
2610 pctx.blk = old_block;
2611 pctx.str = name;
2612
Theodore Ts'o617446e2009-08-18 22:27:42 -04002613 /*
2614 * For flex_bg filesystems, first try to allocate the metadata
2615 * within the flex_bg, and if that fails then try finding the
2616 * space anywhere in the filesystem.
2617 */
2618 is_flexbg = EXT2_HAS_INCOMPAT_FEATURE(fs->super,
2619 EXT4_FEATURE_INCOMPAT_FLEX_BG);
2620 if (is_flexbg) {
2621 flexbg_size = 1 << fs->super->s_log_groups_per_flex;
2622 flexbg = group / flexbg_size;
JP Abgralle0ed7402014-03-19 19:08:39 -07002623 first_block = ext2fs_group_first_block2(fs,
2624 flexbg_size * flexbg);
Theodore Ts'o617446e2009-08-18 22:27:42 -04002625 last_grp = group | (flexbg_size - 1);
2626 if (last_grp > fs->group_desc_count)
2627 last_grp = fs->group_desc_count;
JP Abgralle0ed7402014-03-19 19:08:39 -07002628 last_block = ext2fs_group_last_block2(fs, last_grp);
Theodore Ts'o617446e2009-08-18 22:27:42 -04002629 } else
JP Abgralle0ed7402014-03-19 19:08:39 -07002630 last_block = ext2fs_group_last_block2(fs, group);
2631 pctx.errcode = ext2fs_get_free_blocks2(fs, first_block, last_block,
2632 num, ctx->block_found_map,
2633 new_block);
Theodore Ts'o617446e2009-08-18 22:27:42 -04002634 if (is_flexbg && (pctx.errcode == EXT2_ET_BLOCK_ALLOC_FAIL))
JP Abgralle0ed7402014-03-19 19:08:39 -07002635 pctx.errcode = ext2fs_get_free_blocks2(fs,
Theodore Ts'o617446e2009-08-18 22:27:42 -04002636 fs->super->s_first_data_block,
JP Abgralle0ed7402014-03-19 19:08:39 -07002637 ext2fs_blocks_count(fs->super),
Theodore Ts'o617446e2009-08-18 22:27:42 -04002638 num, ctx->block_found_map, new_block);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002639 if (pctx.errcode) {
2640 pctx.num = num;
2641 fix_problem(ctx, PR_1_RELOC_BLOCK_ALLOCATE, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +00002642 ext2fs_unmark_valid(fs);
Theodore Ts'o617446e2009-08-18 22:27:42 -04002643 ctx->flags |= E2F_FLAG_ABORT;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002644 return;
2645 }
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -04002646 pctx.errcode = ext2fs_get_mem(fs->blocksize, &buf);
Theodore Ts'o08b21301997-11-03 19:42:40 +00002647 if (pctx.errcode) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002648 fix_problem(ctx, PR_1_RELOC_MEMORY_ALLOCATE, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +00002649 ext2fs_unmark_valid(fs);
Theodore Ts'o617446e2009-08-18 22:27:42 -04002650 ctx->flags |= E2F_FLAG_ABORT;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002651 return;
2652 }
2653 ext2fs_mark_super_dirty(fs);
Theodore Ts'o299d7422002-11-08 11:10:28 -05002654 fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002655 pctx.blk2 = *new_block;
2656 fix_problem(ctx, (old_block ? PR_1_RELOC_FROM_TO :
2657 PR_1_RELOC_TO), &pctx);
2658 pctx.blk2 = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002659 for (i = 0; i < num; i++) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002660 pctx.blk = i;
JP Abgralle0ed7402014-03-19 19:08:39 -07002661 ext2fs_mark_block_bitmap2(ctx->block_found_map, (*new_block)+i);
Theodore Ts'of3db3561997-04-26 13:34:30 +00002662 if (old_block) {
JP Abgralle0ed7402014-03-19 19:08:39 -07002663 pctx.errcode = io_channel_read_blk64(fs->io,
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002664 old_block + i, 1, buf);
2665 if (pctx.errcode)
2666 fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx);
Theodore Ts'of3db3561997-04-26 13:34:30 +00002667 } else
2668 memset(buf, 0, fs->blocksize);
2669
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002670 pctx.blk = (*new_block) + i;
JP Abgralle0ed7402014-03-19 19:08:39 -07002671 pctx.errcode = io_channel_write_blk64(fs->io, pctx.blk,
Theodore Ts'o3839e651997-04-26 13:21:57 +00002672 1, buf);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002673 if (pctx.errcode)
2674 fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +00002675 }
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -04002676 ext2fs_free_mem(&buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +00002677}
2678
2679/*
Theodore Ts'of3db3561997-04-26 13:34:30 +00002680 * This routine gets called at the end of pass 1 if bad blocks are
2681 * detected in the superblock, group descriptors, inode_bitmaps, or
2682 * block bitmaps. At this point, all of the blocks have been mapped
2683 * out, so we can try to allocate new block(s) to replace the bad
2684 * blocks.
Theodore Ts'o3839e651997-04-26 13:21:57 +00002685 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002686static void handle_fs_bad_blocks(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +00002687{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002688 ext2_filsys fs = ctx->fs;
Theodore Ts'o54434922003-12-07 01:28:50 -05002689 dgrp_t i;
JP Abgralle0ed7402014-03-19 19:08:39 -07002690 blk64_t first_block;
2691 blk64_t new_blk;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002692
2693 for (i = 0; i < fs->group_desc_count; i++) {
JP Abgralle0ed7402014-03-19 19:08:39 -07002694 first_block = ext2fs_group_first_block2(fs, i);
Eric Sandeenabf23432006-09-12 14:56:16 -04002695
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002696 if (ctx->invalid_block_bitmap_flag[i]) {
JP Abgralle0ed7402014-03-19 19:08:39 -07002697 new_blk = ext2fs_block_bitmap_loc(fs, i);
Theodore Ts'o0c4a0722000-02-07 03:11:03 +00002698 new_table_block(ctx, first_block, i, _("block bitmap"),
JP Abgralle0ed7402014-03-19 19:08:39 -07002699 1, &new_blk);
2700 ext2fs_block_bitmap_loc_set(fs, i, new_blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +00002701 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002702 if (ctx->invalid_inode_bitmap_flag[i]) {
JP Abgralle0ed7402014-03-19 19:08:39 -07002703 new_blk = ext2fs_inode_bitmap_loc(fs, i);
Theodore Ts'o0c4a0722000-02-07 03:11:03 +00002704 new_table_block(ctx, first_block, i, _("inode bitmap"),
JP Abgralle0ed7402014-03-19 19:08:39 -07002705 1, &new_blk);
2706 ext2fs_inode_bitmap_loc_set(fs, i, new_blk);
Theodore Ts'o3839e651997-04-26 13:21:57 +00002707 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002708 if (ctx->invalid_inode_table_flag[i]) {
JP Abgralle0ed7402014-03-19 19:08:39 -07002709 new_blk = ext2fs_inode_table_loc(fs, i);
Theodore Ts'o0c4a0722000-02-07 03:11:03 +00002710 new_table_block(ctx, first_block, i, _("inode table"),
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002711 fs->inode_blocks_per_group,
JP Abgralle0ed7402014-03-19 19:08:39 -07002712 &new_blk);
2713 ext2fs_inode_table_loc_set(fs, i, new_blk);
Theodore Ts'o08b21301997-11-03 19:42:40 +00002714 ctx->flags |= E2F_FLAG_RESTART;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002715 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00002716 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002717 ctx->invalid_bitmaps = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002718}
2719
2720/*
2721 * This routine marks all blocks which are used by the superblock,
2722 * group descriptors, inode bitmaps, and block bitmaps.
2723 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002724static void mark_table_blocks(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +00002725{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002726 ext2_filsys fs = ctx->fs;
JP Abgralle0ed7402014-03-19 19:08:39 -07002727 blk64_t b;
Theodore Ts'o54434922003-12-07 01:28:50 -05002728 dgrp_t i;
JP Abgralle0ed7402014-03-19 19:08:39 -07002729 unsigned int j;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002730 struct problem_context pctx;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002731
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002732 clear_problem_context(&pctx);
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002733
Theodore Ts'o3839e651997-04-26 13:21:57 +00002734 for (i = 0; i < fs->group_desc_count; i++) {
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002735 pctx.group = i;
Theodore Ts'oda2e97f1997-06-12 04:28:07 +00002736
Theodore Ts'oef344e12003-11-21 09:02:21 -05002737 ext2fs_reserve_super_and_bgd(fs, i, ctx->block_found_map);
2738
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002739 /*
2740 * Mark the blocks used for the inode table
2741 */
JP Abgralle0ed7402014-03-19 19:08:39 -07002742 if (ext2fs_inode_table_loc(fs, i)) {
2743 for (j = 0, b = ext2fs_inode_table_loc(fs, i);
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002744 j < fs->inode_blocks_per_group;
2745 j++, b++) {
JP Abgralle0ed7402014-03-19 19:08:39 -07002746 if (ext2fs_test_block_bitmap2(ctx->block_found_map,
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002747 b)) {
2748 pctx.blk = b;
Theodore Ts'o9a7fe4b2009-08-18 23:14:03 -04002749 if (!ctx->invalid_inode_table_flag[i] &&
2750 fix_problem(ctx,
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002751 PR_1_ITABLE_CONFLICT, &pctx)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002752 ctx->invalid_inode_table_flag[i]++;
2753 ctx->invalid_bitmaps++;
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002754 }
2755 } else {
JP Abgralle0ed7402014-03-19 19:08:39 -07002756 ext2fs_mark_block_bitmap2(ctx->block_found_map,
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002757 b);
Theodore Ts'o21c84b71997-04-29 16:15:03 +00002758 }
2759 }
2760 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002761
Theodore Ts'o3839e651997-04-26 13:21:57 +00002762 /*
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002763 * Mark block used for the block bitmap
Theodore Ts'o3839e651997-04-26 13:21:57 +00002764 */
JP Abgralle0ed7402014-03-19 19:08:39 -07002765 if (ext2fs_block_bitmap_loc(fs, i)) {
2766 if (ext2fs_test_block_bitmap2(ctx->block_found_map,
2767 ext2fs_block_bitmap_loc(fs, i))) {
2768 pctx.blk = ext2fs_block_bitmap_loc(fs, i);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002769 if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) {
2770 ctx->invalid_block_bitmap_flag[i]++;
2771 ctx->invalid_bitmaps++;
Theodore Ts'of3db3561997-04-26 13:34:30 +00002772 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002773 } else {
JP Abgralle0ed7402014-03-19 19:08:39 -07002774 ext2fs_mark_block_bitmap2(ctx->block_found_map,
2775 ext2fs_block_bitmap_loc(fs, i));
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002776 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002777
Theodore Ts'of3db3561997-04-26 13:34:30 +00002778 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00002779 /*
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002780 * Mark block used for the inode bitmap
Theodore Ts'o3839e651997-04-26 13:21:57 +00002781 */
JP Abgralle0ed7402014-03-19 19:08:39 -07002782 if (ext2fs_inode_bitmap_loc(fs, i)) {
2783 if (ext2fs_test_block_bitmap2(ctx->block_found_map,
2784 ext2fs_inode_bitmap_loc(fs, i))) {
2785 pctx.blk = ext2fs_inode_bitmap_loc(fs, i);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002786 if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) {
2787 ctx->invalid_inode_bitmap_flag[i]++;
2788 ctx->invalid_bitmaps++;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002789 }
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002790 } else {
JP Abgralle0ed7402014-03-19 19:08:39 -07002791 ext2fs_mark_block_bitmap2(ctx->block_found_map,
2792 ext2fs_inode_bitmap_loc(fs, i));
Theodore Ts'o50e1e101997-04-26 13:58:21 +00002793 }
Theodore Ts'of3db3561997-04-26 13:34:30 +00002794 }
Theodore Ts'o3839e651997-04-26 13:21:57 +00002795 }
2796}
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002797
Theodore Ts'o3839e651997-04-26 13:21:57 +00002798/*
Theodore Ts'oe72a9ba1999-06-25 15:40:18 +00002799 * Thes subroutines short circuits ext2fs_get_blocks and
Theodore Ts'o3839e651997-04-26 13:21:57 +00002800 * ext2fs_check_directory; we use them since we already have the inode
2801 * structure, so there's no point in letting the ext2fs library read
2802 * the inode again.
2803 */
Theodore Ts'o86c627e2001-01-11 15:12:14 +00002804static errcode_t pass1_get_blocks(ext2_filsys fs, ext2_ino_t ino,
2805 blk_t *blocks)
Theodore Ts'o3839e651997-04-26 13:21:57 +00002806{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00002807 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002808 int i;
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002809
Theodore Ts'o71d521c2001-06-01 19:29:36 +00002810 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
Theodore Ts'o521e3681997-04-29 17:48:10 +00002811 return EXT2_ET_CALLBACK_NOTHANDLED;
2812
2813 for (i=0; i < EXT2_N_BLOCKS; i++)
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002814 blocks[i] = ctx->stashed_inode->i_block[i];
Theodore Ts'o521e3681997-04-29 17:48:10 +00002815 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002816}
2817
Theodore Ts'o86c627e2001-01-11 15:12:14 +00002818static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino,
Theodore Ts'oe72a9ba1999-06-25 15:40:18 +00002819 struct ext2_inode *inode)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00002820{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00002821 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002822
Theodore Ts'o71d521c2001-06-01 19:29:36 +00002823 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00002824 return EXT2_ET_CALLBACK_NOTHANDLED;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002825 *inode = *ctx->stashed_inode;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00002826 return 0;
2827}
2828
Theodore Ts'o86c627e2001-01-11 15:12:14 +00002829static errcode_t pass1_write_inode(ext2_filsys fs, ext2_ino_t ino,
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00002830 struct ext2_inode *inode)
2831{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00002832 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002833
Theodore Ts'o27431592005-07-25 11:36:43 -05002834 if ((ino == ctx->stashed_ino) && ctx->stashed_inode &&
2835 (inode != ctx->stashed_inode))
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002836 *ctx->stashed_inode = *inode;
Theodore Ts'o1e3472c1997-04-29 14:53:37 +00002837 return EXT2_ET_CALLBACK_NOTHANDLED;
2838}
2839
Theodore Ts'o86c627e2001-01-11 15:12:14 +00002840static errcode_t pass1_check_directory(ext2_filsys fs, ext2_ino_t ino)
Theodore Ts'o3839e651997-04-26 13:21:57 +00002841{
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +00002842 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002843
Theodore Ts'o71d521c2001-06-01 19:29:36 +00002844 if ((ino != ctx->stashed_ino) || !ctx->stashed_inode)
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002845 return EXT2_ET_CALLBACK_NOTHANDLED;
2846
2847 if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode))
Theodore Ts'o291c9041997-10-31 06:17:08 +00002848 return EXT2_ET_NO_DIRECTORY;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00002849 return 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +00002850}
Theodore Ts'oe72a9ba1999-06-25 15:40:18 +00002851
Theodore Ts'o16bd3492008-06-02 17:27:59 -04002852static errcode_t e2fsck_get_alloc_block(ext2_filsys fs, blk64_t goal,
2853 blk64_t *ret)
2854{
2855 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
2856 errcode_t retval;
JP Abgralle0ed7402014-03-19 19:08:39 -07002857 blk64_t new_block;
Theodore Ts'o16bd3492008-06-02 17:27:59 -04002858
2859 if (ctx->block_found_map) {
JP Abgralle0ed7402014-03-19 19:08:39 -07002860 retval = ext2fs_new_block2(fs, goal, ctx->block_found_map,
2861 &new_block);
Theodore Ts'o16bd3492008-06-02 17:27:59 -04002862 if (retval)
2863 return retval;
Theodore Ts'o8a2cbe22009-11-29 01:24:06 -05002864 if (fs->block_map) {
JP Abgralle0ed7402014-03-19 19:08:39 -07002865 ext2fs_mark_block_bitmap2(fs->block_map, new_block);
Theodore Ts'o8a2cbe22009-11-29 01:24:06 -05002866 ext2fs_mark_bb_dirty(fs);
2867 }
Theodore Ts'o16bd3492008-06-02 17:27:59 -04002868 } else {
2869 if (!fs->block_map) {
2870 retval = ext2fs_read_block_bitmap(fs);
2871 if (retval)
2872 return retval;
2873 }
2874
JP Abgralle0ed7402014-03-19 19:08:39 -07002875 retval = ext2fs_new_block2(fs, goal, 0, &new_block);
Theodore Ts'o16bd3492008-06-02 17:27:59 -04002876 if (retval)
2877 return retval;
2878 }
Theodore Ts'oefc6f622008-08-27 23:07:54 -04002879
Theodore Ts'o16bd3492008-06-02 17:27:59 -04002880 *ret = new_block;
2881 return (0);
2882}
2883
2884static void e2fsck_block_alloc_stats(ext2_filsys fs, blk64_t blk, int inuse)
2885{
2886 e2fsck_t ctx = (e2fsck_t) fs->priv_data;
2887
2888 if (ctx->block_found_map) {
2889 if (inuse > 0)
JP Abgralle0ed7402014-03-19 19:08:39 -07002890 ext2fs_mark_block_bitmap2(ctx->block_found_map, blk);
Theodore Ts'o16bd3492008-06-02 17:27:59 -04002891 else
JP Abgralle0ed7402014-03-19 19:08:39 -07002892 ext2fs_unmark_block_bitmap2(ctx->block_found_map, blk);
Theodore Ts'o16bd3492008-06-02 17:27:59 -04002893 }
2894}
2895
JP Abgralle0ed7402014-03-19 19:08:39 -07002896void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int use_shortcuts)
Theodore Ts'oe72a9ba1999-06-25 15:40:18 +00002897{
2898 ext2_filsys fs = ctx->fs;
2899
JP Abgralle0ed7402014-03-19 19:08:39 -07002900 if (use_shortcuts) {
Theodore Ts'oe72a9ba1999-06-25 15:40:18 +00002901 fs->get_blocks = pass1_get_blocks;
2902 fs->check_directory = pass1_check_directory;
2903 fs->read_inode = pass1_read_inode;
2904 fs->write_inode = pass1_write_inode;
2905 ctx->stashed_ino = 0;
Theodore Ts'o16bd3492008-06-02 17:27:59 -04002906 ext2fs_set_alloc_block_callback(fs, e2fsck_get_alloc_block,
2907 0);
2908 ext2fs_set_block_alloc_stats_callback(fs,
2909 e2fsck_block_alloc_stats,
2910 0);
Theodore Ts'oe72a9ba1999-06-25 15:40:18 +00002911 } else {
2912 fs->get_blocks = 0;
2913 fs->check_directory = 0;
2914 fs->read_inode = 0;
2915 fs->write_inode = 0;
2916 }
2917}