diff options
Diffstat (limited to 'fs/ext4/extents.c')
-rw-r--r-- | fs/ext4/extents.c | 49 |
1 files changed, 32 insertions, 17 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 91ae46098ea4..7d7b74e94687 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -296,29 +296,44 @@ static inline int ext4_ext_space_root_idx(struct inode *inode, int check) | |||
296 | * to allocate @blocks | 296 | * to allocate @blocks |
297 | * Worse case is one block per extent | 297 | * Worse case is one block per extent |
298 | */ | 298 | */ |
299 | int ext4_ext_calc_metadata_amount(struct inode *inode, int blocks) | 299 | int ext4_ext_calc_metadata_amount(struct inode *inode, sector_t lblock) |
300 | { | 300 | { |
301 | int lcap, icap, rcap, leafs, idxs, num; | 301 | struct ext4_inode_info *ei = EXT4_I(inode); |
302 | int newextents = blocks; | 302 | int idxs, num = 0; |
303 | |||
304 | rcap = ext4_ext_space_root_idx(inode, 0); | ||
305 | lcap = ext4_ext_space_block(inode, 0); | ||
306 | icap = ext4_ext_space_block_idx(inode, 0); | ||
307 | 303 | ||
308 | /* number of new leaf blocks needed */ | 304 | idxs = ((inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header)) |
309 | num = leafs = (newextents + lcap - 1) / lcap; | 305 | / sizeof(struct ext4_extent_idx)); |
310 | 306 | ||
311 | /* | 307 | /* |
312 | * Worse case, we need separate index block(s) | 308 | * If the new delayed allocation block is contiguous with the |
313 | * to link all new leaf blocks | 309 | * previous da block, it can share index blocks with the |
310 | * previous block, so we only need to allocate a new index | ||
311 | * block every idxs leaf blocks. At ldxs**2 blocks, we need | ||
312 | * an additional index block, and at ldxs**3 blocks, yet | ||
313 | * another index blocks. | ||
314 | */ | 314 | */ |
315 | idxs = (leafs + icap - 1) / icap; | 315 | if (ei->i_da_metadata_calc_len && |
316 | do { | 316 | ei->i_da_metadata_calc_last_lblock+1 == lblock) { |
317 | num += idxs; | 317 | if ((ei->i_da_metadata_calc_len % idxs) == 0) |
318 | idxs = (idxs + icap - 1) / icap; | 318 | num++; |
319 | } while (idxs > rcap); | 319 | if ((ei->i_da_metadata_calc_len % (idxs*idxs)) == 0) |
320 | num++; | ||
321 | if ((ei->i_da_metadata_calc_len % (idxs*idxs*idxs)) == 0) { | ||
322 | num++; | ||
323 | ei->i_da_metadata_calc_len = 0; | ||
324 | } else | ||
325 | ei->i_da_metadata_calc_len++; | ||
326 | ei->i_da_metadata_calc_last_lblock++; | ||
327 | return num; | ||
328 | } | ||
320 | 329 | ||
321 | return num; | 330 | /* |
331 | * In the worst case we need a new set of index blocks at | ||
332 | * every level of the inode's extent tree. | ||
333 | */ | ||
334 | ei->i_da_metadata_calc_len = 1; | ||
335 | ei->i_da_metadata_calc_last_lblock = lblock; | ||
336 | return ext_depth(inode) + 1; | ||
322 | } | 337 | } |
323 | 338 | ||
324 | static int | 339 | static int |