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 |