]>
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) | |
5c5685d1 | 29 | * - Ref counts for ea_inodes. (ea_inode_refs) |
2ba05753 | 30 | * - The encryption policy ID of each encrypted inode. (encrypted_files) |
3839e657 TT |
31 | * |
32 | * Pass 1 is designed to stash away enough information so that the | |
33 | * other passes should not need to read in the inode information | |
055866d8 | 34 | * during the normal course of a filesystem check. (Although if an |
3839e657 TT |
35 | * inconsistency is detected, other passes may need to read in an |
36 | * inode to fix it.) | |
37 | * | |
38 | * Note that pass 1B will be invoked if there are any duplicate blocks | |
39 | * found. | |
40 | */ | |
41 | ||
b969b1b8 | 42 | #define _GNU_SOURCE 1 /* get strnlen() */ |
d1154eb4 | 43 | #include "config.h" |
3e699064 | 44 | #include <string.h> |
3839e657 | 45 | #include <time.h> |
50e1e10f TT |
46 | #ifdef HAVE_ERRNO_H |
47 | #include <errno.h> | |
48 | #endif | |
3839e657 | 49 | |
3839e657 | 50 | #include "e2fsck.h" |
342d847d | 51 | #include <ext2fs/ext2_ext_attr.h> |
28b44ef0 | 52 | #include <e2p/e2p.h> |
342d847d | 53 | |
21c84b71 | 54 | #include "problem.h" |
3839e657 | 55 | |
50e1e10f TT |
56 | #ifdef NO_INLINE_FUNCS |
57 | #define _INLINE_ | |
58 | #else | |
59 | #define _INLINE_ inline | |
60 | #endif | |
61 | ||
e228d700 DW |
62 | #undef DEBUG |
63 | ||
0b4ffc27 TE |
64 | struct ea_quota { |
65 | blk64_t blocks; | |
66 | __u64 inodes; | |
67 | }; | |
68 | ||
6dc64392 VAH |
69 | static int process_block(ext2_filsys fs, blk64_t *blocknr, |
70 | e2_blkcnt_t blockcnt, blk64_t ref_blk, | |
54dc7ca2 | 71 | int ref_offset, void *priv_data); |
6dc64392 VAH |
72 | static int process_bad_block(ext2_filsys fs, blk64_t *block_nr, |
73 | e2_blkcnt_t blockcnt, blk64_t ref_blk, | |
54dc7ca2 | 74 | int ref_offset, void *priv_data); |
1b6bf175 | 75 | static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, |
0b4ffc27 TE |
76 | char *block_buf, |
77 | const struct ea_quota *ea_ibody_quota); | |
1b6bf175 | 78 | static void mark_table_blocks(e2fsck_t ctx); |
1b6bf175 | 79 | static void alloc_bb_map(e2fsck_t ctx); |
aa4115a4 | 80 | static void alloc_imagic_map(e2fsck_t ctx); |
fdbdea09 | 81 | static void mark_inode_bad(e2fsck_t ctx, ino_t ino); |
1b6bf175 TT |
82 | static void handle_fs_bad_blocks(e2fsck_t ctx); |
83 | static void process_inodes(e2fsck_t ctx, char *block_buf); | |
4c77fe50 | 84 | static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b); |
f3db3566 | 85 | static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan, |
54dc7ca2 | 86 | dgrp_t group, void * priv_data); |
efc6f628 | 87 | static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount, |
e8a3ee62 | 88 | char *block_buf, int adjust_sign); |
6dc64392 | 89 | /* static char *describe_illegal_block(ext2_filsys fs, blk64_t block); */ |
3839e657 TT |
90 | |
91 | struct process_block_struct { | |
86c627ec | 92 | ext2_ino_t ino; |
83e692e8 | 93 | unsigned is_dir:1, is_reg:1, clear:1, suppress:1, |
23d6dd1f DW |
94 | fragmented:1, compressed:1, bbcheck:1, |
95 | inode_modified:1; | |
65d71894 | 96 | blk64_t num_blocks; |
6dc64392 | 97 | blk64_t max_blocks; |
62f9bd0e | 98 | blk64_t last_block; |
010dc7b9 | 99 | e2_blkcnt_t last_init_lblock; |
4dbe79bc | 100 | e2_blkcnt_t last_db_block; |
246501c6 | 101 | int num_illegal_blocks; |
6dc64392 | 102 | blk64_t previous_block; |
f3db3566 | 103 | struct ext2_inode *inode; |
21c84b71 | 104 | struct problem_context *pctx; |
000ba404 | 105 | ext2fs_block_bitmap fs_meta_blocks; |
1b6bf175 | 106 | e2fsck_t ctx; |
ee84bbc8 | 107 | blk64_t next_lblock; |
e228d700 | 108 | struct extent_tree_info eti; |
3839e657 TT |
109 | }; |
110 | ||
111 | struct process_inode_block { | |
86c627ec | 112 | ext2_ino_t ino; |
0b4ffc27 | 113 | struct ea_quota ea_ibody_quota; |
080e09b4 | 114 | struct ext2_inode_large inode; |
3839e657 TT |
115 | }; |
116 | ||
f8188fff TT |
117 | struct scan_callback_struct { |
118 | e2fsck_t ctx; | |
119 | char *block_buf; | |
120 | }; | |
121 | ||
3839e657 TT |
122 | /* |
123 | * For the inodes to process list. | |
124 | */ | |
125 | static struct process_inode_block *inodes_to_process; | |
126 | static int process_inode_count; | |
3839e657 | 127 | |
7823dd65 TT |
128 | static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE - |
129 | EXT2_MIN_BLOCK_LOG_SIZE + 1]; | |
246501c6 | 130 | |
f3db3566 TT |
131 | /* |
132 | * Free all memory allocated by pass1 in preparation for restarting | |
133 | * things. | |
134 | */ | |
54434927 | 135 | static void unwind_pass1(ext2_filsys fs EXT2FS_ATTR((unused))) |
f3db3566 | 136 | { |
c4e3d3f3 | 137 | ext2fs_free_mem(&inodes_to_process); |
08b21301 | 138 | inodes_to_process = 0; |
f3db3566 TT |
139 | } |
140 | ||
7cf73dcd TT |
141 | /* |
142 | * Check to make sure a device inode is real. Returns 1 if the device | |
143 | * checks out, 0 if not. | |
1dde43f0 TT |
144 | * |
145 | * Note: this routine is now also used to check FIFO's and Sockets, | |
146 | * since they have the same requirement; the i_block fields should be | |
efc6f628 | 147 | * zero. |
7cf73dcd | 148 | */ |
efc6f628 | 149 | int e2fsck_pass1_check_device_inode(ext2_filsys fs EXT2FS_ATTR((unused)), |
f954ba01 | 150 | struct ext2_inode *inode) |
7cf73dcd TT |
151 | { |
152 | int i; | |
153 | ||
a40ecbb1 | 154 | /* |
9302bda1 | 155 | * If the index or extents flag is set, then this is a bogus |
441ab1e0 | 156 | * device/fifo/socket |
a40ecbb1 | 157 | */ |
9302bda1 | 158 | if (inode->i_flags & (EXT2_INDEX_FL | EXT4_EXTENTS_FL)) |
53abed0a | 159 | return 0; |
bcf9c5d4 | 160 | |
7fdfabd3 TT |
161 | /* |
162 | * We should be able to do the test below all the time, but | |
163 | * because the kernel doesn't forcibly clear the device | |
164 | * inode's additional i_block fields, there are some rare | |
165 | * occasions when a legitimate device inode will have non-zero | |
166 | * additional i_block fields. So for now, we only complain | |
167 | * when the immutable flag is set, which should never happen | |
168 | * for devices. (And that's when the problem is caused, since | |
169 | * you can't set or clear immutable flags for devices.) Once | |
170 | * the kernel has been fixed we can change this... | |
171 | */ | |
01fbc701 | 172 | if (inode->i_flags & (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL)) { |
efc6f628 | 173 | for (i=4; i < EXT2_N_BLOCKS; i++) |
7fdfabd3 TT |
174 | if (inode->i_block[i]) |
175 | return 0; | |
176 | } | |
7cf73dcd TT |
177 | return 1; |
178 | } | |
179 | ||
67052a8a AD |
180 | /* |
181 | * Check to make sure a symlink inode is real. Returns 1 if the symlink | |
182 | * checks out, 0 if not. | |
183 | */ | |
7cadc577 TT |
184 | int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino, |
185 | struct ext2_inode *inode, char *buf) | |
67052a8a | 186 | { |
22be59d1 | 187 | unsigned int buflen; |
54434927 | 188 | unsigned int len; |
67052a8a | 189 | |
bcf9c5d4 | 190 | if ((inode->i_size_high || inode->i_size == 0) || |
f9f8fded | 191 | (inode->i_flags & EXT2_INDEX_FL)) |
67052a8a AD |
192 | return 0; |
193 | ||
f9f8fded ZL |
194 | if (inode->i_flags & EXT4_INLINE_DATA_FL) { |
195 | size_t inline_size; | |
196 | ||
9666fbfb EB |
197 | if (inode->i_flags & EXT4_EXTENTS_FL) |
198 | return 0; | |
f9f8fded ZL |
199 | if (ext2fs_inline_data_size(fs, ino, &inline_size)) |
200 | return 0; | |
201 | if (inode->i_size != inline_size) | |
202 | return 0; | |
203 | ||
204 | return 1; | |
205 | } | |
206 | ||
2c733c3f EB |
207 | if (ext2fs_is_fast_symlink(inode)) { |
208 | if (inode->i_flags & EXT4_EXTENTS_FL) | |
209 | return 0; | |
22be59d1 EB |
210 | buf = (char *)inode->i_block; |
211 | buflen = sizeof(inode->i_block); | |
cf0be234 | 212 | } else { |
9666fbfb EB |
213 | ext2_extent_handle_t handle; |
214 | struct ext2_extent_info info; | |
215 | struct ext2fs_extent extent; | |
216 | blk64_t blk; | |
217 | int i; | |
67052a8a | 218 | |
9666fbfb EB |
219 | if (inode->i_flags & EXT4_EXTENTS_FL) { |
220 | if (ext2fs_extent_open2(fs, ino, inode, &handle)) | |
221 | return 0; | |
222 | if (ext2fs_extent_get_info(handle, &info) || | |
223 | (info.num_entries != 1) || | |
224 | (info.max_depth != 0)) { | |
225 | ext2fs_extent_free(handle); | |
226 | return 0; | |
227 | } | |
228 | if (ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, | |
229 | &extent) || | |
230 | (extent.e_lblk != 0) || | |
231 | (extent.e_len != 1)) { | |
232 | ext2fs_extent_free(handle); | |
67052a8a | 233 | return 0; |
9666fbfb EB |
234 | } |
235 | blk = extent.e_pblk; | |
236 | ext2fs_extent_free(handle); | |
237 | } else { | |
238 | blk = inode->i_block[0]; | |
239 | ||
240 | for (i = 1; i < EXT2_N_BLOCKS; i++) | |
241 | if (inode->i_block[i]) | |
242 | return 0; | |
243 | } | |
244 | ||
245 | if (blk < fs->super->s_first_data_block || | |
246 | blk >= ext2fs_blocks_count(fs->super)) | |
247 | return 0; | |
b94a052a | 248 | |
9666fbfb | 249 | if (io_channel_read_blk64(fs->io, blk, 1, buf)) |
b94a052a AD |
250 | return 0; |
251 | ||
22be59d1 | 252 | buflen = fs->blocksize; |
67052a8a | 253 | } |
22be59d1 EB |
254 | |
255 | if (inode->i_flags & EXT4_ENCRYPT_FL) | |
256 | len = ext2fs_le16_to_cpu(*(__u16 *)buf) + 2; | |
257 | else | |
258 | len = strnlen(buf, buflen); | |
259 | ||
260 | if (len >= buflen) | |
261 | return 0; | |
262 | ||
b94a052a | 263 | if (len != inode->i_size) |
203be6fe | 264 | return 0; |
67052a8a AD |
265 | return 1; |
266 | } | |
267 | ||
8dae07fb DW |
268 | /* |
269 | * If the extents or inlinedata flags are set on the inode, offer to clear 'em. | |
270 | */ | |
271 | #define BAD_SPECIAL_FLAGS (EXT4_EXTENTS_FL | EXT4_INLINE_DATA_FL) | |
272 | static void check_extents_inlinedata(e2fsck_t ctx, | |
273 | struct problem_context *pctx) | |
274 | { | |
275 | if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS)) | |
276 | return; | |
277 | ||
278 | if (!fix_problem(ctx, PR_1_SPECIAL_EXTENTS_IDATA, pctx)) | |
279 | return; | |
280 | ||
281 | pctx->inode->i_flags &= ~BAD_SPECIAL_FLAGS; | |
282 | e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1"); | |
283 | } | |
284 | #undef BAD_SPECIAL_FLAGS | |
285 | ||
6fdc7a32 | 286 | /* |
01fbc701 TT |
287 | * If the immutable (or append-only) flag is set on the inode, offer |
288 | * to clear it. | |
6fdc7a32 | 289 | */ |
bcf9c5d4 | 290 | #define BAD_SPECIAL_FLAGS (EXT2_IMMUTABLE_FL | EXT2_APPEND_FL) |
6fdc7a32 TT |
291 | static void check_immutable(e2fsck_t ctx, struct problem_context *pctx) |
292 | { | |
b94a052a | 293 | if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS)) |
6fdc7a32 TT |
294 | return; |
295 | ||
296 | if (!fix_problem(ctx, PR_1_SET_IMMUTABLE, pctx)) | |
297 | return; | |
298 | ||
b94a052a | 299 | pctx->inode->i_flags &= ~BAD_SPECIAL_FLAGS; |
6fdc7a32 TT |
300 | e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1"); |
301 | } | |
302 | ||
d647a1ea TT |
303 | /* |
304 | * If device, fifo or socket, check size is zero -- if not offer to | |
305 | * clear it | |
306 | */ | |
307 | static void check_size(e2fsck_t ctx, struct problem_context *pctx) | |
308 | { | |
309 | struct ext2_inode *inode = pctx->inode; | |
efc6f628 | 310 | |
0bd0e593 | 311 | if (EXT2_I_SIZE(inode) == 0) |
d647a1ea | 312 | return; |
efc6f628 | 313 | |
85645a6f | 314 | if (!fix_problem(ctx, PR_1_SET_NONZSIZE, pctx)) |
d647a1ea | 315 | return; |
efc6f628 | 316 | |
97c607b1 | 317 | ext2fs_inode_size_set(ctx->fs, inode, 0); |
d647a1ea TT |
318 | e2fsck_write_inode(ctx, pctx->ino, pctx->inode, "pass1"); |
319 | } | |
efc6f628 | 320 | |
b0f457bd TE |
321 | /* |
322 | * For a given size, calculate how many blocks would be charged towards quota. | |
323 | */ | |
324 | static blk64_t size_to_quota_blocks(ext2_filsys fs, size_t size) | |
325 | { | |
326 | blk64_t clusters; | |
327 | ||
328 | clusters = DIV_ROUND_UP(size, fs->blocksize << fs->cluster_ratio_bits); | |
329 | return EXT2FS_C2B(fs, clusters); | |
330 | } | |
331 | ||
6a081f6d AD |
332 | /* |
333 | * Check validity of EA inode. Return 0 if EA inode is valid, otherwise return | |
334 | * the problem code. | |
335 | */ | |
336 | static problem_t check_large_ea_inode(e2fsck_t ctx, | |
337 | struct ext2_ext_attr_entry *entry, | |
b0f457bd TE |
338 | struct problem_context *pctx, |
339 | blk64_t *quota_blocks) | |
6a081f6d AD |
340 | { |
341 | struct ext2_inode inode; | |
2477e163 TE |
342 | __u32 hash; |
343 | errcode_t retval; | |
6a081f6d AD |
344 | |
345 | /* Check if inode is within valid range */ | |
346 | if ((entry->e_value_inum < EXT2_FIRST_INODE(ctx->fs->super)) || | |
2477e163 TE |
347 | (entry->e_value_inum > ctx->fs->super->s_inodes_count)) { |
348 | pctx->num = entry->e_value_inum; | |
6a081f6d | 349 | return PR_1_ATTR_VALUE_EA_INODE; |
2477e163 | 350 | } |
6a081f6d AD |
351 | |
352 | e2fsck_read_inode(ctx, entry->e_value_inum, &inode, "pass1"); | |
2477e163 TE |
353 | |
354 | retval = ext2fs_ext_attr_hash_entry2(ctx->fs, entry, NULL, &hash); | |
355 | if (retval) { | |
356 | com_err("check_large_ea_inode", retval, | |
357 | _("while hashing entry with e_value_inum = %u"), | |
358 | entry->e_value_inum); | |
359 | fatal_error(ctx, 0); | |
360 | } | |
361 | ||
b0f457bd TE |
362 | if (hash == entry->e_hash) { |
363 | *quota_blocks = size_to_quota_blocks(ctx->fs, | |
364 | entry->e_value_size); | |
365 | } else { | |
2477e163 | 366 | /* This might be an old Lustre-style ea_inode reference. */ |
b0f457bd TE |
367 | if (inode.i_mtime == pctx->ino && |
368 | inode.i_generation == pctx->inode->i_generation) { | |
369 | *quota_blocks = 0; | |
370 | } else { | |
2477e163 TE |
371 | /* If target inode is also missing EA_INODE flag, |
372 | * this is likely to be a bad reference. | |
373 | */ | |
374 | if (!(inode.i_flags & EXT4_EA_INODE_FL)) { | |
375 | pctx->num = entry->e_value_inum; | |
376 | return PR_1_ATTR_VALUE_EA_INODE; | |
377 | } else { | |
378 | pctx->num = entry->e_hash; | |
379 | return PR_1_ATTR_HASH; | |
380 | } | |
381 | } | |
382 | } | |
383 | ||
6a081f6d | 384 | if (!(inode.i_flags & EXT4_EA_INODE_FL)) { |
2477e163 TE |
385 | pctx->num = entry->e_value_inum; |
386 | if (fix_problem(ctx, PR_1_ATTR_SET_EA_INODE_FL, pctx)) { | |
6a081f6d | 387 | inode.i_flags |= EXT4_EA_INODE_FL; |
2477e163 TE |
388 | ext2fs_write_inode(ctx->fs, entry->e_value_inum, |
389 | &inode); | |
390 | } else { | |
6a081f6d | 391 | return PR_1_ATTR_NO_EA_INODE_FL; |
2477e163 TE |
392 | } |
393 | } | |
6a081f6d AD |
394 | return 0; |
395 | } | |
396 | ||
5c5685d1 TE |
397 | static void inc_ea_inode_refs(e2fsck_t ctx, struct problem_context *pctx, |
398 | struct ext2_ext_attr_entry *first, void *end) | |
399 | { | |
400 | struct ext2_ext_attr_entry *entry; | |
401 | ||
402 | for (entry = first; | |
403 | (void *)entry < end && !EXT2_EXT_IS_LAST_ENTRY(entry); | |
404 | entry = EXT2_EXT_ATTR_NEXT(entry)) { | |
405 | if (!entry->e_value_inum) | |
406 | continue; | |
407 | if (!ctx->ea_inode_refs) { | |
408 | pctx->errcode = ea_refcount_create(0, | |
409 | &ctx->ea_inode_refs); | |
410 | if (pctx->errcode) { | |
411 | pctx->num = 4; | |
412 | fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx); | |
413 | ctx->flags |= E2F_FLAG_ABORT; | |
414 | return; | |
415 | } | |
416 | } | |
417 | ea_refcount_increment(ctx->ea_inode_refs, entry->e_value_inum, | |
418 | 0); | |
419 | } | |
420 | } | |
421 | ||
b0f457bd | 422 | static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx, |
0b4ffc27 | 423 | struct ea_quota *ea_ibody_quota) |
cebe48a1 TT |
424 | { |
425 | struct ext2_super_block *sb = ctx->fs->super; | |
426 | struct ext2_inode_large *inode; | |
427 | struct ext2_ext_attr_entry *entry; | |
5c5685d1 | 428 | char *start, *header, *end; |
1a8c2c4a | 429 | unsigned int storage_size, remain; |
3c7c6d73 | 430 | problem_t problem = 0; |
78c666b8 | 431 | region_t region = 0; |
b0f457bd | 432 | |
0b4ffc27 TE |
433 | ea_ibody_quota->blocks = 0; |
434 | ea_ibody_quota->inodes = 0; | |
cebe48a1 TT |
435 | |
436 | inode = (struct ext2_inode_large *) pctx->inode; | |
437 | storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE - | |
438 | inode->i_extra_isize; | |
78c666b8 DW |
439 | header = ((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + |
440 | inode->i_extra_isize; | |
5c5685d1 | 441 | end = header + storage_size; |
78c666b8 | 442 | start = header + sizeof(__u32); |
cebe48a1 TT |
443 | entry = (struct ext2_ext_attr_entry *) start; |
444 | ||
445 | /* scan all entry's headers first */ | |
446 | ||
447 | /* take finish entry 0UL into account */ | |
efc6f628 | 448 | remain = storage_size - sizeof(__u32); |
cebe48a1 | 449 | |
78c666b8 DW |
450 | region = region_create(0, storage_size); |
451 | if (!region) { | |
452 | fix_problem(ctx, PR_1_EA_ALLOC_REGION_ABORT, pctx); | |
453 | problem = 0; | |
454 | ctx->flags |= E2F_FLAG_ABORT; | |
455 | return; | |
456 | } | |
457 | if (region_allocate(region, 0, sizeof(__u32))) { | |
458 | problem = PR_1_INODE_EA_ALLOC_COLLISION; | |
459 | goto fix; | |
460 | } | |
461 | ||
88334ce0 DW |
462 | while (remain >= sizeof(struct ext2_ext_attr_entry) && |
463 | !EXT2_EXT_IS_LAST_ENTRY(entry)) { | |
fefaef39 | 464 | __u32 hash; |
cebe48a1 | 465 | |
78c666b8 DW |
466 | if (region_allocate(region, (char *)entry - (char *)header, |
467 | EXT2_EXT_ATTR_LEN(entry->e_name_len))) { | |
468 | problem = PR_1_INODE_EA_ALLOC_COLLISION; | |
469 | goto fix; | |
470 | } | |
471 | ||
cebe48a1 TT |
472 | /* header eats this space */ |
473 | remain -= sizeof(struct ext2_ext_attr_entry); | |
efc6f628 | 474 | |
cebe48a1 TT |
475 | /* is attribute name valid? */ |
476 | if (EXT2_EXT_ATTR_SIZE(entry->e_name_len) > remain) { | |
477 | pctx->num = entry->e_name_len; | |
478 | problem = PR_1_ATTR_NAME_LEN; | |
479 | goto fix; | |
480 | } | |
481 | ||
482 | /* attribute len eats this space */ | |
483 | remain -= EXT2_EXT_ATTR_SIZE(entry->e_name_len); | |
484 | ||
6a081f6d AD |
485 | if (entry->e_value_inum == 0) { |
486 | /* check value size */ | |
487 | if (entry->e_value_size > remain) { | |
488 | pctx->num = entry->e_value_size; | |
489 | problem = PR_1_ATTR_VALUE_SIZE; | |
490 | goto fix; | |
491 | } | |
cebe48a1 | 492 | |
6a081f6d AD |
493 | if (entry->e_value_size && |
494 | region_allocate(region, | |
495 | sizeof(__u32) + entry->e_value_offs, | |
496 | EXT2_EXT_ATTR_SIZE( | |
497 | entry->e_value_size))) { | |
498 | problem = PR_1_INODE_EA_ALLOC_COLLISION; | |
499 | goto fix; | |
500 | } | |
2477e163 TE |
501 | |
502 | hash = ext2fs_ext_attr_hash_entry(entry, | |
503 | start + entry->e_value_offs); | |
504 | ||
505 | /* e_hash may be 0 in older inode's ea */ | |
506 | if (entry->e_hash != 0 && entry->e_hash != hash) { | |
507 | pctx->num = entry->e_hash; | |
508 | problem = PR_1_ATTR_HASH; | |
509 | goto fix; | |
510 | } | |
6a081f6d | 511 | } else { |
0b4ffc27 | 512 | blk64_t quota_blocks; |
b0f457bd TE |
513 | |
514 | problem = check_large_ea_inode(ctx, entry, pctx, | |
0b4ffc27 | 515 | "a_blocks); |
6a081f6d AD |
516 | if (problem != 0) |
517 | goto fix; | |
fefaef39 | 518 | |
0b4ffc27 TE |
519 | ea_ibody_quota->blocks += quota_blocks; |
520 | ea_ibody_quota->inodes++; | |
78c666b8 DW |
521 | } |
522 | ||
6a081f6d AD |
523 | /* If EA value is stored in external inode then it does not |
524 | * consume space here */ | |
525 | if (entry->e_value_inum == 0) | |
526 | remain -= entry->e_value_size; | |
cebe48a1 TT |
527 | |
528 | entry = EXT2_EXT_ATTR_NEXT(entry); | |
529 | } | |
78c666b8 DW |
530 | |
531 | if (region_allocate(region, (char *)entry - (char *)header, | |
532 | sizeof(__u32))) { | |
533 | problem = PR_1_INODE_EA_ALLOC_COLLISION; | |
534 | goto fix; | |
535 | } | |
cebe48a1 | 536 | fix: |
78c666b8 DW |
537 | if (region) |
538 | region_free(region); | |
cebe48a1 TT |
539 | /* |
540 | * it seems like a corruption. it's very unlikely we could repair | |
541 | * EA(s) in automatic fashion -bzzz | |
542 | */ | |
b0f457bd | 543 | if (problem == 0 || !fix_problem(ctx, problem, pctx)) { |
5c5685d1 TE |
544 | inc_ea_inode_refs(ctx, pctx, |
545 | (struct ext2_ext_attr_entry *)start, end); | |
cebe48a1 | 546 | return; |
b0f457bd | 547 | } |
cebe48a1 | 548 | |
fefaef39 | 549 | /* simply remove all possible EA(s) */ |
78c666b8 | 550 | *((__u32 *)header) = 0UL; |
da938f20 | 551 | e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode, |
cebe48a1 | 552 | EXT2_INODE_SIZE(sb), "pass1"); |
0b4ffc27 TE |
553 | ea_ibody_quota->blocks = 0; |
554 | ea_ibody_quota->inodes = 0; | |
cebe48a1 TT |
555 | } |
556 | ||
082ed5dc | 557 | static int check_inode_extra_negative_epoch(__u32 xtime, __u32 extra) { |
c8ca2397 | 558 | return (xtime & (1U << 31)) != 0 && |
082ed5dc DT |
559 | (extra & EXT4_EPOCH_MASK) == EXT4_EPOCH_MASK; |
560 | } | |
561 | ||
562 | #define CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, xtime) \ | |
563 | check_inode_extra_negative_epoch(inode->i_##xtime, \ | |
564 | inode->i_##xtime##_extra) | |
565 | ||
566 | /* When today's date is earlier than 2242, we assume that atimes, | |
567 | * ctimes, crtimes, and mtimes with years in the range 2310..2378 are | |
568 | * actually pre-1970 dates mis-encoded. | |
569 | */ | |
570 | #define EXT4_EXTRA_NEGATIVE_DATE_CUTOFF 2 * (1LL << 32) | |
571 | ||
b0f457bd | 572 | static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx, |
0b4ffc27 | 573 | struct ea_quota *ea_ibody_quota) |
cebe48a1 TT |
574 | { |
575 | struct ext2_super_block *sb = ctx->fs->super; | |
576 | struct ext2_inode_large *inode; | |
577 | __u32 *eamagic; | |
578 | int min, max; | |
579 | ||
0b4ffc27 TE |
580 | ea_ibody_quota->blocks = 0; |
581 | ea_ibody_quota->inodes = 0; | |
b0f457bd | 582 | |
cebe48a1 TT |
583 | inode = (struct ext2_inode_large *) pctx->inode; |
584 | if (EXT2_INODE_SIZE(sb) == EXT2_GOOD_OLD_INODE_SIZE) { | |
585 | /* this isn't large inode. so, nothing to check */ | |
586 | return; | |
587 | } | |
588 | ||
589 | #if 0 | |
590 | printf("inode #%u, i_extra_size %d\n", pctx->ino, | |
591 | inode->i_extra_isize); | |
efc6f628 | 592 | #endif |
89efc88e TT |
593 | /* i_extra_isize must cover i_extra_isize + i_checksum_hi at least */ |
594 | min = sizeof(inode->i_extra_isize) + sizeof(inode->i_checksum_hi); | |
cebe48a1 | 595 | max = EXT2_INODE_SIZE(sb) - EXT2_GOOD_OLD_INODE_SIZE; |
efc6f628 | 596 | /* |
cebe48a1 TT |
597 | * For now we will allow i_extra_isize to be 0, but really |
598 | * implementations should never allow i_extra_isize to be 0 | |
599 | */ | |
600 | if (inode->i_extra_isize && | |
a7b27f11 TT |
601 | (inode->i_extra_isize < min || inode->i_extra_isize > max || |
602 | inode->i_extra_isize & 3)) { | |
cebe48a1 TT |
603 | if (!fix_problem(ctx, PR_1_EXTRA_ISIZE, pctx)) |
604 | return; | |
a7b27f11 TT |
605 | if (inode->i_extra_isize < min || inode->i_extra_isize > max) |
606 | inode->i_extra_isize = sb->s_want_extra_isize; | |
607 | else | |
608 | inode->i_extra_isize = (inode->i_extra_isize + 3) & ~3; | |
cebe48a1 TT |
609 | e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode, |
610 | EXT2_INODE_SIZE(sb), "pass1"); | |
cebe48a1 TT |
611 | } |
612 | ||
2b833c9a AV |
613 | /* check if there is no place for an EA header */ |
614 | if (inode->i_extra_isize >= max - sizeof(__u32)) | |
615 | return; | |
616 | ||
cebe48a1 TT |
617 | eamagic = (__u32 *) (((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + |
618 | inode->i_extra_isize); | |
619 | if (*eamagic == EXT2_EXT_ATTR_MAGIC) { | |
620 | /* it seems inode has an extended attribute(s) in body */ | |
0b4ffc27 | 621 | check_ea_in_inode(ctx, pctx, ea_ibody_quota); |
cebe48a1 | 622 | } |
082ed5dc DT |
623 | |
624 | /* | |
625 | * If the inode's extended atime (ctime, crtime, mtime) is stored in | |
626 | * the old, invalid format, repair it. | |
627 | */ | |
25419562 TT |
628 | if (((sizeof(time_t) <= 4) || |
629 | (((sizeof(time_t) > 4) && | |
630 | ctx->now < EXT4_EXTRA_NEGATIVE_DATE_CUTOFF))) && | |
082ed5dc DT |
631 | (CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, atime) || |
632 | CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, ctime) || | |
633 | CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, crtime) || | |
634 | CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, mtime))) { | |
635 | ||
636 | if (!fix_problem(ctx, PR_1_EA_TIME_OUT_OF_RANGE, pctx)) | |
637 | return; | |
638 | ||
639 | if (CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, atime)) | |
640 | inode->i_atime_extra &= ~EXT4_EPOCH_MASK; | |
641 | if (CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, ctime)) | |
642 | inode->i_ctime_extra &= ~EXT4_EPOCH_MASK; | |
643 | if (CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, crtime)) | |
644 | inode->i_crtime_extra &= ~EXT4_EPOCH_MASK; | |
645 | if (CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, mtime)) | |
646 | inode->i_mtime_extra &= ~EXT4_EPOCH_MASK; | |
647 | e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode, | |
648 | EXT2_INODE_SIZE(sb), "pass1"); | |
649 | } | |
650 | ||
cebe48a1 | 651 | } |
6fdc7a32 | 652 | |
efc6f628 | 653 | /* |
fbc3f901 TT |
654 | * Check to see if the inode might really be a directory, despite i_mode |
655 | * | |
656 | * This is a lot of complexity for something for which I'm not really | |
657 | * convinced happens frequently in the wild. If for any reason this | |
658 | * causes any problems, take this code out. | |
659 | * [tytso:20070331.0827EDT] | |
660 | */ | |
661 | static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx, | |
662 | char *buf) | |
663 | { | |
664 | struct ext2_inode *inode = pctx->inode; | |
fbc3f901 | 665 | struct ext2_dir_entry *dirent; |
e94bc631 | 666 | errcode_t retval; |
cf5301d7 | 667 | blk64_t blk; |
03fa6f8a | 668 | unsigned int i, rec_len, not_device = 0; |
1ec42a00 | 669 | int extent_fs; |
042e0719 | 670 | int inlinedata_fs; |
fbc3f901 | 671 | |
1ec42a00 ND |
672 | /* |
673 | * If the mode looks OK, we believe it. If the first block in | |
674 | * the i_block array is 0, this cannot be a directory. If the | |
675 | * inode is extent-mapped, it is still the case that the latter | |
676 | * cannot be 0 - the magic number in the extent header would make | |
677 | * it nonzero. | |
678 | */ | |
fbc3f901 | 679 | if (LINUX_S_ISDIR(inode->i_mode) || LINUX_S_ISREG(inode->i_mode) || |
0eeb1549 | 680 | LINUX_S_ISLNK(inode->i_mode) || inode->i_block[0] == 0) |
fbc3f901 TT |
681 | return; |
682 | ||
1ec42a00 ND |
683 | /* |
684 | * Check the block numbers in the i_block array for validity: | |
685 | * zero blocks are skipped (but the first one cannot be zero - | |
686 | * see above), other blocks are checked against the first and | |
687 | * max data blocks (from the the superblock) and against the | |
688 | * block bitmap. Any invalid block found means this cannot be | |
689 | * a directory. | |
690 | * | |
691 | * If there are non-zero blocks past the fourth entry, then | |
692 | * this cannot be a device file: we remember that for the next | |
693 | * check. | |
694 | * | |
695 | * For extent mapped files, we don't do any sanity checking: | |
696 | * just try to get the phys block of logical block 0 and run | |
697 | * with it. | |
042e0719 ZL |
698 | * |
699 | * For inline data files, we just try to get the size of inline | |
700 | * data. If it's true, we will treat it as a directory. | |
1ec42a00 ND |
701 | */ |
702 | ||
86f3b6cf DW |
703 | extent_fs = ext2fs_has_feature_extents(ctx->fs->super); |
704 | inlinedata_fs = ext2fs_has_feature_inline_data(ctx->fs->super); | |
042e0719 | 705 | if (inlinedata_fs && (inode->i_flags & EXT4_INLINE_DATA_FL)) { |
24997f1c | 706 | size_t size; |
e274cc39 | 707 | __u32 dotdot; |
82e48fb1 | 708 | unsigned int rec_len2; |
e274cc39 | 709 | struct ext2_dir_entry de; |
042e0719 ZL |
710 | |
711 | if (ext2fs_inline_data_size(ctx->fs, pctx->ino, &size)) | |
712 | return; | |
4339c6d4 DW |
713 | /* |
714 | * If the size isn't a multiple of 4, it's probably not a | |
715 | * directory?? | |
716 | */ | |
717 | if (size & 3) | |
718 | return; | |
e274cc39 DW |
719 | /* |
720 | * If the first 10 bytes don't look like a directory entry, | |
721 | * it's probably not a directory. | |
722 | */ | |
723 | memcpy(&dotdot, inode->i_block, sizeof(dotdot)); | |
724 | memcpy(&de, ((char *)inode->i_block) + EXT4_INLINE_DATA_DOTDOT_SIZE, | |
725 | EXT2_DIR_REC_LEN(0)); | |
726 | dotdot = ext2fs_le32_to_cpu(dotdot); | |
727 | de.inode = ext2fs_le32_to_cpu(de.inode); | |
728 | de.rec_len = ext2fs_le16_to_cpu(de.rec_len); | |
82e48fb1 | 729 | ext2fs_get_rec_len(ctx->fs, &de, &rec_len2); |
e274cc39 DW |
730 | if (dotdot >= ctx->fs->super->s_inodes_count || |
731 | (dotdot < EXT2_FIRST_INO(ctx->fs->super) && | |
732 | dotdot != EXT2_ROOT_INO) || | |
733 | de.inode >= ctx->fs->super->s_inodes_count || | |
734 | (de.inode < EXT2_FIRST_INO(ctx->fs->super) && | |
735 | de.inode != 0) || | |
82e48fb1 | 736 | rec_len2 > EXT4_MIN_INLINE_DATA_SIZE - |
e274cc39 DW |
737 | EXT4_INLINE_DATA_DOTDOT_SIZE) |
738 | return; | |
042e0719 ZL |
739 | /* device files never have a "system.data" entry */ |
740 | goto isdir; | |
741 | } else if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) { | |
1ec42a00 | 742 | /* extent mapped */ |
6dc64392 | 743 | if (ext2fs_bmap2(ctx->fs, pctx->ino, inode, 0, 0, 0, 0, |
1ec42a00 ND |
744 | &blk)) |
745 | return; | |
746 | /* device files are never extent mapped */ | |
747 | not_device++; | |
748 | } else { | |
749 | for (i=0; i < EXT2_N_BLOCKS; i++) { | |
750 | blk = inode->i_block[i]; | |
751 | if (!blk) | |
752 | continue; | |
753 | if (i >= 4) | |
754 | not_device++; | |
755 | ||
756 | if (blk < ctx->fs->super->s_first_data_block || | |
cc84d866 TT |
757 | blk >= ext2fs_blocks_count(ctx->fs->super) || |
758 | ext2fs_fast_test_block_bitmap2(ctx->block_found_map, | |
759 | blk)) | |
1ec42a00 ND |
760 | return; /* Invalid block, can't be dir */ |
761 | } | |
762 | blk = inode->i_block[0]; | |
fbc3f901 TT |
763 | } |
764 | ||
1ec42a00 ND |
765 | /* |
766 | * If the mode says this is a device file and the i_links_count field | |
767 | * is sane and we have not ruled it out as a device file previously, | |
768 | * we declare it a device file, not a directory. | |
769 | */ | |
efc6f628 | 770 | if ((LINUX_S_ISCHR(inode->i_mode) || LINUX_S_ISBLK(inode->i_mode)) && |
fbc3f901 TT |
771 | (inode->i_links_count == 1) && !not_device) |
772 | return; | |
773 | ||
1ec42a00 | 774 | /* read the first block */ |
f85a9ae6 | 775 | ehandler_operation(_("reading directory block")); |
81683c6a | 776 | retval = ext2fs_read_dir_block4(ctx->fs, blk, buf, 0, pctx->ino); |
e94bc631 TT |
777 | ehandler_operation(0); |
778 | if (retval) | |
fbc3f901 TT |
779 | return; |
780 | ||
781 | dirent = (struct ext2_dir_entry *) buf; | |
8a480350 TT |
782 | retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len); |
783 | if (retval) | |
784 | return; | |
70f4632b | 785 | if ((ext2fs_dirent_name_len(dirent) != 1) || |
fbc3f901 TT |
786 | (dirent->name[0] != '.') || |
787 | (dirent->inode != pctx->ino) || | |
5dd77dbe TT |
788 | (rec_len < 12) || |
789 | (rec_len % 4) || | |
790 | (rec_len >= ctx->fs->blocksize - 12)) | |
fbc3f901 TT |
791 | return; |
792 | ||
5dd77dbe | 793 | dirent = (struct ext2_dir_entry *) (buf + rec_len); |
8a480350 TT |
794 | retval = ext2fs_get_rec_len(ctx->fs, dirent, &rec_len); |
795 | if (retval) | |
796 | return; | |
70f4632b | 797 | if ((ext2fs_dirent_name_len(dirent) != 2) || |
fbc3f901 TT |
798 | (dirent->name[0] != '.') || |
799 | (dirent->name[1] != '.') || | |
5dd77dbe TT |
800 | (rec_len < 12) || |
801 | (rec_len % 4)) | |
fbc3f901 TT |
802 | return; |
803 | ||
042e0719 | 804 | isdir: |
fbc3f901 TT |
805 | if (fix_problem(ctx, PR_1_TREAT_AS_DIRECTORY, pctx)) { |
806 | inode->i_mode = (inode->i_mode & 07777) | LINUX_S_IFDIR; | |
efc6f628 TT |
807 | e2fsck_write_inode_full(ctx, pctx->ino, inode, |
808 | EXT2_INODE_SIZE(ctx->fs->super), | |
fbc3f901 TT |
809 | "check_is_really_dir"); |
810 | } | |
811 | } | |
812 | ||
749f0712 TT |
813 | extern errcode_t e2fsck_setup_icount(e2fsck_t ctx, const char *icount_name, |
814 | int flags, ext2_icount_t hint, | |
815 | ext2_icount_t *ret) | |
34b9f796 | 816 | { |
f954ba01 | 817 | unsigned int threshold; |
749f0712 | 818 | unsigned int save_type; |
34b9f796 TT |
819 | ext2_ino_t num_dirs; |
820 | errcode_t retval; | |
f954ba01 TT |
821 | char *tdb_dir; |
822 | int enable; | |
34b9f796 TT |
823 | |
824 | *ret = 0; | |
825 | ||
826 | profile_get_string(ctx->profile, "scratch_files", "directory", 0, 0, | |
827 | &tdb_dir); | |
f954ba01 TT |
828 | profile_get_uint(ctx->profile, "scratch_files", |
829 | "numdirs_threshold", 0, 0, &threshold); | |
34b9f796 TT |
830 | profile_get_boolean(ctx->profile, "scratch_files", |
831 | "icount", 0, 1, &enable); | |
832 | ||
833 | retval = ext2fs_get_num_dirs(ctx->fs, &num_dirs); | |
834 | if (retval) | |
835 | num_dirs = 1024; /* Guess */ | |
836 | ||
749f0712 TT |
837 | if (enable && tdb_dir && !access(tdb_dir, W_OK) && |
838 | (!threshold || num_dirs > threshold)) { | |
839 | retval = ext2fs_create_icount_tdb(ctx->fs, tdb_dir, | |
840 | flags, ret); | |
841 | if (retval == 0) | |
842 | return 0; | |
843 | } | |
844 | e2fsck_set_bitmap_type(ctx->fs, EXT2FS_BMAP64_RBTREE, icount_name, | |
845 | &save_type); | |
6304d212 JK |
846 | if (ctx->options & E2F_OPT_ICOUNT_FULLMAP) |
847 | flags |= EXT2_ICOUNT_OPT_FULLMAP; | |
749f0712 TT |
848 | retval = ext2fs_create_icount2(ctx->fs, flags, 0, hint, ret); |
849 | ctx->fs->default_bitmap_type = save_type; | |
850 | return retval; | |
34b9f796 TT |
851 | } |
852 | ||
b9cde40d DW |
853 | static errcode_t recheck_bad_inode_checksum(ext2_filsys fs, ext2_ino_t ino, |
854 | e2fsck_t ctx, | |
855 | struct problem_context *pctx) | |
856 | { | |
857 | errcode_t retval; | |
858 | struct ext2_inode_large inode; | |
859 | ||
860 | /* | |
861 | * Reread inode. If we don't see checksum error, then this inode | |
862 | * has been fixed elsewhere. | |
863 | */ | |
25030487 | 864 | ctx->stashed_ino = 0; |
b9cde40d DW |
865 | retval = ext2fs_read_inode_full(fs, ino, (struct ext2_inode *)&inode, |
866 | sizeof(inode)); | |
867 | if (retval && retval != EXT2_ET_INODE_CSUM_INVALID) | |
868 | return retval; | |
869 | if (!retval) | |
870 | return 0; | |
871 | ||
872 | /* | |
873 | * Checksum still doesn't match. That implies that the inode passes | |
874 | * all the sanity checks, so maybe the checksum is simply corrupt. | |
875 | * See if the user will go for fixing that. | |
876 | */ | |
877 | if (!fix_problem(ctx, PR_1_INODE_ONLY_CSUM_INVALID, pctx)) | |
878 | return 0; | |
879 | ||
880 | retval = ext2fs_write_inode_full(fs, ino, (struct ext2_inode *)&inode, | |
881 | sizeof(inode)); | |
6e3c3b75 | 882 | return retval; |
b9cde40d DW |
883 | } |
884 | ||
b729b7df DW |
885 | static void reserve_block_for_root_repair(e2fsck_t ctx) |
886 | { | |
887 | blk64_t blk = 0; | |
888 | errcode_t err; | |
889 | ext2_filsys fs = ctx->fs; | |
890 | ||
891 | ctx->root_repair_block = 0; | |
892 | if (ext2fs_test_inode_bitmap2(ctx->inode_used_map, EXT2_ROOT_INO)) | |
893 | return; | |
894 | ||
895 | err = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); | |
896 | if (err) | |
897 | return; | |
898 | ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); | |
899 | ctx->root_repair_block = blk; | |
900 | } | |
901 | ||
902 | static void reserve_block_for_lnf_repair(e2fsck_t ctx) | |
903 | { | |
904 | blk64_t blk = 0; | |
905 | errcode_t err; | |
906 | ext2_filsys fs = ctx->fs; | |
907 | static const char name[] = "lost+found"; | |
908 | ext2_ino_t ino; | |
909 | ||
910 | ctx->lnf_repair_block = 0; | |
911 | if (!ext2fs_lookup(fs, EXT2_ROOT_INO, name, sizeof(name)-1, 0, &ino)) | |
912 | return; | |
913 | ||
914 | err = ext2fs_new_block2(fs, 0, ctx->block_found_map, &blk); | |
915 | if (err) | |
916 | return; | |
917 | ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); | |
918 | ctx->lnf_repair_block = blk; | |
919 | } | |
920 | ||
49a3749a DW |
921 | static errcode_t get_inline_data_ea_size(ext2_filsys fs, ext2_ino_t ino, |
922 | size_t *sz) | |
923 | { | |
924 | void *p; | |
925 | struct ext2_xattr_handle *handle; | |
926 | errcode_t retval; | |
927 | ||
928 | retval = ext2fs_xattrs_open(fs, ino, &handle); | |
929 | if (retval) | |
930 | return retval; | |
931 | ||
932 | retval = ext2fs_xattrs_read(handle); | |
933 | if (retval) | |
934 | goto err; | |
935 | ||
936 | retval = ext2fs_xattr_get(handle, "system.data", &p, sz); | |
937 | if (retval) | |
938 | goto err; | |
939 | ext2fs_free_mem(&p); | |
940 | err: | |
941 | (void) ext2fs_xattrs_close(&handle); | |
942 | return retval; | |
943 | } | |
944 | ||
6e3c3b75 DW |
945 | static void finish_processing_inode(e2fsck_t ctx, ext2_ino_t ino, |
946 | struct problem_context *pctx, | |
947 | int failed_csum) | |
948 | { | |
949 | if (!failed_csum) | |
950 | return; | |
951 | ||
952 | /* | |
953 | * If the inode failed the checksum and the user didn't | |
954 | * clear the inode, test the checksum again -- if it still | |
955 | * fails, ask the user if the checksum should be corrected. | |
956 | */ | |
957 | pctx->errcode = recheck_bad_inode_checksum(ctx->fs, ino, ctx, pctx); | |
958 | if (pctx->errcode) | |
959 | ctx->flags |= E2F_FLAG_ABORT; | |
960 | } | |
961 | #define FINISH_INODE_LOOP(ctx, ino, pctx, failed_csum) \ | |
962 | do { \ | |
963 | finish_processing_inode((ctx), (ino), (pctx), (failed_csum)); \ | |
964 | if ((ctx)->flags & E2F_FLAG_ABORT) \ | |
965 | return; \ | |
966 | } while (0) | |
967 | ||
fa441f91 DW |
968 | static int could_be_block_map(ext2_filsys fs, struct ext2_inode *inode) |
969 | { | |
970 | __u32 x; | |
971 | int i; | |
972 | ||
973 | for (i = 0; i < EXT2_N_BLOCKS; i++) { | |
974 | x = inode->i_block[i]; | |
975 | #ifdef WORDS_BIGENDIAN | |
976 | x = ext2fs_swab32(x); | |
977 | #endif | |
978 | if (x >= ext2fs_blocks_count(fs->super)) | |
979 | return 0; | |
980 | } | |
981 | ||
982 | return 1; | |
983 | } | |
984 | ||
985 | /* | |
986 | * Figure out what to do with an inode that has both extents and inline data | |
987 | * inode flags set. Returns -1 if we decide to erase the inode, 0 otherwise. | |
988 | */ | |
989 | static int fix_inline_data_extents_file(e2fsck_t ctx, | |
990 | ext2_ino_t ino, | |
991 | struct ext2_inode *inode, | |
992 | int inode_size, | |
993 | struct problem_context *pctx) | |
994 | { | |
995 | size_t max_inline_ea_size; | |
996 | ext2_filsys fs = ctx->fs; | |
997 | int dirty = 0; | |
998 | ||
999 | /* Both feature flags not set? Just run the regular checks */ | |
86f3b6cf DW |
1000 | if (!ext2fs_has_feature_extents(fs->super) && |
1001 | !ext2fs_has_feature_inline_data(fs->super)) | |
fa441f91 DW |
1002 | return 0; |
1003 | ||
1004 | /* Clear both flags if it's a special file */ | |
1005 | if (LINUX_S_ISCHR(inode->i_mode) || | |
1006 | LINUX_S_ISBLK(inode->i_mode) || | |
1007 | LINUX_S_ISFIFO(inode->i_mode) || | |
1008 | LINUX_S_ISSOCK(inode->i_mode)) { | |
1009 | check_extents_inlinedata(ctx, pctx); | |
1010 | return 0; | |
1011 | } | |
1012 | ||
1013 | /* If it looks like an extent tree, try to clear inlinedata */ | |
1014 | if (ext2fs_extent_header_verify(inode->i_block, | |
1015 | sizeof(inode->i_block)) == 0 && | |
1016 | fix_problem(ctx, PR_1_CLEAR_INLINE_DATA_FOR_EXTENT, pctx)) { | |
1017 | inode->i_flags &= ~EXT4_INLINE_DATA_FL; | |
1018 | dirty = 1; | |
1019 | goto out; | |
1020 | } | |
1021 | ||
1022 | /* If it looks short enough to be inline data, try to clear extents */ | |
25f291c9 TT |
1023 | if (inode_size > EXT2_GOOD_OLD_INODE_SIZE) |
1024 | max_inline_ea_size = inode_size - | |
fa441f91 DW |
1025 | (EXT2_GOOD_OLD_INODE_SIZE + |
1026 | ((struct ext2_inode_large *)inode)->i_extra_isize); | |
1027 | else | |
1028 | max_inline_ea_size = 0; | |
1029 | if (EXT2_I_SIZE(inode) < | |
1030 | EXT4_MIN_INLINE_DATA_SIZE + max_inline_ea_size && | |
1031 | fix_problem(ctx, PR_1_CLEAR_EXTENT_FOR_INLINE_DATA, pctx)) { | |
1032 | inode->i_flags &= ~EXT4_EXTENTS_FL; | |
1033 | dirty = 1; | |
1034 | goto out; | |
1035 | } | |
1036 | ||
1037 | /* | |
1038 | * Too big for inline data, but no evidence of extent tree - | |
1039 | * maybe it's a block map file? If the mappings all look valid? | |
1040 | */ | |
1041 | if (could_be_block_map(fs, inode) && | |
1042 | fix_problem(ctx, PR_1_CLEAR_EXTENT_INLINE_DATA_FLAGS, pctx)) { | |
1043 | #ifdef WORDS_BIGENDIAN | |
1044 | int i; | |
1045 | ||
1046 | for (i = 0; i < EXT2_N_BLOCKS; i++) | |
1047 | inode->i_block[i] = ext2fs_swab32(inode->i_block[i]); | |
1048 | #endif | |
1049 | ||
1050 | inode->i_flags &= ~(EXT4_EXTENTS_FL | EXT4_INLINE_DATA_FL); | |
1051 | dirty = 1; | |
1052 | goto out; | |
1053 | } | |
1054 | ||
1055 | /* Oh well, just clear the busted inode. */ | |
1056 | if (fix_problem(ctx, PR_1_CLEAR_EXTENT_INLINE_DATA_INODE, pctx)) { | |
1057 | e2fsck_clear_inode(ctx, ino, inode, 0, "pass1"); | |
1058 | return -1; | |
1059 | } | |
1060 | ||
1061 | out: | |
1062 | if (dirty) | |
1063 | e2fsck_write_inode(ctx, ino, inode, "pass1"); | |
1064 | ||
1065 | return 0; | |
1066 | } | |
1067 | ||
a5abfe03 DW |
1068 | static void pass1_readahead(e2fsck_t ctx, dgrp_t *group, ext2_ino_t *next_ino) |
1069 | { | |
1070 | ext2_ino_t inodes_in_group = 0, inodes_per_block, inodes_per_buffer; | |
1071 | dgrp_t start = *group, grp; | |
1072 | blk64_t blocks_to_read = 0; | |
1073 | errcode_t err = EXT2_ET_INVALID_ARGUMENT; | |
1074 | ||
1075 | if (ctx->readahead_kb == 0) | |
1076 | goto out; | |
1077 | ||
1078 | /* Keep iterating groups until we have enough to readahead */ | |
1079 | inodes_per_block = EXT2_INODES_PER_BLOCK(ctx->fs->super); | |
1080 | for (grp = start; grp < ctx->fs->group_desc_count; grp++) { | |
1081 | if (ext2fs_bg_flags_test(ctx->fs, grp, EXT2_BG_INODE_UNINIT)) | |
1082 | continue; | |
1083 | inodes_in_group = ctx->fs->super->s_inodes_per_group - | |
1084 | ext2fs_bg_itable_unused(ctx->fs, grp); | |
1085 | blocks_to_read += (inodes_in_group + inodes_per_block - 1) / | |
1086 | inodes_per_block; | |
1087 | if (blocks_to_read * ctx->fs->blocksize > | |
1088 | ctx->readahead_kb * 1024) | |
1089 | break; | |
1090 | } | |
1091 | ||
1092 | err = e2fsck_readahead(ctx->fs, E2FSCK_READA_ITABLE, start, | |
1093 | grp - start + 1); | |
1094 | if (err == EAGAIN) { | |
1095 | ctx->readahead_kb /= 2; | |
1096 | err = 0; | |
1097 | } | |
1098 | ||
1099 | out: | |
1100 | if (err) { | |
1101 | /* Error; disable itable readahead */ | |
1102 | *group = ctx->fs->group_desc_count; | |
1103 | *next_ino = ctx->fs->super->s_inodes_count; | |
1104 | } else { | |
1105 | /* | |
1106 | * Don't do more readahead until we've reached the first inode | |
1107 | * of the last inode scan buffer block for the last group. | |
1108 | */ | |
1109 | *group = grp + 1; | |
1110 | inodes_per_buffer = (ctx->inode_buffer_blocks ? | |
1111 | ctx->inode_buffer_blocks : | |
1112 | EXT2_INODE_SCAN_DEFAULT_BUFFER_BLOCKS) * | |
1113 | ctx->fs->blocksize / | |
1114 | EXT2_INODE_SIZE(ctx->fs->super); | |
1115 | inodes_in_group--; | |
1116 | *next_ino = inodes_in_group - | |
1117 | (inodes_in_group % inodes_per_buffer) + 1 + | |
1118 | (grp * ctx->fs->super->s_inodes_per_group); | |
1119 | } | |
1120 | } | |
1121 | ||
2d2d799c LX |
1122 | /* |
1123 | * Check if the passed ino is one of the used superblock quota inodes. | |
1124 | * | |
1125 | * Before the quota inodes were journaled, older superblock quota inodes | |
1126 | * were just regular files in the filesystem and not reserved inodes. This | |
1127 | * checks if the passed ino is one of the s_*_quota_inum superblock fields, | |
1128 | * which may not always be the same as the EXT4_*_QUOTA_INO fields. | |
1129 | */ | |
1130 | static int quota_inum_is_super(struct ext2_super_block *sb, ext2_ino_t ino) | |
1131 | { | |
1132 | enum quota_type qtype; | |
1133 | ||
1134 | for (qtype = 0; qtype < MAXQUOTAS; qtype++) | |
1135 | if (*quota_sb_inump(sb, qtype) == ino) | |
1136 | return 1; | |
1137 | ||
1138 | return 0; | |
1139 | } | |
1140 | ||
1141 | /* | |
1142 | * Check if the passed ino is one of the reserved quota inodes. | |
1143 | * This checks if the inode number is one of the reserved EXT4_*_QUOTA_INO | |
1144 | * inodes. These inodes may or may not be in use by the quota feature. | |
1145 | */ | |
1146 | static int quota_inum_is_reserved(ext2_filsys fs, ext2_ino_t ino) | |
1147 | { | |
1148 | enum quota_type qtype; | |
1149 | ||
1150 | for (qtype = 0; qtype < MAXQUOTAS; qtype++) | |
1151 | if (quota_type2inum(qtype, fs->super) == ino) | |
1152 | return 1; | |
1153 | ||
1154 | return 0; | |
1155 | } | |
1156 | ||
08b21301 | 1157 | void e2fsck_pass1(e2fsck_t ctx) |
3839e657 | 1158 | { |
9d1bd3de | 1159 | int i; |
31e29a12 | 1160 | __u64 max_sizes; |
1b6bf175 | 1161 | ext2_filsys fs = ctx->fs; |
24c91184 | 1162 | ext2_ino_t ino = 0; |
125f76e7 TT |
1163 | struct ext2_inode *inode = NULL; |
1164 | ext2_inode_scan scan = NULL; | |
1165 | char *block_buf = NULL; | |
8bf191e8 | 1166 | #ifdef RESOURCE_TRACK |
3839e657 | 1167 | struct resource_track rtrack; |
8bf191e8 | 1168 | #endif |
1e3472c5 | 1169 | unsigned char frag, fsize; |
21c84b71 | 1170 | struct problem_context pctx; |
f8188fff | 1171 | struct scan_callback_struct scan_struct; |
5dd8f963 | 1172 | struct ext2_super_block *sb = ctx->fs->super; |
e94bc631 | 1173 | const char *old_op; |
16eca7ce | 1174 | int imagic_fs, extent_fs, inlinedata_fs, casefold_fs; |
6f6f567f | 1175 | int low_dtime_check = 1; |
ac3256fd TT |
1176 | unsigned int inode_size = EXT2_INODE_SIZE(fs->super); |
1177 | unsigned int bufsize; | |
b9cde40d | 1178 | int failed_csum = 0; |
a5abfe03 DW |
1179 | ext2_ino_t ino_threshold = 0; |
1180 | dgrp_t ra_group = 0; | |
0b4ffc27 | 1181 | struct ea_quota ea_ibody_quota; |
efc6f628 | 1182 | |
6d96b00d | 1183 | init_resource_track(&rtrack, ctx->fs->io); |
1b6bf175 TT |
1184 | clear_problem_context(&pctx); |
1185 | ||
a5abfe03 DW |
1186 | /* If we can do readahead, figure out how many groups to pull in. */ |
1187 | if (!e2fsck_can_readahead(ctx->fs)) | |
1188 | ctx->readahead_kb = 0; | |
1189 | else if (ctx->readahead_kb == ~0ULL) | |
1190 | ctx->readahead_kb = e2fsck_guess_readahead(ctx->fs); | |
1191 | pass1_readahead(ctx, &ra_group, &ino_threshold); | |
1192 | ||
1b6bf175 TT |
1193 | if (!(ctx->options & E2F_OPT_PREEN)) |
1194 | fix_problem(ctx, PR_1_PASS_HEADER, &pctx); | |
3839e657 | 1195 | |
86f3b6cf | 1196 | if (ext2fs_has_feature_dir_index(fs->super) && |
3214a453 | 1197 | !(ctx->options & E2F_OPT_NO)) { |
b7a00563 TT |
1198 | if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50)) |
1199 | ctx->dirs_to_hash = 0; | |
1200 | } | |
1201 | ||
3839e657 TT |
1202 | #ifdef MTRACE |
1203 | mtrace_print("Pass 1"); | |
1204 | #endif | |
1205 | ||
932a489c AD |
1206 | #define EXT2_BPP(bits) (1ULL << ((bits) - 2)) |
1207 | ||
1208 | for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) { | |
1209 | max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i); | |
1210 | max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i); | |
1211 | max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i); | |
66df1468 | 1212 | max_sizes = (max_sizes * (1UL << i)); |
7823dd65 | 1213 | ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes; |
9d1bd3de TT |
1214 | } |
1215 | #undef EXT2_BPP | |
6fdc7a32 | 1216 | |
86f3b6cf DW |
1217 | imagic_fs = ext2fs_has_feature_imagic_inodes(sb); |
1218 | extent_fs = ext2fs_has_feature_extents(sb); | |
1219 | inlinedata_fs = ext2fs_has_feature_inline_data(sb); | |
16eca7ce | 1220 | casefold_fs = ext2fs_has_feature_casefold(sb); |
6fdc7a32 | 1221 | |
3839e657 TT |
1222 | /* |
1223 | * Allocate bitmaps structures | |
1224 | */ | |
830b44f4 TT |
1225 | pctx.errcode = e2fsck_allocate_inode_bitmap(fs, _("in-use inode map"), |
1226 | EXT2FS_BMAP64_RBTREE, | |
1227 | "inode_used_map", | |
1228 | &ctx->inode_used_map); | |
1b6bf175 TT |
1229 | if (pctx.errcode) { |
1230 | pctx.num = 1; | |
1231 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
08b21301 TT |
1232 | ctx->flags |= E2F_FLAG_ABORT; |
1233 | return; | |
3839e657 | 1234 | } |
830b44f4 TT |
1235 | pctx.errcode = e2fsck_allocate_inode_bitmap(fs, |
1236 | _("directory inode map"), | |
1237 | EXT2FS_BMAP64_AUTODIR, | |
1238 | "inode_dir_map", &ctx->inode_dir_map); | |
1b6bf175 TT |
1239 | if (pctx.errcode) { |
1240 | pctx.num = 2; | |
1241 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
08b21301 TT |
1242 | ctx->flags |= E2F_FLAG_ABORT; |
1243 | return; | |
3839e657 | 1244 | } |
830b44f4 TT |
1245 | pctx.errcode = e2fsck_allocate_inode_bitmap(fs, |
1246 | _("regular file inode map"), EXT2FS_BMAP64_RBTREE, | |
1247 | "inode_reg_map", &ctx->inode_reg_map); | |
aa4115a4 TT |
1248 | if (pctx.errcode) { |
1249 | pctx.num = 6; | |
1250 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
1251 | ctx->flags |= E2F_FLAG_ABORT; | |
1252 | return; | |
1253 | } | |
830b44f4 TT |
1254 | pctx.errcode = e2fsck_allocate_subcluster_bitmap(fs, |
1255 | _("in-use block map"), EXT2FS_BMAP64_RBTREE, | |
1256 | "block_found_map", &ctx->block_found_map); | |
1b6bf175 TT |
1257 | if (pctx.errcode) { |
1258 | pctx.num = 1; | |
1259 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx); | |
08b21301 TT |
1260 | ctx->flags |= E2F_FLAG_ABORT; |
1261 | return; | |
3839e657 | 1262 | } |
35c8faaf DW |
1263 | pctx.errcode = e2fsck_allocate_block_bitmap(fs, |
1264 | _("metadata block map"), EXT2FS_BMAP64_RBTREE, | |
1265 | "block_metadata_map", &ctx->block_metadata_map); | |
1266 | if (pctx.errcode) { | |
1267 | pctx.num = 1; | |
1268 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx); | |
1269 | ctx->flags |= E2F_FLAG_ABORT; | |
1270 | return; | |
1271 | } | |
749f0712 TT |
1272 | pctx.errcode = e2fsck_setup_icount(ctx, "inode_link_info", 0, NULL, |
1273 | &ctx->inode_link_info); | |
1b6bf175 TT |
1274 | if (pctx.errcode) { |
1275 | fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx); | |
08b21301 TT |
1276 | ctx->flags |= E2F_FLAG_ABORT; |
1277 | return; | |
21c84b71 | 1278 | } |
750000cf TT |
1279 | bufsize = inode_size; |
1280 | if (bufsize < sizeof(struct ext2_inode_large)) | |
1281 | bufsize = sizeof(struct ext2_inode_large); | |
cebe48a1 | 1282 | inode = (struct ext2_inode *) |
750000cf | 1283 | e2fsck_allocate_memory(ctx, bufsize, "scratch inode"); |
cebe48a1 | 1284 | |
54dc7ca2 TT |
1285 | inodes_to_process = (struct process_inode_block *) |
1286 | e2fsck_allocate_memory(ctx, | |
1287 | (ctx->process_inode_size * | |
1288 | sizeof(struct process_inode_block)), | |
1289 | "array of inodes to process"); | |
3839e657 TT |
1290 | process_inode_count = 0; |
1291 | ||
1b6bf175 TT |
1292 | pctx.errcode = ext2fs_init_dblist(fs, 0); |
1293 | if (pctx.errcode) { | |
1294 | fix_problem(ctx, PR_1_ALLOCATE_DBCOUNT, &pctx); | |
08b21301 | 1295 | ctx->flags |= E2F_FLAG_ABORT; |
125f76e7 | 1296 | goto endit; |
21c84b71 | 1297 | } |
3839e657 | 1298 | |
9cbfb8d0 TT |
1299 | /* |
1300 | * If the last orphan field is set, clear it, since the pass1 | |
1301 | * processing will automatically find and clear the orphans. | |
1302 | * In the future, we may want to try using the last_orphan | |
1303 | * linked list ourselves, but for now, we clear it so that the | |
1304 | * ext3 mount code won't get confused. | |
1305 | */ | |
1306 | if (!(ctx->options & E2F_OPT_READONLY)) { | |
1307 | if (fs->super->s_last_orphan) { | |
1308 | fs->super->s_last_orphan = 0; | |
1309 | ext2fs_mark_super_dirty(fs); | |
1310 | } | |
1311 | } | |
1312 | ||
1b6bf175 | 1313 | mark_table_blocks(ctx); |
44fe08f1 TT |
1314 | pctx.errcode = ext2fs_convert_subcluster_bitmap(fs, |
1315 | &ctx->block_found_map); | |
1316 | if (pctx.errcode) { | |
1317 | fix_problem(ctx, PR_1_CONVERT_SUBCLUSTER, &pctx); | |
1318 | ctx->flags |= E2F_FLAG_ABORT; | |
125f76e7 | 1319 | goto endit; |
44fe08f1 | 1320 | } |
54dc7ca2 TT |
1321 | block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 3, |
1322 | "block interate buffer"); | |
91db7e20 DW |
1323 | if (EXT2_INODE_SIZE(fs->super) == EXT2_GOOD_OLD_INODE_SIZE) |
1324 | e2fsck_use_inode_shortcuts(ctx, 1); | |
b4a40883 | 1325 | e2fsck_intercept_block_allocations(ctx); |
e94bc631 | 1326 | old_op = ehandler_operation(_("opening inode scan")); |
efc6f628 | 1327 | pctx.errcode = ext2fs_open_inode_scan(fs, ctx->inode_buffer_blocks, |
1b6bf175 | 1328 | &scan); |
e94bc631 | 1329 | ehandler_operation(old_op); |
1b6bf175 TT |
1330 | if (pctx.errcode) { |
1331 | fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx); | |
08b21301 | 1332 | ctx->flags |= E2F_FLAG_ABORT; |
125f76e7 | 1333 | goto endit; |
3839e657 | 1334 | } |
68d70624 DW |
1335 | ext2fs_inode_scan_flags(scan, EXT2_SF_SKIP_MISSING_ITABLE | |
1336 | EXT2_SF_WARN_GARBAGE_INODES, 0); | |
cebe48a1 | 1337 | ctx->stashed_inode = inode; |
f8188fff TT |
1338 | scan_struct.ctx = ctx; |
1339 | scan_struct.block_buf = block_buf; | |
1340 | ext2fs_set_inode_callback(scan, scan_callback, &scan_struct); | |
125f76e7 TT |
1341 | if (ctx->progress && ((ctx->progress)(ctx, 1, 0, |
1342 | ctx->fs->group_desc_count))) | |
1343 | goto endit; | |
576fada1 TT |
1344 | if ((fs->super->s_wtime && |
1345 | fs->super->s_wtime < fs->super->s_inodes_count) || | |
1346 | (fs->super->s_mtime && | |
1347 | fs->super->s_mtime < fs->super->s_inodes_count) || | |
6f6f567f TT |
1348 | (fs->super->s_mkfs_time && |
1349 | fs->super->s_mkfs_time < fs->super->s_inodes_count)) | |
1350 | low_dtime_check = 0; | |
be93ef0c | 1351 | |
86f3b6cf | 1352 | if (ext2fs_has_feature_mmp(fs->super) && |
2fe2d408 AD |
1353 | fs->super->s_mmp_block > fs->super->s_first_data_block && |
1354 | fs->super->s_mmp_block < ext2fs_blocks_count(fs->super)) | |
0f5eba75 AD |
1355 | ext2fs_mark_block_bitmap2(ctx->block_found_map, |
1356 | fs->super->s_mmp_block); | |
1357 | ||
07307114 DW |
1358 | /* Set up ctx->lost_and_found if possible */ |
1359 | (void) e2fsck_get_lost_and_found(ctx, 0); | |
1360 | ||
d237a78e | 1361 | while (1) { |
0f5eba75 AD |
1362 | if (ino % (fs->super->s_inodes_per_group * 4) == 1) { |
1363 | if (e2fsck_mmp_update(fs)) | |
1364 | fatal_error(ctx, 0); | |
1365 | } | |
e94bc631 | 1366 | old_op = ehandler_operation(_("getting next inode from scan")); |
efc6f628 | 1367 | pctx.errcode = ext2fs_get_next_inode_full(scan, &ino, |
cebe48a1 | 1368 | inode, inode_size); |
a5abfe03 DW |
1369 | if (ino > ino_threshold) |
1370 | pass1_readahead(ctx, &ra_group, &ino_threshold); | |
e94bc631 | 1371 | ehandler_operation(old_op); |
d237a78e | 1372 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
db3d8718 | 1373 | goto endit; |
d237a78e | 1374 | if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) { |
c6c68163 DW |
1375 | /* |
1376 | * If badblocks says badblocks is bad, offer to clear | |
1377 | * the list, update the in-core bb list, and restart | |
1378 | * the inode scan. | |
1379 | */ | |
1380 | if (ino == EXT2_BAD_INO && | |
1381 | fix_problem(ctx, PR_1_BADBLOCKS_IN_BADBLOCKS, | |
1382 | &pctx)) { | |
1383 | errcode_t err; | |
1384 | ||
1385 | e2fsck_clear_inode(ctx, ino, inode, 0, "pass1"); | |
1386 | ext2fs_badblocks_list_free(ctx->fs->badblocks); | |
1387 | ctx->fs->badblocks = NULL; | |
1388 | err = ext2fs_read_bb_inode(ctx->fs, | |
1389 | &ctx->fs->badblocks); | |
1390 | if (err) { | |
1391 | fix_problem(ctx, PR_1_ISCAN_ERROR, | |
1392 | &pctx); | |
1393 | ctx->flags |= E2F_FLAG_ABORT; | |
1394 | goto endit; | |
1395 | } | |
1396 | err = ext2fs_inode_scan_goto_blockgroup(scan, | |
1397 | 0); | |
1398 | if (err) { | |
1399 | fix_problem(ctx, PR_1_ISCAN_ERROR, | |
1400 | &pctx); | |
1401 | ctx->flags |= E2F_FLAG_ABORT; | |
1402 | goto endit; | |
1403 | } | |
1404 | continue; | |
1405 | } | |
d237a78e TT |
1406 | if (!ctx->inode_bb_map) |
1407 | alloc_bb_map(ctx); | |
c5d2f50d VAH |
1408 | ext2fs_mark_inode_bitmap2(ctx->inode_bb_map, ino); |
1409 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); | |
d237a78e TT |
1410 | continue; |
1411 | } | |
b9cde40d | 1412 | if (pctx.errcode && |
68d70624 DW |
1413 | pctx.errcode != EXT2_ET_INODE_CSUM_INVALID && |
1414 | pctx.errcode != EXT2_ET_INODE_IS_GARBAGE) { | |
d237a78e TT |
1415 | fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx); |
1416 | ctx->flags |= E2F_FLAG_ABORT; | |
125f76e7 | 1417 | goto endit; |
d237a78e TT |
1418 | } |
1419 | if (!ino) | |
1420 | break; | |
21c84b71 | 1421 | pctx.ino = ino; |
cebe48a1 | 1422 | pctx.inode = inode; |
1b6bf175 | 1423 | ctx->stashed_ino = ino; |
b9cde40d | 1424 | |
68d70624 DW |
1425 | /* Clear trashed inode? */ |
1426 | if (pctx.errcode == EXT2_ET_INODE_IS_GARBAGE && | |
1427 | inode->i_links_count > 0 && | |
1428 | fix_problem(ctx, PR_1_INODE_IS_GARBAGE, &pctx)) { | |
1429 | pctx.errcode = 0; | |
1430 | e2fsck_clear_inode(ctx, ino, inode, 0, "pass1"); | |
b9cde40d | 1431 | } |
68d70624 | 1432 | failed_csum = pctx.errcode != 0; |
b9cde40d | 1433 | |
3fac78e6 TT |
1434 | /* |
1435 | * Check for inodes who might have been part of the | |
1436 | * orphaned list linked list. They should have gotten | |
1437 | * dealt with by now, unless the list had somehow been | |
1438 | * corrupted. | |
1439 | * | |
1440 | * FIXME: In the future, inodes which are still in use | |
1441 | * (and which are therefore) pending truncation should | |
1442 | * be handled specially. Right now we just clear the | |
1443 | * dtime field, and the normal e2fsck handling of | |
1444 | * inodes where i_size and the inode blocks are | |
1445 | * inconsistent is to fix i_size, instead of releasing | |
1446 | * the extra blocks. This won't catch the inodes that | |
1447 | * was at the end of the orphan list, but it's better | |
1448 | * than nothing. The right answer is that there | |
1449 | * shouldn't be any bugs in the orphan list handling. :-) | |
1450 | */ | |
1451 | if (inode->i_dtime && low_dtime_check && | |
1452 | inode->i_dtime < ctx->fs->super->s_inodes_count) { | |
1453 | if (fix_problem(ctx, PR_1_LOW_DTIME, &pctx)) { | |
1454 | inode->i_dtime = inode->i_links_count ? | |
1455 | 0 : ctx->now; | |
1456 | e2fsck_write_inode(ctx, ino, inode, | |
1457 | "pass1"); | |
1458 | failed_csum = 0; | |
1459 | } | |
1460 | } | |
1461 | ||
cebe48a1 | 1462 | if (inode->i_links_count) { |
efc6f628 | 1463 | pctx.errcode = ext2fs_icount_store(ctx->inode_link_info, |
cebe48a1 | 1464 | ino, inode->i_links_count); |
1b6bf175 | 1465 | if (pctx.errcode) { |
cebe48a1 | 1466 | pctx.num = inode->i_links_count; |
1b6bf175 | 1467 | fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx); |
08b21301 | 1468 | ctx->flags |= E2F_FLAG_ABORT; |
125f76e7 | 1469 | goto endit; |
1b6bf175 | 1470 | } |
3fac78e6 TT |
1471 | } else if ((ino >= EXT2_FIRST_INODE(fs->super)) && |
1472 | !quota_inum_is_reserved(fs, ino)) { | |
1473 | if (!inode->i_dtime && inode->i_mode) { | |
1474 | if (fix_problem(ctx, | |
1475 | PR_1_ZERO_DTIME, &pctx)) { | |
1476 | inode->i_dtime = ctx->now; | |
1477 | e2fsck_write_inode(ctx, ino, inode, | |
1478 | "pass1"); | |
1479 | failed_csum = 0; | |
1480 | } | |
1481 | } | |
1482 | FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum); | |
1483 | continue; | |
1b6bf175 | 1484 | } |
dfc870c7 | 1485 | |
16eca7ce TT |
1486 | if ((inode->i_flags & EXT4_CASEFOLD_FL) && |
1487 | ((!LINUX_S_ISDIR(inode->i_mode) && | |
1488 | fix_problem(ctx, PR_1_CASEFOLD_NONDIR, &pctx)) || | |
1489 | (!casefold_fs && | |
1490 | fix_problem(ctx, PR_1_CASEFOLD_FEATURE, &pctx)))) { | |
1491 | inode->i_flags &= ~EXT4_CASEFOLD_FL; | |
1492 | e2fsck_write_inode(ctx, ino, inode, "pass1"); | |
1493 | } | |
1494 | ||
fa441f91 DW |
1495 | /* Conflicting inlinedata/extents inode flags? */ |
1496 | if ((inode->i_flags & EXT4_INLINE_DATA_FL) && | |
1497 | (inode->i_flags & EXT4_EXTENTS_FL)) { | |
1498 | int res = fix_inline_data_extents_file(ctx, ino, inode, | |
1499 | inode_size, | |
1500 | &pctx); | |
1501 | if (res < 0) { | |
1502 | /* skip FINISH_INODE_LOOP */ | |
1503 | continue; | |
1504 | } | |
1505 | } | |
1506 | ||
25fed0fc ZL |
1507 | /* Test for incorrect inline_data flags settings. */ |
1508 | if ((inode->i_flags & EXT4_INLINE_DATA_FL) && !inlinedata_fs && | |
1509 | (ino >= EXT2_FIRST_INODE(fs->super))) { | |
1510 | size_t size = 0; | |
1511 | ||
4a11f499 LD |
1512 | pctx.errcode = get_inline_data_ea_size(fs, ino, &size); |
1513 | if (!pctx.errcode && | |
dbb32857 | 1514 | fix_problem(ctx, PR_1_INLINE_DATA_FEATURE, &pctx)) { |
86f3b6cf | 1515 | ext2fs_set_feature_inline_data(sb); |
25fed0fc ZL |
1516 | ext2fs_mark_super_dirty(fs); |
1517 | inlinedata_fs = 1; | |
dbb32857 | 1518 | } else if (fix_problem(ctx, PR_1_INLINE_DATA_SET, &pctx)) { |
25fed0fc | 1519 | e2fsck_clear_inode(ctx, ino, inode, 0, "pass1"); |
6e3c3b75 | 1520 | /* skip FINISH_INODE_LOOP */ |
25fed0fc ZL |
1521 | continue; |
1522 | } | |
1523 | } | |
1524 | ||
49a3749a DW |
1525 | /* Test for inline data flag but no attr */ |
1526 | if ((inode->i_flags & EXT4_INLINE_DATA_FL) && inlinedata_fs && | |
49a3749a DW |
1527 | (ino >= EXT2_FIRST_INODE(fs->super))) { |
1528 | size_t size = 0; | |
1529 | errcode_t err; | |
1530 | int flags; | |
1531 | ||
1532 | flags = fs->flags; | |
1533 | if (failed_csum) | |
1534 | fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; | |
1535 | err = get_inline_data_ea_size(fs, ino, &size); | |
1536 | fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) | | |
1537 | (fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS); | |
1538 | ||
1539 | switch (err) { | |
1540 | case 0: | |
1541 | /* Everything is awesome... */ | |
1542 | break; | |
1543 | case EXT2_ET_BAD_EA_BLOCK_NUM: | |
1544 | case EXT2_ET_BAD_EA_HASH: | |
1545 | case EXT2_ET_BAD_EA_HEADER: | |
1546 | case EXT2_ET_EA_BAD_NAME_LEN: | |
1547 | case EXT2_ET_EA_BAD_VALUE_SIZE: | |
1548 | case EXT2_ET_EA_KEY_NOT_FOUND: | |
1549 | case EXT2_ET_EA_NO_SPACE: | |
1550 | case EXT2_ET_MISSING_EA_FEATURE: | |
1551 | case EXT2_ET_INLINE_DATA_CANT_ITERATE: | |
1552 | case EXT2_ET_INLINE_DATA_NO_BLOCK: | |
1553 | case EXT2_ET_INLINE_DATA_NO_SPACE: | |
1554 | case EXT2_ET_NO_INLINE_DATA: | |
1555 | case EXT2_ET_EXT_ATTR_CSUM_INVALID: | |
1556 | case EXT2_ET_EA_BAD_VALUE_OFFSET: | |
9db53e3f | 1557 | case EXT2_ET_EA_INODE_CORRUPTED: |
49a3749a DW |
1558 | /* broken EA or no system.data EA; truncate */ |
1559 | if (fix_problem(ctx, PR_1_INLINE_DATA_NO_ATTR, | |
1560 | &pctx)) { | |
47b89417 | 1561 | err = ext2fs_inode_size_set(fs, inode, 0); |
49a3749a DW |
1562 | if (err) { |
1563 | pctx.errcode = err; | |
1564 | ctx->flags |= E2F_FLAG_ABORT; | |
1565 | goto endit; | |
1566 | } | |
47b89417 TT |
1567 | inode->i_flags &= ~EXT4_INLINE_DATA_FL; |
1568 | memset(&inode->i_block, 0, | |
1569 | sizeof(inode->i_block)); | |
49a3749a DW |
1570 | e2fsck_write_inode(ctx, ino, inode, |
1571 | "pass1"); | |
1572 | failed_csum = 0; | |
1573 | } | |
1574 | break; | |
1575 | default: | |
1576 | /* Some other kind of non-xattr error? */ | |
1577 | pctx.errcode = err; | |
1578 | ctx->flags |= E2F_FLAG_ABORT; | |
1579 | goto endit; | |
1580 | } | |
1581 | } | |
1582 | ||
dfc870c7 ES |
1583 | /* |
1584 | * Test for incorrect extent flag settings. | |
1585 | * | |
1586 | * On big-endian machines we must be careful: | |
1587 | * When the inode is read, the i_block array is not swapped | |
1588 | * if the extent flag is set. Therefore if we are testing | |
1589 | * for or fixing a wrongly-set flag, we must potentially | |
1590 | * (un)swap before testing, or after fixing. | |
1591 | */ | |
1592 | ||
1593 | /* | |
1594 | * In this case the extents flag was set when read, so | |
1595 | * extent_header_verify is ok. If the inode is cleared, | |
1596 | * no need to swap... so no extra swapping here. | |
1597 | */ | |
efc6f628 | 1598 | if ((inode->i_flags & EXT4_EXTENTS_FL) && !extent_fs && |
15d482ba TT |
1599 | (inode->i_links_count || (ino == EXT2_BAD_INO) || |
1600 | (ino == EXT2_ROOT_INO) || (ino == EXT2_JOURNAL_INO))) { | |
efc6f628 | 1601 | if ((ext2fs_extent_header_verify(inode->i_block, |
15d482ba TT |
1602 | sizeof(inode->i_block)) == 0) && |
1603 | fix_problem(ctx, PR_1_EXTENT_FEATURE, &pctx)) { | |
86f3b6cf | 1604 | ext2fs_set_feature_extents(sb); |
15d482ba TT |
1605 | ext2fs_mark_super_dirty(fs); |
1606 | extent_fs = 1; | |
1607 | } else if (fix_problem(ctx, PR_1_EXTENTS_SET, &pctx)) { | |
1608 | clear_inode: | |
1609 | e2fsck_clear_inode(ctx, ino, inode, 0, "pass1"); | |
1610 | if (ino == EXT2_BAD_INO) | |
c5d2f50d | 1611 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, |
15d482ba | 1612 | ino); |
6e3c3b75 | 1613 | /* skip FINISH_INODE_LOOP */ |
15d482ba TT |
1614 | continue; |
1615 | } | |
1616 | } | |
1617 | ||
dfc870c7 ES |
1618 | /* |
1619 | * For big-endian machines: | |
1620 | * If the inode didn't have the extents flag set when it | |
1621 | * was read, then the i_blocks array was swapped. To test | |
1622 | * as an extents header, we must swap it back first. | |
1623 | * IF we then set the extents flag, the entire i_block | |
1624 | * array must be un/re-swapped to make it proper extents data. | |
1625 | */ | |
15d482ba TT |
1626 | if (extent_fs && !(inode->i_flags & EXT4_EXTENTS_FL) && |
1627 | (inode->i_links_count || (ino == EXT2_BAD_INO) || | |
1628 | (ino == EXT2_ROOT_INO) || (ino == EXT2_JOURNAL_INO)) && | |
1629 | (LINUX_S_ISREG(inode->i_mode) || | |
dfc870c7 ES |
1630 | LINUX_S_ISDIR(inode->i_mode))) { |
1631 | void *ehp; | |
1632 | #ifdef WORDS_BIGENDIAN | |
1633 | __u32 tmp_block[EXT2_N_BLOCKS]; | |
1634 | ||
1635 | for (i = 0; i < EXT2_N_BLOCKS; i++) | |
1636 | tmp_block[i] = ext2fs_swab32(inode->i_block[i]); | |
1637 | ehp = tmp_block; | |
1638 | #else | |
1639 | ehp = inode->i_block; | |
1640 | #endif | |
efc6f628 | 1641 | if ((ext2fs_extent_header_verify(ehp, |
dfc870c7 ES |
1642 | sizeof(inode->i_block)) == 0) && |
1643 | (fix_problem(ctx, PR_1_UNSET_EXTENT_FL, &pctx))) { | |
15d482ba | 1644 | inode->i_flags |= EXT4_EXTENTS_FL; |
dfc870c7 | 1645 | #ifdef WORDS_BIGENDIAN |
efc6f628 | 1646 | memcpy(inode->i_block, tmp_block, |
dfc870c7 ES |
1647 | sizeof(inode->i_block)); |
1648 | #endif | |
15d482ba | 1649 | e2fsck_write_inode(ctx, ino, inode, "pass1"); |
6e3c3b75 | 1650 | failed_csum = 0; |
15d482ba TT |
1651 | } |
1652 | } | |
1653 | ||
3839e657 TT |
1654 | if (ino == EXT2_BAD_INO) { |
1655 | struct process_block_struct pb; | |
efc6f628 | 1656 | |
492f901e DW |
1657 | if ((failed_csum || inode->i_mode || inode->i_uid || |
1658 | inode->i_gid || inode->i_links_count || | |
1659 | (inode->i_flags & EXT4_INLINE_DATA_FL) || | |
1660 | inode->i_file_acl) && | |
96a8afa7 TT |
1661 | fix_problem(ctx, PR_1_INVALID_BAD_INODE, &pctx)) { |
1662 | memset(inode, 0, sizeof(struct ext2_inode)); | |
1663 | e2fsck_write_inode(ctx, ino, inode, | |
1664 | "clear bad inode"); | |
6e3c3b75 | 1665 | failed_csum = 0; |
96a8afa7 TT |
1666 | } |
1667 | ||
000ba404 TT |
1668 | pctx.errcode = ext2fs_copy_bitmap(ctx->block_found_map, |
1669 | &pb.fs_meta_blocks); | |
1670 | if (pctx.errcode) { | |
1671 | pctx.num = 4; | |
1672 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx); | |
1673 | ctx->flags |= E2F_FLAG_ABORT; | |
125f76e7 | 1674 | goto endit; |
000ba404 | 1675 | } |
3839e657 TT |
1676 | pb.ino = EXT2_BAD_INO; |
1677 | pb.num_blocks = pb.last_block = 0; | |
4dbe79bc | 1678 | pb.last_db_block = -1; |
f3db3566 | 1679 | pb.num_illegal_blocks = 0; |
21c84b71 | 1680 | pb.suppress = 0; pb.clear = 0; pb.is_dir = 0; |
000ba404 | 1681 | pb.is_reg = 0; pb.fragmented = 0; pb.bbcheck = 0; |
cebe48a1 | 1682 | pb.inode = inode; |
21c84b71 | 1683 | pb.pctx = &pctx; |
1b6bf175 | 1684 | pb.ctx = ctx; |
6dc64392 | 1685 | pctx.errcode = ext2fs_block_iterate3(fs, ino, 0, |
1b6bf175 | 1686 | block_buf, process_bad_block, &pb); |
000ba404 | 1687 | ext2fs_free_block_bitmap(pb.fs_meta_blocks); |
1b6bf175 TT |
1688 | if (pctx.errcode) { |
1689 | fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx); | |
08b21301 | 1690 | ctx->flags |= E2F_FLAG_ABORT; |
125f76e7 | 1691 | goto endit; |
1b6bf175 | 1692 | } |
000ba404 TT |
1693 | if (pb.bbcheck) |
1694 | if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK_PROMPT, &pctx)) { | |
1695 | ctx->flags |= E2F_FLAG_ABORT; | |
125f76e7 | 1696 | goto endit; |
000ba404 | 1697 | } |
c5d2f50d | 1698 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); |
21c84b71 | 1699 | clear_problem_context(&pctx); |
6e3c3b75 | 1700 | FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum); |
d237a78e | 1701 | continue; |
a9ca2016 | 1702 | } else if (ino == EXT2_ROOT_INO) { |
3839e657 TT |
1703 | /* |
1704 | * Make sure the root inode is a directory; if | |
1705 | * not, offer to clear it. It will be | |
055866d8 | 1706 | * regenerated in pass #3. |
3839e657 | 1707 | */ |
cebe48a1 | 1708 | if (!LINUX_S_ISDIR(inode->i_mode)) { |
15d482ba TT |
1709 | if (fix_problem(ctx, PR_1_ROOT_NO_DIR, &pctx)) |
1710 | goto clear_inode; | |
3839e657 TT |
1711 | } |
1712 | /* | |
1713 | * If dtime is set, offer to clear it. mke2fs | |
1714 | * version 0.2b created filesystems with the | |
1715 | * dtime field set for the root and lost+found | |
1716 | * directories. We won't worry about | |
1717 | * /lost+found, since that can be regenerated | |
1718 | * easily. But we will fix the root directory | |
1719 | * as a special case. | |
1720 | */ | |
cebe48a1 | 1721 | if (inode->i_dtime && inode->i_links_count) { |
1b6bf175 | 1722 | if (fix_problem(ctx, PR_1_ROOT_DTIME, &pctx)) { |
cebe48a1 TT |
1723 | inode->i_dtime = 0; |
1724 | e2fsck_write_inode(ctx, ino, inode, | |
f3db3566 | 1725 | "pass1"); |
6e3c3b75 | 1726 | failed_csum = 0; |
21c84b71 | 1727 | } |
3839e657 | 1728 | } |
a9ca2016 | 1729 | } else if (ino == EXT2_JOURNAL_INO) { |
c5d2f50d | 1730 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); |
f18996c8 | 1731 | if (fs->super->s_journal_inum == EXT2_JOURNAL_INO) { |
cebe48a1 | 1732 | if (!LINUX_S_ISREG(inode->i_mode) && |
a9ca2016 TT |
1733 | fix_problem(ctx, PR_1_JOURNAL_BAD_MODE, |
1734 | &pctx)) { | |
cebe48a1 TT |
1735 | inode->i_mode = LINUX_S_IFREG; |
1736 | e2fsck_write_inode(ctx, ino, inode, | |
a9ca2016 | 1737 | "pass1"); |
6e3c3b75 | 1738 | failed_csum = 0; |
a9ca2016 | 1739 | } |
0b4ffc27 | 1740 | check_blocks(ctx, &pctx, block_buf, NULL); |
6e3c3b75 | 1741 | FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum); |
d237a78e | 1742 | continue; |
f18996c8 | 1743 | } |
6dc64392 | 1744 | if ((inode->i_links_count || |
cebe48a1 | 1745 | inode->i_blocks || inode->i_block[0]) && |
efc6f628 | 1746 | fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR, |
f18996c8 | 1747 | &pctx)) { |
cebe48a1 | 1748 | memset(inode, 0, inode_size); |
a9ca2016 TT |
1749 | ext2fs_icount_store(ctx->inode_link_info, |
1750 | ino, 0); | |
efc6f628 | 1751 | e2fsck_write_inode_full(ctx, ino, inode, |
cebe48a1 | 1752 | inode_size, "pass1"); |
6e3c3b75 | 1753 | failed_csum = 0; |
f18996c8 | 1754 | } |
2d2d799c | 1755 | } else if (quota_inum_is_reserved(fs, ino)) { |
624e4a64 | 1756 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); |
86f3b6cf | 1757 | if (ext2fs_has_feature_quota(fs->super) && |
2d2d799c | 1758 | quota_inum_is_super(fs->super, ino)) { |
624e4a64 AK |
1759 | if (!LINUX_S_ISREG(inode->i_mode) && |
1760 | fix_problem(ctx, PR_1_QUOTA_BAD_MODE, | |
1761 | &pctx)) { | |
1762 | inode->i_mode = LINUX_S_IFREG; | |
1763 | e2fsck_write_inode(ctx, ino, inode, | |
1764 | "pass1"); | |
6e3c3b75 | 1765 | failed_csum = 0; |
624e4a64 | 1766 | } |
0b4ffc27 | 1767 | check_blocks(ctx, &pctx, block_buf, NULL); |
6e3c3b75 | 1768 | FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum); |
624e4a64 AK |
1769 | continue; |
1770 | } | |
1771 | if ((inode->i_links_count || | |
1772 | inode->i_blocks || inode->i_block[0]) && | |
1773 | fix_problem(ctx, PR_1_QUOTA_INODE_NOT_CLEAR, | |
1774 | &pctx)) { | |
1775 | memset(inode, 0, inode_size); | |
1776 | ext2fs_icount_store(ctx->inode_link_info, | |
1777 | ino, 0); | |
1778 | e2fsck_write_inode_full(ctx, ino, inode, | |
1779 | inode_size, "pass1"); | |
6e3c3b75 | 1780 | failed_csum = 0; |
624e4a64 | 1781 | } |
a9ca2016 | 1782 | } else if (ino < EXT2_FIRST_INODE(fs->super)) { |
3c7c6d73 | 1783 | problem_t problem = 0; |
efc6f628 | 1784 | |
c5d2f50d | 1785 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); |
53ef44c4 | 1786 | if (ino == EXT2_BOOT_LOADER_INO) { |
cebe48a1 | 1787 | if (LINUX_S_ISDIR(inode->i_mode)) |
b09a4b0c | 1788 | problem = PR_1_RESERVED_BAD_MODE; |
b1f204f7 | 1789 | } else if (ino == EXT2_RESIZE_INO) { |
cebe48a1 TT |
1790 | if (inode->i_mode && |
1791 | !LINUX_S_ISREG(inode->i_mode)) | |
b1f204f7 | 1792 | problem = PR_1_RESERVED_BAD_MODE; |
53ef44c4 | 1793 | } else { |
cebe48a1 | 1794 | if (inode->i_mode != 0) |
b09a4b0c | 1795 | problem = PR_1_RESERVED_BAD_MODE; |
b09a4b0c TT |
1796 | } |
1797 | if (problem) { | |
1798 | if (fix_problem(ctx, problem, &pctx)) { | |
cebe48a1 TT |
1799 | inode->i_mode = 0; |
1800 | e2fsck_write_inode(ctx, ino, inode, | |
50e1e10f | 1801 | "pass1"); |
6e3c3b75 | 1802 | failed_csum = 0; |
21c84b71 | 1803 | } |
50e1e10f | 1804 | } |
0b4ffc27 | 1805 | check_blocks(ctx, &pctx, block_buf, NULL); |
6e3c3b75 | 1806 | FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum); |
d237a78e | 1807 | continue; |
3839e657 | 1808 | } |
624e4a64 | 1809 | |
cebe48a1 | 1810 | if (!inode->i_links_count) { |
6e3c3b75 | 1811 | FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum); |
d237a78e | 1812 | continue; |
3839e657 TT |
1813 | } |
1814 | /* | |
1e3472c5 | 1815 | * n.b. 0.3c ext2fs code didn't clear i_links_count for |
3839e657 | 1816 | * deleted files. Oops. |
1e3472c5 TT |
1817 | * |
1818 | * Since all new ext2 implementations get this right, | |
1819 | * we now assume that the case of non-zero | |
1820 | * i_links_count and non-zero dtime means that we | |
1821 | * should keep the file, not delete it. | |
efc6f628 | 1822 | * |
3839e657 | 1823 | */ |
cebe48a1 | 1824 | if (inode->i_dtime) { |
1b6bf175 | 1825 | if (fix_problem(ctx, PR_1_SET_DTIME, &pctx)) { |
cebe48a1 TT |
1826 | inode->i_dtime = 0; |
1827 | e2fsck_write_inode(ctx, ino, inode, "pass1"); | |
6e3c3b75 | 1828 | failed_csum = 0; |
21c84b71 | 1829 | } |
3839e657 | 1830 | } |
efc6f628 | 1831 | |
c5d2f50d | 1832 | ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); |
1e3472c5 | 1833 | switch (fs->super->s_creator_os) { |
1e3472c5 | 1834 | case EXT2_OS_HURD: |
cebe48a1 TT |
1835 | frag = inode->osd2.hurd2.h_i_frag; |
1836 | fsize = inode->osd2.hurd2.h_i_fsize; | |
1e3472c5 | 1837 | break; |
1e3472c5 TT |
1838 | default: |
1839 | frag = fsize = 0; | |
1840 | } | |
efc6f628 | 1841 | |
cebe48a1 | 1842 | if (inode->i_faddr || frag || fsize || |
3f0cf647 AB |
1843 | (!ext2fs_has_feature_largedir(fs->super) && |
1844 | (LINUX_S_ISDIR(inode->i_mode) && inode->i_size_high))) | |
fdbdea09 | 1845 | mark_inode_bad(ctx, ino); |
c0495d96 | 1846 | if ((fs->super->s_creator_os != EXT2_OS_HURD) && |
86f3b6cf | 1847 | !ext2fs_has_feature_64bit(fs->super) && |
911ec626 TT |
1848 | inode->osd2.linux2.l_i_file_acl_high != 0) |
1849 | mark_inode_bad(ctx, ino); | |
c0495d96 | 1850 | if ((fs->super->s_creator_os != EXT2_OS_HURD) && |
86f3b6cf | 1851 | !ext2fs_has_feature_huge_file(fs->super) && |
5d17119d TT |
1852 | (inode->osd2.linux2.l_i_blocks_hi != 0)) |
1853 | mark_inode_bad(ctx, ino); | |
cebe48a1 | 1854 | if (inode->i_flags & EXT2_IMAGIC_FL) { |
6fdc7a32 TT |
1855 | if (imagic_fs) { |
1856 | if (!ctx->inode_imagic_map) | |
1857 | alloc_imagic_map(ctx); | |
c5d2f50d | 1858 | ext2fs_mark_inode_bitmap2(ctx->inode_imagic_map, |
6fdc7a32 TT |
1859 | ino); |
1860 | } else { | |
1861 | if (fix_problem(ctx, PR_1_SET_IMAGIC, &pctx)) { | |
cebe48a1 | 1862 | inode->i_flags &= ~EXT2_IMAGIC_FL; |
6fdc7a32 | 1863 | e2fsck_write_inode(ctx, ino, |
cebe48a1 | 1864 | inode, "pass1"); |
6e3c3b75 | 1865 | failed_csum = 0; |
6fdc7a32 TT |
1866 | } |
1867 | } | |
aa4115a4 | 1868 | } |
cebe48a1 | 1869 | |
0b4ffc27 | 1870 | check_inode_extra_space(ctx, &pctx, &ea_ibody_quota); |
fbc3f901 | 1871 | check_is_really_dir(ctx, &pctx, block_buf); |
cebe48a1 | 1872 | |
dfc870c7 | 1873 | /* |
0c80c44b | 1874 | * ext2fs_inode_has_valid_blocks2 does not actually look |
dfc870c7 ES |
1875 | * at i_block[] values, so not endian-sensitive here. |
1876 | */ | |
cb23cad5 TT |
1877 | if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL) && |
1878 | LINUX_S_ISLNK(inode->i_mode) && | |
0c80c44b | 1879 | !ext2fs_inode_has_valid_blocks2(fs, inode) && |
cb23cad5 TT |
1880 | fix_problem(ctx, PR_1_FAST_SYMLINK_EXTENT_FL, &pctx)) { |
1881 | inode->i_flags &= ~EXT4_EXTENTS_FL; | |
1882 | e2fsck_write_inode(ctx, ino, inode, "pass1"); | |
6e3c3b75 | 1883 | failed_csum = 0; |
cb23cad5 TT |
1884 | } |
1885 | ||
2ba05753 EB |
1886 | if ((inode->i_flags & EXT4_ENCRYPT_FL) && |
1887 | add_encrypted_file(ctx, &pctx) < 0) | |
1888 | goto clear_inode; | |
1889 | ||
cebe48a1 | 1890 | if (LINUX_S_ISDIR(inode->i_mode)) { |
c5d2f50d | 1891 | ext2fs_mark_inode_bitmap2(ctx->inode_dir_map, ino); |
08b21301 | 1892 | e2fsck_add_dir_info(ctx, ino, 0); |
1b6bf175 | 1893 | ctx->fs_directory_count++; |
cebe48a1 | 1894 | } else if (LINUX_S_ISREG (inode->i_mode)) { |
c5d2f50d | 1895 | ext2fs_mark_inode_bitmap2(ctx->inode_reg_map, ino); |
1b6bf175 | 1896 | ctx->fs_regular_count++; |
cebe48a1 TT |
1897 | } else if (LINUX_S_ISCHR (inode->i_mode) && |
1898 | e2fsck_pass1_check_device_inode(fs, inode)) { | |
8dae07fb | 1899 | check_extents_inlinedata(ctx, &pctx); |
6fdc7a32 | 1900 | check_immutable(ctx, &pctx); |
d647a1ea | 1901 | check_size(ctx, &pctx); |
1b6bf175 | 1902 | ctx->fs_chardev_count++; |
cebe48a1 TT |
1903 | } else if (LINUX_S_ISBLK (inode->i_mode) && |
1904 | e2fsck_pass1_check_device_inode(fs, inode)) { | |
8dae07fb | 1905 | check_extents_inlinedata(ctx, &pctx); |
6fdc7a32 | 1906 | check_immutable(ctx, &pctx); |
d647a1ea | 1907 | check_size(ctx, &pctx); |
1b6bf175 | 1908 | ctx->fs_blockdev_count++; |
cebe48a1 | 1909 | } else if (LINUX_S_ISLNK (inode->i_mode) && |
efc6f628 | 1910 | e2fsck_pass1_check_symlink(fs, ino, inode, |
7cadc577 | 1911 | block_buf)) { |
fd77b2c7 | 1912 | check_immutable(ctx, &pctx); |
1b6bf175 | 1913 | ctx->fs_symlinks_count++; |
f9f8fded | 1914 | if (inode->i_flags & EXT4_INLINE_DATA_FL) { |
6e3c3b75 | 1915 | FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum); |
f9f8fded | 1916 | continue; |
cf0be234 | 1917 | } else if (ext2fs_is_fast_symlink(inode)) { |
1b6bf175 | 1918 | ctx->fs_fast_symlinks_count++; |
b0f457bd | 1919 | check_blocks(ctx, &pctx, block_buf, |
0b4ffc27 | 1920 | &ea_ibody_quota); |
6e3c3b75 | 1921 | FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum); |
d237a78e | 1922 | continue; |
21c84b71 | 1923 | } |
3839e657 | 1924 | } |
cebe48a1 TT |
1925 | else if (LINUX_S_ISFIFO (inode->i_mode) && |
1926 | e2fsck_pass1_check_device_inode(fs, inode)) { | |
8dae07fb | 1927 | check_extents_inlinedata(ctx, &pctx); |
6fdc7a32 | 1928 | check_immutable(ctx, &pctx); |
d647a1ea | 1929 | check_size(ctx, &pctx); |
1b6bf175 | 1930 | ctx->fs_fifo_count++; |
cebe48a1 TT |
1931 | } else if ((LINUX_S_ISSOCK (inode->i_mode)) && |
1932 | e2fsck_pass1_check_device_inode(fs, inode)) { | |
8dae07fb | 1933 | check_extents_inlinedata(ctx, &pctx); |
6fdc7a32 | 1934 | check_immutable(ctx, &pctx); |
d647a1ea TT |
1935 | check_size(ctx, &pctx); |
1936 | ctx->fs_sockets_count++; | |
fdbdea09 TT |
1937 | } else |
1938 | mark_inode_bad(ctx, ino); | |
042e0719 ZL |
1939 | if (!(inode->i_flags & EXT4_EXTENTS_FL) && |
1940 | !(inode->i_flags & EXT4_INLINE_DATA_FL)) { | |
8da6d1a1 TT |
1941 | if (inode->i_block[EXT2_IND_BLOCK]) |
1942 | ctx->fs_ind_count++; | |
1943 | if (inode->i_block[EXT2_DIND_BLOCK]) | |
1944 | ctx->fs_dind_count++; | |
1945 | if (inode->i_block[EXT2_TIND_BLOCK]) | |
1946 | ctx->fs_tind_count++; | |
1947 | } | |
15d482ba | 1948 | if (!(inode->i_flags & EXT4_EXTENTS_FL) && |
042e0719 | 1949 | !(inode->i_flags & EXT4_INLINE_DATA_FL) && |
15d482ba TT |
1950 | (inode->i_block[EXT2_IND_BLOCK] || |
1951 | inode->i_block[EXT2_DIND_BLOCK] || | |
1952 | inode->i_block[EXT2_TIND_BLOCK] || | |
0c80c44b | 1953 | ext2fs_file_acl_block(fs, inode))) { |
b0f457bd | 1954 | struct process_inode_block *itp; |
e251f358 | 1955 | |
b0f457bd TE |
1956 | itp = &inodes_to_process[process_inode_count]; |
1957 | itp->ino = ino; | |
0b4ffc27 | 1958 | itp->ea_ibody_quota = ea_ibody_quota; |
e251f358 | 1959 | if (inode_size < sizeof(struct ext2_inode_large)) |
b0f457bd | 1960 | memcpy(&itp->inode, inode, inode_size); |
e251f358 | 1961 | else |
b0f457bd | 1962 | memcpy(&itp->inode, inode, sizeof(itp->inode)); |
3839e657 | 1963 | process_inode_count++; |
f3db3566 | 1964 | } else |
0b4ffc27 | 1965 | check_blocks(ctx, &pctx, block_buf, &ea_ibody_quota); |
3839e657 | 1966 | |
6e3c3b75 | 1967 | FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum); |
b9cde40d | 1968 | |
a02ce9df | 1969 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
125f76e7 | 1970 | goto endit; |
08b21301 TT |
1971 | |
1972 | if (process_inode_count >= ctx->process_inode_size) { | |
1b6bf175 | 1973 | process_inodes(ctx, block_buf); |
08b21301 | 1974 | |
a02ce9df | 1975 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
125f76e7 | 1976 | goto endit; |
08b21301 | 1977 | } |
3839e657 | 1978 | } |
1b6bf175 | 1979 | process_inodes(ctx, block_buf); |
3839e657 | 1980 | ext2fs_close_inode_scan(scan); |
125f76e7 | 1981 | scan = NULL; |
3839e657 | 1982 | |
b729b7df DW |
1983 | reserve_block_for_root_repair(ctx); |
1984 | reserve_block_for_lnf_repair(ctx); | |
1985 | ||
e8a3ee62 TT |
1986 | /* |
1987 | * If any extended attribute blocks' reference counts need to | |
1988 | * be adjusted, either up (ctx->refcount_extra), or down | |
1989 | * (ctx->refcount), then fix them. | |
1990 | */ | |
1991 | if (ctx->refcount) { | |
1992 | adjust_extattr_refcount(ctx, ctx->refcount, block_buf, -1); | |
1993 | ea_refcount_free(ctx->refcount); | |
1994 | ctx->refcount = 0; | |
1995 | } | |
1996 | if (ctx->refcount_extra) { | |
1997 | adjust_extattr_refcount(ctx, ctx->refcount_extra, | |
1998 | block_buf, +1); | |
1999 | ea_refcount_free(ctx->refcount_extra); | |
2000 | ctx->refcount_extra = 0; | |
2001 | } | |
efc6f628 | 2002 | |
0b4ffc27 TE |
2003 | if (ctx->ea_block_quota_blocks) { |
2004 | ea_refcount_free(ctx->ea_block_quota_blocks); | |
2005 | ctx->ea_block_quota_blocks = 0; | |
2006 | } | |
2007 | ||
2008 | if (ctx->ea_block_quota_inodes) { | |
2009 | ea_refcount_free(ctx->ea_block_quota_inodes); | |
2010 | ctx->ea_block_quota_inodes = 0; | |
5c5685d1 TE |
2011 | } |
2012 | ||
1b6bf175 TT |
2013 | if (ctx->invalid_bitmaps) |
2014 | handle_fs_bad_blocks(ctx); | |
f3db3566 | 2015 | |
24ceb248 TT |
2016 | /* We don't need the block_ea_map any more */ |
2017 | if (ctx->block_ea_map) { | |
2018 | ext2fs_free_block_bitmap(ctx->block_ea_map); | |
2019 | ctx->block_ea_map = 0; | |
2020 | } | |
2021 | ||
2ba05753 EB |
2022 | /* We don't need the encryption policy => ID map any more */ |
2023 | destroy_encryption_policy_map(ctx); | |
2024 | ||
c3ffaf83 | 2025 | if (ctx->flags & E2F_FLAG_RESIZE_INODE) { |
c3ffaf83 TT |
2026 | clear_problem_context(&pctx); |
2027 | pctx.errcode = ext2fs_create_resize_inode(fs); | |
2028 | if (pctx.errcode) { | |
a6217f5a TT |
2029 | if (!fix_problem(ctx, PR_1_RESIZE_INODE_CREATE, |
2030 | &pctx)) { | |
2031 | ctx->flags |= E2F_FLAG_ABORT; | |
125f76e7 | 2032 | goto endit; |
a6217f5a TT |
2033 | } |
2034 | pctx.errcode = 0; | |
2035 | } | |
2036 | if (!pctx.errcode) { | |
2037 | e2fsck_read_inode(ctx, EXT2_RESIZE_INO, inode, | |
2038 | "recreate inode"); | |
2039 | inode->i_mtime = ctx->now; | |
2040 | e2fsck_write_inode(ctx, EXT2_RESIZE_INO, inode, | |
2041 | "recreate inode"); | |
c3ffaf83 | 2042 | } |
c3ffaf83 TT |
2043 | ctx->flags &= ~E2F_FLAG_RESIZE_INODE; |
2044 | } | |
efc6f628 | 2045 | |
08b21301 | 2046 | if (ctx->flags & E2F_FLAG_RESTART) { |
aa4115a4 TT |
2047 | /* |
2048 | * Only the master copy of the superblock and block | |
2049 | * group descriptors are going to be written during a | |
2050 | * restart, so set the superblock to be used to be the | |
2051 | * master superblock. | |
2052 | */ | |
2053 | ctx->use_superblock = 0; | |
f3db3566 TT |
2054 | unwind_pass1(fs); |
2055 | goto endit; | |
2056 | } | |
2057 | ||
1b6bf175 TT |
2058 | if (ctx->block_dup_map) { |
2059 | if (ctx->options & E2F_OPT_PREEN) { | |
2060 | clear_problem_context(&pctx); | |
2061 | fix_problem(ctx, PR_1_DUP_BLOCKS_PREENSTOP, &pctx); | |
3839e657 | 2062 | } |
08b21301 | 2063 | e2fsck_pass1_dupblocks(ctx, block_buf); |
3839e657 | 2064 | } |
e228d700 | 2065 | ctx->flags |= E2F_FLAG_ALLOC_OK; |
c4e3d3f3 | 2066 | ext2fs_free_mem(&inodes_to_process); |
f3db3566 | 2067 | endit: |
e72a9ba3 | 2068 | e2fsck_use_inode_shortcuts(ctx, 0); |
efc6f628 | 2069 | |
125f76e7 TT |
2070 | if (scan) |
2071 | ext2fs_close_inode_scan(scan); | |
2072 | if (block_buf) | |
2073 | ext2fs_free_mem(&block_buf); | |
2074 | if (inode) | |
2075 | ext2fs_free_mem(&inode); | |
21c84b71 | 2076 | |
82372e32 TT |
2077 | /* |
2078 | * The l+f inode may have been cleared, so zap it now and | |
2079 | * later passes will recalculate it if necessary | |
2080 | */ | |
2081 | ctx->lost_and_found = 0; | |
2082 | ||
125f76e7 TT |
2083 | if ((ctx->flags & E2F_FLAG_SIGNAL_MASK) == 0) |
2084 | print_resource_track(ctx, _("Pass 1"), &rtrack, ctx->fs->io); | |
db3d8718 AD |
2085 | else |
2086 | ctx->invalid_bitmaps++; | |
3839e657 | 2087 | } |
6e3c3b75 | 2088 | #undef FINISH_INODE_LOOP |
3839e657 | 2089 | |
f3db3566 TT |
2090 | /* |
2091 | * When the inode_scan routines call this callback at the end of the | |
2092 | * glock group, call process_inodes. | |
2093 | */ | |
efc6f628 | 2094 | static errcode_t scan_callback(ext2_filsys fs, |
54434927 | 2095 | ext2_inode_scan scan EXT2FS_ATTR((unused)), |
54dc7ca2 | 2096 | dgrp_t group, void * priv_data) |
f3db3566 | 2097 | { |
54dc7ca2 | 2098 | struct scan_callback_struct *scan_struct; |
f8188fff TT |
2099 | e2fsck_t ctx; |
2100 | ||
54dc7ca2 | 2101 | scan_struct = (struct scan_callback_struct *) priv_data; |
f8188fff | 2102 | ctx = scan_struct->ctx; |
efc6f628 | 2103 | |
54dc7ca2 | 2104 | process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf); |
f8188fff TT |
2105 | |
2106 | if (ctx->progress) | |
a02ce9df TT |
2107 | if ((ctx->progress)(ctx, 1, group+1, |
2108 | ctx->fs->group_desc_count)) | |
2109 | return EXT2_ET_CANCEL_REQUESTED; | |
f8188fff | 2110 | |
f3db3566 TT |
2111 | return 0; |
2112 | } | |
2113 | ||
3839e657 TT |
2114 | /* |
2115 | * Process the inodes in the "inodes to process" list. | |
2116 | */ | |
1b6bf175 | 2117 | static void process_inodes(e2fsck_t ctx, char *block_buf) |
3839e657 TT |
2118 | { |
2119 | int i; | |
2120 | struct ext2_inode *old_stashed_inode; | |
86c627ec | 2121 | ext2_ino_t old_stashed_ino; |
3839e657 TT |
2122 | const char *old_operation; |
2123 | char buf[80]; | |
21c84b71 | 2124 | struct problem_context pctx; |
efc6f628 | 2125 | |
3839e657 | 2126 | #if 0 |
f3db3566 | 2127 | printf("begin process_inodes: "); |
3839e657 | 2128 | #endif |
86a63e92 TT |
2129 | if (process_inode_count == 0) |
2130 | return; | |
3839e657 | 2131 | old_operation = ehandler_operation(0); |
1b6bf175 TT |
2132 | old_stashed_inode = ctx->stashed_inode; |
2133 | old_stashed_ino = ctx->stashed_ino; | |
3839e657 TT |
2134 | qsort(inodes_to_process, process_inode_count, |
2135 | sizeof(struct process_inode_block), process_inode_cmp); | |
21c84b71 | 2136 | clear_problem_context(&pctx); |
3839e657 | 2137 | for (i=0; i < process_inode_count; i++) { |
82e48fb1 TT |
2138 | pctx.inode = ctx->stashed_inode = |
2139 | (struct ext2_inode *) &inodes_to_process[i].inode; | |
1b6bf175 | 2140 | pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino; |
efc6f628 | 2141 | |
3839e657 | 2142 | #if 0 |
21c84b71 | 2143 | printf("%u ", pctx.ino); |
3839e657 | 2144 | #endif |
86c627ec | 2145 | sprintf(buf, _("reading indirect blocks of inode %u"), |
0c4a0726 | 2146 | pctx.ino); |
3839e657 | 2147 | ehandler_operation(buf); |
b0f457bd | 2148 | check_blocks(ctx, &pctx, block_buf, |
0b4ffc27 | 2149 | &inodes_to_process[i].ea_ibody_quota); |
a02ce9df | 2150 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
2df1f6aa | 2151 | break; |
3839e657 | 2152 | } |
1b6bf175 TT |
2153 | ctx->stashed_inode = old_stashed_inode; |
2154 | ctx->stashed_ino = old_stashed_ino; | |
3839e657 TT |
2155 | process_inode_count = 0; |
2156 | #if 0 | |
f3db3566 | 2157 | printf("end process inodes\n"); |
3839e657 TT |
2158 | #endif |
2159 | ehandler_operation(old_operation); | |
2160 | } | |
2161 | ||
4c77fe50 | 2162 | static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b) |
3839e657 TT |
2163 | { |
2164 | const struct process_inode_block *ib_a = | |
2165 | (const struct process_inode_block *) a; | |
2166 | const struct process_inode_block *ib_b = | |
2167 | (const struct process_inode_block *) b; | |
b5acdb6a | 2168 | int ret; |
efc6f628 | 2169 | |
b5acdb6a TT |
2170 | ret = (ib_a->inode.i_block[EXT2_IND_BLOCK] - |
2171 | ib_b->inode.i_block[EXT2_IND_BLOCK]); | |
2172 | if (ret == 0) | |
0c80c44b TT |
2173 | /* |
2174 | * We only call process_inodes() for non-extent | |
2175 | * inodes, so it's OK to pass NULL to | |
2176 | * ext2fs_file_acl_block() here. | |
2177 | */ | |
82e48fb1 TT |
2178 | ret = ext2fs_file_acl_block(0, ext2fs_const_inode(&ib_a->inode)) - |
2179 | ext2fs_file_acl_block(0, ext2fs_const_inode(&ib_b->inode)); | |
0eeec8ac TT |
2180 | if (ret == 0) |
2181 | ret = ib_a->ino - ib_b->ino; | |
b5acdb6a | 2182 | return ret; |
3839e657 TT |
2183 | } |
2184 | ||
3839e657 | 2185 | /* |
fdbdea09 | 2186 | * Mark an inode as being bad in some what |
3839e657 | 2187 | */ |
fdbdea09 | 2188 | static void mark_inode_bad(e2fsck_t ctx, ino_t ino) |
3839e657 | 2189 | { |
1b6bf175 | 2190 | struct problem_context pctx; |
fdbdea09 TT |
2191 | |
2192 | if (!ctx->inode_bad_map) { | |
2193 | clear_problem_context(&pctx); | |
efc6f628 | 2194 | |
830b44f4 TT |
2195 | pctx.errcode = e2fsck_allocate_inode_bitmap(ctx->fs, |
2196 | _("bad inode map"), EXT2FS_BMAP64_RBTREE, | |
2197 | "inode_bad_map", &ctx->inode_bad_map); | |
fdbdea09 TT |
2198 | if (pctx.errcode) { |
2199 | pctx.num = 3; | |
2200 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
2201 | /* Should never get here */ | |
2202 | ctx->flags |= E2F_FLAG_ABORT; | |
2203 | return; | |
2204 | } | |
3839e657 | 2205 | } |
c5d2f50d | 2206 | ext2fs_mark_inode_bitmap2(ctx->inode_bad_map, ino); |
3839e657 TT |
2207 | } |
2208 | ||
21c84b71 TT |
2209 | /* |
2210 | * This procedure will allocate the inode "bb" (badblock) map table | |
2211 | */ | |
1b6bf175 | 2212 | static void alloc_bb_map(e2fsck_t ctx) |
21c84b71 | 2213 | { |
1b6bf175 | 2214 | struct problem_context pctx; |
efc6f628 | 2215 | |
1b6bf175 | 2216 | clear_problem_context(&pctx); |
830b44f4 TT |
2217 | pctx.errcode = e2fsck_allocate_inode_bitmap(ctx->fs, |
2218 | _("inode in bad block map"), EXT2FS_BMAP64_RBTREE, | |
2219 | "inode_bb_map", &ctx->inode_bb_map); | |
1b6bf175 TT |
2220 | if (pctx.errcode) { |
2221 | pctx.num = 4; | |
2222 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
08b21301 TT |
2223 | /* Should never get here */ |
2224 | ctx->flags |= E2F_FLAG_ABORT; | |
2225 | return; | |
21c84b71 TT |
2226 | } |
2227 | } | |
2228 | ||
aa4115a4 TT |
2229 | /* |
2230 | * This procedure will allocate the inode imagic table | |
2231 | */ | |
2232 | static void alloc_imagic_map(e2fsck_t ctx) | |
2233 | { | |
2234 | struct problem_context pctx; | |
efc6f628 | 2235 | |
aa4115a4 | 2236 | clear_problem_context(&pctx); |
830b44f4 TT |
2237 | pctx.errcode = e2fsck_allocate_inode_bitmap(ctx->fs, |
2238 | _("imagic inode map"), EXT2FS_BMAP64_RBTREE, | |
2239 | "inode_imagic_map", &ctx->inode_imagic_map); | |
aa4115a4 TT |
2240 | if (pctx.errcode) { |
2241 | pctx.num = 5; | |
2242 | fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx); | |
2243 | /* Should never get here */ | |
2244 | ctx->flags |= E2F_FLAG_ABORT; | |
2245 | return; | |
2246 | } | |
2247 | } | |
2248 | ||
3839e657 TT |
2249 | /* |
2250 | * Marks a block as in use, setting the dup_map if it's been set | |
2251 | * already. Called by process_block and process_bad_block. | |
50e1e10f TT |
2252 | * |
2253 | * WARNING: Assumes checks have already been done to make sure block | |
2254 | * is valid. This is true in both process_block and process_bad_block. | |
3839e657 | 2255 | */ |
6dc64392 | 2256 | static _INLINE_ void mark_block_used(e2fsck_t ctx, blk64_t block) |
3839e657 | 2257 | { |
1b6bf175 | 2258 | struct problem_context pctx; |
efc6f628 | 2259 | |
1b6bf175 | 2260 | clear_problem_context(&pctx); |
efc6f628 | 2261 | |
c5d2f50d | 2262 | if (ext2fs_fast_test_block_bitmap2(ctx->block_found_map, block)) { |
91327df4 DA |
2263 | if (ext2fs_has_feature_shared_blocks(ctx->fs->super) && |
2264 | !(ctx->options & E2F_OPT_UNSHARE_BLOCKS)) { | |
9c5413b1 | 2265 | return; |
91327df4 | 2266 | } |
1b6bf175 | 2267 | if (!ctx->block_dup_map) { |
830b44f4 TT |
2268 | pctx.errcode = e2fsck_allocate_block_bitmap(ctx->fs, |
2269 | _("multiply claimed block map"), | |
2270 | EXT2FS_BMAP64_RBTREE, "block_dup_map", | |
2271 | &ctx->block_dup_map); | |
1b6bf175 TT |
2272 | if (pctx.errcode) { |
2273 | pctx.num = 3; | |
efc6f628 | 2274 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, |
1b6bf175 | 2275 | &pctx); |
08b21301 TT |
2276 | /* Should never get here */ |
2277 | ctx->flags |= E2F_FLAG_ABORT; | |
2278 | return; | |
3839e657 TT |
2279 | } |
2280 | } | |
c5d2f50d | 2281 | ext2fs_fast_mark_block_bitmap2(ctx->block_dup_map, block); |
3839e657 | 2282 | } else { |
c5d2f50d | 2283 | ext2fs_fast_mark_block_bitmap2(ctx->block_found_map, block); |
3839e657 TT |
2284 | } |
2285 | } | |
2286 | ||
d5d981a3 TE |
2287 | /* |
2288 | * When cluster size is greater than one block, it is caller's responsibility | |
2289 | * to make sure block parameter starts at a cluster boundary. | |
2290 | */ | |
2ae49fd0 TT |
2291 | static _INLINE_ void mark_blocks_used(e2fsck_t ctx, blk64_t block, |
2292 | unsigned int num) | |
2293 | { | |
2294 | if (ext2fs_test_block_bitmap_range2(ctx->block_found_map, block, num)) | |
2295 | ext2fs_mark_block_bitmap_range2(ctx->block_found_map, block, num); | |
d5d981a3 | 2296 | else { |
ac3256fd TT |
2297 | unsigned int i; |
2298 | ||
d5d981a3 TE |
2299 | for (i = 0; i < num; i += EXT2FS_CLUSTER_RATIO(ctx->fs)) |
2300 | mark_block_used(ctx, block + i); | |
2301 | } | |
2ae49fd0 TT |
2302 | } |
2303 | ||
e8a3ee62 TT |
2304 | /* |
2305 | * Adjust the extended attribute block's reference counts at the end | |
2306 | * of pass 1, either by subtracting out references for EA blocks that | |
2307 | * are still referenced in ctx->refcount, or by adding references for | |
2308 | * EA blocks that had extra references as accounted for in | |
2309 | * ctx->refcount_extra. | |
2310 | */ | |
efc6f628 | 2311 | static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount, |
e8a3ee62 TT |
2312 | char *block_buf, int adjust_sign) |
2313 | { | |
2314 | struct ext2_ext_attr_header *header; | |
2315 | struct problem_context pctx; | |
2316 | ext2_filsys fs = ctx->fs; | |
6dc64392 | 2317 | blk64_t blk; |
e8a3ee62 | 2318 | __u32 should_be; |
e8b3cc90 | 2319 | ea_value_t count; |
e8a3ee62 TT |
2320 | |
2321 | clear_problem_context(&pctx); | |
efc6f628 | 2322 | |
e8a3ee62 TT |
2323 | ea_refcount_intr_begin(refcount); |
2324 | while (1) { | |
2325 | if ((blk = ea_refcount_intr_next(refcount, &count)) == 0) | |
2326 | break; | |
2327 | pctx.blk = blk; | |
39f5659a DW |
2328 | pctx.errcode = ext2fs_read_ext_attr3(fs, blk, block_buf, |
2329 | pctx.ino); | |
e8a3ee62 TT |
2330 | if (pctx.errcode) { |
2331 | fix_problem(ctx, PR_1_EXTATTR_READ_ABORT, &pctx); | |
2332 | return; | |
2333 | } | |
2334 | header = (struct ext2_ext_attr_header *) block_buf; | |
2335 | pctx.blkcount = header->h_refcount; | |
e8b3cc90 | 2336 | should_be = header->h_refcount + adjust_sign * (int)count; |
e8a3ee62 TT |
2337 | pctx.num = should_be; |
2338 | if (fix_problem(ctx, PR_1_EXTATTR_REFCOUNT, &pctx)) { | |
2339 | header->h_refcount = should_be; | |
39f5659a DW |
2340 | pctx.errcode = ext2fs_write_ext_attr3(fs, blk, |
2341 | block_buf, | |
2342 | pctx.ino); | |
e8a3ee62 | 2343 | if (pctx.errcode) { |
a6217f5a TT |
2344 | fix_problem(ctx, PR_1_EXTATTR_WRITE_ABORT, |
2345 | &pctx); | |
e8a3ee62 TT |
2346 | continue; |
2347 | } | |
2348 | } | |
2349 | } | |
2350 | } | |
2351 | ||
342d847d TT |
2352 | /* |
2353 | * Handle processing the extended attribute blocks | |
2354 | */ | |
2355 | static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx, | |
0b4ffc27 | 2356 | char *block_buf, struct ea_quota *ea_block_quota) |
342d847d TT |
2357 | { |
2358 | ext2_filsys fs = ctx->fs; | |
2359 | ext2_ino_t ino = pctx->ino; | |
2360 | struct ext2_inode *inode = pctx->inode; | |
6dc64392 | 2361 | blk64_t blk; |
55fd07ed | 2362 | char * end; |
e8a3ee62 | 2363 | struct ext2_ext_attr_header *header; |
5c5685d1 | 2364 | struct ext2_ext_attr_entry *first, *entry; |
b0f457bd | 2365 | blk64_t quota_blocks = EXT2FS_C2B(fs, 1); |
0b4ffc27 | 2366 | __u64 quota_inodes = 0; |
86bc90f4 | 2367 | region_t region = 0; |
5e07cb28 | 2368 | int failed_csum = 0; |
5469d767 | 2369 | |
0b4ffc27 TE |
2370 | ea_block_quota->blocks = 0; |
2371 | ea_block_quota->inodes = 0; | |
2372 | ||
0c80c44b | 2373 | blk = ext2fs_file_acl_block(fs, inode); |
342d847d TT |
2374 | if (blk == 0) |
2375 | return 0; | |
2376 | ||
2377 | /* | |
2378 | * If the Extended attribute flag isn't set, then a non-zero | |
2379 | * file acl means that the inode is corrupted. | |
2380 | * | |
2381 | * Or if the extended attribute block is an invalid block, | |
2382 | * then the inode is also corrupted. | |
2383 | */ | |
86f3b6cf | 2384 | if (!ext2fs_has_feature_xattr(fs->super) || |
342d847d | 2385 | (blk < fs->super->s_first_data_block) || |
4efbac6f | 2386 | (blk >= ext2fs_blocks_count(fs->super))) { |
342d847d TT |
2387 | mark_inode_bad(ctx, ino); |
2388 | return 0; | |
2389 | } | |
2390 | ||
2391 | /* If ea bitmap hasn't been allocated, create it */ | |
2392 | if (!ctx->block_ea_map) { | |
830b44f4 TT |
2393 | pctx->errcode = e2fsck_allocate_block_bitmap(fs, |
2394 | _("ext attr block map"), | |
2395 | EXT2FS_BMAP64_RBTREE, "block_ea_map", | |
2396 | &ctx->block_ea_map); | |
342d847d TT |
2397 | if (pctx->errcode) { |
2398 | pctx->num = 2; | |
2399 | fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, pctx); | |
2400 | ctx->flags |= E2F_FLAG_ABORT; | |
2401 | return 0; | |
2402 | } | |
2403 | } | |
2404 | ||
2405 | /* Create the EA refcount structure if necessary */ | |
2406 | if (!ctx->refcount) { | |
2407 | pctx->errcode = ea_refcount_create(0, &ctx->refcount); | |
2408 | if (pctx->errcode) { | |
2409 | pctx->num = 1; | |
2410 | fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx); | |
2411 | ctx->flags |= E2F_FLAG_ABORT; | |
2412 | return 0; | |
2413 | } | |
2414 | } | |
2415 | ||
b5acdb6a TT |
2416 | #if 0 |
2417 | /* Debugging text */ | |
2418 | printf("Inode %u has EA block %u\n", ino, blk); | |
2419 | #endif | |
2420 | ||
342d847d | 2421 | /* Have we seen this EA block before? */ |
c5d2f50d | 2422 | if (ext2fs_fast_test_block_bitmap2(ctx->block_ea_map, blk)) { |
0b4ffc27 TE |
2423 | ea_block_quota->blocks = EXT2FS_C2B(fs, 1); |
2424 | ea_block_quota->inodes = 0; | |
2425 | ||
2426 | if (ctx->ea_block_quota_blocks) { | |
2427 | ea_refcount_fetch(ctx->ea_block_quota_blocks, blk, | |
2428 | "a_blocks); | |
2429 | if (quota_blocks) | |
2430 | ea_block_quota->blocks = quota_blocks; | |
2431 | } | |
2432 | ||
2433 | if (ctx->ea_block_quota_inodes) | |
2434 | ea_refcount_fetch(ctx->ea_block_quota_inodes, blk, | |
2435 | &ea_block_quota->inodes); | |
b0f457bd | 2436 | |
342d847d TT |
2437 | if (ea_refcount_decrement(ctx->refcount, blk, 0) == 0) |
2438 | return 1; | |
2439 | /* Ooops, this EA was referenced more than it stated */ | |
2440 | if (!ctx->refcount_extra) { | |
2441 | pctx->errcode = ea_refcount_create(0, | |
2442 | &ctx->refcount_extra); | |
2443 | if (pctx->errcode) { | |
2444 | pctx->num = 2; | |
2445 | fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx); | |
2446 | ctx->flags |= E2F_FLAG_ABORT; | |
55fd07ed | 2447 | return 0; |
342d847d TT |
2448 | } |
2449 | } | |
2450 | ea_refcount_increment(ctx->refcount_extra, blk, 0); | |
2451 | return 1; | |
2452 | } | |
5469d767 | 2453 | |
342d847d TT |
2454 | /* |
2455 | * OK, we haven't seen this EA block yet. So we need to | |
2456 | * validate it | |
2457 | */ | |
2458 | pctx->blk = blk; | |
39f5659a | 2459 | pctx->errcode = ext2fs_read_ext_attr3(fs, blk, block_buf, pctx->ino); |
5e07cb28 | 2460 | if (pctx->errcode == EXT2_ET_EXT_ATTR_CSUM_INVALID) { |
5b9cbd76 | 2461 | pctx->errcode = 0; |
5e07cb28 | 2462 | failed_csum = 1; |
5b9cbd76 DW |
2463 | } else if (pctx->errcode == EXT2_ET_BAD_EA_HEADER) |
2464 | pctx->errcode = 0; | |
2465 | ||
2466 | if (pctx->errcode && | |
2467 | fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx)) { | |
2468 | pctx->errcode = 0; | |
342d847d | 2469 | goto clear_extattr; |
5b9cbd76 | 2470 | } |
342d847d | 2471 | header = (struct ext2_ext_attr_header *) block_buf; |
0c80c44b | 2472 | pctx->blk = ext2fs_file_acl_block(fs, inode); |
0684a4f3 TT |
2473 | if (((ctx->ext_attr_ver == 1) && |
2474 | (header->h_magic != EXT2_EXT_ATTR_MAGIC_v1)) || | |
2475 | ((ctx->ext_attr_ver == 2) && | |
2476 | (header->h_magic != EXT2_EXT_ATTR_MAGIC))) { | |
2477 | if (fix_problem(ctx, PR_1_BAD_EA_BLOCK, pctx)) | |
2478 | goto clear_extattr; | |
2479 | } | |
0d63467d | 2480 | |
55fd07ed TT |
2481 | if (header->h_blocks != 1) { |
2482 | if (fix_problem(ctx, PR_1_EA_MULTI_BLOCK, pctx)) | |
2483 | goto clear_extattr; | |
2484 | } | |
2485 | ||
5b9cbd76 DW |
2486 | if (pctx->errcode && fix_problem(ctx, PR_1_READ_EA_BLOCK, pctx)) |
2487 | goto clear_extattr; | |
2488 | ||
55fd07ed TT |
2489 | region = region_create(0, fs->blocksize); |
2490 | if (!region) { | |
a6217f5a | 2491 | fix_problem(ctx, PR_1_EA_ALLOC_REGION_ABORT, pctx); |
55fd07ed TT |
2492 | ctx->flags |= E2F_FLAG_ABORT; |
2493 | return 0; | |
2494 | } | |
2495 | if (region_allocate(region, 0, sizeof(struct ext2_ext_attr_header))) { | |
2496 | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) | |
342d847d TT |
2497 | goto clear_extattr; |
2498 | } | |
5469d767 | 2499 | |
5c5685d1 | 2500 | first = (struct ext2_ext_attr_entry *)(header+1); |
55fd07ed | 2501 | end = block_buf + fs->blocksize; |
5c5685d1 | 2502 | entry = first; |
55fd07ed | 2503 | while ((char *)entry < end && *(__u32 *)entry) { |
fefaef39 AD |
2504 | __u32 hash; |
2505 | ||
55fd07ed TT |
2506 | if (region_allocate(region, (char *)entry - (char *)header, |
2507 | EXT2_EXT_ATTR_LEN(entry->e_name_len))) { | |
2508 | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) | |
2509 | goto clear_extattr; | |
fefaef39 | 2510 | break; |
55fd07ed | 2511 | } |
0684a4f3 | 2512 | if ((ctx->ext_attr_ver == 1 && |
0d63467d | 2513 | (entry->e_name_len == 0 || entry->e_name_index != 0)) || |
0684a4f3 | 2514 | (ctx->ext_attr_ver == 2 && |
0d63467d | 2515 | entry->e_name_index == 0)) { |
55fd07ed TT |
2516 | if (fix_problem(ctx, PR_1_EA_BAD_NAME, pctx)) |
2517 | goto clear_extattr; | |
fefaef39 | 2518 | break; |
55fd07ed | 2519 | } |
6a081f6d AD |
2520 | if (entry->e_value_inum == 0) { |
2521 | if (entry->e_value_offs + entry->e_value_size > | |
2522 | fs->blocksize) { | |
2523 | if (fix_problem(ctx, PR_1_EA_BAD_VALUE, pctx)) | |
2524 | goto clear_extattr; | |
2525 | break; | |
2526 | } | |
2527 | if (entry->e_value_size && | |
2528 | region_allocate(region, entry->e_value_offs, | |
2529 | EXT2_EXT_ATTR_SIZE(entry->e_value_size))) { | |
2530 | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, | |
2531 | pctx)) | |
2532 | goto clear_extattr; | |
2533 | } | |
2477e163 TE |
2534 | |
2535 | hash = ext2fs_ext_attr_hash_entry(entry, block_buf + | |
2536 | entry->e_value_offs); | |
2537 | ||
2538 | if (entry->e_hash != hash) { | |
2539 | pctx->num = entry->e_hash; | |
2540 | if (fix_problem(ctx, PR_1_ATTR_HASH, pctx)) | |
2541 | goto clear_extattr; | |
2542 | entry->e_hash = hash; | |
2543 | } | |
6a081f6d AD |
2544 | } else { |
2545 | problem_t problem; | |
b0f457bd | 2546 | blk64_t entry_quota_blocks; |
6a081f6d | 2547 | |
b0f457bd TE |
2548 | problem = check_large_ea_inode(ctx, entry, pctx, |
2549 | &entry_quota_blocks); | |
5c5685d1 | 2550 | if (problem && fix_problem(ctx, problem, pctx)) |
55fd07ed | 2551 | goto clear_extattr; |
b0f457bd TE |
2552 | |
2553 | quota_blocks += entry_quota_blocks; | |
0b4ffc27 | 2554 | quota_inodes++; |
55fd07ed | 2555 | } |
fefaef39 | 2556 | |
55fd07ed TT |
2557 | entry = EXT2_EXT_ATTR_NEXT(entry); |
2558 | } | |
2559 | if (region_allocate(region, (char *)entry - (char *)header, 4)) { | |
2560 | if (fix_problem(ctx, PR_1_EA_ALLOC_COLLISION, pctx)) | |
2561 | goto clear_extattr; | |
2562 | } | |
2563 | region_free(region); | |
342d847d | 2564 | |
5e07cb28 DW |
2565 | /* |
2566 | * We only get here if there was no other errors that were fixed. | |
2567 | * If there was a checksum fail, ask to correct it. | |
2568 | */ | |
2569 | if (failed_csum && | |
2570 | fix_problem(ctx, PR_1_EA_BLOCK_ONLY_CSUM_INVALID, pctx)) { | |
2571 | pctx->errcode = ext2fs_write_ext_attr3(fs, blk, block_buf, | |
2572 | pctx->ino); | |
2573 | if (pctx->errcode) | |
2574 | return 0; | |
2575 | } | |
2576 | ||
ac3256fd | 2577 | if (quota_blocks != EXT2FS_C2B(fs, 1U)) { |
0b4ffc27 | 2578 | if (!ctx->ea_block_quota_blocks) { |
b0f457bd | 2579 | pctx->errcode = ea_refcount_create(0, |
0b4ffc27 | 2580 | &ctx->ea_block_quota_blocks); |
b0f457bd TE |
2581 | if (pctx->errcode) { |
2582 | pctx->num = 3; | |
0b4ffc27 TE |
2583 | goto refcount_fail; |
2584 | } | |
2585 | } | |
2586 | ea_refcount_store(ctx->ea_block_quota_blocks, blk, | |
2587 | quota_blocks); | |
2588 | } | |
2589 | ||
2590 | if (quota_inodes) { | |
2591 | if (!ctx->ea_block_quota_inodes) { | |
2592 | pctx->errcode = ea_refcount_create(0, | |
2593 | &ctx->ea_block_quota_inodes); | |
2594 | if (pctx->errcode) { | |
2595 | pctx->num = 4; | |
2596 | refcount_fail: | |
b0f457bd TE |
2597 | fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx); |
2598 | ctx->flags |= E2F_FLAG_ABORT; | |
2599 | return 0; | |
2600 | } | |
2601 | } | |
0b4ffc27 TE |
2602 | |
2603 | ea_refcount_store(ctx->ea_block_quota_inodes, blk, | |
2604 | quota_inodes); | |
b0f457bd | 2605 | } |
0b4ffc27 TE |
2606 | ea_block_quota->blocks = quota_blocks; |
2607 | ea_block_quota->inodes = quota_inodes; | |
2608 | ||
5c5685d1 | 2609 | inc_ea_inode_refs(ctx, pctx, first, end); |
b0f457bd | 2610 | ea_refcount_store(ctx->refcount, blk, header->h_refcount - 1); |
342d847d | 2611 | mark_block_used(ctx, blk); |
c5d2f50d | 2612 | ext2fs_fast_mark_block_bitmap2(ctx->block_ea_map, blk); |
342d847d TT |
2613 | return 1; |
2614 | ||
2615 | clear_extattr: | |
5469d767 BB |
2616 | if (region) |
2617 | region_free(region); | |
0c80c44b | 2618 | ext2fs_file_acl_block_set(fs, inode, 0); |
342d847d TT |
2619 | e2fsck_write_inode(ctx, ino, inode, "check_ext_attr"); |
2620 | return 0; | |
2621 | } | |
2622 | ||
503f9e7f TT |
2623 | /* Returns 1 if bad htree, 0 if OK */ |
2624 | static int handle_htree(e2fsck_t ctx, struct problem_context *pctx, | |
15d482ba | 2625 | ext2_ino_t ino, struct ext2_inode *inode, |
503f9e7f TT |
2626 | char *block_buf) |
2627 | { | |
2628 | struct ext2_dx_root_info *root; | |
2629 | ext2_filsys fs = ctx->fs; | |
2630 | errcode_t retval; | |
6dc64392 | 2631 | blk64_t blk; |
503f9e7f TT |
2632 | |
2633 | if ((!LINUX_S_ISDIR(inode->i_mode) && | |
2634 | fix_problem(ctx, PR_1_HTREE_NODIR, pctx)) || | |
86f3b6cf | 2635 | (!ext2fs_has_feature_dir_index(fs->super) && |
503f9e7f TT |
2636 | fix_problem(ctx, PR_1_HTREE_SET, pctx))) |
2637 | return 1; | |
2638 | ||
6dc64392 | 2639 | pctx->errcode = ext2fs_bmap2(fs, ino, inode, 0, 0, 0, 0, &blk); |
15d482ba TT |
2640 | |
2641 | if ((pctx->errcode) || | |
2642 | (blk == 0) || | |
2643 | (blk < fs->super->s_first_data_block) || | |
4efbac6f | 2644 | (blk >= ext2fs_blocks_count(fs->super))) { |
15d482ba TT |
2645 | if (fix_problem(ctx, PR_1_HTREE_BADROOT, pctx)) |
2646 | return 1; | |
2647 | else | |
2648 | return 0; | |
2649 | } | |
503f9e7f | 2650 | |
24a117ab | 2651 | retval = io_channel_read_blk64(fs->io, blk, 1, block_buf); |
503f9e7f TT |
2652 | if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx)) |
2653 | return 1; | |
efc6f628 | 2654 | |
503f9e7f TT |
2655 | /* XXX should check that beginning matches a directory */ |
2656 | root = (struct ext2_dx_root_info *) (block_buf + 24); | |
2657 | ||
2658 | if ((root->reserved_zero || root->info_length < 8) && | |
2659 | fix_problem(ctx, PR_1_HTREE_BADROOT, pctx)) | |
2660 | return 1; | |
2661 | ||
2662 | pctx->num = root->hash_version; | |
2663 | if ((root->hash_version != EXT2_HASH_LEGACY) && | |
2664 | (root->hash_version != EXT2_HASH_HALF_MD4) && | |
f044b4d8 | 2665 | (root->hash_version != EXT2_HASH_TEA) && |
503f9e7f TT |
2666 | fix_problem(ctx, PR_1_HTREE_HASHV, pctx)) |
2667 | return 1; | |
efc6f628 | 2668 | |
503f9e7f TT |
2669 | if ((root->unused_flags & EXT2_HASH_FLAG_INCOMPAT) && |
2670 | fix_problem(ctx, PR_1_HTREE_INCOMPAT, pctx)) | |
2671 | return 1; | |
2672 | ||
2673 | pctx->num = root->indirect_levels; | |
3f0cf647 | 2674 | if ((root->indirect_levels > ext2_dir_htree_level(fs)) && |
503f9e7f TT |
2675 | fix_problem(ctx, PR_1_HTREE_DEPTH, pctx)) |
2676 | return 1; | |
efc6f628 | 2677 | |
503f9e7f TT |
2678 | return 0; |
2679 | } | |
342d847d | 2680 | |
e3df15ab TT |
2681 | void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino, |
2682 | struct ext2_inode *inode, int restart_flag, | |
2683 | const char *source) | |
2684 | { | |
15d482ba | 2685 | inode->i_flags = 0; |
e3df15ab TT |
2686 | inode->i_links_count = 0; |
2687 | ext2fs_icount_store(ctx->inode_link_info, ino, 0); | |
2688 | inode->i_dtime = ctx->now; | |
2689 | ||
3ee29465 DW |
2690 | /* |
2691 | * If a special inode has such rotten block mappings that we | |
2692 | * want to clear the whole inode, be sure to actually zap | |
2693 | * the block maps because i_links_count isn't checked for | |
2694 | * special inodes, and we'll end up right back here the next | |
2695 | * time we run fsck. | |
2696 | */ | |
2697 | if (ino < EXT2_FIRST_INODE(ctx->fs->super)) | |
2698 | memset(inode->i_block, 0, sizeof(inode->i_block)); | |
2699 | ||
c5d2f50d VAH |
2700 | ext2fs_unmark_inode_bitmap2(ctx->inode_dir_map, ino); |
2701 | ext2fs_unmark_inode_bitmap2(ctx->inode_used_map, ino); | |
e3df15ab | 2702 | if (ctx->inode_reg_map) |
c5d2f50d | 2703 | ext2fs_unmark_inode_bitmap2(ctx->inode_reg_map, ino); |
e3df15ab | 2704 | if (ctx->inode_bad_map) |
c5d2f50d | 2705 | ext2fs_unmark_inode_bitmap2(ctx->inode_bad_map, ino); |
e3df15ab TT |
2706 | |
2707 | /* | |
2708 | * If the inode was partially accounted for before processing | |
2709 | * was aborted, we need to restart the pass 1 scan. | |
2710 | */ | |
2711 | ctx->flags |= restart_flag; | |
2712 | ||
96a8afa7 TT |
2713 | if (ino == EXT2_BAD_INO) |
2714 | memset(inode, 0, sizeof(struct ext2_inode)); | |
2715 | ||
e3df15ab TT |
2716 | e2fsck_write_inode(ctx, ino, inode, source); |
2717 | } | |
2718 | ||
9a1d614d DW |
2719 | /* |
2720 | * Use the multiple-blocks reclamation code to fix alignment problems in | |
2721 | * a bigalloc filesystem. We want a logical cluster to map to *only* one | |
2722 | * physical cluster, and we want the block offsets within that cluster to | |
2723 | * line up. | |
2724 | */ | |
2725 | static int has_unaligned_cluster_map(e2fsck_t ctx, | |
62f9bd0e | 2726 | blk64_t last_pblk, blk64_t last_lblk, |
9a1d614d DW |
2727 | blk64_t pblk, blk64_t lblk) |
2728 | { | |
2729 | blk64_t cluster_mask; | |
2730 | ||
2731 | if (!ctx->fs->cluster_ratio_bits) | |
2732 | return 0; | |
2733 | cluster_mask = EXT2FS_CLUSTER_MASK(ctx->fs); | |
2734 | ||
2735 | /* | |
2736 | * If the block in the logical cluster doesn't align with the block in | |
2737 | * the physical cluster... | |
2738 | */ | |
2739 | if ((lblk & cluster_mask) != (pblk & cluster_mask)) | |
2740 | return 1; | |
2741 | ||
2742 | /* | |
2743 | * If we cross a physical cluster boundary within a logical cluster... | |
2744 | */ | |
2745 | if (last_pblk && (lblk & cluster_mask) != 0 && | |
2746 | EXT2FS_B2C(ctx->fs, lblk) == EXT2FS_B2C(ctx->fs, last_lblk) && | |
2747 | EXT2FS_B2C(ctx->fs, pblk) != EXT2FS_B2C(ctx->fs, last_pblk)) | |
2748 | return 1; | |
2749 | ||
2750 | return 0; | |
2751 | } | |
2752 | ||
15d482ba | 2753 | static void scan_extent_node(e2fsck_t ctx, struct problem_context *pctx, |
d5a8f9a9 | 2754 | struct process_block_struct *pb, |
d3f32c2d | 2755 | blk64_t start_block, blk64_t end_block, |
085757fc | 2756 | blk64_t eof_block, |
35c8faaf DW |
2757 | ext2_extent_handle_t ehandle, |
2758 | int try_repairs) | |
15d482ba TT |
2759 | { |
2760 | struct ext2fs_extent extent; | |
d3f32c2d | 2761 | blk64_t blk, last_lblk; |
d5d981a3 | 2762 | unsigned int i, n; |
15d482ba | 2763 | int is_dir, is_leaf; |
3c7c6d73 | 2764 | problem_t problem; |
11de9261 | 2765 | struct ext2_extent_info info; |
49fed79e DW |
2766 | int failed_csum = 0; |
2767 | ||
2768 | if (pctx->errcode == EXT2_ET_EXTENT_CSUM_INVALID) | |
2769 | failed_csum = 1; | |
15d482ba | 2770 | |
11de9261 TT |
2771 | pctx->errcode = ext2fs_extent_get_info(ehandle, &info); |
2772 | if (pctx->errcode) | |
2773 | return; | |
e228d700 DW |
2774 | if (!(ctx->options & E2F_OPT_FIXES_ONLY) && |
2775 | !pb->eti.force_rebuild) { | |
2776 | struct extent_tree_level *etl; | |
2777 | ||
2778 | etl = pb->eti.ext_info + info.curr_level; | |
2779 | etl->num_extents += info.num_entries; | |
2780 | etl->max_extents += info.max_entries; | |
2781 | /* | |
2782 | * Implementation wart: Splitting extent blocks when appending | |
2783 | * will leave the old block with one free entry. Therefore | |
2784 | * unless the node is totally full, pretend that a non-root | |
2785 | * extent block can hold one fewer entry than it actually does, | |
2786 | * so that we don't repeatedly rebuild the extent tree. | |
2787 | */ | |
2788 | if (info.curr_level && info.num_entries < info.max_entries) | |
2789 | etl->max_extents--; | |
2790 | } | |
15d482ba TT |
2791 | |
2792 | pctx->errcode = ext2fs_extent_get(ehandle, EXT2_EXTENT_FIRST_SIB, | |
2793 | &extent); | |
1e2372b3 DW |
2794 | while ((pctx->errcode == 0 || |
2795 | pctx->errcode == EXT2_ET_EXTENT_CSUM_INVALID) && | |
2796 | info.num_entries-- > 0) { | |
15d482ba TT |
2797 | is_leaf = extent.e_flags & EXT2_EXTENT_FLAGS_LEAF; |
2798 | is_dir = LINUX_S_ISDIR(pctx->inode->i_mode); | |
d3f32c2d | 2799 | last_lblk = extent.e_lblk + extent.e_len - 1; |
15d482ba TT |
2800 | |
2801 | problem = 0; | |
ae23dd19 DW |
2802 | pctx->blk = extent.e_pblk; |
2803 | pctx->blk2 = extent.e_lblk; | |
2804 | pctx->num = extent.e_len; | |
2805 | pctx->blkcount = extent.e_lblk + extent.e_len; | |
2806 | ||
e6238d37 TT |
2807 | if (extent.e_pblk == 0 || |
2808 | extent.e_pblk < ctx->fs->super->s_first_data_block || | |
4efbac6f | 2809 | extent.e_pblk >= ext2fs_blocks_count(ctx->fs->super)) |
15d482ba | 2810 | problem = PR_1_EXTENT_BAD_START_BLK; |
d5a8f9a9 TT |
2811 | else if (extent.e_lblk < start_block) |
2812 | problem = PR_1_OUT_OF_ORDER_EXTENTS; | |
085757fc | 2813 | else if ((end_block && last_lblk > end_block) && |
43466d03 EB |
2814 | !(last_lblk > eof_block && |
2815 | ((extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) || | |
2816 | (pctx->inode->i_flags & EXT4_VERITY_FL)))) | |
d3f32c2d | 2817 | problem = PR_1_EXTENT_END_OUT_OF_BOUNDS; |
9c40d148 | 2818 | else if (is_leaf && extent.e_len == 0) |
26c09eb8 | 2819 | problem = PR_1_EXTENT_LENGTH_ZERO; |
7a1eac2f ES |
2820 | else if (is_leaf && |
2821 | (extent.e_pblk + extent.e_len) > | |
4efbac6f | 2822 | ext2fs_blocks_count(ctx->fs->super)) |
15d482ba | 2823 | problem = PR_1_EXTENT_ENDS_BEYOND; |
dd50ef87 TT |
2824 | else if (is_leaf && is_dir && |
2825 | ((extent.e_lblk + extent.e_len) > | |
62f9bd0e | 2826 | (1U << (21 - ctx->fs->super->s_log_block_size)))) |
dd50ef87 | 2827 | problem = PR_1_TOOBIG_DIR; |
15d482ba | 2828 | |
ee84bbc8 JK |
2829 | if (is_leaf && problem == 0 && extent.e_len > 0) { |
2830 | #if 0 | |
2831 | printf("extent_region(ino=%u, expect=%llu, " | |
2832 | "lblk=%llu, len=%u)\n", | |
2833 | pb->ino, pb->next_lblock, | |
2834 | extent.e_lblk, extent.e_len); | |
2835 | #endif | |
2836 | if (extent.e_lblk < pb->next_lblock) | |
2837 | problem = PR_1_EXTENT_COLLISION; | |
2838 | else if (extent.e_lblk + extent.e_len > pb->next_lblock) | |
2839 | pb->next_lblock = extent.e_lblk + extent.e_len; | |
2840 | } | |
79362360 | 2841 | |
57b7fabc DW |
2842 | /* |
2843 | * Uninitialized blocks in a directory? Clear the flag and | |
2844 | * we'll interpret the blocks later. | |
2845 | */ | |
e05a0563 | 2846 | if (try_repairs && is_dir && problem == 0 && |
57b7fabc DW |
2847 | (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) && |
2848 | fix_problem(ctx, PR_1_UNINIT_DBLOCK, pctx)) { | |
2849 | extent.e_flags &= ~EXT2_EXTENT_FLAGS_UNINIT; | |
2850 | pb->inode_modified = 1; | |
2851 | pctx->errcode = ext2fs_extent_replace(ehandle, 0, | |
2852 | &extent); | |
2853 | if (pctx->errcode) | |
2854 | return; | |
e05a0563 | 2855 | failed_csum = 0; |
57b7fabc | 2856 | } |
b9e66a18 TT |
2857 | #ifdef CONFIG_DEVELOPER_FEATURES |
2858 | if (try_repairs && !is_dir && problem == 0 && | |
2859 | (ctx->options & E2F_OPT_CLEAR_UNINIT) && | |
2860 | (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) && | |
2861 | fix_problem(ctx, PR_1_CLEAR_UNINIT_EXTENT, pctx)) { | |
2862 | extent.e_flags &= ~EXT2_EXTENT_FLAGS_UNINIT; | |
2863 | pb->inode_modified = 1; | |
2864 | pctx->errcode = ext2fs_extent_replace(ehandle, 0, | |
2865 | &extent); | |
2866 | if (pctx->errcode) | |
2867 | return; | |
2868 | failed_csum = 0; | |
2869 | } | |
2870 | #endif | |
35c8faaf | 2871 | if (try_repairs && problem) { |
789bd401 | 2872 | report_problem: |
15d482ba | 2873 | if (fix_problem(ctx, problem, pctx)) { |
27a129f3 DW |
2874 | if (ctx->invalid_bitmaps) { |
2875 | /* | |
2876 | * If fsck knows the bitmaps are bad, | |
2877 | * skip to the next extent and | |
2878 | * try to clear this extent again | |
2879 | * after fixing the bitmaps, by | |
2880 | * restarting fsck. | |
2881 | */ | |
2882 | pctx->errcode = ext2fs_extent_get( | |
2883 | ehandle, | |
2884 | EXT2_EXTENT_NEXT_SIB, | |
2885 | &extent); | |
2886 | ctx->flags |= E2F_FLAG_RESTART_LATER; | |
2887 | if (pctx->errcode == | |
2888 | EXT2_ET_NO_CURRENT_NODE) { | |
2889 | pctx->errcode = 0; | |
2890 | break; | |
2891 | } | |
2892 | continue; | |
2893 | } | |
19f433a5 | 2894 | e2fsck_read_bitmaps(ctx); |
23d6dd1f | 2895 | pb->inode_modified = 1; |
15d482ba TT |
2896 | pctx->errcode = |
2897 | ext2fs_extent_delete(ehandle, 0); | |
2898 | if (pctx->errcode) { | |
7518c176 | 2899 | pctx->str = "ext2fs_extent_delete"; |
15d482ba TT |
2900 | return; |
2901 | } | |
7722961d TT |
2902 | pctx->errcode = ext2fs_extent_fix_parents(ehandle); |
2903 | if (pctx->errcode && | |
2904 | pctx->errcode != EXT2_ET_NO_CURRENT_NODE) { | |
2905 | pctx->str = "ext2fs_extent_fix_parents"; | |
2906 | return; | |
2907 | } | |
73e5abcf TT |
2908 | pctx->errcode = ext2fs_extent_get(ehandle, |
2909 | EXT2_EXTENT_CURRENT, | |
2910 | &extent); | |
2911 | if (pctx->errcode == EXT2_ET_NO_CURRENT_NODE) { | |
2912 | pctx->errcode = 0; | |
2913 | break; | |
2914 | } | |
49fed79e | 2915 | failed_csum = 0; |
73e5abcf | 2916 | continue; |
15d482ba TT |
2917 | } |
2918 | goto next; | |
2919 | } | |
2920 | ||
2921 | if (!is_leaf) { | |
d3f32c2d | 2922 | blk64_t lblk = extent.e_lblk; |
35c8faaf | 2923 | int next_try_repairs = 1; |
789bd401 | 2924 | |
7518c176 | 2925 | blk = extent.e_pblk; |
35c8faaf DW |
2926 | |
2927 | /* | |
2928 | * If this lower extent block collides with critical | |
2929 | * metadata, don't try to repair the damage. Pass 1b | |
2930 | * will reallocate the block; then we can try again. | |
2931 | */ | |
2932 | if (pb->ino != EXT2_RESIZE_INO && | |
9c5b443c | 2933 | extent.e_pblk < ctx->fs->super->s_blocks_count && |
35c8faaf DW |
2934 | ext2fs_test_block_bitmap2(ctx->block_metadata_map, |
2935 | extent.e_pblk)) { | |
2936 | next_try_repairs = 0; | |
2937 | pctx->blk = blk; | |
2938 | fix_problem(ctx, | |
2939 | PR_1_CRITICAL_METADATA_COLLISION, | |
2940 | pctx); | |
f97c601a TT |
2941 | if ((ctx->options & E2F_OPT_NO) == 0) |
2942 | ctx->flags |= E2F_FLAG_RESTART_LATER; | |
35c8faaf | 2943 | } |
15d482ba TT |
2944 | pctx->errcode = ext2fs_extent_get(ehandle, |
2945 | EXT2_EXTENT_DOWN, &extent); | |
49fed79e DW |
2946 | if (pctx->errcode && |
2947 | pctx->errcode != EXT2_ET_EXTENT_CSUM_INVALID) { | |
7518c176 TT |
2948 | pctx->str = "EXT2_EXTENT_DOWN"; |
2949 | problem = PR_1_EXTENT_HEADER_INVALID; | |
35c8faaf DW |
2950 | if (!next_try_repairs) |
2951 | return; | |
49fed79e | 2952 | if (pctx->errcode == EXT2_ET_EXTENT_HEADER_BAD) |
7518c176 TT |
2953 | goto report_problem; |
2954 | return; | |
15d482ba | 2955 | } |
789bd401 ES |
2956 | /* The next extent should match this index's logical start */ |
2957 | if (extent.e_lblk != lblk) { | |
68477355 | 2958 | struct ext2_extent_info e_info; |
789bd401 | 2959 | |
68477355 | 2960 | ext2fs_extent_get_info(ehandle, &e_info); |
789bd401 ES |
2961 | pctx->blk = lblk; |
2962 | pctx->blk2 = extent.e_lblk; | |
68477355 | 2963 | pctx->num = e_info.curr_level - 1; |
789bd401 | 2964 | problem = PR_1_EXTENT_INDEX_START_INVALID; |
ec3a42b1 | 2965 | if (fix_problem(ctx, problem, pctx)) { |
23d6dd1f | 2966 | pb->inode_modified = 1; |
ec3a42b1 DW |
2967 | pctx->errcode = |
2968 | ext2fs_extent_fix_parents(ehandle); | |
7722961d TT |
2969 | if (pctx->errcode) { |
2970 | pctx->str = "ext2fs_extent_fix_parents"; | |
ec3a42b1 | 2971 | return; |
7722961d | 2972 | } |
ec3a42b1 | 2973 | } |
789bd401 | 2974 | } |
d3f32c2d | 2975 | scan_extent_node(ctx, pctx, pb, extent.e_lblk, |
35c8faaf DW |
2976 | last_lblk, eof_block, ehandle, |
2977 | next_try_repairs); | |
7518c176 TT |
2978 | if (pctx->errcode) |
2979 | return; | |
15d482ba TT |
2980 | pctx->errcode = ext2fs_extent_get(ehandle, |
2981 | EXT2_EXTENT_UP, &extent); | |
2982 | if (pctx->errcode) { | |
7518c176 TT |
2983 | pctx->str = "EXT2_EXTENT_UP"; |
2984 | return; | |
15d482ba | 2985 | } |
7518c176 TT |
2986 | mark_block_used(ctx, blk); |
2987 | pb->num_blocks++; | |
15d482ba TT |
2988 | goto next; |
2989 | } | |
2990 | ||
63b5e354 TT |
2991 | if ((pb->previous_block != 0) && |
2992 | (pb->previous_block+1 != extent.e_pblk)) { | |
100d4701 TT |
2993 | if (ctx->options & E2F_OPT_FRAGCHECK) { |
2994 | char type = '?'; | |
2995 | ||
2996 | if (pb->is_dir) | |
2997 | type = 'd'; | |
2998 | else if (pb->is_reg) | |
2999 | type = 'f'; | |
3000 | ||
3001 | printf(("%6lu(%c): expecting %6lu " | |
3002 | "actual extent " | |
63b5e354 | 3003 | "phys %6lu log %lu len %lu\n"), |
100d4701 | 3004 | (unsigned long) pctx->ino, type, |
63b5e354 TT |
3005 | (unsigned long) pb->previous_block+1, |
3006 | (unsigned long) extent.e_pblk, | |
3007 | (unsigned long) extent.e_lblk, | |
3008 | (unsigned long) extent.e_len); | |
100d4701 | 3009 | } |
63b5e354 TT |
3010 | pb->fragmented = 1; |
3011 | } | |
9f005a90 DW |
3012 | /* |
3013 | * If we notice a gap in the logical block mappings of an | |
3014 | * extent-mapped directory, offer to close the hole by | |
3015 | * moving the logical block down, otherwise we'll go mad in | |
3016 | * pass 3 allocating empty directory blocks to fill the hole. | |
3017 | */ | |
60203cb1 | 3018 | if (try_repairs && is_dir && |
62f9bd0e | 3019 | pb->last_block + 1 < extent.e_lblk) { |
9f005a90 DW |
3020 | blk64_t new_lblk; |
3021 | ||
3022 | new_lblk = pb->last_block + 1; | |
3023 | if (EXT2FS_CLUSTER_RATIO(ctx->fs) > 1) | |
3024 | new_lblk = ((new_lblk + | |
7ef1b8b4 DW |
3025 | EXT2FS_CLUSTER_RATIO(ctx->fs) - 1) & |
3026 | ~EXT2FS_CLUSTER_MASK(ctx->fs)) | | |
3027 | (extent.e_pblk & | |
9f005a90 DW |
3028 | EXT2FS_CLUSTER_MASK(ctx->fs)); |
3029 | pctx->blk = extent.e_lblk; | |
3030 | pctx->blk2 = new_lblk; | |
3031 | if (fix_problem(ctx, PR_1_COLLAPSE_DBLOCK, pctx)) { | |
3032 | extent.e_lblk = new_lblk; | |
3033 | pb->inode_modified = 1; | |
3034 | pctx->errcode = ext2fs_extent_replace(ehandle, | |
3035 | 0, &extent); | |
3036 | if (pctx->errcode) { | |
3037 | pctx->errcode = 0; | |
3038 | goto alloc_later; | |
3039 | } | |
3040 | pctx->errcode = ext2fs_extent_fix_parents(ehandle); | |
3041 | if (pctx->errcode) | |
3042 | goto failed_add_dir_block; | |
3043 | pctx->errcode = ext2fs_extent_goto(ehandle, | |
3044 | extent.e_lblk); | |
3045 | if (pctx->errcode) | |
3046 | goto failed_add_dir_block; | |
3047 | last_lblk = extent.e_lblk + extent.e_len - 1; | |
49fed79e | 3048 | failed_csum = 0; |
9f005a90 DW |
3049 | } |
3050 | } | |
3051 | alloc_later: | |
d5d981a3 TE |
3052 | if (is_dir) { |
3053 | while (++pb->last_db_block < | |
3054 | (e2_blkcnt_t) extent.e_lblk) { | |
3055 | pctx->errcode = ext2fs_add_dir_block2( | |
3056 | ctx->fs->dblist, | |
3057 | pb->ino, 0, | |
3058 | pb->last_db_block); | |
3059 | if (pctx->errcode) { | |
3060 | pctx->blk = 0; | |
3061 | pctx->num = pb->last_db_block; | |
3062 | goto failed_add_dir_block; | |
3063 | } | |
9a1d614d | 3064 | } |
15d482ba | 3065 | |
d5d981a3 TE |
3066 | for (i = 0; i < extent.e_len; i++) { |
3067 | pctx->errcode = ext2fs_add_dir_block2( | |
3068 | ctx->fs->dblist, | |
3069 | pctx->ino, | |
3070 | extent.e_pblk + i, | |
3071 | extent.e_lblk + i); | |
15d482ba | 3072 | if (pctx->errcode) { |
d5d981a3 TE |
3073 | pctx->blk = extent.e_pblk + i; |
3074 | pctx->num = extent.e_lblk + i; | |
4607ef7d | 3075 | failed_add_dir_block: |
15d482ba TT |
3076 | fix_problem(ctx, PR_1_ADD_DBLOCK, pctx); |
3077 | /* Should never get here */ | |
3078 | ctx->flags |= E2F_FLAG_ABORT; | |
3079 | return; | |
3080 | } | |
3081 | } | |
d5d981a3 TE |
3082 | if (extent.e_len > 0) |
3083 | pb->last_db_block = extent.e_lblk + extent.e_len - 1; | |
3084 | } | |
3085 | if (has_unaligned_cluster_map(ctx, pb->previous_block, | |
3086 | pb->last_block, | |
3087 | extent.e_pblk, | |
3088 | extent.e_lblk)) { | |
3089 | for (i = 0; i < extent.e_len; i++) { | |
3090 | pctx->blk = extent.e_lblk + i; | |
3091 | pctx->blk2 = extent.e_pblk + i; | |
3092 | fix_problem(ctx, PR_1_MISALIGNED_CLUSTER, pctx); | |
3093 | mark_block_used(ctx, extent.e_pblk + i); | |
3094 | mark_block_used(ctx, extent.e_pblk + i); | |
3095 | } | |
3096 | } | |
3097 | ||
3098 | /* | |
3099 | * Check whether first cluster got marked in previous iteration. | |
3100 | */ | |
3101 | if (ctx->fs->cluster_ratio_bits && | |
3102 | pb->previous_block && | |
3103 | (EXT2FS_B2C(ctx->fs, extent.e_pblk) == | |
3104 | EXT2FS_B2C(ctx->fs, pb->previous_block))) | |
3105 | /* Set blk to the beginning of next cluster. */ | |
3106 | blk = EXT2FS_C2B( | |
3107 | ctx->fs, | |
3108 | EXT2FS_B2C(ctx->fs, extent.e_pblk) + 1); | |
3109 | else | |
3110 | /* Set blk to the beginning of current cluster. */ | |
3111 | blk = EXT2FS_C2B(ctx->fs, | |
3112 | EXT2FS_B2C(ctx->fs, extent.e_pblk)); | |
3113 | ||
3114 | if (blk < extent.e_pblk + extent.e_len) { | |
3115 | mark_blocks_used(ctx, blk, | |
3116 | extent.e_pblk + extent.e_len - blk); | |
3117 | n = DIV_ROUND_UP(extent.e_pblk + extent.e_len - blk, | |
3118 | EXT2FS_CLUSTER_RATIO(ctx->fs)); | |
3119 | pb->num_blocks += n; | |
15d482ba | 3120 | } |
d5d981a3 | 3121 | pb->last_block = extent.e_lblk + extent.e_len - 1; |
63b5e354 | 3122 | pb->previous_block = extent.e_pblk + extent.e_len - 1; |
d3f32c2d | 3123 | start_block = pb->last_block = last_lblk; |
010dc7b9 LC |
3124 | if (is_leaf && !is_dir && |
3125 | !(extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)) | |
d3f32c2d | 3126 | pb->last_init_lblock = last_lblk; |
15d482ba TT |
3127 | next: |
3128 | pctx->errcode = ext2fs_extent_get(ehandle, | |
3129 | EXT2_EXTENT_NEXT_SIB, | |
3130 | &extent); | |
3131 | } | |
49fed79e DW |
3132 | |
3133 | /* Failed csum but passes checks? Ask to fix checksum. */ | |
3134 | if (failed_csum && | |
3135 | fix_problem(ctx, PR_1_EXTENT_ONLY_CSUM_INVALID, pctx)) { | |
3136 | pb->inode_modified = 1; | |
3137 | pctx->errcode = ext2fs_extent_replace(ehandle, 0, &extent); | |
3138 | if (pctx->errcode) | |
3139 | return; | |
3140 | } | |
3141 | ||
15d482ba TT |
3142 | if (pctx->errcode == EXT2_ET_EXTENT_NO_NEXT) |
3143 | pctx->errcode = 0; | |
3144 | } | |
3145 | ||
3146 | static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx, | |
2acad6b4 | 3147 | struct process_block_struct *pb) |
15d482ba | 3148 | { |
8da6d1a1 | 3149 | struct ext2_extent_info info; |
15d482ba TT |
3150 | struct ext2_inode *inode = pctx->inode; |
3151 | ext2_extent_handle_t ehandle; | |
3152 | ext2_filsys fs = ctx->fs; | |
3153 | ext2_ino_t ino = pctx->ino; | |
8da6d1a1 | 3154 | errcode_t retval; |
085757fc | 3155 | blk64_t eof_lblk; |
f680db65 | 3156 | struct ext3_extent_header *eh; |
15d482ba | 3157 | |
f680db65 DW |
3158 | /* Check for a proper extent header... */ |
3159 | eh = (struct ext3_extent_header *) &inode->i_block[0]; | |
3160 | retval = ext2fs_extent_header_verify(eh, sizeof(inode->i_block)); | |
3161 | if (retval) { | |
3162 | if (fix_problem(ctx, PR_1_MISSING_EXTENT_HEADER, pctx)) | |
3163 | e2fsck_clear_inode(ctx, ino, inode, 0, | |
3164 | "check_blocks_extents"); | |
3165 | pctx->errcode = 0; | |
3166 | return; | |
3167 | } | |
15d482ba | 3168 | |
f680db65 | 3169 | /* ...since this function doesn't fail if i_block is zeroed. */ |
84b239ae | 3170 | pctx->errcode = ext2fs_extent_open2(fs, ino, inode, &ehandle); |
0a68b181 TT |
3171 | if (pctx->errcode) { |
3172 | if (fix_problem(ctx, PR_1_READ_EXTENT, pctx)) | |
3173 | e2fsck_clear_inode(ctx, ino, inode, 0, | |
3174 | "check_blocks_extents"); | |
15d482ba TT |
3175 | pctx->errcode = 0; |
3176 | return; | |
3177 | } | |
3178 | ||
8da6d1a1 TT |
3179 | retval = ext2fs_extent_get_info(ehandle, &info); |
3180 | if (retval == 0) { | |
e228d700 DW |
3181 | int max_depth = info.max_depth; |
3182 | ||
3183 | if (max_depth >= MAX_EXTENT_DEPTH_COUNT) | |
3184 | max_depth = MAX_EXTENT_DEPTH_COUNT-1; | |
3185 | ctx->extent_depth_count[max_depth]++; | |
8da6d1a1 TT |
3186 | } |
3187 | ||
e228d700 DW |
3188 | /* Check maximum extent depth */ |
3189 | pctx->blk = info.max_depth; | |
3190 | pctx->blk2 = ext2fs_max_extent_depth(ehandle); | |
3191 | if (pctx->blk2 < pctx->blk && | |
3192 | fix_problem(ctx, PR_1_EXTENT_BAD_MAX_DEPTH, pctx)) | |
3193 | pb->eti.force_rebuild = 1; | |
3194 | ||
3195 | /* Can we collect extent tree level stats? */ | |
3196 | pctx->blk = MAX_EXTENT_DEPTH_COUNT; | |
3197 | if (pctx->blk2 > pctx->blk) | |
3198 | fix_problem(ctx, PR_1E_MAX_EXTENT_TREE_DEPTH, pctx); | |
3199 | memset(pb->eti.ext_info, 0, sizeof(pb->eti.ext_info)); | |
3200 | pb->eti.ino = pb->ino; | |
3201 | ||
ee84bbc8 | 3202 | pb->next_lblock = 0; |
79362360 | 3203 | |
085757fc EW |
3204 | eof_lblk = ((EXT2_I_SIZE(inode) + fs->blocksize - 1) >> |
3205 | EXT2_BLOCK_SIZE_BITS(fs->super)) - 1; | |
35c8faaf | 3206 | scan_extent_node(ctx, pctx, pb, 0, 0, eof_lblk, ehandle, 1); |
7518c176 TT |
3207 | if (pctx->errcode && |
3208 | fix_problem(ctx, PR_1_EXTENT_ITERATE_FAILURE, pctx)) { | |
3209 | pb->num_blocks = 0; | |
3210 | inode->i_blocks = 0; | |
3211 | e2fsck_clear_inode(ctx, ino, inode, E2F_FLAG_RESTART, | |
3212 | "check_blocks_extents"); | |
3213 | pctx->errcode = 0; | |
3214 | } | |
15d482ba | 3215 | ext2fs_extent_free(ehandle); |
e228d700 DW |
3216 | |
3217 | /* Rebuild unless it's a dir and we're rehashing it */ | |
3218 | if (LINUX_S_ISDIR(inode->i_mode) && | |
3219 | e2fsck_dir_will_be_rehashed(ctx, ino)) | |
3220 | return; | |
3221 | ||
3222 | if (ctx->options & E2F_OPT_CONVERT_BMAP) | |
3223 | e2fsck_rebuild_extents_later(ctx, ino); | |
3224 | else | |
3225 | e2fsck_should_rebuild_extents(ctx, pctx, &pb->eti, &info); | |
15d482ba TT |
3226 | } |
3227 | ||
042e0719 ZL |
3228 | /* |
3229 | * In fact we don't need to check blocks for an inode with inline data | |
3230 | * because this inode doesn't have any blocks. In this function all | |
3231 | * we need to do is add this inode into dblist when it is a directory. | |
3232 | */ | |
3233 | static void check_blocks_inline_data(e2fsck_t ctx, struct problem_context *pctx, | |
3234 | struct process_block_struct *pb) | |
3235 | { | |
0ac4b397 DW |
3236 | int flags; |
3237 | size_t inline_data_size = 0; | |
3238 | ||
cc7d12ac DW |
3239 | if (!pb->is_dir) { |
3240 | pctx->errcode = 0; | |
042e0719 | 3241 | return; |
cc7d12ac | 3242 | } |
042e0719 | 3243 | |
0ac4b397 | 3244 | /* Process the dirents in i_block[] as the "first" block. */ |
042e0719 | 3245 | pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist, pb->ino, 0, 0); |
0ac4b397 DW |
3246 | if (pctx->errcode) |
3247 | goto err; | |
3248 | ||
3249 | /* Process the dirents in the EA as a "second" block. */ | |
3250 | flags = ctx->fs->flags; | |
3251 | ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; | |
3252 | pctx->errcode = ext2fs_inline_data_size(ctx->fs, pb->ino, | |
3253 | &inline_data_size); | |
3254 | ctx->fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) | | |
3255 | (ctx->fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS); | |
042e0719 | 3256 | if (pctx->errcode) { |
0ac4b397 DW |
3257 | pctx->errcode = 0; |
3258 | return; | |
042e0719 | 3259 | } |
0ac4b397 DW |
3260 | |
3261 | if (inline_data_size <= EXT4_MIN_INLINE_DATA_SIZE) | |
3262 | return; | |
3263 | ||
3264 | pctx->errcode = ext2fs_add_dir_block2(ctx->fs->dblist, pb->ino, 0, 1); | |
3265 | if (pctx->errcode) | |
3266 | goto err; | |
3267 | ||
3268 | return; | |
3269 | err: | |
3270 | pctx->blk = 0; | |
3271 | pctx->num = 0; | |
3272 | fix_problem(ctx, PR_1_ADD_DBLOCK, pctx); | |
3273 | ctx->flags |= E2F_FLAG_ABORT; | |
042e0719 ZL |
3274 | } |
3275 | ||
3839e657 TT |
3276 | /* |
3277 | * This subroutine is called on each inode to account for all of the | |
3278 | * blocks used by that inode. | |
3279 | */ | |
1b6bf175 | 3280 | static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, |
0b4ffc27 | 3281 | char *block_buf, const struct ea_quota *ea_ibody_quota) |
3839e657 | 3282 | { |
1b6bf175 | 3283 | ext2_filsys fs = ctx->fs; |
3839e657 | 3284 | struct process_block_struct pb; |
86c627ec | 3285 | ext2_ino_t ino = pctx->ino; |
21c84b71 | 3286 | struct ext2_inode *inode = pctx->inode; |
3971bfe8 | 3287 | unsigned bad_size = 0; |
503f9e7f | 3288 | int dirty_inode = 0; |
7c1e090c | 3289 | int extent_fs; |
042e0719 | 3290 | int inlinedata_fs; |
246501c6 | 3291 | __u64 size; |
0b4ffc27 | 3292 | struct ea_quota ea_block_quota; |
efc6f628 | 3293 | |
3839e657 | 3294 | pb.ino = ino; |
0b4ffc27 TE |
3295 | pb.num_blocks = EXT2FS_B2C(ctx->fs, |
3296 | ea_ibody_quota ? ea_ibody_quota->blocks : 0); | |
62f9bd0e | 3297 | pb.last_block = ~0; |
010dc7b9 | 3298 | pb.last_init_lblock = -1; |
4dbe79bc | 3299 | pb.last_db_block = -1; |
f3db3566 | 3300 | pb.num_illegal_blocks = 0; |
21c84b71 | 3301 | pb.suppress = 0; pb.clear = 0; |
74becf3c | 3302 | pb.fragmented = 0; |
1917875f | 3303 | pb.compressed = 0; |
74becf3c | 3304 | pb.previous_block = 0; |
b94a052a | 3305 | pb.is_dir = LINUX_S_ISDIR(inode->i_mode); |
da307041 | 3306 | pb.is_reg = LINUX_S_ISREG(inode->i_mode); |
c8ca2397 | 3307 | pb.max_blocks = 1U << (31 - fs->super->s_log_block_size); |
f3db3566 | 3308 | pb.inode = inode; |
21c84b71 | 3309 | pb.pctx = pctx; |
1b6bf175 | 3310 | pb.ctx = ctx; |
23d6dd1f | 3311 | pb.inode_modified = 0; |
e228d700 | 3312 | pb.eti.force_rebuild = 0; |
1b6bf175 | 3313 | pctx->ino = ino; |
0684a4f3 | 3314 | pctx->errcode = 0; |
1917875f | 3315 | |
86f3b6cf DW |
3316 | extent_fs = ext2fs_has_feature_extents(ctx->fs->super); |
3317 | inlinedata_fs = ext2fs_has_feature_inline_data(ctx->fs->super); | |
7c1e090c | 3318 | |
0b4ffc27 | 3319 | if (check_ext_attr(ctx, pctx, block_buf, &ea_block_quota)) { |
fefaef39 AD |
3320 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
3321 | goto out; | |
0b4ffc27 | 3322 | pb.num_blocks += EXT2FS_B2C(ctx->fs, ea_block_quota.blocks); |
fefaef39 | 3323 | } |
dc71f23e | 3324 | |
68073429 DW |
3325 | if (inlinedata_fs && (inode->i_flags & EXT4_INLINE_DATA_FL)) |
3326 | check_blocks_inline_data(ctx, pctx, &pb); | |
3327 | else if (ext2fs_inode_has_valid_blocks2(fs, inode)) { | |
7c1e090c | 3328 | if (extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) |
2acad6b4 | 3329 | check_blocks_extents(ctx, pctx, &pb); |
010dc7b9 | 3330 | else { |
d4864e02 | 3331 | int flags; |
23d6dd1f DW |
3332 | /* |
3333 | * If we've modified the inode, write it out before | |
3334 | * iterate() tries to use it. | |
3335 | */ | |
3336 | if (dirty_inode) { | |
3337 | e2fsck_write_inode(ctx, ino, inode, | |
3338 | "check_blocks"); | |
3339 | dirty_inode = 0; | |
3340 | } | |
d4864e02 | 3341 | flags = fs->flags; |
f9f3050a | 3342 | fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; |
6dc64392 | 3343 | pctx->errcode = ext2fs_block_iterate3(fs, ino, |
15d482ba TT |
3344 | pb.is_dir ? BLOCK_FLAG_HOLE : 0, |
3345 | block_buf, process_block, &pb); | |
010dc7b9 LC |
3346 | /* |
3347 | * We do not have uninitialized extents in non extent | |
3348 | * files. | |
3349 | */ | |
3350 | pb.last_init_lblock = pb.last_block; | |
23d6dd1f DW |
3351 | /* |
3352 | * If iterate() changed a block mapping, we have to | |
3353 | * re-read the inode. If we decide to clear the | |
3354 | * inode after clearing some stuff, we'll re-write the | |
3355 | * bad mappings into the inode! | |
3356 | */ | |
3357 | if (pb.inode_modified) | |
3358 | e2fsck_read_inode(ctx, ino, inode, | |
3359 | "check_blocks"); | |
d4864e02 DW |
3360 | fs->flags = (flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) | |
3361 | (fs->flags & ~EXT2_FLAG_IGNORE_CSUM_ERRORS); | |
e228d700 DW |
3362 | |
3363 | if (ctx->options & E2F_OPT_CONVERT_BMAP) { | |
3364 | #ifdef DEBUG | |
3365 | printf("bmap rebuild ino=%d\n", ino); | |
3366 | #endif | |
3367 | if (!LINUX_S_ISDIR(inode->i_mode) || | |
3368 | !e2fsck_dir_will_be_rehashed(ctx, ino)) | |
3369 | e2fsck_rebuild_extents_later(ctx, ino); | |
3370 | } | |
010dc7b9 | 3371 | } |
15d482ba | 3372 | } |
1b6bf175 | 3373 | end_problem_latch(ctx, PR_LATCH_BLOCK); |
da307041 | 3374 | end_problem_latch(ctx, PR_LATCH_TOOBIG); |
0684a4f3 TT |
3375 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
3376 | goto out; | |
1b6bf175 TT |
3377 | if (pctx->errcode) |
3378 | fix_problem(ctx, PR_1_BLOCK_ITERATE, pctx); | |
3839e657 | 3379 | |
ce44d8ca TT |
3380 | if (pb.fragmented && pb.num_blocks < fs->super->s_blocks_per_group) { |
3381 | if (LINUX_S_ISDIR(inode->i_mode)) | |
3382 | ctx->fs_fragmented_dir++; | |
3383 | else | |
3384 | ctx->fs_fragmented++; | |
3385 | } | |
74becf3c | 3386 | |
f3db3566 | 3387 | if (pb.clear) { |
e3df15ab TT |
3388 | e2fsck_clear_inode(ctx, ino, inode, E2F_FLAG_RESTART, |
3389 | "check_blocks"); | |
3390 | return; | |
f3db3566 | 3391 | } |
efc6f628 | 3392 | |
8fdc9985 | 3393 | if (inode->i_flags & EXT2_INDEX_FL) { |
503f9e7f TT |
3394 | if (handle_htree(ctx, pctx, ino, inode, block_buf)) { |
3395 | inode->i_flags &= ~EXT2_INDEX_FL; | |
3396 | dirty_inode++; | |
3397 | } else { | |
28b44ef0 | 3398 | e2fsck_add_dx_dir(ctx, ino, inode, pb.last_block+1); |
503f9e7f | 3399 | } |
8fdc9985 | 3400 | } |
efc6f628 | 3401 | |
042e0719 ZL |
3402 | if (!pb.num_blocks && pb.is_dir && |
3403 | !(inode->i_flags & EXT4_INLINE_DATA_FL)) { | |
1b6bf175 | 3404 | if (fix_problem(ctx, PR_1_ZERO_LENGTH_DIR, pctx)) { |
e3df15ab | 3405 | e2fsck_clear_inode(ctx, ino, inode, 0, "check_blocks"); |
1b6bf175 | 3406 | ctx->fs_directory_count--; |
e3df15ab | 3407 | return; |
21c84b71 | 3408 | } |
3839e657 | 3409 | } |
0684a4f3 | 3410 | |
080e09b4 | 3411 | if (ino != quota_type2inum(PRJQUOTA, fs->super) && |
0b4ffc27 TE |
3412 | (ino == EXT2_ROOT_INO || ino >= EXT2_FIRST_INODE(ctx->fs->super)) && |
3413 | !(inode->i_flags & EXT4_EA_INODE_FL)) { | |
bc1ec4b4 | 3414 | quota_data_add(ctx->qctx, (struct ext2_inode_large *) inode, |
97126931 EW |
3415 | ino, |
3416 | pb.num_blocks * EXT2_CLUSTER_SIZE(fs->super)); | |
bc1ec4b4 | 3417 | quota_data_inodes(ctx->qctx, (struct ext2_inode_large *) inode, |
0b4ffc27 TE |
3418 | ino, (ea_ibody_quota ? |
3419 | ea_ibody_quota->inodes : 0) + | |
3420 | ea_block_quota.inodes + 1); | |
624e4a64 AK |
3421 | } |
3422 | ||
86f3b6cf | 3423 | if (!ext2fs_has_feature_huge_file(fs->super) || |
1ca1059f TT |
3424 | !(inode->i_flags & EXT4_HUGE_FILE_FL)) |
3425 | pb.num_blocks *= (fs->blocksize / 512); | |
b2e6c86d | 3426 | pb.num_blocks *= EXT2FS_CLUSTER_RATIO(fs); |
0684a4f3 | 3427 | #if 0 |
62f9bd0e | 3428 | printf("inode %u, i_size = %u, last_block = %llu, i_blocks=%llu, num_blocks = %llu\n", |
6dc64392 | 3429 | ino, inode->i_size, pb.last_block, ext2fs_inode_i_blocks(fs, inode), |
0684a4f3 TT |
3430 | pb.num_blocks); |
3431 | #endif | |
246501c6 | 3432 | if (pb.is_dir) { |
62f9bd0e | 3433 | unsigned nblock = inode->i_size >> EXT2_BLOCK_SIZE_BITS(fs->super); |
042e0719 | 3434 | if (inode->i_flags & EXT4_INLINE_DATA_FL) { |
d4864e02 | 3435 | int flags; |
62f9bd0e | 3436 | size_t sz = 0; |
ef9c58d5 | 3437 | errcode_t err; |
042e0719 | 3438 | |
d4864e02 DW |
3439 | flags = ctx->fs->flags; |
3440 | ctx->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; | |
ef9c58d5 | 3441 | err = ext2fs_inline_data_size(ctx->fs, pctx->ino, |
62f9bd0e | 3442 | &sz); |
d4864e02 DW |
3443 | ctx->fs->flags = (flags & |
3444 | EXT2_FLAG_IGNORE_CSUM_ERRORS) | | |
3445 | (ctx->fs->flags & | |
3446 | ~EXT2_FLAG_IGNORE_CSUM_ERRORS); | |
62f9bd0e | 3447 | if (err || sz != inode->i_size) { |
ef9c58d5 | 3448 | bad_size = 7; |
62f9bd0e | 3449 | pctx->num = sz; |
ef9c58d5 | 3450 | } |
042e0719 | 3451 | } else if (inode->i_size & (fs->blocksize - 1)) |
2cd12338 TT |
3452 | bad_size = 5; |
3453 | else if (nblock > (pb.last_block + 1)) | |
246501c6 TT |
3454 | bad_size = 1; |
3455 | else if (nblock < (pb.last_block + 1)) { | |
246501c6 | 3456 | if (((pb.last_block + 1) - nblock) > |
5dd8f963 | 3457 | fs->super->s_prealloc_dir_blocks) |
9d1bd3de | 3458 | bad_size = 2; |
246501c6 TT |
3459 | } |
3460 | } else { | |
4f489285 | 3461 | size = EXT2_I_SIZE(inode); |
010dc7b9 | 3462 | if ((pb.last_init_lblock >= 0) && |
cabde499 | 3463 | /* Do not allow initialized allocated blocks past i_size*/ |
3baafde6 EB |
3464 | (size < (__u64)pb.last_init_lblock * fs->blocksize) && |
3465 | !(inode->i_flags & EXT4_VERITY_FL)) | |
9d1bd3de | 3466 | bad_size = 3; |
7c1e090c ES |
3467 | else if (!(extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) && |
3468 | size > ext2_max_sizes[fs->super->s_log_block_size]) | |
3469 | /* too big for a direct/indirect-mapped file */ | |
9d1bd3de | 3470 | bad_size = 4; |
7c1e090c | 3471 | else if ((extent_fs && (inode->i_flags & EXT4_EXTENTS_FL)) && |
3ec7be43 | 3472 | size > |
03fa6f8a | 3473 | ((1ULL << (32 + EXT2_BLOCK_SIZE_BITS(fs->super))) - 1)) |
7c1e090c ES |
3474 | /* too big for an extent-based file - 32bit ee_block */ |
3475 | bad_size = 6; | |
246501c6 | 3476 | } |
0684a4f3 TT |
3477 | /* i_size for symlinks is checked elsewhere */ |
3478 | if (bad_size && !LINUX_S_ISLNK(inode->i_mode)) { | |
ef9c58d5 DW |
3479 | /* Did inline_data set pctx->num earlier? */ |
3480 | if (bad_size != 7) | |
3481 | pctx->num = (pb.last_block + 1) * fs->blocksize; | |
3ec7be43 | 3482 | pctx->group = bad_size; |
1b6bf175 | 3483 | if (fix_problem(ctx, PR_1_BAD_I_SIZE, pctx)) { |
97c607b1 DW |
3484 | if (LINUX_S_ISDIR(inode->i_mode)) |
3485 | pctx->num &= 0xFFFFFFFFULL; | |
3486 | ext2fs_inode_size_set(fs, inode, pctx->num); | |
ef9c58d5 DW |
3487 | if (EXT2_I_SIZE(inode) == 0 && |
3488 | (inode->i_flags & EXT4_INLINE_DATA_FL)) { | |
3489 | memset(inode->i_block, 0, | |
3490 | sizeof(inode->i_block)); | |
3491 | inode->i_flags &= ~EXT4_INLINE_DATA_FL; | |
3492 | } | |
503f9e7f | 3493 | dirty_inode++; |
21c84b71 TT |
3494 | } |
3495 | pctx->num = 0; | |
3839e657 | 3496 | } |
3b6c0938 DW |
3497 | if (LINUX_S_ISREG(inode->i_mode) && |
3498 | ext2fs_needs_large_file_feature(EXT2_I_SIZE(inode))) | |
246501c6 | 3499 | ctx->large_files++; |
c0495d96 | 3500 | if ((fs->super->s_creator_os != EXT2_OS_HURD) && |
36769c60 | 3501 | ((pb.num_blocks != ext2fs_inode_i_blocks(fs, inode)) || |
86f3b6cf | 3502 | (ext2fs_has_feature_huge_file(fs->super) && |
36769c60 JW |
3503 | (inode->i_flags & EXT4_HUGE_FILE_FL) && |
3504 | (inode->osd2.linux2.l_i_blocks_hi != 0)))) { | |
21c84b71 | 3505 | pctx->num = pb.num_blocks; |
1b6bf175 | 3506 | if (fix_problem(ctx, PR_1_BAD_I_BLOCKS, pctx)) { |
3839e657 | 3507 | inode->i_blocks = pb.num_blocks; |
b70506bf | 3508 | inode->osd2.linux2.l_i_blocks_hi = pb.num_blocks >> 32; |
503f9e7f | 3509 | dirty_inode++; |
21c84b71 TT |
3510 | } |
3511 | pctx->num = 0; | |
3839e657 | 3512 | } |
a49249d2 | 3513 | |
faa427d3 DW |
3514 | /* |
3515 | * The kernel gets mad if we ask it to allocate bigalloc clusters to | |
3516 | * a block mapped file, so rebuild it as an extent file. We can skip | |
3517 | * symlinks because they're never rewritten. | |
3518 | */ | |
86f3b6cf | 3519 | if (ext2fs_has_feature_bigalloc(fs->super) && |
faa427d3 DW |
3520 | (LINUX_S_ISREG(inode->i_mode) || LINUX_S_ISDIR(inode->i_mode)) && |
3521 | ext2fs_inode_data_blocks2(fs, inode) > 0 && | |
3522 | (ino == EXT2_ROOT_INO || ino >= EXT2_FIRST_INO(fs->super)) && | |
3523 | !(inode->i_flags & (EXT4_EXTENTS_FL | EXT4_INLINE_DATA_FL)) && | |
3524 | fix_problem(ctx, PR_1_NO_BIGALLOC_BLOCKMAP_FILES, pctx)) { | |
3525 | pctx->errcode = e2fsck_rebuild_extents_later(ctx, ino); | |
3526 | if (pctx->errcode) | |
3527 | goto out; | |
3528 | } | |
3529 | ||
a49249d2 | 3530 | if (ctx->dirs_to_hash && pb.is_dir && |
82372e32 | 3531 | !(ctx->lost_and_found && ctx->lost_and_found == ino) && |
a49249d2 TT |
3532 | !(inode->i_flags & EXT2_INDEX_FL) && |
3533 | ((inode->i_size / fs->blocksize) >= 3)) | |
07307114 | 3534 | e2fsck_rehash_dir_later(ctx, ino); |
a49249d2 | 3535 | |
503f9e7f TT |
3536 | out: |
3537 | if (dirty_inode) | |
3538 | e2fsck_write_inode(ctx, ino, inode, "check_blocks"); | |
50e1e10f TT |
3539 | } |
3540 | ||
21c84b71 | 3541 | #if 0 |
50e1e10f TT |
3542 | /* |
3543 | * Helper function called by process block when an illegal block is | |
3544 | * found. It returns a description about why the block is illegal | |
3545 | */ | |
6dc64392 | 3546 | static char *describe_illegal_block(ext2_filsys fs, blk64_t block) |
50e1e10f | 3547 | { |
6dc64392 | 3548 | blk64_t super; |
50e1e10f TT |
3549 | int i; |
3550 | static char problem[80]; | |
3551 | ||
3552 | super = fs->super->s_first_data_block; | |
3553 | strcpy(problem, "PROGRAMMING ERROR: Unknown reason for illegal block"); | |
3554 | if (block < super) { | |
3555 | sprintf(problem, "< FIRSTBLOCK (%u)", super); | |
3556 | return(problem); | |
4efbac6f VAH |
3557 | } else if (block >= ext2fs_blocks_count(fs->super)) { |
3558 | sprintf(problem, "> BLOCKS (%u)", ext2fs_blocks_count(fs->super)); | |
50e1e10f TT |
3559 | return(problem); |
3560 | } | |
3561 | for (i = 0; i < fs->group_desc_count; i++) { | |
3562 | if (block == super) { | |
3563 | sprintf(problem, "is the superblock in group %d", i); | |
3564 | break; | |
3565 | } | |
3566 | if (block > super && | |
3567 | block <= (super + fs->desc_blocks)) { | |
3568 | sprintf(problem, "is in the group descriptors " | |
3569 | "of group %d", i); | |
3570 | break; | |
3571 | } | |
d7cca6b0 | 3572 | if (block == ext2fs_block_bitmap_loc(fs, i)) { |
50e1e10f TT |
3573 | sprintf(problem, "is the block bitmap of group %d", i); |
3574 | break; | |
3575 | } | |
d7cca6b0 | 3576 | if (block == ext2fs_inode_bitmap_loc(fs, i)) { |
50e1e10f TT |
3577 | sprintf(problem, "is the inode bitmap of group %d", i); |
3578 | break; | |
3579 | } | |
d7cca6b0 VAH |
3580 | if (block >= ext2fs_inode_table_loc(fs, i) && |
3581 | (block < ext2fs_inode_table_loc(fs, i) | |
50e1e10f TT |
3582 | + fs->inode_blocks_per_group)) { |
3583 | sprintf(problem, "is in the inode table of group %d", | |
3584 | i); | |
3585 | break; | |
3586 | } | |
3587 | super += fs->super->s_blocks_per_group; | |
3588 | } | |
3589 | return(problem); | |
3590 | } | |
21c84b71 | 3591 | #endif |
3839e657 TT |
3592 | |
3593 | /* | |
3594 | * This is a helper function for check_blocks(). | |
3595 | */ | |
53ef44c4 | 3596 | static int process_block(ext2_filsys fs, |
6dc64392 | 3597 | blk64_t *block_nr, |
9d1bd3de | 3598 | e2_blkcnt_t blockcnt, |
6dc64392 | 3599 | blk64_t ref_block EXT2FS_ATTR((unused)), |
54434927 | 3600 | int ref_offset EXT2FS_ATTR((unused)), |
54dc7ca2 | 3601 | void *priv_data) |
3839e657 TT |
3602 | { |
3603 | struct process_block_struct *p; | |
21c84b71 | 3604 | struct problem_context *pctx; |
6dc64392 | 3605 | blk64_t blk = *block_nr; |
50e1e10f | 3606 | int ret_code = 0; |
3c7c6d73 | 3607 | problem_t problem = 0; |
1b6bf175 | 3608 | e2fsck_t ctx; |
3839e657 | 3609 | |
54dc7ca2 | 3610 | p = (struct process_block_struct *) priv_data; |
21c84b71 | 3611 | pctx = p->pctx; |
1b6bf175 | 3612 | ctx = p->ctx; |
3839e657 | 3613 | |
0733835b DW |
3614 | /* |
3615 | * For a directory, add logical block zero for processing even if it's | |
3616 | * not mapped or we'll be perennially stuck with broken "." and ".." | |
3617 | * entries. | |
3618 | */ | |
3619 | if (p->is_dir && blockcnt == 0 && blk == 0) { | |
3620 | pctx->errcode = ext2fs_add_dir_block2(fs->dblist, p->ino, 0, 0); | |
3621 | if (pctx->errcode) { | |
3622 | pctx->blk = blk; | |
3623 | pctx->num = blockcnt; | |
3624 | goto failed_add_dir_block; | |
3625 | } | |
3626 | p->last_db_block++; | |
3627 | } | |
3628 | ||
4dbe79bc | 3629 | if (blk == 0) |
50e1e10f | 3630 | return 0; |
50e1e10f | 3631 | |
3839e657 | 3632 | #if 0 |
50e1e10f | 3633 | printf("Process_block, inode %lu, block %u, #%d\n", p->ino, blk, |
3839e657 | 3634 | blockcnt); |
50e1e10f | 3635 | #endif |
efc6f628 | 3636 | |
74becf3c TT |
3637 | /* |
3638 | * Simplistic fragmentation check. We merely require that the | |
3639 | * file be contiguous. (Which can never be true for really | |
3640 | * big files that are greater than a block group.) | |
3641 | */ | |
4a05268c | 3642 | if (p->previous_block && p->ino != EXT2_RESIZE_INO) { |
63b5e354 | 3643 | if (p->previous_block+1 != blk) { |
100d4701 TT |
3644 | if (ctx->options & E2F_OPT_FRAGCHECK) { |
3645 | char type = '?'; | |
3646 | ||
3647 | if (p->is_dir) | |
3648 | type = 'd'; | |
3649 | else if (p->is_reg) | |
3650 | type = 'f'; | |
3651 | ||
3652 | printf(_("%6lu(%c): expecting %6lu " | |
3653 | "got phys %6lu (blkcnt %lld)\n"), | |
3654 | (unsigned long) pctx->ino, type, | |
63b5e354 TT |
3655 | (unsigned long) p->previous_block+1, |
3656 | (unsigned long) blk, | |
f4e2c991 | 3657 | blockcnt); |
100d4701 | 3658 | } |
74becf3c | 3659 | p->fragmented = 1; |
63b5e354 | 3660 | } |
74becf3c | 3661 | } |
503f9e7f | 3662 | |
49f28a06 AB |
3663 | if (p->is_dir && !ext2fs_has_feature_largedir(fs->super) && |
3664 | blockcnt > (1 << (21 - fs->super->s_log_block_size))) | |
da307041 | 3665 | problem = PR_1_TOOBIG_DIR; |
49f28a06 AB |
3666 | if (p->is_dir && p->num_blocks + 1 >= p->max_blocks) |
3667 | problem = PR_1_TOOBIG_DIR; | |
3668 | if (p->is_reg && p->num_blocks + 1 >= p->max_blocks) | |
da307041 TT |
3669 | problem = PR_1_TOOBIG_REG; |
3670 | if (!p->is_dir && !p->is_reg && blockcnt > 0) | |
3671 | problem = PR_1_TOOBIG_SYMLINK; | |
efc6f628 | 3672 | |
50e1e10f | 3673 | if (blk < fs->super->s_first_data_block || |
4efbac6f | 3674 | blk >= ext2fs_blocks_count(fs->super)) |
21c84b71 | 3675 | problem = PR_1_ILLEGAL_BLOCK_NUM; |
21c84b71 | 3676 | |
35c8faaf DW |
3677 | /* |
3678 | * If this IND/DIND/TIND block is squatting atop some critical metadata | |
3679 | * (group descriptors, superblock, bitmap, inode table), any write to | |
3680 | * "fix" mapping problems will destroy the metadata. We'll let pass 1b | |
3681 | * fix that and restart fsck. | |
3682 | */ | |
3683 | if (blockcnt < 0 && | |
3684 | p->ino != EXT2_RESIZE_INO && | |
9c5b443c | 3685 | blk < ctx->fs->super->s_blocks_count && |
35c8faaf | 3686 | ext2fs_test_block_bitmap2(ctx->block_metadata_map, blk)) { |
35c8faaf DW |
3687 | pctx->blk = blk; |
3688 | fix_problem(ctx, PR_1_CRITICAL_METADATA_COLLISION, pctx); | |
f97c601a TT |
3689 | if ((ctx->options & E2F_OPT_NO) == 0) |
3690 | ctx->flags |= E2F_FLAG_RESTART_LATER; | |
35c8faaf DW |
3691 | } |
3692 | ||
21c84b71 | 3693 | if (problem) { |
f3db3566 | 3694 | p->num_illegal_blocks++; |
35c8faaf DW |
3695 | /* |
3696 | * A bit of subterfuge here -- we're trying to fix a block | |
5e61441a | 3697 | * mapping, but the IND/DIND/TIND block could have collided |
35c8faaf DW |
3698 | * with some critical metadata. So, fix the in-core mapping so |
3699 | * iterate won't go insane, but return 0 instead of | |
3700 | * BLOCK_CHANGED so that it won't write the remapping out to | |
3701 | * our multiply linked block. | |
5e61441a DW |
3702 | * |
3703 | * Even if we previously determined that an *IND block | |
3704 | * conflicts with critical metadata, we must still try to | |
3705 | * iterate the *IND block as if it is an *IND block to find and | |
3706 | * mark the blocks it points to. Better to be overly cautious | |
3707 | * with the used_blocks map so that we don't move the *IND | |
3708 | * block to a block that's really in use! | |
35c8faaf | 3709 | */ |
5e61441a DW |
3710 | if (p->ino != EXT2_RESIZE_INO && |
3711 | ref_block != 0 && | |
3712 | ext2fs_test_block_bitmap2(ctx->block_metadata_map, | |
3713 | ref_block)) { | |
35c8faaf DW |
3714 | *block_nr = 0; |
3715 | return 0; | |
3716 | } | |
21c84b71 | 3717 | if (!p->suppress && (p->num_illegal_blocks % 12) == 0) { |
1b6bf175 | 3718 | if (fix_problem(ctx, PR_1_TOO_MANY_BAD_BLOCKS, pctx)) { |
f3db3566 TT |
3719 | p->clear = 1; |
3720 | return BLOCK_ABORT; | |
3721 | } | |
f8188fff | 3722 | if (fix_problem(ctx, PR_1_SUPPRESS_MESSAGES, pctx)) { |
f3db3566 | 3723 | p->suppress = 1; |
1b6bf175 TT |
3724 | set_latch_flags(PR_LATCH_BLOCK, |
3725 | PRL_SUPPRESS, 0); | |
f3db3566 TT |
3726 | } |
3727 | } | |
21c84b71 TT |
3728 | pctx->blk = blk; |
3729 | pctx->blkcount = blockcnt; | |
1b6bf175 | 3730 | if (fix_problem(ctx, problem, pctx)) { |
50e1e10f TT |
3731 | blk = *block_nr = 0; |
3732 | ret_code = BLOCK_CHANGED; | |
23d6dd1f | 3733 | p->inode_modified = 1; |
c28c2741 DW |
3734 | /* |
3735 | * If the directory block is too big and is beyond the | |
3736 | * end of the FS, don't bother trying to add it for | |
3737 | * processing -- the kernel would never have created a | |
3738 | * directory this large, and we risk an ENOMEM abort. | |
3739 | * In any case, the toobig handler for extent-based | |
3740 | * directories also doesn't feed toobig blocks to | |
3741 | * pass 2. | |
3742 | */ | |
3743 | if (problem == PR_1_TOOBIG_DIR) | |
3744 | return ret_code; | |
50e1e10f | 3745 | goto mark_dir; |
21c84b71 | 3746 | } else |
3839e657 | 3747 | return 0; |
3839e657 TT |
3748 | } |
3749 | ||
d323f8fb | 3750 | if (p->ino == EXT2_RESIZE_INO) { |
efc6f628 | 3751 | /* |
c3ffaf83 TT |
3752 | * The resize inode has already be sanity checked |
3753 | * during pass #0 (the superblock checks). All we | |
3754 | * have to do is mark the double indirect block as | |
3755 | * being in use; all of the other blocks are handled | |
3756 | * by mark_table_blocks()). | |
3757 | */ | |
3758 | if (blockcnt == BLOCK_COUNT_DIND) | |
d323f8fb | 3759 | mark_block_used(ctx, blk); |
95a7f15f TT |
3760 | p->num_blocks++; |
3761 | } else if (!(ctx->fs->cluster_ratio_bits && | |
3762 | p->previous_block && | |
3763 | (EXT2FS_B2C(ctx->fs, blk) == | |
3764 | EXT2FS_B2C(ctx->fs, p->previous_block)) && | |
3765 | (blk & EXT2FS_CLUSTER_MASK(ctx->fs)) == | |
68477355 | 3766 | ((unsigned) blockcnt & EXT2FS_CLUSTER_MASK(ctx->fs)))) { |
d323f8fb | 3767 | mark_block_used(ctx, blk); |
95a7f15f | 3768 | p->num_blocks++; |
9a1d614d DW |
3769 | } else if (has_unaligned_cluster_map(ctx, p->previous_block, |
3770 | p->last_block, blk, blockcnt)) { | |
3771 | pctx->blk = blockcnt; | |
3772 | pctx->blk2 = blk; | |
3773 | fix_problem(ctx, PR_1_MISALIGNED_CLUSTER, pctx); | |
3774 | mark_block_used(ctx, blk); | |
3775 | mark_block_used(ctx, blk); | |
95a7f15f | 3776 | } |
1e3472c5 TT |
3777 | if (blockcnt >= 0) |
3778 | p->last_block = blockcnt; | |
95a7f15f | 3779 | p->previous_block = blk; |
50e1e10f | 3780 | mark_dir: |
1e3472c5 | 3781 | if (p->is_dir && (blockcnt >= 0)) { |
4dbe79bc | 3782 | while (++p->last_db_block < blockcnt) { |
6dc64392 VAH |
3783 | pctx->errcode = ext2fs_add_dir_block2(fs->dblist, |
3784 | p->ino, 0, | |
3785 | p->last_db_block); | |
4dbe79bc TT |
3786 | if (pctx->errcode) { |
3787 | pctx->blk = 0; | |
3788 | pctx->num = p->last_db_block; | |
3789 | goto failed_add_dir_block; | |
3790 | } | |
3791 | } | |
6dc64392 VAH |
3792 | pctx->errcode = ext2fs_add_dir_block2(fs->dblist, p->ino, |
3793 | blk, blockcnt); | |
1b6bf175 TT |
3794 | if (pctx->errcode) { |
3795 | pctx->blk = blk; | |
3796 | pctx->num = blockcnt; | |
4dbe79bc | 3797 | failed_add_dir_block: |
1b6bf175 | 3798 | fix_problem(ctx, PR_1_ADD_DBLOCK, pctx); |
08b21301 TT |
3799 | /* Should never get here */ |
3800 | ctx->flags |= E2F_FLAG_ABORT; | |
3801 | return BLOCK_ABORT; | |
3839e657 | 3802 | } |
3839e657 | 3803 | } |
50e1e10f | 3804 | return ret_code; |
3839e657 TT |
3805 | } |
3806 | ||
53ef44c4 | 3807 | static int process_bad_block(ext2_filsys fs, |
6dc64392 | 3808 | blk64_t *block_nr, |
9d1bd3de | 3809 | e2_blkcnt_t blockcnt, |
6dc64392 | 3810 | blk64_t ref_block EXT2FS_ATTR((unused)), |
54434927 | 3811 | int ref_offset EXT2FS_ATTR((unused)), |
54dc7ca2 | 3812 | void *priv_data) |
3839e657 TT |
3813 | { |
3814 | struct process_block_struct *p; | |
6dc64392 VAH |
3815 | blk64_t blk = *block_nr; |
3816 | blk64_t first_block; | |
54434927 | 3817 | dgrp_t i; |
21c84b71 | 3818 | struct problem_context *pctx; |
1b6bf175 | 3819 | e2fsck_t ctx; |
21c84b71 | 3820 | |
3839e657 TT |
3821 | if (!blk) |
3822 | return 0; | |
efc6f628 | 3823 | |
54dc7ca2 | 3824 | p = (struct process_block_struct *) priv_data; |
1b6bf175 | 3825 | ctx = p->ctx; |
21c84b71 | 3826 | pctx = p->pctx; |
efc6f628 | 3827 | |
f8188fff | 3828 | pctx->ino = EXT2_BAD_INO; |
21c84b71 TT |
3829 | pctx->blk = blk; |
3830 | pctx->blkcount = blockcnt; | |
3839e657 TT |
3831 | |
3832 | if ((blk < fs->super->s_first_data_block) || | |
4efbac6f | 3833 | (blk >= ext2fs_blocks_count(fs->super))) { |
1b6bf175 | 3834 | if (fix_problem(ctx, PR_1_BB_ILLEGAL_BLOCK_NUM, pctx)) { |
3839e657 TT |
3835 | *block_nr = 0; |
3836 | return BLOCK_CHANGED; | |
21c84b71 | 3837 | } else |
3839e657 | 3838 | return 0; |
3839e657 TT |
3839 | } |
3840 | ||
3841 | if (blockcnt < 0) { | |
c5d2f50d | 3842 | if (ext2fs_test_block_bitmap2(p->fs_meta_blocks, blk)) { |
000ba404 TT |
3843 | p->bbcheck = 1; |
3844 | if (fix_problem(ctx, PR_1_BB_FS_BLOCK, pctx)) { | |
3845 | *block_nr = 0; | |
3846 | return BLOCK_CHANGED; | |
3847 | } | |
c5d2f50d | 3848 | } else if (ext2fs_test_block_bitmap2(ctx->block_found_map, |
000ba404 TT |
3849 | blk)) { |
3850 | p->bbcheck = 1; | |
efc6f628 | 3851 | if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, |
000ba404 TT |
3852 | pctx)) { |
3853 | *block_nr = 0; | |
3854 | return BLOCK_CHANGED; | |
3855 | } | |
a02ce9df | 3856 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 TT |
3857 | return BLOCK_ABORT; |
3858 | } else | |
1b6bf175 | 3859 | mark_block_used(ctx, blk); |
3839e657 TT |
3860 | return 0; |
3861 | } | |
efc6f628 | 3862 | #if 0 |
50e1e10f | 3863 | printf ("DEBUG: Marking %u as bad.\n", blk); |
3839e657 | 3864 | #endif |
1b6bf175 | 3865 | ctx->fs_badblocks_count++; |
3839e657 TT |
3866 | /* |
3867 | * If the block is not used, then mark it as used and return. | |
3868 | * If it is already marked as found, this must mean that | |
3869 | * there's an overlap between the filesystem table blocks | |
3870 | * (bitmaps and inode table) and the bad block list. | |
3871 | */ | |
c5d2f50d VAH |
3872 | if (!ext2fs_test_block_bitmap2(ctx->block_found_map, blk)) { |
3873 | ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); | |
3839e657 TT |
3874 | return 0; |
3875 | } | |
f3db3566 TT |
3876 | /* |
3877 | * Try to find the where the filesystem block was used... | |
3878 | */ | |
3879 | first_block = fs->super->s_first_data_block; | |
efc6f628 | 3880 | |
f3db3566 | 3881 | for (i = 0; i < fs->group_desc_count; i++ ) { |
21c84b71 | 3882 | pctx->group = i; |
1b6bf175 | 3883 | pctx->blk = blk; |
8039c480 TT |
3884 | if (!ext2fs_bg_has_super(fs, i)) |
3885 | goto skip_super; | |
f3db3566 TT |
3886 | if (blk == first_block) { |
3887 | if (i == 0) { | |
1b6bf175 TT |
3888 | if (fix_problem(ctx, |
3889 | PR_1_BAD_PRIMARY_SUPERBLOCK, | |
3890 | pctx)) { | |
3891 | *block_nr = 0; | |
50e1e10f | 3892 | return BLOCK_CHANGED; |
1b6bf175 | 3893 | } |
50e1e10f | 3894 | return 0; |
f3db3566 | 3895 | } |
1b6bf175 | 3896 | fix_problem(ctx, PR_1_BAD_SUPERBLOCK, pctx); |
f3db3566 TT |
3897 | return 0; |
3898 | } | |
3899 | if ((blk > first_block) && | |
3900 | (blk <= first_block + fs->desc_blocks)) { | |
3901 | if (i == 0) { | |
1b6bf175 TT |
3902 | pctx->blk = *block_nr; |
3903 | if (fix_problem(ctx, | |
3904 | PR_1_BAD_PRIMARY_GROUP_DESCRIPTOR, pctx)) { | |
3905 | *block_nr = 0; | |
50e1e10f | 3906 | return BLOCK_CHANGED; |
1b6bf175 | 3907 | } |
50e1e10f | 3908 | return 0; |
f3db3566 | 3909 | } |
1b6bf175 | 3910 | fix_problem(ctx, PR_1_BAD_GROUP_DESCRIPTORS, pctx); |
f3db3566 | 3911 | return 0; |
3839e657 | 3912 | } |
8039c480 | 3913 | skip_super: |
d7cca6b0 | 3914 | if (blk == ext2fs_block_bitmap_loc(fs, i)) { |
1b6bf175 TT |
3915 | if (fix_problem(ctx, PR_1_BB_BAD_BLOCK, pctx)) { |
3916 | ctx->invalid_block_bitmap_flag[i]++; | |
3917 | ctx->invalid_bitmaps++; | |
21c84b71 | 3918 | } |
f3db3566 TT |
3919 | return 0; |
3920 | } | |
d7cca6b0 | 3921 | if (blk == ext2fs_inode_bitmap_loc(fs, i)) { |
1b6bf175 TT |
3922 | if (fix_problem(ctx, PR_1_IB_BAD_BLOCK, pctx)) { |
3923 | ctx->invalid_inode_bitmap_flag[i]++; | |
3924 | ctx->invalid_bitmaps++; | |
21c84b71 | 3925 | } |
f3db3566 TT |
3926 | return 0; |
3927 | } | |
d7cca6b0 VAH |
3928 | if ((blk >= ext2fs_inode_table_loc(fs, i)) && |
3929 | (blk < (ext2fs_inode_table_loc(fs, i) + | |
f3db3566 | 3930 | fs->inode_blocks_per_group))) { |
21c84b71 TT |
3931 | /* |
3932 | * If there are bad blocks in the inode table, | |
3933 | * the inode scan code will try to do | |
3934 | * something reasonable automatically. | |
3935 | */ | |
f3db3566 TT |
3936 | return 0; |
3937 | } | |
8039c480 | 3938 | first_block += fs->super->s_blocks_per_group; |
f3db3566 TT |
3939 | } |
3940 | /* | |
3941 | * If we've gotten to this point, then the only | |
3942 | * possibility is that the bad block inode meta data | |
3943 | * is using a bad block. | |
3944 | */ | |
3945 | if ((blk == p->inode->i_block[EXT2_IND_BLOCK]) || | |
000ba404 TT |
3946 | (blk == p->inode->i_block[EXT2_DIND_BLOCK]) || |
3947 | (blk == p->inode->i_block[EXT2_TIND_BLOCK])) { | |
3948 | p->bbcheck = 1; | |
3949 | if (fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK, pctx)) { | |
3950 | *block_nr = 0; | |
3951 | return BLOCK_CHANGED; | |
3952 | } | |
a02ce9df | 3953 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 | 3954 | return BLOCK_ABORT; |
f3db3566 | 3955 | return 0; |
3839e657 | 3956 | } |
1b6bf175 TT |
3957 | |
3958 | pctx->group = -1; | |
3959 | ||
3960 | /* Warn user that the block wasn't claimed */ | |
3961 | fix_problem(ctx, PR_1_PROGERR_CLAIMED_BLOCK, pctx); | |
3962 | ||
f3db3566 | 3963 | return 0; |
3839e657 TT |
3964 | } |
3965 | ||
3971bfe8 | 3966 | static void new_table_block(e2fsck_t ctx, blk64_t first_block, dgrp_t group, |
c5d2f50d | 3967 | const char *name, int num, blk64_t *new_block) |
3839e657 | 3968 | { |
1b6bf175 | 3969 | ext2_filsys fs = ctx->fs; |
617446e4 | 3970 | dgrp_t last_grp; |
c5d2f50d VAH |
3971 | blk64_t old_block = *new_block; |
3972 | blk64_t last_block; | |
3971bfe8 TT |
3973 | dgrp_t flexbg; |
3974 | unsigned flexbg_size; | |
3975 | int i, is_flexbg; | |
3839e657 | 3976 | char *buf; |
1b6bf175 TT |
3977 | struct problem_context pctx; |
3978 | ||
3979 | clear_problem_context(&pctx); | |
3980 | ||
3981 | pctx.group = group; | |
3982 | pctx.blk = old_block; | |
3983 | pctx.str = name; | |
3984 | ||
617446e4 TT |
3985 | /* |
3986 | * For flex_bg filesystems, first try to allocate the metadata | |
3987 | * within the flex_bg, and if that fails then try finding the | |
3988 | * space anywhere in the filesystem. | |
3989 | */ | |
86f3b6cf | 3990 | is_flexbg = ext2fs_has_feature_flex_bg(fs->super); |
617446e4 TT |
3991 | if (is_flexbg) { |
3992 | flexbg_size = 1 << fs->super->s_log_groups_per_flex; | |
3993 | flexbg = group / flexbg_size; | |
b49f78fe TT |
3994 | first_block = ext2fs_group_first_block2(fs, |
3995 | flexbg_size * flexbg); | |
617446e4 | 3996 | last_grp = group | (flexbg_size - 1); |
b4f724c8 DW |
3997 | if (last_grp >= fs->group_desc_count) |
3998 | last_grp = fs->group_desc_count - 1; | |
b49f78fe | 3999 | last_block = ext2fs_group_last_block2(fs, last_grp); |
617446e4 | 4000 | } else |
b49f78fe | 4001 | last_block = ext2fs_group_last_block2(fs, group); |
c5d2f50d VAH |
4002 | pctx.errcode = ext2fs_get_free_blocks2(fs, first_block, last_block, |
4003 | num, ctx->block_found_map, | |
4004 | new_block); | |
617446e4 | 4005 | if (is_flexbg && (pctx.errcode == EXT2_ET_BLOCK_ALLOC_FAIL)) |
c5d2f50d | 4006 | pctx.errcode = ext2fs_get_free_blocks2(fs, |
617446e4 | 4007 | fs->super->s_first_data_block, |
4efbac6f | 4008 | ext2fs_blocks_count(fs->super), |
617446e4 | 4009 | num, ctx->block_found_map, new_block); |
1b6bf175 TT |
4010 | if (pctx.errcode) { |
4011 | pctx.num = num; | |
4012 | fix_problem(ctx, PR_1_RELOC_BLOCK_ALLOCATE, &pctx); | |
3839e657 | 4013 | ext2fs_unmark_valid(fs); |
617446e4 | 4014 | ctx->flags |= E2F_FLAG_ABORT; |
3839e657 TT |
4015 | return; |
4016 | } | |
c4e3d3f3 | 4017 | pctx.errcode = ext2fs_get_mem(fs->blocksize, &buf); |
08b21301 | 4018 | if (pctx.errcode) { |
1b6bf175 | 4019 | fix_problem(ctx, PR_1_RELOC_MEMORY_ALLOCATE, &pctx); |
3839e657 | 4020 | ext2fs_unmark_valid(fs); |
617446e4 | 4021 | ctx->flags |= E2F_FLAG_ABORT; |
3839e657 TT |
4022 | return; |
4023 | } | |
4024 | ext2fs_mark_super_dirty(fs); | |
299d7424 | 4025 | fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; |
1b6bf175 TT |
4026 | pctx.blk2 = *new_block; |
4027 | fix_problem(ctx, (old_block ? PR_1_RELOC_FROM_TO : | |
4028 | PR_1_RELOC_TO), &pctx); | |
4029 | pctx.blk2 = 0; | |
3839e657 | 4030 | for (i = 0; i < num; i++) { |
1b6bf175 | 4031 | pctx.blk = i; |
c5d2f50d | 4032 | ext2fs_mark_block_bitmap2(ctx->block_found_map, (*new_block)+i); |
f3db3566 | 4033 | if (old_block) { |
24a117ab | 4034 | pctx.errcode = io_channel_read_blk64(fs->io, |
1b6bf175 TT |
4035 | old_block + i, 1, buf); |
4036 | if (pctx.errcode) | |
4037 | fix_problem(ctx, PR_1_RELOC_READ_ERR, &pctx); | |
08c8e319 DW |
4038 | pctx.blk = (*new_block) + i; |
4039 | pctx.errcode = io_channel_write_blk64(fs->io, pctx.blk, | |
4040 | 1, buf); | |
4041 | } else { | |
4042 | pctx.blk = (*new_block) + i; | |
4043 | pctx.errcode = ext2fs_zero_blocks2(fs, pctx.blk, 1, | |
4044 | NULL, NULL); | |
4045 | } | |
f3db3566 | 4046 | |
1b6bf175 TT |
4047 | if (pctx.errcode) |
4048 | fix_problem(ctx, PR_1_RELOC_WRITE_ERR, &pctx); | |
3839e657 | 4049 | } |
c4e3d3f3 | 4050 | ext2fs_free_mem(&buf); |
3839e657 TT |
4051 | } |
4052 | ||
4053 | /* | |
f3db3566 TT |
4054 | * This routine gets called at the end of pass 1 if bad blocks are |
4055 | * detected in the superblock, group descriptors, inode_bitmaps, or | |
4056 | * block bitmaps. At this point, all of the blocks have been mapped | |
4057 | * out, so we can try to allocate new block(s) to replace the bad | |
4058 | * blocks. | |
3839e657 | 4059 | */ |
1b6bf175 | 4060 | static void handle_fs_bad_blocks(e2fsck_t ctx) |
3839e657 | 4061 | { |
1b6bf175 | 4062 | ext2_filsys fs = ctx->fs; |
54434927 | 4063 | dgrp_t i; |
c5d2f50d VAH |
4064 | blk64_t first_block; |
4065 | blk64_t new_blk; | |
3839e657 TT |
4066 | |
4067 | for (i = 0; i < fs->group_desc_count; i++) { | |
b49f78fe | 4068 | first_block = ext2fs_group_first_block2(fs, i); |
abf23439 | 4069 | |
1b6bf175 | 4070 | if (ctx->invalid_block_bitmap_flag[i]) { |
c5d2f50d | 4071 | new_blk = ext2fs_block_bitmap_loc(fs, i); |
0c4a0726 | 4072 | new_table_block(ctx, first_block, i, _("block bitmap"), |
c5d2f50d VAH |
4073 | 1, &new_blk); |
4074 | ext2fs_block_bitmap_loc_set(fs, i, new_blk); | |
3839e657 | 4075 | } |
1b6bf175 | 4076 | if (ctx->invalid_inode_bitmap_flag[i]) { |
c5d2f50d | 4077 | new_blk = ext2fs_inode_bitmap_loc(fs, i); |
0c4a0726 | 4078 | new_table_block(ctx, first_block, i, _("inode bitmap"), |
c5d2f50d VAH |
4079 | 1, &new_blk); |
4080 | ext2fs_inode_bitmap_loc_set(fs, i, new_blk); | |
3839e657 | 4081 | } |
1b6bf175 | 4082 | if (ctx->invalid_inode_table_flag[i]) { |
c5d2f50d | 4083 | new_blk = ext2fs_inode_table_loc(fs, i); |
0c4a0726 | 4084 | new_table_block(ctx, first_block, i, _("inode table"), |
efc6f628 | 4085 | fs->inode_blocks_per_group, |
c5d2f50d VAH |
4086 | &new_blk); |
4087 | ext2fs_inode_table_loc_set(fs, i, new_blk); | |
08b21301 | 4088 | ctx->flags |= E2F_FLAG_RESTART; |
3839e657 | 4089 | } |
3839e657 | 4090 | } |
1b6bf175 | 4091 | ctx->invalid_bitmaps = 0; |
3839e657 TT |
4092 | } |
4093 | ||
4094 | /* | |
4095 | * This routine marks all blocks which are used by the superblock, | |
4096 | * group descriptors, inode bitmaps, and block bitmaps. | |
4097 | */ | |
1b6bf175 | 4098 | static void mark_table_blocks(e2fsck_t ctx) |
3839e657 | 4099 | { |
1b6bf175 | 4100 | ext2_filsys fs = ctx->fs; |
6dc64392 | 4101 | blk64_t b; |
54434927 | 4102 | dgrp_t i; |
68477355 | 4103 | unsigned int j; |
21c84b71 | 4104 | struct problem_context pctx; |
efc6f628 | 4105 | |
21c84b71 | 4106 | clear_problem_context(&pctx); |
efc6f628 | 4107 | |
3839e657 | 4108 | for (i = 0; i < fs->group_desc_count; i++) { |
21c84b71 | 4109 | pctx.group = i; |
da2e97f7 | 4110 | |
ef344e13 | 4111 | ext2fs_reserve_super_and_bgd(fs, i, ctx->block_found_map); |
35c8faaf | 4112 | ext2fs_reserve_super_and_bgd(fs, i, ctx->block_metadata_map); |
ef344e13 | 4113 | |
21c84b71 TT |
4114 | /* |
4115 | * Mark the blocks used for the inode table | |
4116 | */ | |
d7cca6b0 VAH |
4117 | if (ext2fs_inode_table_loc(fs, i)) { |
4118 | for (j = 0, b = ext2fs_inode_table_loc(fs, i); | |
21c84b71 TT |
4119 | j < fs->inode_blocks_per_group; |
4120 | j++, b++) { | |
c5d2f50d | 4121 | if (ext2fs_test_block_bitmap2(ctx->block_found_map, |
21c84b71 TT |
4122 | b)) { |
4123 | pctx.blk = b; | |
9a7fe4bd TT |
4124 | if (!ctx->invalid_inode_table_flag[i] && |
4125 | fix_problem(ctx, | |
21c84b71 | 4126 | PR_1_ITABLE_CONFLICT, &pctx)) { |
1b6bf175 TT |
4127 | ctx->invalid_inode_table_flag[i]++; |
4128 | ctx->invalid_bitmaps++; | |
21c84b71 TT |
4129 | } |
4130 | } else { | |
35c8faaf DW |
4131 | ext2fs_mark_block_bitmap2( |
4132 | ctx->block_found_map, b); | |
4133 | ext2fs_mark_block_bitmap2( | |
4134 | ctx->block_metadata_map, b); | |
21c84b71 TT |
4135 | } |
4136 | } | |
4137 | } | |
efc6f628 | 4138 | |
3839e657 | 4139 | /* |
efc6f628 | 4140 | * Mark block used for the block bitmap |
3839e657 | 4141 | */ |
d7cca6b0 | 4142 | if (ext2fs_block_bitmap_loc(fs, i)) { |
c5d2f50d | 4143 | if (ext2fs_test_block_bitmap2(ctx->block_found_map, |
d7cca6b0 VAH |
4144 | ext2fs_block_bitmap_loc(fs, i))) { |
4145 | pctx.blk = ext2fs_block_bitmap_loc(fs, i); | |
1b6bf175 TT |
4146 | if (fix_problem(ctx, PR_1_BB_CONFLICT, &pctx)) { |
4147 | ctx->invalid_block_bitmap_flag[i]++; | |
4148 | ctx->invalid_bitmaps++; | |
f3db3566 | 4149 | } |
50e1e10f | 4150 | } else { |
c5d2f50d | 4151 | ext2fs_mark_block_bitmap2(ctx->block_found_map, |
d7cca6b0 | 4152 | ext2fs_block_bitmap_loc(fs, i)); |
35c8faaf DW |
4153 | ext2fs_mark_block_bitmap2(ctx->block_metadata_map, |
4154 | ext2fs_block_bitmap_loc(fs, i)); | |
4155 | } | |
f3db3566 | 4156 | } |
3839e657 | 4157 | /* |
efc6f628 | 4158 | * Mark block used for the inode bitmap |
3839e657 | 4159 | */ |
d7cca6b0 | 4160 | if (ext2fs_inode_bitmap_loc(fs, i)) { |
c5d2f50d | 4161 | if (ext2fs_test_block_bitmap2(ctx->block_found_map, |
d7cca6b0 VAH |
4162 | ext2fs_inode_bitmap_loc(fs, i))) { |
4163 | pctx.blk = ext2fs_inode_bitmap_loc(fs, i); | |
1b6bf175 TT |
4164 | if (fix_problem(ctx, PR_1_IB_CONFLICT, &pctx)) { |
4165 | ctx->invalid_inode_bitmap_flag[i]++; | |
4166 | ctx->invalid_bitmaps++; | |
efc6f628 | 4167 | } |
50e1e10f | 4168 | } else { |
35c8faaf DW |
4169 | ext2fs_mark_block_bitmap2(ctx->block_metadata_map, |
4170 | ext2fs_inode_bitmap_loc(fs, i)); | |
c5d2f50d | 4171 | ext2fs_mark_block_bitmap2(ctx->block_found_map, |
d7cca6b0 | 4172 | ext2fs_inode_bitmap_loc(fs, i)); |
50e1e10f | 4173 | } |
f3db3566 | 4174 | } |
3839e657 TT |
4175 | } |
4176 | } | |
efc6f628 | 4177 | |
3839e657 | 4178 | /* |
055866d8 | 4179 | * These subroutines short circuits ext2fs_get_blocks and |
3839e657 TT |
4180 | * ext2fs_check_directory; we use them since we already have the inode |
4181 | * structure, so there's no point in letting the ext2fs library read | |
4182 | * the inode again. | |
4183 | */ | |
86c627ec TT |
4184 | static errcode_t pass1_get_blocks(ext2_filsys fs, ext2_ino_t ino, |
4185 | blk_t *blocks) | |
3839e657 | 4186 | { |
54dc7ca2 | 4187 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
3839e657 | 4188 | int i; |
efc6f628 | 4189 | |
71d521c6 | 4190 | if ((ino != ctx->stashed_ino) || !ctx->stashed_inode) |
521e3685 TT |
4191 | return EXT2_ET_CALLBACK_NOTHANDLED; |
4192 | ||
4193 | for (i=0; i < EXT2_N_BLOCKS; i++) | |
1b6bf175 | 4194 | blocks[i] = ctx->stashed_inode->i_block[i]; |
521e3685 | 4195 | return 0; |
3839e657 TT |
4196 | } |
4197 | ||
86c627ec | 4198 | static errcode_t pass1_read_inode(ext2_filsys fs, ext2_ino_t ino, |
e72a9ba3 | 4199 | struct ext2_inode *inode) |
1e3472c5 | 4200 | { |
54dc7ca2 | 4201 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
1b6bf175 | 4202 | |
71d521c6 | 4203 | if ((ino != ctx->stashed_ino) || !ctx->stashed_inode) |
1e3472c5 | 4204 | return EXT2_ET_CALLBACK_NOTHANDLED; |
1b6bf175 | 4205 | *inode = *ctx->stashed_inode; |
1e3472c5 TT |
4206 | return 0; |
4207 | } | |
4208 | ||
86c627ec | 4209 | static errcode_t pass1_write_inode(ext2_filsys fs, ext2_ino_t ino, |
1e3472c5 TT |
4210 | struct ext2_inode *inode) |
4211 | { | |
54dc7ca2 | 4212 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
1b6bf175 | 4213 | |
27431595 TT |
4214 | if ((ino == ctx->stashed_ino) && ctx->stashed_inode && |
4215 | (inode != ctx->stashed_inode)) | |
1b6bf175 | 4216 | *ctx->stashed_inode = *inode; |
1e3472c5 TT |
4217 | return EXT2_ET_CALLBACK_NOTHANDLED; |
4218 | } | |
4219 | ||
86c627ec | 4220 | static errcode_t pass1_check_directory(ext2_filsys fs, ext2_ino_t ino) |
3839e657 | 4221 | { |
54dc7ca2 | 4222 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; |
1b6bf175 | 4223 | |
71d521c6 | 4224 | if ((ino != ctx->stashed_ino) || !ctx->stashed_inode) |
1b6bf175 TT |
4225 | return EXT2_ET_CALLBACK_NOTHANDLED; |
4226 | ||
4227 | if (!LINUX_S_ISDIR(ctx->stashed_inode->i_mode)) | |
291c9049 | 4228 | return EXT2_ET_NO_DIRECTORY; |
1b6bf175 | 4229 | return 0; |
3839e657 | 4230 | } |
e72a9ba3 | 4231 | |
16bd349e TT |
4232 | static errcode_t e2fsck_get_alloc_block(ext2_filsys fs, blk64_t goal, |
4233 | blk64_t *ret) | |
4234 | { | |
4235 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; | |
4236 | errcode_t retval; | |
c5d2f50d | 4237 | blk64_t new_block; |
16bd349e TT |
4238 | |
4239 | if (ctx->block_found_map) { | |
28843200 TT |
4240 | retval = ext2fs_new_block2(fs, goal, ctx->block_found_map, |
4241 | &new_block); | |
16bd349e TT |
4242 | if (retval) |
4243 | return retval; | |
8a2cbe2c | 4244 | if (fs->block_map) { |
2d07b3ad | 4245 | ext2fs_mark_block_bitmap2(fs->block_map, new_block); |
8a2cbe2c TT |
4246 | ext2fs_mark_bb_dirty(fs); |
4247 | } | |
16bd349e TT |
4248 | } else { |
4249 | if (!fs->block_map) { | |
4250 | retval = ext2fs_read_block_bitmap(fs); | |
4251 | if (retval) | |
4252 | return retval; | |
4253 | } | |
4254 | ||
fae2467f | 4255 | retval = ext2fs_new_block2(fs, goal, fs->block_map, &new_block); |
16bd349e TT |
4256 | if (retval) |
4257 | return retval; | |
4258 | } | |
efc6f628 | 4259 | |
16bd349e TT |
4260 | *ret = new_block; |
4261 | return (0); | |
4262 | } | |
4263 | ||
647e8786 DW |
4264 | static errcode_t e2fsck_new_range(ext2_filsys fs, int flags, blk64_t goal, |
4265 | blk64_t len, blk64_t *pblk, blk64_t *plen) | |
4266 | { | |
4267 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; | |
4268 | errcode_t retval; | |
4269 | ||
4270 | if (ctx->block_found_map) | |
4271 | return ext2fs_new_range(fs, flags, goal, len, | |
4272 | ctx->block_found_map, pblk, plen); | |
4273 | ||
4274 | if (!fs->block_map) { | |
4275 | retval = ext2fs_read_block_bitmap(fs); | |
4276 | if (retval) | |
4277 | return retval; | |
4278 | } | |
4279 | ||
4280 | return ext2fs_new_range(fs, flags, goal, len, fs->block_map, | |
4281 | pblk, plen); | |
4282 | } | |
4283 | ||
16bd349e TT |
4284 | static void e2fsck_block_alloc_stats(ext2_filsys fs, blk64_t blk, int inuse) |
4285 | { | |
4286 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; | |
4287 | ||
409f3884 DW |
4288 | /* Never free a critical metadata block */ |
4289 | if (ctx->block_found_map && | |
4290 | ctx->block_metadata_map && | |
4291 | inuse < 0 && | |
4292 | ext2fs_test_block_bitmap2(ctx->block_metadata_map, blk)) | |
4293 | return; | |
4294 | ||
16bd349e TT |
4295 | if (ctx->block_found_map) { |
4296 | if (inuse > 0) | |
28843200 | 4297 | ext2fs_mark_block_bitmap2(ctx->block_found_map, blk); |
16bd349e | 4298 | else |
28843200 | 4299 | ext2fs_unmark_block_bitmap2(ctx->block_found_map, blk); |
16bd349e TT |
4300 | } |
4301 | } | |
4302 | ||
647e8786 DW |
4303 | static void e2fsck_block_alloc_stats_range(ext2_filsys fs, blk64_t blk, |
4304 | blk_t num, int inuse) | |
4305 | { | |
4306 | e2fsck_t ctx = (e2fsck_t) fs->priv_data; | |
4307 | ||
4308 | /* Never free a critical metadata block */ | |
4309 | if (ctx->block_found_map && | |
4310 | ctx->block_metadata_map && | |
4311 | inuse < 0 && | |
4312 | ext2fs_test_block_bitmap_range2(ctx->block_metadata_map, blk, num)) | |
4313 | return; | |
4314 | ||
4315 | if (ctx->block_found_map) { | |
4316 | if (inuse > 0) | |
4317 | ext2fs_mark_block_bitmap_range2(ctx->block_found_map, | |
4318 | blk, num); | |
4319 | else | |
4320 | ext2fs_unmark_block_bitmap_range2(ctx->block_found_map, | |
4321 | blk, num); | |
4322 | } | |
4323 | } | |
4324 | ||
2d2abcc6 | 4325 | void e2fsck_use_inode_shortcuts(e2fsck_t ctx, int use_shortcuts) |
e72a9ba3 TT |
4326 | { |
4327 | ext2_filsys fs = ctx->fs; | |
4328 | ||
2d2abcc6 | 4329 | if (use_shortcuts) { |
e72a9ba3 TT |
4330 | fs->get_blocks = pass1_get_blocks; |
4331 | fs->check_directory = pass1_check_directory; | |
4332 | fs->read_inode = pass1_read_inode; | |
4333 | fs->write_inode = pass1_write_inode; | |
4334 | ctx->stashed_ino = 0; | |
4335 | } else { | |
4336 | fs->get_blocks = 0; | |
4337 | fs->check_directory = 0; | |
4338 | fs->read_inode = 0; | |
4339 | fs->write_inode = 0; | |
4340 | } | |
4341 | } | |
b4a40883 DW |
4342 | |
4343 | void e2fsck_intercept_block_allocations(e2fsck_t ctx) | |
4344 | { | |
4345 | ext2fs_set_alloc_block_callback(ctx->fs, e2fsck_get_alloc_block, 0); | |
4346 | ext2fs_set_block_alloc_stats_callback(ctx->fs, | |
4347 | e2fsck_block_alloc_stats, 0); | |
647e8786 DW |
4348 | ext2fs_set_new_range_callback(ctx->fs, e2fsck_new_range, NULL); |
4349 | ext2fs_set_block_alloc_stats_range_callback(ctx->fs, | |
4350 | e2fsck_block_alloc_stats_range, NULL); | |
b4a40883 | 4351 | } |