aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorYan Zheng <zheng.yan@oracle.com>2008-10-30 14:19:41 -0400
committerChris Mason <chris.mason@oracle.com>2008-10-30 14:19:41 -0400
commit9036c10208e1fc496cef7692ba66a78699b360dc (patch)
treea5b272158acc0e01e71731f5ccbc895a8eee1151 /fs
parent19b9bdb054895ba07086f0264641c9f80e0eb2c4 (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')
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/extent_map.h1
-rw-r--r--fs/btrfs/file.c41
-rw-r--r--fs/btrfs/inode.c189
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,
1908int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode); 1908int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode);
1909int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode); 1909int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode);
1910void btrfs_orphan_cleanup(struct btrfs_root *root); 1910void btrfs_orphan_cleanup(struct btrfs_root *root);
1911int btrfs_cont_expand(struct inode *inode, loff_t size);
1911 1912
1912/* ioctl.c */ 1913/* ioctl.c */
1913long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); 1914long 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
15struct extent_map { 16struct 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 }
194failed:
195 err = btrfs_end_transaction(trans, root); 160 err = btrfs_end_transaction(trans, root);
196out_unlock: 161out_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 *));
701again: 672again:
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
2299static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) 2299int 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; 2364static 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 }
2368out: 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);
2373fail:
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;
3571not_found_em: 3581not_found_em:
3572 em->block_start = EXTENT_MAP_HOLE; 3582 em->block_start = EXTENT_MAP_HOLE;
3583 set_bit(EXTENT_FLAG_VACANCY, &em->flags);
3573insert: 3584insert:
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) {