📄 fsck.c
字号:
for (q = p + dev.blocksize/4 - 4; q > p; q -= 4) {
if ( ~(q[0] & q[1] & q[2] & q[3]) )
break;
}
if ( ~(q[0] & q[1] & q[2] & q[3]) )
q += 4;
used = atomalign((char *) q - (char *) p);
tw(tr(TR_FUNC, TrFsckLow, "ffs_block_used(%d) %d\n", b, used));
return used;
}
age_t age_distance(age_t x, age_t y)
{
age_t a = x - y;
if (a > 0x8000)
a = -a;
tw(tr(TR_FUNC, TrFsckLow, "age_distance(%d, %d) %d\n", x, y, a));
return a;
}
// For each ffs block, we initialise the basic bstat array information,
// namely the number of used bytes. Also, we locate the inodes block and if
// a previous operation was interrupted by a powerfail, we clean it up.
//
// We return EFFS_OK if all is fine. If a positive integer is returned, it
// denotes a block that needs to be cleaned by block_clean() once FFS
// has been properly intialized (we actually return the block number + 1
// because otherwise it would clash with EFFS_OK return code). If no inodes
// block is found or another error occurs, we return the error code.
bref_t blocks_fsck(void)
{
bref_t b, b_to_clean, b_inode_lost;
int age_valid;
age_t age_min, age_max, age_dist, age_dist_min, age_dist_max;
struct block_header_s *bhp;
uint16 flags_msb, flags_lsb;
ttw(str(TTrInitLow, "blocks_fsck {" NL));
tw(tr(TR_BEGIN, TrFsck, "blocks_fsck() {\n"));
// initialize ages to the illegal/unset value
age_min = age_max = age_dist = 0;
fs.format = 0;
fs.inodes = -1;
fs.newinodes = -1;
b_inode_lost = -1;
b_to_clean = EFFS_OK;
for (b = 0; b < dev.numblocks; b++)
{
tlw(led_toggle(LED_DRV_INIT));
// read block flags from flash
bhp = (struct block_header_s *) offset2addr(dev.binfo[b].offset);
fs.format = bhp->version;
// Format check is performed early because this new version thinks
// that the old state is in an intermediate state thus it tries to
// fix it and we can not allow that
if ((bhp->magic_low == BLOCK_MAGIC_LOW &&
bhp->magic_high == BLOCK_MAGIC_HIGH) &&
(bhp->version >> 8) != (FFS_FORMAT_VERSION >> 8)) {
tw(tr(TR_END, TrFsck, "} %d\n", EFFS_BADFORMAT));
ttw(ttr(TTrInitLow, "} %d" NL, EFFS_BADFORMAT));
return EFFS_BADFORMAT;
}
tw(tr(TR_FUNC, TrFsck, "Block %d, flags 0x%x\n", b, bhp->flags));
#if 0
// Check block header flag for intermediate states (01 or 10)
// NOTEME add further comments?
if ((bhp->flags & 0xAAAA) != ((bhp->flags & 0x5555) << 1)) {
tw(tr(TR_FUNC, TrFsck,"Intermediate state detected in block header:\n"));
// Push the flags to well defined states (01,10 -> 00)
flags_msb = (bhp->flags << 1) & 0xAAAA & bhp->flags;
flags_lsb = (bhp->flags >> 1) & 0x5555 & bhp->flags;
tw(tr(TR_FUNC, TrFsck," blk %d (0x%x->0x%x) \n", b, bhp->flags,
BIT_SET(bstat[b].flags, ~(flags_msb | flags_lsb))));
block_flags_write(b, ~(flags_msb | flags_lsb));
}
#endif
bstat[b].flags = bhp->flags;
bstat[b].used = dev.blocksize;
bstat[b].lost = bstat[b].used;
bstat[b].objects = 0;
age_valid = 0;
if (bhp->magic_low != BLOCK_MAGIC_LOW ||
bhp->magic_high != BLOCK_MAGIC_HIGH) {
// The block magic as bad! It *could* be because the flash
// memory map is incorrect or because another application has
// spuriously written to the flash or ... who knows what.
// Quickly test if block is in empty state. We do not make a
// full check with block_used() because that takes too
// long --- we let preformat() do that.
if (bhp->magic_low == FLASH_NULL16 &&
bhp->magic_high == FLASH_NULL16 &&
bhp->age == FLASH_NULL16 &&
bhp->version == FLASH_NULL16 &&
bhp->flags == FLASH_NULL16)
{
bstat[b].used = 0;
bstat[b].lost = 0;
bstat[b].flags = BF_IS_EMPTY;
tw(tr(TR_FUNC, TrFsck, "EMPTY "));
}
else {
// If the block is not free, it is probably corrupted.
// Thus we reset its age and free it.
tw(tr(TR_FUNC, TrFsck, "magic = 0x%08x\n",
bhp->magic_low | (bhp->magic_high << 16)));
ffsdrv.write_halfword(&bhp->age, 0);
block_free(b);
tw(tr(TR_FUNC, TrFsck, "BAD "));
}
}
else {
age_valid = 1;
if (!is_block(b, BF_IS_FREE)) {
bstat[b].used = block_used(b);
bstat[b].lost = bstat[b].used - BHEADER_SIZE;
}
if (is_block(b, BF_IS_FREE)) {
// The only case where we do not call block_used() is
// when the block is truly free.
bstat[b].used = 0;
bstat[b].lost = 0;
tw(tr(TR_FUNC, TrFsck, "FREE "));
ttw(ttr(TTrInitLow, "FREE" NL));
}
else if (is_block(b, BF_IS_DATA)) {
tw(tr(TR_FUNC, TrFsck, "DATA "));
ttw(ttr(TTrInitLow, "DATA" NL));
}
else if (is_block(b, BF_IS_CLEANING)) {
// Here we schedule a block_clean(). Note that we can
// and do not execute the block cleaning now, as the info
// that block_clean() needs is not at all ready at this
// point in the initialization. So we set a flag and then
// clean the block at the end of ffs_initialize()
tw(tr(TR_FUNC, TrFsck, "CLEANING "));
ttw(ttr(TTrInitLow, "CLEANING" NL));
b_to_clean = b + 1;
}
else if (is_block(b, BF_IS_COPYING)) {
tw(tr(TR_FUNC, TrFsck, "COPYING "));
ttw(ttr(TTrInitLow, "COPYING" NL));
fs.newinodes = b;
}
else if (is_block(b, BF_IS_INODES)) {
tw(tr(TR_FUNC, TrFsck, "INODES "));
ttw(ttr(TTrInitLow, "INODES" NL));
fs.inodes = b;
}
else if (is_block(b, BF_IS_INODES_LOST)) {
tw(tr(TR_FUNC, TrFsck, "INODESLOST"));
ttw(ttr(TTrInitLow, "INODESLOST" NL));
b_inode_lost = b;
}
else {
block_free(b);
tw(tr(TR_FUNC, TrFsck, "INVALID "));
ttw(ttr(TTrInitLow, "INVALID" NL));
}
}
tw(tr(TR_NULL, TrFsck, " %2d: (0x%05x) %02x, used = %6d\n",
b, dev.binfo[b].offset, bstat[b].flags & 0xFF, bstat[b].used));
if (age_valid) {
if (age_min == 0) {
// Initialize minimum and maximum block ages
age_min = age_max = bhp->age;
tw(tr(TR_FUNC, TrFsckLow, "age_min/max = %d\n", age_min));
}
else {
age_dist_min = age_distance(bhp->age, age_min);
age_dist_max = age_distance(bhp->age, age_max);
if (age_dist_min > age_dist ||
age_dist_max > age_dist) {
if (age_dist_max > age_dist_min) {
age_dist = age_dist_max;
age_min = bhp->age;
tw(tr(TR_FUNC, TrFsckLow, "age_min = %d (dist = %d)\n",
age_min, age_dist));
}
else {
age_dist = age_dist_min;
age_max = bhp->age;
tw(tr(TR_FUNC, TrFsckLow, "age_max = %d (dist = %d)\n",
age_max, age_dist));
}
}
}
}
}
tlw(led_off(LED_DRV_INIT));
tw(tr(TR_FUNC, TrFsck, "age min, max, max-min = %d, %d, %d\n",
age_min, age_max, (uint16) (age_max-age_min)));
// If age_max is untouched is is because all blocks were in the 'Empty'
// state. In this case we let the age be as it is (0xFFFF).
if (age_max == 0)
age_max = age_min = BLOCK_AGE_MAX;
// Handle age wrap around thus ensuring fs.age_max is set correctly. We
// have to type-cast the whole computation, otherwise it will be
// incorrect.
if ((age_t) (age_max - age_min) > 0x8000) {
age_dist = age_max;
age_max = age_min;
age_min = age_dist;
}
// save maximum age found for the case of a bad block that is going to
// be reclaimed later on by blocks_reclaim()
fs.age_max = age_max;
tw(tr(TR_FUNC, TrFsck, "fs.format = 0x%04x\n", fs.format));
tw(tr(TR_FUNC, TrFsck, "fs.inodes, newinodes = %d, %d\n",
fs.inodes, fs.newinodes));
ttw(ttr(TTrInit, "fs.inodes, newinodes = %d, %d" NL,
fs.inodes, fs.newinodes));
tw(tr(TR_FUNC, TrFsck, "age min, max = %d, %d\n", age_min, age_max));
// If any blocks were in the EMPTY state, now is the time to bring them
// into the FREE state. Note that we must only do this *after*
// fs.age_max has been initialized.
for (b = 0; b < dev.numblocks; b++) {
if (is_block(b, BF_IS_EMPTY)) {
if ((bstat[b].used = block_used(b)) == 0)
block_preformat(b, 0);
else
block_free(b);
}
}
if (fs.inodes >= 0) {
// The 'old' inode block is still valid thus we keep it.
if (fs.newinodes >= 0)
// The copying of inodes to the new block was not finished thus
// we free the block
block_free(fs.newinodes);
inodes_set(fs.inodes);
}
else {
// Copying must have been finished
if (fs.newinodes >= 0 && b_inode_lost >= 0) {
// The inode reclaim did finish but currently there is no valid
// inode block thus the operation must be finished by committing
// the new block as the valid inode block.
fs.inodes = b_inode_lost;
block_commit();
}
else {
// No old or new Inode block!
tw(tr(TR_END, TrFsck, "} %d\n", EFFS_NOFORMAT));
ttw(ttr(TTrInitLow, "} %d" NL, EFFS_NOFORMAT));
return EFFS_NOFORMAT;
}
}
// FIXME: Insert age sanity check; age distance must not be too big (> 2
// * FFS_AGE_DISTANCE)?
tw(tr(TR_END, TrFsck, "} %d\n", b_to_clean));
ttw(ttr(TTrInitLow, "} %d" NL, b_to_clean));
return b_to_clean;
}
// Set fs.inodes and fs.inodes_addr
void inodes_set(iref_t i)
{
fs.inodes = i;
fs.inodes_addr = (struct inode_s *)
(offset2addr(dev.binfo[fs.inodes].offset)
+ dev.atomsize - sizeof(struct inode_s));
}
/******************************************************************************
* inodes_fsck()
******************************************************************************/
// Now for each inode in the inodes block, update the bstat array
// information: free, used, objects. Also, locate the root inode. We could
// optimize this a little, because bstat[binodes].used gives an inidication
// of how many inodes are actually present in the system.
iref_t inodes_fsck(void)
{
iref_t i, nrepi = 0;
struct inode_s *ip;
char *addr;
bref_t block;
ttw(str(TTrInitLow, "inodes_fsck {" NL));
tw(tr(TR_BEGIN, TrFsck, "inodes_fsck() {\n"));
tw(tr(TR_FUNC, TrFsck, "inodes in block %d:\n", fs.inodes));
// the fields of the bstat entry for the inodes have the meaning:
// used = total number of used inodes (valid, erased, invalid)
// lost = total number of lost inodes (erased, invalid)
// objects = index of first free inode (used by inode_alloc())
fs.root = 0; // default to root inode not found
fs.ijournal = 0; // default to journal file inode not found
bstat[fs.inodes].objects = 1;
bstat[fs.inodes].used = 0;
bstat[fs.inodes].lost = 0;
fs.sequence = 0; // just for debug (fun)
memset(fs.repi_table, 0, sizeof(fs.repi_table));
// we must set some default value for this, so we set it to max possible!
fs.inodes_max = dev.blocksize / sizeof(struct inode_s);
ip = inode_addr(1);
tw(tr(TR_FUNC, TrFsck, " i addr cld sib seq upd flag size name\n"));
for (i = 1; i < fs.inodes_max; i++, ip++)
{
// just for debug (fun)
if (ip->sequence > fs.sequence)
fs.sequence = ip->sequence;
// compute block index and total data space occupied
block = offset2block(location2offset(ip->location));
// Only scan used inodes. blocks_fsck() accounted all used space as
// also being lost space, so now we subtract from the lost space,
// the space used by valid objects
if (ip->location != FLASH_NULL32)
{
bstat[fs.inodes].used++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -