|
|
7711c0 |
From a1cc5d5a181559a6f68c459cbae8488303112660 Mon Sep 17 00:00:00 2001
|
|
|
7711c0 |
From: Kevin Wolf <kwolf@redhat.com>
|
|
|
7711c0 |
Date: Fri, 15 Mar 2019 18:10:09 +0100
|
|
|
7711c0 |
Subject: [PATCH 013/163] file-posix: Prepare permission code for fd switching
|
|
|
7711c0 |
|
|
|
7711c0 |
RH-Author: Kevin Wolf <kwolf@redhat.com>
|
|
|
7711c0 |
Message-id: <20190315181010.14964-14-kwolf@redhat.com>
|
|
|
7711c0 |
Patchwork-id: 84890
|
|
|
7711c0 |
O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 13/14] file-posix: Prepare permission code for fd switching
|
|
|
7711c0 |
Bugzilla: 1685989
|
|
|
7711c0 |
RH-Acked-by: John Snow <jsnow@redhat.com>
|
|
|
7711c0 |
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
|
|
|
7711c0 |
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
7711c0 |
|
|
|
7711c0 |
In order to be able to dynamically reopen the file read-only or
|
|
|
7711c0 |
read-write, depending on the users that are attached, we need to be able
|
|
|
7711c0 |
to switch to a different file descriptor during the permission change.
|
|
|
7711c0 |
|
|
|
7711c0 |
This interacts with reopen, which also creates a new file descriptor and
|
|
|
7711c0 |
performs permission changes internally. In this case, the permission
|
|
|
7711c0 |
change code must reuse the reopen file descriptor instead of creating a
|
|
|
7711c0 |
third one.
|
|
|
7711c0 |
|
|
|
7711c0 |
In turn, reopen can drop its code to copy file locks to the new file
|
|
|
7711c0 |
descriptor because that is now done when applying the new permissions.
|
|
|
7711c0 |
|
|
|
7711c0 |
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
|
|
7711c0 |
(cherry picked from commit 6ceabe6f77e4ae5ac2fa3d2ac1be11dc95021941)
|
|
|
7711c0 |
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
|
|
|
7711c0 |
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
|
|
|
7711c0 |
---
|
|
|
7711c0 |
block/file-posix.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++-------
|
|
|
7711c0 |
1 file changed, 85 insertions(+), 11 deletions(-)
|
|
|
7711c0 |
|
|
|
7711c0 |
diff --git a/block/file-posix.c b/block/file-posix.c
|
|
|
7711c0 |
index ae16f2f..f0f8eaf 100644
|
|
|
7711c0 |
--- a/block/file-posix.c
|
|
|
7711c0 |
+++ b/block/file-posix.c
|
|
|
7711c0 |
@@ -156,6 +156,7 @@ typedef struct BDRVRawState {
|
|
|
7711c0 |
uint64_t locked_perm;
|
|
|
7711c0 |
uint64_t locked_shared_perm;
|
|
|
7711c0 |
|
|
|
7711c0 |
+ int perm_change_fd;
|
|
|
7711c0 |
BDRVReopenState *reopen_state;
|
|
|
7711c0 |
|
|
|
7711c0 |
#ifdef CONFIG_XFS
|
|
|
7711c0 |
@@ -837,7 +838,8 @@ static int raw_handle_perm_lock(BlockDriverState *bs,
|
|
|
7711c0 |
}
|
|
|
7711c0 |
|
|
|
7711c0 |
static int raw_reconfigure_getfd(BlockDriverState *bs, int flags,
|
|
|
7711c0 |
- int *open_flags, Error **errp)
|
|
|
7711c0 |
+ int *open_flags, bool force_dup,
|
|
|
7711c0 |
+ Error **errp)
|
|
|
7711c0 |
{
|
|
|
7711c0 |
BDRVRawState *s = bs->opaque;
|
|
|
7711c0 |
int fd = -1;
|
|
|
7711c0 |
@@ -863,6 +865,11 @@ static int raw_reconfigure_getfd(BlockDriverState *bs, int flags,
|
|
|
7711c0 |
assert((s->open_flags & O_ASYNC) == 0);
|
|
|
7711c0 |
#endif
|
|
|
7711c0 |
|
|
|
7711c0 |
+ if (!force_dup && *open_flags == s->open_flags) {
|
|
|
7711c0 |
+ /* We're lucky, the existing fd is fine */
|
|
|
7711c0 |
+ return s->fd;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+
|
|
|
7711c0 |
if ((*open_flags & ~fcntl_flags) == (s->open_flags & ~fcntl_flags)) {
|
|
|
7711c0 |
/* dup the original fd */
|
|
|
7711c0 |
fd = qemu_dup(s->fd);
|
|
|
7711c0 |
@@ -909,7 +916,7 @@ static int raw_reopen_prepare(BDRVReopenState *state,
|
|
|
7711c0 |
rs = state->opaque;
|
|
|
7711c0 |
|
|
|
7711c0 |
rs->fd = raw_reconfigure_getfd(state->bs, state->flags, &rs->open_flags,
|
|
|
7711c0 |
- &local_err);
|
|
|
7711c0 |
+ true, &local_err);
|
|
|
7711c0 |
if (local_err) {
|
|
|
7711c0 |
error_propagate(errp, local_err);
|
|
|
7711c0 |
ret = -1;
|
|
|
7711c0 |
@@ -925,14 +932,6 @@ static int raw_reopen_prepare(BDRVReopenState *state,
|
|
|
7711c0 |
ret = -EINVAL;
|
|
|
7711c0 |
goto out_fd;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
-
|
|
|
7711c0 |
- /* Copy locks to the new fd */
|
|
|
7711c0 |
- ret = raw_apply_lock_bytes(NULL, rs->fd, s->locked_perm,
|
|
|
7711c0 |
- s->locked_shared_perm, false, errp);
|
|
|
7711c0 |
- if (ret < 0) {
|
|
|
7711c0 |
- ret = -EINVAL;
|
|
|
7711c0 |
- goto out_fd;
|
|
|
7711c0 |
- }
|
|
|
7711c0 |
}
|
|
|
7711c0 |
|
|
|
7711c0 |
s->reopen_state = state;
|
|
|
7711c0 |
@@ -2524,12 +2523,78 @@ static QemuOptsList raw_create_opts = {
|
|
|
7711c0 |
static int raw_check_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared,
|
|
|
7711c0 |
Error **errp)
|
|
|
7711c0 |
{
|
|
|
7711c0 |
- return raw_handle_perm_lock(bs, RAW_PL_PREPARE, perm, shared, errp);
|
|
|
7711c0 |
+ BDRVRawState *s = bs->opaque;
|
|
|
7711c0 |
+ BDRVRawReopenState *rs = NULL;
|
|
|
7711c0 |
+ int open_flags;
|
|
|
7711c0 |
+ int ret;
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ if (s->perm_change_fd) {
|
|
|
7711c0 |
+ /*
|
|
|
7711c0 |
+ * In the context of reopen, this function may be called several times
|
|
|
7711c0 |
+ * (directly and recursively while change permissions of the parent).
|
|
|
7711c0 |
+ * This is even true for children that don't inherit from the original
|
|
|
7711c0 |
+ * reopen node, so s->reopen_state is not set.
|
|
|
7711c0 |
+ *
|
|
|
7711c0 |
+ * Ignore all but the first call.
|
|
|
7711c0 |
+ */
|
|
|
7711c0 |
+ return 0;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ if (s->reopen_state) {
|
|
|
7711c0 |
+ /* We already have a new file descriptor to set permissions for */
|
|
|
7711c0 |
+ assert(s->reopen_state->perm == perm);
|
|
|
7711c0 |
+ assert(s->reopen_state->shared_perm == shared);
|
|
|
7711c0 |
+ rs = s->reopen_state->opaque;
|
|
|
7711c0 |
+ s->perm_change_fd = rs->fd;
|
|
|
7711c0 |
+ } else {
|
|
|
7711c0 |
+ /* We may need a new fd if auto-read-only switches the mode */
|
|
|
7711c0 |
+ ret = raw_reconfigure_getfd(bs, bs->open_flags, &open_flags,
|
|
|
7711c0 |
+ false, errp);
|
|
|
7711c0 |
+ if (ret < 0) {
|
|
|
7711c0 |
+ return ret;
|
|
|
7711c0 |
+ } else if (ret != s->fd) {
|
|
|
7711c0 |
+ s->perm_change_fd = ret;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ /* Prepare permissions on old fd to avoid conflicts between old and new,
|
|
|
7711c0 |
+ * but keep everything locked that new will need. */
|
|
|
7711c0 |
+ ret = raw_handle_perm_lock(bs, RAW_PL_PREPARE, perm, shared, errp);
|
|
|
7711c0 |
+ if (ret < 0) {
|
|
|
7711c0 |
+ goto fail;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ /* Copy locks to the new fd */
|
|
|
7711c0 |
+ if (s->perm_change_fd) {
|
|
|
7711c0 |
+ ret = raw_apply_lock_bytes(NULL, s->perm_change_fd, perm, ~shared,
|
|
|
7711c0 |
+ false, errp);
|
|
|
7711c0 |
+ if (ret < 0) {
|
|
|
7711c0 |
+ raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL);
|
|
|
7711c0 |
+ goto fail;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+ return 0;
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+fail:
|
|
|
7711c0 |
+ if (s->perm_change_fd && !s->reopen_state) {
|
|
|
7711c0 |
+ qemu_close(s->perm_change_fd);
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+ s->perm_change_fd = 0;
|
|
|
7711c0 |
+ return ret;
|
|
|
7711c0 |
}
|
|
|
7711c0 |
|
|
|
7711c0 |
static void raw_set_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared)
|
|
|
7711c0 |
{
|
|
|
7711c0 |
BDRVRawState *s = bs->opaque;
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ /* For reopen, we have already switched to the new fd (.bdrv_set_perm is
|
|
|
7711c0 |
+ * called after .bdrv_reopen_commit) */
|
|
|
7711c0 |
+ if (s->perm_change_fd && s->fd != s->perm_change_fd) {
|
|
|
7711c0 |
+ qemu_close(s->fd);
|
|
|
7711c0 |
+ s->fd = s->perm_change_fd;
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+ s->perm_change_fd = 0;
|
|
|
7711c0 |
+
|
|
|
7711c0 |
raw_handle_perm_lock(bs, RAW_PL_COMMIT, perm, shared, NULL);
|
|
|
7711c0 |
s->perm = perm;
|
|
|
7711c0 |
s->shared_perm = shared;
|
|
|
7711c0 |
@@ -2537,6 +2602,15 @@ static void raw_set_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared)
|
|
|
7711c0 |
|
|
|
7711c0 |
static void raw_abort_perm_update(BlockDriverState *bs)
|
|
|
7711c0 |
{
|
|
|
7711c0 |
+ BDRVRawState *s = bs->opaque;
|
|
|
7711c0 |
+
|
|
|
7711c0 |
+ /* For reopen, .bdrv_reopen_abort is called afterwards and will close
|
|
|
7711c0 |
+ * the file descriptor. */
|
|
|
7711c0 |
+ if (s->perm_change_fd && !s->reopen_state) {
|
|
|
7711c0 |
+ qemu_close(s->perm_change_fd);
|
|
|
7711c0 |
+ }
|
|
|
7711c0 |
+ s->perm_change_fd = 0;
|
|
|
7711c0 |
+
|
|
|
7711c0 |
raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL);
|
|
|
7711c0 |
}
|
|
|
7711c0 |
|
|
|
7711c0 |
--
|
|
|
7711c0 |
1.8.3.1
|
|
|
7711c0 |
|