diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-11-01 11:28:41 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:03:57 -0400 |
commit | 179e29e488cc74f1e9bd67bc45f70b832740e9ec (patch) | |
tree | aa055d77b8d3f2b4bc59b1bb8a5b98ec0b223fb5 /fs/btrfs/inode.c | |
parent | 35ebb934bd7fcc7ca991b155b7980c3c4ff9f1a5 (diff) |
Btrfs: Fix a number of inline extent problems that Yan Zheng reported.
The fixes do a number of things:
1) Most btrfs_drop_extent callers will try to leave the inline extents in
place. It can truncate bytes off the beginning of the inline extent if
required.
2) writepage can now update the inline extent, allowing mmap writes to
go directly into the inline extent.
3) btrfs_truncate_in_transaction truncates inline extents
4) extent_map.c fixed to not merge inline extent mappings and hole
mappings together
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 67 |
1 files changed, 48 insertions, 19 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5d10b64e42df..0c65141b9993 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -89,6 +89,9 @@ static int run_delalloc_range(struct inode *inode, u64 start, u64 end) | |||
89 | ret = btrfs_drop_extents(trans, root, inode, | 89 | ret = btrfs_drop_extents(trans, root, inode, |
90 | start, start + num_bytes, start, &alloc_hint); | 90 | start, start + num_bytes, start, &alloc_hint); |
91 | 91 | ||
92 | if (alloc_hint == EXTENT_MAP_INLINE) | ||
93 | goto out; | ||
94 | |||
92 | ret = btrfs_alloc_extent(trans, root, inode->i_ino, num_bytes, 0, | 95 | ret = btrfs_alloc_extent(trans, root, inode->i_ino, num_bytes, 0, |
93 | alloc_hint, (u64)-1, &ins, 1); | 96 | alloc_hint, (u64)-1, &ins, 1); |
94 | if (ret) { | 97 | if (ret) { |
@@ -558,6 +561,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
558 | u64 item_end = 0; | 561 | u64 item_end = 0; |
559 | int found_extent; | 562 | int found_extent; |
560 | int del_item; | 563 | int del_item; |
564 | int extent_type = -1; | ||
561 | 565 | ||
562 | btrfs_drop_extent_cache(inode, inode->i_size, (u64)-1); | 566 | btrfs_drop_extent_cache(inode, inode->i_size, (u64)-1); |
563 | path = btrfs_alloc_path(); | 567 | path = btrfs_alloc_path(); |
@@ -597,10 +601,15 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
597 | if (found_type == BTRFS_EXTENT_DATA_KEY) { | 601 | if (found_type == BTRFS_EXTENT_DATA_KEY) { |
598 | fi = btrfs_item_ptr(leaf, path->slots[0], | 602 | fi = btrfs_item_ptr(leaf, path->slots[0], |
599 | struct btrfs_file_extent_item); | 603 | struct btrfs_file_extent_item); |
600 | if (btrfs_file_extent_type(leaf, fi) != | 604 | extent_type = btrfs_file_extent_type(leaf, fi); |
601 | BTRFS_FILE_EXTENT_INLINE) { | 605 | if (extent_type != BTRFS_FILE_EXTENT_INLINE) { |
602 | item_end += | 606 | item_end += |
603 | btrfs_file_extent_num_bytes(leaf, fi); | 607 | btrfs_file_extent_num_bytes(leaf, fi); |
608 | } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { | ||
609 | struct btrfs_item *item = btrfs_item_nr(leaf, | ||
610 | path->slots[0]); | ||
611 | item_end += btrfs_file_extent_inline_len(leaf, | ||
612 | item); | ||
604 | } | 613 | } |
605 | } | 614 | } |
606 | if (found_type == BTRFS_CSUM_ITEM_KEY) { | 615 | if (found_type == BTRFS_CSUM_ITEM_KEY) { |
@@ -608,7 +617,7 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
608 | inode->i_size); | 617 | inode->i_size); |
609 | BUG_ON(ret); | 618 | BUG_ON(ret); |
610 | } | 619 | } |
611 | if (item_end < inode->i_size) { | 620 | if (item_end <= inode->i_size) { |
612 | if (found_type == BTRFS_DIR_ITEM_KEY) { | 621 | if (found_type == BTRFS_DIR_ITEM_KEY) { |
613 | found_type = BTRFS_INODE_ITEM_KEY; | 622 | found_type = BTRFS_INODE_ITEM_KEY; |
614 | } else if (found_type == BTRFS_EXTENT_ITEM_KEY) { | 623 | } else if (found_type == BTRFS_EXTENT_ITEM_KEY) { |
@@ -629,9 +638,10 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
629 | found_extent = 0; | 638 | found_extent = 0; |
630 | 639 | ||
631 | /* FIXME, shrink the extent if the ref count is only 1 */ | 640 | /* FIXME, shrink the extent if the ref count is only 1 */ |
632 | if (found_type == BTRFS_EXTENT_DATA_KEY && | 641 | if (found_type != BTRFS_EXTENT_DATA_KEY) |
633 | btrfs_file_extent_type(leaf, fi) != | 642 | goto delete; |
634 | BTRFS_FILE_EXTENT_INLINE) { | 643 | |
644 | if (extent_type != BTRFS_FILE_EXTENT_INLINE) { | ||
635 | u64 num_dec; | 645 | u64 num_dec; |
636 | extent_start = btrfs_file_extent_disk_bytenr(leaf, fi); | 646 | extent_start = btrfs_file_extent_disk_bytenr(leaf, fi); |
637 | if (!del_item) { | 647 | if (!del_item) { |
@@ -659,7 +669,15 @@ static int btrfs_truncate_in_trans(struct btrfs_trans_handle *trans, | |||
659 | inode->i_blocks -= num_dec; | 669 | inode->i_blocks -= num_dec; |
660 | } | 670 | } |
661 | } | 671 | } |
672 | } else if (extent_type == BTRFS_FILE_EXTENT_INLINE && | ||
673 | !del_item) { | ||
674 | u32 newsize = inode->i_size - found_key.offset; | ||
675 | newsize = btrfs_file_extent_calc_inline_size(newsize); | ||
676 | ret = btrfs_truncate_item(trans, root, path, | ||
677 | newsize, 1); | ||
678 | BUG_ON(ret); | ||
662 | } | 679 | } |
680 | delete: | ||
663 | if (del_item) { | 681 | if (del_item) { |
664 | ret = btrfs_del_item(trans, root, path); | 682 | ret = btrfs_del_item(trans, root, path); |
665 | if (ret) | 683 | if (ret) |
@@ -769,7 +787,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
769 | u64 pos = (inode->i_size + mask) & ~mask; | 787 | u64 pos = (inode->i_size + mask) & ~mask; |
770 | u64 block_end = attr->ia_size | mask; | 788 | u64 block_end = attr->ia_size | mask; |
771 | u64 hole_size; | 789 | u64 hole_size; |
772 | u64 alloc_hint; | 790 | u64 alloc_hint = 0; |
773 | 791 | ||
774 | if (attr->ia_size <= pos) | 792 | if (attr->ia_size <= pos) |
775 | goto out; | 793 | goto out; |
@@ -786,8 +804,11 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
786 | pos, pos + hole_size, pos, | 804 | pos, pos + hole_size, pos, |
787 | &alloc_hint); | 805 | &alloc_hint); |
788 | 806 | ||
789 | err = btrfs_insert_file_extent(trans, root, inode->i_ino, | 807 | if (alloc_hint != EXTENT_MAP_INLINE) { |
790 | pos, 0, 0, hole_size); | 808 | err = btrfs_insert_file_extent(trans, root, |
809 | inode->i_ino, | ||
810 | pos, 0, 0, hole_size); | ||
811 | } | ||
791 | btrfs_end_transaction(trans, root); | 812 | btrfs_end_transaction(trans, root); |
792 | mutex_unlock(&root->fs_info->fs_mutex); | 813 | mutex_unlock(&root->fs_info->fs_mutex); |
793 | unlock_extent(em_tree, pos, block_end, GFP_NOFS); | 814 | unlock_extent(em_tree, pos, block_end, GFP_NOFS); |
@@ -1531,8 +1552,8 @@ again: | |||
1531 | em->end = EXTENT_MAP_HOLE; | 1552 | em->end = EXTENT_MAP_HOLE; |
1532 | } | 1553 | } |
1533 | em->bdev = inode->i_sb->s_bdev; | 1554 | em->bdev = inode->i_sb->s_bdev; |
1534 | ret = btrfs_lookup_file_extent(NULL, root, path, | 1555 | ret = btrfs_lookup_file_extent(trans, root, path, |
1535 | objectid, start, 0); | 1556 | objectid, start, trans != NULL); |
1536 | if (ret < 0) { | 1557 | if (ret < 0) { |
1537 | err = ret; | 1558 | err = ret; |
1538 | goto out; | 1559 | goto out; |
@@ -1627,15 +1648,23 @@ again: | |||
1627 | ((u64)root->sectorsize -1); | 1648 | ((u64)root->sectorsize -1); |
1628 | map = kmap(page); | 1649 | map = kmap(page); |
1629 | ptr = btrfs_file_extent_inline_start(item) + extent_offset; | 1650 | ptr = btrfs_file_extent_inline_start(item) + extent_offset; |
1630 | read_extent_buffer(leaf, map + page_offset, ptr, copy_size); | 1651 | if (create == 0 && !PageUptodate(page)) { |
1631 | 1652 | read_extent_buffer(leaf, map + page_offset, ptr, | |
1632 | if (em->start + copy_size <= em->end) { | 1653 | copy_size); |
1633 | size = min_t(u64, em->end + 1 - em->start, | 1654 | flush_dcache_page(page); |
1634 | PAGE_CACHE_SIZE - page_offset) - copy_size; | 1655 | } else if (create && PageUptodate(page)) { |
1635 | memset(map + page_offset + copy_size, 0, size); | 1656 | if (!trans) { |
1657 | kunmap(page); | ||
1658 | free_extent_map(em); | ||
1659 | em = NULL; | ||
1660 | btrfs_release_path(root, path); | ||
1661 | trans = btrfs_start_transaction(root, 1); | ||
1662 | goto again; | ||
1663 | } | ||
1664 | write_extent_buffer(leaf, map + page_offset, ptr, | ||
1665 | copy_size); | ||
1666 | btrfs_mark_buffer_dirty(leaf); | ||
1636 | } | 1667 | } |
1637 | |||
1638 | flush_dcache_page(page); | ||
1639 | kunmap(page); | 1668 | kunmap(page); |
1640 | set_extent_uptodate(em_tree, em->start, em->end, GFP_NOFS); | 1669 | set_extent_uptodate(em_tree, em->start, em->end, GFP_NOFS); |
1641 | goto insert; | 1670 | goto insert; |