📄 fsintrnl.c
字号:
/* Returns: 0 on success, -1 on failure */
/* */
/***********************************************************************/
static int free_block(ui32 block, ui32 last_dirty, int *adjust_set,
int *modified)
{
ui32 i, j, last_sect = (block + 1) * Flash->block_sects - 1;
int do_erase, s, add_to_free_list = TRUE;
/*-------------------------------------------------------------------*/
/* Erase only good, non used, non control blocks. */
/*-------------------------------------------------------------------*/
if (!Flash->blocks[block].bad_block && !Flash->blocks[block].ctrl_block
&& Flash->blocks[block].used_sects == 0)
{
/*-----------------------------------------------------------------*/
/* If last sector in block is free, only consider if it's beginning*/
/* of free list and it has dirty sectors on it. */
/*-----------------------------------------------------------------*/
if (Flash->sect_tbl[last_sect].prev == FFREE_SECT)
{
/*---------------------------------------------------------------*/
/* If first sector in block is free, skip block. */
/*---------------------------------------------------------------*/
if (Flash->sect_tbl[block * Flash->block_sects +
Flash->hdr_sects].prev == FFREE_SECT)
return 0;
/*---------------------------------------------------------------*/
/* This block must be the beginning of the free list. */
/*---------------------------------------------------------------*/
PfAssert(Flash->free_sect / Flash->block_sects == block);
Flash->free_sect = block * Flash->block_sects + Flash->hdr_sects;
add_to_free_list = FALSE;
}
/*-----------------------------------------------------------------*/
/* First, free up all dirty sectors in block. */
/*-----------------------------------------------------------------*/
i = block * Flash->block_sects + Flash->hdr_sects;
for (j = 0, do_erase = FALSE; j < Flash->block_sects; ++j)
if (Flash->sect_tbl[i + j].prev == FDRTY_SECT)
{
++Flash->free_sects;
Flash->sect_tbl[i + j].prev = FFREE_SECT;
Flash->sect_tbl[i + j].next = (ui16)(i + j + 1);
do_erase = TRUE;
}
/*-----------------------------------------------------------------*/
/* Erase block. */
/*-----------------------------------------------------------------*/
if (do_erase)
{
/*---------------------------------------------------------------*/
/* If blocks from erase set are erased, readjust erase set. */
/*---------------------------------------------------------------*/
for (s = 0; s < Flash->set_blocks; ++s)
if (Flash->erase_set[s] == block)
break;
if (s < Flash->set_blocks)
{
Flash->erase_set[s] = -1;
*adjust_set = TRUE;
}
*modified = TRUE;
if (FlashEraseBlock(block))
return -1;
/*---------------------------------------------------------------*/
/* If block is not bad, tie it to free list. */
/*---------------------------------------------------------------*/
if (!Flash->blocks[block].bad_block && add_to_free_list)
{
/*-------------------------------------------------------------*/
/* Free sector needs to be updated if invalid. */
/*-------------------------------------------------------------*/
if (Flash->free_sect == (ui32)-1)
{
Flash->free_sect = i;
Flash->last_free_sect = i + Flash->block_sects -
Flash->hdr_sects - 1;
Flash->sect_tbl[Flash->last_free_sect].next = FLAST_SECT;
/*-----------------------------------------------------------*/
/* Tie last dirty with new free so resume has contiguous list*/
/*-----------------------------------------------------------*/
if (last_dirty != (ui32)-1)
Flash->sect_tbl[last_dirty].next = (ui16)Flash->free_sect;
}
/*-------------------------------------------------------------*/
/* Add block to end of free list. */
/*-------------------------------------------------------------*/
else
{
PfAssert(Flash->free_sect / Flash->block_sects != block);
PfAssert(Flash->sect_tbl[Flash->free_sect].prev == FFREE_SECT
&& Flash->sect_tbl[Flash->last_free_sect].prev ==
FFREE_SECT);
Flash->sect_tbl[Flash->last_free_sect].next = (ui16)i;
Flash->last_free_sect = i + Flash->block_sects -
Flash->hdr_sects - 1;
Flash->sect_tbl[Flash->last_free_sect].next = FLAST_SECT;
}
}
}
}
return 0;
}
/***********************************************************************/
/* check_flash: Ensure that the 'free' sectors are actually free, the */
/* 'dirty' are dirty, count the number of dirty sectors */
/* and set free_sect */
/* */
/* Output: modified = flag to due a sync if stat changes */
/* Input: fast_mount_check = check NOR/MLC for fast mount */
/* */
/* Returns: FFS_NORMAL_POWER_UP on a normal shut down, */
/* FFS_SLOW_POWER_UP on an abnormal shut down, */
/* FFS_FAILED_POWER_UP on error */
/* */
/***********************************************************************/
static int check_flash(int *modified, int fast_mount_check)
{
ui32 i, j, sect, min_free_block, block;
ui32 free_sects = Flash->free_sects, last_dirty = (ui32)-1;
int adjust_set = FALSE;
PfAssert(Flash->sect_tbl[Flash->free_sect].prev == FFREE_SECT &&
Flash->last_free_sect % Flash->block_sects ==
Flash->block_sects - 1);
/*-------------------------------------------------------------------*/
/* For NAND/MLC assume it's fast mount and adjust later. */
/*-------------------------------------------------------------------*/
Flash->fast_mount = (Flash->type != FFS_NOR);
/*-------------------------------------------------------------------*/
/* Count the used sectors. */
/*-------------------------------------------------------------------*/
for (i = 0; i < Flash->num_sects; ++i)
if (used_sect(i))
{
++Flash->used_sects;
++Flash->blocks[i / Flash->block_sects].used_sects;
}
/*-------------------------------------------------------------------*/
/* Take the ctrl sectors out of the used sectors block counts. */
/*-------------------------------------------------------------------*/
for (i = Flash->frst_ctrl_sect; i != FLAST_SECT;
i = Flash->sect_tbl[i].next)
{
--Flash->blocks[i / Flash->block_sects].used_sects;
--Flash->used_sects;
}
/*-------------------------------------------------------------------*/
/* Read the fast mount flag for NOR. */
/*-------------------------------------------------------------------*/
if (Flash->type == FFS_NOR)
{
/*-----------------------------------------------------------------*/
/* Check the fast mount flag. */
/*-----------------------------------------------------------------*/
if (fast_mount_check)
{
if (Flash->read_sector(Flash->tmp_sect, Flash->last_ctrl_sect))
{
set_errno(EIO);
return FFS_FAILED_POWER_UP;
}
Flash->fast_mount = (Flash->tmp_sect[Flash->sect_sz - 1] ==
FAST_MOUNT);
}
/*-----------------------------------------------------------------*/
/* Rebuild the erase set at the time of power off. */
/*-----------------------------------------------------------------*/
FlashCountAndChoose(SKIP_CHECK_RECYCLE);
}
/*-------------------------------------------------------------------*/
/* Check for fast mount. */
/*-------------------------------------------------------------------*/
if (Flash->type != FFS_NOR || !Flash->fast_mount)
{
/*-----------------------------------------------------------------*/
/* A fast mount happens when all the sectors past frst_free_ctrl */
/* sector in same block are free, the first FOPEN_MAX sectors on */
/* free list are free(cache size) plus the next block worth of */
/* sectors is free (it could have been selected for control info */
/* and we got cut off). */
/*-----------------------------------------------------------------*/
if (Flash->free_ctrl_sect != (ui32)-1)
for (i = Flash->free_ctrl_sect; i % Flash->block_sects; ++i)
{
if (!Flash->empty_sect(i))
{
Flash->fast_mount = FALSE;
Flash->free_ctrl_sect = (ui32)-1;
}
else if (Flash->free_ctrl_sect == (ui32)-1)
Flash->free_ctrl_sect = i;
}
/*-----------------------------------------------------------------*/
/* Now check all the free list, skipping sectors if fast mount. */
/*-----------------------------------------------------------------*/
Flash->free_sects = 0;
for (i = Flash->free_sect; i != FLAST_SECT;)
{
PfAssert(i < Flash->num_sects &&
Flash->sect_tbl[i].prev == FFREE_SECT);
/*---------------------------------------------------------------*/
/* If known a priori or verified, count sector as free. First */
/* cache size worth of sectors plus next block worth of sectors */
/* are always checked. */
/*---------------------------------------------------------------*/
if ((Flash->fast_mount &&
Flash->free_sects > FOPEN_MAX + Flash->block_sects + 1) ||
Flash->empty_sect(i))
{
++Flash->free_sects;
Flash->last_free_sect = i;
}
/*---------------------------------------------------------------*/
/* Else mark sector as dirty. */
/*---------------------------------------------------------------*/
else
{
Flash->fast_mount = FALSE;
Flash->sect_tbl[i].prev = FDRTY_SECT;
last_dirty = i;
}
/*---------------------------------------------------------------*/
/* Move to next free sector. */
/*---------------------------------------------------------------*/
i = Flash->sect_tbl[i].next;
}
}
/*-------------------------------------------------------------------*/
/* For fast mount NOR, set last free sector pointer. */
/*-------------------------------------------------------------------*/
else
for (i = Flash->free_sect, Flash->free_sects = 0;;)
{
++Flash->free_sects;
if (Flash->sect_tbl[i].next == FLAST_SECT)
{
Flash->last_free_sect = i;
break;
}
else
i = Flash->sect_tbl[i].next;
}
/*-------------------------------------------------------------------*/
/* If there were dirty sectors, invalidate all free sectors that */
/* preceeded the last dirty sector in list. */
/*-------------------------------------------------------------------*/
if (last_dirty != (ui32)-1)
{
for (i = Flash->free_sect; i != last_dirty;
i = Flash->sect_tbl[i].next)
if (Flash->sect_tbl[i].prev == FFREE_SECT)
{
--Flash->free_sects;
Flash->sect_tbl[i].prev = FDRTY_SECT;
}
/*-----------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -