diff options
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 177 |
1 files changed, 14 insertions, 163 deletions
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 = { |