diff options
author | Yan Zheng <zheng.yan@oracle.com> | 2008-10-30 14:19:41 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-10-30 14:19:41 -0400 |
commit | 9036c10208e1fc496cef7692ba66a78699b360dc (patch) | |
tree | a5b272158acc0e01e71731f5ccbc895a8eee1151 /fs/btrfs/inode.c | |
parent | 19b9bdb054895ba07086f0264641c9f80e0eb2c4 (diff) |
Btrfs: update hole handling v2
This patch splits the hole insertion code out of btrfs_setattr
into btrfs_cont_expand and updates btrfs_get_extent to properly
handle the case that file extent items are not continuous.
Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 189 |
1 files changed, 100 insertions, 89 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index dd9cd01042b8..8254d6fa6910 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -2296,81 +2296,91 @@ out: | |||
2296 | return ret; | 2296 | return ret; |
2297 | } | 2297 | } |
2298 | 2298 | ||
2299 | static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) | 2299 | int btrfs_cont_expand(struct inode *inode, loff_t size) |
2300 | { | 2300 | { |
2301 | struct inode *inode = dentry->d_inode; | 2301 | struct btrfs_trans_handle *trans; |
2302 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
2303 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; | ||
2304 | struct extent_map *em; | ||
2305 | u64 mask = root->sectorsize - 1; | ||
2306 | u64 hole_start = (inode->i_size + mask) & ~mask; | ||
2307 | u64 block_end = (size + mask) & ~mask; | ||
2308 | u64 last_byte; | ||
2309 | u64 cur_offset; | ||
2310 | u64 hole_size; | ||
2302 | int err; | 2311 | int err; |
2303 | 2312 | ||
2304 | err = inode_change_ok(inode, attr); | 2313 | if (size <= hole_start) |
2314 | return 0; | ||
2315 | |||
2316 | err = btrfs_check_free_space(root, 1, 0); | ||
2305 | if (err) | 2317 | if (err) |
2306 | return err; | 2318 | return err; |
2307 | 2319 | ||
2308 | if (S_ISREG(inode->i_mode) && | 2320 | btrfs_truncate_page(inode->i_mapping, inode->i_size); |
2309 | attr->ia_valid & ATTR_SIZE && attr->ia_size > inode->i_size) { | ||
2310 | struct btrfs_trans_handle *trans; | ||
2311 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
2312 | struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; | ||
2313 | 2321 | ||
2314 | u64 mask = root->sectorsize - 1; | 2322 | while (1) { |
2315 | u64 hole_start = (inode->i_size + mask) & ~mask; | 2323 | struct btrfs_ordered_extent *ordered; |
2316 | u64 block_end = (attr->ia_size + mask) & ~mask; | 2324 | btrfs_wait_ordered_range(inode, hole_start, |
2317 | u64 hole_size; | 2325 | block_end - hole_start); |
2318 | u64 alloc_hint = 0; | 2326 | lock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS); |
2327 | ordered = btrfs_lookup_ordered_extent(inode, hole_start); | ||
2328 | if (!ordered) | ||
2329 | break; | ||
2330 | unlock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS); | ||
2331 | btrfs_put_ordered_extent(ordered); | ||
2332 | } | ||
2319 | 2333 | ||
2320 | if (attr->ia_size <= hole_start) | 2334 | trans = btrfs_start_transaction(root, 1); |
2321 | goto out; | 2335 | btrfs_set_trans_block_group(trans, inode); |
2322 | 2336 | ||
2323 | err = btrfs_check_free_space(root, 1, 0); | 2337 | cur_offset = hole_start; |
2324 | if (err) | 2338 | while (1) { |
2325 | goto fail; | 2339 | em = btrfs_get_extent(inode, NULL, 0, cur_offset, |
2340 | block_end - cur_offset, 0); | ||
2341 | BUG_ON(IS_ERR(em) || !em); | ||
2342 | last_byte = min(extent_map_end(em), block_end); | ||
2343 | last_byte = (last_byte + mask) & ~mask; | ||
2344 | if (test_bit(EXTENT_FLAG_VACANCY, &em->flags)) { | ||
2345 | hole_size = last_byte - cur_offset; | ||
2346 | err = btrfs_insert_file_extent(trans, root, | ||
2347 | inode->i_ino, cur_offset, 0, | ||
2348 | 0, hole_size, 0, hole_size, | ||
2349 | 0, 0, 0); | ||
2350 | btrfs_drop_extent_cache(inode, hole_start, | ||
2351 | last_byte - 1, 0); | ||
2352 | } | ||
2353 | free_extent_map(em); | ||
2354 | cur_offset = last_byte; | ||
2355 | if (err || cur_offset >= block_end) | ||
2356 | break; | ||
2357 | } | ||
2326 | 2358 | ||
2327 | btrfs_truncate_page(inode->i_mapping, inode->i_size); | 2359 | btrfs_end_transaction(trans, root); |
2360 | unlock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS); | ||
2361 | return err; | ||
2362 | } | ||
2328 | 2363 | ||
2329 | hole_size = block_end - hole_start; | 2364 | static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) |
2330 | while(1) { | 2365 | { |
2331 | struct btrfs_ordered_extent *ordered; | 2366 | struct inode *inode = dentry->d_inode; |
2332 | btrfs_wait_ordered_range(inode, hole_start, hole_size); | 2367 | int err; |
2333 | |||
2334 | lock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS); | ||
2335 | ordered = btrfs_lookup_ordered_extent(inode, hole_start); | ||
2336 | if (ordered) { | ||
2337 | unlock_extent(io_tree, hole_start, | ||
2338 | block_end - 1, GFP_NOFS); | ||
2339 | btrfs_put_ordered_extent(ordered); | ||
2340 | } else { | ||
2341 | break; | ||
2342 | } | ||
2343 | } | ||
2344 | 2368 | ||
2345 | trans = btrfs_start_transaction(root, 1); | 2369 | err = inode_change_ok(inode, attr); |
2346 | btrfs_set_trans_block_group(trans, inode); | 2370 | if (err) |
2347 | mutex_lock(&BTRFS_I(inode)->extent_mutex); | 2371 | return err; |
2348 | err = btrfs_drop_extents(trans, root, inode, | ||
2349 | hole_start, block_end, hole_start, | ||
2350 | &alloc_hint); | ||
2351 | 2372 | ||
2352 | if (alloc_hint != EXTENT_MAP_INLINE) { | 2373 | if (S_ISREG(inode->i_mode) && |
2353 | err = btrfs_insert_file_extent(trans, root, | 2374 | attr->ia_valid & ATTR_SIZE && attr->ia_size > inode->i_size) { |
2354 | inode->i_ino, | 2375 | err = btrfs_cont_expand(inode, attr->ia_size); |
2355 | hole_start, 0, 0, | ||
2356 | hole_size, 0, hole_size, | ||
2357 | 0, 0, 0); | ||
2358 | btrfs_drop_extent_cache(inode, hole_start, | ||
2359 | (u64)-1, 0); | ||
2360 | btrfs_check_file(root, inode); | ||
2361 | } | ||
2362 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); | ||
2363 | btrfs_end_transaction(trans, root); | ||
2364 | unlock_extent(io_tree, hole_start, block_end - 1, GFP_NOFS); | ||
2365 | if (err) | 2376 | if (err) |
2366 | return err; | 2377 | return err; |
2367 | } | 2378 | } |
2368 | out: | 2379 | |
2369 | err = inode_setattr(inode, attr); | 2380 | err = inode_setattr(inode, attr); |
2370 | 2381 | ||
2371 | if (!err && ((attr->ia_valid & ATTR_MODE))) | 2382 | if (!err && ((attr->ia_valid & ATTR_MODE))) |
2372 | err = btrfs_acl_chmod(inode); | 2383 | err = btrfs_acl_chmod(inode); |
2373 | fail: | ||
2374 | return err; | 2384 | return err; |
2375 | } | 2385 | } |
2376 | 2386 | ||
@@ -3456,27 +3466,44 @@ again: | |||
3456 | if (found_type == BTRFS_FILE_EXTENT_REG) { | 3466 | if (found_type == BTRFS_FILE_EXTENT_REG) { |
3457 | extent_end = extent_start + | 3467 | extent_end = extent_start + |
3458 | btrfs_file_extent_num_bytes(leaf, item); | 3468 | btrfs_file_extent_num_bytes(leaf, item); |
3459 | err = 0; | 3469 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { |
3460 | if (start < extent_start || start >= extent_end) { | 3470 | size_t size; |
3461 | em->start = start; | 3471 | size = btrfs_file_extent_inline_len(leaf, item); |
3462 | if (start < extent_start) { | 3472 | extent_end = (extent_start + size + root->sectorsize - 1) & |
3463 | if (start + len <= extent_start) | 3473 | ~((u64)root->sectorsize - 1); |
3464 | goto not_found; | 3474 | } |
3465 | em->len = extent_end - extent_start; | 3475 | |
3466 | } else { | 3476 | if (start >= extent_end) { |
3467 | em->len = len; | 3477 | path->slots[0]++; |
3478 | if (path->slots[0] >= btrfs_header_nritems(leaf)) { | ||
3479 | ret = btrfs_next_leaf(root, path); | ||
3480 | if (ret < 0) { | ||
3481 | err = ret; | ||
3482 | goto out; | ||
3468 | } | 3483 | } |
3469 | goto not_found_em; | 3484 | if (ret > 0) |
3485 | goto not_found; | ||
3486 | leaf = path->nodes[0]; | ||
3470 | } | 3487 | } |
3488 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | ||
3489 | if (found_key.objectid != objectid || | ||
3490 | found_key.type != BTRFS_EXTENT_DATA_KEY) | ||
3491 | goto not_found; | ||
3492 | if (start + len <= found_key.offset) | ||
3493 | goto not_found; | ||
3494 | em->start = start; | ||
3495 | em->len = found_key.offset - start; | ||
3496 | goto not_found_em; | ||
3497 | } | ||
3498 | |||
3499 | if (found_type == BTRFS_FILE_EXTENT_REG) { | ||
3500 | em->start = extent_start; | ||
3501 | em->len = extent_end - extent_start; | ||
3471 | bytenr = btrfs_file_extent_disk_bytenr(leaf, item); | 3502 | bytenr = btrfs_file_extent_disk_bytenr(leaf, item); |
3472 | if (bytenr == 0) { | 3503 | if (bytenr == 0) { |
3473 | em->start = extent_start; | ||
3474 | em->len = extent_end - extent_start; | ||
3475 | em->block_start = EXTENT_MAP_HOLE; | 3504 | em->block_start = EXTENT_MAP_HOLE; |
3476 | goto insert; | 3505 | goto insert; |
3477 | } | 3506 | } |
3478 | em->start = extent_start; | ||
3479 | em->len = extent_end - extent_start; | ||
3480 | if (compressed) { | 3507 | if (compressed) { |
3481 | set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); | 3508 | set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); |
3482 | em->block_start = bytenr; | 3509 | em->block_start = bytenr; |
@@ -3489,38 +3516,21 @@ again: | |||
3489 | } | 3516 | } |
3490 | goto insert; | 3517 | goto insert; |
3491 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { | 3518 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { |
3492 | u64 page_start; | ||
3493 | unsigned long ptr; | 3519 | unsigned long ptr; |
3494 | char *map; | 3520 | char *map; |
3495 | size_t size; | 3521 | size_t size; |
3496 | size_t extent_offset; | 3522 | size_t extent_offset; |
3497 | size_t copy_size; | 3523 | size_t copy_size; |
3498 | 3524 | ||
3499 | size = btrfs_file_extent_inline_len(leaf, item); | ||
3500 | extent_end = (extent_start + size + root->sectorsize - 1) & | ||
3501 | ~((u64)root->sectorsize - 1); | ||
3502 | if (start < extent_start || start >= extent_end) { | ||
3503 | em->start = start; | ||
3504 | if (start < extent_start) { | ||
3505 | if (start + len <= extent_start) | ||
3506 | goto not_found; | ||
3507 | em->len = extent_end - extent_start; | ||
3508 | } else { | ||
3509 | em->len = len; | ||
3510 | } | ||
3511 | goto not_found_em; | ||
3512 | } | ||
3513 | em->block_start = EXTENT_MAP_INLINE; | 3525 | em->block_start = EXTENT_MAP_INLINE; |
3514 | |||
3515 | if (!page || create) { | 3526 | if (!page || create) { |
3516 | em->start = extent_start; | 3527 | em->start = extent_start; |
3517 | em->len = (size + root->sectorsize - 1) & | 3528 | em->len = extent_end - extent_start; |
3518 | ~((u64)root->sectorsize - 1); | ||
3519 | goto out; | 3529 | goto out; |
3520 | } | 3530 | } |
3521 | 3531 | ||
3522 | page_start = page_offset(page) + pg_offset; | 3532 | size = btrfs_file_extent_inline_len(leaf, item); |
3523 | extent_offset = page_start - extent_start; | 3533 | extent_offset = page_offset(page) + pg_offset - extent_start; |
3524 | copy_size = min_t(u64, PAGE_CACHE_SIZE - pg_offset, | 3534 | copy_size = min_t(u64, PAGE_CACHE_SIZE - pg_offset, |
3525 | size - extent_offset); | 3535 | size - extent_offset); |
3526 | em->start = extent_start + extent_offset; | 3536 | em->start = extent_start + extent_offset; |
@@ -3570,6 +3580,7 @@ not_found: | |||
3570 | em->len = len; | 3580 | em->len = len; |
3571 | not_found_em: | 3581 | not_found_em: |
3572 | em->block_start = EXTENT_MAP_HOLE; | 3582 | em->block_start = EXTENT_MAP_HOLE; |
3583 | set_bit(EXTENT_FLAG_VACANCY, &em->flags); | ||
3573 | insert: | 3584 | insert: |
3574 | btrfs_release_path(root, path); | 3585 | btrfs_release_path(root, path); |
3575 | if (em->start > start || extent_map_end(em) <= start) { | 3586 | if (em->start > start || extent_map_end(em) <= start) { |