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

📄 fs2.c

📁 支持nvram盘
💻 C
📖 第 1 页 / 共 5 页
字号:
					lphy = paddr(&ef->first_dls);
					counter = &ef->num_dls;
					if (ef) {
						ef->first_seq = h.seq;
						ef->vers = h.version;
					}
					goto check_ef;
				case FSBCLASS_H:	// Metadata LSs (normally only 1).
					ef = fs_find_create_ef(h.filenum, FS_PTR2LXN(lxd), 0);
					lphy = paddr(&ef->first_mls);
					counter = &ef->num_mls;
				check_ef:
					if (!ef || *counter) {
						TRACE(("Internal error 1\n"));
						// Something wrong: same file in another LX, or too many EFs.
						// Set flag to ignore this chain.
						igchain = 1;
					}
					else
						pvers = 0;
					break;
			}
		}
		
		if (!igchain) {
			if ((kclass == FSBCLASS_B || kclass == FSBCLASS_H) && h.version > ef->vers)
				ef->vers = h.version;
			fs_set_lstabent(lphy, ls);
			(*counter)++;
			lphy = FS_LSTABPHYS(lxd, ls);
		}
		
	}

	// Terminate last chain.
	if (!igchain)
		fs_set_lstabent(lphy, FS_INVALID_LS);
	
	xrelease(ttab, ttabsize);
	return 0;
}

fs_nodebug int fs_scan_file(FS_ef * ef)
{
	// This routine determines whether a given file (as recognised by fs_init_lstab) is
	// self-consistent.  Some files may have blocks with the same sequence but different
	// versions.  The appropriate version is selected and all other versions are purged.
	// All LSs with invalid header checksums have already been purged.  All completed data LSs
	// with bad checksums have been purged.  This leaves only incomplete data LSs, whose checksums
	// need to be checked against the metadata log.  With metadata, the latest version is always
	// chosen since this only occurs when rewriting the log header and the header checksum has
	// already been validated.  From the metadata the incomplete data checksum is obtained (and
	// offset) by reading the log to the most recent valid entry.  If the rest of the metadata
	// LS is not 0xFF and it's on a BW device, then the metadata entry is rewritten if possible.
	// Given the incomplete checksum/offset, the most recent data LS version is checked to see
	// if it's consistent.  If not, the next oldest version is used.  This works because of the
	// write sequence for LS updates.
	// Old versions may exist because of a power interruption during the last write.
	// In addition, sequence numbers may have wrapped.  If sequence numbers are contiguous (modulo
	// 2**16) then the file is a valid sequence.  If not, then at least one LS is missing and the
	// file is declared corrupt.  Version numbers cannot be tested for contiguity, however they
	// do not wrap until 2**32 which is unlikely to cause problems.
	// Return value is 0 if OK, or 1 if there was an unrecoverable inconsistency in the file
	// (e.g. inability to fix the log, or missing file sequence).  On return code 1, the caller
	// should normally purge the file.
	
	auto FS_h meta;					// Metadata results from header plus log entries
	auto FS_h data;					// Data LS header (actually an FS_b)
	auto FS_lxd * mlxd, * dlxd;	// Metadata and data lxd's
	auto FSseq seq;					// Current data sequence
	auto FSLSnum mls, dls;			// Current LS numbers
	auto long lstabp, p2;
	auto int first, last;
	auto FSLSnum ls2;
	auto FS_h data2;
	
	mlxd = FS_LXN2PTR(ef->metalx);	
	dlxd = FS_LXN2PTR(ef->datalx);
	
	// Erase all but 1st in metadata LS chain, then get log results.
	mls = ef->first_mls;
	fs_erase_chain(mlxd, FS_LSTABPHYS(mlxd, mls), 0, 0, 0, &ef->num_mls);
	ef->m_offs = fs_get_meta(mlxd, mls, &meta);
	ef->first_offs = meta.first_offs;
	ef->d_offs = meta.last_offs;
	ef->data_chk = meta.last_chk;
	
	// Now scan the data
	lstabp = paddr(&ef->first_dls);
	first = 1;
	for (;;) {
		dls = fs_lstabent(lstabp);
		if (dls == FS_INVALID_LS)
			break;
		fs_get_headers(dlxd, dls, NULL, &data, NULL);
		// Throw away any which are less than meta.first_seq
		if ((short)(data.seq - meta.first_seq) < 0) {
			fs_erase_chain(dlxd, lstabp, FSHALT_SEQ, 0, data.seq, &ef->num_dls);
			continue;
		}
		if (first)
			ef->first_seq = seq = data.seq;
		else {
			if (data.seq != (FSseq)(seq + 1))
				return 1;		// Missing sequence number
			seq = data.seq;
		}
		// Peek ahead to see if this is last in sequence
		last = 0;
		ls2 = dls;
		for (;;) {
			p2 = FS_LSTABPHYS(dlxd, ls2);
			ls2 = fs_lstabent(p2);
			if (ls2 == FS_INVALID_LS) {
				last = 1;
				break;
			}
			fs_get_headers(dlxd, ls2, NULL, (FS_h *)&data2, NULL);
			if (data2.seq != seq)
				break;	// not last
		}
		
		if (last) {
			// Check each version of this seq against metadata.  If inconsistent, purge
			// and try next older version.  If no older versions left, declare error.
			// Otherwise, purge any remaining older versions of this seq.
			// FIXME: implement.  Also, ensure BW devices have trailing 0xFF.
			p2 = FS_LSTABPHYS(dlxd, dls);
			ls2 = fs_lstabent(p2);	// Next older LS, or -1 if this is the last
			fs_erase_chain(dlxd, FS_LSTABPHYS(dlxd, dls), 0, 0, 0, &ef->num_dls);
		}
		else {
			// Not the last, so we can verify the data checksum.
			if (fs_verify_data(dlxd, dls)) {
				TRACE(("Data verify failed for LS %u\n", dls));
				fs_erase_chain(dlxd, lstabp, FSHALT_COUNT, 1, 0, &ef->num_dls);
				continue;
			}
			fs_erase_chain(dlxd, FS_LSTABPHYS(dlxd, dls), FSHALT_SEQ, 0, seq, &ef->num_dls);
		}
		
		first = 0;
		dls = fs_lstabent(lstabp);	// Get again, may have changed
		lstabp = FS_LSTABPHYS(dlxd, dls);
	}
	
	ef->eof = (long)(ef->num_dls - 1) * dlxd->d_size + meta.last_offs - meta.first_offs;
	
	return 0;
}

fs_nodebug int fs_open(File * f, FileNumber name)
{
	auto FSLXnum dlxn, mlxn;
	
	FS_SPLITFN(name, mlxn, f->name);
	if (!FS_EXISTS(f->name) || mlxn && FS_METALX_OF_FILE(f->name) != mlxn) {
		_set_errno(ENOENT);
		f->name = 0;
		return 1;
	}
	if (!mlxn)
		mlxn = FS_METALX_OF_FILE(f->name);
	dlxn = FS_DATALX_OF_FILE(f->name);
	f->ef = FS_EF_OF_FILE(f->name);
	f->mlxd = FS_LXN2PTR(mlxn);
	f->dlxd = FS_LXN2PTR(dlxn);
	f->mode = 0;
	f->position = 0;
	f->ef->ref_count++;
	return 0;
}

fs_nodebug int fs_locate(FS_ef * ef, long pos, FSLSnum * ls, FSoffset * offs,
					long * lstabpp, FSseq * seq, FSLSnum * prevlsp)
{
	// In existing file ef, locate the LS that contains byte number 'pos'.  Return
	// parameters are the LS number, the offset within that LS, and the phys. addr.
	// of the lstab entry which contains that LS.  *seq is set to the expected LS sequence.
	// Returns 1 if error (i.e. not in the file chain), else 0.
	// Works by scanning the chain from its start, while the chain exists and pos
	// is greater than or equal to lxd->d_size.  If pos represents the EOF, and happens to
	// be the start of an as-yet unallocated LS, then returns 1 -- this may not be an error
	// for appending data to a file.  In this case, *lstabpp is set to the entry containing
	// 0xFFFF (end of chain) and *offs will be set to 0.  Otherwise if end-of-chain is
	// encountered, then *offs will be set to 0xFFFF.  *prevlsp will be set to the previous
	// LS in the chain, of FS_INVALID_LS if none.
	// FIXME: efficiency needs to be improved, especially for append.
	auto FS_lxd * lxd;
	auto long lstabp;
	
	lxd = FS_LXN2PTR(ef->datalx);
	lstabp = paddr(&ef->first_dls);
	*prevlsp = FS_INVALID_LS;
	pos += ef->first_offs;	// Convert to offset from byte 0 of 1st LS.
	*seq = ef->first_seq;
	for (;;) {
		*ls = fs_lstabent(lstabp);
		if (*ls == FS_INVALID_LS) {
			_set_errno(EUNEXEOC);
			*lstabpp = lstabp;
			if (pos)
				*offs = 0xFFFF;
			else
				*offs = 0;
			return 1;
		}
		if (pos < lxd->d_size) {
			// Found it
			*lstabpp = lstabp;
			*offs = (FSoffset)pos;
			break;
		}
		pos -= lxd->d_size;
		*prevlsp = *ls;
		lstabp = FS_LSTABPHYS(lxd, *ls);
		(*seq)++;
	}
	return 0;
}


/*** BeginHeader fs_init */
#ifndef __TESTENV__
#use "fs_dev.lib"
#endif
int fs_init(long reserveblocks, int num_blocks);
/*** EndHeader */
/* START FUNCTION DESCRIPTION ********************************************
fs_init                      <fs2.lib>

SYNTAX: int fs_init(long reserveblocks, int num_blocks)

KEYWORDS:      file system

DESCRIPTION:   Initialize the filesystem.  The static structure _fs
               contains information which defines the number and
               parameters associated with each extent or "partition".
               This function must be called before any of the other
               functions in this library, except for fs_setup(),
               fs_get_*_lx() and fs_get_lx_size().

               Pre-main initialization will create up to 3 devices:
               . The second flash device (if available on the board)
               . Battery-backed SRAM (if FS2_RAM_RESERVE defined)
               . The first (program) flash (if XMEM_RESERVE_SIZE and
                 FS2_USE_PROGRAM_FLASH defined).
               The LX numbers of the default devices can be obtained
               using the fs_get_flash_lx(), fs_get_ram_lx() and
               fs_get_other_lx() calls.
               
               If none of these devices can be set up successfully,
               fs_init() will return ENOSPC when called.

               This function performs complete consistency checks
               and, if necessary, fixups for each LX.  It may take
               up to several seconds to run.  It should only be called
               once at application initialization time.

PARAMETER1:    Must be zero.  Retained for backward compatibility.
PARAMETER2:    Ignored (backward compatibility).

RETURN VALUE:  0 - success
               non-zero - failure

ERRNO VALUES:  EINVAL - the reserveblocks parameter was non-zero.
               EIO - I/O error.  This indicates a hardware problem.
               ENOMEM - Insufficient memory for required buffers.
               ENOSPC - No valid extents obtained e.g. there is no
                 recognized flash or RAM memory device available.

SEE ALSO:      fs_setup, fs_get_flash_lx

END DESCRIPTION **********************************************************/
fs_nodebug int fs_init(long reserveblocks, int num_blocks)
{
	auto int rc;
	auto int i;
	static FS_lxd * lxd;
	auto FS_ef * ef;
	auto word ps_size;	// Set to largest PS size in any SSW

#ifndef __TESTENV__
	#GLOBAL_INIT {
		// Set up reasonable defaults, based on user and BIOS defines
		_fs.num_lx = 0;
		_fs.flash_lx = 0;
		_fs.ram_lx = 0;
		_fs.other_lx = 0;
		_fs.setup_failed = 0;
		memset(_fs.lx, 0, sizeof(_fs.lx));

		// Get the flash ID, and set up some derived quantities in LXD #1.
		lxd = _fs.lx + 1;
		// Set good default for flash - this will give 256 LSs for a 256K flash.
		lxd->ls_shift = FS_DEFAULT_FLASH_SHIFT;	
		_fs.setup_failed = gflash_setup(lxd, CS_FLASH2|FLASH_WSTATES, &lxd->id);
		if (!_fs.setup_failed) {
			_fs.num_lx++;
			_fs.flash_lx = _fs.num_lx;
		}
#if (FS2_RAM_RESERVE > 0)
		// Next device is NVRAM, if requested.
		if (_fs.num_lx < FS_MAX_LX) {
			lxd = _fs.lx + _fs.num_lx + 1;
			lxd->ls_shift = FS_DEFAULT_RAM_SHIFT;	// Set good default for RAM
			_fs.setup_failed = nvram_setup(lxd, CS_RAM|RAM_WSTATES);
			lxd->id = 0;	// No ID for RAM.
			if (!_fs.setup_failed) {
				_fs.num_lx++;
				_fs.ram_lx = _fs.num_lx;
			}
		}
#endif
#if (FS2_USE_PROGRAM_FLASH > 0 && XMEM_RESERVE_SIZE > 0)
		// Last device is for program flash.  
		if (_fs.num_lx < FS_MAX_LX) {
			lxd = _fs.lx + _fs.num_lx + 1;
			lxd->ls_shift = FS_DEFAULT_FLASH_SHIFT;	// Set good default for program flash
			_fs.setup_failed = pflash_setup(lxd, CS_FLASH|FLASH_WSTATES, &lxd->id);
			if (!_fs.setup_failed) {
				_fs.num_lx++;
				if (_fs.flash_lx)
					_fs.other_lx = _fs.num_lx;
				else
					_fs.flash_lx = _fs.num_lx;
			}
		}
#endif
	}
#endif

	if (!_fs.num_lx) {
		_set_errno(ENOSPC);
		return 1;
	}
	
	rc = 0;
	if (reserveblocks) {
		_set_errno(EINVAL);
		return 1;
	}
	
	ps_size = FS_MIN_PBUF_SIZE;
	
	_fs.init = 1;
	
	// Initialize the static structures to sane state.  Note that some fields are already
	// initialized by global init sections which examine the bios and compiled-in info.
	_fs.cur_meta = 0;
	_fs.cur_data = 0;
	for (i = 0; i <= FS_MAX_FILES; i++)
		_fs.ef[i].in_use = 0;
	
	memset(_fs.eftab, 0, sizeof(_fs.eftab));
	for (i = 1; i <= _fs.num_lx; i++)
		if (!FS_IS_DUMMY_LX(i)) {
			if (!_fs.cur_meta) {
				_fs.cur_meta = i;		// Set initial defaults to first non-dummy LX
				_fs.cur_data = i;
			}
			lxd = FS_LXN2PTR(i);
			lxd->this = (FSLXnum)i;
			lxd->ls_size = 1 << lxd->ls_shift;
			lxd->num_ls = (FSLSnum)((lxd->num_ps * lxd->ps_size) >> lxd->ls_shift);
			lxd->lstab = xalloc((long)sizeof(FSLSnum) * lxd->num_ls);
			if (!lxd->lstab) {
				_set_errno(ENOMEM);
				rc = 1;
				break;
			}
			if (lxd->ps_size > 0)
				lxd->ps_per_ls = (word)(lxd->ls_size / lxd->ps_size);
			else
				lxd->ps_per_ls = 0;
			if (lxd->ps_size >= lxd->ls_size)
				lxd->ls_per_ps = (word)(lxd->ps_size >> lxd->ls_shift);
			else
				lxd->ls_per_ps = 0;
			lxd->d_size = lxd->ls_size - sizeof(FS_b) - sizeof(FSchecksum);
			if (lxd->wear_leveling)
				lxd->d_size -= sizeof(FS_w);
			if (FS_IS_SSW(lxd) && lxd->ps_size > ps_size)
				ps_size = (word)lxd->ps_size;
			if (FS_IS_BW(lxd) && lxd->ls_size > ps_size)
				ps_size = lxd->ls_size;
			if (lxd->ls_per_ps)
				lxd->min_free = lxd->ls_per_ps - 1;
			else
				lxd->min_free = 0;
			if (lxd->init)
				FS_CALL_INIT(lxd);
		}
	
	for (i = 1; i <= _fs.num_lx; i++)
		if (!FS_IS_DUMMY_LX(i)) {
			// Do the major work of sorting blocks from each LX and setting up RAM tables.
			lxd = FS_LXN2PTR(i);
			rc = fs_init_lstab(lxd);
			if (rc)
				break;
		}
	
	// Clean up any files which have data or metadata but not both.
	// FIXME: this may be a bit drastic.  Could try to reconstruct metadata.
	for (i = 1; i <= FS_MAX_FILES; i++) {
		ef = _fs.ef + i;
		if (!ef->in_use)
			continue;
		if (!ef->metalx || !ef->datalx)
			fs_purge_file(ef);
	}
	
	// Scan all remaining metadata to correctly determine the start and end offsets
	// of each file, and to reject any old LS versions or corrupted files.
	for (i = 1; i <= FS_MAX_FILES; i++) {
		ef = _fs.ef + i;
		if 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -