All of lore.kernel.org
 help / color / mirror / Atom feed
* locking in net_device_ops callbacks
@ 2012-03-21 18:59 Jeff Haran
  2012-03-21 19:25 ` Stephen Hemminger
  2012-03-21 19:58 ` Ben Hutchings
  0 siblings, 2 replies; 7+ messages in thread
From: Jeff Haran @ 2012-03-21 18:59 UTC (permalink / raw)
  To: netdev

Hi,

I had posted the below to the kernelnewbies email list and never got a response. I am hoping somebody on this list could provide some feedback.

Just to be clear, it's not the issue of copying the MAC address that I am asking about. That's just an example.

What I am trying to understand is, what mechanisms generally are at play to serialize access to struct net_device private data that is accessed in both process and softirq contexts? Explicit locking "seems" to be mostly absent from the driver sources I've inspected so I can't help but believe I am missing something fundamental here.

Thanks in advance,

Jeff Haran

I was hoping somebody could enlighten me on how serialization of access
to data in struct net_device and associated netdev_priv() data works in
the callback functions registered in net_device_ops. For example, I am
looking at drivers/net/e1000/e1000_main.c in my 2.6.32 based kernel
tree. My understanding is this is a reference driver of sorts, so it
should be doing the "right thing".

This driver registers a callback for the ndo_set_mac_address callback
like this (much of what I think is not significant to the question code
replaced with "..." below for brevity):

static const struct net_device_ops e1000_netdev_ops = {
        ...
        .ndo_set_mac_address    = e1000_set_mac,
        ...
};

static int __devinit e1000_probe(struct pci_dev *pdev,
                                 const struct pci_device_id *ent)
{
        struct net_device *netdev;
       ....

        netdev = alloc_etherdev(sizeof(struct e1000_adapter));
        ....
        netdev->netdev_ops = &e1000_netdev_ops;
        ...
        err = register_netdev(netdev);
        ...
}

Most network drivers seem to follow more or less the same initialization
sequence.

When I look at the implementation of e1000_set_mac(), I see this:

static int e1000_set_mac(struct net_device *netdev, void *p)
{
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        struct sockaddr *addr = p;

        ...
        memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
        memcpy(hw->mac_addr, addr->sa_data, netdev->addr_len);
        ...

        return 0;
}

I can't help but notice there is no locking going on around the
memcpy()s of the passed in MAC address to the net_device dev_addr and
private data mac_addr fields.

I assume that e1000_set_mac() is typically called in process context in
response to some user space application like ifconfig or ip changing the
interface MAC address. I am also assuming that these dev_addr and
mac_addr fields are also referenced in other contexts. An Ethernet MAC
address is 6 bytes, so the memcpy()'s can't be atomic operations at
least on a 32 bit machine.

Shouldn't there have been some sort of lock taken before the memcpy()s
are executed so that other execution contexts won't see a partially
copied MAC address?

Is there some sort of lock taken higher up the call stack by the code
that calls these callback functions so that the callbacks themselves
don't have to do it explicitly?

I am writing a network device driver (modifying an existing one
actually) and am therefore trying to understand what kinds of explicit
locking my net_device_ops callbacks need to take in order to ensure
proper operation on an SMP system.

Thanks,

Jeff Haran

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: locking in net_device_ops callbacks
  2012-03-21 18:59 locking in net_device_ops callbacks Jeff Haran
@ 2012-03-21 19:25 ` Stephen Hemminger
  2012-03-21 20:38   ` Jeff Haran
  2012-03-21 19:58 ` Ben Hutchings
  1 sibling, 1 reply; 7+ messages in thread
From: Stephen Hemminger @ 2012-03-21 19:25 UTC (permalink / raw)
  To: Jeff Haran; +Cc: netdev

On Wed, 21 Mar 2012 18:59:30 +0000
Jeff Haran <jharan@bytemobile.com> wrote:

> Hi,
> 
> I had posted the below to the kernelnewbies email list and never got a response. I am hoping somebody on this list could provide some feedback.
> 
> Just to be clear, it's not the issue of copying the MAC address that I am asking about. That's just an example.
> 
> What I am trying to understand is, what mechanisms generally are at play to serialize access to struct net_device private data that is accessed in both process and softirq contexts? Explicit locking "seems" to be mostly absent from the driver sources I've inspected so I can't help but believe I am missing something fundamental here.

Look at rtnl_lock() in net/core/rtnetlink.c; this is global mutex against
all changes to network device state.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: locking in net_device_ops callbacks
  2012-03-21 18:59 locking in net_device_ops callbacks Jeff Haran
  2012-03-21 19:25 ` Stephen Hemminger
@ 2012-03-21 19:58 ` Ben Hutchings
  2012-03-21 23:00   ` Stephen Hemminger
  1 sibling, 1 reply; 7+ messages in thread
From: Ben Hutchings @ 2012-03-21 19:58 UTC (permalink / raw)
  To: Jeff Haran; +Cc: netdev

On Wed, 2012-03-21 at 18:59 +0000, Jeff Haran wrote:
> Hi,
> 
> I had posted the below to the kernelnewbies email list and never got a
> response. I am hoping somebody on this list could provide some
> feedback.
> 
> Just to be clear, it's not the issue of copying the MAC address that I
> am asking about. That's just an example.
> 
> What I am trying to understand is, what mechanisms generally are at
> play to serialize access to struct net_device private data that is
> accessed in both process and softirq contexts? Explicit locking
> "seems" to be mostly absent from the driver sources I've inspected so
> I can't help but believe I am missing something fundamental here.
[...]
> I can't help but notice there is no locking going on around the
> memcpy()s of the passed in MAC address to the net_device dev_addr and
> private data mac_addr fields.
> 
> I assume that e1000_set_mac() is typically called in process context in
> response to some user space application like ifconfig or ip changing the
> interface MAC address.

Yes.  Most interface reconfiguration is done in process context, with
the (global) rtnetlink lock held.  The address *lists* (additional
unicast addresses and multicast addresses) may be updated in softirq
context, and are updated with the (per-interface) addr_lock held.

> I am also assuming that these dev_addr and
> mac_addr fields are also referenced in other contexts. An Ethernet MAC
> address is 6 bytes, so the memcpy()'s can't be atomic operations at
> least on a 32 bit machine.
> 
> Shouldn't there have been some sort of lock taken before the memcpy()s
> are executed so that other execution contexts won't see a partially
> copied MAC address?

As I think you've recognised, the MAC address may still be read when
constructing packet headers.  eth_mac_addr() fails if the interface is
running, which should avoid this problem.  However some other
implementations of ndo_set_mac_address don't check that.  Maybe they
should - or else that check should be done in the caller,
dev_set_mac_address().

> Is there some sort of lock taken higher up the call stack by the code
> that calls these callback functions so that the callbacks themselves
> don't have to do it explicitly?

In most cases, yes.

> I am writing a network device driver (modifying an existing one
> actually) and am therefore trying to understand what kinds of explicit
> locking my net_device_ops callbacks need to take in order to ensure
> proper operation on an SMP system.

I would like to point you to documentation, but unfortunately I can't
see an up-to-date description.

Ben.

-- 
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: locking in net_device_ops callbacks
  2012-03-21 19:25 ` Stephen Hemminger
@ 2012-03-21 20:38   ` Jeff Haran
  2012-03-21 23:37     ` Francois Romieu
  0 siblings, 1 reply; 7+ messages in thread
From: Jeff Haran @ 2012-03-21 20:38 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev

> -----Original Message-----
> From: Stephen Hemminger [mailto:shemminger@vyatta.com]
> Sent: Wednesday, March 21, 2012 12:25 PM
> To: Jeff Haran
> Cc: netdev@vger.kernel.org
> Subject: Re: locking in net_device_ops callbacks
> 
> On Wed, 21 Mar 2012 18:59:30 +0000
> Jeff Haran <jharan@bytemobile.com> wrote:
> 
> > Hi,
> >
> > I had posted the below to the kernelnewbies email list and never got a
> response. I am hoping somebody on this list could provide some feedback.
> >
> > Just to be clear, it's not the issue of copying the MAC address that I am
> asking about. That's just an example.
> >
> > What I am trying to understand is, what mechanisms generally are at play
> to serialize access to struct net_device private data that is accessed in both
> process and softirq contexts? Explicit locking "seems" to be mostly absent
> from the driver sources I've inspected so I can't help but believe I am missing
> something fundamental here.
> 
> Look at rtnl_lock() in net/core/rtnetlink.c; this is global mutex against
> all changes to network device state.

Steve,

Thanks for the response.

rtnl_lock() does this:

void rtnl_lock(void)
{
        mutex_lock(&rtnl_mutex);
}

I can see where that would serialize process context access, but as I understand it much of the networking stack runs in soft IRQ context. Soft IRQs can't take mutexes, can they?

It seems to me that some other serialization mechanism should be in place to serialize soft IRQ context access to instances of struct net_device.

Jeff Haran

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: locking in net_device_ops callbacks
  2012-03-21 19:58 ` Ben Hutchings
@ 2012-03-21 23:00   ` Stephen Hemminger
  0 siblings, 0 replies; 7+ messages in thread
From: Stephen Hemminger @ 2012-03-21 23:00 UTC (permalink / raw)
  To: Ben Hutchings; +Cc: Jeff Haran, netdev

Another part of this is that it is not allowed to change many settings
like name, mac address or master relationship if device is UP.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: locking in net_device_ops callbacks
  2012-03-21 20:38   ` Jeff Haran
@ 2012-03-21 23:37     ` Francois Romieu
  0 siblings, 0 replies; 7+ messages in thread
From: Francois Romieu @ 2012-03-21 23:37 UTC (permalink / raw)
  To: Jeff Haran; +Cc: Stephen Hemminger, netdev

Jeff Haran <jharan@bytemobile.com> :
[...]
> It seems to me that some other serialization mechanism should be in place
> to serialize soft IRQ context access to instances of struct net_device.

The driver must implement adequate locking -mostly bh or irq spinlock- if
you want to change the MTU at any time. It is possible to temporarily stop
some bh as well too, see napi_disable for instance.

net_device stats locking is a different beast.

Other than that, some serializing is already done with rules such as
"xmit happens in locally bh disabled context" or through special purpose
lock (think Tx locking).

So, yes, there are some mechanisms. However most drivers only care about
the net_device itself when it goes up or down. As soon as the net_device
is up, it won't change much behind the driver's back (nor should the driver
try to modify it much btw).

-- 
Ueimor

^ permalink raw reply	[flat|nested] 7+ messages in thread

* locking in net_device_ops callbacks
@ 2012-02-24 19:43 Jeff Haran
  0 siblings, 0 replies; 7+ messages in thread
From: Jeff Haran @ 2012-02-24 19:43 UTC (permalink / raw)
  To: kernelnewbies

Hi,

I was hoping somebody could enlighten me on how serialization of access
to data in struct net_device and associated netdev_priv() data works in
the callback functions registered in net_device_ops. For example, I am
looking at drivers/net/e1000/e1000_main.c in my 2.6.32 based kernel
tree. My understanding is this is a reference driver of sorts, so it
should be doing the "right thing".

This driver registers a callback for the ndo_set_mac_address callback
like this (much of what I think is not significant to the question code
replaced with "..." below for brevity):

static const struct net_device_ops e1000_netdev_ops = {
        ...
        .ndo_set_mac_address    = e1000_set_mac,
        ...
};

static int __devinit e1000_probe(struct pci_dev *pdev,
                                 const struct pci_device_id *ent)
{
        struct net_device *netdev;
       ....

        netdev = alloc_etherdev(sizeof(struct e1000_adapter));
        ....
        netdev->netdev_ops = &e1000_netdev_ops;
        ...
        err = register_netdev(netdev);
        ...
}

Most network drivers seem to follow more or less the same initialization
sequence.

When I look at the implementation of e1000_set_mac(), I see this:

static int e1000_set_mac(struct net_device *netdev, void *p)
{
        struct e1000_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
        struct sockaddr *addr = p;

        ...
        memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
        memcpy(hw->mac_addr, addr->sa_data, netdev->addr_len);
        ...

        return 0;
}

I can't help but notice there is no locking going on around the
memcpy()s of the passed in MAC address to the net_device dev_addr and
private data mac_addr fields.

I assume that e1000_set_mac() is typically called in process context in
response to some user space application like ifconfig or ip changing the
interface MAC address. I am also assuming that these dev_addr and
mac_addr fields are also referenced in other contexts. An Ethernet MAC
address is 6 bytes, so the memcpy()'s can't be atomic operations at
least on a 32 bit machine.

Shouldn't there have been some sort of lock taken before the memcpy()s
are executed so that other execution contexts won't see a partially
copied MAC address?

Is there some sort of lock taken higher up the call stack by the code
that calls these callback functions so that the callbacks themselves
don't have to do it explicitly?

I am writing a network device driver (modifying an existing one
actually) and am therefore trying to understand what kinds of explicit
locking my net_device_ops callbacks need to take in order to ensure
proper operation on an SMP system.

Thanks,

Jeff Haran

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2012-03-21 23:39 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-21 18:59 locking in net_device_ops callbacks Jeff Haran
2012-03-21 19:25 ` Stephen Hemminger
2012-03-21 20:38   ` Jeff Haran
2012-03-21 23:37     ` Francois Romieu
2012-03-21 19:58 ` Ben Hutchings
2012-03-21 23:00   ` Stephen Hemminger
  -- strict thread matches above, loose matches on Subject: below --
2012-02-24 19:43 Jeff Haran

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.