]>
Commit | Line | Data |
---|---|---|
3839e657 TT |
1 | /* |
2 | * pass1.c -- pass #1 of e2fsck: sequential scan of the inode table | |
efc6f628 | 3 | * |
21c84b71 TT |
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% | |
efc6f628 | 10 | * |
3839e657 TT |
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) | |
aa4115a4 | 22 | * - A bitmap of which inodes are regular files. (inode_reg_map) |
3839e657 | 23 | * - A bitmap of which inodes have bad fields. (inode_bad_map) |
21c84b71 | 24 | * - A bitmap of which inodes are in bad blocks. (inode_bb_map) |
aa4115a4 | 25 | * - A bitmap of which inodes are imagic inodes. (inode_imagic_map) |
3839e657 TT |
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 | ||
b969b1b8 | 40 | #define _GNU_SOURCE 1 /* get strnlen() */ |
d1154eb4 | 41 | #include "config.h" |
3e699064 | 42 | #include <string.h> |
3839e657 | 43 | #include <time.h> |
50e1e10f TT |
44 | #ifdef HAVE_ERRNO_H |
45 | #include <errno.h> | |
46 | #endif | |
3839e657 | 47 | |
3839e657 | 48 | #include "e2fsck.h" |
342d847d TT |
49 | #include <ext2fs/ext2_ext_attr.h> |
50 | ||
21c84b71 | 51 | #include "problem.h" |
3839e657 | 52 | |
50e1e10f TT |
53 | #ifdef NO_INLINE_FUNCS |
54 | #define _INLINE_ | |
55 | #else | |
56 | #define _INLINE_ inline | |
57 | #endif | |
58 | ||
6dc64392 VAH |
59 | static int process_block(ext2_filsys fs, blk64_t *blocknr, |
60 | e2_blkcnt_t blockcnt, blk64_t ref_blk, | |
54dc7ca2 | 61 | int ref_offset, void *priv_data); |
6dc64392 VAH |
62 | static int process_bad_block(ext2_filsys fs, blk64_t *block_nr, |
63 | e2_blkcnt_t blockcnt, blk64_t ref_blk, | |
54dc7ca2 | 64 | int ref_offset, void *priv_data); |
1b6bf175 | 65 | static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, |
3839e657 | 66 | char *block_buf); |
1b6bf175 | 67 | static void mark_table_blocks(e2fsck_t ctx); |
1b6bf175 | 68 | static void alloc_bb_map(e2fsck_t ctx); |
aa4115a4 | 69 | static void alloc_imagic_map(e2fsck_t ctx); |
fdbdea09 | 70 | static void mark_inode_bad(e2fsck_t ctx, ino_t ino); |
1b6bf175 TT |
71 | static void handle_fs_bad_blocks(e2fsck_t ctx); |
72 | static void process_inodes(e2fsck_t ctx, char *block_buf); | |
4c77fe50 | 73 | static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b); |
f3db3566 | 74 | static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan, |
54dc7ca2 | 75 | dgrp_t group, void * priv_data); |
efc6f628 | 76 | static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount, |
e8a3ee62 | 77 | char *block_buf, int adjust_sign); |
6dc64392 | 78 | /* static char *describe_illegal_block(ext2_filsys fs, blk64_t block); */ |
3839e657 TT |
79 | |
80 | struct process_block_struct { | |
86c627ec | 81 | ext2_ino_t ino; |
83e692e8 | 82 | unsigned is_dir:1, is_reg:1, clear:1, suppress:1, |
000ba404 | 83 | fragmented:1, compressed:1, bbcheck:1; |
65d71894 | 84 | blk64_t num_blocks; |
6dc64392 | 85 | blk64_t max_blocks; |
9d1bd3de | 86 | e2_blkcnt_t last_block; |
010dc7b9 | 87 | e2_blkcnt_t last_init_lblock; |
4dbe79bc | 88 | e2_blkcnt_t last_db_block; |
246501c6 | 89 | int num_illegal_blocks; |
6dc64392 | 90 | blk64_t previous_block; |
f3db3566 | 91 | struct ext2_inode *inode; |
21c84b71 | 92 | struct problem_context *pctx; |
000ba404 | 93 | ext2fs_block_bitmap fs_meta_blocks; |
1b6bf175 | 94 | e2fsck_t ctx; |
3839e657 TT |
95 | }; |
96 | ||
97 | struct process_inode_block { | |
86c627ec | 98 | ext2_ino_t ino; |
3839e657 TT |
99 | struct ext2_inode inode; |
100 | }; | |
101 | ||
f8188fff TT |
102 | struct scan_callback_struct { |
103 | e2fsck_t ctx; | |
104 | char *block_buf; | |
105 | }; | |
106 | ||
3839e657 TT |
107 | /* |
108 | * For the inodes to process list. | |
109 | */ | |
110 | static struct process_inode_block *inodes_to_process; | |
111 | static int process_inode_count; | |
3839e657 | 112 | |
7823dd65 TT |
113 | static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE - |
114 | EXT2_MIN_BLOCK_LOG_SIZE + 1]; | |
246501c6 | 115 | |
f3db3566 TT |
116 | /* |
117 | * Free all memory allocated by pass1 in preparation for restarting | |
118 | * things. | |
119 | */ | |
54434927 | 120 | static void unwind_pass1(ext2_filsys fs EXT2FS_ATTR((unused))) |
f3db3566 | 121 | { |
c4e3d3f3 | 122 | ext2fs_free_mem(&inodes_to_process); |
08b21301 | 123 | inodes_to_process = 0; |
f3db3566 TT |
124 | } |
125 | ||
7cf73dcd TT |
126 | /* |
127 | * Check to make sure a device inode is real. Returns 1 if the device | |
128 | * checks out, 0 if not. | |
1dde43f0 TT |
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 | |
efc6f628 | 132 | * zero. |
7cf73dcd | 133 | */ |
efc6f628 | 134 | int e2fsck_pass1_check_device_inode(ext2_filsys fs EXT2FS_ATTR((unused)), |
f954ba01 | 135 | struct ext2_inode *inode) |
7cf73dcd TT |
136 | { |
137 | int i; | |
138 | ||
a40ecbb1 | 139 | /* |
441ab1e0 TT |
140 | * If the index flag is set, then this is a bogus |
141 | * device/fifo/socket | |
a40ecbb1 | 142 | */ |
441ab1e0 | 143 | if (inode->i_flags & EXT2_INDEX_FL) |
53abed0a | 144 | return 0; |
bcf9c5d4 | 145 | |
7fdfabd3 TT |
146 | /* |
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 | */ | |
01fbc701 | 157 | if (inode->i_flags & (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)) { |
efc6f628 | 158 | for (i=4; i < EXT2_N_BLOCKS; i++) |
7fdfabd3 TT |
159 | if (inode->i_block[i]) |
160 | return 0; | |
161 | } | |
7cf73dcd TT |
162 | return 1; |
163 | } | |
164 | ||
67052a8a AD |
165 | /* |
166 | * Check to make sure a symlink inode is real. Returns 1 if the symlink | |
167 | * checks out, 0 if not. | |
168 | */ | |
7cadc577 TT |
169 | int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino, |
170 | struct ext2_inode *inode, char *buf) | |
67052a8a | 171 | { |
54434927 | 172 | unsigned int len; |
d007cb4c | 173 | int i; |
6dc64392 | 174 | blk64_t blocks; |
7cadc577 TT |
175 | ext2_extent_handle_t handle; |
176 | struct ext2_extent_info info; | |
177 | struct ext2fs_extent extent; | |
67052a8a | 178 | |
bcf9c5d4 TT |
179 | if ((inode->i_size_high || inode->i_size == 0) || |
180 | (inode->i_flags & EXT2_INDEX_FL)) | |
67052a8a AD |
181 | return 0; |
182 | ||
7cadc577 TT |
183 | if (inode->i_flags & EXT4_EXTENTS_FL) { |
184 | if (inode->i_size > fs->blocksize) | |
185 | return 0; | |
84b239ae | 186 | if (ext2fs_extent_open2(fs, ino, inode, &handle)) |
7cadc577 TT |
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) || | |
4efbac6f | 197 | (extent.e_pblk >= ext2fs_blocks_count(fs->super))) |
7cadc577 TT |
198 | goto exit_extent; |
199 | i = 1; | |
200 | exit_extent: | |
201 | ext2fs_extent_free(handle); | |
202 | return i; | |
203 | } | |
204 | ||
6dc64392 | 205 | blocks = ext2fs_inode_data_blocks2(fs, inode); |
0684a4f3 | 206 | if (blocks) { |
b94a052a | 207 | if ((inode->i_size >= fs->blocksize) || |
0684a4f3 | 208 | (blocks != fs->blocksize >> 9) || |
d007cb4c | 209 | (inode->i_block[0] < fs->super->s_first_data_block) || |
4efbac6f | 210 | (inode->i_block[0] >= ext2fs_blocks_count(fs->super))) |
67052a8a AD |
211 | return 0; |
212 | ||
213 | for (i = 1; i < EXT2_N_BLOCKS; i++) | |
214 | if (inode->i_block[i]) | |
215 | return 0; | |
b94a052a | 216 | |
24a117ab | 217 | if (io_channel_read_blk64(fs->io, inode->i_block[0], 1, buf)) |
b94a052a AD |
218 | return 0; |
219 | ||
220 | len = strnlen(buf, fs->blocksize); | |
221 | if (len == fs->blocksize) | |
222 | return 0; | |
67052a8a | 223 | } else { |
b94a052a | 224 | if (inode->i_size >= sizeof(inode->i_block)) |
67052a8a AD |
225 | return 0; |
226 | ||
b94a052a AD |
227 | len = strnlen((char *)inode->i_block, sizeof(inode->i_block)); |
228 | if (len == sizeof(inode->i_block)) | |
67052a8a AD |
229 | return 0; |
230 | } | |
b94a052a AD |
231 | if (len != inode->i_size) |
232 | return 0; | |
67052a8a AD |
233 | return 1; |
234 | } | |
235 | ||
6fdc7a32 | 236 | /* |
01fbc701 TT |
237 | * If the immutable (or append-only) flag is set on the inode, offer |
238 | * to clear it. | |
6fdc7a32 | 239 | */ |
bcf9c5d4 | 240 | #define BAD_SPECIAL_FLAGS (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL) |
6fdc7a32 TT |
241 | static void check_immutable(e2fsck_t ctx, struct problem_context *pctx) |
242 | { | |
b94a052a | 243 | if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS)) |
6fdc7a32 TT |
244 | return; |
245 | ||
246 | if (!fix_problem(ctx, PR_1_SET_IMMUTABLE, pctx)) | |
247 | return; | |
248 | ||
b94a052a | 249 | pctx->inode->i_flags &= ~BAD_SPECIAL_FLAGS; |
6fdc7a32 TT |
250 | e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1"); |
251 | } | |
252 | ||
d647a1ea TT |
253 | /* |
254 | * If device, fifo or socket, check size is zero -- if not offer to | |
255 | * clear it | |
256 | */ | |
257 | static void check_size(e2fsck_t ctx, struct problem_context *pctx) | |
258 | { | |
259 | struct ext2_inode *inode = pctx->inode; | |
efc6f628 | 260 | |
0bd0e593 | 261 | if (EXT2_I_SIZE(inode) == 0) |
d647a1ea | 262 | return; |
efc6f628 | 263 | |
85645a6f | 264 | if (!fix_problem(ctx, PR_1_SET_NONZSIZE, pctx)) |
d647a1ea | 265 | return; |
efc6f628 | 266 | |
d647a1ea | 267 | inode->i_size = 0; |
fdbdea09 | 268 | inode->i_size_high = 0; |
d647a1ea TT |
269 | e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1"); |
270 | } | |
efc6f628 | 271 | |
cebe48a1 TT |
272 | static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx) |
273 | { | |
274 | struct ext2_super_block *sb = ctx->fs->super; | |
275 | struct ext2_inode_large *inode; | |
276 | struct ext2_ext_attr_entry *entry; | |
e3507739 | 277 | char *start; |
1a8c2c4a | 278 | unsigned int storage_size, remain; |
3c7c6d73 | 279 | problem_t problem = 0; |
cebe48a1 TT |
280 | |
281 | inode = (struct ext2_inode_large *) pctx->inode; | |
282 | storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE - | |
283 | inode->i_extra_isize; | |
284 | start = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + | |
285 | inode->i_extra_isize + sizeof(__u32); | |
cebe48a1 TT |
286 | entry = (struct ext2_ext_attr_entry *) start; |
287 | ||
288 | /* scan all entry's headers first */ | |
289 | ||
290 | /* take finish entry 0UL into account */ | |
efc6f628 | 291 | remain = storage_size - sizeof(__u32); |
cebe48a1 TT |
292 | |
293 | while (!EXT2_EXT_IS_LAST_ENTRY(entry)) { | |
fefaef39 | 294 | __u32 hash; |
cebe48a1 TT |
295 | |
296 | /* header eats this space */ | |
297 | remain -= sizeof(struct ext2_ext_attr_entry); | |
efc6f628 | 298 | |
cebe48a1 TT |
299 | /* is attribute name valid? */ |
300 | if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain) { | |
301 | pctx->num = entry->e_name_len; | |
302 | problem = PR_1_ATTR_NAME_LEN; | |
303 | goto fix; | |
304 | } | |
305 | ||
306 | /* attribute len eats this space */ | |
307 | remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len); | |
308 | ||
309 | /* check value size */ | |
10fc3a63 | 310 | if (entry->e_value_size > remain) { |
cebe48a1 TT |
311 | pctx->num = entry->e_value_size; |
312 | problem = PR_1_ATTR_VALUE_SIZE; | |
313 | goto fix; | |
314 | } | |
315 | ||
cebe48a1 TT |
316 | /* e_value_block must be 0 in inode's ea */ |
317 | if (entry->e_value_block != 0) { | |
318 | pctx->num = entry->e_value_block; | |
319 | problem = PR_1_ATTR_VALUE_BLOCK; | |
320 | goto fix; | |
321 | } | |
fefaef39 AD |
322 | |
323 | hash = ext2fs_ext_attr_hash_entry(entry, | |
324 | start + entry->e_value_offs); | |
325 | ||
326 | /* e_hash may be 0 in older inode's ea */ | |
327 | if (entry->e_hash != 0 && entry->e_hash != hash) { | |
cebe48a1 TT |
328 | pctx->num = entry->e_hash; |
329 | problem = PR_1_ATTR_HASH; | |
330 | goto fix; | |
331 | } | |
332 | ||
333 | remain -= entry->e_value_size; | |
cebe48a1 TT |
334 | |
335 | entry = EXT2_EXT_ATTR_NEXT(entry); | |
336 | } | |
337 | fix: | |
338 | /* | |
339 | * it seems like a corruption. it's very unlikely we could repair | |
340 | * EA(s) in automatic fashion -bzzz | |
341 | */ | |
cebe48a1 TT |
342 | if (problem == 0 || !fix_problem(ctx, problem, pctx)) |
343 | return; | |
344 | ||
fefaef39 | 345 | /* simply remove all possible EA(s) */ |
cebe48a1 | 346 | *((__u32 *)start) = 0UL; |
da938f20 | 347 | e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode, |
cebe48a1 TT |
348 | EXT2_INODE_SIZE(sb), "pass1"); |
349 | } | |
350 | ||
351 | static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx) | |
352 | { | |
353 | struct ext2_super_block *sb = ctx->fs->super; | |
354 | struct ext2_inode_large *inode; | |
355 | __u32 *eamagic; | |
356 | int min, max; | |
357 | ||
358 | inode = (struct ext2_inode_large *) pctx->inode; | |
359 | if (EXT2_INODE_SIZE(sb) == EXT2_GOOD_OLD_INODE_SIZE) { | |
360 | /* this isn't large inode. so, nothing to check */ | |
361 | return; | |
362 | } | |
363 | ||
364 | #if 0 | |
365 | printf("inode #%u, i_extra_size %d\n", pctx->ino, | |
366 | inode->i_extra_isize); | |
efc6f628 | 367 | #endif |
89efc88e TT |
368 | /* i_extra_isize must cover i_extra_isize + i_checksum_hi at least */ |
369 | min = sizeof(inode->i_extra_isize) + sizeof(inode->i_checksum_hi); | |
cebe48a1 | 370 | max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE; |
efc6f628 | 371 | /* |
cebe48a1 TT |
372 | * For now we will allow i_extra_isize to be 0, but really |
373 | * implementations should never allow i_extra_isize to be 0 | |
374 | */ | |
375 | if (inode->i_extra_isize && | |
376 | (inode->i_extra_isize < min || inode->i_extra_isize > max)) { | |
377 | if (!fix_problem(ctx, PR_1_EXTRA_ISIZE, pctx)) | |
378 | return; | |
379 | inode->i_extra_isize = min; | |
380 | e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode, | |
381 | EXT2_INODE_SIZE(sb), "pass1"); | |
382 | return; | |
383 | } | |
384 | ||
385 | eamagic = (__u32 *) (((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + | |
386 | inode->i_extra_isize); | |
387 | if (*eamagic == EXT2_EXT_ATTR_MAGIC) { | |
388 | /* it seems inode has an extended attribute(s) in body */ | |
389 | check_ea_in_inode(ctx, pctx); | |
390 | } | |
391 | } | |
6fdc7a32 | 392 | |
efc6f628 | 393 | /* |
fbc3f901 TT |
394 | * Check to see if the inode might really be a directory, despite i_mode |
395 | * | |
396 | * This is a lot of complexity for something for which I'm not really | |
397 | * convinced happens frequently in the wild. If for any reason this | |
398 | * causes any problems, take this code out. | |
399 | * [tytso:20070331.0827EDT] | |
400 | */ | |
401 | static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx, | |
402 | char *buf) | |
403 | { | |
404 | struct ext2_inode *inode = pctx->inode; | |
fbc3f901 | 405 | struct ext2_dir_entry *dirent; |
e94bc631 | 406 | errcode_t retval; |
cf5301d7 | 407 | blk64_t blk; |
03fa6f8a | 408 | unsigned int i, rec_len, not_device = 0; |
1ec42a00 | 409 | int extent_fs; |
fbc3f901 | 410 | |
1ec42a00 ND |
411 | /* |
412 | * If the mode looks OK, we believe it. If the first block in | |
413 | * the i_block array is 0, this cannot be a directory. If the | |
414 | * inode is extent-mapped, it is still the case that the latter | |
415 | * cannot be 0 - the magic number in the extent header would make | |
416 | * it nonzero. | |
417 | */ | |
fbc3f901 | 418 | if (LINUX_S_ISDIR(inode->i_mode) || LINUX_S_ISREG(inode->i_mode) || |
0eeb1549 | 419 | LINUX_S_ISLNK(inode->i_mode) || inode->i_block[0] == 0) |
fbc3f901 TT |
420 | return; |
421 | ||
1ec42a00 ND |
422 | /* |
423 | * Check the block numbers in the i_block array for validity: | |
424 | * zero blocks are skipped (but the first one cannot be zero - | |
425 | * see above), other blocks are checked against the first and | |
426 | * max data blocks (from the the superblock) and against the | |
427 | * block bitmap. Any invalid block found means this cannot be | |
428 | * a directory. | |
429 | * | |
430 | * If there are non-zero blocks past the fourth entry, then | |
431 | * this cannot be a device file: we remember that for the next | |
432 | * check. | |
433 | * | |
434 | * For extent mapped files, we don't do any sanity checking: | |
435 | * just try to get the phys block of logical block 0 and run | |
436 | * with it. | |
437 | */ | |
438 | ||
cf5301d7 AD |
439 | extent_fs = (ctx->fs->super->s_feature_incompat & |
440 | EXT3_FEATURE_INCOMPAT_EXTENTS); | |
1ec42a00 ND |
441 | if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) { |
442 | /* extent mapped */ | |
6dc64392 | 443 | if (ext2fs_bmap2(ctx->fs, pctx->ino, inode, 0, 0, 0, 0, |
1ec42a00 ND |
444 | &blk)) |
445 | return; | |
446 | /* device files are never extent mapped */ | |
447 | not_device++; | |
448 | } else { | |
449 | for (i=0; i < EXT2_N_BLOCKS; i++) { | |
450 | blk = inode->i_block[i]; | |
451 | if (!blk) | |
452 | continue; | |
453 | if (i >= 4) | |
454 | not_device++; | |
455 | ||
456 | if (blk < ctx->fs->super->s_first_data_block || | |
cc84d866 TT |
457 | blk >= ext2fs_blocks_count(ctx->fs->super) || |
458 | ext2fs_fast_test_block_bitmap2(ctx->block_found_map, | |
459 | blk)) | |
1ec42a00 ND |
460 | return; /* Invalid block, can't be dir */ |
461 | } | |
462 | blk = inode->i_block[0]; | |
fbc3f901 TT |
463 | } |
464 | ||
1ec42a00 ND |
465 | /* |
466 | * If the mode says this is a device file and the i_links_count field | |
467 | * is sane and we have not ruled it out as a device file previously, | |
468 | * we declare it a device file, not a directory. | |
469 | */ | |
efc6f628 | 470 | if ((LINUX_S_ISCHR(inode->i_mode) || LINUX_S_ISBLK(inode->i_mode)) && |
fbc3f901 TT |
471 | (inode->i_links_count == 1) && !not_device) |
472 | return; | |
473 | ||
1ec42a00 | 474 | /* read the first block */ |
f85a9ae6 | 475 | ehandler_operation(_("reading directory block")); |
6dc64392 | 476 | retval = ext2fs_read_dir_block3(ctx->fs, blk, buf, 0); |
e94bc631 TT |
477 | ehandler_operation(0); |
478 | if (retval) | |
fbc3f901 TT |
479 | return; |
480 | ||
481 | dirent = (struct ext2_dir_entry *) buf; | |
8a480350 TT |
482 | retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len); |
483 | if (retval) | |
484 | return; | |
fbc3f901 TT |
485 | if (((dirent->name_len & 0xFF) != 1) || |
486 | (dirent->name[0] != '.') || | |
487 | (dirent->inode != pctx->ino) || | |
5dd77dbe TT |
488 | (rec_len < 12) || |
489 | (rec_len % 4) || | |
490 | (rec_len >= ctx->fs->blocksize - 12)) | |
fbc3f901 TT |
491 | return; |
492 | ||
5dd77dbe | 493 | dirent = (struct ext2_dir_entry *) (buf + rec_len); |
8a480350 TT |
494 | retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len); |
495 | if (retval) | |
496 | return; | |
fbc3f901 TT |
497 | if (((dirent->name_len & 0xFF) != 2) || |
498 | (dirent->name[0] != '.') || | |
499 | (dirent->name[1] != '.') || | |
5dd77dbe TT |
500 | (rec_len < 12) || |
501 | (rec_len % 4)) | |
fbc3f901 TT |
502 | return; |
503 | ||
504 | if (fix_problem(ctx, PR_1_TREAT_AS_DIRECTORY, pctx)) { | |
505 | inode->i_mode = (inode->i_mode & 07777) | LINUX_S_IFDIR; | |
efc6f628 TT |
506 | e2fsck_write_inode_full(ctx, pctx->ino, inode, |
507 | EXT2_INODE_SIZE(ctx->fs->super), | |
fbc3f901 TT |
508 | "check_is_really_dir"); |
509 | } | |
510 | } | |
511 | ||
f404167d TT |
512 | void e2fsck_setup_tdb_icount(e2fsck_t ctx, int flags, |
513 | ext2_icount_t *ret) | |
34b9f796 | 514 | { |
f954ba01 | 515 | unsigned int threshold; |
34b9f796 TT |
516 | ext2_ino_t num_dirs; |
517 | errcode_t retval; | |
f954ba01 TT |
518 | char *tdb_dir; |
519 | int enable; | |
34b9f796 TT |
520 | |
521 | *ret = 0; | |
522 | ||
523 | profile_get_string(ctx->profile, "scratch_files", "directory", 0, 0, | |
524 | &tdb_dir); | |
f954ba01 TT |
525 | profile_get_uint(ctx->profile, "scratch_files", |
526 | "numdirs_threshold", 0, 0, &threshold); | |
34b9f796 TT |
527 | profile_get_boolean(ctx->profile, "scratch_files", |
528 | "icount", 0, 1, &enable); | |
529 | ||
530 | retval = ext2fs_get_num_dirs(ctx->fs, &num_dirs); | |
531 | if (retval) | |
532 | num_dirs = 1024; /* Guess */ | |
533 | ||
534 | if (!enable || !tdb_dir || access(tdb_dir, W_OK) || | |
535 | (threshold && num_dirs <= threshold)) | |
536 | return; | |
537 | ||
538 | retval = ext2fs_create_icount_tdb(ctx->fs, tdb_dir, flags, ret); | |
539 | if (retval) | |
540 | *ret = 0; | |
541 | } | |
542 | ||
08b21301 | 543 | void e2fsck_pass1(e2fsck_t ctx) |
3839e657 | 544 | { |
9d1bd3de | 545 | int i; |
31e29a12 | 546 | __u64 max_sizes; |
1b6bf175 | 547 | ext2_filsys fs = ctx->fs; |
24c91184 | 548 | ext2_ino_t ino = 0; |
125f76e7 TT |
549 | struct ext2_inode *inode = NULL; |
550 | ext2_inode_scan scan = NULL; | |
551 | char *block_buf = NULL; | |
8bf191e8 | 552 | #ifdef RESOURCE_TRACK |
3839e657 | 553 | struct resource_track rtrack; |
8bf191e8 | 554 | #endif |
1e3472c5 | 555 | unsigned char frag, fsize; |
21c84b71 | 556 | struct problem_context pctx; |
f8188fff | 557 | struct scan_callback_struct scan_struct; |
5dd8f963 | 558 | struct ext2_super_block *sb = ctx->fs->super; |
e94bc631 | 559 | const char *old_op; |
830b44f4 | 560 | unsigned int save_type; |
15d482ba | 561 | int imagic_fs, extent_fs; |
be93ef0c | 562 | int busted_fs_time = 0; |
cebe48a1 | 563 | int inode_size; |
efc6f628 | 564 | |
6d96b00d | 565 | init_resource_track(&rtrack, ctx->fs->io); |
1b6bf175 TT |
566 | clear_problem_context(&pctx); |
567 | ||
568 | if (!(ctx->options & E2F_OPT_PREEN)) | |
569 | fix_problem(ctx, PR_1_PASS_HEADER, &pctx); | |
3839e657 | 570 | |
3214a453 TT |
571 | if ((fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) && |
572 | !(ctx->options & E2F_OPT_NO)) { | |
b7a00563 TT |
573 | if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50)) |
574 | ctx->dirs_to_hash = 0; | |
575 | } | |
576 | ||
3839e657 TT |
577 | #ifdef MTRACE |
578 | mtrace_print("Pass 1"); | |
579 | #endif | |
580 | ||
932a489c AD |
581 | #define EXT2_BPP(bits) (1ULL << ((bits) - 2)) |
582 | ||
583 | for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) { | |
584 | max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i); | |
585 | max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i); | |
586 | max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i); | |
66df1468 | 587 | max_sizes = (max_sizes * (1UL << i)); |
7823dd65 | 588 | ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes; |
9d1bd3de TT |
589 | } |
590 | #undef EXT2_BPP | |
6fdc7a32 | 591 | |
6fdc7a32 | 592 | imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES); |
15d482ba | 593 | extent_fs = (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS); |
6fdc7a32 | 594 | |
3839e657 TT |
595 | /* |
596 | * Allocate bitmaps structures | |
597 | */ | |
830b44f4 TT |
598 | pctx.errcode = e2fsck_allocate_inode_bitmap(fs, _("in-use inode map"), |
599 | EXT2FS_BMAP64_RBTREE, | |
600 | "inode_used_map", | |
601 | &ctx->inode_used_map); | |
1b6bf175 TT |
602 | if (pctx.errcode) { |
603 | pctx.num = 1; | |
604 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
08b21301 TT |
605 | ctx->flags |= E2F_FLAG_ABORT; |
606 | return; | |
3839e657 | 607 | } |
830b44f4 TT |
608 | pctx.errcode = e2fsck_allocate_inode_bitmap(fs, |
609 | _("directory inode map"), | |
610 | EXT2FS_BMAP64_AUTODIR, | |
611 | "inode_dir_map", &ctx->inode_dir_map); | |
1b6bf175 TT |
612 | if (pctx.errcode) { |
613 | pctx.num = 2; | |
614 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
08b21301 TT |
615 | ctx->flags |= E2F_FLAG_ABORT; |
616 | return; | |
3839e657 | 617 | } |
830b44f4 TT |
618 | pctx.errcode = e2fsck_allocate_inode_bitmap(fs, |
619 | _("regular file inode map"), EXT2FS_BMAP64_RBTREE, | |
620 | "inode_reg_map", &ctx->inode_reg_map); | |
aa4115a4 TT |
621 | if (pctx.errcode) { |
622 | pctx.num = 6; | |
623 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
624 | ctx->flags |= E2F_FLAG_ABORT; | |
625 | return; | |
626 | } | |
830b44f4 TT |
627 | pctx.errcode = e2fsck_allocate_subcluster_bitmap(fs, |
628 | _("in-use block map"), EXT2FS_BMAP64_RBTREE, | |
629 | "block_found_map", &ctx->block_found_map); | |
1b6bf175 TT |
630 | if (pctx.errcode) { |
631 | pctx.num = 1; | |
632 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx); | |
08b21301 TT |
633 | ctx->flags |= E2F_FLAG_ABORT; |
634 | return; | |
3839e657 | 635 | } |
34b9f796 | 636 | e2fsck_setup_tdb_icount(ctx, 0, &ctx->inode_link_info); |
830b44f4 TT |
637 | if (!ctx->inode_link_info) { |
638 | e2fsck_set_bitmap_type(fs, EXT2FS_BMAP64_RBTREE, | |
639 | "inode_link_info", &save_type); | |
34b9f796 TT |
640 | pctx.errcode = ext2fs_create_icount2(fs, 0, 0, 0, |
641 | &ctx->inode_link_info); | |
830b44f4 TT |
642 | fs->default_bitmap_type = save_type; |
643 | } | |
644 | ||
1b6bf175 TT |
645 | if (pctx.errcode) { |
646 | fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx); | |
08b21301 TT |
647 | ctx->flags |= E2F_FLAG_ABORT; |
648 | return; | |
21c84b71 | 649 | } |
cebe48a1 TT |
650 | inode_size = EXT2_INODE_SIZE(fs->super); |
651 | inode = (struct ext2_inode *) | |
652 | e2fsck_allocate_memory(ctx, inode_size, "scratch inode"); | |
653 | ||
54dc7ca2 TT |
654 | inodes_to_process = (struct process_inode_block *) |
655 | e2fsck_allocate_memory(ctx, | |
656 | (ctx->process_inode_size * | |
657 | sizeof(struct process_inode_block)), | |
658 | "array of inodes to process"); | |
3839e657 TT |
659 | process_inode_count = 0; |
660 | ||
1b6bf175 TT |
661 | pctx.errcode = ext2fs_init_dblist(fs, 0); |
662 | if (pctx.errcode) { | |
663 | fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx); | |
08b21301 | 664 | ctx->flags |= E2F_FLAG_ABORT; |
125f76e7 | 665 | goto endit; |
21c84b71 | 666 | } |
3839e657 | 667 | |
9cbfb8d0 TT |
668 | /* |
669 | * If the last orphan field is set, clear it, since the pass1 | |
670 | * processing will automatically find and clear the orphans. | |
671 | * In the future, we may want to try using the last_orphan | |
672 | * linked list ourselves, but for now, we clear it so that the | |
673 | * ext3 mount code won't get confused. | |
674 | */ | |
675 | if (!(ctx->options & E2F_OPT_READONLY)) { | |
676 | if (fs->super->s_last_orphan) { | |
677 | fs->super->s_last_orphan = 0; | |
678 | ext2fs_mark_super_dirty(fs); | |
679 | } | |
680 | } | |
681 | ||
1b6bf175 | 682 | mark_table_blocks(ctx); |
44fe08f1 TT |
683 | pctx.errcode = ext2fs_convert_subcluster_bitmap(fs, |
684 | &ctx->block_found_map); | |
685 | if (pctx.errcode) { | |
686 | fix_problem(ctx, PR_1_CONVERT_SUBCLUSTER, &pctx); | |
687 | ctx->flags |= E2F_FLAG_ABORT; | |
125f76e7 | 688 | goto endit; |
44fe08f1 | 689 | } |
54dc7ca2 TT |
690 | block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3, |
691 | "block interate buffer"); | |
e72a9ba3 | 692 | e2fsck_use_inode_shortcuts(ctx, 1); |
e94bc631 | 693 | old_op = ehandler_operation(_("opening inode scan")); |
efc6f628 | 694 | pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks, |
1b6bf175 | 695 | &scan); |
e94bc631 | 696 | ehandler_operation(old_op); |
1b6bf175 TT |
697 | if (pctx.errcode) { |
698 | fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx); | |
08b21301 | 699 | ctx->flags |= E2F_FLAG_ABORT; |
125f76e7 | 700 | goto endit; |
3839e657 | 701 | } |
21c84b71 | 702 | ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE, 0); |
cebe48a1 | 703 | ctx->stashed_inode = inode; |
f8188fff TT |
704 | scan_struct.ctx = ctx; |
705 | scan_struct.block_buf = block_buf; | |
706 | ext2fs_set_inode_callback(scan, scan_callback, &scan_struct); | |
125f76e7 TT |
707 | if (ctx->progress && ((ctx->progress)(ctx, 1, 0, |
708 | ctx->fs->group_desc_count))) | |
709 | goto endit; | |
4147d9f0 TT |
710 | if ((fs->super->s_wtime < fs->super->s_inodes_count) || |
711 | (fs->super->s_mtime < fs->super->s_inodes_count)) | |
be93ef0c TT |
712 | busted_fs_time = 1; |
713 | ||
0f5eba75 | 714 | if ((fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) && |
2fe2d408 AD |
715 | fs->super->s_mmp_block > fs->super->s_first_data_block && |
716 | fs->super->s_mmp_block < ext2fs_blocks_count(fs->super)) | |
0f5eba75 AD |
717 | ext2fs_mark_block_bitmap2(ctx->block_found_map, |
718 | fs->super->s_mmp_block); | |
719 | ||
d237a78e | 720 | while (1) { |
0f5eba75 AD |
721 | if (ino % (fs->super->s_inodes_per_group * 4) == 1) { |
722 | if (e2fsck_mmp_update(fs)) | |
723 | fatal_error(ctx, 0); | |
724 | } | |
e94bc631 | 725 | old_op = ehandler_operation(_("getting next inode from scan")); |
efc6f628 | 726 | pctx.errcode = ext2fs_get_next_inode_full(scan, &ino, |
cebe48a1 | 727 | inode, inode_size); |
e94bc631 | 728 | ehandler_operation(old_op); |
d237a78e TT |
729 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
730 | return; | |
731 | if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) { | |
732 | if (!ctx->inode_bb_map) | |
733 | alloc_bb_map(ctx); | |
c5d2f50d VAH |
734 | ext2fs_mark_inode_bitmap2(ctx->inode_bb_map, ino); |
735 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); | |
d237a78e TT |
736 | continue; |
737 | } | |
738 | if (pctx.errcode) { | |
739 | fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx); | |
740 | ctx->flags |= E2F_FLAG_ABORT; | |
125f76e7 | 741 | goto endit; |
d237a78e TT |
742 | } |
743 | if (!ino) | |
744 | break; | |
21c84b71 | 745 | pctx.ino = ino; |
cebe48a1 | 746 | pctx.inode = inode; |
1b6bf175 | 747 | ctx->stashed_ino = ino; |
cebe48a1 | 748 | if (inode->i_links_count) { |
efc6f628 | 749 | pctx.errcode = ext2fs_icount_store(ctx->inode_link_info, |
cebe48a1 | 750 | ino, inode->i_links_count); |
1b6bf175 | 751 | if (pctx.errcode) { |
cebe48a1 | 752 | pctx.num = inode->i_links_count; |
1b6bf175 | 753 | fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx); |
08b21301 | 754 | ctx->flags |= E2F_FLAG_ABORT; |
125f76e7 | 755 | goto endit; |
1b6bf175 TT |
756 | } |
757 | } | |
dfc870c7 ES |
758 | |
759 | /* | |
760 | * Test for incorrect extent flag settings. | |
761 | * | |
762 | * On big-endian machines we must be careful: | |
763 | * When the inode is read, the i_block array is not swapped | |
764 | * if the extent flag is set. Therefore if we are testing | |
765 | * for or fixing a wrongly-set flag, we must potentially | |
766 | * (un)swap before testing, or after fixing. | |
767 | */ | |
768 | ||
769 | /* | |
770 | * In this case the extents flag was set when read, so | |
771 | * extent_header_verify is ok. If the inode is cleared, | |
772 | * no need to swap... so no extra swapping here. | |
773 | */ | |
efc6f628 | 774 | if ((inode->i_flags & EXT4_EXTENTS_FL) && !extent_fs && |
15d482ba TT |
775 | (inode->i_links_count || (ino == EXT2_BAD_INO) || |
776 | (ino == EXT2_ROOT_INO) || (ino == EXT2_JOURNAL_INO))) { | |
efc6f628 | 777 | if ((ext2fs_extent_header_verify(inode->i_block, |
15d482ba TT |
778 | sizeof(inode->i_block)) == 0) && |
779 | fix_problem(ctx, PR_1_EXTENT_FEATURE, &pctx)) { | |
780 | sb->s_feature_incompat |= EXT3_FEATURE_INCOMPAT_EXTENTS; | |
781 | ext2fs_mark_super_dirty(fs); | |
782 | extent_fs = 1; | |
783 | } else if (fix_problem(ctx, PR_1_EXTENTS_SET, &pctx)) { | |
784 | clear_inode: | |
785 | e2fsck_clear_inode(ctx, ino, inode, 0, "pass1"); | |
786 | if (ino == EXT2_BAD_INO) | |
c5d2f50d | 787 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, |
15d482ba TT |
788 | ino); |
789 | continue; | |
790 | } | |
791 | } | |
792 | ||
dfc870c7 ES |
793 | /* |
794 | * For big-endian machines: | |
795 | * If the inode didn't have the extents flag set when it | |
796 | * was read, then the i_blocks array was swapped. To test | |
797 | * as an extents header, we must swap it back first. | |
798 | * IF we then set the extents flag, the entire i_block | |
799 | * array must be un/re-swapped to make it proper extents data. | |
800 | */ | |
15d482ba TT |
801 | if (extent_fs && !(inode->i_flags & EXT4_EXTENTS_FL) && |
802 | (inode->i_links_count || (ino == EXT2_BAD_INO) || | |
803 | (ino == EXT2_ROOT_INO) || (ino == EXT2_JOURNAL_INO)) && | |
804 | (LINUX_S_ISREG(inode->i_mode) || | |
dfc870c7 ES |
805 | LINUX_S_ISDIR(inode->i_mode))) { |
806 | void *ehp; | |
807 | #ifdef WORDS_BIGENDIAN | |
808 | __u32 tmp_block[EXT2_N_BLOCKS]; | |
809 | ||
810 | for (i = 0; i < EXT2_N_BLOCKS; i++) | |
811 | tmp_block[i] = ext2fs_swab32(inode->i_block[i]); | |
812 | ehp = tmp_block; | |
813 | #else | |
814 | ehp = inode->i_block; | |
815 | #endif | |
efc6f628 | 816 | if ((ext2fs_extent_header_verify(ehp, |
dfc870c7 ES |
817 | sizeof(inode->i_block)) == 0) && |
818 | (fix_problem(ctx, PR_1_UNSET_EXTENT_FL, &pctx))) { | |
15d482ba | 819 | inode->i_flags |= EXT4_EXTENTS_FL; |
dfc870c7 | 820 | #ifdef WORDS_BIGENDIAN |
efc6f628 | 821 | memcpy(inode->i_block, tmp_block, |
dfc870c7 ES |
822 | sizeof(inode->i_block)); |
823 | #endif | |
15d482ba TT |
824 | e2fsck_write_inode(ctx, ino, inode, "pass1"); |
825 | } | |
826 | } | |
827 | ||
3839e657 TT |
828 | if (ino == EXT2_BAD_INO) { |
829 | struct process_block_struct pb; | |
efc6f628 | 830 | |
96a8afa7 TT |
831 | if ((inode->i_mode || inode->i_uid || inode->i_gid || |
832 | inode->i_links_count || inode->i_file_acl) && | |
833 | fix_problem(ctx, PR_1_INVALID_BAD_INODE, &pctx)) { | |
834 | memset(inode, 0, sizeof(struct ext2_inode)); | |
835 | e2fsck_write_inode(ctx, ino, inode, | |
836 | "clear bad inode"); | |
837 | } | |
838 | ||
000ba404 TT |
839 | pctx.errcode = ext2fs_copy_bitmap(ctx->block_found_map, |
840 | &pb.fs_meta_blocks); | |
841 | if (pctx.errcode) { | |
842 | pctx.num = 4; | |
843 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx); | |
844 | ctx->flags |= E2F_FLAG_ABORT; | |
125f76e7 | 845 | goto endit; |
000ba404 | 846 | } |
3839e657 TT |
847 | pb.ino = EXT2_BAD_INO; |
848 | pb.num_blocks = pb.last_block = 0; | |
4dbe79bc | 849 | pb.last_db_block = -1; |
f3db3566 | 850 | pb.num_illegal_blocks = 0; |
21c84b71 | 851 | pb.suppress = 0; pb.clear = 0; pb.is_dir = 0; |
000ba404 | 852 | pb.is_reg = 0; pb.fragmented = 0; pb.bbcheck = 0; |
cebe48a1 | 853 | pb.inode = inode; |
21c84b71 | 854 | pb.pctx = &pctx; |
1b6bf175 | 855 | pb.ctx = ctx; |
6dc64392 | 856 | pctx.errcode = ext2fs_block_iterate3(fs, ino, 0, |
1b6bf175 | 857 | block_buf, process_bad_block, &pb); |
000ba404 | 858 | ext2fs_free_block_bitmap(pb.fs_meta_blocks); |
1b6bf175 TT |
859 | if (pctx.errcode) { |
860 | fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx); | |
08b21301 | 861 | ctx->flags |= E2F_FLAG_ABORT; |
125f76e7 | 862 | goto endit; |
1b6bf175 | 863 | } |
000ba404 TT |
864 | if (pb.bbcheck) |
865 | if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK_PROMPT, &pctx)) { | |
866 | ctx->flags |= E2F_FLAG_ABORT; | |
125f76e7 | 867 | goto endit; |
000ba404 | 868 | } |
c5d2f50d | 869 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); |
21c84b71 | 870 | clear_problem_context(&pctx); |
d237a78e | 871 | continue; |
a9ca2016 | 872 | } else if (ino == EXT2_ROOT_INO) { |
3839e657 TT |
873 | /* |
874 | * Make sure the root inode is a directory; if | |
875 | * not, offer to clear it. It will be | |
876 | * regnerated in pass #3. | |
877 | */ | |
cebe48a1 | 878 | if (!LINUX_S_ISDIR(inode->i_mode)) { |
15d482ba TT |
879 | if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) |
880 | goto clear_inode; | |
3839e657 TT |
881 | } |
882 | /* | |
883 | * If dtime is set, offer to clear it. mke2fs | |
884 | * version 0.2b created filesystems with the | |
885 | * dtime field set for the root and lost+found | |
886 | * directories. We won't worry about | |
887 | * /lost+found, since that can be regenerated | |
888 | * easily. But we will fix the root directory | |
889 | * as a special case. | |
890 | */ | |
cebe48a1 | 891 | if (inode->i_dtime && inode->i_links_count) { |
1b6bf175 | 892 | if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) { |
cebe48a1 TT |
893 | inode->i_dtime = 0; |
894 | e2fsck_write_inode(ctx, ino, inode, | |
f3db3566 | 895 | "pass1"); |
21c84b71 | 896 | } |
3839e657 | 897 | } |
a9ca2016 | 898 | } else if (ino == EXT2_JOURNAL_INO) { |
c5d2f50d | 899 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); |
f18996c8 | 900 | if (fs->super->s_journal_inum == EXT2_JOURNAL_INO) { |
cebe48a1 | 901 | if (!LINUX_S_ISREG(inode->i_mode) && |
a9ca2016 TT |
902 | fix_problem(ctx, PR_1_JOURNAL_BAD_MODE, |
903 | &pctx)) { | |
cebe48a1 TT |
904 | inode->i_mode = LINUX_S_IFREG; |
905 | e2fsck_write_inode(ctx, ino, inode, | |
a9ca2016 TT |
906 | "pass1"); |
907 | } | |
f18996c8 | 908 | check_blocks(ctx, &pctx, block_buf); |
d237a78e | 909 | continue; |
f18996c8 | 910 | } |
6dc64392 | 911 | if ((inode->i_links_count || |
cebe48a1 | 912 | inode->i_blocks || inode->i_block[0]) && |
efc6f628 | 913 | fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR, |
f18996c8 | 914 | &pctx)) { |
cebe48a1 | 915 | memset(inode, 0, inode_size); |
a9ca2016 TT |
916 | ext2fs_icount_store(ctx->inode_link_info, |
917 | ino, 0); | |
efc6f628 | 918 | e2fsck_write_inode_full(ctx, ino, inode, |
cebe48a1 | 919 | inode_size, "pass1"); |
f18996c8 | 920 | } |
624e4a64 AK |
921 | } else if ((ino == EXT4_USR_QUOTA_INO) || |
922 | (ino == EXT4_GRP_QUOTA_INO)) { | |
923 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); | |
924 | if ((fs->super->s_feature_ro_compat & | |
925 | EXT4_FEATURE_RO_COMPAT_QUOTA) && | |
9b01faa8 TT |
926 | ((fs->super->s_usr_quota_inum == ino) || |
927 | (fs->super->s_grp_quota_inum == ino))) { | |
624e4a64 AK |
928 | if (!LINUX_S_ISREG(inode->i_mode) && |
929 | fix_problem(ctx, PR_1_QUOTA_BAD_MODE, | |
930 | &pctx)) { | |
931 | inode->i_mode = LINUX_S_IFREG; | |
932 | e2fsck_write_inode(ctx, ino, inode, | |
933 | "pass1"); | |
934 | } | |
935 | check_blocks(ctx, &pctx, block_buf); | |
936 | continue; | |
937 | } | |
938 | if ((inode->i_links_count || | |
939 | inode->i_blocks || inode->i_block[0]) && | |
940 | fix_problem(ctx, PR_1_QUOTA_INODE_NOT_CLEAR, | |
941 | &pctx)) { | |
942 | memset(inode, 0, inode_size); | |
943 | ext2fs_icount_store(ctx->inode_link_info, | |
944 | ino, 0); | |
945 | e2fsck_write_inode_full(ctx, ino, inode, | |
946 | inode_size, "pass1"); | |
947 | } | |
a9ca2016 | 948 | } else if (ino < EXT2_FIRST_INODE(fs->super)) { |
3c7c6d73 | 949 | problem_t problem = 0; |
efc6f628 | 950 | |
c5d2f50d | 951 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); |
53ef44c4 | 952 | if (ino == EXT2_BOOT_LOADER_INO) { |
cebe48a1 | 953 | if (LINUX_S_ISDIR(inode->i_mode)) |
b09a4b0c | 954 | problem = PR_1_RESERVED_BAD_MODE; |
b1f204f7 | 955 | } else if (ino == EXT2_RESIZE_INO) { |
cebe48a1 TT |
956 | if (inode->i_mode && |
957 | !LINUX_S_ISREG(inode->i_mode)) | |
b1f204f7 | 958 | problem = PR_1_RESERVED_BAD_MODE; |
53ef44c4 | 959 | } else { |
cebe48a1 | 960 | if (inode->i_mode != 0) |
b09a4b0c | 961 | problem = PR_1_RESERVED_BAD_MODE; |
b09a4b0c TT |
962 | } |
963 | if (problem) { | |
964 | if (fix_problem(ctx, problem, &pctx)) { | |
cebe48a1 TT |
965 | inode->i_mode = 0; |
966 | e2fsck_write_inode(ctx, ino, inode, | |
50e1e10f | 967 | "pass1"); |
21c84b71 | 968 | } |
50e1e10f | 969 | } |
1b6bf175 | 970 | check_blocks(ctx, &pctx, block_buf); |
d237a78e | 971 | continue; |
3839e657 | 972 | } |
624e4a64 | 973 | |
21afac09 TT |
974 | /* |
975 | * Check for inodes who might have been part of the | |
976 | * orphaned list linked list. They should have gotten | |
977 | * dealt with by now, unless the list had somehow been | |
978 | * corrupted. | |
efc6f628 | 979 | * |
21afac09 TT |
980 | * FIXME: In the future, inodes which are still in use |
981 | * (and which are therefore) pending truncation should | |
982 | * be handled specially. Right now we just clear the | |
983 | * dtime field, and the normal e2fsck handling of | |
984 | * inodes where i_size and the inode blocks are | |
985 | * inconsistent is to fix i_size, instead of releasing | |
986 | * the extra blocks. This won't catch the inodes that | |
987 | * was at the end of the orphan list, but it's better | |
988 | * than nothing. The right answer is that there | |
989 | * shouldn't be any bugs in the orphan list handling. :-) | |
990 | */ | |
cebe48a1 TT |
991 | if (inode->i_dtime && !busted_fs_time && |
992 | inode->i_dtime < ctx->fs->super->s_inodes_count) { | |
21afac09 | 993 | if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) { |
cebe48a1 | 994 | inode->i_dtime = inode->i_links_count ? |
1f3ad14a | 995 | 0 : ctx->now; |
cebe48a1 | 996 | e2fsck_write_inode(ctx, ino, inode, |
21afac09 TT |
997 | "pass1"); |
998 | } | |
999 | } | |
efc6f628 | 1000 | |
3839e657 TT |
1001 | /* |
1002 | * This code assumes that deleted inodes have | |
efc6f628 | 1003 | * i_links_count set to 0. |
3839e657 | 1004 | */ |
cebe48a1 TT |
1005 | if (!inode->i_links_count) { |
1006 | if (!inode->i_dtime && inode->i_mode) { | |
1b6bf175 | 1007 | if (fix_problem(ctx, |
21c84b71 | 1008 | PR_1_ZERO_DTIME, &pctx)) { |
1f3ad14a | 1009 | inode->i_dtime = ctx->now; |
cebe48a1 | 1010 | e2fsck_write_inode(ctx, ino, inode, |
f3db3566 | 1011 | "pass1"); |
21c84b71 | 1012 | } |
3839e657 | 1013 | } |
d237a78e | 1014 | continue; |
3839e657 TT |
1015 | } |
1016 | /* | |
1e3472c5 | 1017 | * n.b. 0.3c ext2fs code didn't clear i_links_count for |
3839e657 | 1018 | * deleted files. Oops. |
1e3472c5 TT |
1019 | * |
1020 | * Since all new ext2 implementations get this right, | |
1021 | * we now assume that the case of non-zero | |
1022 | * i_links_count and non-zero dtime means that we | |
1023 | * should keep the file, not delete it. | |
efc6f628 | 1024 | * |
3839e657 | 1025 | */ |
cebe48a1 | 1026 | if (inode->i_dtime) { |
1b6bf175 | 1027 | if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) { |
cebe48a1 TT |
1028 | inode->i_dtime = 0; |
1029 | e2fsck_write_inode(ctx, ino, inode, "pass1"); | |
21c84b71 | 1030 | } |
3839e657 | 1031 | } |
efc6f628 | 1032 | |
c5d2f50d | 1033 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); |
1e3472c5 | 1034 | switch (fs->super->s_creator_os) { |
1e3472c5 | 1035 | case EXT2_OS_HURD: |
cebe48a1 TT |
1036 | frag = inode->osd2.hurd2.h_i_frag; |
1037 | fsize = inode->osd2.hurd2.h_i_fsize; | |
1e3472c5 | 1038 | break; |
1e3472c5 TT |
1039 | default: |
1040 | frag = fsize = 0; | |
1041 | } | |
efc6f628 | 1042 | |
cebe48a1 TT |
1043 | if (inode->i_faddr || frag || fsize || |
1044 | (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl)) | |
fdbdea09 | 1045 | mark_inode_bad(ctx, ino); |
911ec626 TT |
1046 | if (!(fs->super->s_feature_incompat & |
1047 | EXT4_FEATURE_INCOMPAT_64BIT) && | |
1048 | inode->osd2.linux2.l_i_file_acl_high != 0) | |
1049 | mark_inode_bad(ctx, ino); | |
5d17119d | 1050 | if ((fs->super->s_creator_os == EXT2_OS_LINUX) && |
efc6f628 | 1051 | !(fs->super->s_feature_ro_compat & |
5d17119d TT |
1052 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE) && |
1053 | (inode->osd2.linux2.l_i_blocks_hi != 0)) | |
1054 | mark_inode_bad(ctx, ino); | |
cebe48a1 | 1055 | if (inode->i_flags & EXT2_IMAGIC_FL) { |
6fdc7a32 TT |
1056 | if (imagic_fs) { |
1057 | if (!ctx->inode_imagic_map) | |
1058 | alloc_imagic_map(ctx); | |
c5d2f50d | 1059 | ext2fs_mark_inode_bitmap2(ctx->inode_imagic_map, |
6fdc7a32 TT |
1060 | ino); |
1061 | } else { | |
1062 | if (fix_problem(ctx, PR_1_SET_IMAGIC, &pctx)) { | |
cebe48a1 | 1063 | inode->i_flags &= ~EXT2_IMAGIC_FL; |
6fdc7a32 | 1064 | e2fsck_write_inode(ctx, ino, |
cebe48a1 | 1065 | inode, "pass1"); |
6fdc7a32 TT |
1066 | } |
1067 | } | |
aa4115a4 | 1068 | } |
cebe48a1 TT |
1069 | |
1070 | check_inode_extra_space(ctx, &pctx); | |
fbc3f901 | 1071 | check_is_really_dir(ctx, &pctx, block_buf); |
cebe48a1 | 1072 | |
dfc870c7 | 1073 | /* |
0c80c44b | 1074 | * ext2fs_inode_has_valid_blocks2 does not actually look |
dfc870c7 ES |
1075 | * at i_block[] values, so not endian-sensitive here. |
1076 | */ | |
cb23cad5 TT |
1077 | if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL) && |
1078 | LINUX_S_ISLNK(inode->i_mode) && | |
0c80c44b | 1079 | !ext2fs_inode_has_valid_blocks2(fs, inode) && |
cb23cad5 TT |
1080 | fix_problem(ctx, PR_1_FAST_SYMLINK_EXTENT_FL, &pctx)) { |
1081 | inode->i_flags &= ~EXT4_EXTENTS_FL; | |
1082 | e2fsck_write_inode(ctx, ino, inode, "pass1"); | |
1083 | } | |
1084 | ||
cebe48a1 | 1085 | if (LINUX_S_ISDIR(inode->i_mode)) { |
c5d2f50d | 1086 | ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino); |
08b21301 | 1087 | e2fsck_add_dir_info(ctx, ino, 0); |
1b6bf175 | 1088 | ctx->fs_directory_count++; |
cebe48a1 | 1089 | } else if (LINUX_S_ISREG (inode->i_mode)) { |
c5d2f50d | 1090 | ext2fs_mark_inode_bitmap2(ctx->inode_reg_map, ino); |
1b6bf175 | 1091 | ctx->fs_regular_count++; |
cebe48a1 TT |
1092 | } else if (LINUX_S_ISCHR (inode->i_mode) && |
1093 | e2fsck_pass1_check_device_inode(fs, inode)) { | |
6fdc7a32 | 1094 | check_immutable(ctx, &pctx); |
d647a1ea | 1095 | check_size(ctx, &pctx); |
1b6bf175 | 1096 | ctx->fs_chardev_count++; |
cebe48a1 TT |
1097 | } else if (LINUX_S_ISBLK (inode->i_mode) && |
1098 | e2fsck_pass1_check_device_inode(fs, inode)) { | |
6fdc7a32 | 1099 | check_immutable(ctx, &pctx); |
d647a1ea | 1100 | check_size(ctx, &pctx); |
1b6bf175 | 1101 | ctx->fs_blockdev_count++; |
cebe48a1 | 1102 | } else if (LINUX_S_ISLNK (inode->i_mode) && |
efc6f628 | 1103 | e2fsck_pass1_check_symlink(fs, ino, inode, |
7cadc577 | 1104 | block_buf)) { |
fd77b2c7 | 1105 | check_immutable(ctx, &pctx); |
1b6bf175 | 1106 | ctx->fs_symlinks_count++; |
cebe48a1 | 1107 | if (ext2fs_inode_data_blocks(fs, inode) == 0) { |
1b6bf175 | 1108 | ctx->fs_fast_symlinks_count++; |
0684a4f3 | 1109 | check_blocks(ctx, &pctx, block_buf); |
d237a78e | 1110 | continue; |
21c84b71 | 1111 | } |
3839e657 | 1112 | } |
cebe48a1 TT |
1113 | else if (LINUX_S_ISFIFO (inode->i_mode) && |
1114 | e2fsck_pass1_check_device_inode(fs, inode)) { | |
6fdc7a32 | 1115 | check_immutable(ctx, &pctx); |
d647a1ea | 1116 | check_size(ctx, &pctx); |
1b6bf175 | 1117 | ctx->fs_fifo_count++; |
cebe48a1 TT |
1118 | } else if ((LINUX_S_ISSOCK (inode->i_mode)) && |
1119 | e2fsck_pass1_check_device_inode(fs, inode)) { | |
6fdc7a32 | 1120 | check_immutable(ctx, &pctx); |
d647a1ea TT |
1121 | check_size(ctx, &pctx); |
1122 | ctx->fs_sockets_count++; | |
fdbdea09 TT |
1123 | } else |
1124 | mark_inode_bad(ctx, ino); | |
8da6d1a1 TT |
1125 | if (!(inode->i_flags & EXT4_EXTENTS_FL)) { |
1126 | if (inode->i_block[EXT2_IND_BLOCK]) | |
1127 | ctx->fs_ind_count++; | |
1128 | if (inode->i_block[EXT2_DIND_BLOCK]) | |
1129 | ctx->fs_dind_count++; | |
1130 | if (inode->i_block[EXT2_TIND_BLOCK]) | |
1131 | ctx->fs_tind_count++; | |
1132 | } | |
15d482ba TT |
1133 | if (!(inode->i_flags & EXT4_EXTENTS_FL) && |
1134 | (inode->i_block[EXT2_IND_BLOCK] || | |
1135 | inode->i_block[EXT2_DIND_BLOCK] || | |
1136 | inode->i_block[EXT2_TIND_BLOCK] || | |
0c80c44b | 1137 | ext2fs_file_acl_block(fs, inode))) { |
3839e657 | 1138 | inodes_to_process[process_inode_count].ino = ino; |
cebe48a1 | 1139 | inodes_to_process[process_inode_count].inode = *inode; |
3839e657 | 1140 | process_inode_count++; |
f3db3566 | 1141 | } else |
1b6bf175 | 1142 | check_blocks(ctx, &pctx, block_buf); |
3839e657 | 1143 | |
a02ce9df | 1144 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
125f76e7 | 1145 | goto endit; |
08b21301 TT |
1146 | |
1147 | if (process_inode_count >= ctx->process_inode_size) { | |
1b6bf175 | 1148 | process_inodes(ctx, block_buf); |
08b21301 | 1149 | |
a02ce9df | 1150 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
125f76e7 | 1151 | goto endit; |
08b21301 | 1152 | } |
3839e657 | 1153 | } |
1b6bf175 | 1154 | process_inodes(ctx, block_buf); |
3839e657 | 1155 | ext2fs_close_inode_scan(scan); |
125f76e7 | 1156 | scan = NULL; |
3839e657 | 1157 | |
e8a3ee62 TT |
1158 | /* |
1159 | * If any extended attribute blocks' reference counts need to | |
1160 | * be adjusted, either up (ctx->refcount_extra), or down | |
1161 | * (ctx->refcount), then fix them. | |
1162 | */ | |
1163 | if (ctx->refcount) { | |
1164 | adjust_extattr_refcount(ctx, ctx->refcount, block_buf, -1); | |
1165 | ea_refcount_free(ctx->refcount); | |
1166 | ctx->refcount = 0; | |
1167 | } | |
1168 | if (ctx->refcount_extra) { | |
1169 | adjust_extattr_refcount(ctx, ctx->refcount_extra, | |
1170 | block_buf, +1); | |
1171 | ea_refcount_free(ctx->refcount_extra); | |
1172 | ctx->refcount_extra = 0; | |
1173 | } | |
efc6f628 | 1174 | |
1b6bf175 TT |
1175 | if (ctx->invalid_bitmaps) |
1176 | handle_fs_bad_blocks(ctx); | |
f3db3566 | 1177 | |
24ceb248 TT |
1178 | /* We don't need the block_ea_map any more */ |
1179 | if (ctx->block_ea_map) { | |
1180 | ext2fs_free_block_bitmap(ctx->block_ea_map); | |
1181 | ctx->block_ea_map = 0; | |
1182 | } | |
1183 | ||
c3ffaf83 TT |
1184 | if (ctx->flags & E2F_FLAG_RESIZE_INODE) { |
1185 | ext2fs_block_bitmap save_bmap; | |
c3ffaf83 TT |
1186 | |
1187 | save_bmap = fs->block_map; | |
1188 | fs->block_map = ctx->block_found_map; | |
1189 | clear_problem_context(&pctx); | |
1190 | pctx.errcode = ext2fs_create_resize_inode(fs); | |
1191 | if (pctx.errcode) { | |
a6217f5a TT |
1192 | if (!fix_problem(ctx, PR_1_RESIZE_INODE_CREATE, |
1193 | &pctx)) { | |
1194 | ctx->flags |= E2F_FLAG_ABORT; | |
125f76e7 | 1195 | goto endit; |
a6217f5a TT |
1196 | } |
1197 | pctx.errcode = 0; | |
1198 | } | |
1199 | if (!pctx.errcode) { | |
1200 | e2fsck_read_inode(ctx, EXT2_RESIZE_INO, inode, | |
1201 | "recreate inode"); | |
1202 | inode->i_mtime = ctx->now; | |
1203 | e2fsck_write_inode(ctx, EXT2_RESIZE_INO, inode, | |
1204 | "recreate inode"); | |
c3ffaf83 TT |
1205 | } |
1206 | fs->block_map = save_bmap; | |
1207 | ctx->flags &= ~E2F_FLAG_RESIZE_INODE; | |
1208 | } | |
efc6f628 | 1209 | |
08b21301 | 1210 | if (ctx->flags & E2F_FLAG_RESTART) { |
aa4115a4 TT |
1211 | /* |
1212 | * Only the master copy of the superblock and block | |
1213 | * group descriptors are going to be written during a | |
1214 | * restart, so set the superblock to be used to be the | |
1215 | * master superblock. | |
1216 | */ | |
1217 | ctx->use_superblock = 0; | |
f3db3566 TT |
1218 | unwind_pass1(fs); |
1219 | goto endit; | |
1220 | } | |
1221 | ||
1b6bf175 TT |
1222 | if (ctx->block_dup_map) { |
1223 | if (ctx->options & E2F_OPT_PREEN) { | |
1224 | clear_problem_context(&pctx); | |
1225 | fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx); | |
3839e657 | 1226 | } |
08b21301 | 1227 | e2fsck_pass1_dupblocks(ctx, block_buf); |
3839e657 | 1228 | } |
c4e3d3f3 | 1229 | ext2fs_free_mem(&inodes_to_process); |
f3db3566 | 1230 | endit: |
e72a9ba3 | 1231 | e2fsck_use_inode_shortcuts(ctx, 0); |
efc6f628 | 1232 | |
125f76e7 TT |
1233 | if (scan) |
1234 | ext2fs_close_inode_scan(scan); | |
1235 | if (block_buf) | |
1236 | ext2fs_free_mem(&block_buf); | |
1237 | if (inode) | |
1238 | ext2fs_free_mem(&inode); | |
21c84b71 | 1239 | |
125f76e7 TT |
1240 | if ((ctx->flags & E2F_FLAG_SIGNAL_MASK) == 0) |
1241 | print_resource_track(ctx, _("Pass 1"), &rtrack, ctx->fs->io); | |
3839e657 TT |
1242 | } |
1243 | ||
f3db3566 TT |
1244 | /* |
1245 | * When the inode_scan routines call this callback at the end of the | |
1246 | * glock group, call process_inodes. | |
1247 | */ | |
efc6f628 | 1248 | static errcode_t scan_callback(ext2_filsys fs, |
54434927 | 1249 | ext2_inode_scan scan EXT2FS_ATTR((unused)), |
54dc7ca2 | 1250 | dgrp_t group, void * priv_data) |
f3db3566 | 1251 | { |
54dc7ca2 | 1252 | struct scan_callback_struct *scan_struct; |
f8188fff TT |
1253 | e2fsck_t ctx; |
1254 | ||
54dc7ca2 | 1255 | scan_struct = (struct scan_callback_struct *) priv_data; |
f8188fff | 1256 | ctx = scan_struct->ctx; |
efc6f628 | 1257 | |
54dc7ca2 | 1258 | process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf); |
f8188fff TT |
1259 | |
1260 | if (ctx->progress) | |
a02ce9df TT |
1261 | if ((ctx->progress)(ctx, 1, group+1, |
1262 | ctx->fs->group_desc_count)) | |
1263 | return EXT2_ET_CANCEL_REQUESTED; | |
f8188fff | 1264 | |
f3db3566 TT |
1265 | return 0; |
1266 | } | |
1267 | ||
3839e657 TT |
1268 | /* |
1269 | * Process the inodes in the "inodes to process" list. | |
1270 | */ | |
1b6bf175 | 1271 | static void process_inodes(e2fsck_t ctx, char *block_buf) |
3839e657 TT |
1272 | { |
1273 | int i; | |
1274 | struct ext2_inode *old_stashed_inode; | |
86c627ec | 1275 | ext2_ino_t old_stashed_ino; |
3839e657 TT |
1276 | const char *old_operation; |
1277 | char buf[80]; | |
21c84b71 | 1278 | struct problem_context pctx; |
efc6f628 | 1279 | |
3839e657 | 1280 | #if 0 |
f3db3566 | 1281 | printf("begin process_inodes: "); |
3839e657 | 1282 | #endif |
86a63e92 TT |
1283 | if (process_inode_count == 0) |
1284 | return; | |
3839e657 | 1285 | old_operation = ehandler_operation(0); |
1b6bf175 TT |
1286 | old_stashed_inode = ctx->stashed_inode; |
1287 | old_stashed_ino = ctx->stashed_ino; | |
3839e657 TT |
1288 | qsort(inodes_to_process, process_inode_count, |
1289 | sizeof(struct process_inode_block), process_inode_cmp); | |
21c84b71 | 1290 | clear_problem_context(&pctx); |
3839e657 | 1291 | for (i=0; i < process_inode_count; i++) { |
1b6bf175 TT |
1292 | pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode; |
1293 | pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino; | |
efc6f628 | 1294 | |
3839e657 | 1295 | #if 0 |
21c84b71 | 1296 | printf("%u ", pctx.ino); |
3839e657 | 1297 | #endif |
86c627ec | 1298 | sprintf(buf, _("reading indirect blocks of inode %u"), |
0c4a0726 | 1299 | pctx.ino); |
3839e657 | 1300 | ehandler_operation(buf); |
1b6bf175 | 1301 | check_blocks(ctx, &pctx, block_buf); |
a02ce9df | 1302 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
2df1f6aa | 1303 | break; |
3839e657 | 1304 | } |
1b6bf175 TT |
1305 | ctx->stashed_inode = old_stashed_inode; |
1306 | ctx->stashed_ino = old_stashed_ino; | |
3839e657 TT |
1307 | process_inode_count = 0; |
1308 | #if 0 | |
f3db3566 | 1309 | printf("end process inodes\n"); |
3839e657 TT |
1310 | #endif |
1311 | ehandler_operation(old_operation); | |
1312 | } | |
1313 | ||
4c77fe50 | 1314 | static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b) |
3839e657 TT |
1315 | { |
1316 | const struct process_inode_block *ib_a = | |
1317 | (const struct process_inode_block *) a; | |
1318 | const struct process_inode_block *ib_b = | |
1319 | (const struct process_inode_block *) b; | |
b5acdb6a | 1320 | int ret; |
efc6f628 | 1321 | |
b5acdb6a TT |
1322 | ret = (ib_a->inode.i_block[EXT2_IND_BLOCK] - |
1323 | ib_b->inode.i_block[EXT2_IND_BLOCK]); | |
1324 | if (ret == 0) | |
0c80c44b TT |
1325 | /* |
1326 | * We only call process_inodes() for non-extent | |
1327 | * inodes, so it's OK to pass NULL to | |
1328 | * ext2fs_file_acl_block() here. | |
1329 | */ | |
1330 | ret = ext2fs_file_acl_block(0, &(ib_a->inode)) - | |
1331 | ext2fs_file_acl_block(0, &(ib_b->inode)); | |
0eeec8ac TT |
1332 | if (ret == 0) |
1333 | ret = ib_a->ino - ib_b->ino; | |
b5acdb6a | 1334 | return ret; |
3839e657 TT |
1335 | } |
1336 | ||
3839e657 | 1337 | /* |
fdbdea09 | 1338 | * Mark an inode as being bad in some what |
3839e657 | 1339 | */ |
fdbdea09 | 1340 | static void mark_inode_bad(e2fsck_t ctx, ino_t ino) |
3839e657 | 1341 | { |
1b6bf175 | 1342 | struct problem_context pctx; |
fdbdea09 TT |
1343 | |
1344 | if (!ctx->inode_bad_map) { | |
1345 | clear_problem_context(&pctx); | |
efc6f628 | 1346 | |
830b44f4 TT |
1347 | pctx.errcode = e2fsck_allocate_inode_bitmap(ctx->fs, |
1348 | _("bad inode map"), EXT2FS_BMAP64_RBTREE, | |
1349 | "inode_bad_map", &ctx->inode_bad_map); | |
fdbdea09 TT |
1350 | if (pctx.errcode) { |
1351 | pctx.num = 3; | |
1352 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
1353 | /* Should never get here */ | |
1354 | ctx->flags |= E2F_FLAG_ABORT; | |
1355 | return; | |
1356 | } | |
3839e657 | 1357 | } |
c5d2f50d | 1358 | ext2fs_mark_inode_bitmap2(ctx->inode_bad_map, ino); |
3839e657 TT |
1359 | } |
1360 | ||
fdbdea09 | 1361 | |
21c84b71 TT |
1362 | /* |
1363 | * This procedure will allocate the inode "bb" (badblock) map table | |
1364 | */ | |
1b6bf175 | 1365 | static void alloc_bb_map(e2fsck_t ctx) |
21c84b71 | 1366 | { |
1b6bf175 | 1367 | struct problem_context pctx; |
efc6f628 | 1368 | |
1b6bf175 | 1369 | clear_problem_context(&pctx); |
830b44f4 TT |
1370 | pctx.errcode = e2fsck_allocate_inode_bitmap(ctx->fs, |
1371 | _("inode in bad block map"), EXT2FS_BMAP64_RBTREE, | |
1372 | "inode_bb_map", &ctx->inode_bb_map); | |
1b6bf175 TT |
1373 | if (pctx.errcode) { |
1374 | pctx.num = 4; | |
1375 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
08b21301 TT |
1376 | /* Should never get here */ |
1377 | ctx->flags |= E2F_FLAG_ABORT; | |
1378 | return; | |
21c84b71 TT |
1379 | } |
1380 | } | |
1381 | ||
aa4115a4 TT |
1382 | /* |
1383 | * This procedure will allocate the inode imagic table | |
1384 | */ | |
1385 | static void alloc_imagic_map(e2fsck_t ctx) | |
1386 | { | |
1387 | struct problem_context pctx; | |
efc6f628 | 1388 | |
aa4115a4 | 1389 | clear_problem_context(&pctx); |
830b44f4 TT |
1390 | pctx.errcode = e2fsck_allocate_inode_bitmap(ctx->fs, |
1391 | _("imagic inode map"), EXT2FS_BMAP64_RBTREE, | |
1392 | "inode_imagic_map", &ctx->inode_imagic_map); | |
aa4115a4 TT |
1393 | if (pctx.errcode) { |
1394 | pctx.num = 5; | |
1395 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
1396 | /* Should never get here */ | |
1397 | ctx->flags |= E2F_FLAG_ABORT; | |
1398 | return; | |
1399 | } | |
1400 | } | |
1401 | ||
3839e657 TT |
1402 | /* |
1403 | * Marks a block as in use, setting the dup_map if it's been set | |
1404 | * already. Called by process_block and process_bad_block. | |
50e1e10f TT |
1405 | * |
1406 | * WARNING: Assumes checks have already been done to make sure block | |
1407 | * is valid. This is true in both process_block and process_bad_block. | |
3839e657 | 1408 | */ |
6dc64392 | 1409 | static _INLINE_ void mark_block_used(e2fsck_t ctx, blk64_t block) |
3839e657 | 1410 | { |
1b6bf175 | 1411 | struct problem_context pctx; |
efc6f628 | 1412 | |
1b6bf175 | 1413 | clear_problem_context(&pctx); |
efc6f628 | 1414 | |
c5d2f50d | 1415 | if (ext2fs_fast_test_block_bitmap2(ctx->block_found_map, block)) { |
1b6bf175 | 1416 | if (!ctx->block_dup_map) { |
830b44f4 TT |
1417 | pctx.errcode = e2fsck_allocate_block_bitmap(ctx->fs, |
1418 | _("multiply claimed block map"), | |
1419 | EXT2FS_BMAP64_RBTREE, "block_dup_map", | |
1420 | &ctx->block_dup_map); | |
1b6bf175 TT |
1421 | if (pctx.errcode) { |
1422 | pctx.num = 3; | |
efc6f628 | 1423 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, |
1b6bf175 | 1424 | &pctx); |
08b21301 TT |
1425 | /* Should never get here */ |
1426 | ctx->flags |= E2F_FLAG_ABORT; | |
1427 | return; | |
3839e657 TT |
1428 | } |
1429 | } | |
c5d2f50d | 1430 | ext2fs_fast_mark_block_bitmap2(ctx->block_dup_map, block); |
3839e657 | 1431 | } else { |
c5d2f50d | 1432 | ext2fs_fast_mark_block_bitmap2(ctx->block_found_map, block); |
3839e657 TT |
1433 | } |
1434 | } | |
1435 | ||
2ae49fd0 TT |
1436 | static _INLINE_ void mark_blocks_used(e2fsck_t ctx, blk64_t block, |
1437 | unsigned int num) | |
1438 | { | |
1439 | if (ext2fs_test_block_bitmap_range2(ctx->block_found_map, block, num)) | |
1440 | ext2fs_mark_block_bitmap_range2(ctx->block_found_map, block, num); | |
1441 | else | |
1442 | while (num--) | |
1443 | mark_block_used(ctx, block++); | |
1444 | } | |
1445 | ||
e8a3ee62 TT |
1446 | /* |
1447 | * Adjust the extended attribute block's reference counts at the end | |
1448 | * of pass 1, either by subtracting out references for EA blocks that | |
1449 | * are still referenced in ctx->refcount, or by adding references for | |
1450 | * EA blocks that had extra references as accounted for in | |
1451 | * ctx->refcount_extra. | |
1452 | */ | |
efc6f628 | 1453 | static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount, |
e8a3ee62 TT |
1454 | char *block_buf, int adjust_sign) |
1455 | { | |
1456 | struct ext2_ext_attr_header *header; | |
1457 | struct problem_context pctx; | |
1458 | ext2_filsys fs = ctx->fs; | |
6dc64392 | 1459 | blk64_t blk; |
e8a3ee62 TT |
1460 | __u32 should_be; |
1461 | int count; | |
1462 | ||
1463 | clear_problem_context(&pctx); | |
efc6f628 | 1464 | |
e8a3ee62 TT |
1465 | ea_refcount_intr_begin(refcount); |
1466 | while (1) { | |
1467 | if ((blk = ea_refcount_intr_next(refcount, &count)) == 0) | |
1468 | break; | |
1469 | pctx.blk = blk; | |
6dc64392 | 1470 | pctx.errcode = ext2fs_read_ext_attr2(fs, blk, block_buf); |
e8a3ee62 TT |
1471 | if (pctx.errcode) { |
1472 | fix_problem(ctx, PR_1_EXTATTR_READ_ABORT, &pctx); | |
1473 | return; | |
1474 | } | |
1475 | header = (struct ext2_ext_attr_header *) block_buf; | |
1476 | pctx.blkcount = header->h_refcount; | |
1477 | should_be = header->h_refcount + adjust_sign * count; | |
1478 | pctx.num = should_be; | |
1479 | if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) { | |
1480 | header->h_refcount = should_be; | |
6dc64392 | 1481 | pctx.errcode = ext2fs_write_ext_attr2(fs, blk, |
e8a3ee62 TT |
1482 | block_buf); |
1483 | if (pctx.errcode) { | |
a6217f5a TT |
1484 | fix_problem(ctx, PR_1_EXTATTR_WRITE_ABORT, |
1485 | &pctx); | |
e8a3ee62 TT |
1486 | continue; |
1487 | } | |
1488 | } | |
1489 | } | |
1490 | } | |
1491 | ||
342d847d TT |
1492 | /* |
1493 | * Handle processing the extended attribute blocks | |
1494 | */ | |
1495 | static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx, | |
1496 | char *block_buf) | |
1497 | { | |
1498 | ext2_filsys fs = ctx->fs; | |
1499 | ext2_ino_t ino = pctx->ino; | |
1500 | struct ext2_inode *inode = pctx->inode; | |
6dc64392 | 1501 | blk64_t blk; |
55fd07ed | 1502 | char * end; |
e8a3ee62 | 1503 | struct ext2_ext_attr_header *header; |
55fd07ed | 1504 | struct ext2_ext_attr_entry *entry; |
342d847d | 1505 | int count; |
86bc90f4 | 1506 | region_t region = 0; |
5469d767 | 1507 | |
0c80c44b | 1508 | blk = ext2fs_file_acl_block(fs, inode); |
342d847d TT |
1509 | if (blk == 0) |
1510 | return 0; | |
1511 | ||
1512 | /* | |
1513 | * If the Extended attribute flag isn't set, then a non-zero | |
1514 | * file acl means that the inode is corrupted. | |
1515 | * | |
1516 | * Or if the extended attribute block is an invalid block, | |
1517 | * then the inode is also corrupted. | |
1518 | */ | |
1519 | if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) || | |
1520 | (blk < fs->super->s_first_data_block) || | |
4efbac6f | 1521 | (blk >= ext2fs_blocks_count(fs->super))) { |
342d847d TT |
1522 | mark_inode_bad(ctx, ino); |
1523 | return 0; | |
1524 | } | |
1525 | ||
1526 | /* If ea bitmap hasn't been allocated, create it */ | |
1527 | if (!ctx->block_ea_map) { | |
830b44f4 TT |
1528 | pctx->errcode = e2fsck_allocate_block_bitmap(fs, |
1529 | _("ext attr block map"), | |
1530 | EXT2FS_BMAP64_RBTREE, "block_ea_map", | |
1531 | &ctx->block_ea_map); | |
342d847d TT |
1532 | if (pctx->errcode) { |
1533 | pctx->num = 2; | |
1534 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, pctx); | |
1535 | ctx->flags |= E2F_FLAG_ABORT; | |
1536 | return 0; | |
1537 | } | |
1538 | } | |
1539 | ||
1540 | /* Create the EA refcount structure if necessary */ | |
1541 | if (!ctx->refcount) { | |
1542 | pctx->errcode = ea_refcount_create(0, &ctx->refcount); | |
1543 | if (pctx->errcode) { | |
1544 | pctx->num = 1; | |
1545 | fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx); | |
1546 | ctx->flags |= E2F_FLAG_ABORT; | |
1547 | return 0; | |
1548 | } | |
1549 | } | |
1550 | ||
b5acdb6a TT |
1551 | #if 0 |
1552 | /* Debugging text */ | |
1553 | printf("Inode %u has EA block %u\n", ino, blk); | |
1554 | #endif | |
1555 | ||
342d847d | 1556 | /* Have we seen this EA block before? */ |
c5d2f50d | 1557 | if (ext2fs_fast_test_block_bitmap2(ctx->block_ea_map, blk)) { |
342d847d TT |
1558 | if (ea_refcount_decrement(ctx->refcount, blk, 0) == 0) |
1559 | return 1; | |
1560 | /* Ooops, this EA was referenced more than it stated */ | |
1561 | if (!ctx->refcount_extra) { | |
1562 | pctx->errcode = ea_refcount_create(0, | |
1563 | &ctx->refcount_extra); | |
1564 | if (pctx->errcode) { | |
1565 | pctx->num = 2; | |
1566 | fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx); | |
1567 | ctx->flags |= E2F_FLAG_ABORT; | |
55fd07ed | 1568 | return 0; |
342d847d TT |
1569 | } |
1570 | } | |
1571 | ea_refcount_increment(ctx->refcount_extra, blk, 0); | |
1572 | return 1; | |
1573 | } | |
5469d767 | 1574 | |
342d847d TT |
1575 | /* |
1576 | * OK, we haven't seen this EA block yet. So we need to | |
1577 | * validate it | |
1578 | */ | |
1579 | pctx->blk = blk; | |
6dc64392 | 1580 | pctx->errcode = ext2fs_read_ext_attr2(fs, blk, block_buf); |
342d847d TT |
1581 | if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx)) |
1582 | goto clear_extattr; | |
342d847d | 1583 | header = (struct ext2_ext_attr_header *) block_buf; |
0c80c44b | 1584 | pctx->blk = ext2fs_file_acl_block(fs, inode); |
0684a4f3 TT |
1585 | if (((ctx->ext_attr_ver == 1) && |
1586 | (header->h_magic != EXT2_EXT_ATTR_MAGIC_v1)) || | |
1587 | ((ctx->ext_attr_ver == 2) && | |
1588 | (header->h_magic != EXT2_EXT_ATTR_MAGIC))) { | |
1589 | if (fix_problem(ctx, PR_1_BAD_EA_BLOCK, pctx)) | |
1590 | goto clear_extattr; | |
1591 | } | |
0d63467d | 1592 | |
55fd07ed TT |
1593 | if (header->h_blocks != 1) { |
1594 | if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx)) | |
1595 | goto clear_extattr; | |
1596 | } | |
1597 | ||
1598 | region = region_create(0, fs->blocksize); | |
1599 | if (!region) { | |
a6217f5a | 1600 | fix_problem(ctx, PR_1_EA_ALLOC_REGION_ABORT, pctx); |
55fd07ed TT |
1601 | ctx->flags |= E2F_FLAG_ABORT; |
1602 | return 0; | |
1603 | } | |
1604 | if (region_allocate(region, 0, sizeof(struct ext2_ext_attr_header))) { | |
1605 | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) | |
342d847d TT |
1606 | goto clear_extattr; |
1607 | } | |
5469d767 | 1608 | |
55fd07ed TT |
1609 | entry = (struct ext2_ext_attr_entry *)(header+1); |
1610 | end = block_buf + fs->blocksize; | |
1611 | while ((char *)entry < end && *(__u32 *)entry) { | |
fefaef39 AD |
1612 | __u32 hash; |
1613 | ||
55fd07ed TT |
1614 | if (region_allocate(region, (char *)entry - (char *)header, |
1615 | EXT2_EXT_ATTR_LEN(entry->e_name_len))) { | |
1616 | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) | |
1617 | goto clear_extattr; | |
fefaef39 | 1618 | break; |
55fd07ed | 1619 | } |
0684a4f3 | 1620 | if ((ctx->ext_attr_ver == 1 && |
0d63467d | 1621 | (entry->e_name_len == 0 || entry->e_name_index != 0)) || |
0684a4f3 | 1622 | (ctx->ext_attr_ver == 2 && |
0d63467d | 1623 | entry->e_name_index == 0)) { |
55fd07ed TT |
1624 | if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx)) |
1625 | goto clear_extattr; | |
fefaef39 | 1626 | break; |
55fd07ed TT |
1627 | } |
1628 | if (entry->e_value_block != 0) { | |
1629 | if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx)) | |
1630 | goto clear_extattr; | |
1631 | } | |
a34c6ffd AD |
1632 | if (entry->e_value_offs + entry->e_value_size > fs->blocksize) { |
1633 | if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx)) | |
1634 | goto clear_extattr; | |
1635 | break; | |
1636 | } | |
14fe1c33 TT |
1637 | if (entry->e_value_size && |
1638 | region_allocate(region, entry->e_value_offs, | |
1639 | EXT2_EXT_ATTR_SIZE(entry->e_value_size))) { | |
55fd07ed TT |
1640 | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) |
1641 | goto clear_extattr; | |
1642 | } | |
fefaef39 AD |
1643 | |
1644 | hash = ext2fs_ext_attr_hash_entry(entry, block_buf + | |
1645 | entry->e_value_offs); | |
1646 | ||
1647 | if (entry->e_hash != hash) { | |
1648 | pctx->num = entry->e_hash; | |
1649 | if (fix_problem(ctx, PR_1_ATTR_HASH, pctx)) | |
1650 | goto clear_extattr; | |
1651 | entry->e_hash = hash; | |
1652 | } | |
1653 | ||
55fd07ed TT |
1654 | entry = EXT2_EXT_ATTR_NEXT(entry); |
1655 | } | |
1656 | if (region_allocate(region, (char *)entry - (char *)header, 4)) { | |
1657 | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) | |
1658 | goto clear_extattr; | |
1659 | } | |
1660 | region_free(region); | |
342d847d TT |
1661 | |
1662 | count = header->h_refcount - 1; | |
1663 | if (count) | |
1664 | ea_refcount_store(ctx->refcount, blk, count); | |
1665 | mark_block_used(ctx, blk); | |
c5d2f50d | 1666 | ext2fs_fast_mark_block_bitmap2(ctx->block_ea_map, blk); |
342d847d TT |
1667 | return 1; |
1668 | ||
1669 | clear_extattr: | |
5469d767 BB |
1670 | if (region) |
1671 | region_free(region); | |
0c80c44b | 1672 | ext2fs_file_acl_block_set(fs, inode, 0); |
342d847d TT |
1673 | e2fsck_write_inode(ctx, ino, inode, "check_ext_attr"); |
1674 | return 0; | |
1675 | } | |
1676 | ||
503f9e7f TT |
1677 | /* Returns 1 if bad htree, 0 if OK */ |
1678 | static int handle_htree(e2fsck_t ctx, struct problem_context *pctx, | |
15d482ba | 1679 | ext2_ino_t ino, struct ext2_inode *inode, |
503f9e7f TT |
1680 | char *block_buf) |
1681 | { | |
1682 | struct ext2_dx_root_info *root; | |
1683 | ext2_filsys fs = ctx->fs; | |
1684 | errcode_t retval; | |
6dc64392 | 1685 | blk64_t blk; |
503f9e7f TT |
1686 | |
1687 | if ((!LINUX_S_ISDIR(inode->i_mode) && | |
1688 | fix_problem(ctx, PR_1_HTREE_NODIR, pctx)) || | |
1689 | (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) && | |
1690 | fix_problem(ctx, PR_1_HTREE_SET, pctx))) | |
1691 | return 1; | |
1692 | ||
6dc64392 | 1693 | pctx->errcode = ext2fs_bmap2(fs, ino, inode, 0, 0, 0, 0, &blk); |
15d482ba TT |
1694 | |
1695 | if ((pctx->errcode) || | |
1696 | (blk == 0) || | |
1697 | (blk < fs->super->s_first_data_block) || | |
4efbac6f | 1698 | (blk >= ext2fs_blocks_count(fs->super))) { |
15d482ba TT |
1699 | if (fix_problem(ctx, PR_1_HTREE_BADROOT, pctx)) |
1700 | return 1; | |
1701 | else | |
1702 | return 0; | |
1703 | } | |
503f9e7f | 1704 | |
24a117ab | 1705 | retval = io_channel_read_blk64(fs->io, blk, 1, block_buf); |
503f9e7f TT |
1706 | if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx)) |
1707 | return 1; | |
efc6f628 | 1708 | |
503f9e7f TT |
1709 | /* XXX should check that beginning matches a directory */ |
1710 | root = (struct ext2_dx_root_info *) (block_buf + 24); | |
1711 | ||
1712 | if ((root->reserved_zero || root->info_length < 8) && | |
1713 | fix_problem(ctx, PR_1_HTREE_BADROOT, pctx)) | |
1714 | return 1; | |
1715 | ||
1716 | pctx->num = root->hash_version; | |
1717 | if ((root->hash_version != EXT2_HASH_LEGACY) && | |
1718 | (root->hash_version != EXT2_HASH_HALF_MD4) && | |
f044b4d8 | 1719 | (root->hash_version != EXT2_HASH_TEA) && |
503f9e7f TT |
1720 | fix_problem(ctx, PR_1_HTREE_HASHV, pctx)) |
1721 | return 1; | |
efc6f628 | 1722 | |
503f9e7f TT |
1723 | if ((root->unused_flags & EXT2_HASH_FLAG_INCOMPAT) && |
1724 | fix_problem(ctx, PR_1_HTREE_INCOMPAT, pctx)) | |
1725 | return 1; | |
1726 | ||
1727 | pctx->num = root->indirect_levels; | |
1728 | if ((root->indirect_levels > 1) && | |
1729 | fix_problem(ctx, PR_1_HTREE_DEPTH, pctx)) | |
1730 | return 1; | |
efc6f628 | 1731 | |
503f9e7f TT |
1732 | return 0; |
1733 | } | |
342d847d | 1734 | |
e3df15ab TT |
1735 | void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino, |
1736 | struct ext2_inode *inode, int restart_flag, | |
1737 | const char *source) | |
1738 | { | |
15d482ba | 1739 | inode->i_flags = 0; |
e3df15ab TT |
1740 | inode->i_links_count = 0; |
1741 | ext2fs_icount_store(ctx->inode_link_info, ino, 0); | |
1742 | inode->i_dtime = ctx->now; | |
1743 | ||
c5d2f50d VAH |
1744 | ext2fs_unmark_inode_bitmap2(ctx->inode_dir_map, ino); |
1745 | ext2fs_unmark_inode_bitmap2(ctx->inode_used_map, ino); | |
e3df15ab | 1746 | if (ctx->inode_reg_map) |
c5d2f50d | 1747 | ext2fs_unmark_inode_bitmap2(ctx->inode_reg_map, ino); |
e3df15ab | 1748 | if (ctx->inode_bad_map) |
c5d2f50d | 1749 | ext2fs_unmark_inode_bitmap2(ctx->inode_bad_map, ino); |
e3df15ab TT |
1750 | |
1751 | /* | |
1752 | * If the inode was partially accounted for before processing | |
1753 | * was aborted, we need to restart the pass 1 scan. | |
1754 | */ | |
1755 | ctx->flags |= restart_flag; | |
1756 | ||
96a8afa7 TT |
1757 | if (ino == EXT2_BAD_INO) |
1758 | memset(inode, 0, sizeof(struct ext2_inode)); | |
1759 | ||
e3df15ab TT |
1760 | e2fsck_write_inode(ctx, ino, inode, source); |
1761 | } | |
1762 | ||
15d482ba | 1763 | static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx, |
d5a8f9a9 | 1764 | struct process_block_struct *pb, |
d3f32c2d | 1765 | blk64_t start_block, blk64_t end_block, |
085757fc | 1766 | blk64_t eof_block, |
15d482ba TT |
1767 | ext2_extent_handle_t ehandle) |
1768 | { | |
1769 | struct ext2fs_extent extent; | |
d3f32c2d | 1770 | blk64_t blk, last_lblk; |
15d482ba | 1771 | e2_blkcnt_t blockcnt; |
2acad6b4 | 1772 | unsigned int i; |
15d482ba | 1773 | int is_dir, is_leaf; |
3c7c6d73 | 1774 | problem_t problem; |
11de9261 | 1775 | struct ext2_extent_info info; |
15d482ba | 1776 | |
11de9261 TT |
1777 | pctx->errcode = ext2fs_extent_get_info(ehandle, &info); |
1778 | if (pctx->errcode) | |
1779 | return; | |
15d482ba TT |
1780 | |
1781 | pctx->errcode = ext2fs_extent_get(ehandle, EXT2_EXTENT_FIRST_SIB, | |
1782 | &extent); | |
11de9261 | 1783 | while (!pctx->errcode && info.num_entries-- > 0) { |
15d482ba TT |
1784 | is_leaf = extent.e_flags & EXT2_EXTENT_FLAGS_LEAF; |
1785 | is_dir = LINUX_S_ISDIR(pctx->inode->i_mode); | |
d3f32c2d | 1786 | last_lblk = extent.e_lblk + extent.e_len - 1; |
15d482ba TT |
1787 | |
1788 | problem = 0; | |
e6238d37 TT |
1789 | if (extent.e_pblk == 0 || |
1790 | extent.e_pblk < ctx->fs->super->s_first_data_block || | |
4efbac6f | 1791 | extent.e_pblk >= ext2fs_blocks_count(ctx->fs->super)) |
15d482ba | 1792 | problem = PR_1_EXTENT_BAD_START_BLK; |
d5a8f9a9 TT |
1793 | else if (extent.e_lblk < start_block) |
1794 | problem = PR_1_OUT_OF_ORDER_EXTENTS; | |
085757fc EW |
1795 | else if ((end_block && last_lblk > end_block) && |
1796 | (!(extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT && | |
1797 | last_lblk > eof_block))) | |
d3f32c2d | 1798 | problem = PR_1_EXTENT_END_OUT_OF_BOUNDS; |
9c40d148 | 1799 | else if (is_leaf && extent.e_len == 0) |
26c09eb8 | 1800 | problem = PR_1_EXTENT_LENGTH_ZERO; |
7a1eac2f ES |
1801 | else if (is_leaf && |
1802 | (extent.e_pblk + extent.e_len) > | |
4efbac6f | 1803 | ext2fs_blocks_count(ctx->fs->super)) |
15d482ba | 1804 | problem = PR_1_EXTENT_ENDS_BEYOND; |
dd50ef87 TT |
1805 | else if (is_leaf && is_dir && |
1806 | ((extent.e_lblk + extent.e_len) > | |
1807 | (1 << (21 - ctx->fs->super->s_log_block_size)))) | |
1808 | problem = PR_1_TOOBIG_DIR; | |
15d482ba TT |
1809 | |
1810 | if (problem) { | |
789bd401 | 1811 | report_problem: |
15d482ba TT |
1812 | pctx->blk = extent.e_pblk; |
1813 | pctx->blk2 = extent.e_lblk; | |
1814 | pctx->num = extent.e_len; | |
dd50ef87 | 1815 | pctx->blkcount = extent.e_lblk + extent.e_len; |
15d482ba | 1816 | if (fix_problem(ctx, problem, pctx)) { |
19f433a5 | 1817 | e2fsck_read_bitmaps(ctx); |
15d482ba TT |
1818 | pctx->errcode = |
1819 | ext2fs_extent_delete(ehandle, 0); | |
1820 | if (pctx->errcode) { | |
7518c176 | 1821 | pctx->str = "ext2fs_extent_delete"; |
15d482ba TT |
1822 | return; |
1823 | } | |
29e8e74e | 1824 | ext2fs_extent_fix_parents(ehandle); |
73e5abcf TT |
1825 | pctx->errcode = ext2fs_extent_get(ehandle, |
1826 | EXT2_EXTENT_CURRENT, | |
1827 | &extent); | |
1828 | if (pctx->errcode == EXT2_ET_NO_CURRENT_NODE) { | |
1829 | pctx->errcode = 0; | |
1830 | break; | |
1831 | } | |
1832 | continue; | |
15d482ba TT |
1833 | } |
1834 | goto next; | |
1835 | } | |
1836 | ||
1837 | if (!is_leaf) { | |
d3f32c2d | 1838 | blk64_t lblk = extent.e_lblk; |
789bd401 | 1839 | |
7518c176 | 1840 | blk = extent.e_pblk; |
15d482ba TT |
1841 | pctx->errcode = ext2fs_extent_get(ehandle, |
1842 | EXT2_EXTENT_DOWN, &extent); | |
1843 | if (pctx->errcode) { | |
7518c176 TT |
1844 | pctx->str = "EXT2_EXTENT_DOWN"; |
1845 | problem = PR_1_EXTENT_HEADER_INVALID; | |
1846 | if (pctx->errcode == EXT2_ET_EXTENT_HEADER_BAD) | |
1847 | goto report_problem; | |
1848 | return; | |
15d482ba | 1849 | } |
789bd401 ES |
1850 | /* The next extent should match this index's logical start */ |
1851 | if (extent.e_lblk != lblk) { | |
68477355 | 1852 | struct ext2_extent_info e_info; |
789bd401 | 1853 | |
68477355 | 1854 | ext2fs_extent_get_info(ehandle, &e_info); |
789bd401 ES |
1855 | pctx->blk = lblk; |
1856 | pctx->blk2 = extent.e_lblk; | |
68477355 | 1857 | pctx->num = e_info.curr_level - 1; |
789bd401 ES |
1858 | problem = PR_1_EXTENT_INDEX_START_INVALID; |
1859 | if (fix_problem(ctx, problem, pctx)) | |
1860 | ext2fs_extent_fix_parents(ehandle); | |
1861 | } | |
d3f32c2d | 1862 | scan_extent_node(ctx, pctx, pb, extent.e_lblk, |
085757fc | 1863 | last_lblk, eof_block, ehandle); |
7518c176 TT |
1864 | if (pctx->errcode) |
1865 | return; | |
15d482ba TT |
1866 | pctx->errcode = ext2fs_extent_get(ehandle, |
1867 | EXT2_EXTENT_UP, &extent); | |
1868 | if (pctx->errcode) { | |
7518c176 TT |
1869 | pctx->str = "EXT2_EXTENT_UP"; |
1870 | return; | |
15d482ba | 1871 | } |
7518c176 TT |
1872 | mark_block_used(ctx, blk); |
1873 | pb->num_blocks++; | |
15d482ba TT |
1874 | goto next; |
1875 | } | |
1876 | ||
63b5e354 TT |
1877 | if ((pb->previous_block != 0) && |
1878 | (pb->previous_block+1 != extent.e_pblk)) { | |
100d4701 TT |
1879 | if (ctx->options & E2F_OPT_FRAGCHECK) { |
1880 | char type = '?'; | |
1881 | ||
1882 | if (pb->is_dir) | |
1883 | type = 'd'; | |
1884 | else if (pb->is_reg) | |
1885 | type = 'f'; | |
1886 | ||
1887 | printf(("%6lu(%c): expecting %6lu " | |
1888 | "actual extent " | |
63b5e354 | 1889 | "phys %6lu log %lu len %lu\n"), |
100d4701 | 1890 | (unsigned long) pctx->ino, type, |
63b5e354 TT |
1891 | (unsigned long) pb->previous_block+1, |
1892 | (unsigned long) extent.e_pblk, | |
1893 | (unsigned long) extent.e_lblk, | |
1894 | (unsigned long) extent.e_len); | |
100d4701 | 1895 | } |
63b5e354 TT |
1896 | pb->fragmented = 1; |
1897 | } | |
68477355 TT |
1898 | while (is_dir && (++pb->last_db_block < |
1899 | (e2_blkcnt_t) extent.e_lblk)) { | |
6dc64392 VAH |
1900 | pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist, |
1901 | pb->ino, 0, | |
1902 | pb->last_db_block); | |
4607ef7d TT |
1903 | if (pctx->errcode) { |
1904 | pctx->blk = 0; | |
1905 | pctx->num = pb->last_db_block; | |
1906 | goto failed_add_dir_block; | |
1907 | } | |
1908 | } | |
2ae49fd0 TT |
1909 | if (!ctx->fs->cluster_ratio_bits) { |
1910 | mark_blocks_used(ctx, extent.e_pblk, extent.e_len); | |
1911 | pb->num_blocks += extent.e_len; | |
1912 | } | |
15d482ba TT |
1913 | for (blk = extent.e_pblk, blockcnt = extent.e_lblk, i = 0; |
1914 | i < extent.e_len; | |
1915 | blk++, blockcnt++, i++) { | |
2ae49fd0 TT |
1916 | if (ctx->fs->cluster_ratio_bits && |
1917 | !(pb->previous_block && | |
44fe08f1 TT |
1918 | (EXT2FS_B2C(ctx->fs, blk) == |
1919 | EXT2FS_B2C(ctx->fs, pb->previous_block)) && | |
1920 | (blk & EXT2FS_CLUSTER_MASK(ctx->fs)) == | |
68477355 | 1921 | ((unsigned) blockcnt & EXT2FS_CLUSTER_MASK(ctx->fs)))) { |
44fe08f1 | 1922 | mark_block_used(ctx, blk); |
b2e6c86d TT |
1923 | pb->num_blocks++; |
1924 | } | |
44fe08f1 TT |
1925 | |
1926 | pb->previous_block = blk; | |
15d482ba TT |
1927 | |
1928 | if (is_dir) { | |
6dc64392 | 1929 | pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist, pctx->ino, blk, blockcnt); |
15d482ba TT |
1930 | if (pctx->errcode) { |
1931 | pctx->blk = blk; | |
1932 | pctx->num = blockcnt; | |
4607ef7d | 1933 | failed_add_dir_block: |
15d482ba TT |
1934 | fix_problem(ctx, PR_1_ADD_DBLOCK, pctx); |
1935 | /* Should never get here */ | |
1936 | ctx->flags |= E2F_FLAG_ABORT; | |
1937 | return; | |
1938 | } | |
1939 | } | |
1940 | } | |
4607ef7d TT |
1941 | if (is_dir && extent.e_len > 0) |
1942 | pb->last_db_block = blockcnt - 1; | |
63b5e354 | 1943 | pb->previous_block = extent.e_pblk + extent.e_len - 1; |
d3f32c2d | 1944 | start_block = pb->last_block = last_lblk; |
010dc7b9 LC |
1945 | if (is_leaf && !is_dir && |
1946 | !(extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)) | |
d3f32c2d | 1947 | pb->last_init_lblock = last_lblk; |
15d482ba TT |
1948 | next: |
1949 | pctx->errcode = ext2fs_extent_get(ehandle, | |
1950 | EXT2_EXTENT_NEXT_SIB, | |
1951 | &extent); | |
1952 | } | |
1953 | if (pctx->errcode == EXT2_ET_EXTENT_NO_NEXT) | |
1954 | pctx->errcode = 0; | |
1955 | } | |
1956 | ||
1957 | static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx, | |
2acad6b4 | 1958 | struct process_block_struct *pb) |
15d482ba | 1959 | { |
8da6d1a1 | 1960 | struct ext2_extent_info info; |
15d482ba TT |
1961 | struct ext2_inode *inode = pctx->inode; |
1962 | ext2_extent_handle_t ehandle; | |
1963 | ext2_filsys fs = ctx->fs; | |
1964 | ext2_ino_t ino = pctx->ino; | |
8da6d1a1 | 1965 | errcode_t retval; |
085757fc | 1966 | blk64_t eof_lblk; |
15d482ba | 1967 | |
84b239ae | 1968 | pctx->errcode = ext2fs_extent_open2(fs, ino, inode, &ehandle); |
0a68b181 TT |
1969 | if (pctx->errcode) { |
1970 | if (fix_problem(ctx, PR_1_READ_EXTENT, pctx)) | |
1971 | e2fsck_clear_inode(ctx, ino, inode, 0, | |
1972 | "check_blocks_extents"); | |
15d482ba TT |
1973 | pctx->errcode = 0; |
1974 | return; | |
1975 | } | |
1976 | ||
8da6d1a1 TT |
1977 | retval = ext2fs_extent_get_info(ehandle, &info); |
1978 | if (retval == 0) { | |
1979 | if (info.max_depth >= MAX_EXTENT_DEPTH_COUNT) | |
1980 | info.max_depth = MAX_EXTENT_DEPTH_COUNT-1; | |
1981 | ctx->extent_depth_count[info.max_depth]++; | |
1982 | } | |
1983 | ||
085757fc EW |
1984 | eof_lblk = ((EXT2_I_SIZE(inode) + fs->blocksize - 1) >> |
1985 | EXT2_BLOCK_SIZE_BITS(fs->super)) - 1; | |
1986 | scan_extent_node(ctx, pctx, pb, 0, 0, eof_lblk, ehandle); | |
7518c176 TT |
1987 | if (pctx->errcode && |
1988 | fix_problem(ctx, PR_1_EXTENT_ITERATE_FAILURE, pctx)) { | |
1989 | pb->num_blocks = 0; | |
1990 | inode->i_blocks = 0; | |
1991 | e2fsck_clear_inode(ctx, ino, inode, E2F_FLAG_RESTART, | |
1992 | "check_blocks_extents"); | |
1993 | pctx->errcode = 0; | |
1994 | } | |
15d482ba TT |
1995 | ext2fs_extent_free(ehandle); |
1996 | } | |
1997 | ||
3839e657 TT |
1998 | /* |
1999 | * This subroutine is called on each inode to account for all of the | |
2000 | * blocks used by that inode. | |
2001 | */ | |
1b6bf175 | 2002 | static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, |
3839e657 TT |
2003 | char *block_buf) |
2004 | { | |
1b6bf175 | 2005 | ext2_filsys fs = ctx->fs; |
3839e657 | 2006 | struct process_block_struct pb; |
86c627ec | 2007 | ext2_ino_t ino = pctx->ino; |
21c84b71 | 2008 | struct ext2_inode *inode = pctx->inode; |
3971bfe8 | 2009 | unsigned bad_size = 0; |
503f9e7f | 2010 | int dirty_inode = 0; |
7c1e090c | 2011 | int extent_fs; |
246501c6 | 2012 | __u64 size; |
efc6f628 | 2013 | |
3839e657 | 2014 | pb.ino = ino; |
0684a4f3 TT |
2015 | pb.num_blocks = 0; |
2016 | pb.last_block = -1; | |
010dc7b9 | 2017 | pb.last_init_lblock = -1; |
4dbe79bc | 2018 | pb.last_db_block = -1; |
f3db3566 | 2019 | pb.num_illegal_blocks = 0; |
21c84b71 | 2020 | pb.suppress = 0; pb.clear = 0; |
74becf3c | 2021 | pb.fragmented = 0; |
1917875f | 2022 | pb.compressed = 0; |
74becf3c | 2023 | pb.previous_block = 0; |
b94a052a | 2024 | pb.is_dir = LINUX_S_ISDIR(inode->i_mode); |
da307041 TT |
2025 | pb.is_reg = LINUX_S_ISREG(inode->i_mode); |
2026 | pb.max_blocks = 1 << (31 - fs->super->s_log_block_size); | |
f3db3566 | 2027 | pb.inode = inode; |
21c84b71 | 2028 | pb.pctx = pctx; |
1b6bf175 TT |
2029 | pb.ctx = ctx; |
2030 | pctx->ino = ino; | |
0684a4f3 | 2031 | pctx->errcode = 0; |
1917875f | 2032 | |
7c1e090c ES |
2033 | extent_fs = (ctx->fs->super->s_feature_incompat & |
2034 | EXT3_FEATURE_INCOMPAT_EXTENTS); | |
2035 | ||
1917875f | 2036 | if (inode->i_flags & EXT2_COMPRBLK_FL) { |
f5ae75e5 TT |
2037 | if (fs->super->s_feature_incompat & |
2038 | EXT2_FEATURE_INCOMPAT_COMPRESSION) | |
1917875f TT |
2039 | pb.compressed = 1; |
2040 | else { | |
2041 | if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) { | |
2042 | inode->i_flags &= ~EXT2_COMPRBLK_FL; | |
503f9e7f | 2043 | dirty_inode++; |
1917875f TT |
2044 | } |
2045 | } | |
2046 | } | |
2047 | ||
0c80c44b | 2048 | if (ext2fs_file_acl_block(fs, inode) && |
a63745e8 | 2049 | check_ext_attr(ctx, pctx, block_buf)) { |
fefaef39 AD |
2050 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
2051 | goto out; | |
dc71f23e | 2052 | pb.num_blocks++; |
fefaef39 | 2053 | } |
dc71f23e | 2054 | |
0c80c44b | 2055 | if (ext2fs_inode_has_valid_blocks2(fs, inode)) { |
7c1e090c | 2056 | if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) |
2acad6b4 | 2057 | check_blocks_extents(ctx, pctx, &pb); |
010dc7b9 | 2058 | else { |
6dc64392 | 2059 | pctx->errcode = ext2fs_block_iterate3(fs, ino, |
15d482ba TT |
2060 | pb.is_dir ? BLOCK_FLAG_HOLE : 0, |
2061 | block_buf, process_block, &pb); | |
010dc7b9 LC |
2062 | /* |
2063 | * We do not have uninitialized extents in non extent | |
2064 | * files. | |
2065 | */ | |
2066 | pb.last_init_lblock = pb.last_block; | |
2067 | } | |
15d482ba | 2068 | } |
1b6bf175 | 2069 | end_problem_latch(ctx, PR_LATCH_BLOCK); |
da307041 | 2070 | end_problem_latch(ctx, PR_LATCH_TOOBIG); |
0684a4f3 TT |
2071 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
2072 | goto out; | |
1b6bf175 TT |
2073 | if (pctx->errcode) |
2074 | fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx); | |
3839e657 | 2075 | |
ce44d8ca TT |
2076 | if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group) { |
2077 | if (LINUX_S_ISDIR(inode->i_mode)) | |
2078 | ctx->fs_fragmented_dir++; | |
2079 | else | |
2080 | ctx->fs_fragmented++; | |
2081 | } | |
74becf3c | 2082 | |
f3db3566 | 2083 | if (pb.clear) { |
e3df15ab TT |
2084 | e2fsck_clear_inode(ctx, ino, inode, E2F_FLAG_RESTART, |
2085 | "check_blocks"); | |
2086 | return; | |
f3db3566 | 2087 | } |
efc6f628 | 2088 | |
8fdc9985 | 2089 | if (inode->i_flags & EXT2_INDEX_FL) { |
503f9e7f TT |
2090 | if (handle_htree(ctx, pctx, ino, inode, block_buf)) { |
2091 | inode->i_flags &= ~EXT2_INDEX_FL; | |
2092 | dirty_inode++; | |
2093 | } else { | |
8fdc9985 TT |
2094 | #ifdef ENABLE_HTREE |
2095 | e2fsck_add_dx_dir(ctx, ino, pb.last_block+1); | |
2096 | #endif | |
503f9e7f | 2097 | } |
8fdc9985 | 2098 | } |
efc6f628 | 2099 | |
3839e657 | 2100 | if (!pb.num_blocks && pb.is_dir) { |
1b6bf175 | 2101 | if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) { |
e3df15ab | 2102 | e2fsck_clear_inode(ctx, ino, inode, 0, "check_blocks"); |
1b6bf175 | 2103 | ctx->fs_directory_count--; |
e3df15ab | 2104 | return; |
21c84b71 | 2105 | } |
3839e657 | 2106 | } |
0684a4f3 | 2107 | |
624e4a64 AK |
2108 | if (ino == EXT2_ROOT_INO || ino >= EXT2_FIRST_INODE(ctx->fs->super)) { |
2109 | quota_data_add(ctx->qctx, inode, ino, | |
2110 | pb.num_blocks * fs->blocksize); | |
2111 | quota_data_inodes(ctx->qctx, inode, ino, +1); | |
2112 | } | |
2113 | ||
1ca1059f TT |
2114 | if (!(fs->super->s_feature_ro_compat & |
2115 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE) || | |
2116 | !(inode->i_flags & EXT4_HUGE_FILE_FL)) | |
2117 | pb.num_blocks *= (fs->blocksize / 512); | |
b2e6c86d | 2118 | pb.num_blocks *= EXT2FS_CLUSTER_RATIO(fs); |
0684a4f3 | 2119 | #if 0 |
b2e6c86d | 2120 | printf("inode %u, i_size = %u, last_block = %lld, i_blocks=%llu, num_blocks = %llu\n", |
6dc64392 | 2121 | ino, inode->i_size, pb.last_block, ext2fs_inode_i_blocks(fs, inode), |
0684a4f3 TT |
2122 | pb.num_blocks); |
2123 | #endif | |
246501c6 TT |
2124 | if (pb.is_dir) { |
2125 | int nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super); | |
efc6f628 | 2126 | if (inode->i_size & (fs->blocksize - 1)) |
2cd12338 TT |
2127 | bad_size = 5; |
2128 | else if (nblock > (pb.last_block + 1)) | |
246501c6 TT |
2129 | bad_size = 1; |
2130 | else if (nblock < (pb.last_block + 1)) { | |
246501c6 | 2131 | if (((pb.last_block + 1) - nblock) > |
5dd8f963 | 2132 | fs->super->s_prealloc_dir_blocks) |
9d1bd3de | 2133 | bad_size = 2; |
246501c6 TT |
2134 | } |
2135 | } else { | |
9f0288d3 TT |
2136 | e2_blkcnt_t blkpg = ctx->blocks_per_page; |
2137 | ||
4f489285 | 2138 | size = EXT2_I_SIZE(inode); |
010dc7b9 | 2139 | if ((pb.last_init_lblock >= 0) && |
9f0288d3 | 2140 | /* allow allocated blocks to end of PAGE_SIZE */ |
010dc7b9 LC |
2141 | (size < (__u64)pb.last_init_lblock * fs->blocksize) && |
2142 | (pb.last_init_lblock / blkpg * blkpg != pb.last_init_lblock || | |
2143 | size < (__u64)(pb.last_init_lblock & ~(blkpg-1)) * | |
2144 | fs->blocksize)) | |
9d1bd3de | 2145 | bad_size = 3; |
7c1e090c ES |
2146 | else if (!(extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) && |
2147 | size > ext2_max_sizes[fs->super->s_log_block_size]) | |
2148 | /* too big for a direct/indirect-mapped file */ | |
9d1bd3de | 2149 | bad_size = 4; |
7c1e090c | 2150 | else if ((extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) && |
3ec7be43 | 2151 | size > |
03fa6f8a | 2152 | ((1ULL << (32 + EXT2_BLOCK_SIZE_BITS(fs->super))) - 1)) |
7c1e090c ES |
2153 | /* too big for an extent-based file - 32bit ee_block */ |
2154 | bad_size = 6; | |
246501c6 | 2155 | } |
0684a4f3 TT |
2156 | /* i_size for symlinks is checked elsewhere */ |
2157 | if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) { | |
21c84b71 | 2158 | pctx->num = (pb.last_block+1) * fs->blocksize; |
3ec7be43 | 2159 | pctx->group = bad_size; |
1b6bf175 | 2160 | if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) { |
21c84b71 | 2161 | inode->i_size = pctx->num; |
0684a4f3 | 2162 | if (!LINUX_S_ISDIR(inode->i_mode)) |
246501c6 | 2163 | inode->i_size_high = pctx->num >> 32; |
503f9e7f | 2164 | dirty_inode++; |
21c84b71 TT |
2165 | } |
2166 | pctx->num = 0; | |
3839e657 | 2167 | } |
3b6c0938 DW |
2168 | if (LINUX_S_ISREG(inode->i_mode) && |
2169 | ext2fs_needs_large_file_feature(EXT2_I_SIZE(inode))) | |
246501c6 | 2170 | ctx->large_files++; |
8a8f3654 | 2171 | if ((pb.num_blocks != ext2fs_inode_i_blocks(fs, inode)) || |
1ca1059f TT |
2172 | ((fs->super->s_feature_ro_compat & |
2173 | EXT4_FEATURE_RO_COMPAT_HUGE_FILE) && | |
2174 | (inode->i_flags & EXT4_HUGE_FILE_FL) && | |
2175 | (inode->osd2.linux2.l_i_blocks_hi != 0))) { | |
21c84b71 | 2176 | pctx->num = pb.num_blocks; |
1b6bf175 | 2177 | if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) { |
3839e657 | 2178 | inode->i_blocks = pb.num_blocks; |
b70506bf | 2179 | inode->osd2.linux2.l_i_blocks_hi = pb.num_blocks >> 32; |
503f9e7f | 2180 | dirty_inode++; |
21c84b71 TT |
2181 | } |
2182 | pctx->num = 0; | |
3839e657 | 2183 | } |
a49249d2 TT |
2184 | |
2185 | if (ctx->dirs_to_hash && pb.is_dir && | |
2186 | !(inode->i_flags & EXT2_INDEX_FL) && | |
2187 | ((inode->i_size / fs->blocksize) >= 3)) | |
2188 | ext2fs_u32_list_add(ctx->dirs_to_hash, ino); | |
2189 | ||
503f9e7f TT |
2190 | out: |
2191 | if (dirty_inode) | |
2192 | e2fsck_write_inode(ctx, ino, inode, "check_blocks"); | |
50e1e10f TT |
2193 | } |
2194 | ||
21c84b71 | 2195 | #if 0 |
50e1e10f TT |
2196 | /* |
2197 | * Helper function called by process block when an illegal block is | |
2198 | * found. It returns a description about why the block is illegal | |
2199 | */ | |
6dc64392 | 2200 | static char *describe_illegal_block(ext2_filsys fs, blk64_t block) |
50e1e10f | 2201 | { |
6dc64392 | 2202 | blk64_t super; |
50e1e10f TT |
2203 | int i; |
2204 | static char problem[80]; | |
2205 | ||
2206 | super = fs->super->s_first_data_block; | |
2207 | strcpy(problem, "PROGRAMMING ERROR: Unknown reason for illegal block"); | |
2208 | if (block < super) { | |
2209 | sprintf(problem, "< FIRSTBLOCK (%u)", super); | |
2210 | return(problem); | |
4efbac6f VAH |
2211 | } else if (block >= ext2fs_blocks_count(fs->super)) { |
2212 | sprintf(problem, "> BLOCKS (%u)", ext2fs_blocks_count(fs->super)); | |
50e1e10f TT |
2213 | return(problem); |
2214 | } | |
2215 | for (i = 0; i < fs->group_desc_count; i++) { | |
2216 | if (block == super) { | |
2217 | sprintf(problem, "is the superblock in group %d", i); | |
2218 | break; | |
2219 | } | |
2220 | if (block > super && | |
2221 | block <= (super + fs->desc_blocks)) { | |
2222 | sprintf(problem, "is in the group descriptors " | |
2223 | "of group %d", i); | |
2224 | break; | |
2225 | } | |
d7cca6b0 | 2226 | if (block == ext2fs_block_bitmap_loc(fs, i)) { |
50e1e10f TT |
2227 | sprintf(problem, "is the block bitmap of group %d", i); |
2228 | break; | |
2229 | } | |
d7cca6b0 | 2230 | if (block == ext2fs_inode_bitmap_loc(fs, i)) { |
50e1e10f TT |
2231 | sprintf(problem, "is the inode bitmap of group %d", i); |
2232 | break; | |
2233 | } | |
d7cca6b0 VAH |
2234 | if (block >= ext2fs_inode_table_loc(fs, i) && |
2235 | (block < ext2fs_inode_table_loc(fs, i) | |
50e1e10f TT |
2236 | + fs->inode_blocks_per_group)) { |
2237 | sprintf(problem, "is in the inode table of group %d", | |
2238 | i); | |
2239 | break; | |
2240 | } | |
2241 | super += fs->super->s_blocks_per_group; | |
2242 | } | |
2243 | return(problem); | |
2244 | } | |
21c84b71 | 2245 | #endif |
3839e657 TT |
2246 | |
2247 | /* | |
2248 | * This is a helper function for check_blocks(). | |
2249 | */ | |
53ef44c4 | 2250 | static int process_block(ext2_filsys fs, |
6dc64392 | 2251 | blk64_t *block_nr, |
9d1bd3de | 2252 | e2_blkcnt_t blockcnt, |
6dc64392 | 2253 | blk64_t ref_block EXT2FS_ATTR((unused)), |
54434927 | 2254 | int ref_offset EXT2FS_ATTR((unused)), |
54dc7ca2 | 2255 | void *priv_data) |
3839e657 TT |
2256 | { |
2257 | struct process_block_struct *p; | |
21c84b71 | 2258 | struct problem_context *pctx; |
6dc64392 | 2259 | blk64_t blk = *block_nr; |
50e1e10f | 2260 | int ret_code = 0; |
3c7c6d73 | 2261 | problem_t problem = 0; |
1b6bf175 | 2262 | e2fsck_t ctx; |
3839e657 | 2263 | |
54dc7ca2 | 2264 | p = (struct process_block_struct *) priv_data; |
21c84b71 | 2265 | pctx = p->pctx; |
1b6bf175 | 2266 | ctx = p->ctx; |
3839e657 | 2267 | |
1917875f TT |
2268 | if (p->compressed && (blk == EXT2FS_COMPRESSED_BLKADDR)) { |
2269 | /* todo: Check that the comprblk_fl is high, that the | |
2270 | blkaddr pattern looks right (all non-holes up to | |
2271 | first EXT2FS_COMPRESSED_BLKADDR, then all | |
2272 | EXT2FS_COMPRESSED_BLKADDR up to end of cluster), | |
2273 | that the feature_incompat bit is high, and that the | |
2274 | inode is a regular file. If we're doing a "full | |
2275 | check" (a concept introduced to e2fsck by e2compr, | |
2276 | meaning that we look at data blocks as well as | |
2277 | metadata) then call some library routine that | |
2278 | checks the compressed data. I'll have to think | |
2279 | about this, because one particularly important | |
2280 | problem to be able to fix is to recalculate the | |
2281 | cluster size if necessary. I think that perhaps | |
2282 | we'd better do most/all e2compr-specific checks | |
2283 | separately, after the non-e2compr checks. If not | |
2284 | doing a full check, it may be useful to test that | |
2285 | the personality is linux; e.g. if it isn't then | |
2286 | perhaps this really is just an illegal block. */ | |
2287 | return 0; | |
2288 | } | |
b94a052a | 2289 | |
4dbe79bc | 2290 | if (blk == 0) |
50e1e10f | 2291 | return 0; |
50e1e10f | 2292 | |
3839e657 | 2293 | #if 0 |
50e1e10f | 2294 | printf("Process_block, inode %lu, block %u, #%d\n", p->ino, blk, |
3839e657 | 2295 | blockcnt); |
50e1e10f | 2296 | #endif |
efc6f628 | 2297 | |
74becf3c TT |
2298 | /* |
2299 | * Simplistic fragmentation check. We merely require that the | |
2300 | * file be contiguous. (Which can never be true for really | |
2301 | * big files that are greater than a block group.) | |
2302 | */ | |
63b5e354 TT |
2303 | if (!HOLE_BLKADDR(p->previous_block) && p->ino != EXT2_RESIZE_INO) { |
2304 | if (p->previous_block+1 != blk) { | |
100d4701 TT |
2305 | if (ctx->options & E2F_OPT_FRAGCHECK) { |
2306 | char type = '?'; | |
2307 | ||
2308 | if (p->is_dir) | |
2309 | type = 'd'; | |
2310 | else if (p->is_reg) | |
2311 | type = 'f'; | |
2312 | ||
2313 | printf(_("%6lu(%c): expecting %6lu " | |
2314 | "got phys %6lu (blkcnt %lld)\n"), | |
2315 | (unsigned long) pctx->ino, type, | |
63b5e354 TT |
2316 | (unsigned long) p->previous_block+1, |
2317 | (unsigned long) blk, | |
f4e2c991 | 2318 | blockcnt); |
100d4701 | 2319 | } |
74becf3c | 2320 | p->fragmented = 1; |
63b5e354 | 2321 | } |
74becf3c | 2322 | } |
503f9e7f | 2323 | |
8421fb67 | 2324 | if (p->is_dir && blockcnt > (1 << (21 - fs->super->s_log_block_size))) |
da307041 TT |
2325 | problem = PR_1_TOOBIG_DIR; |
2326 | if (p->is_reg && p->num_blocks+1 >= p->max_blocks) | |
2327 | problem = PR_1_TOOBIG_REG; | |
2328 | if (!p->is_dir && !p->is_reg && blockcnt > 0) | |
2329 | problem = PR_1_TOOBIG_SYMLINK; | |
efc6f628 | 2330 | |
50e1e10f | 2331 | if (blk < fs->super->s_first_data_block || |
4efbac6f | 2332 | blk >= ext2fs_blocks_count(fs->super)) |
21c84b71 | 2333 | problem = PR_1_ILLEGAL_BLOCK_NUM; |
21c84b71 TT |
2334 | |
2335 | if (problem) { | |
f3db3566 | 2336 | p->num_illegal_blocks++; |
21c84b71 | 2337 | if (!p->suppress && (p->num_illegal_blocks % 12) == 0) { |
1b6bf175 | 2338 | if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) { |
f3db3566 TT |
2339 | p->clear = 1; |
2340 | return BLOCK_ABORT; | |
2341 | } | |
f8188fff | 2342 | if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) { |
f3db3566 | 2343 | p->suppress = 1; |
1b6bf175 TT |
2344 | set_latch_flags(PR_LATCH_BLOCK, |
2345 | PRL_SUPPRESS, 0); | |
f3db3566 TT |
2346 | } |
2347 | } | |
21c84b71 TT |
2348 | pctx->blk = blk; |
2349 | pctx->blkcount = blockcnt; | |
1b6bf175 | 2350 | if (fix_problem(ctx, problem, pctx)) { |
50e1e10f TT |
2351 | blk = *block_nr = 0; |
2352 | ret_code = BLOCK_CHANGED; | |
2353 | goto mark_dir; | |
21c84b71 | 2354 | } else |
3839e657 | 2355 | return 0; |
3839e657 TT |
2356 | } |
2357 | ||
d323f8fb | 2358 | if (p->ino == EXT2_RESIZE_INO) { |
efc6f628 | 2359 | /* |
c3ffaf83 TT |
2360 | * The resize inode has already be sanity checked |
2361 | * during pass #0 (the superblock checks). All we | |
2362 | * have to do is mark the double indirect block as | |
2363 | * being in use; all of the other blocks are handled | |
2364 | * by mark_table_blocks()). | |
2365 | */ | |
2366 | if (blockcnt == BLOCK_COUNT_DIND) | |
d323f8fb | 2367 | mark_block_used(ctx, blk); |
95a7f15f TT |
2368 | p->num_blocks++; |
2369 | } else if (!(ctx->fs->cluster_ratio_bits && | |
2370 | p->previous_block && | |
2371 | (EXT2FS_B2C(ctx->fs, blk) == | |
2372 | EXT2FS_B2C(ctx->fs, p->previous_block)) && | |
2373 | (blk & EXT2FS_CLUSTER_MASK(ctx->fs)) == | |
68477355 | 2374 | ((unsigned) blockcnt & EXT2FS_CLUSTER_MASK(ctx->fs)))) { |
d323f8fb | 2375 | mark_block_used(ctx, blk); |
95a7f15f TT |
2376 | p->num_blocks++; |
2377 | } | |
1e3472c5 TT |
2378 | if (blockcnt >= 0) |
2379 | p->last_block = blockcnt; | |
95a7f15f | 2380 | p->previous_block = blk; |
50e1e10f | 2381 | mark_dir: |
1e3472c5 | 2382 | if (p->is_dir && (blockcnt >= 0)) { |
4dbe79bc | 2383 | while (++p->last_db_block < blockcnt) { |
6dc64392 VAH |
2384 | pctx->errcode = ext2fs_add_dir_block2(fs->dblist, |
2385 | p->ino, 0, | |
2386 | p->last_db_block); | |
4dbe79bc TT |
2387 | if (pctx->errcode) { |
2388 | pctx->blk = 0; | |
2389 | pctx->num = p->last_db_block; | |
2390 | goto failed_add_dir_block; | |
2391 | } | |
2392 | } | |
6dc64392 VAH |
2393 | pctx->errcode = ext2fs_add_dir_block2(fs->dblist, p->ino, |
2394 | blk, blockcnt); | |
1b6bf175 TT |
2395 | if (pctx->errcode) { |
2396 | pctx->blk = blk; | |
2397 | pctx->num = blockcnt; | |
4dbe79bc | 2398 | failed_add_dir_block: |
1b6bf175 | 2399 | fix_problem(ctx, PR_1_ADD_DBLOCK, pctx); |
08b21301 TT |
2400 | /* Should never get here */ |
2401 | ctx->flags |= E2F_FLAG_ABORT; | |
2402 | return BLOCK_ABORT; | |
3839e657 | 2403 | } |
3839e657 | 2404 | } |
50e1e10f | 2405 | return ret_code; |
3839e657 TT |
2406 | } |
2407 | ||
53ef44c4 | 2408 | static int process_bad_block(ext2_filsys fs, |
6dc64392 | 2409 | blk64_t *block_nr, |
9d1bd3de | 2410 | e2_blkcnt_t blockcnt, |
6dc64392 | 2411 | blk64_t ref_block EXT2FS_ATTR((unused)), |
54434927 | 2412 | int ref_offset EXT2FS_ATTR((unused)), |
54dc7ca2 | 2413 | void *priv_data) |
3839e657 TT |
2414 | { |
2415 | struct process_block_struct *p; | |
6dc64392 VAH |
2416 | blk64_t blk = *block_nr; |
2417 | blk64_t first_block; | |
54434927 | 2418 | dgrp_t i; |
21c84b71 | 2419 | struct problem_context *pctx; |
1b6bf175 | 2420 | e2fsck_t ctx; |
21c84b71 | 2421 | |
1917875f TT |
2422 | /* |
2423 | * Note: This function processes blocks for the bad blocks | |
2424 | * inode, which is never compressed. So we don't use HOLE_BLKADDR(). | |
2425 | */ | |
2426 | ||
3839e657 TT |
2427 | if (!blk) |
2428 | return 0; | |
efc6f628 | 2429 | |
54dc7ca2 | 2430 | p = (struct process_block_struct *) priv_data; |
1b6bf175 | 2431 | ctx = p->ctx; |
21c84b71 | 2432 | pctx = p->pctx; |
efc6f628 | 2433 | |
f8188fff | 2434 | pctx->ino = EXT2_BAD_INO; |
21c84b71 TT |
2435 | pctx->blk = blk; |
2436 | pctx->blkcount = blockcnt; | |
3839e657 TT |
2437 | |
2438 | if ((blk < fs->super->s_first_data_block) || | |
4efbac6f | 2439 | (blk >= ext2fs_blocks_count(fs->super))) { |
1b6bf175 | 2440 | if (fix_problem(ctx, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) { |
3839e657 TT |
2441 | *block_nr = 0; |
2442 | return BLOCK_CHANGED; | |
21c84b71 | 2443 | } else |
3839e657 | 2444 | return 0; |
3839e657 TT |
2445 | } |
2446 | ||
2447 | if (blockcnt < 0) { | |
c5d2f50d | 2448 | if (ext2fs_test_block_bitmap2(p->fs_meta_blocks, blk)) { |
000ba404 TT |
2449 | p->bbcheck = 1; |
2450 | if (fix_problem(ctx, PR_1_BB_FS_BLOCK, pctx)) { | |
2451 | *block_nr = 0; | |
2452 | return BLOCK_CHANGED; | |
2453 | } | |
c5d2f50d | 2454 | } else if (ext2fs_test_block_bitmap2(ctx->block_found_map, |
000ba404 TT |
2455 | blk)) { |
2456 | p->bbcheck = 1; | |
efc6f628 | 2457 | if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, |
000ba404 TT |
2458 | pctx)) { |
2459 | *block_nr = 0; | |
2460 | return BLOCK_CHANGED; | |
2461 | } | |
a02ce9df | 2462 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 TT |
2463 | return BLOCK_ABORT; |
2464 | } else | |
1b6bf175 | 2465 | mark_block_used(ctx, blk); |
3839e657 TT |
2466 | return 0; |
2467 | } | |
efc6f628 | 2468 | #if 0 |
50e1e10f | 2469 | printf ("DEBUG: Marking %u as bad.\n", blk); |
3839e657 | 2470 | #endif |
1b6bf175 | 2471 | ctx->fs_badblocks_count++; |
3839e657 TT |
2472 | /* |
2473 | * If the block is not used, then mark it as used and return. | |
2474 | * If it is already marked as found, this must mean that | |
2475 | * there's an overlap between the filesystem table blocks | |
2476 | * (bitmaps and inode table) and the bad block list. | |
2477 | */ | |
c5d2f50d VAH |
2478 | if (!ext2fs_test_block_bitmap2(ctx->block_found_map, blk)) { |
2479 | ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); | |
3839e657 TT |
2480 | return 0; |
2481 | } | |
f3db3566 TT |
2482 | /* |
2483 | * Try to find the where the filesystem block was used... | |
2484 | */ | |
2485 | first_block = fs->super->s_first_data_block; | |
efc6f628 | 2486 | |
f3db3566 | 2487 | for (i = 0; i < fs->group_desc_count; i++ ) { |
21c84b71 | 2488 | pctx->group = i; |
1b6bf175 | 2489 | pctx->blk = blk; |
8039c480 TT |
2490 | if (!ext2fs_bg_has_super(fs, i)) |
2491 | goto skip_super; | |
f3db3566 TT |
2492 | if (blk == first_block) { |
2493 | if (i == 0) { | |
1b6bf175 TT |
2494 | if (fix_problem(ctx, |
2495 | PR_1_BAD_PRIMARY_SUPERBLOCK, | |
2496 | pctx)) { | |
2497 | *block_nr = 0; | |
50e1e10f | 2498 | return BLOCK_CHANGED; |
1b6bf175 | 2499 | } |
50e1e10f | 2500 | return 0; |
f3db3566 | 2501 | } |
1b6bf175 | 2502 | fix_problem(ctx, PR_1_BAD_SUPERBLOCK, pctx); |
f3db3566 TT |
2503 | return 0; |
2504 | } | |
2505 | if ((blk > first_block) && | |
2506 | (blk <= first_block + fs->desc_blocks)) { | |
2507 | if (i == 0) { | |
1b6bf175 TT |
2508 | pctx->blk = *block_nr; |
2509 | if (fix_problem(ctx, | |
2510 | PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR, pctx)) { | |
2511 | *block_nr = 0; | |
50e1e10f | 2512 | return BLOCK_CHANGED; |
1b6bf175 | 2513 | } |
50e1e10f | 2514 | return 0; |
f3db3566 | 2515 | } |
1b6bf175 | 2516 | fix_problem(ctx, PR_1_BAD_GROUP_DESCRIPTORS, pctx); |
f3db3566 | 2517 | return 0; |
3839e657 | 2518 | } |
8039c480 | 2519 | skip_super: |
d7cca6b0 | 2520 | if (blk == ext2fs_block_bitmap_loc(fs, i)) { |
1b6bf175 TT |
2521 | if (fix_problem(ctx, PR_1_BB_BAD_BLOCK, pctx)) { |
2522 | ctx->invalid_block_bitmap_flag[i]++; | |
2523 | ctx->invalid_bitmaps++; | |
21c84b71 | 2524 | } |
f3db3566 TT |
2525 | return 0; |
2526 | } | |
d7cca6b0 | 2527 | if (blk == ext2fs_inode_bitmap_loc(fs, i)) { |
1b6bf175 TT |
2528 | if (fix_problem(ctx, PR_1_IB_BAD_BLOCK, pctx)) { |
2529 | ctx->invalid_inode_bitmap_flag[i]++; | |
2530 | ctx->invalid_bitmaps++; | |
21c84b71 | 2531 | } |
f3db3566 TT |
2532 | return 0; |
2533 | } | |
d7cca6b0 VAH |
2534 | if ((blk >= ext2fs_inode_table_loc(fs, i)) && |
2535 | (blk < (ext2fs_inode_table_loc(fs, i) + | |
f3db3566 | 2536 | fs->inode_blocks_per_group))) { |
21c84b71 TT |
2537 | /* |
2538 | * If there are bad blocks in the inode table, | |
2539 | * the inode scan code will try to do | |
2540 | * something reasonable automatically. | |
2541 | */ | |
f3db3566 TT |
2542 | return 0; |
2543 | } | |
8039c480 | 2544 | first_block += fs->super->s_blocks_per_group; |
f3db3566 TT |
2545 | } |
2546 | /* | |
2547 | * If we've gotten to this point, then the only | |
2548 | * possibility is that the bad block inode meta data | |
2549 | * is using a bad block. | |
2550 | */ | |
2551 | if ((blk == p->inode->i_block[EXT2_IND_BLOCK]) || | |
000ba404 TT |
2552 | (blk == p->inode->i_block[EXT2_DIND_BLOCK]) || |
2553 | (blk == p->inode->i_block[EXT2_TIND_BLOCK])) { | |
2554 | p->bbcheck = 1; | |
2555 | if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, pctx)) { | |
2556 | *block_nr = 0; | |
2557 | return BLOCK_CHANGED; | |
2558 | } | |
a02ce9df | 2559 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 | 2560 | return BLOCK_ABORT; |
f3db3566 | 2561 | return 0; |
3839e657 | 2562 | } |
1b6bf175 TT |
2563 | |
2564 | pctx->group = -1; | |
2565 | ||
2566 | /* Warn user that the block wasn't claimed */ | |
2567 | fix_problem(ctx, PR_1_PROGERR_CLAIMED_BLOCK, pctx); | |
2568 | ||
f3db3566 | 2569 | return 0; |
3839e657 TT |
2570 | } |
2571 | ||
3971bfe8 | 2572 | static void new_table_block(e2fsck_t ctx, blk64_t first_block, dgrp_t group, |
c5d2f50d | 2573 | const char *name, int num, blk64_t *new_block) |
3839e657 | 2574 | { |
1b6bf175 | 2575 | ext2_filsys fs = ctx->fs; |
617446e4 | 2576 | dgrp_t last_grp; |
c5d2f50d VAH |
2577 | blk64_t old_block = *new_block; |
2578 | blk64_t last_block; | |
3971bfe8 TT |
2579 | dgrp_t flexbg; |
2580 | unsigned flexbg_size; | |
2581 | int i, is_flexbg; | |
3839e657 | 2582 | char *buf; |
1b6bf175 TT |
2583 | struct problem_context pctx; |
2584 | ||
2585 | clear_problem_context(&pctx); | |
2586 | ||
2587 | pctx.group = group; | |
2588 | pctx.blk = old_block; | |
2589 | pctx.str = name; | |
2590 | ||
617446e4 TT |
2591 | /* |
2592 | * For flex_bg filesystems, first try to allocate the metadata | |
2593 | * within the flex_bg, and if that fails then try finding the | |
2594 | * space anywhere in the filesystem. | |
2595 | */ | |
2596 | is_flexbg = EXT2_HAS_INCOMPAT_FEATURE(fs->super, | |
2597 | EXT4_FEATURE_INCOMPAT_FLEX_BG); | |
2598 | if (is_flexbg) { | |
2599 | flexbg_size = 1 << fs->super->s_log_groups_per_flex; | |
2600 | flexbg = group / flexbg_size; | |
b49f78fe TT |
2601 | first_block = ext2fs_group_first_block2(fs, |
2602 | flexbg_size * flexbg); | |
617446e4 TT |
2603 | last_grp = group | (flexbg_size - 1); |
2604 | if (last_grp > fs->group_desc_count) | |
2605 | last_grp = fs->group_desc_count; | |
b49f78fe | 2606 | last_block = ext2fs_group_last_block2(fs, last_grp); |
617446e4 | 2607 | } else |
b49f78fe | 2608 | last_block = ext2fs_group_last_block2(fs, group); |
c5d2f50d VAH |
2609 | pctx.errcode = ext2fs_get_free_blocks2(fs, first_block, last_block, |
2610 | num, ctx->block_found_map, | |
2611 | new_block); | |
617446e4 | 2612 | if (is_flexbg && (pctx.errcode == EXT2_ET_BLOCK_ALLOC_FAIL)) |
c5d2f50d | 2613 | pctx.errcode = ext2fs_get_free_blocks2(fs, |
617446e4 | 2614 | fs->super->s_first_data_block, |
4efbac6f | 2615 | ext2fs_blocks_count(fs->super), |
617446e4 | 2616 | num, ctx->block_found_map, new_block); |
1b6bf175 TT |
2617 | if (pctx.errcode) { |
2618 | pctx.num = num; | |
2619 | fix_problem(ctx, PR_1_RELOC_BLOCK_ALLOCATE, &pctx); | |
3839e657 | 2620 | ext2fs_unmark_valid(fs); |
617446e4 | 2621 | ctx->flags |= E2F_FLAG_ABORT; |
3839e657 TT |
2622 | return; |
2623 | } | |
c4e3d3f3 | 2624 | pctx.errcode = ext2fs_get_mem(fs->blocksize, &buf); |
08b21301 | 2625 | if (pctx.errcode) { |
1b6bf175 | 2626 | fix_problem(ctx, PR_1_RELOC_MEMORY_ALLOCATE, &pctx); |
3839e657 | 2627 | ext2fs_unmark_valid(fs); |
617446e4 | 2628 | ctx->flags |= E2F_FLAG_ABORT; |
3839e657 TT |
2629 | return; |
2630 | } | |
2631 | ext2fs_mark_super_dirty(fs); | |
299d7424 | 2632 | fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; |
1b6bf175 TT |
2633 | pctx.blk2 = *new_block; |
2634 | fix_problem(ctx, (old_block ? PR_1_RELOC_FROM_TO : | |
2635 | PR_1_RELOC_TO), &pctx); | |
2636 | pctx.blk2 = 0; | |
3839e657 | 2637 | for (i = 0; i < num; i++) { |
1b6bf175 | 2638 | pctx.blk = i; |
c5d2f50d | 2639 | ext2fs_mark_block_bitmap2(ctx->block_found_map, (*new_block)+i); |
f3db3566 | 2640 | if (old_block) { |
24a117ab | 2641 | pctx.errcode = io_channel_read_blk64(fs->io, |
1b6bf175 TT |
2642 | old_block + i, 1, buf); |
2643 | if (pctx.errcode) | |
2644 | fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx); | |
f3db3566 TT |
2645 | } else |
2646 | memset(buf, 0, fs->blocksize); | |
2647 | ||
1b6bf175 | 2648 | pctx.blk = (*new_block) + i; |
24a117ab | 2649 | pctx.errcode = io_channel_write_blk64(fs->io, pctx.blk, |
3839e657 | 2650 | 1, buf); |
1b6bf175 TT |
2651 | if (pctx.errcode) |
2652 | fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx); | |
3839e657 | 2653 | } |
c4e3d3f3 | 2654 | ext2fs_free_mem(&buf); |
3839e657 TT |
2655 | } |
2656 | ||
2657 | /* | |
f3db3566 TT |
2658 | * This routine gets called at the end of pass 1 if bad blocks are |
2659 | * detected in the superblock, group descriptors, inode_bitmaps, or | |
2660 | * block bitmaps. At this point, all of the blocks have been mapped | |
2661 | * out, so we can try to allocate new block(s) to replace the bad | |
2662 | * blocks. | |
3839e657 | 2663 | */ |
1b6bf175 | 2664 | static void handle_fs_bad_blocks(e2fsck_t ctx) |
3839e657 | 2665 | { |
1b6bf175 | 2666 | ext2_filsys fs = ctx->fs; |
54434927 | 2667 | dgrp_t i; |
c5d2f50d VAH |
2668 | blk64_t first_block; |
2669 | blk64_t new_blk; | |
3839e657 TT |
2670 | |
2671 | for (i = 0; i < fs->group_desc_count; i++) { | |
b49f78fe | 2672 | first_block = ext2fs_group_first_block2(fs, i); |
abf23439 | 2673 | |
1b6bf175 | 2674 | if (ctx->invalid_block_bitmap_flag[i]) { |
c5d2f50d | 2675 | new_blk = ext2fs_block_bitmap_loc(fs, i); |
0c4a0726 | 2676 | new_table_block(ctx, first_block, i, _("block bitmap"), |
c5d2f50d VAH |
2677 | 1, &new_blk); |
2678 | ext2fs_block_bitmap_loc_set(fs, i, new_blk); | |
3839e657 | 2679 | } |
1b6bf175 | 2680 | if (ctx->invalid_inode_bitmap_flag[i]) { |
c5d2f50d | 2681 | new_blk = ext2fs_inode_bitmap_loc(fs, i); |
0c4a0726 | 2682 | new_table_block(ctx, first_block, i, _("inode bitmap"), |
c5d2f50d VAH |
2683 | 1, &new_blk); |
2684 | ext2fs_inode_bitmap_loc_set(fs, i, new_blk); | |
3839e657 | 2685 | } |
1b6bf175 | 2686 | if (ctx->invalid_inode_table_flag[i]) { |
c5d2f50d | 2687 | new_blk = ext2fs_inode_table_loc(fs, i); |
0c4a0726 | 2688 | new_table_block(ctx, first_block, i, _("inode table"), |
efc6f628 | 2689 | fs->inode_blocks_per_group, |
c5d2f50d VAH |
2690 | &new_blk); |
2691 | ext2fs_inode_table_loc_set(fs, i, new_blk); | |
08b21301 | 2692 | ctx->flags |= E2F_FLAG_RESTART; |
3839e657 | 2693 | } |
3839e657 | 2694 | } |
1b6bf175 | 2695 | ctx->invalid_bitmaps = 0; |
3839e657 TT |
2696 | } |
2697 | ||
2698 | /* | |
2699 | * This routine marks all blocks which are used by the superblock, | |
2700 | * group descriptors, inode bitmaps, and block bitmaps. | |
2701 | */ | |
1b6bf175 | 2702 | static void mark_table_blocks(e2fsck_t ctx) |
3839e657 | 2703 | { |
1b6bf175 | 2704 | ext2_filsys fs = ctx->fs; |
6dc64392 | 2705 | blk64_t b; |
54434927 | 2706 | dgrp_t i; |
68477355 | 2707 | unsigned int j; |
21c84b71 | 2708 | struct problem_context pctx; |
efc6f628 | 2709 | |
21c84b71 | 2710 | clear_problem_context(&pctx); |
efc6f628 | 2711 | |
3839e657 | 2712 | for (i = 0; i < fs->group_desc_count; i++) { |
21c84b71 | 2713 | pctx.group = i; |
da2e97f7 | 2714 | |
ef344e13 TT |
2715 | ext2fs_reserve_super_and_bgd(fs, i, ctx->block_found_map); |
2716 | ||
21c84b71 TT |
2717 | /* |
2718 | * Mark the blocks used for the inode table | |
2719 | */ | |
d7cca6b0 VAH |
2720 | if (ext2fs_inode_table_loc(fs, i)) { |
2721 | for (j = 0, b = ext2fs_inode_table_loc(fs, i); | |
21c84b71 TT |
2722 | j < fs->inode_blocks_per_group; |
2723 | j++, b++) { | |
c5d2f50d | 2724 | if (ext2fs_test_block_bitmap2(ctx->block_found_map, |
21c84b71 TT |
2725 | b)) { |
2726 | pctx.blk = b; | |
9a7fe4bd TT |
2727 | if (!ctx->invalid_inode_table_flag[i] && |
2728 | fix_problem(ctx, | |
21c84b71 | 2729 | PR_1_ITABLE_CONFLICT, &pctx)) { |
1b6bf175 TT |
2730 | ctx->invalid_inode_table_flag[i]++; |
2731 | ctx->invalid_bitmaps++; | |
21c84b71 TT |
2732 | } |
2733 | } else { | |
c5d2f50d | 2734 | ext2fs_mark_block_bitmap2(ctx->block_found_map, |
21c84b71 | 2735 | b); |
21c84b71 TT |
2736 | } |
2737 | } | |
2738 | } | |
efc6f628 | 2739 | |
3839e657 | 2740 | /* |
efc6f628 | 2741 | * Mark block used for the block bitmap |
3839e657 | 2742 | */ |
d7cca6b0 | 2743 | if (ext2fs_block_bitmap_loc(fs, i)) { |
c5d2f50d | 2744 | if (ext2fs_test_block_bitmap2(ctx->block_found_map, |
d7cca6b0 VAH |
2745 | ext2fs_block_bitmap_loc(fs, i))) { |
2746 | pctx.blk = ext2fs_block_bitmap_loc(fs, i); | |
1b6bf175 TT |
2747 | if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) { |
2748 | ctx->invalid_block_bitmap_flag[i]++; | |
2749 | ctx->invalid_bitmaps++; | |
f3db3566 | 2750 | } |
50e1e10f | 2751 | } else { |
c5d2f50d | 2752 | ext2fs_mark_block_bitmap2(ctx->block_found_map, |
d7cca6b0 | 2753 | ext2fs_block_bitmap_loc(fs, i)); |
50e1e10f | 2754 | } |
efc6f628 | 2755 | |
f3db3566 | 2756 | } |
3839e657 | 2757 | /* |
efc6f628 | 2758 | * Mark block used for the inode bitmap |
3839e657 | 2759 | */ |
d7cca6b0 | 2760 | if (ext2fs_inode_bitmap_loc(fs, i)) { |
c5d2f50d | 2761 | if (ext2fs_test_block_bitmap2(ctx->block_found_map, |
d7cca6b0 VAH |
2762 | ext2fs_inode_bitmap_loc(fs, i))) { |
2763 | pctx.blk = ext2fs_inode_bitmap_loc(fs, i); | |
1b6bf175 TT |
2764 | if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) { |
2765 | ctx->invalid_inode_bitmap_flag[i]++; | |
2766 | ctx->invalid_bitmaps++; | |
efc6f628 | 2767 | } |
50e1e10f | 2768 | } else { |
c5d2f50d | 2769 | ext2fs_mark_block_bitmap2(ctx->block_found_map, |
d7cca6b0 | 2770 | ext2fs_inode_bitmap_loc(fs, i)); |
50e1e10f | 2771 | } |
f3db3566 | 2772 | } |
3839e657 TT |
2773 | } |
2774 | } | |
efc6f628 | 2775 | |
3839e657 | 2776 | /* |
e72a9ba3 | 2777 | * Thes subroutines short circuits ext2fs_get_blocks and |
3839e657 TT |
2778 | * ext2fs_check_directory; we use them since we already have the inode |
2779 | * structure, so there's no point in letting the ext2fs library read | |
2780 | * the inode again. | |
2781 | */ | |
86c627ec TT |
2782 | static errcode_t pass1_get_blocks(ext2_filsys fs, ext2_ino_t ino, |
2783 | blk_t *blocks) | |
3839e657 | 2784 | { |
54dc7ca2 | 2785 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
3839e657 | 2786 | int i; |
efc6f628 | 2787 | |
71d521c6 | 2788 | if ((ino != ctx->stashed_ino) || !ctx->stashed_inode) |
521e3685 TT |
2789 | return EXT2_ET_CALLBACK_NOTHANDLED; |
2790 | ||
2791 | for (i=0; i < EXT2_N_BLOCKS; i++) | |
1b6bf175 | 2792 | blocks[i] = ctx->stashed_inode->i_block[i]; |
521e3685 | 2793 | return 0; |
3839e657 TT |
2794 | } |
2795 | ||
86c627ec | 2796 | static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino, |
e72a9ba3 | 2797 | struct ext2_inode *inode) |
1e3472c5 | 2798 | { |
54dc7ca2 | 2799 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
1b6bf175 | 2800 | |
71d521c6 | 2801 | if ((ino != ctx->stashed_ino) || !ctx->stashed_inode) |
1e3472c5 | 2802 | return EXT2_ET_CALLBACK_NOTHANDLED; |
1b6bf175 | 2803 | *inode = *ctx->stashed_inode; |
1e3472c5 TT |
2804 | return 0; |
2805 | } | |
2806 | ||
86c627ec | 2807 | static errcode_t pass1_write_inode(ext2_filsys fs, ext2_ino_t ino, |
1e3472c5 TT |
2808 | struct ext2_inode *inode) |
2809 | { | |
54dc7ca2 | 2810 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
1b6bf175 | 2811 | |
27431595 TT |
2812 | if ((ino == ctx->stashed_ino) && ctx->stashed_inode && |
2813 | (inode != ctx->stashed_inode)) | |
1b6bf175 | 2814 | *ctx->stashed_inode = *inode; |
1e3472c5 TT |
2815 | return EXT2_ET_CALLBACK_NOTHANDLED; |
2816 | } | |
2817 | ||
86c627ec | 2818 | static errcode_t pass1_check_directory(ext2_filsys fs, ext2_ino_t ino) |
3839e657 | 2819 | { |
54dc7ca2 | 2820 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
1b6bf175 | 2821 | |
71d521c6 | 2822 | if ((ino != ctx->stashed_ino) || !ctx->stashed_inode) |
1b6bf175 TT |
2823 | return EXT2_ET_CALLBACK_NOTHANDLED; |
2824 | ||
2825 | if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode)) | |
291c9049 | 2826 | return EXT2_ET_NO_DIRECTORY; |
1b6bf175 | 2827 | return 0; |
3839e657 | 2828 | } |
e72a9ba3 | 2829 | |
16bd349e TT |
2830 | static errcode_t e2fsck_get_alloc_block(ext2_filsys fs, blk64_t goal, |
2831 | blk64_t *ret) | |
2832 | { | |
2833 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; | |
2834 | errcode_t retval; | |
c5d2f50d | 2835 | blk64_t new_block; |
16bd349e TT |
2836 | |
2837 | if (ctx->block_found_map) { | |
28843200 TT |
2838 | retval = ext2fs_new_block2(fs, goal, ctx->block_found_map, |
2839 | &new_block); | |
16bd349e TT |
2840 | if (retval) |
2841 | return retval; | |
8a2cbe2c | 2842 | if (fs->block_map) { |
2d07b3ad | 2843 | ext2fs_mark_block_bitmap2(fs->block_map, new_block); |
8a2cbe2c TT |
2844 | ext2fs_mark_bb_dirty(fs); |
2845 | } | |
16bd349e TT |
2846 | } else { |
2847 | if (!fs->block_map) { | |
2848 | retval = ext2fs_read_block_bitmap(fs); | |
2849 | if (retval) | |
2850 | return retval; | |
2851 | } | |
2852 | ||
28843200 | 2853 | retval = ext2fs_new_block2(fs, goal, 0, &new_block); |
16bd349e TT |
2854 | if (retval) |
2855 | return retval; | |
2856 | } | |
efc6f628 | 2857 | |
16bd349e TT |
2858 | *ret = new_block; |
2859 | return (0); | |
2860 | } | |
2861 | ||
2862 | static void e2fsck_block_alloc_stats(ext2_filsys fs, blk64_t blk, int inuse) | |
2863 | { | |
2864 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; | |
2865 | ||
2866 | if (ctx->block_found_map) { | |
2867 | if (inuse > 0) | |
28843200 | 2868 | ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); |
16bd349e | 2869 | else |
28843200 | 2870 | ext2fs_unmark_block_bitmap2(ctx->block_found_map, blk); |
16bd349e TT |
2871 | } |
2872 | } | |
2873 | ||
2d2abcc6 | 2874 | void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int use_shortcuts) |
e72a9ba3 TT |
2875 | { |
2876 | ext2_filsys fs = ctx->fs; | |
2877 | ||
2d2abcc6 | 2878 | if (use_shortcuts) { |
e72a9ba3 TT |
2879 | fs->get_blocks = pass1_get_blocks; |
2880 | fs->check_directory = pass1_check_directory; | |
2881 | fs->read_inode = pass1_read_inode; | |
2882 | fs->write_inode = pass1_write_inode; | |
2883 | ctx->stashed_ino = 0; | |
16bd349e TT |
2884 | ext2fs_set_alloc_block_callback(fs, e2fsck_get_alloc_block, |
2885 | 0); | |
2886 | ext2fs_set_block_alloc_stats_callback(fs, | |
2887 | e2fsck_block_alloc_stats, | |
2888 | 0); | |
e72a9ba3 TT |
2889 | } else { |
2890 | fs->get_blocks = 0; | |
2891 | fs->check_directory = 0; | |
2892 | fs->read_inode = 0; | |
2893 | fs->write_inode = 0; | |
2894 | } | |
2895 | } |