QNX相關(guān)歷史文章:
Filesystem Resource Managers
這篇文章主要描述文件系統(tǒng)資源管理器劲够。
1. Considerations for filesystem resource managers
由于文件系統(tǒng)資源管理器可能會(huì)收到很長(zhǎng)的路徑名,因此它必須要能夠正確地解析和處理路徑的每個(gè)部分蹲姐。
比如,一個(gè)資源管理器注冊(cè)了掛載點(diǎn)/mount
柴墩,當(dāng)用戶輸入:ls -l /mount/home
時(shí)江咳, 其中/mount/home
是設(shè)備中的一個(gè)路徑,
那么ls
會(huì)做以下事情:
d = opendir("/mount/home");
while (...) {
dirent = readdir(d);
...
}
2. Taking over more than one device
當(dāng)資源管理器需要處理多個(gè)設(shè)備時(shí)歼指,可以對(duì)每個(gè)設(shè)備名調(diào)用resmgr_attach()
接口進(jìn)行注冊(cè)踩身,此外每個(gè)設(shè)備還需要唯一的屬性結(jié)構(gòu),當(dāng)像chmod()
等函數(shù)被調(diào)用時(shí)挟阻,便可對(duì)特定設(shè)備的屬性進(jìn)行修改。
示例代碼如下:
/*
* MOD [1]: allocate multiple attribute structures,
* and fill in a names array (convenience)
*/
#define NumDevices 2
iofunc_attr_t sample_attrs [NumDevices];
char *names [NumDevices] =
{
"/dev/sample1",
"/dev/sample2"
};
main ()
{
...
/*
* MOD [2]: fill in the attribute structure for each device
* and call resmgr_attach for each device
*/
for (i = 0; i < NumDevices; i++) {
iofunc_attr_init (&sample_attrs [i],
S_IFCHR | 0666, NULL, NULL);
pathID = resmgr_attach (dpp, &resmgr_attr, name[i],
_FTYPE_ANY, 0,
&my_connect_funcs,
&my_io_funcs,
&sample_attrs [i]);
}
...
}
在這個(gè)代碼中脱拼,增加了屬性結(jié)構(gòu)的數(shù)組熄浓,并且多次調(diào)用了resmgr_attach()
接口击你,其他地方不需要修改。io_read
或io_write
處理函數(shù)不需要改動(dòng)丁侄,iofunc layer
默認(rèn)處理函數(shù)會(huì)去處理多種設(shè)備的情況鸿摇。
3. Handling directories
之前的例子路徑名都是在/dev
目錄下,資源管理器不會(huì)限制只能在某個(gè)路徑下拙吉,并可以處理任何數(shù)量的路徑名,一個(gè)實(shí)際的限制在于當(dāng)數(shù)量越多的時(shí)候往史,可能面臨內(nèi)存不足以及查找速度慢等問題佛舱。
當(dāng)路徑名數(shù)量很多時(shí)挨决,一個(gè)最直接的辦法就是使用路徑名前綴订歪,比如:
-
CD-ROM
文件系統(tǒng)刷晋,可以使用前綴/cdrom
,當(dāng)對(duì)這個(gè)路徑下的名字操作時(shí)眼虱,都會(huì)去處理CD-ROM
設(shè)備; - 一個(gè)處理壓縮文件的文件系統(tǒng)映凳,可以使用前綴
/uncompressed
邮破; - 網(wǎng)絡(luò)文件系統(tǒng)可以使用
/mount/flipper
路徑名來顯示遠(yuǎn)程機(jī)器仆救,當(dāng)訪問這個(gè)路徑時(shí)彤蔽,就像訪問本地機(jī)器;
上邊這些例子的特點(diǎn)是都實(shí)現(xiàn)了文件系統(tǒng)顿痪,文件系統(tǒng)資源管理器與設(shè)備資源管理器在以下幾個(gè)關(guān)鍵領(lǐng)域有區(qū)別:
-
resmgr_attach()
參數(shù)中的_RESMGR_FLAG_DIR
位會(huì)通知庫(kù)蚁袭,資源管理器會(huì)在掛載點(diǎn)路徑或掛載點(diǎn)路徑下接受匹配; -
_IO_CONNECT
邏輯必須根據(jù)數(shù)據(jù)權(quán)限和訪問權(quán)限來檢查路徑名的各個(gè)部分揩悄,它還必須確保在訪問特定文件名時(shí)綁定了適當(dāng)?shù)膶傩裕?/li> -
_IO_READ
邏輯必須返回路徑名指定的“文件”或“路徑”數(shù)據(jù)删性;
3.1 Matching at or below a mountpoint
在使用resmgr_attach()
函數(shù)時(shí),傳入的flags
參數(shù)為_RESMGR_FLAG_DIR
時(shí)蹬挺,表明允許在指定的掛載點(diǎn)路徑或該路徑之下進(jìn)行路徑名解析巴帮。如果flags
參數(shù)為0群发,表明使用默認(rèn)值发乔。
3.2 The _IO_OPEN message for filesystems
假設(shè)注冊(cè)了一個(gè)掛載點(diǎn)/sample_fsys
,如下:
pathID = resmgr_attach
(dpp,
&resmgr_attr,
"/sample_fsys", /* mountpoint */
_FTYPE_ANY,
_RESMGR_FLAG_DIR, /* it's a directory */
&connect_funcs,
&io_funcs,
&attr);
當(dāng)客戶端調(diào)用如下代碼:
fopen ("/sample_fsys/spud", "r");
資源管理器會(huì)收到_IO_CONNECT
消息起愈,并且調(diào)用io_read
處理函數(shù)译仗。_IO_CONNECT
消息的數(shù)據(jù)結(jié)構(gòu)如下:
struct _io_connect {
unsigned short type;
unsigned short subtype; /* _IO_CONNECT_* */
unsigned long file_type; /* _FTYPE_* in sys/ftype.h */
unsigned short reply_max;
unsigned short entry_max;
unsigned long key;
unsigned long handle;
unsigned long ioflag; /* O_* in fcntl.h, _IO_FLAG_* */
unsigned long mode; /* S_IF* in sys/stat.h */
unsigned short sflag; /* SH_* in share.h */
unsigned short access; /* S_I in sys/stat.h */
unsigned short zero;
unsigned short path_len;
unsigned char eflag; /* _IO_CONNECT_EFLAG_* */
unsigned char extra_type; /* _IO_EXTRA_* */
unsigned short extra_len;
unsigned char path[1]; /* path_len, null, extra_len */
};
其中ioflat, mode, sflag, access
表明資源是如何打開的纵菌。參數(shù)path_len
表明路徑名占多少字節(jié),path
放置實(shí)際的路徑名笛辟。注意序苏,出現(xiàn)的路徑名是spud
,而不是/sample_fsys/spud
忱详,這是因?yàn)橄⒅话鄬?duì)于掛載點(diǎn)的路徑名匈睁。還要注意的是,路徑名中不會(huì)有相對(duì)路徑(.
, ..
)部分航唆,也不會(huì)冗余的斜杠(/
),這些都會(huì)在消息發(fā)送到資源管理器時(shí)被解析和刪除醇滥。
當(dāng)編寫文件系統(tǒng)資源管理器時(shí)超营,在處理路徑名時(shí)可能會(huì)有一些復(fù)雜的情況,為了驗(yàn)證訪問不跟,我們需要分解傳遞的路徑名米碰,并對(duì)每個(gè)部分進(jìn)行檢查购城∨耙耄可以使用strtok()
等來分解路徑名字符串漆诽,然后調(diào)用iofunc_check_access()
來進(jìn)行訪問驗(yàn)證。驗(yàn)證名稱之后發(fā)生的綁定要求處理的每個(gè)路徑都有自己的屬性結(jié)構(gòu)厢拭,如果將錯(cuò)誤的屬性綁定到所提供的路徑名供鸠,將會(huì)導(dǎo)致意外的行為。
3.3 Returning directory entries from _IO_READ
當(dāng)_IO_READ
處理函數(shù)被調(diào)用后楞捂,可能需要返回文件(如果S_ISDIR(ocb->attr->mode)為
false)泡一,也可能需要返回目錄(如果
S_ISDIR(ocb->attr->mode)為true
)觅廓。
對(duì)于將目錄返回給客戶端,存在一些約束杈绸,返回的不是一個(gè)字節(jié)流瞳脓,返回的是幾個(gè)struct dirent
的數(shù)據(jù)結(jié)構(gòu),dirent
結(jié)構(gòu)必須4字節(jié)對(duì)齊劫侧。數(shù)據(jù)結(jié)構(gòu)如下:
struct dirent {
#if _FILE_OFFSET_BITS - 0 == 64
ino_t d_ino; /* File serial number. */
off_t d_offset;
#elif !defined(_FILE_OFFSET_BITS) || _FILE_OFFSET_BITS == 32
#if defined(__LITTLEENDIAN__)
ino_t d_ino; /* File serial number. */
ino_t d_ino_hi;
off_t d_offset;
off_t d_offset_hi;
#elif defined(__BIGENDIAN__)
ino_t d_ino_hi;
ino_t d_ino; /* File serial number. */
off_t d_offset_hi;
off_t d_offset;
#else
#error endian not configured for system
#endif
#else
#error _FILE_OFFSET_BITS value is unsupported
#endif
_Int16t d_reclen;
_Int16t d_namelen;
char d_name[1];
};
d_ino
成員包含一個(gè)掛載點(diǎn)唯一的文件序列號(hào)烧栋。這個(gè)序列號(hào)通常用于各種磁盤檢查程序中。在有些文件系統(tǒng)中珍特,d_offset
用于標(biāo)識(shí)目錄條目本身魔吐,而在其他情況下莱找,它是下一個(gè)目錄項(xiàng)的偏移量嗜桌。d_reclen
成員包含此目錄項(xiàng)的大小和任何其他相關(guān)信息骨宠。d_namelen
參數(shù)指示d_name
參數(shù)的大小,d_name
保存該目錄項(xiàng)的實(shí)際名稱诱篷。
dirent
結(jié)構(gòu)中僅包含名稱的前四個(gè)字節(jié)的空間棕所,_IO_READ
處理程序需要返回一個(gè)更大的結(jié)構(gòu),包含名字和dirent
琳省,如下:
struct {
struct dirent ent;
char namebuf[NAME_MAX + 1 + offsetof(struct dirent, d_name) -
sizeof( struct dirent)];
} entry
或者定義成聯(lián)合體:
union {
struct dirent ent;
char filler[ offsetof( struct dirent, dname ) + NAME_MAX + 1];
} entry;
在我們的io_read
處理程序中针贬,需要生成許多struct dirent
條目,并返回給客戶端桦他。如果在資源管理器中維護(hù)了目錄項(xiàng)緩存快压,那么構(gòu)造一組IOVs來指向這些項(xiàng)即可。如果沒有緩存的話蔫劣,則必須手動(dòng)將目錄項(xiàng)組裝到緩沖區(qū)中脉幢,然后返回指向該緩沖區(qū)的IOV。
3.3.1 Returning information associated with a directory structure
除了返回_IO_READ
消息中的struct dirent
外嫌松,還可以返回struct stat
豆瘫,盡管這個(gè)可以提高效率,但是struct stat
完全是可選的,如果不返回struct stat
的話腻窒,客戶端就必須通過stat()/lstat()
來獲取該信息磅崭。
客戶端可以通過將消息的xtype
成員設(shè)置成_IO_XFLAG_DIR_EXTRA_HINT
,以便向文件系統(tǒng)發(fā)送提示以返回額外的信息柔逼,但文件系統(tǒng)不保證這樣做割岛。如果資源管理器提供信息,則必須將其放入到struct dirent_extra_stat
中维咸,定義如下:
struct dirent_extra_stat {
_Uint16t d_datalen;
_Uint16t d_type;
_Uint32t d_reserved;
struct stat d_stat;
};
資源管理器必須將d_type
設(shè)置為_DTYPE_LSTAT
或_DTYPE_STAT
惠爽,這取決于它是否解析符號(hào)鏈接。比如:
if(msg->i.xtype & _IO_XFLAG_DIR_EXTRA_HINT) {
struct dirent_extra_stat extra;
extra.d_datalen = sizeof extra.d_stat;
extra.d_type = _DTYPE_LSTAT;
extra.d_reserved = 0;
iofunc_stat(ctp, &attr, &extra.d_stat);
...
}
每個(gè)目錄項(xiàng)后都有一個(gè)dirent_extra_stat
:
dirent
結(jié)構(gòu)必須在4字節(jié)邊界上對(duì)齊,dirent_extra_stat
結(jié)構(gòu)必須在8字節(jié)邊界上對(duì)齊较性,d_reclen
成員必須包含這兩個(gè)結(jié)構(gòu)的大小两残,包含路徑名和對(duì)齊所需的任何空間。最多不超過7字節(jié)的對(duì)齊填充人弓。
客戶端必須調(diào)用_DEXTRA_*()
宏來檢查額外的數(shù)據(jù)着逐,如果檢查失敗耸别,則需要顯示調(diào)用lstat()
或stat()
。比如秀姐,ls -l
檢查額外的_DTYPE_LSTAT
信息,如果不存在痒留,ls
調(diào)用lstat()
。ls -L
檢查額外的_DTYPE_STAT
信息匾效,如果不存在恤磷,ls
調(diào)用stat()
。