LAYOUTGET(四)

    前面一篇文章讲到了nfs4_pnfs_get_layout()最终调用struct pnfs_export_operations结构中的layout_get()创建一个新的layout,这篇文章中就详细讲讲file layout中layout的创建过程。file layout中的pnfs_export_operations定义如下:

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,
};

    因此,file layout中最终调用了nfsd4_pnfs_dlm_layoutget()创建新的layout。这个函数不复杂,因为pNFS正在实现过程中,还没有整合进标准的内核代码,因此很多地方只考虑了最基本的情况,nfsd4_pnfs_dlm_layoutget()中很多数据都是固定的。首先看一个数据结构struct pnfs_filelayout_layout,这个数据结构定义如下:

// 这是一个file layout的数据结构.
struct pnfs_filelayout_layout {
        // layout类型,这里当然是file layout了。
        u32                             lg_layout_type; /* response */
        // 数据分发方式,DENSE还是SPARSE.
        u32                             lg_stripe_type; /* response */
        // COMMIT请求是提交给MDS还是DS.
        u32                             lg_commit_through_mds; /* response */   
        // file layout中每个Stripe Unit的大小
        u64                             lg_stripe_unit; /* response */
        // pattern在文件中的起始位置
        u64                             lg_pattern_offset; /* response */
        // 客户端应该首先向哪个DS组传输数据.
        u32                             lg_first_stripe_index;  /* response */
        // deviceid
        struct nfsd4_pnfs_deviceid      device_id;              /* response */
        // 应答报文中文件句柄数量
        u32                             lg_fh_length;           /* response */  
        // 这是返回给客户端的文件句柄,客户端向DS传输数据时使用这组文件句柄.
        struct knfsd_fh                 *lg_fh_list;            /* response */  
};
这个数据结构中包含了LAYOUTGET应答报文中的各种信息,nfsd4_pnfs_dlm_layoutget()的作用就是填充这个数据结构,然后将数据封装进LAYOUTGET应答报文中,这个函数代码如下:

static enum nfsstat4 nfsd4_pnfs_dlm_layoutget(struct inode *inode,      // 这是文件索引节点,就是获取这个文件的layout信息.
                           struct exp_xdr_stream *xdr,
                           const struct nfsd4_pnfs_layoutget_arg *args, // 这是LAYOUTGET的参数
                           struct nfsd4_pnfs_layoutget_res *res)        // 这是LAYOUTGET的返回值
{
        struct pnfs_filelayout_layout *layout = NULL;
        struct knfsd_fh *fhp = NULL;
        int index;
        enum nfsstat4 rc = NFS4_OK;

        dprintk("%s: LAYOUT_GET\n", __func__);

        /* DLM exported file systems only support layouts for READ */
	// file layout目前只支持读操作
	// DLM是distributed lock manager的缩写,这是一种分布式锁机制,GFS文件系统依赖这种锁机制实现数据同步.
        if (res->lg_seg.iomode == IOMODE_RW)
                return NFS4ERR_BADIOMODE;

        // 第一个I/O操作应该发给哪个DS组.
        index = dlm_ino_hash(inode);
        dprintk("%s first stripe index %d i_ino %lu\n", __func__, index,
                inode->i_ino);
        if (index < 0)
                return NFS4ERR_LAYOUTUNAVAILABLE; 

        res->lg_seg.layout_type = LAYOUT_NFSV4_1_FILES;         // file_layout.
        /* Always give out whole file layouts */
	// file layout目前只能返回这个文件的layout,与用户请求的layout范围无关.
        res->lg_seg.offset = 0;                 // 偏移是0
        res->lg_seg.length = NFS4_MAX_UINT64;   // 最大长度
        /* Always give out READ ONLY layouts */
        res->lg_seg.iomode = IOMODE_READ;       // 只能是读方式.

        layout = kzalloc(sizeof(*layout), GFP_KERNEL); 
        if (layout == NULL) {
                rc = NFS4ERR_LAYOUTTRYLATER;
                goto error;
        }

        /* Set file layout response args */
        layout->lg_layout_type = LAYOUT_NFSV4_1_FILES;          // file layout.
        layout->lg_stripe_type = STRIPE_SPARSE;		// 目前固定支持SPARSE方式
        layout->lg_commit_through_mds = false;          // 将COMMIT请求提交给DS
	// 计算Stripe Unit的大小
        layout->lg_stripe_unit = get_stripe_unit(inode->i_sb->s_blocksize);
        // 只有一个文件句柄,所有的DS使用同一个文件句柄.
        layout->lg_fh_length = 1;
	// 组装deviceid.
        layout->device_id.sbid = args->lg_sbid;
        layout->device_id.devid = 1;                                /*FSFTEMP*/
        // 第一个I/O操作应该发给哪个DS组.
        layout->lg_first_stripe_index = index;                      /*FSFTEMP*/
	// pattern在文件中的偏移是0.
        layout->lg_pattern_offset = 0;

	// 为文件句柄分配内存,这个文件句柄供客户端和DS传输数据时使用.
        fhp = kmalloc(sizeof(*fhp), GFP_KERNEL);
        if (fhp == NULL) {
                rc = NFS4ERR_LAYOUTTRYLATER;
                goto error;
        }

	// 下面在组装供客户端和DS传输数据时使用的文件句柄.
        memcpy(fhp, args->lg_fh, sizeof(*fhp));
        pnfs_fh_mark_ds(fhp);
        layout->lg_fh_list = fhp;

        /* Call nfsd to encode layout */
	// 这是应答消息封装函数,将layout的信息封装进应答报文了.
        rc = filelayout_encode_layout(xdr, layout);
exit:
        kfree(layout);
        kfree(fhp);
        return rc;
error:
        res->lg_seg.length = 0;
        goto exit;
}
    看这个函数时可以参考前面介绍file layout的这篇文章: http://blog.csdn.net/ycnian/article/details/8719051。可以看到,struct pnfs_filelayout_layout结构中大部分字段都是固定值,只有几个值经过了计算,但是这些计算也都很简单。

计算从哪个DS分组开始使用,代码如下:

static int dlm_ino_hash(struct inode *ino)
{
        struct dlm_device_entry *de;
        u32 hash_mask = 0;

        /* If can't find the inode block device in the pnfs_dlm_deivce list
         * then don't hand out a layout
         */
        // 根据文件系统所在设备的名称查找对应的的dlm_device_entry结构.
        de = nfsd4_find_pnfs_dlm_device(ino->i_sb);
        if (!de)
                return -1;      // 没有找到
        hash_mask = de->num_ds - 1;     // de->num_ds是DS组的数量
        return ino->i_ino & hash_mask;  // 就是随机选择了一个DS组
}

可以看出,就是随机选择了一个DS分组。

Stripe Unit大小的计算方式如下:

static int get_stripe_unit(int blocksize)
{
        // 如果超出了RPC限制,Stripe Unit大小就是数据块大小,
        // 每个数据块传输给一个DS组.
        if (blocksize >= NFSSVC_MAXBLKSIZE)
                return blocksize;
        // 结果是blocksize的倍数.
        // 在不超过RPC限制的条件下,尽可能将多一些数据块传输给DS组.
        return NFSSVC_MAXBLKSIZE - (NFSSVC_MAXBLKSIZE % blocksize);
}
这个函数只生成了一个文件句柄,所有的DS都使用这个文件句柄,文件句柄的组装方式如下:

static inline void pnfs_fh_mark_ds(struct knfsd_fh *fh)
{
        BUG_ON(fh->fh_version != 1);
        BUG_ON(pnfs_fh_is_ds(fh));
        fh->fh_fsid_type += FSID_MAX;
}

        memcpy(fhp, args->lg_fh, sizeof(*fhp));
        pnfs_fh_mark_ds(fhp);
        layout->lg_fh_list = fhp;
从上面这个函数可以看出,DS就使用MDS的文件句柄,只是修改了fsid type。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值