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

📄 fsck.c

📁 是一个手机功能的模拟程序
💻 C
📖 第 1 页 / 共 4 页
字号:
{
    struct inode_s *ip    = inode_addr(fs.journal.i);
    struct inode_s *oldip = inode_addr(fs.journal.oldi);
    struct inode_s *dp;
    bref_t b;

    tw(tr(TR_BEGIN, TrJournal, "journal_commit(%d) {\n", type));
    tw(tr(TR_FUNC, TrJournal, "i = %d\n", fs.journal.i));
    ttw(ttr(TTrObj, "jc(){" NL));

    if (fs.journal.i)
    {
        // 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;
        
        tw(tr(TR_FUNC, TrJournal, "loc   = 0x%04x, size = %d\n",
              fs.journal.location, fs.journal.size));
        ffsdrv.write((uint32 *) &ip->location, (uint32 *) &fs.journal.location, sizeof(location_t));
        ffsdrv.write_halfword((uint16 *) &ip->size,     fs.journal.size);

        if (fs.journal.oldi != 0 && fs.link_child != 0)
            // If this is an update, we copy the child member from old
            // inode. We must do this before we validate the new object,
            // otherwise an intermediate readdir() will detect an empty
            // directory!
            ffsdrv.write_halfword((uint16*) &ip->child, oldip->child);
    
        tw(tr(TR_FUNC, TrJournal, "seq   = %d\n", fs.sequence));
        // We must check if sequence is already written because if this
        // commit was inititiated by journal_init(), we don't know exactly
        // what was written
        if (ip->sequence == FLASH_NULL16)
            ffsdrv.write_halfword(&ip->sequence, fs.sequence++);
        if (fs.journal.oldi == 0)
            ffsdrv.write_halfword(&ip->updates,  0);
        else
            ffsdrv.write_halfword(&ip->updates,  oldip->updates + 1);

        JOURNAL_TEST(JOURNAL_TEST_COMMITTING, "Oops in JOURNAL_TEST_COMMITTING")

        // Insert object into directory structure. We must do this before
        // deleting old object, otherwise an intermediate readdir() will
        // fail with EFFS_NOTFOUND. Note that when the root directory is
        // created, fs.journal.diri is zero --- thus the test!
        if (fs.journal.diri != 0) {
            tw(tr(TR_FUNC,  TrJournal, "diri  = %d ", fs.journal.diri));
            if (fs.journal.diri < 0) {
                tw(tr(TR_NULL,  TrJournal, "child\n"));
                dp = inode_addr(-fs.journal.diri);
                ffsdrv.write_halfword((uint16 *) &dp->child, fs.journal.i);
            }
            else {
                tw(tr(TR_NULL,  TrJournal, "sibling\n"));
                dp = inode_addr(fs.journal.diri);
                ffsdrv.write_halfword((uint16 *) &dp->sibling, fs.journal.i);
            }
        }

        // The new object is validated before the old object is deleted.
        // This is in order to avoid an interrupting stat or read operation
        // to fail with EFFS_NOTFOUND
        tw(tr(TR_FUNC,  TrJournal, "flags = 0x%02x\n", fs.journal.flags));
        ffsdrv_write_byte(&ip->flags, fs.journal.flags);

        // Update bstat[] appropriately
        b = offset2block(location2offset(ip->location));
        bstat[b].objects++;
        tw(tr(TR_FUNC,  TrJournal, "bstat[%d].objects = %d\n", b, bstat[b].objects));
    }

    tw(tr(TR_FUNC,  TrJournal, "oldi  = %d\n", fs.journal.oldi));
    if (fs.journal.oldi != 0)
    {
        // If this is an update or an erase, we erase the old object
        ffsdrv_write_byte(&oldip->flags, OT_ERASED);

        // Update bstat according to deletion of the old object.
        b = offset2block(location2offset(oldip->location));
        bstat[b].objects--;
        tw(tr(TR_FUNC,  TrJournal, "bstat[%d].objects = %d\n", b, bstat[b].objects));

        // If we moved the data (all cases, except fcontrol), update lost
        if (fs.journal.location != oldip->location)
            bstat[b].lost += oldip->size;

        bstat[fs.inodes].lost++;
        
        // If we renamed a file to an existing filename, remove the replaced file. 
        if (fs.journal.repli > 0)
            object_remove(fs.journal.repli); // Ignore error! 
    }

    tw(tr(TR_END, TrJournal, "}\n"));
    ttw(ttr(TTrObj, "}" NL));
}

// Save the current journal into "old" journal. We need this because an
// object_create() can call data_reclaim() which can call object_relocate()
// which uses the journal system.
int journal_push(void)
{
    memcpy(&fs.ojournal, &fs.journal, sizeof(struct journal_s));
    fs.journal_depth++;
    if (fs.journal_depth > 1) {
        tw(tr(TR_FUNC, TrAll, "FATAL: journal_push() to depth %d\n",
              fs.journal_depth));
		return -1;
	}

    tw(tr(TR_FUNC, TrJournal, "journal_push() to depth %d\n",
          fs.journal_depth));
	
	return EFFS_OK;
}

// Recall "old" journal into current journal
int journal_pop(void)
{
    tw(tr(TR_FUNC, TrJournal, "journal_pop() from depth %d\n",
          fs.journal_depth));

    fs.journal_depth--;
    if (fs.journal_depth < 0) {
        tw(tr(TR_FUNC, TrAll, "FATAL: journal_pop() to depth %d\n",
              fs.journal_depth));
		return -1;
    }
    memcpy(&fs.journal, &fs.ojournal, sizeof(struct journal_s));

	return EFFS_OK;
}

// Initialize the journalling system. Create journal file if it not already
// exist. Commit/write pending journal if such exists --- return 1 in that
// case. Otherwise, if journal file is clean (no journals pending) and all
// is fine, return EFFS_OK.
effs_t journal_init(iref_t i)
{
    int j;
    struct inode_s *ip = inode_addr(i);
    struct journal_s *addr;

    if (i == 0) {
        // Journal file does not exist, so create it
        if ((i = journal_create(0)) <= 0) {
            fs.ijournal = 0;
            return i;
        }
    }

    fs.journal_depth = 0;
    fs.journal_pos = JOURNAL_POS_INITIAL;

    addr = (struct journal_s *)
        offset2addr(location2offset(ip->location) + fs.journal_pos);

    tw(tr(TR_BEGIN, TrJournal, "journal_init(%d) {\n", i));

    fs.ijournal = i;

    // Search for first non-completed journal entry.
    for (j = 0; /* FIXME: limit to end of journal */; j++, addr++) {
        if (addr->state != (uint8) JOURNAL_IS_DONE)
            break;
    }
    tw(tr(TR_FUNC, TrJournal, "entry %d is in state 0x%x\n", j, addr->state));

    fs.journal_pos += j * sizeof(fs.journal);
    i = EFFS_OK;

    if (addr->state == (uint8) JOURNAL_IS_EMPTY) {
        tw(tr(TR_FUNC, TrJournal, "Last journal is in EMPTY state\n"));
        // Journal file is proper, so just record position
    }
    else if (addr->state == (uint8) JOURNAL_IS_READY) {
        // Copy the entry into fs.journal.
        tw(tr(TR_FUNC, TrJournal, "Last journal is in READY state\n"));
        memcpy(&fs.journal, addr, sizeof(fs.journal));
        journal_end(0);
        i = 1;
    }
    else {
        // Journal entry wasn't finished, so just ignore it after updating
        // its state to JOURNAL_IS_DONE.
        tw(tr(TR_FUNC, TrJournal, "Last journal is between EMPTY and READY\n"));
        ffsdrv_write_byte(&addr->state, JOURNAL_IS_DONE);
        fs.journal_pos += sizeof(fs.journal);
    }

    if (ip->size != fs.journal_size + atomalign(sizeof(FFS_JOURNAL_NAME) + 1)) {
        tw(tr(TR_FUNC, TrJournal, "Wrong journal size, create new\n"));
        // Journal size do not match default size, so create new. This
        // should only happen if we use an old FFS image with a newer FFS
        // version.
        if ((i = journal_create(fs.ijournal)) <= 0) {
            fs.ijournal = 0;
            return i;
        }
    }

    tw(tr(TR_FUNC, TrJournal, "journal_pos = 0x%04x\n", fs.journal_pos));
    tw(tr(TR_END, TrJournal, "} %d\n", i));
    
    return i;
}

// Create the journal file from scratch or relocate an existing one. It is
// marked read-only just for clarity --- it cannot be deleted anyway!
// fs_format() calls this function. Note that no data are written in
// object_create() because the journal file is handled specially in that
// function.
iref_t journal_create(iref_t oldi)
{
    iref_t i;

    tw(tr(TR_BEGIN, TrJournal, "journal_create(%d) {\n", oldi));
    tw(tr(TR_FUNC, TrJournal, "journal file size = %d\n", fs.journal_size));

    if (fs.journal_size == 0) {
        tw(tr(TR_FUNC, TrJournal, "Journal file creation aborted because fs.journal_size = 0 (No journal file wanted)\n"));
        tw(tr(TR_END, TrJournal, "} %d\n", 0));
        return 0;
    }

    // If we are working on a write-once file system, we do not need a
    // journal.
    if (fs.blocks_free_min == 0) {
        tw(tr(TR_FUNC, TrJournal, "Journal file creation aborted because fs.blocks_free_min = 0 (write-once system)\n"));
        tw(tr(TR_END, TrJournal, "} %d\n", 0));
        return 0;
    }

    journal_begin(oldi);

    i = object_create(FFS_JOURNAL_NAME, 0, fs.journal_size, -fs.root);
    if (i < 0) {
        tw(tr(TR_END, TrJournal, "} %d\n", i));
        return i;
    }
    fs.journal.flags = BIT_SET(fs.journal.flags, OF_READONLY);

    // commit the creation or relocation
    if (oldi != 0)
        journal_end(0);
    else {
        journal_commit(OT_FILE);
        fs.journal_pos = JOURNAL_POS_INITIAL;
    }

    tw(tr(TR_END, TrJournal, "} %d\n", i));

    return i;
}

/******************************************************************************
 * FFS Begin and End
 ******************************************************************************/

// The following two functions should surround the code of every API
// function in ffs.c (except preformat and format). The functions
// ensures that the operation about to be executed can be made without
// race-conditions or other problems.
#if (TARGET == 0)
int debug_suspend = 0;
#endif


// Check if ffs has been initialized. Suspend an erase operation.
effs_t ffs_begin(void)
{
#if (TARGET == 0)  
    if (debug_suspend > 0) {
        tw(tr(TR_FUNC, TrAll, "FATAL: Previous erase_suspend was not resumed\n"));
        return EFFS_CORRUPTED;
    }
//    tw(tr(TR_FUNC, TrHelper, "Set debug_suspend\n"));
    debug_suspend = 1;
#endif

    if (fs.initerror != EFFS_OK)
        return fs.initerror;

    // Suspend an erase in progress (only applicable if we are using a
    // multi-bank device driver)
    if (dev.state == DEV_ERASE) {
        ffsdrv.erase_suspend();
    }
    else if (dev.state == DEV_WRITE) {
        ffsdrv.write_end();
    }
        
    return EFFS_OK;
}

// Resume an erase operation that was in progress.
int ffs_end(int error)
{
#if (TARGET == 1)
    // Resume an erase in progress (only applicable if we are using a
    // multi-bank device driver)
    if (dev.state == DEV_ERASE_SUSPEND) {
        ffsdrv.erase_resume();
    }
#else
    debug_suspend = 0;
#endif

    return error;
}

/******************************************************************************
 * FFS Statistics functions
 ******************************************************************************/

// Not implemented:
int statistics_file_create(void)
{
    return 0;
}

// Not implemented:
// Rewrite the statistics file if it exists. Otherwise return error
// code. The function is called after each data and inodes reclaim (after
// writing the file that provoked the reclaim).
int statistics_write(void)
{
    return 0;
}

// Read the statistics file if it exists. Otherwise reset all statistics to
// zero and set the magic. This function is called from ffs_init().
void statistics_init(void)
{
	memset(&stats, 0, sizeof(struct ffs_stats_s));
}

void statistics_update_drec(int valid, int lost, int candidate)
{
    unsigned int old;

    switch (candidate) {
    case MOST_LOST:   stats.drec.most_lost++;   break;
    case MOST_UNUSED: stats.drec.most_unused++; break;
    case YOUNGEST:    stats.drec.youngest++;    break;
    }

    // Increment Most Significant Word if overflow is detected
    old = stats.drec.valid[0];
    stats.drec.valid[0] += valid;
    if (old > stats.drec.valid[0])
        stats.drec.valid[1]++;

    old = stats.drec.lost[0];
    stats.drec.lost[0] += lost;
    if (old > stats.drec.lost[0])
        stats.drec.lost[1]++;
}

void statistics_update_irec(int valid, int lost)
{
    stats.irec.num++;
    stats.irec.valid += valid;
    stats.irec.lost += lost;
}
 

⌨️ 快捷键说明

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