📄 tapdisk.c
字号:
/* tapdisk.c * * separate disk process, spawned by blktapctrl. Inherits code from driver * plugins * * Copyright (c) 2005 Julian Chesterfield and Andrew Warfield. * */#define MSG_SIZE 4096#define TAPDISK#include <stdio.h>#include <stdlib.h>#include <sys/mman.h>#include <fcntl.h>#include <string.h>#include <signal.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/poll.h>#include <unistd.h>#include <errno.h>#include <pthread.h>#include <time.h>#include <err.h>#include <poll.h>#include <sys/statvfs.h>#include <sys/ioctl.h>#include "blktaplib.h"#include "tapdisk.h"#if 1 #define ASSERT(_p) \ if ( !(_p) ) { DPRINTF("Assertion '%s' failed, line %d, file %s", #_p , \ __LINE__, __FILE__); *(int*)0=0; }#else#define ASSERT(_p) ((void)0)#endif #define INPUT 0#define OUTPUT 1static int maxfds, fds[2], run = 1;static pid_t process;int connected_disks = 0;fd_list_entry_t *fd_start = NULL;int do_cow_read(struct disk_driver *dd, blkif_request_t *req, int sidx, uint64_t sector, int nr_secs);#define td_for_each_disk(tds, drv) \ for (drv = tds->disks; drv != NULL; drv = drv->next)static void usage(void) { fprintf(stderr, "blktap-utils: v1.0.0\n"); fprintf(stderr, "usage: tapdisk <READ fifo> <WRITE fifo>\n"); exit(-1);}static void daemonize(void){ int i; if (getppid()==1) return; /* already a daemon */ if (fork() != 0) exit(0);#if 0 /*Set new program session ID and close all descriptors*/ setsid(); for (i = getdtablesize(); i >= 0; --i) close(i); /*Send all I/O to /dev/null */ i = open("/dev/null",O_RDWR); dup(i); dup(i);#endif return;}static void free_driver(struct disk_driver *d){ if (d->name) free(d->name); if (d->private) free(d->private); free(d);}static void unmap_disk(struct td_state *s){ tapdev_info_t *info = s->ring_info; struct disk_driver *dd, *tmp; fd_list_entry_t *entry; dd = s->disks; while (dd) { tmp = dd->next; dd->drv->td_close(dd); free_driver(dd); dd = tmp; } if (info != NULL && info->mem > 0) munmap(info->mem, getpagesize() * BLKTAP_MMAP_REGION_SIZE); entry = s->fd_entry; *entry->pprev = entry->next; if (entry->next) entry->next->pprev = entry->pprev; close(info->fd); free(s->fd_entry); free(s->blkif); free(s->ring_info); free(s); return;}static void sig_handler(int sig){ /*Received signal to close. If no disks are active, we close app.*/ if (connected_disks < 1) run = 0; }static inline int LOCAL_FD_SET(fd_set *readfds){ fd_list_entry_t *ptr; struct disk_driver *dd; ptr = fd_start; while (ptr != NULL) { if (ptr->tap_fd) { FD_SET(ptr->tap_fd, readfds); td_for_each_disk(ptr->s, dd) { if (dd->io_fd[READ]) FD_SET(dd->io_fd[READ], readfds); maxfds = (dd->io_fd[READ] > maxfds ? dd->io_fd[READ] : maxfds); } maxfds = (ptr->tap_fd > maxfds ? ptr->tap_fd : maxfds); } ptr = ptr->next; } return 0;}static inline fd_list_entry_t *add_fd_entry(int tap_fd, struct td_state *s){ fd_list_entry_t **pprev, *entry; int i; DPRINTF("Adding fd_list_entry\n"); /*Add to linked list*/ s->fd_entry = entry = malloc(sizeof(fd_list_entry_t)); entry->tap_fd = tap_fd; entry->s = s; entry->next = NULL; pprev = &fd_start; while (*pprev != NULL) pprev = &(*pprev)->next; *pprev = entry; entry->pprev = pprev; return entry;}static inline struct td_state *get_state(int cookie){ fd_list_entry_t *ptr; ptr = fd_start; while (ptr != NULL) { if (ptr->cookie == cookie) return ptr->s; ptr = ptr->next; } return NULL;}static struct tap_disk *get_driver(int drivertype){ /* blktapctrl has passed us the driver type */ return dtypes[drivertype]->drv;}static struct td_state *state_init(void){ int i; struct td_state *s; blkif_t *blkif; s = malloc(sizeof(struct td_state)); blkif = s->blkif = malloc(sizeof(blkif_t)); s->ring_info = calloc(1, sizeof(tapdev_info_t)); for (i = 0; i < MAX_REQUESTS; i++) { blkif->pending_list[i].secs_pending = 0; blkif->pending_list[i].submitting = 0; } return s;}static int map_new_dev(struct td_state *s, int minor){ int tap_fd; tapdev_info_t *info = s->ring_info; char *devname; fd_list_entry_t *ptr; int page_size; if (asprintf(&devname,"%s/%s%d", BLKTAP_DEV_DIR, BLKTAP_DEV_NAME, minor) == -1) return -1; tap_fd = open(devname, O_RDWR); if (tap_fd == -1) { DPRINTF("open failed on dev %s!",devname); goto fail; } info->fd = tap_fd; /*Map the shared memory*/ page_size = getpagesize(); info->mem = mmap(0, page_size * BLKTAP_MMAP_REGION_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, info->fd, 0); if ((long int)info->mem == -1) { DPRINTF("mmap failed on dev %s!\n",devname); goto fail; } /* assign the rings to the mapped memory */ info->sring = (blkif_sring_t *)((unsigned long)info->mem); BACK_RING_INIT(&info->fe_ring, info->sring, page_size); info->vstart = (unsigned long)info->mem + (BLKTAP_RING_PAGES * page_size); ioctl(info->fd, BLKTAP_IOCTL_SENDPID, process ); ioctl(info->fd, BLKTAP_IOCTL_SETMODE, BLKTAP_MODE_INTERPOSE ); free(devname); /*Update the fd entry*/ ptr = fd_start; while (ptr != NULL) { if (s == ptr->s) { ptr->tap_fd = tap_fd; break; } ptr = ptr->next; } return minor; fail: free(devname); return -1;}static struct disk_driver *disk_init(struct td_state *s, struct tap_disk *drv, char *name, td_flag_t flags){ struct disk_driver *dd; dd = calloc(1, sizeof(struct disk_driver)); if (!dd) return NULL; dd->private = malloc(drv->private_data_size); if (!dd->private) { free(dd); return NULL; } dd->drv = drv; dd->td_state = s; dd->name = name; dd->flags = flags; return dd;}static int open_disk(struct td_state *s, struct tap_disk *drv, char *path, td_flag_t flags){ int err; char *dup; td_flag_t pflags; struct disk_id id; struct disk_driver *d; dup = strdup(path); if (!dup) return -ENOMEM; memset(&id, 0, sizeof(struct disk_id)); s->disks = d = disk_init(s, drv, dup, flags); if (!d) return -ENOMEM; err = drv->td_open(d, path, flags); if (err) { free_driver(d); s->disks = NULL; return -ENOMEM; } pflags = flags | TD_RDONLY; /* load backing files as necessary */ while ((err = d->drv->td_get_parent_id(d, &id)) == 0) { struct disk_driver *new; if (id.drivertype > MAX_DISK_TYPES || !get_driver(id.drivertype) || !id.name) goto fail; dup = strdup(id.name); if (!dup) goto fail; new = disk_init(s, get_driver(id.drivertype), dup, pflags); if (!new) goto fail; err = new->drv->td_open(new, new->name, pflags); if (err) goto fail; err = d->drv->td_validate_parent(d, new, 0); if (err) { d->next = new; goto fail; } d = d->next = new; free(id.name); } s->info |= ((flags & TD_RDONLY) ? VDISK_READONLY : 0); if (err >= 0) return 0; fail: DPRINTF("failed opening disk\n"); if (id.name) free(id.name); d = s->disks; while (d) { struct disk_driver *tmp = d->next; d->drv->td_close(d); free_driver(d); d = tmp; } s->disks = NULL; return -1;}static int read_msg(char *buf){ int length, len, msglen, tap_fd, *io_fd; char *ptr, *path; image_t *img; msg_hdr_t *msg; msg_newdev_t *msg_dev; msg_pid_t *msg_pid; struct tap_disk *drv; int ret = -1; struct td_state *s = NULL; fd_list_entry_t *entry; length = read(fds[READ], buf, MSG_SIZE); if (length > 0 && length >= sizeof(msg_hdr_t)) { msg = (msg_hdr_t *)buf; DPRINTF("Tapdisk: Received msg, len %d, type %d, UID %d\n", length,msg->type,msg->cookie); switch (msg->type) { case CTLMSG_PARAMS: ptr = buf + sizeof(msg_hdr_t); len = (length - sizeof(msg_hdr_t)); path = calloc(1, len); memcpy(path, ptr, len); DPRINTF("Received CTLMSG_PARAMS: [%s]\n", path); /*Assign driver*/ drv = get_driver(msg->drivertype); if (drv == NULL) goto params_done; DPRINTF("Loaded driver: name [%s], type [%d]\n", drv->disk_type, msg->drivertype); /* Allocate the disk structs */ s = state_init(); if (s == NULL) goto params_done; /*Open file*/ ret = open_disk(s, drv, path, ((msg->readonly) ? TD_RDONLY : 0)); if (ret) goto params_done; entry = add_fd_entry(0, s); entry->cookie = msg->cookie; DPRINTF("Entered cookie %d\n", entry->cookie); memset(buf, 0x00, MSG_SIZE); params_done: if (ret == 0) { msglen = sizeof(msg_hdr_t) + sizeof(image_t); msg->type = CTLMSG_IMG; img = (image_t *)(buf + sizeof(msg_hdr_t)); img->size = s->size; img->secsize = s->sector_size; img->info = s->info; } else { msglen = sizeof(msg_hdr_t); msg->type = CTLMSG_IMG_FAIL; msg->len = msglen; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -