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

📄 fsck.c

📁 是一个手机功能的模拟程序
💻 C
📖 第 1 页 / 共 4 页
字号:
    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 *bhp =
        (struct block_header_s *) offset2addr(dev.binfo[b].offset);

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

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

    ffsdrv.write_halfword(&bhp->age,        age);
    ffsdrv.write_halfword(&bhp->version,    FFS_FORMAT_VERSION);
    ffsdrv.write_halfword(&bhp->magic_low,  BLOCK_MAGIC_LOW);
    ffsdrv.write_halfword(&bhp->magic_high, BLOCK_MAGIC_HIGH);

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

    block_flags_write(b, BF_FREE);

    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 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 the next block a data block
    if ((b = block_alloc(1, 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(OT_DIR);

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

    fs.initerror = ffs_initialize();

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

    fs.journal.i = 0;
    fs.journal.state = JOURNAL_IS_EMPTY;
    fs.journal.repli = 0;
    fs.link_child = 1;   //Default link child in journal_commit()

    if (oldi == 0) {
        fs.journal.flags    = 0xFF;
        fs.journal.diri     = 0;
        fs.journal.oldi     = 0;
        fs.journal.location = 0;
        fs.journal.size     = 0;
    }
    else {
        struct inode_s *oldip = inode_addr(oldi);
        fs.journal.flags    = oldip->flags;
        fs.journal.diri     = oldi;
        fs.journal.oldi     = oldi;
        fs.journal.location = oldip->location;
        fs.journal.size     = oldip->size;
    }
}

// NOTEME: We have compressed the macro code because it will NOT compile on
// Unix otherwise. So until we find out why, we use this as a work-around.
#if (FFS_TEST == 1)
#define JOURNAL_TEST(testcase, text) if (fs.testflags == testcase) { tw(tr(TR_END, TrJournal, "} (" text ")\n")); return; }
#else
#define JOURNAL_TEST(testcase, text)
#endif

// NOTEME: Should we empty journal file when we are anyway relocating it in
// data_reclaim()?
void journal_end(uint8 type)
{
    struct inode_s *ip = inode_addr(fs.ijournal);
    struct journal_s *addr = (struct journal_s *)
        offset2addr(location2offset(ip->location) + fs.journal_pos);
    
    tw(tr(TR_BEGIN, TrJournal, "journal_end(0x%x) {\n", type));
    tw(tr(TR_FUNC, TrJournal, "journal_pos = 0x%04x (%d)\n", fs.journal_pos,
          (fs.journal_pos - JOURNAL_POS_INITIAL) / sizeof(struct journal_s)));
    
    // If this is a create, set the object type
    if (type != 0 && fs.journal.oldi == 0)
        fs.journal.flags = (fs.journal.flags & OF_MASK) | type;

    // If there is no journal file, we can do without it, although we
    // certainly don't like it!
    if (fs.ijournal == 0) {
        journal_commit(0); 
        tw(tr(TR_END, TrJournal, "} No jounal file\n"));
        return;
    }
    
    JOURNAL_TEST(JOURNAL_TEST_EMPTY, "Oops in JOURNAL_IS_EMPTY");
        
    // Write RAM journal to journal file.
    if (fs.journal.state == (uint8) JOURNAL_IS_EMPTY) {
        fs.journal.state = JOURNAL_IS_WRITING;
        ffsdrv.write(addr, &fs.journal, sizeof(fs.journal));
    }
    
    JOURNAL_TEST(JOURNAL_TEST_WRITING, "Oops in JOURNAL_IS_WRITING");
        
    // Advance journal file's state
    if (fs.journal.state == (uint8) JOURNAL_IS_WRITING) {
        fs.journal.state = JOURNAL_IS_READY;
        ffsdrv_write_byte(&addr->state, fs.journal.state);
    }
    
    JOURNAL_TEST(JOURNAL_TEST_READY, "Oops in JOURNAL_IS_READY");
    
    journal_commit(0);
    
    JOURNAL_TEST(JOURNAL_TEST_COMMITTING, "Oops in JOURNAL_TEST_COMMITTING");
    JOURNAL_TEST(JOURNAL_TEST_COMMITTED, "Oops in JOURNAL_COMMITTED");

    // Advance journal file's state
    ffsdrv_write_byte(&addr->state, JOURNAL_IS_DONE);

    JOURNAL_TEST(JOURNAL_TEST_DONE, "Oops in JOURNAL_IS_DONE");

    // Advance journal
    fs.journal_pos += sizeof(struct journal_s);

    // Unless we are currently relocating the journal file itself, check if
    // journal file is near full and relocate it if it is.
    if (fs.journal_pos >= fs.journal_size - FFS_JOURNAL_MARGIN * 
		sizeof(struct journal_s) && fs.journal.oldi != fs.ijournal) {
        tw(tr(TR_FUNC, TrJournal, "Journal file (near) full!\n"));
        journal_create(fs.ijournal);
    }

    // Check if we have just committed the journal file itself
    if (fs.journal.oldi == fs.ijournal) {
        fs.journal_pos = JOURNAL_POS_INITIAL;
        fs.ijournal = fs.journal.i;
        tw(tr(TR_FUNC, TrJournal, "Journal file re-created, fs.ijournal = %d\n",
              fs.ijournal));
    }
    tw(tr(TR_END, TrJournal, "}\n"));
}

// Write contents of fs.journal to FFS meta data (inodes). Note that we do
// NOT traverse ip->copied as we used to do in the old
// object_update_commit(). Also, we do not check if object has been
// erased after traversing ip->copied. All this code has been removed
// because we will very soon have full callback functionality and thus the
// code is redundant.
void journal_commit(uint8 type)

⌨️ 快捷键说明

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