diff mbox

vmw_pvrdma: Release netdev when vmxnet3 module is removed

Message ID 20180628135938.19625-1-nhorman@tuxdriver.com (mailing list archive)
State Changes Requested
Headers show

Commit Message

Neil Horman June 28, 2018, 1:59 p.m. UTC
On repeated module load/unload cycles, its possible for the pvrmda
driver to encounter this crash:

...
297.032448] RIP: 0010:[<ffffffff839e4620>]  [<ffffffff839e4620>] netdev_walk_all_upper_dev_rcu+0x50/0xb0
[  297.034078] RSP: 0018:ffff95087780bd08  EFLAGS: 00010286
[  297.034986] RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffff95087a0c0000
[  297.036196] RDX: ffff95087a0c0000 RSI: ffffffff839e44e0 RDI: ffff950835d0c000
[  297.037421] RBP: ffff95087780bd40 R08: ffff95087a0e0ea0 R09: abddacd03f8e0ea0
[  297.038636] R10: abddacd03f8e0ea0 R11: ffffef5901e9dbc0 R12: ffff95087a0c0000
[  297.039854] R13: ffffffff839e44e0 R14: ffff95087a0c0000 R15: ffff950835d0c828
[  297.041071] FS:  0000000000000000(0000) GS:ffff95087fc00000(0000) knlGS:0000000000000000
[  297.042443] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  297.043429] CR2: ffffffffffffffe8 CR3: 000000007a652000 CR4: 00000000003607f0
[  297.044674] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[  297.045893] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[  297.047109] Call Trace:
[  297.047545]  [<ffffffff839e4698>] netdev_has_upper_dev_all_rcu+0x18/0x20
[  297.048691]  [<ffffffffc05d31af>] is_eth_port_of_netdev+0x2f/0xa0 [ib_core]
[  297.049886]  [<ffffffffc05d3180>] ? is_eth_active_slave_of_bonding_rcu+0x70/0x70 [ib_core]
...

This occurs because vmw_pvrdma on probe stores a pointer to the netdev
that exists on function 0 of the same bus/device/slot (which represents
the vmxnet3 ethernet driver).  However, it never removes this pointer if
the vmxnet3 module is removed, leading to crashes resulting from use
after free dereferencing incidents like the one above.

The fix is pretty straightforward.  vmw_pvrdma should listen for
NETDEV_REGISTER and NETDEV_UNREGISTER events in its event listener code
block, and update the stored netdev pointer accordingly.  This solution
has been tested by myself and the reporter with successful results.
This fix also allows the pvrdma driver to find its underlying ethernet
device in the event that vmxnet3 is loaded after pvrdma, which it was
not able to do before.

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
Reported-by: ruquin@redhat.com
CC: Adit Ranadive <aditr@vmware.com>
CC: VMware PV-Drivers <pv-drivers@vmware.com>
CC: Doug Ledford <dledford@redhat.com>
CC: Jason Gunthorpe <jgg@ziepe.ca>
CC: linux-kernel@vger.kernel.org
---
 .../infiniband/hw/vmw_pvrdma/pvrdma_main.c    | 25 +++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)

Comments

Jason Gunthorpe June 28, 2018, 6:59 p.m. UTC | #1
On Thu, Jun 28, 2018 at 09:59:38AM -0400, Neil Horman wrote:
> On repeated module load/unload cycles, its possible for the pvrmda
> driver to encounter this crash:
> 
> ...
> 297.032448] RIP: 0010:[<ffffffff839e4620>]  [<ffffffff839e4620>] netdev_walk_all_upper_dev_rcu+0x50/0xb0
> [  297.034078] RSP: 0018:ffff95087780bd08  EFLAGS: 00010286
> [  297.034986] RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffff95087a0c0000
> [  297.036196] RDX: ffff95087a0c0000 RSI: ffffffff839e44e0 RDI: ffff950835d0c000
> [  297.037421] RBP: ffff95087780bd40 R08: ffff95087a0e0ea0 R09: abddacd03f8e0ea0
> [  297.038636] R10: abddacd03f8e0ea0 R11: ffffef5901e9dbc0 R12: ffff95087a0c0000
> [  297.039854] R13: ffffffff839e44e0 R14: ffff95087a0c0000 R15: ffff950835d0c828
> [  297.041071] FS:  0000000000000000(0000) GS:ffff95087fc00000(0000) knlGS:0000000000000000
> [  297.042443] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [  297.043429] CR2: ffffffffffffffe8 CR3: 000000007a652000 CR4: 00000000003607f0
> [  297.044674] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> [  297.045893] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> [  297.047109] Call Trace:
> [  297.047545]  [<ffffffff839e4698>] netdev_has_upper_dev_all_rcu+0x18/0x20
> [  297.048691]  [<ffffffffc05d31af>] is_eth_port_of_netdev+0x2f/0xa0 [ib_core]
> [  297.049886]  [<ffffffffc05d3180>] ? is_eth_active_slave_of_bonding_rcu+0x70/0x70 [ib_core]
> ...
> 
> This occurs because vmw_pvrdma on probe stores a pointer to the netdev
> that exists on function 0 of the same bus/device/slot (which represents
> the vmxnet3 ethernet driver).  However, it never removes this pointer if
> the vmxnet3 module is removed, leading to crashes resulting from use
> after free dereferencing incidents like the one above.
> 
> The fix is pretty straightforward.  vmw_pvrdma should listen for
> NETDEV_REGISTER and NETDEV_UNREGISTER events in its event listener code
> block, and update the stored netdev pointer accordingly.  This solution
> has been tested by myself and the reporter with successful results.
> This fix also allows the pvrdma driver to find its underlying ethernet
> device in the event that vmxnet3 is loaded after pvrdma, which it was
> not able to do before.
> 
> Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> Reported-by: ruquin@redhat.com
> CC: Adit Ranadive <aditr@vmware.com>
> CC: VMware PV-Drivers <pv-drivers@vmware.com>
> CC: Doug Ledford <dledford@redhat.com>
> CC: Jason Gunthorpe <jgg@ziepe.ca>
> CC: linux-kernel@vger.kernel.org
>  .../infiniband/hw/vmw_pvrdma/pvrdma_main.c    | 25 +++++++++++++++++--
>  1 file changed, 23 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
> index 0be33a81bbe6..5b4782078a74 100644
> +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
> @@ -699,8 +699,12 @@ static int pvrdma_del_gid(const struct ib_gid_attr *attr, void **context)
>  }
>  
>  static void pvrdma_netdevice_event_handle(struct pvrdma_dev *dev,
> +					  struct net_device *ndev,
>  					  unsigned long event)
>  {
> +	struct pci_dev *pdev_net;
> +
> +
>  	switch (event) {
>  	case NETDEV_REBOOT:
>  	case NETDEV_DOWN:
> @@ -718,6 +722,21 @@ static void pvrdma_netdevice_event_handle(struct pvrdma_dev *dev,
>  		else
>  			pvrdma_dispatch_event(dev, 1, IB_EVENT_PORT_ACTIVE);
>  		break;
> +	case NETDEV_UNREGISTER:
> +		dev_put(dev->netdev);
> +		dev->netdev = NULL;
> +		break;
> +	case NETDEV_REGISTER:
> +		/* Paired vmxnet3 will have same bus, slot. But func will be 0 */
> +		pdev_net = pci_get_slot(dev->pdev->bus, PCI_DEVFN(PCI_SLOT(dev->pdev->devfn), 0));
> +		if ((dev->netdev == NULL) && (pci_get_drvdata(pdev_net) == ndev)) {
> +			/* this is our netdev */
> +			dev->netdev = ndev;
> +			dev_hold(ndev);
> +		}
> +		pci_dev_put(pdev_net);
> +		break;
> +
>  	default:
>  		dev_dbg(&dev->pdev->dev, "ignore netdevice event %ld on %s\n",
>  			event, dev->ib_dev.name);
> @@ -734,8 +753,9 @@ static void pvrdma_netdevice_event_work(struct work_struct *work)
>  
>  	mutex_lock(&pvrdma_device_list_lock);
>  	list_for_each_entry(dev, &pvrdma_device_list, device_link) {
> -		if (dev->netdev == netdev_work->event_netdev) {
> -			pvrdma_netdevice_event_handle(dev, netdev_work->event);
> +		if ((netdev_work->event == NETDEV_REGISTER) ||
> +		    (dev->netdev == netdev_work->event_netdev)) {
> +			pvrdma_netdevice_event_handle(dev, netdev_work->event_netdev, netdev_work->event);
>  			break;
>  		}
>  	}
> @@ -962,6 +982,7 @@ static int pvrdma_pci_probe(struct pci_dev *pdev,
>  	}
>  
>  	dev->netdev = pci_get_drvdata(pdev_net);
> +	dev_hold(dev->netdev);
>  	pci_dev_put(pdev_net);
>  	if (!dev->netdev) {
>  		dev_err(&pdev->dev, "failed to get vmxnet3 device\n");

I see a lot of new dev_hold's here, where are the matching
dev_puts()?

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Neil Horman June 28, 2018, 7:45 p.m. UTC | #2
On Thu, Jun 28, 2018 at 12:59:46PM -0600, Jason Gunthorpe wrote:
> On Thu, Jun 28, 2018 at 09:59:38AM -0400, Neil Horman wrote:
> > On repeated module load/unload cycles, its possible for the pvrmda
> > driver to encounter this crash:
> > 
> > ...
> > 297.032448] RIP: 0010:[<ffffffff839e4620>]  [<ffffffff839e4620>] netdev_walk_all_upper_dev_rcu+0x50/0xb0
> > [  297.034078] RSP: 0018:ffff95087780bd08  EFLAGS: 00010286
> > [  297.034986] RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffff95087a0c0000
> > [  297.036196] RDX: ffff95087a0c0000 RSI: ffffffff839e44e0 RDI: ffff950835d0c000
> > [  297.037421] RBP: ffff95087780bd40 R08: ffff95087a0e0ea0 R09: abddacd03f8e0ea0
> > [  297.038636] R10: abddacd03f8e0ea0 R11: ffffef5901e9dbc0 R12: ffff95087a0c0000
> > [  297.039854] R13: ffffffff839e44e0 R14: ffff95087a0c0000 R15: ffff950835d0c828
> > [  297.041071] FS:  0000000000000000(0000) GS:ffff95087fc00000(0000) knlGS:0000000000000000
> > [  297.042443] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > [  297.043429] CR2: ffffffffffffffe8 CR3: 000000007a652000 CR4: 00000000003607f0
> > [  297.044674] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> > [  297.045893] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> > [  297.047109] Call Trace:
> > [  297.047545]  [<ffffffff839e4698>] netdev_has_upper_dev_all_rcu+0x18/0x20
> > [  297.048691]  [<ffffffffc05d31af>] is_eth_port_of_netdev+0x2f/0xa0 [ib_core]
> > [  297.049886]  [<ffffffffc05d3180>] ? is_eth_active_slave_of_bonding_rcu+0x70/0x70 [ib_core]
> > ...
> > 
> > This occurs because vmw_pvrdma on probe stores a pointer to the netdev
> > that exists on function 0 of the same bus/device/slot (which represents
> > the vmxnet3 ethernet driver).  However, it never removes this pointer if
> > the vmxnet3 module is removed, leading to crashes resulting from use
> > after free dereferencing incidents like the one above.
> > 
> > The fix is pretty straightforward.  vmw_pvrdma should listen for
> > NETDEV_REGISTER and NETDEV_UNREGISTER events in its event listener code
> > block, and update the stored netdev pointer accordingly.  This solution
> > has been tested by myself and the reporter with successful results.
> > This fix also allows the pvrdma driver to find its underlying ethernet
> > device in the event that vmxnet3 is loaded after pvrdma, which it was
> > not able to do before.
> > 
> > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> > Reported-by: ruquin@redhat.com
> > CC: Adit Ranadive <aditr@vmware.com>
> > CC: VMware PV-Drivers <pv-drivers@vmware.com>
> > CC: Doug Ledford <dledford@redhat.com>
> > CC: Jason Gunthorpe <jgg@ziepe.ca>
> > CC: linux-kernel@vger.kernel.org
> >  .../infiniband/hw/vmw_pvrdma/pvrdma_main.c    | 25 +++++++++++++++++--
> >  1 file changed, 23 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
> > index 0be33a81bbe6..5b4782078a74 100644
> > +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
> > @@ -699,8 +699,12 @@ static int pvrdma_del_gid(const struct ib_gid_attr *attr, void **context)
> >  }
> >  
> >  static void pvrdma_netdevice_event_handle(struct pvrdma_dev *dev,
> > +					  struct net_device *ndev,
> >  					  unsigned long event)
> >  {
> > +	struct pci_dev *pdev_net;
> > +
> > +
> >  	switch (event) {
> >  	case NETDEV_REBOOT:
> >  	case NETDEV_DOWN:
> > @@ -718,6 +722,21 @@ static void pvrdma_netdevice_event_handle(struct pvrdma_dev *dev,
> >  		else
> >  			pvrdma_dispatch_event(dev, 1, IB_EVENT_PORT_ACTIVE);
> >  		break;
> > +	case NETDEV_UNREGISTER:
> > +		dev_put(dev->netdev);
> > +		dev->netdev = NULL;
> > +		break;
> > +	case NETDEV_REGISTER:
> > +		/* Paired vmxnet3 will have same bus, slot. But func will be 0 */
> > +		pdev_net = pci_get_slot(dev->pdev->bus, PCI_DEVFN(PCI_SLOT(dev->pdev->devfn), 0));
> > +		if ((dev->netdev == NULL) && (pci_get_drvdata(pdev_net) == ndev)) {
> > +			/* this is our netdev */
> > +			dev->netdev = ndev;
> > +			dev_hold(ndev);
> > +		}
> > +		pci_dev_put(pdev_net);
> > +		break;
> > +
> >  	default:
> >  		dev_dbg(&dev->pdev->dev, "ignore netdevice event %ld on %s\n",
> >  			event, dev->ib_dev.name);
> > @@ -734,8 +753,9 @@ static void pvrdma_netdevice_event_work(struct work_struct *work)
> >  
> >  	mutex_lock(&pvrdma_device_list_lock);
> >  	list_for_each_entry(dev, &pvrdma_device_list, device_link) {
> > -		if (dev->netdev == netdev_work->event_netdev) {
> > -			pvrdma_netdevice_event_handle(dev, netdev_work->event);
> > +		if ((netdev_work->event == NETDEV_REGISTER) ||
> > +		    (dev->netdev == netdev_work->event_netdev)) {
> > +			pvrdma_netdevice_event_handle(dev, netdev_work->event_netdev, netdev_work->event);
> >  			break;
> >  		}
> >  	}
> > @@ -962,6 +982,7 @@ static int pvrdma_pci_probe(struct pci_dev *pdev,
> >  	}
> >  
> >  	dev->netdev = pci_get_drvdata(pdev_net);
> > +	dev_hold(dev->netdev);
> >  	pci_dev_put(pdev_net);
> >  	if (!dev->netdev) {
> >  		dev_err(&pdev->dev, "failed to get vmxnet3 device\n");
> 
> I see a lot of new dev_hold's here, where are the matching
> dev_puts()?
> 
I'm not sure I'd call 2 alot, but sure, there is a new dev_hold in the
pvrdma_pci_probe routine, to hold a reference to the netdev that is looked up
there.  It is balanced by the NETDEV_UNREGISTER case in
pvrdma_netdevice_event_handle.  The UNREGISTER clause is also balancing the
NETDEV_REGISTER case of the hanlder that looks up the matching netdev should a
new device be registered.  Note that we will only hold a single device at a
time, because a given pvrdma device only recongnizes a single vmxnet3 device
(the one on function 0 of its own bus/device tuple).

Note also that, under normal circumstances, the dev_hold/dev_put pair isn't
needed, but in this case it is, because pvrdma for some reason defers net event
notifications to a work queue that executes after the notifier chain completes.

Neil

> Jason
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jason Gunthorpe June 28, 2018, 8:37 p.m. UTC | #3
On Thu, Jun 28, 2018 at 03:45:26PM -0400, Neil Horman wrote:
> On Thu, Jun 28, 2018 at 12:59:46PM -0600, Jason Gunthorpe wrote:
> > On Thu, Jun 28, 2018 at 09:59:38AM -0400, Neil Horman wrote:
> > > On repeated module load/unload cycles, its possible for the pvrmda
> > > driver to encounter this crash:
> > > 
> > > ...
> > > 297.032448] RIP: 0010:[<ffffffff839e4620>]  [<ffffffff839e4620>] netdev_walk_all_upper_dev_rcu+0x50/0xb0
> > > [  297.034078] RSP: 0018:ffff95087780bd08  EFLAGS: 00010286
> > > [  297.034986] RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffff95087a0c0000
> > > [  297.036196] RDX: ffff95087a0c0000 RSI: ffffffff839e44e0 RDI: ffff950835d0c000
> > > [  297.037421] RBP: ffff95087780bd40 R08: ffff95087a0e0ea0 R09: abddacd03f8e0ea0
> > > [  297.038636] R10: abddacd03f8e0ea0 R11: ffffef5901e9dbc0 R12: ffff95087a0c0000
> > > [  297.039854] R13: ffffffff839e44e0 R14: ffff95087a0c0000 R15: ffff950835d0c828
> > > [  297.041071] FS:  0000000000000000(0000) GS:ffff95087fc00000(0000) knlGS:0000000000000000
> > > [  297.042443] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > > [  297.043429] CR2: ffffffffffffffe8 CR3: 000000007a652000 CR4: 00000000003607f0
> > > [  297.044674] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> > > [  297.045893] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> > > [  297.047109] Call Trace:
> > > [  297.047545]  [<ffffffff839e4698>] netdev_has_upper_dev_all_rcu+0x18/0x20
> > > [  297.048691]  [<ffffffffc05d31af>] is_eth_port_of_netdev+0x2f/0xa0 [ib_core]
> > > [  297.049886]  [<ffffffffc05d3180>] ? is_eth_active_slave_of_bonding_rcu+0x70/0x70 [ib_core]
> > > ...
> > > 
> > > This occurs because vmw_pvrdma on probe stores a pointer to the netdev
> > > that exists on function 0 of the same bus/device/slot (which represents
> > > the vmxnet3 ethernet driver).  However, it never removes this pointer if
> > > the vmxnet3 module is removed, leading to crashes resulting from use
> > > after free dereferencing incidents like the one above.
> > > 
> > > The fix is pretty straightforward.  vmw_pvrdma should listen for
> > > NETDEV_REGISTER and NETDEV_UNREGISTER events in its event listener code
> > > block, and update the stored netdev pointer accordingly.  This solution
> > > has been tested by myself and the reporter with successful results.
> > > This fix also allows the pvrdma driver to find its underlying ethernet
> > > device in the event that vmxnet3 is loaded after pvrdma, which it was
> > > not able to do before.
> > > 
> > > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> > > Reported-by: ruquin@redhat.com
> > > CC: Adit Ranadive <aditr@vmware.com>
> > > CC: VMware PV-Drivers <pv-drivers@vmware.com>
> > > CC: Doug Ledford <dledford@redhat.com>
> > > CC: Jason Gunthorpe <jgg@ziepe.ca>
> > > CC: linux-kernel@vger.kernel.org
> > >  .../infiniband/hw/vmw_pvrdma/pvrdma_main.c    | 25 +++++++++++++++++--
> > >  1 file changed, 23 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
> > > index 0be33a81bbe6..5b4782078a74 100644
> > > +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
> > > @@ -699,8 +699,12 @@ static int pvrdma_del_gid(const struct ib_gid_attr *attr, void **context)
> > >  }
> > >  
> > >  static void pvrdma_netdevice_event_handle(struct pvrdma_dev *dev,
> > > +					  struct net_device *ndev,
> > >  					  unsigned long event)
> > >  {
> > > +	struct pci_dev *pdev_net;
> > > +
> > > +
> > >  	switch (event) {
> > >  	case NETDEV_REBOOT:
> > >  	case NETDEV_DOWN:
> > > @@ -718,6 +722,21 @@ static void pvrdma_netdevice_event_handle(struct pvrdma_dev *dev,
> > >  		else
> > >  			pvrdma_dispatch_event(dev, 1, IB_EVENT_PORT_ACTIVE);
> > >  		break;
> > > +	case NETDEV_UNREGISTER:
> > > +		dev_put(dev->netdev);
> > > +		dev->netdev = NULL;
> > > +		break;
> > > +	case NETDEV_REGISTER:
> > > +		/* Paired vmxnet3 will have same bus, slot. But func will be 0 */
> > > +		pdev_net = pci_get_slot(dev->pdev->bus, PCI_DEVFN(PCI_SLOT(dev->pdev->devfn), 0));
> > > +		if ((dev->netdev == NULL) && (pci_get_drvdata(pdev_net) == ndev)) {
> > > +			/* this is our netdev */
> > > +			dev->netdev = ndev;
> > > +			dev_hold(ndev);
> > > +		}
> > > +		pci_dev_put(pdev_net);
> > > +		break;
> > > +
> > >  	default:
> > >  		dev_dbg(&dev->pdev->dev, "ignore netdevice event %ld on %s\n",
> > >  			event, dev->ib_dev.name);
> > > @@ -734,8 +753,9 @@ static void pvrdma_netdevice_event_work(struct work_struct *work)
> > >  
> > >  	mutex_lock(&pvrdma_device_list_lock);
> > >  	list_for_each_entry(dev, &pvrdma_device_list, device_link) {
> > > -		if (dev->netdev == netdev_work->event_netdev) {
> > > -			pvrdma_netdevice_event_handle(dev, netdev_work->event);
> > > +		if ((netdev_work->event == NETDEV_REGISTER) ||
> > > +		    (dev->netdev == netdev_work->event_netdev)) {
> > > +			pvrdma_netdevice_event_handle(dev, netdev_work->event_netdev, netdev_work->event);
> > >  			break;
> > >  		}
> > >  	}
> > > @@ -962,6 +982,7 @@ static int pvrdma_pci_probe(struct pci_dev *pdev,
> > >  	}
> > >  
> > >  	dev->netdev = pci_get_drvdata(pdev_net);
> > > +	dev_hold(dev->netdev);
> > >  	pci_dev_put(pdev_net);
> > >  	if (!dev->netdev) {
> > >  		dev_err(&pdev->dev, "failed to get vmxnet3 device\n");
> > 
> > I see a lot of new dev_hold's here, where are the matching
> > dev_puts()?
> > 
> I'm not sure I'd call 2 alot, but sure, there is a new dev_hold in the
> pvrdma_pci_probe routine, to hold a reference to the netdev that is looked up
> there.  It is balanced by the NETDEV_UNREGISTER case in
> pvrdma_netdevice_event_handle.  The UNREGISTER clause is also balancing the
> NETDEV_REGISTER case of the hanlder that looks up the matching netdev should a
> new device be registered.  Note that we will only hold a single device at a
> time, because a given pvrdma device only recongnizes a single vmxnet3 device
> (the one on function 0 of its own bus/device tuple).

I don't see how the dev_hold in pvrdma_pci_probe is undone during
error unwind (eg goto err_free_cq_ring)

And I don't see how it is put when pvrdma_pci_remove() is called.

Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Adit Ranadive June 28, 2018, 9:15 p.m. UTC | #4
T24gNi8yOC8xOCwgMTozNyBQTSwgIkphc29uIEd1bnRob3JwZSIgPGpnZ0B6aWVwZS5jYT4gd3Jv
dGU6DQo+IE9uIFRodSwgSnVuIDI4LCAyMDE4IGF0IDAzOjQ1OjI2UE0gLTA0MDAsIE5laWwgSG9y
bWFuIHdyb3RlOg0KPiA+IE9uIFRodSwgSnVuIDI4LCAyMDE4IGF0IDEyOjU5OjQ2UE0gLTA2MDAs
IEphc29uIEd1bnRob3JwZSB3cm90ZToNCj4gPiA+IE9uIFRodSwgSnVuIDI4LCAyMDE4IGF0IDA5
OjU5OjM4QU0gLTA0MDAsIE5laWwgSG9ybWFuIHdyb3RlOg0KPiA+ID4gPiBPbiByZXBlYXRlZCBt
b2R1bGUgbG9hZC91bmxvYWQgY3ljbGVzLCBpdHMgcG9zc2libGUgZm9yIHRoZSBwdnJtZGENCj4g
PiA+ID4gZHJpdmVyIHRvIGVuY291bnRlciB0aGlzIGNyYXNoOg0KPHNuaXA+DQo+ID4gPiA+IEBA
IC05NjIsNiArOTgyLDcgQEAgc3RhdGljIGludCBwdnJkbWFfcGNpX3Byb2JlKHN0cnVjdCBwY2lf
ZGV2ICpwZGV2LA0KPiA+ID4gPiAgCX0NCj4gPiA+ID4gIA0KPiA+ID4gPiAgCWRldi0+bmV0ZGV2
ID0gcGNpX2dldF9kcnZkYXRhKHBkZXZfbmV0KTsNCj4gPiA+ID4gKwlkZXZfaG9sZChkZXYtPm5l
dGRldik7DQoNClRoYXQgZG9lc24ndCBzZWVtIHJpZ2h0LiBJZiB0aGUgdm14bmV0MyBkcml2ZXIg
aXNuJ3QgbG9hZGVkIGF0IGFsbCBvciBmYWlsZWQNCnRvIGNyZWF0ZSBhIG5ldGRldiwgeW91IHdv
dWxkIGJlIHJlcXVlc3RpbmcgYSBob2xkIG9uIGEgTlVMTCBuZXRkZXYuIFdoYXQgaWYNCnlvdSBt
b3ZlZCB0aGlzIHRvIGFmdGVyIHRoZSBpZighZGV2LT5uZXRkZXYpIGNoZWNrPw0KDQo+ID4gPiA+
ICAJcGNpX2Rldl9wdXQocGRldl9uZXQpOw0KPiA+ID4gPiAgCWlmICghZGV2LT5uZXRkZXYpIHsN
Cj4gPiA+ID4gIAkJZGV2X2VycigmcGRldi0+ZGV2LCAiZmFpbGVkIHRvIGdldCB2bXhuZXQzIGRl
dmljZVxuIik7DQo+ID4gPiANCj4gPiA+IEkgc2VlIGEgbG90IG9mIG5ldyBkZXZfaG9sZCdzIGhl
cmUsIHdoZXJlIGFyZSB0aGUgbWF0Y2hpbmcNCj4gPiA+IGRldl9wdXRzKCk/DQo+ID4gPiANCj4g
SSdtIG5vdCBzdXJlIEknZCBjYWxsIDIgYWxvdCwgYnV0IHN1cmUsIHRoZXJlIGlzIGEgbmV3IGRl
dl9ob2xkIGluIHRoZQ0KPiBwdnJkbWFfcGNpX3Byb2JlIHJvdXRpbmUsIHRvIGhvbGQgYSByZWZl
cmVuY2UgdG8gdGhlIG5ldGRldiB0aGF0IGlzIGxvb2tlZCB1cA0KPiB0aGVyZS4gIEl0IGlzIGJh
bGFuY2VkIGJ5IHRoZSBORVRERVZfVU5SRUdJU1RFUiBjYXNlIGluDQo+IHB2cmRtYV9uZXRkZXZp
Y2VfZXZlbnRfaGFuZGxlLiAgVGhlIFVOUkVHSVNURVIgY2xhdXNlIGlzIGFsc28gYmFsYW5jaW5n
IHRoZQ0KPiBORVRERVZfUkVHSVNURVIgY2FzZSBvZiB0aGUgaGFubGRlciB0aGF0IGxvb2tzIHVw
IHRoZSBtYXRjaGluZyBuZXRkZXYgc2hvdWxkIGENCj4gbmV3IGRldmljZSBiZSByZWdpc3RlcmVk
LiAgTm90ZSB0aGF0IHdlIHdpbGwgb25seSBob2xkIGEgc2luZ2xlIGRldmljZSBhdCBhDQo+IHRp
bWUsIGJlY2F1c2UgYSBnaXZlbiBwdnJkbWEgZGV2aWNlIG9ubHkgcmVjb25nbml6ZXMgYSBzaW5n
bGUgdm14bmV0MyBkZXZpY2UNCj4gKHRoZSBvbmUgb24gZnVuY3Rpb24gMCBvZiBpdHMgb3duIGJ1
cy9kZXZpY2UgdHVwbGUpLg0KPiANCj4gSSBkb24ndCBzZWUgaG93IHRoZSBkZXZfaG9sZCBpbiBw
dnJkbWFfcGNpX3Byb2JlIGlzIHVuZG9uZSBkdXJpbmcNCj4gZXJyb3IgdW53aW5kIChlZyBnb3Rv
IGVycl9mcmVlX2NxX3JpbmcpDQo+IA0KPiBBbmQgSSBkb24ndCBzZWUgaG93IGl0IGlzIHB1dCB3
aGVuIHB2cmRtYV9wY2lfcmVtb3ZlKCkgaXMgY2FsbGVkLg0KDQpUaGF0J3MgcmlnaHQuIFRoZXNl
IHNlZW0gbWlzc2luZyBhcyB3ZWxsLiANCg0K
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Neil Horman June 29, 2018, 11:21 a.m. UTC | #5
On Thu, Jun 28, 2018 at 02:37:09PM -0600, Jason Gunthorpe wrote:
> On Thu, Jun 28, 2018 at 03:45:26PM -0400, Neil Horman wrote:
> > On Thu, Jun 28, 2018 at 12:59:46PM -0600, Jason Gunthorpe wrote:
> > > On Thu, Jun 28, 2018 at 09:59:38AM -0400, Neil Horman wrote:
> > > > On repeated module load/unload cycles, its possible for the pvrmda
> > > > driver to encounter this crash:
> > > > 
> > > > ...
> > > > 297.032448] RIP: 0010:[<ffffffff839e4620>]  [<ffffffff839e4620>] netdev_walk_all_upper_dev_rcu+0x50/0xb0
> > > > [  297.034078] RSP: 0018:ffff95087780bd08  EFLAGS: 00010286
> > > > [  297.034986] RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffff95087a0c0000
> > > > [  297.036196] RDX: ffff95087a0c0000 RSI: ffffffff839e44e0 RDI: ffff950835d0c000
> > > > [  297.037421] RBP: ffff95087780bd40 R08: ffff95087a0e0ea0 R09: abddacd03f8e0ea0
> > > > [  297.038636] R10: abddacd03f8e0ea0 R11: ffffef5901e9dbc0 R12: ffff95087a0c0000
> > > > [  297.039854] R13: ffffffff839e44e0 R14: ffff95087a0c0000 R15: ffff950835d0c828
> > > > [  297.041071] FS:  0000000000000000(0000) GS:ffff95087fc00000(0000) knlGS:0000000000000000
> > > > [  297.042443] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> > > > [  297.043429] CR2: ffffffffffffffe8 CR3: 000000007a652000 CR4: 00000000003607f0
> > > > [  297.044674] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> > > > [  297.045893] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> > > > [  297.047109] Call Trace:
> > > > [  297.047545]  [<ffffffff839e4698>] netdev_has_upper_dev_all_rcu+0x18/0x20
> > > > [  297.048691]  [<ffffffffc05d31af>] is_eth_port_of_netdev+0x2f/0xa0 [ib_core]
> > > > [  297.049886]  [<ffffffffc05d3180>] ? is_eth_active_slave_of_bonding_rcu+0x70/0x70 [ib_core]
> > > > ...
> > > > 
> > > > This occurs because vmw_pvrdma on probe stores a pointer to the netdev
> > > > that exists on function 0 of the same bus/device/slot (which represents
> > > > the vmxnet3 ethernet driver).  However, it never removes this pointer if
> > > > the vmxnet3 module is removed, leading to crashes resulting from use
> > > > after free dereferencing incidents like the one above.
> > > > 
> > > > The fix is pretty straightforward.  vmw_pvrdma should listen for
> > > > NETDEV_REGISTER and NETDEV_UNREGISTER events in its event listener code
> > > > block, and update the stored netdev pointer accordingly.  This solution
> > > > has been tested by myself and the reporter with successful results.
> > > > This fix also allows the pvrdma driver to find its underlying ethernet
> > > > device in the event that vmxnet3 is loaded after pvrdma, which it was
> > > > not able to do before.
> > > > 
> > > > Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
> > > > Reported-by: ruquin@redhat.com
> > > > CC: Adit Ranadive <aditr@vmware.com>
> > > > CC: VMware PV-Drivers <pv-drivers@vmware.com>
> > > > CC: Doug Ledford <dledford@redhat.com>
> > > > CC: Jason Gunthorpe <jgg@ziepe.ca>
> > > > CC: linux-kernel@vger.kernel.org
> > > >  .../infiniband/hw/vmw_pvrdma/pvrdma_main.c    | 25 +++++++++++++++++--
> > > >  1 file changed, 23 insertions(+), 2 deletions(-)
> > > > 
> > > > diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
> > > > index 0be33a81bbe6..5b4782078a74 100644
> > > > +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
> > > > @@ -699,8 +699,12 @@ static int pvrdma_del_gid(const struct ib_gid_attr *attr, void **context)
> > > >  }
> > > >  
> > > >  static void pvrdma_netdevice_event_handle(struct pvrdma_dev *dev,
> > > > +					  struct net_device *ndev,
> > > >  					  unsigned long event)
> > > >  {
> > > > +	struct pci_dev *pdev_net;
> > > > +
> > > > +
> > > >  	switch (event) {
> > > >  	case NETDEV_REBOOT:
> > > >  	case NETDEV_DOWN:
> > > > @@ -718,6 +722,21 @@ static void pvrdma_netdevice_event_handle(struct pvrdma_dev *dev,
> > > >  		else
> > > >  			pvrdma_dispatch_event(dev, 1, IB_EVENT_PORT_ACTIVE);
> > > >  		break;
> > > > +	case NETDEV_UNREGISTER:
> > > > +		dev_put(dev->netdev);
> > > > +		dev->netdev = NULL;
> > > > +		break;
> > > > +	case NETDEV_REGISTER:
> > > > +		/* Paired vmxnet3 will have same bus, slot. But func will be 0 */
> > > > +		pdev_net = pci_get_slot(dev->pdev->bus, PCI_DEVFN(PCI_SLOT(dev->pdev->devfn), 0));
> > > > +		if ((dev->netdev == NULL) && (pci_get_drvdata(pdev_net) == ndev)) {
> > > > +			/* this is our netdev */
> > > > +			dev->netdev = ndev;
> > > > +			dev_hold(ndev);
> > > > +		}
> > > > +		pci_dev_put(pdev_net);
> > > > +		break;
> > > > +
> > > >  	default:
> > > >  		dev_dbg(&dev->pdev->dev, "ignore netdevice event %ld on %s\n",
> > > >  			event, dev->ib_dev.name);
> > > > @@ -734,8 +753,9 @@ static void pvrdma_netdevice_event_work(struct work_struct *work)
> > > >  
> > > >  	mutex_lock(&pvrdma_device_list_lock);
> > > >  	list_for_each_entry(dev, &pvrdma_device_list, device_link) {
> > > > -		if (dev->netdev == netdev_work->event_netdev) {
> > > > -			pvrdma_netdevice_event_handle(dev, netdev_work->event);
> > > > +		if ((netdev_work->event == NETDEV_REGISTER) ||
> > > > +		    (dev->netdev == netdev_work->event_netdev)) {
> > > > +			pvrdma_netdevice_event_handle(dev, netdev_work->event_netdev, netdev_work->event);
> > > >  			break;
> > > >  		}
> > > >  	}
> > > > @@ -962,6 +982,7 @@ static int pvrdma_pci_probe(struct pci_dev *pdev,
> > > >  	}
> > > >  
> > > >  	dev->netdev = pci_get_drvdata(pdev_net);
> > > > +	dev_hold(dev->netdev);
> > > >  	pci_dev_put(pdev_net);
> > > >  	if (!dev->netdev) {
> > > >  		dev_err(&pdev->dev, "failed to get vmxnet3 device\n");
> > > 
> > > I see a lot of new dev_hold's here, where are the matching
> > > dev_puts()?
> > > 
> > I'm not sure I'd call 2 alot, but sure, there is a new dev_hold in the
> > pvrdma_pci_probe routine, to hold a reference to the netdev that is looked up
> > there.  It is balanced by the NETDEV_UNREGISTER case in
> > pvrdma_netdevice_event_handle.  The UNREGISTER clause is also balancing the
> > NETDEV_REGISTER case of the hanlder that looks up the matching netdev should a
> > new device be registered.  Note that we will only hold a single device at a
> > time, because a given pvrdma device only recongnizes a single vmxnet3 device
> > (the one on function 0 of its own bus/device tuple).
> 
> I don't see how the dev_hold in pvrdma_pci_probe is undone during
> error unwind (eg goto err_free_cq_ring)
> 
Ah, I missed that, thank you, I'll update the patch.

> And I don't see how it is put when pvrdma_pci_remove() is called.
> 
Yup, you're right, it should be dropped there too, immediately after the
unregisteration of the netdevice notifier.


> Jason
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Neil Horman June 29, 2018, 11:33 a.m. UTC | #6
On Thu, Jun 28, 2018 at 09:15:46PM +0000, Adit Ranadive wrote:
> On 6/28/18, 1:37 PM, "Jason Gunthorpe" <jgg@ziepe.ca> wrote:
> > On Thu, Jun 28, 2018 at 03:45:26PM -0400, Neil Horman wrote:
> > > On Thu, Jun 28, 2018 at 12:59:46PM -0600, Jason Gunthorpe wrote:
> > > > On Thu, Jun 28, 2018 at 09:59:38AM -0400, Neil Horman wrote:
> > > > > On repeated module load/unload cycles, its possible for the pvrmda
> > > > > driver to encounter this crash:
> <snip>
> > > > > @@ -962,6 +982,7 @@ static int pvrdma_pci_probe(struct pci_dev *pdev,
> > > > >  	}
> > > > >  
> > > > >  	dev->netdev = pci_get_drvdata(pdev_net);
> > > > > +	dev_hold(dev->netdev);
> 
> That doesn't seem right. If the vmxnet3 driver isn't loaded at all or failed
> to create a netdev, you would be requesting a hold on a NULL netdev. What if
> you moved this to after the if(!dev->netdev) check?
> 
You're correct, I was thinking that there was a null check in dev_hold, but
there isn't, it needs to be moved after the the !dev->netdev, and released in
the error path.

> > > > >  	pci_dev_put(pdev_net);
> > > > >  	if (!dev->netdev) {
> > > > >  		dev_err(&pdev->dev, "failed to get vmxnet3 device\n");
> > > > 
> > > > I see a lot of new dev_hold's here, where are the matching
> > > > dev_puts()?
> > > > 
> > I'm not sure I'd call 2 alot, but sure, there is a new dev_hold in the
> > pvrdma_pci_probe routine, to hold a reference to the netdev that is looked up
> > there.  It is balanced by the NETDEV_UNREGISTER case in
> > pvrdma_netdevice_event_handle.  The UNREGISTER clause is also balancing the
> > NETDEV_REGISTER case of the hanlder that looks up the matching netdev should a
> > new device be registered.  Note that we will only hold a single device at a
> > time, because a given pvrdma device only recongnizes a single vmxnet3 device
> > (the one on function 0 of its own bus/device tuple).
> > 
> > I don't see how the dev_hold in pvrdma_pci_probe is undone during
> > error unwind (eg goto err_free_cq_ring)
> > 
> > And I don't see how it is put when pvrdma_pci_remove() is called.
> 
> That's right. These seem missing as well. 
> 
yup

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Dan Carpenter June 30, 2018, 7:15 p.m. UTC | #7
Hi Neil,

I love your patch! Perhaps something to improve:

url:    https://github.com/0day-ci/linux/commits/Neil-Horman/vmw_pvrdma-Release-netdev-when-vmxnet3-module-is-removed/20180628-232414

smatch warnings:
drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c:987 pvrdma_pci_probe() warn: variable dereferenced before check 'dev->netdev' (see line 985)

# https://github.com/0day-ci/linux/commit/d5bb424e18e2ecab4ac590a66b0cca9dfb96d3da
git remote add linux-review https://github.com/0day-ci/linux
git remote update linux-review
git checkout d5bb424e18e2ecab4ac590a66b0cca9dfb96d3da
vim +987 drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c

29c8d9eb Adit Ranadive     2016-10-02   784  
29c8d9eb Adit Ranadive     2016-10-02   785  static int pvrdma_pci_probe(struct pci_dev *pdev,
29c8d9eb Adit Ranadive     2016-10-02   786  			    const struct pci_device_id *id)
29c8d9eb Adit Ranadive     2016-10-02   787  {
29c8d9eb Adit Ranadive     2016-10-02   788  	struct pci_dev *pdev_net;
29c8d9eb Adit Ranadive     2016-10-02   789  	struct pvrdma_dev *dev;
29c8d9eb Adit Ranadive     2016-10-02   790  	int ret;
29c8d9eb Adit Ranadive     2016-10-02   791  	unsigned long start;
29c8d9eb Adit Ranadive     2016-10-02   792  	unsigned long len;
29c8d9eb Adit Ranadive     2016-10-02   793  	dma_addr_t slot_dma = 0;
29c8d9eb Adit Ranadive     2016-10-02   794  
29c8d9eb Adit Ranadive     2016-10-02   795  	dev_dbg(&pdev->dev, "initializing driver %s\n", pci_name(pdev));
29c8d9eb Adit Ranadive     2016-10-02   796  
29c8d9eb Adit Ranadive     2016-10-02   797  	/* Allocate zero-out device */
29c8d9eb Adit Ranadive     2016-10-02   798  	dev = (struct pvrdma_dev *)ib_alloc_device(sizeof(*dev));
29c8d9eb Adit Ranadive     2016-10-02   799  	if (!dev) {
29c8d9eb Adit Ranadive     2016-10-02   800  		dev_err(&pdev->dev, "failed to allocate IB device\n");
29c8d9eb Adit Ranadive     2016-10-02   801  		return -ENOMEM;
29c8d9eb Adit Ranadive     2016-10-02   802  	}
29c8d9eb Adit Ranadive     2016-10-02   803  
29c8d9eb Adit Ranadive     2016-10-02   804  	mutex_lock(&pvrdma_device_list_lock);
29c8d9eb Adit Ranadive     2016-10-02   805  	list_add(&dev->device_link, &pvrdma_device_list);
29c8d9eb Adit Ranadive     2016-10-02   806  	mutex_unlock(&pvrdma_device_list_lock);
29c8d9eb Adit Ranadive     2016-10-02   807  
29c8d9eb Adit Ranadive     2016-10-02   808  	ret = pvrdma_init_device(dev);
29c8d9eb Adit Ranadive     2016-10-02   809  	if (ret)
29c8d9eb Adit Ranadive     2016-10-02   810  		goto err_free_device;
29c8d9eb Adit Ranadive     2016-10-02   811  
29c8d9eb Adit Ranadive     2016-10-02   812  	dev->pdev = pdev;
29c8d9eb Adit Ranadive     2016-10-02   813  	pci_set_drvdata(pdev, dev);
29c8d9eb Adit Ranadive     2016-10-02   814  
29c8d9eb Adit Ranadive     2016-10-02   815  	ret = pci_enable_device(pdev);
29c8d9eb Adit Ranadive     2016-10-02   816  	if (ret) {
29c8d9eb Adit Ranadive     2016-10-02   817  		dev_err(&pdev->dev, "cannot enable PCI device\n");
29c8d9eb Adit Ranadive     2016-10-02   818  		goto err_free_device;
29c8d9eb Adit Ranadive     2016-10-02   819  	}
29c8d9eb Adit Ranadive     2016-10-02   820  
29c8d9eb Adit Ranadive     2016-10-02   821  	dev_dbg(&pdev->dev, "PCI resource flags BAR0 %#lx\n",
29c8d9eb Adit Ranadive     2016-10-02   822  		pci_resource_flags(pdev, 0));
29c8d9eb Adit Ranadive     2016-10-02   823  	dev_dbg(&pdev->dev, "PCI resource len %#llx\n",
29c8d9eb Adit Ranadive     2016-10-02   824  		(unsigned long long)pci_resource_len(pdev, 0));
29c8d9eb Adit Ranadive     2016-10-02   825  	dev_dbg(&pdev->dev, "PCI resource start %#llx\n",
29c8d9eb Adit Ranadive     2016-10-02   826  		(unsigned long long)pci_resource_start(pdev, 0));
29c8d9eb Adit Ranadive     2016-10-02   827  	dev_dbg(&pdev->dev, "PCI resource flags BAR1 %#lx\n",
29c8d9eb Adit Ranadive     2016-10-02   828  		pci_resource_flags(pdev, 1));
29c8d9eb Adit Ranadive     2016-10-02   829  	dev_dbg(&pdev->dev, "PCI resource len %#llx\n",
29c8d9eb Adit Ranadive     2016-10-02   830  		(unsigned long long)pci_resource_len(pdev, 1));
29c8d9eb Adit Ranadive     2016-10-02   831  	dev_dbg(&pdev->dev, "PCI resource start %#llx\n",
29c8d9eb Adit Ranadive     2016-10-02   832  		(unsigned long long)pci_resource_start(pdev, 1));
29c8d9eb Adit Ranadive     2016-10-02   833  
29c8d9eb Adit Ranadive     2016-10-02   834  	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
29c8d9eb Adit Ranadive     2016-10-02   835  	    !(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
29c8d9eb Adit Ranadive     2016-10-02   836  		dev_err(&pdev->dev, "PCI BAR region not MMIO\n");
29c8d9eb Adit Ranadive     2016-10-02   837  		ret = -ENOMEM;
29c8d9eb Adit Ranadive     2016-10-02   838  		goto err_free_device;
29c8d9eb Adit Ranadive     2016-10-02   839  	}
29c8d9eb Adit Ranadive     2016-10-02   840  
29c8d9eb Adit Ranadive     2016-10-02   841  	ret = pci_request_regions(pdev, DRV_NAME);
29c8d9eb Adit Ranadive     2016-10-02   842  	if (ret) {
29c8d9eb Adit Ranadive     2016-10-02   843  		dev_err(&pdev->dev, "cannot request PCI resources\n");
29c8d9eb Adit Ranadive     2016-10-02   844  		goto err_disable_pdev;
29c8d9eb Adit Ranadive     2016-10-02   845  	}
29c8d9eb Adit Ranadive     2016-10-02   846  
29c8d9eb Adit Ranadive     2016-10-02   847  	/* Enable 64-Bit DMA */
29c8d9eb Adit Ranadive     2016-10-02   848  	if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) {
29c8d9eb Adit Ranadive     2016-10-02   849  		ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
29c8d9eb Adit Ranadive     2016-10-02   850  		if (ret != 0) {
29c8d9eb Adit Ranadive     2016-10-02   851  			dev_err(&pdev->dev,
29c8d9eb Adit Ranadive     2016-10-02   852  				"pci_set_consistent_dma_mask failed\n");
29c8d9eb Adit Ranadive     2016-10-02   853  			goto err_free_resource;
29c8d9eb Adit Ranadive     2016-10-02   854  		}
29c8d9eb Adit Ranadive     2016-10-02   855  	} else {
29c8d9eb Adit Ranadive     2016-10-02   856  		ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
29c8d9eb Adit Ranadive     2016-10-02   857  		if (ret != 0) {
29c8d9eb Adit Ranadive     2016-10-02   858  			dev_err(&pdev->dev,
29c8d9eb Adit Ranadive     2016-10-02   859  				"pci_set_dma_mask failed\n");
29c8d9eb Adit Ranadive     2016-10-02   860  			goto err_free_resource;
29c8d9eb Adit Ranadive     2016-10-02   861  		}
29c8d9eb Adit Ranadive     2016-10-02   862  	}
29c8d9eb Adit Ranadive     2016-10-02   863  
29c8d9eb Adit Ranadive     2016-10-02   864  	pci_set_master(pdev);
29c8d9eb Adit Ranadive     2016-10-02   865  
29c8d9eb Adit Ranadive     2016-10-02   866  	/* Map register space */
29c8d9eb Adit Ranadive     2016-10-02   867  	start = pci_resource_start(dev->pdev, PVRDMA_PCI_RESOURCE_REG);
29c8d9eb Adit Ranadive     2016-10-02   868  	len = pci_resource_len(dev->pdev, PVRDMA_PCI_RESOURCE_REG);
29c8d9eb Adit Ranadive     2016-10-02   869  	dev->regs = ioremap(start, len);
29c8d9eb Adit Ranadive     2016-10-02   870  	if (!dev->regs) {
29c8d9eb Adit Ranadive     2016-10-02   871  		dev_err(&pdev->dev, "register mapping failed\n");
29c8d9eb Adit Ranadive     2016-10-02   872  		ret = -ENOMEM;
29c8d9eb Adit Ranadive     2016-10-02   873  		goto err_free_resource;
29c8d9eb Adit Ranadive     2016-10-02   874  	}
29c8d9eb Adit Ranadive     2016-10-02   875  
29c8d9eb Adit Ranadive     2016-10-02   876  	/* Setup per-device UAR. */
29c8d9eb Adit Ranadive     2016-10-02   877  	dev->driver_uar.index = 0;
29c8d9eb Adit Ranadive     2016-10-02   878  	dev->driver_uar.pfn =
29c8d9eb Adit Ranadive     2016-10-02   879  		pci_resource_start(dev->pdev, PVRDMA_PCI_RESOURCE_UAR) >>
29c8d9eb Adit Ranadive     2016-10-02   880  		PAGE_SHIFT;
29c8d9eb Adit Ranadive     2016-10-02   881  	dev->driver_uar.map =
29c8d9eb Adit Ranadive     2016-10-02   882  		ioremap(dev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE);
29c8d9eb Adit Ranadive     2016-10-02   883  	if (!dev->driver_uar.map) {
29c8d9eb Adit Ranadive     2016-10-02   884  		dev_err(&pdev->dev, "failed to remap UAR pages\n");
29c8d9eb Adit Ranadive     2016-10-02   885  		ret = -ENOMEM;
29c8d9eb Adit Ranadive     2016-10-02   886  		goto err_unmap_regs;
29c8d9eb Adit Ranadive     2016-10-02   887  	}
29c8d9eb Adit Ranadive     2016-10-02   888  
05297b66 Bryan Tan         2017-08-22   889  	dev->dsr_version = pvrdma_read_reg(dev, PVRDMA_REG_VERSION);
29c8d9eb Adit Ranadive     2016-10-02   890  	dev_info(&pdev->dev, "device version %d, driver version %d\n",
05297b66 Bryan Tan         2017-08-22   891  		 dev->dsr_version, PVRDMA_VERSION);
29c8d9eb Adit Ranadive     2016-10-02   892  
58355656 Himanshu Jha      2017-12-31   893  	dev->dsr = dma_zalloc_coherent(&pdev->dev, sizeof(*dev->dsr),
29c8d9eb Adit Ranadive     2016-10-02   894  				       &dev->dsrbase, GFP_KERNEL);
29c8d9eb Adit Ranadive     2016-10-02   895  	if (!dev->dsr) {
29c8d9eb Adit Ranadive     2016-10-02   896  		dev_err(&pdev->dev, "failed to allocate shared region\n");
29c8d9eb Adit Ranadive     2016-10-02   897  		ret = -ENOMEM;
29c8d9eb Adit Ranadive     2016-10-02   898  		goto err_uar_unmap;
29c8d9eb Adit Ranadive     2016-10-02   899  	}
29c8d9eb Adit Ranadive     2016-10-02   900  
29c8d9eb Adit Ranadive     2016-10-02   901  	/* Setup the shared region */
29c8d9eb Adit Ranadive     2016-10-02   902  	dev->dsr->driver_version = PVRDMA_VERSION;
29c8d9eb Adit Ranadive     2016-10-02   903  	dev->dsr->gos_info.gos_bits = sizeof(void *) == 4 ?
29c8d9eb Adit Ranadive     2016-10-02   904  		PVRDMA_GOS_BITS_32 :
29c8d9eb Adit Ranadive     2016-10-02   905  		PVRDMA_GOS_BITS_64;
29c8d9eb Adit Ranadive     2016-10-02   906  	dev->dsr->gos_info.gos_type = PVRDMA_GOS_TYPE_LINUX;
29c8d9eb Adit Ranadive     2016-10-02   907  	dev->dsr->gos_info.gos_ver = 1;
29c8d9eb Adit Ranadive     2016-10-02   908  	dev->dsr->uar_pfn = dev->driver_uar.pfn;
29c8d9eb Adit Ranadive     2016-10-02   909  
29c8d9eb Adit Ranadive     2016-10-02   910  	/* Command slot. */
29c8d9eb Adit Ranadive     2016-10-02   911  	dev->cmd_slot = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
29c8d9eb Adit Ranadive     2016-10-02   912  					   &slot_dma, GFP_KERNEL);
29c8d9eb Adit Ranadive     2016-10-02   913  	if (!dev->cmd_slot) {
29c8d9eb Adit Ranadive     2016-10-02   914  		ret = -ENOMEM;
29c8d9eb Adit Ranadive     2016-10-02   915  		goto err_free_dsr;
29c8d9eb Adit Ranadive     2016-10-02   916  	}
29c8d9eb Adit Ranadive     2016-10-02   917  
29c8d9eb Adit Ranadive     2016-10-02   918  	dev->dsr->cmd_slot_dma = (u64)slot_dma;
29c8d9eb Adit Ranadive     2016-10-02   919  
29c8d9eb Adit Ranadive     2016-10-02   920  	/* Response slot. */
29c8d9eb Adit Ranadive     2016-10-02   921  	dev->resp_slot = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
29c8d9eb Adit Ranadive     2016-10-02   922  					    &slot_dma, GFP_KERNEL);
29c8d9eb Adit Ranadive     2016-10-02   923  	if (!dev->resp_slot) {
29c8d9eb Adit Ranadive     2016-10-02   924  		ret = -ENOMEM;
29c8d9eb Adit Ranadive     2016-10-02   925  		goto err_free_slots;
29c8d9eb Adit Ranadive     2016-10-02   926  	}
29c8d9eb Adit Ranadive     2016-10-02   927  
29c8d9eb Adit Ranadive     2016-10-02   928  	dev->dsr->resp_slot_dma = (u64)slot_dma;
29c8d9eb Adit Ranadive     2016-10-02   929  
29c8d9eb Adit Ranadive     2016-10-02   930  	/* Async event ring */
6332dee8 Adit Ranadive     2017-02-22   931  	dev->dsr->async_ring_pages.num_pages = PVRDMA_NUM_RING_PAGES;
29c8d9eb Adit Ranadive     2016-10-02   932  	ret = pvrdma_page_dir_init(dev, &dev->async_pdir,
29c8d9eb Adit Ranadive     2016-10-02   933  				   dev->dsr->async_ring_pages.num_pages, true);
29c8d9eb Adit Ranadive     2016-10-02   934  	if (ret)
29c8d9eb Adit Ranadive     2016-10-02   935  		goto err_free_slots;
29c8d9eb Adit Ranadive     2016-10-02   936  	dev->async_ring_state = dev->async_pdir.pages[0];
29c8d9eb Adit Ranadive     2016-10-02   937  	dev->dsr->async_ring_pages.pdir_dma = dev->async_pdir.dir_dma;
29c8d9eb Adit Ranadive     2016-10-02   938  
29c8d9eb Adit Ranadive     2016-10-02   939  	/* CQ notification ring */
6332dee8 Adit Ranadive     2017-02-22   940  	dev->dsr->cq_ring_pages.num_pages = PVRDMA_NUM_RING_PAGES;
29c8d9eb Adit Ranadive     2016-10-02   941  	ret = pvrdma_page_dir_init(dev, &dev->cq_pdir,
29c8d9eb Adit Ranadive     2016-10-02   942  				   dev->dsr->cq_ring_pages.num_pages, true);
29c8d9eb Adit Ranadive     2016-10-02   943  	if (ret)
29c8d9eb Adit Ranadive     2016-10-02   944  		goto err_free_async_ring;
29c8d9eb Adit Ranadive     2016-10-02   945  	dev->cq_ring_state = dev->cq_pdir.pages[0];
29c8d9eb Adit Ranadive     2016-10-02   946  	dev->dsr->cq_ring_pages.pdir_dma = dev->cq_pdir.dir_dma;
29c8d9eb Adit Ranadive     2016-10-02   947  
29c8d9eb Adit Ranadive     2016-10-02   948  	/*
29c8d9eb Adit Ranadive     2016-10-02   949  	 * Write the PA of the shared region to the device. The writes must be
29c8d9eb Adit Ranadive     2016-10-02   950  	 * ordered such that the high bits are written last. When the writes
29c8d9eb Adit Ranadive     2016-10-02   951  	 * complete, the device will have filled out the capabilities.
29c8d9eb Adit Ranadive     2016-10-02   952  	 */
29c8d9eb Adit Ranadive     2016-10-02   953  
29c8d9eb Adit Ranadive     2016-10-02   954  	pvrdma_write_reg(dev, PVRDMA_REG_DSRLOW, (u32)dev->dsrbase);
29c8d9eb Adit Ranadive     2016-10-02   955  	pvrdma_write_reg(dev, PVRDMA_REG_DSRHIGH,
29c8d9eb Adit Ranadive     2016-10-02   956  			 (u32)((u64)(dev->dsrbase) >> 32));
29c8d9eb Adit Ranadive     2016-10-02   957  
29c8d9eb Adit Ranadive     2016-10-02   958  	/* Make sure the write is complete before reading status. */
29c8d9eb Adit Ranadive     2016-10-02   959  	mb();
29c8d9eb Adit Ranadive     2016-10-02   960  
05297b66 Bryan Tan         2017-08-22   961  	/* The driver supports RoCE V1 and V2. */
05297b66 Bryan Tan         2017-08-22   962  	if (!PVRDMA_SUPPORTED(dev)) {
05297b66 Bryan Tan         2017-08-22   963  		dev_err(&pdev->dev, "driver needs RoCE v1 or v2 support\n");
29c8d9eb Adit Ranadive     2016-10-02   964  		ret = -EFAULT;
29c8d9eb Adit Ranadive     2016-10-02   965  		goto err_free_cq_ring;
29c8d9eb Adit Ranadive     2016-10-02   966  	}
29c8d9eb Adit Ranadive     2016-10-02   967  
29c8d9eb Adit Ranadive     2016-10-02   968  	/* Paired vmxnet3 will have same bus, slot. But func will be 0 */
29c8d9eb Adit Ranadive     2016-10-02   969  	pdev_net = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 0));
29c8d9eb Adit Ranadive     2016-10-02   970  	if (!pdev_net) {
29c8d9eb Adit Ranadive     2016-10-02   971  		dev_err(&pdev->dev, "failed to find paired net device\n");
29c8d9eb Adit Ranadive     2016-10-02   972  		ret = -ENODEV;
29c8d9eb Adit Ranadive     2016-10-02   973  		goto err_free_cq_ring;
29c8d9eb Adit Ranadive     2016-10-02   974  	}
29c8d9eb Adit Ranadive     2016-10-02   975  
29c8d9eb Adit Ranadive     2016-10-02   976  	if (pdev_net->vendor != PCI_VENDOR_ID_VMWARE ||
29c8d9eb Adit Ranadive     2016-10-02   977  	    pdev_net->device != PCI_DEVICE_ID_VMWARE_VMXNET3) {
29c8d9eb Adit Ranadive     2016-10-02   978  		dev_err(&pdev->dev, "failed to find paired vmxnet3 device\n");
29c8d9eb Adit Ranadive     2016-10-02   979  		pci_dev_put(pdev_net);
29c8d9eb Adit Ranadive     2016-10-02   980  		ret = -ENODEV;
29c8d9eb Adit Ranadive     2016-10-02   981  		goto err_free_cq_ring;
29c8d9eb Adit Ranadive     2016-10-02   982  	}
29c8d9eb Adit Ranadive     2016-10-02   983  
29c8d9eb Adit Ranadive     2016-10-02   984  	dev->netdev = pci_get_drvdata(pdev_net);
d5bb424e Neil Horman       2018-06-28  @985  	dev_hold(dev->netdev);
                                                ^^^^^^^^^^^^^^^^^^^^^
Dereferenced inside the function

29c8d9eb Adit Ranadive     2016-10-02   986  	pci_dev_put(pdev_net);
29c8d9eb Adit Ranadive     2016-10-02  @987  	if (!dev->netdev) {
                                                     ^^^^^^^^^^^
Checked too late.

29c8d9eb Adit Ranadive     2016-10-02   988  		dev_err(&pdev->dev, "failed to get vmxnet3 device\n");
29c8d9eb Adit Ranadive     2016-10-02   989  		ret = -ENODEV;
29c8d9eb Adit Ranadive     2016-10-02   990  		goto err_free_cq_ring;
29c8d9eb Adit Ranadive     2016-10-02   991  	}
29c8d9eb Adit Ranadive     2016-10-02   992  
29c8d9eb Adit Ranadive     2016-10-02   993  	dev_info(&pdev->dev, "paired device to %s\n", dev->netdev->name);
29c8d9eb Adit Ranadive     2016-10-02   994  
29c8d9eb Adit Ranadive     2016-10-02   995  	/* Interrupt setup */
29c8d9eb Adit Ranadive     2016-10-02   996  	ret = pvrdma_alloc_intrs(dev);
29c8d9eb Adit Ranadive     2016-10-02   997  	if (ret) {
29c8d9eb Adit Ranadive     2016-10-02   998  		dev_err(&pdev->dev, "failed to allocate interrupts\n");
29c8d9eb Adit Ranadive     2016-10-02   999  		ret = -ENOMEM;
ff89b070 Adit Ranadive     2017-01-19  1000  		goto err_free_cq_ring;
29c8d9eb Adit Ranadive     2016-10-02  1001  	}
29c8d9eb Adit Ranadive     2016-10-02  1002  
29c8d9eb Adit Ranadive     2016-10-02  1003  	/* Allocate UAR table. */
29c8d9eb Adit Ranadive     2016-10-02  1004  	ret = pvrdma_uar_table_init(dev);
29c8d9eb Adit Ranadive     2016-10-02  1005  	if (ret) {
29c8d9eb Adit Ranadive     2016-10-02  1006  		dev_err(&pdev->dev, "failed to allocate UAR table\n");
29c8d9eb Adit Ranadive     2016-10-02  1007  		ret = -ENOMEM;
29c8d9eb Adit Ranadive     2016-10-02  1008  		goto err_free_intrs;
29c8d9eb Adit Ranadive     2016-10-02  1009  	}
29c8d9eb Adit Ranadive     2016-10-02  1010  
29c8d9eb Adit Ranadive     2016-10-02  1011  	/* Allocate GID table */
29c8d9eb Adit Ranadive     2016-10-02  1012  	dev->sgid_tbl = kcalloc(dev->dsr->caps.gid_tbl_len,
29c8d9eb Adit Ranadive     2016-10-02  1013  				sizeof(union ib_gid), GFP_KERNEL);
29c8d9eb Adit Ranadive     2016-10-02  1014  	if (!dev->sgid_tbl) {
29c8d9eb Adit Ranadive     2016-10-02  1015  		ret = -ENOMEM;
29c8d9eb Adit Ranadive     2016-10-02  1016  		goto err_free_uar_table;
29c8d9eb Adit Ranadive     2016-10-02  1017  	}
29c8d9eb Adit Ranadive     2016-10-02  1018  	dev_dbg(&pdev->dev, "gid table len %d\n", dev->dsr->caps.gid_tbl_len);
29c8d9eb Adit Ranadive     2016-10-02  1019  
29c8d9eb Adit Ranadive     2016-10-02  1020  	pvrdma_enable_intrs(dev);
29c8d9eb Adit Ranadive     2016-10-02  1021  
29c8d9eb Adit Ranadive     2016-10-02  1022  	/* Activate pvrdma device */
29c8d9eb Adit Ranadive     2016-10-02  1023  	pvrdma_write_reg(dev, PVRDMA_REG_CTL, PVRDMA_DEVICE_CTL_ACTIVATE);
29c8d9eb Adit Ranadive     2016-10-02  1024  
29c8d9eb Adit Ranadive     2016-10-02  1025  	/* Make sure the write is complete before reading status. */
29c8d9eb Adit Ranadive     2016-10-02  1026  	mb();
29c8d9eb Adit Ranadive     2016-10-02  1027  
29c8d9eb Adit Ranadive     2016-10-02  1028  	/* Check if device was successfully activated */
29c8d9eb Adit Ranadive     2016-10-02  1029  	ret = pvrdma_read_reg(dev, PVRDMA_REG_ERR);
29c8d9eb Adit Ranadive     2016-10-02  1030  	if (ret != 0) {
29c8d9eb Adit Ranadive     2016-10-02  1031  		dev_err(&pdev->dev, "failed to activate device\n");
29c8d9eb Adit Ranadive     2016-10-02  1032  		ret = -EFAULT;
29c8d9eb Adit Ranadive     2016-10-02  1033  		goto err_disable_intr;
29c8d9eb Adit Ranadive     2016-10-02  1034  	}
29c8d9eb Adit Ranadive     2016-10-02  1035  
29c8d9eb Adit Ranadive     2016-10-02  1036  	/* Register IB device */
29c8d9eb Adit Ranadive     2016-10-02  1037  	ret = pvrdma_register_device(dev);
29c8d9eb Adit Ranadive     2016-10-02  1038  	if (ret) {
29c8d9eb Adit Ranadive     2016-10-02  1039  		dev_err(&pdev->dev, "failed to register IB device\n");
29c8d9eb Adit Ranadive     2016-10-02  1040  		goto err_disable_intr;
29c8d9eb Adit Ranadive     2016-10-02  1041  	}
29c8d9eb Adit Ranadive     2016-10-02  1042  
29c8d9eb Adit Ranadive     2016-10-02  1043  	dev->nb_netdev.notifier_call = pvrdma_netdevice_event;
29c8d9eb Adit Ranadive     2016-10-02  1044  	ret = register_netdevice_notifier(&dev->nb_netdev);
29c8d9eb Adit Ranadive     2016-10-02  1045  	if (ret) {
29c8d9eb Adit Ranadive     2016-10-02  1046  		dev_err(&pdev->dev, "failed to register netdevice events\n");
29c8d9eb Adit Ranadive     2016-10-02  1047  		goto err_unreg_ibdev;
29c8d9eb Adit Ranadive     2016-10-02  1048  	}
29c8d9eb Adit Ranadive     2016-10-02  1049  
29c8d9eb Adit Ranadive     2016-10-02  1050  	dev_info(&pdev->dev, "attached to device\n");
29c8d9eb Adit Ranadive     2016-10-02  1051  	return 0;
29c8d9eb Adit Ranadive     2016-10-02  1052  
29c8d9eb Adit Ranadive     2016-10-02  1053  err_unreg_ibdev:
29c8d9eb Adit Ranadive     2016-10-02  1054  	ib_unregister_device(&dev->ib_dev);
29c8d9eb Adit Ranadive     2016-10-02  1055  err_disable_intr:
29c8d9eb Adit Ranadive     2016-10-02  1056  	pvrdma_disable_intrs(dev);
29c8d9eb Adit Ranadive     2016-10-02  1057  	kfree(dev->sgid_tbl);
29c8d9eb Adit Ranadive     2016-10-02  1058  err_free_uar_table:
29c8d9eb Adit Ranadive     2016-10-02  1059  	pvrdma_uar_table_cleanup(dev);
29c8d9eb Adit Ranadive     2016-10-02  1060  err_free_intrs:
29c8d9eb Adit Ranadive     2016-10-02  1061  	pvrdma_free_irq(dev);
7bf3976d Christoph Hellwig 2017-02-15  1062  	pci_free_irq_vectors(pdev);
29c8d9eb Adit Ranadive     2016-10-02  1063  err_free_cq_ring:
29c8d9eb Adit Ranadive     2016-10-02  1064  	pvrdma_page_dir_cleanup(dev, &dev->cq_pdir);
29c8d9eb Adit Ranadive     2016-10-02  1065  err_free_async_ring:
29c8d9eb Adit Ranadive     2016-10-02  1066  	pvrdma_page_dir_cleanup(dev, &dev->async_pdir);
29c8d9eb Adit Ranadive     2016-10-02  1067  err_free_slots:
29c8d9eb Adit Ranadive     2016-10-02  1068  	pvrdma_free_slots(dev);
29c8d9eb Adit Ranadive     2016-10-02  1069  err_free_dsr:
29c8d9eb Adit Ranadive     2016-10-02  1070  	dma_free_coherent(&pdev->dev, sizeof(*dev->dsr), dev->dsr,
29c8d9eb Adit Ranadive     2016-10-02  1071  			  dev->dsrbase);
29c8d9eb Adit Ranadive     2016-10-02  1072  err_uar_unmap:
29c8d9eb Adit Ranadive     2016-10-02  1073  	iounmap(dev->driver_uar.map);
29c8d9eb Adit Ranadive     2016-10-02  1074  err_unmap_regs:
29c8d9eb Adit Ranadive     2016-10-02  1075  	iounmap(dev->regs);
29c8d9eb Adit Ranadive     2016-10-02  1076  err_free_resource:
29c8d9eb Adit Ranadive     2016-10-02  1077  	pci_release_regions(pdev);
29c8d9eb Adit Ranadive     2016-10-02  1078  err_disable_pdev:
29c8d9eb Adit Ranadive     2016-10-02  1079  	pci_disable_device(pdev);
29c8d9eb Adit Ranadive     2016-10-02  1080  	pci_set_drvdata(pdev, NULL);
29c8d9eb Adit Ranadive     2016-10-02  1081  err_free_device:
29c8d9eb Adit Ranadive     2016-10-02  1082  	mutex_lock(&pvrdma_device_list_lock);
29c8d9eb Adit Ranadive     2016-10-02  1083  	list_del(&dev->device_link);
29c8d9eb Adit Ranadive     2016-10-02  1084  	mutex_unlock(&pvrdma_device_list_lock);
29c8d9eb Adit Ranadive     2016-10-02  1085  	ib_dealloc_device(&dev->ib_dev);
29c8d9eb Adit Ranadive     2016-10-02  1086  	return ret;
29c8d9eb Adit Ranadive     2016-10-02  1087  }
29c8d9eb Adit Ranadive     2016-10-02  1088  

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Neil Horman July 1, 2018, 12:18 p.m. UTC | #8
On Sat, Jun 30, 2018 at 10:15:07PM +0300, Dan Carpenter wrote:
> Hi Neil,
> 
> I love your patch! Perhaps something to improve:
> 
> url:    https://github.com/0day-ci/linux/commits/Neil-Horman/vmw_pvrdma-Release-netdev-when-vmxnet3-module-is-removed/20180628-232414
> 
> smatch warnings:
> drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c:987 pvrdma_pci_probe() warn: variable dereferenced before check 'dev->netdev' (see line 985)
> 
Appreciate the smatch check, but this was caught by visual review and fixed in V2 already.

Best
Neil

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
index 0be33a81bbe6..5b4782078a74 100644
--- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
+++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c
@@ -699,8 +699,12 @@  static int pvrdma_del_gid(const struct ib_gid_attr *attr, void **context)
 }
 
 static void pvrdma_netdevice_event_handle(struct pvrdma_dev *dev,
+					  struct net_device *ndev,
 					  unsigned long event)
 {
+	struct pci_dev *pdev_net;
+
+
 	switch (event) {
 	case NETDEV_REBOOT:
 	case NETDEV_DOWN:
@@ -718,6 +722,21 @@  static void pvrdma_netdevice_event_handle(struct pvrdma_dev *dev,
 		else
 			pvrdma_dispatch_event(dev, 1, IB_EVENT_PORT_ACTIVE);
 		break;
+	case NETDEV_UNREGISTER:
+		dev_put(dev->netdev);
+		dev->netdev = NULL;
+		break;
+	case NETDEV_REGISTER:
+		/* Paired vmxnet3 will have same bus, slot. But func will be 0 */
+		pdev_net = pci_get_slot(dev->pdev->bus, PCI_DEVFN(PCI_SLOT(dev->pdev->devfn), 0));
+		if ((dev->netdev == NULL) && (pci_get_drvdata(pdev_net) == ndev)) {
+			/* this is our netdev */
+			dev->netdev = ndev;
+			dev_hold(ndev);
+		}
+		pci_dev_put(pdev_net);
+		break;
+
 	default:
 		dev_dbg(&dev->pdev->dev, "ignore netdevice event %ld on %s\n",
 			event, dev->ib_dev.name);
@@ -734,8 +753,9 @@  static void pvrdma_netdevice_event_work(struct work_struct *work)
 
 	mutex_lock(&pvrdma_device_list_lock);
 	list_for_each_entry(dev, &pvrdma_device_list, device_link) {
-		if (dev->netdev == netdev_work->event_netdev) {
-			pvrdma_netdevice_event_handle(dev, netdev_work->event);
+		if ((netdev_work->event == NETDEV_REGISTER) ||
+		    (dev->netdev == netdev_work->event_netdev)) {
+			pvrdma_netdevice_event_handle(dev, netdev_work->event_netdev, netdev_work->event);
 			break;
 		}
 	}
@@ -962,6 +982,7 @@  static int pvrdma_pci_probe(struct pci_dev *pdev,
 	}
 
 	dev->netdev = pci_get_drvdata(pdev_net);
+	dev_hold(dev->netdev);
 	pci_dev_put(pdev_net);
 	if (!dev->netdev) {
 		dev_err(&pdev->dev, "failed to get vmxnet3 device\n");