diff options
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; |