|
|
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 |
|