aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r--fs/btrfs/file.c148
1 files changed, 147 insertions, 1 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index fa4ef18b66b1..bd4d061c6e4d 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1664,8 +1664,154 @@ out:
1664 return ret; 1664 return ret;
1665} 1665}
1666 1666
1667static int find_desired_extent(struct inode *inode, loff_t *offset, int origin)
1668{
1669 struct btrfs_root *root = BTRFS_I(inode)->root;
1670 struct extent_map *em;
1671 struct extent_state *cached_state = NULL;
1672 u64 lockstart = *offset;
1673 u64 lockend = i_size_read(inode);
1674 u64 start = *offset;
1675 u64 orig_start = *offset;
1676 u64 len = i_size_read(inode);
1677 u64 last_end = 0;
1678 int ret = 0;
1679
1680 lockend = max_t(u64, root->sectorsize, lockend);
1681 if (lockend <= lockstart)
1682 lockend = lockstart + root->sectorsize;
1683
1684 len = lockend - lockstart + 1;
1685
1686 len = max_t(u64, len, root->sectorsize);
1687 if (inode->i_size == 0)
1688 return -ENXIO;
1689
1690 lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, 0,
1691 &cached_state, GFP_NOFS);
1692
1693 /*
1694 * Delalloc is such a pain. If we have a hole and we have pending
1695 * delalloc for a portion of the hole we will get back a hole that
1696 * exists for the entire range since it hasn't been actually written
1697 * yet. So to take care of this case we need to look for an extent just
1698 * before the position we want in case there is outstanding delalloc
1699 * going on here.
1700 */
1701 if (origin == SEEK_HOLE && start != 0) {
1702 if (start <= root->sectorsize)
1703 em = btrfs_get_extent_fiemap(inode, NULL, 0, 0,
1704 root->sectorsize, 0);
1705 else
1706 em = btrfs_get_extent_fiemap(inode, NULL, 0,
1707 start - root->sectorsize,
1708 root->sectorsize, 0);
1709 if (IS_ERR(em)) {
1710 ret = -ENXIO;
1711 goto out;
1712 }
1713 last_end = em->start + em->len;
1714 if (em->block_start == EXTENT_MAP_DELALLOC)
1715 last_end = min_t(u64, last_end, inode->i_size);
1716 free_extent_map(em);
1717 }
1718
1719 while (1) {
1720 em = btrfs_get_extent_fiemap(inode, NULL, 0, start, len, 0);
1721 if (IS_ERR(em)) {
1722 ret = -ENXIO;
1723 break;
1724 }
1725
1726 if (em->block_start == EXTENT_MAP_HOLE) {
1727 if (test_bit(EXTENT_FLAG_VACANCY, &em->flags)) {
1728 if (last_end <= orig_start) {
1729 free_extent_map(em);
1730 ret = -ENXIO;
1731 break;
1732 }
1733 }
1734
1735 if (origin == SEEK_HOLE) {
1736 *offset = start;
1737 free_extent_map(em);
1738 break;
1739 }
1740 } else {
1741 if (origin == SEEK_DATA) {
1742 if (em->block_start == EXTENT_MAP_DELALLOC) {
1743 if (start >= inode->i_size) {
1744 free_extent_map(em);
1745 ret = -ENXIO;
1746 break;
1747 }
1748 }
1749
1750 *offset = start;
1751 free_extent_map(em);
1752 break;
1753 }
1754 }
1755
1756 start = em->start + em->len;
1757 last_end = em->start + em->len;
1758
1759 if (em->block_start == EXTENT_MAP_DELALLOC)
1760 last_end = min_t(u64, last_end, inode->i_size);
1761
1762 if (test_bit(EXTENT_FLAG_VACANCY, &em->flags)) {
1763 free_extent_map(em);
1764 ret = -ENXIO;
1765 break;
1766 }
1767 free_extent_map(em);
1768 cond_resched();
1769 }
1770 if (!ret)
1771 *offset = min(*offset, inode->i_size);
1772out:
1773 unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,
1774 &cached_state, GFP_NOFS);
1775 return ret;
1776}
1777
1778static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int origin)
1779{
1780 struct inode *inode = file->f_mapping->host;
1781 int ret;
1782
1783 mutex_lock(&inode->i_mutex);
1784 switch (origin) {
1785 case SEEK_END:
1786 case SEEK_CUR:
1787 offset = generic_file_llseek_unlocked(file, offset, origin);
1788 goto out;
1789 case SEEK_DATA:
1790 case SEEK_HOLE:
1791 ret = find_desired_extent(inode, &offset, origin);
1792 if (ret) {
1793 mutex_unlock(&inode->i_mutex);
1794 return ret;
1795 }
1796 }
1797
1798 if (offset < 0 && !(file->f_mode & FMODE_UNSIGNED_OFFSET))
1799 return -EINVAL;
1800 if (offset > inode->i_sb->s_maxbytes)
1801 return -EINVAL;
1802
1803 /* Special lock needed here? */
1804 if (offset != file->f_pos) {
1805 file->f_pos = offset;
1806 file->f_version = 0;
1807 }
1808out:
1809 mutex_unlock(&inode->i_mutex);
1810 return offset;
1811}
1812
1667const struct file_operations btrfs_file_operations = { 1813const struct file_operations btrfs_file_operations = {
1668 .llseek = generic_file_llseek, 1814 .llseek = btrfs_file_llseek,
1669 .read = do_sync_read, 1815 .read = do_sync_read,
1670 .write = do_sync_write, 1816 .write = do_sync_write,
1671 .aio_read = generic_file_aio_read, 1817 .aio_read = generic_file_aio_read,