⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fsck.c

📁 是一个手机功能的模拟程序
💻 C
📖 第 1 页 / 共 4 页
字号:
    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;
    struct block_header_old_s *obhp;

    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);
        obhp = (struct block_header_old_s *) bhp;

        bstat[b].used    = dev.blocksize;
        bstat[b].lost    = bstat[b].used;
        bstat[b].flags   = bhp->flags;
        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. First
            // we check to see if the reason is that we are dealing with a
            // (really) old ffs format version.
            if (obhp->magic_low == OLD_BLOCK_MAGIC_LOW &&
                obhp->magic_high == OLD_FFS_FORMAT_VERSION) {
                tw(tr(TR_FUNC, TrFsck, "OLD     "));
                fs.format = obhp->magic_high;
                // We simulate that all the blocks are data blocks, in order
                // to have some well-defined state that preformat() can work
                // on. Later we will return EFFS_BADFORMAT and otherwise
                // leave everything as it is, *without* modifying anything!
                bstat[b].flags = BF_IS_DATA;
            }
            else {
                // 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 {
            fs.format = bhp->version;
            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) {                   // Keep inode
		if (fs.newinodes >= 0)
			block_free(fs.newinodes);   // Not finish copying
		inodes_set(fs.inodes);
	}
	else {                                  // No valid inode block
		// Copying must have been finish
		if (fs.newinodes >= 0 && b_inode_lost >= 0) {
			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;
		}
	}
	
    if ((fs.format >> 8) != (FFS_FORMAT_VERSION >> 8)) {
        tw(tr(TR_END, TrFsck, "} %d\n", EFFS_BADFORMAT));
        ttw(ttr(TTrInitLow, "} %d" NL, EFFS_BADFORMAT));
        return EFFS_BADFORMAT;
    }

    // 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;
    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)

    // 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++;

            tw(tr(TR_FUNC, TrFsck, "%3d 0x%05X  %3d %3d %4d %3d  %s%s%s%s%s%s %6d %s\n",
                  i,
                  location2offset(ip->location),
                  ip->child, ip->sibling,
                  ip->sequence, ip->updates,
                  is_object(ip, OT_DIR)     ? "d" : "",
                  is_object(ip, OT_LINK)    ? "l" : "",
                  is_object(ip, OT_FILE)    ? "f" : "",
                  is_object(ip, OT_SEGMENT) ? "s" : "",
                  is_object(ip, OT_ERASED)  ? " " : "",
                  IS_BIT_SET(ip->flags, OF_READONLY) && !is_object(ip, OT_ERASED) ?
                  "r" : " ",
                  ip->size,
                  // Erased chunks do not have any name so we can not trace erased objects!
                  (ip->size && !is_object(ip, OT_SEGMENT) && !is_object(ip, OT_ERASED) ? 
                   addr2name(offset2addr(location2offset(ip->location))) : "")
                  ));
            
            if (is_object_valid(ip)) {
                // This inode is valid, so we account the data space as used
                // and the inode as used too.
                bstat[block].lost -= ip->size;
                bstat[block].objects++;
                // test if this is the root inode. store index if it is.
                if (!is_object(ip, OT_SEGMENT)) {
                    addr = addr2name(offset2addr(location2offset(ip->location)));
                    if (*addr == '/')
                        fs.root = i;
                    else if (*addr == '.' &&
                             ffs_strcmp(addr, FFS_JOURNAL_NAME) == 0) {
                        fs.ijournal = i;
                    }
                }
            }
            else if (is_object(ip, OT_ERASED)) {
                // this inode's data is deleted, so we account the data
                // space as used and lost and the inode as lost too.
                bstat[fs.inodes].lost++;
            }
            else {
                // This is an invalid object, so we account the data space
                // as used and lost and the inode as lost too. NOTEME: error
                // what should we do? Perhaps we should record semi-lost
                // inodes? Can we safely account for it here if this is an
                // object to be recovered because another inode.copied is
                // referring to this?  Will used/lost etc. be updated
                // correctly then?
                bstat[fs.inodes].lost++;
                tw(tr(TR_NULL, TrFsck, "(invalid = %d)\n", ip->flags & OT_MASK));
            }
        }
    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -