main()会fork个进程,子进程负责执行tapdisk2_main_processor(params);
tapdisk2_main_processor(params):
params的举例如:storage_vhd:{conf:/guest/VMguohu800529/conf/174942.conf},这个是要传给tdc的字符串参数调用函数 tapdisk2_create_device(params, &path, &control_path, &type)
调用函数 tapdisk2_open_device(type, path, params)创建控制设备/dev/xen/blktap-2/control初始化server这个全局变量监听/var/run/blktap-control/ctl(pid)这个socket地址创建字符设备/dev/xen/blktap-2/blktapX,作为接收请求的环设备创建块设备/dev/xen/blktap-2/tapdevX,作为后端的块设备path = {conf:/guest/VMguohu800156/conf/174569.conf}control_path = /var/run/blktap-control/ctl(pid)准备server的aio_queue,初始化tio指向的地方,和tio_data的空间创建一个监听td_control.path( /var/run/blktap-control/ctl(pid) )的socket,基于这个socket的事件被加入了scheduler的链给控制设备/dev/xen/blktap-2/control发一个ioctl,code=BLKTAP2_IOCTL_ALLOC_TAP=200
初始化一个vbd,包括callback,ipc的fd,并初始化req链表,并把vbd加入到server的vbd链
填充vbd设备的driver链表
基于driver链表,填充image链表。在这里会创建每一个image,并执行VHD的打开流程vbd的
初始化vbd设备的ring设备
把blktapX的fd注册事件在scheduler,回调函数是tapdisk_vbd_ring_event,负责从ring环取数据。这个回调函数将进入blktap的处理流程调用函数 tapdisk_server_register_storage_event()
把storage_fd注册到server的事件里面
aio_queue,即为与tdc联系的queue,它的tio_data存储着tdc相关的内容,例如storage_id和storage_fd
aio_queue的tio_data,作为storage_io结构的storage_fd,注册事件在scheduler,事件id为storage_io的storage_id,亦即storage_event_id调用 tapdisk_server_run(path),开始进入服务端流程
tapdisk2_create_device(const char *params, char **path, char **control_path, int *type):
调用 tapdisk2_check_environment(),检查下环境,主要是查看/proc/misc,并寻找里面有没有一个blktap-control。如果有则造一个字符设备,路径为/dev/xen/blktap-2/control调用 tapdisk_parse_disk_type(params, path, type),获得参数和类型。path = {conf:/guest/VMguohu800156/conf/174569.conf},type=VHD调用 tapdisk_server_initialize(NULL, NULL, *type)初始化tapdisk的server里面的一些参数,包括vbd链表,scheduler集合,ipc等调用 tapdisk_control_open(control_path),创建一个监听td_control.path( /var/run/blktap-control/ctl(pid) )的socket,基于这个socket的事件被加入了scheduler的链表里调用 tapdisk_server_complete(*type),会把server.aio_queue给创建出来调用 tapdisk2_prepare_device():
tapdisk2_open_device(int type, const char *path, const char *name):给控制设备/dev/xen/blktap-2/control发一个ioctl,code=BLKTAP2_IOCTL_ALLOC_TAP=200创建字符设备/dev/xen/blktap-2/blktapX创建块设备/dev/xen/blktap-2/tapdevX
调用 tapdisk_vbd_initialize(-1, -1, TAPDISK2_VBD),初始化一个vbd,包括callback,ipc的fd,并初始化req链表,并把vbd加入到server的vbd链
tapdisk_vbd_initialize(int rfd, int wfd, uint16_t uuid):
调用tapdisk_server_get_vbd(uuid),根据uuid,找到对应的vbd结构如果能找到,就不用初始化了,直接返回-EEXIST如果找不到,就分配空间,td_vbd_t *vbd = calloc(1, sizeof(td_vbd_t))记录一下ipc的一些fd,即:vbd->uuid = uuid;vbd->ipc.rfd = rfd;vbd->ipc.wfd = wfd;vbd->ipc.uuid = uuid;vbd->ring.fd = -1;//回调函数,用于往ring环里填写rsp请求vbd->callback = tapdisk_vbd_callback;//vbd->argument其实就是vbd本身vbd->argument = vbd;初始化vbd里的每一个request,总数为 BLKTAP_MAX_REQUESTS = BLK_RING_SIZE * 2 个,即:for (i = 0; i < BLKTAP_MAX_REQUESTS; i++) tapdisk_vbd_initialize_vreq(vbd->request_list + i);加入到server的vbd链表里,即tapdisk_server_add_vbd(vbd);
调用 tapdisk_vbd_parse_stack(vbd, name); 其实是基于路径里的conf填写一个VBD,再把name作为参数,构造一个driver,加入到vbd的driver_stack链表里调用 tapdisk_vbd_open(vbd, path, type, TAPDISK_STORAGE_TYPE_DEFAULT, devname, 0)
函数功能是打开并初始化好一个vbd,使他能够正常使用
基于vbd的driver链,初始化vbd的image链初始化每一个image,具体会调用到td_open,进入VHD的初始化工作流程对blktapX做内存映射到vbd的ring结构,作为io环
其中,环的大小在tapdisk_vbd_map_device有指定,默认为BLKTAP_MMAP_REGION_SIZE页,如果blktap能够识别BLKTAP2_IOCTL_GET_MMAP_PAGES指令,则采用blktap返回的环大小BLKTAP_MMAP_REGION_SIZE = BLKTAP_RING_PAGES + MMAP_PAGES
其中,BLKTAP_RING_PAGES = 1MMAP_PAGES = MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUESTMAX_PENDING_REQS = BLK_RING_SIZE = 32BLKIF_MAX_SEGMENTS_PER_REQUEST = 11 (blkif.h里指定)
把vbd的ring设备注册event
调用 tapdisk_vbd_get_image_info(vbd, &image),把vbd的第一个image的一些信息,size,secsize,info写入image这个变量给ring驱动设备发ioctl,即ioctl(vbd->ring.fd, BLKTAP2_IOCTL_CREATE_DEVICE, ¶ms);
tapdisk_vbd_open(td_vbd_t *vbd, const char *name, uint16_t type, uint16_t storage, const char *ring, td_flag_t flags):
调用tapdisk_vbd_open_stack(vbd, storage, flags)。其实是不断重试,调用__tapdisk_vbd_open_vdi(vbd, 0)
__tapdisk_vbd_open_vdi(td_vbd_t *vbd, td_flag_t extra_flags):
会循环vbd里的每一个driver,任一driver命名driver_info,对其:
搞到file和type,即
file = driver_info->params;type = driver_info->type;调用images = tapdisk_vbd_open_level(vbd, file, type, parent_info, flags),处理这个driver的image链
tapdisk_vbd_open_level(td_vbd_t *vbd, char* params, int driver_type, td_disk_info_t *parent_info, td_flag_t flags):
这个函数只会做个死循环,直到找不到image,循环如下:
首先生成个image = tapdisk_image_allocate(name, type, vbd->storage, flags, vbd);再生成driver = tapdisk_driver_allocate(image->type, image->name, image->flags, image->storage);image->driver = driver;image->info = driver->info;试图寻找共享的image,即err = td_load(image);如果找不到,就试图打开,即err = td_open(image):
其实是调用driver里的td_open函数,打开image,即err = driver->ops->td_open(driver, image->name, image->flags);其实是调用storage-vhd.c的tap_disk tapdisk_vhd结构的td_open(_storage_vhd_open)此时进入VHD的打开流程
获得父镜像,err = td_get_parent_id(image, &id);加入到镜像链表里, list_add_tail(&image->next, images);
如果有td_flag_test(vbd->flags, TD_OPEN_LOG_DIRTY),就读取相关的vbd,即:调用ist_splice(images, &vbd->images),把images加入到vbd的images链表里拿到vbd的第一个image,写入parent_info,即:tmp = tapdisk_vbd_first_image(vbd);parent_info = &tmp->info;
err = tapdisk_vbd_add_dirty_log(vbd);
如果有td_flag_test(vbd->flags, TD_OPEN_ADD_CACHE),就读取相关的vbd,即:err = tapdisk_vbd_add_block_cache(vbd);调用tapdisk_vbd_validate_chain(vbd),检查下image链的正确性
tapdisk_server_complete(int type):
对于DISK_TYPE_STORAGE_VHD的类型,将调用tapdisk_init_queue(&server.aio_queue, TAPDISK_TIOCBS, TIO_DRV_STORAGE_IO, NULL)
其中:
TAPDISK_TIOCBS = TAPDISK_DATA_REQUESTS + 50
TAPDISK_DATA_REQUESTS = MAX_REQUESTS * MAX_SEGMENTS_PER_REQ
MAX_REQUESTS = BLK_RING_SIZE = 32
MAX_SEGMENTS_PER_REQ = 11
所以,往下创建的aio_queue的queue->size为32 * 11 + 50 = 402
tapdisk_init_queue(struct tqueue *queue, int size, int drv, struct tfilter *filter):
调用tapdisk_queue_init_io(queue, drv),基于drv的类型(比如tdc的类型storage),把queue的tio以及tio_data结构初始化
tapdisk_queue_init_io(struct tqueue *queue, int drv):根据这个queue要接入的后端类型,指定接口函数列表。TIO_DRV_STORAGE_IO类型,tio = &td_tio_storage_io;初始化queue的tio_data,即queue->tio_data = calloc(1, tio->data_size);queue->tio = tio;如果tio有tio->setup,则调用,即tio->tio_setup(queue, queue->size); 这里会把tio_data(实际为td_tio_storage_io结构)里面的几个io_events数组都初始化
把q里的iocb数组给初始化,分配好空间,queue->iocbs = calloc(size, sizeof(struct iocb *));
初始化q里面的opioctx用于对io的合并,opio_init(&queue->opioctx, size);