Commit edd1400be9f983f521c7397740d810fa210ee52f

Authored by Miao Xie
Committed by Josef Bacik
1 parent 826aa0a82c

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>

Showing 1 changed file with 22 additions and 1 deletions Side-by-side Diff

... ... @@ -3224,6 +3224,11 @@
3224 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 3232 key.type = BTRFS_INODE_ITEM_KEY;
3228 3233 key.objectid = inum;
3229 3234 key.offset = 0;
3230 3235  
... ... @@ -3232,12 +3237,16 @@
3232 3237 if (IS_ERR(inode))
3233 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 3244 ret = 0;
3236 3245 physical_for_dev_replace = nocow_ctx->physical_for_dev_replace;
3237 3246 len = nocow_ctx->len;
3238 3247 while (len >= PAGE_CACHE_SIZE) {
3239 3248 index = offset >> PAGE_CACHE_SHIFT;
3240   -
  3249 +again:
3241 3250 page = find_or_create_page(inode->i_mapping, index, GFP_NOFS);
3242 3251 if (!page) {
3243 3252 pr_err("find_or_create_page() failed\n");
3244 3253  
... ... @@ -3258,7 +3267,18 @@
3258 3267 ret = err;
3259 3268 goto next_page;
3260 3269 }
  3270 +
3261 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 3282 if (!PageUptodate(page)) {
3263 3283 ret = -EIO;
3264 3284 goto next_page;
... ... @@ -3280,6 +3300,7 @@
3280 3300 len -= PAGE_CACHE_SIZE;
3281 3301 }
3282 3302 out:
  3303 + mutex_unlock(&inode->i_mutex);
3283 3304 iput(inode);
3284 3305 return ret;
3285 3306 }