diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-08-30 11:54:02 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-08-30 11:54:02 -0400 |
commit | 2bf5a725a3b82efeaf7b292c085e69a9388a89ea (patch) | |
tree | 47f76cf43ba6cea2e07fc34d708ac2915d6bdaa9 /fs | |
parent | 07157aacb1ecd394a5494910b5f80d7e7d407d37 (diff) |
Btrfs: fsx delalloc fixes
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/extent_map.c | 9 | ||||
-rw-r--r-- | fs/btrfs/file.c | 26 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 177 |
3 files changed, 38 insertions, 174 deletions
diff --git a/fs/btrfs/extent_map.c b/fs/btrfs/extent_map.c index 6053f9db0739..8ad6f8efc5a0 100644 --- a/fs/btrfs/extent_map.c +++ b/fs/btrfs/extent_map.c | |||
@@ -77,6 +77,8 @@ EXPORT_SYMBOL(alloc_extent_map); | |||
77 | 77 | ||
78 | void free_extent_map(struct extent_map *em) | 78 | void free_extent_map(struct extent_map *em) |
79 | { | 79 | { |
80 | if (!em) | ||
81 | return; | ||
80 | if (atomic_dec_and_test(&em->refs)) { | 82 | if (atomic_dec_and_test(&em->refs)) { |
81 | WARN_ON(em->in_tree); | 83 | WARN_ON(em->in_tree); |
82 | kmem_cache_free(extent_map_cache, em); | 84 | kmem_cache_free(extent_map_cache, em); |
@@ -102,6 +104,8 @@ EXPORT_SYMBOL(alloc_extent_state); | |||
102 | 104 | ||
103 | void free_extent_state(struct extent_state *state) | 105 | void free_extent_state(struct extent_state *state) |
104 | { | 106 | { |
107 | if (!state) | ||
108 | return; | ||
105 | if (atomic_dec_and_test(&state->refs)) { | 109 | if (atomic_dec_and_test(&state->refs)) { |
106 | WARN_ON(state->in_tree); | 110 | WARN_ON(state->in_tree); |
107 | kmem_cache_free(extent_state_cache, state); | 111 | kmem_cache_free(extent_state_cache, state); |
@@ -1395,8 +1399,8 @@ int extent_read_full_page(struct extent_map_tree *tree, struct page *page, | |||
1395 | 1399 | ||
1396 | if (!PagePrivate(page)) { | 1400 | if (!PagePrivate(page)) { |
1397 | SetPagePrivate(page); | 1401 | SetPagePrivate(page); |
1398 | set_page_private(page, 1); | ||
1399 | WARN_ON(!page->mapping->a_ops->invalidatepage); | 1402 | WARN_ON(!page->mapping->a_ops->invalidatepage); |
1403 | set_page_private(page, 1); | ||
1400 | page_cache_get(page); | 1404 | page_cache_get(page); |
1401 | } | 1405 | } |
1402 | 1406 | ||
@@ -1638,7 +1642,8 @@ int extent_invalidatepage(struct extent_map_tree *tree, | |||
1638 | 1642 | ||
1639 | lock_extent(tree, start, end, GFP_NOFS); | 1643 | lock_extent(tree, start, end, GFP_NOFS); |
1640 | wait_on_extent_writeback(tree, start, end); | 1644 | wait_on_extent_writeback(tree, start, end); |
1641 | clear_extent_bit(tree, start, end, EXTENT_LOCKED | EXTENT_DIRTY, | 1645 | clear_extent_bit(tree, start, end, |
1646 | EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC, | ||
1642 | 1, 1, GFP_NOFS); | 1647 | 1, 1, GFP_NOFS); |
1643 | return 0; | 1648 | return 0; |
1644 | } | 1649 | } |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index d3d39e4a2797..07b121d4bd93 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -186,8 +186,16 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
186 | u64 mask = root->blocksize - 1; | 186 | u64 mask = root->blocksize - 1; |
187 | last_pos_in_file = (isize + mask) & ~mask; | 187 | last_pos_in_file = (isize + mask) & ~mask; |
188 | hole_size = (start_pos - last_pos_in_file + mask) & ~mask; | 188 | hole_size = (start_pos - last_pos_in_file + mask) & ~mask; |
189 | hole_size >>= inode->i_blkbits; | 189 | |
190 | if (last_pos_in_file < start_pos) { | 190 | if (last_pos_in_file < start_pos) { |
191 | err = btrfs_drop_extents(trans, root, inode, | ||
192 | last_pos_in_file, | ||
193 | last_pos_in_file + hole_size, | ||
194 | &hint_block); | ||
195 | if (err) | ||
196 | goto failed; | ||
197 | |||
198 | hole_size >>= inode->i_blkbits; | ||
191 | err = btrfs_insert_file_extent(trans, root, | 199 | err = btrfs_insert_file_extent(trans, root, |
192 | inode->i_ino, | 200 | inode->i_ino, |
193 | last_pos_in_file, | 201 | last_pos_in_file, |
@@ -217,13 +225,11 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
217 | struct page *p = pages[0]; | 225 | struct page *p = pages[0]; |
218 | /* step one, delete the existing extents in this range */ | 226 | /* step one, delete the existing extents in this range */ |
219 | /* FIXME blocksize != pagesize */ | 227 | /* FIXME blocksize != pagesize */ |
220 | if (start_pos < inode->i_size) { | 228 | err = btrfs_drop_extents(trans, root, inode, start_pos, |
221 | err = btrfs_drop_extents(trans, root, inode, start_pos, | 229 | (pos + write_bytes + root->blocksize -1) & |
222 | (pos + write_bytes + root->blocksize -1) & | 230 | ~((u64)root->blocksize - 1), &hint_block); |
223 | ~((u64)root->blocksize - 1), &hint_block); | 231 | if (err) |
224 | if (err) | 232 | goto failed; |
225 | goto failed; | ||
226 | } | ||
227 | 233 | ||
228 | err = insert_inline_extent(trans, root, inode, start_pos, | 234 | err = insert_inline_extent(trans, root, inode, start_pos, |
229 | end_pos - start_pos, p, 0); | 235 | end_pos - start_pos, p, 0); |
@@ -400,6 +406,8 @@ next_slot: | |||
400 | keep = 1; | 406 | keep = 1; |
401 | WARN_ON(start & (root->blocksize - 1)); | 407 | WARN_ON(start & (root->blocksize - 1)); |
402 | if (found_extent) { | 408 | if (found_extent) { |
409 | btrfs_drop_extent_cache(inode, key.offset, | ||
410 | start - 1 ); | ||
403 | new_num = (start - key.offset) >> | 411 | new_num = (start - key.offset) >> |
404 | inode->i_blkbits; | 412 | inode->i_blkbits; |
405 | old_num = btrfs_file_extent_num_blocks(extent); | 413 | old_num = btrfs_file_extent_num_blocks(extent); |
@@ -464,7 +472,7 @@ next_slot: | |||
464 | 472 | ||
465 | if (ret) { | 473 | if (ret) { |
466 | btrfs_print_leaf(root, btrfs_buffer_leaf(path->nodes[0])); | 474 | btrfs_print_leaf(root, btrfs_buffer_leaf(path->nodes[0])); |
467 | printk("got %d on inserting %Lu %u %Lu start %Lu end %Lu found %Lu %Lu\n", ret , ins.objectid, ins.flags, ins.offset, start, end, key.offset, extent_end); | 475 | printk("got %d on inserting %Lu %u %Lu start %Lu end %Lu found %Lu %Lu keep was %d\n", ret , ins.objectid, ins.flags, ins.offset, start, end, key.offset, extent_end, keep); |
468 | } | 476 | } |
469 | BUG_ON(ret); | 477 | BUG_ON(ret); |
470 | extent = btrfs_item_ptr( | 478 | extent = btrfs_item_ptr( |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 3ee6b2fadf58..64710fa77d01 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -721,25 +721,35 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
721 | attr->ia_valid & ATTR_SIZE && attr->ia_size > inode->i_size) { | 721 | attr->ia_valid & ATTR_SIZE && attr->ia_size > inode->i_size) { |
722 | struct btrfs_trans_handle *trans; | 722 | struct btrfs_trans_handle *trans; |
723 | struct btrfs_root *root = BTRFS_I(inode)->root; | 723 | struct btrfs_root *root = BTRFS_I(inode)->root; |
724 | struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; | ||
725 | |||
724 | u64 mask = root->blocksize - 1; | 726 | u64 mask = root->blocksize - 1; |
725 | u64 pos = (inode->i_size + mask) & ~mask; | 727 | u64 pos = (inode->i_size + mask) & ~mask; |
728 | u64 block_end = attr->ia_size | mask; | ||
726 | u64 hole_size; | 729 | u64 hole_size; |
730 | u64 alloc_hint; | ||
727 | 731 | ||
728 | if (attr->ia_size <= pos) | 732 | if (attr->ia_size <= pos) |
729 | goto out; | 733 | goto out; |
730 | 734 | ||
731 | btrfs_truncate_page(inode->i_mapping, inode->i_size); | 735 | btrfs_truncate_page(inode->i_mapping, inode->i_size); |
732 | 736 | ||
737 | lock_extent(em_tree, pos, block_end, GFP_NOFS); | ||
733 | hole_size = (attr->ia_size - pos + mask) & ~mask; | 738 | hole_size = (attr->ia_size - pos + mask) & ~mask; |
734 | hole_size >>= inode->i_blkbits; | ||
735 | 739 | ||
736 | mutex_lock(&root->fs_info->fs_mutex); | 740 | mutex_lock(&root->fs_info->fs_mutex); |
737 | trans = btrfs_start_transaction(root, 1); | 741 | trans = btrfs_start_transaction(root, 1); |
738 | btrfs_set_trans_block_group(trans, inode); | 742 | btrfs_set_trans_block_group(trans, inode); |
743 | err = btrfs_drop_extents(trans, root, inode, | ||
744 | pos, pos + hole_size, &alloc_hint); | ||
745 | |||
746 | hole_size >>= inode->i_blkbits; | ||
747 | |||
739 | err = btrfs_insert_file_extent(trans, root, inode->i_ino, | 748 | err = btrfs_insert_file_extent(trans, root, inode->i_ino, |
740 | pos, 0, 0, hole_size); | 749 | pos, 0, 0, hole_size); |
741 | btrfs_end_transaction(trans, root); | 750 | btrfs_end_transaction(trans, root); |
742 | mutex_unlock(&root->fs_info->fs_mutex); | 751 | mutex_unlock(&root->fs_info->fs_mutex); |
752 | unlock_extent(em_tree, pos, block_end, GFP_NOFS); | ||
743 | if (err) | 753 | if (err) |
744 | return err; | 754 | return err; |
745 | } | 755 | } |
@@ -1529,13 +1539,13 @@ insert: | |||
1529 | ret = add_extent_mapping(em_tree, em); | 1539 | ret = add_extent_mapping(em_tree, em); |
1530 | if (ret == -EEXIST) { | 1540 | if (ret == -EEXIST) { |
1531 | free_extent_map(em); | 1541 | free_extent_map(em); |
1542 | em = NULL; | ||
1532 | failed_insert++; | 1543 | failed_insert++; |
1533 | if (failed_insert > 5) { | 1544 | if (failed_insert > 5) { |
1534 | printk("failing to insert %Lu %Lu\n", start, end); | 1545 | printk("failing to insert %Lu %Lu\n", start, end); |
1535 | err = -EIO; | 1546 | err = -EIO; |
1536 | goto out; | 1547 | goto out; |
1537 | } | 1548 | } |
1538 | em = NULL; | ||
1539 | goto again; | 1549 | goto again; |
1540 | } | 1550 | } |
1541 | err = 0; | 1551 | err = 0; |
@@ -1555,167 +1565,6 @@ out: | |||
1555 | return em; | 1565 | return em; |
1556 | } | 1566 | } |
1557 | 1567 | ||
1558 | |||
1559 | /* | ||
1560 | * FIBMAP and others want to pass in a fake buffer head. They need to | ||
1561 | * use BTRFS_GET_BLOCK_NO_DIRECT to make sure we don't try to memcpy | ||
1562 | * any packed file data into the fake bh | ||
1563 | */ | ||
1564 | #define BTRFS_GET_BLOCK_NO_CREATE 0 | ||
1565 | #define BTRFS_GET_BLOCK_CREATE 1 | ||
1566 | #define BTRFS_GET_BLOCK_NO_DIRECT 2 | ||
1567 | |||
1568 | /* | ||
1569 | * FIXME create==1 doe not work. | ||
1570 | */ | ||
1571 | static int btrfs_get_block_lock(struct inode *inode, sector_t iblock, | ||
1572 | struct buffer_head *result, int create) | ||
1573 | { | ||
1574 | int ret; | ||
1575 | int err = 0; | ||
1576 | u64 blocknr; | ||
1577 | u64 extent_start = 0; | ||
1578 | u64 extent_end = 0; | ||
1579 | u64 objectid = inode->i_ino; | ||
1580 | u32 found_type; | ||
1581 | u64 alloc_hint = 0; | ||
1582 | struct btrfs_path *path; | ||
1583 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
1584 | struct btrfs_file_extent_item *item; | ||
1585 | struct btrfs_leaf *leaf; | ||
1586 | struct btrfs_disk_key *found_key; | ||
1587 | struct btrfs_trans_handle *trans = NULL; | ||
1588 | |||
1589 | path = btrfs_alloc_path(); | ||
1590 | BUG_ON(!path); | ||
1591 | if (create & BTRFS_GET_BLOCK_CREATE) { | ||
1592 | /* | ||
1593 | * danger!, this only works if the page is properly up | ||
1594 | * to date somehow | ||
1595 | */ | ||
1596 | trans = btrfs_start_transaction(root, 1); | ||
1597 | if (!trans) { | ||
1598 | err = -ENOMEM; | ||
1599 | goto out; | ||
1600 | } | ||
1601 | ret = btrfs_drop_extents(trans, root, inode, | ||
1602 | iblock << inode->i_blkbits, | ||
1603 | (iblock + 1) << inode->i_blkbits, | ||
1604 | &alloc_hint); | ||
1605 | BUG_ON(ret); | ||
1606 | } | ||
1607 | |||
1608 | ret = btrfs_lookup_file_extent(NULL, root, path, | ||
1609 | objectid, | ||
1610 | iblock << inode->i_blkbits, 0); | ||
1611 | if (ret < 0) { | ||
1612 | err = ret; | ||
1613 | goto out; | ||
1614 | } | ||
1615 | |||
1616 | if (ret != 0) { | ||
1617 | if (path->slots[0] == 0) { | ||
1618 | btrfs_release_path(root, path); | ||
1619 | goto not_found; | ||
1620 | } | ||
1621 | path->slots[0]--; | ||
1622 | } | ||
1623 | |||
1624 | item = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), path->slots[0], | ||
1625 | struct btrfs_file_extent_item); | ||
1626 | leaf = btrfs_buffer_leaf(path->nodes[0]); | ||
1627 | blocknr = btrfs_file_extent_disk_blocknr(item); | ||
1628 | blocknr += btrfs_file_extent_offset(item); | ||
1629 | |||
1630 | /* are we inside the extent that was found? */ | ||
1631 | found_key = &leaf->items[path->slots[0]].key; | ||
1632 | found_type = btrfs_disk_key_type(found_key); | ||
1633 | if (btrfs_disk_key_objectid(found_key) != objectid || | ||
1634 | found_type != BTRFS_EXTENT_DATA_KEY) { | ||
1635 | extent_end = 0; | ||
1636 | extent_start = 0; | ||
1637 | goto not_found; | ||
1638 | } | ||
1639 | found_type = btrfs_file_extent_type(item); | ||
1640 | extent_start = btrfs_disk_key_offset(&leaf->items[path->slots[0]].key); | ||
1641 | if (found_type == BTRFS_FILE_EXTENT_REG) { | ||
1642 | extent_start = extent_start >> inode->i_blkbits; | ||
1643 | extent_end = extent_start + btrfs_file_extent_num_blocks(item); | ||
1644 | err = 0; | ||
1645 | if (btrfs_file_extent_disk_blocknr(item) == 0) | ||
1646 | goto out; | ||
1647 | if (iblock >= extent_start && iblock < extent_end) { | ||
1648 | btrfs_map_bh_to_logical(root, result, blocknr + | ||
1649 | iblock - extent_start); | ||
1650 | goto out; | ||
1651 | } | ||
1652 | } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { | ||
1653 | char *ptr; | ||
1654 | char *map; | ||
1655 | u32 size; | ||
1656 | |||
1657 | if (create & BTRFS_GET_BLOCK_NO_DIRECT) { | ||
1658 | err = -EINVAL; | ||
1659 | goto out; | ||
1660 | } | ||
1661 | size = btrfs_file_extent_inline_len(leaf->items + | ||
1662 | path->slots[0]); | ||
1663 | extent_end = (extent_start + size) >> inode->i_blkbits; | ||
1664 | extent_start >>= inode->i_blkbits; | ||
1665 | if (iblock < extent_start || iblock > extent_end) { | ||
1666 | goto not_found; | ||
1667 | } | ||
1668 | ptr = btrfs_file_extent_inline_start(item); | ||
1669 | map = kmap(result->b_page); | ||
1670 | memcpy(map, ptr, size); | ||
1671 | memset(map + size, 0, PAGE_CACHE_SIZE - size); | ||
1672 | flush_dcache_page(result->b_page); | ||
1673 | kunmap(result->b_page); | ||
1674 | set_buffer_uptodate(result); | ||
1675 | SetPageChecked(result->b_page); | ||
1676 | btrfs_map_bh_to_logical(root, result, 0); | ||
1677 | } | ||
1678 | not_found: | ||
1679 | if (create & BTRFS_GET_BLOCK_CREATE) { | ||
1680 | struct btrfs_key ins; | ||
1681 | ret = btrfs_alloc_extent(trans, root, inode->i_ino, | ||
1682 | 1, 0, alloc_hint, (u64)-1, | ||
1683 | &ins, 1); | ||
1684 | if (ret) { | ||
1685 | err = ret; | ||
1686 | goto out; | ||
1687 | } | ||
1688 | ret = btrfs_insert_file_extent(trans, root, inode->i_ino, | ||
1689 | iblock << inode->i_blkbits, | ||
1690 | ins.objectid, ins.offset, | ||
1691 | ins.offset); | ||
1692 | if (ret) { | ||
1693 | err = ret; | ||
1694 | goto out; | ||
1695 | } | ||
1696 | btrfs_map_bh_to_logical(root, result, ins.objectid); | ||
1697 | } | ||
1698 | out: | ||
1699 | if (trans) { | ||
1700 | ret = btrfs_end_transaction(trans, root); | ||
1701 | if (!err) | ||
1702 | err = ret; | ||
1703 | } | ||
1704 | btrfs_free_path(path); | ||
1705 | return err; | ||
1706 | } | ||
1707 | |||
1708 | int btrfs_get_block(struct inode *inode, sector_t iblock, | ||
1709 | struct buffer_head *result, int create) | ||
1710 | { | ||
1711 | int err; | ||
1712 | struct btrfs_root *root = BTRFS_I(inode)->root; | ||
1713 | mutex_lock(&root->fs_info->fs_mutex); | ||
1714 | err = btrfs_get_block_lock(inode, iblock, result, create); | ||
1715 | mutex_unlock(&root->fs_info->fs_mutex); | ||
1716 | return err; | ||
1717 | } | ||
1718 | |||
1719 | static int btrfs_get_block_bmap(struct inode *inode, sector_t iblock, | 1568 | static int btrfs_get_block_bmap(struct inode *inode, sector_t iblock, |
1720 | struct buffer_head *result, int create) | 1569 | struct buffer_head *result, int create) |
1721 | { | 1570 | { |
@@ -2469,6 +2318,8 @@ static struct address_space_operations btrfs_aops = { | |||
2469 | static struct address_space_operations btrfs_symlink_aops = { | 2318 | static struct address_space_operations btrfs_symlink_aops = { |
2470 | .readpage = btrfs_readpage, | 2319 | .readpage = btrfs_readpage, |
2471 | .writepage = btrfs_writepage, | 2320 | .writepage = btrfs_writepage, |
2321 | .invalidatepage = btrfs_invalidatepage, | ||
2322 | .releasepage = btrfs_releasepage, | ||
2472 | }; | 2323 | }; |
2473 | 2324 | ||
2474 | static struct inode_operations btrfs_file_inode_operations = { | 2325 | static struct inode_operations btrfs_file_inode_operations = { |