linux+内核中开启nfs,NFS Client in Linux Kernel - Open
1. Callstack for Opening for a file
open() => nfs4_file_open() => nfs4_atomic_open() => nfs4_do_open() => _nfs4_do_open()
_nfs4_do_open分析:
nfs4_get_state_owner()獲得open owner對(duì)象
設(shè)置claim,他有幾種可能CLAIM_NULL(文件用文件名描述),CLAIM_FH(文件用current filehandle描述), CLAIM_PREVIOUS(用于reclaim open)
nfs4_opendata_alloc()分配nfs4_opendata
_nfs4_open_and_get_state()發(fā)送OPEN NFS命令
4.1 _nfs4_proc_open, 發(fā)送OPEN NFS命令
4.2 nfs4_opendata_to_nfs4_state() =>_nfs4_opendata_to_nfs4_state(), 創(chuàng)建open state,并將OPEN NFS命令得到的open state id,跟新這里。
open state存在ctx->state,其中ctx是nfs_open_context,它存儲(chǔ)在filp->private_data。對(duì)文件open以后,就可以通過filp->private_data得到ctx,并得到ctx->state->open_stateid,通過這個(gè)stateid向NFS Server發(fā)送READ/WRITE/LOCK操作。
2. NFS協(xié)議中的Open owner
NFS協(xié)議規(guī)定發(fā)送OPEN時(shí)候要發(fā)送一個(gè)open owner,標(biāo)識(shí)這個(gè)open的owner。在Server看來,clientid可以區(qū)分是來自哪個(gè)client的,open owner可以區(qū)分不同進(jìn)程的open請(qǐng)求。
摘自[nfs4.1協(xié)議]https://tools.ietf.org/html/rfc5661
NFS協(xié)議中Open owner和Lock owner都用下面這個(gè)結(jié)構(gòu)體表達(dá)。
struct state_owner4 {
clientid4 clientid;
opaque owner;
};
clientid,Server分配的,唯一標(biāo)識(shí)一個(gè)和server建立session的client
字符串+字符串的長度,唯一標(biāo)識(shí)client中的一個(gè)進(jìn)程
client標(biāo)識(shí)+進(jìn)程標(biāo)識(shí),唯一確定一個(gè)lock的owner。
### 2.1 Linux Kernel中對(duì)Open owner的設(shè)置
static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg)
{
...
*p++ = cpu_to_be32(24);
p = xdr_encode_opaque_fixed(p, "open id:", 8);
*p++ = cpu_to_be32(arg->server->s_dev);
*p++ = cpu_to_be32(arg->id.uniquifier);
xdr_encode_hyper(p, arg->id.create_time);
}
Lock owner大小24字節(jié):
8字節(jié)的固定字符,"lock id:"
4字節(jié)的s_dev,表示是本地哪個(gè)文件系統(tǒng)。
4字節(jié)的id。由ida_get_new函數(shù)創(chuàng)建,在本地文件系統(tǒng)中唯一。
8字節(jié)的create_time
以上三點(diǎn),保證了在一個(gè)client內(nèi)Lock owner是唯一的。
再加上clientid,可以保證所有和Server建立session連接的client來自的lock owner是唯一確定。
3. Linux Kernel對(duì)一個(gè)打開實(shí)體Owner的描述
struct nfs4_state_owner {
struct nfs_server *so_server;
struct list_head so_lru;
unsigned long so_expires;
struct rb_node so_server_node;
struct rpc_cred *so_cred; //以這個(gè)為key,插入到紅黑樹里
spinlock_t so_lock;
atomic_t so_count;
unsigned long so_flags;
struct list_head so_states;
struct nfs_seqid_counter so_seqid;
seqcount_t so_reclaim_seqcount;
struct mutex so_delegreturn_mutex;
};
3.1 創(chuàng)建nfs4_state_owner
nfs4_get_state_owner()
首先通過so_cred為key,在紅黑樹里搜索
如果沒有搜到,創(chuàng)建一個(gè)
4. Linux Kernel對(duì)一個(gè)打開實(shí)體的描述
這個(gè)數(shù)據(jù)結(jié)構(gòu)專門描述open state,一個(gè)實(shí)體會(huì)被多個(gè)Owner打開,所以struct nfs4_state和struct nfs4_state_owner是一對(duì)多的關(guān)系
struct nfs4_state {
struct list_head open_states; //對(duì)于同一個(gè)inode,所有open state存在inode->open_states
struct list_head inode_states; //對(duì)于同一個(gè)owner,所有的open state存在owner->so_states
struct list_head lock_states; //這個(gè)open state下所有的lock state
struct nfs4_state_owner *owner; /* Pointer to the open owner */
struct inode *inode; /* Pointer to the inode */
unsigned long flags; /* Do we hold any locks? */
spinlock_t state_lock; /* Protects the lock_states list */
seqlock_t seqlock; /* Protects the stateid/open_stateid */
nfs4_stateid stateid; /* Current stateid: may be delegation */
nfs4_stateid open_stateid; /* OPEN stateid */
/* The following 3 fields are protected by owner->so_lock */
unsigned int n_rdonly; /* Number of read-only references */
unsigned int n_wronly; /* Number of write-only references */
unsigned int n_rdwr; /* Number of read/write references */
fmode_t state; /* State on the server (R,W, or RW) */
atomic_t count;
};
4.1 創(chuàng)建nfs4_state
nfs4_get_open_state
通過owner和inode的組合,試圖尋找一下
如果找不到創(chuàng)建一個(gè)和inode關(guān)聯(lián)
4. open stateid for Read/Write/Lock/Setattr/Close
這些操作都是依靠open stateid來向Server交互的。
參見下列函數(shù)的實(shí)現(xiàn)
encode_read()
encode_write()
encode_setattr()
encode_close()
encode_lock()
encode_locku()
static void encode_read(struct xdr_stream *xdr, const struct nfs_pgio_args *args,
struct compound_hdr *hdr)
{
__be32 *p;
encode_op_hdr(xdr, OP_READ, decode_read_maxsz, hdr);
encode_nfs4_stateid(xdr, &args->stateid); //NFS Server需要通過stateid找到file owner
p = reserve_space(xdr, 12);
p = xdr_encode_hyper(p, args->offset);
*p = cpu_to_be32(args->count);
}
調(diào)用棧
//open for file
nfs4_file_open <= sys_open
open_context // nfs4_atomic_open
nfs4_do_open
_nfs4_do_open
nfs4_recover_expired_lease
//如果當(dāng)前Dentry訪問過,則claim = NFS4_OPEN_CLAIM_FH
nfs4_opendata_alloc
_nfs4_open_and_get_state
_nfs4_proc_open
nfs4_run_open_task //send OPEN request to server
nfs4_open_prepare
//如果claim == NFS4_OPEN_CLAIM_FH,將OPEN修改成OPEN_NOATTR
//open for dir
nfs_opendir <= sys_open
if (filp->f_path.dentry == filp->f_path.mnt->mnt_root)
__nfs_revalidate_inode
getattr
//read dir
nfs_readdir <= sys_getdents
readdir_search_pagecache
find_cache_page
get_cache_page
=> nfs_readdir_filler
nfs_readdir_xdr_to_array
nfs_readdir_xdr_filler
readdir //nfs4_proc_readdir
_nfs4_proc_readdir //send READDIR
nfs_readdir_search_array
總結(jié)
以上是生活随笔為你收集整理的linux+内核中开启nfs,NFS Client in Linux Kernel - Open的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php ignore special c
- 下一篇: 两台linux之间实现共享文件夹挂载实例