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()
{
struct in_device *in_dev = __in_dev_get_rtnl(dev);
ASSERT_RTNL();
if (!in_dev) {
inet_free_ifa(ifa);
return -ENOBUFS;
}
-ENOBUFS will happen if __in_dev_get_rtnl(dev) fails.
include/linux/inetdevice.h::__in_dev_get_rtnl():
static __inline__ struct in_device *
__in_dev_get_rtnl(const struct net_device *dev)
{
return (struct in_device*)dev->ip_ptr;
}
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:
static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa)
{
struct in_device *in_dev;
rcu_read_lock();
in_dev = __in_dev_get_rcu(dev);
ASSERT_RTNL();
--
No NET with 2.6.27: No buffer space available
https://bugs.launchpad.net/bugs/284377
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
--
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs