aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-11-01 11:28:41 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:03:57 -0400
commit179e29e488cc74f1e9bd67bc45f70b832740e9ec (patch)
treeaa055d77b8d3f2b4bc59b1bb8a5b98ec0b223fb5 /fs/btrfs/inode.c
parent35ebb934bd7fcc7ca991b155b7980c3c4ff9f1a5 (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.c67
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 }
680delete:
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;