日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

深入理解Lustre文件系統(tǒng)-第6篇 OST和obdfilter

系統(tǒng) 2342 0

/* Sigh -really, this is an OSS, the _server_, not the _target_ */

static intost_setup(struct obd_device *obd, obd_count len, void *buf)

{ ... }

from Lustre source tree b16

如果我們正確地理解了上述注釋,Lustre源碼樹lustre/ost和所有的以ost_開頭的函數(shù)名可能都應(yīng)該作為服務(wù)器(OSS)函數(shù)。

6.1OSS 和OST

OST以內(nèi)核模塊的形式加載。它和obdfilter緊密合作,完成了服務(wù)器/OST端的大部分工作。在這兩層中,OSS是交換層(switch layer),或者薄層(thin layer),它解釋從Portal RPC來的請求,為請求做準備,然后將請求傳遞到obdfilter做進一步處理。在接下來的討論中,我們集中討論它的兩個方面:初始建立和交換結(jié)構(gòu),它們分別由ost_setup()和ost_handle()完成。

初始建立

  • 首先,OST檢查OSS的線程數(shù)是否確定了。如果沒有,則根據(jù)CPU和內(nèi)存計算最小線程數(shù),確保最大和最小線程數(shù)之間有四倍的動態(tài)范圍。

oss_min_threads= num_possible_cpus() * num_physpages >> (27 - CFS_PAGE_SHIFT);

if(oss_min_threads < OSS_THREADS_MIN)

oss_min_threads = OSS_THREADS_MIN;

/* Insure a 4xrange for dynamic threads */

if(oss_min_threads > OSS_THREADS_MAX / 4)

oss_min_threads = OSS_THREADS_MAX / 4;

oss_max_threads= min(OSS_THREADS_MAX, oss_min_threads * 4 + 1);

為了得到OST的obd設(shè)備,使用了如下的函數(shù)調(diào)用:

struct ost_obd*ost = &obd->u.ost;

  • 然后服務(wù)器端初始化RPC服務(wù),如下:

ost->ost_service= ptlrpc_init_svc( , , , , , , ost_handle, , , , "ll_ost");

這個函數(shù)返回指向結(jié)構(gòu)體ptlrpc_service的指針。這里需要指出的一個重要的事情是,我們已經(jīng)提供了一個處理函數(shù)ost_handle。一旦像下面所示的一樣,服務(wù)啟動了,Portal RPC將向這個處理函數(shù)派遣(dispatch)請求來做進一步處理。這是下一節(jié)中的內(nèi)容。

  • prtrpc線程開始,如下:

rc =ptlrpc_start_threads(obd, ost->ost_service);

重復執(zhí)行類似的調(diào)用序列,創(chuàng)建ost create線程,而服務(wù)處理函數(shù)設(shè)置為ost->ost_create_service。這個流程還為創(chuàng)建ost io線程而重復執(zhí)行,而服務(wù)處理函數(shù)設(shè)置為ost->ost_io_service。

最后,ping驅(qū)逐(eviction?)服務(wù)開始了。

派遣(dispatching)

處理函數(shù)使用一個輸入?yún)?shù)struct ptlrpc_request *req,而它大部分由請求的類型驅(qū)動。解碼請求的類型是通過將req->rq_reqmsg(它指向結(jié)構(gòu)體lustre_msg)傳遞到一個由Portal RPC提供的幫助函數(shù)lustre_msg_get_opc()來完成的。所以派遣的結(jié)構(gòu)類似于:

swtich(lsutre_msg_get_opc(req->rq_reqmsg)) {

case OST_CONNECT:

...

rc = target_handle_connect(req, ost_handle);

break;

case OST_CREATE:

...

rc = ost_create(req->rq_export, req, oti);

break;

case OST_WRITE:

...

rc = ost_brw_write(req, oti);

RETURN (rc);

case OST_READ:

...

rc = ost_brw_read(req, oti);

RETURN(rc);

}

意外處理包括可能出現(xiàn)的恢復,這種恢復可能在除了OST_CONNECT之外的任何請求中出現(xiàn)。另外,我們需要通過檢查req->rq_export是否為NULL來檢查連接是否從未知客戶端而來。

6.2 OSS 目錄布局

這節(jié)介紹當?shù)卿浀揭粋€OST節(jié)點上時,你將在磁盤中觀察到那些東西?,F(xiàn)在為止,磁盤中的文件系統(tǒng)最有可能是ldiskfs。這意味著后端數(shù)據(jù)實際上以普通文件的方式存儲,以一種Lustre特有的方法組織著:

組號

在OST的頂層目錄下是以各組命名的子目錄。這種布局容許了集群MDS的存在,而每個組對應(yīng)一個MDS。就目前來說,只使用一個MDS,所以只有第零組是有效的。

對象ID

在每個組里,創(chuàng)建了32個子目錄。對每個文件對象,它的最后五位用來表明這個文件應(yīng)該放置在哪個子目錄中。這里,文件名是對象ID。

6.3 obdfilter

obdfilter設(shè)備是在OST服務(wù)初始化的時候創(chuàng)建的。對每個OST我們有一個相對應(yīng)的obdfilter設(shè)備。對每個客戶端連接,obdfilter創(chuàng)建一個輸出口(export)作為輸出的管道。所有的輸出口都維護在一個全局哈希表中,哈希關(guān)鍵字稱為UUID,在Figure 10和11中都給出了。Portal RPC層使用UUID來快速確定到來的請求應(yīng)當送去哪個輸出口(和obdfilter設(shè)備)。另外,每個obdfilter設(shè)備維護一個它服務(wù)的輸出口鏈表。這種關(guān)系在Figure 10中畫出來了。

obdfilter提供了如下函數(shù):

  • 處理創(chuàng)建請求,該請求可能是來自于MDS的對文件數(shù)據(jù)對象的請求。
  • 處理讀取和限額如請求,該請求來自于OSC客戶端。
  • 處理連接和斷開連接請求,該請求是來自于低層Portal RPC層的,對已建立好的輸出口和輸入口的請求。
  • 處理銷毀請求(牽涉到客戶端和MDS兩方面)。

6.3.1文件刪除

銷毀協(xié)議如下所述。首先,客戶端決定刪除一個文件,而這個請求傳送到了MDS。MDS檢查了EA分條,并用llog產(chǎn)生了一個事務(wù)日志。這個日志包含如下:<從OST1中unlink對象1,從OST2中unlink對象2,等等>。然后MDS將布局和事務(wù)日志傳輸?shù)娇蛻舳???蛻舳说玫竭@個日志,并與每個OST(實際上是obdfilter)聯(lián)系,刪除(unlink)每個文件對象。一旦所有在MDS上的的刪除(unlink)llog記錄都已經(jīng)被告知,那么文件刪除過程就結(jié)束了。

6.3.2文件創(chuàng)建

正如早先在第5節(jié)所講的,所有的請求都由OST和obdfilter一起處理?,F(xiàn)在我們來理順處理創(chuàng)建請求的流程。處理請求的第一部分是在ost_create()進行了如下操作:

1. 準備回復消息的大小。這由兩個記錄組成,所以需要兩塊緩沖。第一個記錄是為portalrpc body準備的,而第二個是為ostreply body準備的。

__u32 size[2] ={ sizeof(struct ptlrpc_body), sizeof(*repbody)};

2. 從原始請求中取得一個請求體的指針,并在需要的時候進行字節(jié)交換。

struct ost_body*body = lustre_swab_reqbuf(req, REQ_REC_OFF,

sizeof(*body),lustre_swab_ost_body);

最后一個參數(shù)是swab處理函數(shù),只有在需要交換的時候才調(diào)用它??蛻舳说恼埱笫褂帽镜刈止?jié)序,里面包含一個預先商量好的魔數(shù)。服務(wù)器端讀取這個魔數(shù),并用以確定是否需要進行交換。

3. 進行實際的空間分配,并填入初步的頭信息。

rc =lustre_pack_replay(req, 2, size, NULL);

repbody =lustre_msg_buf(req->rq_repmsg, REPLY_REC_OFF,sizeof(*repbody));

在第一個調(diào)用之后,req->rq_repmsg()指向新分配的空間。第二個調(diào)用為回復體緩沖設(shè)置了開始地址的repbody。

4. 最后,它用與請求體完全一樣內(nèi)容填充回復體,然后傳給obdfilter做進一步處理。

memcpy(&repbody->oa,&body->oa, sizeof(body->oa));

req-rq_status =obd_create(exp, &repbody->oa, NULL, oti);

對于創(chuàng)建請求,obdfilter的入口點是通過filter_create():

static intfilter_create(struct obd_export *exp, struct obdo *oa ..).

我們忽略了牽涉到struct lov_stripe_md **ea和struct obd_trans_info *oti的處理過程,這是因為前者是遺留代碼,將來不大可能使用。

1. 首先,保存當前上下文,并指定客戶端的上下文為它自己的操作上下文。這是為讓線程在想要訪問后端文件系統(tǒng)時,為其確定必須的信息。這就像一個sandbox(?),限制在處理客戶端請求時,服務(wù)線程的reach(?)。它為服務(wù)線程存儲“文件系統(tǒng)根”和“當前工作目錄”(當然,不是從客戶端取得,而是取決于我們正在哪個個OST上工作)。

obd =exp->exp_obd;

put_ctxt(&saved,&obd->obd_lvfs_ctxt, NULL);

2. 如果請求的目的是重新創(chuàng)建一個對象,那么我們?nèi)∠屑釉谥亟▽ο笊系膃xtent鎖,取消方法是要求所有加在對象上的鎖調(diào)用filter_recreate()來做實際的工作。否則,我們按照正常的重建對象的流程執(zhí)行。重建的原因是,從概念上講,當MDS指示OST創(chuàng)建一個對象,OST并不單單創(chuàng)建一個對象,而是創(chuàng)建多個已指定了對象ID的對象。創(chuàng)建的這一組對象的磁盤大小是零。這樣做的目的是,當下一次MDS回復客戶端創(chuàng)建新文件的請求時,它不用再向OST發(fā)送請求,就能為客戶端呈現(xiàn)布局信息。通過查看每個OST中預先創(chuàng)建的對象池,MDS就可能已經(jīng)擁有所有用來回復客戶端所需的信息。

if(oa->o_valid & OBD_MD_FLFLAGS) &&

(oa->o_flags & OBD_FL_RECREATE_OBJS)){

rc =ldlm_cli_enqueue_local(obd->obd_namespace, &res_id, ... );

rc = filter_recreate(obd, oa);

ldlm_lock_deref(&lockh, LCK_PW);

} else {

rc = filter_handle_precreate(exp, oa,oa->o_gr, oti);

}

這里,從預先創(chuàng)建處理函數(shù)中返回的rc要么是一個負數(shù),表明錯誤,要么是一個非負數(shù),表明創(chuàng)建的文件數(shù)目。

3. 現(xiàn)在,我們更近一點看看預先創(chuàng)建函數(shù):

當客戶端通過一個預先創(chuàng)建對象ID與一個OST聯(lián)系時,OST知道這個對象ID現(xiàn)在被激活了。但是這里出現(xiàn)一個問題:如果MDS掛了,它關(guān)于預先創(chuàng)建對象的信息就過時了。為了解決這個沖突,當MDS重啟時,它檢查未使用的預先創(chuàng)建對象的記錄,向OST發(fā)送請求,刪除那些對象(刪除孤兒)。obdfilter接收這些請求,跳過那些實際上已經(jīng)被使用(但是沒有和MDS自己的記錄同步)的對象,將剩下的對象刪除。這就是filter_handle_precreate()在第一部分中所需要做的:

if((oa->o_valid & OBD_MD_FLFLAGS) &&

(oa->o_flags & OBD_FL_DELORPHAN)) {

down(&filter->fo_create_lock);

rc = filter_destroy_precreated(exp,oa,filter);

...

} else {

rc = filter_precreate(obd, oa, group, &diff);

...

}

4. 最終,創(chuàng)建請求傳遞到fsfilt,由VFS調(diào)用完成。這個進程稍后將經(jīng)過更多的步驟,例如取得父親索引節(jié)點,事務(wù)創(chuàng)建等等。

rc =ll_vfs_create(dparent->d_inode, dchild,

S_IFREG | S_ISUID | S_ISGID | 0666, NULL);

本文章歡迎轉(zhuǎn)載,請保留原始博客鏈接http://blog.csdn.net/fsdev/article

深入理解Lustre文件系統(tǒng)-第6篇 OST和obdfilter


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!??!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 夏河县| 清河县| 新宁县| 巴塘县| 昔阳县| 安国市| 积石山| 南投市| 大英县| 法库县| 元朗区| 县级市| 奉节县| 朔州市| 黄浦区| 丹棱县| 苗栗市| 仙游县| 忻城县| 柏乡县| 阿尔山市| 永胜县| 金昌市| 崇礼县| 浙江省| 镇平县| 合江县| 长沙县| 平南县| 安阳县| 江陵县| 肇东市| 太谷县| 彭州市| 临安市| 邵阳市| 巴马| 临邑县| 河西区| 红原县| 铜陵市|