Blame SOURCES/kvm-file-posix-Prepare-permission-code-for-fd-switching.patch

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