From patchwork Fri Aug 17 05:47:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fam Zheng X-Patchwork-Id: 10568471 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4E716921 for ; Fri, 17 Aug 2018 05:49:49 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3E75D2B5E5 for ; Fri, 17 Aug 2018 05:49:49 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3242D2B61B; Fri, 17 Aug 2018 05:49:49 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id A080D2B5E5 for ; Fri, 17 Aug 2018 05:49:48 +0000 (UTC) Received: from localhost ([::1]:60094 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fqXdr-0006d6-Tt for patchwork-qemu-devel@patchwork.kernel.org; Fri, 17 Aug 2018 01:49:47 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41468) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fqXcO-0005Mv-6i for qemu-devel@nongnu.org; Fri, 17 Aug 2018 01:48:17 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fqXcN-00033C-4z for qemu-devel@nongnu.org; Fri, 17 Aug 2018 01:48:16 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:39026 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fqXcK-00031f-M5; Fri, 17 Aug 2018 01:48:12 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 5CAA941B88; Fri, 17 Aug 2018 05:48:12 +0000 (UTC) Received: from lemon.usersys.redhat.com (ovpn-12-174.pek2.redhat.com [10.72.12.174]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4365610FD285; Fri, 17 Aug 2018 05:48:08 +0000 (UTC) From: Fam Zheng To: qemu-devel@nongnu.org Date: Fri, 17 Aug 2018 13:47:56 +0800 Message-Id: <20180817054758.14515-2-famz@redhat.com> In-Reply-To: <20180817054758.14515-1-famz@redhat.com> References: <20180817054758.14515-1-famz@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Fri, 17 Aug 2018 05:48:12 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Fri, 17 Aug 2018 05:48:12 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'famz@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 1/3] file-posix: Skip effectiveless OFD lock operations X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , qemu-block@nongnu.org, Max Reitz Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP If we know we've already locked the bytes, don't do it again; similarly don't unlock a byte if we haven't locked it. This doesn't change the behavior, but fixes a corner case explained below. Libvirt had an error handling bug that an image can get its (ownership, file mode, SELinux) permissions changed (RHBZ 1584982) by mistake behind QEMU. Specifically, an image in use by Libvirt VM has: $ ls -lhZ b.img -rw-r--r--. qemu qemu system_u:object_r:svirt_image_t:s0:c600,c690 b.img Trying to attach it a second time won't work because of image locking. And after the error, it becomes: $ ls -lhZ b.img -rw-r--r--. root root system_u:object_r:virt_image_t:s0 b.img Then, we won't be able to do OFD lock operations with the existing fd. In other words, the code such as in blk_detach_dev: blk_set_perm(blk, 0, BLK_PERM_ALL, &error_abort); can abort() QEMU, out of environmental changes. This patch is an easy fix to this and the change is regardlessly reasonable, so do it. Signed-off-by: Fam Zheng --- v3: Don't misuse s->perm and s->shared_perm. v2: For s == NULL, unlock all bits. [Kevin] --- block/file-posix.c | 54 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index fe83cbf0eb..f062e477e9 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -152,6 +152,11 @@ typedef struct BDRVRawState { uint64_t perm; uint64_t shared_perm; + /* The perms bits whose corresponding bytes are already locked in + * s->lock_fd. */ + uint64_t locked_perm; + uint64_t locked_shared_perm; + #ifdef CONFIG_XFS bool is_xfs:1; #endif @@ -680,43 +685,72 @@ typedef enum { * file; if @unlock == true, also unlock the unneeded bytes. * @shared_perm_lock_bits is the mask of all permissions that are NOT shared. */ -static int raw_apply_lock_bytes(int fd, +static int raw_apply_lock_bytes(BDRVRawState *s, int fd, uint64_t perm_lock_bits, uint64_t shared_perm_lock_bits, bool unlock, Error **errp) { int ret; int i; + uint64_t locked_perm, locked_shared_perm; + + if (s) { + locked_perm = s->locked_perm; + locked_shared_perm = s->locked_shared_perm; + } else { + /* + * We don't have the previous bits, just lock/unlock for each of the + * requested bits. + */ + if (unlock) { + locked_perm = BLK_PERM_ALL; + locked_shared_perm = BLK_PERM_ALL; + } else { + locked_perm = 0; + locked_shared_perm = 0; + } + } PERM_FOREACH(i) { int off = RAW_LOCK_PERM_BASE + i; - if (perm_lock_bits & (1ULL << i)) { + uint64_t bit = (1ULL << i); + if ((perm_lock_bits & bit) && !(locked_perm & bit)) { ret = qemu_lock_fd(fd, off, 1, false); if (ret) { error_setg(errp, "Failed to lock byte %d", off); return ret; + } else if (s) { + s->locked_perm |= bit; } - } else if (unlock) { + } else if (unlock && (locked_perm & bit) && !(perm_lock_bits & bit)) { ret = qemu_unlock_fd(fd, off, 1); if (ret) { error_setg(errp, "Failed to unlock byte %d", off); return ret; + } else if (s) { + s->locked_perm &= ~bit; } } } PERM_FOREACH(i) { int off = RAW_LOCK_SHARED_BASE + i; - if (shared_perm_lock_bits & (1ULL << i)) { + uint64_t bit = (1ULL << i); + if ((shared_perm_lock_bits & bit) && !(locked_shared_perm & bit)) { ret = qemu_lock_fd(fd, off, 1, false); if (ret) { error_setg(errp, "Failed to lock byte %d", off); return ret; + } else if (s) { + s->locked_shared_perm |= bit; } - } else if (unlock) { + } else if (unlock && (locked_shared_perm & bit) && + !(shared_perm_lock_bits & bit)) { ret = qemu_unlock_fd(fd, off, 1); if (ret) { error_setg(errp, "Failed to unlock byte %d", off); return ret; + } else if (s) { + s->locked_shared_perm &= ~bit; } } } @@ -788,7 +822,7 @@ static int raw_handle_perm_lock(BlockDriverState *bs, switch (op) { case RAW_PL_PREPARE: - ret = raw_apply_lock_bytes(s->lock_fd, s->perm | new_perm, + ret = raw_apply_lock_bytes(s, s->lock_fd, s->perm | new_perm, ~s->shared_perm | ~new_shared, false, errp); if (!ret) { @@ -800,7 +834,7 @@ static int raw_handle_perm_lock(BlockDriverState *bs, op = RAW_PL_ABORT; /* fall through to unlock bytes. */ case RAW_PL_ABORT: - raw_apply_lock_bytes(s->lock_fd, s->perm, ~s->shared_perm, + raw_apply_lock_bytes(s, s->lock_fd, s->perm, ~s->shared_perm, true, &local_err); if (local_err) { /* Theoretically the above call only unlocks bytes and it cannot @@ -810,7 +844,7 @@ static int raw_handle_perm_lock(BlockDriverState *bs, } break; case RAW_PL_COMMIT: - raw_apply_lock_bytes(s->lock_fd, new_perm, ~new_shared, + raw_apply_lock_bytes(s, s->lock_fd, new_perm, ~new_shared, true, &local_err); if (local_err) { /* Theoretically the above call only unlocks bytes and it cannot @@ -2209,7 +2243,7 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp) shared = BLK_PERM_ALL & ~BLK_PERM_RESIZE; /* Step one: Take locks */ - result = raw_apply_lock_bytes(fd, perm, ~shared, false, errp); + result = raw_apply_lock_bytes(NULL, fd, perm, ~shared, false, errp); if (result < 0) { goto out_close; } @@ -2250,7 +2284,7 @@ raw_co_create(BlockdevCreateOptions *options, Error **errp) } out_unlock: - raw_apply_lock_bytes(fd, 0, 0, true, &local_err); + raw_apply_lock_bytes(NULL, fd, 0, 0, true, &local_err); if (local_err) { /* The above call should not fail, and if it does, that does * not mean the whole creation operation has failed. So From patchwork Fri Aug 17 05:47:57 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fam Zheng X-Patchwork-Id: 10568469 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7E23A13B6 for ; Fri, 17 Aug 2018 05:49:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6D69C2B5D0 for ; Fri, 17 Aug 2018 05:49:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 618D02B615; Fri, 17 Aug 2018 05:49:39 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 04AB42B5D0 for ; Fri, 17 Aug 2018 05:49:39 +0000 (UTC) Received: from localhost ([::1]:60093 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fqXdi-0006Mw-Au for patchwork-qemu-devel@patchwork.kernel.org; Fri, 17 Aug 2018 01:49:38 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41495) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fqXcR-0005Pf-5T for qemu-devel@nongnu.org; Fri, 17 Aug 2018 01:48:19 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fqXcQ-00037j-8w for qemu-devel@nongnu.org; Fri, 17 Aug 2018 01:48:19 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:39886 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fqXcO-00033x-8l; Fri, 17 Aug 2018 01:48:16 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id EA1957A7E8; Fri, 17 Aug 2018 05:48:15 +0000 (UTC) Received: from lemon.usersys.redhat.com (ovpn-12-174.pek2.redhat.com [10.72.12.174]) by smtp.corp.redhat.com (Postfix) with ESMTP id 133AF10EE837; Fri, 17 Aug 2018 05:48:12 +0000 (UTC) From: Fam Zheng To: qemu-devel@nongnu.org Date: Fri, 17 Aug 2018 13:47:57 +0800 Message-Id: <20180817054758.14515-3-famz@redhat.com> In-Reply-To: <20180817054758.14515-1-famz@redhat.com> References: <20180817054758.14515-1-famz@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Fri, 17 Aug 2018 05:48:15 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Fri, 17 Aug 2018 05:48:15 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'famz@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 2/3] file-posix: Drop s->lock_fd X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , qemu-block@nongnu.org, Max Reitz Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP The lock_fd field is not strictly necessary because transferring locked bytes from old fd to the new one shouldn't fail anyway. This spares the user one fd per image. Signed-off-by: Fam Zheng --- block/file-posix.c | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/block/file-posix.c b/block/file-posix.c index f062e477e9..26d4e487d2 100644 --- a/block/file-posix.c +++ b/block/file-posix.c @@ -142,7 +142,6 @@ do { \ typedef struct BDRVRawState { int fd; - int lock_fd; bool use_lock; int type; int open_flags; @@ -153,7 +152,7 @@ typedef struct BDRVRawState { uint64_t shared_perm; /* The perms bits whose corresponding bytes are already locked in - * s->lock_fd. */ + * s->fd. */ uint64_t locked_perm; uint64_t locked_shared_perm; @@ -542,18 +541,6 @@ static int raw_open_common(BlockDriverState *bs, QDict *options, } s->fd = fd; - s->lock_fd = -1; - if (s->use_lock) { - fd = qemu_open(filename, s->open_flags); - if (fd < 0) { - ret = -errno; - error_setg_errno(errp, errno, "Could not open '%s' for locking", - filename); - qemu_close(s->fd); - goto fail; - } - s->lock_fd = fd; - } s->perm = 0; s->shared_perm = BLK_PERM_ALL; @@ -818,15 +805,13 @@ static int raw_handle_perm_lock(BlockDriverState *bs, return 0; } - assert(s->lock_fd > 0); - switch (op) { case RAW_PL_PREPARE: - ret = raw_apply_lock_bytes(s, s->lock_fd, s->perm | new_perm, + ret = raw_apply_lock_bytes(s, s->fd, s->perm | new_perm, ~s->shared_perm | ~new_shared, false, errp); if (!ret) { - ret = raw_check_lock_bytes(s->lock_fd, new_perm, new_shared, errp); + ret = raw_check_lock_bytes(s->fd, new_perm, new_shared, errp); if (!ret) { return 0; } @@ -834,7 +819,7 @@ static int raw_handle_perm_lock(BlockDriverState *bs, op = RAW_PL_ABORT; /* fall through to unlock bytes. */ case RAW_PL_ABORT: - raw_apply_lock_bytes(s, s->lock_fd, s->perm, ~s->shared_perm, + raw_apply_lock_bytes(s, s->fd, s->perm, ~s->shared_perm, true, &local_err); if (local_err) { /* Theoretically the above call only unlocks bytes and it cannot @@ -844,7 +829,7 @@ static int raw_handle_perm_lock(BlockDriverState *bs, } break; case RAW_PL_COMMIT: - raw_apply_lock_bytes(s, s->lock_fd, new_perm, ~new_shared, + raw_apply_lock_bytes(s, s->fd, new_perm, ~new_shared, true, &local_err); if (local_err) { /* Theoretically the above call only unlocks bytes and it cannot @@ -956,10 +941,18 @@ static void raw_reopen_commit(BDRVReopenState *state) { BDRVRawReopenState *rs = state->opaque; BDRVRawState *s = state->bs->opaque; + Error *local_err = NULL; s->check_cache_dropped = rs->check_cache_dropped; s->open_flags = rs->open_flags; + /* Copy locks to the new fd before closing the old one. */ + raw_apply_lock_bytes(NULL, rs->fd, s->locked_perm, + ~s->locked_shared_perm, false, &local_err); + if (local_err) { + /* shouldn't fail in a sane host, but report it just in case. */ + error_report_err(local_err); + } qemu_close(s->fd); s->fd = rs->fd; @@ -1952,10 +1945,6 @@ static void raw_close(BlockDriverState *bs) qemu_close(s->fd); s->fd = -1; } - if (s->lock_fd >= 0) { - qemu_close(s->lock_fd); - s->lock_fd = -1; - } } /** From patchwork Fri Aug 17 05:47:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fam Zheng X-Patchwork-Id: 10568475 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DE81913B6 for ; Fri, 17 Aug 2018 05:51:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CD5E12B0EB for ; Fri, 17 Aug 2018 05:51:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C17492B661; Fri, 17 Aug 2018 05:51:31 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 31EB82B0EB for ; Fri, 17 Aug 2018 05:51:31 +0000 (UTC) Received: from localhost ([::1]:60107 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fqXfW-0007tm-HW for patchwork-qemu-devel@patchwork.kernel.org; Fri, 17 Aug 2018 01:51:30 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:41530) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fqXcY-0005WJ-1q for qemu-devel@nongnu.org; Fri, 17 Aug 2018 01:48:27 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fqXcW-0003BE-UT for qemu-devel@nongnu.org; Fri, 17 Aug 2018 01:48:25 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:43728 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fqXcR-00038D-H1; Fri, 17 Aug 2018 01:48:19 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 3949340216F1; Fri, 17 Aug 2018 05:48:19 +0000 (UTC) Received: from lemon.usersys.redhat.com (ovpn-12-174.pek2.redhat.com [10.72.12.174]) by smtp.corp.redhat.com (Postfix) with ESMTP id B7660112D167; Fri, 17 Aug 2018 05:48:16 +0000 (UTC) From: Fam Zheng To: qemu-devel@nongnu.org Date: Fri, 17 Aug 2018 13:47:58 +0800 Message-Id: <20180817054758.14515-4-famz@redhat.com> In-Reply-To: <20180817054758.14515-1-famz@redhat.com> References: <20180817054758.14515-1-famz@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Fri, 17 Aug 2018 05:48:19 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Fri, 17 Aug 2018 05:48:19 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'famz@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH v3 3/3] tests: Add unit tests for image locking X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Kevin Wolf , qemu-block@nongnu.org, Max Reitz Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Fam Zheng --- tests/Makefile.include | 2 + tests/test-image-locking.c | 152 +++++++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 tests/test-image-locking.c diff --git a/tests/Makefile.include b/tests/Makefile.include index 760a0f18b6..8cc0595b39 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -95,6 +95,7 @@ check-unit-y += tests/test-bdrv-drain$(EXESUF) check-unit-y += tests/test-blockjob$(EXESUF) check-unit-y += tests/test-blockjob-txn$(EXESUF) check-unit-y += tests/test-block-backend$(EXESUF) +check-unit-y += tests/test-image-locking$(EXESUF) check-unit-y += tests/test-x86-cpuid$(EXESUF) # all code tested by test-x86-cpuid is inside topology.h gcov-files-test-x86-cpuid-y = @@ -640,6 +641,7 @@ tests/test-bdrv-drain$(EXESUF): tests/test-bdrv-drain.o $(test-block-obj-y) $(te tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y) tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y) tests/test-block-backend$(EXESUF): tests/test-block-backend.o $(test-block-obj-y) $(test-util-obj-y) +tests/test-image-locking$(EXESUF): tests/test-image-locking.o $(test-block-obj-y) $(test-util-obj-y) tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y) tests/test-iov$(EXESUF): tests/test-iov.o $(test-util-obj-y) tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y) $(test-crypto-obj-y) diff --git a/tests/test-image-locking.c b/tests/test-image-locking.c new file mode 100644 index 0000000000..ccfa4e2c54 --- /dev/null +++ b/tests/test-image-locking.c @@ -0,0 +1,152 @@ +/* + * Image locking tests + * + * Copyright (c) 2018 Red Hat Inc. + * + * Author: Fam Zheng + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "qemu/osdep.h" +#include "block/block.h" +#include "sysemu/block-backend.h" +#include "qapi/error.h" +#include "qapi/qmp/qdict.h" + +static BlockBackend *open_image(const char *path, + uint64_t perm, uint64_t shared_perm, + Error **errp) +{ + Error *local_err = NULL; + BlockBackend *blk; + QDict *options = qdict_new(); + + qdict_put_str(options, "driver", "raw"); + blk = blk_new_open(path, NULL, options, BDRV_O_RDWR, &local_err); + if (blk) { + g_assert_null(local_err); + if (blk_set_perm(blk, perm, shared_perm, errp)) { + blk_unref(blk); + blk = NULL; + } + } else { + error_propagate(errp, local_err); + } + return blk; +} + +static void check_locked_bytes(int fd, uint64_t perm_locks, + uint64_t shared_perm_locks) +{ + int i; + + if (!perm_locks && !shared_perm_locks) { + g_assert(!qemu_lock_fd_test(fd, 0, 0, true)); + return; + } + for (i = 0; (1ULL << i) <= BLK_PERM_ALL; i++) { + uint64_t bit = (1ULL << i); + bool perm_expected = !!(bit & perm_locks); + bool shared_perm_expected = !!(bit & shared_perm_locks); + g_assert_cmpint(perm_expected, ==, + !!qemu_lock_fd_test(fd, 100 + i, 1, true)); + g_assert_cmpint(shared_perm_expected, ==, + !!qemu_lock_fd_test(fd, 200 + i, 1, true)); + } +} + +static void test_image_locking_basic(void) +{ + BlockBackend *blk1, *blk2, *blk3; + char img_path[] = "/tmp/qtest.XXXXXX"; + uint64_t perm, shared_perm; + + int fd = mkstemp(img_path); + assert(fd >= 0); + + perm = BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ; + shared_perm = BLK_PERM_ALL; + blk1 = open_image(img_path, perm, shared_perm, &error_abort); + g_assert(blk1); + + check_locked_bytes(fd, perm, ~shared_perm); + + /* compatible perm between blk1 and blk2 */ + blk2 = open_image(img_path, perm | BLK_PERM_RESIZE, shared_perm, NULL); + g_assert(blk2); + check_locked_bytes(fd, perm | BLK_PERM_RESIZE, ~shared_perm); + + /* incompatible perm with already open blk1 and blk2 */ + blk3 = open_image(img_path, perm, BLK_PERM_WRITE_UNCHANGED, NULL); + g_assert_null(blk3); + + blk_unref(blk2); + + /* Check that extra bytes in blk2 are correctly unlocked */ + check_locked_bytes(fd, perm, ~shared_perm); + + blk_unref(blk1); + + /* Image is unused, no lock there */ + check_locked_bytes(fd, 0, 0); + blk3 = open_image(img_path, perm, BLK_PERM_WRITE_UNCHANGED, &error_abort); + g_assert(blk3); + blk_unref(blk3); + close(fd); +} + +static void test_set_perm_abort(void) +{ + BlockBackend *blk1, *blk2; + char img_path[] = "/tmp/qtest.XXXXXX"; + uint64_t perm, shared_perm; + int r; + int fd = mkstemp(img_path); + assert(fd >= 0); + + perm = BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ; + shared_perm = BLK_PERM_ALL; + blk1 = open_image(img_path, perm, shared_perm, &error_abort); + g_assert(blk1); + + blk2 = open_image(img_path, perm, shared_perm, &error_abort); + g_assert(blk2); + + check_locked_bytes(fd, perm, ~shared_perm); + + /* A failed blk_set_perm mustn't change perm status (locked bytes) */ + r = blk_set_perm(blk2, perm | BLK_PERM_RESIZE, BLK_PERM_WRITE_UNCHANGED, + NULL); + g_assert_cmpint(r, !=, 0); + check_locked_bytes(fd, perm, ~shared_perm); +} + +int main(int argc, char **argv) +{ + bdrv_init(); + qemu_init_main_loop(&error_abort); + + g_test_init(&argc, &argv, NULL); + + g_test_add_func("/image-locking/basic", test_image_locking_basic); + g_test_add_func("/image-locking/set-perm-abort", test_set_perm_abort); + + return g_test_run(); +}