block: Remove bdrv_aio_multiwrite()
Since virtio-blk implements request merging itself these days, the only remaining users are test cases for the function. That doesn't make the function exactly useful any more. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Reviewed-by: Max Reitz <mreitz@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com>
This commit is contained in:
parent
66a0fae438
commit
91c6e4b7bb
@ -1067,20 +1067,6 @@ void blk_aio_cancel_async(BlockAIOCB *acb)
|
|||||||
bdrv_aio_cancel_async(acb);
|
bdrv_aio_cancel_async(acb);
|
||||||
}
|
}
|
||||||
|
|
||||||
int blk_aio_multiwrite(BlockBackend *blk, BlockRequest *reqs, int num_reqs)
|
|
||||||
{
|
|
||||||
int i, ret;
|
|
||||||
|
|
||||||
for (i = 0; i < num_reqs; i++) {
|
|
||||||
ret = blk_check_request(blk, reqs[i].sector, reqs[i].nb_sectors);
|
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bdrv_aio_multiwrite(blk_bs(blk), reqs, num_reqs);
|
|
||||||
}
|
|
||||||
|
|
||||||
int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
|
int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf)
|
||||||
{
|
{
|
||||||
if (!blk_is_available(blk)) {
|
if (!blk_is_available(blk)) {
|
||||||
|
194
block/io.c
194
block/io.c
@ -1878,200 +1878,6 @@ BlockAIOCB *bdrv_aio_write_zeroes(BlockDriverState *bs,
|
|||||||
cb, opaque, true);
|
cb, opaque, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct MultiwriteCB {
|
|
||||||
int error;
|
|
||||||
int num_requests;
|
|
||||||
int num_callbacks;
|
|
||||||
struct {
|
|
||||||
BlockCompletionFunc *cb;
|
|
||||||
void *opaque;
|
|
||||||
QEMUIOVector *free_qiov;
|
|
||||||
} callbacks[];
|
|
||||||
} MultiwriteCB;
|
|
||||||
|
|
||||||
static void multiwrite_user_cb(MultiwriteCB *mcb)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < mcb->num_callbacks; i++) {
|
|
||||||
mcb->callbacks[i].cb(mcb->callbacks[i].opaque, mcb->error);
|
|
||||||
if (mcb->callbacks[i].free_qiov) {
|
|
||||||
qemu_iovec_destroy(mcb->callbacks[i].free_qiov);
|
|
||||||
}
|
|
||||||
g_free(mcb->callbacks[i].free_qiov);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void multiwrite_cb(void *opaque, int ret)
|
|
||||||
{
|
|
||||||
MultiwriteCB *mcb = opaque;
|
|
||||||
|
|
||||||
trace_multiwrite_cb(mcb, ret);
|
|
||||||
|
|
||||||
if (ret < 0 && !mcb->error) {
|
|
||||||
mcb->error = ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
mcb->num_requests--;
|
|
||||||
if (mcb->num_requests == 0) {
|
|
||||||
multiwrite_user_cb(mcb);
|
|
||||||
g_free(mcb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int multiwrite_req_compare(const void *a, const void *b)
|
|
||||||
{
|
|
||||||
const BlockRequest *req1 = a, *req2 = b;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Note that we can't simply subtract req2->sector from req1->sector
|
|
||||||
* here as that could overflow the return value.
|
|
||||||
*/
|
|
||||||
if (req1->sector > req2->sector) {
|
|
||||||
return 1;
|
|
||||||
} else if (req1->sector < req2->sector) {
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Takes a bunch of requests and tries to merge them. Returns the number of
|
|
||||||
* requests that remain after merging.
|
|
||||||
*/
|
|
||||||
static int multiwrite_merge(BlockDriverState *bs, BlockRequest *reqs,
|
|
||||||
int num_reqs, MultiwriteCB *mcb)
|
|
||||||
{
|
|
||||||
int i, outidx;
|
|
||||||
|
|
||||||
// Sort requests by start sector
|
|
||||||
qsort(reqs, num_reqs, sizeof(*reqs), &multiwrite_req_compare);
|
|
||||||
|
|
||||||
// Check if adjacent requests touch the same clusters. If so, combine them,
|
|
||||||
// filling up gaps with zero sectors.
|
|
||||||
outidx = 0;
|
|
||||||
for (i = 1; i < num_reqs; i++) {
|
|
||||||
int merge = 0;
|
|
||||||
int64_t oldreq_last = reqs[outidx].sector + reqs[outidx].nb_sectors;
|
|
||||||
|
|
||||||
// Handle exactly sequential writes and overlapping writes.
|
|
||||||
if (reqs[i].sector <= oldreq_last) {
|
|
||||||
merge = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reqs[outidx].qiov->niov + reqs[i].qiov->niov + 1 >
|
|
||||||
bs->bl.max_iov) {
|
|
||||||
merge = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bs->bl.max_transfer_length && reqs[outidx].nb_sectors +
|
|
||||||
reqs[i].nb_sectors > bs->bl.max_transfer_length) {
|
|
||||||
merge = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (merge) {
|
|
||||||
size_t size;
|
|
||||||
QEMUIOVector *qiov = g_malloc0(sizeof(*qiov));
|
|
||||||
qemu_iovec_init(qiov,
|
|
||||||
reqs[outidx].qiov->niov + reqs[i].qiov->niov + 1);
|
|
||||||
|
|
||||||
// Add the first request to the merged one. If the requests are
|
|
||||||
// overlapping, drop the last sectors of the first request.
|
|
||||||
size = (reqs[i].sector - reqs[outidx].sector) << 9;
|
|
||||||
qemu_iovec_concat(qiov, reqs[outidx].qiov, 0, size);
|
|
||||||
|
|
||||||
// We should need to add any zeros between the two requests
|
|
||||||
assert (reqs[i].sector <= oldreq_last);
|
|
||||||
|
|
||||||
// Add the second request
|
|
||||||
qemu_iovec_concat(qiov, reqs[i].qiov, 0, reqs[i].qiov->size);
|
|
||||||
|
|
||||||
// Add tail of first request, if necessary
|
|
||||||
if (qiov->size < reqs[outidx].qiov->size) {
|
|
||||||
qemu_iovec_concat(qiov, reqs[outidx].qiov, qiov->size,
|
|
||||||
reqs[outidx].qiov->size - qiov->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
reqs[outidx].nb_sectors = qiov->size >> 9;
|
|
||||||
reqs[outidx].qiov = qiov;
|
|
||||||
|
|
||||||
mcb->callbacks[i].free_qiov = reqs[outidx].qiov;
|
|
||||||
} else {
|
|
||||||
outidx++;
|
|
||||||
reqs[outidx].sector = reqs[i].sector;
|
|
||||||
reqs[outidx].nb_sectors = reqs[i].nb_sectors;
|
|
||||||
reqs[outidx].qiov = reqs[i].qiov;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bs->blk) {
|
|
||||||
block_acct_merge_done(blk_get_stats(bs->blk), BLOCK_ACCT_WRITE,
|
|
||||||
num_reqs - outidx - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return outidx + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Submit multiple AIO write requests at once.
|
|
||||||
*
|
|
||||||
* On success, the function returns 0 and all requests in the reqs array have
|
|
||||||
* been submitted. In error case this function returns -1, and any of the
|
|
||||||
* requests may or may not be submitted yet. In particular, this means that the
|
|
||||||
* callback will be called for some of the requests, for others it won't. The
|
|
||||||
* caller must check the error field of the BlockRequest to wait for the right
|
|
||||||
* callbacks (if error != 0, no callback will be called).
|
|
||||||
*
|
|
||||||
* The implementation may modify the contents of the reqs array, e.g. to merge
|
|
||||||
* requests. However, the fields opaque and error are left unmodified as they
|
|
||||||
* are used to signal failure for a single request to the caller.
|
|
||||||
*/
|
|
||||||
int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs, int num_reqs)
|
|
||||||
{
|
|
||||||
MultiwriteCB *mcb;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* don't submit writes if we don't have a medium */
|
|
||||||
if (bs->drv == NULL) {
|
|
||||||
for (i = 0; i < num_reqs; i++) {
|
|
||||||
reqs[i].error = -ENOMEDIUM;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_reqs == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create MultiwriteCB structure
|
|
||||||
mcb = g_malloc0(sizeof(*mcb) + num_reqs * sizeof(*mcb->callbacks));
|
|
||||||
mcb->num_requests = 0;
|
|
||||||
mcb->num_callbacks = num_reqs;
|
|
||||||
|
|
||||||
for (i = 0; i < num_reqs; i++) {
|
|
||||||
mcb->callbacks[i].cb = reqs[i].cb;
|
|
||||||
mcb->callbacks[i].opaque = reqs[i].opaque;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for mergable requests
|
|
||||||
num_reqs = multiwrite_merge(bs, reqs, num_reqs, mcb);
|
|
||||||
|
|
||||||
trace_bdrv_aio_multiwrite(mcb, mcb->num_callbacks, num_reqs);
|
|
||||||
|
|
||||||
/* Run the aio requests. */
|
|
||||||
mcb->num_requests = num_reqs;
|
|
||||||
for (i = 0; i < num_reqs; i++) {
|
|
||||||
bdrv_co_aio_rw_vector(bs, reqs[i].sector, reqs[i].qiov,
|
|
||||||
reqs[i].nb_sectors, reqs[i].flags,
|
|
||||||
multiwrite_cb, mcb,
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bdrv_aio_cancel(BlockAIOCB *acb)
|
void bdrv_aio_cancel(BlockAIOCB *acb)
|
||||||
{
|
{
|
||||||
qemu_aio_ref(acb);
|
qemu_aio_ref(acb);
|
||||||
|
@ -329,7 +329,7 @@ void bdrv_aio_cancel(BlockAIOCB *acb);
|
|||||||
void bdrv_aio_cancel_async(BlockAIOCB *acb);
|
void bdrv_aio_cancel_async(BlockAIOCB *acb);
|
||||||
|
|
||||||
typedef struct BlockRequest {
|
typedef struct BlockRequest {
|
||||||
/* Fields to be filled by multiwrite caller */
|
/* Fields to be filled by caller */
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
int64_t sector;
|
int64_t sector;
|
||||||
@ -345,13 +345,10 @@ typedef struct BlockRequest {
|
|||||||
BlockCompletionFunc *cb;
|
BlockCompletionFunc *cb;
|
||||||
void *opaque;
|
void *opaque;
|
||||||
|
|
||||||
/* Filled by multiwrite implementation */
|
/* Filled by block layer */
|
||||||
int error;
|
int error;
|
||||||
} BlockRequest;
|
} BlockRequest;
|
||||||
|
|
||||||
int bdrv_aio_multiwrite(BlockDriverState *bs, BlockRequest *reqs,
|
|
||||||
int num_reqs);
|
|
||||||
|
|
||||||
/* sg packet commands */
|
/* sg packet commands */
|
||||||
int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf);
|
int bdrv_ioctl(BlockDriverState *bs, unsigned long int req, void *buf);
|
||||||
BlockAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
|
BlockAIOCB *bdrv_aio_ioctl(BlockDriverState *bs,
|
||||||
|
@ -138,7 +138,6 @@ BlockAIOCB *blk_aio_discard(BlockBackend *blk,
|
|||||||
BlockCompletionFunc *cb, void *opaque);
|
BlockCompletionFunc *cb, void *opaque);
|
||||||
void blk_aio_cancel(BlockAIOCB *acb);
|
void blk_aio_cancel(BlockAIOCB *acb);
|
||||||
void blk_aio_cancel_async(BlockAIOCB *acb);
|
void blk_aio_cancel_async(BlockAIOCB *acb);
|
||||||
int blk_aio_multiwrite(BlockBackend *blk, BlockRequest *reqs, int num_reqs);
|
|
||||||
int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf);
|
int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf);
|
||||||
BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
|
BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf,
|
||||||
BlockCompletionFunc *cb, void *opaque);
|
BlockCompletionFunc *cb, void *opaque);
|
||||||
|
203
qemu-io-cmds.c
203
qemu-io-cmds.c
@ -574,49 +574,6 @@ static int do_aio_writev(BlockBackend *blk, QEMUIOVector *qiov,
|
|||||||
return async_ret < 0 ? async_ret : 1;
|
return async_ret < 0 ? async_ret : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct multiwrite_async_ret {
|
|
||||||
int num_done;
|
|
||||||
int error;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void multiwrite_cb(void *opaque, int ret)
|
|
||||||
{
|
|
||||||
struct multiwrite_async_ret *async_ret = opaque;
|
|
||||||
|
|
||||||
async_ret->num_done++;
|
|
||||||
if (ret < 0) {
|
|
||||||
async_ret->error = ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int do_aio_multiwrite(BlockBackend *blk, BlockRequest* reqs,
|
|
||||||
int num_reqs, int *total)
|
|
||||||
{
|
|
||||||
int i, ret;
|
|
||||||
struct multiwrite_async_ret async_ret = {
|
|
||||||
.num_done = 0,
|
|
||||||
.error = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
*total = 0;
|
|
||||||
for (i = 0; i < num_reqs; i++) {
|
|
||||||
reqs[i].cb = multiwrite_cb;
|
|
||||||
reqs[i].opaque = &async_ret;
|
|
||||||
*total += reqs[i].qiov->size;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = blk_aio_multiwrite(blk, reqs, num_reqs);
|
|
||||||
if (ret < 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (async_ret.num_done < num_reqs) {
|
|
||||||
main_loop_wait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return async_ret.error < 0 ? async_ret.error : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void read_help(void)
|
static void read_help(void)
|
||||||
{
|
{
|
||||||
printf(
|
printf(
|
||||||
@ -1211,165 +1168,6 @@ out:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void multiwrite_help(void)
|
|
||||||
{
|
|
||||||
printf(
|
|
||||||
"\n"
|
|
||||||
" writes a range of bytes from the given offset source from multiple buffers,\n"
|
|
||||||
" in a batch of requests that may be merged by qemu\n"
|
|
||||||
"\n"
|
|
||||||
" Example:\n"
|
|
||||||
" 'multiwrite 512 1k 1k ; 4k 1k'\n"
|
|
||||||
" writes 2 kB at 512 bytes and 1 kB at 4 kB into the open file\n"
|
|
||||||
"\n"
|
|
||||||
" Writes into a segment of the currently open file, using a buffer\n"
|
|
||||||
" filled with a set pattern (0xcdcdcdcd). The pattern byte is increased\n"
|
|
||||||
" by one for each request contained in the multiwrite command.\n"
|
|
||||||
" -P, -- use different pattern to fill file\n"
|
|
||||||
" -C, -- report statistics in a machine parsable format\n"
|
|
||||||
" -q, -- quiet mode, do not show I/O statistics\n"
|
|
||||||
"\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int multiwrite_f(BlockBackend *blk, int argc, char **argv);
|
|
||||||
|
|
||||||
static const cmdinfo_t multiwrite_cmd = {
|
|
||||||
.name = "multiwrite",
|
|
||||||
.cfunc = multiwrite_f,
|
|
||||||
.argmin = 2,
|
|
||||||
.argmax = -1,
|
|
||||||
.args = "[-Cq] [-P pattern ] off len [len..] [; off len [len..]..]",
|
|
||||||
.oneline = "issues multiple write requests at once",
|
|
||||||
.help = multiwrite_help,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int multiwrite_f(BlockBackend *blk, int argc, char **argv)
|
|
||||||
{
|
|
||||||
struct timeval t1, t2;
|
|
||||||
bool Cflag = false, qflag = false;
|
|
||||||
int c, cnt;
|
|
||||||
char **buf;
|
|
||||||
int64_t offset, first_offset = 0;
|
|
||||||
/* Some compilers get confused and warn if this is not initialized. */
|
|
||||||
int total = 0;
|
|
||||||
int nr_iov;
|
|
||||||
int nr_reqs;
|
|
||||||
int pattern = 0xcd;
|
|
||||||
QEMUIOVector *qiovs;
|
|
||||||
int i;
|
|
||||||
BlockRequest *reqs;
|
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "CqP:")) != -1) {
|
|
||||||
switch (c) {
|
|
||||||
case 'C':
|
|
||||||
Cflag = true;
|
|
||||||
break;
|
|
||||||
case 'q':
|
|
||||||
qflag = true;
|
|
||||||
break;
|
|
||||||
case 'P':
|
|
||||||
pattern = parse_pattern(optarg);
|
|
||||||
if (pattern < 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return qemuio_command_usage(&writev_cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (optind > argc - 2) {
|
|
||||||
return qemuio_command_usage(&writev_cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
nr_reqs = 1;
|
|
||||||
for (i = optind; i < argc; i++) {
|
|
||||||
if (!strcmp(argv[i], ";")) {
|
|
||||||
nr_reqs++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reqs = g_new0(BlockRequest, nr_reqs);
|
|
||||||
buf = g_new0(char *, nr_reqs);
|
|
||||||
qiovs = g_new(QEMUIOVector, nr_reqs);
|
|
||||||
|
|
||||||
for (i = 0; i < nr_reqs && optind < argc; i++) {
|
|
||||||
int j;
|
|
||||||
|
|
||||||
/* Read the offset of the request */
|
|
||||||
offset = cvtnum(argv[optind]);
|
|
||||||
if (offset < 0) {
|
|
||||||
print_cvtnum_err(offset, argv[optind]);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
optind++;
|
|
||||||
|
|
||||||
if (offset & 0x1ff) {
|
|
||||||
printf("offset %lld is not sector aligned\n",
|
|
||||||
(long long)offset);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == 0) {
|
|
||||||
first_offset = offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read lengths for qiov entries */
|
|
||||||
for (j = optind; j < argc; j++) {
|
|
||||||
if (!strcmp(argv[j], ";")) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nr_iov = j - optind;
|
|
||||||
|
|
||||||
/* Build request */
|
|
||||||
buf[i] = create_iovec(blk, &qiovs[i], &argv[optind], nr_iov, pattern);
|
|
||||||
if (buf[i] == NULL) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
reqs[i].qiov = &qiovs[i];
|
|
||||||
reqs[i].sector = offset >> 9;
|
|
||||||
reqs[i].nb_sectors = reqs[i].qiov->size >> 9;
|
|
||||||
|
|
||||||
optind = j + 1;
|
|
||||||
|
|
||||||
pattern++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If there were empty requests at the end, ignore them */
|
|
||||||
nr_reqs = i;
|
|
||||||
|
|
||||||
gettimeofday(&t1, NULL);
|
|
||||||
cnt = do_aio_multiwrite(blk, reqs, nr_reqs, &total);
|
|
||||||
gettimeofday(&t2, NULL);
|
|
||||||
|
|
||||||
if (cnt < 0) {
|
|
||||||
printf("aio_multiwrite failed: %s\n", strerror(-cnt));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (qflag) {
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Finally, report back -- -C gives a parsable format */
|
|
||||||
t2 = tsub(t2, t1);
|
|
||||||
print_report("wrote", &t2, first_offset, total, total, cnt, Cflag);
|
|
||||||
out:
|
|
||||||
for (i = 0; i < nr_reqs; i++) {
|
|
||||||
qemu_io_free(buf[i]);
|
|
||||||
if (reqs[i].qiov != NULL) {
|
|
||||||
qemu_iovec_destroy(&qiovs[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g_free(buf);
|
|
||||||
g_free(reqs);
|
|
||||||
g_free(qiovs);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct aio_ctx {
|
struct aio_ctx {
|
||||||
BlockBackend *blk;
|
BlockBackend *blk;
|
||||||
QEMUIOVector qiov;
|
QEMUIOVector qiov;
|
||||||
@ -2436,7 +2234,6 @@ static void __attribute((constructor)) init_qemuio_commands(void)
|
|||||||
qemuio_add_command(&readv_cmd);
|
qemuio_add_command(&readv_cmd);
|
||||||
qemuio_add_command(&write_cmd);
|
qemuio_add_command(&write_cmd);
|
||||||
qemuio_add_command(&writev_cmd);
|
qemuio_add_command(&writev_cmd);
|
||||||
qemuio_add_command(&multiwrite_cmd);
|
|
||||||
qemuio_add_command(&aio_read_cmd);
|
qemuio_add_command(&aio_read_cmd);
|
||||||
qemuio_add_command(&aio_write_cmd);
|
qemuio_add_command(&aio_write_cmd);
|
||||||
qemuio_add_command(&aio_flush_cmd);
|
qemuio_add_command(&aio_flush_cmd);
|
||||||
|
@ -1,152 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# Test simple read/write using plain bdrv_read/bdrv_write
|
|
||||||
#
|
|
||||||
# Copyright (C) 2014 Red Hat, Inc.
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
|
|
||||||
# creator
|
|
||||||
owner=stefanha@redhat.com
|
|
||||||
|
|
||||||
seq=`basename $0`
|
|
||||||
echo "QA output created by $seq"
|
|
||||||
|
|
||||||
here=`pwd`
|
|
||||||
status=1 # failure is the default!
|
|
||||||
|
|
||||||
_cleanup()
|
|
||||||
{
|
|
||||||
_cleanup_test_img
|
|
||||||
}
|
|
||||||
trap "_cleanup; exit \$status" 0 1 2 3 15
|
|
||||||
|
|
||||||
# get standard environment, filters and checks
|
|
||||||
. ./common.rc
|
|
||||||
. ./common.filter
|
|
||||||
|
|
||||||
_supported_fmt generic
|
|
||||||
_supported_proto generic
|
|
||||||
_supported_os Linux
|
|
||||||
|
|
||||||
|
|
||||||
size=128M
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "== Single request =="
|
|
||||||
_make_test_img $size
|
|
||||||
$QEMU_IO -c "write -z 0 8k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
$QEMU_IO -c "multiwrite 0 4k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "== verify pattern =="
|
|
||||||
$QEMU_IO -c "read -P 0xcd 0 4k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
$QEMU_IO -c "read -P 0 4k 4k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
|
|
||||||
_cleanup_test_img
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "== Sequential requests =="
|
|
||||||
_make_test_img $size
|
|
||||||
$QEMU_IO -c "write -z 0 12k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
$QEMU_IO -c "multiwrite 0 4k ; 4k 4k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "== verify pattern =="
|
|
||||||
$QEMU_IO -c "read -P 0xcd 0 4k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
$QEMU_IO -c "read -P 0xce 4k 4k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
$QEMU_IO -c "read -P 0 8k 4k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
|
|
||||||
_cleanup_test_img
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "== Superset overlapping requests =="
|
|
||||||
_make_test_img $size
|
|
||||||
$QEMU_IO -c "write -z 0 8k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
$QEMU_IO -c "multiwrite 0 4k ; 1k 2k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "== verify pattern =="
|
|
||||||
# Order of overlapping in-flight requests is not guaranteed so we cannot verify
|
|
||||||
# [1k, 3k) since it could have either pattern 0xcd or 0xce.
|
|
||||||
$QEMU_IO -c "read -P 0xcd 0 1k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
$QEMU_IO -c "read -P 0xcd 3k 1k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
$QEMU_IO -c "read -P 0 4k 4k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
|
|
||||||
_cleanup_test_img
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "== Subset overlapping requests =="
|
|
||||||
_make_test_img $size
|
|
||||||
$QEMU_IO -c "write -z 0 8k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
$QEMU_IO -c "multiwrite 1k 2k ; 0k 4k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "== verify pattern =="
|
|
||||||
# Order of overlapping in-flight requests is not guaranteed so we cannot verify
|
|
||||||
# [1k, 3k) since it could have either pattern 0xcd or 0xce.
|
|
||||||
$QEMU_IO -c "read -P 0xce 0 1k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
$QEMU_IO -c "read -P 0xce 3k 1k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
$QEMU_IO -c "read -P 0 4k 4k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
|
|
||||||
_cleanup_test_img
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "== Head overlapping requests =="
|
|
||||||
_make_test_img $size
|
|
||||||
$QEMU_IO -c "write -z 0 8k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
$QEMU_IO -c "multiwrite 0k 2k ; 0k 4k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "== verify pattern =="
|
|
||||||
# Order of overlapping in-flight requests is not guaranteed so we cannot verify
|
|
||||||
# [0k, 2k) since it could have either pattern 0xcd or 0xce.
|
|
||||||
$QEMU_IO -c "read -P 0xce 2k 2k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
$QEMU_IO -c "read -P 0 4k 4k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
|
|
||||||
_cleanup_test_img
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "== Tail overlapping requests =="
|
|
||||||
_make_test_img $size
|
|
||||||
$QEMU_IO -c "write -z 0 8k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
$QEMU_IO -c "multiwrite 2k 2k ; 0k 4k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "== verify pattern =="
|
|
||||||
# Order of overlapping in-flight requests is not guaranteed so we cannot verify
|
|
||||||
# [2k, 4k) since it could have either pattern 0xcd or 0xce.
|
|
||||||
$QEMU_IO -c "read -P 0xce 0k 2k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
$QEMU_IO -c "read -P 0 4k 4k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
|
|
||||||
_cleanup_test_img
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "== Disjoint requests =="
|
|
||||||
_make_test_img $size
|
|
||||||
$QEMU_IO -c "write -z 0 72k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
$QEMU_IO -c "multiwrite 0 4k ; 64k 4k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
|
|
||||||
echo
|
|
||||||
echo "== verify pattern =="
|
|
||||||
$QEMU_IO -c "read -P 0xcd 0 4k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
$QEMU_IO -c "read -P 0 4k 60k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
$QEMU_IO -c "read -P 0xce 64k 4k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
$QEMU_IO -c "read -P 0 68k 4k" "$TEST_IMG" | _filter_qemu_io
|
|
||||||
|
|
||||||
# success, all done
|
|
||||||
echo "*** done"
|
|
||||||
rm -f $seq.full
|
|
||||||
status=0
|
|
@ -1,103 +0,0 @@
|
|||||||
QA output created by 100
|
|
||||||
|
|
||||||
== Single request ==
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
|
||||||
wrote 8192/8192 bytes at offset 0
|
|
||||||
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
wrote 4096/4096 bytes at offset 0
|
|
||||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
|
|
||||||
== verify pattern ==
|
|
||||||
read 4096/4096 bytes at offset 0
|
|
||||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
read 4096/4096 bytes at offset 4096
|
|
||||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
|
|
||||||
== Sequential requests ==
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
|
||||||
wrote 12288/12288 bytes at offset 0
|
|
||||||
12 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
wrote 8192/8192 bytes at offset 0
|
|
||||||
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
|
|
||||||
== verify pattern ==
|
|
||||||
read 4096/4096 bytes at offset 0
|
|
||||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
read 4096/4096 bytes at offset 4096
|
|
||||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
read 4096/4096 bytes at offset 8192
|
|
||||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
|
|
||||||
== Superset overlapping requests ==
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
|
||||||
wrote 8192/8192 bytes at offset 0
|
|
||||||
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
wrote 6144/6144 bytes at offset 0
|
|
||||||
6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
|
|
||||||
== verify pattern ==
|
|
||||||
read 1024/1024 bytes at offset 0
|
|
||||||
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
read 1024/1024 bytes at offset 3072
|
|
||||||
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
read 4096/4096 bytes at offset 4096
|
|
||||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
|
|
||||||
== Subset overlapping requests ==
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
|
||||||
wrote 8192/8192 bytes at offset 0
|
|
||||||
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
wrote 6144/6144 bytes at offset 1024
|
|
||||||
6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
|
|
||||||
== verify pattern ==
|
|
||||||
read 1024/1024 bytes at offset 0
|
|
||||||
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
read 1024/1024 bytes at offset 3072
|
|
||||||
1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
read 4096/4096 bytes at offset 4096
|
|
||||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
|
|
||||||
== Head overlapping requests ==
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
|
||||||
wrote 8192/8192 bytes at offset 0
|
|
||||||
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
wrote 6144/6144 bytes at offset 0
|
|
||||||
6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
|
|
||||||
== verify pattern ==
|
|
||||||
read 2048/2048 bytes at offset 2048
|
|
||||||
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
read 4096/4096 bytes at offset 4096
|
|
||||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
|
|
||||||
== Tail overlapping requests ==
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
|
||||||
wrote 8192/8192 bytes at offset 0
|
|
||||||
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
wrote 6144/6144 bytes at offset 2048
|
|
||||||
6 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
|
|
||||||
== verify pattern ==
|
|
||||||
read 2048/2048 bytes at offset 0
|
|
||||||
2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
read 4096/4096 bytes at offset 4096
|
|
||||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
|
|
||||||
== Disjoint requests ==
|
|
||||||
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
|
|
||||||
wrote 73728/73728 bytes at offset 0
|
|
||||||
72 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
wrote 8192/8192 bytes at offset 0
|
|
||||||
8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
|
|
||||||
== verify pattern ==
|
|
||||||
read 4096/4096 bytes at offset 0
|
|
||||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
read 61440/61440 bytes at offset 4096
|
|
||||||
60 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
read 4096/4096 bytes at offset 65536
|
|
||||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
read 4096/4096 bytes at offset 69632
|
|
||||||
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
|
|
||||||
*** done
|
|
@ -248,14 +248,6 @@ sector = "%d"
|
|||||||
if failed_wr_ops > 0:
|
if failed_wr_ops > 0:
|
||||||
highest_offset = max(highest_offset, bad_offset + 512)
|
highest_offset = max(highest_offset, bad_offset + 512)
|
||||||
|
|
||||||
for i in range(wr_merged):
|
|
||||||
first = i * wr_size * 2
|
|
||||||
second = first + wr_size
|
|
||||||
ops.append("multiwrite %d %d ; %d %d" %
|
|
||||||
(first, wr_size, second, wr_size))
|
|
||||||
|
|
||||||
highest_offset = max(highest_offset, wr_merged * wr_size * 2)
|
|
||||||
|
|
||||||
# Now perform all operations
|
# Now perform all operations
|
||||||
for op in ops:
|
for op in ops:
|
||||||
self.vm.hmp_qemu_io("drive0", op)
|
self.vm.hmp_qemu_io("drive0", op)
|
||||||
@ -309,19 +301,15 @@ sector = "%d"
|
|||||||
def test_flush(self):
|
def test_flush(self):
|
||||||
self.do_test_stats(flush_ops = 8)
|
self.do_test_stats(flush_ops = 8)
|
||||||
|
|
||||||
def test_merged(self):
|
|
||||||
for i in range(5):
|
|
||||||
self.do_test_stats(wr_merged = i * 3)
|
|
||||||
|
|
||||||
def test_all(self):
|
def test_all(self):
|
||||||
# rd_size, rd_ops, wr_size, wr_ops, flush_ops
|
# rd_size, rd_ops, wr_size, wr_ops, flush_ops
|
||||||
# invalid_rd_ops, invalid_wr_ops,
|
# invalid_rd_ops, invalid_wr_ops,
|
||||||
# failed_rd_ops, failed_wr_ops
|
# failed_rd_ops, failed_wr_ops
|
||||||
# wr_merged
|
# wr_merged
|
||||||
test_values = [[512, 1, 512, 1, 1, 4, 7, 5, 2, 1],
|
test_values = [[512, 1, 512, 1, 1, 4, 7, 5, 2, 0],
|
||||||
[65536, 1, 2048, 12, 7, 7, 5, 2, 5, 5],
|
[65536, 1, 2048, 12, 7, 7, 5, 2, 5, 0],
|
||||||
[32768, 9, 8192, 1, 4, 3, 2, 4, 6, 4],
|
[32768, 9, 8192, 1, 4, 3, 2, 4, 6, 0],
|
||||||
[16384, 11, 3584, 16, 9, 8, 6, 7, 3, 4]]
|
[16384, 11, 3584, 16, 9, 8, 6, 7, 3, 0]]
|
||||||
for i in test_values:
|
for i in test_values:
|
||||||
self.do_test_stats(*i)
|
self.do_test_stats(*i)
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
........................................
|
...................................
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
Ran 40 tests
|
Ran 35 tests
|
||||||
|
|
||||||
OK
|
OK
|
||||||
|
@ -106,7 +106,7 @@
|
|||||||
097 rw auto backing
|
097 rw auto backing
|
||||||
098 rw auto backing quick
|
098 rw auto backing quick
|
||||||
099 rw auto quick
|
099 rw auto quick
|
||||||
100 rw auto quick
|
# 100 was removed, do not reuse
|
||||||
101 rw auto quick
|
101 rw auto quick
|
||||||
102 rw auto quick
|
102 rw auto quick
|
||||||
103 rw auto quick
|
103 rw auto quick
|
||||||
|
@ -62,8 +62,6 @@ bdrv_open_common(void *bs, const char *filename, int flags, const char *format_n
|
|||||||
bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d"
|
bdrv_lock_medium(void *bs, bool locked) "bs %p locked %d"
|
||||||
|
|
||||||
# block/io.c
|
# block/io.c
|
||||||
multiwrite_cb(void *mcb, int ret) "mcb %p ret %d"
|
|
||||||
bdrv_aio_multiwrite(void *mcb, int num_callbacks, int num_reqs) "mcb %p num_callbacks %d num_reqs %d"
|
|
||||||
bdrv_aio_discard(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
|
bdrv_aio_discard(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
|
||||||
bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p"
|
bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p"
|
||||||
bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
|
bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
|
||||||
|
Loading…
Reference in New Issue
Block a user