diff mbox series

[for-4.13,v2] passthrough: simplify locking and logging

Message ID 1572632881-9050-1-git-send-email-igor.druzhinin@citrix.com (mailing list archive)
State Superseded
Headers show
Series [for-4.13,v2] passthrough: simplify locking and logging | expand

Commit Message

Igor Druzhinin Nov. 1, 2019, 6:28 p.m. UTC
From: Paul Durrant <pdurrant@amazon.com>

Dropping the pcidevs lock between calling device_assigned() and
assign_device() means that the latter has to do the same check as the
former for no obvious gain. Also, since long running operations under
pcidevs lock already drop the lock and return -ERESTART periodically there
is little point in immediately failing an assignment operation with
-ERESTART just because the pcidevs lock could not be acquired (for the
second time, having already blocked on acquiring the lock in
device_assigned()).

This patch instead acquires the lock once for assignment (or test assign)
operations directly in iommu_do_pci_domctl() and thus can remove the
duplicate domain ownership check in assign_device(). Whilst in the
neighbourhood, the patch also removes some debug logging from
assign_device() and deassign_device() and replaces it with proper error
logging, which allows error logging in iommu_do_pci_domctl() to be
removed. Also, since device_assigned() can tell the difference between a
guest assigned device and a non-existent one, log the actual error
condition rather then being ambiguous for the sake a few extra lines of
code.

Signed-off-by: Paul Durrant <pdurrant@amazon.com>
---

This is XSA-302 followup and contains some changes important for XenServer.
Juergen, could this be considered for 4.13 inclusion?

v2: updated Paul's email address

---
 xen/drivers/passthrough/pci.c | 101 ++++++++++++++++++------------------------
 1 file changed, 42 insertions(+), 59 deletions(-)

Comments

Paul Durrant Nov. 4, 2019, 8:31 a.m. UTC | #1
> -----Original Message-----
> From: Igor Druzhinin <igor.druzhinin@citrix.com>
> Sent: 01 November 2019 19:28
> To: xen-devel@lists.xenproject.org
> Cc: Durrant, Paul <pdurrant@amazon.com>; jbeulich@suse.com;
> jgross@suse.com
> Subject: [PATCH for-4.13 v2] passthrough: simplify locking and logging
> 
> From: Paul Durrant <pdurrant@amazon.com>
> 
> Dropping the pcidevs lock between calling device_assigned() and
> assign_device() means that the latter has to do the same check as the
> former for no obvious gain. Also, since long running operations under
> pcidevs lock already drop the lock and return -ERESTART periodically there
> is little point in immediately failing an assignment operation with
> -ERESTART just because the pcidevs lock could not be acquired (for the
> second time, having already blocked on acquiring the lock in
> device_assigned()).
> 
> This patch instead acquires the lock once for assignment (or test assign)
> operations directly in iommu_do_pci_domctl() and thus can remove the
> duplicate domain ownership check in assign_device(). Whilst in the
> neighbourhood, the patch also removes some debug logging from
> assign_device() and deassign_device() and replaces it with proper error
> logging, which allows error logging in iommu_do_pci_domctl() to be
> removed. Also, since device_assigned() can tell the difference between a
> guest assigned device and a non-existent one, log the actual error
> condition rather then being ambiguous for the sake a few extra lines of
> code.
> 
> Signed-off-by: Paul Durrant <pdurrant@amazon.com>
> ---
> 
> This is XSA-302 followup and contains some changes important for
> XenServer.
> Juergen, could this be considered for 4.13 inclusion?
> 
> v2: updated Paul's email address

Reviewed-by: Paul Durrant <pdurrant@amazon.com>

> 
> ---
>  xen/drivers/passthrough/pci.c | 101 ++++++++++++++++++-------------------
> -----
>  1 file changed, 42 insertions(+), 59 deletions(-)
> 
> diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
> index e64666d..ea0770d 100644
> --- a/xen/drivers/passthrough/pci.c
> +++ b/xen/drivers/passthrough/pci.c
> @@ -932,30 +932,27 @@ static int deassign_device(struct domain *d,
> uint16_t seg, uint8_t bus,
>              break;
>          ret = hd->platform_ops->reassign_device(d, target, devfn,
>                                                  pci_to_dev(pdev));
> -        if ( !ret )
> -            continue;
> -
> -        printk(XENLOG_G_ERR "%pd: deassign %04x:%02x:%02x.%u failed
> (%d)\n",
> -               d, seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), ret);
> -        return ret;
> +        if ( ret )
> +            goto out;
>      }
> 
>      devfn = pdev->devfn;
>      ret = hd->platform_ops->reassign_device(d, target, devfn,
>                                              pci_to_dev(pdev));
>      if ( ret )
> -    {
> -        dprintk(XENLOG_G_ERR,
> -                "%pd: deassign device (%04x:%02x:%02x.%u) failed\n",
> -                d, seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
> -        return ret;
> -    }
> +        goto out;
> 
>      if ( pdev->domain == hardware_domain  )
>          pdev->quarantine = false;
> 
>      pdev->fault.count = 0;
> 
> +out:
> +    if ( ret )
> +        printk(XENLOG_G_ERR
> +               "%pd: deassign device (%04x:%02x:%02x.%u) failed (%d)\n",
> d,
> +               seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), ret);
> +
>      return ret;
>  }
> 
> @@ -976,10 +973,7 @@ int pci_release_devices(struct domain *d)
>      {
>          bus = pdev->bus;
>          devfn = pdev->devfn;
> -        if ( deassign_device(d, pdev->seg, bus, devfn) )
> -            printk("domain %d: deassign device (%04x:%02x:%02x.%u)
> failed!\n",
> -                   d->domain_id, pdev->seg, bus,
> -                   PCI_SLOT(devfn), PCI_FUNC(devfn));
> +        deassign_device(d, pdev->seg, bus, devfn);
>      }
>      pcidevs_unlock();
> 
> @@ -1534,8 +1528,7 @@ static int device_assigned(u16 seg, u8 bus, u8
> devfn)
>      struct pci_dev *pdev;
>      int rc = 0;
> 
> -    pcidevs_lock();
> -
> +    ASSERT(pcidevs_locked());
>      pdev = pci_get_pdev(seg, bus, devfn);
> 
>      if ( !pdev )
> @@ -1549,11 +1542,10 @@ static int device_assigned(u16 seg, u8 bus, u8
> devfn)
>                pdev->domain != dom_io )
>          rc = -EBUSY;
> 
> -    pcidevs_unlock();
> -
>      return rc;
>  }
> 
> +/* caller should hold the pcidevs_lock */
>  static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32
> flag)
>  {
>      const struct domain_iommu *hd = dom_iommu(d);
> @@ -1571,23 +1563,11 @@ static int assign_device(struct domain *d, u16
> seg, u8 bus, u8 devfn, u32 flag)
>                    vm_event_check_ring(d->vm_event_paging)) )
>          return -EXDEV;
> 
> -    if ( !pcidevs_trylock() )
> -        return -ERESTART;
> -
> +    /* device_assigned() should already have cleared the device for
> assignment */
> +    ASSERT(pcidevs_locked());
>      pdev = pci_get_pdev(seg, bus, devfn);
> -
> -    rc = -ENODEV;
> -    if ( !pdev )
> -        goto done;
> -
> -    rc = 0;
> -    if ( d == pdev->domain )
> -        goto done;
> -
> -    rc = -EBUSY;
> -    if ( pdev->domain != hardware_domain &&
> -         pdev->domain != dom_io )
> -        goto done;
> +    ASSERT(pdev && (pdev->domain == hardware_domain ||
> +                    pdev->domain == dom_io));
> 
>      if ( pdev->msix )
>      {
> @@ -1608,19 +1588,17 @@ static int assign_device(struct domain *d, u16
> seg, u8 bus, u8 devfn, u32 flag)
>          if ( PCI_SLOT(devfn) != PCI_SLOT(pdev->devfn) )
>              break;
>          rc = hd->platform_ops->assign_device(d, devfn, pci_to_dev(pdev),
> flag);
> -        if ( rc )
> -            printk(XENLOG_G_WARNING "d%d: assign %04x:%02x:%02x.%u failed
> (%d)\n",
> -                   d->domain_id, seg, bus, PCI_SLOT(devfn),
> PCI_FUNC(devfn),
> -                   rc);
>      }
> 
>   done:
> +    if ( rc )
> +        printk(XENLOG_G_ERR
> +               "%pd: assign device (%04x:%02x:%02x.%u) failed (%d)\n", d,
> +               seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), rc);
>      /* The device is assigned to dom_io so mark it as quarantined */
> -    if ( !rc && d == dom_io )
> +    else if ( d == dom_io )
>          pdev->quarantine = true;
> 
> -    pcidevs_unlock();
> -
>      return rc;
>  }
> 
> @@ -1776,29 +1754,40 @@ int iommu_do_pci_domctl(
>          bus = PCI_BUS(machine_sbdf);
>          devfn = PCI_DEVFN2(machine_sbdf);
> 
> +        pcidevs_lock();
>          ret = device_assigned(seg, bus, devfn);
>          if ( domctl->cmd == XEN_DOMCTL_test_assign_device )
>          {
> -            if ( ret )
> +            switch ( ret )
>              {
> +            case 0:
> +                break;
> +
> +            case -ENODEV:
>                  printk(XENLOG_G_INFO
> -                       "%04x:%02x:%02x.%u already assigned, or non-
> existent\n",
> +                       "%04x:%02x:%02x.%u non-existent\n",
>                         seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
>                  ret = -EINVAL;
> +                break;
> +
> +            case -EBUSY:
> +                printk(XENLOG_G_INFO
> +                       "%04x:%02x:%02x.%u already assigned\n",
> +                       seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
> +                ret = -EINVAL;
> +                break;
> +
> +            default:
> +                ret = -EINVAL;
> +                break;
>              }
> -            break;
>          }
> -        if ( !ret )
> +        else if ( !ret )
>              ret = assign_device(d, seg, bus, devfn, flags);
> +        pcidevs_unlock();
>          if ( ret == -ERESTART )
>              ret = hypercall_create_continuation(__HYPERVISOR_domctl,
>                                                  "h", u_domctl);
> -        else if ( ret )
> -            printk(XENLOG_G_ERR
> -                   "assign %04x:%02x:%02x.%u to dom%d failed (%d)\n",
> -                   seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
> -                   d->domain_id, ret);
> -
>          break;
> 
>      case XEN_DOMCTL_deassign_device:
> @@ -1830,12 +1819,6 @@ int iommu_do_pci_domctl(
>          pcidevs_lock();
>          ret = deassign_device(d, seg, bus, devfn);
>          pcidevs_unlock();
> -        if ( ret )
> -            printk(XENLOG_G_ERR
> -                   "deassign %04x:%02x:%02x.%u from dom%d failed (%d)\n",
> -                   seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
> -                   d->domain_id, ret);
> -
>          break;
> 
>      default:
> --
> 2.7.4
Andrew Cooper Nov. 4, 2019, 11:06 a.m. UTC | #2
On 04/11/2019 08:31, Durrant, Paul wrote:
>> -----Original Message-----
>> From: Igor Druzhinin <igor.druzhinin@citrix.com>
>> Sent: 01 November 2019 19:28
>> To: xen-devel@lists.xenproject.org
>> Cc: Durrant, Paul <pdurrant@amazon.com>; jbeulich@suse.com;
>> jgross@suse.com
>> Subject: [PATCH for-4.13 v2] passthrough: simplify locking and logging
>>
>> From: Paul Durrant <pdurrant@amazon.com>
>>
>> Dropping the pcidevs lock between calling device_assigned() and
>> assign_device() means that the latter has to do the same check as the
>> former for no obvious gain. Also, since long running operations under
>> pcidevs lock already drop the lock and return -ERESTART periodically there
>> is little point in immediately failing an assignment operation with
>> -ERESTART just because the pcidevs lock could not be acquired (for the
>> second time, having already blocked on acquiring the lock in
>> device_assigned()).
>>
>> This patch instead acquires the lock once for assignment (or test assign)
>> operations directly in iommu_do_pci_domctl() and thus can remove the
>> duplicate domain ownership check in assign_device(). Whilst in the
>> neighbourhood, the patch also removes some debug logging from
>> assign_device() and deassign_device() and replaces it with proper error
>> logging, which allows error logging in iommu_do_pci_domctl() to be
>> removed. Also, since device_assigned() can tell the difference between a
>> guest assigned device and a non-existent one, log the actual error
>> condition rather then being ambiguous for the sake a few extra lines of
>> code.
>>
>> Signed-off-by: Paul Durrant <pdurrant@amazon.com>
>> ---
>>
>> This is XSA-302 followup and contains some changes important for
>> XenServer.
>> Juergen, could this be considered for 4.13 inclusion?
>>
>> v2: updated Paul's email address

This was work you did at Citrix, yes?

> Reviewed-by: Paul Durrant <pdurrant@amazon.com>

SoB and R-by?

~Andrew
Paul Durrant Nov. 4, 2019, 11:13 a.m. UTC | #3
> -----Original Message-----
> From: Andrew Cooper <andrew.cooper3@citrix.com>
> Sent: 04 November 2019 11:06
> To: Durrant, Paul <pdurrant@amazon.com>; xen-devel@lists.xenproject.org
> Cc: Igor Druzhinin <igor.druzhinin@citrix.com>; jgross@suse.com;
> jbeulich@suse.com
> Subject: Re: [Xen-devel] [PATCH for-4.13 v2] passthrough: simplify locking
> and logging
> 
> On 04/11/2019 08:31, Durrant, Paul wrote:
> >> -----Original Message-----
> >> From: Igor Druzhinin <igor.druzhinin@citrix.com>
> >> Sent: 01 November 2019 19:28
> >> To: xen-devel@lists.xenproject.org
> >> Cc: Durrant, Paul <pdurrant@amazon.com>; jbeulich@suse.com;
> >> jgross@suse.com
> >> Subject: [PATCH for-4.13 v2] passthrough: simplify locking and logging
> >>
> >> From: Paul Durrant <pdurrant@amazon.com>
> >>
> >> Dropping the pcidevs lock between calling device_assigned() and
> >> assign_device() means that the latter has to do the same check as the
> >> former for no obvious gain. Also, since long running operations under
> >> pcidevs lock already drop the lock and return -ERESTART periodically
> there
> >> is little point in immediately failing an assignment operation with
> >> -ERESTART just because the pcidevs lock could not be acquired (for the
> >> second time, having already blocked on acquiring the lock in
> >> device_assigned()).
> >>
> >> This patch instead acquires the lock once for assignment (or test
> assign)
> >> operations directly in iommu_do_pci_domctl() and thus can remove the
> >> duplicate domain ownership check in assign_device(). Whilst in the
> >> neighbourhood, the patch also removes some debug logging from
> >> assign_device() and deassign_device() and replaces it with proper error
> >> logging, which allows error logging in iommu_do_pci_domctl() to be
> >> removed. Also, since device_assigned() can tell the difference between
> a
> >> guest assigned device and a non-existent one, log the actual error
> >> condition rather then being ambiguous for the sake a few extra lines of
> >> code.
> >>
> >> Signed-off-by: Paul Durrant <pdurrant@amazon.com>
> >> ---
> >>
> >> This is XSA-302 followup and contains some changes important for
> >> XenServer.
> >> Juergen, could this be considered for 4.13 inclusion?
> >>
> >> v2: updated Paul's email address
> 
> This was work you did at Citrix, yes?
> 
> > Reviewed-by: Paul Durrant <pdurrant@amazon.com>
> 
> SoB and R-by?

I did do the work while I was at Citrix, but surely the SoB must be updated since the patch is only now being posted? As for the R-b, why should that be historic?

  Paul

> 
> ~Andrew
Anthony PERARD Nov. 4, 2019, 12:14 p.m. UTC | #4
On Mon, Nov 04, 2019 at 11:13:48AM +0000, Durrant, Paul wrote:
> > -----Original Message-----
> > From: Andrew Cooper <andrew.cooper3@citrix.com>
> > Sent: 04 November 2019 11:06
> > To: Durrant, Paul <pdurrant@amazon.com>; xen-devel@lists.xenproject.org
> > Cc: Igor Druzhinin <igor.druzhinin@citrix.com>; jgross@suse.com;
> > jbeulich@suse.com
> > Subject: Re: [Xen-devel] [PATCH for-4.13 v2] passthrough: simplify locking
> > and logging
> > 
> > On 04/11/2019 08:31, Durrant, Paul wrote:
> > >> -----Original Message-----
> > >> From: Igor Druzhinin <igor.druzhinin@citrix.com>
> > >> Sent: 01 November 2019 19:28
> > >> To: xen-devel@lists.xenproject.org
> > >> Cc: Durrant, Paul <pdurrant@amazon.com>; jbeulich@suse.com;
> > >> jgross@suse.com
> > >> Subject: [PATCH for-4.13 v2] passthrough: simplify locking and logging
> > >>
> > >> From: Paul Durrant <pdurrant@amazon.com>
> > >>
> > >>
> > >> Signed-off-by: Paul Durrant <pdurrant@amazon.com>
> > >> ---
> > >>
> > >>
> > >> v2: updated Paul's email address
> > 
> > This was work you did at Citrix, yes?
> > 
> > > Reviewed-by: Paul Durrant <pdurrant@amazon.com>
> > 
> > SoB and R-by?
> 
> I did do the work while I was at Citrix, but surely the SoB must be updated since the patch is only now being posted?

I don't think it matters when a patch is publicly posted, the SoB
shouldn't change.
Also, Igor, I think you need to add your own SoB to the patch. This would
be because of (b) or (c) of the "Developer's Certificate of Origin 1.1" [1].

> As for the R-b, why should that be historic?

I think he meant that reviewing your own work is a bit weird. On the
other hand, it is possible to have both a SoB and a R-b from the same
persone, if the original patch has been modified.


[1]:
Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.


Cheers,
Paul Durrant Nov. 4, 2019, 12:36 p.m. UTC | #5
> -----Original Message-----
> From: Anthony PERARD <anthony.perard@citrix.com>
> Sent: 04 November 2019 12:14
> To: Durrant, Paul <pdurrant@amazon.com>
> Cc: Andrew Cooper <andrew.cooper3@citrix.com>; xen-
> devel@lists.xenproject.org; jgross@suse.com; Igor Druzhinin
> <igor.druzhinin@citrix.com>; jbeulich@suse.com
> Subject: Re: [Xen-devel] [PATCH for-4.13 v2] passthrough: simplify locking
> and logging
> 
> On Mon, Nov 04, 2019 at 11:13:48AM +0000, Durrant, Paul wrote:
> > > -----Original Message-----
> > > From: Andrew Cooper <andrew.cooper3@citrix.com>
> > > Sent: 04 November 2019 11:06
> > > To: Durrant, Paul <pdurrant@amazon.com>; xen-
> devel@lists.xenproject.org
> > > Cc: Igor Druzhinin <igor.druzhinin@citrix.com>; jgross@suse.com;
> > > jbeulich@suse.com
> > > Subject: Re: [Xen-devel] [PATCH for-4.13 v2] passthrough: simplify
> locking
> > > and logging
> > >
> > > On 04/11/2019 08:31, Durrant, Paul wrote:
> > > >> -----Original Message-----
> > > >> From: Igor Druzhinin <igor.druzhinin@citrix.com>
> > > >> Sent: 01 November 2019 19:28
> > > >> To: xen-devel@lists.xenproject.org
> > > >> Cc: Durrant, Paul <pdurrant@amazon.com>; jbeulich@suse.com;
> > > >> jgross@suse.com
> > > >> Subject: [PATCH for-4.13 v2] passthrough: simplify locking and
> logging
> > > >>
> > > >> From: Paul Durrant <pdurrant@amazon.com>
> > > >>
> > > >>
> > > >> Signed-off-by: Paul Durrant <pdurrant@amazon.com>
> > > >> ---
> > > >>
> > > >>
> > > >> v2: updated Paul's email address
> > >
> > > This was work you did at Citrix, yes?
> > >
> > > > Reviewed-by: Paul Durrant <pdurrant@amazon.com>
> > >
> > > SoB and R-by?
> >
> > I did do the work while I was at Citrix, but surely the SoB must be
> updated since the patch is only now being posted?
> 
> I don't think it matters when a patch is publicly posted, the SoB
> shouldn't change.
> Also, Igor, I think you need to add your own SoB to the patch. This would
> be because of (b) or (c) of the "Developer's Certificate of Origin 1.1"
> [1].
> 
> > As for the R-b, why should that be historic?
> 
> I think he meant that reviewing your own work is a bit weird. On the
> other hand, it is possible to have both a SoB and a R-b from the same
> persone, if the original patch has been modified.

I was merely reviewing the change of email address and verifying that it was the patch I wrote :-)

 Paul

> 
> 
> [1]:
> Developer's Certificate of Origin 1.1
> 
> By making a contribution to this project, I certify that:
> 
> (a) The contribution was created in whole or in part by me and I
>     have the right to submit it under the open source license
>     indicated in the file; or
> 
> (b) The contribution is based upon previous work that, to the best
>     of my knowledge, is covered under an appropriate open source
>     license and I have the right under that license to submit that
>     work with modifications, whether created in whole or in part
>     by me, under the same open source license (unless I am
>     permitted to submit under a different license), as indicated
>     in the file; or
> 
> (c) The contribution was provided directly to me by some other
>     person who certified (a), (b) or (c) and I have not modified
>     it.
> 
> (d) I understand and agree that this project and the contribution
>     are public and that a record of the contribution (including all
>     personal information I submit with it, including my sign-off) is
>     maintained indefinitely and may be redistributed consistent with
>     this project or the open source license(s) involved.
> 
> 
> Cheers,
> 
> --
> Anthony PERARD
Jan Beulich Nov. 7, 2019, 3:16 p.m. UTC | #6
On 01.11.2019 19:28, Igor Druzhinin wrote:
> This patch instead acquires the lock once for assignment (or test assign)
> operations directly in iommu_do_pci_domctl() and thus can remove the
> duplicate domain ownership check in assign_device(). Whilst in the
> neighbourhood, the patch also removes some debug logging from
> assign_device() and deassign_device() and replaces it with proper error
> logging, which allows error logging in iommu_do_pci_domctl() to be
> removed. Also, since device_assigned() can tell the difference between a
> guest assigned device and a non-existent one, log the actual error
> condition rather then being ambiguous for the sake a few extra lines of
> code.

In this last sentence it looks like you mean the caller of
device_assigned(), not the function itself.

> --- a/xen/drivers/passthrough/pci.c
> +++ b/xen/drivers/passthrough/pci.c
> @@ -932,30 +932,27 @@ static int deassign_device(struct domain *d, uint16_t seg, uint8_t bus,
>              break;
>          ret = hd->platform_ops->reassign_device(d, target, devfn,
>                                                  pci_to_dev(pdev));
> -        if ( !ret )
> -            continue;
> -
> -        printk(XENLOG_G_ERR "%pd: deassign %04x:%02x:%02x.%u failed (%d)\n",
> -               d, seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), ret);
> -        return ret;
> +        if ( ret )
> +            goto out;
>      }
>  
>      devfn = pdev->devfn;
>      ret = hd->platform_ops->reassign_device(d, target, devfn,
>                                              pci_to_dev(pdev));
>      if ( ret )
> -    {
> -        dprintk(XENLOG_G_ERR,
> -                "%pd: deassign device (%04x:%02x:%02x.%u) failed\n",
> -                d, seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
> -        return ret;
> -    }
> +        goto out;
>  
>      if ( pdev->domain == hardware_domain  )
>          pdev->quarantine = false;
>  
>      pdev->fault.count = 0;
>  
> +out:
> +    if ( ret )
> +        printk(XENLOG_G_ERR
> +               "%pd: deassign device (%04x:%02x:%02x.%u) failed (%d)\n", d,
> +               seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), ret);
> +
>      return ret;
>  }

There would have been quite a bit less code churn if you simply
replaced the dprintk(). If you really want to stick to the goto
approach you're introducing (which I dislike, but I know others
prefer it in cases like this one), then please indent the label and
shorten the message to the one that was used in the original printk().

> @@ -1549,11 +1542,10 @@ static int device_assigned(u16 seg, u8 bus, u8 devfn)
>                pdev->domain != dom_io )
>          rc = -EBUSY;
>  
> -    pcidevs_unlock();
> -
>      return rc;
>  }
>  
> +/* caller should hold the pcidevs_lock */
>  static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag)

Just like the comment ahead of deassign_device(), this one should
start with a capital letter.

> @@ -1608,19 +1588,17 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag)
>          if ( PCI_SLOT(devfn) != PCI_SLOT(pdev->devfn) )
>              break;
>          rc = hd->platform_ops->assign_device(d, devfn, pci_to_dev(pdev), flag);
> -        if ( rc )
> -            printk(XENLOG_G_WARNING "d%d: assign %04x:%02x:%02x.%u failed (%d)\n",
> -                   d->domain_id, seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
> -                   rc);
>      }
>  
>   done:
> +    if ( rc )
> +        printk(XENLOG_G_ERR
> +               "%pd: assign device (%04x:%02x:%02x.%u) failed (%d)\n", d,
> +               seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), rc);

I'd prefer if we could stick to this being XENLOG_G_WARNING: Other
than device de-assignment failure, assignment failure is unlikely
to be an issue to the host as a whole. Also please again shorten
the message to what it was before.

> @@ -1776,29 +1754,40 @@ int iommu_do_pci_domctl(
>          bus = PCI_BUS(machine_sbdf);
>          devfn = PCI_DEVFN2(machine_sbdf);
>  
> +        pcidevs_lock();
>          ret = device_assigned(seg, bus, devfn);
>          if ( domctl->cmd == XEN_DOMCTL_test_assign_device )
>          {
> -            if ( ret )
> +            switch ( ret )
>              {
> +            case 0:
> +                break;
> +
> +            case -ENODEV:
>                  printk(XENLOG_G_INFO
> -                       "%04x:%02x:%02x.%u already assigned, or non-existent\n",
> +                       "%04x:%02x:%02x.%u non-existent\n",
>                         seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
>                  ret = -EINVAL;
> +                break;
> +
> +            case -EBUSY:
> +                printk(XENLOG_G_INFO
> +                       "%04x:%02x:%02x.%u already assigned\n",
> +                       seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
> +                ret = -EINVAL;
> +                break;
> +
> +            default:
> +                ret = -EINVAL;
> +                break;
>              }

Three separate but identical assignments to ret look a little odd at
least. Is there a reason why we need to (continue to) convert the
original error code? I can't seem to be able to find any after some
looking around, but I surely may have missed something.

Jan
diff mbox series

Patch

diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
index e64666d..ea0770d 100644
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -932,30 +932,27 @@  static int deassign_device(struct domain *d, uint16_t seg, uint8_t bus,
             break;
         ret = hd->platform_ops->reassign_device(d, target, devfn,
                                                 pci_to_dev(pdev));
-        if ( !ret )
-            continue;
-
-        printk(XENLOG_G_ERR "%pd: deassign %04x:%02x:%02x.%u failed (%d)\n",
-               d, seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), ret);
-        return ret;
+        if ( ret )
+            goto out;
     }
 
     devfn = pdev->devfn;
     ret = hd->platform_ops->reassign_device(d, target, devfn,
                                             pci_to_dev(pdev));
     if ( ret )
-    {
-        dprintk(XENLOG_G_ERR,
-                "%pd: deassign device (%04x:%02x:%02x.%u) failed\n",
-                d, seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
-        return ret;
-    }
+        goto out;
 
     if ( pdev->domain == hardware_domain  )
         pdev->quarantine = false;
 
     pdev->fault.count = 0;
 
+out:
+    if ( ret )
+        printk(XENLOG_G_ERR
+               "%pd: deassign device (%04x:%02x:%02x.%u) failed (%d)\n", d,
+               seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), ret);
+
     return ret;
 }
 
@@ -976,10 +973,7 @@  int pci_release_devices(struct domain *d)
     {
         bus = pdev->bus;
         devfn = pdev->devfn;
-        if ( deassign_device(d, pdev->seg, bus, devfn) )
-            printk("domain %d: deassign device (%04x:%02x:%02x.%u) failed!\n",
-                   d->domain_id, pdev->seg, bus,
-                   PCI_SLOT(devfn), PCI_FUNC(devfn));
+        deassign_device(d, pdev->seg, bus, devfn);
     }
     pcidevs_unlock();
 
@@ -1534,8 +1528,7 @@  static int device_assigned(u16 seg, u8 bus, u8 devfn)
     struct pci_dev *pdev;
     int rc = 0;
 
-    pcidevs_lock();
-
+    ASSERT(pcidevs_locked());
     pdev = pci_get_pdev(seg, bus, devfn);
 
     if ( !pdev )
@@ -1549,11 +1542,10 @@  static int device_assigned(u16 seg, u8 bus, u8 devfn)
               pdev->domain != dom_io )
         rc = -EBUSY;
 
-    pcidevs_unlock();
-
     return rc;
 }
 
+/* caller should hold the pcidevs_lock */
 static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag)
 {
     const struct domain_iommu *hd = dom_iommu(d);
@@ -1571,23 +1563,11 @@  static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag)
                   vm_event_check_ring(d->vm_event_paging)) )
         return -EXDEV;
 
-    if ( !pcidevs_trylock() )
-        return -ERESTART;
-
+    /* device_assigned() should already have cleared the device for assignment */
+    ASSERT(pcidevs_locked());
     pdev = pci_get_pdev(seg, bus, devfn);
-
-    rc = -ENODEV;
-    if ( !pdev )
-        goto done;
-
-    rc = 0;
-    if ( d == pdev->domain )
-        goto done;
-
-    rc = -EBUSY;
-    if ( pdev->domain != hardware_domain &&
-         pdev->domain != dom_io )
-        goto done;
+    ASSERT(pdev && (pdev->domain == hardware_domain ||
+                    pdev->domain == dom_io));
 
     if ( pdev->msix )
     {
@@ -1608,19 +1588,17 @@  static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag)
         if ( PCI_SLOT(devfn) != PCI_SLOT(pdev->devfn) )
             break;
         rc = hd->platform_ops->assign_device(d, devfn, pci_to_dev(pdev), flag);
-        if ( rc )
-            printk(XENLOG_G_WARNING "d%d: assign %04x:%02x:%02x.%u failed (%d)\n",
-                   d->domain_id, seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
-                   rc);
     }
 
  done:
+    if ( rc )
+        printk(XENLOG_G_ERR
+               "%pd: assign device (%04x:%02x:%02x.%u) failed (%d)\n", d,
+               seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn), rc);
     /* The device is assigned to dom_io so mark it as quarantined */
-    if ( !rc && d == dom_io )
+    else if ( d == dom_io )
         pdev->quarantine = true;
 
-    pcidevs_unlock();
-
     return rc;
 }
 
@@ -1776,29 +1754,40 @@  int iommu_do_pci_domctl(
         bus = PCI_BUS(machine_sbdf);
         devfn = PCI_DEVFN2(machine_sbdf);
 
+        pcidevs_lock();
         ret = device_assigned(seg, bus, devfn);
         if ( domctl->cmd == XEN_DOMCTL_test_assign_device )
         {
-            if ( ret )
+            switch ( ret )
             {
+            case 0:
+                break;
+
+            case -ENODEV:
                 printk(XENLOG_G_INFO
-                       "%04x:%02x:%02x.%u already assigned, or non-existent\n",
+                       "%04x:%02x:%02x.%u non-existent\n",
                        seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
                 ret = -EINVAL;
+                break;
+
+            case -EBUSY:
+                printk(XENLOG_G_INFO
+                       "%04x:%02x:%02x.%u already assigned\n",
+                       seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+                ret = -EINVAL;
+                break;
+
+            default:
+                ret = -EINVAL;
+                break;
             }
-            break;
         }
-        if ( !ret )
+        else if ( !ret )
             ret = assign_device(d, seg, bus, devfn, flags);
+        pcidevs_unlock();
         if ( ret == -ERESTART )
             ret = hypercall_create_continuation(__HYPERVISOR_domctl,
                                                 "h", u_domctl);
-        else if ( ret )
-            printk(XENLOG_G_ERR
-                   "assign %04x:%02x:%02x.%u to dom%d failed (%d)\n",
-                   seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
-                   d->domain_id, ret);
-
         break;
 
     case XEN_DOMCTL_deassign_device:
@@ -1830,12 +1819,6 @@  int iommu_do_pci_domctl(
         pcidevs_lock();
         ret = deassign_device(d, seg, bus, devfn);
         pcidevs_unlock();
-        if ( ret )
-            printk(XENLOG_G_ERR
-                   "deassign %04x:%02x:%02x.%u from dom%d failed (%d)\n",
-                   seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
-                   d->domain_id, ret);
-
         break;
 
     default: