Message ID | 20230213074941.919324-3-baolu.lu@linux.intel.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp2225029wrn; Mon, 13 Feb 2023 00:04:13 -0800 (PST) X-Google-Smtp-Source: AK7set+ea3c4YqBANfu7LWbdd9OZiHSLzODt8zM9iafrMFa0125YJKzSMcv7BEKlov84/2B9ARUg X-Received: by 2002:a05:6a21:3389:b0:bc:c86a:f60f with SMTP id yy9-20020a056a21338900b000bcc86af60fmr26972959pzb.54.1676275453404; Mon, 13 Feb 2023 00:04:13 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1676275453; cv=none; d=google.com; s=arc-20160816; b=dTq80zp2r9Qy5sQ4Q3QBn8YzwN7cz4cdPnvZiQXFoSHkwnFhwVcUeXwbEdK7VW4FJ3 lKJb8Bq9G0HO7DOXsR390EMVpVceeNFZ/alk3FnkJEfFoXWOQqXK3lVi869104EH3WaX ky7DylKgCdnGIOH/Od4hGy+WHuuRLgpyY8Ju1S9EOi1dc84i2WOi/Tz0u2SRg6GJ3B3D lJ9FOW3fJOA0KZ6uYSB2NqMK2a81u5lqw6IuePj7CIyjrDPgDeT1eCQD0McOLQZLnBJB BEN4SaXDfBYfJIEs6TyXcw9t4JbJQG6NMwM9Vqmsr8Qm64lovYJzMfzSx9GcFqx1OhzV nlCQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=HKx4WQeXSTRsXudhGW0/x5kQVKOGriI107MUkHjkZ8k=; b=T4q4OHZXbeev2FrzoP1AFBrhRw0FXJdjec7WzCqT3MgBPYf0FUp/XFjio9gSGf7E5+ cTAZPj0HI9fAMim7V4Omj5nlpsL//2dpZ82RyBI2HAgMx5XrjT1cWtHt+um56hTf0v26 vhCcMXeSDMNyXZueVf/pTbsQhH3OfXk/gtyeup/OuJ6e21/UkRLxNOlmJjkmUZLluMTj tKE2cbUv8AdyCVPP/qMT1MQnt2KZtGyDp5/EZEt8JwS0HHcpXmUbZiJ6ZkfKJpYSegac 1NtsGKM1j9CNEksM+XXjJFgH3jKzmw2PhVB6OYyQ0vAJprn1Wvg05NXn4S2QExzU5kf6 U6XA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b="njK/FKk/"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id a13-20020a63704d000000b004f1cd1ad1b9si11030041pgn.216.2023.02.13.00.04.00; Mon, 13 Feb 2023 00:04:13 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@intel.com header.s=Intel header.b="njK/FKk/"; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=intel.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229819AbjBMH6a (ORCPT <rfc822;tebrre53rla2o@gmail.com> + 99 others); Mon, 13 Feb 2023 02:58:30 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46938 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229747AbjBMH6X (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Mon, 13 Feb 2023 02:58:23 -0500 Received: from mga05.intel.com (mga05.intel.com [192.55.52.43]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1AC684EE8 for <linux-kernel@vger.kernel.org>; Sun, 12 Feb 2023 23:58:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1676275099; x=1707811099; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=AazWd96xxOSoSDyvZpaQLi9s44x2C1YOu7YcySHmaWw=; b=njK/FKk/1ET1BQz9vbmL0Z9czc4Xl6Cj4ohlu9cQZRun3c42H+mEwGZO tbC4L231KL63zRk3GsWhskmEoIzHekbV0YMr65T4dtV13KWjQDLfUefpO 2k7lOlSV6rNuVbqQ/MEfb3o1CONqlalImg2TVtXBtM226OFCpBRiSLQN2 N64nSFY12Am8dRZ6Ew+JfsLsRjzgaWXhWrNMU5AR1OkezFKsBfB7CyWe6 zomoY8RIZOAlT/soDH83ywrIWhQVo8G5w3IqTwSTNesdIXckrFaYcDxKM 1dayHrQsIDIDD6f7mYGtO46+uaAPWEdoYtfTSLs9bMq1mLab0jO/n7VLC g==; X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="417058772" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="417058772" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by fmsmga105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 12 Feb 2023 23:58:18 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="842684807" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="842684807" Received: from allen-box.sh.intel.com ([10.239.159.48]) by orsmga005.jf.intel.com with ESMTP; 12 Feb 2023 23:58:16 -0800 From: Lu Baolu <baolu.lu@linux.intel.com> To: iommu@lists.linux.dev Cc: Joerg Roedel <joro@8bytes.org>, Jason Gunthorpe <jgg@nvidia.com>, Christoph Hellwig <hch@infradead.org>, Kevin Tian <kevin.tian@intel.com>, Will Deacon <will@kernel.org>, Robin Murphy <robin.murphy@arm.com>, linux-kernel@vger.kernel.org, Lu Baolu <baolu.lu@linux.intel.com> Subject: [PATCH 2/4] iommu: Use group ownership to avoid driver attachment Date: Mon, 13 Feb 2023 15:49:39 +0800 Message-Id: <20230213074941.919324-3-baolu.lu@linux.intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230213074941.919324-1-baolu.lu@linux.intel.com> References: <20230213074941.919324-1-baolu.lu@linux.intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-4.3 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_EF,RCVD_IN_DNSWL_MED,SPF_HELO_NONE, SPF_NONE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1757702209428981704?= X-GMAIL-MSGID: =?utf-8?q?1757702209428981704?= |
Series |
iommu: Extend changing default domain to normal group
|
|
Commit Message
Baolu Lu
Feb. 13, 2023, 7:49 a.m. UTC
The iommu_group_store_type() requires the devices in the iommu group are
not bound to any device driver during the whole operation. The existing
code locks the device with device_lock(dev) and use device_is_bound() to
check whether any driver is bound to device.
In fact, this can be achieved through the DMA ownership helpers. Replace
them with iommu_group_claim/release_dma_owner() helpers.
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
drivers/iommu/iommu.c | 27 +++++++++++++--------------
1 file changed, 13 insertions(+), 14 deletions(-)
Comments
On Mon, Feb 13, 2023 at 03:49:39PM +0800, Lu Baolu wrote: > The iommu_group_store_type() requires the devices in the iommu group are > not bound to any device driver during the whole operation. The existing > code locks the device with device_lock(dev) and use device_is_bound() to > check whether any driver is bound to device. > > In fact, this can be achieved through the DMA ownership helpers. Replace > them with iommu_group_claim/release_dma_owner() helpers. > > Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com> > --- > drivers/iommu/iommu.c | 27 +++++++++++++-------------- > 1 file changed, 13 insertions(+), 14 deletions(-) > > diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c > index 4f71dcd2621b..6547cb38480c 100644 > --- a/drivers/iommu/iommu.c > +++ b/drivers/iommu/iommu.c > @@ -2807,12 +2807,6 @@ static int iommu_change_dev_def_domain(struct iommu_group *group, > > mutex_lock(&group->mutex); > > - if (group->default_domain != group->domain) { > - dev_err_ratelimited(prev_dev, "Group not assigned to default domain\n"); > - ret = -EBUSY; > - goto out; > - } > - > /* > * iommu group wasn't locked while acquiring device lock in > * iommu_group_store_type(). So, make sure that the device count hasn't > @@ -2971,6 +2965,7 @@ static void iommu_group_unfreeze_dev_ops(struct iommu_group *group) > static ssize_t iommu_group_store_type(struct iommu_group *group, > const char *buf, size_t count) > { > + bool group_owner_claimed = false; > struct group_device *grp_dev; > struct device *dev; > int ret, req_type; > @@ -2992,6 +2987,14 @@ static ssize_t iommu_group_store_type(struct iommu_group *group, > else > return -EINVAL; > > + if (req_type != IOMMU_DOMAIN_DMA_FQ || > + group->default_domain->type != IOMMU_DOMAIN_DMA) { > + ret = iommu_group_claim_dma_owner(group, (void *)buf); > + if (ret) > + return ret; > + group_owner_claimed = true; > + } I don't get it, this should be done unconditionally. If we couldn't take ownership then we simply can't progress. But there is more to it than that, a device that is owned should not be release and to achieve this the general logic around the owner scheme assumes that a driver is attached. So if you call it from this non-driver context you have to hold the group_mutex as previously discussed, which also means this needs to be an externally version of iommu_group_claim_dma_owner() Jason
On 2/13/23 10:19 PM, Jason Gunthorpe wrote: > On Mon, Feb 13, 2023 at 03:49:39PM +0800, Lu Baolu wrote: >> The iommu_group_store_type() requires the devices in the iommu group are >> not bound to any device driver during the whole operation. The existing >> code locks the device with device_lock(dev) and use device_is_bound() to >> check whether any driver is bound to device. >> >> In fact, this can be achieved through the DMA ownership helpers. Replace >> them with iommu_group_claim/release_dma_owner() helpers. >> >> Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com> >> --- >> drivers/iommu/iommu.c | 27 +++++++++++++-------------- >> 1 file changed, 13 insertions(+), 14 deletions(-) >> >> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c >> index 4f71dcd2621b..6547cb38480c 100644 >> --- a/drivers/iommu/iommu.c >> +++ b/drivers/iommu/iommu.c >> @@ -2807,12 +2807,6 @@ static int iommu_change_dev_def_domain(struct iommu_group *group, >> >> mutex_lock(&group->mutex); >> >> - if (group->default_domain != group->domain) { >> - dev_err_ratelimited(prev_dev, "Group not assigned to default domain\n"); >> - ret = -EBUSY; >> - goto out; >> - } >> - >> /* >> * iommu group wasn't locked while acquiring device lock in >> * iommu_group_store_type(). So, make sure that the device count hasn't >> @@ -2971,6 +2965,7 @@ static void iommu_group_unfreeze_dev_ops(struct iommu_group *group) >> static ssize_t iommu_group_store_type(struct iommu_group *group, >> const char *buf, size_t count) >> { >> + bool group_owner_claimed = false; >> struct group_device *grp_dev; >> struct device *dev; >> int ret, req_type; >> @@ -2992,6 +2987,14 @@ static ssize_t iommu_group_store_type(struct iommu_group *group, >> else >> return -EINVAL; >> >> + if (req_type != IOMMU_DOMAIN_DMA_FQ || >> + group->default_domain->type != IOMMU_DOMAIN_DMA) { >> + ret = iommu_group_claim_dma_owner(group, (void *)buf); >> + if (ret) >> + return ret; >> + group_owner_claimed = true; >> + } > > I don't get it, this should be done unconditionally. If we couldn't > take ownership then we simply can't progress. The existing code allows the user to switch the default domain from strict to lazy invalidation mode. The default domain is not changed, hence it should be seamless and transparent to the device driver. > > But there is more to it than that, a device that is owned should not > be release and to achieve this the general logic around the owner > scheme assumes that a driver is attached. Yes. Current ownership scheme was built on this assumption. > > So if you call it from this non-driver context you have to hold the > group_mutex as previously discussed, Yes. > which also means this needs to be > an externally version of iommu_group_claim_dma_owner() Sorry! What does "an externally version of iommu_group_claim_dma_owner()" mean? My understanding is that we should limit iommu_group_claim_dma_owner() use in the driver context. For this non-driver context, we should not use iommu_group_claim_dma_owner() directly, but hold the group->mutex and check the group->owner_cnt directly: mutex_lock(&group->mutex); if (group->owner_cnt) { ret = -EPERM; goto unlock_out; } the group->mutex should be held until everything is done. Best regards, baolu
> From: Baolu Lu <baolu.lu@linux.intel.com> > Sent: Wednesday, February 15, 2023 1:51 PM > > On 2/13/23 10:19 PM, Jason Gunthorpe wrote: > > On Mon, Feb 13, 2023 at 03:49:39PM +0800, Lu Baolu wrote: > >> @@ -2992,6 +2987,14 @@ static ssize_t iommu_group_store_type(struct > iommu_group *group, > >> else > >> return -EINVAL; > >> > >> + if (req_type != IOMMU_DOMAIN_DMA_FQ || > >> + group->default_domain->type != IOMMU_DOMAIN_DMA) { > >> + ret = iommu_group_claim_dma_owner(group, (void *)buf); > >> + if (ret) > >> + return ret; > >> + group_owner_claimed = true; > >> + } > > > > I don't get it, this should be done unconditionally. If we couldn't > > take ownership then we simply can't progress. > > The existing code allows the user to switch the default domain from > strict to lazy invalidation mode. The default domain is not changed, > hence it should be seamless and transparent to the device driver. Is there real usage relying on this transition for a bound device? In concept strict->lazy transition implies relaxed DMA security. It's hard to think of a motivation of doing so while the device might be doing in-fly DMAs. Presumably such perf/security tradeoff should be planned way before binding device/driver together. btw if strict->lazy is allowed why lazy->strict is prohibited? > > > which also means this needs to be > > an externally version of iommu_group_claim_dma_owner() > > Sorry! What does "an externally version of > iommu_group_claim_dma_owner()" mean? > > My understanding is that we should limit iommu_group_claim_dma_owner() > use in the driver context. For this non-driver context, we should not > use iommu_group_claim_dma_owner() directly, but hold the group->mutex > and check the group->owner_cnt directly: > > mutex_lock(&group->mutex); > if (group->owner_cnt) { > ret = -EPERM; > goto unlock_out; > } > > the group->mutex should be held until everything is done. > I guess you two meant the same thing. mutex_lock(&group->mutex); iommu_group_claim_dma_owner_unlocked(); //blah blah mutex_unlock(&group->mutex);
On 2023/2/15 14:56, Tian, Kevin wrote: >> From: Baolu Lu<baolu.lu@linux.intel.com> >> Sent: Wednesday, February 15, 2023 1:51 PM >> >> On 2/13/23 10:19 PM, Jason Gunthorpe wrote: >>> On Mon, Feb 13, 2023 at 03:49:39PM +0800, Lu Baolu wrote: >>>> @@ -2992,6 +2987,14 @@ static ssize_t iommu_group_store_type(struct >> iommu_group *group, >>>> else >>>> return -EINVAL; >>>> >>>> + if (req_type != IOMMU_DOMAIN_DMA_FQ || >>>> + group->default_domain->type != IOMMU_DOMAIN_DMA) { >>>> + ret = iommu_group_claim_dma_owner(group, (void *)buf); >>>> + if (ret) >>>> + return ret; >>>> + group_owner_claimed = true; >>>> + } >>> I don't get it, this should be done unconditionally. If we couldn't >>> take ownership then we simply can't progress. >> The existing code allows the user to switch the default domain from >> strict to lazy invalidation mode. The default domain is not changed, >> hence it should be seamless and transparent to the device driver. > Is there real usage relying on this transition for a bound device? > > In concept strict->lazy transition implies relaxed DMA security. It's hard > to think of a motivation of doing so while the device might be doing > in-fly DMAs. > > Presumably such perf/security tradeoff should be planned way before > binding device/driver together. > > btw if strict->lazy is allowed why lazy->strict is prohibited? > We all know, strict vs. lazy is a tradeoff between performance and security. strict -> lazy: driver works in secure mode. This transition trades off security for better performance. lazy->strict: The driver is already working in non-safety mode. This transition only results in worse performance. It makes no sense. If user want to put the driver in a secure mode, they need to unbind the driver, reset the device and do the lazy->strict transition. Robin might have better insights. Best regards, baolu
On 2023-02-15 07:28, Baolu Lu wrote: > On 2023/2/15 14:56, Tian, Kevin wrote: >>> From: Baolu Lu<baolu.lu@linux.intel.com> >>> Sent: Wednesday, February 15, 2023 1:51 PM >>> >>> On 2/13/23 10:19 PM, Jason Gunthorpe wrote: >>>> On Mon, Feb 13, 2023 at 03:49:39PM +0800, Lu Baolu wrote: >>>>> @@ -2992,6 +2987,14 @@ static ssize_t iommu_group_store_type(struct >>> iommu_group *group, >>>>> else >>>>> return -EINVAL; >>>>> >>>>> + if (req_type != IOMMU_DOMAIN_DMA_FQ || >>>>> + group->default_domain->type != IOMMU_DOMAIN_DMA) { >>>>> + ret = iommu_group_claim_dma_owner(group, (void *)buf); >>>>> + if (ret) >>>>> + return ret; >>>>> + group_owner_claimed = true; >>>>> + } >>>> I don't get it, this should be done unconditionally. If we couldn't >>>> take ownership then we simply can't progress. >>> The existing code allows the user to switch the default domain from >>> strict to lazy invalidation mode. The default domain is not changed, >>> hence it should be seamless and transparent to the device driver. >> Is there real usage relying on this transition for a bound device? >> >> In concept strict->lazy transition implies relaxed DMA security. It's >> hard >> to think of a motivation of doing so while the device might be doing >> in-fly DMAs. >> >> Presumably such perf/security tradeoff should be planned way before >> binding device/driver together. >> >> btw if strict->lazy is allowed why lazy->strict is prohibited? >> > > We all know, strict vs. lazy is a tradeoff between performance and > security. > > strict -> lazy: driver works in secure mode. This transition trades off > security for better performance. > > lazy->strict: The driver is already working in non-safety mode. This > transition only results in worse performance. It makes no sense. If user > want to put the driver in a secure mode, they need to unbind the driver, > reset the device and do the lazy->strict transition. > > Robin might have better insights. Yes, this was added for a definite use-case in ChromeOS, where strict->lazy needs to support being done "live" since the device in question is the storage controller for the already-mounted root filesystem. Your reasoning seems to match what I summarised in the original commit message :) Thanks, Robin.
On Wed, Feb 15, 2023 at 01:51:14PM +0800, Baolu Lu wrote: > On 2/13/23 10:19 PM, Jason Gunthorpe wrote: > > On Mon, Feb 13, 2023 at 03:49:39PM +0800, Lu Baolu wrote: > > > The iommu_group_store_type() requires the devices in the iommu group are > > > not bound to any device driver during the whole operation. The existing > > > code locks the device with device_lock(dev) and use device_is_bound() to > > > check whether any driver is bound to device. > > > > > > In fact, this can be achieved through the DMA ownership helpers. Replace > > > them with iommu_group_claim/release_dma_owner() helpers. > > > > > > Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com> > > > --- > > > drivers/iommu/iommu.c | 27 +++++++++++++-------------- > > > 1 file changed, 13 insertions(+), 14 deletions(-) > > > > > > diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c > > > index 4f71dcd2621b..6547cb38480c 100644 > > > --- a/drivers/iommu/iommu.c > > > +++ b/drivers/iommu/iommu.c > > > @@ -2807,12 +2807,6 @@ static int iommu_change_dev_def_domain(struct iommu_group *group, > > > mutex_lock(&group->mutex); > > > - if (group->default_domain != group->domain) { > > > - dev_err_ratelimited(prev_dev, "Group not assigned to default domain\n"); > > > - ret = -EBUSY; > > > - goto out; > > > - } > > > - > > > /* > > > * iommu group wasn't locked while acquiring device lock in > > > * iommu_group_store_type(). So, make sure that the device count hasn't > > > @@ -2971,6 +2965,7 @@ static void iommu_group_unfreeze_dev_ops(struct iommu_group *group) > > > static ssize_t iommu_group_store_type(struct iommu_group *group, > > > const char *buf, size_t count) > > > { > > > + bool group_owner_claimed = false; > > > struct group_device *grp_dev; > > > struct device *dev; > > > int ret, req_type; > > > @@ -2992,6 +2987,14 @@ static ssize_t iommu_group_store_type(struct iommu_group *group, > > > else > > > return -EINVAL; > > > + if (req_type != IOMMU_DOMAIN_DMA_FQ || > > > + group->default_domain->type != IOMMU_DOMAIN_DMA) { > > > + ret = iommu_group_claim_dma_owner(group, (void *)buf); > > > + if (ret) > > > + return ret; > > > + group_owner_claimed = true; > > > + } > > > > I don't get it, this should be done unconditionally. If we couldn't > > take ownership then we simply can't progress. > > The existing code allows the user to switch the default domain from > strict to lazy invalidation mode. The default domain is not changed, > hence it should be seamless and transparent to the device driver. So make that a special case, get the group lock check if it is this case and then just adjust it and exit, otherwise get ownership under the group lock as discussed. > > > which also means this needs to be > > an externally version of iommu_group_claim_dma_owner() > > Sorry! What does "an externally version of > iommu_group_claim_dma_owner()" mean? > Oops "externally locked" > My understanding is that we should limit iommu_group_claim_dma_owner() > use in the driver context. For this non-driver context, we should not > use iommu_group_claim_dma_owner() directly, but hold the group->mutex > and check the group->owner_cnt directly: > > mutex_lock(&group->mutex); > if (group->owner_cnt) { > ret = -EPERM; > goto unlock_out; > } > > the group->mutex should be held until everything is done. Yes, that would be fine as long as we can hold the group mutex throughout Jason
On 2/15/23 8:56 PM, Jason Gunthorpe wrote: > On Wed, Feb 15, 2023 at 01:51:14PM +0800, Baolu Lu wrote: >> On 2/13/23 10:19 PM, Jason Gunthorpe wrote: >>> On Mon, Feb 13, 2023 at 03:49:39PM +0800, Lu Baolu wrote: >>>> The iommu_group_store_type() requires the devices in the iommu group are >>>> not bound to any device driver during the whole operation. The existing >>>> code locks the device with device_lock(dev) and use device_is_bound() to >>>> check whether any driver is bound to device. >>>> >>>> In fact, this can be achieved through the DMA ownership helpers. Replace >>>> them with iommu_group_claim/release_dma_owner() helpers. >>>> >>>> Signed-off-by: Lu Baolu<baolu.lu@linux.intel.com> >>>> --- >>>> drivers/iommu/iommu.c | 27 +++++++++++++-------------- >>>> 1 file changed, 13 insertions(+), 14 deletions(-) >>>> >>>> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c >>>> index 4f71dcd2621b..6547cb38480c 100644 >>>> --- a/drivers/iommu/iommu.c >>>> +++ b/drivers/iommu/iommu.c >>>> @@ -2807,12 +2807,6 @@ static int iommu_change_dev_def_domain(struct iommu_group *group, >>>> mutex_lock(&group->mutex); >>>> - if (group->default_domain != group->domain) { >>>> - dev_err_ratelimited(prev_dev, "Group not assigned to default domain\n"); >>>> - ret = -EBUSY; >>>> - goto out; >>>> - } >>>> - >>>> /* >>>> * iommu group wasn't locked while acquiring device lock in >>>> * iommu_group_store_type(). So, make sure that the device count hasn't >>>> @@ -2971,6 +2965,7 @@ static void iommu_group_unfreeze_dev_ops(struct iommu_group *group) >>>> static ssize_t iommu_group_store_type(struct iommu_group *group, >>>> const char *buf, size_t count) >>>> { >>>> + bool group_owner_claimed = false; >>>> struct group_device *grp_dev; >>>> struct device *dev; >>>> int ret, req_type; >>>> @@ -2992,6 +2987,14 @@ static ssize_t iommu_group_store_type(struct iommu_group *group, >>>> else >>>> return -EINVAL; >>>> + if (req_type != IOMMU_DOMAIN_DMA_FQ || >>>> + group->default_domain->type != IOMMU_DOMAIN_DMA) { >>>> + ret = iommu_group_claim_dma_owner(group, (void *)buf); >>>> + if (ret) >>>> + return ret; >>>> + group_owner_claimed = true; >>>> + } >>> I don't get it, this should be done unconditionally. If we couldn't >>> take ownership then we simply can't progress. >> The existing code allows the user to switch the default domain from >> strict to lazy invalidation mode. The default domain is not changed, >> hence it should be seamless and transparent to the device driver. > So make that a special case, get the group lock check if it is this > case and then just adjust it and exit, otherwise get ownership under > the group lock as discussed. OK. Will do like this in the next version. Best regards, baolu
On 2/15/23 7:09 PM, Robin Murphy wrote: > On 2023-02-15 07:28, Baolu Lu wrote: >> On 2023/2/15 14:56, Tian, Kevin wrote: >>>> From: Baolu Lu<baolu.lu@linux.intel.com> >>>> Sent: Wednesday, February 15, 2023 1:51 PM >>>> >>>> On 2/13/23 10:19 PM, Jason Gunthorpe wrote: >>>>> On Mon, Feb 13, 2023 at 03:49:39PM +0800, Lu Baolu wrote: >>>>>> @@ -2992,6 +2987,14 @@ static ssize_t iommu_group_store_type(struct >>>> iommu_group *group, >>>>>> else >>>>>> return -EINVAL; >>>>>> >>>>>> + if (req_type != IOMMU_DOMAIN_DMA_FQ || >>>>>> + group->default_domain->type != IOMMU_DOMAIN_DMA) { >>>>>> + ret = iommu_group_claim_dma_owner(group, (void *)buf); >>>>>> + if (ret) >>>>>> + return ret; >>>>>> + group_owner_claimed = true; >>>>>> + } >>>>> I don't get it, this should be done unconditionally. If we couldn't >>>>> take ownership then we simply can't progress. >>>> The existing code allows the user to switch the default domain from >>>> strict to lazy invalidation mode. The default domain is not changed, >>>> hence it should be seamless and transparent to the device driver. >>> Is there real usage relying on this transition for a bound device? >>> >>> In concept strict->lazy transition implies relaxed DMA security. It's >>> hard >>> to think of a motivation of doing so while the device might be doing >>> in-fly DMAs. >>> >>> Presumably such perf/security tradeoff should be planned way before >>> binding device/driver together. >>> >>> btw if strict->lazy is allowed why lazy->strict is prohibited? >>> >> >> We all know, strict vs. lazy is a tradeoff between performance and >> security. >> >> strict -> lazy: driver works in secure mode. This transition trades off >> security for better performance. >> >> lazy->strict: The driver is already working in non-safety mode. This >> transition only results in worse performance. It makes no sense. If user >> want to put the driver in a secure mode, they need to unbind the driver, >> reset the device and do the lazy->strict transition. >> >> Robin might have better insights. > > Yes, this was added for a definite use-case in ChromeOS, where > strict->lazy needs to support being done "live" since the device in > question is the storage controller for the already-mounted root > filesystem. Thanks for letting us know this. > Your reasoning seems to match what I summarised in the > original commit message 😄 Haha, it seems that my memory is till good. :-) Best regards, baolu
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 4f71dcd2621b..6547cb38480c 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -2807,12 +2807,6 @@ static int iommu_change_dev_def_domain(struct iommu_group *group, mutex_lock(&group->mutex); - if (group->default_domain != group->domain) { - dev_err_ratelimited(prev_dev, "Group not assigned to default domain\n"); - ret = -EBUSY; - goto out; - } - /* * iommu group wasn't locked while acquiring device lock in * iommu_group_store_type(). So, make sure that the device count hasn't @@ -2971,6 +2965,7 @@ static void iommu_group_unfreeze_dev_ops(struct iommu_group *group) static ssize_t iommu_group_store_type(struct iommu_group *group, const char *buf, size_t count) { + bool group_owner_claimed = false; struct group_device *grp_dev; struct device *dev; int ret, req_type; @@ -2992,6 +2987,14 @@ static ssize_t iommu_group_store_type(struct iommu_group *group, else return -EINVAL; + if (req_type != IOMMU_DOMAIN_DMA_FQ || + group->default_domain->type != IOMMU_DOMAIN_DMA) { + ret = iommu_group_claim_dma_owner(group, (void *)buf); + if (ret) + return ret; + group_owner_claimed = true; + } + /* * Lock/Unlock the group mutex here before device lock to * 1. Make sure that the iommu group has only one device (this is a @@ -3001,6 +3004,8 @@ static ssize_t iommu_group_store_type(struct iommu_group *group, mutex_lock(&group->mutex); if (iommu_group_device_count(group) != 1) { mutex_unlock(&group->mutex); + if (group_owner_claimed) + iommu_group_release_dma_owner(group); pr_err_ratelimited("Cannot change default domain: Group has more than one device\n"); return -EINVAL; } @@ -3038,22 +3043,16 @@ static ssize_t iommu_group_store_type(struct iommu_group *group, iommu_group_freeze_dev_ops(group); - /* Check if the device in the group still has a driver bound to it */ device_lock(dev); - if (device_is_bound(dev) && !(req_type == IOMMU_DOMAIN_DMA_FQ && - group->default_domain->type == IOMMU_DOMAIN_DMA)) { - pr_err_ratelimited("Device is still bound to driver\n"); - ret = -EBUSY; - goto out; - } ret = iommu_change_dev_def_domain(group, dev, req_type); ret = ret ?: count; -out: device_unlock(dev); iommu_group_unfreeze_dev_ops(group); put_device(dev); + if (group_owner_claimed) + iommu_group_release_dma_owner(group); return ret; }