hmp: Request permissions in qemu-io

The HMP command 'qemu-io' is a bit tricky because it wants to work on
the original BlockBackend, but additional permissions could be required.
The details are explained in a comment in the code, but in summary, just
request whatever permissions the current qemu-io command needs.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>
Acked-by: Fam Zheng <famz@redhat.com>
This commit is contained in:
Kevin Wolf 2017-02-10 16:24:56 +01:00
parent 0db832f42e
commit 887354bd13
5 changed files with 61 additions and 1 deletions

View File

@ -584,6 +584,12 @@ int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
return 0;
}
void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm)
{
*perm = blk->perm;
*shared_perm = blk->shared_perm;
}
static int blk_do_attach_dev(BlockBackend *blk, void *dev)
{
if (blk->dev) {

26
hmp.c
View File

@ -2051,7 +2051,6 @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
if (!blk) {
BlockDriverState *bs = bdrv_lookup_bs(NULL, device, &err);
if (bs) {
/* FIXME Use real permissions */
blk = local_blk = blk_new(0, BLK_PERM_ALL);
ret = blk_insert_bs(blk, bs, &err);
if (ret < 0) {
@ -2065,6 +2064,31 @@ void hmp_qemu_io(Monitor *mon, const QDict *qdict)
aio_context = blk_get_aio_context(blk);
aio_context_acquire(aio_context);
/*
* Notably absent: Proper permission management. This is sad, but it seems
* almost impossible to achieve without changing the semantics and thereby
* limiting the use cases of the qemu-io HMP command.
*
* In an ideal world we would unconditionally create a new BlockBackend for
* qemuio_command(), but we have commands like 'reopen' and want them to
* take effect on the exact BlockBackend whose name the user passed instead
* of just on a temporary copy of it.
*
* Another problem is that deleting the temporary BlockBackend involves
* draining all requests on it first, but some qemu-iotests cases want to
* issue multiple aio_read/write requests and expect them to complete in
* the background while the monitor has already returned.
*
* This is also what prevents us from saving the original permissions and
* restoring them later: We can't revoke permissions until all requests
* have completed, and we don't know when that is nor can we really let
* anything else run before we have revoken them to avoid race conditions.
*
* What happens now is that command() in qemu-io-cmds.c can extend the
* permissions if necessary for the qemu-io command. And they simply stay
* extended, possibly resulting in a read-only guest device keeping write
* permissions. Ugly, but it appears to be the lesser evil.
*/
qemuio_command(blk, command);
aio_context_release(aio_context);

View File

@ -36,6 +36,7 @@ typedef struct cmdinfo {
const char *args;
const char *oneline;
helpfunc_t help;
uint64_t perm;
} cmdinfo_t;
extern bool qemuio_misalign;

View File

@ -107,6 +107,7 @@ bool bdrv_has_blk(BlockDriverState *bs);
bool bdrv_is_root_node(BlockDriverState *bs);
int blk_set_perm(BlockBackend *blk, uint64_t perm, uint64_t shared_perm,
Error **errp);
void blk_get_perm(BlockBackend *blk, uint64_t *perm, uint64_t *shared_perm);
void blk_set_allow_write_beyond_eof(BlockBackend *blk, bool allow);
void blk_iostatus_enable(BlockBackend *blk);

View File

@ -83,6 +83,29 @@ static int command(BlockBackend *blk, const cmdinfo_t *ct, int argc,
}
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);
}
@ -918,6 +941,7 @@ static const cmdinfo_t write_cmd = {
.name = "write",
.altname = "w",
.cfunc = write_f,
.perm = BLK_PERM_WRITE,
.argmin = 2,
.argmax = -1,
.args = "[-bcCfquz] [-P pattern] off len",
@ -1093,6 +1117,7 @@ static int writev_f(BlockBackend *blk, int argc, char **argv);
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..]",
@ -1392,6 +1417,7 @@ static int aio_write_f(BlockBackend *blk, int argc, char **argv);
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..]",
@ -1556,6 +1582,7 @@ static const cmdinfo_t truncate_cmd = {
.name = "truncate",
.altname = "t",
.cfunc = truncate_f,
.perm = BLK_PERM_WRITE | BLK_PERM_RESIZE,
.argmin = 1,
.argmax = 1,
.args = "off",
@ -1653,6 +1680,7 @@ static const cmdinfo_t discard_cmd = {
.name = "discard",
.altname = "d",
.cfunc = discard_f,
.perm = BLK_PERM_WRITE,
.argmin = 2,
.argmax = -1,
.args = "[-Cq] off len",