Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1 | /* |
| 2 | * pass1.c -- pass #1 of e2fsck: sequential scan of the inode table |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 3 | * |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 4 | * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o. |
| 5 | * |
| 6 | * %Begin-Header% |
| 7 | * This file may be redistributed under the terms of the GNU Public |
| 8 | * License. |
| 9 | * %End-Header% |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 10 | * |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 11 | * Pass 1 of e2fsck iterates over all the inodes in the filesystems, |
| 12 | * and applies the following tests to each inode: |
| 13 | * |
| 14 | * - The mode field of the inode must be legal. |
| 15 | * - The size and block count fields of the inode are correct. |
| 16 | * - A data block must not be used by another inode |
| 17 | * |
| 18 | * Pass 1 also gathers the collects the following information: |
| 19 | * |
| 20 | * - A bitmap of which inodes are in use. (inode_used_map) |
| 21 | * - A bitmap of which inodes are directories. (inode_dir_map) |
Theodore Ts'o | aa4115a | 1999-10-21 19:33:18 +0000 | [diff] [blame] | 22 | * - A bitmap of which inodes are regular files. (inode_reg_map) |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 23 | * - A bitmap of which inodes have bad fields. (inode_bad_map) |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 24 | * - A bitmap of which inodes are in bad blocks. (inode_bb_map) |
Theodore Ts'o | aa4115a | 1999-10-21 19:33:18 +0000 | [diff] [blame] | 25 | * - A bitmap of which inodes are imagic inodes. (inode_imagic_map) |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 26 | * - 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 Andree | b969b1b | 2003-12-28 13:04:35 +0100 | [diff] [blame] | 40 | #define _GNU_SOURCE 1 /* get strnlen() */ |
Theodore Ts'o | 3e69906 | 2002-10-13 23:56:28 -0400 | [diff] [blame] | 41 | #include <string.h> |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 42 | #include <time.h> |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 43 | #ifdef HAVE_ERRNO_H |
| 44 | #include <errno.h> |
| 45 | #endif |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 46 | |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 47 | #include "e2fsck.h" |
Theodore Ts'o | 342d847 | 2001-07-02 11:54:09 -0400 | [diff] [blame] | 48 | #include <ext2fs/ext2_ext_attr.h> |
| 49 | |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 50 | #include "problem.h" |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 51 | |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 52 | #ifdef NO_INLINE_FUNCS |
| 53 | #define _INLINE_ |
| 54 | #else |
| 55 | #define _INLINE_ inline |
| 56 | #endif |
| 57 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 58 | static int process_block(ext2_filsys fs, blk64_t *blocknr, |
| 59 | e2_blkcnt_t blockcnt, blk64_t ref_blk, |
Theodore Ts'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 60 | int ref_offset, void *priv_data); |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 61 | static int process_bad_block(ext2_filsys fs, blk64_t *block_nr, |
| 62 | e2_blkcnt_t blockcnt, blk64_t ref_blk, |
Theodore Ts'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 63 | int ref_offset, void *priv_data); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 64 | static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 65 | char *block_buf); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 66 | static void mark_table_blocks(e2fsck_t ctx); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 67 | static void alloc_bb_map(e2fsck_t ctx); |
Theodore Ts'o | aa4115a | 1999-10-21 19:33:18 +0000 | [diff] [blame] | 68 | static void alloc_imagic_map(e2fsck_t ctx); |
Theodore Ts'o | fdbdea0 | 2001-06-02 04:26:26 +0000 | [diff] [blame] | 69 | static void mark_inode_bad(e2fsck_t ctx, ino_t ino); |
Theodore Ts'o | 890a2f9 | 2015-07-14 22:50:51 -0400 | [diff] [blame] | 70 | static void add_encrypted_dir(e2fsck_t ctx, ino_t ino); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 71 | static void handle_fs_bad_blocks(e2fsck_t ctx); |
| 72 | static void process_inodes(e2fsck_t ctx, char *block_buf); |
Theodore Ts'o | 4c77fe5 | 1998-04-30 17:35:59 +0000 | [diff] [blame] | 73 | static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b); |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 74 | static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan, |
Theodore Ts'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 75 | dgrp_t group, void * priv_data); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 76 | static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount, |
Theodore Ts'o | e8a3ee6 | 2001-07-07 11:12:50 -0400 | [diff] [blame] | 77 | char *block_buf, int adjust_sign); |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 78 | /* static char *describe_illegal_block(ext2_filsys fs, blk64_t block); */ |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 79 | |
| 80 | struct process_block_struct { |
Theodore Ts'o | 86c627e | 2001-01-11 15:12:14 +0000 | [diff] [blame] | 81 | ext2_ino_t ino; |
Matthias Andree | 83e692e | 2004-03-30 04:17:14 +0200 | [diff] [blame] | 82 | unsigned is_dir:1, is_reg:1, clear:1, suppress:1, |
Theodore Ts'o | 000ba40 | 2003-11-21 10:41:58 -0500 | [diff] [blame] | 83 | fragmented:1, compressed:1, bbcheck:1; |
Eric Sandeen | 65d7189 | 2010-03-30 11:42:51 -0500 | [diff] [blame] | 84 | blk64_t num_blocks; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 85 | blk64_t max_blocks; |
Theodore Ts'o | 9d1bd3d | 1998-06-10 20:45:22 +0000 | [diff] [blame] | 86 | e2_blkcnt_t last_block; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 87 | e2_blkcnt_t last_init_lblock; |
Theodore Ts'o | 4dbe79b | 2009-11-28 09:35:37 -0500 | [diff] [blame] | 88 | e2_blkcnt_t last_db_block; |
Theodore Ts'o | 246501c | 1998-03-24 16:22:38 +0000 | [diff] [blame] | 89 | int num_illegal_blocks; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 90 | blk64_t previous_block; |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 91 | struct ext2_inode *inode; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 92 | struct problem_context *pctx; |
Theodore Ts'o | 000ba40 | 2003-11-21 10:41:58 -0500 | [diff] [blame] | 93 | ext2fs_block_bitmap fs_meta_blocks; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 94 | e2fsck_t ctx; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 95 | }; |
| 96 | |
| 97 | struct process_inode_block { |
Theodore Ts'o | 86c627e | 2001-01-11 15:12:14 +0000 | [diff] [blame] | 98 | ext2_ino_t ino; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 99 | struct ext2_inode inode; |
| 100 | }; |
| 101 | |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 102 | struct scan_callback_struct { |
| 103 | e2fsck_t ctx; |
| 104 | char *block_buf; |
| 105 | }; |
| 106 | |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 107 | /* |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 108 | * For the inodes to process list. |
| 109 | */ |
| 110 | static struct process_inode_block *inodes_to_process; |
| 111 | static int process_inode_count; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 112 | |
Theodore Ts'o | 7823dd6 | 2002-05-17 23:37:42 -0400 | [diff] [blame] | 113 | static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE - |
| 114 | EXT2_MIN_BLOCK_LOG_SIZE + 1]; |
Theodore Ts'o | 246501c | 1998-03-24 16:22:38 +0000 | [diff] [blame] | 115 | |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 116 | /* |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 117 | * Free all memory allocated by pass1 in preparation for restarting |
| 118 | * things. |
| 119 | */ |
Theodore Ts'o | 5443492 | 2003-12-07 01:28:50 -0500 | [diff] [blame] | 120 | static void unwind_pass1(ext2_filsys fs EXT2FS_ATTR((unused))) |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 121 | { |
Theodore Ts'o | c4e3d3f | 2003-08-01 09:41:07 -0400 | [diff] [blame] | 122 | ext2fs_free_mem(&inodes_to_process); |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 123 | inodes_to_process = 0; |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 124 | } |
| 125 | |
Theodore Ts'o | 7cf73dc | 1997-08-14 17:17:16 +0000 | [diff] [blame] | 126 | /* |
| 127 | * Check to make sure a device inode is real. Returns 1 if the device |
| 128 | * checks out, 0 if not. |
Theodore Ts'o | 1dde43f | 1998-11-14 04:18:28 +0000 | [diff] [blame] | 129 | * |
| 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'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 132 | * zero. |
Theodore Ts'o | 7cf73dc | 1997-08-14 17:17:16 +0000 | [diff] [blame] | 133 | */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 134 | int e2fsck_pass1_check_device_inode(ext2_filsys fs EXT2FS_ATTR((unused)), |
Theodore Ts'o | f954ba0 | 2007-05-22 20:53:01 -0400 | [diff] [blame] | 135 | struct ext2_inode *inode) |
Theodore Ts'o | 7cf73dc | 1997-08-14 17:17:16 +0000 | [diff] [blame] | 136 | { |
| 137 | int i; |
| 138 | |
Theodore Ts'o | 7fdfabd | 1997-11-24 11:51:17 +0000 | [diff] [blame] | 139 | /* |
Theodore Ts'o | 441ab1e | 2007-03-31 18:56:09 -0400 | [diff] [blame] | 140 | * If the index flag is set, then this is a bogus |
| 141 | * device/fifo/socket |
Theodore Ts'o | a40ecbb | 2001-08-13 06:15:36 -0400 | [diff] [blame] | 142 | */ |
Theodore Ts'o | 441ab1e | 2007-03-31 18:56:09 -0400 | [diff] [blame] | 143 | if (inode->i_flags & EXT2_INDEX_FL) |
Theodore Ts'o | 53abed0 | 2001-08-27 12:18:16 -0400 | [diff] [blame] | 144 | return 0; |
Theodore Ts'o | bcf9c5d | 2002-05-21 09:14:17 -0400 | [diff] [blame] | 145 | |
Theodore Ts'o | a40ecbb | 2001-08-13 06:15:36 -0400 | [diff] [blame] | 146 | /* |
Theodore Ts'o | 7fdfabd | 1997-11-24 11:51:17 +0000 | [diff] [blame] | 147 | * 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'o | 01fbc70 | 2000-04-03 13:57:21 +0000 | [diff] [blame] | 157 | if (inode->i_flags & (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)) { |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 158 | for (i=4; i < EXT2_N_BLOCKS; i++) |
Theodore Ts'o | 7fdfabd | 1997-11-24 11:51:17 +0000 | [diff] [blame] | 159 | if (inode->i_block[i]) |
| 160 | return 0; |
| 161 | } |
Theodore Ts'o | 7cf73dc | 1997-08-14 17:17:16 +0000 | [diff] [blame] | 162 | return 1; |
| 163 | } |
| 164 | |
Theodore Ts'o | 6fdc7a3 | 1999-11-10 13:34:40 +0000 | [diff] [blame] | 165 | /* |
Andreas Dilger | 67052a8 | 2001-08-04 00:51:18 -0600 | [diff] [blame] | 166 | * Check to make sure a symlink inode is real. Returns 1 if the symlink |
| 167 | * checks out, 0 if not. |
| 168 | */ |
Theodore Ts'o | 7cadc57 | 2008-03-13 23:05:00 -0400 | [diff] [blame] | 169 | int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino, |
| 170 | struct ext2_inode *inode, char *buf) |
Andreas Dilger | 67052a8 | 2001-08-04 00:51:18 -0600 | [diff] [blame] | 171 | { |
Theodore Ts'o | 5443492 | 2003-12-07 01:28:50 -0500 | [diff] [blame] | 172 | unsigned int len; |
Theodore Ts'o | d007cb4 | 2001-08-04 20:39:39 -0400 | [diff] [blame] | 173 | int i; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 174 | blk64_t blocks; |
Theodore Ts'o | 7cadc57 | 2008-03-13 23:05:00 -0400 | [diff] [blame] | 175 | ext2_extent_handle_t handle; |
| 176 | struct ext2_extent_info info; |
| 177 | struct ext2fs_extent extent; |
Andreas Dilger | 67052a8 | 2001-08-04 00:51:18 -0600 | [diff] [blame] | 178 | |
Theodore Ts'o | bcf9c5d | 2002-05-21 09:14:17 -0400 | [diff] [blame] | 179 | if ((inode->i_size_high || inode->i_size == 0) || |
| 180 | (inode->i_flags & EXT2_INDEX_FL)) |
Andreas Dilger | 67052a8 | 2001-08-04 00:51:18 -0600 | [diff] [blame] | 181 | return 0; |
| 182 | |
Theodore Ts'o | 7cadc57 | 2008-03-13 23:05:00 -0400 | [diff] [blame] | 183 | if (inode->i_flags & EXT4_EXTENTS_FL) { |
| 184 | if (inode->i_size > fs->blocksize) |
| 185 | return 0; |
number9652 | 84b239a | 2009-05-19 13:34:12 -0700 | [diff] [blame] | 186 | if (ext2fs_extent_open2(fs, ino, inode, &handle)) |
Theodore Ts'o | 7cadc57 | 2008-03-13 23:05:00 -0400 | [diff] [blame] | 187 | 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 197 | (extent.e_pblk >= ext2fs_blocks_count(fs->super))) |
Theodore Ts'o | 7cadc57 | 2008-03-13 23:05:00 -0400 | [diff] [blame] | 198 | goto exit_extent; |
| 199 | i = 1; |
| 200 | exit_extent: |
| 201 | ext2fs_extent_free(handle); |
| 202 | return i; |
| 203 | } |
| 204 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 205 | blocks = ext2fs_inode_data_blocks2(fs, inode); |
Theodore Ts'o | 0684a4f | 2002-08-17 10:19:44 -0400 | [diff] [blame] | 206 | if (blocks) { |
Andreas Dilger | b94a052 | 2002-05-18 13:16:30 -0600 | [diff] [blame] | 207 | if ((inode->i_size >= fs->blocksize) || |
Theodore Ts'o | 0684a4f | 2002-08-17 10:19:44 -0400 | [diff] [blame] | 208 | (blocks != fs->blocksize >> 9) || |
Theodore Ts'o | d007cb4 | 2001-08-04 20:39:39 -0400 | [diff] [blame] | 209 | (inode->i_block[0] < fs->super->s_first_data_block) || |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 210 | (inode->i_block[0] >= ext2fs_blocks_count(fs->super))) |
Andreas Dilger | 67052a8 | 2001-08-04 00:51:18 -0600 | [diff] [blame] | 211 | return 0; |
| 212 | |
| 213 | for (i = 1; i < EXT2_N_BLOCKS; i++) |
| 214 | if (inode->i_block[i]) |
| 215 | return 0; |
Andreas Dilger | b94a052 | 2002-05-18 13:16:30 -0600 | [diff] [blame] | 216 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 217 | if (io_channel_read_blk64(fs->io, inode->i_block[0], 1, buf)) |
Andreas Dilger | 67052a8 | 2001-08-04 00:51:18 -0600 | [diff] [blame] | 218 | return 0; |
| 219 | |
Theodore Ts'o | 890a2f9 | 2015-07-14 22:50:51 -0400 | [diff] [blame] | 220 | 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 Dilger | b94a052 | 2002-05-18 13:16:30 -0600 | [diff] [blame] | 225 | if (len == fs->blocksize) |
| 226 | return 0; |
Andreas Dilger | b94a052 | 2002-05-18 13:16:30 -0600 | [diff] [blame] | 227 | } 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 Dilger | 67052a8 | 2001-08-04 00:51:18 -0600 | [diff] [blame] | 233 | return 0; |
| 234 | } |
Andreas Dilger | b94a052 | 2002-05-18 13:16:30 -0600 | [diff] [blame] | 235 | if (len != inode->i_size) |
Theodore Ts'o | 890a2f9 | 2015-07-14 22:50:51 -0400 | [diff] [blame] | 236 | if ((inode->i_flags & EXT4_ENCRYPT_FL) == 0) |
| 237 | return 0; |
Andreas Dilger | 67052a8 | 2001-08-04 00:51:18 -0600 | [diff] [blame] | 238 | return 1; |
| 239 | } |
| 240 | |
| 241 | /* |
Theodore Ts'o | 01fbc70 | 2000-04-03 13:57:21 +0000 | [diff] [blame] | 242 | * If the immutable (or append-only) flag is set on the inode, offer |
| 243 | * to clear it. |
Theodore Ts'o | 6fdc7a3 | 1999-11-10 13:34:40 +0000 | [diff] [blame] | 244 | */ |
Theodore Ts'o | bcf9c5d | 2002-05-21 09:14:17 -0400 | [diff] [blame] | 245 | #define BAD_SPECIAL_FLAGS (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL) |
Theodore Ts'o | 6fdc7a3 | 1999-11-10 13:34:40 +0000 | [diff] [blame] | 246 | static void check_immutable(e2fsck_t ctx, struct problem_context *pctx) |
| 247 | { |
Andreas Dilger | b94a052 | 2002-05-18 13:16:30 -0600 | [diff] [blame] | 248 | if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS)) |
Theodore Ts'o | 6fdc7a3 | 1999-11-10 13:34:40 +0000 | [diff] [blame] | 249 | return; |
| 250 | |
| 251 | if (!fix_problem(ctx, PR_1_SET_IMMUTABLE, pctx)) |
| 252 | return; |
| 253 | |
Andreas Dilger | b94a052 | 2002-05-18 13:16:30 -0600 | [diff] [blame] | 254 | pctx->inode->i_flags &= ~BAD_SPECIAL_FLAGS; |
Theodore Ts'o | 6fdc7a3 | 1999-11-10 13:34:40 +0000 | [diff] [blame] | 255 | e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1"); |
| 256 | } |
| 257 | |
Theodore Ts'o | d647a1e | 2000-05-27 14:40:09 +0000 | [diff] [blame] | 258 | /* |
| 259 | * If device, fifo or socket, check size is zero -- if not offer to |
| 260 | * clear it |
| 261 | */ |
| 262 | static void check_size(e2fsck_t ctx, struct problem_context *pctx) |
| 263 | { |
| 264 | struct ext2_inode *inode = pctx->inode; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 265 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 266 | if (EXT2_I_SIZE(inode) == 0) |
Theodore Ts'o | d647a1e | 2000-05-27 14:40:09 +0000 | [diff] [blame] | 267 | return; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 268 | |
Theodore Ts'o | 85645a6f | 2001-08-13 06:11:39 -0400 | [diff] [blame] | 269 | if (!fix_problem(ctx, PR_1_SET_NONZSIZE, pctx)) |
Theodore Ts'o | d647a1e | 2000-05-27 14:40:09 +0000 | [diff] [blame] | 270 | return; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 271 | |
Theodore Ts'o | d647a1e | 2000-05-27 14:40:09 +0000 | [diff] [blame] | 272 | inode->i_size = 0; |
Theodore Ts'o | fdbdea0 | 2001-06-02 04:26:26 +0000 | [diff] [blame] | 273 | inode->i_size_high = 0; |
Theodore Ts'o | d647a1e | 2000-05-27 14:40:09 +0000 | [diff] [blame] | 274 | e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1"); |
| 275 | } |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 276 | |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 277 | static 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 282 | char *start; |
Kalpak Shah | 1a8c2c4 | 2007-05-08 01:07:30 -0400 | [diff] [blame] | 283 | unsigned int storage_size, remain; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 284 | problem_t problem = 0; |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 285 | |
| 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'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 291 | 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'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 296 | remain = storage_size - sizeof(__u32); |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 297 | |
| 298 | while (!EXT2_EXT_IS_LAST_ENTRY(entry)) { |
Andreas Dilger | fefaef3 | 2008-02-02 01:16:32 -0700 | [diff] [blame] | 299 | __u32 hash; |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 300 | |
| 301 | /* header eats this space */ |
| 302 | remain -= sizeof(struct ext2_ext_attr_entry); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 303 | |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 304 | /* 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 315 | if (entry->e_value_size > remain) { |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 316 | pctx->num = entry->e_value_size; |
| 317 | problem = PR_1_ATTR_VALUE_SIZE; |
| 318 | goto fix; |
| 319 | } |
| 320 | |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 321 | /* 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 Dilger | fefaef3 | 2008-02-02 01:16:32 -0700 | [diff] [blame] | 327 | |
| 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'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 333 | pctx->num = entry->e_hash; |
| 334 | problem = PR_1_ATTR_HASH; |
| 335 | goto fix; |
| 336 | } |
| 337 | |
| 338 | remain -= entry->e_value_size; |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 339 | |
| 340 | entry = EXT2_EXT_ATTR_NEXT(entry); |
| 341 | } |
| 342 | fix: |
| 343 | /* |
| 344 | * it seems like a corruption. it's very unlikely we could repair |
| 345 | * EA(s) in automatic fashion -bzzz |
| 346 | */ |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 347 | if (problem == 0 || !fix_problem(ctx, problem, pctx)) |
| 348 | return; |
| 349 | |
Andreas Dilger | fefaef3 | 2008-02-02 01:16:32 -0700 | [diff] [blame] | 350 | /* simply remove all possible EA(s) */ |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 351 | *((__u32 *)start) = 0UL; |
Dmitry V. Levin | da938f2 | 2007-10-20 22:10:26 +0400 | [diff] [blame] | 352 | e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode, |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 353 | EXT2_INODE_SIZE(sb), "pass1"); |
| 354 | } |
| 355 | |
| 356 | static 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'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 372 | #endif |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 373 | /* 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'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 375 | max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 376 | /* |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 377 | * 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'o | 6fdc7a3 | 1999-11-10 13:34:40 +0000 | [diff] [blame] | 397 | |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 398 | /* |
Theodore Ts'o | fbc3f90 | 2007-04-02 10:08:59 -0400 | [diff] [blame] | 399 | * 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 | */ |
| 406 | static 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'o | fbc3f90 | 2007-04-02 10:08:59 -0400 | [diff] [blame] | 410 | struct ext2_dir_entry *dirent; |
Theodore Ts'o | e94bc63 | 2007-04-14 09:29:02 -0400 | [diff] [blame] | 411 | errcode_t retval; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 412 | blk64_t blk; |
Theodore Ts'o | 03fa6f8 | 2008-11-16 10:03:00 -0500 | [diff] [blame] | 413 | unsigned int i, rec_len, not_device = 0; |
Nick Dokos | 1ec42a0 | 2010-02-05 10:35:17 -0500 | [diff] [blame] | 414 | int extent_fs; |
Theodore Ts'o | fbc3f90 | 2007-04-02 10:08:59 -0400 | [diff] [blame] | 415 | |
Nick Dokos | 1ec42a0 | 2010-02-05 10:35:17 -0500 | [diff] [blame] | 416 | /* |
| 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'o | fbc3f90 | 2007-04-02 10:08:59 -0400 | [diff] [blame] | 423 | if (LINUX_S_ISDIR(inode->i_mode) || LINUX_S_ISREG(inode->i_mode) || |
Theodore Ts'o | 0eeb154 | 2007-04-14 12:01:39 -0400 | [diff] [blame] | 424 | LINUX_S_ISLNK(inode->i_mode) || inode->i_block[0] == 0) |
Theodore Ts'o | fbc3f90 | 2007-04-02 10:08:59 -0400 | [diff] [blame] | 425 | return; |
| 426 | |
Nick Dokos | 1ec42a0 | 2010-02-05 10:35:17 -0500 | [diff] [blame] | 427 | /* |
| 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'o | fbc3f90 | 2007-04-02 10:08:59 -0400 | [diff] [blame] | 443 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 444 | extent_fs = (ctx->fs->super->s_feature_incompat & |
| 445 | EXT3_FEATURE_INCOMPAT_EXTENTS); |
Nick Dokos | 1ec42a0 | 2010-02-05 10:35:17 -0500 | [diff] [blame] | 446 | if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) { |
| 447 | /* extent mapped */ |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 448 | if (ext2fs_bmap2(ctx->fs, pctx->ino, inode, 0, 0, 0, 0, |
Nick Dokos | 1ec42a0 | 2010-02-05 10:35:17 -0500 | [diff] [blame] | 449 | &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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 462 | blk >= ext2fs_blocks_count(ctx->fs->super) || |
| 463 | ext2fs_fast_test_block_bitmap2(ctx->block_found_map, |
| 464 | blk)) |
Nick Dokos | 1ec42a0 | 2010-02-05 10:35:17 -0500 | [diff] [blame] | 465 | return; /* Invalid block, can't be dir */ |
| 466 | } |
| 467 | blk = inode->i_block[0]; |
Theodore Ts'o | fbc3f90 | 2007-04-02 10:08:59 -0400 | [diff] [blame] | 468 | } |
| 469 | |
Nick Dokos | 1ec42a0 | 2010-02-05 10:35:17 -0500 | [diff] [blame] | 470 | /* |
| 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'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 475 | if ((LINUX_S_ISCHR(inode->i_mode) || LINUX_S_ISBLK(inode->i_mode)) && |
Theodore Ts'o | fbc3f90 | 2007-04-02 10:08:59 -0400 | [diff] [blame] | 476 | (inode->i_links_count == 1) && !not_device) |
| 477 | return; |
| 478 | |
Nick Dokos | 1ec42a0 | 2010-02-05 10:35:17 -0500 | [diff] [blame] | 479 | /* read the first block */ |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 480 | ehandler_operation(_("reading directory block")); |
| 481 | retval = ext2fs_read_dir_block3(ctx->fs, blk, buf, 0); |
Theodore Ts'o | e94bc63 | 2007-04-14 09:29:02 -0400 | [diff] [blame] | 482 | ehandler_operation(0); |
| 483 | if (retval) |
Theodore Ts'o | fbc3f90 | 2007-04-02 10:08:59 -0400 | [diff] [blame] | 484 | return; |
| 485 | |
| 486 | dirent = (struct ext2_dir_entry *) buf; |
Theodore Ts'o | 8a48035 | 2009-06-21 21:07:38 -0400 | [diff] [blame] | 487 | retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len); |
| 488 | if (retval) |
| 489 | return; |
Theodore Ts'o | fbc3f90 | 2007-04-02 10:08:59 -0400 | [diff] [blame] | 490 | if (((dirent->name_len & 0xFF) != 1) || |
| 491 | (dirent->name[0] != '.') || |
| 492 | (dirent->inode != pctx->ino) || |
Theodore Ts'o | 5dd77db | 2008-08-25 21:08:19 -0400 | [diff] [blame] | 493 | (rec_len < 12) || |
| 494 | (rec_len % 4) || |
| 495 | (rec_len >= ctx->fs->blocksize - 12)) |
Theodore Ts'o | fbc3f90 | 2007-04-02 10:08:59 -0400 | [diff] [blame] | 496 | return; |
| 497 | |
Theodore Ts'o | 5dd77db | 2008-08-25 21:08:19 -0400 | [diff] [blame] | 498 | dirent = (struct ext2_dir_entry *) (buf + rec_len); |
Theodore Ts'o | 8a48035 | 2009-06-21 21:07:38 -0400 | [diff] [blame] | 499 | retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len); |
| 500 | if (retval) |
| 501 | return; |
Theodore Ts'o | fbc3f90 | 2007-04-02 10:08:59 -0400 | [diff] [blame] | 502 | if (((dirent->name_len & 0xFF) != 2) || |
| 503 | (dirent->name[0] != '.') || |
| 504 | (dirent->name[1] != '.') || |
Theodore Ts'o | 5dd77db | 2008-08-25 21:08:19 -0400 | [diff] [blame] | 505 | (rec_len < 12) || |
| 506 | (rec_len % 4)) |
Theodore Ts'o | fbc3f90 | 2007-04-02 10:08:59 -0400 | [diff] [blame] | 507 | 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'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 511 | e2fsck_write_inode_full(ctx, pctx->ino, inode, |
| 512 | EXT2_INODE_SIZE(ctx->fs->super), |
Theodore Ts'o | fbc3f90 | 2007-04-02 10:08:59 -0400 | [diff] [blame] | 513 | "check_is_really_dir"); |
| 514 | } |
| 515 | } |
| 516 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 517 | void e2fsck_setup_tdb_icount(e2fsck_t ctx, int flags, |
| 518 | ext2_icount_t *ret) |
Theodore Ts'o | 34b9f79 | 2007-04-06 18:43:11 -0400 | [diff] [blame] | 519 | { |
Theodore Ts'o | f954ba0 | 2007-05-22 20:53:01 -0400 | [diff] [blame] | 520 | unsigned int threshold; |
Theodore Ts'o | 34b9f79 | 2007-04-06 18:43:11 -0400 | [diff] [blame] | 521 | ext2_ino_t num_dirs; |
| 522 | errcode_t retval; |
Theodore Ts'o | f954ba0 | 2007-05-22 20:53:01 -0400 | [diff] [blame] | 523 | char *tdb_dir; |
| 524 | int enable; |
Theodore Ts'o | 34b9f79 | 2007-04-06 18:43:11 -0400 | [diff] [blame] | 525 | |
| 526 | *ret = 0; |
| 527 | |
| 528 | profile_get_string(ctx->profile, "scratch_files", "directory", 0, 0, |
| 529 | &tdb_dir); |
Theodore Ts'o | f954ba0 | 2007-05-22 20:53:01 -0400 | [diff] [blame] | 530 | profile_get_uint(ctx->profile, "scratch_files", |
| 531 | "numdirs_threshold", 0, 0, &threshold); |
Theodore Ts'o | 34b9f79 | 2007-04-06 18:43:11 -0400 | [diff] [blame] | 532 | 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'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 548 | void e2fsck_pass1(e2fsck_t ctx) |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 549 | { |
Theodore Ts'o | 9d1bd3d | 1998-06-10 20:45:22 +0000 | [diff] [blame] | 550 | int i; |
Theodore Ts'o | 31e29a1 | 2002-05-17 10:53:07 -0400 | [diff] [blame] | 551 | __u64 max_sizes; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 552 | ext2_filsys fs = ctx->fs; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 553 | ext2_ino_t ino = 0; |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 554 | struct ext2_inode *inode; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 555 | ext2_inode_scan scan; |
| 556 | char *block_buf; |
Theodore Ts'o | 8bf191e | 1997-10-20 01:38:32 +0000 | [diff] [blame] | 557 | #ifdef RESOURCE_TRACK |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 558 | struct resource_track rtrack; |
Theodore Ts'o | 8bf191e | 1997-10-20 01:38:32 +0000 | [diff] [blame] | 559 | #endif |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 560 | unsigned char frag, fsize; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 561 | struct problem_context pctx; |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 562 | struct scan_callback_struct scan_struct; |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 563 | struct ext2_super_block *sb = ctx->fs->super; |
Theodore Ts'o | e94bc63 | 2007-04-14 09:29:02 -0400 | [diff] [blame] | 564 | const char *old_op; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 565 | unsigned int save_type; |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 566 | int imagic_fs, extent_fs; |
Theodore Ts'o | be93ef0 | 2002-10-31 18:38:55 -0500 | [diff] [blame] | 567 | int busted_fs_time = 0; |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 568 | int inode_size; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 569 | |
Theodore Ts'o | 6d96b00 | 2007-08-03 20:07:09 -0400 | [diff] [blame] | 570 | init_resource_track(&rtrack, ctx->fs->io); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 571 | clear_problem_context(&pctx); |
| 572 | |
| 573 | if (!(ctx->options & E2F_OPT_PREEN)) |
| 574 | fix_problem(ctx, PR_1_PASS_HEADER, &pctx); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 575 | |
Theodore Ts'o | 3214a45 | 2002-07-23 12:00:00 -0400 | [diff] [blame] | 576 | if ((fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) && |
| 577 | !(ctx->options & E2F_OPT_NO)) { |
Theodore Ts'o | b7a0056 | 2002-07-20 00:28:07 -0400 | [diff] [blame] | 578 | if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50)) |
| 579 | ctx->dirs_to_hash = 0; |
| 580 | } |
| 581 | |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 582 | #ifdef MTRACE |
| 583 | mtrace_print("Pass 1"); |
| 584 | #endif |
| 585 | |
Andreas Dilger | 932a489 | 2002-05-16 03:20:07 -0600 | [diff] [blame] | 586 | #define EXT2_BPP(bits) (1ULL << ((bits) - 2)) |
Theodore Ts'o | 9d1bd3d | 1998-06-10 20:45:22 +0000 | [diff] [blame] | 587 | |
Andreas Dilger | 932a489 | 2002-05-16 03:20:07 -0600 | [diff] [blame] | 588 | 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 592 | max_sizes = (max_sizes * (1UL << i)); |
Theodore Ts'o | 7823dd6 | 2002-05-17 23:37:42 -0400 | [diff] [blame] | 593 | ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes; |
Theodore Ts'o | 9d1bd3d | 1998-06-10 20:45:22 +0000 | [diff] [blame] | 594 | } |
| 595 | #undef EXT2_BPP |
Theodore Ts'o | 6fdc7a3 | 1999-11-10 13:34:40 +0000 | [diff] [blame] | 596 | |
Theodore Ts'o | 6fdc7a3 | 1999-11-10 13:34:40 +0000 | [diff] [blame] | 597 | imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES); |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 598 | extent_fs = (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS); |
Theodore Ts'o | 6fdc7a3 | 1999-11-10 13:34:40 +0000 | [diff] [blame] | 599 | |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 600 | /* |
| 601 | * Allocate bitmaps structures |
| 602 | */ |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 603 | 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'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 607 | if (pctx.errcode) { |
| 608 | pctx.num = 1; |
| 609 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 610 | ctx->flags |= E2F_FLAG_ABORT; |
| 611 | return; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 612 | } |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 613 | 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'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 617 | if (pctx.errcode) { |
| 618 | pctx.num = 2; |
| 619 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 620 | ctx->flags |= E2F_FLAG_ABORT; |
| 621 | return; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 622 | } |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 623 | 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'o | aa4115a | 1999-10-21 19:33:18 +0000 | [diff] [blame] | 626 | 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 632 | 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'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 635 | if (pctx.errcode) { |
| 636 | pctx.num = 1; |
| 637 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx); |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 638 | ctx->flags |= E2F_FLAG_ABORT; |
| 639 | return; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 640 | } |
Theodore Ts'o | 34b9f79 | 2007-04-06 18:43:11 -0400 | [diff] [blame] | 641 | e2fsck_setup_tdb_icount(ctx, 0, &ctx->inode_link_info); |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 642 | if (!ctx->inode_link_info) { |
| 643 | e2fsck_set_bitmap_type(fs, EXT2FS_BMAP64_RBTREE, |
| 644 | "inode_link_info", &save_type); |
Theodore Ts'o | 34b9f79 | 2007-04-06 18:43:11 -0400 | [diff] [blame] | 645 | pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0, |
| 646 | &ctx->inode_link_info); |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 647 | fs->default_bitmap_type = save_type; |
| 648 | } |
| 649 | |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 650 | if (pctx.errcode) { |
| 651 | fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx); |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 652 | ctx->flags |= E2F_FLAG_ABORT; |
| 653 | return; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 654 | } |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 655 | inode_size = EXT2_INODE_SIZE(fs->super); |
| 656 | inode = (struct ext2_inode *) |
| 657 | e2fsck_allocate_memory(ctx, inode_size, "scratch inode"); |
| 658 | |
Theodore Ts'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 659 | 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'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 664 | process_inode_count = 0; |
| 665 | |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 666 | pctx.errcode = ext2fs_init_dblist(fs, 0); |
| 667 | if (pctx.errcode) { |
| 668 | fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx); |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 669 | ctx->flags |= E2F_FLAG_ABORT; |
Brian Behlendorf | 9d45b6e | 2007-03-28 11:57:20 -0400 | [diff] [blame] | 670 | ext2fs_free_mem(&inode); |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 671 | return; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 672 | } |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 673 | |
Theodore Ts'o | 9cbfb8d | 2000-07-04 19:51:22 +0000 | [diff] [blame] | 674 | /* |
| 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'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 688 | mark_table_blocks(ctx); |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 689 | 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'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 697 | block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3, |
| 698 | "block interate buffer"); |
Theodore Ts'o | e72a9ba | 1999-06-25 15:40:18 +0000 | [diff] [blame] | 699 | e2fsck_use_inode_shortcuts(ctx, 1); |
Theodore Ts'o | e94bc63 | 2007-04-14 09:29:02 -0400 | [diff] [blame] | 700 | old_op = ehandler_operation(_("opening inode scan")); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 701 | pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks, |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 702 | &scan); |
Theodore Ts'o | e94bc63 | 2007-04-14 09:29:02 -0400 | [diff] [blame] | 703 | ehandler_operation(old_op); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 704 | if (pctx.errcode) { |
| 705 | fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx); |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 706 | ctx->flags |= E2F_FLAG_ABORT; |
Brian Behlendorf | 9d45b6e | 2007-03-28 11:57:20 -0400 | [diff] [blame] | 707 | ext2fs_free_mem(&block_buf); |
| 708 | ext2fs_free_mem(&inode); |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 709 | return; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 710 | } |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 711 | ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0); |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 712 | ctx->stashed_inode = inode; |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 713 | 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'o | a02ce9d | 1998-02-24 20:22:23 +0000 | [diff] [blame] | 717 | if ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count)) |
| 718 | return; |
Theodore Ts'o | 4147d9f | 2005-04-06 14:55:53 -0400 | [diff] [blame] | 719 | if ((fs->super->s_wtime < fs->super->s_inodes_count) || |
| 720 | (fs->super->s_mtime < fs->super->s_inodes_count)) |
Theodore Ts'o | be93ef0 | 2002-10-31 18:38:55 -0500 | [diff] [blame] | 721 | busted_fs_time = 1; |
| 722 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 723 | 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'o | d237a78 | 2002-10-03 01:09:35 -0400 | [diff] [blame] | 729 | while (1) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 730 | if (ino % (fs->super->s_inodes_per_group * 4) == 1) { |
| 731 | if (e2fsck_mmp_update(fs)) |
| 732 | fatal_error(ctx, 0); |
| 733 | } |
Theodore Ts'o | e94bc63 | 2007-04-14 09:29:02 -0400 | [diff] [blame] | 734 | old_op = ehandler_operation(_("getting next inode from scan")); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 735 | pctx.errcode = ext2fs_get_next_inode_full(scan, &ino, |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 736 | inode, inode_size); |
Theodore Ts'o | e94bc63 | 2007-04-14 09:29:02 -0400 | [diff] [blame] | 737 | ehandler_operation(old_op); |
Theodore Ts'o | d237a78 | 2002-10-03 01:09:35 -0400 | [diff] [blame] | 738 | 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 743 | ext2fs_mark_inode_bitmap2(ctx->inode_bb_map, ino); |
| 744 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); |
Theodore Ts'o | d237a78 | 2002-10-03 01:09:35 -0400 | [diff] [blame] | 745 | 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'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 754 | pctx.ino = ino; |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 755 | pctx.inode = inode; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 756 | ctx->stashed_ino = ino; |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 757 | if (inode->i_links_count) { |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 758 | pctx.errcode = ext2fs_icount_store(ctx->inode_link_info, |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 759 | ino, inode->i_links_count); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 760 | if (pctx.errcode) { |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 761 | pctx.num = inode->i_links_count; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 762 | fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx); |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 763 | ctx->flags |= E2F_FLAG_ABORT; |
| 764 | return; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 765 | } |
| 766 | } |
Eric Sandeen | dfc870c | 2008-04-01 15:18:44 -0400 | [diff] [blame] | 767 | |
| 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'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 783 | if ((inode->i_flags & EXT4_EXTENTS_FL) && !extent_fs && |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 784 | (inode->i_links_count || (ino == EXT2_BAD_INO) || |
| 785 | (ino == EXT2_ROOT_INO) || (ino == EXT2_JOURNAL_INO))) { |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 786 | if ((ext2fs_extent_header_verify(inode->i_block, |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 787 | 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 796 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 797 | ino); |
| 798 | continue; |
| 799 | } |
| 800 | } |
| 801 | |
Eric Sandeen | dfc870c | 2008-04-01 15:18:44 -0400 | [diff] [blame] | 802 | /* |
| 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'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 810 | 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 Sandeen | dfc870c | 2008-04-01 15:18:44 -0400 | [diff] [blame] | 814 | 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'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 825 | if ((ext2fs_extent_header_verify(ehp, |
Eric Sandeen | dfc870c | 2008-04-01 15:18:44 -0400 | [diff] [blame] | 826 | sizeof(inode->i_block)) == 0) && |
| 827 | (fix_problem(ctx, PR_1_UNSET_EXTENT_FL, &pctx))) { |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 828 | inode->i_flags |= EXT4_EXTENTS_FL; |
Eric Sandeen | dfc870c | 2008-04-01 15:18:44 -0400 | [diff] [blame] | 829 | #ifdef WORDS_BIGENDIAN |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 830 | memcpy(inode->i_block, tmp_block, |
Eric Sandeen | dfc870c | 2008-04-01 15:18:44 -0400 | [diff] [blame] | 831 | sizeof(inode->i_block)); |
| 832 | #endif |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 833 | e2fsck_write_inode(ctx, ino, inode, "pass1"); |
| 834 | } |
| 835 | } |
| 836 | |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 837 | if (ino == EXT2_BAD_INO) { |
| 838 | struct process_block_struct pb; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 839 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 840 | 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'o | 000ba40 | 2003-11-21 10:41:58 -0500 | [diff] [blame] | 848 | 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'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 856 | pb.ino = EXT2_BAD_INO; |
| 857 | pb.num_blocks = pb.last_block = 0; |
Theodore Ts'o | 4dbe79b | 2009-11-28 09:35:37 -0500 | [diff] [blame] | 858 | pb.last_db_block = -1; |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 859 | pb.num_illegal_blocks = 0; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 860 | pb.suppress = 0; pb.clear = 0; pb.is_dir = 0; |
Theodore Ts'o | 000ba40 | 2003-11-21 10:41:58 -0500 | [diff] [blame] | 861 | pb.is_reg = 0; pb.fragmented = 0; pb.bbcheck = 0; |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 862 | pb.inode = inode; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 863 | pb.pctx = &pctx; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 864 | pb.ctx = ctx; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 865 | pctx.errcode = ext2fs_block_iterate3(fs, ino, 0, |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 866 | block_buf, process_bad_block, &pb); |
Theodore Ts'o | 000ba40 | 2003-11-21 10:41:58 -0500 | [diff] [blame] | 867 | ext2fs_free_block_bitmap(pb.fs_meta_blocks); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 868 | if (pctx.errcode) { |
| 869 | fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx); |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 870 | ctx->flags |= E2F_FLAG_ABORT; |
| 871 | return; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 872 | } |
Theodore Ts'o | 000ba40 | 2003-11-21 10:41:58 -0500 | [diff] [blame] | 873 | 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 878 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 879 | clear_problem_context(&pctx); |
Theodore Ts'o | d237a78 | 2002-10-03 01:09:35 -0400 | [diff] [blame] | 880 | continue; |
Theodore Ts'o | a9ca201 | 2001-01-12 21:53:25 +0000 | [diff] [blame] | 881 | } else if (ino == EXT2_ROOT_INO) { |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 882 | /* |
| 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'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 887 | if (!LINUX_S_ISDIR(inode->i_mode)) { |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 888 | if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) |
| 889 | goto clear_inode; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 890 | } |
| 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'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 900 | if (inode->i_dtime && inode->i_links_count) { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 901 | if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) { |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 902 | inode->i_dtime = 0; |
| 903 | e2fsck_write_inode(ctx, ino, inode, |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 904 | "pass1"); |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 905 | } |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 906 | } |
Theodore Ts'o | a9ca201 | 2001-01-12 21:53:25 +0000 | [diff] [blame] | 907 | } else if (ino == EXT2_JOURNAL_INO) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 908 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); |
Theodore Ts'o | f18996c | 2001-01-03 16:57:24 +0000 | [diff] [blame] | 909 | if (fs->super->s_journal_inum == EXT2_JOURNAL_INO) { |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 910 | if (!LINUX_S_ISREG(inode->i_mode) && |
Theodore Ts'o | a9ca201 | 2001-01-12 21:53:25 +0000 | [diff] [blame] | 911 | fix_problem(ctx, PR_1_JOURNAL_BAD_MODE, |
| 912 | &pctx)) { |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 913 | inode->i_mode = LINUX_S_IFREG; |
| 914 | e2fsck_write_inode(ctx, ino, inode, |
Theodore Ts'o | a9ca201 | 2001-01-12 21:53:25 +0000 | [diff] [blame] | 915 | "pass1"); |
| 916 | } |
Theodore Ts'o | f18996c | 2001-01-03 16:57:24 +0000 | [diff] [blame] | 917 | check_blocks(ctx, &pctx, block_buf); |
Theodore Ts'o | d237a78 | 2002-10-03 01:09:35 -0400 | [diff] [blame] | 918 | continue; |
Theodore Ts'o | f18996c | 2001-01-03 16:57:24 +0000 | [diff] [blame] | 919 | } |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 920 | if ((inode->i_links_count || |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 921 | inode->i_blocks || inode->i_block[0]) && |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 922 | fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR, |
Theodore Ts'o | f18996c | 2001-01-03 16:57:24 +0000 | [diff] [blame] | 923 | &pctx)) { |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 924 | memset(inode, 0, inode_size); |
Theodore Ts'o | a9ca201 | 2001-01-12 21:53:25 +0000 | [diff] [blame] | 925 | ext2fs_icount_store(ctx->inode_link_info, |
| 926 | ino, 0); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 927 | e2fsck_write_inode_full(ctx, ino, inode, |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 928 | inode_size, "pass1"); |
Theodore Ts'o | f18996c | 2001-01-03 16:57:24 +0000 | [diff] [blame] | 929 | } |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 930 | } 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'o | a9ca201 | 2001-01-12 21:53:25 +0000 | [diff] [blame] | 957 | } else if (ino < EXT2_FIRST_INODE(fs->super)) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 958 | problem_t problem = 0; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 959 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 960 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); |
Theodore Ts'o | 53ef44c | 2001-01-06 05:55:58 +0000 | [diff] [blame] | 961 | if (ino == EXT2_BOOT_LOADER_INO) { |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 962 | if (LINUX_S_ISDIR(inode->i_mode)) |
Theodore Ts'o | b09a4b0 | 2000-10-24 21:16:09 +0000 | [diff] [blame] | 963 | problem = PR_1_RESERVED_BAD_MODE; |
Theodore Ts'o | b1f204f | 2001-08-30 16:42:09 -0400 | [diff] [blame] | 964 | } else if (ino == EXT2_RESIZE_INO) { |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 965 | if (inode->i_mode && |
| 966 | !LINUX_S_ISREG(inode->i_mode)) |
Theodore Ts'o | b1f204f | 2001-08-30 16:42:09 -0400 | [diff] [blame] | 967 | problem = PR_1_RESERVED_BAD_MODE; |
Theodore Ts'o | 53ef44c | 2001-01-06 05:55:58 +0000 | [diff] [blame] | 968 | } else { |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 969 | if (inode->i_mode != 0) |
Theodore Ts'o | b09a4b0 | 2000-10-24 21:16:09 +0000 | [diff] [blame] | 970 | problem = PR_1_RESERVED_BAD_MODE; |
Theodore Ts'o | b09a4b0 | 2000-10-24 21:16:09 +0000 | [diff] [blame] | 971 | } |
| 972 | if (problem) { |
| 973 | if (fix_problem(ctx, problem, &pctx)) { |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 974 | inode->i_mode = 0; |
| 975 | e2fsck_write_inode(ctx, ino, inode, |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 976 | "pass1"); |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 977 | } |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 978 | } |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 979 | check_blocks(ctx, &pctx, block_buf); |
Theodore Ts'o | d237a78 | 2002-10-03 01:09:35 -0400 | [diff] [blame] | 980 | continue; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 981 | } |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 982 | |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 983 | /* |
Theodore Ts'o | 21afac0 | 2001-05-14 12:47:41 +0000 | [diff] [blame] | 984 | * 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'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 988 | * |
Theodore Ts'o | 21afac0 | 2001-05-14 12:47:41 +0000 | [diff] [blame] | 989 | * 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'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1000 | if (inode->i_dtime && !busted_fs_time && |
| 1001 | inode->i_dtime < ctx->fs->super->s_inodes_count) { |
Theodore Ts'o | 21afac0 | 2001-05-14 12:47:41 +0000 | [diff] [blame] | 1002 | if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) { |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1003 | inode->i_dtime = inode->i_links_count ? |
Theodore Ts'o | 1f3ad14 | 2005-04-14 14:07:53 -0400 | [diff] [blame] | 1004 | 0 : ctx->now; |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1005 | e2fsck_write_inode(ctx, ino, inode, |
Theodore Ts'o | 21afac0 | 2001-05-14 12:47:41 +0000 | [diff] [blame] | 1006 | "pass1"); |
| 1007 | } |
| 1008 | } |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1009 | |
Theodore Ts'o | 21afac0 | 2001-05-14 12:47:41 +0000 | [diff] [blame] | 1010 | /* |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1011 | * This code assumes that deleted inodes have |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1012 | * i_links_count set to 0. |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1013 | */ |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1014 | if (!inode->i_links_count) { |
| 1015 | if (!inode->i_dtime && inode->i_mode) { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1016 | if (fix_problem(ctx, |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 1017 | PR_1_ZERO_DTIME, &pctx)) { |
Theodore Ts'o | 1f3ad14 | 2005-04-14 14:07:53 -0400 | [diff] [blame] | 1018 | inode->i_dtime = ctx->now; |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1019 | e2fsck_write_inode(ctx, ino, inode, |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 1020 | "pass1"); |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 1021 | } |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1022 | } |
Theodore Ts'o | d237a78 | 2002-10-03 01:09:35 -0400 | [diff] [blame] | 1023 | continue; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1024 | } |
| 1025 | /* |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 1026 | * n.b. 0.3c ext2fs code didn't clear i_links_count for |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1027 | * deleted files. Oops. |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 1028 | * |
| 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'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1033 | * |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1034 | */ |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1035 | if (inode->i_dtime) { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1036 | if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) { |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1037 | inode->i_dtime = 0; |
| 1038 | e2fsck_write_inode(ctx, ino, inode, "pass1"); |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 1039 | } |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1040 | } |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1041 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1042 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 1043 | switch (fs->super->s_creator_os) { |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 1044 | case EXT2_OS_HURD: |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1045 | frag = inode->osd2.hurd2.h_i_frag; |
| 1046 | fsize = inode->osd2.hurd2.h_i_fsize; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 1047 | break; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 1048 | default: |
| 1049 | frag = fsize = 0; |
| 1050 | } |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1051 | |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1052 | if (inode->i_faddr || frag || fsize || |
| 1053 | (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl)) |
Theodore Ts'o | fdbdea0 | 2001-06-02 04:26:26 +0000 | [diff] [blame] | 1054 | mark_inode_bad(ctx, ino); |
Theodore Ts'o | 911ec62 | 2009-04-23 21:31:16 -0400 | [diff] [blame] | 1055 | 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'o | 5d17119 | 2006-11-11 06:32:03 -0500 | [diff] [blame] | 1059 | if ((fs->super->s_creator_os == EXT2_OS_LINUX) && |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1060 | !(fs->super->s_feature_ro_compat & |
Theodore Ts'o | 5d17119 | 2006-11-11 06:32:03 -0500 | [diff] [blame] | 1061 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE) && |
| 1062 | (inode->osd2.linux2.l_i_blocks_hi != 0)) |
| 1063 | mark_inode_bad(ctx, ino); |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1064 | if (inode->i_flags & EXT2_IMAGIC_FL) { |
Theodore Ts'o | 6fdc7a3 | 1999-11-10 13:34:40 +0000 | [diff] [blame] | 1065 | if (imagic_fs) { |
| 1066 | if (!ctx->inode_imagic_map) |
| 1067 | alloc_imagic_map(ctx); |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1068 | ext2fs_mark_inode_bitmap2(ctx->inode_imagic_map, |
Theodore Ts'o | 6fdc7a3 | 1999-11-10 13:34:40 +0000 | [diff] [blame] | 1069 | ino); |
| 1070 | } else { |
| 1071 | if (fix_problem(ctx, PR_1_SET_IMAGIC, &pctx)) { |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1072 | inode->i_flags &= ~EXT2_IMAGIC_FL; |
Theodore Ts'o | 6fdc7a3 | 1999-11-10 13:34:40 +0000 | [diff] [blame] | 1073 | e2fsck_write_inode(ctx, ino, |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1074 | inode, "pass1"); |
Theodore Ts'o | 6fdc7a3 | 1999-11-10 13:34:40 +0000 | [diff] [blame] | 1075 | } |
| 1076 | } |
Theodore Ts'o | aa4115a | 1999-10-21 19:33:18 +0000 | [diff] [blame] | 1077 | } |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1078 | |
| 1079 | check_inode_extra_space(ctx, &pctx); |
Theodore Ts'o | fbc3f90 | 2007-04-02 10:08:59 -0400 | [diff] [blame] | 1080 | check_is_really_dir(ctx, &pctx, block_buf); |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1081 | |
Eric Sandeen | dfc870c | 2008-04-01 15:18:44 -0400 | [diff] [blame] | 1082 | /* |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1083 | * ext2fs_inode_has_valid_blocks2 does not actually look |
Eric Sandeen | dfc870c | 2008-04-01 15:18:44 -0400 | [diff] [blame] | 1084 | * at i_block[] values, so not endian-sensitive here. |
| 1085 | */ |
Theodore Ts'o | cb23cad | 2008-03-24 08:17:24 -0400 | [diff] [blame] | 1086 | if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL) && |
| 1087 | LINUX_S_ISLNK(inode->i_mode) && |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1088 | !ext2fs_inode_has_valid_blocks2(fs, inode) && |
Theodore Ts'o | cb23cad | 2008-03-24 08:17:24 -0400 | [diff] [blame] | 1089 | 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'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1094 | if (LINUX_S_ISDIR(inode->i_mode)) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1095 | ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino); |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 1096 | e2fsck_add_dir_info(ctx, ino, 0); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1097 | ctx->fs_directory_count++; |
Theodore Ts'o | 890a2f9 | 2015-07-14 22:50:51 -0400 | [diff] [blame] | 1098 | if (inode->i_flags & EXT4_ENCRYPT_FL) |
| 1099 | add_encrypted_dir(ctx, ino); |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1100 | } else if (LINUX_S_ISREG (inode->i_mode)) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1101 | ext2fs_mark_inode_bitmap2(ctx->inode_reg_map, ino); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1102 | ctx->fs_regular_count++; |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1103 | } else if (LINUX_S_ISCHR (inode->i_mode) && |
| 1104 | e2fsck_pass1_check_device_inode(fs, inode)) { |
Theodore Ts'o | 6fdc7a3 | 1999-11-10 13:34:40 +0000 | [diff] [blame] | 1105 | check_immutable(ctx, &pctx); |
Theodore Ts'o | d647a1e | 2000-05-27 14:40:09 +0000 | [diff] [blame] | 1106 | check_size(ctx, &pctx); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1107 | ctx->fs_chardev_count++; |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1108 | } else if (LINUX_S_ISBLK (inode->i_mode) && |
| 1109 | e2fsck_pass1_check_device_inode(fs, inode)) { |
Theodore Ts'o | 6fdc7a3 | 1999-11-10 13:34:40 +0000 | [diff] [blame] | 1110 | check_immutable(ctx, &pctx); |
Theodore Ts'o | d647a1e | 2000-05-27 14:40:09 +0000 | [diff] [blame] | 1111 | check_size(ctx, &pctx); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1112 | ctx->fs_blockdev_count++; |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1113 | } else if (LINUX_S_ISLNK (inode->i_mode) && |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1114 | e2fsck_pass1_check_symlink(fs, ino, inode, |
Theodore Ts'o | 7cadc57 | 2008-03-13 23:05:00 -0400 | [diff] [blame] | 1115 | block_buf)) { |
Theodore Ts'o | fd77b2c | 2001-07-27 22:10:01 -0400 | [diff] [blame] | 1116 | check_immutable(ctx, &pctx); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1117 | ctx->fs_symlinks_count++; |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1118 | if (ext2fs_inode_data_blocks(fs, inode) == 0) { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1119 | ctx->fs_fast_symlinks_count++; |
Theodore Ts'o | 0684a4f | 2002-08-17 10:19:44 -0400 | [diff] [blame] | 1120 | check_blocks(ctx, &pctx, block_buf); |
Theodore Ts'o | d237a78 | 2002-10-03 01:09:35 -0400 | [diff] [blame] | 1121 | continue; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 1122 | } |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1123 | } |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1124 | else if (LINUX_S_ISFIFO (inode->i_mode) && |
| 1125 | e2fsck_pass1_check_device_inode(fs, inode)) { |
Theodore Ts'o | 6fdc7a3 | 1999-11-10 13:34:40 +0000 | [diff] [blame] | 1126 | check_immutable(ctx, &pctx); |
Theodore Ts'o | d647a1e | 2000-05-27 14:40:09 +0000 | [diff] [blame] | 1127 | check_size(ctx, &pctx); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1128 | ctx->fs_fifo_count++; |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1129 | } else if ((LINUX_S_ISSOCK (inode->i_mode)) && |
| 1130 | e2fsck_pass1_check_device_inode(fs, inode)) { |
Theodore Ts'o | 6fdc7a3 | 1999-11-10 13:34:40 +0000 | [diff] [blame] | 1131 | check_immutable(ctx, &pctx); |
Theodore Ts'o | d647a1e | 2000-05-27 14:40:09 +0000 | [diff] [blame] | 1132 | check_size(ctx, &pctx); |
| 1133 | ctx->fs_sockets_count++; |
Theodore Ts'o | fdbdea0 | 2001-06-02 04:26:26 +0000 | [diff] [blame] | 1134 | } else |
| 1135 | mark_inode_bad(ctx, ino); |
Theodore Ts'o | 8da6d1a | 2008-08-14 09:48:07 -0400 | [diff] [blame] | 1136 | 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'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1144 | 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1148 | ext2fs_file_acl_block(fs, inode))) { |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1149 | inodes_to_process[process_inode_count].ino = ino; |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1150 | inodes_to_process[process_inode_count].inode = *inode; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1151 | process_inode_count++; |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 1152 | } else |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1153 | check_blocks(ctx, &pctx, block_buf); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1154 | |
Theodore Ts'o | a02ce9d | 1998-02-24 20:22:23 +0000 | [diff] [blame] | 1155 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 1156 | return; |
| 1157 | |
| 1158 | if (process_inode_count >= ctx->process_inode_size) { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1159 | process_inodes(ctx, block_buf); |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 1160 | |
Theodore Ts'o | a02ce9d | 1998-02-24 20:22:23 +0000 | [diff] [blame] | 1161 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 1162 | return; |
| 1163 | } |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1164 | } |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1165 | process_inodes(ctx, block_buf); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1166 | ext2fs_close_inode_scan(scan); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1167 | |
Theodore Ts'o | e8a3ee6 | 2001-07-07 11:12:50 -0400 | [diff] [blame] | 1168 | /* |
| 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'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1184 | |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1185 | if (ctx->invalid_bitmaps) |
| 1186 | handle_fs_bad_blocks(ctx); |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 1187 | |
Theodore Ts'o | 24ceb24 | 2001-07-26 09:02:56 -0400 | [diff] [blame] | 1188 | /* 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'o | c3ffaf8 | 2004-12-24 01:42:22 -0500 | [diff] [blame] | 1194 | if (ctx->flags & E2F_FLAG_RESIZE_INODE) { |
| 1195 | ext2fs_block_bitmap save_bmap; |
Theodore Ts'o | c3ffaf8 | 2004-12-24 01:42:22 -0500 | [diff] [blame] | 1196 | |
| 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'o | a6217f5 | 2010-05-12 18:58:53 -0400 | [diff] [blame] | 1202 | 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'o | c3ffaf8 | 2004-12-24 01:42:22 -0500 | [diff] [blame] | 1208 | } |
Theodore Ts'o | a6217f5 | 2010-05-12 18:58:53 -0400 | [diff] [blame] | 1209 | 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'o | c3ffaf8 | 2004-12-24 01:42:22 -0500 | [diff] [blame] | 1216 | fs->block_map = save_bmap; |
| 1217 | ctx->flags &= ~E2F_FLAG_RESIZE_INODE; |
| 1218 | } |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1219 | |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 1220 | if (ctx->flags & E2F_FLAG_RESTART) { |
Theodore Ts'o | aa4115a | 1999-10-21 19:33:18 +0000 | [diff] [blame] | 1221 | /* |
| 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'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 1228 | unwind_pass1(fs); |
| 1229 | goto endit; |
| 1230 | } |
| 1231 | |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1232 | 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'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1236 | } |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 1237 | e2fsck_pass1_dupblocks(ctx, block_buf); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1238 | } |
Theodore Ts'o | c4e3d3f | 2003-08-01 09:41:07 -0400 | [diff] [blame] | 1239 | ext2fs_free_mem(&inodes_to_process); |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 1240 | endit: |
Theodore Ts'o | e72a9ba | 1999-06-25 15:40:18 +0000 | [diff] [blame] | 1241 | e2fsck_use_inode_shortcuts(ctx, 0); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1242 | |
Theodore Ts'o | c4e3d3f | 2003-08-01 09:41:07 -0400 | [diff] [blame] | 1243 | ext2fs_free_mem(&block_buf); |
Theodore Ts'o | cebe48a | 2005-03-21 13:15:45 -0500 | [diff] [blame] | 1244 | ext2fs_free_mem(&inode); |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 1245 | |
Ken Chen | 9facd07 | 2009-05-28 09:55:10 -0400 | [diff] [blame] | 1246 | print_resource_track(ctx, _("Pass 1"), &rtrack, ctx->fs->io); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1247 | } |
| 1248 | |
| 1249 | /* |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 1250 | * When the inode_scan routines call this callback at the end of the |
| 1251 | * glock group, call process_inodes. |
| 1252 | */ |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1253 | static errcode_t scan_callback(ext2_filsys fs, |
Theodore Ts'o | 5443492 | 2003-12-07 01:28:50 -0500 | [diff] [blame] | 1254 | ext2_inode_scan scan EXT2FS_ATTR((unused)), |
Theodore Ts'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 1255 | dgrp_t group, void * priv_data) |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 1256 | { |
Theodore Ts'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 1257 | struct scan_callback_struct *scan_struct; |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 1258 | e2fsck_t ctx; |
| 1259 | |
Theodore Ts'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 1260 | scan_struct = (struct scan_callback_struct *) priv_data; |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 1261 | ctx = scan_struct->ctx; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1262 | |
Theodore Ts'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 1263 | process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf); |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 1264 | |
| 1265 | if (ctx->progress) |
Theodore Ts'o | a02ce9d | 1998-02-24 20:22:23 +0000 | [diff] [blame] | 1266 | if ((ctx->progress)(ctx, 1, group+1, |
| 1267 | ctx->fs->group_desc_count)) |
| 1268 | return EXT2_ET_CANCEL_REQUESTED; |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 1269 | |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 1270 | return 0; |
| 1271 | } |
| 1272 | |
| 1273 | /* |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1274 | * Process the inodes in the "inodes to process" list. |
| 1275 | */ |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1276 | static void process_inodes(e2fsck_t ctx, char *block_buf) |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1277 | { |
| 1278 | int i; |
| 1279 | struct ext2_inode *old_stashed_inode; |
Theodore Ts'o | 86c627e | 2001-01-11 15:12:14 +0000 | [diff] [blame] | 1280 | ext2_ino_t old_stashed_ino; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1281 | const char *old_operation; |
| 1282 | char buf[80]; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 1283 | struct problem_context pctx; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1284 | |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1285 | #if 0 |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 1286 | printf("begin process_inodes: "); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1287 | #endif |
Theodore Ts'o | 86a63e9 | 1999-11-23 13:52:48 +0000 | [diff] [blame] | 1288 | if (process_inode_count == 0) |
| 1289 | return; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1290 | old_operation = ehandler_operation(0); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1291 | old_stashed_inode = ctx->stashed_inode; |
| 1292 | old_stashed_ino = ctx->stashed_ino; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1293 | qsort(inodes_to_process, process_inode_count, |
| 1294 | sizeof(struct process_inode_block), process_inode_cmp); |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 1295 | clear_problem_context(&pctx); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1296 | for (i=0; i < process_inode_count; i++) { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1297 | pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode; |
| 1298 | pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1299 | |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 1300 | #if 0 |
| 1301 | printf("%u ", pctx.ino); |
| 1302 | #endif |
Theodore Ts'o | 86c627e | 2001-01-11 15:12:14 +0000 | [diff] [blame] | 1303 | sprintf(buf, _("reading indirect blocks of inode %u"), |
Theodore Ts'o | 0c4a072 | 2000-02-07 03:11:03 +0000 | [diff] [blame] | 1304 | pctx.ino); |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 1305 | ehandler_operation(buf); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1306 | check_blocks(ctx, &pctx, block_buf); |
Theodore Ts'o | a02ce9d | 1998-02-24 20:22:23 +0000 | [diff] [blame] | 1307 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
Theodore Ts'o | 2df1f6a | 1998-02-27 05:03:48 +0000 | [diff] [blame] | 1308 | break; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1309 | } |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1310 | ctx->stashed_inode = old_stashed_inode; |
| 1311 | ctx->stashed_ino = old_stashed_ino; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1312 | process_inode_count = 0; |
| 1313 | #if 0 |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 1314 | printf("end process inodes\n"); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1315 | #endif |
| 1316 | ehandler_operation(old_operation); |
| 1317 | } |
| 1318 | |
Theodore Ts'o | 4c77fe5 | 1998-04-30 17:35:59 +0000 | [diff] [blame] | 1319 | static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b) |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1320 | { |
| 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'o | b5acdb6 | 2001-07-07 22:27:40 -0400 | [diff] [blame] | 1325 | int ret; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1326 | |
Theodore Ts'o | b5acdb6 | 2001-07-07 22:27:40 -0400 | [diff] [blame] | 1327 | ret = (ib_a->inode.i_block[EXT2_IND_BLOCK] - |
| 1328 | ib_b->inode.i_block[EXT2_IND_BLOCK]); |
| 1329 | if (ret == 0) |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1330 | /* |
| 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'o | 0eeec8a | 2008-09-12 09:10:39 -0400 | [diff] [blame] | 1337 | if (ret == 0) |
| 1338 | ret = ib_a->ino - ib_b->ino; |
Theodore Ts'o | b5acdb6 | 2001-07-07 22:27:40 -0400 | [diff] [blame] | 1339 | return ret; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1340 | } |
| 1341 | |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1342 | /* |
Theodore Ts'o | fdbdea0 | 2001-06-02 04:26:26 +0000 | [diff] [blame] | 1343 | * Mark an inode as being bad in some what |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1344 | */ |
Theodore Ts'o | fdbdea0 | 2001-06-02 04:26:26 +0000 | [diff] [blame] | 1345 | static void mark_inode_bad(e2fsck_t ctx, ino_t ino) |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1346 | { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1347 | struct problem_context pctx; |
Theodore Ts'o | fdbdea0 | 2001-06-02 04:26:26 +0000 | [diff] [blame] | 1348 | |
| 1349 | if (!ctx->inode_bad_map) { |
| 1350 | clear_problem_context(&pctx); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1351 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1352 | 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'o | fdbdea0 | 2001-06-02 04:26:26 +0000 | [diff] [blame] | 1355 | 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'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1362 | } |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1363 | ext2fs_mark_inode_bitmap2(ctx->inode_bad_map, ino); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1364 | } |
| 1365 | |
Theodore Ts'o | 890a2f9 | 2015-07-14 22:50:51 -0400 | [diff] [blame] | 1366 | static 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; |
| 1378 | error: |
| 1379 | fix_problem(ctx, PR_1_ALLOCATE_ENCRYPTED_DIRLIST, &pctx); |
| 1380 | /* Should never get here */ |
| 1381 | ctx->flags |= E2F_FLAG_ABORT; |
| 1382 | } |
Theodore Ts'o | fdbdea0 | 2001-06-02 04:26:26 +0000 | [diff] [blame] | 1383 | |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1384 | /* |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 1385 | * This procedure will allocate the inode "bb" (badblock) map table |
| 1386 | */ |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1387 | static void alloc_bb_map(e2fsck_t ctx) |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 1388 | { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1389 | struct problem_context pctx; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1390 | |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1391 | clear_problem_context(&pctx); |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1392 | 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'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1395 | if (pctx.errcode) { |
| 1396 | pctx.num = 4; |
| 1397 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 1398 | /* Should never get here */ |
| 1399 | ctx->flags |= E2F_FLAG_ABORT; |
| 1400 | return; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 1401 | } |
| 1402 | } |
| 1403 | |
| 1404 | /* |
Theodore Ts'o | aa4115a | 1999-10-21 19:33:18 +0000 | [diff] [blame] | 1405 | * This procedure will allocate the inode imagic table |
| 1406 | */ |
| 1407 | static void alloc_imagic_map(e2fsck_t ctx) |
| 1408 | { |
| 1409 | struct problem_context pctx; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1410 | |
Theodore Ts'o | aa4115a | 1999-10-21 19:33:18 +0000 | [diff] [blame] | 1411 | clear_problem_context(&pctx); |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1412 | 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'o | aa4115a | 1999-10-21 19:33:18 +0000 | [diff] [blame] | 1415 | 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'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1425 | * 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'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 1427 | * |
| 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'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1430 | */ |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1431 | static _INLINE_ void mark_block_used(e2fsck_t ctx, blk64_t block) |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1432 | { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1433 | struct problem_context pctx; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1434 | |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1435 | clear_problem_context(&pctx); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1436 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1437 | if (ext2fs_fast_test_block_bitmap2(ctx->block_found_map, block)) { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1438 | if (!ctx->block_dup_map) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1439 | 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'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1443 | if (pctx.errcode) { |
| 1444 | pctx.num = 3; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1445 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 1446 | &pctx); |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 1447 | /* Should never get here */ |
| 1448 | ctx->flags |= E2F_FLAG_ABORT; |
| 1449 | return; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1450 | } |
| 1451 | } |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1452 | ext2fs_fast_mark_block_bitmap2(ctx->block_dup_map, block); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1453 | } else { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1454 | ext2fs_fast_mark_block_bitmap2(ctx->block_found_map, block); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1455 | } |
| 1456 | } |
| 1457 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1458 | static _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'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 1468 | /* |
Theodore Ts'o | e8a3ee6 | 2001-07-07 11:12:50 -0400 | [diff] [blame] | 1469 | * 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'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1475 | static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount, |
Theodore Ts'o | e8a3ee6 | 2001-07-07 11:12:50 -0400 | [diff] [blame] | 1476 | 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1481 | blk64_t blk; |
Theodore Ts'o | e8a3ee6 | 2001-07-07 11:12:50 -0400 | [diff] [blame] | 1482 | __u32 should_be; |
| 1483 | int count; |
| 1484 | |
| 1485 | clear_problem_context(&pctx); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1486 | |
Theodore Ts'o | e8a3ee6 | 2001-07-07 11:12:50 -0400 | [diff] [blame] | 1487 | 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1492 | pctx.errcode = ext2fs_read_ext_attr2(fs, blk, block_buf); |
Theodore Ts'o | e8a3ee6 | 2001-07-07 11:12:50 -0400 | [diff] [blame] | 1493 | 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1503 | pctx.errcode = ext2fs_write_ext_attr2(fs, blk, |
Theodore Ts'o | e8a3ee6 | 2001-07-07 11:12:50 -0400 | [diff] [blame] | 1504 | block_buf); |
| 1505 | if (pctx.errcode) { |
Theodore Ts'o | a6217f5 | 2010-05-12 18:58:53 -0400 | [diff] [blame] | 1506 | fix_problem(ctx, PR_1_EXTATTR_WRITE_ABORT, |
| 1507 | &pctx); |
Theodore Ts'o | e8a3ee6 | 2001-07-07 11:12:50 -0400 | [diff] [blame] | 1508 | continue; |
| 1509 | } |
| 1510 | } |
| 1511 | } |
| 1512 | } |
| 1513 | |
| 1514 | /* |
Theodore Ts'o | 342d847 | 2001-07-02 11:54:09 -0400 | [diff] [blame] | 1515 | * Handle processing the extended attribute blocks |
| 1516 | */ |
| 1517 | static 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1523 | blk64_t blk; |
Theodore Ts'o | 55fd07e | 2001-07-19 16:31:25 -0400 | [diff] [blame] | 1524 | char * end; |
Theodore Ts'o | e8a3ee6 | 2001-07-07 11:12:50 -0400 | [diff] [blame] | 1525 | struct ext2_ext_attr_header *header; |
Theodore Ts'o | 55fd07e | 2001-07-19 16:31:25 -0400 | [diff] [blame] | 1526 | struct ext2_ext_attr_entry *entry; |
Theodore Ts'o | 342d847 | 2001-07-02 11:54:09 -0400 | [diff] [blame] | 1527 | int count; |
Theodore Ts'o | 86bc90f | 2007-04-04 21:42:42 -0400 | [diff] [blame] | 1528 | region_t region = 0; |
Brian Behlendorf | 5469d76 | 2007-03-28 11:41:40 -0400 | [diff] [blame] | 1529 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1530 | blk = ext2fs_file_acl_block(fs, inode); |
Theodore Ts'o | 342d847 | 2001-07-02 11:54:09 -0400 | [diff] [blame] | 1531 | 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1543 | (blk >= ext2fs_blocks_count(fs->super))) { |
Theodore Ts'o | 342d847 | 2001-07-02 11:54:09 -0400 | [diff] [blame] | 1544 | 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1550 | 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'o | 342d847 | 2001-07-02 11:54:09 -0400 | [diff] [blame] | 1554 | 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'o | b5acdb6 | 2001-07-07 22:27:40 -0400 | [diff] [blame] | 1573 | #if 0 |
| 1574 | /* Debugging text */ |
| 1575 | printf("Inode %u has EA block %u\n", ino, blk); |
| 1576 | #endif |
| 1577 | |
Theodore Ts'o | 342d847 | 2001-07-02 11:54:09 -0400 | [diff] [blame] | 1578 | /* Have we seen this EA block before? */ |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1579 | if (ext2fs_fast_test_block_bitmap2(ctx->block_ea_map, blk)) { |
Theodore Ts'o | 342d847 | 2001-07-02 11:54:09 -0400 | [diff] [blame] | 1580 | 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'o | 55fd07e | 2001-07-19 16:31:25 -0400 | [diff] [blame] | 1590 | return 0; |
Theodore Ts'o | 342d847 | 2001-07-02 11:54:09 -0400 | [diff] [blame] | 1591 | } |
| 1592 | } |
| 1593 | ea_refcount_increment(ctx->refcount_extra, blk, 0); |
| 1594 | return 1; |
| 1595 | } |
Brian Behlendorf | 5469d76 | 2007-03-28 11:41:40 -0400 | [diff] [blame] | 1596 | |
Theodore Ts'o | 342d847 | 2001-07-02 11:54:09 -0400 | [diff] [blame] | 1597 | /* |
| 1598 | * OK, we haven't seen this EA block yet. So we need to |
| 1599 | * validate it |
| 1600 | */ |
| 1601 | pctx->blk = blk; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1602 | pctx->errcode = ext2fs_read_ext_attr2(fs, blk, block_buf); |
Theodore Ts'o | 342d847 | 2001-07-02 11:54:09 -0400 | [diff] [blame] | 1603 | if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx)) |
| 1604 | goto clear_extattr; |
Theodore Ts'o | 342d847 | 2001-07-02 11:54:09 -0400 | [diff] [blame] | 1605 | header = (struct ext2_ext_attr_header *) block_buf; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1606 | pctx->blk = ext2fs_file_acl_block(fs, inode); |
Theodore Ts'o | 0684a4f | 2002-08-17 10:19:44 -0400 | [diff] [blame] | 1607 | 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'o | 0d63467 | 2002-05-22 00:22:38 -0400 | [diff] [blame] | 1614 | |
Theodore Ts'o | 55fd07e | 2001-07-19 16:31:25 -0400 | [diff] [blame] | 1615 | 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'o | a6217f5 | 2010-05-12 18:58:53 -0400 | [diff] [blame] | 1622 | fix_problem(ctx, PR_1_EA_ALLOC_REGION_ABORT, pctx); |
Theodore Ts'o | 55fd07e | 2001-07-19 16:31:25 -0400 | [diff] [blame] | 1623 | 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'o | 342d847 | 2001-07-02 11:54:09 -0400 | [diff] [blame] | 1628 | goto clear_extattr; |
| 1629 | } |
Brian Behlendorf | 5469d76 | 2007-03-28 11:41:40 -0400 | [diff] [blame] | 1630 | |
Theodore Ts'o | 55fd07e | 2001-07-19 16:31:25 -0400 | [diff] [blame] | 1631 | entry = (struct ext2_ext_attr_entry *)(header+1); |
| 1632 | end = block_buf + fs->blocksize; |
| 1633 | while ((char *)entry < end && *(__u32 *)entry) { |
Andreas Dilger | fefaef3 | 2008-02-02 01:16:32 -0700 | [diff] [blame] | 1634 | __u32 hash; |
| 1635 | |
Theodore Ts'o | 55fd07e | 2001-07-19 16:31:25 -0400 | [diff] [blame] | 1636 | 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 Dilger | fefaef3 | 2008-02-02 01:16:32 -0700 | [diff] [blame] | 1640 | break; |
Theodore Ts'o | 55fd07e | 2001-07-19 16:31:25 -0400 | [diff] [blame] | 1641 | } |
Theodore Ts'o | 0684a4f | 2002-08-17 10:19:44 -0400 | [diff] [blame] | 1642 | if ((ctx->ext_attr_ver == 1 && |
Theodore Ts'o | 0d63467 | 2002-05-22 00:22:38 -0400 | [diff] [blame] | 1643 | (entry->e_name_len == 0 || entry->e_name_index != 0)) || |
Theodore Ts'o | 0684a4f | 2002-08-17 10:19:44 -0400 | [diff] [blame] | 1644 | (ctx->ext_attr_ver == 2 && |
Theodore Ts'o | 0d63467 | 2002-05-22 00:22:38 -0400 | [diff] [blame] | 1645 | entry->e_name_index == 0)) { |
Theodore Ts'o | 55fd07e | 2001-07-19 16:31:25 -0400 | [diff] [blame] | 1646 | if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx)) |
| 1647 | goto clear_extattr; |
Andreas Dilger | fefaef3 | 2008-02-02 01:16:32 -0700 | [diff] [blame] | 1648 | break; |
Theodore Ts'o | 55fd07e | 2001-07-19 16:31:25 -0400 | [diff] [blame] | 1649 | } |
| 1650 | if (entry->e_value_block != 0) { |
| 1651 | if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx)) |
| 1652 | goto clear_extattr; |
| 1653 | } |
Andreas Dilger | a34c6ff | 2007-06-22 02:22:38 -0400 | [diff] [blame] | 1654 | 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'o | 14fe1c3 | 2001-07-25 19:48:24 -0400 | [diff] [blame] | 1659 | if (entry->e_value_size && |
| 1660 | region_allocate(region, entry->e_value_offs, |
| 1661 | EXT2_EXT_ATTR_SIZE(entry->e_value_size))) { |
Theodore Ts'o | 55fd07e | 2001-07-19 16:31:25 -0400 | [diff] [blame] | 1662 | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) |
| 1663 | goto clear_extattr; |
| 1664 | } |
Andreas Dilger | fefaef3 | 2008-02-02 01:16:32 -0700 | [diff] [blame] | 1665 | |
| 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'o | 55fd07e | 2001-07-19 16:31:25 -0400 | [diff] [blame] | 1676 | 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'o | 342d847 | 2001-07-02 11:54:09 -0400 | [diff] [blame] | 1683 | |
| 1684 | count = header->h_refcount - 1; |
| 1685 | if (count) |
| 1686 | ea_refcount_store(ctx->refcount, blk, count); |
| 1687 | mark_block_used(ctx, blk); |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1688 | ext2fs_fast_mark_block_bitmap2(ctx->block_ea_map, blk); |
Theodore Ts'o | 342d847 | 2001-07-02 11:54:09 -0400 | [diff] [blame] | 1689 | return 1; |
| 1690 | |
| 1691 | clear_extattr: |
Brian Behlendorf | 5469d76 | 2007-03-28 11:41:40 -0400 | [diff] [blame] | 1692 | if (region) |
| 1693 | region_free(region); |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1694 | ext2fs_file_acl_block_set(fs, inode, 0); |
Theodore Ts'o | 342d847 | 2001-07-02 11:54:09 -0400 | [diff] [blame] | 1695 | e2fsck_write_inode(ctx, ino, inode, "check_ext_attr"); |
| 1696 | return 0; |
| 1697 | } |
| 1698 | |
Theodore Ts'o | 503f9e7 | 2002-06-26 16:52:10 -0400 | [diff] [blame] | 1699 | /* Returns 1 if bad htree, 0 if OK */ |
| 1700 | static int handle_htree(e2fsck_t ctx, struct problem_context *pctx, |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1701 | ext2_ino_t ino, struct ext2_inode *inode, |
Theodore Ts'o | 503f9e7 | 2002-06-26 16:52:10 -0400 | [diff] [blame] | 1702 | char *block_buf) |
| 1703 | { |
| 1704 | struct ext2_dx_root_info *root; |
| 1705 | ext2_filsys fs = ctx->fs; |
| 1706 | errcode_t retval; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1707 | blk64_t blk; |
Theodore Ts'o | 503f9e7 | 2002-06-26 16:52:10 -0400 | [diff] [blame] | 1708 | |
| 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1715 | pctx->errcode = ext2fs_bmap2(fs, ino, inode, 0, 0, 0, 0, &blk); |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1716 | |
| 1717 | if ((pctx->errcode) || |
| 1718 | (blk == 0) || |
| 1719 | (blk < fs->super->s_first_data_block) || |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1720 | (blk >= ext2fs_blocks_count(fs->super))) { |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1721 | if (fix_problem(ctx, PR_1_HTREE_BADROOT, pctx)) |
| 1722 | return 1; |
| 1723 | else |
| 1724 | return 0; |
| 1725 | } |
Theodore Ts'o | 503f9e7 | 2002-06-26 16:52:10 -0400 | [diff] [blame] | 1726 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1727 | retval = io_channel_read_blk64(fs->io, blk, 1, block_buf); |
Theodore Ts'o | 503f9e7 | 2002-06-26 16:52:10 -0400 | [diff] [blame] | 1728 | if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx)) |
| 1729 | return 1; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1730 | |
Theodore Ts'o | 503f9e7 | 2002-06-26 16:52:10 -0400 | [diff] [blame] | 1731 | /* 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'o | f044b4d | 2002-08-17 13:32:21 -0400 | [diff] [blame] | 1741 | (root->hash_version != EXT2_HASH_TEA) && |
Theodore Ts'o | 503f9e7 | 2002-06-26 16:52:10 -0400 | [diff] [blame] | 1742 | fix_problem(ctx, PR_1_HTREE_HASHV, pctx)) |
| 1743 | return 1; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1744 | |
Theodore Ts'o | 503f9e7 | 2002-06-26 16:52:10 -0400 | [diff] [blame] | 1745 | 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'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 1753 | |
Theodore Ts'o | 503f9e7 | 2002-06-26 16:52:10 -0400 | [diff] [blame] | 1754 | return 0; |
| 1755 | } |
Theodore Ts'o | 342d847 | 2001-07-02 11:54:09 -0400 | [diff] [blame] | 1756 | |
Theodore Ts'o | e3df15a | 2007-09-15 14:10:47 -0400 | [diff] [blame] | 1757 | void 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'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1761 | inode->i_flags = 0; |
Theodore Ts'o | e3df15a | 2007-09-15 14:10:47 -0400 | [diff] [blame] | 1762 | inode->i_links_count = 0; |
| 1763 | ext2fs_icount_store(ctx->inode_link_info, ino, 0); |
| 1764 | inode->i_dtime = ctx->now; |
| 1765 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1766 | ext2fs_unmark_inode_bitmap2(ctx->inode_dir_map, ino); |
| 1767 | ext2fs_unmark_inode_bitmap2(ctx->inode_used_map, ino); |
Theodore Ts'o | e3df15a | 2007-09-15 14:10:47 -0400 | [diff] [blame] | 1768 | if (ctx->inode_reg_map) |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1769 | ext2fs_unmark_inode_bitmap2(ctx->inode_reg_map, ino); |
Theodore Ts'o | e3df15a | 2007-09-15 14:10:47 -0400 | [diff] [blame] | 1770 | if (ctx->inode_bad_map) |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1771 | ext2fs_unmark_inode_bitmap2(ctx->inode_bad_map, ino); |
Theodore Ts'o | e3df15a | 2007-09-15 14:10:47 -0400 | [diff] [blame] | 1772 | |
| 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1779 | if (ino == EXT2_BAD_INO) |
| 1780 | memset(inode, 0, sizeof(struct ext2_inode)); |
| 1781 | |
Theodore Ts'o | e3df15a | 2007-09-15 14:10:47 -0400 | [diff] [blame] | 1782 | e2fsck_write_inode(ctx, ino, inode, source); |
| 1783 | } |
| 1784 | |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1785 | static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx, |
Theodore Ts'o | d5a8f9a | 2008-06-02 20:12:34 -0400 | [diff] [blame] | 1786 | struct process_block_struct *pb, |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1787 | blk64_t start_block, blk64_t end_block, |
| 1788 | blk64_t eof_block, |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1789 | ext2_extent_handle_t ehandle) |
| 1790 | { |
| 1791 | struct ext2fs_extent extent; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1792 | blk64_t blk, last_lblk; |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1793 | e2_blkcnt_t blockcnt; |
Theodore Ts'o | 2acad6b | 2008-06-07 11:04:10 -0400 | [diff] [blame] | 1794 | unsigned int i; |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1795 | int is_dir, is_leaf; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1796 | problem_t problem; |
Theodore Ts'o | 11de926 | 2008-05-30 15:23:24 -0400 | [diff] [blame] | 1797 | struct ext2_extent_info info; |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1798 | |
Theodore Ts'o | 11de926 | 2008-05-30 15:23:24 -0400 | [diff] [blame] | 1799 | pctx->errcode = ext2fs_extent_get_info(ehandle, &info); |
| 1800 | if (pctx->errcode) |
| 1801 | return; |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1802 | |
| 1803 | pctx->errcode = ext2fs_extent_get(ehandle, EXT2_EXTENT_FIRST_SIB, |
| 1804 | &extent); |
Theodore Ts'o | 11de926 | 2008-05-30 15:23:24 -0400 | [diff] [blame] | 1805 | while (!pctx->errcode && info.num_entries-- > 0) { |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1806 | is_leaf = extent.e_flags & EXT2_EXTENT_FLAGS_LEAF; |
| 1807 | is_dir = LINUX_S_ISDIR(pctx->inode->i_mode); |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1808 | last_lblk = extent.e_lblk + extent.e_len - 1; |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1809 | |
| 1810 | problem = 0; |
Theodore Ts'o | e6238d3 | 2010-05-14 18:03:14 -0400 | [diff] [blame] | 1811 | if (extent.e_pblk == 0 || |
| 1812 | extent.e_pblk < ctx->fs->super->s_first_data_block || |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1813 | extent.e_pblk >= ext2fs_blocks_count(ctx->fs->super)) |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1814 | problem = PR_1_EXTENT_BAD_START_BLK; |
Theodore Ts'o | d5a8f9a | 2008-06-02 20:12:34 -0400 | [diff] [blame] | 1815 | else if (extent.e_lblk < start_block) |
| 1816 | problem = PR_1_OUT_OF_ORDER_EXTENTS; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1817 | 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 Sandeen | 7a1eac2 | 2008-04-01 20:38:58 -0500 | [diff] [blame] | 1823 | else if (is_leaf && |
| 1824 | (extent.e_pblk + extent.e_len) > |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1825 | ext2fs_blocks_count(ctx->fs->super)) |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1826 | problem = PR_1_EXTENT_ENDS_BEYOND; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1827 | 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'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1831 | |
| 1832 | if (problem) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1833 | report_problem: |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1834 | pctx->blk = extent.e_pblk; |
| 1835 | pctx->blk2 = extent.e_lblk; |
| 1836 | pctx->num = extent.e_len; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1837 | pctx->blkcount = extent.e_lblk + extent.e_len; |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1838 | if (fix_problem(ctx, problem, pctx)) { |
Theodore Ts'o | 19f433a | 2010-03-17 13:32:52 -0400 | [diff] [blame] | 1839 | e2fsck_read_bitmaps(ctx); |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1840 | pctx->errcode = |
| 1841 | ext2fs_extent_delete(ehandle, 0); |
| 1842 | if (pctx->errcode) { |
Theodore Ts'o | 7518c17 | 2008-12-25 22:42:38 -0500 | [diff] [blame] | 1843 | pctx->str = "ext2fs_extent_delete"; |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1844 | return; |
| 1845 | } |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1846 | ext2fs_extent_fix_parents(ehandle); |
Theodore Ts'o | 73e5abc | 2008-05-28 04:54:44 -0400 | [diff] [blame] | 1847 | 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'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1855 | } |
| 1856 | goto next; |
| 1857 | } |
| 1858 | |
| 1859 | if (!is_leaf) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1860 | blk64_t lblk = extent.e_lblk; |
| 1861 | |
Theodore Ts'o | 7518c17 | 2008-12-25 22:42:38 -0500 | [diff] [blame] | 1862 | blk = extent.e_pblk; |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1863 | pctx->errcode = ext2fs_extent_get(ehandle, |
| 1864 | EXT2_EXTENT_DOWN, &extent); |
| 1865 | if (pctx->errcode) { |
Theodore Ts'o | 7518c17 | 2008-12-25 22:42:38 -0500 | [diff] [blame] | 1866 | 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'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1871 | } |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1872 | /* 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'o | 7518c17 | 2008-12-25 22:42:38 -0500 | [diff] [blame] | 1886 | if (pctx->errcode) |
| 1887 | return; |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1888 | pctx->errcode = ext2fs_extent_get(ehandle, |
| 1889 | EXT2_EXTENT_UP, &extent); |
| 1890 | if (pctx->errcode) { |
Theodore Ts'o | 7518c17 | 2008-12-25 22:42:38 -0500 | [diff] [blame] | 1891 | pctx->str = "EXT2_EXTENT_UP"; |
| 1892 | return; |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1893 | } |
Theodore Ts'o | 7518c17 | 2008-12-25 22:42:38 -0500 | [diff] [blame] | 1894 | mark_block_used(ctx, blk); |
| 1895 | pb->num_blocks++; |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1896 | goto next; |
| 1897 | } |
| 1898 | |
Theodore Ts'o | 63b5e35 | 2008-08-10 22:43:24 -0400 | [diff] [blame] | 1899 | if ((pb->previous_block != 0) && |
| 1900 | (pb->previous_block+1 != extent.e_pblk)) { |
Theodore Ts'o | 100d470 | 2008-12-08 22:00:13 -0500 | [diff] [blame] | 1901 | 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'o | 63b5e35 | 2008-08-10 22:43:24 -0400 | [diff] [blame] | 1911 | "phys %6lu log %lu len %lu\n"), |
Theodore Ts'o | 100d470 | 2008-12-08 22:00:13 -0500 | [diff] [blame] | 1912 | (unsigned long) pctx->ino, type, |
Theodore Ts'o | 63b5e35 | 2008-08-10 22:43:24 -0400 | [diff] [blame] | 1913 | (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'o | 100d470 | 2008-12-08 22:00:13 -0500 | [diff] [blame] | 1917 | } |
Theodore Ts'o | 63b5e35 | 2008-08-10 22:43:24 -0400 | [diff] [blame] | 1918 | pb->fragmented = 1; |
| 1919 | } |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1920 | 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'o | 4607ef7 | 2009-11-29 00:06:10 -0500 | [diff] [blame] | 1925 | if (pctx->errcode) { |
| 1926 | pctx->blk = 0; |
| 1927 | pctx->num = pb->last_db_block; |
| 1928 | goto failed_add_dir_block; |
| 1929 | } |
| 1930 | } |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1931 | 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'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1935 | for (blk = extent.e_pblk, blockcnt = extent.e_lblk, i = 0; |
| 1936 | i < extent.e_len; |
| 1937 | blk++, blockcnt++, i++) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1938 | 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'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1949 | |
| 1950 | if (is_dir) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1951 | pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist, pctx->ino, blk, blockcnt); |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1952 | if (pctx->errcode) { |
| 1953 | pctx->blk = blk; |
| 1954 | pctx->num = blockcnt; |
Theodore Ts'o | 4607ef7 | 2009-11-29 00:06:10 -0500 | [diff] [blame] | 1955 | failed_add_dir_block: |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1956 | 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'o | 4607ef7 | 2009-11-29 00:06:10 -0500 | [diff] [blame] | 1963 | if (is_dir && extent.e_len > 0) |
| 1964 | pb->last_db_block = blockcnt - 1; |
Theodore Ts'o | 63b5e35 | 2008-08-10 22:43:24 -0400 | [diff] [blame] | 1965 | pb->previous_block = extent.e_pblk + extent.e_len - 1; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1966 | 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'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1970 | 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 | |
| 1979 | static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx, |
Theodore Ts'o | 2acad6b | 2008-06-07 11:04:10 -0400 | [diff] [blame] | 1980 | struct process_block_struct *pb) |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1981 | { |
Theodore Ts'o | 8da6d1a | 2008-08-14 09:48:07 -0400 | [diff] [blame] | 1982 | struct ext2_extent_info info; |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1983 | 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'o | 8da6d1a | 2008-08-14 09:48:07 -0400 | [diff] [blame] | 1987 | errcode_t retval; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 1988 | blk64_t eof_lblk; |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1989 | |
number9652 | 84b239a | 2009-05-19 13:34:12 -0700 | [diff] [blame] | 1990 | pctx->errcode = ext2fs_extent_open2(fs, ino, inode, &ehandle); |
Theodore Ts'o | 0a68b18 | 2009-05-17 08:42:52 -0400 | [diff] [blame] | 1991 | 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'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 1995 | pctx->errcode = 0; |
| 1996 | return; |
| 1997 | } |
| 1998 | |
Theodore Ts'o | 8da6d1a | 2008-08-14 09:48:07 -0400 | [diff] [blame] | 1999 | 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2006 | 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'o | 7518c17 | 2008-12-25 22:42:38 -0500 | [diff] [blame] | 2009 | 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'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 2017 | ext2fs_extent_free(ehandle); |
| 2018 | } |
| 2019 | |
Theodore Ts'o | 342d847 | 2001-07-02 11:54:09 -0400 | [diff] [blame] | 2020 | /* |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2021 | * This subroutine is called on each inode to account for all of the |
| 2022 | * blocks used by that inode. |
| 2023 | */ |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2024 | static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2025 | char *block_buf) |
| 2026 | { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2027 | ext2_filsys fs = ctx->fs; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2028 | struct process_block_struct pb; |
Theodore Ts'o | 86c627e | 2001-01-11 15:12:14 +0000 | [diff] [blame] | 2029 | ext2_ino_t ino = pctx->ino; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2030 | struct ext2_inode *inode = pctx->inode; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2031 | unsigned bad_size = 0; |
Theodore Ts'o | 503f9e7 | 2002-06-26 16:52:10 -0400 | [diff] [blame] | 2032 | int dirty_inode = 0; |
Eric Sandeen | 7c1e090 | 2008-07-06 23:02:47 -0500 | [diff] [blame] | 2033 | int extent_fs; |
Theodore Ts'o | 246501c | 1998-03-24 16:22:38 +0000 | [diff] [blame] | 2034 | __u64 size; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2035 | |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2036 | pb.ino = ino; |
Theodore Ts'o | 0684a4f | 2002-08-17 10:19:44 -0400 | [diff] [blame] | 2037 | pb.num_blocks = 0; |
| 2038 | pb.last_block = -1; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2039 | pb.last_init_lblock = -1; |
Theodore Ts'o | 4dbe79b | 2009-11-28 09:35:37 -0500 | [diff] [blame] | 2040 | pb.last_db_block = -1; |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2041 | pb.num_illegal_blocks = 0; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2042 | pb.suppress = 0; pb.clear = 0; |
Theodore Ts'o | 74becf3 | 1997-04-26 14:37:06 +0000 | [diff] [blame] | 2043 | pb.fragmented = 0; |
Theodore Ts'o | 1917875 | 2000-02-11 15:55:07 +0000 | [diff] [blame] | 2044 | pb.compressed = 0; |
Theodore Ts'o | 74becf3 | 1997-04-26 14:37:06 +0000 | [diff] [blame] | 2045 | pb.previous_block = 0; |
Andreas Dilger | b94a052 | 2002-05-18 13:16:30 -0600 | [diff] [blame] | 2046 | pb.is_dir = LINUX_S_ISDIR(inode->i_mode); |
Theodore Ts'o | da30704 | 2002-05-21 21:19:14 -0400 | [diff] [blame] | 2047 | pb.is_reg = LINUX_S_ISREG(inode->i_mode); |
| 2048 | pb.max_blocks = 1 << (31 - fs->super->s_log_block_size); |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2049 | pb.inode = inode; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2050 | pb.pctx = pctx; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2051 | pb.ctx = ctx; |
| 2052 | pctx->ino = ino; |
Theodore Ts'o | 0684a4f | 2002-08-17 10:19:44 -0400 | [diff] [blame] | 2053 | pctx->errcode = 0; |
Theodore Ts'o | 1917875 | 2000-02-11 15:55:07 +0000 | [diff] [blame] | 2054 | |
Eric Sandeen | 7c1e090 | 2008-07-06 23:02:47 -0500 | [diff] [blame] | 2055 | extent_fs = (ctx->fs->super->s_feature_incompat & |
| 2056 | EXT3_FEATURE_INCOMPAT_EXTENTS); |
| 2057 | |
Theodore Ts'o | 1917875 | 2000-02-11 15:55:07 +0000 | [diff] [blame] | 2058 | if (inode->i_flags & EXT2_COMPRBLK_FL) { |
Theodore Ts'o | f5ae75e | 2001-01-01 14:52:52 +0000 | [diff] [blame] | 2059 | if (fs->super->s_feature_incompat & |
| 2060 | EXT2_FEATURE_INCOMPAT_COMPRESSION) |
Theodore Ts'o | 1917875 | 2000-02-11 15:55:07 +0000 | [diff] [blame] | 2061 | pb.compressed = 1; |
| 2062 | else { |
| 2063 | if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) { |
| 2064 | inode->i_flags &= ~EXT2_COMPRBLK_FL; |
Theodore Ts'o | 503f9e7 | 2002-06-26 16:52:10 -0400 | [diff] [blame] | 2065 | dirty_inode++; |
Theodore Ts'o | 1917875 | 2000-02-11 15:55:07 +0000 | [diff] [blame] | 2066 | } |
| 2067 | } |
| 2068 | } |
| 2069 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2070 | if (ext2fs_file_acl_block(fs, inode) && |
| 2071 | check_ext_attr(ctx, pctx, block_buf)) { |
Andreas Dilger | fefaef3 | 2008-02-02 01:16:32 -0700 | [diff] [blame] | 2072 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| 2073 | goto out; |
Theodore Ts'o | dc71f23 | 2005-03-20 16:57:10 -0500 | [diff] [blame] | 2074 | pb.num_blocks++; |
Andreas Dilger | fefaef3 | 2008-02-02 01:16:32 -0700 | [diff] [blame] | 2075 | } |
Theodore Ts'o | dc71f23 | 2005-03-20 16:57:10 -0500 | [diff] [blame] | 2076 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2077 | if (ext2fs_inode_has_valid_blocks2(fs, inode)) { |
Eric Sandeen | 7c1e090 | 2008-07-06 23:02:47 -0500 | [diff] [blame] | 2078 | if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) |
Theodore Ts'o | 2acad6b | 2008-06-07 11:04:10 -0400 | [diff] [blame] | 2079 | check_blocks_extents(ctx, pctx, &pb); |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2080 | else { |
| 2081 | pctx->errcode = ext2fs_block_iterate3(fs, ino, |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 2082 | pb.is_dir ? BLOCK_FLAG_HOLE : 0, |
| 2083 | block_buf, process_block, &pb); |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2084 | /* |
| 2085 | * We do not have uninitialized extents in non extent |
| 2086 | * files. |
| 2087 | */ |
| 2088 | pb.last_init_lblock = pb.last_block; |
| 2089 | } |
Theodore Ts'o | 15d482b | 2007-08-20 21:31:11 -0400 | [diff] [blame] | 2090 | } |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2091 | end_problem_latch(ctx, PR_LATCH_BLOCK); |
Theodore Ts'o | da30704 | 2002-05-21 21:19:14 -0400 | [diff] [blame] | 2092 | end_problem_latch(ctx, PR_LATCH_TOOBIG); |
Theodore Ts'o | 0684a4f | 2002-08-17 10:19:44 -0400 | [diff] [blame] | 2093 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
| 2094 | goto out; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2095 | if (pctx->errcode) |
| 2096 | fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2097 | |
Theodore Ts'o | ce44d8c | 2008-12-08 21:33:11 -0500 | [diff] [blame] | 2098 | 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'o | 74becf3 | 1997-04-26 14:37:06 +0000 | [diff] [blame] | 2104 | |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2105 | if (pb.clear) { |
Theodore Ts'o | e3df15a | 2007-09-15 14:10:47 -0400 | [diff] [blame] | 2106 | e2fsck_clear_inode(ctx, ino, inode, E2F_FLAG_RESTART, |
| 2107 | "check_blocks"); |
| 2108 | return; |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2109 | } |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2110 | |
Theodore Ts'o | 8fdc998 | 2002-06-25 23:26:34 -0400 | [diff] [blame] | 2111 | if (inode->i_flags & EXT2_INDEX_FL) { |
Theodore Ts'o | 503f9e7 | 2002-06-26 16:52:10 -0400 | [diff] [blame] | 2112 | if (handle_htree(ctx, pctx, ino, inode, block_buf)) { |
| 2113 | inode->i_flags &= ~EXT2_INDEX_FL; |
| 2114 | dirty_inode++; |
| 2115 | } else { |
Theodore Ts'o | 8fdc998 | 2002-06-25 23:26:34 -0400 | [diff] [blame] | 2116 | #ifdef ENABLE_HTREE |
| 2117 | e2fsck_add_dx_dir(ctx, ino, pb.last_block+1); |
| 2118 | #endif |
Theodore Ts'o | 503f9e7 | 2002-06-26 16:52:10 -0400 | [diff] [blame] | 2119 | } |
Theodore Ts'o | 8fdc998 | 2002-06-25 23:26:34 -0400 | [diff] [blame] | 2120 | } |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2121 | |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2122 | if (!pb.num_blocks && pb.is_dir) { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2123 | if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) { |
Theodore Ts'o | e3df15a | 2007-09-15 14:10:47 -0400 | [diff] [blame] | 2124 | e2fsck_clear_inode(ctx, ino, inode, 0, "check_blocks"); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2125 | ctx->fs_directory_count--; |
Theodore Ts'o | e3df15a | 2007-09-15 14:10:47 -0400 | [diff] [blame] | 2126 | return; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2127 | } |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2128 | } |
Theodore Ts'o | 0684a4f | 2002-08-17 10:19:44 -0400 | [diff] [blame] | 2129 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2130 | 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'o | 1ca1059 | 2008-04-09 11:39:11 -0400 | [diff] [blame] | 2136 | 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2140 | pb.num_blocks *= EXT2FS_CLUSTER_RATIO(fs); |
Theodore Ts'o | 0684a4f | 2002-08-17 10:19:44 -0400 | [diff] [blame] | 2141 | #if 0 |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2142 | 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'o | 0684a4f | 2002-08-17 10:19:44 -0400 | [diff] [blame] | 2144 | pb.num_blocks); |
| 2145 | #endif |
Theodore Ts'o | 246501c | 1998-03-24 16:22:38 +0000 | [diff] [blame] | 2146 | if (pb.is_dir) { |
| 2147 | int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2148 | if (inode->i_size & (fs->blocksize - 1)) |
Theodore Ts'o | 2cd1233 | 2008-03-13 00:58:54 -0400 | [diff] [blame] | 2149 | bad_size = 5; |
| 2150 | else if (nblock > (pb.last_block + 1)) |
Theodore Ts'o | 246501c | 1998-03-24 16:22:38 +0000 | [diff] [blame] | 2151 | bad_size = 1; |
| 2152 | else if (nblock < (pb.last_block + 1)) { |
Theodore Ts'o | 246501c | 1998-03-24 16:22:38 +0000 | [diff] [blame] | 2153 | if (((pb.last_block + 1) - nblock) > |
Theodore Ts'o | 5dd8f96 | 2001-01-01 15:51:50 +0000 | [diff] [blame] | 2154 | fs->super->s_prealloc_dir_blocks) |
Theodore Ts'o | 9d1bd3d | 1998-06-10 20:45:22 +0000 | [diff] [blame] | 2155 | bad_size = 2; |
Theodore Ts'o | 246501c | 1998-03-24 16:22:38 +0000 | [diff] [blame] | 2156 | } |
| 2157 | } else { |
Theodore Ts'o | 9f0288d | 2007-08-03 20:43:37 -0400 | [diff] [blame] | 2158 | e2_blkcnt_t blkpg = ctx->blocks_per_page; |
| 2159 | |
Theodore Ts'o | 4f48928 | 2003-01-22 18:28:15 -0500 | [diff] [blame] | 2160 | size = EXT2_I_SIZE(inode); |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2161 | if ((pb.last_init_lblock >= 0) && |
Theodore Ts'o | 9f0288d | 2007-08-03 20:43:37 -0400 | [diff] [blame] | 2162 | /* allow allocated blocks to end of PAGE_SIZE */ |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2163 | (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'o | 9d1bd3d | 1998-06-10 20:45:22 +0000 | [diff] [blame] | 2167 | bad_size = 3; |
Eric Sandeen | 7c1e090 | 2008-07-06 23:02:47 -0500 | [diff] [blame] | 2168 | 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'o | 9d1bd3d | 1998-06-10 20:45:22 +0000 | [diff] [blame] | 2171 | bad_size = 4; |
Eric Sandeen | 7c1e090 | 2008-07-06 23:02:47 -0500 | [diff] [blame] | 2172 | else if ((extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) && |
Theodore Ts'o | 3ec7be4 | 2008-08-17 09:41:38 -0400 | [diff] [blame] | 2173 | size > |
Theodore Ts'o | 03fa6f8 | 2008-11-16 10:03:00 -0500 | [diff] [blame] | 2174 | ((1ULL << (32 + EXT2_BLOCK_SIZE_BITS(fs->super))) - 1)) |
Eric Sandeen | 7c1e090 | 2008-07-06 23:02:47 -0500 | [diff] [blame] | 2175 | /* too big for an extent-based file - 32bit ee_block */ |
| 2176 | bad_size = 6; |
Theodore Ts'o | 246501c | 1998-03-24 16:22:38 +0000 | [diff] [blame] | 2177 | } |
Theodore Ts'o | 0684a4f | 2002-08-17 10:19:44 -0400 | [diff] [blame] | 2178 | /* i_size for symlinks is checked elsewhere */ |
| 2179 | if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) { |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2180 | pctx->num = (pb.last_block+1) * fs->blocksize; |
Theodore Ts'o | 3ec7be4 | 2008-08-17 09:41:38 -0400 | [diff] [blame] | 2181 | pctx->group = bad_size; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2182 | if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) { |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2183 | inode->i_size = pctx->num; |
Theodore Ts'o | 0684a4f | 2002-08-17 10:19:44 -0400 | [diff] [blame] | 2184 | if (!LINUX_S_ISDIR(inode->i_mode)) |
Theodore Ts'o | 246501c | 1998-03-24 16:22:38 +0000 | [diff] [blame] | 2185 | inode->i_size_high = pctx->num >> 32; |
Theodore Ts'o | 503f9e7 | 2002-06-26 16:52:10 -0400 | [diff] [blame] | 2186 | dirty_inode++; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2187 | } |
| 2188 | pctx->num = 0; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2189 | } |
Darrick J. Wong | 3b6c093 | 2013-12-10 17:18:27 -0800 | [diff] [blame] | 2190 | if (LINUX_S_ISREG(inode->i_mode) && |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2191 | ext2fs_needs_large_file_feature(EXT2_I_SIZE(inode))) |
Theodore Ts'o | 246501c | 1998-03-24 16:22:38 +0000 | [diff] [blame] | 2192 | ctx->large_files++; |
Theodore Ts'o | 8a8f365 | 2009-10-12 21:59:37 -0400 | [diff] [blame] | 2193 | if ((pb.num_blocks != ext2fs_inode_i_blocks(fs, inode)) || |
Theodore Ts'o | 1ca1059 | 2008-04-09 11:39:11 -0400 | [diff] [blame] | 2194 | ((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'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2198 | pctx->num = pb.num_blocks; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2199 | if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) { |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2200 | inode->i_blocks = pb.num_blocks; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2201 | inode->osd2.linux2.l_i_blocks_hi = pb.num_blocks >> 32; |
Theodore Ts'o | 503f9e7 | 2002-06-26 16:52:10 -0400 | [diff] [blame] | 2202 | dirty_inode++; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2203 | } |
| 2204 | pctx->num = 0; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2205 | } |
Theodore Ts'o | a49249d | 2009-11-28 09:44:08 -0500 | [diff] [blame] | 2206 | |
| 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'o | 503f9e7 | 2002-06-26 16:52:10 -0400 | [diff] [blame] | 2212 | out: |
| 2213 | if (dirty_inode) |
| 2214 | e2fsck_write_inode(ctx, ino, inode, "check_blocks"); |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2215 | } |
| 2216 | |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2217 | #if 0 |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2218 | /* |
| 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2222 | static char *describe_illegal_block(ext2_filsys fs, blk64_t block) |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2223 | { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2224 | blk64_t super; |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2225 | 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2233 | } else if (block >= ext2fs_blocks_count(fs->super)) { |
| 2234 | sprintf(problem, "> BLOCKS (%u)", ext2fs_blocks_count(fs->super)); |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2235 | 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2248 | if (block == ext2fs_block_bitmap_loc(fs, i)) { |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2249 | sprintf(problem, "is the block bitmap of group %d", i); |
| 2250 | break; |
| 2251 | } |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2252 | if (block == ext2fs_inode_bitmap_loc(fs, i)) { |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2253 | sprintf(problem, "is the inode bitmap of group %d", i); |
| 2254 | break; |
| 2255 | } |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2256 | if (block >= ext2fs_inode_table_loc(fs, i) && |
| 2257 | (block < ext2fs_inode_table_loc(fs, i) |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2258 | + 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'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2267 | #endif |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2268 | |
| 2269 | /* |
| 2270 | * This is a helper function for check_blocks(). |
| 2271 | */ |
Theodore Ts'o | 53ef44c | 2001-01-06 05:55:58 +0000 | [diff] [blame] | 2272 | static int process_block(ext2_filsys fs, |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2273 | blk64_t *block_nr, |
Theodore Ts'o | 9d1bd3d | 1998-06-10 20:45:22 +0000 | [diff] [blame] | 2274 | e2_blkcnt_t blockcnt, |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2275 | blk64_t ref_block EXT2FS_ATTR((unused)), |
Theodore Ts'o | 5443492 | 2003-12-07 01:28:50 -0500 | [diff] [blame] | 2276 | int ref_offset EXT2FS_ATTR((unused)), |
Theodore Ts'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 2277 | void *priv_data) |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2278 | { |
| 2279 | struct process_block_struct *p; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2280 | struct problem_context *pctx; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2281 | blk64_t blk = *block_nr; |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2282 | int ret_code = 0; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2283 | problem_t problem = 0; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2284 | e2fsck_t ctx; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2285 | |
Theodore Ts'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 2286 | p = (struct process_block_struct *) priv_data; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2287 | pctx = p->pctx; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2288 | ctx = p->ctx; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2289 | |
Theodore Ts'o | 1917875 | 2000-02-11 15:55:07 +0000 | [diff] [blame] | 2290 | 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 Dilger | b94a052 | 2002-05-18 13:16:30 -0600 | [diff] [blame] | 2311 | |
Theodore Ts'o | 4dbe79b | 2009-11-28 09:35:37 -0500 | [diff] [blame] | 2312 | if (blk == 0) |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2313 | return 0; |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2314 | |
| 2315 | #if 0 |
| 2316 | printf("Process_block, inode %lu, block %u, #%d\n", p->ino, blk, |
| 2317 | blockcnt); |
| 2318 | #endif |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2319 | |
Theodore Ts'o | 74becf3 | 1997-04-26 14:37:06 +0000 | [diff] [blame] | 2320 | /* |
| 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'o | 63b5e35 | 2008-08-10 22:43:24 -0400 | [diff] [blame] | 2325 | if (!HOLE_BLKADDR(p->previous_block) && p->ino != EXT2_RESIZE_INO) { |
| 2326 | if (p->previous_block+1 != blk) { |
Theodore Ts'o | 100d470 | 2008-12-08 22:00:13 -0500 | [diff] [blame] | 2327 | 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'o | 63b5e35 | 2008-08-10 22:43:24 -0400 | [diff] [blame] | 2338 | (unsigned long) p->previous_block+1, |
| 2339 | (unsigned long) blk, |
Theodore Ts'o | f4e2c99 | 2008-08-12 22:11:02 -0400 | [diff] [blame] | 2340 | blockcnt); |
Theodore Ts'o | 100d470 | 2008-12-08 22:00:13 -0500 | [diff] [blame] | 2341 | } |
Theodore Ts'o | 74becf3 | 1997-04-26 14:37:06 +0000 | [diff] [blame] | 2342 | p->fragmented = 1; |
Theodore Ts'o | 63b5e35 | 2008-08-10 22:43:24 -0400 | [diff] [blame] | 2343 | } |
Theodore Ts'o | 74becf3 | 1997-04-26 14:37:06 +0000 | [diff] [blame] | 2344 | } |
Theodore Ts'o | 503f9e7 | 2002-06-26 16:52:10 -0400 | [diff] [blame] | 2345 | |
Theodore Ts'o | 8421fb6 | 2004-07-26 20:11:49 -0400 | [diff] [blame] | 2346 | if (p->is_dir && blockcnt > (1 << (21 - fs->super->s_log_block_size))) |
Theodore Ts'o | da30704 | 2002-05-21 21:19:14 -0400 | [diff] [blame] | 2347 | 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'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2352 | |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2353 | if (blk < fs->super->s_first_data_block || |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2354 | blk >= ext2fs_blocks_count(fs->super)) |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2355 | problem = PR_1_ILLEGAL_BLOCK_NUM; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2356 | |
| 2357 | if (problem) { |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2358 | p->num_illegal_blocks++; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2359 | if (!p->suppress && (p->num_illegal_blocks % 12) == 0) { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2360 | if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) { |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2361 | p->clear = 1; |
| 2362 | return BLOCK_ABORT; |
| 2363 | } |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 2364 | if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) { |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2365 | p->suppress = 1; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2366 | set_latch_flags(PR_LATCH_BLOCK, |
| 2367 | PRL_SUPPRESS, 0); |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2368 | } |
| 2369 | } |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2370 | pctx->blk = blk; |
| 2371 | pctx->blkcount = blockcnt; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2372 | if (fix_problem(ctx, problem, pctx)) { |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2373 | blk = *block_nr = 0; |
| 2374 | ret_code = BLOCK_CHANGED; |
| 2375 | goto mark_dir; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2376 | } else |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2377 | return 0; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2378 | } |
| 2379 | |
Theodore Ts'o | d323f8f | 2004-12-15 14:39:16 -0500 | [diff] [blame] | 2380 | if (p->ino == EXT2_RESIZE_INO) { |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2381 | /* |
Theodore Ts'o | c3ffaf8 | 2004-12-24 01:42:22 -0500 | [diff] [blame] | 2382 | * 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'o | d323f8f | 2004-12-15 14:39:16 -0500 | [diff] [blame] | 2389 | mark_block_used(ctx, blk); |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2390 | 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'o | d323f8f | 2004-12-15 14:39:16 -0500 | [diff] [blame] | 2397 | mark_block_used(ctx, blk); |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2398 | p->num_blocks++; |
| 2399 | } |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 2400 | if (blockcnt >= 0) |
| 2401 | p->last_block = blockcnt; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2402 | p->previous_block = blk; |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2403 | mark_dir: |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 2404 | if (p->is_dir && (blockcnt >= 0)) { |
Theodore Ts'o | 4dbe79b | 2009-11-28 09:35:37 -0500 | [diff] [blame] | 2405 | while (++p->last_db_block < blockcnt) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2406 | pctx->errcode = ext2fs_add_dir_block2(fs->dblist, |
| 2407 | p->ino, 0, |
| 2408 | p->last_db_block); |
Theodore Ts'o | 4dbe79b | 2009-11-28 09:35:37 -0500 | [diff] [blame] | 2409 | if (pctx->errcode) { |
| 2410 | pctx->blk = 0; |
| 2411 | pctx->num = p->last_db_block; |
| 2412 | goto failed_add_dir_block; |
| 2413 | } |
| 2414 | } |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2415 | pctx->errcode = ext2fs_add_dir_block2(fs->dblist, p->ino, |
| 2416 | blk, blockcnt); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2417 | if (pctx->errcode) { |
| 2418 | pctx->blk = blk; |
| 2419 | pctx->num = blockcnt; |
Theodore Ts'o | 4dbe79b | 2009-11-28 09:35:37 -0500 | [diff] [blame] | 2420 | failed_add_dir_block: |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2421 | fix_problem(ctx, PR_1_ADD_DBLOCK, pctx); |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 2422 | /* Should never get here */ |
| 2423 | ctx->flags |= E2F_FLAG_ABORT; |
| 2424 | return BLOCK_ABORT; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2425 | } |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2426 | } |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2427 | return ret_code; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2428 | } |
| 2429 | |
Theodore Ts'o | 53ef44c | 2001-01-06 05:55:58 +0000 | [diff] [blame] | 2430 | static int process_bad_block(ext2_filsys fs, |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2431 | blk64_t *block_nr, |
Theodore Ts'o | 9d1bd3d | 1998-06-10 20:45:22 +0000 | [diff] [blame] | 2432 | e2_blkcnt_t blockcnt, |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2433 | blk64_t ref_block EXT2FS_ATTR((unused)), |
Theodore Ts'o | 5443492 | 2003-12-07 01:28:50 -0500 | [diff] [blame] | 2434 | int ref_offset EXT2FS_ATTR((unused)), |
Theodore Ts'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 2435 | void *priv_data) |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2436 | { |
| 2437 | struct process_block_struct *p; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2438 | blk64_t blk = *block_nr; |
| 2439 | blk64_t first_block; |
Theodore Ts'o | 5443492 | 2003-12-07 01:28:50 -0500 | [diff] [blame] | 2440 | dgrp_t i; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2441 | struct problem_context *pctx; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2442 | e2fsck_t ctx; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2443 | |
Theodore Ts'o | 1917875 | 2000-02-11 15:55:07 +0000 | [diff] [blame] | 2444 | /* |
| 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'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2449 | if (!blk) |
| 2450 | return 0; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2451 | |
Theodore Ts'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 2452 | p = (struct process_block_struct *) priv_data; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2453 | ctx = p->ctx; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2454 | pctx = p->pctx; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2455 | |
Theodore Ts'o | f8188ff | 1997-11-14 05:23:04 +0000 | [diff] [blame] | 2456 | pctx->ino = EXT2_BAD_INO; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2457 | pctx->blk = blk; |
| 2458 | pctx->blkcount = blockcnt; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2459 | |
| 2460 | if ((blk < fs->super->s_first_data_block) || |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2461 | (blk >= ext2fs_blocks_count(fs->super))) { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2462 | if (fix_problem(ctx, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) { |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2463 | *block_nr = 0; |
| 2464 | return BLOCK_CHANGED; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2465 | } else |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2466 | return 0; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2467 | } |
| 2468 | |
| 2469 | if (blockcnt < 0) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2470 | if (ext2fs_test_block_bitmap2(p->fs_meta_blocks, blk)) { |
Theodore Ts'o | 000ba40 | 2003-11-21 10:41:58 -0500 | [diff] [blame] | 2471 | p->bbcheck = 1; |
| 2472 | if (fix_problem(ctx, PR_1_BB_FS_BLOCK, pctx)) { |
| 2473 | *block_nr = 0; |
| 2474 | return BLOCK_CHANGED; |
| 2475 | } |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2476 | } else if (ext2fs_test_block_bitmap2(ctx->block_found_map, |
Theodore Ts'o | 000ba40 | 2003-11-21 10:41:58 -0500 | [diff] [blame] | 2477 | blk)) { |
| 2478 | p->bbcheck = 1; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2479 | if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, |
Theodore Ts'o | 000ba40 | 2003-11-21 10:41:58 -0500 | [diff] [blame] | 2480 | pctx)) { |
| 2481 | *block_nr = 0; |
| 2482 | return BLOCK_CHANGED; |
| 2483 | } |
Theodore Ts'o | a02ce9d | 1998-02-24 20:22:23 +0000 | [diff] [blame] | 2484 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 2485 | return BLOCK_ABORT; |
| 2486 | } else |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2487 | mark_block_used(ctx, blk); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2488 | return 0; |
| 2489 | } |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2490 | #if 0 |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2491 | printf ("DEBUG: Marking %u as bad.\n", blk); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2492 | #endif |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2493 | ctx->fs_badblocks_count++; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2494 | /* |
| 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2500 | if (!ext2fs_test_block_bitmap2(ctx->block_found_map, blk)) { |
| 2501 | ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2502 | return 0; |
| 2503 | } |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2504 | /* |
| 2505 | * Try to find the where the filesystem block was used... |
| 2506 | */ |
| 2507 | first_block = fs->super->s_first_data_block; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2508 | |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2509 | for (i = 0; i < fs->group_desc_count; i++ ) { |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2510 | pctx->group = i; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2511 | pctx->blk = blk; |
Theodore Ts'o | 8039c48 | 1997-11-19 21:39:13 +0000 | [diff] [blame] | 2512 | if (!ext2fs_bg_has_super(fs, i)) |
| 2513 | goto skip_super; |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2514 | if (blk == first_block) { |
| 2515 | if (i == 0) { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2516 | if (fix_problem(ctx, |
| 2517 | PR_1_BAD_PRIMARY_SUPERBLOCK, |
| 2518 | pctx)) { |
| 2519 | *block_nr = 0; |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2520 | return BLOCK_CHANGED; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2521 | } |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2522 | return 0; |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2523 | } |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2524 | fix_problem(ctx, PR_1_BAD_SUPERBLOCK, pctx); |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2525 | return 0; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2526 | } |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2527 | if ((blk > first_block) && |
| 2528 | (blk <= first_block + fs->desc_blocks)) { |
| 2529 | if (i == 0) { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2530 | pctx->blk = *block_nr; |
| 2531 | if (fix_problem(ctx, |
| 2532 | PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR, pctx)) { |
| 2533 | *block_nr = 0; |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2534 | return BLOCK_CHANGED; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2535 | } |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2536 | return 0; |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2537 | } |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2538 | fix_problem(ctx, PR_1_BAD_GROUP_DESCRIPTORS, pctx); |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2539 | return 0; |
| 2540 | } |
Theodore Ts'o | 8039c48 | 1997-11-19 21:39:13 +0000 | [diff] [blame] | 2541 | skip_super: |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2542 | if (blk == ext2fs_block_bitmap_loc(fs, i)) { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2543 | if (fix_problem(ctx, PR_1_BB_BAD_BLOCK, pctx)) { |
| 2544 | ctx->invalid_block_bitmap_flag[i]++; |
| 2545 | ctx->invalid_bitmaps++; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2546 | } |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2547 | return 0; |
| 2548 | } |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2549 | if (blk == ext2fs_inode_bitmap_loc(fs, i)) { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2550 | if (fix_problem(ctx, PR_1_IB_BAD_BLOCK, pctx)) { |
| 2551 | ctx->invalid_inode_bitmap_flag[i]++; |
| 2552 | ctx->invalid_bitmaps++; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2553 | } |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2554 | return 0; |
| 2555 | } |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2556 | if ((blk >= ext2fs_inode_table_loc(fs, i)) && |
| 2557 | (blk < (ext2fs_inode_table_loc(fs, i) + |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2558 | fs->inode_blocks_per_group))) { |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2559 | /* |
| 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'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2564 | return 0; |
| 2565 | } |
Theodore Ts'o | 8039c48 | 1997-11-19 21:39:13 +0000 | [diff] [blame] | 2566 | first_block += fs->super->s_blocks_per_group; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2567 | } |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2568 | /* |
| 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'o | 000ba40 | 2003-11-21 10:41:58 -0500 | [diff] [blame] | 2574 | (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'o | a02ce9d | 1998-02-24 20:22:23 +0000 | [diff] [blame] | 2581 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 2582 | return BLOCK_ABORT; |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2583 | return 0; |
| 2584 | } |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2585 | |
| 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'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2591 | return 0; |
| 2592 | } |
| 2593 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2594 | static 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'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2596 | { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2597 | ext2_filsys fs = ctx->fs; |
Theodore Ts'o | 617446e | 2009-08-18 22:27:42 -0400 | [diff] [blame] | 2598 | dgrp_t last_grp; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2599 | 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'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2604 | char *buf; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2605 | 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'o | 617446e | 2009-08-18 22:27:42 -0400 | [diff] [blame] | 2613 | /* |
| 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2623 | first_block = ext2fs_group_first_block2(fs, |
| 2624 | flexbg_size * flexbg); |
Theodore Ts'o | 617446e | 2009-08-18 22:27:42 -0400 | [diff] [blame] | 2625 | last_grp = group | (flexbg_size - 1); |
| 2626 | if (last_grp > fs->group_desc_count) |
| 2627 | last_grp = fs->group_desc_count; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2628 | last_block = ext2fs_group_last_block2(fs, last_grp); |
Theodore Ts'o | 617446e | 2009-08-18 22:27:42 -0400 | [diff] [blame] | 2629 | } else |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2630 | 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'o | 617446e | 2009-08-18 22:27:42 -0400 | [diff] [blame] | 2634 | if (is_flexbg && (pctx.errcode == EXT2_ET_BLOCK_ALLOC_FAIL)) |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2635 | pctx.errcode = ext2fs_get_free_blocks2(fs, |
Theodore Ts'o | 617446e | 2009-08-18 22:27:42 -0400 | [diff] [blame] | 2636 | fs->super->s_first_data_block, |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2637 | ext2fs_blocks_count(fs->super), |
Theodore Ts'o | 617446e | 2009-08-18 22:27:42 -0400 | [diff] [blame] | 2638 | num, ctx->block_found_map, new_block); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2639 | if (pctx.errcode) { |
| 2640 | pctx.num = num; |
| 2641 | fix_problem(ctx, PR_1_RELOC_BLOCK_ALLOCATE, &pctx); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2642 | ext2fs_unmark_valid(fs); |
Theodore Ts'o | 617446e | 2009-08-18 22:27:42 -0400 | [diff] [blame] | 2643 | ctx->flags |= E2F_FLAG_ABORT; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2644 | return; |
| 2645 | } |
Theodore Ts'o | c4e3d3f | 2003-08-01 09:41:07 -0400 | [diff] [blame] | 2646 | pctx.errcode = ext2fs_get_mem(fs->blocksize, &buf); |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 2647 | if (pctx.errcode) { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2648 | fix_problem(ctx, PR_1_RELOC_MEMORY_ALLOCATE, &pctx); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2649 | ext2fs_unmark_valid(fs); |
Theodore Ts'o | 617446e | 2009-08-18 22:27:42 -0400 | [diff] [blame] | 2650 | ctx->flags |= E2F_FLAG_ABORT; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2651 | return; |
| 2652 | } |
| 2653 | ext2fs_mark_super_dirty(fs); |
Theodore Ts'o | 299d742 | 2002-11-08 11:10:28 -0500 | [diff] [blame] | 2654 | fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2655 | 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'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2659 | for (i = 0; i < num; i++) { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2660 | pctx.blk = i; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2661 | ext2fs_mark_block_bitmap2(ctx->block_found_map, (*new_block)+i); |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2662 | if (old_block) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2663 | pctx.errcode = io_channel_read_blk64(fs->io, |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2664 | old_block + i, 1, buf); |
| 2665 | if (pctx.errcode) |
| 2666 | fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx); |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2667 | } else |
| 2668 | memset(buf, 0, fs->blocksize); |
| 2669 | |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2670 | pctx.blk = (*new_block) + i; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2671 | pctx.errcode = io_channel_write_blk64(fs->io, pctx.blk, |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2672 | 1, buf); |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2673 | if (pctx.errcode) |
| 2674 | fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2675 | } |
Theodore Ts'o | c4e3d3f | 2003-08-01 09:41:07 -0400 | [diff] [blame] | 2676 | ext2fs_free_mem(&buf); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2677 | } |
| 2678 | |
| 2679 | /* |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2680 | * 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'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2685 | */ |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2686 | static void handle_fs_bad_blocks(e2fsck_t ctx) |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2687 | { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2688 | ext2_filsys fs = ctx->fs; |
Theodore Ts'o | 5443492 | 2003-12-07 01:28:50 -0500 | [diff] [blame] | 2689 | dgrp_t i; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2690 | blk64_t first_block; |
| 2691 | blk64_t new_blk; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2692 | |
| 2693 | for (i = 0; i < fs->group_desc_count; i++) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2694 | first_block = ext2fs_group_first_block2(fs, i); |
Eric Sandeen | abf2343 | 2006-09-12 14:56:16 -0400 | [diff] [blame] | 2695 | |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2696 | if (ctx->invalid_block_bitmap_flag[i]) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2697 | new_blk = ext2fs_block_bitmap_loc(fs, i); |
Theodore Ts'o | 0c4a072 | 2000-02-07 03:11:03 +0000 | [diff] [blame] | 2698 | new_table_block(ctx, first_block, i, _("block bitmap"), |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2699 | 1, &new_blk); |
| 2700 | ext2fs_block_bitmap_loc_set(fs, i, new_blk); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2701 | } |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2702 | if (ctx->invalid_inode_bitmap_flag[i]) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2703 | new_blk = ext2fs_inode_bitmap_loc(fs, i); |
Theodore Ts'o | 0c4a072 | 2000-02-07 03:11:03 +0000 | [diff] [blame] | 2704 | new_table_block(ctx, first_block, i, _("inode bitmap"), |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2705 | 1, &new_blk); |
| 2706 | ext2fs_inode_bitmap_loc_set(fs, i, new_blk); |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2707 | } |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2708 | if (ctx->invalid_inode_table_flag[i]) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2709 | new_blk = ext2fs_inode_table_loc(fs, i); |
Theodore Ts'o | 0c4a072 | 2000-02-07 03:11:03 +0000 | [diff] [blame] | 2710 | new_table_block(ctx, first_block, i, _("inode table"), |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2711 | fs->inode_blocks_per_group, |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2712 | &new_blk); |
| 2713 | ext2fs_inode_table_loc_set(fs, i, new_blk); |
Theodore Ts'o | 08b2130 | 1997-11-03 19:42:40 +0000 | [diff] [blame] | 2714 | ctx->flags |= E2F_FLAG_RESTART; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2715 | } |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2716 | } |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2717 | ctx->invalid_bitmaps = 0; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2718 | } |
| 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'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2724 | static void mark_table_blocks(e2fsck_t ctx) |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2725 | { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2726 | ext2_filsys fs = ctx->fs; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2727 | blk64_t b; |
Theodore Ts'o | 5443492 | 2003-12-07 01:28:50 -0500 | [diff] [blame] | 2728 | dgrp_t i; |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2729 | unsigned int j; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2730 | struct problem_context pctx; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2731 | |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2732 | clear_problem_context(&pctx); |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2733 | |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2734 | for (i = 0; i < fs->group_desc_count; i++) { |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2735 | pctx.group = i; |
Theodore Ts'o | da2e97f | 1997-06-12 04:28:07 +0000 | [diff] [blame] | 2736 | |
Theodore Ts'o | ef344e1 | 2003-11-21 09:02:21 -0500 | [diff] [blame] | 2737 | ext2fs_reserve_super_and_bgd(fs, i, ctx->block_found_map); |
| 2738 | |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2739 | /* |
| 2740 | * Mark the blocks used for the inode table |
| 2741 | */ |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2742 | if (ext2fs_inode_table_loc(fs, i)) { |
| 2743 | for (j = 0, b = ext2fs_inode_table_loc(fs, i); |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2744 | j < fs->inode_blocks_per_group; |
| 2745 | j++, b++) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2746 | if (ext2fs_test_block_bitmap2(ctx->block_found_map, |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2747 | b)) { |
| 2748 | pctx.blk = b; |
Theodore Ts'o | 9a7fe4b | 2009-08-18 23:14:03 -0400 | [diff] [blame] | 2749 | if (!ctx->invalid_inode_table_flag[i] && |
| 2750 | fix_problem(ctx, |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2751 | PR_1_ITABLE_CONFLICT, &pctx)) { |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2752 | ctx->invalid_inode_table_flag[i]++; |
| 2753 | ctx->invalid_bitmaps++; |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2754 | } |
| 2755 | } else { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2756 | ext2fs_mark_block_bitmap2(ctx->block_found_map, |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2757 | b); |
Theodore Ts'o | 21c84b7 | 1997-04-29 16:15:03 +0000 | [diff] [blame] | 2758 | } |
| 2759 | } |
| 2760 | } |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2761 | |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2762 | /* |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2763 | * Mark block used for the block bitmap |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2764 | */ |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2765 | 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'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2769 | if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) { |
| 2770 | ctx->invalid_block_bitmap_flag[i]++; |
| 2771 | ctx->invalid_bitmaps++; |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2772 | } |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2773 | } else { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2774 | ext2fs_mark_block_bitmap2(ctx->block_found_map, |
| 2775 | ext2fs_block_bitmap_loc(fs, i)); |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2776 | } |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2777 | |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2778 | } |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2779 | /* |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2780 | * Mark block used for the inode bitmap |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2781 | */ |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2782 | 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'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2786 | if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) { |
| 2787 | ctx->invalid_inode_bitmap_flag[i]++; |
| 2788 | ctx->invalid_bitmaps++; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2789 | } |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2790 | } else { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2791 | ext2fs_mark_block_bitmap2(ctx->block_found_map, |
| 2792 | ext2fs_inode_bitmap_loc(fs, i)); |
Theodore Ts'o | 50e1e10 | 1997-04-26 13:58:21 +0000 | [diff] [blame] | 2793 | } |
Theodore Ts'o | f3db356 | 1997-04-26 13:34:30 +0000 | [diff] [blame] | 2794 | } |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2795 | } |
| 2796 | } |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2797 | |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2798 | /* |
Theodore Ts'o | e72a9ba | 1999-06-25 15:40:18 +0000 | [diff] [blame] | 2799 | * Thes subroutines short circuits ext2fs_get_blocks and |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2800 | * 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'o | 86c627e | 2001-01-11 15:12:14 +0000 | [diff] [blame] | 2804 | static errcode_t pass1_get_blocks(ext2_filsys fs, ext2_ino_t ino, |
| 2805 | blk_t *blocks) |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2806 | { |
Theodore Ts'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 2807 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2808 | int i; |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2809 | |
Theodore Ts'o | 71d521c | 2001-06-01 19:29:36 +0000 | [diff] [blame] | 2810 | if ((ino != ctx->stashed_ino) || !ctx->stashed_inode) |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 2811 | return EXT2_ET_CALLBACK_NOTHANDLED; |
| 2812 | |
| 2813 | for (i=0; i < EXT2_N_BLOCKS; i++) |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2814 | blocks[i] = ctx->stashed_inode->i_block[i]; |
Theodore Ts'o | 521e368 | 1997-04-29 17:48:10 +0000 | [diff] [blame] | 2815 | return 0; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2816 | } |
| 2817 | |
Theodore Ts'o | 86c627e | 2001-01-11 15:12:14 +0000 | [diff] [blame] | 2818 | static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino, |
Theodore Ts'o | e72a9ba | 1999-06-25 15:40:18 +0000 | [diff] [blame] | 2819 | struct ext2_inode *inode) |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 2820 | { |
Theodore Ts'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 2821 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2822 | |
Theodore Ts'o | 71d521c | 2001-06-01 19:29:36 +0000 | [diff] [blame] | 2823 | if ((ino != ctx->stashed_ino) || !ctx->stashed_inode) |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 2824 | return EXT2_ET_CALLBACK_NOTHANDLED; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2825 | *inode = *ctx->stashed_inode; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 2826 | return 0; |
| 2827 | } |
| 2828 | |
Theodore Ts'o | 86c627e | 2001-01-11 15:12:14 +0000 | [diff] [blame] | 2829 | static errcode_t pass1_write_inode(ext2_filsys fs, ext2_ino_t ino, |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 2830 | struct ext2_inode *inode) |
| 2831 | { |
Theodore Ts'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 2832 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2833 | |
Theodore Ts'o | 2743159 | 2005-07-25 11:36:43 -0500 | [diff] [blame] | 2834 | if ((ino == ctx->stashed_ino) && ctx->stashed_inode && |
| 2835 | (inode != ctx->stashed_inode)) |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2836 | *ctx->stashed_inode = *inode; |
Theodore Ts'o | 1e3472c | 1997-04-29 14:53:37 +0000 | [diff] [blame] | 2837 | return EXT2_ET_CALLBACK_NOTHANDLED; |
| 2838 | } |
| 2839 | |
Theodore Ts'o | 86c627e | 2001-01-11 15:12:14 +0000 | [diff] [blame] | 2840 | static errcode_t pass1_check_directory(ext2_filsys fs, ext2_ino_t ino) |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2841 | { |
Theodore Ts'o | 54dc7ca | 1998-01-19 14:50:49 +0000 | [diff] [blame] | 2842 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2843 | |
Theodore Ts'o | 71d521c | 2001-06-01 19:29:36 +0000 | [diff] [blame] | 2844 | if ((ino != ctx->stashed_ino) || !ctx->stashed_inode) |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2845 | return EXT2_ET_CALLBACK_NOTHANDLED; |
| 2846 | |
| 2847 | if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode)) |
Theodore Ts'o | 291c904 | 1997-10-31 06:17:08 +0000 | [diff] [blame] | 2848 | return EXT2_ET_NO_DIRECTORY; |
Theodore Ts'o | 1b6bf17 | 1997-10-03 17:48:10 +0000 | [diff] [blame] | 2849 | return 0; |
Theodore Ts'o | 3839e65 | 1997-04-26 13:21:57 +0000 | [diff] [blame] | 2850 | } |
Theodore Ts'o | e72a9ba | 1999-06-25 15:40:18 +0000 | [diff] [blame] | 2851 | |
Theodore Ts'o | 16bd349 | 2008-06-02 17:27:59 -0400 | [diff] [blame] | 2852 | static 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2857 | blk64_t new_block; |
Theodore Ts'o | 16bd349 | 2008-06-02 17:27:59 -0400 | [diff] [blame] | 2858 | |
| 2859 | if (ctx->block_found_map) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2860 | retval = ext2fs_new_block2(fs, goal, ctx->block_found_map, |
| 2861 | &new_block); |
Theodore Ts'o | 16bd349 | 2008-06-02 17:27:59 -0400 | [diff] [blame] | 2862 | if (retval) |
| 2863 | return retval; |
Theodore Ts'o | 8a2cbe2 | 2009-11-29 01:24:06 -0500 | [diff] [blame] | 2864 | if (fs->block_map) { |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2865 | ext2fs_mark_block_bitmap2(fs->block_map, new_block); |
Theodore Ts'o | 8a2cbe2 | 2009-11-29 01:24:06 -0500 | [diff] [blame] | 2866 | ext2fs_mark_bb_dirty(fs); |
| 2867 | } |
Theodore Ts'o | 16bd349 | 2008-06-02 17:27:59 -0400 | [diff] [blame] | 2868 | } else { |
| 2869 | if (!fs->block_map) { |
| 2870 | retval = ext2fs_read_block_bitmap(fs); |
| 2871 | if (retval) |
| 2872 | return retval; |
| 2873 | } |
| 2874 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2875 | retval = ext2fs_new_block2(fs, goal, 0, &new_block); |
Theodore Ts'o | 16bd349 | 2008-06-02 17:27:59 -0400 | [diff] [blame] | 2876 | if (retval) |
| 2877 | return retval; |
| 2878 | } |
Theodore Ts'o | efc6f62 | 2008-08-27 23:07:54 -0400 | [diff] [blame] | 2879 | |
Theodore Ts'o | 16bd349 | 2008-06-02 17:27:59 -0400 | [diff] [blame] | 2880 | *ret = new_block; |
| 2881 | return (0); |
| 2882 | } |
| 2883 | |
| 2884 | static 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 Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2890 | ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); |
Theodore Ts'o | 16bd349 | 2008-06-02 17:27:59 -0400 | [diff] [blame] | 2891 | else |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2892 | ext2fs_unmark_block_bitmap2(ctx->block_found_map, blk); |
Theodore Ts'o | 16bd349 | 2008-06-02 17:27:59 -0400 | [diff] [blame] | 2893 | } |
| 2894 | } |
| 2895 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2896 | void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int use_shortcuts) |
Theodore Ts'o | e72a9ba | 1999-06-25 15:40:18 +0000 | [diff] [blame] | 2897 | { |
| 2898 | ext2_filsys fs = ctx->fs; |
| 2899 | |
JP Abgrall | e0ed740 | 2014-03-19 19:08:39 -0700 | [diff] [blame] | 2900 | if (use_shortcuts) { |
Theodore Ts'o | e72a9ba | 1999-06-25 15:40:18 +0000 | [diff] [blame] | 2901 | 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'o | 16bd349 | 2008-06-02 17:27:59 -0400 | [diff] [blame] | 2906 | 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'o | e72a9ba | 1999-06-25 15:40:18 +0000 | [diff] [blame] | 2911 | } else { |
| 2912 | fs->get_blocks = 0; |
| 2913 | fs->check_directory = 0; |
| 2914 | fs->read_inode = 0; |
| 2915 | fs->write_inode = 0; |
| 2916 | } |
| 2917 | } |