📄 fsck.c
字号:
{
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 + -