diff options
Diffstat (limited to 'fs')
| -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 abb27332c91..ca5547af609 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 abbcbeb28c7..e693e1b4ac4 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 0aa15436590..b8a7637e14a 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 dd9cd01042b..8254d6fa691 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) { |
