* [PATCH 1/7] btrfs: cleanup btrfs_check_super_csum() for better code flow
2018-03-29 10:36 [PATCH v3 0/9] Superblock read and verify cleanups Anand Jain
@ 2018-03-29 10:36 ` Anand Jain
2018-03-29 10:36 ` [PATCH v2 2/7] btrfs: return required error from btrfs_check_super_csum Anand Jain
` (5 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: Anand Jain @ 2018-03-29 10:36 UTC (permalink / raw)
To: linux-btrfs
We check the %csum_type twice. Drop one. Check for the csum_type and
then for the csum. Which also matches with the progs which have better
logic. This is preparatory patch to get proper error code from
btrfs_check_super_csum().
Signed-off-by: Anand Jain <anand.jain@oracle.com>
Reviewed-by: Nikolay Borisov <nborisov@suse.com>
---
fs/btrfs/disk-io.c | 38 +++++++++++++++++---------------------
1 file changed, 17 insertions(+), 21 deletions(-)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 1657d6aa4fa6..b9b435579527 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -399,32 +399,28 @@ static int btrfs_check_super_csum(struct btrfs_fs_info *fs_info,
struct btrfs_super_block *disk_sb =
(struct btrfs_super_block *)raw_disk_sb;
u16 csum_type = btrfs_super_csum_type(disk_sb);
- int ret = 0;
-
- if (csum_type == BTRFS_CSUM_TYPE_CRC32) {
- u32 crc = ~(u32)0;
- char result[sizeof(crc)];
-
- /*
- * The super_block structure does not span the whole
- * BTRFS_SUPER_INFO_SIZE range, we expect that the unused space
- * is filled with zeros and is included in the checksum.
- */
- crc = btrfs_csum_data(raw_disk_sb + BTRFS_CSUM_SIZE,
- crc, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
- btrfs_csum_final(crc, result);
-
- if (memcmp(raw_disk_sb, result, sizeof(result)))
- ret = 1;
- }
+ u32 crc = ~(u32)0;
+ char result[sizeof(crc)];
if (csum_type >= ARRAY_SIZE(btrfs_csum_sizes)) {
btrfs_err(fs_info, "unsupported checksum algorithm %u",
- csum_type);
- ret = 1;
+ csum_type);
+ return 1;
}
- return ret;
+ /*
+ * The super_block structure does not span the whole
+ * BTRFS_SUPER_INFO_SIZE range, we expect that the unused space
+ * is filled with zeros and is included in the checksum.
+ */
+ crc = btrfs_csum_data(raw_disk_sb + BTRFS_CSUM_SIZE,
+ crc, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE);
+ btrfs_csum_final(crc, result);
+
+ if (memcmp(raw_disk_sb, result, sizeof(result)))
+ return 1;
+
+ return 0;
}
/*
--
2.7.0
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH v2 2/7] btrfs: return required error from btrfs_check_super_csum
2018-03-29 10:36 [PATCH v3 0/9] Superblock read and verify cleanups Anand Jain
2018-03-29 10:36 ` [PATCH 1/7] btrfs: cleanup btrfs_check_super_csum() for better code flow Anand Jain
@ 2018-03-29 10:36 ` Anand Jain
2018-03-29 12:49 ` Nikolay Borisov
2018-03-29 10:37 ` [PATCH v2 3/7] btrfs: cleanup btrfs_read_disk_super() to return std error Anand Jain
` (4 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Anand Jain @ 2018-03-29 10:36 UTC (permalink / raw)
To: linux-btrfs
Return the required -EINVAL and -EUCLEAN from the function
btrfs_check_super_csum(). And more the error log into the
parent function.
Signed-off-by: Anand Jain <anand.jain@oracle.com>
v1->v2:
Fix commit indent reported by checkpatch.pl
Fix pr_err split string
---
fs/btrfs/disk-io.c | 25 ++++++++++++++-----------
1 file changed, 14 insertions(+), 11 deletions(-)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index b9b435579527..4c573602480c 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -392,9 +392,10 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
/*
* Return 0 if the superblock checksum type matches the checksum value of that
* algorithm. Pass the raw disk superblock data.
+ * Otherwise: -EINVAL if csum type is not found
+ * -EUCLEAN if csum does not match
*/
-static int btrfs_check_super_csum(struct btrfs_fs_info *fs_info,
- char *raw_disk_sb)
+static int btrfs_check_super_csum(char *raw_disk_sb)
{
struct btrfs_super_block *disk_sb =
(struct btrfs_super_block *)raw_disk_sb;
@@ -402,11 +403,8 @@ static int btrfs_check_super_csum(struct btrfs_fs_info *fs_info,
u32 crc = ~(u32)0;
char result[sizeof(crc)];
- if (csum_type >= ARRAY_SIZE(btrfs_csum_sizes)) {
- btrfs_err(fs_info, "unsupported checksum algorithm %u",
- csum_type);
- return 1;
- }
+ if (csum_type >= ARRAY_SIZE(btrfs_csum_sizes))
+ return -EINVAL;
/*
* The super_block structure does not span the whole
@@ -418,7 +416,7 @@ static int btrfs_check_super_csum(struct btrfs_fs_info *fs_info,
btrfs_csum_final(crc, result);
if (memcmp(raw_disk_sb, result, sizeof(result)))
- return 1;
+ return -EUCLEAN;
return 0;
}
@@ -2570,9 +2568,14 @@ int open_ctree(struct super_block *sb,
* We want to check superblock checksum, the type is stored inside.
* Pass the whole disk block of size BTRFS_SUPER_INFO_SIZE (4k).
*/
- if (btrfs_check_super_csum(fs_info, bh->b_data)) {
- btrfs_err(fs_info, "superblock checksum mismatch");
- err = -EINVAL;
+ err = btrfs_check_super_csum(bh->b_data);
+ if (err) {
+ if (err == -EINVAL)
+ pr_err("BTRFS error (device %pg): unsupported checksum algorithm",
+ fs_devices->latest_bdev);
+ else
+ pr_err("BTRFS error (device %pg): superblock checksum mismatch",
+ fs_devices->latest_bdev);
brelse(bh);
goto fail_alloc;
}
--
2.7.0
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH v2 2/7] btrfs: return required error from btrfs_check_super_csum
2018-03-29 10:36 ` [PATCH v2 2/7] btrfs: return required error from btrfs_check_super_csum Anand Jain
@ 2018-03-29 12:49 ` Nikolay Borisov
2018-03-30 0:11 ` Anand Jain
0 siblings, 1 reply; 13+ messages in thread
From: Nikolay Borisov @ 2018-03-29 12:49 UTC (permalink / raw)
To: Anand Jain, linux-btrfs
On 29.03.2018 13:36, Anand Jain wrote:
> Return the required -EINVAL and -EUCLEAN from the function
> btrfs_check_super_csum(). And more the error log into the
> parent function.
>
> Signed-off-by: Anand Jain <anand.jain@oracle.com>
> v1->v2:
> Fix commit indent reported by checkpatch.pl
> Fix pr_err split string
The change log has to go below the scissors line. I guess it can be
fixed at merge time so I don't think a resubmit is warranted.
There is one nit below but I don't think it's critical so :
Reviewed-by: Nikolay Borisov <nborisov@suse.com>
> ---
> fs/btrfs/disk-io.c | 25 ++++++++++++++-----------
> 1 file changed, 14 insertions(+), 11 deletions(-)
>
> diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
> index b9b435579527..4c573602480c 100644
> --- a/fs/btrfs/disk-io.c
> +++ b/fs/btrfs/disk-io.c
> @@ -392,9 +392,10 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
> /*
> * Return 0 if the superblock checksum type matches the checksum value of that
> * algorithm. Pass the raw disk superblock data.
> + * Otherwise: -EINVAL if csum type is not found
> + * -EUCLEAN if csum does not match
> */
> -static int btrfs_check_super_csum(struct btrfs_fs_info *fs_info,
> - char *raw_disk_sb)
> +static int btrfs_check_super_csum(char *raw_disk_sb)
> {
> struct btrfs_super_block *disk_sb =
> (struct btrfs_super_block *)raw_disk_sb;
> @@ -402,11 +403,8 @@ static int btrfs_check_super_csum(struct btrfs_fs_info *fs_info,
> u32 crc = ~(u32)0;
> char result[sizeof(crc)];
>
> - if (csum_type >= ARRAY_SIZE(btrfs_csum_sizes)) {
> - btrfs_err(fs_info, "unsupported checksum algorithm %u",
> - csum_type);
> - return 1;
> - }
> + if (csum_type >= ARRAY_SIZE(btrfs_csum_sizes))
> + return -EINVAL;
>
> /*
> * The super_block structure does not span the whole
> @@ -418,7 +416,7 @@ static int btrfs_check_super_csum(struct btrfs_fs_info *fs_info,
> btrfs_csum_final(crc, result);
>
> if (memcmp(raw_disk_sb, result, sizeof(result)))
> - return 1;
> + return -EUCLEAN;
>
> return 0;
> }
> @@ -2570,9 +2568,14 @@ int open_ctree(struct super_block *sb,
> * We want to check superblock checksum, the type is stored inside.
> * Pass the whole disk block of size BTRFS_SUPER_INFO_SIZE (4k).
> */
> - if (btrfs_check_super_csum(fs_info, bh->b_data)) {
> - btrfs_err(fs_info, "superblock checksum mismatch");
> - err = -EINVAL;
> + err = btrfs_check_super_csum(bh->b_data);
> + if (err) {
> + if (err == -EINVAL)
> + pr_err("BTRFS error (device %pg): unsupported checksum algorithm",
> + fs_devices->latest_bdev);
> + else
> + pr_err("BTRFS error (device %pg): superblock checksum mismatch",
> + fs_devices->latest_bdev);
nit: I think your initial version of specifically checking for EUCLEAN
was better but I don't have strong preferences.
> brelse(bh);
> goto fail_alloc;
> }
>
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v2 2/7] btrfs: return required error from btrfs_check_super_csum
2018-03-29 12:49 ` Nikolay Borisov
@ 2018-03-30 0:11 ` Anand Jain
0 siblings, 0 replies; 13+ messages in thread
From: Anand Jain @ 2018-03-30 0:11 UTC (permalink / raw)
To: Nikolay Borisov, linux-btrfs
>> @@ -2570,9 +2568,14 @@ int open_ctree(struct super_block *sb,
>> * We want to check superblock checksum, the type is stored inside.
>> * Pass the whole disk block of size BTRFS_SUPER_INFO_SIZE (4k).
>> */
>> - if (btrfs_check_super_csum(fs_info, bh->b_data)) {
>> - btrfs_err(fs_info, "superblock checksum mismatch");
>> - err = -EINVAL;
>> + err = btrfs_check_super_csum(bh->b_data);
>> + if (err) {
>> + if (err == -EINVAL)
>> + pr_err("BTRFS error (device %pg): unsupported checksum algorithm",
>> + fs_devices->latest_bdev);
>> + else
>> + pr_err("BTRFS error (device %pg): superblock checksum mismatch",
>> + fs_devices->latest_bdev);
>
> nit: I think your initial version of specifically checking for EUCLEAN
> was better but I don't have strong preferences.
Fixed this in v4. Also updated the changelog.
Thanks for the review.
Anand
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 3/7] btrfs: cleanup btrfs_read_disk_super() to return std error
2018-03-29 10:36 [PATCH v3 0/9] Superblock read and verify cleanups Anand Jain
2018-03-29 10:36 ` [PATCH 1/7] btrfs: cleanup btrfs_check_super_csum() for better code flow Anand Jain
2018-03-29 10:36 ` [PATCH v2 2/7] btrfs: return required error from btrfs_check_super_csum Anand Jain
@ 2018-03-29 10:37 ` Anand Jain
2018-03-29 10:37 ` [PATCH v2 4/7] btrfs: check if the fsid in the primary sb and copy sb are same Anand Jain
` (3 subsequent siblings)
6 siblings, 0 replies; 13+ messages in thread
From: Anand Jain @ 2018-03-29 10:37 UTC (permalink / raw)
To: linux-btrfs
The only caller btrfs_scan_one_device() sets -EINVAL for error from
btrfs_read_disk_super(), so this patch returns -EINVAL from the latter
function.
A preparatory patch to add csum check in btrfs_read_disk_super().
Signed-off-by: Anand Jain <anand.jain@oracle.com>
Reviewed-by: Nikolay Borisov <nborisov@suse.com>
v1->v2:
Check btrfs_read_disk_super() to be more explicit ret < 0
---
fs/btrfs/volumes.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 87d183accdb2..e63723f23227 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -1154,23 +1154,23 @@ static int btrfs_read_disk_super(struct block_device *bdev, u64 bytenr,
/* make sure our super fits in the device */
if (bytenr + PAGE_SIZE >= i_size_read(bdev->bd_inode))
- return 1;
+ return -EINVAL;
/* make sure our super fits in the page */
if (sizeof(**disk_super) > PAGE_SIZE)
- return 1;
+ return -EINVAL;
/* make sure our super doesn't straddle pages on disk */
index = bytenr >> PAGE_SHIFT;
if ((bytenr + sizeof(**disk_super) - 1) >> PAGE_SHIFT != index)
- return 1;
+ return -EINVAL;
/* pull in the page with our super */
*page = read_cache_page_gfp(bdev->bd_inode->i_mapping,
index, GFP_KERNEL);
if (IS_ERR_OR_NULL(*page))
- return 1;
+ return -EINVAL;
p = kmap(*page);
@@ -1180,7 +1180,7 @@ static int btrfs_read_disk_super(struct block_device *bdev, u64 bytenr,
if (btrfs_super_bytenr(*disk_super) != bytenr ||
btrfs_super_magic(*disk_super) != BTRFS_MAGIC) {
btrfs_release_disk_super(*page);
- return 1;
+ return -EINVAL;
}
if ((*disk_super)->label[0] &&
@@ -1218,10 +1218,9 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
if (IS_ERR(bdev))
return PTR_ERR(bdev);
- if (btrfs_read_disk_super(bdev, bytenr, &page, &disk_super)) {
- ret = -EINVAL;
+ ret = btrfs_read_disk_super(bdev, bytenr, &page, &disk_super);
+ if (ret < 0)
goto error_bdev_put;
- }
mutex_lock(&uuid_mutex);
device = device_list_add(path, disk_super);
--
2.7.0
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH v2 4/7] btrfs: check if the fsid in the primary sb and copy sb are same
2018-03-29 10:36 [PATCH v3 0/9] Superblock read and verify cleanups Anand Jain
` (2 preceding siblings ...)
2018-03-29 10:37 ` [PATCH v2 3/7] btrfs: cleanup btrfs_read_disk_super() to return std error Anand Jain
@ 2018-03-29 10:37 ` Anand Jain
2018-03-29 12:56 ` Nikolay Borisov
2018-03-29 10:37 ` [PATCH v3 5/7] btrfs: verify superblock checksum during scan Anand Jain
` (2 subsequent siblings)
6 siblings, 1 reply; 13+ messages in thread
From: Anand Jain @ 2018-03-29 10:37 UTC (permalink / raw)
To: linux-btrfs
During the btrfs dev scan make sure that other copies of superblock
contain the same fsid as the primary SB. So that we bring to the
user notice if the superblock has been overwritten.
mkfs.btrfs -fq /dev/sdc
mkfs.btrfs -fq /dev/sdb
dd if=/dev/sdb of=/dev/sdc count=4K skip=64K seek=64K obs=1 ibs=1
mount /dev/sdc /btrfs
Caveat: Pls note that older btrfs-progs do not wipe the non-overwriting
stale superblock like copy2 if a smaller mkfs.btrfs -b <size> is created.
Thus this patch in the kernel will report error. The workaround is to wipe
the superblock manually, like
dd if=/dev/zero of=<dev> seek=274877906944 ibs=1 obs=1 count4K
OR apply the btrfs-progs patch
btrfs-progs: wipe copies of the stale superblock beyond -b size
which shall find and wipe the non overwriting superblock during mkfs.
Signed-off-by: Anand Jain <anand.jain@oracle.com>
v1->v2:
Do an explicit read for primary superblock. Drop kzalloc().
Fix split pr_err().
---
fs/btrfs/volumes.c | 48 ++++++++++++++++++++++++++++++++++++++----------
1 file changed, 38 insertions(+), 10 deletions(-)
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index e63723f23227..035affa447fa 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -1198,39 +1198,67 @@ static int btrfs_read_disk_super(struct block_device *bdev, u64 bytenr,
int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
struct btrfs_fs_devices **fs_devices_ret)
{
+ struct btrfs_super_block *disk_super_primary;
struct btrfs_super_block *disk_super;
struct btrfs_device *device;
struct block_device *bdev;
+ struct page *page_primary;
struct page *page;
int ret = 0;
u64 bytenr;
+ int i;
- /*
- * we would like to check all the supers, but that would make
- * a btrfs mount succeed after a mkfs from a different FS.
- * So, we need to add a special mount option to scan for
- * later supers, using BTRFS_SUPER_MIRROR_MAX instead
- */
- bytenr = btrfs_sb_offset(0);
flags |= FMODE_EXCL;
bdev = blkdev_get_by_path(path, flags, holder);
if (IS_ERR(bdev))
return PTR_ERR(bdev);
- ret = btrfs_read_disk_super(bdev, bytenr, &page, &disk_super);
+ /*
+ * We would like to check all the supers and use one good copy,
+ * but that would make a btrfs mount succeed after a mkfs from
+ * a different FS.
+ * So, we need to add a special mount option to scan for
+ * later supers, using BTRFS_SUPER_MIRROR_MAX instead.
+ * So, just validate if all copies of the superblocks are ok
+ * and have the same fsid.
+ */
+ bytenr = btrfs_sb_offset(0);
+ ret = btrfs_read_disk_super(bdev, bytenr, &page_primary,
+ &disk_super_primary);
if (ret < 0)
goto error_bdev_put;
+ for (i = 1; i < BTRFS_SUPER_MIRROR_MAX; i++) {
+ bytenr = btrfs_sb_offset(i);
+ ret = btrfs_read_disk_super(bdev, bytenr, &page, &disk_super);
+ if (ret < 0) {
+ ret = 0;
+ continue;
+ }
+
+ if (memcmp(disk_super_primary->fsid, disk_super->fsid,
+ BTRFS_FSID_SIZE)) {
+ pr_err("BTRFS (device %pg): superblock fsid mismatch, primary %pU copy%d %pU",
+ bdev, disk_super_primary->fsid, i,
+ disk_super->fsid);
+ ret = -EINVAL;
+ btrfs_release_disk_super(page);
+ goto error_rel_primary;
+ }
+ btrfs_release_disk_super(page);
+ }
+
mutex_lock(&uuid_mutex);
- device = device_list_add(path, disk_super);
+ device = device_list_add(path, disk_super_primary);
if (IS_ERR(device))
ret = PTR_ERR(device);
else
*fs_devices_ret = device->fs_devices;
mutex_unlock(&uuid_mutex);
- btrfs_release_disk_super(page);
+error_rel_primary:
+ btrfs_release_disk_super(page_primary);
error_bdev_put:
blkdev_put(bdev, flags);
--
2.7.0
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH v2 4/7] btrfs: check if the fsid in the primary sb and copy sb are same
2018-03-29 10:37 ` [PATCH v2 4/7] btrfs: check if the fsid in the primary sb and copy sb are same Anand Jain
@ 2018-03-29 12:56 ` Nikolay Borisov
0 siblings, 0 replies; 13+ messages in thread
From: Nikolay Borisov @ 2018-03-29 12:56 UTC (permalink / raw)
To: Anand Jain, linux-btrfs
On 29.03.2018 13:37, Anand Jain wrote:
> During the btrfs dev scan make sure that other copies of superblock
> contain the same fsid as the primary SB. So that we bring to the
> user notice if the superblock has been overwritten.
>
> mkfs.btrfs -fq /dev/sdc
> mkfs.btrfs -fq /dev/sdb
> dd if=/dev/sdb of=/dev/sdc count=4K skip=64K seek=64K obs=1 ibs=1
> mount /dev/sdc /btrfs
>
> Caveat: Pls note that older btrfs-progs do not wipe the non-overwriting
> stale superblock like copy2 if a smaller mkfs.btrfs -b <size> is created.
> Thus this patch in the kernel will report error. The workaround is to wipe
> the superblock manually, like
> dd if=/dev/zero of=<dev> seek=274877906944 ibs=1 obs=1 count4K
> OR apply the btrfs-progs patch
> btrfs-progs: wipe copies of the stale superblock beyond -b size
> which shall find and wipe the non overwriting superblock during mkfs.
>
> Signed-off-by: Anand Jain <anand.jain@oracle.com>
> v1->v2:
> Do an explicit read for primary superblock. Drop kzalloc().
> Fix split pr_err().
Same thing about the change log as in 2/7. Otherwise :
Reviewed-by: Nikolay Borisov <nborisov@suse.com>
> ---
> fs/btrfs/volumes.c | 48 ++++++++++++++++++++++++++++++++++++++----------
> 1 file changed, 38 insertions(+), 10 deletions(-)
>
> diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
> index e63723f23227..035affa447fa 100644
> --- a/fs/btrfs/volumes.c
> +++ b/fs/btrfs/volumes.c
> @@ -1198,39 +1198,67 @@ static int btrfs_read_disk_super(struct block_device *bdev, u64 bytenr,
> int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
> struct btrfs_fs_devices **fs_devices_ret)
> {
> + struct btrfs_super_block *disk_super_primary;
> struct btrfs_super_block *disk_super;
> struct btrfs_device *device;
> struct block_device *bdev;
> + struct page *page_primary;
> struct page *page;
> int ret = 0;
> u64 bytenr;
> + int i;
>
> - /*
> - * we would like to check all the supers, but that would make
> - * a btrfs mount succeed after a mkfs from a different FS.
> - * So, we need to add a special mount option to scan for
> - * later supers, using BTRFS_SUPER_MIRROR_MAX instead
> - */
> - bytenr = btrfs_sb_offset(0);
> flags |= FMODE_EXCL;
>
> bdev = blkdev_get_by_path(path, flags, holder);
> if (IS_ERR(bdev))
> return PTR_ERR(bdev);
>
> - ret = btrfs_read_disk_super(bdev, bytenr, &page, &disk_super);
> + /*
> + * We would like to check all the supers and use one good copy,
> + * but that would make a btrfs mount succeed after a mkfs from
> + * a different FS.
> + * So, we need to add a special mount option to scan for
> + * later supers, using BTRFS_SUPER_MIRROR_MAX instead.
> + * So, just validate if all copies of the superblocks are ok
> + * and have the same fsid.
> + */
> + bytenr = btrfs_sb_offset(0);
> + ret = btrfs_read_disk_super(bdev, bytenr, &page_primary,
> + &disk_super_primary);
> if (ret < 0)
> goto error_bdev_put;
>
> + for (i = 1; i < BTRFS_SUPER_MIRROR_MAX; i++) {
> + bytenr = btrfs_sb_offset(i);
> + ret = btrfs_read_disk_super(bdev, bytenr, &page, &disk_super);
> + if (ret < 0) {
> + ret = 0;
> + continue;
> + }
> +
> + if (memcmp(disk_super_primary->fsid, disk_super->fsid,
> + BTRFS_FSID_SIZE)) {
> + pr_err("BTRFS (device %pg): superblock fsid mismatch, primary %pU copy%d %pU",
> + bdev, disk_super_primary->fsid, i,
> + disk_super->fsid);
> + ret = -EINVAL;
> + btrfs_release_disk_super(page);
> + goto error_rel_primary;
> + }
> + btrfs_release_disk_super(page);
> + }
> +
> mutex_lock(&uuid_mutex);
> - device = device_list_add(path, disk_super);
> + device = device_list_add(path, disk_super_primary);
> if (IS_ERR(device))
> ret = PTR_ERR(device);
> else
> *fs_devices_ret = device->fs_devices;
> mutex_unlock(&uuid_mutex);
>
> - btrfs_release_disk_super(page);
> +error_rel_primary:
> + btrfs_release_disk_super(page_primary);
>
> error_bdev_put:
> blkdev_put(bdev, flags);
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v3 5/7] btrfs: verify superblock checksum during scan
2018-03-29 10:36 [PATCH v3 0/9] Superblock read and verify cleanups Anand Jain
` (3 preceding siblings ...)
2018-03-29 10:37 ` [PATCH v2 4/7] btrfs: check if the fsid in the primary sb and copy sb are same Anand Jain
@ 2018-03-29 10:37 ` Anand Jain
2018-03-29 12:57 ` Nikolay Borisov
2018-03-29 10:37 ` [PATCH v2 6/7] btrfs: verify checksum for all devices in mount context Anand Jain
2018-03-29 10:37 ` [PATCH 7/7] btrfs: drop the redundant invalidate_bdev() Anand Jain
6 siblings, 1 reply; 13+ messages in thread
From: Anand Jain @ 2018-03-29 10:37 UTC (permalink / raw)
To: linux-btrfs
During the scan context, we aren't verifying the superblock-
checksum when read.
This patch fixes it by adding the checksum verification function
btrfs_check_super_csum() in the function btrfs_read_disk_super().
And makes device scan to error fail if the primary superblock csum
is wrong, whereas if the copy-superblock csum is wrong it will just
just report mismatch and continue mount/scan as usual. When the
mount is successful We anyway overwrite all superblocks upon unmount.
The context in which this will be called is - device scan, device ready,
and mount -o device option.
Test script:
Corrupt primary superblock and check if device scan and mount
fails:
mkfs.btrfs -fq /dev/sdc
dd if=/dev/urandom of=/dev/sdc ibs=1 obs=1 count=1 seek=64K
btrfs dev scan /dev/sdc
mount /dev/sdc /btrfs
Corrupt secondary superblock and check if device scan and mount
is succcessful, check for the dmesg for errors.
mkfs.btrfs -fq /dev/sdc
dd if=/dev/urandom of=/dev/sdc ibs=1 obs=1 count=1 seek=67108864
btrfs dev scan /dev/sdc
mount /dev/sdc /btrfs
Signed-off-by: Anand Jain <anand.jain@oracle.com>
v3->v2:
Also squash 4/8 in here.
4/8: btrfs: make btrfs_check_super_csum() non-static
v1->v2:
changed title.
use explicit (< 0) check for %errr.
Un-split pr_err() string.
Fix typo in the git commit log.
Move the csum check after bytenr and btrfs magic verified.
btrfs: make btrfs_check_super_csum() non-static
In preparation to add the superblock csum verification for the
scan context, make btrfs_check_super_csum() non-static.
Signed-off-by: Anand Jain <anand.jain@oracle.com>
Reviewed-by: Nikolay Borisov <nborisov@suse.com>
---
fs/btrfs/disk-io.c | 2 +-
fs/btrfs/disk-io.h | 1 +
fs/btrfs/volumes.c | 13 +++++++++++++
3 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 4c573602480c..35dbbdc613cd 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -395,7 +395,7 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
* Otherwise: -EINVAL if csum type is not found
* -EUCLEAN if csum does not match
*/
-static int btrfs_check_super_csum(char *raw_disk_sb)
+int btrfs_check_super_csum(char *raw_disk_sb)
{
struct btrfs_super_block *disk_sb =
(struct btrfs_super_block *)raw_disk_sb;
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
index 70a88d61b547..c400cc68f913 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -69,6 +69,7 @@ int write_all_supers(struct btrfs_fs_info *fs_info, int max_mirrors);
struct buffer_head *btrfs_read_dev_super(struct block_device *bdev);
int btrfs_read_dev_one_super(struct block_device *bdev, int copy_num,
struct buffer_head **bh_ret);
+int btrfs_check_super_csum(char *raw_disk_sb);
int btrfs_commit_super(struct btrfs_fs_info *fs_info);
struct btrfs_root *btrfs_read_fs_root(struct btrfs_root *tree_root,
struct btrfs_key *location);
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 035affa447fa..f1f074fbfee1 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -1149,6 +1149,7 @@ static int btrfs_read_disk_super(struct block_device *bdev, u64 bytenr,
struct page **page,
struct btrfs_super_block **disk_super)
{
+ int err;
void *p;
pgoff_t index;
@@ -1183,6 +1184,18 @@ static int btrfs_read_disk_super(struct block_device *bdev, u64 bytenr,
return -EINVAL;
}
+ err = btrfs_check_super_csum((char *) *disk_super);
+ if (err < 0) {
+ if (err == -EINVAL)
+ pr_err("BTRFS error (device %pg): unsupported checksum type, bytenr=%llu",
+ bdev, bytenr);
+ else
+ pr_err("BTRFS error (device %pg): superblock checksum failed, bytenr=%llu",
+ bdev, bytenr);
+ btrfs_release_disk_super(*page);
+ return err;
+ }
+
if ((*disk_super)->label[0] &&
(*disk_super)->label[BTRFS_LABEL_SIZE - 1])
(*disk_super)->label[BTRFS_LABEL_SIZE - 1] = '\0';
--
2.7.0
^ permalink raw reply related [flat|nested] 13+ messages in thread* Re: [PATCH v3 5/7] btrfs: verify superblock checksum during scan
2018-03-29 10:37 ` [PATCH v3 5/7] btrfs: verify superblock checksum during scan Anand Jain
@ 2018-03-29 12:57 ` Nikolay Borisov
0 siblings, 0 replies; 13+ messages in thread
From: Nikolay Borisov @ 2018-03-29 12:57 UTC (permalink / raw)
To: Anand Jain, linux-btrfs
On 29.03.2018 13:37, Anand Jain wrote:
> During the scan context, we aren't verifying the superblock-
> checksum when read.
> This patch fixes it by adding the checksum verification function
> btrfs_check_super_csum() in the function btrfs_read_disk_super().
> And makes device scan to error fail if the primary superblock csum
> is wrong, whereas if the copy-superblock csum is wrong it will just
> just report mismatch and continue mount/scan as usual. When the
> mount is successful We anyway overwrite all superblocks upon unmount.
>
> The context in which this will be called is - device scan, device ready,
> and mount -o device option.
>
> Test script:
>
> Corrupt primary superblock and check if device scan and mount
> fails:
> mkfs.btrfs -fq /dev/sdc
> dd if=/dev/urandom of=/dev/sdc ibs=1 obs=1 count=1 seek=64K
> btrfs dev scan /dev/sdc
> mount /dev/sdc /btrfs
>
> Corrupt secondary superblock and check if device scan and mount
> is succcessful, check for the dmesg for errors.
> mkfs.btrfs -fq /dev/sdc
> dd if=/dev/urandom of=/dev/sdc ibs=1 obs=1 count=1 seek=67108864
> btrfs dev scan /dev/sdc
> mount /dev/sdc /btrfs
>
> Signed-off-by: Anand Jain <anand.jain@oracle.com>
> v3->v2:
> Also squash 4/8 in here.
> 4/8: btrfs: make btrfs_check_super_csum() non-static
> v1->v2:
> changed title.
> use explicit (< 0) check for %errr.
> Un-split pr_err() string.
> Fix typo in the git commit log.
> Move the csum check after bytenr and btrfs magic verified.
>
> btrfs: make btrfs_check_super_csum() non-static
>
> In preparation to add the superblock csum verification for the
> scan context, make btrfs_check_super_csum() non-static.
>
> Signed-off-by: Anand Jain <anand.jain@oracle.com>
> Reviewed-by: Nikolay Borisov <nborisov@suse.com>
This patch's changelog is garbaged. Duplicated signed off by ,
changelog above scissors etc. Please review your patches carefully
before sending upstream.
> ---
> fs/btrfs/disk-io.c | 2 +-
> fs/btrfs/disk-io.h | 1 +
> fs/btrfs/volumes.c | 13 +++++++++++++
> 3 files changed, 15 insertions(+), 1 deletion(-)
>
> diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
> index 4c573602480c..35dbbdc613cd 100644
> --- a/fs/btrfs/disk-io.c
> +++ b/fs/btrfs/disk-io.c
> @@ -395,7 +395,7 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
> * Otherwise: -EINVAL if csum type is not found
> * -EUCLEAN if csum does not match
> */
> -static int btrfs_check_super_csum(char *raw_disk_sb)
> +int btrfs_check_super_csum(char *raw_disk_sb)
> {
> struct btrfs_super_block *disk_sb =
> (struct btrfs_super_block *)raw_disk_sb;
> diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
> index 70a88d61b547..c400cc68f913 100644
> --- a/fs/btrfs/disk-io.h
> +++ b/fs/btrfs/disk-io.h
> @@ -69,6 +69,7 @@ int write_all_supers(struct btrfs_fs_info *fs_info, int max_mirrors);
> struct buffer_head *btrfs_read_dev_super(struct block_device *bdev);
> int btrfs_read_dev_one_super(struct block_device *bdev, int copy_num,
> struct buffer_head **bh_ret);
> +int btrfs_check_super_csum(char *raw_disk_sb);
> int btrfs_commit_super(struct btrfs_fs_info *fs_info);
> struct btrfs_root *btrfs_read_fs_root(struct btrfs_root *tree_root,
> struct btrfs_key *location);
> diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
> index 035affa447fa..f1f074fbfee1 100644
> --- a/fs/btrfs/volumes.c
> +++ b/fs/btrfs/volumes.c
> @@ -1149,6 +1149,7 @@ static int btrfs_read_disk_super(struct block_device *bdev, u64 bytenr,
> struct page **page,
> struct btrfs_super_block **disk_super)
> {
> + int err;
> void *p;
> pgoff_t index;
>
> @@ -1183,6 +1184,18 @@ static int btrfs_read_disk_super(struct block_device *bdev, u64 bytenr,
> return -EINVAL;
> }
>
> + err = btrfs_check_super_csum((char *) *disk_super);
> + if (err < 0) {
> + if (err == -EINVAL)
> + pr_err("BTRFS error (device %pg): unsupported checksum type, bytenr=%llu",
> + bdev, bytenr);
> + else
> + pr_err("BTRFS error (device %pg): superblock checksum failed, bytenr=%llu",
> + bdev, bytenr);
> + btrfs_release_disk_super(*page);
> + return err;
> + }
> +
> if ((*disk_super)->label[0] &&
> (*disk_super)->label[BTRFS_LABEL_SIZE - 1])
> (*disk_super)->label[BTRFS_LABEL_SIZE - 1] = '\0';
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v2 6/7] btrfs: verify checksum for all devices in mount context
2018-03-29 10:36 [PATCH v3 0/9] Superblock read and verify cleanups Anand Jain
` (4 preceding siblings ...)
2018-03-29 10:37 ` [PATCH v3 5/7] btrfs: verify superblock checksum during scan Anand Jain
@ 2018-03-29 10:37 ` Anand Jain
2018-03-29 10:37 ` [PATCH 7/7] btrfs: drop the redundant invalidate_bdev() Anand Jain
6 siblings, 0 replies; 13+ messages in thread
From: Anand Jain @ 2018-03-29 10:37 UTC (permalink / raw)
To: linux-btrfs
During mount context, we aren't verifying the superblock checksum
for all the devices, instead, we verify it only for the
struct btrfs_fs_device::latest_bdev. This patch fixes it by moving
the checksum verification code from the function open_ctree() into
the function btrfs_read_dev_one_super().
By doing this now we are verifying the superblock checksum in the
mount-context, device-replace and, device-delete context. The
device-replace and device-delete call-chain is as show below after
this patch.
delete-device/replace:
btrfs_rm_device() || btrfs_dev_replace_by_ioctl()
|_btrfs_find_device_by_devspec()
|_btrfs_find_device_missing_or_by_path()
|_btrfs_find_device_by_path()
|_btrfs_get_bdev_and_sb()
|_btrfs_read_dev_super()
|_btrfs_read_dev_one_super()
|_btrfs_check_super_csum()
Test case:
Before:
mkfs.btrfs -fq -draid1 -mraid1 /dev/sdb /dev/sdc
dd if=/dev/urandom of=/dev/sdc ibs=1 obs=1 count=1 seek=64K
mount /dev/sdb /btrfs <-- success as kernel does not check csum
for non-btrfs_fs_devices::latest_bdev.
After:
mkfs.btrfs -fq -draid1 -mraid1 /dev/sdb /dev/sdc
dd if=/dev/urandom of=/dev/sdc ibs=1 obs=1 count=1 seek=64K
mount /dev/sdb /btrfs
mount: mount /dev/sdc on /btrfs failed: Structure needs cleaning
mount -o degraded /dev/sdc /btrfs
mount: mount /dev/sdc on /btrfs failed: Structure needs cleaning
So the current recovery step is to fix the primary superblock, by
using the btrfs-progs cli.
Signed-off-by: Anand Jain <anand.jain@oracle.com>
Reviewed-by: Nikolay Borisov <nborisov@suse.com>
v1->v2:
git commit log update. With the call-chain (which I believe will
go away in the long term, we need the uuid from the userland not
the disk-path). And add test case.
Check err < 0 explicitly and drop check for "else if (err == -EUCLEAN)"
v1:
err = btrfs_check_super_csum(bh->b_data);
if (err) {
if (err == -EINVAL)
pr_err("BTRFS error (device %pg): unsupported checksum algorithm",
bdev);
else if (err == -EUCLEAN)
pr_err("BTRFS error (device %pg): superblock checksum mismatch",
bdev);
brelse(bh);
return err;
}
---
fs/btrfs/disk-io.c | 33 +++++++++++++++++----------------
1 file changed, 17 insertions(+), 16 deletions(-)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 35dbbdc613cd..110465bec775 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2565,22 +2565,6 @@ int open_ctree(struct super_block *sb,
}
/*
- * We want to check superblock checksum, the type is stored inside.
- * Pass the whole disk block of size BTRFS_SUPER_INFO_SIZE (4k).
- */
- err = btrfs_check_super_csum(bh->b_data);
- if (err) {
- if (err == -EINVAL)
- pr_err("BTRFS error (device %pg): unsupported checksum algorithm",
- fs_devices->latest_bdev);
- else
- pr_err("BTRFS error (device %pg): superblock checksum mismatch",
- fs_devices->latest_bdev);
- brelse(bh);
- goto fail_alloc;
- }
-
- /*
* super_copy is zeroed at allocation time and we never touch the
* following bytes up to INFO_SIZE, the checksum is calculated from
* the whole block of INFO_SIZE
@@ -3126,6 +3110,7 @@ int btrfs_read_dev_one_super(struct block_device *bdev, int copy_num,
struct buffer_head *bh;
struct btrfs_super_block *super;
u64 bytenr;
+ int err;
bytenr = btrfs_sb_offset(copy_num);
if (bytenr + BTRFS_SUPER_INFO_SIZE >= i_size_read(bdev->bd_inode))
@@ -3146,6 +3131,22 @@ int btrfs_read_dev_one_super(struct block_device *bdev, int copy_num,
return -EINVAL;
}
+ /*
+ * Check the superblock checksum, the type is stored inside.
+ * Pass the whole disk block of size BTRFS_SUPER_INFO_SIZE (4k).
+ */
+ err = btrfs_check_super_csum(bh->b_data);
+ if (err < 0) {
+ if (err == -EINVAL)
+ pr_err("BTRFS error (device %pg): unsupported checksum algorithm",
+ bdev);
+ else
+ pr_err("BTRFS error (device %pg): superblock checksum mismatch",
+ bdev);
+ brelse(bh);
+ return err;
+ }
+
*bh_ret = bh;
return 0;
}
--
2.7.0
^ permalink raw reply related [flat|nested] 13+ messages in thread* [PATCH 7/7] btrfs: drop the redundant invalidate_bdev()
2018-03-29 10:36 [PATCH v3 0/9] Superblock read and verify cleanups Anand Jain
` (5 preceding siblings ...)
2018-03-29 10:37 ` [PATCH v2 6/7] btrfs: verify checksum for all devices in mount context Anand Jain
@ 2018-03-29 10:37 ` Anand Jain
6 siblings, 0 replies; 13+ messages in thread
From: Anand Jain @ 2018-03-29 10:37 UTC (permalink / raw)
To: linux-btrfs
During the mount context btrfs_open_devices() calls invalidate_bdev()
for all the devices. So drop the invalidate_bdev() in open_ctree()
which is only for the btrfs_fs_devices::latest_bdev.
The call trace is as shown below.
btrfs_mount_root()
|
|_btrfs_parse_early_options (-o device only)
| |_btrfs_scan_one_device
| |_btrfs_read_disk_super()
| |_read_cache_page_gfp()
|
|_btrfs_scan_one_device(mount-arg-dev only)
| |_btrfs_read_disk_super()
| |_read_cache_page_gfp()
|
|
|_btrfs_open_devices(fsid:all)
| |_btrfs_open_one_device()
| |_btrfs_get_bdev_and_sb() <--- invalidate_bdev(fsid:all)
| |_btrfs_read_dev_super()
| |_btrfs_read_dev_one_super()
| |___bread()
|
|_btrfs_fill_super()
|_btrfs_open_ctree() <-- invalidate_bdev(latest_bdev) <-- redundant
|_btrfs_read_dev_super(latest_bdev only)
|_btrfs_read_dev_one_super(latest_bdev only)
|___bread(latest_bdev)
Signed-off-by: Anand Jain <anand.jain@oracle.com>
---
fs/btrfs/disk-io.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 110465bec775..628c2b1d1349 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2553,8 +2553,6 @@ int open_ctree(struct super_block *sb,
__setup_root(tree_root, fs_info, BTRFS_ROOT_TREE_OBJECTID);
- invalidate_bdev(fs_devices->latest_bdev);
-
/*
* Read super block and check the signature bytes only
*/
--
2.7.0
^ permalink raw reply related [flat|nested] 13+ messages in thread