Skip to content

Commit

Permalink
block: Base permissions on rw state after reopen
Browse files Browse the repository at this point in the history
When new permissions are calculated during bdrv_reopen(), they need to
be based on the state of the graph as it will be after the reopen has
completed, not on the current state of the involved nodes.

This patch makes bdrv_is_writable() optionally accept a BlockReopenQueue
from which the new flags are taken. This is then used for determining
the new bs->file permissions of format drivers as soon as we add the
code to actually pass a non-NULL reopen queue to the .bdrv_child_perm
callbacks.

While moving bdrv_is_writable(), make it static. It isn't used outside
block.c.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
  • Loading branch information
kevmw committed Sep 26, 2017
1 parent 3121fb4 commit 148eb13
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 16 deletions.
52 changes: 37 additions & 15 deletions block.c
Expand Up @@ -239,12 +239,6 @@ bool bdrv_is_read_only(BlockDriverState *bs)
return bs->read_only;
}

/* Returns whether the image file can be written to right now */
bool bdrv_is_writable(BlockDriverState *bs)
{
return !bdrv_is_read_only(bs) && !(bs->open_flags & BDRV_O_INACTIVE);
}

int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
bool ignore_allow_rdw, Error **errp)
{
Expand Down Expand Up @@ -1537,6 +1531,41 @@ static int bdrv_child_check_perm(BdrvChild *c, BlockReopenQueue *q,
static void bdrv_child_abort_perm_update(BdrvChild *c);
static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared);

typedef struct BlockReopenQueueEntry {
bool prepared;
BDRVReopenState state;
QSIMPLEQ_ENTRY(BlockReopenQueueEntry) entry;
} BlockReopenQueueEntry;

/*
* Return the flags that @bs will have after the reopens in @q have
* successfully completed. If @q is NULL (or @bs is not contained in @q),
* return the current flags.
*/
static int bdrv_reopen_get_flags(BlockReopenQueue *q, BlockDriverState *bs)
{
BlockReopenQueueEntry *entry;

if (q != NULL) {
QSIMPLEQ_FOREACH(entry, q, entry) {
if (entry->state.bs == bs) {
return entry->state.flags;
}
}
}

return bs->open_flags;
}

/* Returns whether the image file can be written to after the reopen queue @q
* has been successfully applied, or right now if @q is NULL. */
static bool bdrv_is_writable(BlockDriverState *bs, BlockReopenQueue *q)
{
int flags = bdrv_reopen_get_flags(q, bs);

return (flags & (BDRV_O_RDWR | BDRV_O_INACTIVE)) == BDRV_O_RDWR;
}

static void bdrv_child_perm(BlockDriverState *bs, BlockDriverState *child_bs,
BdrvChild *c, const BdrvChildRole *role,
BlockReopenQueue *reopen_queue,
Expand Down Expand Up @@ -1574,7 +1603,7 @@ static int bdrv_check_perm(BlockDriverState *bs, BlockReopenQueue *q,

/* Write permissions never work with read-only images */
if ((cumulative_perms & (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED)) &&
!bdrv_is_writable(bs))
!bdrv_is_writable(bs, q))
{
error_setg(errp, "Block node is read-only");
return -EPERM;
Expand Down Expand Up @@ -1864,8 +1893,7 @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
&perm, &shared);

/* Format drivers may touch metadata even if the guest doesn't write */
/* TODO Take flags from reopen_queue */
if (bdrv_is_writable(bs)) {
if (bdrv_is_writable(bs, reopen_queue)) {
perm |= BLK_PERM_WRITE | BLK_PERM_RESIZE;
}

Expand Down Expand Up @@ -2642,12 +2670,6 @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
NULL, errp);
}

typedef struct BlockReopenQueueEntry {
bool prepared;
BDRVReopenState state;
QSIMPLEQ_ENTRY(BlockReopenQueueEntry) entry;
} BlockReopenQueueEntry;

/*
* Adds a BlockDriverState to a simple queue for an atomic, transactional
* reopen of multiple devices.
Expand Down
1 change: 0 additions & 1 deletion include/block/block.h
Expand Up @@ -435,7 +435,6 @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
int64_t offset, int64_t bytes, int64_t *pnum);

bool bdrv_is_read_only(BlockDriverState *bs);
bool bdrv_is_writable(BlockDriverState *bs);
int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
bool ignore_allow_rdw, Error **errp);
int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp);
Expand Down

0 comments on commit 148eb13

Please sign in to comment.