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 | |
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>
-rw-r--r-- | fs/btrfs/ctree.h | 1 | ||||
-rw-r--r-- | fs/btrfs/extent_map.h | 1 | ||||
-rw-r--r-- | fs/btrfs/file.c | 41 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 189 |
4 files changed, 108 insertions, 124 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index abb27332c914..ca5547af6090 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1908,6 +1908,7 @@ int btrfs_update_inode(struct btrfs_trans_handle *trans, | |||
1908 | int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode); | 1908 | int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode); |
1909 | int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode); | 1909 | int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode); |
1910 | void btrfs_orphan_cleanup(struct btrfs_root *root); | 1910 | void btrfs_orphan_cleanup(struct btrfs_root *root); |
1911 | int btrfs_cont_expand(struct inode *inode, loff_t size); | ||
1911 | 1912 | ||
1912 | /* ioctl.c */ | 1913 | /* ioctl.c */ |
1913 | long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); | 1914 | long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); |
diff --git a/fs/btrfs/extent_map.h b/fs/btrfs/extent_map.h index abbcbeb28c79..e693e1b4ac4a 100644 --- a/fs/btrfs/extent_map.h +++ b/fs/btrfs/extent_map.h | |||
@@ -11,6 +11,7 @@ | |||
11 | /* bits for the flags field */ | 11 | /* bits for the flags field */ |
12 | #define EXTENT_FLAG_PINNED 0 /* this entry not yet on disk, don't free it */ | 12 | #define EXTENT_FLAG_PINNED 0 /* this entry not yet on disk, don't free it */ |
13 | #define EXTENT_FLAG_COMPRESSED 1 | 13 | #define EXTENT_FLAG_COMPRESSED 1 |
14 | #define EXTENT_FLAG_VACANCY 2 /* no file extent item found */ | ||
14 | 15 | ||
15 | struct extent_map { | 16 | struct extent_map { |
16 | struct rb_node rb_node; | 17 | struct rb_node rb_node; |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 0aa15436590e..b8a7637e14a1 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -142,40 +142,6 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
142 | } | 142 | } |
143 | set_extent_uptodate(io_tree, start_pos, end_of_last_block, GFP_NOFS); | 143 | set_extent_uptodate(io_tree, start_pos, end_of_last_block, GFP_NOFS); |
144 | 144 | ||
145 | /* FIXME...EIEIO, ENOSPC and more */ | ||
146 | /* insert any holes we need to create */ | ||
147 | if (isize < start_pos) { | ||
148 | u64 last_pos_in_file; | ||
149 | u64 hole_size; | ||
150 | u64 mask = root->sectorsize - 1; | ||
151 | last_pos_in_file = (isize + mask) & ~mask; | ||
152 | hole_size = (start_pos - last_pos_in_file + mask) & ~mask; | ||
153 | if (hole_size > 0) { | ||
154 | btrfs_wait_ordered_range(inode, last_pos_in_file, | ||
155 | last_pos_in_file + hole_size); | ||
156 | mutex_lock(&BTRFS_I(inode)->extent_mutex); | ||
157 | err = btrfs_drop_extents(trans, root, inode, | ||
158 | last_pos_in_file, | ||
159 | last_pos_in_file + hole_size, | ||
160 | last_pos_in_file, | ||
161 | &hint_byte); | ||
162 | if (err) | ||
163 | goto failed; | ||
164 | |||
165 | err = btrfs_insert_file_extent(trans, root, | ||
166 | inode->i_ino, | ||
167 | last_pos_in_file, | ||
168 | 0, 0, hole_size, 0, | ||
169 | hole_size, 0, 0, 0); | ||
170 | btrfs_drop_extent_cache(inode, last_pos_in_file, | ||
171 | last_pos_in_file + hole_size - 1, 0); | ||
172 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); | ||
173 | btrfs_check_file(root, inode); | ||
174 | } | ||
175 | if (err) | ||
176 | goto failed; | ||
177 | } | ||
178 | |||
179 | /* check for reserved extents on each page, we don't want | 145 | /* check for reserved extents on each page, we don't want |
180 | * to reset the delalloc bit on things that already have | 146 | * to reset the delalloc bit on things that already have |
181 | * extents reserved. | 147 | * extents reserved. |
@@ -191,7 +157,6 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
191 | i_size_write(inode, end_pos); | 157 | i_size_write(inode, end_pos); |
192 | btrfs_update_inode(trans, root, inode); | 158 | btrfs_update_inode(trans, root, inode); |
193 | } | 159 | } |
194 | failed: | ||
195 | err = btrfs_end_transaction(trans, root); | 160 | err = btrfs_end_transaction(trans, root); |
196 | out_unlock: | 161 | out_unlock: |
197 | unlock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS); | 162 | unlock_extent(io_tree, start_pos, end_of_last_block, GFP_NOFS); |
@@ -697,6 +662,12 @@ static int noinline prepare_pages(struct btrfs_root *root, struct file *file, | |||
697 | start_pos = pos & ~((u64)root->sectorsize - 1); | 662 | start_pos = pos & ~((u64)root->sectorsize - 1); |
698 | last_pos = ((u64)index + num_pages) << PAGE_CACHE_SHIFT; | 663 | last_pos = ((u64)index + num_pages) << PAGE_CACHE_SHIFT; |
699 | 664 | ||
665 | if (start_pos > inode->i_size) { | ||
666 | err = btrfs_cont_expand(inode, start_pos); | ||
667 | if (err) | ||
668 | return err; | ||
669 | } | ||
670 | |||
700 | memset(pages, 0, num_pages * sizeof(struct page *)); | 671 | memset(pages, 0, num_pages * sizeof(struct page *)); |
701 | again: | 672 | again: |
702 | for (i = 0; i < num_pages; i++) { | 673 | for (i = 0; i < num_pages; i++) { |
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) { |