📄 fsck.c
字号:
tw(tr(TR_FUNC, TrJournal, "Last journal is between WRITING and READY\n"));
ffsdrv_write_byte(&addr->state, JOURNAL_IS_DONE);
fs.journal_pos += sizeof(fs.journal);
}
// Never create a new journal file if a replacementinode just have been
// made because the new replacementinode is not yet added in the table
// fs.repi_table[] and it could be the journal which is replaced.
if (i == EFFS_OK) {
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 there is use an old FFS image with a newer FFS
// version.
if ((i = journal_create(fs.ijournal)) <= 0) {
fs.ijournal = 0;
return i;
}
}
// Minimize the risk of running out of journal space.
if (fs.journal_pos >= fs.journal_size - FFS_JOURNAL_MARGIN *
sizeof(struct journal_s)) {
tw(tr(TR_FUNC, TrJournal, "Journal file (near) full! Create new\n"));
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_ram.flags = BIT_SET(fs.journal_ram.flags, OFE_READONLY);
// commit the creation or relocation
if (oldi != 0)
journal_end(0);
else {
journal_commit(OTE_FILE);
fs.journal_pos = JOURNAL_POS_INITIAL;
}
tw(tr(TR_END, TrJournal, "} %d\n", i));
return i;
}
/******************************************************************************
* Replacementinode
******************************************************************************/
// Validate the replacement inode, mark old diri as replaced and close
// journal entry
void validate_replacementinode(struct journal_s *addr)
{
struct inode_s *ip, *dir_ip;
iref_t zero[2] = {0, 0};
ip = inode_addr(addr->i);
if (addr->oldi > 0)
dir_ip = inode_addr(addr->oldi);
else
dir_ip = inode_addr(-addr->oldi);
// Validate replacementinode
ffsdrv_write_byte(&ip->flags, (OT_VALID & ip->flags));
// Mark directory inode as replaced (set child and sibling to zero)
ffsdrv.write(&dir_ip->child, zero, sizeof(zero));
// Mark the creation of the replacementinode as done
ffsdrv_write_byte(&addr->state, JOURNAL_IS_DONE);
fs.journal_pos++;
if (fs.journal_pos == fs.journal_size)
ffs_panic(EFFS_JNLFULL);
}
// Create a replacementinode for diri. It is possible that there exist a
// non-complete replacement inode because the previous creation of the inode
// was interrupted. In this case the inode will be finalized (if prevalid)
// or removed so there can be made a new.
void create_replacementinode(struct journal_s *old_addr)
{
int j;
struct inode_s *ip, *dir_ip, ib;
struct journal_s *addr = old_addr;
tw(tr(TR_BEGIN, TrJournal, "create_repi(0x%x) {\n", old_addr));
tw(tr(TR_NULL, TrJournal, "Search for next non-complete journal entry:"));
addr++; // Advance one journal entry (the current state is READY)
for (j = 1 + fs.journal_pos / sizeof(fs.journal);/* 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);
if ((addr->state == (uint8) JOURNAL_IS_READY) &&
is_object_valid(inode_addr(addr->i))) {
validate_replacementinode(addr);
return;
}
// If the journal entry not is EMPTY it must be a non completed
// replacement inode which must be remove before there is created a new
if (addr->state != (uint8) JOURNAL_IS_EMPTY) {
tw(tr(TR_FUNC, TrJournal, "Remove old repi\n"));
ffsdrv_write_byte(&addr->state, JOURNAL_IS_DONE);
// Advance journal.
addr++;
fs.journal_pos++;
if (fs.journal_pos == fs.journal_size)
ffs_panic(EFFS_JNLFULL);
}
tw(tr(TR_FUNC, TrJournal, "create replacementinode\n"));
journal_push();
journal_begin(0);
// Alloc an inode. Note fs.inodes_max is temporarily added
// a margin because this alloc is allowed to use the last inode
fs.inodes_max += FFS_INODES_MARGIN;
fs.journal.i = inode_alloc_try();
fs.inodes_max -= FFS_INODES_MARGIN;
fs.journal.oldi = get_repi(old_addr->diri);
fs.journal_ram.location = fs.journal.oldi > 0 ? fs.journal.oldi : -fs.journal.oldi;
fs.journal_ram.flags = OT_REP;
ffsdrv_write_byte(&addr->state, JOURNAL_IS_WRITING);
fs.journal.state = JOURNAL_IS_WRITING;
// Write ram journal to flash and advance journal to READY
tw(tr(TR_FUNC, TrJournal, "Write ram journal to flash\n"));
ffsdrv.write(addr, &fs.journal, sizeof(fs.journal));
ffsdrv_write_byte(&addr->state, JOURNAL_IS_READY);
ip = inode_addr(fs.journal.i);
// NOTEME: change the macro inode_addr() to handle a negative inode?
if (addr->oldi > 0)
dir_ip = inode_addr(addr->oldi);
else
dir_ip = inode_addr(-addr->oldi);
tw(tr(TR_FUNC, TrJournal,"Replace i: %d (%s%s%s%s%s %s) with %d\n",
fs.journal.oldi,
is_object(dir_ip, OTE_DIR) ? " d" : "",
is_object(dir_ip, OTE_LINK) ? " l" : "",
is_object(dir_ip, OTE_FILE) ? " f" : "",
is_object(dir_ip, OTE_SEGMENT) ? " s" : "",
is_object(dir_ip, OT_REP) ? "rp" : "",
(dir_ip->size && !is_object(dir_ip, OTE_SEGMENT) &&
!is_object_erased(dir_ip) && is_object_valid(dir_ip) ?
addr2name(offset2addr(location2offset(dir_ip->location))) : ""),
fs.journal.i));
// Init inode buffer
// Set all elements to 0xFF.. NOTEME: do this in another way?
memcpy(&ib, ip, sizeof(ib));
ib.size = ib.sequence = ib.updates = 0;
ib.flags = fs.journal_ram.flags | OF_MASK;
ib.location = fs.journal_ram.location;
// Write the replacement inodes Child or Sibling field
if (fs.journal.oldi < 0) {
// diri child is maybe invalid thus we keep it as empty and only
// write sibling
tw(tr(TR_FUNC, TrJournal, "copy sibling: 0x%x\n", dir_ip->sibling));
ib.sibling = dir_ip->sibling;
}
else {
// diri sibling is maybe invalid thus we keep it as empty and only
// write child
tw(tr(TR_FUNC, TrJournal, "copy child: 0x%x\n", dir_ip->child));
ib.child = dir_ip->child;
}
// Write the inode to flash
ffsdrv.write(ip, &ib, sizeof(ib));
journal_pop();
validate_replacementinode(addr);
tw(tr(TR_END, TrJournal, "} 0\n"));
}
/******************************************************************************
* 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();
}
// Suspend a write in progress (only applicable if we are using a
// multi-bank device driver)
else if (dev.state == DEV_WRITE) {
ffsdrv.write_suspend();
}
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();
// Resume a write in progress (only applicable if we are using a
// multi-bank device driver)
else if (dev.state == DEV_WRITE_SUSPEND)
ffsdrv.write_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 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 + -