chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀(guān)看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

xv6的文件系統(tǒng)是如何實(shí)現(xiàn)的

Linux閱碼場(chǎng) ? 來(lái)源:Rand ? 作者:Rand ? 2021-10-12 18:00 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

文件系統(tǒng)

本文繼續(xù)來(lái)看 的文件系統(tǒng)部分, 將文件系統(tǒng)的設(shè)計(jì)分為 7 層: ,磁盤(pán)、緩存區(qū)、日志三個(gè)部分在前文已經(jīng)說(shuō)了,本文接著講述 ,目錄,路徑三個(gè)層次。

這部分的理論知識(shí)可以參考文章:捋一捋文件系統(tǒng)。本文直接來(lái)看 xv6 的文件系統(tǒng)這部分是如何實(shí)現(xiàn)的。

文件系統(tǒng)布局

再來(lái)系統(tǒng)的看看 xv6 文件系統(tǒng)的布局圖:

a8cd53e4-22a0-11ec-82a8-dac502259ad0.png

這個(gè)圖與 文檔給出的布局圖有些不一樣,主要是日志區(qū)的位置變化了。 文檔給出的布局圖日志區(qū)位于文件系統(tǒng)的末尾,但是根據(jù)源碼來(lái)看日志區(qū)應(yīng)該是位于超級(jí)塊后面的。前文直接用的 文檔中的圖,應(yīng)該是有誤的,實(shí)在抱歉。我看了幾個(gè)版本的 源碼和文檔,源碼是日志區(qū)都是安排在超級(jí)塊后面,而文檔的布局圖描述的是將日志區(qū)放在末尾。不過(guò)這不是重點(diǎn),不影響咱們理解,不管位于哪兒,在超級(jí)塊中做相應(yīng)修改就行。

引導(dǎo)塊、超級(jí)塊

第 0 塊是引導(dǎo)塊,里面存放的啟動(dòng)程序也就是 ,詳見(jiàn)前文:實(shí)例講解多處理器下的計(jì)算機(jī)啟動(dòng)

第 1 塊是超級(jí)塊,存有文件系統(tǒng)的元信息,相關(guān)結(jié)構(gòu)體定義如下:

structsuperblock{
uintsize;//Sizeoffilesystemimage(blocks)文件系統(tǒng)大小,也就是一共多少塊
uintnblocks;//Numberofdatablocks數(shù)據(jù)塊數(shù)量
uintninodes;//Numberofinodes.//i結(jié)點(diǎn)數(shù)量
uintnlog;//Numberoflogblocks//日志塊數(shù)量
uintlogstart;//Blocknumberoffirstlogblock//第一個(gè)日志塊塊號(hào)
uintinodestart;//Blocknumberoffirstinodeblock//第一個(gè)i結(jié)點(diǎn)所在塊號(hào)
uintbmapstart;//Blocknumberoffirstfreemapblock//第一個(gè)位圖塊塊號(hào)
};

可以看出超級(jí)塊實(shí)則就是文件系統(tǒng)布局的信息集合。在 中我們可以知道:

#defineNINODES200
#defineMAXOPBLOCKS10
#defineLOGSIZE(MAXOPBLOCKS*3)
#defineFSSIZE1000
#defineIPB(BSIZE/sizeof(structdinode))


intnbitmap=FSSIZE/(BSIZE*8)+1;
intninodeblocks=NINODES/IPB+1;
intnlog=LOGSIZE;

intnmeta=2+nlog+ninodeblocks+nbitmap;
intnblocks=FSSIZE-nmeta;

intlogstart=2;
intinodestart=2+nlog;
intbmapstart=2+nlog+ninodeblocks;

從上述代碼可以看出,文件系統(tǒng)的各個(gè)部分從哪開(kāi)始,到哪結(jié)束都是可以明確計(jì)算出來(lái)的,所以其實(shí)不管將日志區(qū)安排在哪,我們都可以從超級(jí)塊中獲取相應(yīng)的位置大小信息。

數(shù)據(jù)區(qū)

緊接著超級(jí)塊的區(qū)域應(yīng)該是 ,但是 的內(nèi)容有些多有些復(fù)雜,我們放在后面講,先來(lái)看看數(shù)據(jù)區(qū)中數(shù)據(jù)塊的組織與管理。

數(shù)據(jù)塊的分配和釋放由位圖來(lái)管理,但位圖管理的區(qū)域不止數(shù)據(jù)區(qū),而是整個(gè)文件系統(tǒng)。有關(guān)位圖的宏定義如下:

//Bitmapbitsperblock每個(gè)塊能有多少個(gè)bit
#defineBPB(BSIZE*8)
//Blockoffreemapcontainingbitforblockb塊b在哪個(gè)位圖塊上
#defineBBLOCK(b,sb)(b/BPB+sb.bmapstart)

分配回收

staticuintballoc(uintdev)
{
intb,bi,m;
structbuf*bp;

bp=0;
for(b=0;b//讀取位圖信息
for(bi=0;bi1<8);
if((bp->data[bi/8]&m)==0){//Isblockfree?如果該塊空閑
bp->data[bi/8]|=m;//Markblockinuse.標(biāo)記該塊使用
log_write(bp);
brelse(bp);//釋放鎖
bzero(dev,b+bi);//將該塊置0
returnb+bi;//返回塊號(hào)
}
}
brelse(bp);//釋放鎖
}
panic("balloc:outofblocks");
}

staticvoidbfree(intdev,uintb)//釋放一個(gè)數(shù)據(jù)塊,相應(yīng)位圖清零
{
structbuf*bp;
intbi,m;

bp=bread(dev,BBLOCK(b,sb));
bi=b%BPB;
m=1<8);
if((bp->data[bi/8]&m)==0)
panic("freeingfreeblock");
bp->data[bi/8]&=~m;
log_write(bp);
brelse(bp);
}

位圖塊中每一位都代表著一塊,該位置 1 表示相應(yīng)的塊正在使用,該位置 0 表示相應(yīng)的塊空閑。分配數(shù)據(jù)塊就是在位圖中尋找空閑位,然后將其置 1 就代表分配出去了。

上述代碼涉及的都是比較簡(jiǎn)單的位運(yùn)算,有詳細(xì)的注釋?zhuān)筒徽f(shuō)明了,釋放一個(gè)數(shù)據(jù)塊的操作就是分配的逆操作,也不再贅述。

inode

磁盤(pán)上的 dinode

緊接著超級(jí)塊后面的區(qū)域是 區(qū)域, 定義的 共有 200 個(gè),每個(gè)磁盤(pán)上的 定義如下:

structdinode{
shorttype;//Filetype
shortmajor;//Majordevicenumber(T_DEVonly)
shortminor;//Minordevicenumber(T_DEVonly)
shortnlink;//Numberoflinkstoinodeinfilesystem
uintsize;//Sizeoffile(bytes)
uintaddrs[NDIRECT+1];//Datablockaddresses
};
#defineNDIRECT12

表示該 指向的文件的類(lèi)型,在 里面就只有三種類(lèi)型,普通文件,目錄文件,設(shè)備文

表示該文件的鏈接數(shù),鏈接分為硬鏈接和軟連接,這里與鏈接數(shù)目直接相關(guān)的是硬鏈接,后面實(shí)現(xiàn)文件系統(tǒng)調(diào)用的時(shí)候我們會(huì)看到, 系統(tǒng)調(diào)用會(huì)創(chuàng)建一個(gè)新目錄項(xiàng)并且增加一個(gè)鏈接數(shù)。 系統(tǒng)調(diào)用將鏈接數(shù)減 1,如果該文件在內(nèi)存中的引用數(shù)和鏈接數(shù)都為 0 的話(huà),則會(huì)刪除該文件。這部分咱們后面再慢慢聊,本文只捎帶提一下。

表示文件的大小,這里是以字節(jié)為單位。

在 里面使用 和 來(lái)區(qū)分設(shè)備,同一類(lèi)設(shè)備有著相同的 , 又表示該類(lèi)設(shè)備中具體的某設(shè)備。后面我們會(huì)看到如果文件類(lèi)型為設(shè)備,則讀寫(xiě)的時(shí)候會(huì)根據(jù) 調(diào)用相應(yīng)設(shè)備的讀寫(xiě)程序。

每個(gè) 有 11 個(gè)一級(jí)指針,一個(gè)間接指針,用來(lái)指向數(shù)據(jù)塊。這些都是可以改變的, 有個(gè)關(guān)于支持大文件的實(shí)現(xiàn)就是要增加一個(gè)間接索引來(lái)實(shí)現(xiàn)。

inode 緩存

磁盤(pán)上的 在內(nèi)存中也有相應(yīng)的緩存:

struct{
structspinlocklock;
structinodeinode[NINODE];
}icache;//磁盤(pán)上i結(jié)點(diǎn)在內(nèi)存中的緩存

內(nèi)存中的 定義如下:

structinode{
uintdev;//Devicenumber設(shè)備號(hào)
uintinum;//Inodenumberinode號(hào)
intref;//Referencecount引用數(shù)
structsleeplocklock;//protectseverythingbelowhere
intvalid;//inodehasbeenreadfromdisk?是否有效

shorttype;//copyofdiskinode
shortmajor;
shortminor;
shortnlink;
uintsize;
uintaddrs[NDIRECT+1];
};

內(nèi)存中的 比磁盤(pán)上的 多了幾個(gè)屬性,首先是設(shè)備號(hào), 里面一切皆文件,設(shè)備也是文件,所以設(shè)備號(hào)來(lái)表示什么設(shè)備。但是 xv6 沒(méi)這么復(fù)雜,這里主要就是來(lái)區(qū)分磁盤(pán)的主盤(pán)和從盤(pán)。時(shí)為從盤(pán), 時(shí)為主盤(pán),這個(gè)值在讀寫(xiě)磁盤(pán)的時(shí)候用到,用它來(lái)設(shè)置磁盤(pán)的 device 寄存器來(lái)指定主盤(pán)從盤(pán)。詳見(jiàn):帶你了解磁盤(pán)驅(qū)動(dòng)程序

表示引用數(shù),這個(gè)要與 鏈接數(shù)作區(qū)別,目前可以暫且理解為 為磁盤(pán)上文件之間的關(guān)系,而 主要用于內(nèi)存中引用該文件的次數(shù),比如 關(guān)閉文件使引用數(shù)減 1。這部分在文件系統(tǒng)調(diào)用的時(shí)候再作詳細(xì)講解。

表示是否有效,跟磁盤(pán)那里緩存塊中的數(shù)據(jù)是否有效一個(gè)意思,如果緩存中的數(shù)據(jù)是從磁盤(pán)中讀取過(guò)來(lái)的,則有效。通常無(wú)效是因?yàn)?剛分配,所以里面的數(shù)據(jù)無(wú)效。

整個(gè) 緩存區(qū)有一把自旋鎖,每個(gè) 緩存有把休眠鎖,為什么如此,道理還是同磁盤(pán)和緩存塊。首先它們都是公共資源,需要鎖來(lái)避免競(jìng)爭(zhēng)條件。再者 的作用就是組織管理 ,像是一個(gè)分配器,訪(fǎng)問(wèn) 的臨界區(qū)的時(shí)間是很短的,使用自旋鎖就行。而一個(gè)進(jìn)程對(duì)某個(gè) 的使用時(shí)間可能很長(zhǎng),最好使用休眠鎖,其他進(jìn)程也想要獲取該 的使用權(quán)時(shí)就休眠讓出 提高性能。

分配 inode

對(duì)于磁盤(pán)上的 , 并沒(méi)有什么組織管理結(jié)構(gòu),分配空閑 的方法就是簡(jiǎn)單粗暴地從頭至尾循環(huán)查找空閑 。

structinode*
ialloc(uintdev,shorttype)
{
intinum;
structbuf*bp;
structdinode*dip;

for(inum=1;inum//讀取第inum個(gè)i結(jié)點(diǎn)所在的位置
dip=(structdinode*)bp->data+inum%IPB;//該i結(jié)點(diǎn)地址
if(dip->type==0){//afreeinode找到空閑i結(jié)點(diǎn)
memset(dip,0,sizeof(*dip));
dip->type=type;
log_write(bp);//markitallocatedonthedisk
brelse(bp);
returniget(dev,inum);//以?xún)?nèi)存中的i結(jié)點(diǎn)形式返回
}
brelse(bp);
}
panic("ialloc:noinodes");
}

#defineIBLOCK(i,sb)((i)/IPB+sb.inodestart)
#defineIPB(BSIZE/sizeof(structdinode))

先來(lái)看看下面兩個(gè)宏定義, 表示一個(gè)塊中能有幾個(gè) , 表示第 個(gè) 在第幾塊。

分配數(shù)據(jù)塊的時(shí)候有位圖來(lái)組織管理,所以分配數(shù)據(jù)塊的時(shí)候就“從頭至尾”的查詢(xún)空閑位,而 沒(méi)有組織管理的機(jī)制,所以就直接從頭至尾的查詢(xún) 的使用情況。如果該 的 屬性為 0 表示該 空閑,可以分配,反之正是用當(dāng)中不可分配。

分配了之后將該 初始化,將其數(shù)據(jù)全部置 0,然后賦其 屬性,表示該 指向一個(gè) 類(lèi)型的文件。

分配了該 需要在磁盤(pán)上也將其標(biāo)記為已分配,因?yàn)槟壳笆窃趦?nèi)存中操作的,得同步到磁盤(pán)上去,所以直接調(diào)用 將該 所在的緩存塊同步到磁盤(pán)。當(dāng)然并未真正地直接寫(xiě)到磁盤(pán)了,只是在將該緩存數(shù)據(jù)標(biāo)記為臟,關(guān)于日志,讀寫(xiě)磁盤(pán)的操作本文不贅述了,可以參考前文:如何實(shí)現(xiàn)一個(gè)簡(jiǎn)單的日志系統(tǒng)

回到分配 的函數(shù)上來(lái),磁盤(pán)上的 已分配,得到了 號(hào),但是文件系統(tǒng)實(shí)際工作的時(shí)候使用的是內(nèi)存中的 緩存,所以調(diào)用 來(lái)分配(獲取)一個(gè)內(nèi)存中的 來(lái)緩存 數(shù)據(jù):

staticstructinode*iget(uintdev,uintinum)
{
structinode*ip,*empty;

acquire(&icache.lock);

//Istheinodealreadycached?如果該dinode在內(nèi)存中已緩存
empty=0;
for(ip=&icache.inode[0];ipif(ip->ref>0&&ip->dev==dev&&ip->inum==inum){//在緩存中找到該i結(jié)點(diǎn)
ip->ref++;//引用加1
release(&icache.lock);
returnip;
}
if(empty==0&&ip->ref==0)//Rememberemptyslot.記錄icache中空閑的inode
empty=ip;
}

//Recycleaninodecacheentry.
if(empty==0)
panic("iget:noinodes");
//該dinode在內(nèi)存中沒(méi)有緩存,分配一個(gè)空閑inodeempty
//根據(jù)參數(shù),初始化該空閑inode,還沒(méi)讀入數(shù)據(jù),valid設(shè)為0
ip=empty;
ip->dev=dev;
ip->inum=inum;
ip->ref=1;
ip->valid=0;
release(&icache.lock);

returnip;
}

如果磁盤(pán)上的 在 中已有緩存,那么直接將該 的引用數(shù)加 1,再返回該 就行。如果沒(méi)有緩存則分配一個(gè)空閑的 ,根據(jù)參數(shù)初始化 ,因?yàn)闆](méi)有實(shí)際讀入 的數(shù)據(jù),所以 的 屬性置 0 表示無(wú)效。

使用修改 inode

使用 之前需要加鎖:

voidilock(structinode*ip)
{
structbuf*bp;
structdinode*dip;

if(ip==0||ip->ref1)//空指針引用小于1都是錯(cuò)誤的
panic("ilock");

acquiresleep(&ip->lock);//上鎖

if(ip->valid==0){//有效位為0,從磁盤(pán)讀入數(shù)據(jù)
bp=bread(ip->dev,IBLOCK(ip->inum,sb));
dip=(structdinode*)bp->data+ip->inum%IPB;
ip->type=dip->type;
ip->major=dip->major;
ip->minor=dip->minor;
ip->nlink=dip->nlink;
ip->size=dip->size;
memmove(ip->addrs,dip->addrs,sizeof(ip->addrs));
brelse(bp);
ip->valid=1;
if(ip->type==0)
panic("ilock:notype");
}
}

分配 的時(shí)候并未從磁盤(pán)中 讀入數(shù)據(jù),只是將 的 置 0 表示數(shù)據(jù)無(wú)效,正式讀入 數(shù)據(jù)在這加鎖的時(shí)候進(jìn)行。

對(duì)緩存中 的修改需要同步到磁盤(pán)上的 :

voidiupdate(structinode*ip)
{
structbuf*bp;
structdinode*dip;

bp=bread(ip->dev,IBLOCK(ip->inum,sb));//讀取磁盤(pán)上的i結(jié)點(diǎn)
dip=(structdinode*)bp->data+ip->inum%IPB;
dip->type=ip->type;//update
dip->major=ip->major;
dip->minor=ip->minor;
dip->nlink=ip->nlink;
dip->size=ip->size;
memmove(dip->addrs,ip->addrs,sizeof(ip->addrs));
log_write(bp);
brelse(bp);
}

用完 需要 “放下” 它:

voidiput(structinode*ip)
{
acquiresleep(&ip->lock);//取鎖
if(ip->valid&&ip->nlink==0){
//獲取該i結(jié)點(diǎn)的引用數(shù)
acquire(&icache.lock);
intr=ip->ref;
release(&icache.lock);

if(r==1){
//inodehasnolinksandnootherreferences:truncateandfree.
itrunc(ip);
ip->type=0;
iupdate(ip);
ip->valid=0;
}
}
releasesleep(&ip->lock);

acquire(&icache.lock);
ip->ref--;
release(&icache.lock);
}

該函數(shù)將 的引用數(shù)減 1,如果本身就是該 的最后一個(gè)引用,且鏈接數(shù)也為 0,那么調(diào)用 將該 指向的所有數(shù)據(jù)塊全部釋放,也就相當(dāng)于刪除了 指向的文件

表示該 已釋放,被回收到了 。將 信息更新到磁盤(pán)上的 之后將 置 0 表數(shù)據(jù)不再有效。

索引

的索引部分用來(lái)指向數(shù)據(jù)塊

staticuintbmap(structinode*ip,uintbn)//給i結(jié)點(diǎn)第bn個(gè)索引指向的地方分配塊
{
uintaddr,*a;
structbuf*bp;

//bn為直接索引
if(bn//如果第bn個(gè)索引指向的塊還未分配,則分配,否則返回塊號(hào)
if((addr=ip->addrs[bn])==0)
ip->addrs[bn]=addr=balloc(ip->dev);
returnaddr;
}

bn-=NDIRECT;//bn為間接索引

if(bn//Loadindirectblock,allocatingifnecessary.
if((addr=ip->addrs[NDIRECT])==0)//如果間接索引所在的塊還未分配,分配
ip->addrs[NDIRECT]=addr=balloc(ip->dev);
bp=bread(ip->dev,addr);//讀取一級(jí)索引塊
a=(uint*)bp->data;
if((addr=a[bn])==0){//如果該索引指向的塊還未分配,分配
a[bn]=addr=balloc(ip->dev);
log_write(bp);
}
brelse(bp);
returnaddr;//返回索引bn指向的塊的塊號(hào)
}

panic("bmap:outofrange");
}

返回索引 指向的數(shù)據(jù)塊塊號(hào),如果該數(shù)據(jù)塊未分配,則分配之后再返回該塊塊號(hào)。

staticvoiditrunc(structinode*ip)
{
inti,j;
structbuf*bp;
uint*a;

for(i=0;i//釋放直接索引指向的數(shù)據(jù)塊
if(ip->addrs[i]){
bfree(ip->dev,ip->addrs[i]);
ip->addrs[i]=0;
}
}

if(ip->addrs[NDIRECT]){
bp=bread(ip->dev,ip->addrs[NDIRECT]);//讀取一級(jí)索引塊
a=(uint*)bp->data;
for(j=0;j//釋放一級(jí)索引指向的塊
if(a[j])
bfree(ip->dev,a[j]);
}
brelse(bp);
bfree(ip->dev,ip->addrs[NDIRECT]);//釋放一級(jí)索引塊
ip->addrs[NDIRECT]=0;
}

ip->size=0;
iupdate(ip);
}

,截?cái)?,不知怎樣翻譯,但這個(gè)函數(shù)的實(shí)際工作就是將 所指向的數(shù)據(jù)塊全部釋放,也就相當(dāng)于刪除文件了。具體的工作方式就是一個(gè)個(gè)的判斷索引是否有效,如果有效就調(diào)用 釋放,然后將該索引置為無(wú)效?;旧暇团c 做相反的工作。

讀寫(xiě)數(shù)據(jù)

intreadi(structinode*ip,char*dst,uintoff,uintn)//從inode讀取數(shù)據(jù)
{
uinttot,m;
structbuf*bp;

if(ip->type==T_DEV){//如果該inode指向的是設(shè)備文件
if(ip->major0||ip->major>=NDEV||!devsw[ip->major].read)
return-1;
returndevsw[ip->major].read(ip,dst,n);//使用設(shè)備特有的讀取方式
}

if(off>ip->size||off+n//如果開(kāi)始讀取的位置超過(guò)文件末尾,如果讀取的字節(jié)數(shù)是負(fù)數(shù)
return-1;
if(off+n>ip->size)//如果從偏移量開(kāi)始的n字節(jié)超過(guò)文件末尾
n=ip->size-off;//則只能夠再讀取這么多字節(jié)

for(tot=0;tot//tol:目前總共已讀的字節(jié)數(shù),n:需要讀取的字節(jié)數(shù),off:從這開(kāi)始讀,dst:目的地
bp=bread(ip->dev,bmap(ip,off/BSIZE));//讀取off所在的數(shù)據(jù)塊到緩存塊
m=min(n-tot,BSIZE-off%BSIZE);//一次性最多讀取m字節(jié)
memmove(dst,bp->data+off%BSIZE,m);//賦值數(shù)據(jù)到dst
brelse(bp);//釋放緩存塊
}
returnn;
}

intwritei(structinode*ip,char*src,uintoff,uintn)
{
uinttot,m;
structbuf*bp;

if(ip->type==T_DEV){
if(ip->major0||ip->major>=NDEV||!devsw[ip->major].write)
return-1;
returndevsw[ip->major].write(ip,src,n);
}

if(off>ip->size||off+nreturn-1;
if(off+n>MAXFILE*BSIZE)
return-1;

for(tot=0;totdev,bmap(ip,off/BSIZE));
m=min(n-tot,BSIZE-off%BSIZE);
memmove(bp->data+off%BSIZE,src,m);
log_write(bp);
brelse(bp);
}

函數(shù)用來(lái)讀取數(shù)據(jù),從 ip 指向的文件中,從 開(kāi)始讀,讀取 字節(jié)到 中去。

如果 指向的文件類(lèi)型是設(shè)備,那么讀取數(shù)據(jù)要使用專(zhuān)門(mén)的讀取方式,比如說(shuō)控制臺(tái)有著自己專(zhuān)門(mén)的讀入數(shù)據(jù)方式,這些設(shè)備的讀取方法集合在 數(shù)組當(dāng)中。關(guān)于這部分我們后面的文章再詳述,這里只說(shuō)磁盤(pán)上的文件的讀寫(xiě)。

緊接著判斷了一下參數(shù)的合理性,比如 不應(yīng)超過(guò)文件末尾,讀取的字節(jié)數(shù) 不應(yīng)該是負(fù)數(shù),如果 超過(guò)了文件末尾,那么最多只能讀取 個(gè)字節(jié)數(shù),要修改 的值。

文件數(shù)據(jù)可能有多塊, 表示 所在的塊數(shù),這個(gè)塊數(shù)是相對(duì)于該文件開(kāi)頭的塊號(hào),調(diào)用 獲取 所在的絕對(duì)塊號(hào)。拿到 所在數(shù)據(jù)塊的絕對(duì)塊號(hào)之后調(diào)用 讀取該數(shù)據(jù)塊的數(shù)據(jù)到緩存塊 。

數(shù)據(jù)在內(nèi)存中已經(jīng)準(zhǔn)備完畢,可以賦值移動(dòng)數(shù)據(jù)了。但是每次讀取的數(shù)據(jù)有上限,不能超過(guò) ,這是還需要讀取的字節(jié)數(shù),不能超過(guò) ,這是每次最多能夠讀取的字節(jié)數(shù)。不能超過(guò)這兩者,所以?xún)烧咧腥≥^小值。

,將數(shù)據(jù)源 中的數(shù)據(jù)寫(xiě) 字節(jié)到 指向的文件中,從偏移量為 的地方開(kāi)始寫(xiě)。

基本上是與 相反的操作,只是最后需要更新 信息,因?yàn)橄裎募袑?xiě)數(shù)據(jù),該文件會(huì)變大, 是文件的代表與文件一一對(duì)應(yīng),需要更新 的 size 屬性,然后再調(diào)用 將 同步到磁盤(pán)上的 。

目錄

目錄也是文件,只是它的數(shù)據(jù)有些特殊,其數(shù)據(jù)是一個(gè)個(gè)目錄項(xiàng),其主要屬性有文件名, 編號(hào)。

是一個(gè)文件的代言人,一個(gè)文件與一個(gè) 一一對(duì)應(yīng),但是 的屬性里面并沒(méi)有文件名。文件名這個(gè)屬性在目錄項(xiàng)這指出,目錄項(xiàng)的主要作用就是將 和文件名聯(lián)系起來(lái)。

結(jié)構(gòu)定義

structdirent{//目錄項(xiàng)結(jié)構(gòu)
ushortinum;
charname[DIRSIZ];
};

#defineDIRSIZ14

中目錄項(xiàng)只由兩項(xiàng)組成,文件名和 編號(hào)。

查找目錄項(xiàng)

structinode*dirlookup(structinode*dp,char*name,uint*poff)
{
uintoff,inum;
structdirentde;

if(dp->type!=T_DIR)//如果該文件不是目錄文件
panic("dirlookupnotDIR");

for(off=0;offsize;off+=sizeof(de)){
if(readi(dp,(char*)&de,off,sizeof(de))!=sizeof(de))//讀取dp指向的目錄文件,每次讀一個(gè)目錄項(xiàng)
panic("dirlookupread");
if(de.inum==0)//如果是根目錄??????????????
continue;
if(namecmp(name,de.name)==0){//根據(jù)名字找文件
//entrymatchespathelement
if(poff)//記錄該目錄項(xiàng)在目錄中的偏移
*poff=off;
inum=de.inum;//name文件的inode編號(hào)
returniget(dp->dev,inum);//或取該inode
}
}

return0;
}

這個(gè)函數(shù)用來(lái)在 指向的目錄文件下尋找名為 的目錄項(xiàng),將該目錄項(xiàng)的偏移量記錄在 中,最后返回名字為 的文件的 。

因此根據(jù)文件名查找文件的是指就是在目錄文件中查找目錄項(xiàng)的過(guò)程,具體的查找方式就是一個(gè)個(gè)的比對(duì)目錄項(xiàng)的名稱(chēng)和要查找的文件名是否相同,如果相同,則找到,反之說(shuō)明該目錄下并沒(méi)有要查找的文件。

添加目錄項(xiàng)

intdirlink(structinode*dp,char*name,uintinum)
{
intoff;
structdirentde;
structinode*ip;

//Checkthatnameisnotpresent.
if((ip=dirlookup(dp,name,0))!=0){
iput(ip);//dirlookup調(diào)用iget使引用數(shù)加1,所以調(diào)用iput使引用數(shù)減1
return-1;//name目錄項(xiàng)已存在,返回-1
}

//Lookforanemptydirent.
for(off=0;offsize;off+=sizeof(de)){
if(readi(dp,(char*)&de,off,sizeof(de))!=sizeof(de))
panic("dirlinkread");
if(de.inum==0)//找到一個(gè)空閑目錄項(xiàng)
break;
}

strncpy(de.name,name,DIRSIZ);//設(shè)置目錄項(xiàng)的文件名字
de.inum=inum;//設(shè)置目錄項(xiàng)的i結(jié)點(diǎn)編號(hào)
if(writei(dp,(char*)&de,off,sizeof(de))!=sizeof(de))//將該目錄項(xiàng)寫(xiě)進(jìn)dp指向的目錄文件中
panic("dirlink");

return0;
}

此函數(shù)用來(lái)在 指向的目錄文件中添加一個(gè)目錄項(xiàng),通常是創(chuàng)建了一個(gè)新文件,需要在該目錄下添加這個(gè)新文件的信息

首先查找該目錄項(xiàng)是否存在,如果不存在則找一個(gè)空閑目錄項(xiàng)位置,將新文件的 和文件名寫(xiě)進(jìn)去。

路徑

路徑,何為路徑,比如常見(jiàn)的 ,仔細(xì)觀(guān)察,會(huì)發(fā)現(xiàn),路徑實(shí)則是一個(gè)個(gè)文件名組成的,這個(gè)文件可能是目錄文件,也可能是普通文件。一般最后一項(xiàng)是普通文件名,中間的都是目錄文件名

另外像 這種路徑以 '/' 開(kāi)頭表示絕對(duì)路徑, 這種不以 '/' 開(kāi)頭的表示相對(duì)路徑。這兩種路徑大家應(yīng)該都很熟悉了,不再多做解釋?zhuān)蛘呖梢詤⒖嘉恼?a target="_blank">捋一捋文件系統(tǒng),其中詳細(xì)的捋了捋文件系統(tǒng)的理論知識(shí)。

不論哪一種路徑表示,都需要一個(gè)路徑解析函數(shù),將其中一個(gè)個(gè)文件名給提取出來(lái):

staticchar*skipelem(char*path,char*name)
{
char*s;
intlen;

while(*path=='/')//跳過(guò)'/'
path++;
if(*path==0)//路徑空
return0;
s=path;
while(*path!='/'&&*path!=0)//path繼續(xù)向后移,剝出最前面的目錄名
path++;
len=path-s;//記錄該目錄名的長(zhǎng)度
if(len>=DIRSIZ)
memmove(name,s,DIRSIZ);//將該目錄名復(fù)制給name
else{
memmove(name,s,len);
name[len]=0;
}
while(*path=='/')//繼續(xù)跳過(guò)'/'
path++;
returnpath;//返回剩下的路徑
}

調(diào)用一次解析一個(gè)頭部的文件名放在 中,返回剩下的路徑。

用源碼注釋中的例子來(lái)說(shuō)明:

skipelem("a/bb/c",name)="bb/c",settingname="a"
skipelem("http:///a//bb",name)="bb",settingname="a"
skipelem("a",name)="",settingname="a"
skipelem("",name)=skipelem("http:////",name)=0
staticstructinode*
namex(char*path,intnameiparent,char*name)
{
structinode*ip,*next;

if(*path=='/')//絕對(duì)路徑
ip=iget(ROOTDEV,ROOTINO);//讀取根目錄
else//相對(duì)路徑
ip=idup(myproc()->cwd);//讀取當(dāng)前工作目錄

while((path=skipelem(path,name))!=0){
ilock(ip);
if(ip->type!=T_DIR){
iunlockput(ip);
return0;
}
if(nameiparent&&*path==''){//如果是要返回父結(jié)點(diǎn),并且剩下的路徑已經(jīng)為空,則當(dāng)前結(jié)點(diǎn)就是i結(jié)點(diǎn)直接返回
//Stoponelevelearly.
iunlock(ip);
returnip;
}
if((next=dirlookup(ip,name,0))==0){//查詢(xún)下一個(gè)目錄
iunlockput(ip);
return0;
}
iunlockput(ip);
ip=next;//當(dāng)前目錄指向下一個(gè),然后while循環(huán),直到解析到最后
}
if(nameiparent){
iput(ip);
return0;
}
returnip;
}

這個(gè)函數(shù)根據(jù)路徑返回 ,比如說(shuō)路徑 ,如果 有效,則返回文件 的 ,如果 無(wú)效,則返回文件 的 。

這個(gè)函數(shù)主要是對(duì)路徑解析函數(shù) 和查找目錄項(xiàng)函數(shù) 函數(shù)的運(yùn)用,根據(jù)路徑查找文件的步驟大致如下:

  • 獲取當(dāng)前目錄的
  • 根據(jù) 獲取目錄文件
  • 在該目錄文件下根據(jù)文件名查找文件/目錄
  • 循環(huán)上述過(guò)程直到文件被找到

函數(shù)就是上述過(guò)程的實(shí)現(xiàn),至于這個(gè)函數(shù)的具體怎么實(shí)現(xiàn)的,就不詳細(xì)說(shuō)明了,可以自己舉個(gè)例子根據(jù)代碼模擬一下過(guò)程就明白了。在模擬的過(guò)程中主要注意幾個(gè)條件判斷:

  • (path = skipelem(path, name)) != 0,當(dāng) 為空字符串的才返回 0,也就是說(shuō) skipelem("", name) = 0。path 指向一個(gè)空字符串,并不是說(shuō) path 本身為空
  • if(nameiparent && *path == ''), 為空字符串的時(shí)候也就是 "" 的時(shí)候 *path = ''。

另外如果是相對(duì)路徑的話(huà),當(dāng)前目錄需要從進(jìn)程 中的 屬性中獲取,相關(guān)內(nèi)容后面進(jìn)程再詳述。

本文主要介紹了 文件系統(tǒng) ,目錄,路徑三個(gè)層次的設(shè)計(jì)與實(shí)現(xiàn),應(yīng)該對(duì)這三個(gè)概念會(huì)有個(gè)更深刻的認(rèn)識(shí)。 是文件的代表,與文件一一對(duì)應(yīng),目錄也是文件,只是其數(shù)據(jù)是其他文件的信息,也就是一個(gè)個(gè)目錄項(xiàng)。目錄項(xiàng)是其他文件的文件名和相應(yīng)的 編號(hào)組合而成。而路徑呢?就是一個(gè)個(gè)文件名組合在一起的字符串??梢允褂寐窂浇馕龊瘮?shù)將一個(gè)個(gè)文件名解析出來(lái),然后根據(jù)一層層目錄中的目錄項(xiàng)從上至下地查找文件

好啦本文就到這里了,有什么錯(cuò)誤還請(qǐng)批評(píng)指針,也歡迎大家來(lái)同我討論交流一起學(xué)習(xí)進(jìn)步。

責(zé)任編輯:haq
聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀(guān)點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 文件
    +關(guān)注

    關(guān)注

    1

    文章

    586

    瀏覽量

    25799
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4922

    瀏覽量

    72237

原文標(biāo)題:inode、目錄、路徑

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    技術(shù)貼|【RK3588】ELF 2開(kāi)發(fā)板如何添加exFAT和NTFS文件系統(tǒng)格式

    如何通過(guò)系統(tǒng)配置實(shí)現(xiàn)對(duì)該兩種文件系統(tǒng)的支持,并配置自動(dòng)掛載功能。Windows系統(tǒng)格式化存儲(chǔ)設(shè)備在使用TF卡前,需通過(guò)Windows自帶工具將其格式化為目標(biāo)
    的頭像 發(fā)表于 08-27 17:21 ?2972次閱讀
    技術(shù)貼|【RK3588】ELF 2開(kāi)發(fā)板如何添加exFAT和NTFS<b class='flag-5'>文件系統(tǒng)</b>格式

    Linux三大主流文件系統(tǒng)解析

    還在為選擇哪個(gè)文件系統(tǒng)而糾結(jié)?作為一名摸爬滾打多年的運(yùn)維老鳥(niǎo),我將用最接地氣的方式,帶你徹底搞懂 Linux 三大主流文件系統(tǒng)的奧秘。
    的頭像 發(fā)表于 08-05 17:37 ?864次閱讀

    飛凌嵌入式ElfBoard ELF 1板卡-文件系統(tǒng)簡(jiǎn)介

    文件系統(tǒng)Journalling Flash File System Version 2是一個(gè)可讀寫(xiě),壓縮,日志型文件系統(tǒng)。其功能是管理在MTD設(shè)備上實(shí)現(xiàn)的日志型文件系統(tǒng)。啟動(dòng)時(shí)間依賴(lài)于
    發(fā)表于 06-19 17:22

    服務(wù)器數(shù)據(jù)恢復(fù)—ocfs2文件系統(tǒng)被格式化為Ext4文件系統(tǒng)的數(shù)據(jù)恢復(fù)案例

    服務(wù)器存儲(chǔ)數(shù)據(jù)恢復(fù)環(huán)境&故障: 人為誤操作將Ext4文件系統(tǒng)誤裝入一臺(tái)服務(wù)器存儲(chǔ)上的Ocfs2文件系統(tǒng)數(shù)據(jù)卷上,導(dǎo)致原Ocfs2文件系統(tǒng)被格式化為Ext4文件系統(tǒng)。
    的頭像 發(fā)表于 06-10 12:03 ?399次閱讀
    服務(wù)器數(shù)據(jù)恢復(fù)—ocfs2<b class='flag-5'>文件系統(tǒng)</b>被格式化為Ext4<b class='flag-5'>文件系統(tǒng)</b>的數(shù)據(jù)恢復(fù)案例

    如何正確選擇嵌入式文件系統(tǒng)

    Linux嵌入式系統(tǒng)中,文件系統(tǒng)和緩存機(jī)制常導(dǎo)致數(shù)據(jù)存儲(chǔ)穩(wěn)定性問(wèn)題。本文通過(guò)案例分析原因,對(duì)比不同文件系統(tǒng)特性,為開(kāi)發(fā)者提供優(yōu)化建議,助力提升數(shù)據(jù)穩(wěn)定性和系統(tǒng)可靠性。前言基于Linux
    的頭像 發(fā)表于 03-17 11:35 ?711次閱讀
    如何正確選擇嵌入式<b class='flag-5'>文件系統(tǒng)</b>?

    在stm32cubeprogrammer上燒錄時(shí),取消勾選根文件系統(tǒng),燒錄后發(fā)現(xiàn)sd卡上根文件系統(tǒng)的分區(qū)沒(méi)有了,為什么?

    在修改了linux內(nèi)核后,我想只把bootfs燒錄到sd卡上,而不擦除根文件系統(tǒng)的分區(qū)。 我在stm32cubeprogrammer上燒錄時(shí),取消勾選根文件系統(tǒng),燒錄后發(fā)現(xiàn)sd卡上根文件系統(tǒng)的分區(qū)沒(méi)有了。
    發(fā)表于 03-07 06:38

    NFS網(wǎng)絡(luò)文件系統(tǒng)深度解析

    NFS:Network File System 網(wǎng)絡(luò)文件系統(tǒng),基于內(nèi)核的文件系統(tǒng)。Sun 公司開(kāi)發(fā),通過(guò)使用 NFS,用戶(hù)和程序可以像訪(fǎng)問(wèn)本地文件一樣訪(fǎng)問(wèn)遠(yuǎn)端系統(tǒng)上的
    的頭像 發(fā)表于 03-01 14:15 ?998次閱讀

    防止根文件系統(tǒng)破壞,OverlayRootfs 讓你的設(shè)備更安全

    多個(gè)文件系統(tǒng)層合并成一個(gè)單一的視圖,在Linux系統(tǒng)中廣泛應(yīng)用。使用OverlayRootfs的設(shè)備可以很輕松的實(shí)現(xiàn):根文件系統(tǒng)寫(xiě)保護(hù)、恢復(fù)出廠(chǎng)設(shè)置功能。根
    的頭像 發(fā)表于 01-08 16:33 ?2179次閱讀
    防止根<b class='flag-5'>文件系統(tǒng)</b>破壞,OverlayRootfs 讓你的設(shè)備更安全

    EE-289:在A(yíng)DSP-BF533 Blackfin處理器上實(shí)現(xiàn)FAT32文件系統(tǒng)

    電子發(fā)燒友網(wǎng)站提供《EE-289:在A(yíng)DSP-BF533 Blackfin處理器上實(shí)現(xiàn)FAT32文件系統(tǒng).pdf》資料免費(fèi)下載
    發(fā)表于 01-05 09:13 ?0次下載
    EE-289:在A(yíng)DSP-BF533 Blackfin處理器上<b class='flag-5'>實(shí)現(xiàn)</b>FAT32<b class='flag-5'>文件系統(tǒng)</b>

    關(guān)于更新openharmony文件系統(tǒng)時(shí)遇到的問(wèn)題

    用的固件,文件系統(tǒng),內(nèi)核是之前的,之前版本用起來(lái)沒(méi)問(wèn)題。但是 用下面三個(gè)的時(shí)候 固件可以正常燒錄,也按照文檔里面加載了環(huán)境變量,但是燒錄內(nèi)核和文件系統(tǒng)(都是U盤(pán)更新的)的時(shí)候出現(xiàn)了這樣的問(wèn)題
    發(fā)表于 12-30 11:55

    華納云:VFS在提升文件系統(tǒng)性能方面的具體實(shí)踐

    VFS(Virtual File System)通過(guò)提供統(tǒng)一的接口和抽象層,使得操作系統(tǒng)能夠以高效的方式管理和訪(fǎng)問(wèn)不同的文件系統(tǒng)。以下是一些VFS在提升文件系統(tǒng)性能方面的具體實(shí)踐示例: 統(tǒng)一的
    的頭像 發(fā)表于 11-27 15:59 ?1262次閱讀

    Jtti:Linux中虛擬文件系統(tǒng)和容器化的關(guān)系

    在Linux中,虛擬文件系統(tǒng)(VFS)和容器化技術(shù)之間有密切的關(guān)系。容器化是指通過(guò)使用容器來(lái)運(yùn)行應(yīng)用程序,而容器本質(zhì)上是在宿主機(jī)上運(yùn)行的獨(dú)立進(jìn)程,它們通常共享宿主機(jī)的操作系統(tǒng)內(nèi)核和部分文件系統(tǒng)
    的頭像 發(fā)表于 11-27 15:38 ?677次閱讀

    虛擬化數(shù)據(jù)恢復(fù)—UFS2文件系統(tǒng)數(shù)據(jù)恢復(fù)案例

    虛擬化數(shù)據(jù)恢復(fù)環(huán)境: SAN環(huán)境下通過(guò)iSCSI實(shí)現(xiàn)FreeNAS,F(xiàn)reeNAS采用的UFS2文件系統(tǒng)。物理存儲(chǔ)架構(gòu)在一臺(tái)服務(wù)器上,另外兩臺(tái)服務(wù)器上安裝ESXi虛擬化系統(tǒng)。整個(gè)存儲(chǔ)建立一個(gè)稀疏
    的頭像 發(fā)表于 11-11 11:02 ?845次閱讀

    stm32單片機(jī)基于rt-thread 的 littlefs 文件系統(tǒng) 的使用

    簡(jiǎn)介littlefs是ARM官方推出的,專(zhuān)為嵌入式系統(tǒng)設(shè)計(jì)的文件系統(tǒng),相比傳統(tǒng)的文件系統(tǒng),littlefs具有以下優(yōu)點(diǎn):1、自帶擦寫(xiě)均衡2、支持掉電保護(hù)3、占用的
    的頭像 發(fā)表于 11-06 08:04 ?3924次閱讀
    stm32單片機(jī)基于rt-thread 的 littlefs <b class='flag-5'>文件系統(tǒng)</b> 的使用

    服務(wù)器數(shù)據(jù)恢復(fù)—EXT3文件系統(tǒng)下誤刪除數(shù)據(jù)的恢復(fù)案例

    服務(wù)器數(shù)據(jù)恢復(fù)環(huán)境: 郵件服務(wù)器中有一組由8塊盤(pán)組成的RAID5陣列, 上層是Linux操作系統(tǒng)+EXT3文件系統(tǒng)。 服務(wù)器故障: 由于誤刪除導(dǎo)致文件系統(tǒng)中的郵件數(shù)據(jù)丟失。
    的頭像 發(fā)表于 10-23 15:11 ?638次閱讀
    服務(wù)器數(shù)據(jù)恢復(fù)—EXT3<b class='flag-5'>文件系統(tǒng)</b>下誤刪除數(shù)據(jù)的恢復(fù)案例