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

📄 fsck.c

📁 MMI层OBJ不能完全编译
💻 C
📖 第 1 页 / 共 5 页
字号:
#if 1
            // Check ERASE flag for intermediate states (10 or 01)
            if ((ip->flags & OT_ERASED_MSb) != 
                ((ip->flags & (OT_ERASED_MSb >> 1)) << 1))
            {
                tw(tr(TR_FUNC, TrFsck,"Intermediate state detected in inode flag:\n"));    
                tw(tr(TR_FUNC, TrFsck, "    inode %d (0x%x->0x%x)\n", 
                      i, ip->flags, ip->flags & OT_ERASED));
                ffsdrv_write_byte(&ip->flags, ip->flags & OT_ERASED);
            }
#endif
            tw(tr(TR_FUNC, TrFsck, "%3d 0x%05X  %3d %3d %4d %3d  %s%s%s%s%s%s%s %6d %s\n",
                  i,
                  location2offset(ip->location),
                  ip->child, ip->sibling,
                  ip->sequence, ip->updates,
                  is_object(ip, OTE_DIR)     ? " d" : "",
                  is_object(ip, OTE_LINK)    ? " l" : "",
                  is_object(ip, OTE_FILE)    ? " f" : "",
                  is_object(ip, OTE_SEGMENT) ? " s" : "",
                  is_object(ip, OT_REP)     ? "rp" : "",
                  is_object_erased(ip)  ? "  " : "",
                  IS_BIT_SET(ip->flags, OFE_READONLY) && !is_object_erased(ip) ?
                  "r" : " ",
                  ip->size,
                  // Erased chunks do not have any name so we cannot trace erased objects!
                  (ip->size && !is_object(ip, OTE_SEGMENT) && !is_object_erased(ip) ? 
                   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. Only exception is the
                // replacement inode, it is not counted as an object
                if (!is_object(ip, OT_REP)) {
                    bstat[block].lost -= ip->size;
                    bstat[block].objects++;
                }
                // test if this is the root inode. store index if it is.
                if (!is_object(ip, OTE_SEGMENT) && !is_object(ip, OT_REP)) {
                    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_erased(ip)) {
                // 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 = 0x%x)\n", ip->flags));
            }

            if (is_object(ip, OT_REP)) {
                // Add the replacement inode in the ram table
                fs.repi_table[nrepi] = i;
                nrepi++;
                if (nrepi == FFS_REPLACEMENT_INODES_MAX)
                    ffs_panic(EFFS_2MANYREPI);
            }
        }
    }
    ttw(ttr(TTrInit, "fs.root=%d, journal=%d" NL, fs.root, fs.ijournal));
    tw(tr(TR_END, TrFsck, "} used: %d, lost: %d, root: %d, journal: %d\n",
       bstat[fs.inodes].used, bstat[fs.inodes].lost, fs.root, fs.ijournal));

    fs.sequence++;
    
    tw(tr_bstat());

    if (fs.root == 0) {
        ttw(ttr(TTrInitLow, "} %d" NL, EFFS_NOFORMAT));
        return EFFS_NOFORMAT;
    }

    ttw(str(TTrInitLow, "} 0" NL));

    return EFFS_OK;
}


/******************************************************************************
 * Preformat and format
 ******************************************************************************/

// Prepare all blocks for fs_format(). Because ffs_is_formattable() has
// already been called prior to this function, we know that no sector erase
// is in progress! The blocks are prepared by putting them into the 'Free'
// state.
effs_t fs_preformat(void)
{
    bref_t b;

    ttw(str(TTrFormat, "preformat {" NL));
    tw(tr(TR_BEGIN, TrFormat, "fs_preformat() {\n"));

    // Mark ffs as being non-formatted from now on.
    fs.root = 0;

    // We must initialize bstat[fs.inodes].used and inodes_high, such that
    // inodes_reclaim() isn't triggered in reclaim() on the following
    // fs_format().
    inodes_set(0);
    bstat[fs.inodes].used    = 0;
    bstat[fs.inodes].lost    = 0;
    bstat[fs.inodes].objects = 0;

    // While format is in progress, we make FFS inaccessible to other
    // functions...
    fs.initerror = EFFS_NOFORMAT;

    if (dev.manufact == 0) {
        b = EFFS_NODEVICE;
    }
    else {
        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);
            }
            else if (!is_block(b, BF_IS_FREE)) {
                block_free(b);
            }
        }
        b = EFFS_OK;
    }

    tw(tr(TR_END, TrFormat, "} %d\n", b));
    ttw(ttr(TTrFormat, "} %d" NL, b));

    return b;
}

// Preformat a single block thus taking it from the 'Empty' state into
// 'Free' state.
void block_preformat(bref_t b, age_t age)
{
    int set_age_max;
    struct block_header_s bhb;
    struct block_header_s *bhp =
        (struct block_header_s *) offset2addr(dev.binfo[b].offset);

    tw(tr(TR_BEGIN, TrFormat, "fs_block_preformat(%d, %d)\n", b, age));

    POWERFAIL_DOMAIN_BEGIN(PFM_BLOCKHEADER);
    POWERFAIL_SET_ADDR((int)bhp);

    if (age == 0) {
        age = fs.age_max;
    }
    else {
        // We schedule an update of fs.age_max. Due to proper handling of
        // age wrap-around, we can not actually set it now.
        set_age_max = (age == fs.age_max);
        age++;
        if (age == 0)
            age++;
        if (set_age_max) {
            fs.age_max = age;
            tw(tr(TR_FUNC, TrFormat, "new fs.age_max = %d\n", fs.age_max));
        }
    }

    bstat[b].flags = BF_IS_EMPTY;
    bstat[b].used = 0;
    bstat[b].lost = 0;
    bstat[b].objects = 0;

    block_flags_write(b, BF_WRITING);

    // Write block header from local buffer
    bhb.magic_low  = BLOCK_MAGIC_LOW;
    bhb.magic_high = BLOCK_MAGIC_HIGH;
    bhb.version    = FFS_FORMAT_VERSION;
    bhb.age        = age;
    // Do not write flag and reserved 
    ffsdrv.write(bhp, &bhb, sizeof(bhb.magic_low) + sizeof(bhb.magic_high) + 
                 sizeof(bhb.version) + sizeof(age_t));

    block_flags_write(b, BF_FREE);

    POWERFAIL_DOMAIN_END();

    tw(tr(TR_END, TrFormat, ""));
}

// After preformat() has erased two blocks, this function can be called to
// initialize ffs by writing fs data and metadata.  Note that ffs_begin() is
// *not* called before this function in ffs.c. Otherwise we would never
// enter this function because fs.root is zero. NOTEME: this is also a bug
// as this means we risk that this operation is started while an erase (or a
// write) is in progress! How the flash device reacts to this is currently
// unknown.
effs_t fs_format(const char *name)
{
    bref_t i,b;

    ttw(str(TTrFormat, "format {" NL));
    tw(tr(TR_BEGIN, TrFormat, "fs_format('%s') {\n", name));

    // Initialize file system parameters. It should be safe to change these
    // now, as the format cannot fail at this point onwards.
    fs_params_init(name);

    // Make the first block be the inodes block
    if ((fs.inodes = block_alloc(1, BF_COPYING)) < 0)
        return EFFS_AGAIN;
    block_flags_write(fs.inodes, BF_INODES);
    inodes_set(fs.inodes);

    // Make all block as data blocks except from the free_min and inode block
    for (i = 0; i < dev.numblocks - fs.blocks_free_min - 1; i++) 
        if ((b = block_alloc(0, BF_DATA)) < 0)
            return EFFS_AGAIN;

    // Restart object sequencing (debug feature only)
    fs.sequence = 0;

    // Create root directory
    journal_begin(0);
    if ((fs.root = object_create(name, 0, 0, 0)) < 0) {
        tw(tr(TR_END, TrFormat, "} %d\n", fs.root));
        return fs.root;
    }
    journal_commit(OTE_DIR);

    if ((fs.ijournal = journal_create(0)) < 0) {
        tw(tr(TR_END, TrFormat, "} %d\n", fs.ijournal));
        return fs.ijournal;
    }

    fs.initerror = ffs_initialize();
	ffs_initerror[4] = fs.initerror;

    ttw(ttr(TTrFormat, "} %d" NL, fs.initerror));
    tw(tr(TR_END, TrFormat, "} %d\n", fs.initerror));

    return fs.initerror;
}

// Check if we are ready to preformat (flag = 0) or format (flag = 1)
//
// For a format, we must first ensure no blocks are valid e.g. a preformat
// has already been run. Next, we must ensure we have preformatted all
// blocks e.g. all blocks are in the 'Free' state. This is actually the same
// thing but it sure helps the user because it yields a more precise error
// code when the format fails. In future we might be able to start a format
// when only two blocks have been preformatted, but this is harder because
// we have to make sure not to read from the physical sector that we are
// erasing, and this is exactly what ffs_ffs_initialize() currently does
// (when it is called at the end of format()).
//
// For a preformat, we must ensure an erase is not in progress (because we
// don't know how the device will react to a new erase when an erase is
// currently suspended).
effs_t is_formattable(int8 flag)
{
    bref_t i, free, valid;
    effs_t error = EFFS_OK;

    tw(tr(TR_FUNC, TrFormat, "is_formattable() "));

    // Count the number of valid and free blocks. These numbers will later
    // be checked to see if we are really ready for a (pre)format(). Note
    // that we *only* read block flags from the bstat[] array. We must not
    // read directly from the flash sectors because an erase might be in
    // progress!
    for (i = 0, free = 0, valid = 0; i < dev.numblocks; i++) {
        if (is_block(i, BF_IS_DATA) || is_block(i, BF_IS_INODES))
            valid++;
        if (is_block(i, BF_IS_FREE))
            free++;
    }
    if (flag == 0) {
        // In the case of a preformat, ensure an erase is not in
        // progress (because we don't know how the device will react to a new
        // erase when an erase is currently suspended).
        if (dev.state == DEV_ERASE || dev.state == DEV_ERASE_SUSPEND) {
            tw(tr(TR_NULL, TrFormat, "(%d)\n", EFFS_AGAIN));
            return EFFS_AGAIN;
        }
    }
    else {
        if (valid > 0)
            // Ensure we have preformatted prior to a format.
            error = EFFS_NOPREFORMAT;
        else if (free < dev.numblocks)
            // Ensure all blocks are free before a format(). If not, a
            // preformat() is currently in progress.
            error = EFFS_AGAIN;
    }

    tw(tr(TR_NULL, TrFormat, "(%d)\n", error));
    return error;
}


/******************************************************************************
 * Journalling
 ******************************************************************************/

// The following matrix illustrates how the members of an inode change for
// the various (journalled) operations:
//
//          | flags | size | loc | child | siblg | dir | oldi | updates
// ---------+-------+------+-----+-------+-------+-----+------+--------
// create   | new   | new  | new | -     | -     | ins | n/a  | 0
// fupdate  | o     | new  | new | o     | -     | ins | del  | old+1
// relocate | o     | o    | new | o     | -     | ins | del  | old+1
// fctrl    | new   | o    | o   | o     | -     | ins | del  | old+1
// remove   | n/a   | n/a  | n/a | n/a   | n/a   | n/a | del  | n/a  
//
//  -  = leave empty (0xFFFF)
// ins = insert/append into directory
// o   = old value
//
// We don't have to store child member in the journal entry because either
// it is EMPTY (fs.journal.oldi = 0) or it is retrieved from oldip->child.

// NOTEME: With journalling implemented, object_relocate might be able just
// to make a simple data copy!

// block_clean() is safe (without journalling), now that only ip->size is
// set to zero.

// Begin a new journal. Either a fresh object create (oldi == 0) or an
// update of an existing object (oldi == iref of old object)
void journal_begin(iref_t oldi)
{
    tw(tr(TR_FUNC, TrJournal, "journal_begin(%d)\n", oldi));

⌨️ 快捷键说明

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