⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fsck.c

📁 是一个手机功能的模拟程序
💻 C
📖 第 1 页 / 共 4 页
字号:
/******************************************************************************
 * 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 + -