Blame SOURCES/kvm-file-posix-Skip-effectiveless-OFD-lock-operations.patch

7711c0
From 63ef1f91221aabc910fea57486ecc54b1958c7a8 Mon Sep 17 00:00:00 2001
7711c0
From: Max Reitz <mreitz@redhat.com>
7711c0
Date: Mon, 4 Feb 2019 20:42:03 +0100
7711c0
Subject: [PATCH 03/33] file-posix: Skip effectiveless OFD lock operations
7711c0
7711c0
RH-Author: Max Reitz <mreitz@redhat.com>
7711c0
Message-id: <20190204204207.18079-4-mreitz@redhat.com>
7711c0
Patchwork-id: 84220
7711c0
O-Subject: [RHEL-7.7 qemu-kvm-rhev PATCH 3/7] file-posix: Skip effectiveless OFD lock operations
7711c0
Bugzilla: 1551486
7711c0
RH-Acked-by: John Snow <jsnow@redhat.com>
7711c0
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
7711c0
RH-Acked-by: Kevin Wolf <kwolf@redhat.com>
7711c0
7711c0
From: Fam Zheng <famz@redhat.com>
7711c0
7711c0
If we know we've already locked the bytes, don't do it again; similarly
7711c0
don't unlock a byte if we haven't locked it. This doesn't change the
7711c0
behavior, but fixes a corner case explained below.
7711c0
7711c0
Libvirt had an error handling bug that an image can get its (ownership,
7711c0
file mode, SELinux) permissions changed (RHBZ 1584982) by mistake behind
7711c0
QEMU. Specifically, an image in use by Libvirt VM has:
7711c0
7711c0
    $ ls -lhZ b.img
7711c0
    -rw-r--r--. qemu qemu system_u:object_r:svirt_image_t:s0:c600,c690 b.img
7711c0
7711c0
Trying to attach it a second time won't work because of image locking.
7711c0
And after the error, it becomes:
7711c0
7711c0
    $ ls -lhZ b.img
7711c0
    -rw-r--r--. root root system_u:object_r:virt_image_t:s0 b.img
7711c0
7711c0
Then, we won't be able to do OFD lock operations with the existing fd.
7711c0
In other words, the code such as in blk_detach_dev:
7711c0
7711c0
    blk_set_perm(blk, 0, BLK_PERM_ALL, &error_abort);
7711c0
7711c0
can abort() QEMU, out of environmental changes.
7711c0
7711c0
This patch is an easy fix to this and the change is regardlessly
7711c0
reasonable, so do it.
7711c0
7711c0
Signed-off-by: Fam Zheng <famz@redhat.com>
7711c0
Reviewed-by: Max Reitz <mreitz@redhat.com>
7711c0
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7711c0
(cherry picked from commit 2996ffad3acabe890fbb4f84a069cdc325a68108)
7711c0
Signed-off-by: Max Reitz <mreitz@redhat.com>
7711c0
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
7711c0
---
7711c0
 block/file-posix.c | 54 ++++++++++++++++++++++++++++++++++++++++++++----------
7711c0
 1 file changed, 44 insertions(+), 10 deletions(-)
7711c0
7711c0
diff --git a/block/file-posix.c b/block/file-posix.c
7711c0
index c2403ba..2a05193 100644
7711c0
--- a/block/file-posix.c
7711c0
+++ b/block/file-posix.c
7711c0
@@ -152,6 +152,11 @@ typedef struct BDRVRawState {
7711c0
     uint64_t perm;
7711c0
     uint64_t shared_perm;
7711c0
 
7711c0
+    /* The perms bits whose corresponding bytes are already locked in
7711c0
+     * s->lock_fd. */
7711c0
+    uint64_t locked_perm;
7711c0
+    uint64_t locked_shared_perm;
7711c0
+
7711c0
 #ifdef CONFIG_XFS
7711c0
     bool is_xfs:1;
7711c0
 #endif
7711c0
@@ -677,43 +682,72 @@ typedef enum {
7711c0
  * file; if @unlock == true, also unlock the unneeded bytes.
7711c0
  * @shared_perm_lock_bits is the mask of all permissions that are NOT shared.
7711c0
  */
7711c0
-static int raw_apply_lock_bytes(int fd,
7711c0
+static int raw_apply_lock_bytes(BDRVRawState *s, int fd,
7711c0
                                 uint64_t perm_lock_bits,
7711c0
                                 uint64_t shared_perm_lock_bits,
7711c0
                                 bool unlock, Error **errp)
7711c0
 {
7711c0
     int ret;
7711c0
     int i;
7711c0
+    uint64_t locked_perm, locked_shared_perm;
7711c0
+
7711c0
+    if (s) {
7711c0
+        locked_perm = s->locked_perm;
7711c0
+        locked_shared_perm = s->locked_shared_perm;
7711c0
+    } else {
7711c0
+        /*
7711c0
+         * We don't have the previous bits, just lock/unlock for each of the
7711c0
+         * requested bits.
7711c0
+         */
7711c0
+        if (unlock) {
7711c0
+            locked_perm = BLK_PERM_ALL;
7711c0
+            locked_shared_perm = BLK_PERM_ALL;
7711c0
+        } else {
7711c0
+            locked_perm = 0;
7711c0
+            locked_shared_perm = 0;
7711c0
+        }
7711c0
+    }
7711c0
 
7711c0
     PERM_FOREACH(i) {
7711c0
         int off = RAW_LOCK_PERM_BASE + i;
7711c0
-        if (perm_lock_bits & (1ULL << i)) {
7711c0
+        uint64_t bit = (1ULL << i);
7711c0
+        if ((perm_lock_bits & bit) && !(locked_perm & bit)) {
7711c0
             ret = qemu_lock_fd(fd, off, 1, false);
7711c0
             if (ret) {
7711c0
                 error_setg(errp, "Failed to lock byte %d", off);
7711c0
                 return ret;
7711c0
+            } else if (s) {
7711c0
+                s->locked_perm |= bit;
7711c0
             }
7711c0
-        } else if (unlock) {
7711c0
+        } else if (unlock && (locked_perm & bit) && !(perm_lock_bits & bit)) {
7711c0
             ret = qemu_unlock_fd(fd, off, 1);
7711c0
             if (ret) {
7711c0
                 error_setg(errp, "Failed to unlock byte %d", off);
7711c0
                 return ret;
7711c0
+            } else if (s) {
7711c0
+                s->locked_perm &= ~bit;
7711c0
             }
7711c0
         }
7711c0
     }
7711c0
     PERM_FOREACH(i) {
7711c0
         int off = RAW_LOCK_SHARED_BASE + i;
7711c0
-        if (shared_perm_lock_bits & (1ULL << i)) {
7711c0
+        uint64_t bit = (1ULL << i);
7711c0
+        if ((shared_perm_lock_bits & bit) && !(locked_shared_perm & bit)) {
7711c0
             ret = qemu_lock_fd(fd, off, 1, false);
7711c0
             if (ret) {
7711c0
                 error_setg(errp, "Failed to lock byte %d", off);
7711c0
                 return ret;
7711c0
+            } else if (s) {
7711c0
+                s->locked_shared_perm |= bit;
7711c0
             }
7711c0
-        } else if (unlock) {
7711c0
+        } else if (unlock && (locked_shared_perm & bit) &&
7711c0
+                   !(shared_perm_lock_bits & bit)) {
7711c0
             ret = qemu_unlock_fd(fd, off, 1);
7711c0
             if (ret) {
7711c0
                 error_setg(errp, "Failed to unlock byte %d", off);
7711c0
                 return ret;
7711c0
+            } else if (s) {
7711c0
+                s->locked_shared_perm &= ~bit;
7711c0
             }
7711c0
         }
7711c0
     }
7711c0
@@ -781,7 +815,7 @@ static int raw_handle_perm_lock(BlockDriverState *bs,
7711c0
 
7711c0
     switch (op) {
7711c0
     case RAW_PL_PREPARE:
7711c0
-        ret = raw_apply_lock_bytes(s->lock_fd, s->perm | new_perm,
7711c0
+        ret = raw_apply_lock_bytes(s, s->lock_fd, s->perm | new_perm,
7711c0
                                    ~s->shared_perm | ~new_shared,
7711c0
                                    false, errp);
7711c0
         if (!ret) {
7711c0
@@ -796,7 +830,7 @@ static int raw_handle_perm_lock(BlockDriverState *bs,
7711c0
         op = RAW_PL_ABORT;
7711c0
         /* fall through to unlock bytes. */
7711c0
     case RAW_PL_ABORT:
7711c0
-        raw_apply_lock_bytes(s->lock_fd, s->perm, ~s->shared_perm,
7711c0
+        raw_apply_lock_bytes(s, s->lock_fd, s->perm, ~s->shared_perm,
7711c0
                              true, &local_err);
7711c0
         if (local_err) {
7711c0
             /* Theoretically the above call only unlocks bytes and it cannot
7711c0
@@ -806,7 +840,7 @@ static int raw_handle_perm_lock(BlockDriverState *bs,
7711c0
         }
7711c0
         break;
7711c0
     case RAW_PL_COMMIT:
7711c0
-        raw_apply_lock_bytes(s->lock_fd, new_perm, ~new_shared,
7711c0
+        raw_apply_lock_bytes(s, s->lock_fd, new_perm, ~new_shared,
7711c0
                              true, &local_err);
7711c0
         if (local_err) {
7711c0
             /* Theoretically the above call only unlocks bytes and it cannot
7711c0
@@ -2160,7 +2194,7 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
7711c0
     shared = BLK_PERM_ALL & ~BLK_PERM_RESIZE;
7711c0
 
7711c0
     /* Step one: Take locks */
7711c0
-    result = raw_apply_lock_bytes(fd, perm, ~shared, false, errp);
7711c0
+    result = raw_apply_lock_bytes(NULL, fd, perm, ~shared, false, errp);
7711c0
     if (result < 0) {
7711c0
         goto out_close;
7711c0
     }
7711c0
@@ -2204,7 +2238,7 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp)
7711c0
     }
7711c0
 
7711c0
 out_unlock:
7711c0
-    raw_apply_lock_bytes(fd, 0, 0, true, &local_err);
7711c0
+    raw_apply_lock_bytes(NULL, fd, 0, 0, true, &local_err);
7711c0
     if (local_err) {
7711c0
         /* The above call should not fail, and if it does, that does
7711c0
          * not mean the whole creation operation has failed.  So
7711c0
-- 
7711c0
1.8.3.1
7711c0