现在可以接着讲解文件打开过程。在前面的文章中我们讲过,客户端在发起OPEN操作前创建了新的数据结构nfs4_state_owner和nfs4_state,nfs4_state_owner表示客户端一个用户,nfs4_state表示一次OPEN过程。如果一个用户打开了多个文件,客户端就需要创建多个nfs4_state结构,但是只需要创建一个nfs4_state_owner就可以了。如果用户多次打开同一个文件,则只需要创建一个nfs4_state结构,每次OPEN操作更新这个结构中的数据就可以了。经过OPEN和OPEN_CONFIRM操作,客户端就打开了一个文件,客户端需要解析应答报文,根据应答报文中的数据设置nfs4_state。这篇文章中我们就讲讲这个设置过程。同样,我们现在只讲解最简单的情况:打开了服务器端存在的一个文件,而且没有分配delegation。
nfs4_state的设置过程是在函数nfs4_opendata_to_nfs4_state中完成的,这个函数的代码如下:
参数data:这是OPEN和OPEN_CONFIRM操作中使用的数据结构,保存了这两个操作中的所有信息。
static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
{
struct inode *inode;
struct nfs4_state *state = NULL;
struct nfs_delegation *delegation;
int ret;
// data->rpc_done表示RPC操作是否正常完成了
if (!data->rpc_done) { // RPC操作没有正常结束。一般情况下,执行不到if语句中。
state = nfs4_try_open_cached(data); // 暂时不讲解这个函数,后面的文章中讲解
goto out;
}
ret = -EAGAIN;
// OPEN操作不是执行OPEN一个请求,而是执行了四个请求:PUTFH、OPEN、GETFH、GETATTR
// GETATTR请求中会获取文件的一些属性信息。如果获取文件属性过程出错了,就直接退出。
if (!(data->f_attr.valid & NFS_ATTR_FATTR))
goto err;
// 获取文件索引节点,并更新文件的属性.
inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr);
ret = PTR_ERR(inode);
if (IS_ERR(inode))
goto err;
ret = -ENOMEM;
// 查找符合条件的nfs4_state结构,如果不存在就创建一个,查找条件是文件索引节点和用户信息。
// 用户发起OPEN请求前已经创建了nfs4_state结构,前面的文章中介绍过这个函数了。
state = nfs4_get_open_state(inode, data->owner); // 这里增加了state的引用计数
if (state == NULL)
goto err_put_inode; // 没有合适的nfs4_state结构
// 暂时不考虑delegation,因此if中的语句直接跳过.
if (data->o_res.delegation_type != 0) {
struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
int delegation_flags = 0;
rcu_read_lock();
delegation = rcu_dereference(NFS_I(inode)->delegation);
if (delegation)
delegation_flags = delegation->flags;
rcu_read_unlock();
if (data->o_arg.cla