獲取layout類型

    NFSv4.1支持三種layout類型:file layout、object layout、block layout,這三種layout對數據讀寫過程的處理方式不同。因此pNFS系統中,客戶端首先需要獲取layout類型,這是在掛載文件系統時實現的。客戶端掛載文件系統時需要發起GETATTR請求,獲取文件系統的基本信息,這個處理函數是nfs4_proc_fsinfo。

static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
{
        int error;

        nfs_fattr_init(fsinfo->fattr);
        error = nfs4_do_fsinfo(server, fhandle, fsinfo);
        if (error == 0) {
                /* block layout checks this! */
                server->pnfs_blksize = fsinfo->blksize;
                set_pnfs_layoutdriver(server, fhandle, fsinfo->layouttype);
        }

        return error;
}

    RFC5661定義了NFS文件系統相關的很多屬性,其中一個屬性是fs_layout_type,這個屬性表示這套pNFS環境中支持的layout類型。當MDS接收到GETATTR請求報文後,如果請求報文中設置了這個屬性位,就會檢查支持的pNFS類型,然後封裝到應答報文中返回給客戶端。客戶端調用set_pnfs_layoutdriver()設置在nfs_server結構中。下一篇文章中再講解這個函數的流程,這篇文章中主要講講MDS查找layout類型的過程。首先介紹一個與layout相關的數據結構struct pnfs_export_operations,這個數據結構定義了MDS中layout相關的函數。NFS是一種網絡文件系統,它必須依附於一種實際的文件系統之上(比如EXT3、JFS等)。如果底層的文件系統支持pNFS,則這種文件系統必須實現struct pnfs_export_operations中定義的方法。這個數據結構定義如下:

struct pnfs_export_operations {
        int (*layout_type) (struct super_block *);

        int (*get_device_info) (struct super_block *,
                                struct exp_xdr_stream *,
                                u32 layout_type,
                                const struct nfsd4_pnfs_deviceid *);
        
        int (*get_device_iter) (struct super_block *,
                                u32 layout_type,
                                struct nfsd4_pnfs_dev_iter_res *);
        
        int (*set_device_notify) (struct super_block *,
                                  struct pnfs_devnotify_arg *);
        
        enum nfsstat4 (*layout_get) (struct inode *,
                                     struct exp_xdr_stream *xdr,
                                     const struct nfsd4_pnfs_layoutget_arg *,
                                     struct nfsd4_pnfs_layoutget_res *);
        
        int (*layout_commit) (struct inode *,
                              const struct nfsd4_pnfs_layoutcommit_arg *,
                              struct nfsd4_pnfs_layoutcommit_res *);
        
        int (*layout_return) (struct inode *,
                              const struct nfsd4_pnfs_layoutreturn_arg *);
        
        int (*can_merge_layouts) (u32 layout_type);
        
        void (*get_verifier) (struct super_block *, u32 *p);
        
        int (*get_state) (struct inode *, struct knfsd_fh *,
                          struct pnfs_get_state *);
};
    這個數據結構中函數很多,看着也很複雜,但是我們通過函數名稱能大概明白每個函數的意思。比如get_device_info()應該是GETDEVICEINFO中調用的函數,laytou_get()應該是LAYOUTGET中調用的函數,layout_return()應該是LAYOUTRETURN中調用的函數,layout_type()應該是獲取layout類型的函數。而且底層文件系統不必實現這個數據結構中所有的函數,根據實際情況實現部分函數就可以了。當然,"實際情況"是什麼,只有這種文件系統的開發者清楚了。在後面的文章中我們將以GFS爲例,GFS文件系統只實現了下列幾個函數:

const struct pnfs_export_operations pnfs_dlm_export_ops = {
        .layout_type = nfsd4_pnfs_dlm_layouttype,
        .get_device_info = nfsd4_pnfs_dlm_getdevinfo,
        .get_device_iter = nfsd4_pnfs_dlm_getdeviter,
        .layout_get = nfsd4_pnfs_dlm_layoutget,
};

    爲了支持pNFS,文件系統超級塊中增加了一個指針 s_pnfs_op,這個指針指向了文件系統layout相關的操作函數集合。當然,這個指針目前只存在於Benny Halevy的代碼樹中,標準內核代碼中還沒有這個指針。

struct super_block {
        ......
        const struct pnfs_export_operations *s_pnfs_op;
        ......
}

    現在可以接着講MDS查找layout類型的過程了。GETATTR請求的處理函數是nfsd4_encode_fattr(),這個函數處理了MDS支持的所有屬性,其中就包含fs_layout_type,處理這個屬性的代碼片段如下:

__be32
nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
                struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval,
                struct svc_rqst *rqstp, int ignore_crossmnt)
{
        ......

        if ((bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) ||
            (bmval2 & FATTR4_WORD2_LAYOUT_TYPES)) {
                // 取出底層文件系統超級塊的數據結構
                struct super_block *sb = dentry->d_inode->i_sb;
                int type = 0;

                /* Query the filesystem for supported pNFS layout types.
                 * Currently, we only support one layout type per file system.
                 * The export_ops->layout_type() returns the pnfs_layouttype4.
                 */
                buflen -= 4;
                if (buflen < 0)         /* length */
                        goto out_resource;

                // 檢查文件系統是否定義了layout_type()函數
                if (sb && sb->s_pnfs_op && sb->s_pnfs_op->layout_type)
                        // 調用layout_tyoe()取出文件系統的layout類型.
                        type = sb->s_pnfs_op->layout_type(sb);
                dprintk("%s: sb=%p s_pnfs_op=%p layout_type()=%p layout_type=%u\n",
                        __func__, sb, sb->s_pnfs_op, sb->s_pnfs_op ? sb->s_pnfs_op->layout_type : NULL, type);
                if (type) {
                        if ((buflen -= 4) < 0)  /* type */
                                goto out_resource;
                        WRITE32(1);     /* length */
                        // 組裝進GETATTR應答報文中.
                        WRITE32(type);  /* type */
                } else
                        WRITE32(0);  /* length */
        }

        if (bmval2 & FATTR4_WORD2_LAYOUT_BLKSIZE) {
                if ((buflen -= 4) < 0)
                        goto out_resource;
                dprintk("%s: layout_blksize=%lu\n", __func__, stat.blksize);
                WRITE32(stat.blksize);
        }

        ......
}
    可以看出,nfsd4_encode_fattr()直接調用底層文件系統的layout_type()獲取layout類型了,而GFS文件系統中這個函數很簡單:

static int
nfsd4_pnfs_dlm_layouttype(struct super_block *sb)
{
        return LAYOUT_NFSV4_1_FILES;
}

講完了。
發佈了70 篇原創文章 · 獲贊 4 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章