Index: sys/dev/virtio/block/virtio_blk.h =================================================================== --- sys/dev/virtio/block/virtio_blk.h +++ sys/dev/virtio/block/virtio_blk.h @@ -34,16 +34,20 @@ #define _VIRTIO_BLK_H /* Feature bits */ -#define VIRTIO_BLK_F_BARRIER 0x0001 /* Does host support barriers? */ -#define VIRTIO_BLK_F_SIZE_MAX 0x0002 /* Indicates maximum segment size */ -#define VIRTIO_BLK_F_SEG_MAX 0x0004 /* Indicates maximum # of segments */ -#define VIRTIO_BLK_F_GEOMETRY 0x0010 /* Legacy geometry available */ -#define VIRTIO_BLK_F_RO 0x0020 /* Disk is read-only */ -#define VIRTIO_BLK_F_BLK_SIZE 0x0040 /* Block size of disk is available*/ -#define VIRTIO_BLK_F_SCSI 0x0080 /* Supports scsi command passthru */ -#define VIRTIO_BLK_F_WCE 0x0200 /* Writeback mode enabled after reset */ -#define VIRTIO_BLK_F_TOPOLOGY 0x0400 /* Topology information is available */ -#define VIRTIO_BLK_F_CONFIG_WCE 0x0800 /* Writeback mode available in config */ +#define VIRTIO_BLK_F_BARRIER (1 << 0) /* Does host support barriers? */ +#define VIRTIO_BLK_F_SIZE_MAX (1 << 1) /* Indicates maximum segment size */ +#define VIRTIO_BLK_F_SEG_MAX (1 << 2) /* Indicates maximum # of segments */ +#define VIRTIO_BLK_F_GEOMETRY (1 << 4) /* Legacy geometry available */ +#define VIRTIO_BLK_F_RO (1 << 5) /* Disk is read-only */ +#define VIRTIO_BLK_F_BLK_SIZE (1 << 6) /* Block size of disk is available*/ +#define VIRTIO_BLK_F_SCSI (1 << 7) /* Supports scsi command passthru */ +#define VIRTIO_BLK_F_FLUSH (1 << 9) /* Writeback mode enabled after reset */ +#define VIRTIO_BLK_F_WCE (1 << 9) /* Legacy alias for FLUSH */ +#define VIRTIO_BLK_F_TOPOLOGY (1 << 10) /* Topology information is available */ +#define VIRTIO_BLK_F_CONFIG_WCE (1 << 11) /* Writeback mode available in config */ +#define VIRTIO_BLK_F_MQ (1 << 12) /* Multi-Queue */ +#define VIRTIO_BLK_F_DISCARD (1 << 13) /* Trim blocks */ +#define VIRTIO_BLK_F_WRITE_ZEROES (1 << 14) /* Write zeros */ #define VIRTIO_BLK_ID_BYTES 20 /* ID string length */ @@ -74,7 +78,15 @@ /* Writeback mode (if VIRTIO_BLK_F_CONFIG_WCE) */ uint8_t 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; /* @@ -89,23 +101,34 @@ */ /* These two define direction. */ -#define VIRTIO_BLK_T_IN 0 -#define VIRTIO_BLK_T_OUT 1 +#define VIRTIO_BLK_T_IN 0 +#define VIRTIO_BLK_T_OUT 1 /* This bit says it's a scsi command, not an actual read or write. */ -#define VIRTIO_BLK_T_SCSI_CMD 2 +#define VIRTIO_BLK_T_SCSI_CMD 2 +#define VIRTIO_BLK_T_SCSI_CMD_OUT 3 /* Cache flush command */ -#define VIRTIO_BLK_T_FLUSH 4 +#define VIRTIO_BLK_T_FLUSH 4 +#define VIRTIO_BLK_T_FLUSH_OUT 5 /* Get device ID command */ -#define VIRTIO_BLK_T_GET_ID 8 +#define VIRTIO_BLK_T_GET_ID 8 + +/* Discard command */ +#define VIRTIO_BLK_T_DISCARD 11 + +/* Write zeros command */ +#define VIRTIO_BLK_T_WRITE_ZEROES 13 /* Barrier before this op. */ -#define VIRTIO_BLK_T_BARRIER 0x80000000 +#define VIRTIO_BLK_T_BARRIER 0x80000000 /* ID string length */ -#define VIRTIO_BLK_ID_BYTES 20 +#define VIRTIO_BLK_ID_BYTES 20 + +/* Unmap this range (only valid for write zeroes command) */ +#define VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP 0x00000001 /* This is the first element of the read scatter-gather list. */ struct virtio_blk_outhdr { @@ -117,6 +140,15 @@ uint64_t sector; }; +struct virtio_blk_discard_write_zeroes { + uint64_t sector; + uint32_t num_sectors; + struct { + uint32_t unmap:1; + uint32_t reserved:31; + } flags; +}; + struct virtio_scsi_inhdr { uint32_t errors; uint32_t data_len; Index: sys/dev/virtio/block/virtio_blk.c =================================================================== --- sys/dev/virtio/block/virtio_blk.c +++ sys/dev/virtio/block/virtio_blk.c @@ -81,6 +81,7 @@ #define VTBLK_FLAG_SUSPEND 0x0008 #define VTBLK_FLAG_BARRIER 0x0010 #define VTBLK_FLAG_WC_CONFIG 0x0020 +#define VTBLK_FLAG_DISCARD 0x0040 struct virtqueue *vtblk_vq; struct sglist *vtblk_sglist; @@ -112,6 +113,7 @@ { VIRTIO_BLK_F_WCE, "WriteCache" }, { VIRTIO_BLK_F_TOPOLOGY, "Topology" }, { VIRTIO_BLK_F_CONFIG_WCE, "ConfigWCE" }, + { VIRTIO_BLK_F_DISCARD, "Discard" }, { 0, NULL } }; @@ -210,6 +212,7 @@ VIRTIO_BLK_F_WCE | \ VIRTIO_BLK_F_TOPOLOGY | \ VIRTIO_BLK_F_CONFIG_WCE | \ + VIRTIO_BLK_F_DISCARD | \ VIRTIO_RING_F_INDIRECT_DESC) #define VTBLK_MTX(_sc) &(_sc)->vtblk_mtx @@ -544,7 +547,8 @@ * be a better way to report our readonly'ness to GEOM above. */ if (sc->vtblk_flags & VTBLK_FLAG_READONLY && - (bp->bio_cmd == BIO_WRITE || bp->bio_cmd == BIO_FLUSH)) { + (bp->bio_cmd == BIO_WRITE || bp->bio_cmd == BIO_FLUSH || + bp->bio_cmd == BIO_DELETE)) { vtblk_bio_done(sc, bp, EROFS); return; } @@ -592,6 +596,8 @@ sc->vtblk_flags |= VTBLK_FLAG_BARRIER; if (virtio_with_feature(dev, VIRTIO_BLK_F_CONFIG_WCE)) sc->vtblk_flags |= VTBLK_FLAG_WC_CONFIG; + if (virtio_with_feature(dev, VIRTIO_BLK_F_DISCARD)) + sc->vtblk_flags |= VTBLK_FLAG_DISCARD; } static int @@ -720,6 +726,12 @@ dp->d_stripesize; } + if (virtio_with_feature(dev, VIRTIO_BLK_F_DISCARD)) { + dp->d_flags |= DISKFLAG_CANDELETE; + dp->d_delmaxsize = blkcfg->max_discard_sectors * + dp->d_sectorsize; + } + if (vtblk_write_cache_enabled(sc, blkcfg) != 0) sc->vtblk_write_cache = VTBLK_CACHE_WRITEBACK; else @@ -876,6 +888,9 @@ req->vbr_hdr.type = VIRTIO_BLK_T_OUT; req->vbr_hdr.sector = bp->bio_offset / 512; break; + case BIO_DELETE: + req->vbr_hdr.type = VIRTIO_BLK_T_DISCARD; + break; default: panic("%s: bio with unhandled cmd: %d", __func__, bp->bio_cmd); } @@ -929,6 +944,16 @@ /* BIO_READ means the host writes into our buffer. */ if (bp->bio_cmd == BIO_READ) writable = sg->sg_nseg - 1; + } else if (bp->bio_cmd == BIO_DELETE) { + struct virtio_blk_discard_write_zeroes discard; + + discard.sector = bp->bio_offset / 512; + discard.num_sectors = bp->bio_bcount / 512; + error = sglist_append(sg, &discard, sizeof(discard)); + if (error || sg->sg_nseg == sg->sg_maxseg) { + panic("%s: bio %p data buffer too big %d", + __func__, bp, error); + } } writable++; @@ -1119,6 +1144,11 @@ VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_BLK_SIZE, blk_size, blkcfg); VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_TOPOLOGY, topology, blkcfg); VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_CONFIG_WCE, writeback, blkcfg); + VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_DISCARD, max_discard_sectors, + blkcfg); + VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_DISCARD, max_discard_seg, blkcfg); + VTBLK_GET_CONFIG(dev, VIRTIO_BLK_F_DISCARD, discard_sector_alignment, + blkcfg); } #undef VTBLK_GET_CONFIG