📄 fsck.c
字号:
/******************************************************************************
* Flash File System (ffs)
* Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com
*
* FFS file system integrity checking, journalling, init and exit
*
* $Id: fsck.c 1.3.1.1.1.33 Thu, 08 Jan 2004 15:05:23 +0100 tsj $
*
******************************************************************************/
#ifndef TARGET
#include "ffs.cfg"
#endif
#include <string.h>
#include <assert.h>
#include "ffs/ffs.h"
#include "ffs/board/core.h"
#include "ffs/board/drv.h"
#include "ffs/board/ffstrace.h"
#if (TARGET == 0 || WITH_TFFS == 1)
#include "ffs/board/tffs.h"
#endif
#include "swconfig.cfg"
/******************************************************************************
* Functions
******************************************************************************/
bref_t blocks_fsck(void);
iref_t inodes_fsck(void);
/******************************************************************************
* Init and Exit
******************************************************************************/
char ffs_initerror[5];
effs_t ffs_initialize(void)
{
bref_t b;
struct inode_s *ip;
int i;
tlw(led_set(0));
tlw(led_on(LED_INIT));
ttw(str(TTrInit, "initialize {" NL));
tw(tr(TR_BEGIN, TrFsck, "ffs_initialize() {\n"));
// default to non-initialized ffs
fs.root = 0;
fs.debug[0] = fs.debug[1] = fs.debug[2] = fs.debug[3] = 0;
fs.testflags = 0;
tlw(led_on(LED_DRV_INIT));
fs.initerror = ffsdrv_init(); // read manufacturer and device ID
ffs_initerror[0] = fs.initerror;//fangcjdebug
tlw(led_off(LED_DRV_INIT));
if (fs.initerror < 0) {
tlw(led_off(0));
tw(tr(TR_END, TrFsck, "} %d\n", fs.initerror));
ttw(ttr(TTrInit, "} %d" NL, fs.initerror));
return fs.initerror;
}
for (i = 0; i < 3; i++)
{
tlw(led_on(LED_BLOCKS_FSCK));
fs.initerror = EFFS_INVALID;
fs.initerror = b = blocks_fsck();
ttr(TTrFatal, "xxx: blocks_fsck() return: %d,for(%d)" NL, fs.initerror, i);
ffs_initerror[1] = fs.initerror;//fangcjdebug
tlw(led_off(LED_BLOCKS_FSCK));
if (fs.initerror < 0) {
tlw(led_off(0));
tw(tr(TR_END, TrFsck, "} %d\n", fs.initerror));
ttw(ttr(TTrInit, "} %d" NL, fs.initerror));
return fs.initerror;
}
tlw(led_on(LED_INODES_FSCK));
fs.initerror = EFFS_INVALID;
fs.initerror = inodes_fsck();
ffs_initerror[2] = fs.initerror;
tlw(led_off(LED_INODES_FSCK));
if (fs.initerror < 0) {
tlw(led_off(0));
tw(tr(TR_END, TrFsck, "} %d\n", fs.initerror));
ttw(ttr(TTrInit, "} %d" NL, fs.initerror));
return fs.initerror;
}
// parse the fs options in the root inode's name
ip = inode_addr(fs.root);
fs_params_init(addr2name(offset2addr(location2offset(ip->location))));
if ((fs.initerror = journal_init(fs.ijournal)) == 0)
{
ffs_initerror[3] = fs.initerror;
break;
}
}
// Init all file_descriptors to zero
memset(fs.fd, 0, sizeof(struct file_descriptor_s) * fs.fd_max);
// If blocks_fsck() found a block that needs cleaning, we do it, now
// that all the file system has been initialized.
if (b > 0) {
block_clean(b - 1);
block_free(b - 1);
}
statistics_init();
// In target, we do this before entering the task event loop...
// Otherwise we would in some cases impose a long reboot delay if we did
// it here. If we test in target it is nessesary to call
// blocks_reclaim() anyway because we re-init ffs.
#if (TARGET == 1)
#if (WITH_TFFS == 1)
blocks_reclaim(); // target and test
if (fs.repi_table[0] != 0)
inodes_reclaim();
#endif
#else
blocks_reclaim(); // not target
if (fs.repi_table[0] != 0)
inodes_reclaim();
#endif
tlw(led_off(LED_INIT));
tw(tr(TR_END, TrFsck, "} %d\n", EFFS_OK));
ttw(str(TTrInit, "} 0" NL));
return EFFS_OK;
}
void fs_params_init(const char *p)
{
uint8 opt, digit;
uint32 n;
int numdatablocks;
tw(tr(TR_BEGIN, TrFsck, "fsparams_init('%s') {\n", p));
// Compiled default values
fs.filename_max = FFS_FILENAME_MAX;
fs.path_depth_max = FFS_PATH_DEPTH_MAX;
fs.fd_max = FFS_FD_MAX;
fs.journal_size = FFS_JOURNAL_SIZE_IN256THS;
fs.flags = 0;
fs.testflags = 0;
fs.is_reclaim_running = 0;
// Flag that it not has been changed by an input arg.
fs.block_files_max = 0;
// If we only have two blocks, we cannot make any reclaims and thus we
// have a write-once FFS system.
fs.blocks_free_min = (dev.numblocks > 2 ? 1 : 0);
// Don't count free and inodes blocks
numdatablocks = dev.numblocks - fs.blocks_free_min - 1;
// Abselute max number of inodes.
fs.inodes_max = dev.blocksize / sizeof(struct inode_s);
if (fs.inodes_max > FFS_INODES_MAX)
fs.inodes_max = FFS_INODES_MAX;
// MUST be true: objects_max <= inodes_max - block_files_max, this is do
// to the fact that we always need to have block_files_max number of
// inodes left when we run a data reclaim.
fs.objects_max = fs.inodes_max / 2;
// Find a suitable chunk_size
//#if (LOCOSTO_LITE)
// fs.chunk_size_max = 2048;
//#else
// The buffer size is optimized to 8k, since not much performance improvement seen with 16 k.
// fs.chunk_size_max = 8192;
//#endif
if (dev.numblocks*dev.blocksize > 1024*1024)
fs.chunk_size_max = 8192;
else
fs.chunk_size_max = (2048 > (dev.blocksize / 8)
? (dev.blocksize / 8)
: 2048);
fs.fd_buf_size = fs.chunk_size_max;
fs.journal_size = fs.journal_size * dev.blocksize / 256;
if (fs.journal_size < FFS_JOURNAL_SIZE_MIN)
fs.journal_size = FFS_JOURNAL_SIZE_MIN;
// Set it just below the same amount as entries in one journal file
fs.block_files_max = (fs.journal_size / sizeof(struct journal_s)
- FFS_JOURNAL_MARGIN - 2);
// MUST be true: block_files_max < objects_max / 2. But if we want
// to reach objects_max must block_files_max >= objects_max / number
// of datablocks, however a big block_files_max require higher
// reserved_space.
if (fs.block_files_max > fs.objects_max / 2)
fs.block_files_max = fs.objects_max / 2 - 4;
// Are we able to reach objects_max? If not then lower the number
if (fs.objects_max > numdatablocks * fs.block_files_max)
fs.objects_max = numdatablocks * fs.block_files_max + 10;
// Absolute minimum is RESERVED_LOW the rest is 'workspace' which is
// needed to have a reasonable performance.
fs.reserved_space = dev.blocksize / 2 +
numdatablocks * dev.blocksize / 16 + RESERVED_LOW;
// skip to first char following second slash in name
n = 0;
while (*p) {
if (*p++ == '/') {
n++;
if (n == 2)
break;
}
}
if (n == 2) {
// while still options to process...
while (*p) {
opt = *p++; // save option letter for later
// collect option value...
n = 0;
while ((digit = *p)) {
if (digit >= '0' && digit <= '9') {
n = 10 * n + digit - '0';
p++;
}
else
break;
}
switch (opt) {
case 'b': dev.numblocks = n; break;
case 'm': fs.blocks_free_min = n; break;
case 'i': fs.inodes_max = n; break;
case 'o': fs.objects_max = n; break;
case 'n': fs.filename_max = n; break;
case 'f': fs.block_files_max = n; break;
case 'd': fs.fd_max = n; break;
case 's': fs.fd_buf_size = n; break;
case 'z': fs.flags = n; break;
case 'j': fs.journal_size = n; break;
case 'c': fs.chunk_size_max = n; break;
case 'r': fs.reserved_space = n; break;
// d = &fs.path_depth_max; // really necessary?
default:
break;
}
}
}
// Now recompute a few parameters based on adjusted values.
// No journal file thuse no reserved space.
if (fs.journal_size == 0) {
fs.block_files_max = fs.objects_max / 2;
fs.reserved_space = 0;
fs.block_files_reserved = 0;
}
else {
// If journal size is less than minimum must it have been changed by an
// input arg, recalculate.
if (fs.journal_size < FFS_JOURNAL_SIZE_MIN)
fs.journal_size = fs.journal_size * dev.blocksize / 256;
if (fs.reserved_space < RESERVED_LOW)
fs.reserved_space = fs.reserved_space * dev.blocksize / 256;
// Only one reserved is needed however we want a margin and set it to two
fs.block_files_reserved = 2;
}
// Don't count free blocks, inode block, reserved space, block headers
// and the size of one filename.
fs.filesize_max = numdatablocks * dev.blocksize - fs.reserved_space -
numdatablocks * BHEADER_SIZE - FFS_FILENAME_MAX;
// Furthermore don't count the overhead from each chunk (alignment)
fs.filesize_max -= ((fs.filesize_max / fs.chunk_size_max) * dev.atomsize
+ dev.atomsize);
// NOTEME: chunk_size_min is never used
fs.chunk_size_min = numdatablocks / fs.objects_max;
tw(tr(TR_FUNC, TrFsck, "dev.numblocks = %d\n", dev.numblocks));
tw(tr(TR_FUNC, TrFsck, "fs.blocks_free_min = %d\n", fs.blocks_free_min));
tw(tr(TR_FUNC, TrFsck, "fs.inodes_max = %d\n", fs.inodes_max));
tw(tr(TR_FUNC, TrFsck, "fs.objects_max = %d\n", fs.objects_max));
tw(tr(TR_FUNC, TrFsck, "fs.block_files_max = %d\n", fs.block_files_max));
tw(tr(TR_FUNC, TrFsck, "fs.block_files_reserved = %d\n", fs.block_files_reserved));
tw(tr(TR_FUNC, TrFsck, "fs.chunk_size_max = %d\n", fs.chunk_size_max));
tw(tr(TR_FUNC, TrFsck, "fs.filename_max = %d\n", fs.filename_max));
tw(tr(TR_FUNC, TrFsck, "fs.path_depth_max = %d\n", fs.path_depth_max));
tw(tr(TR_FUNC, TrFsck, "fs.journal_size = %d\n", fs.journal_size));
tw(tr(TR_FUNC, TrFsck, "fs.reserved_space = %d\n", fs.reserved_space));
tw(tr(TR_FUNC, TrFsck, "fs.fd_max = %d\n", fs.fd_max));
tw(tr(TR_FUNC, TrFsck, "fs.fd_buf_size = 0x%02x\n", fs.fd_buf_size));
tw(tr(TR_FUNC, TrFsck, "fs.flags = 0x%02x\n", fs.flags));
tw(tr(TR_END, TrFsck, "}\n"));
}
// TODO: Finish pending commits/writes.
effs_t ffs_exit(void)
{
#if (OP_WCP == 1)
// Make FFS inaccessible.
fs.initerror = EFFS_AGAIN;
// Finish pending commits/writes.
if (ffs_remove("dummy") != EFFS_AGAIN)
return EFFS_CORRUPTED;
#else
tw(tr(TR_FUNC, TrFsck, "exit() 0\n"));
#endif
return EFFS_OK;
}
/******************************************************************************
* blocks_fsck()
******************************************************************************/
blocksize_t block_used(bref_t b)
{
blocksize_t used;
uint32 *p, *q;
tlw(led_toggle(LED_BLOCKS_FSCK));
// We search backwards through block to find the last used byte and
// thus the total number of used bytes. Note that this code depends
// on the fact that an erased flash location is 0xFF!
p = (uint32 *) offset2addr(dev.binfo[b].offset);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -