QNX相關歷史文章:
Fleshing Out the Skeleton
在講完大體框架后痛阻,這篇文章將涉及到更多細節(jié):消息類型;資源管理器屬性锄禽;添加功能赢赊;安全事項等唤蔗。
1. Message types
在前文中也提到過窘拯,資源管理器需要處理兩類消息:
- connect message底桂,連接消息
- I/O message湖苞, IO消息
1.1 connect message
客戶端發(fā)出connect message
來執(zhí)行基于路徑名的操作烹吵。當調用resmgr_attach()
函數(shù)時碉熄,會將一個指針傳遞給resmgr_connect_funcs_t
結構,該結構定義了一系列連接函數(shù):
typedef struct _resmgr_connect_funcs {
unsigned nfuncs;
int (*open) (resmgr_context_t *ctp, io_open_t *msg,
RESMGR_HANDLE_T *handle, void *extra);
int (*unlink) (resmgr_context_t *ctp, io_unlink_t *msg,
RESMGR_HANDLE_T *handle, void *reserved);
int (*rename) (resmgr_context_t *ctp, io_rename_t *msg,
RESMGR_HANDLE_T *handle,
io_rename_extra_t *extra);
int (*mknod) (resmgr_context_t *ctp, io_mknod_t *msg,
RESMGR_HANDLE_T *handle, void *reserved);
int (*readlink) (resmgr_context_t *ctp, io_readlink_t *msg,
RESMGR_HANDLE_T *handle, void *reserved);
int (*link) (resmgr_context_t *ctp, io_link_t *msg,
RESMGR_HANDLE_T *handle,
io_link_extra_t *extra);
int (*unblock) (resmgr_context_t *ctp, io_pulse_t *msg,
RESMGR_HANDLE_T *handle, void *reserved);
int (*mount) (resmgr_context_t *ctp, io_mount_t *msg,
RESMGR_HANDLE_T *handle,
io_mount_extra_t *extra);
} resmgr_connect_funcs_t;
可以調用iofunc_func_init()
接口來用默認的處理程序指針來初始化這個結構肋拔。自己也可以重寫某些接口锈津,進行覆蓋即可。
需要注意的是凉蜂,resmgr_attach()
接口只是將函數(shù)指針拷貝到resmgr_connect_func_t
和resmgr_io_funcs_t
結構中琼梆,而不是拷貝整個結構。需要分配這些結構窿吩,將它們聲明為靜態(tài)的或者全局變量茎杂。如果資源管理器用于具有不同處理程序的多個設備,則應該分開定義獨立的結構纫雁。
這些連接消息都有一個_IO_CONNECT
類型煌往,此外還有子類型來進行分類,各個字段介紹如下:
-
nfuncs
轧邪,結構中函數(shù)的個數(shù)刽脖,可用于擴展; -
open
忌愚,處理客戶端的open()/fopen()/sopen()
等請求曲管,消息子類型包括_IO_CONNECT_COMBINE
,_IO_CONNECT_COMBINE_CLOSE
,_IO_CONNECT_OPEN
等; -
unlink
菜循,處理客戶端unlink()
請求翘地,消息子類型為_IO_CONNECT_UNLINK
申尤; -
rename
,處理客戶端rename()
請求衙耕,消息子類型為_IO_CONNECT_RENAME
昧穿; -
mknod
,處理客戶端mkdir()/mkfifo()/mknod()
請求橙喘,消息子類型為_IO_CONNECT_MKNOD
时鸵; -
readlink
,處理客戶端readlink()
請求厅瞎,消息子類型為_IO_CONNECT_READLINK
饰潜; -
link
,處理客戶端link()
請求和簸,消息子類型為_IO_CONNECT_LINK
彭雾; -
unlock
,處理來自內核的請求锁保,以便在連接消息階段接觸對客戶端的阻塞薯酝; -
mount
,處理客戶端mount()
請求爽柒,消息子類型為_IO_CONNECT_MOUNT
吴菠;
1.2 I/O messages
I/O消息依賴于客戶端和資源管理器之間已有的綁定關系,比如當客戶端調用read()
函數(shù)發(fā)送_IO_READ
消息時浩村,需要先通過open()
函數(shù)來與資源管理器建立綁定關系做葵,進而獲取到文件描述符。
regmgr_io_funcs_t
結構體定義了I/O消息處理函數(shù):
typedef struct _resmgr_io_funcs {
unsigned nfuncs;
int (*read) (resmgr_context_t *ctp, io_read_t *msg,
RESMGR_OCB_T *ocb);
int (*write) (resmgr_context_t *ctp, io_write_t *msg,
RESMGR_OCB_T *ocb);
int (*close_ocb) (resmgr_context_t *ctp, void *reserved,
RESMGR_OCB_T *ocb);
int (*stat) (resmgr_context_t *ctp, io_stat_t *msg,
RESMGR_OCB_T *ocb);
int (*notify) (resmgr_context_t *ctp, io_notify_t *msg,
RESMGR_OCB_T *ocb);
int (*devctl) (resmgr_context_t *ctp, io_devctl_t *msg,
RESMGR_OCB_T *ocb);
int (*unblock) (resmgr_context_t *ctp, io_pulse_t *msg,
RESMGR_OCB_T *ocb);
int (*pathconf) (resmgr_context_t *ctp, io_pathconf_t *msg,
RESMGR_OCB_T *ocb);
int (*lseek) (resmgr_context_t *ctp, io_lseek_t *msg,
RESMGR_OCB_T *ocb);
int (*chmod) (resmgr_context_t *ctp, io_chmod_t *msg,
RESMGR_OCB_T *ocb);
int (*chown) (resmgr_context_t *ctp, io_chown_t *msg,
RESMGR_OCB_T *ocb);
int (*utime) (resmgr_context_t *ctp, io_utime_t *msg,
RESMGR_OCB_T *ocb);
int (*openfd) (resmgr_context_t *ctp, io_openfd_t *msg,
RESMGR_OCB_T *ocb);
int (*fdinfo) (resmgr_context_t *ctp, io_fdinfo_t *msg,
RESMGR_OCB_T *ocb);
int (*lock) (resmgr_context_t *ctp, io_lock_t *msg,
RESMGR_OCB_T *ocb);
int (*space) (resmgr_context_t *ctp, io_space_t *msg,
RESMGR_OCB_T *ocb);
int (*shutdown) (resmgr_context_t *ctp, io_shutdown_t *msg,
RESMGR_OCB_T *ocb);
int (*mmap) (resmgr_context_t *ctp, io_mmap_t *msg,
RESMGR_OCB_T *ocb);
int (*msg) (resmgr_context_t *ctp, io_msg_t *msg,
RESMGR_OCB_T *ocb);
int (*reserved) (resmgr_context_t *ctp, void *msg,
RESMGR_OCB_T *ocb);
int (*dup) (resmgr_context_t *ctp, io_dup_t *msg,
RESMGR_OCB_T *ocb);
int (*close_dup) (resmgr_context_t *ctp, io_close_t *msg,
RESMGR_OCB_T *ocb);
int (*lock_ocb) (resmgr_context_t *ctp, void *reserved,
RESMGR_OCB_T *ocb);
int (*unlock_ocb) (resmgr_context_t *ctp, void *reserved,
RESMGR_OCB_T *ocb);
int (*sync) (resmgr_context_t *ctp, io_sync_t *msg,
RESMGR_OCB_T *ocb);
int (*power) (resmgr_context_t *ctp, io_power_t *msg,
RESMGR_OCB_T *ocb);
} resmgr_io_funcs_t;
這個結構的使用與resmgr_connect_funcs_t
一樣心墅,對應到客戶端的不同請求酿矢,及消息類型。
1.3 Default message handling
由于資源管理器接收的大量消息處理的是一組公共的屬性怎燥,因此QNX提供了一個iofunc_*()
共享庫棠涮,實現(xiàn)了一些默認的消息處理函數(shù)。目前實現(xiàn)的默認函數(shù)可用于處理客戶端的以下請求:
chmod()
chown()
close()
devctl()
fpathconf()
fseek()
fstat()
lockf()
lseek()
mmap()
open()
pathconf()
stat()
utime()
2. Setting resource manager attribute
除了定義connect
和I/O
函數(shù)結構體之外刺覆,resmgr_attach()
函數(shù)還需要用到resmgr_attr_t
來指定資源管理器的屬性严肪。定義如下:
typedef struct _resmgr_attr {
unsigned flags;
unsigned nparts_max;
unsigned msg_max_size;
int (*other_func)(resmgr_context_t *,
void *msg);
unsigned reserved[4];
} resmgr_attr_t;
各個成員介紹如下:
-
flags
可用于修改資源管理器接口的行為,可以將其設置為0谦屑,或者是以下不同狀態(tài)的組合:
-
RESMGR_FLAG_ATTACH_LOCAL
驳糯,設置資源管理器,不向procnto
注冊路徑氢橙,可以向資源管理器通道發(fā)送消息酝枢; -
RESMGR_FLAG_ATTACH_OTHERFUNC
,該結構中的other_func
成員指向一個用于未處理I/O消息的函數(shù)悍手; -
RESMGR_FLAG_CROSS_ENDIAN
帘睦,服務器支持跨端處理袍患,可以在服務器端做必要的轉換,客戶端不需要做任何事情竣付; -
RESMGR_FLAG_NO_DEFAULT
诡延,未實現(xiàn); -
RESMGR_FLAG_RCM
古胆,在處理請求時自動采取客戶端的資源約束模式肆良;
nparts_max
分配給IOV數(shù)組的組件數(shù)量。msg_max_size
消息緩沖的大小逸绎。
這些成員在實現(xiàn)自己的處理函數(shù)時很重要惹恃。other_func
other_func
可用于指定一個例程,在資源管理器接收到不能理解的I/O消息時調用棺牧。要使用這個成員巫糙,需要在flag
字段里置上RESMGR_FLAG_ATTACH_OTHERFUNC
。如果other_func
成員設置成NULL
的話颊乘,資源管理器在收到不能理解的消息時曲秉,便會返回ENOSYS
錯誤給客戶端。
對于非I/O消息類型時疲牵,需要使用message_attach()
接口來將消息綁定到dispatch handle
上。
3. Ways of adding functionality to the resource manager
3.1 Using the default functions
下邊是一個使用自己的io_open
處理程序的示例:
main (int argc, char **argv)
{
…
/* install all of the default functions */
iofunc_func_init (_RESMGR_CONNECT_NFUNCS, &connect_funcs,
_RESMGR_IO_NFUNCS, &io_funcs);
/* take over the open function */
connect_funcs.open = io_open;
…
}
int
io_open (resmgr_context_t *ctp, io_open_t *msg,
RESMGR_HANDLE_T *handle, void *extra)
{
return (iofunc_open_default (ctp, msg, handle, extra));
}
上述的代碼只是一個增量步驟榆鼠,可以允許在調用默認處理函數(shù)之前或者之后執(zhí)行某些操作纲爸,比如可以實現(xiàn)如下代碼:
/* example of doing something before */
extern int accepting_opens_now;
int
io_open (resmgr_context_t *ctp, io_open_t *msg,
RESMGR_HANDLE_T *handle, void *extra)
{
if (!accepting_opens_now) {
return (EBUSY);
}
/*
* at this point, we're okay to let the open happen,
* so let the default function do the "work".
*/
return (iofunc_open_default (ctp, msg, handle, extra));
}
或者:
/* example of doing something after */
int
io_open (resmgr_context_t *ctp, io_open_t *msg,
RESMGR_HANDLE_T *handle, void *extra)
{
int sts;
/*
* have the default function do the checking
* and the work for us
*/
sts = iofunc_open_default (ctp, msg, handle, extra);
/*
* if the default function says it's okay to let the open
* happen, we want to log the request
*/
if (sts == EOK) {
log_open_request (ctp, msg);
}
return (sts);
}
這種方法的優(yōu)勢是,只需要很少的工作就可以添加到標準的默認POSIX處理程序中妆够。
3.2 Using the helper functions
在很多默認處理函數(shù)中识啦,都調用到了幫助函數(shù),比如下邊的iofunc_chmod_default()
和iofunc_stat_default()
:
int
iofunc_chmod_default (resmgr_context_t *ctp, io_chmod_t *msg,
iofunc_ocb_t *ocb)
{
return (iofunc_chmod (ctp, msg, ocb, ocb -> attr));
}
int
iofunc_stat_default (resmgr_context_t *ctp, io_stat_t *msg,
iofunc_ocb_t *ocb)
{
iofunc_time_update (ocb -> attr);
iofunc_stat (ocb -> attr, &msg -> o);
return (_RESMGR_PTR (ctp, &msg -> o,
sizeof (msg -> o)));
}
在上邊的代碼中分別都調用到了iofunc_chmod()
神妹、iofunc_time_update()
颓哮、iofunc_stat()
等幫助函數(shù)。
更復雜的case如下:
int
iofunc_open_default (resmgr_context_t *ctp, io_open_t *msg,
iofunc_attr_t *attr, void *extra)
{
int status;
iofunc_attr_lock (attr);
if ((status = iofunc_open (ctp, msg, attr, 0, 0)) != EOK) {
iofunc_attr_unlock (attr);
return (status);
}
if ((status = iofunc_ocb_attach (ctp, msg, 0, attr, 0))
!= EOK) {
iofunc_attr_unlock (attr);
return (status);
}
iofunc_attr_unlock (attr);
return (EOK);
}
調用了以下幫助函數(shù):
-
iofunc_attr_lock()
接口鸵荠,獲取鎖冕茅,用于互斥訪問屬性結構; -
iofunc_open()
蛹找,進行權限驗證姨伤; -
iofunc_ocb_attach()
,綁定OCB
結構庸疾; -
iofunc_attr_unlock()
乍楚,釋放鎖;
3.3 Writing the entire function yourself
有時候默認的處理函數(shù)對特定的資源管理器來說沒有用處届慈,可以自己實現(xiàn)處理函數(shù)徒溪,在這些實現(xiàn)的處理函數(shù)中忿偷,可以去調用幫助函數(shù),比如iofunc_read_verify()
臊泌。
4. Security
資源管理器通常是一個特權進程鲤桥,因此需要小心,防止客戶端迫使它耗盡資源或損耗系統(tǒng)缺虐。在設計資源管理器時芜壁,應該考慮以下幾點:
- 管理路徑名空間中資源管理器條目的權限,可以將權限指定為
iofunc_attr_init()
的參數(shù)高氮; - 資源管理器通常需要運行在root權限慧妄,以便能與路徑名空間綁定,但是更好的方式是運行在非root權限剪芍,而使用
procmgr_ability()
去獲取特權的能力塞淹。 - 如果資源管理器不是一個沒有資源約束閾值的關鍵進程,它可以簡單的運行在約束模式下罪裹,而如果是一個關鍵進程饱普,應該保持
PROCMGR_AID_RCONSTRAINT
能力,需要確保受約束的客戶端不使用它來分配超過當前閾值的資源状共。 - 對客戶端的能力進行檢查套耕,通常可以調用
ConnectClientInfoAble()
或iofunc_client_info_able()
來檢查峡继。