From nobody Fri May 17 04:49:53 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1655933228; cv=none; d=zohomail.com; s=zohoarc; b=NNpTHKQH7UJHODXJ67EDUbnGI0gRaBTXLGk+qJsaLF7Nl9N0AsF2phT5GFG4KkSD0CgSNkBVQXBwSIZQ2RiwfM0OqVGZj4oTFaLTdj0Ay9y9RCSxHSozEqN7Pz9+O261ynBzcckQdTqdY/CkXVcdM7PlocF2zdiZkjOMDOxWC1U= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1655933228; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=hviVjKspS/Blq2+IvRULt22n02aHVKjXYowFJ/LVCD0=; b=jQgidB5+IGezZo03U8hmlpe0thRBAQCCbXZoNn8tjLivkyeedZLMAaZdPKjneczata1BjIVcodcUc1CWd5DjlK7TTR7DpVJQjVYSJKMux9oXtt9XnaPPw785TXpQQAA3ywXCP4y/xub6nkfXHU5DBGcuj5f5weWAPPfnz2+N6cQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 1655933228019351.60924541807003; Wed, 22 Jun 2022 14:27:08 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-605-SlYqPOEGPkCDQ3FtJ0wkPQ-1; Wed, 22 Jun 2022 17:26:36 -0400 Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id B9EA03C0CD4E; Wed, 22 Jun 2022 21:26:33 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id A7CED4619F4; Wed, 22 Jun 2022 21:26:33 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 81E4719451EC; Wed, 22 Jun 2022 21:26:30 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id C9D891947051 for ; Wed, 22 Jun 2022 21:26:27 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id AF21218EA8; Wed, 22 Jun 2022 21:26:27 +0000 (UTC) Received: from himantopus.redhat.com (unknown [10.22.8.228]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 8719A9D54; Wed, 22 Jun 2022 21:26:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1655933226; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=hviVjKspS/Blq2+IvRULt22n02aHVKjXYowFJ/LVCD0=; b=W8wbQ2OJPzWAVcP/cXahK5+uvLKiRzPGnHa+ERqsaD9Dii4dnVUPbi3VWcNlYUf3bhIQeP j0qedddbXvmyquz5y8Z82yFril0aqEH/pFjoH86TObC9yuhhj5VrZPlW6erUfyxD7h6D71 fNowzcPXSQJM/WwpY30X0HdXeYYRkCM= X-MC-Unique: SlYqPOEGPkCDQ3FtJ0wkPQ-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Jonathon Jongsma To: libvir-list@redhat.com Subject: [libvirt PATCH 1/3] docs: clarify 'readahead' and 'timeout' for disks Date: Wed, 22 Jun 2022 16:26:24 -0500 Message-Id: <20220622212626.2734141-2-jjongsma@redhat.com> In-Reply-To: <20220622212626.2734141-1-jjongsma@redhat.com> References: <20220622212626.2734141-1-jjongsma@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: pkrempa@redhat.com Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.85 on 10.11.54.10 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1655933228778100001 Content-Type: text/plain; charset="utf-8"; x-default="true" Document the format of the 'readahead' and 'timeout' XML elements more accurately. Signed-off-by: Jonathon Jongsma Reviewed-by: Michal Privoznik --- docs/formatdomain.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 991d45672a..62a94890f0 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -2878,11 +2878,13 @@ paravirtualized driver is specified via the ``disk`= ` element. more cookies. The cookie name and value must conform to the HTTP specification. :since:`Since 6.2.0` ``readahead`` - Specifies the size of the readahead buffer for protocols which suppo= rt it. - (all 'curl' based drivers in qemu). The size is in bytes. Note that = '0' is - considered as if the value is not provided. :since:`Since 6.2.0` + The ``readahead`` element has a ``size`` attribute which specifies t= he + size of the readahead buffer in bytes for protocols which support it. + Note that '0' is considered as if the value is not provided. + :since:`Since 6.2.0` ``timeout`` - Specifies the connection timeout for protocols which support it. Not= e that + The ``timeout`` element has a ``seconds`` attribute which specifies = the + connection timeout in seconds for protocols which support it. Note t= hat '0' is considered as if the value is not provided. :since:`Since 6.2= .0` ``identity`` When using an ``nfs`` protocol, this is used to provide information = on the --=20 2.35.3 From nobody Fri May 17 04:49:53 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1655933201; cv=none; d=zohomail.com; s=zohoarc; b=Rfl/k1d8MyqvF10vF1HjIlSLLic2nr4GLIL8jOwjtG5Vlxq0uRXw3isjRMY+X+yd+XPqhlfSoTNc5PQrtFG4/DRmI/Os43B+FofxKMh7+Cdp3xi6ee3gY2LpFQx1lmsOrC+1R1SP1Fbq/Olxe03B72qA54YFjfqtlibf3Wv9oRc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1655933201; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=7TrDR9t9QPn7yye+ps6+BubnIcoAxm0hlICC4Cm+u5w=; b=KkEWzlIey3enlgGKw6+C3/7xtP89YpQZ4qzMUB/LE5JpbPO8wo1vjc1gNbqMJRTMda0xs2fVn2Q1GhHwdpbx32ZQg31JlTXdKHS8Q2GmqxJNw5g3jtafBuUfv3wcAwx6NkL+9EaqFGx2oqG8YSV3UP1EsyxpXdQO+XxqDNwM/E8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 1655933201282245.91953403900413; Wed, 22 Jun 2022 14:26:41 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-588-iA3O0CloM2COkozG3LC7pA-1; Wed, 22 Jun 2022 17:26:36 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 21D7880A1CF; Wed, 22 Jun 2022 21:26:34 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0BC232166B26; Wed, 22 Jun 2022 21:26:34 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id E8DCA1947B8C; Wed, 22 Jun 2022 21:26:30 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 161E81947051 for ; Wed, 22 Jun 2022 21:26:28 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id EA3EB18EA8; Wed, 22 Jun 2022 21:26:27 +0000 (UTC) Received: from himantopus.redhat.com (unknown [10.22.8.228]) by smtp.corp.redhat.com (Postfix) with ESMTPS id C19281131D; Wed, 22 Jun 2022 21:26:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1655933200; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=7TrDR9t9QPn7yye+ps6+BubnIcoAxm0hlICC4Cm+u5w=; b=SRsQmFP3LdRA2sc6rfH1T0StzbFBqqqytL1xElshJPeP/ex/jzebONUwzT8cdcFfGzAm7R 5IJMI1A/0GNGzyJAVmAxGzBPYn1eGr5vTHK1zDJooDNZBazhusluqkXr+/WfVGYYfesljU UdtSY9GfG1WGEe1X9o4jMAPDndDs1UY= X-MC-Unique: iA3O0CloM2COkozG3LC7pA-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Jonathon Jongsma To: libvir-list@redhat.com Subject: [libvirt PATCH 2/3] schema: Be more flexible for diskSourceNetworkProtocolPropsCommon Date: Wed, 22 Jun 2022 16:26:25 -0500 Message-Id: <20220622212626.2734141-3-jjongsma@redhat.com> In-Reply-To: <20220622212626.2734141-1-jjongsma@redhat.com> References: <20220622212626.2734141-1-jjongsma@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: pkrempa@redhat.com Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1655933202527100001 Content-Type: text/plain; charset="utf-8"; x-default="true" Add to allow the subproperties to be specified in any order. Signed-off-by: Jonathon Jongsma Reviewed-by: Michal Privoznik --- src/conf/schemas/domaincommon.rng | 34 ++++++++++++++++--------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincom= mon.rng index e2246e6b63..da2fb0d5cb 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -1967,22 +1967,24 @@ =20 - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + =20 --=20 2.35.3 From nobody Fri May 17 04:49:53 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1655933200; cv=none; d=zohomail.com; s=zohoarc; b=PHelq0gFYy7V30bc1EMx38il9FqeuP0fqhCnspWhxMouHVehAWXpyn6Hwik5Z4GurLJSseQAzmBm2Vckp4NREUJvvQVh1mrWOGaLtI0DUvQF00sD8rei268DyYjG7GaGLNp9f4zb2b3fAvkUKjezSP/GljKZmSuySI6E6q/y5IU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1655933200; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=MQ23N7xH5tDLTDkrAi4Z/Yl2XHksXv9kV+QTE10eTck=; b=YLFzVz6XAzH+LNce9b4y8kn0ztNBXjmyI/9kMX9C5Vb0+TNxuW09foH2rimnR7kHbpVgAWZB0HcuQh1tt5nKEU1kVWBxUE7+BsNi9sfCYvEATBsEsoYRR/MaLZw+iFan0z6G+69/BU8CpCfju/P80av5GWBq4r7/pf8o+SW816k= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 1655933200488884.134014528573; Wed, 22 Jun 2022 14:26:40 -0700 (PDT) Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-568-2RzedBe1MdaxTkOkWofAyg-1; Wed, 22 Jun 2022 17:26:35 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.rdu2.redhat.com [10.11.54.1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 875301C01B45; Wed, 22 Jun 2022 21:26:33 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com [10.30.29.100]) by smtp.corp.redhat.com (Postfix) with ESMTP id DF06440FF643; Wed, 22 Jun 2022 21:26:32 +0000 (UTC) Received: from mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (localhost [IPv6:::1]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 1AC3E1947071; Wed, 22 Jun 2022 21:26:30 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) by mm-prod-listman-01.mail-001.prod.us-east-1.aws.redhat.com (Postfix) with ESMTP id 828501947051 for ; Wed, 22 Jun 2022 21:26:28 +0000 (UTC) Received: by smtp.corp.redhat.com (Postfix) id 5127F9D54; Wed, 22 Jun 2022 21:26:28 +0000 (UTC) Received: from himantopus.redhat.com (unknown [10.22.8.228]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 0E70C18EAB; Wed, 22 Jun 2022 21:26:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1655933199; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=MQ23N7xH5tDLTDkrAi4Z/Yl2XHksXv9kV+QTE10eTck=; b=Lm2VC2u5tpx5iFesx/k4ir7lFHfIpJlADL4Cig40/DtDw7+mFzJc+xFz1+mZ53E6iuBgWo BKB3g9Du0aSmCywZJi+KPYI0kMqG5vgd2ykYaCOXAy3PcI5rpJwDIpcgeo6X97R26Rzp5h wlq4W+IQK0lc0SFoD0iaszizQZ2g6c4= X-MC-Unique: 2RzedBe1MdaxTkOkWofAyg-1 X-Original-To: libvir-list@listman.corp.redhat.com From: Jonathon Jongsma To: libvir-list@redhat.com Subject: [libvirt PATCH 3/3] WIP: use nbdkit for remote disk sources Date: Wed, 22 Jun 2022 16:26:26 -0500 Message-Id: <20220622212626.2734141-4-jjongsma@redhat.com> In-Reply-To: <20220622212626.2734141-1-jjongsma@redhat.com> References: <20220622212626.2734141-1-jjongsma@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: pkrempa@redhat.com Errors-To: libvir-list-bounces@redhat.com Sender: "libvir-list" X-Scanned-By: MIMEDefang 2.84 on 10.11.54.1 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) X-ZM-MESSAGEID: 1655933202627100003 Content-Type: text/plain; charset="utf-8"; x-default="true" --- include/libvirt/virterror.h | 1 + po/POTFILES | 1 + src/qemu/meson.build | 1 + src/qemu/qemu_block.c | 64 +- src/qemu/qemu_block.h | 1 + src/qemu/qemu_command.c | 26 +- src/qemu/qemu_conf.c | 19 + src/qemu/qemu_conf.h | 5 + src/qemu/qemu_domain.c | 110 ++- src/qemu/qemu_domain.h | 5 + src/qemu/qemu_driver.c | 4 +- src/qemu/qemu_extdevice.c | 25 + src/qemu/qemu_nbdkit.c | 629 ++++++++++++++++++ src/qemu/qemu_nbdkit.h | 89 +++ src/qemu/qemu_validate.c | 22 +- src/qemu/qemu_validate.h | 4 +- src/util/virerror.c | 1 + tests/qemublocktest.c | 8 +- tests/qemustatusxml2xmldata/modern-in.xml | 1 - ...sk-cdrom-network-nbdkit.x86_64-latest.args | 42 ++ .../disk-cdrom-network-nbdkit.xml | 1 + ...isk-network-http-nbdkit.x86_64-latest.args | 45 ++ .../disk-network-http-nbdkit.xml | 1 + ...work-source-curl-nbdkit.x86_64-latest.args | 49 ++ .../disk-network-source-curl-nbdkit.xml | 1 + ...isk-network-source-curl.x86_64-latest.args | 53 ++ .../disk-network-source-curl.xml | 71 ++ tests/qemuxml2argvtest.c | 12 + tests/testutilsqemu.c | 16 + tests/testutilsqemu.h | 4 + 30 files changed, 1278 insertions(+), 33 deletions(-) create mode 100644 src/qemu/qemu_nbdkit.c create mode 100644 src/qemu/qemu_nbdkit.h create mode 100644 tests/qemuxml2argvdata/disk-cdrom-network-nbdkit.x86_64= -latest.args create mode 120000 tests/qemuxml2argvdata/disk-cdrom-network-nbdkit.xml create mode 100644 tests/qemuxml2argvdata/disk-network-http-nbdkit.x86_64-= latest.args create mode 120000 tests/qemuxml2argvdata/disk-network-http-nbdkit.xml create mode 100644 tests/qemuxml2argvdata/disk-network-source-curl-nbdkit.= x86_64-latest.args create mode 120000 tests/qemuxml2argvdata/disk-network-source-curl-nbdkit.= xml create mode 100644 tests/qemuxml2argvdata/disk-network-source-curl.x86_64-= latest.args create mode 100644 tests/qemuxml2argvdata/disk-network-source-curl.xml diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h index df13e4f11e..dd198dfd7d 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -141,6 +141,7 @@ typedef enum { VIR_FROM_TPM =3D 70, /* Error from TPM (Since: 5.6.0) */ VIR_FROM_BPF =3D 71, /* Error from BPF code (Since: 5.10.0) */ VIR_FROM_CH =3D 72, /* Error from Cloud-Hypervisor driver (S= ince: 7.5.0) */ + VIR_FROM_NBDKIT =3D 73, /* Error from Nbdkit code (Since: 8.5.0)= */ =20 # ifdef VIR_ENUM_SENTINELS VIR_ERR_DOMAIN_LAST /* (Since: 0.9.13) */ diff --git a/po/POTFILES b/po/POTFILES index faaba53c8f..99284b8173 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -177,6 +177,7 @@ src/qemu/qemu_monitor.c src/qemu/qemu_monitor_json.c src/qemu/qemu_monitor_text.c src/qemu/qemu_namespace.c +src/qemu/qemu_nbdkit.c src/qemu/qemu_process.c src/qemu/qemu_qapi.c src/qemu/qemu_saveimage.c diff --git a/src/qemu/meson.build b/src/qemu/meson.build index 96952cc52d..101cf3591f 100644 --- a/src/qemu/meson.build +++ b/src/qemu/meson.build @@ -28,6 +28,7 @@ qemu_driver_sources =3D [ 'qemu_monitor_json.c', 'qemu_monitor_text.c', 'qemu_namespace.c', + 'qemu_nbdkit.c', 'qemu_process.c', 'qemu_qapi.c', 'qemu_saveimage.c', diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c index 9fe22f18f2..91f17f133f 100644 --- a/src/qemu/qemu_block.c +++ b/src/qemu/qemu_block.c @@ -773,6 +773,35 @@ qemuBlockStorageSourceGetCURLProps(virStorageSource *s= rc, } =20 =20 +static virJSONValue * +qemuBlockStorageSourceGetNbdkitProps(virStorageSource *src) +{ + qemuDomainStorageSourcePrivate *srcPriv =3D QEMU_DOMAIN_STORAGE_SOURCE= _PRIVATE(src); + virJSONValue *ret =3D NULL; + g_autoptr(virJSONValue) serverprops =3D NULL; + virStorageNetHostDef host =3D { NULL }; + + /* srcPriv->nbdkitProcess will already be initialized if we can use nb= dkit + * to proxy this storage source */ + if (!(srcPriv && srcPriv->nbdkitProcess)) + return NULL; + + host.transport =3D VIR_STORAGE_NET_HOST_TRANS_UNIX; + host.socket =3D srcPriv->nbdkitProcess->socketfile; + serverprops =3D qemuBlockStorageSourceBuildJSONSocketAddress(&host, + false); + if (!serverprops) + return NULL; + + if (virJSONValueObjectAdd(&ret, + "a:server", &serverprops, + NULL) < 0) + return NULL; + + return ret; +} + + static virJSONValue * qemuBlockStorageSourceGetISCSIProps(virStorageSource *src, bool onlytarget) @@ -1207,6 +1236,14 @@ qemuBlockStorageSourceGetBackendProps(virStorageSour= ce *src, case VIR_STORAGE_NET_PROTOCOL_FTP: case VIR_STORAGE_NET_PROTOCOL_FTPS: case VIR_STORAGE_NET_PROTOCOL_TFTP: + /* first try to use nbdkit for http/ftp sources */ + if ((fileprops =3D qemuBlockStorageSourceGetNbdkitProps(src)))= { + driver =3D "nbd"; + break; + } + + /* nbdkit is not supported for this host/source, fall back to = old + * qemu storage plugins */ driver =3D virStorageNetProtocolTypeToString(src->protocol); if (!(fileprops =3D qemuBlockStorageSourceGetCURLProps(src, on= lytarget))) return NULL; @@ -1237,6 +1274,14 @@ qemuBlockStorageSourceGetBackendProps(virStorageSour= ce *src, break; =20 case VIR_STORAGE_NET_PROTOCOL_SSH: + /* first try to use nbdkit for ssh sources */ + if ((fileprops =3D qemuBlockStorageSourceGetNbdkitProps(src)))= { + driver =3D "nbd"; + break; + } + + /* nbdkit is not supported for this host/source. fallback to + * the old qemu storage plugins */ driver =3D "ssh"; if (!(fileprops =3D qemuBlockStorageSourceGetSshProps(src))) return NULL; @@ -1671,6 +1716,7 @@ qemuBlockStorageSourceAttachPrepareBlockdev(virStorag= eSource *src, { g_autoptr(qemuBlockStorageSourceAttachData) data =3D NULL; unsigned int backendpropsflags =3D 0; + qemuDomainStorageSourcePrivate *srcpriv =3D QEMU_DOMAIN_STORAGE_SOURCE= _PRIVATE(src); =20 if (autoreadonly) backendpropsflags |=3D QEMU_BLOCK_STORAGE_SOURCE_BACKEND_PROPS_AUT= O_READONLY; @@ -1685,6 +1731,7 @@ qemuBlockStorageSourceAttachPrepareBlockdev(virStorag= eSource *src, =20 data->storageNodeName =3D src->nodestorage; data->formatNodeName =3D src->nodeformat; + data->useNbdkit =3D srcpriv && srcpriv->nbdkitProcess; =20 if (qemuBlockStorageSourceNeedsStorageSliceLayer(src)) { if (!(data->storageSliceProps =3D qemuBlockStorageSourceGetBlockde= vStorageSliceProps(src))) @@ -1701,6 +1748,10 @@ static int qemuBlockStorageSourceAttachApplyStorageDeps(qemuMonitor *mon, qemuBlockStorageSourceAttachD= ata *data) { + /* when using nbdkit, data is not passed via qemu secrets */ + if (data->useNbdkit) + return 0; + if (data->prmgrProps && qemuMonitorAddObject(mon, &data->prmgrProps, &data->prmgrAlias) < = 0) return -1; @@ -2205,6 +2256,8 @@ qemuBlockGetBackingStoreString(virStorageSource *src, virJSONValue *props =3D NULL; g_autoptr(virURI) uri =3D NULL; g_autofree char *backingJSON =3D NULL; + qemuDomainStorageSourcePrivate *srcPriv =3D QEMU_DOMAIN_STORAGE_SOURCE= _PRIVATE(src); + bool useNbdkit =3D srcPriv && srcPriv->nbdkitProcess; =20 if (!src->sliceStorage) { if (virStorageSourceIsLocalStorage(src)) { @@ -2223,7 +2276,8 @@ qemuBlockGetBackingStoreString(virStorageSource *src, src->ncookies =3D=3D 0 && src->sslverify =3D=3D VIR_TRISTATE_BOOL_ABSENT && src->timeout =3D=3D 0 && - src->readahead =3D=3D 0) { + src->readahead =3D=3D 0 && + !useNbdkit) { =20 switch ((virStorageNetProtocol) src->protocol) { case VIR_STORAGE_NET_PROTOCOL_NBD: @@ -2602,6 +2656,7 @@ qemuBlockStorageSourceCreateGetStorageProps(virStorag= eSource *src, g_autoptr(virJSONValue) location =3D NULL; const char *driver =3D NULL; const char *filename =3D NULL; + qemuDomainStorageSourcePrivate *srcPriv =3D QEMU_DOMAIN_STORAGE_SOURCE= _PRIVATE(src); =20 switch (actualType) { case VIR_STORAGE_TYPE_FILE: @@ -2630,6 +2685,13 @@ qemuBlockStorageSourceCreateGetStorageProps(virStora= geSource *src, break; =20 case VIR_STORAGE_NET_PROTOCOL_SSH: + if (srcPriv->nbdkitProcess) { + /* disk creation not yet supported with nbdkit, and even i= f it + * was supported, it would not be done with blockdev-create + * props */ + return 0; + } + driver =3D "ssh"; if (!(location =3D qemuBlockStorageSourceGetSshProps(src))) return -1; diff --git a/src/qemu/qemu_block.h b/src/qemu/qemu_block.h index 8641c8a2d2..a1f98f4452 100644 --- a/src/qemu/qemu_block.h +++ b/src/qemu/qemu_block.h @@ -113,6 +113,7 @@ struct qemuBlockStorageSourceAttachData { char *tlsAlias; virJSONValue *tlsKeySecretProps; char *tlsKeySecretAlias; + bool useNbdkit; }; =20 =20 diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index b307d3139c..dd410362fb 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1578,6 +1578,7 @@ qemuBuildNetworkDriveStr(virStorageSource *src, qemuDomainSecretInfo *secinfo) { g_auto(virBuffer) buf =3D VIR_BUFFER_INITIALIZER; + qemuDomainStorageSourcePrivate *priv =3D QEMU_DOMAIN_STORAGE_SOURCE_PR= IVATE(src); size_t i; char *ret =3D NULL; =20 @@ -1637,6 +1638,13 @@ qemuBuildNetworkDriveStr(virStorageSource *src, case VIR_STORAGE_NET_PROTOCOL_FTP: case VIR_STORAGE_NET_PROTOCOL_FTPS: case VIR_STORAGE_NET_PROTOCOL_TFTP: + if (priv && priv->nbdkitProcess) { + virBufferAsprintf(&buf, "nbd:unix:%s", priv->nbdkitProcess= ->socketfile); + ret =3D virBufferContentAndReset(&buf); + } else { + ret =3D qemuBuildNetworkDriveURI(src); + } + break; case VIR_STORAGE_NET_PROTOCOL_ISCSI: case VIR_STORAGE_NET_PROTOCOL_GLUSTER: ret =3D qemuBuildNetworkDriveURI(src); @@ -2497,13 +2505,17 @@ qemuBuildBlockStorageSourceAttachDataCommandline(vi= rCommand *cmd, { char *tmp; =20 - if (qemuBuildObjectCommandline(cmd, data->prmgrProps, qemuCaps) < 0 || - qemuBuildObjectCommandline(cmd, data->authsecretProps, qemuCaps) <= 0 || - qemuBuildObjectCommandline(cmd, data->encryptsecretProps, qemuCaps= ) < 0 || - qemuBuildObjectCommandline(cmd, data->httpcookiesecretProps, qemuC= aps) < 0 || - qemuBuildObjectCommandline(cmd, data->tlsKeySecretProps, qemuCaps)= < 0 || - qemuBuildObjectCommandline(cmd, data->tlsProps, qemuCaps) < 0) - return -1; + /* disks that are backed by nbdkit do not send these secrets to qemu, = but + * rather directly to nbdkit */ + if (!data->useNbdkit) { + if (qemuBuildObjectCommandline(cmd, data->prmgrProps, qemuCaps) < = 0 || + qemuBuildObjectCommandline(cmd, data->authsecretProps, qemuCap= s) < 0 || + qemuBuildObjectCommandline(cmd, data->encryptsecretProps, qemu= Caps) < 0 || + qemuBuildObjectCommandline(cmd, data->httpcookiesecretProps, q= emuCaps) < 0 || + qemuBuildObjectCommandline(cmd, data->tlsKeySecretProps, qemuC= aps) < 0 || + qemuBuildObjectCommandline(cmd, data->tlsProps, qemuCaps) < 0) + return -1; + } =20 if (data->driveCmd) virCommandAddArgList(cmd, "-drive", data->driveCmd, NULL); diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c index 3b75cdeb95..22aeab0c49 100644 --- a/src/qemu/qemu_conf.c +++ b/src/qemu/qemu_conf.c @@ -1571,3 +1571,22 @@ qemuGetMemoryBackingPath(virQEMUDriver *driver, *memPath =3D g_strdup_printf("%s/%s", domainPath, alias); return 0; } + +/* + * qemuGetNbdkitCaps: + * @driver: the qemu driver + * + * Gets the capabilities for Nbdkit for the specified driver. These can be= used + * to determine whether a particular disk source can be served by nbdkit or + * not. + * + * Returns: a reference to qemuNbdkitCaps or NULL + */ +qemuNbdkitCaps* +qemuGetNbdkitCaps(virQEMUDriver *driver) +{ + if (!QEMU_IS_NBDKIT_CAPS(driver->nbdkitCaps)) + return NULL; + + return g_object_ref(driver->nbdkitCaps); +} diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h index c40c452f58..f14f9fc4c1 100644 --- a/src/qemu/qemu_conf.h +++ b/src/qemu/qemu_conf.h @@ -36,6 +36,7 @@ #include "virthreadpool.h" #include "locking/lock_manager.h" #include "qemu_capabilities.h" +#include "qemu_nbdkit.h" #include "virclosecallbacks.h" #include "virhostdev.h" #include "virfile.h" @@ -306,6 +307,8 @@ struct _virQEMUDriver { =20 /* Immutable pointer, self-locking APIs */ virHashAtomic *migrationErrors; + + qemuNbdkitCaps *nbdkitCaps; }; =20 virQEMUDriverConfig *virQEMUDriverConfigNew(bool privileged, @@ -359,3 +362,5 @@ int qemuGetMemoryBackingPath(virQEMUDriver *driver, const virDomainDef *def, const char *alias, char **memPath); + +qemuNbdkitCaps * qemuGetNbdkitCaps(virQEMUDriver *driver); diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c index 9769e3bb92..faeb779b3f 100644 --- a/src/qemu/qemu_domain.c +++ b/src/qemu/qemu_domain.c @@ -21,6 +21,7 @@ =20 #include =20 +#include "qemu_conf.h" #include "qemu_domain.h" #include "qemu_alias.h" #include "qemu_block.h" @@ -818,6 +819,7 @@ qemuDomainStorageSourcePrivateDispose(void *obj) g_clear_pointer(&priv->encinfo, qemuDomainSecretInfoFree); g_clear_pointer(&priv->httpcookie, qemuDomainSecretInfoFree); g_clear_pointer(&priv->tlsKeySecret, qemuDomainSecretInfoFree); + g_clear_pointer(&priv->nbdkitProcess, qemuNbdkitProcessFree); } =20 =20 @@ -1293,10 +1295,7 @@ qemuDomainSecretStorageSourcePrepare(qemuDomainObjPr= ivate *priv, if (!src->auth && !hasEnc && src->ncookies =3D=3D 0) return 0; =20 - if (!(src->privateData =3D qemuDomainStorageSourcePrivateNew())) - return -1; - - srcPriv =3D QEMU_DOMAIN_STORAGE_SOURCE_PRIVATE(src); + srcPriv =3D qemuDomainStorageSourcePrivateFetch(src); =20 if (src->auth) { virSecretUsageType usageType =3D VIR_SECRET_USAGE_TYPE_ISCSI; @@ -1321,7 +1320,9 @@ qemuDomainSecretStorageSourcePrepare(qemuDomainObjPri= vate *priv, return -1; } =20 - if (src->ncookies && + /* when using nbdkit for http(s) sources, we don't need to pass cookie= s as + * qemu secrets */ + if (!srcPriv->nbdkitProcess && src->ncookies && virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV) && !(srcPriv->httpcookie =3D qemuDomainSecretStorageSourcePrepareCook= ies(priv, = src, @@ -1792,6 +1793,31 @@ qemuStorageSourcePrivateDataAssignSecinfo(qemuDomain= SecretInfo **secinfo, } =20 =20 +static int +qemuStorageSourcePrivateDataParseNbdkit(xmlNodePtr node, + xmlXPathContextPtr ctxt, + virStorageSource *src) +{ + qemuDomainStorageSourcePrivate *srcpriv =3D qemuDomainStorageSourcePri= vateFetch(src); + g_autofree char *pidfile =3D NULL; + g_autofree char *socketfile =3D NULL; + VIR_XPATH_NODE_AUTORESTORE(ctxt); + + ctxt->node =3D node; + + if (!(pidfile =3D virXPathString("string(./pidfile)", ctxt))) + return -1; + + if (!(socketfile =3D virXPathString("string(./socketfile)", ctxt))) + return -1; + + if (!srcpriv->nbdkitProcess) + srcpriv->nbdkitProcess =3D qemuNbdkitProcessLoad(src, pidfile, soc= ketfile); + + return 0; +} + + static int qemuStorageSourcePrivateDataParse(xmlXPathContextPtr ctxt, virStorageSource *src) @@ -1802,6 +1828,7 @@ qemuStorageSourcePrivateDataParse(xmlXPathContextPtr = ctxt, g_autofree char *httpcookiealias =3D NULL; g_autofree char *tlskeyalias =3D NULL; g_autofree char *thresholdEventWithIndex =3D NULL; + xmlNodePtr nbdkitnode =3D NULL; =20 src->nodestorage =3D virXPathString("string(./nodenames/nodename[@type= =3D'storage']/@name)", ctxt); src->nodeformat =3D virXPathString("string(./nodenames/nodename[@type= =3D'format']/@name)", ctxt); @@ -1845,6 +1872,10 @@ qemuStorageSourcePrivateDataParse(xmlXPathContextPtr= ctxt, virTristateBoolTypeFromString(thresholdEventWithIndex) =3D=3D VIR_= TRISTATE_BOOL_YES) src->thresholdEventWithIndex =3D true; =20 + if ((nbdkitnode =3D virXPathNode("nbdkit", ctxt))) { + if (qemuStorageSourcePrivateDataParseNbdkit(nbdkitnode, ctxt, src)= < 0) + return -1; + } return 0; } =20 @@ -1862,6 +1893,23 @@ qemuStorageSourcePrivateDataFormatSecinfo(virBuffer = *buf, } =20 =20 +static void +qemuStorageSourcePrivateDataFormatNbdkit(qemuNbdkitProcess *nbdkit, + virBuffer *buf) +{ + g_auto(virBuffer) childBuf =3D VIR_BUFFER_INIT_CHILD(buf); + + if (!nbdkit) + return; + + virBufferEscapeString(&childBuf, "%s\n", + nbdkit->pidfile); + virBufferEscapeString(&childBuf, "%s\n", + nbdkit->socketfile); + virXMLFormatElement(buf, "nbdkit", NULL, &childBuf); +} + + static int qemuStorageSourcePrivateDataFormat(virStorageSource *src, virBuffer *buf) @@ -1900,6 +1948,9 @@ qemuStorageSourcePrivateDataFormat(virStorageSource *= src, if (src->thresholdEventWithIndex) virBufferAddLit(buf, "\n"); =20 + if (srcPriv) + qemuStorageSourcePrivateDataFormatNbdkit(srcPriv->nbdkitProcess, b= uf); + return 0; } =20 @@ -4804,6 +4855,7 @@ qemuDomainValidateActualNetDef(const virDomainNetDef = *net, int qemuDomainValidateStorageSource(virStorageSource *src, virQEMUCaps *qemuCaps, + qemuNbdkitCaps *nbdkitCaps, bool maskBlockdev) { virStorageType actualType =3D virStorageSourceGetActualType(src); @@ -4899,7 +4951,8 @@ qemuDomainValidateStorageSource(virStorageSource *src, return -1; } =20 - if (!src->detected && !blockdev) { + if (!src->detected && !blockdev && + !qemuNbdkitCapsGet(nbdkitCaps, QEMU_NBDKIT_CAPS_PLUGIN_CURL)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("http cookies are not supported by this QEMU = binary")); return -1; @@ -4920,7 +4973,8 @@ qemuDomainValidateStorageSource(virStorageSource *src, return -1; } =20 - if (!src->detected && !blockdev) { + if (!src->detected && !blockdev && + !qemuNbdkitCapsGet(nbdkitCaps, QEMU_NBDKIT_CAPS_FILTER_READAHE= AD)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("readahead setting is not supported with this= QEMU binary")); return -1; @@ -4938,7 +4992,8 @@ qemuDomainValidateStorageSource(virStorageSource *src, return -1; } =20 - if (!src->detected && !blockdev) { + if (!src->detected && !blockdev && + !qemuNbdkitCapsGet(nbdkitCaps, QEMU_NBDKIT_CAPS_PLUGIN_CURL)) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", _("timeout setting is not supported with this Q= EMU binary")); return -1; @@ -7705,6 +7760,7 @@ qemuDomainDetermineDiskChain(virQEMUDriver *driver, bool isSD =3D qemuDiskBusIsSD(disk->bus); uid_t uid; gid_t gid; + g_autoptr(qemuNbdkitCaps) nbdkitcaps =3D qemuGetNbdkitCaps(priv->drive= r); =20 if (!disksrc) disksrc =3D disk->src; @@ -7787,7 +7843,8 @@ qemuDomainDetermineDiskChain(virQEMUDriver *driver, n->format =3D VIR_STORAGE_FILE_RAW; =20 /* mask-out blockdev for 'sd' disks */ - if (qemuDomainValidateStorageSource(n, priv->qemuCaps, isSD) < 0) + if (qemuDomainValidateStorageSource(n, priv->qemuCaps, + nbdkitcaps, isSD) < 0) return -1; =20 qemuDomainPrepareStorageSourceConfig(n, cfg, priv->qemuCaps); @@ -10112,6 +10169,29 @@ qemuDomainPrepareStorageSourceNFS(virStorageSource= *src) } =20 =20 +/* qemuPrepareStorageSourceNbdkit: + * @src: source for a disk + * + * If src is an network source that is managed by nbdkit, prepare data so = that + * nbdkit can be launched before the domain is started + */ +static void +qemuDomainPrepareStorageSourceNbdkit(virDomainDiskDef *disk, + virQEMUDriverConfig *cfg, + qemuDomainObjPrivate *priv) +{ + g_autoptr(qemuNbdkitCaps) nbdkit =3D qemuGetNbdkitCaps(priv->driver); + if (!nbdkit) + return; + + if (virStorageSourceGetActualType(disk->src) !=3D VIR_STORAGE_TYPE_NET= WORK) + return; + + qemuNbdkitInitStorageSource(nbdkit, disk->src, priv->libDir, + disk->info.alias, cfg->user, cfg->group); +} + + /* qemuProcessPrepareStorageSourceTLS: * @source: source for a disk * @cfg: driver configuration @@ -10828,7 +10908,9 @@ qemuDomainPrepareDiskSourceLegacy(virDomainDiskDef = *disk, qemuDomainObjPrivate *priv, virQEMUDriverConfig *cfg) { - if (qemuDomainValidateStorageSource(disk->src, priv->qemuCaps, true) <= 0) + g_autoptr(qemuNbdkitCaps) nbdkitcaps =3D qemuGetNbdkitCaps(priv->drive= r); + if (qemuDomainValidateStorageSource(disk->src, priv->qemuCaps, + nbdkitcaps, true) < 0) return -1; =20 qemuDomainPrepareStorageSourceConfig(disk->src, cfg, priv->qemuCaps); @@ -10846,6 +10928,8 @@ qemuDomainPrepareDiskSourceLegacy(virDomainDiskDef = *disk, priv) < 0) return -1; =20 + qemuDomainPrepareStorageSourceNbdkit(disk, cfg, priv); + return 0; } =20 @@ -10857,6 +10941,7 @@ qemuDomainPrepareStorageSourceBlockdevNodename(virD= omainDiskDef *disk, qemuDomainObjPrivate *priv, virQEMUDriverConfig *cfg) { + g_autoptr(qemuNbdkitCaps) nbdkitcaps =3D qemuGetNbdkitCaps(priv->drive= r); src->nodestorage =3D g_strdup_printf("%s-storage", nodenameprefix); src->nodeformat =3D g_strdup_printf("%s-format", nodenameprefix); =20 @@ -10866,7 +10951,8 @@ qemuDomainPrepareStorageSourceBlockdevNodename(virD= omainDiskDef *disk, if (src->encryption && src->encryption->engine =3D=3D VIR_STORAGE_ENCR= YPTION_ENGINE_DEFAULT) src->encryption->engine =3D VIR_STORAGE_ENCRYPTION_ENGINE_QEMU; =20 - if (qemuDomainValidateStorageSource(src, priv->qemuCaps, false) < 0) + if (qemuDomainValidateStorageSource(src, priv->qemuCaps, + nbdkitcaps, false) < 0) return -1; =20 qemuDomainPrepareStorageSourceConfig(src, cfg, priv->qemuCaps); @@ -10887,6 +10973,8 @@ qemuDomainPrepareStorageSourceBlockdevNodename(virD= omainDiskDef *disk, if (qemuDomainPrepareStorageSourceNFS(src) < 0) return -1; =20 + qemuDomainPrepareStorageSourceNbdkit(disk, cfg, priv); + return 0; } =20 diff --git a/src/qemu/qemu_domain.h b/src/qemu/qemu_domain.h index a87dfff1bb..34e1bb6fba 100644 --- a/src/qemu/qemu_domain.h +++ b/src/qemu/qemu_domain.h @@ -33,6 +33,7 @@ #include "qemu_conf.h" #include "qemu_capabilities.h" #include "qemu_migration_params.h" +#include "qemu_nbdkit.h" #include "qemu_slirp.h" #include "qemu_fd.h" #include "virchrdev.h" @@ -290,6 +291,9 @@ struct _qemuDomainStorageSourcePrivate { =20 /* key for decrypting TLS certificate */ qemuDomainSecretInfo *tlsKeySecret; + + /* an nbdkit process for serving network storage sources */ + qemuNbdkitProcess *nbdkitProcess; }; =20 virObject *qemuDomainStorageSourcePrivateNew(void); @@ -995,6 +999,7 @@ qemuDomainPrepareDiskSourceData(virDomainDiskDef *disk, int qemuDomainValidateStorageSource(virStorageSource *src, virQEMUCaps *qemuCaps, + qemuNbdkitCaps *nbdkitCaps, bool maskBlockdev); =20 =20 diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 3b5c3db67c..d1a972eb37 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -831,6 +831,9 @@ qemuStateInitialize(bool privileged, defsecmodel))) goto error; =20 + /* find whether nbdkit is available and query its capabilities */ + qemu_driver->nbdkitCaps =3D qemuNbdkitCapsQuery(); + /* If hugetlbfs is present, then we need to create a sub-directory wit= hin * it, since we can't assume the root mount point has permissions that * will let our spawned QEMU instances use it. */ @@ -14471,7 +14474,6 @@ qemuDomainBlockPivot(virQEMUDriver *driver, if (reuse && shallow && virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKDEV_SNAPSHOT= _ALLOW_WRITE_ONLY) && virStorageSourceHasBacking(disk->mirror)) { - if (!(chainattachdata =3D qemuBuildStorageSourceChainAttac= hPrepareBlockdev(disk->mirror->backingStore))) return -1; =20 diff --git a/src/qemu/qemu_extdevice.c b/src/qemu/qemu_extdevice.c index b8e3c1000a..0f9361b294 100644 --- a/src/qemu/qemu_extdevice.c +++ b/src/qemu/qemu_extdevice.c @@ -218,6 +218,14 @@ qemuExtDevicesStart(virQEMUDriver *driver, return -1; } =20 + for (i =3D 0; i < def->ndisks; i++) { + virDomainDiskDef *disk =3D def->disks[i]; + qemuDomainStorageSourcePrivate *priv =3D QEMU_DOMAIN_STORAGE_SOURC= E_PRIVATE(disk->src); + if (priv && priv->nbdkitProcess && + qemuNbdkitProcessStart(priv->nbdkitProcess, vm, driver) < 0) + return -1; + } + return 0; } =20 @@ -262,6 +270,14 @@ qemuExtDevicesStop(virQEMUDriver *driver, fs->fsdriver =3D=3D VIR_DOMAIN_FS_DRIVER_TYPE_VIRTIOFS) qemuVirtioFSStop(driver, vm, fs); } + + for (i =3D 0; i < def->ndisks; i++) { + virDomainDiskDef *disk =3D def->disks[i]; + qemuDomainStorageSourcePrivate *priv =3D QEMU_DOMAIN_STORAGE_SOURC= E_PRIVATE(disk->src); + + if (priv && priv->nbdkitProcess) + qemuNbdkitProcessStop(priv->nbdkitProcess); + } } =20 =20 @@ -324,6 +340,15 @@ qemuExtDevicesSetupCgroup(virQEMUDriver *driver, return -1; } =20 + for (i =3D 0; i < def->ndisks; i++) { + virDomainDiskDef *disk =3D def->disks[i]; + qemuDomainStorageSourcePrivate *priv =3D QEMU_DOMAIN_STORAGE_SOURC= E_PRIVATE(disk); + + if (priv && priv->nbdkitProcess && + qemuNbdkitProcessSetupCgroup(priv->nbdkitProcess, cgroup) < 0) + return -1; + } + for (i =3D 0; i < def->nfss; i++) { virDomainFSDef *fs =3D def->fss[i]; =20 diff --git a/src/qemu/qemu_nbdkit.c b/src/qemu/qemu_nbdkit.c new file mode 100644 index 0000000000..dd8759689c --- /dev/null +++ b/src/qemu/qemu_nbdkit.c @@ -0,0 +1,629 @@ +/* + * qemu_nbdkit.c: helpers for using nbdkit + * + * Copyright (C) 2021 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + */ + +#include +#include + +#include "vircommand.h" +#include "virerror.h" +#include "virlog.h" +#include "virpidfile.h" +#include "virsecureerase.h" +#include "qemu_block.h" +#include "qemu_conf.h" +#include "qemu_domain.h" +#include "qemu_driver.h" +#include "qemu_extdevice.h" +#include "qemu_nbdkit.h" +#include "qemu_security.h" + +#include + +#define VIR_FROM_THIS VIR_FROM_NBDKIT + +VIR_LOG_INIT("qemu.nbdkit"); + +struct _qemuNbdkitCaps { + GObject parent; + + char *path; + char *version; + + virBitmap *flags; +}; +G_DEFINE_TYPE(qemuNbdkitCaps, qemu_nbdkit_caps, G_TYPE_OBJECT); + + +static void +qemuNbdkitCheckCommandCap(qemuNbdkitCaps *nbdkit, + virCommand *cmd, + qemuNbdkitCapsFlags cap) +{ + if (virCommandRun(cmd, NULL) !=3D 0) + return; + + VIR_DEBUG("Setting nbdkit capability %i", cap); + ignore_value(virBitmapSetBit(nbdkit->flags, cap)); +} + + +static void +qemuNbdkitQueryFilter(qemuNbdkitCaps *nbdkit, + const char *filter, + qemuNbdkitCapsFlags cap) +{ + g_autoptr(virCommand) cmd =3D virCommandNewArgList(nbdkit->path, + "--version", + NULL); + + virCommandAddArgPair(cmd, "--filter", filter); + + /* use null plugin to check for filter */ + virCommandAddArg(cmd, "null"); + + qemuNbdkitCheckCommandCap(nbdkit, cmd, cap); +} + + +static void +qemuNbdkitQueryPlugin(qemuNbdkitCaps *nbdkit, + const char *plugin, + qemuNbdkitCapsFlags cap) +{ + g_autoptr(virCommand) cmd =3D virCommandNewArgList(nbdkit->path, + plugin, + "--version", + NULL); + + qemuNbdkitCheckCommandCap(nbdkit, cmd, cap); +} + + +static void +qemuNbdkitQueryPlugins(qemuNbdkitCaps *nbdkit) +{ + qemuNbdkitQueryPlugin(nbdkit, "curl", QEMU_NBDKIT_CAPS_PLUGIN_CURL); + qemuNbdkitQueryPlugin(nbdkit, "ssh", QEMU_NBDKIT_CAPS_PLUGIN_SSH); +} + + +static void +qemuNbdkitQueryFilters(qemuNbdkitCaps *nbdkit) +{ + qemuNbdkitQueryFilter(nbdkit, "readahead", + QEMU_NBDKIT_CAPS_FILTER_READAHEAD); +} + + +static int +qemuNbdkitQueryVersion(qemuNbdkitCaps *nbdkit) +{ + g_autoptr(virCommand) cmd =3D virCommandNewArgList(nbdkit->path, + "--version", + NULL); + + virCommandSetOutputBuffer(cmd, &nbdkit->version); + + if (virCommandRun(cmd, NULL) !=3D 0) + return -1; + + VIR_DEBUG("Got nbdkit version %s", nbdkit->version); + return 0; +} + + +static void qemuNbdkitCapsFinalize(GObject *object) +{ + qemuNbdkitCaps *nbdkit =3D QEMU_NBDKIT_CAPS(object); + + g_clear_pointer(&nbdkit->path, g_free); + g_clear_pointer(&nbdkit->version, g_free); + g_clear_pointer(&nbdkit->flags, virBitmapFree); + + G_OBJECT_CLASS(qemu_nbdkit_caps_parent_class)->finalize(object); +} + + +void qemu_nbdkit_caps_init(qemuNbdkitCaps *caps) +{ + caps->flags =3D virBitmapNew(QEMU_NBDKIT_CAPS_LAST); + caps->version =3D NULL; +} + + +static void +qemu_nbdkit_caps_class_init(qemuNbdkitCapsClass *klass) +{ + GObjectClass *obj =3D G_OBJECT_CLASS(klass); + + obj->finalize =3D qemuNbdkitCapsFinalize; +} + + +qemuNbdkitCaps * +qemuNbdkitCapsNew(const char *path) +{ + qemuNbdkitCaps *caps =3D g_object_new(QEMU_TYPE_NBDKIT_CAPS, NULL); + caps->path =3D g_strdup(path); + + return caps; +} + + +qemuNbdkitCaps * +qemuNbdkitCapsQuery(void) +{ + qemuNbdkitCaps *caps =3D NULL; + g_autofree char *path =3D virFindFileInPath("nbdkit"); + + if (!path) + return NULL; + + // make sure it's executable + if (!virFileIsExecutable(path)) { + virReportError(VIR_ERR_INTERNAL_ERROR, _("nbdkit '%s' is not execu= table"), + path); + return NULL; + } + + VIR_DEBUG("found nbdkit executable '%s'", path); + caps =3D qemuNbdkitCapsNew(path); + + qemuNbdkitQueryPlugins(caps); + qemuNbdkitQueryFilters(caps); + qemuNbdkitQueryVersion(caps); + + return caps; +} + + +bool +qemuNbdkitCapsGet(qemuNbdkitCaps *nbdkitCaps, qemuNbdkitCapsFlags flag) +{ + return virBitmapIsBitSet(nbdkitCaps->flags, flag); +} + + +void +qemuNbdkitCapsSet(qemuNbdkitCaps *nbdkitCaps, qemuNbdkitCapsFlags flag) +{ + ignore_value(virBitmapSetBit(nbdkitCaps->flags, flag)); +} + + +static int childProcess(int fd, uint8_t *output, size_t outputlen) +{ + if (safewrite(fd, output, outputlen) < 0) { + virReportSystemError(errno, "%s", + _("failed to write to socket for nbdkit")); + return -errno; + } + return 0; +} + + +/* Forks a process to write a password to a socket to the nbdkit process. + * Returns a file descriptor that can be passed to ndkit */ +static int qemuNbdkitForkHandler(uint8_t *output, size_t outputlen) +{ + enum { + PARENT_SOCKET =3D 0, + CHILD_SOCKET =3D 1 + }; + int pair[2] =3D { -1, -1 }; + pid_t pid; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) < 0) { + virReportSystemError(errno, "%s", + _("failed to create socket for nbdkit")); + return -errno; + } + + pid =3D virFork(); + + if (pid < 0) + return -errno; + + /* child process */ + if (pid =3D=3D 0) { + int ret =3D childProcess(pair[CHILD_SOCKET], output, outputlen); + _exit(ret); + } + + /* parent process */ + VIR_FORCE_CLOSE(pair[CHILD_SOCKET]); + + return pair[PARENT_SOCKET]; +} + + +/* Forks a process to write cookies to a socket to the nbdkit process. + * Returns a file descriptor that can be passed to ndkit */ +static int qemuNbdkitProcessForkCookieHandler(qemuNbdkitProcess *proc) +{ + g_autofree char *cookies =3D qemuBlockStorageSourceGetCookieString(pro= c->source); + + if (!cookies) + return 0; + + if ((proc->cookiefd =3D qemuNbdkitForkHandler((uint8_t*)cookies, strle= n(cookies))) < 0) + return -1; + + return 0; +} + + +/* Forks a process to write a password to a socket to the nbdkit process. + * Returns a file descriptor that can be passed to ndkit */ +static int qemuNbdkitProcessForkPasswordHandler(qemuNbdkitProcess *proc) +{ + g_autofree uint8_t *password =3D NULL; + size_t passwordlen =3D 0; + g_autoptr(virConnect) conn =3D virGetConnectSecret(); + + if (!proc->source->auth->username) + return 0; + + if (virSecretGetSecretString(conn, + &proc->source->auth->seclookupdef, + /* FIXME: for some reason auth->authType = is always NONE... */ + VIR_SECRET_USAGE_TYPE_ISCSI, + &password, + &passwordlen) < 0) + { + /* FIXME: message */ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("failed to get auth secret for storage")); + return -1; + } + + if ((proc->authfd =3D qemuNbdkitForkHandler(password, passwordlen)) < = 0) + return -1; + + return 0; +} + + +qemuNbdkitProcess * +qemuNbdkitProcessLoad(virStorageSource *source, + const char *pidfile, + const char *socketfile) +{ + int rc; + qemuNbdkitProcess *nbdkit =3D g_new0(qemuNbdkitProcess, 1); + + nbdkit->pidfile =3D g_strdup(pidfile); + nbdkit->socketfile =3D g_strdup(socketfile); + nbdkit->source =3D virObjectRef(source); + nbdkit->user =3D -1; + nbdkit->group =3D -1; + + if ((rc =3D virPidFileReadPath(nbdkit->pidfile, &nbdkit->pid)) < 0) + VIR_WARN("Failed to read pidfile %s", nbdkit->pidfile); + + return nbdkit; +} + + +static qemuNbdkitProcess * +qemuNbdkitProcessNew(qemuNbdkitCaps *caps, + virStorageSource *source, + char *statedir, + const char *alias, + uid_t user, + gid_t group + /*, char *selinux_label*/) +{ + qemuNbdkitProcess *proc =3D g_new0(qemuNbdkitProcess, 1); + g_autofree char *pidfile =3D g_strdup_printf("nbdkit-%s.pid", alias); + g_autofree char *socketfile =3D g_strdup_printf("nbdkit-%s.socket", al= ias); + + proc->caps =3D g_object_ref(caps); + /* weak reference -- source owns this object, so it will always outliv= e us */ + proc->source =3D source; + proc->user =3D user; + proc->group =3D group; + proc->pidfile =3D g_build_filename(statedir, pidfile, NULL); + proc->socketfile =3D g_build_filename(statedir, socketfile, NULL); + + return proc; +} + + +void +qemuNbdkitInitStorageSource(qemuNbdkitCaps *caps, + virStorageSource *source, + char *statedir, + const char *alias, + uid_t user, + gid_t group + /*, char *selinux_label*/) +{ + /* FIXME: onlytarget ??? */ + qemuDomainStorageSourcePrivate *srcPriv =3D qemuDomainStorageSourcePri= vateFetch(source); + + if (srcPriv->nbdkitProcess) + return; + + switch (source->protocol) { + case VIR_STORAGE_NET_PROTOCOL_HTTP: + case VIR_STORAGE_NET_PROTOCOL_HTTPS: + case VIR_STORAGE_NET_PROTOCOL_FTP: + case VIR_STORAGE_NET_PROTOCOL_FTPS: + case VIR_STORAGE_NET_PROTOCOL_TFTP: + if (!virBitmapIsBitSet(caps->flags, QEMU_NBDKIT_CAPS_PLUGIN_CU= RL)) + return; + break; + case VIR_STORAGE_NET_PROTOCOL_SSH: + if (!virBitmapIsBitSet(caps->flags, QEMU_NBDKIT_CAPS_PLUGIN_SS= H)) + return; + break; + case VIR_STORAGE_NET_PROTOCOL_NONE: + case VIR_STORAGE_NET_PROTOCOL_NBD: + case VIR_STORAGE_NET_PROTOCOL_RBD: + case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG: + case VIR_STORAGE_NET_PROTOCOL_GLUSTER: + case VIR_STORAGE_NET_PROTOCOL_ISCSI: + case VIR_STORAGE_NET_PROTOCOL_VXHS: + case VIR_STORAGE_NET_PROTOCOL_NFS: + case VIR_STORAGE_NET_PROTOCOL_LAST: + return; + } + srcPriv->nbdkitProcess =3D qemuNbdkitProcessNew(caps, source, statedir= , alias, user, group); +} + + +static void +qemuNbdkitProcessBuildCommandCurl(qemuNbdkitProcess *proc, + virCommand *cmd) +{ + g_autoptr(virURI) uri =3D qemuBlockStorageSourceGetURI(proc->source); + g_autofree char *uristring =3D virURIFormat(uri); + + /* nbdkit plugin name */ + virCommandAddArg(cmd, "curl"); + virCommandAddArgPair(cmd, "protocols", + virStorageNetProtocolTypeToString(proc->source->p= rotocol)); + virCommandAddArgPair(cmd, "url", uristring); + + if (proc->source->auth) { + virCommandAddArgPair(cmd, "user", + proc->source->auth->username); + } + + // FIXME: if (srcPriv->secinfo)??? + if (proc->authfd > 0) { + /* nbdkit auth parameter accepts a variation where nbdkit + * will read the cookies from a file descriptor: password=3D-FD */ + g_autofree char *fdfmt =3D g_strdup_printf("-%i", proc->authfd); + virCommandAddArgPair(cmd, "password", fdfmt); + virCommandPassFD(cmd, proc->authfd, VIR_COMMAND_PASS_FD_CLOSE_PARE= NT); + } + + if (proc->cookiefd > 0) { + /* nbdkit cookie parameter accepts a variation where nbdkit + * will read the cookies from a file descriptor: cookie=3D-FD */ + g_autofree char *fdfmt =3D g_strdup_printf("-%i", proc->cookiefd); + virCommandAddArgPair(cmd, "cookie", fdfmt); + virCommandPassFD(cmd, proc->cookiefd, VIR_COMMAND_PASS_FD_CLOSE_PA= RENT); + } + + if (proc->source->sslverify =3D=3D VIR_TRISTATE_BOOL_NO) { + virCommandAddArgPair(cmd, "sslverify", "false"); + } + + if (proc->source->timeout > 0) { + g_autofree char *timeout =3D g_strdup_printf("%llu", proc->source-= >timeout); + virCommandAddArgPair(cmd, "timeout", timeout); + } +} + + +static void +qemuNbdkitProcessBuildCommandSSH(qemuNbdkitProcess *proc, + virCommand *cmd) +{ + char *user =3D NULL; + virStorageNetHostDef *host =3D &proc->source->hosts[0]; + + /* nbdkit plugin name */ + virCommandAddArg(cmd, "ssh"); + + virCommandAddArgPair(cmd, "host", g_strdup(host->name)); + virCommandAddArgPair(cmd, "port", g_strdup_printf("%u", + host->port)); + virCommandAddArgPair(cmd, "path", g_strdup(proc->source->path)); + + if (proc->source->auth) { + user =3D g_strdup(proc->source->auth->username); + } else if (proc->source->ssh_user) { + user =3D g_strdup(proc->source->ssh_user); + } + + if (user) { + virCommandAddArgPair(cmd, "user", user); + } + + if (proc->source->ssh_host_key_check_disabled) { + virCommandAddArgPair(cmd, "verify-remote-host", + g_strdup("false")); + } +} + + +static virCommand * +qemuNbdkitProcessBuildCommand(qemuNbdkitProcess *proc) +{ + g_autoptr(virCommand) cmd =3D virCommandNewArgList(proc->caps->path, + "--exit-with-parent", + "--unix", + proc->socketfile, + "--foreground", + "--pidfile", + proc->pidfile, + "--verbose", + //"--selinux-label", + //selinux_label, + NULL); + + if (proc->source->readonly) + virCommandAddArg(cmd, "--readonly"); + + if (qemuNbdkitCapsGet(proc->caps, QEMU_NBDKIT_CAPS_FILTER_READAHEAD) && + proc->source->readahead > 0) + virCommandAddArgPair(cmd, "--filter", "readahead"); + + switch (proc->source->protocol) { + case VIR_STORAGE_NET_PROTOCOL_HTTP: + case VIR_STORAGE_NET_PROTOCOL_HTTPS: + case VIR_STORAGE_NET_PROTOCOL_FTP: + case VIR_STORAGE_NET_PROTOCOL_FTPS: + case VIR_STORAGE_NET_PROTOCOL_TFTP: + qemuNbdkitProcessBuildCommandCurl(proc, cmd); + break; + case VIR_STORAGE_NET_PROTOCOL_SSH: + qemuNbdkitProcessBuildCommandSSH(proc, cmd); + break; + + case VIR_STORAGE_NET_PROTOCOL_NONE: + case VIR_STORAGE_NET_PROTOCOL_NBD: + case VIR_STORAGE_NET_PROTOCOL_RBD: + case VIR_STORAGE_NET_PROTOCOL_SHEEPDOG: + case VIR_STORAGE_NET_PROTOCOL_GLUSTER: + case VIR_STORAGE_NET_PROTOCOL_ISCSI: + case VIR_STORAGE_NET_PROTOCOL_VXHS: + case VIR_STORAGE_NET_PROTOCOL_NFS: + case VIR_STORAGE_NET_PROTOCOL_LAST: + virReportError(VIR_ERR_NO_SUPPORT, + _("protocol '%s' is not supported by nbdkit"), + virStorageNetProtocolTypeToString(proc->source-= >protocol)); + return NULL; + } + + virCommandDaemonize(cmd); + + return g_steal_pointer(&cmd); +} + + +void +qemuNbdkitProcessFree(qemuNbdkitProcess *proc) +{ + if (virProcessKillPainfully(proc->pid, true) < 0) + VIR_WARN("Unable to kill nbdkit process"); + + unlink(proc->pidfile); + g_clear_pointer(&proc->pidfile, g_free); + unlink(proc->socketfile); + g_clear_pointer(&proc->socketfile, g_free); + VIR_FORCE_CLOSE(proc->cookiefd); + VIR_FORCE_CLOSE(proc->authfd); + g_clear_object(&proc->caps); + g_free(proc); +} + + +int +qemuNbdkitProcessSetupCgroup(qemuNbdkitProcess *proc, + virCgroup *cgroup) +{ + return virCgroupAddProcess(cgroup, proc->pid); +} + + +/* FIXME: selinux permissions errors */ +int +qemuNbdkitProcessStart(qemuNbdkitProcess *proc, + virDomainObj *vm, + virQEMUDriver *driver) +{ + g_autoptr(virCommand) cmd =3D NULL; + int rc; + int exitstatus =3D 0; + int cmdret =3D 0; + unsigned int loops =3D 0; + int errfd =3D -1; + + if (qemuNbdkitProcessForkCookieHandler(proc) < 0) + return -1; + + if (qemuNbdkitProcessForkPasswordHandler(proc) < 0) + return -1; + + if (!(cmd =3D qemuNbdkitProcessBuildCommand(proc))) + return -1; + + virCommandSetErrorFD(cmd, &errfd); + + if (qemuExtDeviceLogCommand(driver, vm, cmd, "nbdkit") < 0) + goto error; + + if (qemuSecurityCommandRun(driver, vm, cmd, proc->user, proc->group, &= exitstatus, &cmdret) < 0) + goto error; + + if (cmdret < 0 || exitstatus !=3D 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Could not start 'nbdkit'. exitstatus: %d"), exit= status); + goto error; + } + + /* Wait for the pid file to appear. The file doesn't appear until nbdk= it is + * ready to accept connections to the socket */ + while (!virFileExists(proc->pidfile)) { + VIR_DEBUG("waiting for nbdkit pidfile %s: %u", proc->pidfile, loop= s); + /* wait for 100ms before checking again, but don't do it for ever = */ + if (errno =3D=3D ENOENT && loops < 10) { + g_usleep(100 * 1000); + loops++; + } else { + char errbuf[1024] =3D { 0 }; + if (errfd && saferead(errfd, errbuf, sizeof(errbuf) - 1) > 0) { + virReportError(VIR_ERR_OPERATION_FAILED, + _("nbdkit failed to start: %s"), errbuf= ); + } else { + virReportSystemError(errno, "%s", + _("Gave up waiting for nbdkit to star= t")); + } + goto error; + } + } + + if ((rc =3D virPidFileReadPath(proc->pidfile, &proc->pid)) < 0) { + virReportSystemError(-rc, + _("Failed to read pidfile %s"), + proc->pidfile); + goto error; + } + + return 0; + + error: + if (proc->pid) + virProcessKillPainfully(proc->pid, true); + return -1; +} + + +int +qemuNbdkitProcessStop(qemuNbdkitProcess *proc) +{ + return virProcessKillPainfully(proc->pid, true); +} diff --git a/src/qemu/qemu_nbdkit.h b/src/qemu/qemu_nbdkit.h new file mode 100644 index 0000000000..628b5010cc --- /dev/null +++ b/src/qemu/qemu_nbdkit.h @@ -0,0 +1,89 @@ +/* + * qemu_nbdkit.h: helpers for using nbdkit + * + * Copyright (C) 2021 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * . + * + */ + +#pragma once + +#include "internal.h" +#include "virbitmap.h" +#include "vircgroup.h" +#include "vircommand.h" +#include "virstorageobj.h" +#include "viruri.h" + +typedef struct _qemuNbdkitCaps qemuNbdkitCaps; +typedef struct _qemuNbdkitProcess qemuNbdkitProcess; + +typedef enum { + QEMU_NBDKIT_CAPS_PLUGIN_CURL, + QEMU_NBDKIT_CAPS_PLUGIN_SSH, + QEMU_NBDKIT_CAPS_FILTER_READAHEAD, + QEMU_NBDKIT_CAPS_LAST, +} qemuNbdkitCapsFlags; + +qemuNbdkitCaps* qemuNbdkitCapsQuery(void); + +qemuNbdkitCaps* qemuNbdkitCapsNew(const char *path); + +void qemuNbdkitInitStorageSource(qemuNbdkitCaps *nbdkitCaps, + virStorageSource *source, + char *statedir, + const char *alias, + uid_t user, + gid_t group + /*, char *selinux_label*/); + +bool qemuNbdkitCapsGet(qemuNbdkitCaps *nbdkitCaps, qemuNbdkitCapsFlags fla= g); + +void qemuNbdkitCapsSet(qemuNbdkitCaps *nbdkitCaps, qemuNbdkitCapsFlags fla= g); + +#define QEMU_TYPE_NBDKIT_CAPS qemu_nbdkit_caps_get_type() +G_DECLARE_FINAL_TYPE(qemuNbdkitCaps, qemu_nbdkit_caps, QEMU, NBDKIT_CAPS, = GObject); + +struct _qemuNbdkitProcess { + qemuNbdkitCaps *caps; + virStorageSource *source; + + char *pidfile; + char *socketfile; + int cookiefd; + int authfd; + uid_t user; + gid_t group; + pid_t pid; +}; + +typedef struct _virQEMUDriver virQEMUDriver; + +int qemuNbdkitProcessStart(qemuNbdkitProcess *proc, + virDomainObj *vm, + virQEMUDriver *driver); + +qemuNbdkitProcess * qemuNbdkitProcessLoad(virStorageSource *source, + const char *pidfile, + const char *socketfile); + +int qemuNbdkitProcessSetupCgroup(qemuNbdkitProcess *proc, virCgroup *cgrou= p); + +int qemuNbdkitProcessStop(qemuNbdkitProcess *proc); + +void qemuNbdkitProcessFree(qemuNbdkitProcess *proc); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuNbdkitProcess, qemuNbdkitProcessFree); diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 39210ba65b..b6cc75b651 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -602,7 +602,8 @@ qemuValidateDomainDefPM(const virDomainDef *def, =20 static int qemuValidateDomainDefNvram(const virDomainDef *def, - virQEMUCaps *qemuCaps) + virQEMUCaps *qemuCaps, + qemuNbdkitCaps *nbdkitCaps) { virStorageSource *src =3D def->os.loader->nvram; =20 @@ -655,7 +656,7 @@ qemuValidateDomainDefNvram(const virDomainDef *def, return -1; } =20 - if (qemuDomainValidateStorageSource(src, qemuCaps, false) < 0) + if (qemuDomainValidateStorageSource(src, qemuCaps, nbdkitCaps, false) = < 0) return -1; =20 return 0; @@ -664,7 +665,8 @@ qemuValidateDomainDefNvram(const virDomainDef *def, =20 static int qemuValidateDomainDefBoot(const virDomainDef *def, - virQEMUCaps *qemuCaps) + virQEMUCaps *qemuCaps, + qemuNbdkitCaps *nbdkitCaps) { if (def->os.loader) { if (def->os.loader->secure =3D=3D VIR_TRISTATE_BOOL_YES) { @@ -695,7 +697,7 @@ qemuValidateDomainDefBoot(const virDomainDef *def, } } =20 - if (qemuValidateDomainDefNvram(def, qemuCaps) < 0) + if (qemuValidateDomainDefNvram(def, qemuCaps, nbdkitCaps) < 0) return -1; } =20 @@ -1167,6 +1169,7 @@ qemuValidateDomainDef(const virDomainDef *def, virQEMUDriver *driver =3D opaque; g_autoptr(virQEMUCaps) qemuCapsLocal =3D NULL; virQEMUCaps *qemuCaps =3D parseOpaque; + g_autoptr(qemuNbdkitCaps) nbdkitCaps =3D qemuGetNbdkitCaps(driver); size_t i; =20 if (!qemuCaps) { @@ -1277,7 +1280,7 @@ qemuValidateDomainDef(const virDomainDef *def, if (qemuValidateDomainDefPM(def, qemuCaps) < 0) return -1; =20 - if (qemuValidateDomainDefBoot(def, qemuCaps) < 0) + if (qemuValidateDomainDefBoot(def, qemuCaps, nbdkitCaps) < 0) return -1; =20 if (qemuValidateDomainVCpuTopology(def, qemuCaps) < 0) @@ -3240,7 +3243,8 @@ qemuValidateDomainDeviceDefDiskTransient(const virDom= ainDiskDef *disk, int qemuValidateDomainDeviceDefDisk(const virDomainDiskDef *disk, const virDomainDef *def, - virQEMUCaps *qemuCaps) + virQEMUCaps *qemuCaps, + qemuNbdkitCaps *nbdkitCaps) { const char *driverName =3D virDomainDiskGetDriver(disk); bool isSD =3D qemuDiskBusIsSD(disk->bus); @@ -3287,7 +3291,7 @@ qemuValidateDomainDeviceDefDisk(const virDomainDiskDe= f *disk, =20 for (n =3D disk->src; virStorageSourceIsBacking(n); n =3D n->backingSt= ore) { /* blockdev support is masked out for 'sd' disks */ - if (qemuDomainValidateStorageSource(n, qemuCaps, isSD) < 0) + if (qemuDomainValidateStorageSource(n, qemuCaps, nbdkitCaps, isSD)= < 0) return -1; } =20 @@ -5234,6 +5238,7 @@ qemuValidateDomainDeviceDef(const virDomainDeviceDef = *dev, virQEMUDriver *driver =3D opaque; g_autoptr(virQEMUCaps) qemuCapsLocal =3D NULL; virQEMUCaps *qemuCaps =3D parseOpaque; + g_autoptr(qemuNbdkitCaps) nbdkitcaps =3D qemuGetNbdkitCaps(driver); =20 if (!qemuCaps) { if (!(qemuCapsLocal =3D virQEMUCapsCacheLookup(driver->qemuCapsCac= he, @@ -5273,7 +5278,8 @@ qemuValidateDomainDeviceDef(const virDomainDeviceDef = *dev, return qemuValidateDomainDeviceDefVideo(dev->data.video, qemuCaps); =20 case VIR_DOMAIN_DEVICE_DISK: - return qemuValidateDomainDeviceDefDisk(dev->data.disk, def, qemuCa= ps); + return qemuValidateDomainDeviceDefDisk(dev->data.disk, def, qemuCa= ps, + nbdkitcaps); =20 case VIR_DOMAIN_DEVICE_CONTROLLER: return qemuValidateDomainDeviceDefController(dev->data.controller,= def, diff --git a/src/qemu/qemu_validate.h b/src/qemu/qemu_validate.h index e06a43b8e3..1498a978ed 100644 --- a/src/qemu/qemu_validate.h +++ b/src/qemu/qemu_validate.h @@ -21,6 +21,7 @@ #pragma once =20 #include "qemu_capabilities.h" +#include "qemu_nbdkit.h" =20 int qemuValidateDomainDef(const virDomainDef *def, @@ -30,7 +31,8 @@ qemuValidateDomainDef(const virDomainDef *def, int qemuValidateDomainDeviceDefDisk(const virDomainDiskDef *disk, const virDomainDef *def, - virQEMUCaps *qemuCaps); + virQEMUCaps *qemuCaps, + qemuNbdkitCaps *nbdkitCaps); =20 int qemuValidateDomainDeviceDef(const virDomainDeviceDef *dev, diff --git a/src/util/virerror.c b/src/util/virerror.c index d114c0a346..5b665931ca 100644 --- a/src/util/virerror.c +++ b/src/util/virerror.c @@ -145,6 +145,7 @@ VIR_ENUM_IMPL(virErrorDomain, "TPM", /* 70 */ "BPF", "Cloud-Hypervisor Driver", + "Nbdkit", ); =20 =20 diff --git a/tests/qemublocktest.c b/tests/qemublocktest.c index 57116c930b..18dd1f61fe 100644 --- a/tests/qemublocktest.c +++ b/tests/qemublocktest.c @@ -280,7 +280,8 @@ testQemuDiskXMLToProps(const void *opaque) =20 virDomainDiskInsert(vmdef, disk); =20 - if (qemuValidateDomainDeviceDefDisk(disk, vmdef, data->qemuCaps) < 0) { + /* FIXME: test with nbdkit */ + if (qemuValidateDomainDeviceDefDisk(disk, vmdef, data->qemuCaps, NULL)= < 0) { VIR_TEST_VERBOSE("invalid configuration for disk"); return -1; } @@ -294,7 +295,8 @@ testQemuDiskXMLToProps(const void *opaque) if (testQemuDiskXMLToJSONFakeSecrets(n) < 0) return -1; =20 - if (qemuDomainValidateStorageSource(n, data->qemuCaps, false) < 0) + /* FIXME: test with nbdkit */ + if (qemuDomainValidateStorageSource(n, data->qemuCaps, NULL, false= ) < 0) return -1; =20 qemuDomainPrepareDiskSourceData(disk, n); @@ -519,7 +521,7 @@ testQemuImageCreate(const void *opaque) src->capacity =3D UINT_MAX * 2ULL; src->physical =3D UINT_MAX + 1ULL; =20 - if (qemuDomainValidateStorageSource(src, data->qemuCaps, false) < 0) + if (qemuDomainValidateStorageSource(src, data->qemuCaps, NULL, false) = < 0) return -1; =20 if (qemuBlockStorageSourceCreateGetStorageProps(src, &protocolprops) <= 0) diff --git a/tests/qemustatusxml2xmldata/modern-in.xml b/tests/qemustatusxm= l2xmldata/modern-in.xml index 7759034f7a..49b005cfc7 100644 --- a/tests/qemustatusxml2xmldata/modern-in.xml +++ b/tests/qemustatusxml2xmldata/modern-in.xml @@ -337,7 +337,6 @@ - diff --git a/tests/qemuxml2argvdata/disk-cdrom-network-nbdkit.x86_64-latest= .args b/tests/qemuxml2argvdata/disk-cdrom-network-nbdkit.x86_64-latest.args new file mode 100644 index 0000000000..c944a3ead4 --- /dev/null +++ b/tests/qemuxml2argvdata/disk-cdrom-network-nbdkit.x86_64-latest.args @@ -0,0 +1,42 @@ +LC_ALL=3DC \ +PATH=3D/bin \ +HOME=3D/tmp/lib/domain--1-QEMUGuest1 \ +USER=3Dtest \ +LOGNAME=3Dtest \ +XDG_DATA_HOME=3D/tmp/lib/domain--1-QEMUGuest1/.local/share \ +XDG_CACHE_HOME=3D/tmp/lib/domain--1-QEMUGuest1/.cache \ +XDG_CONFIG_HOME=3D/tmp/lib/domain--1-QEMUGuest1/.config \ +/usr/bin/qemu-system-x86_64 \ +-name guest=3DQEMUGuest1,debug-threads=3Don \ +-S \ +-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/tm= p/lib/domain--1-QEMUGuest1/master-key.aes"}' \ +-machine pc,usb=3Doff,dump-guest-core=3Doff,memory-backend=3Dpc.ram \ +-accel kvm \ +-cpu qemu64 \ +-m 1024 \ +-object '{"qom-type":"memory-backend-ram","id":"pc.ram","size":1073741824}= ' \ +-overcommit mem-lock=3Doff \ +-smp 1,sockets=3D1,cores=3D1,threads=3D1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=3Dcharmonitor,fd=3D1729,server=3Don,wait=3Doff \ +-mon chardev=3Dcharmonitor,id=3Dmonitor,mode=3Dcontrol \ +-rtc base=3Dutc \ +-no-shutdown \ +-boot strict=3Don \ +-device '{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0= x2"}' \ +-blockdev '{"driver":"nbd","server":{"type":"unix","path":"/tmp/lib/domain= --1-QEMUGuest1/nbdkit-ide0-0-0.socket"},"node-name":"libvirt-3-storage","au= to-read-only":true,"discard":"unmap"}' \ +-blockdev '{"node-name":"libvirt-3-format","read-only":true,"driver":"raw"= ,"file":"libvirt-3-storage"}' \ +-device '{"driver":"ide-cd","bus":"ide.0","unit":0,"drive":"libvirt-3-form= at","id":"ide0-0-0","bootindex":1}' \ +-blockdev '{"driver":"nbd","server":{"type":"unix","path":"/tmp/lib/domain= --1-QEMUGuest1/nbdkit-ide0-0-1.socket"},"node-name":"libvirt-2-storage","au= to-read-only":true,"discard":"unmap"}' \ +-blockdev '{"node-name":"libvirt-2-format","read-only":true,"driver":"raw"= ,"file":"libvirt-2-storage"}' \ +-device '{"driver":"ide-cd","bus":"ide.0","unit":1,"drive":"libvirt-2-form= at","id":"ide0-0-1"}' \ +-blockdev '{"driver":"nbd","server":{"type":"unix","path":"/tmp/lib/domain= --1-QEMUGuest1/nbdkit-ide0-1-0.socket"},"node-name":"libvirt-1-storage","au= to-read-only":true,"discard":"unmap"}' \ +-blockdev '{"node-name":"libvirt-1-format","read-only":true,"driver":"raw"= ,"file":"libvirt-1-storage"}' \ +-device '{"driver":"ide-cd","bus":"ide.1","unit":0,"drive":"libvirt-1-form= at","id":"ide0-1-0"}' \ +-audiodev '{"id":"audio1","driver":"none"}' \ +-device '{"driver":"virtio-balloon-pci","id":"balloon0","bus":"pci.0","add= r":"0x2"}' \ +-sandbox on,obsolete=3Ddeny,elevateprivileges=3Ddeny,spawn=3Ddeny,resource= control=3Ddeny \ +-msg timestamp=3Don diff --git a/tests/qemuxml2argvdata/disk-cdrom-network-nbdkit.xml b/tests/q= emuxml2argvdata/disk-cdrom-network-nbdkit.xml new file mode 120000 index 0000000000..55f677546f --- /dev/null +++ b/tests/qemuxml2argvdata/disk-cdrom-network-nbdkit.xml @@ -0,0 +1 @@ +disk-cdrom-network.xml \ No newline at end of file diff --git a/tests/qemuxml2argvdata/disk-network-http-nbdkit.x86_64-latest.= args b/tests/qemuxml2argvdata/disk-network-http-nbdkit.x86_64-latest.args new file mode 100644 index 0000000000..378dcc3e62 --- /dev/null +++ b/tests/qemuxml2argvdata/disk-network-http-nbdkit.x86_64-latest.args @@ -0,0 +1,45 @@ +LC_ALL=3DC \ +PATH=3D/bin \ +HOME=3D/tmp/lib/domain--1-QEMUGuest1 \ +USER=3Dtest \ +LOGNAME=3Dtest \ +XDG_DATA_HOME=3D/tmp/lib/domain--1-QEMUGuest1/.local/share \ +XDG_CACHE_HOME=3D/tmp/lib/domain--1-QEMUGuest1/.cache \ +XDG_CONFIG_HOME=3D/tmp/lib/domain--1-QEMUGuest1/.config \ +/usr/bin/qemu-system-x86_64 \ +-name guest=3DQEMUGuest1,debug-threads=3Don \ +-S \ +-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/tm= p/lib/domain--1-QEMUGuest1/master-key.aes"}' \ +-machine pc,usb=3Doff,dump-guest-core=3Doff,memory-backend=3Dpc.ram \ +-accel kvm \ +-cpu qemu64 \ +-m 214 \ +-object '{"qom-type":"memory-backend-ram","id":"pc.ram","size":224395264}'= \ +-overcommit mem-lock=3Doff \ +-smp 1,sockets=3D1,cores=3D1,threads=3D1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=3Dcharmonitor,fd=3D1729,server=3Don,wait=3Doff \ +-mon chardev=3Dcharmonitor,id=3Dmonitor,mode=3Dcontrol \ +-rtc base=3Dutc \ +-no-shutdown \ +-no-acpi \ +-boot strict=3Don \ +-device '{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0= x2"}' \ +-blockdev '{"driver":"nbd","server":{"type":"unix","path":"/tmp/lib/domain= --1-QEMUGuest1/nbdkit-virtio-disk0.socket"},"node-name":"libvirt-4-storage"= ,"auto-read-only":true,"discard":"unmap"}' \ +-blockdev '{"node-name":"libvirt-4-format","read-only":false,"driver":"raw= ","file":"libvirt-4-storage"}' \ +-device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x2","drive":"li= bvirt-4-format","id":"virtio-disk0","bootindex":1}' \ +-blockdev '{"driver":"nbd","server":{"type":"unix","path":"/tmp/lib/domain= --1-QEMUGuest1/nbdkit-virtio-disk1.socket"},"node-name":"libvirt-3-storage"= ,"auto-read-only":true,"discard":"unmap"}' \ +-blockdev '{"node-name":"libvirt-3-format","read-only":false,"driver":"raw= ","file":"libvirt-3-storage"}' \ +-device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x3","drive":"li= bvirt-3-format","id":"virtio-disk1"}' \ +-blockdev '{"driver":"nbd","server":{"type":"unix","path":"/tmp/lib/domain= --1-QEMUGuest1/nbdkit-virtio-disk2.socket"},"node-name":"libvirt-2-storage"= ,"auto-read-only":true,"discard":"unmap"}' \ +-blockdev '{"node-name":"libvirt-2-format","read-only":false,"driver":"raw= ","file":"libvirt-2-storage"}' \ +-device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x4","drive":"li= bvirt-2-format","id":"virtio-disk2"}' \ +-blockdev '{"driver":"nbd","server":{"type":"unix","path":"/tmp/lib/domain= --1-QEMUGuest1/nbdkit-virtio-disk3.socket"},"node-name":"libvirt-1-storage"= ,"auto-read-only":true,"discard":"unmap"}' \ +-blockdev '{"node-name":"libvirt-1-format","read-only":false,"driver":"raw= ","file":"libvirt-1-storage"}' \ +-device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x5","drive":"li= bvirt-1-format","id":"virtio-disk3"}' \ +-audiodev '{"id":"audio1","driver":"none"}' \ +-sandbox on,obsolete=3Ddeny,elevateprivileges=3Ddeny,spawn=3Ddeny,resource= control=3Ddeny \ +-msg timestamp=3Don diff --git a/tests/qemuxml2argvdata/disk-network-http-nbdkit.xml b/tests/qe= muxml2argvdata/disk-network-http-nbdkit.xml new file mode 120000 index 0000000000..6a05204e8a --- /dev/null +++ b/tests/qemuxml2argvdata/disk-network-http-nbdkit.xml @@ -0,0 +1 @@ +disk-network-http.xml \ No newline at end of file diff --git a/tests/qemuxml2argvdata/disk-network-source-curl-nbdkit.x86_64-= latest.args b/tests/qemuxml2argvdata/disk-network-source-curl-nbdkit.x86_64= -latest.args new file mode 100644 index 0000000000..2410d8dfa5 --- /dev/null +++ b/tests/qemuxml2argvdata/disk-network-source-curl-nbdkit.x86_64-latest.= args @@ -0,0 +1,49 @@ +LC_ALL=3DC \ +PATH=3D/bin \ +HOME=3D/tmp/lib/domain--1-QEMUGuest1 \ +USER=3Dtest \ +LOGNAME=3Dtest \ +XDG_DATA_HOME=3D/tmp/lib/domain--1-QEMUGuest1/.local/share \ +XDG_CACHE_HOME=3D/tmp/lib/domain--1-QEMUGuest1/.cache \ +XDG_CONFIG_HOME=3D/tmp/lib/domain--1-QEMUGuest1/.config \ +/usr/bin/qemu-system-x86_64 \ +-name guest=3DQEMUGuest1,debug-threads=3Don \ +-S \ +-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/tm= p/lib/domain--1-QEMUGuest1/master-key.aes"}' \ +-machine pc,usb=3Doff,dump-guest-core=3Doff,memory-backend=3Dpc.ram \ +-accel tcg \ +-cpu qemu64 \ +-m 214 \ +-object '{"qom-type":"memory-backend-ram","id":"pc.ram","size":224395264}'= \ +-overcommit mem-lock=3Doff \ +-smp 1,sockets=3D1,cores=3D1,threads=3D1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=3Dcharmonitor,fd=3D1729,server=3Don,wait=3Doff \ +-mon chardev=3Dcharmonitor,id=3Dmonitor,mode=3Dcontrol \ +-rtc base=3Dutc \ +-no-shutdown \ +-no-acpi \ +-boot strict=3Don \ +-device '{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0= x2"}' \ +-device '{"driver":"ahci","id":"sata0","bus":"pci.0","addr":"0x2"}' \ +-blockdev '{"driver":"nbd","server":{"type":"unix","path":"/tmp/lib/domain= --1-QEMUGuest1/nbdkit-virtio-disk0.socket"},"node-name":"libvirt-5-storage"= ,"auto-read-only":true,"discard":"unmap"}' \ +-blockdev '{"node-name":"libvirt-5-format","read-only":true,"driver":"raw"= ,"file":"libvirt-5-storage"}' \ +-device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x3","drive":"li= bvirt-5-format","id":"virtio-disk0","bootindex":1}' \ +-blockdev '{"driver":"nbd","server":{"type":"unix","path":"/tmp/lib/domain= --1-QEMUGuest1/nbdkit-virtio-disk4.socket"},"node-name":"libvirt-4-storage"= ,"auto-read-only":true,"discard":"unmap"}' \ +-blockdev '{"node-name":"libvirt-4-format","read-only":false,"driver":"luk= s","key-secret":"libvirt-4-format-encryption-secret0","file":"libvirt-4-sto= rage"}' \ +-device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x4","drive":"li= bvirt-4-format","id":"virtio-disk4"}' \ +-blockdev '{"driver":"nbd","server":{"type":"unix","path":"/tmp/lib/domain= --1-QEMUGuest1/nbdkit-sata0-0-1.socket"},"node-name":"libvirt-3-storage","a= uto-read-only":true,"discard":"unmap"}' \ +-blockdev '{"node-name":"libvirt-3-format","read-only":true,"driver":"raw"= ,"file":"libvirt-3-storage"}' \ +-device '{"driver":"ide-cd","bus":"sata0.1","drive":"libvirt-3-format","id= ":"sata0-0-1"}' \ +-blockdev '{"driver":"nbd","server":{"type":"unix","path":"/tmp/lib/domain= --1-QEMUGuest1/nbdkit-sata0-0-2.socket"},"node-name":"libvirt-2-storage","a= uto-read-only":true,"discard":"unmap"}' \ +-blockdev '{"node-name":"libvirt-2-format","read-only":true,"driver":"raw"= ,"file":"libvirt-2-storage"}' \ +-device '{"driver":"ide-cd","bus":"sata0.2","drive":"libvirt-2-format","id= ":"sata0-0-2"}' \ +-blockdev '{"driver":"nbd","server":{"type":"unix","path":"/tmp/lib/domain= --1-QEMUGuest1/nbdkit-sata0-0-3.socket"},"node-name":"libvirt-1-storage","a= uto-read-only":true,"discard":"unmap"}' \ +-blockdev '{"node-name":"libvirt-1-format","read-only":true,"driver":"raw"= ,"file":"libvirt-1-storage"}' \ +-device '{"driver":"ide-cd","bus":"sata0.3","drive":"libvirt-1-format","id= ":"sata0-0-3"}' \ +-audiodev '{"id":"audio1","driver":"none"}' \ +-sandbox on,obsolete=3Ddeny,elevateprivileges=3Ddeny,spawn=3Ddeny,resource= control=3Ddeny \ +-msg timestamp=3Don diff --git a/tests/qemuxml2argvdata/disk-network-source-curl-nbdkit.xml b/t= ests/qemuxml2argvdata/disk-network-source-curl-nbdkit.xml new file mode 120000 index 0000000000..4a1e40bd70 --- /dev/null +++ b/tests/qemuxml2argvdata/disk-network-source-curl-nbdkit.xml @@ -0,0 +1 @@ +disk-network-source-curl.xml \ No newline at end of file diff --git a/tests/qemuxml2argvdata/disk-network-source-curl.x86_64-latest.= args b/tests/qemuxml2argvdata/disk-network-source-curl.x86_64-latest.args new file mode 100644 index 0000000000..ec6dd13f6c --- /dev/null +++ b/tests/qemuxml2argvdata/disk-network-source-curl.x86_64-latest.args @@ -0,0 +1,53 @@ +LC_ALL=3DC \ +PATH=3D/bin \ +HOME=3D/tmp/lib/domain--1-QEMUGuest1 \ +USER=3Dtest \ +LOGNAME=3Dtest \ +XDG_DATA_HOME=3D/tmp/lib/domain--1-QEMUGuest1/.local/share \ +XDG_CACHE_HOME=3D/tmp/lib/domain--1-QEMUGuest1/.cache \ +XDG_CONFIG_HOME=3D/tmp/lib/domain--1-QEMUGuest1/.config \ +/usr/bin/qemu-system-x86_64 \ +-name guest=3DQEMUGuest1,debug-threads=3Don \ +-S \ +-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/tm= p/lib/domain--1-QEMUGuest1/master-key.aes"}' \ +-machine pc,usb=3Doff,dump-guest-core=3Doff,memory-backend=3Dpc.ram \ +-accel tcg \ +-cpu qemu64 \ +-m 214 \ +-object '{"qom-type":"memory-backend-ram","id":"pc.ram","size":224395264}'= \ +-overcommit mem-lock=3Doff \ +-smp 1,sockets=3D1,cores=3D1,threads=3D1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=3Dcharmonitor,fd=3D1729,server=3Don,wait=3Doff \ +-mon chardev=3Dcharmonitor,id=3Dmonitor,mode=3Dcontrol \ +-rtc base=3Dutc \ +-no-shutdown \ +-no-acpi \ +-boot strict=3Don \ +-device '{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.0","addr":"0x1.0= x2"}' \ +-device '{"driver":"ahci","id":"sata0","bus":"pci.0","addr":"0x2"}' \ +-object '{"qom-type":"secret","id":"libvirt-5-storage-httpcookie-secret0",= "data":"BUU0KmnWfonHdjzhYhwVQZ5iTI1KweTJ22q8XWUVoBCVu1z70reDuczPBIabZtC3","= keyid":"masterKey0","iv":"AAECAwQFBgcICQoLDA0ODw=3D=3D","format":"base64"}'= \ +-blockdev '{"driver":"https","url":"https://https.example.org:8443/path/to= /disk1.iso","cookie-secret":"libvirt-5-storage-httpcookie-secret0","node-na= me":"libvirt-5-storage","auto-read-only":true,"discard":"unmap"}' \ +-blockdev '{"node-name":"libvirt-5-format","read-only":true,"driver":"raw"= ,"file":"libvirt-5-storage"}' \ +-device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x3","drive":"li= bvirt-5-format","id":"virtio-disk0","bootindex":1}' \ +-object '{"qom-type":"secret","id":"libvirt-4-format-encryption-secret0","= data":"9eao5F8qtkGt+seB1HYivWIxbtwUu6MQtg1zpj/oDtUsPr1q8wBYM91uEHCn6j/1","k= eyid":"masterKey0","iv":"AAECAwQFBgcICQoLDA0ODw=3D=3D","format":"base64"}' \ +-object '{"qom-type":"secret","id":"libvirt-4-storage-httpcookie-secret0",= "data":"BUU0KmnWfonHdjzhYhwVQZ5iTI1KweTJ22q8XWUVoBCVu1z70reDuczPBIabZtC3","= keyid":"masterKey0","iv":"AAECAwQFBgcICQoLDA0ODw=3D=3D","format":"base64"}'= \ +-blockdev '{"driver":"https","url":"https://https.example.org:8443/path/to= /disk5.iso?foo=3Dbar","sslverify":false,"cookie-secret":"libvirt-4-storage-= httpcookie-secret0","node-name":"libvirt-4-storage","auto-read-only":true,"= discard":"unmap"}' \ +-blockdev '{"node-name":"libvirt-4-format","read-only":false,"driver":"luk= s","key-secret":"libvirt-4-format-encryption-secret0","file":"libvirt-4-sto= rage"}' \ +-device '{"driver":"virtio-blk-pci","bus":"pci.0","addr":"0x4","drive":"li= bvirt-4-format","id":"virtio-disk4"}' \ +-object '{"qom-type":"secret","id":"libvirt-3-storage-httpcookie-secret0",= "data":"BUU0KmnWfonHdjzhYhwVQZ5iTI1KweTJ22q8XWUVoBBv7TuTgTkyAyOPpC2P5qLbOIy= pLoHpppjz+u5O+X8oT+jA1m7q/OJQ8dk2EFD5c0A=3D","keyid":"masterKey0","iv":"AAE= CAwQFBgcICQoLDA0ODw=3D=3D","format":"base64"}' \ +-blockdev '{"driver":"http","url":"http://http.example.org:8080/path/to/di= sk2.iso","cookie-secret":"libvirt-3-storage-httpcookie-secret0","node-name"= :"libvirt-3-storage","auto-read-only":true,"discard":"unmap"}' \ +-blockdev '{"node-name":"libvirt-3-format","read-only":true,"driver":"raw"= ,"file":"libvirt-3-storage"}' \ +-device '{"driver":"ide-cd","bus":"sata0.1","drive":"libvirt-3-format","id= ":"sata0-0-1"}' \ +-blockdev '{"driver":"ftp","url":"ftp://ftp.example.org:20/path/to/disk3.i= so","node-name":"libvirt-2-storage","auto-read-only":true,"discard":"unmap"= }' \ +-blockdev '{"node-name":"libvirt-2-format","read-only":true,"driver":"raw"= ,"file":"libvirt-2-storage"}' \ +-device '{"driver":"ide-cd","bus":"sata0.2","drive":"libvirt-2-format","id= ":"sata0-0-2"}' \ +-blockdev '{"driver":"ftps","url":"ftps://ftps.example.org:22/path/to/disk= 4.iso","node-name":"libvirt-1-storage","auto-read-only":true,"discard":"unm= ap"}' \ +-blockdev '{"node-name":"libvirt-1-format","read-only":true,"driver":"raw"= ,"file":"libvirt-1-storage"}' \ +-device '{"driver":"ide-cd","bus":"sata0.3","drive":"libvirt-1-format","id= ":"sata0-0-3"}' \ +-audiodev '{"id":"audio1","driver":"none"}' \ +-sandbox on,obsolete=3Ddeny,elevateprivileges=3Ddeny,spawn=3Ddeny,resource= control=3Ddeny \ +-msg timestamp=3Don diff --git a/tests/qemuxml2argvdata/disk-network-source-curl.xml b/tests/qe= muxml2argvdata/disk-network-source-curl.xml new file mode 100644 index 0000000000..1e50314abe --- /dev/null +++ b/tests/qemuxml2argvdata/disk-network-source-curl.xml @@ -0,0 +1,71 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219136 + 219136 + 1 + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu-system-x86_64 + + + + + cookievalue1 + cookievalue2 + + + + + + + + + + cookievalue1 + cookievalue2 + cookievalue3 + + + + + + + + + + + + + + + + + + + + + + cookievalue1 + cookievalue2 + + + + + + + + + + + + + + diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 48dd20458e..379ea307f8 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -705,6 +705,11 @@ testCompareXMLToArgv(const void *data) if (rc < 0) goto cleanup; =20 + if (info->nbdkitCaps) { + driver.nbdkitCaps =3D info->nbdkitCaps; + g_object_add_weak_pointer(G_OBJECT(info->nbdkitCaps), (void**)&dri= ver.nbdkitCaps); + } + if (info->migrateFrom && !(migrateURI =3D qemuMigrationDstGetURI(info->migrateFrom, info->migrateFd))) @@ -963,6 +968,9 @@ mymain(void) # define DO_TEST_CAPS_ARCH_VER(name, arch, ver) \ DO_TEST_CAPS_ARCH_VER_FULL(name, arch, ver, ARG_END) =20 +# define DO_TEST_CAPS_LATEST_NBDKIT(name, ...) \ + DO_TEST_CAPS_ARCH_LATEST_FULL(name, "x86_64", ARG_NBDKIT_CAPS, __VA_AR= GS__, QEMU_NBDKIT_CAPS_LAST, ARG_END) + # define DO_TEST_CAPS_LATEST(name) \ DO_TEST_CAPS_ARCH_LATEST(name, "x86_64") =20 @@ -1330,6 +1338,7 @@ mymain(void) DO_TEST_CAPS_LATEST("disk-cdrom-bus-other"); DO_TEST_CAPS_VER("disk-cdrom-network", "4.1.0"); DO_TEST_CAPS_LATEST("disk-cdrom-network"); + DO_TEST_CAPS_LATEST_NBDKIT("disk-cdrom-network-nbdkit", QEMU_NBDKIT_CA= PS_PLUGIN_CURL); DO_TEST_CAPS_VER("disk-cdrom-tray", "4.1.0"); DO_TEST_CAPS_LATEST("disk-cdrom-tray"); DO_TEST_CAPS_VER("disk-floppy", "4.1.0"); @@ -1390,6 +1399,8 @@ mymain(void) DO_TEST_CAPS_VER("disk-network-sheepdog", "6.0.0"); DO_TEST_CAPS_VER("disk-network-source-auth", "4.1.0"); DO_TEST_CAPS_LATEST("disk-network-source-auth"); + DO_TEST_CAPS_LATEST("disk-network-source-curl"); + DO_TEST_CAPS_LATEST_NBDKIT("disk-network-source-curl-nbdkit", QEMU_NBD= KIT_CAPS_PLUGIN_CURL); DO_TEST_CAPS_LATEST("disk-network-nfs"); driver.config->vxhsTLS =3D 1; driver.config->nbdTLSx509secretUUID =3D g_strdup("6fd3f62d-9fe7-4a4e-a= 869-7acd6376d8ea"); @@ -1402,6 +1413,7 @@ mymain(void) DO_TEST_CAPS_LATEST("disk-network-tlsx509-nbd-hostname"); DO_TEST_CAPS_VER("disk-network-tlsx509-vxhs", "5.0.0"); DO_TEST_CAPS_LATEST("disk-network-http"); + DO_TEST_CAPS_LATEST_NBDKIT("disk-network-http-nbdkit", QEMU_NBDKIT_CAP= S_PLUGIN_CURL); driver.config->vxhsTLS =3D 0; VIR_FREE(driver.config->vxhsTLSx509certdir); DO_TEST_CAPS_LATEST("disk-no-boot"); diff --git a/tests/testutilsqemu.c b/tests/testutilsqemu.c index 6dabbaf36a..65b403c991 100644 --- a/tests/testutilsqemu.c +++ b/tests/testutilsqemu.c @@ -395,6 +395,7 @@ void qemuTestDriverFree(virQEMUDriver *driver) virObjectUnref(driver->caps); virObjectUnref(driver->config); virObjectUnref(driver->securityManager); + g_clear_object(&driver->nbdkitCaps); =20 virCPUDefFree(cpuDefault); virCPUDefFree(cpuHaswell); @@ -632,6 +633,8 @@ int qemuTestDriverInit(virQEMUDriver *driver) if (!driver->caps) goto error; =20 + driver->nbdkitCaps =3D NULL; + /* Using /dev/null for libDir and cacheDir automatically produces erro= rs * upon attempt to use any of them */ driver->qemuCapsCache =3D virQEMUCapsCacheNew("/dev/null", "/dev/null"= , 0, 0); @@ -858,6 +861,7 @@ testQemuInfoSetArgs(struct testQemuInfo *info, =20 info->conf =3D conf; info->args.newargs =3D true; + info->args.fakeNbdkitCaps =3D qemuNbdkitCapsNew("/bin/true"); =20 va_start(argptr, conf); while ((argname =3D va_arg(argptr, testQemuInfoArgName)) !=3D ARG_END)= { @@ -869,6 +873,13 @@ testQemuInfoSetArgs(struct testQemuInfo *info, virQEMUCapsSet(info->args.fakeCaps, flag); break; =20 + case ARG_NBDKIT_CAPS: + info->args.fakeNbdkitCapsUsed =3D true; + + while ((flag =3D va_arg(argptr, int)) < QEMU_NBDKIT_CAPS_LAST) + qemuNbdkitCapsSet(info->args.fakeNbdkitCaps, flag); + break; + case ARG_GIC: info->args.gic =3D va_arg(argptr, int); break; @@ -993,6 +1004,9 @@ testQemuInfoInitArgs(struct testQemuInfo *info) info->qemuCaps =3D g_steal_pointer(&info->args.fakeCaps); } =20 + if (info->args.fakeNbdkitCapsUsed) + info->nbdkitCaps =3D g_steal_pointer(&info->args.fakeNbdkitCaps); + if (info->args.gic !=3D GIC_NONE && testQemuCapsSetGIC(info->qemuCaps, info->args.gic) < 0) return -1; @@ -1010,6 +1024,8 @@ testQemuInfoClear(struct testQemuInfo *info) VIR_FREE(info->errfile); virObjectUnref(info->qemuCaps); g_clear_pointer(&info->args.fakeCaps, virObjectUnref); + g_clear_object(&info->nbdkitCaps); + g_clear_object(&info->args.fakeNbdkitCaps); } =20 =20 diff --git a/tests/testutilsqemu.h b/tests/testutilsqemu.h index 7ce4c4ad8d..7d407004b4 100644 --- a/tests/testutilsqemu.h +++ b/tests/testutilsqemu.h @@ -49,6 +49,7 @@ typedef enum { ARG_CAPS_VER, ARG_CAPS_HOST_CPU_MODEL, ARG_HOST_OS, + ARG_NBDKIT_CAPS, ARG_END, } testQemuInfoArgName; =20 @@ -79,6 +80,8 @@ struct testQemuArgs { bool newargs; virQEMUCaps *fakeCaps; bool fakeCapsUsed; + qemuNbdkitCaps *fakeNbdkitCaps; + bool fakeNbdkitCapsUsed; char *capsver; char *capsarch; qemuTestCPUDef capsHostCPUModel; @@ -93,6 +96,7 @@ struct testQemuInfo { char *outfile; char *errfile; virQEMUCaps *qemuCaps; + qemuNbdkitCaps *nbdkitCaps; const char *migrateFrom; int migrateFd; unsigned int flags; --=20 2.35.3