aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/disk-io.c1
-rw-r--r--fs/btrfs/file.c2
-rw-r--r--fs/btrfs/inode.c10
4 files changed, 13 insertions, 1 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index cd75c906048f..03e1c4ad341b 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -333,6 +333,7 @@ struct btrfs_root {
333 struct inode *inode; 333 struct inode *inode;
334 struct kobject root_kobj; 334 struct kobject root_kobj;
335 struct completion kobj_unregister; 335 struct completion kobj_unregister;
336 struct rw_semaphore snap_sem;
336 u64 objectid; 337 u64 objectid;
337 u64 last_trans; 338 u64 last_trans;
338 u32 blocksize; 339 u32 blocksize;
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index c25ef0a68f18..6c953a0e0aa3 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -300,6 +300,7 @@ static int __setup_root(int blocksize,
300 memset(&root->defrag_progress, 0, sizeof(root->defrag_progress)); 300 memset(&root->defrag_progress, 0, sizeof(root->defrag_progress));
301 memset(&root->root_kobj, 0, sizeof(root->root_kobj)); 301 memset(&root->root_kobj, 0, sizeof(root->root_kobj));
302 init_completion(&root->kobj_unregister); 302 init_completion(&root->kobj_unregister);
303 init_rwsem(&root->snap_sem);
303 root->defrag_running = 0; 304 root->defrag_running = 0;
304 root->defrag_level = 0; 305 root->defrag_level = 0;
305 root->root_key.objectid = objectid; 306 root->root_key.objectid = objectid;
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index acef8cb7fb79..77f1950b0aa0 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -160,6 +160,7 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
160 num_blocks = (write_bytes + pos - start_pos + root->blocksize - 1) >> 160 num_blocks = (write_bytes + pos - start_pos + root->blocksize - 1) >>
161 inode->i_blkbits; 161 inode->i_blkbits;
162 162
163 down_read(&BTRFS_I(inode)->root->snap_sem);
163 end_of_last_block = start_pos + (num_blocks << inode->i_blkbits) - 1; 164 end_of_last_block = start_pos + (num_blocks << inode->i_blkbits) - 1;
164 lock_extent(em_tree, start_pos, end_of_last_block, GFP_NOFS); 165 lock_extent(em_tree, start_pos, end_of_last_block, GFP_NOFS);
165 mutex_lock(&root->fs_info->fs_mutex); 166 mutex_lock(&root->fs_info->fs_mutex);
@@ -250,6 +251,7 @@ out_unlock:
250 mutex_unlock(&root->fs_info->fs_mutex); 251 mutex_unlock(&root->fs_info->fs_mutex);
251 unlock_extent(em_tree, start_pos, end_of_last_block, GFP_NOFS); 252 unlock_extent(em_tree, start_pos, end_of_last_block, GFP_NOFS);
252 free_extent_map(em); 253 free_extent_map(em);
254 up_read(&BTRFS_I(inode)->root->snap_sem);
253 return err; 255 return err;
254} 256}
255 257
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}