OPEN(一)

1.OPEN請求報文和應答報文中的數據

        OPEN操作比較複雜,涉及到很多種特殊情況。按照RFC3530的規定,OPEN請求報文中需要包含下列數據:

struct OPEN4args {
        seqid4          seqid;          // 這是一個序號,保證請求能夠序列化.
        uint32_t        share_access;   // 這是用戶請求的訪問權限
        uint32_t        share_deny;     // 一定不能有這些權限,Linux中固定設置爲0.
        open_owner4     owner;          // clientid + 這次OPEN操作的名稱.
        openflag4       openhow;        // 有兩個取值:OPEN4_NOCREATE和OPEN4_CREATE
        open_claim4     claim;          // 有四個取值:CLAIM_NULL、CLAIM_PREVIOUS、CLAIM_DELEGATE_CUR、CLAIM_DELEGATE_PREV
};

        owner包含兩個字段:clientid和這次操作的名稱,  服務器端可以根據clientid和OPEN操作的名稱查找是否已經保存了這次操作的信息。seqid是OPEN操作的序號,保證多個OPEN操作序列化執行。share_access是用戶打開文件時請求的訪問權限,share_deny是爲Windows share reservation設置的字段,Linux系統中這個字段固定爲0。openhow表示如果文件不存在是否創建一個新文件。claim表示OPEN類型,按照按照claim值不同,OPEN操作分爲四種類型。這篇文>章中,我們只講解最常見的一種情況:打開服務器端存在的一個文件。這種請求中claim的類型是CLAIM_NULL。這種情況下,open_claim4中還包含了文件的名>稱,這是我們要打開的文件。

    按照RFC3530的規定,OPEN操作應答報文包含下列內容

struct OPEN4resok {
        stateid4        stateid;        /* Stateid for open */
        change_info4    cinfo;          /* Directory Change Info */
        uint32_t        rflags;         /* Result flags */
        bitmap4         attrset;        /* attributes on create */
        open_delegation4 delegation;    /* Info on any open
                                           delegation */
}; 
        stateid固定長度爲16字節,代表了這個打開的文件,後續發起READ、WRITE操作時需要將這個stateid包含在請求報文中,服務器根據stateid查找對應的>文件。cinfo包含了父目錄的屬性信息。rflags是一些標誌位,目前定義了兩個標誌位:

   const OPEN4_RESULT_CONFIRM      = 0x00000002;    // 應答報文中的stateid不能馬上使用,需要發起OPEN_CONFIRM請求。
   const OPEN4_RESULT_LOCKTYPE_POSIX = 0x00000004;  // 服務器支持POSIX文件鎖

        如果OPEN請求報文中openhow字段的值爲NFS4_CREATE,則服務器端可以創建一個新的文件,應答消息中的attrset就包含了新創建文件的屬性信息。應答消息最後一個字段是delegation的信息,RFC3530定義了三種取值:

    OPEN_DELEGATE_NONE   // 沒有使用delegation
    OPEN_DELEGATE_READ   // 讀操作使用的delegation
    OPEN_DELEGATE_WRITE  // 寫操作使用的delegation

        OPEN_DELEGATE_READ表示讀操作中使用的delegation。如果文件以只讀方式打開,則可以申請這種delegation。一個客戶端的多個用戶或者不同的客戶端可以共享同一個OPEN_DELEGATE_READ,因爲多個用戶同時執行讀操作不會造成衝突。當另外一個用戶試圖向文件中寫入數據時服務器會回收OPEN_DELEGATE_READ。OPEN_DELEGATE_WRITE表示寫操作中使用的delegation,OPEN_DELEGATE_WRITE只能被一個用戶獨佔。當另一個用戶向文件寫入數據時服務器會回收OPEN_DELEGATE_WRITE。具體實現中,Linux沒有實現OPEN_DELEGATE_WRITE。


2.客戶端程序

        客戶端設置OPEN請求報文中數據的函數是nfs4_opendata_alloc(),這個函數的代碼如下:

參數dentry:這是要打開的文件在客戶端的目錄項結構

參數sp:這表示客戶端的一個用戶,就是這個用戶要打開文件

參數fmode:這是文件的打開權限,讀權限還是寫權限

參數flags:這是打開文件時指定的一些標誌位,如O_CREAT表示如何文件不存在就創建一個新文件

參數attrs:這是爲新創建的文件設置的屬性信息,如訪問權限。

參數gfp_mask:這是分配內存時使用的標誌位

static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
		struct nfs4_state_owner *sp, fmode_t fmode, int flags,
		const struct iattr *attrs,
		gfp_t gfp_mask)
{
	struct dentry *parent = dget_parent(dentry);	// 獲取父目錄的目錄項結構
	struct inode *dir = parent->d_inode;		// 這是父目錄的索引節點
	struct nfs_server *server = NFS_SERVER(dir);	// 文件系統結構
	struct nfs4_opendata *p;

	p = kzalloc(sizeof(*p), gfp_mask);		// 分配內存
	if (p == NULL)
		goto err;	// 分配內存失敗
	// 這時分配了一個nfs_seqid結構,暫時沒有鏈接到nfs_seqid_counter中
	p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask);
	if (p->o_arg.seqid == NULL)	// seqid分配失敗.
		goto err_free;
	nfs_sb_active(dentry->d_sb);
	p->dentry = dget(dentry);	// 這是要打開文件的目錄項結構
	p->dir = parent;	// 設置父目錄的索引節點
	p->owner = sp;		// nfs4_state_owner結構
	atomic_inc(&sp->so_count);	// 增加這個結構的引用計數
	p->o_arg.fh = NFS_FH(dir);	// 父目錄的文件句柄
	p->o_arg.open_flags = flags;	// 打開目標文件時設置的標誌信息,如O_CREAT
	p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);	// 文件的訪問模式
	p->o_arg.clientid = server->nfs_client->cl_clientid;	// 這表示一個NFS客戶端
	// nfs_seqid_counter的創建時間
	p->o_arg.id.create_time = ktime_to_ns(sp->so_seqid.create_time);
	// 這是客戶端爲nfs4_state_owner結構設置的編號
	p->o_arg.id.uniquifier = sp->so_seqid.owner_id;
	p->o_arg.name = &dentry->d_name;	// 目標文件的名稱
	p->o_arg.server = server;		// nfs_server結構
	p->o_arg.bitmask = server->attr_bitmask;	// NFS服務器端文件系統支持的屬性信息
	p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];	// 需要查找的基本屬性信息
	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;		// 正常打開文件.
	// 這是爲OPEN4_CREATE設置的信息
	if (attrs != NULL && attrs->ia_valid != 0) {
		__be32 verf[2];

		p->o_arg.u.attrs = &p->attrs;
		memcpy(&p->attrs, attrs, sizeof(p->attrs));

		verf[0] = jiffies;		// 當前時間
		verf[1] = current->pid;		// 進程的pid
		memcpy(p->o_arg.u.verifier.data, verf,
				sizeof(p->o_arg.u.verifier.data));
	}
	p->c_arg.fh = &p->o_res.fh;
	p->c_arg.stateid = &p->o_res.stateid;
	p->c_arg.seqid = p->o_arg.seqid;
	nfs4_init_opendata_res(p);
	kref_init(&p->kref);
	return p;
err_free:
	kfree(p);
err:
	dput(parent);
	return NULL;
}

        函數encode_open()根據nfs4_opendata_alloc()設置的信息封裝OPEN請求報文。

static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, struct compound_hdr *hdr)
{
        encode_op_hdr(xdr, OP_OPEN, decode_open_maxsz, hdr);    // OPEN請求編號
        encode_openhdr(xdr, arg);
        encode_opentype(xdr, arg);     // openhow,取值爲OPEN4_CREATE或者OPEN4_NOCREATE
        switch (arg->claim) {             // claim  通常情況下取值是NFS4_OPEN_CLAIM_NULL
        case NFS4_OPEN_CLAIM_NULL:
                encode_claim_null(xdr, arg->name);
                break;
        case NFS4_OPEN_CLAIM_PREVIOUS:
                encode_claim_previous(xdr, arg->u.delegation_type);
                break;
        case NFS4_OPEN_CLAIM_DELEGATE_CUR:
                encode_claim_delegate_cur(xdr, arg->name, &arg->u.delegation);
                break;
        default:
                BUG();
        }
}


static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg)
{
        __be32 *p;
 /*
 * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
 * owner 4 = 32
 */
        // 這是seqid
        encode_nfs4_seqid(xdr, arg->seqid);     // arg->seqid->sequence->counter    seqid
        // share_accessed  文件訪問權限    只讀 0x00000001   只寫 0x00000002   讀寫 0x00000003
        // share_deny = 0   always 
        encode_share_access(xdr, arg->fmode);   // 編碼share_access和share_deny
        p = reserve_space(xdr, 36);
        p = xdr_encode_hyper(p, arg->clientid); // 編碼clientid   8字節
        *p++ = cpu_to_be32(24);         // owner 長度固定爲24字節
        p = xdr_encode_opaque_fixed(p, "open id:", 8);  // 8字節
        *p++ = cpu_to_be32(arg->server->s_dev);         // 4字節        // 設備號
        *p++ = cpu_to_be32(arg->id.uniquifier);         // nfs4_state_owner結構的編號  4字節
        xdr_encode_hyper(p, arg->id.create_time);       // nfs4_state_owner結構的創建時間  8字節
}
對照RFC3530的規定,請求報文中的owner字段由clientid和這次請求操作的名稱兩部分構成,名稱字段長度固定爲24字節,包含了字符串"open id:"(8字節)、NFS文件系統所在設備的設備號(4字節)、用戶信息數據結構的編號(4字節)、用戶信息結構的創建時間(8字節)。
發佈了70 篇原創文章 · 獲贊 4 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章