#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "qemu/timer.h"
-#include "sysemu/block-backend.h"
#include "qemu/cutils.h"
#define CMD_NOFILE_OK 0x01
}
return 0;
}
+
+ /* Request additional permissions if necessary for this command. The caller
+ * is responsible for restoring the original permissions afterwards if this
+ * is what it wants. */
+ if (ct->perm && blk_is_available(blk)) {
+ uint64_t orig_perm, orig_shared_perm;
+ blk_get_perm(blk, &orig_perm, &orig_shared_perm);
+
+ if (ct->perm & ~orig_perm) {
+ uint64_t new_perm;
+ Error *local_err = NULL;
+ int ret;
+
+ new_perm = orig_perm | ct->perm;
+
+ ret = blk_set_perm(blk, new_perm, orig_shared_perm, &local_err);
+ if (ret < 0) {
+ error_report_err(local_err);
+ return 0;
+ }
+ }
+ }
+
optind = 0;
return ct->cfunc(blk, argc, argv);
}
static int64_t cvtnum(const char *s)
{
- char *end;
- int64_t ret;
+ int err;
+ uint64_t value;
- ret = qemu_strtosz_suffix(s, &end, QEMU_STRTOSZ_DEFSUFFIX_B);
- if (*end != '\0') {
- /* Detritus at the end of the string */
- return -EINVAL;
+ err = qemu_strtosz(s, NULL, &value);
+ if (err < 0) {
+ return err;
+ }
+ if (value > INT64_MAX) {
+ return -ERANGE;
}
- return ret;
+ return value;
}
static void print_cvtnum_err(int64_t rc, const char *arg)
goto fail;
}
- /* should be SIZE_T_MAX, but that doesn't exist */
- if (len > INT_MAX) {
- printf("Argument '%s' exceeds maximum size %d\n", arg, INT_MAX);
+ if (len > BDRV_REQUEST_MAX_BYTES) {
+ printf("Argument '%s' exceeds maximum size %" PRIu64 "\n", arg,
+ (uint64_t)BDRV_REQUEST_MAX_BYTES);
+ goto fail;
+ }
+
+ if (count > BDRV_REQUEST_MAX_BYTES - len) {
+ printf("The total number of bytes exceed the maximum size %" PRIu64
+ "\n", (uint64_t)BDRV_REQUEST_MAX_BYTES);
goto fail;
}
bool done;
} CoWriteZeroes;
-static void coroutine_fn co_write_zeroes_entry(void *opaque)
+static void coroutine_fn co_pwrite_zeroes_entry(void *opaque)
{
CoWriteZeroes *data = opaque;
- data->ret = blk_co_write_zeroes(data->blk, data->offset, data->count,
- data->flags);
+ data->ret = blk_co_pwrite_zeroes(data->blk, data->offset, data->count,
+ data->flags);
data->done = true;
if (data->ret < 0) {
*data->total = data->ret;
*data->total = data->count;
}
-static int do_co_write_zeroes(BlockBackend *blk, int64_t offset, int64_t count,
- int flags, int64_t *total)
+static int do_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
+ int64_t count, int flags, int64_t *total)
{
Coroutine *co;
CoWriteZeroes data = {
.done = false,
};
- if (count >> BDRV_SECTOR_BITS > INT_MAX) {
+ if (count > INT_MAX) {
return -ERANGE;
}
- co = qemu_coroutine_create(co_write_zeroes_entry);
- qemu_coroutine_enter(co, &data);
+ co = qemu_coroutine_create(co_pwrite_zeroes_entry, &data);
+ qemu_coroutine_enter(co);
while (!data.done) {
aio_poll(blk_get_aio_context(blk), true);
}
{
int ret;
- if (count >> 9 > INT_MAX) {
+ if (count >> 9 > BDRV_REQUEST_MAX_SECTORS) {
return -ERANGE;
}
- ret = blk_write_compressed(blk, offset >> 9, (uint8_t *)buf, count >> 9);
+ ret = blk_pwrite_compressed(blk, offset, buf, count);
if (ret < 0) {
return ret;
}
if (count < 0) {
print_cvtnum_err(count, argv[optind]);
return 0;
- } else if (count > SIZE_MAX) {
+ } else if (count > BDRV_REQUEST_MAX_BYTES) {
printf("length cannot exceed %" PRIu64 ", given %s\n",
- (uint64_t) SIZE_MAX, argv[optind]);
+ (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]);
return 0;
}
" -C, -- report statistics in a machine parsable format\n"
" -q, -- quiet mode, do not show I/O statistics\n"
" -u, -- with -z, allow unmapping\n"
-" -z, -- write zeroes using blk_co_write_zeroes\n"
+" -z, -- write zeroes using blk_co_pwrite_zeroes\n"
"\n");
}
.name = "write",
.altname = "w",
.cfunc = write_f,
+ .perm = BLK_PERM_WRITE,
.argmin = 2,
.argmax = -1,
.args = "[-bcCfquz] [-P pattern] off len",
if (count < 0) {
print_cvtnum_err(count, argv[optind]);
return 0;
- } else if (count > SIZE_MAX) {
+ } else if (count > BDRV_REQUEST_MAX_BYTES) {
printf("length cannot exceed %" PRIu64 ", given %s\n",
- (uint64_t) SIZE_MAX, argv[optind]);
+ (uint64_t)BDRV_REQUEST_MAX_BYTES, argv[optind]);
return 0;
}
if (bflag) {
cnt = do_save_vmstate(blk, buf, offset, count, &total);
} else if (zflag) {
- cnt = do_co_write_zeroes(blk, offset, count, flags, &total);
+ cnt = do_co_pwrite_zeroes(blk, offset, count, flags, &total);
} else if (cflag) {
cnt = do_write_compressed(blk, buf, offset, count, &total);
} else {
static const cmdinfo_t writev_cmd = {
.name = "writev",
.cfunc = writev_f,
+ .perm = BLK_PERM_WRITE,
.argmin = 2,
.argmax = -1,
.args = "[-Cfq] [-P pattern] off len [len..]",
" -i, -- treat request as invalid, for exercising stats\n"
" -q, -- quiet mode, do not show I/O statistics\n"
" -u, -- with -z, allow unmapping\n"
-" -z, -- write zeroes using blk_aio_write_zeroes\n"
+" -z, -- write zeroes using blk_aio_pwrite_zeroes\n"
"\n");
}
static const cmdinfo_t aio_write_cmd = {
.name = "aio_write",
.cfunc = aio_write_f,
+ .perm = BLK_PERM_WRITE,
.argmin = 2,
.argmax = -1,
.args = "[-Cfiquz] [-P pattern] off len [len..]",
}
ctx->qiov.size = count;
- blk_aio_write_zeroes(blk, ctx->offset, count, flags, aio_write_done,
- ctx);
+ blk_aio_pwrite_zeroes(blk, ctx->offset, count, flags, aio_write_done,
+ ctx);
} else {
nr_iov = argc - optind;
ctx->buf = create_iovec(blk, &ctx->qiov, &argv[optind], nr_iov,
.name = "truncate",
.altname = "t",
.cfunc = truncate_f,
+ .perm = BLK_PERM_WRITE | BLK_PERM_RESIZE,
.argmin = 1,
.argmax = 1,
.args = "off",
.name = "discard",
.altname = "d",
.cfunc = discard_f,
+ .perm = BLK_PERM_WRITE,
.argmin = 2,
.argmax = -1,
.args = "[-Cq] off len",
if (count < 0) {
print_cvtnum_err(count, argv[optind]);
return 0;
- } else if (count >> BDRV_SECTOR_BITS > INT_MAX) {
+ } else if (count >> BDRV_SECTOR_BITS > BDRV_REQUEST_MAX_SECTORS) {
printf("length cannot exceed %"PRIu64", given %s\n",
- (uint64_t)INT_MAX << BDRV_SECTOR_BITS,
+ (uint64_t)BDRV_REQUEST_MAX_SECTORS << BDRV_SECTOR_BITS,
argv[optind]);
return 0;
}
gettimeofday(&t1, NULL);
- ret = blk_discard(blk, offset >> BDRV_SECTOR_BITS,
- count >> BDRV_SECTOR_BITS);
+ ret = blk_pdiscard(blk, offset, count);
gettimeofday(&t2, NULL);
if (ret < 0) {
qemu_opts_reset(&reopen_opts);
brq = bdrv_reopen_queue(NULL, bs, opts, flags);
- bdrv_reopen_multiple(brq, &local_err);
+ bdrv_reopen_multiple(bdrv_get_aio_context(bs), brq, &local_err);
if (local_err) {
error_report_err(local_err);
} else {
bool qemuio_command(BlockBackend *blk, const char *cmd)
{
+ AioContext *ctx;
char *input;
const cmdinfo_t *ct;
char **v;
if (c) {
ct = find_command(v[0]);
if (ct) {
+ ctx = blk ? blk_get_aio_context(blk) : qemu_get_aio_context();
+ aio_context_acquire(ctx);
done = command(blk, ct, c, v);
+ aio_context_release(ctx);
} else {
fprintf(stderr, "command \"%s\" not found\n", v[0]);
}