mirror of
https://github.com/kdave/btrfs-progs
synced 2024-12-28 17:12:17 +00:00
2aa4085bf7
[BUG] For a degraded RAID5, btrfs check will fail to even read the chunk root: # mkfs.btrfs -f -m raid5 -d raid5 $dev1 $dev2 $dev3 # wipefs -fa $dev1 # btrfs check $dev2 Opening filesystem to check... warning, device 1 is missing bad tree block 22036480, bytenr mismatch, want=22036480, have=0 ERROR: cannot read chunk root ERROR: cannot open file system [CAUSE] Although read_tree_block() function from btrfs-progs is properly iterating the mirrors (mirror 1 is reading from the disk directly, mirror 2 will be rebuild from parity), the raid56 recovery path is not handling the read error correctly. The existing code will try to read the full stripe, but any read failure (including missing device) will immediately cause an error: for (i = 0; i < num_stripes; i++) { ret = btrfs_pread(multi->stripes[i].dev->fd, pointers[i], BTRFS_STRIPE_LEN, multi->stripes[i].physical, fs_info->zoned); if (ret < BTRFS_STRIPE_LEN) { ret = -EIO; goto out; } } [FIX] To make failed_a/failed_b calculation much easier, and properly handle too many missing devices, here this patch will introduce a new bitmap based solution. The new @failed_stripe_bitmap will represent all the failed stripes. So the initial read will mark all the missing devices in the @failed_stripe_bitmap, and later operations will all operate on that bitmap. Only before we call raid56_recov(), we convert the bitmap to the old failed_a/failed_b interface and continue. Now btrfs check can handle above case properly: # btrfs check $dev2 Opening filesystem to check... warning, device 1 is missing Checking filesystem on /dev/test/scratch2 UUID: 8b2e1cb4-f35b-4856-9b11-262d39d8458b [1/7] checking root items [2/7] checking extents [3/7] checking free space tree [4/7] checking fs roots [5/7] checking only csums items (without verifying data) [6/7] checking root refs [7/7] checking quota groups skipped (not enabled on this FS) found 147456 bytes used, no error found total csum bytes: 0 total tree bytes: 147456 total fs tree bytes: 32768 total extent tree bytes: 16384 btree space waste bytes: 139871 file data blocks allocated: 0 referenced 0 Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
46 lines
1.0 KiB
C
46 lines
1.0 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
|
|
/*
|
|
* A user-space bitmap wrapper to provide a subset of kernel bitmap operations.
|
|
*
|
|
* Most functions are not a direct copy of the kernel version, but should be
|
|
* good enough for single thread usage.
|
|
*/
|
|
|
|
#ifndef _BTRFS_PROGS_LINUX_BITMAP_H_
|
|
#define _BTRFS_PROGS_LINUX_BITMAP_H_
|
|
|
|
#include <stdlib.h>
|
|
#include "kerncompat.h"
|
|
#include "kernel-lib/bitops.h"
|
|
|
|
static inline unsigned long *bitmap_zalloc(unsigned int nbits)
|
|
{
|
|
return calloc(BITS_TO_LONGS(nbits), BITS_PER_LONG);
|
|
}
|
|
|
|
static inline void bitmap_free(unsigned long *bitmap)
|
|
{
|
|
free(bitmap);
|
|
}
|
|
|
|
#define BITMAP_LAST_WORK_MASK(nbits) (~0ULL >> (-(nbits) & (BITS_PER_LONG - 1)))
|
|
|
|
static inline unsigned int bitmap_weight(const unsigned long *bitmap, unsigned int nbits)
|
|
{
|
|
int ret = 0;
|
|
int i;
|
|
|
|
/* Handle the aligned part first. */
|
|
for (i = 0; i < nbits / BITS_PER_LONG; i++)
|
|
ret += hweight_long(bitmap[i]);
|
|
|
|
/* The remaining unaligned part. */
|
|
if (nbits % BITS_PER_LONG)
|
|
ret += bitmap[i] & BITMAP_LAST_WORD_MASK(nbits);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif
|