diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/scrub.c | 169 |
1 files changed, 163 insertions, 6 deletions
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 35099fa97d56..221fd5c48736 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c | |||
@@ -17,10 +17,12 @@ | |||
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/blkdev.h> | 19 | #include <linux/blkdev.h> |
20 | #include <linux/ratelimit.h> | ||
20 | #include "ctree.h" | 21 | #include "ctree.h" |
21 | #include "volumes.h" | 22 | #include "volumes.h" |
22 | #include "disk-io.h" | 23 | #include "disk-io.h" |
23 | #include "ordered-data.h" | 24 | #include "ordered-data.h" |
25 | #include "backref.h" | ||
24 | 26 | ||
25 | /* | 27 | /* |
26 | * This is only the first step towards a full-features scrub. It reads all | 28 | * This is only the first step towards a full-features scrub. It reads all |
@@ -100,6 +102,19 @@ struct scrub_dev { | |||
100 | spinlock_t stat_lock; | 102 | spinlock_t stat_lock; |
101 | }; | 103 | }; |
102 | 104 | ||
105 | struct scrub_warning { | ||
106 | struct btrfs_path *path; | ||
107 | u64 extent_item_size; | ||
108 | char *scratch_buf; | ||
109 | char *msg_buf; | ||
110 | const char *errstr; | ||
111 | sector_t sector; | ||
112 | u64 logical; | ||
113 | struct btrfs_device *dev; | ||
114 | int msg_bufsize; | ||
115 | int scratch_bufsize; | ||
116 | }; | ||
117 | |||
103 | static void scrub_free_csums(struct scrub_dev *sdev) | 118 | static void scrub_free_csums(struct scrub_dev *sdev) |
104 | { | 119 | { |
105 | while (!list_empty(&sdev->csum_list)) { | 120 | while (!list_empty(&sdev->csum_list)) { |
@@ -195,6 +210,143 @@ nomem: | |||
195 | return ERR_PTR(-ENOMEM); | 210 | return ERR_PTR(-ENOMEM); |
196 | } | 211 | } |
197 | 212 | ||
213 | static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root, void *ctx) | ||
214 | { | ||
215 | u64 isize; | ||
216 | u32 nlink; | ||
217 | int ret; | ||
218 | int i; | ||
219 | struct extent_buffer *eb; | ||
220 | struct btrfs_inode_item *inode_item; | ||
221 | struct scrub_warning *swarn = ctx; | ||
222 | struct btrfs_fs_info *fs_info = swarn->dev->dev_root->fs_info; | ||
223 | struct inode_fs_paths *ipath = NULL; | ||
224 | struct btrfs_root *local_root; | ||
225 | struct btrfs_key root_key; | ||
226 | |||
227 | root_key.objectid = root; | ||
228 | root_key.type = BTRFS_ROOT_ITEM_KEY; | ||
229 | root_key.offset = (u64)-1; | ||
230 | local_root = btrfs_read_fs_root_no_name(fs_info, &root_key); | ||
231 | if (IS_ERR(local_root)) { | ||
232 | ret = PTR_ERR(local_root); | ||
233 | goto err; | ||
234 | } | ||
235 | |||
236 | ret = inode_item_info(inum, 0, local_root, swarn->path); | ||
237 | if (ret) { | ||
238 | btrfs_release_path(swarn->path); | ||
239 | goto err; | ||
240 | } | ||
241 | |||
242 | eb = swarn->path->nodes[0]; | ||
243 | inode_item = btrfs_item_ptr(eb, swarn->path->slots[0], | ||
244 | struct btrfs_inode_item); | ||
245 | isize = btrfs_inode_size(eb, inode_item); | ||
246 | nlink = btrfs_inode_nlink(eb, inode_item); | ||
247 | btrfs_release_path(swarn->path); | ||
248 | |||
249 | ipath = init_ipath(4096, local_root, swarn->path); | ||
250 | ret = paths_from_inode(inum, ipath); | ||
251 | |||
252 | if (ret < 0) | ||
253 | goto err; | ||
254 | |||
255 | /* | ||
256 | * we deliberately ignore the bit ipath might have been too small to | ||
257 | * hold all of the paths here | ||
258 | */ | ||
259 | for (i = 0; i < ipath->fspath->elem_cnt; ++i) | ||
260 | printk(KERN_WARNING "btrfs: %s at logical %llu on dev " | ||
261 | "%s, sector %llu, root %llu, inode %llu, offset %llu, " | ||
262 | "length %llu, links %u (path: %s)\n", swarn->errstr, | ||
263 | swarn->logical, swarn->dev->name, | ||
264 | (unsigned long long)swarn->sector, root, inum, offset, | ||
265 | min(isize - offset, (u64)PAGE_SIZE), nlink, | ||
266 | ipath->fspath->str[i]); | ||
267 | |||
268 | free_ipath(ipath); | ||
269 | return 0; | ||
270 | |||
271 | err: | ||
272 | printk(KERN_WARNING "btrfs: %s at logical %llu on dev " | ||
273 | "%s, sector %llu, root %llu, inode %llu, offset %llu: path " | ||
274 | "resolving failed with ret=%d\n", swarn->errstr, | ||
275 | swarn->logical, swarn->dev->name, | ||
276 | (unsigned long long)swarn->sector, root, inum, offset, ret); | ||
277 | |||
278 | free_ipath(ipath); | ||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static void scrub_print_warning(const char *errstr, struct scrub_bio *sbio, | ||
283 | int ix) | ||
284 | { | ||
285 | struct btrfs_device *dev = sbio->sdev->dev; | ||
286 | struct btrfs_fs_info *fs_info = dev->dev_root->fs_info; | ||
287 | struct btrfs_path *path; | ||
288 | struct btrfs_key found_key; | ||
289 | struct extent_buffer *eb; | ||
290 | struct btrfs_extent_item *ei; | ||
291 | struct scrub_warning swarn; | ||
292 | u32 item_size; | ||
293 | int ret; | ||
294 | u64 ref_root; | ||
295 | u8 ref_level; | ||
296 | unsigned long ptr = 0; | ||
297 | const int bufsize = 4096; | ||
298 | u64 extent_offset; | ||
299 | |||
300 | path = btrfs_alloc_path(); | ||
301 | |||
302 | swarn.scratch_buf = kmalloc(bufsize, GFP_NOFS); | ||
303 | swarn.msg_buf = kmalloc(bufsize, GFP_NOFS); | ||
304 | swarn.sector = (sbio->physical + ix * PAGE_SIZE) >> 9; | ||
305 | swarn.logical = sbio->logical + ix * PAGE_SIZE; | ||
306 | swarn.errstr = errstr; | ||
307 | swarn.dev = dev; | ||
308 | swarn.msg_bufsize = bufsize; | ||
309 | swarn.scratch_bufsize = bufsize; | ||
310 | |||
311 | if (!path || !swarn.scratch_buf || !swarn.msg_buf) | ||
312 | goto out; | ||
313 | |||
314 | ret = extent_from_logical(fs_info, swarn.logical, path, &found_key); | ||
315 | if (ret < 0) | ||
316 | goto out; | ||
317 | |||
318 | extent_offset = swarn.logical - found_key.objectid; | ||
319 | swarn.extent_item_size = found_key.offset; | ||
320 | |||
321 | eb = path->nodes[0]; | ||
322 | ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item); | ||
323 | item_size = btrfs_item_size_nr(eb, path->slots[0]); | ||
324 | |||
325 | if (ret & BTRFS_EXTENT_FLAG_TREE_BLOCK) { | ||
326 | do { | ||
327 | ret = tree_backref_for_extent(&ptr, eb, ei, item_size, | ||
328 | &ref_root, &ref_level); | ||
329 | printk(KERN_WARNING "%s at logical %llu on dev %s, " | ||
330 | "sector %llu: metadata %s (level %d) in tree " | ||
331 | "%llu\n", errstr, swarn.logical, dev->name, | ||
332 | (unsigned long long)swarn.sector, | ||
333 | ref_level ? "node" : "leaf", | ||
334 | ret < 0 ? -1 : ref_level, | ||
335 | ret < 0 ? -1 : ref_root); | ||
336 | } while (ret != 1); | ||
337 | } else { | ||
338 | swarn.path = path; | ||
339 | iterate_extent_inodes(fs_info, path, found_key.objectid, | ||
340 | extent_offset, | ||
341 | scrub_print_warning_inode, &swarn); | ||
342 | } | ||
343 | |||
344 | out: | ||
345 | btrfs_free_path(path); | ||
346 | kfree(swarn.scratch_buf); | ||
347 | kfree(swarn.msg_buf); | ||
348 | } | ||
349 | |||
198 | /* | 350 | /* |
199 | * scrub_recheck_error gets called when either verification of the page | 351 | * scrub_recheck_error gets called when either verification of the page |
200 | * failed or the bio failed to read, e.g. with EIO. In the latter case, | 352 | * failed or the bio failed to read, e.g. with EIO. In the latter case, |
@@ -205,6 +357,8 @@ static int scrub_recheck_error(struct scrub_bio *sbio, int ix) | |||
205 | { | 357 | { |
206 | struct scrub_dev *sdev = sbio->sdev; | 358 | struct scrub_dev *sdev = sbio->sdev; |
207 | u64 sector = (sbio->physical + ix * PAGE_SIZE) >> 9; | 359 | u64 sector = (sbio->physical + ix * PAGE_SIZE) >> 9; |
360 | static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL, | ||
361 | DEFAULT_RATELIMIT_BURST); | ||
208 | 362 | ||
209 | if (sbio->err) { | 363 | if (sbio->err) { |
210 | if (scrub_fixup_io(READ, sbio->sdev->dev->bdev, sector, | 364 | if (scrub_fixup_io(READ, sbio->sdev->dev->bdev, sector, |
@@ -212,6 +366,11 @@ static int scrub_recheck_error(struct scrub_bio *sbio, int ix) | |||
212 | if (scrub_fixup_check(sbio, ix) == 0) | 366 | if (scrub_fixup_check(sbio, ix) == 0) |
213 | return 0; | 367 | return 0; |
214 | } | 368 | } |
369 | if (__ratelimit(&_rs)) | ||
370 | scrub_print_warning("i/o error", sbio, ix); | ||
371 | } else { | ||
372 | if (__ratelimit(&_rs)) | ||
373 | scrub_print_warning("checksum error", sbio, ix); | ||
215 | } | 374 | } |
216 | 375 | ||
217 | spin_lock(&sdev->stat_lock); | 376 | spin_lock(&sdev->stat_lock); |
@@ -326,9 +485,8 @@ static void scrub_fixup(struct scrub_bio *sbio, int ix) | |||
326 | ++sdev->stat.corrected_errors; | 485 | ++sdev->stat.corrected_errors; |
327 | spin_unlock(&sdev->stat_lock); | 486 | spin_unlock(&sdev->stat_lock); |
328 | 487 | ||
329 | if (printk_ratelimit()) | 488 | printk_ratelimited(KERN_ERR "btrfs: fixed up error at logical %llu\n", |
330 | printk(KERN_ERR "btrfs: fixed up at %llu\n", | 489 | (unsigned long long)logical); |
331 | (unsigned long long)logical); | ||
332 | return; | 490 | return; |
333 | 491 | ||
334 | uncorrectable: | 492 | uncorrectable: |
@@ -337,9 +495,8 @@ uncorrectable: | |||
337 | ++sdev->stat.uncorrectable_errors; | 495 | ++sdev->stat.uncorrectable_errors; |
338 | spin_unlock(&sdev->stat_lock); | 496 | spin_unlock(&sdev->stat_lock); |
339 | 497 | ||
340 | if (printk_ratelimit()) | 498 | printk_ratelimited(KERN_ERR "btrfs: unable to fixup (regular) error at " |
341 | printk(KERN_ERR "btrfs: unable to fixup at %llu\n", | 499 | "logical %llu\n", (unsigned long long)logical); |
342 | (unsigned long long)logical); | ||
343 | } | 500 | } |
344 | 501 | ||
345 | static int scrub_fixup_io(int rw, struct block_device *bdev, sector_t sector, | 502 | static int scrub_fixup_io(int rw, struct block_device *bdev, sector_t sector, |