设置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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章