这篇文章中我们接着讲解服务器端的处理程序,首先介绍几个与OPEN操作有关的数据结构。第1个数据结构是struct nfs4_openowner,这个数据结构跟客户端的nfs4_state_owner相对应,保存了一个用户的信息,这个数据结构的定义如下:
struct nfs4_openowner {
struct nfs4_stateowner oo_owner; /* must be first field */
// 每个nfs4_client结构中包含多个nfs4_openowner结构,这些结构构成了一个链表
// oo_perclient指向链表中相邻的元素.
struct list_head oo_perclient;
/*
* We keep around openowners a little while after last close,
* which saves clients from having to confirm, and allows us to
* handle close replays if they come soon enough. The close_lru
* is a list of such openowners, to be reaped by the laundromat
* thread eventually if they remain unused:
*/
// 所有空闲未用的nfs4_openowner结构保存在一个全局链表(close_lru)中.
struct list_head oo_close_lru;
struct nfs4_ol_stateid *oo_last_closed_stid; // 最后使用的nfs4_ol_stateid结构
// 放置到close_lru链表中的时间.
time_t oo_time; /* time of placement on so_close_lru */
// 表示这个nfs4_openowner结构已经确认过了,可以使用了.
#define NFS4_OO_CONFIRMED 1 // OPEN_CONFIRM
// 设置这个标志位后表示下次就需要释放oo_last_closed_stid了
#define NFS4_OO_PURGE_CLOSE 2
// 这是一个新创建的nfs4_openowner结构,还不能使用.
#define NFS4_OO_NEW 4 // OPEN
unsigned char oo_flags;
};
nfs4_openowner结构中第一个字段的数据类型是nfs4_stateowner,这个结构的定义如下:
struct nfs4_stateowner {
// 所有的nfs4_stateowner(nfs4_openowner和nfs4_lockowner)保存在一个hash表中(ownerstr_hashtbl)
struct list_head so_strhash; /* hash by op_name */
// 这是一个链表,链表中的数据结构是nfs4_ol_stateid,表示了用户打开的所有文件.
struct list_head so_stateids; //
struct nfs4_client * so_client; // 这个nfs4_stateowner结构所属的客户端
/* after increment in ENCODE_SEQID_OP_TAIL, represents the next
* sequence id expected from the client: */
// 这是一个序号,这个seqid和nfs4_state_owner->so_seqid.counter对应.
u32 so_seqid; // 每次操作都会更新seqid
// 这表示了一个用户 open id:<server->s_dev><nfs_seqid_counter->create_time><nfs_seqid_counter->owner_id>
// so_owner保存了这次OPEN操作的名称,从OPEN请求报文中解析得到的.
struct xdr_netobj so_owner; /* open owner name */
struct nfs4_replay so_replay;
bool so_is_open_owner; // 这是一个nfs4_opwnowner结构
};
因此nfs4_stateowner结构中的信息也是nfs4_openowner结构中的信息,那么为什么要把这些信息独立出来组成一个新的数据结构呢?因为我们现在只讲到了OPEN操作,还没有讲解LOCK操作。服务器端保存LOCK信息的数据结构是nfs4_lockowner,nfs4_openowner和nfs4_lockowner有些相似之处,这些相似的信息提取出来构成了nfs4_stateowner。
与客户端中nfs4_state相对应的数据结构是nfs4_ol_stateid,这个数据结构保存了一次OPEN操作的信息,这个数据结构的定义如下:
struct nfs4_ol_stateid {
// 这里包含了这个stateid的类型和归属的客户端(nfs4_client)
struct nfs4_stid st_stid; /* must be first field */
// 同一个nfs4_file结构中所有的nfs4_ol_stateid结构构成了一个链表。
// st_perfile指向了链表中相邻的元素.
struct list_head st_perfile;
// 一个nfs4_stateowner结构中包含多个nfs4_ol_stateid结构,st_perstateowner指向链表中下一个元素。
struct list_head st_perstateowner;
// 这是一个链表,链表中的数据结构是nfs4_lockowner.
struct list_head st_lockowners;
// 属于的nfs4_stateowner结构,有可能是nfs4_openowner结构,也有可能是nfs4_lockowner结构.
struct nfs4_stateowner * st_stateowner;
// 这个nfs4_ol_stateid结构所属于的nfs4_file
struct nfs4_file * st_file;
// 这是访问权限标志位
unsigned long st_access_bmap; // NONE READ WRITE BOTH
unsigned long st_deny_bmap; // NOEN READ WRITE BOTH
// 如果这是一个(nfs4_lockowner-->nfs4_ol_stateid),指向所在的(nfs4_openlock->nfs4_ol_stateid)
struct nfs4_ol_stateid * st_openstp;
};
NFS服务器端还定义了一个数据结构nfs4_file,这个数据结构表示一个文件,包含了文件的一些信息,如文件索引节点等。每个文件用一个nfs4_file结构表示,这个数据结构定义如下:
struct nfs4_file {
atomic_t fi_ref; // 这个结构的引用计数
// fi_hash将这个nfs4_file结构链接到file_hashtbl中
// file_hashtbl是一个全局hash表,保存了系统中所有的nfs4_file结构.
struct list_head fi_hash; /* hash by "struct inode *" */
// 这个文件上关联了很多个nfs4_ol_stateid结构,这是链表头.
struct list_head fi_stateids;
// 这个文件上还关联了很多nfs4_delegation结构,这些delegation共用一个租借锁
// 比如多个客户端以只读权限打开同一个文件,这是delegation的链表头.
struct list_head fi_delegations;
/* One each for O_RDONLY, O_WRONLY, O_RDWR: */
// 这个文件可能打开了多次,有多个文件对象结构,保存在这里.
struct file * fi_fds[3];
/*
* Each open or lock stateid contributes 0-4 to the counts
* below depending on which bits are set in st_access_bitmap:
* 1 to fi_access[O_RDONLY] if NFS4_SHARE_ACCES_READ is set
* + 1 to fi_access[O_WRONLY] if NFS4_SHARE_ACCESS_WRITE is set
* + 1 to both of the above if NFS4_SHARE_ACCESS_BOTH is set.
*/
// 这是各种权限的引用计数.
atomic_t fi_access[2];
// 关联到的文件对象
struct file *fi_deleg_file;
// 这是一个租借锁,NFSv4用租借锁机制实现delegation
// 所有的delegation共用同一个租借锁
struct file_lock *fi_lease; // 这是一个文件锁结构
// 这应该是fi_lease指针的引用数量,这是一个租借锁
atomic_t fi_delegees;
struct inode *fi_inode; // 这是文件的索引节点结构
// 文件锁是否发生了冲突,当服务器删除租借锁时就会先将fi_had_conflict设置为true,
// 这时客户端就不能申请delegation了.
bool fi_had_conflict;
};
struct nfsd4_open {
// CLAIM_DELEGATE_CUR
u32 op_claim_type; /* request */
struct xdr_netobj op_fname; /* request - everything but CLAIM_PREV */
u32 op_delegate_type; /* request - CLAIM_PREV only */
// NFS4_OPEN_CLAIM_DELEGATE_CUR中这是客户端传过来的delegation的stateid
stateid_t op_delegate_stateid; /* request - response */
u32 op_why_no_deleg; /* response - DELEG_NONE_EXT only */
u32 op_create; /* request */
u32 op_createmode; /* request */
u32 op_bmval[3]; /* request */
struct iattr iattr; /* UNCHECKED4, GUARDED4, EXCLUSIVE4_1 */
nfs4_verifier op_verf __attribute__((aligned(32)));
/* EXCLUSIVE4 */
clientid_t op_clientid; /* request */
struct xdr_netobj op_owner; /* request */
u32 op_seqid; /* request */
u32 op_share_access; /* request */
u32 op_share_deny; /* request */
u32 op_deleg_want; /* request */
stateid_t op_stateid; /* response */
u32 op_recall; /* recall */
struct nfsd4_change_info op_cinfo; /* response */
u32 op_rflags; /* response */
bool op_truncate; /* used during processing */
bool op_created; /* used during processing */
struct nfs4_openowner *op_openowner; /* used during processing */
struct nfs4_file *op_file; /* used during processing */
struct nfs4_ol_stat