So if dev->ip_ptr is NULL the -ENOBUFS could be fired.
There aren't many places where this will be set. One of them is
net/ipv4/devinet.c::inetdev_init()
...
/* Account for reference dev->ip_ptr (below) */
in_dev_hold(in_dev);
...
/* we can receive as soon as ip_ptr is set -- do this last */
rcu_assign_pointer(dev->ip_ptr, in_dev);
which is only ever called from
net/ipv4/devinit.c::inetdev_event()
if (!in_dev) {
if (event == NETDEV_REGISTER) {
in_dev = inetdev_init(dev);
...
} else if (event == NETDEV_CHANGEMTU) {
/* Re-enabling IP */
if (inetdev_valid_mtu(dev->mtu))
in_dev = inetdev_init(dev);
I'm wondering if this is an obscure RCU issue. Having read up on other
changes to similar code it could be that inet_set_ifa() should be:
I stepped back a bit and re-considered. Realised I'd missed something
important.
The -ENOBUFS in devinit_ioctl() isn't the only place this error value
could be set.
If the allocation in devinet_ioctl() succeeds execution continues
through to:
ret = inet_set_ifa(dev, ifa);
break;
That calls:
net/ipv4/ devinet. c::inet_ set_ifa( ) get_rtnl( dev);
{
struct in_device *in_dev = __in_dev_
ASSERT_RTNL();
if (!in_dev) { free_ifa( ifa);
inet_
return -ENOBUFS;
}
-ENOBUFS will happen if __in_dev_ get_rtnl( dev) fails.
include/ linux/inetdevic e.h::__ in_dev_ get_rtnl( ):
static __inline__ struct in_device * get_rtnl( const struct net_device *dev) )dev->ip_ ptr;
__in_dev_
{
return (struct in_device*
}
So if dev->ip_ptr is NULL the -ENOBUFS could be fired.
There aren't many places where this will be set. One of them is
net/ipv4/ devinet. c::inetdev_ init()
... hold(in_ dev); pointer( dev->ip_ ptr, in_dev);
/* Account for reference dev->ip_ptr (below) */
in_dev_
...
/* we can receive as soon as ip_ptr is set -- do this last */
rcu_assign_
which is only ever called from
net/ipv4/ devinit. c::inetdev_ event()
if (!in_dev) { valid_mtu( dev->mtu) )
if (event == NETDEV_REGISTER) {
in_dev = inetdev_init(dev);
...
} else if (event == NETDEV_CHANGEMTU) {
/* Re-enabling IP */
if (inetdev_
in_dev = inetdev_init(dev);
I'm wondering if this is an obscure RCU issue. Having read up on other
changes to similar code it could be that inet_set_ifa() should be:
static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa) get_rcu( dev);
{
struct in_device *in_dev;
rcu_read_lock();
in_dev = __in_dev_
ASSERT_RTNL();