From nobody Thu May 15 11:34:35 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1510235897668399.1819780465879; Thu, 9 Nov 2017 05:58:17 -0800 (PST) Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 724A22D0FB8; Thu, 9 Nov 2017 13:58:16 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 5339E6C414; Thu, 9 Nov 2017 13:58:16 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 1F6B63D387; Thu, 9 Nov 2017 13:58:16 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id vA9Dw0Aj010217 for ; Thu, 9 Nov 2017 08:58:00 -0500 Received: by smtp.corp.redhat.com (Postfix) id A1EFF60012; Thu, 9 Nov 2017 13:58:00 +0000 (UTC) Received: from mx1.redhat.com (ext-mx07.extmail.prod.ext.phx2.redhat.com [10.5.110.31]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 9BA0D6178D for ; Thu, 9 Nov 2017 13:57:58 +0000 (UTC) Received: from relay.sw.ru (mailhub.sw.ru [195.214.232.25]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 63626C047B8A for ; Thu, 9 Nov 2017 13:57:57 +0000 (UTC) Received: from dim-vz7.qa.sw.ru (msk-vpn.virtuozzo.com [195.214.232.6]) by relay.sw.ru (8.13.4/8.13.4) with ESMTP id vA9DJWR9009796 for ; Thu, 9 Nov 2017 16:19:32 +0300 (MSK) From: Nikolay Shirokovskiy To: libvir-list@redhat.com Date: Thu, 9 Nov 2017 16:18:47 +0300 Message-Id: <1510233537-848259-2-git-send-email-nshirokovskiy@virtuozzo.com> In-Reply-To: <1510233537-848259-1-git-send-email-nshirokovskiy@virtuozzo.com> References: <1510233537-848259-1-git-send-email-nshirokovskiy@virtuozzo.com> X-Greylist: Delayed for 00:38:03 by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Thu, 09 Nov 2017 13:57:58 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Thu, 09 Nov 2017 13:57:58 +0000 (UTC) for IP:'195.214.232.25' DOMAIN:'mailhub.sw.ru' HELO:'relay.sw.ru' FROM:'nshirokovskiy@virtuozzo.com' RCPT:'' X-RedHat-Spam-Score: -0.001 (SPF_PASS) 195.214.232.25 mailhub.sw.ru 195.214.232.25 mailhub.sw.ru X-Scanned-By: MIMEDefang 2.78 on 10.5.110.31 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH v3 01/11] qemu: introduce routines for interruptible state X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Thu, 09 Nov 2017 13:58:16 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Async job that wants to allow concurrent execution of regular job should call qemuDomainObjEnterInterruptible and then qemuDomainObjExitInterruptible when it wants to disable concurrent execution of regular jobs. These functions can be called from non concurrent regular jobs. In this case the functions are noops. Non concurrent regular job is regular job started when no async job is running. We need to take care of these functions being called from non concurrent regular jobs because some high level routines can be called from both contexts - async job and non concurrent regular job. One example is qemuConnectAgent which can be called during domain startup (async job) or domain reconnect (non concurrent regular job). qemuDomainObjEnterInterruptible result is void even though it detects some error conditions. These error conditions depend solely on qemu driver design thus for the sake of simplicity errors are not propagated. If by mistake function will be used improreply at least we have diagnostics in log. These enter/exit functions detect some error conditions but do not propagate them to the callers because this conditions depend solely on qemu driver consistensy and not outer conditions. (By driver consistency I mean domain mutex, domain condition should be initialised and enter/exit should not be called without any job or from concurret regular job). In other words propagating error can not help handling any world situation which is not under out control. Drop some log on detecting self inconsistency should be enough as it should be fixed eventually. qemuDomainObjWait and qemuDomainObjSleep are typical uses cases of interruptible state - wait on domain condition/sleep with interruptible state set. --- src/qemu/qemu_domain.c | 144 +++++++++++++++++++++++++++++++++++++++++++++= ++++ src/qemu/qemu_domain.h | 12 +++++ 2 files changed, 156 insertions(+) diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 61d2833..f6a403c 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -333,6 +333,7 @@ qemuDomainObjResetAsyncJob(qemuDomainObjPrivatePtr priv) job->spiceMigration =3D false; job->spiceMigrated =3D false; job->postcopyEnabled =3D false; + job->asyncInterruptible =3D false; VIR_FREE(job->current); } =20 @@ -4697,6 +4698,149 @@ qemuDomainObjEnterMonitorAsync(virQEMUDriverPtr dri= ver, return qemuDomainObjEnterMonitorInternal(driver, obj, asyncJob); } =20 +/* + * @obj must be locked before calling. Must be used within context of asyn= c job + * or non concurrent regular job. + * + * Enters interruptible state for async job. When async job is in this + * state another thread can run concurrent regular job. + */ +void +qemuDomainObjEnterInterruptible(virDomainObjPtr obj) +{ + qemuDomainObjPrivatePtr priv =3D obj->privateData; + struct qemuDomainJobObj *job =3D &priv->job; + + if (job->asyncJob) { + /* + * Entering interruptible state from concurrent regular job is des= ign + * flaw. Let's not return error in this case to try to recover but + * drop error message to help detect this situation. + */ + if (job->active) { + VIR_ERROR(_("Attempt to enter interruptible state for the conc= urrent " + "regular job")); + return; + } + } else { + /* + * Entering interruptible state without any job at all is design f= law. + * Let's not return error in this case to try to recover but + * drop error message to help detect this situation. + */ + if (!job->active) + VIR_ERROR(_("Attempt to enter interruptible state without any = job")); + + /* In case of non concurrent regular we don't need to do anything = and + * this situation can be easily detected on exit interruptible sta= te + * as no job con run concurrently to non concurrent regular job. */ + return; + } + + job->asyncInterruptible =3D true; + VIR_DEBUG("Async job enters interruptible state.(obj=3D%p name=3D%s, a= sync=3D%s)", + obj, obj->def->name, + qemuDomainAsyncJobTypeToString(job->asyncJob)); + virCondBroadcast(&priv->job.asyncCond); +} + + +/* + * @obj must be locked before calling. Must be used within context of asyn= c job + * or non concurrent regular job. Must be called if qemuDomainObjEnterInte= rruptible + * is called before. + * + * Exits async job interruptible state so after exit from this function + * no concurrent regular jobs are allowed to run simultaneously. The funct= ion + * waits until any concurrent regular job started after async job entered + * interruptible state is finished before exit. + */ +void +qemuDomainObjExitInterruptible(virDomainObjPtr obj) +{ + qemuDomainObjPrivatePtr priv =3D obj->privateData; + struct qemuDomainJobObj *job =3D &priv->job; + + /* Just noop for the case of non concurrent regular job. See + * also entering function. */ + if (!job->asyncJob && job->active) + return; + + job->asyncInterruptible =3D false; + VIR_DEBUG("Async job exits interruptible state. " + "(obj=3D%p name=3D%s, async=3D%s)", + obj, obj->def->name, + qemuDomainAsyncJobTypeToString(job->asyncJob)); + + /* + * Wait until no concurrent regular job is running. There is no real + * conditions for wait to fail thus just do not return error in case + * wait fails but log error just for safety. + */ + while (job->active) { + if (virCondWait(&priv->job.cond, &obj->parent.lock) < 0) { + char buf[1024]; + + VIR_ERROR(_("failed to wait for job condition: %s"), + virStrerror(errno, buf, sizeof(buf))); + return; + } + } +} + + +/* + * @obj must be locked before calling. Must be used within context of asyn= c job + * or non concurrent regular job. + * + * Wait on @obj lock. Async job is in interruptlible state during wait so + * concurrent regular jobs are allowed to run. + */ +int +qemuDomainObjWait(virDomainObjPtr obj) +{ + qemuDomainObjEnterInterruptible(obj); + + if (virCondWait(&obj->cond, &obj->parent.lock) < 0) { + virReportSystemError(errno, "%s", + _("failed to wait for domain condition")); + qemuDomainObjExitInterruptible(obj); + return -1; + } + + qemuDomainObjExitInterruptible(obj); + + if (!virDomainObjIsActive(obj)) { + virReportError(VIR_ERR_OPERATION_FAILED, "%s", + _("domain is not running")); + return -1; + } + + return 0; +} + + +/* + * obj must be locked before calling. Must be used within context of async= job + * or nonconcurrent regular job. + * + * Sleep with obj lock dropped. Async job is in interruptlible state durin= g wait + * so concurrent regular jobs are allowed to run. + */ +void +qemuDomainObjSleep(virDomainObjPtr obj, unsigned long nsec) +{ + struct timespec ts =3D { .tv_sec =3D 0, .tv_nsec =3D nsec }; + + qemuDomainObjEnterInterruptible(obj); + + virObjectUnlock(obj); + nanosleep(&ts, NULL); + virObjectLock(obj); + + qemuDomainObjExitInterruptible(obj); +} + =20 /* * obj must be locked before calling diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index e021da5..25a6823 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -151,6 +151,8 @@ struct qemuDomainJobObj { =20 virCond asyncCond; /* Use to coordinate with async jo= bs */ qemuDomainAsyncJob asyncJob; /* Currently active async job */ + bool asyncInterruptible; /* Regular jobs compatible with cu= rrent + async job are allowed to run */ unsigned long long asyncOwner; /* Thread which set current async = job */ const char *asyncOwnerAPI; /* The API which owns the async jo= b */ unsigned long long asyncStarted; /* When the current async job star= ted */ @@ -527,6 +529,16 @@ int qemuDomainObjEnterMonitorAsync(virQEMUDriverPtr dr= iver, qemuDomainAsyncJob asyncJob) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; =20 +void qemuDomainObjEnterInterruptible(virDomainObjPtr obj) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); +void qemuDomainObjExitInterruptible(virDomainObjPtr obj) + ATTRIBUTE_NONNULL(1); + +int qemuDomainObjWait(virDomainObjPtr obj) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + +void qemuDomainObjSleep(virDomainObjPtr obj, unsigned long nsec) + ATTRIBUTE_NONNULL(1); =20 qemuAgentPtr qemuDomainObjEnterAgent(virDomainObjPtr obj) ATTRIBUTE_NONNULL(1); --=20 1.8.3.1 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list