|
@@ -1514,18 +1514,34 @@ static void net_vm_change_state_handler(void *opaque, bool running,
|
|
|
|
|
|
void net_cleanup(void)
|
|
void net_cleanup(void)
|
|
{
|
|
{
|
|
- NetClientState *nc;
|
|
|
|
|
|
+ NetClientState *nc, **p = &QTAILQ_FIRST(&net_clients);
|
|
|
|
|
|
/*cleanup colo compare module for COLO*/
|
|
/*cleanup colo compare module for COLO*/
|
|
colo_compare_cleanup();
|
|
colo_compare_cleanup();
|
|
|
|
|
|
- /* We may del multiple entries during qemu_del_net_client(),
|
|
|
|
- * so QTAILQ_FOREACH_SAFE() is also not safe here.
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Walk the net_clients list and remove the netdevs but *not* any
|
|
|
|
+ * NET_CLIENT_DRIVER_NIC entries. The latter are owned by the device
|
|
|
|
+ * model which created them, and in some cases (e.g. xen-net-device)
|
|
|
|
+ * the device itself may do cleanup at exit and will be upset if we
|
|
|
|
+ * just delete its NIC from underneath it.
|
|
|
|
+ *
|
|
|
|
+ * Since qemu_del_net_client() may delete multiple entries, using
|
|
|
|
+ * QTAILQ_FOREACH_SAFE() is not safe here. The only safe pointer
|
|
|
|
+ * to keep as a bookmark is a NET_CLIENT_DRIVER_NIC entry, so keep
|
|
|
|
+ * 'p' pointing to either the head of the list, or the 'next' field
|
|
|
|
+ * of the latest NET_CLIENT_DRIVER_NIC, and operate on *p as we walk
|
|
|
|
+ * the list.
|
|
|
|
+ *
|
|
|
|
+ * The 'nc' variable isn't part of the list traversal; it's purely
|
|
|
|
+ * for convenience as too much '(*p)->' has a tendency to make the
|
|
|
|
+ * readers' eyes bleed.
|
|
*/
|
|
*/
|
|
- while (!QTAILQ_EMPTY(&net_clients)) {
|
|
|
|
- nc = QTAILQ_FIRST(&net_clients);
|
|
|
|
|
|
+ while (*p) {
|
|
|
|
+ nc = *p;
|
|
if (nc->info->type == NET_CLIENT_DRIVER_NIC) {
|
|
if (nc->info->type == NET_CLIENT_DRIVER_NIC) {
|
|
- qemu_del_nic(qemu_get_nic(nc));
|
|
|
|
|
|
+ /* Skip NET_CLIENT_DRIVER_NIC entries */
|
|
|
|
+ p = &QTAILQ_NEXT(nc, next);
|
|
} else {
|
|
} else {
|
|
qemu_del_net_client(nc);
|
|
qemu_del_net_client(nc);
|
|
}
|
|
}
|