📄 fsck.c
字号:
fs.journal.i = 0;
fs.journal.state = JOURNAL_IS_EMPTY;
fs.journal_ram.repli = 0;
fs.link_child = 1; //Default link child in journal_commit()
if (oldi == 0) {
fs.journal.diri = 0;
fs.journal.oldi = 0;
fs.journal_ram.flags = 0xFF;
fs.journal_ram.location = 0;
fs.journal_ram.size = 0;
}
else {
struct inode_s *oldip = inode_addr(oldi);
fs.journal.diri = oldi;
fs.journal.oldi = oldi;
fs.journal_ram.flags = oldip->flags | OF_MASK; // Clean valid flag
fs.journal_ram.location = oldip->location;
fs.journal_ram.size = oldip->size;
}
}
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)));
POWERFAIL_DOMAIN_BEGIN(PFM_JOURNAL);
POWERFAIL_SET_ADDR(0);
// If this is a create, set the object type
if (type != 0 && fs.journal.oldi == 0)
fs.journal_ram.flags = (fs.journal_ram.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;
}
POWERFAIL_BOUNDARY(JOURNAL_TEST_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));
}
POWERFAIL_BOUNDARY(JOURNAL_TEST_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);
}
POWERFAIL_BOUNDARY(JOURNAL_TEST_READY);
journal_commit(0);
// journal_commit() change the domain thus we must set it again
POWERFAIL_DOMAIN_BEGIN(PFM_JOURNAL);
POWERFAIL_SET_ADDR(0);
POWERFAIL_BOUNDARY(JOURNAL_TEST_COMMITTED);
// Advance journal file's state
ffsdrv_write_byte(&addr->state, JOURNAL_IS_DONE);
POWERFAIL_BOUNDARY(JOURNAL_TEST_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) {
if (fs.journal_pos == fs.journal_size - sizeof(struct journal_s))
ffs_panic(EFFS_JNLFULL);
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));
}
POWERFAIL_DOMAIN_END();
tw(tr(TR_END, TrJournal, "}\n"));
}
// Write contents of fs.journal to FFS meta data (inodes).
void journal_commit(uint8 type)
{
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));
POWERFAIL_DOMAIN_BEGIN(PFM_INODES);
POWERFAIL_SET_ADDR(0);
if (fs.journal.i)
{
struct inode_s ib; // Inode buffer
// Set all elements to 0xFF.. NOTEME: do this in another way?
memcpy(&ib, ip, sizeof(ib));
#if (LINEAR_FILE_SYSTEM)
if(fs.journal.align == 0xee) {
ib.reserved = 0xee;
fs.journal.align = 0xff;
}
#endif
// If this is a create, set the object type
if (type != 0 && fs.journal.oldi == 0)
fs.journal_ram.flags = (fs.journal_ram.flags & OF_MASK) | type;
tw(tr(TR_FUNC, TrJournal, "loc = 0x%04x, size = %d\n",
fs.journal_ram.location, fs.journal_ram.size));
ib.location = fs.journal_ram.location;
ib.size = fs.journal_ram.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!
ib.child = get_child(oldip);
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)
ib.sequence = fs.sequence++;
if (fs.journal.oldi == 0)
ib.updates = 0;
else
ib.updates = oldip->updates + 1;
// 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_ram.flags));
ib.flags = ip->flags & fs.journal_ram.flags;
// Write the inode to flash
ffsdrv.write(ip, &ib, sizeof(ib));
// 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(get_repi(-fs.journal.diri));
ffsdrv.write_halfword((uint16 *) &dp->child, fs.journal.i);
}
else {
tw(tr(TR_NULL, TrJournal, "sibling\n"));
dp = inode_addr(get_repi(fs.journal.diri));
ffsdrv.write_halfword((uint16 *) &dp->sibling, fs.journal.i);
}
}
// 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));
POWERFAIL_BOUNDARY(JOURNAL_TEST_COMMITTING);
// Validate the object (write valid flags)
ffsdrv_write_byte(&ip->flags, (ip->flags & OT_VALID));
}
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 & oldip->flags);
// 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_ram.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_ram.repli > 0)
object_remove(fs.journal_ram.repli); // Ignore error!
}
POWERFAIL_DOMAIN_END();
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));
memcpy(&fs.ojournal_ram, &fs.journal_ram, sizeof(struct journal_ram_s));
fs.journal_depth++;
if (fs.journal_depth > 1) {
ffs_panic(EFFS_JNLPUSH2DPTH);
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) {
ffs_panic(EFFS_JNLPOP2DPTH);
return -1;
}
memcpy(&fs.journal, &fs.ojournal, sizeof(struct journal_s));
memcpy(&fs.journal_ram, &fs.ojournal_ram, sizeof(struct journal_ram_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;
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;
}
}
ip = inode_addr(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) {
struct inode_s *obj_ip = inode_addr(addr->i);
tw(tr(TR_FUNC, TrJournal, "First non-complete journal is in READY state\n"));
// Is the object valid?
if (is_object_valid(obj_ip)) {
struct inode_s *ip;
// Copy the entry into fs.journal.
tw(tr(TR_FUNC, TrJournal, "Last journal is READY/PREVALID\n"));
memcpy(&fs.journal, addr, sizeof(fs.journal));
ip = inode_addr(fs.journal.i);
// The existing fields 'flags', 'location' and 'size' is already
// written but they are re-written in journal_commit() thus the
// journal_ram struct must be filled with valid data.
fs.journal_ram.flags = ip->flags ;
fs.journal_ram.location = ip->location;
fs.journal_ram.size = ip->size;
journal_end(0); // Validate obj and maybe erase old obj
i = 1;
}
else {
// Skip last modify operation and replace the diri with a
// replacement inode. Furthermore, clean the last allocated inode
struct inode_s ib;
// Clean inode
memset(&ib, 0, sizeof(ib));
ffsdrv.write(obj_ip, &ib, sizeof(ib));
create_replacementinode(addr);
ffsdrv_write_byte(&addr->state, JOURNAL_IS_DONE);
i = 1;
}
}
else {
// Journal entry wasn't finished, so just ignore it after updating
// its state to JOURNAL_IS_DONE.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -