分析的 ceph 代码版本: 12.2.4
分析的 kernel 代码版本: 4.16.0
在执行 `rbd map <pool_name>/<image_name>` ,整个执行流程是如何完成的呢?
这个 map 主要可以分为两个部分:
1. 通知 kernel ,告知 kernel 需要 map 的信息(pool_name, image_name, 延伸的还包含 ceph 集群信息)
2. kernel 完成剩下的工作
一、通知 kernel
执行 `rbd map <pool_name>/<image_name>` 是怎样通知 kernel 的呢?
大致流程是通过写 /sys/bus/rbd 下的文件来完成,具体过程如下:
1. 命令行的入口 src/tools/rbd/action/Kernel.cc
入口:
520 Shell::Action action_map(
521 {"map"}, {}, "Map image to a block device using the kernel.", "",
522 &get_map_arguments, &execute_map);
2. 调用流程:
execute_map --> do_kernel_map --> krbd_map --> map_image --> do_map --> sysfs_write_rbd_add
sysfs_write_rbd_add 就是向 /sys/bus/rbd/add_single_major 写入添加的 image 及 ceph 集群信息,通知 kernel 。
写入的信息参考如下:
192.168.122.114:6789,192.168.122.25:6789,192.168.122.174:6789 name=admin rbd test -
|________________________ mon info _________________________| |________| |_| |__||_|
| | | |
\|/ | | |
auth | | |
\|/ | |
pool | |
| |
\|/ |
img |
\|/
snap
二、kernel 完成剩下的工作
1. 首先会安装 libceph, rbd 两个模块
这两个模块,如果`rbd map` 执行时没安装,则会在 map_image(参见 "一、通知 kernel --> 2. 调用流程") 中安装:
map_image 会探测 rbd 模块是否安装,没有会安装模块:
302 /*
303 * Modprobe rbd kernel module. If it supports single-major device
304 * number allocation scheme, make sure it's turned on.
305 */
306 if (access("/sys/bus/rbd", F_OK) != 0) {
307 const char *module_options = NULL;
308 if (module_has_param("rbd", "single_major"))
309 module_options = "single_major=Y";
310
311 r = module_load("rbd", module_options);
312 if (r) {
313 cerr << "rbd: failed to load rbd kernel module (" << r << ")"
314 << std::endl;
315 /*
316 * Ignore the error: modprobe failing doesn't necessarily prevent
317 * from working.
318 */
319 }
320 }
2. kernel 入口:
drivers/block/rbd.c
6471 module_init(rbd_init);
3. rbd_init:
a. rbd_slab_init
b. alloc_workqueue
c. register_blkdev
d. rbd_sysfs_init
4. rbd_sysfs_init 流程
rbd_sysfs_init --> device_register && bus_register
bus_register 注册时传入了 rbd_bus_type
rbd_bus_type --> rbd_bus_group --> rbd_bus_attrs
rbd_bus_attrs 中定义了 add/remove 相关的属性文件,
如果我们向 add_single_major 文件写入时,kernel 将调用相应的函数来完成相应工作,这里的函数是 rbd_add_single_major.
rbd_bus_type --> rbd_bus_group --> rbd_bus_attrs 相关的定义如下:
503 static BUS_ATTR(add, S_IWUSR, NULL, rbd_add);
504 static BUS_ATTR(remove, S_IWUSR, NULL, rbd_remove);
505 static BUS_ATTR(add_single_major, S_IWUSR, NULL, rbd_add_single_major);
506 static BUS_ATTR(remove_single_major, S_IWUSR, NULL, rbd_remove_single_major);
507 static BUS_ATTR(supported_features, S_IRUGO, rbd_supported_features_show, NULL);
508
509 static struct attribute *rbd_bus_attrs[] = {
510 &bus_attr_add.attr,
511 &bus_attr_remove.attr,
512 &bus_attr_add_single_major.attr,
513 &bus_attr_remove_single_major.attr,
514 &bus_attr_supported_features.attr,
515 NULL,
516 };
517
...
529 static const struct attribute_group rbd_bus_group = {
530 .attrs = rbd_bus_attrs,
531 .is_visible = rbd_bus_is_visible,
532 };
533 __ATTRIBUTE_GROUPS(rbd_bus);
534
535 static struct bus_type rbd_bus_type = {
536 .name = "rbd",
537 .bus_groups = rbd_bus_groups,
538 };
5. rbd_add_single_major 分析:
rbd_dev_create
/
rbd_add_single_major --> do_rbd_add /
\
\
rbd_dev_device_setup
rbd_dev_create, rbd_dev_device_setup 完成了 创建 rbd device 的工作。