aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/inode.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-09-10 19:58:36 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-09-10 19:58:36 -0400
commit011410bd859a481a335d7db1fb559542c5663fd5 (patch)
tree39b7d65352f49abe4eeb9cabd3b19d1b50faf9a2 /fs/btrfs/inode.c
parent86479a04eef8f304a13aeb8b64bcc8e506a68268 (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.c10
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);
707out: 709out:
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
1690out_unlock: 1693out_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
1898fail: 1905fail:
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}