diff options
Diffstat (limited to 'fs/btrfs/scrub.c')
-rw-r--r-- | fs/btrfs/scrub.c | 92 |
1 files changed, 53 insertions, 39 deletions
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 79bd479317cb..64a157becbe5 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c | |||
@@ -2126,8 +2126,7 @@ static int scrub_find_csum(struct scrub_ctx *sctx, u64 logical, u64 len, | |||
2126 | u8 *csum) | 2126 | u8 *csum) |
2127 | { | 2127 | { |
2128 | struct btrfs_ordered_sum *sum = NULL; | 2128 | struct btrfs_ordered_sum *sum = NULL; |
2129 | int ret = 0; | 2129 | unsigned long index; |
2130 | unsigned long i; | ||
2131 | unsigned long num_sectors; | 2130 | unsigned long num_sectors; |
2132 | 2131 | ||
2133 | while (!list_empty(&sctx->csum_list)) { | 2132 | while (!list_empty(&sctx->csum_list)) { |
@@ -2146,19 +2145,14 @@ static int scrub_find_csum(struct scrub_ctx *sctx, u64 logical, u64 len, | |||
2146 | if (!sum) | 2145 | if (!sum) |
2147 | return 0; | 2146 | return 0; |
2148 | 2147 | ||
2148 | index = ((u32)(logical - sum->bytenr)) / sctx->sectorsize; | ||
2149 | num_sectors = sum->len / sctx->sectorsize; | 2149 | num_sectors = sum->len / sctx->sectorsize; |
2150 | for (i = 0; i < num_sectors; ++i) { | 2150 | memcpy(csum, sum->sums + index, sctx->csum_size); |
2151 | if (sum->sums[i].bytenr == logical) { | 2151 | if (index == num_sectors - 1) { |
2152 | memcpy(csum, &sum->sums[i].sum, sctx->csum_size); | ||
2153 | ret = 1; | ||
2154 | break; | ||
2155 | } | ||
2156 | } | ||
2157 | if (ret && i == num_sectors - 1) { | ||
2158 | list_del(&sum->list); | 2152 | list_del(&sum->list); |
2159 | kfree(sum); | 2153 | kfree(sum); |
2160 | } | 2154 | } |
2161 | return ret; | 2155 | return 1; |
2162 | } | 2156 | } |
2163 | 2157 | ||
2164 | /* scrub extent tries to collect up to 64 kB for each bio */ | 2158 | /* scrub extent tries to collect up to 64 kB for each bio */ |
@@ -2501,10 +2495,11 @@ again: | |||
2501 | ret = scrub_extent(sctx, extent_logical, extent_len, | 2495 | ret = scrub_extent(sctx, extent_logical, extent_len, |
2502 | extent_physical, extent_dev, flags, | 2496 | extent_physical, extent_dev, flags, |
2503 | generation, extent_mirror_num, | 2497 | generation, extent_mirror_num, |
2504 | extent_physical); | 2498 | extent_logical - logical + physical); |
2505 | if (ret) | 2499 | if (ret) |
2506 | goto out; | 2500 | goto out; |
2507 | 2501 | ||
2502 | scrub_free_csums(sctx); | ||
2508 | if (extent_logical + extent_len < | 2503 | if (extent_logical + extent_len < |
2509 | key.objectid + bytes) { | 2504 | key.objectid + bytes) { |
2510 | logical += increment; | 2505 | logical += increment; |
@@ -3204,16 +3199,18 @@ out: | |||
3204 | 3199 | ||
3205 | static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, void *ctx) | 3200 | static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, void *ctx) |
3206 | { | 3201 | { |
3207 | unsigned long index; | ||
3208 | struct scrub_copy_nocow_ctx *nocow_ctx = ctx; | 3202 | struct scrub_copy_nocow_ctx *nocow_ctx = ctx; |
3209 | int ret = 0; | 3203 | struct btrfs_fs_info *fs_info = nocow_ctx->sctx->dev_root->fs_info; |
3210 | struct btrfs_key key; | 3204 | struct btrfs_key key; |
3211 | struct inode *inode = NULL; | 3205 | struct inode *inode; |
3206 | struct page *page; | ||
3212 | struct btrfs_root *local_root; | 3207 | struct btrfs_root *local_root; |
3213 | u64 physical_for_dev_replace; | 3208 | u64 physical_for_dev_replace; |
3214 | u64 len; | 3209 | u64 len; |
3215 | struct btrfs_fs_info *fs_info = nocow_ctx->sctx->dev_root->fs_info; | 3210 | unsigned long index; |
3216 | int srcu_index; | 3211 | int srcu_index; |
3212 | int ret; | ||
3213 | int err; | ||
3217 | 3214 | ||
3218 | key.objectid = root; | 3215 | key.objectid = root; |
3219 | key.type = BTRFS_ROOT_ITEM_KEY; | 3216 | key.type = BTRFS_ROOT_ITEM_KEY; |
@@ -3227,6 +3224,11 @@ static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, void *ctx) | |||
3227 | return PTR_ERR(local_root); | 3224 | return PTR_ERR(local_root); |
3228 | } | 3225 | } |
3229 | 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 | |||
3230 | key.type = BTRFS_INODE_ITEM_KEY; | 3232 | key.type = BTRFS_INODE_ITEM_KEY; |
3231 | key.objectid = inum; | 3233 | key.objectid = inum; |
3232 | key.offset = 0; | 3234 | key.offset = 0; |
@@ -3235,19 +3237,21 @@ static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, void *ctx) | |||
3235 | if (IS_ERR(inode)) | 3237 | if (IS_ERR(inode)) |
3236 | return PTR_ERR(inode); | 3238 | return PTR_ERR(inode); |
3237 | 3239 | ||
3240 | /* Avoid truncate/dio/punch hole.. */ | ||
3241 | mutex_lock(&inode->i_mutex); | ||
3242 | inode_dio_wait(inode); | ||
3243 | |||
3244 | ret = 0; | ||
3238 | physical_for_dev_replace = nocow_ctx->physical_for_dev_replace; | 3245 | physical_for_dev_replace = nocow_ctx->physical_for_dev_replace; |
3239 | len = nocow_ctx->len; | 3246 | len = nocow_ctx->len; |
3240 | while (len >= PAGE_CACHE_SIZE) { | 3247 | while (len >= PAGE_CACHE_SIZE) { |
3241 | struct page *page = NULL; | ||
3242 | int ret_sub; | ||
3243 | |||
3244 | index = offset >> PAGE_CACHE_SHIFT; | 3248 | index = offset >> PAGE_CACHE_SHIFT; |
3245 | 3249 | again: | |
3246 | page = find_or_create_page(inode->i_mapping, index, GFP_NOFS); | 3250 | page = find_or_create_page(inode->i_mapping, index, GFP_NOFS); |
3247 | if (!page) { | 3251 | if (!page) { |
3248 | pr_err("find_or_create_page() failed\n"); | 3252 | pr_err("find_or_create_page() failed\n"); |
3249 | ret = -ENOMEM; | 3253 | ret = -ENOMEM; |
3250 | goto next_page; | 3254 | goto out; |
3251 | } | 3255 | } |
3252 | 3256 | ||
3253 | if (PageUptodate(page)) { | 3257 | if (PageUptodate(page)) { |
@@ -3255,39 +3259,49 @@ static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, void *ctx) | |||
3255 | goto next_page; | 3259 | goto next_page; |
3256 | } else { | 3260 | } else { |
3257 | ClearPageError(page); | 3261 | ClearPageError(page); |
3258 | ret_sub = extent_read_full_page(&BTRFS_I(inode)-> | 3262 | err = extent_read_full_page(&BTRFS_I(inode)-> |
3259 | io_tree, | 3263 | io_tree, |
3260 | page, btrfs_get_extent, | 3264 | page, btrfs_get_extent, |
3261 | nocow_ctx->mirror_num); | 3265 | nocow_ctx->mirror_num); |
3262 | if (ret_sub) { | 3266 | if (err) { |
3263 | ret = ret_sub; | 3267 | ret = err; |
3264 | goto next_page; | 3268 | goto next_page; |
3265 | } | 3269 | } |
3266 | wait_on_page_locked(page); | 3270 | |
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 | } | ||
3267 | if (!PageUptodate(page)) { | 3282 | if (!PageUptodate(page)) { |
3268 | ret = -EIO; | 3283 | ret = -EIO; |
3269 | goto next_page; | 3284 | goto next_page; |
3270 | } | 3285 | } |
3271 | } | 3286 | } |
3272 | ret_sub = write_page_nocow(nocow_ctx->sctx, | 3287 | err = write_page_nocow(nocow_ctx->sctx, |
3273 | physical_for_dev_replace, page); | 3288 | physical_for_dev_replace, page); |
3274 | if (ret_sub) { | 3289 | if (err) |
3275 | ret = ret_sub; | 3290 | ret = err; |
3276 | goto next_page; | ||
3277 | } | ||
3278 | |||
3279 | next_page: | 3291 | next_page: |
3280 | if (page) { | 3292 | unlock_page(page); |
3281 | unlock_page(page); | 3293 | page_cache_release(page); |
3282 | put_page(page); | 3294 | |
3283 | } | 3295 | if (ret) |
3296 | break; | ||
3297 | |||
3284 | offset += PAGE_CACHE_SIZE; | 3298 | offset += PAGE_CACHE_SIZE; |
3285 | physical_for_dev_replace += PAGE_CACHE_SIZE; | 3299 | physical_for_dev_replace += PAGE_CACHE_SIZE; |
3286 | len -= PAGE_CACHE_SIZE; | 3300 | len -= PAGE_CACHE_SIZE; |
3287 | } | 3301 | } |
3288 | 3302 | out: | |
3289 | if (inode) | 3303 | mutex_unlock(&inode->i_mutex); |
3290 | iput(inode); | 3304 | iput(inode); |
3291 | return ret; | 3305 | return ret; |
3292 | } | 3306 | } |
3293 | 3307 | ||