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

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