📄 blktapctrl.c
字号:
/* * blktapctrl.c * * userspace controller for the blktap disks. * As requests for new block devices arrive, * the controller spawns off a separate process * per-disk. * * * Copyright (c) 2005 Julian Chesterfield and Andrew Warfield. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation; or, when distributed * separately from the Linux kernel or incorporated into other * software packages, subject to the following license: * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this source file (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, copy, modify, * merge, publish, distribute, sublicense, and/or sell copies of the Software, * and to permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */#include <stdio.h>#include <stdlib.h>#include <sys/mman.h>#include <err.h>#include <errno.h>#include <sys/types.h>#include <sys/wait.h>#include <signal.h>#include <fcntl.h>#include <sys/poll.h>#include <sys/ioctl.h>#include <string.h>#include <unistd.h>#include <xs.h>#include <sys/time.h>#include <syslog.h> #include "blktaplib.h"#include "blktapctrl.h"#include "tapdisk.h"#include "list.h"#include "xs_api.h" /* for xs_fire_next_watch() */#define PIDFILE "/var/run/blktapctrl.pid"#define NUM_POLL_FDS 2#define MSG_SIZE 4096#define MAX_TIMEOUT 10#define MAX_RAND_VAL 0xFFFF#define MAX_ATTEMPTS 10int run = 1;int max_timeout = MAX_TIMEOUT;int ctlfd = 0;int blktap_major;static int open_ctrl_socket(char *devname);static int write_msg(int fd, int msgtype, void *ptr, void *ptr2);static int read_msg(int fd, int msgtype, void *ptr);static driver_list_entry_t *active_disks[MAX_DISK_TYPES];static unsigned long long tapdisk_get_size(blkif_t *blkif){ image_t *img = (image_t *)blkif->prv; return img->size;}static unsigned long tapdisk_get_secsize(blkif_t *blkif){ image_t *img = (image_t *)blkif->prv; return img->secsize;}static unsigned int tapdisk_get_info(blkif_t *blkif){ image_t *img = (image_t *)blkif->prv; return img->info;}struct blkif_ops tapdisk_ops = { .get_size = tapdisk_get_size, .get_secsize = tapdisk_get_secsize, .get_info = tapdisk_get_info,};static void init_driver_list(void){ int i; for (i = 0; i < MAX_DISK_TYPES; i++) active_disks[i] = NULL; return;}static void init_rng(void){ static uint32_t seed; struct timeval tv; gettimeofday(&tv, NULL); seed = tv.tv_usec; srand48(seed); return;}static int get_tapdisk_pid(blkif_t *blkif){ int ret; if ((ret = write_msg(blkif->fds[WRITE], CTLMSG_PID, blkif, NULL)) <= 0) { DPRINTF("Write_msg failed - CTLMSG_PID(%d)\n", ret); return -EINVAL; } if ((ret = read_msg(blkif->fds[READ], CTLMSG_PID_RSP, blkif)) <= 0) { DPRINTF("Read_msg failure - CTLMSG_PID(%d)\n", ret); return -EINVAL; } return 1;}/* Look up the disk specified by path: * if found, dev points to the device string in the path * type is the tapdisk driver type id * blkif is the existing interface if this is a shared driver * and NULL otherwise. * return 0 on success, -1 on error. */static int test_path(char *path, char **dev, int *type, blkif_t **blkif){ char *ptr, handle[10]; int i, size, found = 0; size_t handle_len; size = sizeof(dtypes)/sizeof(disk_info_t *); *type = MAX_DISK_TYPES + 1; *blkif = NULL; if ( (ptr = strstr(path, ":"))!=NULL) { handle_len = (ptr - path); memcpy(handle, path, handle_len); *dev = ptr + 1; ptr = handle + handle_len; *ptr = '\0'; DPRINTF("Detected handle: [%s]\n",handle); for (i = 0; i < size; i++) { if ((strlen(dtypes[i]->handle) == handle_len) && strncmp(handle, dtypes[i]->handle, handle_len) == 0) { found = 1; } if (found) { *type = dtypes[i]->idnum; if (dtypes[i]->single_handler == 1) { /* Check whether tapdisk process already exists */ if (active_disks[dtypes[i]->idnum] == NULL) *blkif = NULL; else *blkif = active_disks[dtypes[i] ->idnum]->blkif; } return 0; } } } /* Fall-through case, we didn't find a disk driver. */ DPRINTF("Unknown blktap disk type [%s]!\n",handle); *dev = NULL; return -1;}static void add_disktype(blkif_t *blkif, int type){ driver_list_entry_t *entry, **pprev; if (type > MAX_DISK_TYPES) return; entry = malloc(sizeof(driver_list_entry_t)); entry->blkif = blkif; entry->next = NULL; pprev = &active_disks[type]; while (*pprev != NULL) pprev = &(*pprev)->next; *pprev = entry; entry->pprev = pprev;}static int del_disktype(blkif_t *blkif){ driver_list_entry_t *entry, **pprev; int type = blkif->drivertype, count = 0, close = 0; if (type > MAX_DISK_TYPES) return 1; pprev = &active_disks[type]; while ((*pprev != NULL) && ((*pprev)->blkif != blkif)) pprev = &(*pprev)->next; if ((entry = *pprev) == NULL) { DPRINTF("DEL_DISKTYPE: No match\n"); return 1; } *pprev = entry->next; if (entry->next) entry->next->pprev = pprev; DPRINTF("DEL_DISKTYPE: Freeing entry\n"); free(entry); /* Caller should close() if no single controller, or list is empty. */ return (!dtypes[type]->single_handler || (active_disks[type] == NULL));}static int write_msg(int fd, int msgtype, void *ptr, void *ptr2){ blkif_t *blkif; blkif_info_t *blk; msg_hdr_t *msg; msg_newdev_t *msg_dev; char *p, *buf, *path; int msglen, len, ret; fd_set writefds; struct timeval timeout; image_t *image, *img; uint32_t seed; blkif = (blkif_t *)ptr; blk = blkif->info; image = blkif->prv; len = 0; switch (msgtype) { case CTLMSG_PARAMS: path = (char *)ptr2; DPRINTF("Write_msg called: CTLMSG_PARAMS, sending [%s, %s]\n", blk->params, path); msglen = sizeof(msg_hdr_t) + strlen(path) + 1; buf = malloc(msglen); /*Assign header fields*/ msg = (msg_hdr_t *)buf; msg->type = CTLMSG_PARAMS; msg->len = msglen; msg->drivertype = blkif->drivertype; msg->readonly = blkif->readonly; gettimeofday(&timeout, NULL); msg->cookie = blkif->cookie; DPRINTF("Generated cookie, %d\n",blkif->cookie); /*Copy blk->params to msg*/ p = buf + sizeof(msg_hdr_t); memcpy(p, path, strlen(path) + 1); break; case CTLMSG_NEWDEV: DPRINTF("Write_msg called: CTLMSG_NEWDEV\n"); msglen = sizeof(msg_hdr_t) + sizeof(msg_newdev_t); buf = malloc(msglen); /*Assign header fields*/ msg = (msg_hdr_t *)buf; msg->type = CTLMSG_NEWDEV; msg->len = msglen; msg->drivertype = blkif->drivertype; msg->cookie = blkif->cookie; msg_dev = (msg_newdev_t *)(buf + sizeof(msg_hdr_t)); msg_dev->devnum = blkif->minor; msg_dev->domid = blkif->domid; break; case CTLMSG_CLOSE: DPRINTF("Write_msg called: CTLMSG_CLOSE\n"); msglen = sizeof(msg_hdr_t); buf = malloc(msglen); /*Assign header fields*/ msg = (msg_hdr_t *)buf; msg->type = CTLMSG_CLOSE; msg->len = msglen; msg->drivertype = blkif->drivertype; msg->cookie = blkif->cookie; break; case CTLMSG_PID: DPRINTF("Write_msg called: CTLMSG_PID\n"); msglen = sizeof(msg_hdr_t); buf = malloc(msglen); /*Assign header fields*/ msg = (msg_hdr_t *)buf; msg->type = CTLMSG_PID; msg->len = msglen; msg->drivertype = blkif->drivertype; msg->cookie = blkif->cookie; break; default: return -1; } /*Now send the message*/ ret = 0; FD_ZERO(&writefds); FD_SET(fd,&writefds); timeout.tv_sec = max_timeout; /*Wait for up to max_timeout seconds*/ timeout.tv_usec = 0; if (select(fd+1, (fd_set *) 0, &writefds, (fd_set *) 0, &timeout) > 0) { len = write(fd, buf, msglen); if (len == -1) DPRINTF("Write failed: (%d)\n",errno); } free(buf); return len;}static int read_msg(int fd, int msgtype, void *ptr){ blkif_t *blkif; blkif_info_t *blk; msg_hdr_t *msg; msg_pid_t *msg_pid; char *p, *buf; int msglen = MSG_SIZE, len, ret; fd_set readfds; struct timeval timeout; image_t *image, *img; blkif = (blkif_t *)ptr; blk = blkif->info; image = blkif->prv; buf = malloc(MSG_SIZE); ret = 0; FD_ZERO(&readfds); FD_SET(fd,&readfds); timeout.tv_sec = max_timeout; /*Wait for up to max_timeout seconds*/ timeout.tv_usec = 0; if (select(fd+1, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout) > 0) { ret = read(fd, buf, msglen); } if (ret > 0) { msg = (msg_hdr_t *)buf; switch (msg->type) { case CTLMSG_IMG: img = (image_t *)(buf + sizeof(msg_hdr_t)); image->size = img->size; image->secsize = img->secsize; image->info = img->info; DPRINTF("Received CTLMSG_IMG: %llu, %lu, %u\n", image->size, image->secsize, image->info); if(msgtype != CTLMSG_IMG) ret = 0; break; case CTLMSG_IMG_FAIL: DPRINTF("Received CTLMSG_IMG_FAIL, " "unable to open image\n"); ret = 0; break; case CTLMSG_NEWDEV_RSP: DPRINTF("Received CTLMSG_NEWDEV_RSP\n"); if(msgtype != CTLMSG_NEWDEV_RSP) ret = 0; break; case CTLMSG_NEWDEV_FAIL: DPRINTF("Received CTLMSG_NEWDEV_FAIL\n"); ret = 0; break; case CTLMSG_CLOSE_RSP: DPRINTF("Received CTLMSG_CLOSE_RSP\n"); if (msgtype != CTLMSG_CLOSE_RSP) ret = 0; break; case CTLMSG_PID_RSP: DPRINTF("Received CTLMSG_PID_RSP\n"); if (msgtype != CTLMSG_PID_RSP) ret = 0; else { msg_pid = (msg_pid_t *) (buf + sizeof(msg_hdr_t)); blkif->tappid = msg_pid->pid; DPRINTF("\tPID: [%d]\n",blkif->tappid); } break; default: DPRINTF("UNKNOWN MESSAGE TYPE RECEIVED\n"); ret = 0; break; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -