dm: storage: support cache mode toggling

1. support "writeback" and "writethru" mode toggling for virtio-blk
conditionally. When starting DM with "writethru" parameter in
virtio-blk, guest OS could not toggle cache mode. When starting DM
with "writeback" parameter in virtio-blk, guest OS could toggle
cache mode.

    ------------------------------
    DM cmdline  | toggle support
    ------------+-----------------
    writeback   | yes
    writethru   | no
    ------------------------------

2. To toggle cache mode, run below command in guest OS:

    echo "write back" > /sys/devices/xxx/vdx/cache_type
OR
    echo "write through" > /sys/devices/xxx/vdx/cache_type

Signed-off-by: Conghui Chen <conghui.chen@intel.com>
Reviewed-by: Shuo Liu <shuo.a.liu@intel.com>
Acked-by: Yin Fengwei <fengwei.yin@intel.com>
This commit is contained in:
Conghui Chen 2018-08-09 09:50:37 +08:00 committed by lijinxia
parent f4fcf5d6eb
commit 49322ac002
3 changed files with 77 additions and 4 deletions

View File

@ -951,3 +951,29 @@ blockif_candelete(struct blockif_ctxt *bc)
assert(bc->magic == BLOCKIF_SIG);
return bc->candelete;
}
uint8_t
blockif_get_wce(struct blockif_ctxt *bc)
{
assert(bc->magic == BLOCKIF_SIG);
return bc->wce;
}
void
blockif_set_wce(struct blockif_ctxt *bc, uint8_t wce)
{
assert(bc->magic == BLOCKIF_SIG);
bc->wce = wce;
}
int
blockif_flush_all(struct blockif_ctxt *bc)
{
int err;
err=0;
assert(bc->magic == BLOCKIF_SIG);
if (fsync(bc->fd))
err = errno;
return err;
}

View File

@ -54,16 +54,25 @@
#define VIRTIO_BLK_F_FLUSH (1 << 9) /* Cache flush support */
#define VIRTIO_BLK_F_TOPOLOGY (1 << 10) /* Optimal I/O alignment */
/* Device can toggle its cache between writeback and writethrough modes */
#define VIRTIO_BLK_F_CONFIG_WCE (1 << 11)
/*
* Host capabilities
* Basic device capabilities
*/
#define VIRTIO_BLK_S_HOSTCAPS \
(VIRTIO_BLK_F_SEG_MAX | \
VIRTIO_BLK_F_BLK_SIZE | \
VIRTIO_BLK_F_FLUSH | \
VIRTIO_BLK_F_TOPOLOGY | \
VIRTIO_RING_F_INDIRECT_DESC) /* indirect descriptors */
/*
* Writeback cache bits
*/
#define VIRTIO_BLK_F_WB_BITS \
(VIRTIO_BLK_F_FLUSH | \
VIRTIO_BLK_F_CONFIG_WCE)
/*
* Config space "registers"
*/
@ -126,6 +135,7 @@ struct virtio_blk {
struct blockif_ctxt *bc;
char ident[VIRTIO_BLK_BLK_ID_BYTES + 1];
struct virtio_blk_ioreq ios[VIRTIO_BLK_RINGSZ];
uint8_t original_wce;
};
static void virtio_blk_reset(void *);
@ -152,6 +162,7 @@ virtio_blk_reset(void *vdev)
DPRINTF(("virtio_blk: device reset requested !\n"));
virtio_reset_dev(&blk->base);
blockif_set_wce(blk->bc, blk->original_wce);
}
static void
@ -273,6 +284,17 @@ virtio_blk_notify(void *vdev, struct virtio_vq_info *vq)
virtio_blk_proc(blk, vq);
}
static uint64_t
virtio_blk_get_caps(struct virtio_blk *blk, bool wb)
{
uint64_t caps;
caps = VIRTIO_BLK_S_HOSTCAPS;
if (wb)
caps |= VIRTIO_BLK_F_WB_BITS;
return caps;
}
static int
virtio_blk_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
{
@ -338,7 +360,6 @@ virtio_blk_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
/* init virtio struct and virtqueues */
virtio_linkup(&blk->base, &virtio_blk_ops, blk, dev, &blk->vq);
blk->base.mtx = &blk->mtx;
blk->base.device_caps = VIRTIO_BLK_S_HOSTCAPS;
blk->vq.qsize = VIRTIO_BLK_RINGSZ;
/* blk->vq.vq_notify = we have no per-queue notify */
@ -367,7 +388,10 @@ virtio_blk_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
(sto != 0) ? ((sts - sto) / sectsz) : 0;
blk->cfg.topology.min_io_size = 0;
blk->cfg.topology.opt_io_size = 0;
blk->cfg.writeback = 0;
blk->cfg.writeback = blockif_get_wce(blk->bc);
blk->original_wce = blk->cfg.writeback; /* save for reset */
blk->base.device_caps =
virtio_blk_get_caps(blk, !!blk->cfg.writeback);
/*
* Should we move some of this into virtio.c? Could
@ -399,6 +423,9 @@ virtio_blk_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
DPRINTF(("virtio_blk: deinit\n"));
blk = (struct virtio_blk *) dev->arg;
bctxt = blk->bc;
if (blockif_flush_all(bctxt))
WPRINTF(("vrito_blk:"
"Failed to flush before close\n"));
blockif_close(bctxt);
free(blk);
}
@ -407,6 +434,23 @@ virtio_blk_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
static int
virtio_blk_cfgwrite(void *vdev, int offset, int size, uint32_t value)
{
struct virtio_blk *blk = vdev;
struct virtio_blk_config *blkcfg = &(blk->cfg);
void *ptr;
ptr = (uint8_t *)blkcfg + offset;
if ((offset == offsetof(struct virtio_blk_config, writeback))
&& (size == 1)) {
memcpy(ptr, &value, size);
blockif_set_wce(blk->bc, blkcfg->writeback);
if (blkcfg->writeback)
blk->base.device_caps |= VIRTIO_BLK_F_FLUSH;
else
blk->base.device_caps &= ~VIRTIO_BLK_F_FLUSH;
return 0;
}
DPRINTF(("virtio_blk: write to readonly reg %d\n\r", offset));
return -1;
}

View File

@ -66,5 +66,8 @@ int blockif_flush(struct blockif_ctxt *bc, struct blockif_req *breq);
int blockif_delete(struct blockif_ctxt *bc, struct blockif_req *breq);
int blockif_cancel(struct blockif_ctxt *bc, struct blockif_req *breq);
int blockif_close(struct blockif_ctxt *bc);
uint8_t blockif_get_wce(struct blockif_ctxt *bc);
void blockif_set_wce(struct blockif_ctxt *bc, uint8_t wce);
int blockif_flush_all(struct blockif_ctxt *bc);
#endif /* _BLOCK_IF_H_ */