对state 和 delegation一直没有准确的认识,通过下面这个函数可以大概有个了解。
服务器端,nfs4_file结构中有链表layout_state,
当客户端打开某个文件第一次获取get_layout 时候,ls = find_get_layout_state(clp, fp);是找不到对应的ls的
然后会调用verify_stateid()函数,到lockstateid_hashtbl[hashval]和stateid_hashtbl[hashval]这两个全局变量,以及nfs4_file结构中的delegation链表中查找,看是否有相等的stateid,若有,则调用ls = alloc_init_layout_state(clp, fp, stateid);创建一个layout_stateid。
lock_stateid[]这个全局变量,会在nfsd4_lock()这个接口中,添加进去一个nfs4_stateid,
stateid_hashtbl[]这个全局变量是在open的时候添加进去的。
static int
verify_stateid(struct nfs4_file *fp, stateid_t *stateid)
{
struct nfs4_stateid *local = NULL;
struct nfs4_delegation *temp = NULL;
/* check if open or lock stateid */
local = find_stateid(stateid, RD_STATE);
if (local)
return 0;
temp = find_delegation_stateid(fp->fi_inode, stateid);
if (temp)
return 0;
return nfserr_bad_stateid;
}
nfs4_process_layout_stateid(struct nfs4_client *clp, struct nfs4_file *fp,
stateid_t *stateid, struct nfs4_layout_state **lsp){
struct nfs4_layout_state *ls = NULL;
__be32 status = 0;
dprintk("--> %s clp %p fp %p \n", __func__, clp, fp);
dprintk("%s: operation stateid=" STATEID_FMT "\n", __func__,
STATEID_VAL(stateid));
status = nfs4_check_stateid(stateid);
if (status)
goto out;
/* Is this the first use of this layout ? */
spin_lock(&layout_lock);
ls = find_get_layout_state(clp, fp);
spin_unlock(&layout_lock);
if (!ls) {
/* Only alloc layout state on layoutget (which sets lsp). */
if (!lsp) {
dprintk("%s ERROR: Not layoutget & no layout stateid\n",
__func__);
status = nfserr_bad_stateid;
goto out;
}
dprintk("%s Initial stateid for layout: file %p client %p\n",
__func__, fp, clp);
/* verify input stateid */
status = verify_stateid(fp, stateid);
if (status < 0) {
dprintk("%s ERROR: invalid open/deleg/lock stateid\n",
__func__);
goto out;
}
ls = alloc_init_layout_state(clp, fp, stateid);
if (!ls) {
dprintk("%s pNFS ERROR: no memory for layout state\n",
__func__);
status = nfserr_resource;
goto out;
}
} else {
dprintk("%s Not initial stateid. Layout state %p file %p\n",
__func__, ls, fp);
/* BAD STATEID */
status = nfserr_bad_stateid;
if (memcmp(&ls->ls_stateid.si_opaque, &stateid->si_opaque,
sizeof(stateid_opaque_t)) != 0) {
/* if a LAYOUTGET operation and stateid is a valid
* open/deleg/lock stateid, accept it as a parallel
* initial layout stateid
*/
if (lsp && ((verify_stateid(fp, stateid)) == 0)) {
dprintk("%s parallel initial layout state\n",
__func__);
goto update;
}
dprintk("%s ERROR bad opaque in stateid 1\n", __func__);
goto out_put;
}
/* stateid is a valid layout stateid for this file. */
if (stateid->si_generation > ls->ls_stateid.si_generation) {
dprintk("%s bad stateid 1\n", __func__);
goto out_put;
}
update:
update_stateid(&ls->ls_stateid);
dprintk("%s Updated ls_stateid to %d on layoutstate %p\n",
__func__, ls->ls_stateid.si_generation, ls);
}
status = 0;
/* Set the stateid to be encoded */
memcpy(stateid, &ls->ls_stateid, sizeof(stateid_t));
/* Return the layout state if requested */
if (lsp) {
get_layout_state(ls);
*lsp = ls;
}
dprintk("%s: layout stateid=" STATEID_FMT "\n", __func__,
STATEID_VAL(&ls->ls_stateid));
out_put:
dprintk("%s PUT LO STATE:\n", __func__);
put_layout_state(ls);
out:
dprintk("<-- %s status %d\n", __func__, htonl(status));
return status;