| From 08613e4626c06ca408fc55071f6aedee36986a87 Mon Sep 17 00:00:00 2001 |
| From: David Woodhouse <dwmw2@infradead.org> |
| Date: Mon, 24 Oct 2011 21:25:21 +0000 |
| Subject: caif: Fix BUG() with network namespaces |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: David Woodhouse <dwmw2@infradead.org> |
| |
| commit 08613e4626c06ca408fc55071f6aedee36986a87 upstream. |
| |
| The caif code will register its own pernet_operations, and then register |
| a netdevice_notifier. Each time the netdevice_notifier is triggered, |
| it'll do some stuff... including a lookup of its own pernet stuff with |
| net_generic(). |
| |
| If the net_generic() call ever returns NULL, the caif code will BUG(). |
| That doesn't seem *so* unreasonable, I suppose — it does seem like it |
| should never happen. |
| |
| However, it *does* happen. When we clone a network namespace, |
| setup_net() runs through all the pernet_operations one at a time. It |
| gets to loopback before it gets to caif. And loopback_net_init() |
| registers a netdevice... while caif hasn't been initialised. So the caif |
| netdevice notifier triggers, and immediately goes BUG(). |
| |
| We could imagine a complex and overengineered solution to this generic |
| class of problems, but this patch takes the simple approach. It just |
| makes caif_device_notify() *not* go looking for its pernet data |
| structures if the device it's being notified about isn't a caif device |
| in the first place. |
| |
| Signed-off-by: David Woodhouse <David.Woodhouse@intel.com> |
| Acked-by: Sjur Brændeland <sjur.brandeland@stericsson.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| net/caif/caif_dev.c | 5 +++-- |
| 1 file changed, 3 insertions(+), 2 deletions(-) |
| |
| --- a/net/caif/caif_dev.c |
| +++ b/net/caif/caif_dev.c |
| @@ -212,8 +212,7 @@ static int caif_device_notify(struct not |
| enum cfcnfg_phy_preference pref; |
| enum cfcnfg_phy_type phy_type; |
| struct cfcnfg *cfg; |
| - struct caif_device_entry_list *caifdevs = |
| - caif_device_list(dev_net(dev)); |
| + struct caif_device_entry_list *caifdevs; |
| |
| if (dev->type != ARPHRD_CAIF) |
| return 0; |
| @@ -222,6 +221,8 @@ static int caif_device_notify(struct not |
| if (cfg == NULL) |
| return 0; |
| |
| + caifdevs = caif_device_list(dev_net(dev)); |
| + |
| switch (what) { |
| case NETDEV_REGISTER: |
| caifd = caif_device_alloc(dev); |