📄 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,v 1.1.1.1 2004/06/19 06:00:30 root Exp $
*
******************************************************************************/
#ifndef TARGET
#include "ffs.cfg"
#endif
#include <string.h>
#include <assert.h>
#include "ffs.h"
#include "core.h"
#include "drv.h"
#include "ffstrace.h"
/******************************************************************************
* Functions
******************************************************************************/
bref_t blocks_fsck(void);
iref_t inodes_fsck(void);
/******************************************************************************
* Init and Exit
******************************************************************************/
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
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 < 2; i++)
{
tlw(led_on(LED_BLOCKS_FSCK));
fs.initerror = EFFS_INVALID;
fs.initerror = b = blocks_fsck();
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();
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)
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) //NOTEME: can this be done in another/better way?
#if (WITH_TFFS == 1)
blocks_reclaim();
#endif
#else
blocks_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;
// Flag that it not has been changed by an input arg.
fs.block_files_max = 0;
// The default lost bytes percentage of a block before it is reclaimed
// is approx. 90%.
fs.lost_threshold = (256 - 256/10);
// 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 (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 't': fs.lost_threshold = 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.lost_threshold = %d\n", fs.lost_threshold));
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)
{
tw(tr(TR_FUNC, TrFsck, "exit() 0\n"));
return EFFS_OK;
}
#if 0 // Not used in this version
// Purely for core internal use; Read a file.
effs_t file_read_int(const char *path, void *src, int size)
{
if (fs.initerror != EFFS_OK)
return fs.initerror;
return object_read(path, src, size, 0);
}
// Purely for core internal use; Update a file.
effs_t file_update(const char *path, void *src, int size)
{
char *name;
iref_t i, dir;
if (fs.initerror != EFFS_OK)
return fs.initerror;
if ((i = object_lookup(path, &name, &dir)) < 0)
return i;
journal_begin(i);
if ((i = object_create(name, src, size, -dir)) < 0)
return i;
journal_end(0);
return EFFS_OK;
}
#endif
/******************************************************************************
* 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);
for (q = p + dev.blocksize/4 - 4; q > p; q -= 4) {
if ( ~(q[0] & q[1] & q[2] & q[3]) )
break;
}
if ( ~(q[0] & q[1] & q[2] & q[3]) )
q += 4;
used = atomalign((char *) q - (char *) p);
tw(tr(TR_FUNC, TrFsckLow, "ffs_block_used(%d) %d\n", b, used));
return used;
}
age_t age_distance(age_t x, age_t y)
{
age_t a = x - y;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -