Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/block_if.c
| Show First 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | |||||
| #include <signal.h> | #include <signal.h> | ||||
| #include <sysexits.h> | #include <sysexits.h> | ||||
| #include <unistd.h> | #include <unistd.h> | ||||
| #include <machine/atomic.h> | #include <machine/atomic.h> | ||||
| #include <machine/vmm_snapshot.h> | #include <machine/vmm_snapshot.h> | ||||
| #include "bhyverun.h" | #include "bhyverun.h" | ||||
| #include "config.h" | |||||
| #include "debug.h" | #include "debug.h" | ||||
| #include "mevent.h" | #include "mevent.h" | ||||
| #include "pci_emul.h" | |||||
| #include "block_if.h" | #include "block_if.h" | ||||
| #define BLOCKIF_SIG 0xb109b109 | #define BLOCKIF_SIG 0xb109b109 | ||||
| #define BLOCKIF_NUMTHR 8 | #define BLOCKIF_NUMTHR 8 | ||||
| #define BLOCKIF_MAXREQ (BLOCKIF_RING_MAX + BLOCKIF_NUMTHR) | #define BLOCKIF_MAXREQ (BLOCKIF_RING_MAX + BLOCKIF_NUMTHR) | ||||
| enum blockop { | enum blockop { | ||||
| ▲ Show 20 Lines • Show All 348 Lines • ▼ Show 20 Lines | |||||
| static void | static void | ||||
| blockif_init(void) | blockif_init(void) | ||||
| { | { | ||||
| mevent_add(SIGCONT, EVF_SIGNAL, blockif_sigcont_handler, NULL); | mevent_add(SIGCONT, EVF_SIGNAL, blockif_sigcont_handler, NULL); | ||||
| (void) signal(SIGCONT, SIG_IGN); | (void) signal(SIGCONT, SIG_IGN); | ||||
| } | } | ||||
| int | |||||
| blockif_legacy_config(nvlist_t *nvl, const char *opts) | |||||
| { | |||||
| char *cp, *path; | |||||
| if (opts == NULL) | |||||
| return (0); | |||||
| cp = strchr(opts, ','); | |||||
| if (cp == NULL) { | |||||
| set_config_value_node(nvl, "path", opts); | |||||
| return (0); | |||||
| } | |||||
| path = strndup(opts, cp - opts); | |||||
| set_config_value_node(nvl, "path", path); | |||||
| free(path); | |||||
| return (pci_parse_legacy_config(nvl, cp + 1)); | |||||
| } | |||||
| struct blockif_ctxt * | struct blockif_ctxt * | ||||
| blockif_open(const char *optstr, const char *ident) | blockif_open(nvlist_t *nvl, const char *ident) | ||||
| { | { | ||||
| char tname[MAXCOMLEN + 1]; | char tname[MAXCOMLEN + 1]; | ||||
| char name[MAXPATHLEN]; | char name[MAXPATHLEN]; | ||||
| char *nopt, *xopts, *cp; | const char *path, *pssval, *ssval; | ||||
| char *cp; | |||||
| struct blockif_ctxt *bc; | struct blockif_ctxt *bc; | ||||
| struct stat sbuf; | struct stat sbuf; | ||||
| struct diocgattr_arg arg; | struct diocgattr_arg arg; | ||||
| off_t size, psectsz, psectoff; | off_t size, psectsz, psectoff; | ||||
| int extra, fd, i, sectsz; | int extra, fd, i, sectsz; | ||||
| int nocache, sync, ro, candelete, geom, ssopt, pssopt; | int ro, candelete, geom, ssopt, pssopt; | ||||
| int nodelete; | int nodelete; | ||||
| #ifndef WITHOUT_CAPSICUM | #ifndef WITHOUT_CAPSICUM | ||||
| cap_rights_t rights; | cap_rights_t rights; | ||||
| cap_ioctl_t cmds[] = { DIOCGFLUSH, DIOCGDELETE }; | cap_ioctl_t cmds[] = { DIOCGFLUSH, DIOCGDELETE }; | ||||
| #endif | #endif | ||||
| pthread_once(&blockif_once, blockif_init); | pthread_once(&blockif_once, blockif_init); | ||||
| fd = -1; | fd = -1; | ||||
| extra = 0; | |||||
| ssopt = 0; | ssopt = 0; | ||||
| nocache = 0; | |||||
| sync = 0; | |||||
| ro = 0; | ro = 0; | ||||
| nodelete = 0; | nodelete = 0; | ||||
| /* | if (get_config_bool_node_default(nvl, "nocache", false)) | ||||
| * The first element in the optstring is always a pathname. | extra |= O_DIRECT; | ||||
| * Optional elements follow | if (get_config_bool_node_default(nvl, "nodelete", false)) | ||||
| */ | |||||
| nopt = xopts = strdup(optstr); | |||||
| while (xopts != NULL) { | |||||
| cp = strsep(&xopts, ","); | |||||
| if (cp == nopt) /* file or device pathname */ | |||||
| continue; | |||||
| else if (!strcmp(cp, "nocache")) | |||||
| nocache = 1; | |||||
| else if (!strcmp(cp, "nodelete")) | |||||
| nodelete = 1; | nodelete = 1; | ||||
| else if (!strcmp(cp, "sync") || !strcmp(cp, "direct")) | if (get_config_bool_node_default(nvl, "sync", false) || | ||||
| sync = 1; | get_config_bool_node_default(nvl, "direct", false)) | ||||
| else if (!strcmp(cp, "ro")) | extra |= O_SYNC; | ||||
| if (get_config_bool_node_default(nvl, "ro", false)) | |||||
| ro = 1; | ro = 1; | ||||
| else if (sscanf(cp, "sectorsize=%d/%d", &ssopt, &pssopt) == 2) | ssval = get_config_value_node(nvl, "sectorsize"); | ||||
| ; | if (ssval != NULL) { | ||||
| else if (sscanf(cp, "sectorsize=%d", &ssopt) == 1) | ssopt = strtol(ssval, &cp, 10); | ||||
| if (cp == ssval) { | |||||
| EPRINTLN("Invalid sector size \"%s\"", ssval); | |||||
| goto err; | |||||
| } | |||||
| if (*cp == '\0') { | |||||
| pssopt = ssopt; | pssopt = ssopt; | ||||
| else { | } else if (*cp == '/') { | ||||
| EPRINTLN("Invalid device option \"%s\"", cp); | pssval = cp + 1; | ||||
| pssopt = strtol(pssval, &cp, 10); | |||||
| if (cp == pssval || *cp != '\0') { | |||||
| EPRINTLN("Invalid sector size \"%s\"", ssval); | |||||
| goto err; | goto err; | ||||
| } | } | ||||
| } else { | |||||
| EPRINTLN("Invalid sector size \"%s\"", ssval); | |||||
| goto err; | |||||
| } | } | ||||
| } | |||||
| extra = 0; | path = get_config_value_node(nvl, "path"); | ||||
| if (nocache) | if (path == NULL) { | ||||
| extra |= O_DIRECT; | EPRINTLN("Missing \"path\" for block device."); | ||||
| if (sync) | goto err; | ||||
| extra |= O_SYNC; | } | ||||
| fd = open(nopt, (ro ? O_RDONLY : O_RDWR) | extra); | fd = open(path, (ro ? O_RDONLY : O_RDWR) | extra); | ||||
| if (fd < 0 && !ro) { | if (fd < 0 && !ro) { | ||||
| /* Attempt a r/w fail with a r/o open */ | /* Attempt a r/w fail with a r/o open */ | ||||
| fd = open(nopt, O_RDONLY | extra); | fd = open(path, O_RDONLY | extra); | ||||
| ro = 1; | ro = 1; | ||||
| } | } | ||||
| if (fd < 0) { | if (fd < 0) { | ||||
| warn("Could not open backing file: %s", nopt); | warn("Could not open backing file: %s", path); | ||||
| goto err; | goto err; | ||||
| } | } | ||||
| if (fstat(fd, &sbuf) < 0) { | if (fstat(fd, &sbuf) < 0) { | ||||
| warn("Could not stat backing file %s", nopt); | warn("Could not stat backing file %s", path); | ||||
| goto err; | goto err; | ||||
| } | } | ||||
| #ifndef WITHOUT_CAPSICUM | #ifndef WITHOUT_CAPSICUM | ||||
| cap_rights_init(&rights, CAP_FSYNC, CAP_IOCTL, CAP_READ, CAP_SEEK, | cap_rights_init(&rights, CAP_FSYNC, CAP_IOCTL, CAP_READ, CAP_SEEK, | ||||
| CAP_WRITE); | CAP_WRITE); | ||||
| if (ro) | if (ro) | ||||
| cap_rights_clear(&rights, CAP_FSYNC, CAP_WRITE); | cap_rights_clear(&rights, CAP_FSYNC, CAP_WRITE); | ||||
| ▲ Show 20 Lines • Show All 97 Lines • ▼ Show 20 Lines | for (i = 0; i < BLOCKIF_NUMTHR; i++) { | ||||
| snprintf(tname, sizeof(tname), "blk-%s-%d", ident, i); | snprintf(tname, sizeof(tname), "blk-%s-%d", ident, i); | ||||
| pthread_set_name_np(bc->bc_btid[i], tname); | pthread_set_name_np(bc->bc_btid[i], tname); | ||||
| } | } | ||||
| return (bc); | return (bc); | ||||
| err: | err: | ||||
| if (fd >= 0) | if (fd >= 0) | ||||
| close(fd); | close(fd); | ||||
| free(nopt); | |||||
| return (NULL); | return (NULL); | ||||
| } | } | ||||
| static int | static int | ||||
| blockif_request(struct blockif_ctxt *bc, struct blockif_req *breq, | blockif_request(struct blockif_ctxt *bc, struct blockif_req *breq, | ||||
| enum blockop op) | enum blockop op) | ||||
| { | { | ||||
| int err; | int err; | ||||
| ▲ Show 20 Lines • Show All 362 Lines • Show Last 20 Lines | |||||