設置layout

    layout需要MDS、DS和客戶端三方共同支持,當客戶端通過GETATTR請求獲取了layout類型後,還需要檢查自己是否支持這種類型,客戶端檢查、設置layout的函數是set_pnfs_layoutdriver()。

    RFC5661定義了三種layout,三種layout的編號依次爲

enum pnfs_layouttype {
        LAYOUT_NFSV4_1_FILES  = 1,
        LAYOUT_OSD2_OBJECTS = 2,
        LAYOUT_BLOCK_VOLUME = 3,
};
layout編號從1開始,0是一個保留序號,不允許出現編號爲0的layout類型。

客戶端與pNFS相關的數據結構是struct pnfs_layoutdriver_type,這個數據結構很恐怖,包含了很多函數:

struct pnfs_layoutdriver_type {
        // 這個數據結構鏈接到全局鏈表pnfs_modules_tbl中
        struct list_head pnfs_tblid;
        const u32 id;           // 這種layout類型的編號.
        const char *name;       // 這種layout類型的名稱
        struct module *owner;   // 模塊
        unsigned flags;         // 一些標誌位

        int (*set_layoutdriver) (struct nfs_server *, const struct nfs_fh *);
        int (*clear_layoutdriver) (struct nfs_server *);

        struct pnfs_layout_hdr * (*alloc_layout_hdr) (struct inode *inode, gfp_t gfp_flags);
        void (*free_layout_hdr) (struct pnfs_layout_hdr *);

        struct pnfs_layout_segment * (*alloc_lseg) (struct pnfs_layout_hdr *layoutid, struct nfs4_layoutget_res *lgr, gfp_t gfp_flags);
        void (*free_lseg) (struct pnfs_layout_segment *lseg);

        /* test for nfs page cache coalescing */
        const struct nfs_pageio_ops *pg_read_ops; 
        const struct nfs_pageio_ops *pg_write_ops;

        struct pnfs_ds_commit_info *(*get_ds_info) (struct inode *inode);
        void (*mark_request_commit) (struct nfs_page *req,
                                     struct pnfs_layout_segment *lseg,
                                     struct nfs_commit_info *cinfo);
        void (*clear_request_commit) (struct nfs_page *req,
                                      struct nfs_commit_info *cinfo);
        int (*scan_commit_lists) (struct nfs_commit_info *cinfo,
                                  int max);
        void (*recover_commit_reqs) (struct list_head *list,
                                     struct nfs_commit_info *cinfo);
        int (*commit_pagelist)(struct inode *inode,
                               struct list_head *mds_pages,
                               int how,
                               struct nfs_commit_info *cinfo);

        /*
         * Return PNFS_ATTEMPTED to indicate the layout code has attempted
         * I/O, else return PNFS_NOT_ATTEMPTED to fall back to normal NFS
         */
        enum pnfs_try_status (*read_pagelist) (struct nfs_read_data *nfs_data);
        enum pnfs_try_status (*write_pagelist) (struct nfs_write_data *nfs_data, int how);

        void (*free_deviceid_node) (struct nfs4_deviceid_node *);

        void (*encode_layoutreturn) (struct pnfs_layout_hdr *layoutid,
                                     struct xdr_stream *xdr,
                                     const struct nfs4_layoutreturn_args *args);

        void (*cleanup_layoutcommit) (struct nfs4_layoutcommit_data *data);

        void (*encode_layoutcommit) (struct pnfs_layout_hdr *layoutid,
                                     struct xdr_stream *xdr,
                                     const struct nfs4_layoutcommit_args *args);
};

現在暫時不講這些函數,後面用到的時候再講。file layout中這個數據結構定義如下:

static struct pnfs_layoutdriver_type filelayout_type = {
        .id                     = LAYOUT_NFSV4_1_FILES,
        .name                   = "LAYOUT_NFSV4_1_FILES",
        .owner                  = THIS_MODULE,
        .alloc_layout_hdr       = filelayout_alloc_layout_hdr,
        .free_layout_hdr        = filelayout_free_layout_hdr,
        .alloc_lseg             = filelayout_alloc_lseg,
        .free_lseg              = filelayout_free_lseg,
        .pg_read_ops            = &filelayout_pg_read_ops,
        .pg_write_ops           = &filelayout_pg_write_ops,
        .get_ds_info            = &filelayout_get_ds_info,
        .mark_request_commit    = filelayout_mark_request_commit,
        .clear_request_commit   = filelayout_clear_request_commit,
        .scan_commit_lists      = filelayout_scan_commit_lists,
        .recover_commit_reqs    = filelayout_recover_commit_reqs,
        .commit_pagelist        = filelayout_commit_pagelist,
        .read_pagelist          = filelayout_read_pagelist,
        .write_pagelist         = filelayout_write_pagelist,
        .free_deviceid_node     = filelayout_free_deveiceid_node,
};

    這個數據結構保存在struct nfs_server中了,表示這個NFS文件系統使用的layout類型。

struct nfs_server {
        ......
        struct pnfs_layoutdriver_type  *pnfs_curr_ld;
        ......
}
    另外,客戶端還定義了一個全局鏈表pnfs_modules_tbl,這個鏈表中保存的也是struct pnfs_layoutdriver_type。因爲layout最多有三種類型,因此這個鏈表中最多有三個元素。現在可以講解了set_pnfs_layoutdriver()。

void
set_pnfs_layoutdriver(struct nfs_server *server, const struct nfs_fh *mntfh,
                      u32 id)
{
        struct pnfs_layoutdriver_type *ld_type = NULL;

        // 編號爲0的layout類型已經預留了,表示不使用layout.
        if (id == 0)
                goto out_no_driver;
	// EXCHGID4_FLAG_USE_PNFS_MDS、EXCHGID4_FLAG_USE_NON_PNFS表示服務器角色,
	// 這些標誌位是通過EXCHANGE_ID獲取的.
        if (!(server->nfs_client->cl_exchange_flags &
                 (EXCHGID4_FLAG_USE_NON_PNFS | EXCHGID4_FLAG_USE_PNFS_MDS))) {
                printk(KERN_ERR "NFS: %s: id %u cl_exchange_flags 0x%x\n",
                        __func__, id, server->nfs_client->cl_exchange_flags);
                goto out_no_driver;
        }
	// 在全局鏈表pnfs_modules_tbl中查找是否已經加載這個layout驅動了.
        ld_type = find_pnfs_driver(id);
        if (!ld_type) {         // 這個內核模塊還沒有加載
                // nfs_layout_nfsv41_files.ko  blocklayoutdriver.ko  objlayoutdriver.ko
		// 好吧,加載這個內核模塊.
                request_module("%s-%u", LAYOUT_NFSV4_1_MODULE_PREFIX, id);
                ld_type = find_pnfs_driver(id);         // 再次查找
                if (!ld_type) {         // 還是沒有找到,只好出錯了.
                        dprintk("%s: No pNFS module found for %u.\n",
                                __func__, id);
                        goto out_no_driver;
                }
        }

	// 客戶端已經加載這個layout驅動程序了
	// 關聯到這個nfs_server結構中.
        server->pnfs_curr_ld = ld_type;
        // 如果layoutdriver定義了set_layoutdriver,就需要先執行這個函數
        // file layout沒有定義這個函數,因此就不看了。
        if (ld_type->set_layoutdriver
            && ld_type->set_layoutdriver(server, mntfh)) {
                // 但是函數執行過程中出錯了
                printk(KERN_ERR "NFS: %s: Error initializing pNFS layout "
                        "driver %u.\n", __func__, id);
                module_put(ld_type->owner);
                goto out_no_driver;
        }
        /* Bump the MDS count */
	// 增加NFS客戶端源數據服務器的數量
        atomic_inc(&server->nfs_client->cl_mds_count);

        dprintk("%s: pNFS module for %u set\n", __func__, id);
        return;

out_no_driver:
        dprintk("%s: Using NFSv4 I/O\n", __func__);
        server->pnfs_curr_ld = NULL;
}
    這個函數邏輯很簡單,首先根據從MDS獲取的layout類型編號在全局鏈表pnfs_modules_tbl中查找對應的pnfs_layoutdriver_type結構。如果找到了,說明已經加載這種layout的驅動程序了。如果沒有找到,則首先加載這種layout的驅動程序,然後添加到全局鏈表中。最後設置nfs_server結構中的指針pnfs_curr_ld就可以了。

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