Added lfsr_file_ckmeta/ckdata
These are basically the same as lfsr_fs_ckmeta/ckdata but limited to a
single file. They may be useful when you need to validate a file but
don't want to bother validating the entire filesystem:
// Check a file for metadata errors
int lfsr_file_ckmeta(lfs_t *lfs, lfsr_file_t *file);
// Check a file for metadata + data errors
int lfsr_file_ckdata(lfs_t *lfs, lfsr_file_t *file);
I've also added test_ck to test these and added some more
lfsr_fs_ckmeta/ckdata tests there. These currently just test simple
full-block clobbering, but we should eventually test more interesting
error patterns.
Unfortunately lfsr_file_ckmeta/ckdata can't reuse the internal
lfsr_mtree_traverse in quite the same way lfsr_fs_ckmeta/ckdata can, so
they're actually a bit more expensive. Though keep in mind with
link-time gc you won't pay the cost unless you call these functions:
code stack
before: 36024 2696
after: 36368 (+1.0%) 2664 (-1.2%)
Oh, and the multiple calls to lfsr_btree/bshrub_traverse apparently
uninlined it out of lfsr_mtree_traverse, saving the stack cost in the
stack hot-path... Yay?
This commit is contained in:
@@ -11744,6 +11744,67 @@ failed:;
|
||||
return err;
|
||||
}
|
||||
|
||||
// file check functions
|
||||
static int lfsr_file_ck(lfs_t *lfs, lfsr_file_t *file, uint32_t flags) {
|
||||
// traverse the file's btree
|
||||
lfsr_btraversal_t bt = LFSR_BTRAVERSAL();
|
||||
while (true) {
|
||||
lfsr_tag_t tag;
|
||||
lfsr_bptr_t bptr;
|
||||
int err = lfsr_bshrub_traverse(lfs,
|
||||
&file->o.o.mdir, &file->o.bshrub,
|
||||
&bt,
|
||||
NULL, &tag, &bptr);
|
||||
if (err) {
|
||||
if (err == LFS_ERR_NOENT) {
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
// validate btree nodes?
|
||||
if ((lfsr_t_isckmeta(flags)
|
||||
|| lfsr_t_isckdata(flags))
|
||||
&& tag == LFSR_TAG_BRANCH) {
|
||||
lfsr_rbyd_t *rbyd = (lfsr_rbyd_t*)bptr.data.u.buffer;
|
||||
err = lfsr_rbyd_fetchck(lfs, rbyd,
|
||||
rbyd->blocks[0], rbyd->trunk,
|
||||
rbyd->cksum);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// validate data blocks?
|
||||
if (lfsr_t_isckdata(flags)
|
||||
&& tag == LFSR_TAG_BLOCK) {
|
||||
err = lfsr_bptr_ck(lfs, &bptr);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lfsr_file_ckmeta(lfs_t *lfs, lfsr_file_t *file) {
|
||||
LFS_ASSERT(lfsr_omdir_isopen(lfs, &file->o.o));
|
||||
// can't read from writeonly files
|
||||
LFS_ASSERT(!lfsr_o_iswronly(file->o.o.flags));
|
||||
|
||||
return lfsr_file_ck(lfs, file, LFS_T_CKMETA);
|
||||
}
|
||||
|
||||
int lfsr_file_ckdata(lfs_t *lfs, lfsr_file_t *file) {
|
||||
LFS_ASSERT(lfsr_omdir_isopen(lfs, &file->o.o));
|
||||
// can't read from writeonly files
|
||||
LFS_ASSERT(!lfsr_o_iswronly(file->o.o.flags));
|
||||
|
||||
return lfsr_file_ck(lfs, file, LFS_T_CKMETA | LFS_T_CKDATA);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user