Commit edd1400be9f983f521c7397740d810fa210ee52f
Committed by
Josef Bacik
1 parent
826aa0a82c
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
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
fs/btrfs/scrub.c
... | ... | @@ -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 | } |