aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMiao Xie <miaox@cn.fujitsu.com>2013-06-27 06:51:00 -0400
committerJosef Bacik <jbacik@fusionio.com>2013-07-02 11:50:58 -0400
commitedd1400be9f983f521c7397740d810fa210ee52f (patch)
tree519d72227701fbb03c368aca6bf75a850841483c /fs
parent826aa0a82c5b9d2c8016c02b552e8f82f5b1e660 (diff)
Btrfs: fix several potential problems in copy_nocow_pages_for_inode
- It makes no sense that we deal with a inode in the dead tree. - fix the race between dio and page copy by waiting the dio completion - avoid the page copy vs truncate/punch hole - check if the page is in the page cache or not Signed-off-by: Miao Xie <miaox@cn.fujitsu.com> Signed-off-by: Josef Bacik <jbacik@fusionio.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/scrub.c23
1 files changed, 22 insertions, 1 deletions
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 186ea82b75f7..4ba2a69a60ad 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -3224,6 +3224,11 @@ static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, void *ctx)
3224 return PTR_ERR(local_root); 3224 return PTR_ERR(local_root);
3225 } 3225 }
3226 3226
3227 if (btrfs_root_refs(&local_root->root_item) == 0) {
3228 srcu_read_unlock(&fs_info->subvol_srcu, srcu_index);
3229 return -ENOENT;
3230 }
3231
3227 key.type = BTRFS_INODE_ITEM_KEY; 3232 key.type = BTRFS_INODE_ITEM_KEY;
3228 key.objectid = inum; 3233 key.objectid = inum;
3229 key.offset = 0; 3234 key.offset = 0;
@@ -3232,12 +3237,16 @@ static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, void *ctx)
3232 if (IS_ERR(inode)) 3237 if (IS_ERR(inode))
3233 return PTR_ERR(inode); 3238 return PTR_ERR(inode);
3234 3239
3240 /* Avoid truncate/dio/punch hole.. */
3241 mutex_lock(&inode->i_mutex);
3242 inode_dio_wait(inode);
3243
3235 ret = 0; 3244 ret = 0;
3236 physical_for_dev_replace = nocow_ctx->physical_for_dev_replace; 3245 physical_for_dev_replace = nocow_ctx->physical_for_dev_replace;
3237 len = nocow_ctx->len; 3246 len = nocow_ctx->len;
3238 while (len >= PAGE_CACHE_SIZE) { 3247 while (len >= PAGE_CACHE_SIZE) {
3239 index = offset >> PAGE_CACHE_SHIFT; 3248 index = offset >> PAGE_CACHE_SHIFT;
3240 3249again:
3241 page = find_or_create_page(inode->i_mapping, index, GFP_NOFS); 3250 page = find_or_create_page(inode->i_mapping, index, GFP_NOFS);
3242 if (!page) { 3251 if (!page) {
3243 pr_err("find_or_create_page() failed\n"); 3252 pr_err("find_or_create_page() failed\n");
@@ -3258,7 +3267,18 @@ static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, void *ctx)
3258 ret = err; 3267 ret = err;
3259 goto next_page; 3268 goto next_page;
3260 } 3269 }
3270
3261 lock_page(page); 3271 lock_page(page);
3272 /*
3273 * If the page has been remove from the page cache,
3274 * the data on it is meaningless, because it may be
3275 * old one, the new data may be written into the new
3276 * page in the page cache.
3277 */
3278 if (page->mapping != inode->i_mapping) {
3279 page_cache_release(page);
3280 goto again;
3281 }
3262 if (!PageUptodate(page)) { 3282 if (!PageUptodate(page)) {
3263 ret = -EIO; 3283 ret = -EIO;
3264 goto next_page; 3284 goto next_page;
@@ -3280,6 +3300,7 @@ next_page:
3280 len -= PAGE_CACHE_SIZE; 3300 len -= PAGE_CACHE_SIZE;
3281 } 3301 }
3282out: 3302out:
3303 mutex_unlock(&inode->i_mutex);
3283 iput(inode); 3304 iput(inode);
3284 return ret; 3305 return ret;
3285} 3306}