ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Linux DRBD-9 内核对象模型详解:resource、connection、device 与 peer_device 矩阵结构

Linux DRBD-9 内核对象模型详解:resource、connection、device 与 peer_device 矩阵结构 Linux DRBD-9 内核对象模型详解resource、connection、device 与 peer_device 矩阵结构【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linuxDRBDDistributed Replicated Block Device是 Linux 内核中一个共享无、同步复制的块设备驱动常被视作网络 RAID 1是构建高可用集群时替代共享存储的基础构件。本文以内核文档>/-----------------------------.....---------------\ | resource | device | | device | -----------------------------.....--------------- | connection | peer_device | | peer_device | -----------------------------.....--------------- : : : : : : : : : : -----------------------------.....--------------- | connection | peer_device | | peer_device | \-----------------------------.....---------------/解读这张图需要把握三条规则均为文档原文的要点且可逐条在源码中得到印证横向同一行device 可以从其 resource 按**卷号volume number**索引到同理peer_device 可以从其 connection 按卷号索引到。纵向同一列/行方向对象之间通过双向链表互联。回指针back pointerspeer_device 指回它所属的 connection 和 deviceconnection 和 device 都指回它们的 resource。与文档对照 drivers/block/drbd/drbd_int.h 中struct drbd_peer_device的定义回指针的说法完全成立struct drbd_peer_device { struct list_head peer_devices; /* 挂入 device-peer_devices 链表 */ struct drbd_device *device; /* 回指针指向本地 device */ struct drbd_connection *connection; /* 回指针指向所属 connection */ struct work_struct send_acks_work; ... };而横向按卷号索引在源码中由idrID Radix tree实现struct drbd_resource中有struct idr devices; /* volume number to device mapping */见 drbd_int.h#L595struct drbd_connection中有struct idr peer_devices; /* volume number to peer device mapping */见 drbd_int.h#L630。查找入口是 drbd_int.h 中的内联函数conn_peer_device()static inline struct drbd_peer_device * conn_peer_device(struct drbd_connection *connection, int volume_number) { return idr_find(connection-peer_devices, volume_number); }这正是文档所说peer_devices can be accessed from connections by their volume number的代码级实现。3. 全局索引drbd_resources 链表与 drbd_devices idr文档指出除了矩阵内部关系外还有两套全局索引所有 resource都挂在drbd_resources这条双向链表中所有 device可以通过次设备号minor device number经drbd_devices这个 idr 查找到。源码中这两个全局对象在 drivers/block/drbd/drbd_main.c 定义并在 drbd_int.h 中导出注释明确写明了并发约束——RCU 保护、更新需持有 genl_lock()/* drbd_int.h */ extern struct idr drbd_devices; /* RCU, updates: genl_lock() */ extern struct list_head drbd_resources; /* RCU, updates: genl_lock() */按 minor 查找 device 的入口是 drbd_int.h#L942-L945static inline struct drbd_device *minor_to_device(unsigned int minor) { return (struct drbd_device *)idr_find(drbd_devices, minor); }resource 的创建与入链过程在 drbd_main.c 的drbd_create_resource()中可以看到全貌分配对象、kref_init()初始化引用计数、idr_init(resource-devices)初始化卷号索引、INIT_LIST_HEAD(resource-connections)初始化连接链表最后list_add_tail_rcu(resource-resources, drbd_resources)把新 resource 以 RCU 方式挂到全局链表尾部——与文档All resources are in the drbd_resources double-linked list一一对应。此外DRBD 代码提供了一整套遍历宏来沿这些结构游走均定义在 drbd_int.h#L958-L983#define for_each_resource(resource, _resources) \ list_for_each_entry(resource, _resources, resources) #define for_each_resource_rcu(resource, _resources) \ list_for_each_entry_rcu(resource, _resources, resources) #define for_each_connection(connection, resource) \ list_for_each_entry(connection, resource-connections, connections) #define for_each_peer_device(peer_device, device) \ list_for_each_entry(peer_device, device-peer_devices, peer_devices)每一组都有普通 /_rcu/_safe三个变体分别对应直接遍历、RCU 读侧遍历和遍历中允许删除的安全遍历。这解释了文档所说的objects are connected by double linked lists在工程上是如何被安全地消费的读路径如 drbd_main.c 中for_each_resource_rcu()无锁写路径如 drbd_main.c#L2333 中for_each_resource_safe()持锁删除。4. 引用计数与对象生命周期文档最后一段明确了四类对象的生命周期规则这是理解整个对象模型谁拥有谁的关键drbd_resource、drbd_connection、drbd_device 对象是引用计数的peer_device 对象仅用于在 device 与 connection 之间建立链接其生命周期由它所引用的 device 和 connection 的生命周期决定。对应源码证据struct drbd_resource内嵌struct kref kref;drbd_int.h#L594struct drbd_connection内嵌struct kref kref;drbd_int.h#L629struct drbd_device内嵌struct kref kref;drbd_int.h#L768而struct drbd_peer_device中没有 kref 成员它只有list_head、两个回指针和一个工作项drbd_int.h#L739-L747。也就是说peer_device 是一个关系对象只要某个 device 还存在、某条 connection 还连着重它们交叉点上的 peer_device 就存在device 或 connection 任一被销毁peer_device 随之消失。这种设计让矩阵的规模卷数 × 连接数不需要额外的生命周期管理代码。5. 结构体要点速查从源码看每类对象持有什么为便于把文档概念落到代码上下面按文档骨架列出四类对象的关键成员摘录自 drivers/block/drbd/drbd_int.h5.1 struct drbd_resourcedrbd_int.h#L586-L610成员作用char *name资源名struct kref kref引用计数struct idr devices卷号 → device 的映射矩阵横向索引struct list_head connections该资源的连接双向链表矩阵纵向struct list_head resources挂入全局drbd_resources链表的节点struct res_opts res_opts资源级配置struct mutex conf_update/adm_mutex配置热更新、管理操作串行化unsigned susp:1; susp_nod:1; susp_fen:1;三种挂起状态用户挂起、无数据挂起、fence 处理挂起enum write_ordering_e write_ordering写排序策略创建时默认WO_BDEV_FLUSH见 drbd_main.c#L2528cpumask_var_t cpu_mask该资源线程绑定的 CPU 掩码5.2 struct drbd_connectiondrbd_int.h#L621-L707成员作用struct list_head connections挂入resource-connections链表的节点struct drbd_resource *resource回指针指向所属资源struct kref kref引用计数struct idr peer_devices卷号 → peer_device 的映射矩阵横向索引enum drbd_conns cstate连接状态文档说明取值范围为 C_STANDALONE 至 C_WF_REPORT_PARAMSstruct net_conf *net_confRCU 保护的网络配置struct drbd_socket data/meta双通道套接字数据/屏障/状态包 与 ping/ack 元数据包分离struct list_head transfer_log尚未完全处理完的请求Transfer Logstruct drbd_thread receiver / worker / ack_receiver接收线程、工作线程、ack 接收线程struct drbd_work_queue sender_work发送侧工作队列可以看到一条 connection 同时承载了矩阵纵列的角色connections链表 resource回指针 peer_devicesidr与完整的网络收发基础设施。5.3 struct drbd_devicedrbd_int.h#L749-L839成员作用struct drbd_resource *resource回指针指向所属资源struct list_head peer_devices该设备上所有 peer_device 的双向链表矩阵纵向unsigned int vnr卷号volume number within the connectionunsigned int minor次设备号是全局drbd_devicesidr 的键struct kref kref引用计数struct drbd_backing_dev *ldev下层块设备drbdsetup 配置struct request_queue *rq_queue/struct gendisk *vdisk暴露给块层的请求队列与虚拟磁盘即/dev/drbdX背后的 gendiskunion drbd_dev_state state磁盘状态D_ 前缀集合atomic_t ap_pending_cnt等一组原子计数in-flight 请求统计网络在途、等待本地完成等struct rb_root read_requests / write_requests未完成本地请求的区间树5.4 struct drbd_peer_device如第 2 节所示仅四个实质成员peer_devices链表节点、device回指针、connection回指针、send_acks_work。它是纯粹的连接关系载体。6. 把文档模型落到运行时的三条查找路径综合以上文档描述的矩阵模型对应三条最常用运行路径均在源码中可直接验证用户态 → device内核接口拿到 minor 后调用minor_to_device(minor)经全局drbd_devicesidr 直接定位O(log N)见 drbd_int.h#L942-L945。resource → device按卷号idr_find(resource-devices, volume_number)语义的 idr 查找resource-devices在drbd_create_resource()中初始化drbd_main.c#L2526。connection → peer_device按卷号conn_peer_device(connection, volume_number)drbd_int.h#L952-L956。反向的游走则靠双向链表与遍历宏从 device 出发for_each_peer_device()找到它在所有连接上的映像从 resource 出发for_each_connection()找到所有对端连接。例如 drbd_nl.c#L3755 与 drbd_main.c#L2763 都采用了先定位 device、再for_each_peer_device遍历其对端的模式正是矩阵纵列遍历的典型用法。7. 小结这套数据结构解决了什么问题回到文档的动机——Starting with Linux v3.14 we are reorganizing DRBD to use this data structure从 Linux v3.14 起DRBD 重组为使用这套数据结构。DRBD-9 的对象模型可以用三点总结矩阵化device 与 connection 的笛卡尔积由 peer_device 承载天然支持多卷多 volume× 多对端含 dual-Primary、多节点组网的场景双索引横向用 idr 按卷号 O(log N) 定位纵向用双向链表RCU 友好遍历另加全局drbd_devicesidr 支持按 minor 直接寻址生命周期分层resource / connection / device 三级引用计数保证共享安全peer_device 无计数、随宿主对象存亡避免了对矩阵交叉点的额外引用管理负担。文档本身很短但它勾勒的骨架是阅读 drivers/block/drbd 全部约 25 个源文件的地图先建立这四类对象与矩阵关系的心智模型再去读 drbd_main.c对象创建与生命周期、drbd_nl.cnetlink 管理接口如何遍历这些结构以及 drbd_int.h结构与遍历宏就能把 DRBD 的每个请求处理路径写数据、resync、fencing放到正确的对象上理解。【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表