Am 19.05.2011 10:58, schrieb Christoph Hellwig: > Add support for TRIM sub function of the data set management command, > and wire it up to the qemu discard infrastructure. > > Signed-off-by: Christoph Hellwig <h...@lst.de> > > Index: qemu/hw/ide/core.c > =================================================================== > --- qemu.orig/hw/ide/core.c 2011-05-18 20:30:20.855172933 +0200 > +++ qemu/hw/ide/core.c 2011-05-18 20:32:26.237625024 +0200 > @@ -124,6 +124,9 @@ static void ide_identify(IDEState *s) > put_le16(p + 66, 120); > put_le16(p + 67, 120); > put_le16(p + 68, 120); > + if (dev && dev->conf.discard_granularity) { > + put_le16(p + 69, (1 << 14)); /* determinate TRIM behavior */ > + } > > if (s->ncq_queues) { > put_le16(p + 75, s->ncq_queues - 1); > @@ -157,6 +160,9 @@ static void ide_identify(IDEState *s) > dev = s->unit ? s->bus->slave : s->bus->master; > if (dev && dev->conf.physical_block_size) > put_le16(p + 106, 0x6000 | get_physical_block_exp(&dev->conf)); > + if (dev && dev->conf.discard_granularity) { > + put_le16(p + 169, 1); /* TRIM support */ > + } > > memcpy(s->identify_data, p, sizeof(s->identify_data)); > s->identify_set = 1; > @@ -299,6 +305,72 @@ static void ide_set_signature(IDEState * > } > } > > +typedef struct TrimAIOCB { > + BlockDriverAIOCB common; > + QEMUBH *bh; > + int ret; > +} TrimAIOCB; > + > +static void trim_aio_cancel(BlockDriverAIOCB *acb) > +{ > + TrimAIOCB *iocb = container_of(acb, TrimAIOCB, common); > + > + qemu_bh_delete(iocb->bh); > + iocb->bh = NULL; > + qemu_aio_release(iocb); > +} > + > +static AIOPool trim_aio_pool = { > + .aiocb_size = sizeof(TrimAIOCB), > + .cancel = trim_aio_cancel, > +}; > + > +static void ide_trim_bh_cb(void *opaque) > +{ > + TrimAIOCB *iocb = opaque; > + > + iocb->common.cb(iocb->common.opaque, iocb->ret); > + > + qemu_bh_delete(iocb->bh); > + iocb->bh = NULL; > + > + qemu_aio_release(iocb); > +} > + > +BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs, > + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, > + BlockDriverCompletionFunc *cb, void *opaque) > +{ > + TrimAIOCB *iocb; > + int i, j, ret; > + > + iocb = qemu_aio_get(&trim_aio_pool, bs, cb, opaque); > + iocb->bh = qemu_bh_new(ide_trim_bh_cb, iocb); > + iocb->ret = 0; > + > + for (j = 0; j < qiov->niov; j++) { > + uint64_t *buffer = qiov->iov[j].iov_base; > + > + for (i = 0; i < qiov->iov[j].iov_len / 8; i++) { > + /* 6-byte LBA + 2-byte range per entry */ > + uint64_t entry = le64_to_cpu(buffer[i]); > + uint64_t sector = entry & 0x0000ffffffffffffULL; > + uint16_t count = entry >> 48; > + > + if (count == 0) > + break; > + > + ret = bdrv_discard(bs, sector * 512, count * 512);
Hm... bdrv_discard wants sector numbers instead of bytes, doesn't it? If you agree, I'll send out and apply a fixed and rebased version. Kevin