GETDEVICEINFO(一)

    这篇文章中我们先说说deviceid。什么是deviceid呢?在使用pNFS的情况下,客户端执行I/O操作前需要先获取文件的layout。同时客户端需要获取DS的详细信息,比如DS的IP地址,否则客户端还是没办法发起I/O请求。deviceid就包含了DS的基本信息。客户端中deviceid用数据结构struct nfs4_deviceid表示:

#define NFS4_DEVICEID4_SIZE 16
struct nfs4_deviceid {
        char data[NFS4_DEVICEID4_SIZE];
};
    deviceid通过LAYOUTGET请求返回给客户端,但是好像从这个数据结构中我们看不到DS的信息。这是因为DS的信息比较多,全部信息放在这个数据结构中操作不方便。因此MDS在LAYOUTGET请求中只提供了一些基本信息,客户端不必(也没办法)解析deviceid。

    客户端可能存在多个deviceid,为了便于管理,客户端定义了一个数据结构struct nfs4_deviceid_node,每个nfs4_deviceid_node结构表示一个deviceid。

struct nfs4_deviceid_node {
        struct hlist_node               node;           // 链接到全局hash表中nfs4_deviceid_cache
        struct hlist_node               tmpnode;        // 链接到一个临时链表中.
        const struct pnfs_layoutdriver_type *ld;        // layout类型
        const struct nfs_client         *nfs_client;    // NFS客户端
        unsigned long                   flags;          // 一些标志位
        unsigned long                   timestamp_unavailable;  // 这是一个时间戳
        struct nfs4_deviceid            deviceid;       // deviceid
        atomic_t                        ref;            // 引用计数
};
nfs4_deviceid_node中包含两个标志位:

enum {
        NFS_DEVICEID_INVALID = 0,       /* set when MDS clientid recalled */
        NFS_DEVICEID_UNAVAILABLE,       /* device temporarily unavailable */
};

    NFS_DEVICEID_INVALID表示这是一个无效的deviceid,绝对不要使用这个deviceid了。NFS_DEVICEID_UNAVAILABLE表示这个deviceid有效,但是临时不可用,比如网络故障。如果在一定的时间内(120秒)网络正常了,客户端就会清除这个标志位。timestamp_unavailable就是设置标志位NFS_DEVICEID_UNAVAILABLE的时间。

    客户端还定义了一个hash表nfs4_deviceid_cache,用来保存客户端所有的deviceid。
static struct hlist_head nfs4_deviceid_cache[NFS4_DEVICE_ID_HASH_SIZE];    // #define NFS4_DEVICE_ID_HASH_SIZE  32

    当接收到deviceid后客户端可以向MDS发起GETDEVICEINFO请求,这个请求会返回DS的详细信息。file layout中,GETDEVICEINFO请求返回的信息保存在数据结构struct nfs4_file_layout_dsaddr中了,这个数据结构定义如下:

struct nfs4_file_layout_dsaddr {
        struct nfs4_deviceid_node       id_node;        // deviceid
        u32                             stripe_count;   // Stripe Count
        u8                              *stripe_indices;// Stripe 信息
        u32                             ds_num;         // DS组的数量
        struct nfs4_pnfs_ds             *ds_list[1];    // DS组中每个DS的地址信息
};
    因此,前面介绍的数据结构nfs4_deviceid_node其实包含在数据结构nfs4_file_layout_dsaddr中。LAYOUTGET填充了nfs4_file_layout_dsaddr中的id_node字段,GETDEVICEINFO负责填充其他字段。前面的文章中介绍过,pNFS对DS进行了分组处理,每个DS组中包含多个DS。ds_list其实是一个指针数组,包含了pNFS中所有DS组的地址。struct nfs4_pnfs_ds是一个DS组的数据结构,定义如下:
struct nfs4_pnfs_ds {
        // 将这个nfs4_pnfs_ds结构链接到全局链表nfs4_data_server_cache中.
        struct list_head        ds_node;  /* nfs4_pnfs_dev_hlist dev_dslist */
        // 这个字段应该是为调试准备的,没有实际用处.
        char                    *ds_remotestr;  /* comma sep list of addrs */
        // 这是一个链表头,链表中保存的数据结构是nfs4_pnfs_ds_addr,每个nfs4_pnfs_ds_addr表示一个ds.
        struct list_head        ds_addrs;
        // 这是为DS创建的客户端结构,这个客户端负责跟DS通信.
        struct nfs_client       *ds_clp;
        atomic_t                ds_count;       // DS组中DS的数量.
};

    因为DS组中包含了多个DS,索引struct nfs4_pnfs_ds中定义了一个链表,链表中每个元素代表一个DS。还需要注意的一点是ds_clp字段,按照RFC5661的规定,每个DS组中包含多个DS,客户端向组中每个DS发起I/O请求是等效的,因此客户端会随便挑选一个DS。但是发起I/O请求前需要先与这个DS客户端连接起来,ds_clp是发起I/O请求前创建的一个新的客户端,这个新客户端的作用是与DS通信。所有I/O请求通过这个新的客户端发送。

    表示一个DS地址的数据结构是struct nfs4_pnfs_ds_addr,这个数据结构定义如下:
struct nfs4_pnfs_ds_addr {
        struct sockaddr_storage da_addr;        // 这是一个DS的地址.
        size_t                  da_addrlen;     // DS地址的长度.
        // 负责将这个DS链接到链表nfs4_pnfs_ds.ds_addrs中.
        struct list_head        da_node;  /* nfs4_pnfs_dev_hlist dev_dslist */
        // 这是字符串形式的DS地址,没什么用处.
        char                    *da_remotestr;  /* human readable addr+port */
};

    现在可以介绍nfs4_find_get_deviceid()和filelayout_get_device_info()了。nfs4_find_get_deviceid()就是在nfs4_deviceid_cache中查找是否有符合条件的nfs4_deviceid_node结构。如果找到了,说明客户端以前获取过DS的地址信息了,就不需要发起GETDEVICEINFO请求了。查找条件有三个:客户端、layout类型、deviceid。如果没有找到符合条件的nfs4_deviceid_node结构,就说明客户端还没有获取DS的信息,这种情况下就会调用filelayout_get_device_info(),这个函数会发起GETDEVICEINFO请求,然后创建一个新的nfs4_file_layout_dsaddr结构,用应答报文中的信息填充这个结构,最后将这个结构添加到nfs4_deviceid_cache中。GETDEVICEINFO请求报文中需要包含下列数据:

   struct GETDEVICEINFO4args {
           deviceid4       gdia_device_id;       // 这是一个deviceid,就是在请求这个device的详细信息。
           layouttype4     gdia_layout_type;    // layout类型
           count4          gdia_maxcount;     // 应答报文中数据的最大长度
           bitmap4         gdia_notify_types;   // 这是一种通知机制
   };
    gdia_notify_types表示一种通知机制。什么意思呢?当MDS中deviceid发生变化时MDS可以将这个事件告诉客户端,客户端接收到这个消息后就可以进行一些处理了。RFC5661定义了两种通知事件

NOTIFY_DEVICEID4_CHANGE   当deviceid发生变化时通知客户端
NOTIFY_DEVICEID4_DELETE   当deviceid删除时通知客户端

就不讲解GETDEVICEINFO请求的发起过程了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值