Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F173699809
D21707.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
10 KB
Referenced Files
None
Subscribers
None
D21707.id.diff
View Options
Index: head/usr.sbin/bhyve/block_if.c
===================================================================
--- head/usr.sbin/bhyve/block_if.c
+++ head/usr.sbin/bhyve/block_if.c
@@ -3,6 +3,7 @@
*
* Copyright (c) 2013 Peter Grehan <grehan@freebsd.org>
* All rights reserved.
+ * Copyright 2020 Joyent, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -410,6 +411,8 @@
off_t size, psectsz, psectoff;
int extra, fd, i, sectsz;
int nocache, sync, ro, candelete, geom, ssopt, pssopt;
+ int nodelete;
+
#ifndef WITHOUT_CAPSICUM
cap_rights_t rights;
cap_ioctl_t cmds[] = { DIOCGFLUSH, DIOCGDELETE };
@@ -422,6 +425,7 @@
nocache = 0;
sync = 0;
ro = 0;
+ nodelete = 0;
/*
* The first element in the optstring is always a pathname.
@@ -434,6 +438,8 @@
continue;
else if (!strcmp(cp, "nocache"))
nocache = 1;
+ else if (!strcmp(cp, "nodelete"))
+ nodelete = 1;
else if (!strcmp(cp, "sync") || !strcmp(cp, "direct"))
sync = 1;
else if (!strcmp(cp, "ro"))
@@ -500,7 +506,7 @@
ioctl(fd, DIOCGSTRIPEOFFSET, &psectoff);
strlcpy(arg.name, "GEOM::candelete", sizeof(arg.name));
arg.len = sizeof(arg.value.i);
- if (ioctl(fd, DIOCGATTR, &arg) == 0)
+ if (nodelete == 0 && ioctl(fd, DIOCGATTR, &arg) == 0)
candelete = arg.value.i;
if (ioctl(fd, DIOCGPROVIDERNAME, name) == 0)
geom = 1;
Index: head/usr.sbin/bhyve/pci_virtio_block.c
===================================================================
--- head/usr.sbin/bhyve/pci_virtio_block.c
+++ head/usr.sbin/bhyve/pci_virtio_block.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2011 NetApp, Inc.
* All rights reserved.
- * Copyright (c) 2019 Joyent, Inc.
+ * Copyright 2020 Joyent, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -57,26 +57,37 @@
#include "virtio.h"
#include "block_if.h"
-#define VTBLK_RINGSZ 128
+#define VTBLK_BSIZE 512
+#define VTBLK_RINGSZ 128
_Static_assert(VTBLK_RINGSZ <= BLOCKIF_RING_MAX, "Each ring entry must be able to queue a request");
-#define VTBLK_S_OK 0
-#define VTBLK_S_IOERR 1
+#define VTBLK_S_OK 0
+#define VTBLK_S_IOERR 1
#define VTBLK_S_UNSUPP 2
#define VTBLK_BLK_ID_BYTES 20 + 1
/* Capability bits */
-#define VTBLK_F_SEG_MAX (1 << 2) /* Maximum request segments */
-#define VTBLK_F_BLK_SIZE (1 << 6) /* cfg block size valid */
-#define VTBLK_F_FLUSH (1 << 9) /* Cache flush support */
-#define VTBLK_F_TOPOLOGY (1 << 10) /* Optimal I/O alignment */
+#define VTBLK_F_BARRIER (1 << 0) /* Does host support barriers? */
+#define VTBLK_F_SIZE_MAX (1 << 1) /* Indicates maximum segment size */
+#define VTBLK_F_SEG_MAX (1 << 2) /* Indicates maximum # of segments */
+#define VTBLK_F_GEOMETRY (1 << 4) /* Legacy geometry available */
+#define VTBLK_F_RO (1 << 5) /* Disk is read-only */
+#define VTBLK_F_BLK_SIZE (1 << 6) /* Block size of disk is available*/
+#define VTBLK_F_SCSI (1 << 7) /* Supports scsi command passthru */
+#define VTBLK_F_FLUSH (1 << 9) /* Writeback mode enabled after reset */
+#define VTBLK_F_WCE (1 << 9) /* Legacy alias for FLUSH */
+#define VTBLK_F_TOPOLOGY (1 << 10) /* Topology information is available */
+#define VTBLK_F_CONFIG_WCE (1 << 11) /* Writeback mode available in config */
+#define VTBLK_F_MQ (1 << 12) /* Multi-Queue */
+#define VTBLK_F_DISCARD (1 << 13) /* Trim blocks */
+#define VTBLK_F_WRITE_ZEROES (1 << 14) /* Write zeros */
/*
* Host capabilities
*/
-#define VTBLK_S_HOSTCAPS \
+#define VTBLK_S_HOSTCAPS \
( VTBLK_F_SEG_MAX | \
VTBLK_F_BLK_SIZE | \
VTBLK_F_FLUSH | \
@@ -84,6 +95,18 @@
VIRTIO_RING_F_INDIRECT_DESC ) /* indirect descriptors */
/*
+ * The current blockif_delete() interface only allows a single delete
+ * request at a time.
+ */
+#define VTBLK_MAX_DISCARD_SEG 1
+
+/*
+ * An arbitrary limit to prevent excessive latency due to large
+ * delete requests.
+ */
+#define VTBLK_MAX_DISCARD_SECT ((16 << 20) / VTBLK_BSIZE) /* 16 MiB */
+
+/*
* Config space "registers"
*/
struct vtblk_config {
@@ -103,6 +126,15 @@
uint32_t opt_io_size;
} vbc_topology;
uint8_t vbc_writeback;
+ uint8_t unused0[1];
+ uint16_t num_queues;
+ uint32_t max_discard_sectors;
+ uint32_t max_discard_seg;
+ uint32_t discard_sector_alignment;
+ uint32_t max_write_zeroes_sectors;
+ uint32_t max_write_zeroes_seg;
+ uint8_t write_zeroes_may_unmap;
+ uint8_t unused1[3];
} __packed;
/*
@@ -111,9 +143,14 @@
struct virtio_blk_hdr {
#define VBH_OP_READ 0
#define VBH_OP_WRITE 1
+#define VBH_OP_SCSI_CMD 2
+#define VBH_OP_SCSI_CMD_OUT 3
#define VBH_OP_FLUSH 4
#define VBH_OP_FLUSH_OUT 5
#define VBH_OP_IDENT 8
+#define VBH_OP_DISCARD 11
+#define VBH_OP_WRITE_ZEROES 13
+
#define VBH_FLAG_BARRIER 0x80000000 /* OR'ed into vbh_type */
uint32_t vbh_type;
uint32_t vbh_ioprio;
@@ -124,8 +161,8 @@
* Debug printf
*/
static int pci_vtblk_debug;
-#define DPRINTF(params) if (pci_vtblk_debug) PRINTLN params
-#define WPRINTF(params) PRINTLN params
+#define DPRINTF(params) if (pci_vtblk_debug) PRINTLN params
+#define WPRINTF(params) PRINTLN params
struct pci_vtblk_ioreq {
struct blockif_req io_req;
@@ -134,6 +171,15 @@
uint16_t io_idx;
};
+struct virtio_blk_discard_write_zeroes {
+ uint64_t sector;
+ uint32_t num_sectors;
+ struct {
+ uint32_t unmap:1;
+ uint32_t reserved:31;
+ } flags;
+};
+
/*
* Per-device softc
*/
@@ -142,6 +188,7 @@
pthread_mutex_t vsc_mtx;
struct vqueue_info vbsc_vq;
struct vtblk_config vbsc_cfg;
+ struct virtio_consts vbsc_consts;
struct blockif_ctxt *bc;
char vbsc_ident[VTBLK_BLK_ID_BYTES];
struct pci_vtblk_ioreq vbsc_ios[VTBLK_RINGSZ];
@@ -174,9 +221,8 @@
}
static void
-pci_vtblk_done(struct blockif_req *br, int err)
+pci_vtblk_done_locked(struct pci_vtblk_ioreq *io, int err)
{
- struct pci_vtblk_ioreq *io = br->br_param;
struct pci_vtblk_softc *sc = io->io_sc;
/* convert errno into a virtio block error return */
@@ -191,9 +237,18 @@
* Return the descriptor back to the host.
* We wrote 1 byte (our status) to host.
*/
- pthread_mutex_lock(&sc->vsc_mtx);
vq_relchain(&sc->vbsc_vq, io->io_idx, 1);
vq_endchains(&sc->vbsc_vq, 0);
+}
+
+static void
+pci_vtblk_done(struct blockif_req *br, int err)
+{
+ struct pci_vtblk_ioreq *io = br->br_param;
+ struct pci_vtblk_softc *sc = io->io_sc;
+
+ pthread_mutex_lock(&sc->vsc_mtx);
+ pci_vtblk_done_locked(io, err);
pthread_mutex_unlock(&sc->vsc_mtx);
}
@@ -208,6 +263,7 @@
int writeop, type;
struct iovec iov[BLOCKIF_IOV_MAX + 2];
uint16_t idx, flags[BLOCKIF_IOV_MAX + 2];
+ struct virtio_blk_discard_write_zeroes *discard;
n = vq_getchain(vq, &idx, iov, BLOCKIF_IOV_MAX + 2, flags);
@@ -224,11 +280,11 @@
io = &sc->vbsc_ios[idx];
assert((flags[0] & VRING_DESC_F_WRITE) == 0);
assert(iov[0].iov_len == sizeof(struct virtio_blk_hdr));
- vbh = iov[0].iov_base;
+ vbh = (struct virtio_blk_hdr *)iov[0].iov_base;
memcpy(&io->io_req.br_iov, &iov[1], sizeof(struct iovec) * (n - 2));
io->io_req.br_iovcnt = n - 2;
- io->io_req.br_offset = vbh->vbh_sector * DEV_BSIZE;
- io->io_status = iov[--n].iov_base;
+ io->io_req.br_offset = vbh->vbh_sector * VTBLK_BSIZE;
+ io->io_status = (uint8_t *)iov[--n].iov_base;
assert(iov[n].iov_len == 1);
assert(flags[n] & VRING_DESC_F_WRITE);
@@ -238,7 +294,7 @@
* we don't advertise the capability.
*/
type = vbh->vbh_type & ~VBH_FLAG_BARRIER;
- writeop = (type == VBH_OP_WRITE);
+ writeop = (type == VBH_OP_WRITE || type == VBH_OP_DISCARD);
iolen = 0;
for (i = 1; i < n; i++) {
@@ -254,7 +310,7 @@
io->io_req.br_resid = iolen;
DPRINTF(("virtio-block: %s op, %zd bytes, %d segs, offset %ld",
- writeop ? "write" : "read/ident", iolen, i - 1,
+ writeop ? "write/discard" : "read/ident", iolen, i - 1,
io->io_req.br_offset));
switch (type) {
@@ -264,6 +320,46 @@
case VBH_OP_WRITE:
err = blockif_write(sc->bc, &io->io_req);
break;
+ case VBH_OP_DISCARD:
+ /*
+ * We currently only support a single request, if the guest
+ * has submitted a request that doesn't conform to the
+ * requirements, we return a error.
+ */
+ if (iov[1].iov_len != sizeof (*discard)) {
+ pci_vtblk_done_locked(io, EINVAL);
+ return;
+ }
+
+ /* The segments to discard are provided rather than data */
+ discard = (struct virtio_blk_discard_write_zeroes *)
+ iov[1].iov_base;
+
+ /*
+ * virtio v1.1 5.2.6.2:
+ * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP
+ * for discard and write zeroes commands if any unknown flag is
+ * set. Furthermore, the device MUST set the status byte to
+ * VIRTIO_BLK_S_UNSUPP for discard commands if the unmap flag
+ * is set.
+ *
+ * Currently there are no known flags for a DISCARD request.
+ */
+ if (discard->flags.unmap != 0 || discard->flags.reserved != 0) {
+ pci_vtblk_done_locked(io, ENOTSUP);
+ return;
+ }
+
+ /* Make sure the request doesn't exceed our size limit */
+ if (discard->num_sectors > VTBLK_MAX_DISCARD_SECT) {
+ pci_vtblk_done_locked(io, EINVAL);
+ return;
+ }
+
+ io->io_req.br_offset = discard->sector * VTBLK_BSIZE;
+ io->io_req.br_resid = discard->num_sectors * VTBLK_BSIZE;
+ err = blockif_delete(sc->bc, &io->io_req);
+ break;
case VBH_OP_FLUSH:
case VBH_OP_FLUSH_OUT:
err = blockif_flush(sc->bc, &io->io_req);
@@ -274,10 +370,10 @@
memset(iov[1].iov_base, 0, iov[1].iov_len);
strncpy(iov[1].iov_base, sc->vbsc_ident,
MIN(iov[1].iov_len, sizeof(sc->vbsc_ident)));
- pci_vtblk_done(&io->io_req, 0);
+ pci_vtblk_done_locked(io, 0);
return;
default:
- pci_vtblk_done(&io->io_req, EOPNOTSUPP);
+ pci_vtblk_done_locked(io, EOPNOTSUPP);
return;
}
assert(err == 0);
@@ -332,10 +428,14 @@
io->io_idx = i;
}
+ bcopy(&vtblk_vi_consts, &sc->vbsc_consts, sizeof (vtblk_vi_consts));
+ if (blockif_candelete(sc->bc))
+ sc->vbsc_consts.vc_hv_caps |= VTBLK_F_DISCARD;
+
pthread_mutex_init(&sc->vsc_mtx, NULL);
/* init virtio softc and virtqueues */
- vi_softc_linkup(&sc->vbsc_vs, &vtblk_vi_consts, sc, pi, &sc->vbsc_vq);
+ vi_softc_linkup(&sc->vbsc_vs, &sc->vbsc_consts, sc, pi, &sc->vbsc_vq);
sc->vbsc_vs.vs_mtx = &sc->vsc_mtx;
sc->vbsc_vq.vq_qsize = VTBLK_RINGSZ;
@@ -353,7 +453,7 @@
digest[0], digest[1], digest[2], digest[3], digest[4], digest[5]);
/* setup virtio block config space */
- sc->vbsc_cfg.vbc_capacity = size / DEV_BSIZE; /* 512-byte units */
+ sc->vbsc_cfg.vbc_capacity = size / VTBLK_BSIZE; /* 512-byte units */
sc->vbsc_cfg.vbc_size_max = 0; /* not negotiated */
/*
@@ -375,6 +475,9 @@
sc->vbsc_cfg.vbc_topology.min_io_size = 0;
sc->vbsc_cfg.vbc_topology.opt_io_size = 0;
sc->vbsc_cfg.vbc_writeback = 0;
+ sc->vbsc_cfg.max_discard_sectors = VTBLK_MAX_DISCARD_SECT;
+ sc->vbsc_cfg.max_discard_seg = VTBLK_MAX_DISCARD_SEG;
+ sc->vbsc_cfg.discard_sector_alignment = sectsz / VTBLK_BSIZE;
/*
* Should we move some of this into virtio.c? Could
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Sep 28, 7:53 PM (2 h, 16 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
39829462
Default Alt Text
D21707.id.diff (10 KB)
Attached To
Mode
D21707: Add VIRTIO_BLK_T_DISCARD (TRIM) support to the bhyve virtio-blk backend
Attached
Detach File
Event Timeline
Log In to Comment