Generic block header checks: crc, magic.

Generally as we call block_get() we should validate that if the block
has a hdr, at a minimum the crc is correct and the magic value is
the expected value passed, and the fsid matches the superblock. This
function implements just that. Returns -EINVAL, up to the caller to
report a problem() and handle the outcome. For now the code just hard
fails, which incedentally makes it fail the clobber-repair.sh tests
I wrote.

Signed-off-by: Auke Kok <auke.kok@versity.com>
This commit is contained in:
Auke Kok
2024-03-26 18:26:33 -04:00
parent f5f39f4432
commit ca57794a00
5 changed files with 67 additions and 0 deletions

View File

@@ -50,6 +50,10 @@ int alloc_list_meta_iter(struct scoutfs_alloc_list_head *lhead, extent_cb_t cb,
lblk = block_buf(blk);
/* XXX verify block */
ret = block_hdr_valid(blk, blkno, 0, SCOUTFS_BLOCK_MAGIC_ALLOC_LIST);
if (ret < 0)
goto out;
/* XXX sort? maybe */
ref = lblk->next;
@@ -89,6 +93,9 @@ int alloc_list_extent_iter(struct scoutfs_alloc_list_head *lhead, extent_cb_t cb
lblk = block_buf(blk);
/* XXX verify block */
ret = block_hdr_valid(blk, blkno, 0, SCOUTFS_BLOCK_MAGIC_ALLOC_LIST);
if (ret < 0)
goto out;
/* XXX sort? maybe */
ret = 0;

View File

@@ -17,7 +17,10 @@
#include "block.h"
#include "debug.h"
#include "super.h"
#include "eno.h"
#include "crc.h"
#include "sns.h"
static struct block_data {
struct list_head *hash_lists;
@@ -297,6 +300,45 @@ static struct list_head *hash_bucket(struct block_data *bdat, u64 blkno)
return &bdat->hash_lists[hash % bdat->hash_nr];
}
int block_hdr_valid(struct block *blk, u64 blkno, int bf, u32 magic)
{
struct scoutfs_block_header *hdr;
size_t size = (bf & BF_SM) ? SCOUTFS_BLOCK_SM_SIZE : SCOUTFS_BLOCK_LG_SIZE;
int ret;
u32 crc;
ret = block_get(&blk, blkno, bf);
if (ret < 0) {
fprintf(stderr, "error reading block %llu\n", blkno);
goto out;
}
hdr = block_buf(blk);
crc = crc_block(hdr, size);
if ((le32_to_cpu(hdr->crc) != crc) ||
(le32_to_cpu(hdr->magic) != magic))
ret = -EINVAL;
/*
* Our first caller fills in global_super. Until this completes,
* we can't do this check.
*/
if ((blkno != SCOUTFS_SUPER_BLKNO) &&
(hdr->fsid != global_super->hdr.fsid))
ret = -EINVAL;
block_put(&blk);
debug("%s blk_hdr_valid blkno %llu size %lu crc 0x%08x magic 0x%08x ret %d",
sns_str(), blkno, size, le32_to_cpu(hdr->crc), le32_to_cpu(hdr->magic),
ret);
out:
return ret;
}
static struct block *get_or_alloc(struct block_data *bdat, u64 blkno, int bf)
{
struct list_head *bucket = hash_bucket(bdat, blkno);

View File

@@ -29,4 +29,6 @@ int block_try_commit(bool force);
int block_setup(int meta_fd, size_t max_cached_bytes, size_t max_dirty_bytes);
void block_shutdown(void);
int block_hdr_valid(struct block *blk, u64 blkno, int bf, u32 magic);
#endif

View File

@@ -88,6 +88,10 @@ static int btree_ref_meta_iter(struct scoutfs_block_ref *ref, unsigned level, ex
if (ret < 0)
return ret;
ret = block_hdr_valid(blk, blkno, 0, SCOUTFS_BLOCK_MAGIC_BTREE);
if (ret < 0)
return ret;
sns_push("btree_parent", blkno, 0);
bt = block_buf(blk);
@@ -157,6 +161,10 @@ static int btree_ref_item_iter(struct scoutfs_block_ref *ref, unsigned level,
else
sns_push("btree_leaf", blkno, 0);
ret = block_hdr_valid(blk, blkno, 0, SCOUTFS_BLOCK_MAGIC_BTREE);
if (ret < 0)
return ret;
bt = block_buf(blk);
/* XXX integrate verification with block cache */

View File

@@ -28,6 +28,8 @@ int check_supers(void)
struct block *blk = NULL;
int ret;
sns_push("supers", 0, 0);
global_super = malloc(sizeof(struct scoutfs_super_block));
if (!global_super) {
fprintf(stderr, "error allocating super block buffer\n");
@@ -41,6 +43,10 @@ int check_supers(void)
goto out;
}
ret = block_hdr_valid(blk, SCOUTFS_SUPER_BLKNO, BF_SM, SCOUTFS_BLOCK_MAGIC_SUPER);
if (ret < 0)
return ret;
super = block_buf(blk);
memcpy(global_super, super, sizeof(struct scoutfs_super_block));
@@ -48,6 +54,8 @@ int check_supers(void)
out:
block_put(&blk);
sns_pop();
return ret;
}