diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-09-10 19:58:36 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-09-10 19:58:36 -0400 |
commit | 011410bd859a481a335d7db1fb559542c5663fd5 (patch) | |
tree | 39b7d65352f49abe4eeb9cabd3b19d1b50faf9a2 /fs/btrfs/inode.c | |
parent | 86479a04eef8f304a13aeb8b64bcc8e506a68268 (diff) |
Btrfs: Add more synchronization before creating a snapshot
File data checksums are only done during writepage, so we have to make sure
all pages are written when the snapshot is taken. This also adds some
locking so that new writes don't race in and add new dirty pages.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 10 |
1 files changed, 9 insertions, 1 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 6b3e4404dc6a..1ace6d11e097 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -686,6 +686,7 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from) | |||
686 | if ((offset & (blocksize - 1)) == 0) | 686 | if ((offset & (blocksize - 1)) == 0) |
687 | goto out; | 687 | goto out; |
688 | 688 | ||
689 | down_read(&BTRFS_I(inode)->root->snap_sem); | ||
689 | ret = -ENOMEM; | 690 | ret = -ENOMEM; |
690 | page = grab_cache_page(mapping, index); | 691 | page = grab_cache_page(mapping, index); |
691 | if (!page) | 692 | if (!page) |
@@ -704,6 +705,7 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from) | |||
704 | 705 | ||
705 | unlock_page(page); | 706 | unlock_page(page); |
706 | page_cache_release(page); | 707 | page_cache_release(page); |
708 | up_read(&BTRFS_I(inode)->root->snap_sem); | ||
707 | out: | 709 | out: |
708 | return ret; | 710 | return ret; |
709 | } | 711 | } |
@@ -1668,6 +1670,7 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page) | |||
1668 | int ret = -EINVAL; | 1670 | int ret = -EINVAL; |
1669 | u64 page_start; | 1671 | u64 page_start; |
1670 | 1672 | ||
1673 | down_read(&BTRFS_I(inode)->root->snap_sem); | ||
1671 | lock_page(page); | 1674 | lock_page(page); |
1672 | wait_on_page_writeback(page); | 1675 | wait_on_page_writeback(page); |
1673 | size = i_size_read(inode); | 1676 | size = i_size_read(inode); |
@@ -1688,6 +1691,7 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page) | |||
1688 | ret = btrfs_cow_one_page(inode, page, end); | 1691 | ret = btrfs_cow_one_page(inode, page, end); |
1689 | 1692 | ||
1690 | out_unlock: | 1693 | out_unlock: |
1694 | up_read(&BTRFS_I(inode)->root->snap_sem); | ||
1691 | unlock_page(page); | 1695 | unlock_page(page); |
1692 | return ret; | 1696 | return ret; |
1693 | } | 1697 | } |
@@ -1851,6 +1855,10 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen) | |||
1851 | if (!root->ref_cows) | 1855 | if (!root->ref_cows) |
1852 | return -EINVAL; | 1856 | return -EINVAL; |
1853 | 1857 | ||
1858 | down_write(&root->snap_sem); | ||
1859 | freeze_bdev(root->fs_info->sb->s_bdev); | ||
1860 | thaw_bdev(root->fs_info->sb->s_bdev, root->fs_info->sb); | ||
1861 | |||
1854 | mutex_lock(&root->fs_info->fs_mutex); | 1862 | mutex_lock(&root->fs_info->fs_mutex); |
1855 | trans = btrfs_start_transaction(root, 1); | 1863 | trans = btrfs_start_transaction(root, 1); |
1856 | BUG_ON(!trans); | 1864 | BUG_ON(!trans); |
@@ -1894,12 +1902,12 @@ static int create_snapshot(struct btrfs_root *root, char *name, int namelen) | |||
1894 | ret = btrfs_inc_root_ref(trans, root); | 1902 | ret = btrfs_inc_root_ref(trans, root); |
1895 | if (ret) | 1903 | if (ret) |
1896 | goto fail; | 1904 | goto fail; |
1897 | |||
1898 | fail: | 1905 | fail: |
1899 | err = btrfs_commit_transaction(trans, root); | 1906 | err = btrfs_commit_transaction(trans, root); |
1900 | if (err && !ret) | 1907 | if (err && !ret) |
1901 | ret = err; | 1908 | ret = err; |
1902 | mutex_unlock(&root->fs_info->fs_mutex); | 1909 | mutex_unlock(&root->fs_info->fs_mutex); |
1910 | up_write(&root->snap_sem); | ||
1903 | btrfs_btree_balance_dirty(root); | 1911 | btrfs_btree_balance_dirty(root); |
1904 | return ret; | 1912 | return ret; |
1905 | } | 1913 | } |