1*6a54128fSAndroid Build Coastguard Worker /*
2*6a54128fSAndroid Build Coastguard Worker * extents.c --- rebuild extent tree
3*6a54128fSAndroid Build Coastguard Worker *
4*6a54128fSAndroid Build Coastguard Worker * Copyright (C) 2014 Oracle.
5*6a54128fSAndroid Build Coastguard Worker *
6*6a54128fSAndroid Build Coastguard Worker * %Begin-Header%
7*6a54128fSAndroid Build Coastguard Worker * This file may be redistributed under the terms of the GNU Public
8*6a54128fSAndroid Build Coastguard Worker * License, version 2.
9*6a54128fSAndroid Build Coastguard Worker * %End-Header%
10*6a54128fSAndroid Build Coastguard Worker */
11*6a54128fSAndroid Build Coastguard Worker
12*6a54128fSAndroid Build Coastguard Worker #include "config.h"
13*6a54128fSAndroid Build Coastguard Worker #include <string.h>
14*6a54128fSAndroid Build Coastguard Worker #include <ctype.h>
15*6a54128fSAndroid Build Coastguard Worker #include <errno.h>
16*6a54128fSAndroid Build Coastguard Worker #include "e2fsck.h"
17*6a54128fSAndroid Build Coastguard Worker #include "problem.h"
18*6a54128fSAndroid Build Coastguard Worker
19*6a54128fSAndroid Build Coastguard Worker #undef DEBUG
20*6a54128fSAndroid Build Coastguard Worker #undef DEBUG_SUMMARY
21*6a54128fSAndroid Build Coastguard Worker #undef DEBUG_FREE
22*6a54128fSAndroid Build Coastguard Worker
23*6a54128fSAndroid Build Coastguard Worker #define NUM_EXTENTS 341 /* about one ETB' worth of extents */
24*6a54128fSAndroid Build Coastguard Worker
25*6a54128fSAndroid Build Coastguard Worker static errcode_t e2fsck_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino);
26*6a54128fSAndroid Build Coastguard Worker
27*6a54128fSAndroid Build Coastguard Worker /* Schedule an inode to have its extent tree rebuilt during pass 1E. */
e2fsck_rebuild_extents_later(e2fsck_t ctx,ext2_ino_t ino)28*6a54128fSAndroid Build Coastguard Worker errcode_t e2fsck_rebuild_extents_later(e2fsck_t ctx, ext2_ino_t ino)
29*6a54128fSAndroid Build Coastguard Worker {
30*6a54128fSAndroid Build Coastguard Worker errcode_t retval = 0;
31*6a54128fSAndroid Build Coastguard Worker
32*6a54128fSAndroid Build Coastguard Worker if (!ext2fs_has_feature_extents(ctx->fs->super) ||
33*6a54128fSAndroid Build Coastguard Worker (ctx->options & E2F_OPT_NO) ||
34*6a54128fSAndroid Build Coastguard Worker (ino != EXT2_ROOT_INO && ino < ctx->fs->super->s_first_ino))
35*6a54128fSAndroid Build Coastguard Worker return 0;
36*6a54128fSAndroid Build Coastguard Worker
37*6a54128fSAndroid Build Coastguard Worker if (ctx->flags & E2F_FLAG_ALLOC_OK)
38*6a54128fSAndroid Build Coastguard Worker return e2fsck_rebuild_extents(ctx, ino);
39*6a54128fSAndroid Build Coastguard Worker
40*6a54128fSAndroid Build Coastguard Worker if (!ctx->inodes_to_rebuild)
41*6a54128fSAndroid Build Coastguard Worker retval = e2fsck_allocate_inode_bitmap(ctx->fs,
42*6a54128fSAndroid Build Coastguard Worker _("extent rebuild inode map"),
43*6a54128fSAndroid Build Coastguard Worker EXT2FS_BMAP64_RBTREE,
44*6a54128fSAndroid Build Coastguard Worker "inodes_to_rebuild",
45*6a54128fSAndroid Build Coastguard Worker &ctx->inodes_to_rebuild);
46*6a54128fSAndroid Build Coastguard Worker if (retval)
47*6a54128fSAndroid Build Coastguard Worker return retval;
48*6a54128fSAndroid Build Coastguard Worker
49*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_inode_bitmap2(ctx->inodes_to_rebuild, ino);
50*6a54128fSAndroid Build Coastguard Worker return 0;
51*6a54128fSAndroid Build Coastguard Worker }
52*6a54128fSAndroid Build Coastguard Worker
53*6a54128fSAndroid Build Coastguard Worker /* Ask if an inode will have its extents rebuilt during pass 1E. */
e2fsck_ino_will_be_rebuilt(e2fsck_t ctx,ext2_ino_t ino)54*6a54128fSAndroid Build Coastguard Worker int e2fsck_ino_will_be_rebuilt(e2fsck_t ctx, ext2_ino_t ino)
55*6a54128fSAndroid Build Coastguard Worker {
56*6a54128fSAndroid Build Coastguard Worker if (!ctx->inodes_to_rebuild)
57*6a54128fSAndroid Build Coastguard Worker return 0;
58*6a54128fSAndroid Build Coastguard Worker return ext2fs_test_inode_bitmap2(ctx->inodes_to_rebuild, ino);
59*6a54128fSAndroid Build Coastguard Worker }
60*6a54128fSAndroid Build Coastguard Worker
load_extents(e2fsck_t ctx,struct extent_list * list)61*6a54128fSAndroid Build Coastguard Worker static errcode_t load_extents(e2fsck_t ctx, struct extent_list *list)
62*6a54128fSAndroid Build Coastguard Worker {
63*6a54128fSAndroid Build Coastguard Worker ext2_filsys fs = ctx->fs;
64*6a54128fSAndroid Build Coastguard Worker ext2_extent_handle_t handle;
65*6a54128fSAndroid Build Coastguard Worker struct ext2fs_extent extent;
66*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
67*6a54128fSAndroid Build Coastguard Worker
68*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_extent_open(fs, list->ino, &handle);
69*6a54128fSAndroid Build Coastguard Worker if (retval)
70*6a54128fSAndroid Build Coastguard Worker return retval;
71*6a54128fSAndroid Build Coastguard Worker
72*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent);
73*6a54128fSAndroid Build Coastguard Worker if (retval)
74*6a54128fSAndroid Build Coastguard Worker goto out;
75*6a54128fSAndroid Build Coastguard Worker
76*6a54128fSAndroid Build Coastguard Worker do {
77*6a54128fSAndroid Build Coastguard Worker if (extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
78*6a54128fSAndroid Build Coastguard Worker goto next;
79*6a54128fSAndroid Build Coastguard Worker
80*6a54128fSAndroid Build Coastguard Worker /* Internal node; free it and we'll re-allocate it later */
81*6a54128fSAndroid Build Coastguard Worker if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) {
82*6a54128fSAndroid Build Coastguard Worker #if defined(DEBUG) || defined(DEBUG_FREE)
83*6a54128fSAndroid Build Coastguard Worker printf("ino=%d free=%llu bf=%llu\n", list->ino,
84*6a54128fSAndroid Build Coastguard Worker extent.e_pblk, list->blocks_freed + 1);
85*6a54128fSAndroid Build Coastguard Worker #endif
86*6a54128fSAndroid Build Coastguard Worker list->blocks_freed++;
87*6a54128fSAndroid Build Coastguard Worker ext2fs_block_alloc_stats2(fs, extent.e_pblk, -1);
88*6a54128fSAndroid Build Coastguard Worker goto next;
89*6a54128fSAndroid Build Coastguard Worker }
90*6a54128fSAndroid Build Coastguard Worker
91*6a54128fSAndroid Build Coastguard Worker list->ext_read++;
92*6a54128fSAndroid Build Coastguard Worker /* Can we attach it to the previous extent? */
93*6a54128fSAndroid Build Coastguard Worker if (list->count) {
94*6a54128fSAndroid Build Coastguard Worker struct ext2fs_extent *last = list->extents +
95*6a54128fSAndroid Build Coastguard Worker list->count - 1;
96*6a54128fSAndroid Build Coastguard Worker blk64_t end = last->e_len + extent.e_len;
97*6a54128fSAndroid Build Coastguard Worker
98*6a54128fSAndroid Build Coastguard Worker if (last->e_pblk + last->e_len == extent.e_pblk &&
99*6a54128fSAndroid Build Coastguard Worker last->e_lblk + last->e_len == extent.e_lblk &&
100*6a54128fSAndroid Build Coastguard Worker (last->e_flags & EXT2_EXTENT_FLAGS_UNINIT) ==
101*6a54128fSAndroid Build Coastguard Worker (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
102*6a54128fSAndroid Build Coastguard Worker end < (1ULL << 32)) {
103*6a54128fSAndroid Build Coastguard Worker last->e_len += extent.e_len;
104*6a54128fSAndroid Build Coastguard Worker #ifdef DEBUG
105*6a54128fSAndroid Build Coastguard Worker printf("R: ino=%d len=%u\n", list->ino,
106*6a54128fSAndroid Build Coastguard Worker last->e_len);
107*6a54128fSAndroid Build Coastguard Worker #endif
108*6a54128fSAndroid Build Coastguard Worker goto next;
109*6a54128fSAndroid Build Coastguard Worker }
110*6a54128fSAndroid Build Coastguard Worker }
111*6a54128fSAndroid Build Coastguard Worker
112*6a54128fSAndroid Build Coastguard Worker /* Do we need to expand? */
113*6a54128fSAndroid Build Coastguard Worker if (list->count == list->size) {
114*6a54128fSAndroid Build Coastguard Worker unsigned int new_size = (list->size + NUM_EXTENTS) *
115*6a54128fSAndroid Build Coastguard Worker sizeof(struct ext2fs_extent);
116*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_resize_mem(0, new_size, &list->extents);
117*6a54128fSAndroid Build Coastguard Worker if (retval)
118*6a54128fSAndroid Build Coastguard Worker goto out;
119*6a54128fSAndroid Build Coastguard Worker list->size += NUM_EXTENTS;
120*6a54128fSAndroid Build Coastguard Worker }
121*6a54128fSAndroid Build Coastguard Worker
122*6a54128fSAndroid Build Coastguard Worker /* Add a new extent */
123*6a54128fSAndroid Build Coastguard Worker memcpy(list->extents + list->count, &extent, sizeof(extent));
124*6a54128fSAndroid Build Coastguard Worker #ifdef DEBUG
125*6a54128fSAndroid Build Coastguard Worker printf("R: ino=%d pblk=%llu lblk=%llu len=%u\n", list->ino,
126*6a54128fSAndroid Build Coastguard Worker extent.e_pblk, extent.e_lblk, extent.e_len);
127*6a54128fSAndroid Build Coastguard Worker #endif
128*6a54128fSAndroid Build Coastguard Worker list->count++;
129*6a54128fSAndroid Build Coastguard Worker next:
130*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT, &extent);
131*6a54128fSAndroid Build Coastguard Worker } while (retval == 0);
132*6a54128fSAndroid Build Coastguard Worker
133*6a54128fSAndroid Build Coastguard Worker out:
134*6a54128fSAndroid Build Coastguard Worker /* Ok if we run off the end */
135*6a54128fSAndroid Build Coastguard Worker if (retval == EXT2_ET_EXTENT_NO_NEXT)
136*6a54128fSAndroid Build Coastguard Worker retval = 0;
137*6a54128fSAndroid Build Coastguard Worker ext2fs_extent_free(handle);
138*6a54128fSAndroid Build Coastguard Worker return retval;
139*6a54128fSAndroid Build Coastguard Worker }
140*6a54128fSAndroid Build Coastguard Worker
find_blocks(ext2_filsys fs,blk64_t * blocknr,e2_blkcnt_t blockcnt,blk64_t ref_blk EXT2FS_ATTR ((unused)),int ref_offset EXT2FS_ATTR ((unused)),void * priv_data)141*6a54128fSAndroid Build Coastguard Worker static int find_blocks(ext2_filsys fs, blk64_t *blocknr, e2_blkcnt_t blockcnt,
142*6a54128fSAndroid Build Coastguard Worker blk64_t ref_blk EXT2FS_ATTR((unused)),
143*6a54128fSAndroid Build Coastguard Worker int ref_offset EXT2FS_ATTR((unused)), void *priv_data)
144*6a54128fSAndroid Build Coastguard Worker {
145*6a54128fSAndroid Build Coastguard Worker struct extent_list *list = priv_data;
146*6a54128fSAndroid Build Coastguard Worker
147*6a54128fSAndroid Build Coastguard Worker /* Internal node? */
148*6a54128fSAndroid Build Coastguard Worker if (blockcnt < 0) {
149*6a54128fSAndroid Build Coastguard Worker #if defined(DEBUG) || defined(DEBUG_FREE)
150*6a54128fSAndroid Build Coastguard Worker printf("ino=%d free=%llu bf=%llu\n", list->ino, *blocknr,
151*6a54128fSAndroid Build Coastguard Worker list->blocks_freed + 1);
152*6a54128fSAndroid Build Coastguard Worker #endif
153*6a54128fSAndroid Build Coastguard Worker list->blocks_freed++;
154*6a54128fSAndroid Build Coastguard Worker ext2fs_block_alloc_stats2(fs, *blocknr, -1);
155*6a54128fSAndroid Build Coastguard Worker return 0;
156*6a54128fSAndroid Build Coastguard Worker }
157*6a54128fSAndroid Build Coastguard Worker
158*6a54128fSAndroid Build Coastguard Worker /* Can we attach it to the previous extent? */
159*6a54128fSAndroid Build Coastguard Worker if (list->count) {
160*6a54128fSAndroid Build Coastguard Worker struct ext2fs_extent *last = list->extents +
161*6a54128fSAndroid Build Coastguard Worker list->count - 1;
162*6a54128fSAndroid Build Coastguard Worker blk64_t end = last->e_len + 1;
163*6a54128fSAndroid Build Coastguard Worker
164*6a54128fSAndroid Build Coastguard Worker if (last->e_lblk + last->e_len == (__u64) blockcnt &&
165*6a54128fSAndroid Build Coastguard Worker last->e_pblk + last->e_len == *blocknr &&
166*6a54128fSAndroid Build Coastguard Worker end < (1ULL << 32)) {
167*6a54128fSAndroid Build Coastguard Worker last->e_len++;
168*6a54128fSAndroid Build Coastguard Worker #ifdef DEBUG
169*6a54128fSAndroid Build Coastguard Worker printf("R: ino=%d len=%u\n", list->ino, last->e_len);
170*6a54128fSAndroid Build Coastguard Worker #endif
171*6a54128fSAndroid Build Coastguard Worker return 0;
172*6a54128fSAndroid Build Coastguard Worker }
173*6a54128fSAndroid Build Coastguard Worker }
174*6a54128fSAndroid Build Coastguard Worker
175*6a54128fSAndroid Build Coastguard Worker /* Do we need to expand? */
176*6a54128fSAndroid Build Coastguard Worker if (list->count == list->size) {
177*6a54128fSAndroid Build Coastguard Worker unsigned int new_size = (list->size + NUM_EXTENTS) *
178*6a54128fSAndroid Build Coastguard Worker sizeof(struct ext2fs_extent);
179*6a54128fSAndroid Build Coastguard Worker list->retval = ext2fs_resize_mem(0, new_size, &list->extents);
180*6a54128fSAndroid Build Coastguard Worker if (list->retval)
181*6a54128fSAndroid Build Coastguard Worker return BLOCK_ABORT;
182*6a54128fSAndroid Build Coastguard Worker list->size += NUM_EXTENTS;
183*6a54128fSAndroid Build Coastguard Worker }
184*6a54128fSAndroid Build Coastguard Worker
185*6a54128fSAndroid Build Coastguard Worker /* Add a new extent */
186*6a54128fSAndroid Build Coastguard Worker list->extents[list->count].e_pblk = *blocknr;
187*6a54128fSAndroid Build Coastguard Worker list->extents[list->count].e_lblk = blockcnt;
188*6a54128fSAndroid Build Coastguard Worker list->extents[list->count].e_len = 1;
189*6a54128fSAndroid Build Coastguard Worker list->extents[list->count].e_flags = 0;
190*6a54128fSAndroid Build Coastguard Worker #ifdef DEBUG
191*6a54128fSAndroid Build Coastguard Worker printf("R: ino=%d pblk=%llu lblk=%llu len=%u\n", list->ino, *blocknr,
192*6a54128fSAndroid Build Coastguard Worker blockcnt, 1);
193*6a54128fSAndroid Build Coastguard Worker #endif
194*6a54128fSAndroid Build Coastguard Worker list->count++;
195*6a54128fSAndroid Build Coastguard Worker
196*6a54128fSAndroid Build Coastguard Worker return 0;
197*6a54128fSAndroid Build Coastguard Worker }
198*6a54128fSAndroid Build Coastguard Worker
rewrite_extent_replay(e2fsck_t ctx,struct extent_list * list,struct ext2_inode_large * inode)199*6a54128fSAndroid Build Coastguard Worker static errcode_t rewrite_extent_replay(e2fsck_t ctx, struct extent_list *list,
200*6a54128fSAndroid Build Coastguard Worker struct ext2_inode_large *inode)
201*6a54128fSAndroid Build Coastguard Worker {
202*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
203*6a54128fSAndroid Build Coastguard Worker ext2_extent_handle_t handle;
204*6a54128fSAndroid Build Coastguard Worker unsigned int i, ext_written;
205*6a54128fSAndroid Build Coastguard Worker struct ext2fs_extent *ex, extent;
206*6a54128fSAndroid Build Coastguard Worker blk64_t start_val, delta;
207*6a54128fSAndroid Build Coastguard Worker
208*6a54128fSAndroid Build Coastguard Worker /* Reset extent tree */
209*6a54128fSAndroid Build Coastguard Worker inode->i_flags &= ~EXT4_EXTENTS_FL;
210*6a54128fSAndroid Build Coastguard Worker memset(inode->i_block, 0, sizeof(inode->i_block));
211*6a54128fSAndroid Build Coastguard Worker
212*6a54128fSAndroid Build Coastguard Worker /* Make a note of freed blocks */
213*6a54128fSAndroid Build Coastguard Worker quota_data_sub(ctx->qctx, inode, list->ino,
214*6a54128fSAndroid Build Coastguard Worker list->blocks_freed * ctx->fs->blocksize);
215*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_iblk_sub_blocks(ctx->fs, EXT2_INODE(inode),
216*6a54128fSAndroid Build Coastguard Worker list->blocks_freed);
217*6a54128fSAndroid Build Coastguard Worker if (retval)
218*6a54128fSAndroid Build Coastguard Worker return retval;
219*6a54128fSAndroid Build Coastguard Worker
220*6a54128fSAndroid Build Coastguard Worker /* Now stuff extents into the file */
221*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_extent_open2(ctx->fs, list->ino, EXT2_INODE(inode),
222*6a54128fSAndroid Build Coastguard Worker &handle);
223*6a54128fSAndroid Build Coastguard Worker if (retval)
224*6a54128fSAndroid Build Coastguard Worker return retval;
225*6a54128fSAndroid Build Coastguard Worker
226*6a54128fSAndroid Build Coastguard Worker ext_written = 0;
227*6a54128fSAndroid Build Coastguard Worker
228*6a54128fSAndroid Build Coastguard Worker start_val = ext2fs_get_stat_i_blocks(ctx->fs, EXT2_INODE(inode));
229*6a54128fSAndroid Build Coastguard Worker
230*6a54128fSAndroid Build Coastguard Worker for (i = 0, ex = list->extents; i < list->count; i++, ex++) {
231*6a54128fSAndroid Build Coastguard Worker if (ex->e_len == 0)
232*6a54128fSAndroid Build Coastguard Worker continue;
233*6a54128fSAndroid Build Coastguard Worker memcpy(&extent, ex, sizeof(struct ext2fs_extent));
234*6a54128fSAndroid Build Coastguard Worker extent.e_flags &= EXT2_EXTENT_FLAGS_UNINIT;
235*6a54128fSAndroid Build Coastguard Worker if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT) {
236*6a54128fSAndroid Build Coastguard Worker if (extent.e_len > EXT_UNINIT_MAX_LEN) {
237*6a54128fSAndroid Build Coastguard Worker extent.e_len = EXT_UNINIT_MAX_LEN;
238*6a54128fSAndroid Build Coastguard Worker ex->e_pblk += EXT_UNINIT_MAX_LEN;
239*6a54128fSAndroid Build Coastguard Worker ex->e_lblk += EXT_UNINIT_MAX_LEN;
240*6a54128fSAndroid Build Coastguard Worker ex->e_len -= EXT_UNINIT_MAX_LEN;
241*6a54128fSAndroid Build Coastguard Worker ex--;
242*6a54128fSAndroid Build Coastguard Worker i--;
243*6a54128fSAndroid Build Coastguard Worker }
244*6a54128fSAndroid Build Coastguard Worker } else {
245*6a54128fSAndroid Build Coastguard Worker if (extent.e_len > EXT_INIT_MAX_LEN) {
246*6a54128fSAndroid Build Coastguard Worker extent.e_len = EXT_INIT_MAX_LEN;
247*6a54128fSAndroid Build Coastguard Worker ex->e_pblk += EXT_INIT_MAX_LEN;
248*6a54128fSAndroid Build Coastguard Worker ex->e_lblk += EXT_INIT_MAX_LEN;
249*6a54128fSAndroid Build Coastguard Worker ex->e_len -= EXT_INIT_MAX_LEN;
250*6a54128fSAndroid Build Coastguard Worker ex--;
251*6a54128fSAndroid Build Coastguard Worker i--;
252*6a54128fSAndroid Build Coastguard Worker }
253*6a54128fSAndroid Build Coastguard Worker }
254*6a54128fSAndroid Build Coastguard Worker
255*6a54128fSAndroid Build Coastguard Worker #ifdef DEBUG
256*6a54128fSAndroid Build Coastguard Worker printf("W: ino=%d pblk=%llu lblk=%llu len=%u\n", list->ino,
257*6a54128fSAndroid Build Coastguard Worker extent.e_pblk, extent.e_lblk, extent.e_len);
258*6a54128fSAndroid Build Coastguard Worker #endif
259*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_extent_insert(handle, EXT2_EXTENT_INSERT_AFTER,
260*6a54128fSAndroid Build Coastguard Worker &extent);
261*6a54128fSAndroid Build Coastguard Worker if (retval)
262*6a54128fSAndroid Build Coastguard Worker goto err;
263*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_extent_fix_parents(handle);
264*6a54128fSAndroid Build Coastguard Worker if (retval)
265*6a54128fSAndroid Build Coastguard Worker goto err;
266*6a54128fSAndroid Build Coastguard Worker ext_written++;
267*6a54128fSAndroid Build Coastguard Worker }
268*6a54128fSAndroid Build Coastguard Worker
269*6a54128fSAndroid Build Coastguard Worker delta = ext2fs_get_stat_i_blocks(ctx->fs, EXT2_INODE(inode)) -
270*6a54128fSAndroid Build Coastguard Worker start_val;
271*6a54128fSAndroid Build Coastguard Worker if (delta)
272*6a54128fSAndroid Build Coastguard Worker quota_data_add(ctx->qctx, inode, list->ino, delta << 9);
273*6a54128fSAndroid Build Coastguard Worker
274*6a54128fSAndroid Build Coastguard Worker #if defined(DEBUG) || defined(DEBUG_SUMMARY)
275*6a54128fSAndroid Build Coastguard Worker printf("rebuild: ino=%d extents=%d->%d\n", ino, list->ext_read,
276*6a54128fSAndroid Build Coastguard Worker ext_written);
277*6a54128fSAndroid Build Coastguard Worker #endif
278*6a54128fSAndroid Build Coastguard Worker e2fsck_write_inode(ctx, list->ino, EXT2_INODE(inode),
279*6a54128fSAndroid Build Coastguard Worker "rebuild_extents");
280*6a54128fSAndroid Build Coastguard Worker
281*6a54128fSAndroid Build Coastguard Worker err:
282*6a54128fSAndroid Build Coastguard Worker ext2fs_extent_free(handle);
283*6a54128fSAndroid Build Coastguard Worker return retval;
284*6a54128fSAndroid Build Coastguard Worker }
285*6a54128fSAndroid Build Coastguard Worker
e2fsck_rewrite_extent_tree(e2fsck_t ctx,struct extent_list * list)286*6a54128fSAndroid Build Coastguard Worker errcode_t e2fsck_rewrite_extent_tree(e2fsck_t ctx, struct extent_list *list)
287*6a54128fSAndroid Build Coastguard Worker {
288*6a54128fSAndroid Build Coastguard Worker struct ext2_inode_large inode;
289*6a54128fSAndroid Build Coastguard Worker blk64_t blk_count;
290*6a54128fSAndroid Build Coastguard Worker errcode_t err;
291*6a54128fSAndroid Build Coastguard Worker
292*6a54128fSAndroid Build Coastguard Worker memset(&inode, 0, sizeof(inode));
293*6a54128fSAndroid Build Coastguard Worker err = ext2fs_read_inode_full(ctx->fs, list->ino, EXT2_INODE(&inode),
294*6a54128fSAndroid Build Coastguard Worker sizeof(inode));
295*6a54128fSAndroid Build Coastguard Worker if (err)
296*6a54128fSAndroid Build Coastguard Worker return err;
297*6a54128fSAndroid Build Coastguard Worker
298*6a54128fSAndroid Build Coastguard Worker /* Skip deleted inodes and inline data files */
299*6a54128fSAndroid Build Coastguard Worker if (inode.i_flags & EXT4_INLINE_DATA_FL)
300*6a54128fSAndroid Build Coastguard Worker return 0;
301*6a54128fSAndroid Build Coastguard Worker
302*6a54128fSAndroid Build Coastguard Worker err = rewrite_extent_replay(ctx, list, &inode);
303*6a54128fSAndroid Build Coastguard Worker if (err)
304*6a54128fSAndroid Build Coastguard Worker return err;
305*6a54128fSAndroid Build Coastguard Worker
306*6a54128fSAndroid Build Coastguard Worker err = ext2fs_count_blocks(ctx->fs, list->ino, EXT2_INODE(&inode),
307*6a54128fSAndroid Build Coastguard Worker &blk_count);
308*6a54128fSAndroid Build Coastguard Worker if (err)
309*6a54128fSAndroid Build Coastguard Worker return err;
310*6a54128fSAndroid Build Coastguard Worker err = ext2fs_iblk_set(ctx->fs, EXT2_INODE(&inode), blk_count);
311*6a54128fSAndroid Build Coastguard Worker if (err)
312*6a54128fSAndroid Build Coastguard Worker return err;
313*6a54128fSAndroid Build Coastguard Worker return ext2fs_write_inode_full(ctx->fs, list->ino, EXT2_INODE(&inode),
314*6a54128fSAndroid Build Coastguard Worker sizeof(inode));
315*6a54128fSAndroid Build Coastguard Worker }
316*6a54128fSAndroid Build Coastguard Worker
e2fsck_read_extents(e2fsck_t ctx,struct extent_list * extents)317*6a54128fSAndroid Build Coastguard Worker errcode_t e2fsck_read_extents(e2fsck_t ctx, struct extent_list *extents)
318*6a54128fSAndroid Build Coastguard Worker {
319*6a54128fSAndroid Build Coastguard Worker struct ext2_inode_large inode;
320*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
321*6a54128fSAndroid Build Coastguard Worker
322*6a54128fSAndroid Build Coastguard Worker extents->extents = NULL;
323*6a54128fSAndroid Build Coastguard Worker extents->count = 0;
324*6a54128fSAndroid Build Coastguard Worker extents->blocks_freed = 0;
325*6a54128fSAndroid Build Coastguard Worker extents->ext_read = 0;
326*6a54128fSAndroid Build Coastguard Worker extents->size = NUM_EXTENTS;
327*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_get_array(NUM_EXTENTS, sizeof(struct ext2fs_extent),
328*6a54128fSAndroid Build Coastguard Worker &extents->extents);
329*6a54128fSAndroid Build Coastguard Worker if (retval)
330*6a54128fSAndroid Build Coastguard Worker return ENOMEM;
331*6a54128fSAndroid Build Coastguard Worker
332*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_read_inode(ctx->fs, extents->ino, EXT2_INODE(&inode));
333*6a54128fSAndroid Build Coastguard Worker if (retval)
334*6a54128fSAndroid Build Coastguard Worker goto err_out;
335*6a54128fSAndroid Build Coastguard Worker
336*6a54128fSAndroid Build Coastguard Worker retval = load_extents(ctx, extents);
337*6a54128fSAndroid Build Coastguard Worker if (!retval)
338*6a54128fSAndroid Build Coastguard Worker return 0;
339*6a54128fSAndroid Build Coastguard Worker err_out:
340*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&extents->extents);
341*6a54128fSAndroid Build Coastguard Worker extents->size = 0;
342*6a54128fSAndroid Build Coastguard Worker extents->count = 0;
343*6a54128fSAndroid Build Coastguard Worker return retval;
344*6a54128fSAndroid Build Coastguard Worker }
345*6a54128fSAndroid Build Coastguard Worker
rebuild_extent_tree(e2fsck_t ctx,struct extent_list * list,ext2_ino_t ino)346*6a54128fSAndroid Build Coastguard Worker static errcode_t rebuild_extent_tree(e2fsck_t ctx, struct extent_list *list,
347*6a54128fSAndroid Build Coastguard Worker ext2_ino_t ino)
348*6a54128fSAndroid Build Coastguard Worker {
349*6a54128fSAndroid Build Coastguard Worker struct ext2_inode_large inode;
350*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
351*6a54128fSAndroid Build Coastguard Worker
352*6a54128fSAndroid Build Coastguard Worker list->count = 0;
353*6a54128fSAndroid Build Coastguard Worker list->blocks_freed = 0;
354*6a54128fSAndroid Build Coastguard Worker list->ino = ino;
355*6a54128fSAndroid Build Coastguard Worker list->ext_read = 0;
356*6a54128fSAndroid Build Coastguard Worker e2fsck_read_inode_full(ctx, ino, EXT2_INODE(&inode), sizeof(inode),
357*6a54128fSAndroid Build Coastguard Worker "rebuild_extents");
358*6a54128fSAndroid Build Coastguard Worker
359*6a54128fSAndroid Build Coastguard Worker /* Skip deleted inodes and inline data files */
360*6a54128fSAndroid Build Coastguard Worker if (inode.i_links_count == 0 ||
361*6a54128fSAndroid Build Coastguard Worker inode.i_flags & EXT4_INLINE_DATA_FL)
362*6a54128fSAndroid Build Coastguard Worker return 0;
363*6a54128fSAndroid Build Coastguard Worker
364*6a54128fSAndroid Build Coastguard Worker /* Collect lblk->pblk mappings */
365*6a54128fSAndroid Build Coastguard Worker if (inode.i_flags & EXT4_EXTENTS_FL) {
366*6a54128fSAndroid Build Coastguard Worker retval = load_extents(ctx, list);
367*6a54128fSAndroid Build Coastguard Worker if (retval)
368*6a54128fSAndroid Build Coastguard Worker return retval;
369*6a54128fSAndroid Build Coastguard Worker return rewrite_extent_replay(ctx, list, &inode);
370*6a54128fSAndroid Build Coastguard Worker }
371*6a54128fSAndroid Build Coastguard Worker
372*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_block_iterate3(ctx->fs, ino, BLOCK_FLAG_READ_ONLY, 0,
373*6a54128fSAndroid Build Coastguard Worker find_blocks, list);
374*6a54128fSAndroid Build Coastguard Worker
375*6a54128fSAndroid Build Coastguard Worker return retval || list->retval ||
376*6a54128fSAndroid Build Coastguard Worker rewrite_extent_replay(ctx, list, &inode);
377*6a54128fSAndroid Build Coastguard Worker }
378*6a54128fSAndroid Build Coastguard Worker
379*6a54128fSAndroid Build Coastguard Worker /* Rebuild the extents immediately */
e2fsck_rebuild_extents(e2fsck_t ctx,ext2_ino_t ino)380*6a54128fSAndroid Build Coastguard Worker static errcode_t e2fsck_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino)
381*6a54128fSAndroid Build Coastguard Worker {
382*6a54128fSAndroid Build Coastguard Worker struct extent_list list = { 0 };
383*6a54128fSAndroid Build Coastguard Worker errcode_t err;
384*6a54128fSAndroid Build Coastguard Worker
385*6a54128fSAndroid Build Coastguard Worker if (!ext2fs_has_feature_extents(ctx->fs->super) ||
386*6a54128fSAndroid Build Coastguard Worker (ctx->options & E2F_OPT_NO) ||
387*6a54128fSAndroid Build Coastguard Worker (ino != EXT2_ROOT_INO && ino < ctx->fs->super->s_first_ino))
388*6a54128fSAndroid Build Coastguard Worker return 0;
389*6a54128fSAndroid Build Coastguard Worker
390*6a54128fSAndroid Build Coastguard Worker e2fsck_read_bitmaps(ctx);
391*6a54128fSAndroid Build Coastguard Worker err = ext2fs_get_array(NUM_EXTENTS, sizeof(struct ext2fs_extent),
392*6a54128fSAndroid Build Coastguard Worker &list.extents);
393*6a54128fSAndroid Build Coastguard Worker if (err)
394*6a54128fSAndroid Build Coastguard Worker return err;
395*6a54128fSAndroid Build Coastguard Worker list.size = NUM_EXTENTS;
396*6a54128fSAndroid Build Coastguard Worker err = rebuild_extent_tree(ctx, &list, ino);
397*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&list.extents);
398*6a54128fSAndroid Build Coastguard Worker
399*6a54128fSAndroid Build Coastguard Worker return err;
400*6a54128fSAndroid Build Coastguard Worker }
401*6a54128fSAndroid Build Coastguard Worker
rebuild_extents(e2fsck_t ctx,const char * pass_name,int pr_header)402*6a54128fSAndroid Build Coastguard Worker static void rebuild_extents(e2fsck_t ctx, const char *pass_name, int pr_header)
403*6a54128fSAndroid Build Coastguard Worker {
404*6a54128fSAndroid Build Coastguard Worker struct problem_context pctx;
405*6a54128fSAndroid Build Coastguard Worker #ifdef RESOURCE_TRACK
406*6a54128fSAndroid Build Coastguard Worker struct resource_track rtrack;
407*6a54128fSAndroid Build Coastguard Worker #endif
408*6a54128fSAndroid Build Coastguard Worker struct extent_list list = { 0 };
409*6a54128fSAndroid Build Coastguard Worker int first = 1;
410*6a54128fSAndroid Build Coastguard Worker ext2_ino_t ino = 0;
411*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
412*6a54128fSAndroid Build Coastguard Worker
413*6a54128fSAndroid Build Coastguard Worker if (!ext2fs_has_feature_extents(ctx->fs->super) ||
414*6a54128fSAndroid Build Coastguard Worker !ext2fs_test_valid(ctx->fs) ||
415*6a54128fSAndroid Build Coastguard Worker ctx->invalid_bitmaps) {
416*6a54128fSAndroid Build Coastguard Worker if (ctx->inodes_to_rebuild)
417*6a54128fSAndroid Build Coastguard Worker ext2fs_free_inode_bitmap(ctx->inodes_to_rebuild);
418*6a54128fSAndroid Build Coastguard Worker ctx->inodes_to_rebuild = NULL;
419*6a54128fSAndroid Build Coastguard Worker }
420*6a54128fSAndroid Build Coastguard Worker
421*6a54128fSAndroid Build Coastguard Worker if (ctx->inodes_to_rebuild == NULL)
422*6a54128fSAndroid Build Coastguard Worker return;
423*6a54128fSAndroid Build Coastguard Worker
424*6a54128fSAndroid Build Coastguard Worker init_resource_track(&rtrack, ctx->fs->io);
425*6a54128fSAndroid Build Coastguard Worker clear_problem_context(&pctx);
426*6a54128fSAndroid Build Coastguard Worker e2fsck_read_bitmaps(ctx);
427*6a54128fSAndroid Build Coastguard Worker
428*6a54128fSAndroid Build Coastguard Worker list.size = NUM_EXTENTS;
429*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_get_array(sizeof(struct ext2fs_extent),
430*6a54128fSAndroid Build Coastguard Worker list.size, &list.extents);
431*6a54128fSAndroid Build Coastguard Worker if (retval)
432*6a54128fSAndroid Build Coastguard Worker return;
433*6a54128fSAndroid Build Coastguard Worker while (1) {
434*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_find_first_set_inode_bitmap2(
435*6a54128fSAndroid Build Coastguard Worker ctx->inodes_to_rebuild, ino + 1,
436*6a54128fSAndroid Build Coastguard Worker ctx->fs->super->s_inodes_count, &ino);
437*6a54128fSAndroid Build Coastguard Worker if (retval)
438*6a54128fSAndroid Build Coastguard Worker break;
439*6a54128fSAndroid Build Coastguard Worker pctx.ino = ino;
440*6a54128fSAndroid Build Coastguard Worker if (first) {
441*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, pr_header, &pctx);
442*6a54128fSAndroid Build Coastguard Worker first = 0;
443*6a54128fSAndroid Build Coastguard Worker }
444*6a54128fSAndroid Build Coastguard Worker pctx.errcode = rebuild_extent_tree(ctx, &list, ino);
445*6a54128fSAndroid Build Coastguard Worker if (pctx.errcode) {
446*6a54128fSAndroid Build Coastguard Worker end_problem_latch(ctx, PR_LATCH_OPTIMIZE_EXT);
447*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_1E_OPTIMIZE_EXT_ERR, &pctx);
448*6a54128fSAndroid Build Coastguard Worker }
449*6a54128fSAndroid Build Coastguard Worker if (ctx->progress && !ctx->progress_fd)
450*6a54128fSAndroid Build Coastguard Worker e2fsck_simple_progress(ctx, "Rebuilding extents",
451*6a54128fSAndroid Build Coastguard Worker 100.0 * (float) ino /
452*6a54128fSAndroid Build Coastguard Worker (float) ctx->fs->super->s_inodes_count,
453*6a54128fSAndroid Build Coastguard Worker ino);
454*6a54128fSAndroid Build Coastguard Worker }
455*6a54128fSAndroid Build Coastguard Worker end_problem_latch(ctx, PR_LATCH_OPTIMIZE_EXT);
456*6a54128fSAndroid Build Coastguard Worker
457*6a54128fSAndroid Build Coastguard Worker ext2fs_free_inode_bitmap(ctx->inodes_to_rebuild);
458*6a54128fSAndroid Build Coastguard Worker ctx->inodes_to_rebuild = NULL;
459*6a54128fSAndroid Build Coastguard Worker ext2fs_free_mem(&list.extents);
460*6a54128fSAndroid Build Coastguard Worker
461*6a54128fSAndroid Build Coastguard Worker print_resource_track(ctx, pass_name, &rtrack, ctx->fs->io);
462*6a54128fSAndroid Build Coastguard Worker }
463*6a54128fSAndroid Build Coastguard Worker
464*6a54128fSAndroid Build Coastguard Worker /* Scan a file to see if we should rebuild its extent tree */
e2fsck_check_rebuild_extents(e2fsck_t ctx,ext2_ino_t ino,struct ext2_inode * inode,struct problem_context * pctx)465*6a54128fSAndroid Build Coastguard Worker errcode_t e2fsck_check_rebuild_extents(e2fsck_t ctx, ext2_ino_t ino,
466*6a54128fSAndroid Build Coastguard Worker struct ext2_inode *inode,
467*6a54128fSAndroid Build Coastguard Worker struct problem_context *pctx)
468*6a54128fSAndroid Build Coastguard Worker {
469*6a54128fSAndroid Build Coastguard Worker struct extent_tree_info eti;
470*6a54128fSAndroid Build Coastguard Worker struct ext2_extent_info info, top_info;
471*6a54128fSAndroid Build Coastguard Worker struct ext2fs_extent extent;
472*6a54128fSAndroid Build Coastguard Worker ext2_extent_handle_t ehandle;
473*6a54128fSAndroid Build Coastguard Worker ext2_filsys fs = ctx->fs;
474*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
475*6a54128fSAndroid Build Coastguard Worker
476*6a54128fSAndroid Build Coastguard Worker /* block map file and we want extent conversion */
477*6a54128fSAndroid Build Coastguard Worker if (!(inode->i_flags & EXT4_EXTENTS_FL) &&
478*6a54128fSAndroid Build Coastguard Worker !(inode->i_flags & EXT4_INLINE_DATA_FL) &&
479*6a54128fSAndroid Build Coastguard Worker (ctx->options & E2F_OPT_CONVERT_BMAP)) {
480*6a54128fSAndroid Build Coastguard Worker return e2fsck_rebuild_extents_later(ctx, ino);
481*6a54128fSAndroid Build Coastguard Worker }
482*6a54128fSAndroid Build Coastguard Worker
483*6a54128fSAndroid Build Coastguard Worker if (!(inode->i_flags & EXT4_EXTENTS_FL))
484*6a54128fSAndroid Build Coastguard Worker return 0;
485*6a54128fSAndroid Build Coastguard Worker memset(&eti, 0, sizeof(eti));
486*6a54128fSAndroid Build Coastguard Worker eti.ino = ino;
487*6a54128fSAndroid Build Coastguard Worker
488*6a54128fSAndroid Build Coastguard Worker /* Otherwise, go scan the extent tree... */
489*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_extent_open2(fs, ino, inode, &ehandle);
490*6a54128fSAndroid Build Coastguard Worker if (retval)
491*6a54128fSAndroid Build Coastguard Worker return 0;
492*6a54128fSAndroid Build Coastguard Worker
493*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_extent_get_info(ehandle, &top_info);
494*6a54128fSAndroid Build Coastguard Worker if (retval)
495*6a54128fSAndroid Build Coastguard Worker goto out;
496*6a54128fSAndroid Build Coastguard Worker
497*6a54128fSAndroid Build Coastguard Worker /* Check maximum extent depth */
498*6a54128fSAndroid Build Coastguard Worker pctx->ino = ino;
499*6a54128fSAndroid Build Coastguard Worker pctx->blk = top_info.max_depth;
500*6a54128fSAndroid Build Coastguard Worker pctx->blk2 = ext2fs_max_extent_depth(ehandle);
501*6a54128fSAndroid Build Coastguard Worker if (pctx->blk2 < pctx->blk &&
502*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_1_EXTENT_BAD_MAX_DEPTH, pctx))
503*6a54128fSAndroid Build Coastguard Worker eti.force_rebuild = 1;
504*6a54128fSAndroid Build Coastguard Worker
505*6a54128fSAndroid Build Coastguard Worker /* Can we collect extent tree level stats? */
506*6a54128fSAndroid Build Coastguard Worker pctx->blk = MAX_EXTENT_DEPTH_COUNT;
507*6a54128fSAndroid Build Coastguard Worker if (pctx->blk2 > pctx->blk)
508*6a54128fSAndroid Build Coastguard Worker fix_problem(ctx, PR_1E_MAX_EXTENT_TREE_DEPTH, pctx);
509*6a54128fSAndroid Build Coastguard Worker
510*6a54128fSAndroid Build Coastguard Worker /* We need to fix tree depth problems, but the scan isn't a fix. */
511*6a54128fSAndroid Build Coastguard Worker if (ctx->options & E2F_OPT_FIXES_ONLY)
512*6a54128fSAndroid Build Coastguard Worker goto out;
513*6a54128fSAndroid Build Coastguard Worker
514*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_extent_get(ehandle, EXT2_EXTENT_ROOT, &extent);
515*6a54128fSAndroid Build Coastguard Worker if (retval)
516*6a54128fSAndroid Build Coastguard Worker goto out;
517*6a54128fSAndroid Build Coastguard Worker
518*6a54128fSAndroid Build Coastguard Worker do {
519*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_extent_get_info(ehandle, &info);
520*6a54128fSAndroid Build Coastguard Worker if (retval)
521*6a54128fSAndroid Build Coastguard Worker break;
522*6a54128fSAndroid Build Coastguard Worker
523*6a54128fSAndroid Build Coastguard Worker /*
524*6a54128fSAndroid Build Coastguard Worker * If this is the first extent in an extent block that we
525*6a54128fSAndroid Build Coastguard Worker * haven't visited, collect stats on the block.
526*6a54128fSAndroid Build Coastguard Worker */
527*6a54128fSAndroid Build Coastguard Worker if (info.curr_entry == 1 &&
528*6a54128fSAndroid Build Coastguard Worker !(extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
529*6a54128fSAndroid Build Coastguard Worker !eti.force_rebuild &&
530*6a54128fSAndroid Build Coastguard Worker info.curr_level < MAX_EXTENT_DEPTH_COUNT) {
531*6a54128fSAndroid Build Coastguard Worker struct extent_tree_level *etl;
532*6a54128fSAndroid Build Coastguard Worker
533*6a54128fSAndroid Build Coastguard Worker etl = eti.ext_info + info.curr_level;
534*6a54128fSAndroid Build Coastguard Worker etl->num_extents += info.num_entries;
535*6a54128fSAndroid Build Coastguard Worker etl->max_extents += info.max_entries;
536*6a54128fSAndroid Build Coastguard Worker /*
537*6a54128fSAndroid Build Coastguard Worker * Implementation wart: Splitting extent blocks when
538*6a54128fSAndroid Build Coastguard Worker * appending will leave the old block with one free
539*6a54128fSAndroid Build Coastguard Worker * entry. Therefore unless the node is totally full,
540*6a54128fSAndroid Build Coastguard Worker * pretend that a non-root extent block can hold one
541*6a54128fSAndroid Build Coastguard Worker * fewer entry than it actually does, so that we don't
542*6a54128fSAndroid Build Coastguard Worker * repeatedly rebuild the extent tree.
543*6a54128fSAndroid Build Coastguard Worker */
544*6a54128fSAndroid Build Coastguard Worker if (info.curr_level &&
545*6a54128fSAndroid Build Coastguard Worker info.num_entries < info.max_entries)
546*6a54128fSAndroid Build Coastguard Worker etl->max_extents--;
547*6a54128fSAndroid Build Coastguard Worker }
548*6a54128fSAndroid Build Coastguard Worker
549*6a54128fSAndroid Build Coastguard Worker /* Skip to the end of a block of leaf nodes */
550*6a54128fSAndroid Build Coastguard Worker if (extent.e_flags & EXT2_EXTENT_FLAGS_LEAF) {
551*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_extent_get(ehandle,
552*6a54128fSAndroid Build Coastguard Worker EXT2_EXTENT_LAST_SIB,
553*6a54128fSAndroid Build Coastguard Worker &extent);
554*6a54128fSAndroid Build Coastguard Worker if (retval)
555*6a54128fSAndroid Build Coastguard Worker break;
556*6a54128fSAndroid Build Coastguard Worker }
557*6a54128fSAndroid Build Coastguard Worker
558*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_extent_get(ehandle, EXT2_EXTENT_NEXT, &extent);
559*6a54128fSAndroid Build Coastguard Worker } while (retval == 0);
560*6a54128fSAndroid Build Coastguard Worker out:
561*6a54128fSAndroid Build Coastguard Worker ext2fs_extent_free(ehandle);
562*6a54128fSAndroid Build Coastguard Worker return e2fsck_should_rebuild_extents(ctx, pctx, &eti, &top_info);
563*6a54128fSAndroid Build Coastguard Worker }
564*6a54128fSAndroid Build Coastguard Worker
565*6a54128fSAndroid Build Coastguard Worker /* Having scanned a file's extent tree, decide if we should rebuild it */
e2fsck_should_rebuild_extents(e2fsck_t ctx,struct problem_context * pctx,struct extent_tree_info * eti,struct ext2_extent_info * info)566*6a54128fSAndroid Build Coastguard Worker errcode_t e2fsck_should_rebuild_extents(e2fsck_t ctx,
567*6a54128fSAndroid Build Coastguard Worker struct problem_context *pctx,
568*6a54128fSAndroid Build Coastguard Worker struct extent_tree_info *eti,
569*6a54128fSAndroid Build Coastguard Worker struct ext2_extent_info *info)
570*6a54128fSAndroid Build Coastguard Worker {
571*6a54128fSAndroid Build Coastguard Worker struct extent_tree_level *ei;
572*6a54128fSAndroid Build Coastguard Worker int i, j, op;
573*6a54128fSAndroid Build Coastguard Worker unsigned int extents_per_block;
574*6a54128fSAndroid Build Coastguard Worker
575*6a54128fSAndroid Build Coastguard Worker if (eti->force_rebuild)
576*6a54128fSAndroid Build Coastguard Worker goto rebuild;
577*6a54128fSAndroid Build Coastguard Worker
578*6a54128fSAndroid Build Coastguard Worker if (ctx->options & E2F_OPT_NOOPT_EXTENTS)
579*6a54128fSAndroid Build Coastguard Worker return 0;
580*6a54128fSAndroid Build Coastguard Worker
581*6a54128fSAndroid Build Coastguard Worker extents_per_block = (ctx->fs->blocksize -
582*6a54128fSAndroid Build Coastguard Worker sizeof(struct ext3_extent_header)) /
583*6a54128fSAndroid Build Coastguard Worker sizeof(struct ext3_extent);
584*6a54128fSAndroid Build Coastguard Worker
585*6a54128fSAndroid Build Coastguard Worker /* If the extent tree is too deep, then rebuild it. */
586*6a54128fSAndroid Build Coastguard Worker if (info->max_depth > MAX_EXTENT_DEPTH_COUNT-1) {
587*6a54128fSAndroid Build Coastguard Worker pctx->blk = info->max_depth;
588*6a54128fSAndroid Build Coastguard Worker op = PR_1E_CAN_COLLAPSE_EXTENT_TREE;
589*6a54128fSAndroid Build Coastguard Worker goto rebuild;
590*6a54128fSAndroid Build Coastguard Worker }
591*6a54128fSAndroid Build Coastguard Worker /*
592*6a54128fSAndroid Build Coastguard Worker * If we can consolidate a level or shorten the tree, schedule the
593*6a54128fSAndroid Build Coastguard Worker * extent tree to be rebuilt.
594*6a54128fSAndroid Build Coastguard Worker */
595*6a54128fSAndroid Build Coastguard Worker for (i = 0, ei = eti->ext_info; i < info->max_depth + 1; i++, ei++) {
596*6a54128fSAndroid Build Coastguard Worker if (ei->max_extents - ei->num_extents > extents_per_block) {
597*6a54128fSAndroid Build Coastguard Worker pctx->blk = i;
598*6a54128fSAndroid Build Coastguard Worker op = PR_1E_CAN_NARROW_EXTENT_TREE;
599*6a54128fSAndroid Build Coastguard Worker goto rebuild;
600*6a54128fSAndroid Build Coastguard Worker }
601*6a54128fSAndroid Build Coastguard Worker for (j = 0; j < i; j++) {
602*6a54128fSAndroid Build Coastguard Worker if (ei->num_extents < eti->ext_info[j].max_extents) {
603*6a54128fSAndroid Build Coastguard Worker pctx->blk = i;
604*6a54128fSAndroid Build Coastguard Worker op = PR_1E_CAN_COLLAPSE_EXTENT_TREE;
605*6a54128fSAndroid Build Coastguard Worker goto rebuild;
606*6a54128fSAndroid Build Coastguard Worker }
607*6a54128fSAndroid Build Coastguard Worker }
608*6a54128fSAndroid Build Coastguard Worker }
609*6a54128fSAndroid Build Coastguard Worker return 0;
610*6a54128fSAndroid Build Coastguard Worker
611*6a54128fSAndroid Build Coastguard Worker rebuild:
612*6a54128fSAndroid Build Coastguard Worker if (eti->force_rebuild || fix_problem(ctx, op, pctx))
613*6a54128fSAndroid Build Coastguard Worker return e2fsck_rebuild_extents_later(ctx, eti->ino);
614*6a54128fSAndroid Build Coastguard Worker return 0;
615*6a54128fSAndroid Build Coastguard Worker }
616*6a54128fSAndroid Build Coastguard Worker
e2fsck_pass1e(e2fsck_t ctx)617*6a54128fSAndroid Build Coastguard Worker void e2fsck_pass1e(e2fsck_t ctx)
618*6a54128fSAndroid Build Coastguard Worker {
619*6a54128fSAndroid Build Coastguard Worker rebuild_extents(ctx, "Pass 1E", PR_1E_PASS_HEADER);
620*6a54128fSAndroid Build Coastguard Worker }
621