当前位置:文档之家› yaffs2文件系统分析

yaffs2文件系统分析

yaffs2文件系统分析
yaffs2文件系统分析

yaffs2文件系统分析

作者:dreamice

1.前言

略。

2.yaffs文件系统简介

按理说这里应该出现一些诸如“yaffs是一种适合于NAND Flash的文件系统XXXXX”之类的字眼,不过考虑到网络上关于yaffs/yaffs2的介绍已经多如牛毛,所以同上,略。

3.本文内容组织

本文将模仿《linux内核源代码情景分析》一书,以情景分析的方式对yaffs2文件系统的

源代码进行分析。首先将分析几组底层函数,如存储空间的分配和释放等;其次分析文件逻辑地址映射;然后是垃圾收集机制;接下来……Sorry,本人还没想好。:-)

4.说明

因为yaffs2貌似还在持续更新中,所以本文所列代码可能和读者手中的代码不完全一致。另外,本文读者应熟悉C语言,熟悉NAND Flash的基本概念(如block和page)。

Ok,步入正题。首先分析存储空间的分配。

5.NAND Flash存储空间分配和释放

我们知道,NAND Flash的基本擦除单位是Block,而基本写入单位是page。yaffs2在分配存储空间的时候是以page为单位的,不过在yaffs2中把基本存储单位称为chunk,和page是一样的大小,在大多数情况下和page是一个意思。在下文中我们使用chunk这个词,以保持和yaffs2的源代码一致。

我们先看存储空间的分配(在yaffs_guts.c中。这个文件也是yaffs2文件系统的核心部分):Yaffs2中将该函数更名为yaffs_alloc_chunk。

static int yaffs_AllocateChunk(yaffs_Device * dev, int useReserve,

yaffs_BlockInfo **blockUsedPtr)

{

int retVal;

yaffs_BlockInfo *bi;

if (dev->allocationBlock < 0) {

/* Get next block to allocate off */

dev->allocationBlock = yaffs_FindBlockForAllocation(dev);

dev->allocationPage = 0;

}

函数有三个参数,dev是yaffs_Device结构的指针,yaffs2用这个结构来记录一个NAND 器件的属性(如block和page的大小)和系统运行过程中的一些统计值(如器件中可用chunk 的总数),还用这个结构维护着一组NAND操作函数(如读、写、删除)的指针。

整个结构体比较大,我们会按情景的不同分别分析。useReserve表示是否使用保留空间。yaffs2文件系统并不会将所有的存储空间全部用于存储文件系统数据,而要空出部分block用于垃圾收集时使用。一般情况下这个参数都是0,只有在垃圾收集时需要分配存

储空间的情况下将该参数置1。yaffs_BlockInfo 是描述block属性的结构,主要由一些统计变量组成,比如该block内还剩多少空闲page等。我们同样在具体情景中再分析这个结构中的字段含义。

函数首先判断dev->allocationBlock的值是否小于0。yaffs_Device结构内的allocationBlock字段用于记录当前从中分配chunk(page)的那个block的序号。当一

个block内的所有page全部分配完毕时,就将这个字段置为-1,下次进入该函数时就会

重新挑选空闲的block。这里我们假定需要重新挑选空闲block,因此进入

yaffs_FindBlockForAllocation函数:

[yaffs_AllocateChunk() => yaffs_FindBlockForAllocation()]

static int yaffs_FindBlockForAllocation(yaffs_Device * dev)

{

int i;

yaffs_BlockInfo *bi;

if (dev->nErasedBlocks < 1) {

/* Hoosterman we've got a problem.

* Can't get space to gc

/*

T(Y AFFS_TRACE_ERROR,

(TSTR("yaffs tragedy: no more eraased blocks" TENDSTR)));

return -1;

}

dev->nErasedBlocks记录着器件内所有可供分配的block的数量。如果该值小于1,那显

然是有问题了。不但正常的分配请求无法完成,就连垃圾收集都办不到了。

for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {

dev->allocationBlockFinder++;

if (dev->allocationBlockFinder < dev->internalStartBlock

|| dev->allocationBlockFinder > dev->internalEndBlock) {

dev->allocationBlockFinder = dev->internalStartBlock;

internalStartBlock和internalEndBlock分别是yaffs2使用的block的起始序号和结束

序号。也就是说yaffs2文件系统不一定要占据整个Flash,可以只占用其中的一部分。

dev->allocationBlockFinder记录着上次分配的块的序号。如果已经分配到系统尾部,就

从头重新开始搜索可用块。

bi = yaffs_get_block_info(dev, dev->alloc_block_finder);

if (bi->block_state == Y AFFS_BLOCK_STATE_EMPTY) {

bi->block_state = YAFFS_BLOCK_STATE_ALLOCATING;

dev->seq_number++;

bi->seq_number = dev->seq_number;

dev->n_erased_blocks--;

yaffs_trace(YAFFS_TRACE_ALLOCATE,

"Allocated block %d, seq %d, %d left" ,

dev->alloc_block_finder, dev->seq_number,

dev->n_erased_blocks);

return dev->alloc_block_finder;

}

yaffs_GetBlockInfo 函数获取指向block信息结构的指针,该函数比较简单,就不详细介

绍了。yaffs_BlockInfo结构中的blockState成员描述该block的状态,比如空,满,已

损坏,当前分配中,等等。因为是要分配空闲块,所以块状态必须是

YAFFS_BLOCK_STATE_EMPTY,如果不是,就继续测试下一个block。找到以后将block 状

态修改为YAFFS_BLOCK_STATE_ALLOCATING,表示当前正从该block中分配存储空间。

常情况下,系统中只会有一个block处于该状态。另外还要更新统计量ErasedBlocks和sequenceNumber。这个sequenceNumber记录着各block被分配出去的先后顺序,以后在垃圾收集的时候会以此作为判断该block是否适合回收的依据。

现在让我们返回到函数yaffs_AllocateChunk中。yaffs_CheckSpaceForAllocation()函数

检查Flash上是否有足够的可用空间,通过检查后,就从当前供分配的block上切下一个if (dev->alloc_block >= 0) {

bi = yaffs_get_block_info(dev, dev->alloc_block);

ret_val = (dev->alloc_block * dev->param.chunks_per_block) +

dev->alloc_page;

bi->pages_in_use++;

yaffs_set_chunk_bit(dev, dev->alloc_block, dev->alloc_page);

dev->alloc_page++;

dev->n_free_chunks--;

/* If the block is full set the state to full */

if (dev->alloc_page >= dev->param.chunks_per_block) {

bi->block_state = YAFFS_BLOCK_STATE_FULL;

dev->alloc_block = -1;

}

if (block_ptr)

*block_ptr = bi;

return ret_val;

dev->allocationPage记录着上次分配的chunk在block中的序号,每分配一次加1。从这

里我们可以看出,系统在分配chunk的时候是从block的开头到结尾按序分配的,直到一个block内的所有chunk全部分配完毕为止。retVal是该chunk在整个device内的总序号。PagesInUse记录着该block中已分配使用的page的数量。系统在设备描述结构yaffs_Device 中维护着一张位图,该位图的每一位都代表着Flash

上的一个chunk的状态。yaffs_SetChunkBit()将刚分配得到的chunk在位图中的对应位置1,表明该块已被使用。更新一些统计量后,就可以返回了。

看过chunk分配以后,我们再来chunk的释放。和chunk分配不同的是,chunk的

释放在大多数情况下并不释放对应的物理介质,这是因为NAND虽然可以按page写,但只能按block擦除,所以物理介质的释放要留到垃圾收集或一个block上的所有page全部变成空闲的时候才进行。根据应用场合的不同,chunk的释放方式并不唯一,分别由yaffs_DeleteChunk函数和yaffs_SoftDeleteChunk函数完成。我们先看

yaffs_DeleteChunk:(该函数在后续版本中被更名为yaffs_chunk_del())

void yaffs_DeleteChunk(yaffs_Device * dev, int chunkId, int markNAND, int lyn)

chunkId就是要删除的chunk的序号,markNand参数用于yaffs一代的代码中,yaffs2不

使用该参数。

参数lyn在调用该函数时置成当前行号(__LINE__),用于调试。

首先通过yaffs_GetBlockInfo获得chunk所在block的信息描述结构指针,然后就跑到

else里面去了。if语句的判断条件中有一条!dev->isYaffs2,所以对于yaffs2而言是不

会执行if分支的。在else分支里面只是递增一下统计计数就出来了,我们接着往下看。if (bi->blockState == Y AFFS_BLOCK_STA TE_ALLOCATING ||

bi->blockState == Y AFFS_BLOCK_STATE_FULL ||

bi->blockState == Y AFFS_BLOCK_STATE_NEEDS_SCANNING ||

bi->blockState == Y AFFS_BLOCK_STATE_COLLECTING) {

dev->nFreeChunks++;

yaffs_ClearChunkBit(dev, block, page);

bi->pagesInUse--;

if (bi->pagesInUse == 0 &&

!bi->hasShrinkHeader &&

bi->blockState != Y AFFS_BLOCK_STATE_ALLOCATING &&

bi->blockState != Y AFFS_BLOCK_STATE_NEEDS_SCANNING) {

yaffs_BlockBecameDirty(dev, block);

首先要判断一下该block上是否确实存在着可释放的chunk。block不能为空,不能是坏块。YAFFS_BLOCK_STATE_NEEDS_SCANNING表明正对该块进行垃圾回收,我们后面会分析;

YAFFS_BLOCK_STATE_NEEDS_SCANNING在我手上的源代码中似乎没有用到。

通过判断以后,所做的工作和chunk分配函数类似,只是一个递增统计值,一个递减。递减统计值以后还要判断该block上的page是否已全部释放,如果已全部释放,并且不是当前分配块,就通过yaffs_BlockBecameDirty函数删除该block,只要能通过删除操作

(不是坏块),该block就又可以用于分配了。

相比较来说,yaffs_SoftDeleteChunk所做的工作就简单多了。关键的代码只有两行:

static void yaffs_SoftDeleteChunk(yaffs_Device * dev, int chunk)

{

……

theBlock->softDeletions++;

dev->nFreeChunks++;

……

}

这里递增的是yaffs_blockInfo结构中的另一个统计量softDeletions,而没有修改pagesInUse成员,也没有修改chunk状态位图。那么,这两个函数的应用场合有什么区别呢?

一般来说,yaffs_DeleteChunk用于文件内容的更新。比如我们要修改文件中的部分内容,这时候yaffs2会分配新的chunk,将更改后的内容写入新chunk中,原chunk的内容自然

就没有用了,所以要将pageInUse减1,并修改位图;

yaffs_SoftDeleteChunk用于文件的删除。yaffs2在删除文件的时候只是删除该文件在内

存中的一些描述结构,而被删除的文件所占用的chunk不会立即释放,也就是不会删除

文件内容,在后续的文件系统操作中一般也不会把这些chunk分配出去,直到系统进行垃圾收集的时候才有选择地释放这些chunk。熟悉DOS的朋友可能还记得,DOS在删除的文件的时候也不会立即删除文件内容,只是将文件名的第一个字符修改为0xA5,事后还可

以恢复文件内容。yaffs2在这点上是类似的。

1.文件地址映射

上面说到,yaffs文件系统在更新文件数据的时候,会分配一块新的chunk,也就是说,

同样的文件偏移地址,在该地址上的数据更新前和更新后,其对应的flash上的存储地

址是不一样的。那么,如何根据文件内偏移地址确定flash存储地址呢?最容易想到的办法,就是在内存中维护一张映射表。由于flash基本存储单位是chunk,因此,只要将以chunk描述的文件偏移量作为表索引,将flash chunk序号作为表内容,就可以解决该问

题了。但是这个方法有几个问题,首先就是在做seek操作的时候,要从表项0开始按序搜索,对于大文件会消耗很多时间;其次是在建立映射表的时候,无法预计文件大小的变化,于是就可能在后来的操作中频繁释放分配内存以改变表长,造成内存碎片。yaffs的

解决方法是将这张大的映射表拆分成若干个等长的小表,并将这些小表组织成树的结构,方便管理。我们先看小表的定义:

struct yaffs_tnode {

struct yaffs_tnode *internal[YAFFS_NTNODES_INTERNAL];

};

YAFFS_NTNODES_INTERNAL定义为(Y AFFS_NTNODES_LEVEL0 / 2),而

YAFFS_NTNODES_LEVEL0定义为16,所以这实际上是一个长度为8的指针数组。不管是叶

子节点还是非叶节点,都是这个结构。当节点为非叶节点时,数组中的每个元素都指向下一层子节点;当节点为叶子节点时,该数组拆分为16个16位长的短整数(也有例外,后面会说到),该短整数就是文件内容在flash上的存储位置(即chunk序号)。至于如何

通过文件内偏移找到对应的flash存储位置,源代码所附文档

(Development/yaffs/Documentation/yaffs-notes2.html)已经有说明,俺就不在此处饶

舌了。下面看具体函数。

为了行文方便,后文中将yaffs_Tnode这个指针数组称为“一组”Tnode,而将数组

中的每个元素称为“一个”Tnode。树中的每个节点,都是“一组”Tnode。

先看映射树的节点的分配。

struct yaffs_tnode *yaffs_get_tnode(struct yaffs_dev *dev)

{

struct yaffs_tnode *tn = yaffs_alloc_raw_tnode(dev);

if (tn) {

memset(tn, 0, dev->tnode_size);

dev->n_tnodes++;

}

dev->checkpoint_blocks_required = 0; /* force recalculation */

return tn;

}

调用yaffs_GetTnodeRaw分配节点,然后将得到的节点初始化为零。

static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device * dev)

{

yaffs_Tnode *tn = NULL;

/* If there are none left make more */

if (!dev->freeTnodes) {

yaffs_CreateTnodes(dev, Y AFFS_ALLOCATION_NTNODES);

}

当前所有空闲节点组成一个链表,dev->freeTnodes是这个链表的表头。我们假定已经没

有空闲节点可用,需通过yaffs_CreateTnodes创建一批新的节点。

static int yaffs_CreateTnodes(yaffs_Device * dev, int nTnodes)

{

......

tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;

newTnodes = YMALLOC(nTnodes * tnodeSize);

mem = (__u8 *)newTnodes;

}

(其实在最新版本的yaffs中已经加入了slab缓冲区,这样提高了效率)

上面说过,叶节点中一个Tnode的位宽默认为16位,也就是可以表示65536个chunk。对于时下的大容量flash,chunk的大小为2K,因此在默认情况下yaffs2所能寻址的最大flash空间就是128M。为了能将yaffs2用于大容量flash上,代码作者试图通过两种手段

解决这个问题。第一种手段就是这里的dev->tnodeWidth,通过增加单个Tnode的位宽,

就可以增加其所能表示的最大chunk Id;另一种手段是我们后面将看到的chunk group,

通过将若干个chunk合成一组用同一个id来表示,也可以增加系统所能寻址的chunk范围。俺为了简单,分析的时候不考虑这两种情况,因此tnodeWidth取默认值16,也不考虑将

多个chunk合成一组的情况,只在遇到跟这两种情况有关的代码时作简单说明。

在32位的系统中,指针的宽度为32位,而chunk id的宽度为16位,因此相同大小的Tnode组,可以用来表示N个非叶Tnode(作为指针使用),也可以用来表示N * 2个叶子Tnode(作为chunk id使用)。代码中分别用Y AFFS_NTNODES_INTERNAL和

YAFFS_NTNODES_LEVEL0来表示。前者取值为8,后者取值为16。从这里我们也可以看出

若将yaffs2用于64位系统需要作哪些修改。针对上一段叙述的问题,俺以为在内存不紧张的情况下,不如将叶节点Tnode和非叶节点Tnode都设为一个指针的长度。

分配得到所需的内存后,就将这些空闲空间组成Tnode链表:

for(i = 0; i < nTnodes -1; i++) {

curr = (yaffs_Tnode *) &mem[i * tnodeSize];

next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize];

curr->internal[0] = next;

}

每组Tnode的第一个元素作为指针指向下一组Tnode。完成链表构造后,还要递增统计量,并将新得到的Tnodes挂入一个全局管理链表yaffs_TnodeList:

dev->nFreeTnodes += nTnodes;

dev->nTnodesCreated += nTnodes;

tnl = YMALLOC(sizeof(yaffs_TnodeList));

if (!tnl) {

T(Y AFFS_TRACE_ERROR,

(TSTR

("yaffs: Could not add tnodes to management list" TENDSTR)));

} else {

tnl->tnodes = newTnodes;

tnl->next = dev->allocatedTnodeList;

dev->allocatedTnodeList = tnl;

}

回到yaffs_GetTnodeRaw,创建了若干组新的Tnode以后,从中切下所需的Tnode,并修

改空闲链表表头指针:

if (dev->freeTnodes) {

tn = dev->freeTnodes;

dev->freeTnodes = dev->freeTnodes->internal[0];

dev->nFreeTnodes--;

}

至此,分配工作就完成了。相比较来说,释放Tnodes的工作就简单多了,简单的链表和统计值操作:

static void yaffs_FreeTnode(yaffs_Device * dev, yaffs_Tnode * tn)

{

if (tn) {

tn->internal[0] = dev->freeTnodes;

dev->freeTnodes = tn;

dev->nFreeTnodes++;

}

}

看过Tnode的分配和释放,我们再来看看这些Tnode是如何使用的。在后文中,我

们把以chunk为单位的文件内偏移称作逻辑chunk id,文件内容在flash上的实际存储位

置称作物理chunk id。先看一个比较简单的函数。

void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,

unsigned val)

这个函数将某个Tnode设置为指定的值。tn是指向一组Tnode的指针;pos是所要设置的那个Tnode在该组Tnode中的索引;val就是所要设置的值,也就是物理chunk id。函数

名中的Level0指映射树的叶节点。函数开头几行如下:

pos &= YAFFS_TNODES_LEVEL0_MASK;

val >>= dev->chunkGroupBits;

bitInMap = pos * dev->tnodeWidth;

wordInMap = bitInMap /32;

bitInWord = bitInMap & (32 -1);

mask = dev->tnodeMask << bitInWord;

上面说过,一组Tnode中的8个指针在叶节点这一层转换成16个16位宽的chunk Id,因此需要4位二进制码对其进行索引,这就是Y AFFS_TNODES_LEVEL0_MASK的值。我们还说

过这个16位值就是chunk在flash上的序号,当flash容量比较大,chunk数量多时,16 位可能无法给flash上的所有chunk编号,这种情况下可以增加chunk id的位宽,具体位

宽的值记录在dev->tnodeWidth中。yaffs2允许使用非字节对齐的tnodeWidth,因此可

能出现某个chunk id跨32位边界存储的情况。所以在下面的代码中,需要分边界前和边界后两部分处理:

map[wordInMap] &= ~mask;

map[wordInMap] |= (mask & (val << bitInWord));

if(dev->tnodeWidth > (32-bitInWord)) {

bitInWord = (32 - bitInWord);

wordInMap++;;

mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord); map[wordInMap] &= ~mask; map[wordInMap] |= (mask & (val >> bitInWord));

}

if语句判断当前chunk序号是否跨越当前32位边界。整个代码初看起来比较难理解,其

实只要将dev->tnodeWidth以16或32代入,就很好懂了。还有一个类似的函数

yaffs_GetChunkGroupBase,返回由tn和pos确定的一组chunk的起始序号,就不详细分

析了。

现在我们假设有这样一个情景:已知文件偏移地址,要找到flash上对应的存储地址,该

怎么做呢?这项工作的主体是由函数yaffs_FindLevel0Tnode完成的。

static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device * dev,

yaffs_FileStructure * fStruct,

__u32 chunkId)

{

yaffs_Tnode *tn = fStruct->top;

__u32 i;

int requiredTallness;

int level = fStruct->topLevel;

函数参数中,fStruct是指向文件描述结构的指针,该结构保存着文件大小、映射树层高、映射树顶层节点指针等信息。chunkId是逻辑chunk id。

fStruct->top是映射树顶层节点指针,fStruct->topLevel是映射树层高。注意:当只有

一层时,层高为0。

/* First check we're tall enough (ie enough topLevel) */

i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;

requiredTallness = 0;

while (i) {

i >>= YAFFS_TNODES_INTERNAL_BITS;

requiredTallness++;

}

if (requiredTallness > fStruct->topLevel) {

/* Not tall enough, so we can't find it, return NULL. */

return NULL;

}

在看这段代码之前,我们先用一个例子来回顾一下映射树的组成。假定我们有一个大小

为128K的文件,flash的page大小为2K,那么我们就需要64个page(或者说chunk)来存储该文件。一组Tnode的size是8个指针,或者16个16位整数,所以我们需要64 / 16 = 4组Tnode来存储物理chunk序号。这4组Tnode就是映射树的叶节点,也就是Level0 节点。由于这4组Tnode在内存中不一定连续,所以我们需要另外一组Tnode,将其作为指针数组使用,这个指针数组的前4个元素分别指向4组Level0节点,而fStruct->top就指向这组作为指针数组使用的Tnode。随着文件长度的增大,所需的叶节点越多,非叶

节点也越多,树也就越长越高。

回过头来看代码,首先是检查函数参数chunkId是否超过文件长度。作为非叶节点使用的Tnode每组有8个指针,需要3位二进制码对其进行索引,因此树每长高一层,逻辑chunkId就多出3位。相反,每3位非零chunkId就代表一层非叶节点。while循环根据这个原则计算参数chunkId所对应的树高。如果树高超过了文件结构中保存的树高,那就

说明该逻辑chunkId已经超出文件长度了。通过文件长度检查之后,同样根据上面的原则,就可以找到逻辑chunkId对应的物理chunkId了。具体的操作通过一个while循环完成:/* Traverse down to level 0 */

while (level > 0 && tn) {

tn = tn->

internal[(chunkId >>

( Y AFFS_TNODES_LEVEL0_BITS +(level - 1) *

YAFFS_TNODES_INTERNAL_BITS)

& (YAFFS_TNODES_INTERNAL_MASK];

level--;

}

return tn;

将返回值和逻辑chunk id作为参数调用yaffs_GetChunkGroupBase,就可以得到物理chunk id了。

下面我们看另一个情景,看看当文件长度增加的时候,映射树是如何扩展的。主要

函数为

static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device * dev,

yaffs_FileStructure * fStruct,

__u32 chunkId,

yaffs_Tnode *passedTn)

函数的前几行和yaffs_FindLevel0Tnode一样,对函数参数作一些检查。通过检查之后,首先看原映射树是否有足够的高度,如果高度不够,就先将其“拔高”:if (required_depth > file_struct->top_level) {

/* Not tall enough, gotta make the tree taller */

for (i = file_struct->top_level; i < required_depth; i++) {

tn = yaffs_get_tnode(dev);

if (tn) {

tn->internal[0] = file_struct->top;

file_struct->top = tn;

file_struct->top_level++;

} else {

yaffs_trace(YAFFS_TRACE_ERROR,

"yaffs: no more tnodes");

return NULL;

}

}

}

for循环完成增加新层的功能。新增的每一层都只有一个节点(即一组

Tnode),fStruct->top始终指向最新分配的节点。将映射树扩展到所需的高度之后,再根据需要将其“增肥”,扩展其“宽度”:

l = file_struct->top_level;

tn = file_struct->top;

if (l > 0) {

while (l > 0 && tn) {

x = (chunk_id >>

(YAFFS_TNODES_LEVEL0_BITS +

(l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &

Y AFFS_TNODES_INTERNAL_MASK;

if ((l > 1) && !tn->internal[x]) {

/* Add missing non-level-zero tnode */

tn->internal[x] = yaffs_get_tnode(dev);

if (!tn->internal[x])

return NULL;

} else if (l == 1) {

/* Looking from level 1 at level 0 */

if (passed_tn) {

/* If we already have one, release it */

if (tn->internal[x])

yaffs_free_tnode(dev,

tn->internal[x]);

tn->internal[x] = passed_tn;

} else if (!tn->internal[x]) {

/* Don't have one, none passed in */

tn->internal[x] = yaffs_get_tnode(dev);

if (!tn->internal[x])

return NULL;

}

}

tn = tn->internal[x];

l--;

}

}

上面“拔高”的时候是从下往上“盖楼”,这里“增肥”的时候是从上往下“扩展”。

tn->internal[x]为空表示下层节点尚未创建,需要通过yaffs_GetTnode分配之,就是“

增肥”了。如果函数参数passedTn有效,就用该组Tnode代替level0上原先的那组Tnode;否则按需分配新的Tnode组。所以这里的函数名似乎应该取作

yaffs_AddOrFindOrReplaceLevel0Tnode更加恰当。不过这个新名字也太长了些……

树的创建、搜索和扩展说完了,下面该说什么?……对了,收缩和删除。不过看过创建搜索扩展之后,收缩和删除已经没什么味道了。主要函数有:

yaffs_DeleteWorker()

yaffs_SoftDeleteWorker()

yaffs_PruneWorker()

前两者用于删除,第三个用于收缩。都是从level0开始,以递归的方式从叶节点向上删,并释放被删除Tnode所对应的物理chunk。递归,伟大的递归啊……俺不想把这篇文章做成递归算法教程,除了递归这三个函数也就不剩啥了,所以一概从略。唯一要说的就是yaffs_DeleteWorker和yaffs_SoftDeleteWorker的区别,这两个函数非常类似,只是在

释放物理chunk的时候分别调用yaffs_DeleteChunk 和yaffs_SoftDeleteChunk。其中函

数yaffs_DeleteWorker在yaffs2中似乎是不用的,而yaffs_SoftDeleteWorker主要用于

在删除文件时资源的释放。

7.文件系统对象

在yaffs2中,不管是文件还是目录或者是链接,在内存都用一个结构体

yaffs_ObjectStruct来描述。我们先简要介绍一下这个结构体中的几个关键字段,然后

再来看代码。在后文中提到“文件”或“文件对象”,若不加特别说明,都指广义的“文

件”,既可以是文件,也可以是目录。

__u8 deleted:1; /* This should only apply to unlinked files. */

__u8 softDeleted:1; /* it has also been soft deleted */

__u8 unlinked:1; /* An unlinked file. The file should be in the unlinked

directory.*/

这三个字段用于描述该文件对象在删除过程中所处的阶段。在删除文件时,首先要将文件从原目录移至一个特殊的系统目录/unlinked,以此拒绝应用程序对该文件的访问,此时将unlinked置1;然后判断该文件长度是否为0,如果为0,该文件就可以直接删除,此时将deleted置1;如果不为0,就将deleted和softDelted都置1,表明该文件数据所占据的chunk还没有释放,要留待后继处理。

struct yaffs_ObjectStruct *parent;

看名字就知道,该指针指向上层目录。

int chunkId;

每个文件在flash上都有一个文件头,存储着该文件的大小、所有者、创建修改时间等信息。chunkId就是该文件头在flash上的chunk序号。

__u32 objectId; /* the object id value */

每一个文件系统对象都被赋予一个唯一的编号,作为对象标识,也用于将该对象挂入一个散列表,加快对象的搜索速度。

yaffs_ObjectType variantType;

yaffs_ObjectVariant variant;

前者表示该对象的类型,是目录、普通文件还是链接文件。后者是一个联合体,根据对象类型的不同有不同的解释。其余的成员变量,我们在后面结合函数一起分析。

下面我们来看相关的函数。先看一个简单的:

static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device * dev, int number,

__u32 mode)

所谓Fake Directory,就是仅存在于内存中,用于管理目的的目录对象,比如我们上面提到的unlinked目录。这种类型的目录有一些特别的地方,如禁止改名、禁止删除等。由于对象仅存在于内存中,因此不涉及对硬件的操作,所以函数体很简单。首先通过

yaffs_CreateNewObject获得一个新对象,然后对其中的一些字段初始化。先把字段初始化看一下,顺便再介绍一些字段:

renameAllowed表示是否允许改名,对于fake对象为0;

unlinkAllowed表示是否允许删除,对于fake对象同样为0;

yst_mode就是linux中的访问权限位;

chunkId是对象头所在chunk,由于fake对象不占flash存储空间,所以置0。

回过头来看yaffs_CreateNewObject:

[yaffs_CreateFakeDirectory --> yaffs_CreateNewObject]

yaffs_Object *yaffs_CreateNewObject(yaffs_Device * dev, int number,

yaffs_ObjectType type)

{

yaffs_Object *theObject;

if (number < 0) {

number = yaffs_CreateNewObjectNumber(dev);

}

theObject = yaffs_AllocateEmptyObject(dev);

前面说过,每个yaffs_Object都有一个唯一的序列号,这个序号既可以在创建对象的时

候由上层函数指定,也可以由系统分配。如果number < 0,那就表示由系统分配。序列号分配函数是yaffs_CreateNewObjectNumber。我们就不深入到这个函数内部了,只说明一

下该函数做了些什么:

系统为了方便根据对象id找到对象本身,将每个对象都通过指针hashLink挂入了一个散

列表,散列函数是number % 256,所以这个散列表有256个表项。

yaffs_CreateNewObjectNumber函数每次搜索10个表项,从中选取挂接链表长度最短的那

一项,再根据表索引试图计算出一个和该索引上挂接对象的id号不重复的id。

分配到了id号和空闲对象后,再根据对象类型的不同作不同的处理。我们主要关心两种

情况,就是对象类型分别为文件和目录的时候:

case Y AFFS_OBJECT_TYPE_FILE:

theObject-> = 0;

theObject-> = 0; theObject-> = 0xFFFFFFFF; /* max __u32 */

theObject-> = 0;

theObject-> = yaffs_GetTnode(dev);

break;

case Y AFFS_OBJECT_TYPE_DIRECTORY:

INIT_LIST_HEAD(&theObject->;

break;

fileSize很好理解;topLevel就是映射树层高,新建的文件层高为0。还要预先分配一组Tnode供该对象使用。scannedFileSize和shrinkSize用于yaffs2初始化时的flash扫描

阶段,这里先跳过。如果该对象是目录,那么所做的工作只是初始化子对象(就是该目

录下的文件或子目录)双向链表指针,前后指针都指向链表头自身。

看过Fake对象创建,我们再看看普通对象的创建。按对象类型的不同,有四个函数分别

用于创建普通文件、目录、设备文件、符号链接和硬链接,它们分别是:

yaffs_MknodFile;

yaffs_MknodDirectory;

yaffs_MknodSpecial;

yaffs_MknodSymLink;

yaffs_Link

这四个函数最终都调用yaffs_MknodObject来完成创建对象的工作,只是调用参数不一样。static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,

yaffs_Object * parent,

const YCHAR * name,

__u32 mode,

__u32 uid,

__u32 gid,

yaffs_Object * equivalentObject,

const YCHAR * aliasString, __u32 rdev)

函数参数中,前面几个都很好理解,分别是对象类型,上级目录对象,文件名,访问权限,文件所属user id和group id;equivalentObject是创建硬链接时的原始文件对象;aliasString是symLink名称;rdev是设备文件的设备号。

函数首先检查在父目录中是否已存在同名文件,然后同样调用yaffs_CreateNewObject创

建新对象。参数-1表示由系统自行选择对象id。

if (in) {

in->chunkId = -1;

in->valid = 1;

in->variantType = type;

in->yst_mode = mode;

in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;

in->yst_rdev = rdev; in->yst_uid = uid;

in->yst_gid = gid;

in->nDataChunks = 0;

yaffs_SetObjectName(in, name);

in->dirty = 1;

yaffs_AddObjectToDirectory(parent, in);

in->myDev = parent->myDev;

这里列出的代码省略了和wince相关的条件编译部分。chunkId是对象头所在chunk,现在还没有将对象写入flash,所以置为-1;该新对象暂时还没有数据,所以nDataChunks是0。in->dirty = 1表示该新对象信息还没有写入flash。然后通过

yaffs_AddObjectToDirectory将新对象挂入父对象的子对象链表。接下来根据对象类型

作不同处理:

switch (type) {

case YAFFS_OBJECT_TYPE_SYMLINK:

in-> =yaffs_CloneString(aliasString);

break;

case YAFFS_OBJECT_TYPE_HARDLINK:

in-> = equivalentObject;

in-> = equivalentObject->objectId;

list_add(&in->hardLinks, &equivalentObject->hardLinks);

break;

case YAFFS_OBJECT_TYPE_FILE:

case YAFFS_OBJECT_TYPE_DIRECTORY:

case YAFFS_OBJECT_TYPE_SPECIAL:

case YAFFS_OBJECT_TYPE_UNKNOWN:

/* do nothing */

break;

}

对于最常用的文件对象和目录对象不做任何处理;如果是hardlink,就将新对象挂入原对象的hardLinks链表。从这里我们可以看出,yaffs2在内存中是以链表的形式处理hardlink的。在将hardlink存储到flash上的时候,则是通过objectId将两者关联起来。Hardlink本身占用一个chunk存储对象头。

最后,通过yaffs_UpdateObjectHeader将新对象头写入flash。

系统分析报告

系统分析报告 Company number:【WTUT-WT88Y-W8BBGB-BWYTT-19998】

宿舍管理信息系统分析报告 一、引言 1、新系统的名称:学生宿舍管理信息系统 2、系统开发背景: 随着时代的发展,计算机技术越来越深入各行各业,为广大的用户提供了更为周到和便捷的服务。目前各行各业广泛使用专用系统,其内容范围跨越了教育科研、文化事业、金融、商业、新闻出版、娱乐、体育等各个领域,其用户群十分庞大,因此,设计开发好一个专用系统对一个机构或部门的发展十分重要。近年来,随着用户要求的不断提高及计算机科学的迅速发展,特别是数据库技术的广泛应用,向用户提供的服务将越来越丰富,越来越人性化。 对于学校而言,学生宿舍管理是必不可少的组成部分。目前仍然存在有学校停留在宿舍管理部门人员手工记录数据的阶段,手工记录对于规模小的学校来说勉强可以接受;但对于学生信息量比较庞大,需要记录存档的数据比较多的高校来说,人工记录是相当麻烦的,而且当查找某条记录时,由于数据量庞大,只能依靠人工去一条一条地查找,这样不但麻烦而且浪费许多时间,工作效率比较低。采用计算机来管理宿舍和学生的信息,大大提高了查询的速度,节约了人力和物力资源,达到了预期的要求。 3、系统开发的目标 由于先前宿舍管理的工作流程建立在手工操作之上而导致处理速度过慢,不能满足上级管理层和住宿学生的要求,所以新系统开发的目标是:适应快速增长学生数的要求,立足于现有的人力资源,充分利用计算机的强大功能,加强住宿工作各阶段的科学管理,并对管理决策提供良好支持。 4、主要功能 (1)、预分宿舍,新生报道之前就根据其专业为其分配宿舍。 (2)、调整宿舍,根据学生入住情况和申请换宿舍的情况,为学生合理安排宿舍。 (3)、对于入住新生的资料、交费情况、每月每个宿舍的水电费等数据能够准确录入。只有对基本数据快速、准确的录入,才能为后继工作提供良好的支持。

简单文件系统的实现

简单文件系统的实现 Company Document number:WUUT-WUUY-WBBGB-BWYTT-1982GT

第三章简单文件系统的实现 设计目的和内容要求 1.设计目的 通过具体的文件存储空间的管理、文件的物理结构、目录结构和文件操作的实现,加深对文件系统内部数据结构、功能以及实现过程的理解。 2.内容要求 (1)在内存中开辟一个虚拟磁盘空间作为文件存储分区,在其上实现一个简单的基于多级目录的单用户单任务系统中的文件系统。在退出该文件系统的使用时,应将该虚拟文件系统以一个Windows文件的方式保存到磁盘上,以便下次可以再将它恢复到内存的虚拟磁盘空间中。 (2)文件存储空间的分配可采用显式链接分配或其他的办法。 (3)空闲磁盘空间的管理可选择位示图或其他的办法。如果采用位示图来管理文件存储空间,并采用显式链接分配方式,那么可以将位示图合并到FAT 中。 (4)文件目录结构采用多级目录结构。为了简单起见,可以不使用索引结点,其中的每个目录项应包含文件名、物理地址、长度等信息,还可以通过目录项实现对文件的读和写的保护。 (5)要求提供以下操作命令: my_format:对文件存储器进行格式化,即按照文件系统的结构对虚拟磁盘空间进行布局,并在其上创建根目录以及用于管理文件存储空间等的数据结构。

●my_mkdir:用于创建子目录。 ●my_rmdir:用于删除子目录。 ●my_ls:用于显示目录中的内容。 ●my_cd:用于更改当前目录。 ●my_create:用于创建文件。 ●my_open:用于打开文件。 ●my_close:用于关闭文件。 ●my_write:用于写文件。 ●my_read:用于读文件。 ●my_rm:用于删除文件。 ●my_exitsys:用于退出文件系统。 3.学时安排 授课2学时,上机9学时。 4.开发平台 C或C++均可。 5.思考 (1)我们的数据结构中的文件物理地址信息是使用C语言的指针类型、还是整型,为什么 (2)如果引入磁盘索引结点,上述实现过程需要作哪些修改 (3)如果设计的是一个单用户多任务文件系统,则系统需要进行哪些扩充(尤其要考虑读写指针问题)如果设计的是一个多用户文件系统,则又要进行哪些扩充

busybox详解制作根文件系统

详解制作根文件系统 单击,返回主页,查看更多内容 一、FHS(Filesystem Hierarchy Standard)标准介绍 当我们在linux下输入ls / 的时候,见到的目录结构以及这些目录下的内容都大同小异,这是因为所有的linux发行版在对根文件系统布局上都遵循FHS标准的建议规定。 该标准规定了根目录下各个子目录的名称及其存放的内容: 制作根文件系统就是要建立以上的目录,并在其中建立完整目录内容。其过程大体包括: ?编译/安装busybox,生成/bin、/sbin、/usr/bin、/usr/sbin目录 ?利用交叉编译工具链,构建/lib目录 ?手工构建/etc目录 ?手工构建最简化的/dev目录 ?创建其它空目录 ?配置系统自动生成/proc目录 ?利用udev构建完整的/dev目录 ?制作根文件系统的jffs2映像文件 下面就来详细介绍这个过程。 二、编译/安装busybox,生成/bin、/sbin、/usr/bin、/usr/sbin目录

这些目录下存储的主要是常用命令的二进制文件。如果要自己编写这几百个常用命令的源程序,my god,这简直是一个噩梦!好在我们有嵌入式Linux系统的瑞士军刀——busybox,事情就简单很多。 1、从https://www.doczj.com/doc/c716131414.html,/下载busybox-1.7.0.tar.bz2 2、tar xjvf busybox-1.7.0.tar.bz2解包 3、修改Makefile文件 175 ARCH ?= arm 176 CROSS_COMPILE ?= arm-linux- 4、make menuconfig配置busybox busybox配置主要分两部分。 第一部分是Busybox Settings,主要编译和安装busybox的一些选项。这里主要需要配置:

文件系统课程设计报告

设计时间: 2011-1-5至2011-1-7 专业年级:08计科4班: 一.设计目的: 通过操作系统其中一个子系统的设计和实现,掌握Linux文件系统的基本原理、结构和实现方法,掌握Linux文件系统中文件的建立、打开、读/写、执行、属性等系统调用的使用,学会设计简单的文件系统并实现一组操作,以及学习文件系统的系统调用命令,提高对文件系统实现功能的理解和掌握。同时,掌握操作系统设计的方法与技巧,增强系统软件设计的实际工作能力。 二.设计容: 为LINUX 设计一个简单的二级文件系统。本文件系统采用类似DOS系统的文件管理方式,每次调用该文件系统时,首先申请一定的存空间,然后对该存空间进行分配。将申请到的空间划分为目录区,文件区;采用位示图进行空间管理,盘块的分配使用显示(FAT 表)的方式。每次调用该文件系统时自动为其分配空间,并将上次操作的结果从硬盘上调入存;当结束调用时则将操作的结果重新存入硬盘,以便下次调用。(每次使用都会自动搜索文件系统,以此确定是否是第一次使用;若是则格式化生成文件系统,否则读取已存在的文件系统。) 三.设计过程 1、实现功能 该系统具备下列功能: login 用户登录logout 注销 mkdir/md 创建目录rmdir/rd 删除目录 cd/cd .. 修改目录creat 创建文件 open 打开文件dir 显示当前目录和文件 write 读文件 delete 删除文件 close 关闭文件 2、添加功能 (1)制作了一个“操作命令符”列表框,说明接下来如何操作,这样有利于更好地阅读、操作和运行程序,使不懂得程序代码的人也可以运行该程序,更好地理解该程序实现的功能。 (2)在命令解释层函数cmdexp()里加了一些选择和操作功能,增加程序实现的功能,如原来程序只有显示当前目录和文件、创建目录和修改目录的功能,把它拓展到系统所要求的全部功能,并在原有的程序的基础上进行相应的修改,使程序更加完善。 3、设计思路 (1)要将文件存储在磁盘上,必须为之分配相应的存储空间,并对文件存储空间进行管

操作系统文件管理实验报告

操作系统实验报告实验名称:文件管理 专业班级:网络工程1301 学号: 姓名: 2015 年6 月16 日

实验一文件管理 一、实验目的 文件管理是操作系统的一个非常重要的组成部分。学生应独立用高级语言编写和调试一个简单的文件系统,模拟文件管理的工作过程。从而对各种文件操作命令的实质容和执行过程有比较深入的了解,掌握它们的实施方法,加深理解课堂上讲授过的知识。 二、预备知识 1.VS2010的使用 2.C#的学习 3.文件主目录与子目录的理解 三、实验容与步骤 用高级语言编写和调试一个简单的文件系统,模拟文件管理的工作过程。要求设计一个10 个用户的文件系统,每次用户可保存10 个文件,一次运行用户可以打开5 个文件。系统能够检查打入命令的正确性,出错时能显示出错原因。对文件必须设置保护措施,例如只能执行,允许读等。在每次打开文件时,根据本次打开的要求,在此设置保护级别,即有二级保护。文件的操作至少有Create、delete、open、close、read、write 等命令。 所编写的程序应采用二级文件目录,即设置主文件目录和用户文件目录。前者应包含文件主及它们的目录区指针;后者应给出每个文件占有的文件目录,即文件名,保护码,文件长度以及它们存放的位置等。另外为打开文件设置运行文件目录(AFD),在文件打开时应填入打开文件号,本次打开保护码和读写指针等。 程序流程图:

逻辑设计: 使用线性数组表表示MFD,泛型数组表示UFD,每个元素包括用户ID、保存的文件数、再使用线性表表示文件信息,每个元素包括文件名,文件属性(保护码),文件的状态等信息。 物理设计: //主目录 private FileUser[] mfd; //当前用户 private FileUser currentuser; ///

/// 文件 /// public class FileObject { public string filename; public int size=20; public int read=0; public int write = 0; public string author; } /// /// 文件系统用户 /// public class FileUser { public string username;

信息化系统诊断分析报告

上海理光传真机有限公司 信息系统分析报告 策划设计:专家组 上海三元企业管理有限公司 目录 第一部分:各系统的现状分析.................................... 一、信息系统现状分析 ............................................. 二、EDP系统的现状与问题分析...................................... 应用情况........................................................ 存在问题........................................................ 三、销售系统分析 ................................................. 应用现状........................................................ 存在问题........................................................ 四、财务系统分析 .................................................

应用现状........................................................ 存在问题........................................................ 五、N OTES办公系统分析............................................. 应用现状........................................................ 存在问题........................................................第二部分:现存问题的原因分析.................................. 一、各子系统内部的缺陷(详见现状分析)............................ 二、企业缺乏一个比较前瞻性的战略,导致信息系统的定位与 规划不明确 ....................................................... 三、子系统之间无法实现信息共享 ................................... 四、缺少一个统一负责信息系统规划和管理的部门,而是分散 在各部门,各司其职,缺乏总体协调 .................................第三部分:上海理光信息系统规划的对策建议...................... 一、信息系统规划的目标 ........................................... 二、信息系统应用系统分析 ......................................... (一)信息系统愿景.............................................. (二)信息系统应用总体结构...................................... (三)订单获取与完成流程........................................ (四)制造与物料流程应用系统.................................... (五)新产品研究与开发流程...................................... (六)售后服务流程应用系统...................................... (七)财务流程应用系统............................................

模拟文件系统的设计与实现

中北大学 操作系统课程设计 说明书 学院、系:软件学院 专业:软件工程 学生姓名:xxx 学号:xxx 设计题目:模拟文件系统的设计与实现 起迄日期: 2015年12月28日- 2016年1月8日指导教师:xxx 2016 年1月8日

1需求分析 通过模拟文件系统的实现,深入理解操作系统中文件系统的理论知识, 加深对教材中的重要算法的理解。同时通过编程实现这些算法,更好地掌握操作系统的原理及实现方法,提高综合运用各专业课知识的能力;掌握操作系统结构、实现机理和各种典型算法,系统地了解操作系统的设计和实现思路,并了解操作系统的发展动向和趋势。 模拟二级文件管理系统的课程设计目的是通过研究Linux的文件系统结构,模拟设计一个简单的二级文件系统,第一级为主目录文件,第二级为用户文件。 2总体设计 结合数据结构、程序设计、计算机原理等课程的知识,设计一个二级文件系统,进一步理解操作系统。 文件的创建: create 文件关闭:close 文件的打开:open 文件的读:read 文件的写:write 文件关闭:close 删除文件:delete 创建子目录:mkdir 删除子目录:rmdir 列出文件目录:dir 退出:exit 系统执行流程图 开始 选择操作 创建文件删 除 文 件 读 文 件 写 文 件 创 建 文 件 夹 删 除 文 件 夹 删 除 子 目 录 显示 当前 子目 录 创 建 子 目 录 更 改 目 录 退 出

退出 3.详细设计 主要数据结构: #define MEM_D_SIZE 1024*1024 //总磁盘空间为1M #define DISKSIZE 1024 //磁盘块的大小1K #define DISK_NUM 1024 //磁盘块数目1K #define FATSIZE DISK_NUM*sizeof(struct fatitem) //FAT表大小 #define ROOT_DISK_NO FATSIZE/DISKSIZE+1 //根目录起始盘块号#define ROOT_DISK_SIZE sizeof(struct direct) //根目录大小 #define DIR_MAXSIZE 1024 //路径最大长度为1KB #define MSD 5 //最大子目录数5 #define MOFN 5 //最大文件深度为5 #define MAX_WRITE 1024*128 //最大写入文字长度128KB struct fatitem /* size 8*/ { int item; /*存放文件下一个磁盘的指针*/ char em_disk; /*磁盘块是否空闲标志位 0 空闲*/ }; struct direct { /*-----文件控制快信息-----*/ struct FCB { char name[9]; /*文件/目录名 8位*/ char property; /*属性 1位目录 0位普通文件*/ int size; /*文件/目录字节数、盘块数)*/

基于busybox的根文件系统制作

龙源期刊网 https://www.doczj.com/doc/c716131414.html, 基于busybox的根文件系统制作 作者:李飞,武金虎,石颖博 来源:《电脑知识与技术》2010年第17期 摘要:Busybox是构建嵌入式Linux文件系统的必备软件,它是所有文件和设备节点的起始点,是决定系统能否正常启动的关键。通过busybox-1.1.3为例,进行配置、编译、安装等过程,从而形成简单的根文件系统映像文件,为以后嵌入式Linux系统的移植打下了良好的开端。 关键词:Busybox;嵌入式Linux;Linux操作系统;根文件系统;cramfs 文件系统 中国分类号:TP316.81文献标识码:A文章编号:1009-3044(2010)17-4655-02 Making Root File System Based on Busybox LI Fei, WU Jin-hu, SHI Ying-bo (College of Computer Science and Information, Guizhou University, Guiyang 550025, China) Abstract: Busybox is an essentiaL software to buiLd an embedded Linux fiLe system. It is the starting node point of aLL the fiLes and devices and the key whether the system can have a normaL start. Taking busybox-1.1.3 for exampLe, making a simpLe root image system fiLe by configuration compiLation and instaLLation Lays a good foundation for migration of the embedded Linux system. Key words: busybox; embedded linux; Linux OS; root file system; cramfs file system 1 根文件系统结构 根文件系统是所有文件和设备节点的起始点,包括系统所必须的各种工具软件、库文件、 脚本、配置文件等一系列的文件。一个基本的Linux根文件系统包含有以下的目录:dev、proc、bin、etc、usr、Lib、temp、var、usr等等目录。其中dev是设备文件节点目录,proc是挂载proc文件系统所用的目录,bin目录下面包含了系统的基本命令,etc目录是系统启动脚本所在的目录,Lib是系统默认的动态链接库目录,usr是用户目录,temp是临时目录,用来保存临时文 件,var目录包含系统运行时要改变的数据。以上都是根文件系统所必须的目录 2 Busybox简介 熟练嵌入式Linux的朋友对busybox一定不会陌生,它是标准Linux工具的一个单个可执行实现,被形象的称为嵌入式Linux系统中的“瑞士军刀”,因为它将许多常用的UNIX工具和命令 结合到一个单独的可执行程序中。虽然busybox中的这些工具相对于GNU常用工具功能有所

二级文件系统演示

湖南工业大学 课程设计 资料袋 学院(系、部)学年第学期课程名称计算机操作系统指导教师职称 学生姓名专业班级学号 题目文件系统演示 成绩起止日期年月日~年月日 目录清单

课程设计任务书 — 学年第 学期 学院(系、部) 专业 班级 课程名称: 计算机操作系统 学生姓名: 设计题目: 文件系统演示 指导教师: 完成期限:自 年 月 日至 年 月 日 共 周 内 容 及 任 务 一、设计内容 设计一个简单的多用户文件系统。即 ①在系统中用一个文件来模拟一个磁盘; ②此系统至少有:Create 、delete 、open 、close 、read 、write 等和部分文件属性的功能。 ③实现这个文件系统。 ④能实际演示这个文件系统。 基本上是进入一个界面(此界面就是该文件系统的界面)后,可以实现设计的操作要求。 二、设计任务 课程设计说明书(纸质+电子版),内容包括:设计内容、系统分析(包括可行性分析、需求分析等)及功能分析;系统设计(要求画出系统整体功能框图、流程图、并给出相应地关键的代码且对所使用的主要数据结构进行说明等。)、设计总结(评价/遇到的问题/体会/建议等)、使用说明等。 三、设计要求 1. 按功能要求开发系统,能正确运行。程序代码书写规范,有充足的注释。 2. 课程设计所使用的编程语言任选,但建议使用C 或C++; 3. 绿色软件:程序运行不需安装,避免写系统和注册表; 进 度 安 排 起止日期 工作内容 完成选题、课题分析、课题设计、编写程序 程序调试、完善代码 优化测试系统、程序答辩 撰写并提交课程设计说明书 (含电子文档)、源程序等。 主 要 参 考 资 料 [1] 胡志刚,谭长庚等. 《计算机操作系统》.中南大学出版社. 2005 [2] 罗宇,邹鹏,邓胜兰.操作系统[M].北京:电子工业出版社,2012. [3] 面向对象程序设计与C++语言.朱战立,宋新爱.电子工业出版社,2010.7 [4] C++面向对象程序设计.谭浩强.清华大学出版社,2006.1 [5] 任爱华,李鹏,刘方毅.操作系统实验指导, 清华大学出版社,2004. [6] 徐虹.操作系统实验指导-基于LINUX 内核, 清华大学出版社, 2004. 指导教师(签字): 年 月 日 系(教研室)主任(签字): 年 月 日

U盘引导根文件系统

1.linux PC机上格式化SD卡 在桌面的PC机上用SD读卡器操作SD卡: 一般情况下PC机上第一个U盘整体设备结点是/dev/sda,第二个是/dev/sdb,在RHEL5下它会被自动mount到/media/disk和/media/disk_1 目录. U盘/dev/sdb上第一个分区是/dev/sdb1,第二是/dev/sdb2 依此类推. 根文件系统采用符号链接等特性,用FAT32是不行的,这里直接采用标准的ext3的文件系统.在实测时,把U盘整个做一个分区做ext3根文件系统.总是出不少问题(可能步骤也不对),因此按网上推荐的,做二个分区,第一个分区采用vfat格式,第二个分区才采用ext3的格式. 1.1 用fdisk分区 执行fdisk /dev/sdb fdisk有如下常用选项 1. 输入m 显示所有命令列示。 2. 输入p 显示硬盘分割情形。 3. 输入a 设定硬盘启动区。 4. 输入n 设定新的硬盘分割区。 4.1. 输入e 硬盘为[扩展]分割区(extend)。 4.2. 输入p 硬盘为[首要]分割区(primary)。 5. 输入t 改变硬盘分割区属性。 6. 输入d 删除硬盘分割区属性。 7. 输入q 结束不存入硬盘分割区属性。 8. 输入w 结束并写入硬盘分割区属性 如果以前U盘有分区,需要输入d命令来依次删除分区,以下执行两次n命令创建一个400M 的FAT分区,以及把剩下的分区设为ext3,最后用w命令把结果保存下来.

Command (m for help): n Command action e extended p primary partition (1-4) p Partition number (1-4): 1 First cylinder (1-1020, default 1): Using default value 1 Last cylinder or +size or +sizeM or +sizeK (1-1020, default 1020): +400M Command (m for help): n Command action e extended p primary partition (1-4) p Partition number (1-4): 2 First cylinder (202-1020, default 202): Using default value 202 Last cylinder or +size or +sizeM or +sizeK (202-1020, default 1020): Using default value 1020 Command (m for help): p Disk /dev/sdb: 2041 MB, 2041577472 bytes 63 heads, 62 sectors/track, 1020 cylinders Units = cylinders of 3906 * 512 = 1999872 bytes Device Boot Start End Blocks Id System /dev/sdb1 1 201 392522 b W95 FAT32 /dev/sdb2 202 1020 1599507 83 Linux Command (m for help): w The partition table has been altered! Calling ioctl() to re-read partition table. WARNING: Re-reading the partition table failed with error 16: 设备或资源忙. The kernel still uses the old table. The new table will be used at the next reboot. WARNING: If you have created or modified any DOS 6.x partitions, please see the fdisk manual page for additional information.

操作系统课程设计二级文件系统

操作系统课程设计报告 专业:计算机信息处理 学号:09103408 姓名:纪旻材 提交日期:2011-12-28

【设计目的】 1. 课程设计目的是通过一个简单多用户文件系统的设计,加深理解文件系统的内部功能和内部实现。 2. 结合数据结构、程序设计、计算机原理等课程的知识,设计一个二级文件系统,进一步理解操作系统。 3. 通过对实际问题的分析、设计、编程实现,提高学生实际应用、编程的能力 【设计内容】 1、delete 删除文件 2、open 打开文件 3、close 关闭文件 4、write 写文件 【实验环境】 Windows7系统

Visual studio 2010 【相关知识综述】 本文件系统采用两级目录,其中第一级对应于用户账号,第二级对应于用户帐号下的文件。另外,为了简便文件系统未考虑文件共享,文件系统安全以及管道文件与设备文件等特殊内容。 首先应确定文件系统的数据结构:主目录、子目录及活动文件等。主目录和子目录都以文件的形式存放于磁盘,这样便于查找和修改。用户创建的文件,可以编号存储于磁盘上。如:file0,file1,file2…并以编号作为物理地址,在目录中进行登记。 【设计思路】 1 主要数据结构 #define MAXNAME 25 /*the largest length of mfdname,ufdname,filename*/ #define MAXCHILD 50 /*the largest child每个用户名下最多有50个文件*/ #define MAX (MAXCHILD*MAXCHILD) /*the size of fpaddrno*/ typedef struct/*the structure of OSFILE定义主文件*/

系统分析与设计报告

系统分析与设计报告 撰写要求 实验报告撰写的基本要报告原则上不少于4000字,需在封面注明设计选题、班级、姓名、学号及课题设计日期、地点,其正文至少包括如下几个面的容: (1)企业简介和系统可行性分析 (2)系统分析部分 1)组织结构图 2)管理功能图 3)业务流程图 4)数据流程图 5)数据字典 6)数据加工处理的描述 7)管理信息系统流程设想图(新系统模型) (3)系统设计部分 1)功能结构图设计 2)新系统信息处理流程设计 3)输出设计(主要指打印输出设计) 4)存储文件格式设计(数据库结构设计) 5)输入设计(主要指数据录入卡设计) 6)代码设计(职工证号和部门代号等) 7)程序设计说明书 (4)系统实施部分(信管班需写此部分容,非信管班不作要求) 1)程序框图 3)模拟运行数据 4)打印报表 5)系统使用说明书 (5)附录或参考资料

案例: 东红照明有限公司 库存管理信息系统的分析、设计和实施 说明:本例时间较早,开发工具选用VFP。在学习过程中,可以现有的硬件和软件环境进行系统再开发实现,学习重点放在在系统分析、系统设计实际过程、法及容。 这里给出一个库存管理信息系统开发的实例,目的是使大家进一步深入了解开发任一个管理信息系统必须经历的主要过程,以及在开发过程的各个阶段上开发者应当完成的各项工作容和应当提交的书面成果。 一、东红照明有限公司产品库存管理系统简介 东红照明有限公司是我国东北地区一家生产照明灯的老企业,每年工业产值在四千万元左右。该厂目前生产的产品如表l所示。 表1 某厂产品品种规格、单价及定额储备

工厂的产品仓库管理组隶属于销售科领导,由七名职工组成,主要负责产品的出入库管理、库存帐务管理和统计报表,并且应当随时向上级部门和领导提供库存查询信息。为了防止超储造成产品库存积压,同时也为了避免产品库存数量不足而影响市场需求,库存管理组还应该经常提供库存报警数据(与储备定额相比较的超储数量或不足数量)。 产品入库管理的过程是,各生产车间随时将制造出来的产品连同填写好的入库单(入库小票)一起送至仓库。仓库人员首先进行检验,一是抽检产品的质量是否合格,二是核对产品的实物数量和规格等是否与入库单上的数据相符,当然还要校核入库单上的产品代码。检验合格的产品立即进行产品入库处理,同时登记产品入库流水帐。检验不合格的产品要及时退回车间。 产品出库管理的过程是,仓库保管员根据销售科开出的有效产品出库单(出库小票)及时付货,并判明是零售出库还是成批销售出库,以便及时登记相应的产品出库流水帐。 平均看来,仓库每天要核收三十笔入库处理,而各种出库处理约五十笔。每天出入库处理结束后,记帐员就根据入库流水帐和出库流水帐按产品及规格分别进行累计,以便将本日发生的累计数填入库存台帐。 产品入库单如表2所示,出库单如表3所示,入库流水帐如表4所示,出库流水帐如表5和表6所示,而库存台帐帐页如表7所示。 产品库存的收发存月报表是根据库存台帐制作出来的。产品库存查询是通过翻阅几本帐之后实现的。目前库存报警功能尚未实现。 表2 产品入库单第册号 表3产品出库单第册号 表4 产品入库流水帐页 表5产品零售出库流水帐页 表6产品批发出库流水帐页

操作系统简单文件系统设计及实现

简单文件系统的设计及实现 一、实验目的: 1、用高级语言编写和调试一个简单的文件系统,模拟文件管理的工作过程。从而对各种文件操作命令的实质内容和执行过程有比较深入的了解 2、要求设计一个 n个用户的文件系统,每次用户可保存m个文件,用户在一次运行中只能打开一个文件,对文件必须设置保护措施,且至少有Create、delete、open、close、read、write等命令。 二、实验内容: 1、设计一个10个用户的文件系统,每次用户可保存10个文件,一次运行用户可以打开5个文件。 2、程序采用二级文件目录(即设置主目录[MFD])和用户文件目录(UED)。另外,为打开文件设置了运行文件目录(AFD)。 3、为了便于实现,对文件的读写作了简化,在执行读写命令时,只需改读写指针,并不进行实际的读写操作 4、算法与框图 ?因系统小,文件目录的检索使用了简单的线性搜索。 ?文件保护简单使用了三位保护码:允许读写执行、对应位为 1,对应位为0,则表示不允许读写、执行。 ?程序中使用的主要设计结构如下:主文件目录和用户文件目录( MFD、UFD); 打开文件目录( AFD)(即运行文件目录) 文件系统算法的流程图如下

三、工具/准备工作: 在开始本实验之前,请回顾教科书的相关内容。并做以下准备: 1) 一台运行Windows 2000 Professional或Windows 2000 Server的操作系统的计算机。 2) 计算机中需安装Visual C++ 6.0专业版或企业版 四、实验要求: (1)按照学校关于实验报告格式的要求,编写实验报告(含流程图); (2)实验时按两人一组进行分组,将本组认为效果较好的程序提交检查。

根文件系统移植

实验五根文件系统移植 实验目的: 通过本次实验,使大家学会根文件系统移植的具体步骤,并对根文件系统有更近一步的感官认识。让同学理解由于根文件系统是内核启动时挂在的第一个文件系统,那么根文件系统就要包括Linux启动时所必须的目录和关键性的文件,任何包括这些Linux 系统启动所必须的文件都可以成为根文件系统。 实验硬件条件: 1、实验PC机一台,TINY6410开发板一台 2、电源线,串口线,数据线。 实验软件条件: 1、VMware Workstation, 2、Ubuntu10.04 3、mktools-20110720.tar.gz 4、busybox-1.13.3-mini2440.tgz, 5、SecureCRT以及dnw烧写工具 实验步骤: 一、实验步骤 1.进入rootfs目录,查看压缩文件,具体操作指令如下:

2.发现有两个压缩文件夹,分别进行解压: 3.tar xvzf busybox-1.13.3-mini2440.tgz, 4.tar xvzf mktools-20110720.tar.gz,解压完成后, 5.查看文件夹#ls

二、实验步骤 1.修改架构,编译器#cd busybox-1.13.3/ 2.进入后查看#ls 3.#gedit Makefile 4.修改 164行 CROSS_COMPILE ?=arm-linux- 5.修改190行 ARCH ?= arm 6.保存后,退出!

三、实验步骤 1.修改配置 #make menuconfig 2.若出现如下提示

3.需调整到最大化。

4.把Busybox Settings -----→>Build Option ------→> Build BusyBox as astatic binary (no shared libs) 选择上,其他的默认即可。 然后一直退出,保存即可 5.接着执行 make接着执行 make install 6.最终生成的文件在_install 中 #cd _install

操作系统课程设计Linux二级文件系统设计

操作系统课程设计Linux二级文件系 统设计

操作系统课程设计报告专业:软件工程

学号: 姓名:马 提交日期: /1/10 【设计目的】 1、经过一个简单多用户文件系统的设计,加深理解文件系统的内 部功能和内部实现 2、结合数据结构、程序设计、计算机原理等课程的知识,设计一 个二级文件系统,进一步理解操作系统 3、经过对实际问题的分析、设计、编程实现,提高学生实际应用、编程的能力 【设计内容】 为Linux系统设计一个简单的二级文件系统。要求做到以下几点: 1.能够实现下列几条命令: login 用户登录

dir 列目录 create 创立文件 delete 删除文件 open 打开文件 close 关闭文件 read 读文件 write 写文件 cd 进出目录 2.列目录时要列出文件名,物理地址,保护码和文件长度 3.源文件能够进行读写保护 【实验环境】 C++ DevCpp 【设计思路】 本文件系统采用两级目录,其中第一级对应于用户账号,第二级对应于用户帐号下的文件。另外,为了简便文件系统未考虑文件共享,文件系统安全以及管道文件与设备文件等特殊内容。

首先应确定文件系统的数据结构:主目录、子目录及活动文件等。主目录和子目录都以文件的形式存放于磁盘,这样便于查找和修改。用户创立的文件,能够编号存储于磁盘上。如:file0,file1,file2…并以编号作为物理地址,在目录中进行登记。 结构体: typedef struct /*the structure of OSFILE*/ { int fpaddr; /*file physical address*/ int flength; /*file length*/ int fmode; /*file mode:0-Read Only;1-Write Only;2-Read and Write; 3-Protect;*/ char fname[MAXNAME]; /*file name*/ } OSFILE; //存放重要信息 typedef struct /*the structure of OSUFD*/ { char ufdname[MAXNAME]; /*ufd name*/

操作系统文件管理_答案

第六部分文件管理 1、文件系统的主要目的就是( )。 A、实现对文件的按名存取 B、实现虚拟存储 C、提供外存的读写速度 D、用于存储系统文件 2、文件系统就是指( )。 A、文件的集合 B、文件的目录集合 C、实现文件管理的一组软件 D、文件、管理文件的软件及数据结构的总体 3、文件管理实际上就是管理( )。 A、主存空间 B、辅助存储空间 C、逻辑地址空间 D、物理地址空间 4、下列文件的物理结构中,不利于文件长度动态增长的文件物理结构就是( )。 A、顺序文件 B、链接文件 C、索引文件 D、系统文件 5、下列描述不就是文件系统功能的就是( )。 A、建立文件目录 B、提供一组文件操作 C、实现对磁盘的驱动调度 D、实现从逻辑文件到物理文件间的转换 6、文件系统在创建一个文件时,为它建立一个( )。 A、文件目录 B、目录文件 C、逻辑结构 D、逻辑空间 7、索引式(随机)文件组织的一个主要优点就是( )。 A、不需要链接指针 B、能实现物理块的动态分配 C、回收实现比较简单 D、用户存取方便 8、面向用户的文件组织机构属于( )。 A、虚拟结构 B、实际结构 C、逻辑结构 D、物理结构 9、按文件用途来分,编译程序就是( )。 A、用户文件 B、档案文件 C、系统文件 D、库文件 10、将信息加工形成具有保留价值的文件就是( )。 A、库文件 B、档案文件 C、系统文件 D、临时文件 11、文件目录的主要作用就是( )。 A、按名存取 B、提高速度 C、节省空间 D、提高外存利用率 12、如果文件系统中有两个文件重名,不应采用( )。 A、一级目录结构 B、树型目录结构 C、二级目录结构 D、A与C 13、文件系统采用树型目录结构后,对于不同用户的文件,其文件名( )。 A、应该相同 B、应该不同 C、可以不同,也可以相同 D、受系统约束 14、文件系统采用二级文件目录可以( )。 A、缩短访问存储器的时间 B、实现文件共享 C、节省内存空间 D、解决不同用户间的文件命名冲突

系统分析报告

报告题目:汽车维修管理系统分析报告 学生姓名:陈彩红学号: 1602102073 年级专业班级: 2016级金融工程 2 班 课程名称:信息系统分析与设计 教师:时青 成绩: 评语:

目录 一、甘特图··2 二、现行系统分析··2 三、可行性分析··2 1、引言··2 2、可行性研究的前提··3 3、对现有系统的分析··4 4、所建议的系统··6 5、可选择的其他系统方案··7 6、投资及效益分析··8 7、社会因素方面的可能性··9 8、结论··9 四、总体设计··9 1、系统的数据需求分析··9 2、流程图··11

3、数据流图··13 4、数据字典··13 5、概念设计:用E-R图描述概念模型··15 6、逻辑设计:将E-R模型转换为关系模型,且规范化··17 五、总结··18 汽车修理管理系统 一、甘特图

二、现行系统分析 某汽车修理厂根据业务发展的需要,需要建立一个以数据库为基础的管理信息系统,以代替单一的人工管理。目标系统取名为“汽车修理管理信息系统”。 三、可行性分析 1、引言 (1)编写目的 随着经济的发展,汽车已经步入了千家万代。随之而来的汽车修理业也忙活起来。为了让汽车修理更顺畅,某汽车修理厂拟开发一套小型汽车维修管理系统。(2)背景 开发的系统名称:汽车修理管理信息系统 用户:汽车修理厂 实现该软件的计算中心:个人计算机 (3)定义 汽车维修管理:主要是指车辆维修流程的计算机管理,通过修理企业的信息管理系统,对车辆的报修进行派工、结算出厂等方面以流程化的方式,把各个环节串连起来,为顾客提供计算机信息管理一体化的服务,达到提高企业管理水平的目的。对出现故障的汽车进行修理然后把要修理的和修理好的情况都整理成册。(4)参考资料

简单文件系统的实现

第三章简单文件系统的实现 3.1 设计目的和内容要求 1. 设计目的 通过具体的文件存储空间的管理、文件的物理结构、目录结构和文件操作的实现,加深对文件系统内部数据结构、功能以及实现过程的理解。 2.内容要求 (1)在内存中开辟一个虚拟磁盘空间作为文件存储分区,在其上实现一个简单的基于多级目录的单用户单任务系统中的文件系统。在退出该文件系统的使用时,应将该虚拟文件系统以一个Windows 文件的方式保存到磁盘上,以便下次可以再将它恢复到内存的虚拟磁盘空间中。 (2)文件存储空间的分配可采用显式链接分配或其他的办法。 (3)空闲磁盘空间的管理可选择位示图或其他的办法。如果采用位示图来管理文件存储空间,并采用显式链接分配方式,那么可以将位示图合并到FAT中。 (4)文件目录结构采用多级目录结构。为了简单起见,可以不使用索引结点,其中的每个目录项应包含文件名、物理地址、长度等信息,还可以通过目录项实现对文件的读和写的保护。 (5)要求提供以下操作命令: my_format:对文件存储器进行格式化,即按照文件系统的结构对虚拟磁盘空间进行布局,并在其上创建根目录以及用于管理文件存储空间等的数据结构。 my_mkdir:用于创建子目录。 my_rmdir:用于删除子目录。 my_ls:用于显示目录中的内容。 my_cd:用于更改当前目录。 my_create:用于创建文件。 my_open:用于打开文件。 my_close:用于关闭文件。

my_write:用于写文件。 my_read:用于读文件。 my_rm:用于删除文件。 my_exitsys:用于退出文件系统。 3.学时安排 授课2学时,上机9学时。 4.开发平台 C或C++均可。 5.思考 (1)我们的数据结构中的文件物理地址信息是使用C语言的指针类型、还是整型,为什么? (2)如果引入磁盘索引结点,上述实现过程需要作哪些修改? (3)如果设计的是一个单用户多任务文件系统,则系统需要进行哪些扩充(尤其要考虑读写指针问题)?如果设计的是一个多用户文件系统,则又要进行哪些扩充? 3.2 预备知识 3.2.1 FAT文件系统介绍 1.概述 FAT文件系统是微软公司在其早期的操作系统MS-DOS及Windows9x中采用的文件系统,它被设计用来管理小容量的磁盘空间。FAT文件系统是以他的文件组织方式——文件分配表(file allocation table,FAT)命名的,文件分配表的每个表项中存放某文件的下一个盘块号,而该文件的起始盘块号则保存在它的文件控制块FCB中。在文件分配表中,一般用FFFF来标识文件的结束;用0000来标识某个逻辑块未被分配,即是空闲块。为了提高文件系统的可靠性,在逻辑磁盘上通常设置两张文件分配表,它们互为备份。此外,文件分配表必须存放在逻辑磁盘上的固定位置,而根目录区通常位于FAT2之后,以便操作系统在启动时能够定位所需的文件,其磁盘布局如图3-1所示: 引导块FAT1FAT2根目录区数据区

相关主题
文本预览
相关文档 最新文档