While been playing with c/r of a container with IP assigned I found that
VE exit (ve_drop_context) is happening earlier than venet::exit
routine which means the ve::ve_netns = nil when we enter into
ip releasing procedure.

 | zap_pid_ns_processes
 |  ve_stop_ns
 |  ve_exit_ns
 |   ve_drop_context(ve);
 |    put_net(ve->ve_netns);
 |    ve->ve_netns = NULL;

Releasing ve context that early looks logical because ve::ve_netns
is a part of ve structure itself, in turn ip address and venet device
is rather a side feature provided by venet module.

So because we do not create nested venet devices and adding
some additional ioctl makes code only harder to read I propose
to use VE exit hook to cleanup ip address.

With the patch applied I can checkpoint/restore container
with venet configured.

Signed-off-by: Cyrill Gorcunov <[email protected]>
CC: Vladimir Davydov <[email protected]>
CC: Konstantin Khorenko <[email protected]>
CC: Pavel Emelyanov <[email protected]>
CC: Andrey Vagin <[email protected]>
---

If there some better idea, please share.

 drivers/net/venetdev.c |   71 ++++++++++++++++++++++---------------------------
 1 file changed, 32 insertions(+), 39 deletions(-)

Index: linux-pcs7.git/drivers/net/venetdev.c
===================================================================
--- linux-pcs7.git.orig/drivers/net/venetdev.c
+++ linux-pcs7.git/drivers/net/venetdev.c
@@ -881,9 +881,13 @@ static int do_ve_ip_map(struct ve_struct
        switch (op)
        {
                case VE_IP_ADD:
-                       err = -ESRCH;
-                       if (ve->is_running)
-                               err = veip_entry_add(ve, addr);
+                       /*
+                        * FIXME We should check if VE
+                        * is either running or in restore
+                        * state instead of allowing adding
+                        * address arbitrary.
+                        */
+                       err = veip_entry_add(ve, addr);
                        break;
 
                case VE_IP_DEL:
@@ -1113,51 +1117,39 @@ err:
        return err;
 }
 
-static __net_exit void venet_exit_net(struct list_head *net_exit_list)
+static struct pernet_operations venet_net_ops = {
+       .init = venet_init_net,
+};
+
+/*
+ * VE context dropping is happening earlier than
+ * pernet_operations::exit method so we can't
+ * rely on it and do the cleanup earlier.
+ */
+static void venet_stop_notifier(void *data)
 {
-       struct net *net;
-       struct ve_struct *env;
-       struct net_device *dev;
-       LIST_HEAD(netdev_kill_list);
+       struct ve_struct *env = data;
 
-       list_for_each_entry(net, net_exit_list, exit_list) {
-               env = net->owner_ve;
-               if (env->ve_netns != net)
-                       continue;
+       if (env->ve_netns) {
+               struct net_device *dev = env->_venet_dev;
 
                venet_ext_clean(env);
                veip_stop(env);
 
-               dev = env->_venet_dev;
-               if (dev == NULL)
-                       continue;
-
-               rtnl_lock();
-               unregister_netdevice_queue(dev, &netdev_kill_list);
-               rtnl_unlock();
-       }
-
-       rtnl_lock();
-       unregister_netdevice_many(&netdev_kill_list);
-       rtnl_unlock();
-
-       list_for_each_entry(net, net_exit_list, exit_list) {
-               env = net->owner_ve;
-               if (env->ve_netns != net)
-                       continue;
-
-               dev = env->_venet_dev;
-               if (dev == NULL)
-                       continue;
-
-               env->_venet_dev = NULL;
-               free_netdev(dev);
+               if (dev) {
+                       env->_venet_dev = NULL;
+                       rtnl_lock();
+                       unregister_netdevice(dev);
+                       rtnl_unlock();
+                       free_netdev(dev);
+               }
        }
 }
 
-static struct pernet_operations venet_net_ops = {
-       .init = venet_init_net,
-       .exit_batch = venet_exit_net,
+static struct ve_hook venet_stop_hook = {
+       .fini           = venet_stop_notifier,
+       .priority       = HOOK_PRIO_FINISHING,
+       .owner          = THIS_MODULE,
 };
 
 static int venet_changelink(struct net_device *dev, struct nlattr *tb[],
@@ -1241,6 +1233,7 @@ __init int venet_init(void)
 
        vzioctl_register(&venetcalls);
        vzmon_register_veaddr_print_cb(veaddr_seq_print);
+       ve_hook_register(VE_SS_CHAIN, &venet_stop_hook);
 
        return rtnl_link_register(&venet_link_ops);
 
_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to