[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH 2/2] mini-os: netfront: fix suspend/resume handling
Suspend/resume handling of netfront is completely broken from the beginning. Commit d225f4012d69a1 ("Save/Restore Support: Add suspend/restore support for netfront") introduced a new structure netfront_dev_list referencing the real struct netfront_dev elements. This list is used to setup the devices when resuming again. Unfortunately the netfront_dev elements are released during suspend, so at resume time those references will be stale. Fix this whole mess by dropping struct netfront_dev_list again and link the netfront_dev elements directly into a list. When suspending don't free those elements. The ip-address, netmask and gateway strings can just be released when suspending and reread from xenstore at resume time. Fixes: d225f4012d69a1 ("Save/Restore Support: Add suspend/restore support for netfront") Signed-off-by: Juergen Gross <jgross@xxxxxxxx> --- netfront.c | 162 ++++++++++++++++++++++------------------------------- 1 file changed, 67 insertions(+), 95 deletions(-) diff --git a/netfront.c b/netfront.c index 9057908..2075410 100644 --- a/netfront.c +++ b/netfront.c @@ -36,6 +36,8 @@ struct net_buffer { }; struct netfront_dev { + int refcount; + domid_t dom; unsigned short tx_freelist[NET_TX_RING_SIZE + 1]; @@ -66,27 +68,19 @@ struct netfront_dev { void (*netif_rx)(unsigned char* data, int len, void* arg); void *netif_rx_arg; - struct netfront_dev_list *ldev; -}; - -struct netfront_dev_list { - struct netfront_dev *dev; unsigned char rawmac[6]; char *ip; char *mask; char *gw; - int refcount; - - struct netfront_dev_list *next; + struct netfront_dev *next; }; -static struct netfront_dev_list *dev_list = NULL; +static struct netfront_dev *dev_list = NULL; void init_rx_buffers(struct netfront_dev *dev); -static struct netfront_dev *_init_netfront(struct netfront_dev *dev, - unsigned char rawmac[6], char **ip, char **mask, char **gw); -static void _shutdown_netfront(struct netfront_dev *dev); +static struct netfront_dev *_init_netfront(struct netfront_dev *dev); +static int _shutdown_netfront(struct netfront_dev *dev); void netfront_set_rx_handler(struct netfront_dev *dev, void (*thenetif_rx)(unsigned char *data, int len, void *arg), @@ -276,6 +270,7 @@ static void free_netfront(struct netfront_dev *dev) mask_evtchn(dev->evtchn); free(dev->mac); + free(dev->ip); free(dev->backend); gnttab_end_access(dev->rx_ring_ref); @@ -309,8 +304,7 @@ struct netfront_dev *init_netfront(char *_nodename, { char nodename[256]; struct netfront_dev *dev; - struct netfront_dev_list *ldev = NULL; - struct netfront_dev_list *list = NULL; + struct netfront_dev *list; static int netfrontends = 0; if (!_nodename) @@ -321,10 +315,9 @@ struct netfront_dev *init_netfront(char *_nodename, } /* Check if the device is already initialized */ - for (list = dev_list; list != NULL; list = list->next) { - if (strcmp(nodename, list->dev->nodename) == 0) { - list->refcount++; - dev = list->dev; + for (dev = dev_list; dev != NULL; dev = dev->next) { + if (strcmp(nodename, dev->nodename) == 0) { + dev->refcount++; if (thenetif_rx) netfront_set_rx_handler(dev, thenetif_rx, NULL); goto out; @@ -345,40 +338,34 @@ struct netfront_dev *init_netfront(char *_nodename, dev->netif_rx = thenetif_rx; dev->netif_rx_arg = NULL; - ldev = malloc(sizeof(struct netfront_dev_list)); - memset(ldev, 0, sizeof(struct netfront_dev_list)); - - if (_init_netfront(dev, ldev->rawmac, &(ldev->ip), &(ldev->mask), &(ldev->gw))) { - dev->ldev = ldev; - ldev->dev = dev; - ldev->refcount = 1; - ldev->next = NULL; + if (_init_netfront(dev)) { + dev->refcount = 1; + dev->next = NULL; if (!dev_list) { - dev_list = ldev; + dev_list = dev; } else { for (list = dev_list; list->next != NULL; list = list->next) ; - list->next = ldev; - } + list->next = dev; + } netfrontends++; } else { - free(ldev); dev = NULL; goto err; } out: if (rawmac) { - rawmac[0] = ldev->rawmac[0]; - rawmac[1] = ldev->rawmac[1]; - rawmac[2] = ldev->rawmac[2]; - rawmac[3] = ldev->rawmac[3]; - rawmac[4] = ldev->rawmac[4]; - rawmac[5] = ldev->rawmac[5]; + rawmac[0] = dev->rawmac[0]; + rawmac[1] = dev->rawmac[1]; + rawmac[2] = dev->rawmac[2]; + rawmac[3] = dev->rawmac[3]; + rawmac[4] = dev->rawmac[4]; + rawmac[5] = dev->rawmac[5]; } if (ip) - *ip = strdup(ldev->ip); + *ip = strdup(dev->ip); err: return dev; @@ -386,17 +373,15 @@ err: char *netfront_get_netmask(struct netfront_dev *dev) { - return dev->ldev->mask ? strdup(dev->ldev->mask) : NULL; + return dev->mask ? strdup(dev->mask) : NULL; } char *netfront_get_gateway(struct netfront_dev *dev) { - return dev->ldev->gw ? strdup(dev->ldev->gw) : NULL; + return dev->gw ? strdup(dev->gw) : NULL; } -static struct netfront_dev *_init_netfront(struct netfront_dev *dev, - unsigned char rawmac[6], - char **ip, char **mask, char **gw) +static struct netfront_dev *_init_netfront(struct netfront_dev *dev) { xenbus_transaction_t xbt; char* err = NULL; @@ -518,6 +503,8 @@ done: { XenbusState state; char path[strlen(dev->backend) + strlen("/state") + 1]; + char *p; + snprintf(path, sizeof(path), "%s/state", dev->backend); xenbus_watch_path_token(XBT_NIL, path, path, &dev->events); @@ -532,26 +519,18 @@ done: goto error; } - if (ip) { - char *p; - - snprintf(path, sizeof(path), "%s/ip", dev->backend); - xenbus_read(XBT_NIL, path, ip); - - if (mask) { - p = strchr(*ip, ' '); - if (p) { - *p++ = '\0'; - *mask = p; - - if (gw) { - p = strchr(p, ' '); - if (p) { - *p++ = '\0'; - *gw = p; - } - } - } + snprintf(path, sizeof(path), "%s/ip", dev->backend); + xenbus_read(XBT_NIL, path, &dev->ip); + + p = strchr(dev->ip, ' '); + if (p) { + *p++ = '\0'; + dev->mask = p; + + p = strchr(p, ' '); + if (p) { + *p++ = '\0'; + dev->gw = p; } } } @@ -563,14 +542,13 @@ done: /* Special conversion specifier 'hh' needed for __ia64__. Without * this mini-os panics with 'Unaligned reference'. */ - if (rawmac) - sscanf(dev->mac,"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", - &rawmac[0], - &rawmac[1], - &rawmac[2], - &rawmac[3], - &rawmac[4], - &rawmac[5]); + sscanf(dev->mac,"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &dev->rawmac[0], + &dev->rawmac[1], + &dev->rawmac[2], + &dev->rawmac[3], + &dev->rawmac[4], + &dev->rawmac[5]); return dev; @@ -600,38 +578,33 @@ int netfront_tap_open(char *nodename) { void shutdown_netfront(struct netfront_dev *dev) { - struct netfront_dev_list *list = NULL; - struct netfront_dev_list *to_del = NULL; + struct netfront_dev *list; /* Check this is a valid device */ - for (list = dev_list; list != NULL; list = list->next) { - if (list->dev == dev) - break; - } + for (list = dev_list; list != NULL && list != dev; list = list->next); if (!list) { printk("Trying to shutdown an invalid netfront device (%p)\n", dev); return; } - list->refcount--; - if (list->refcount == 0) { - _shutdown_netfront(dev); + dev->refcount--; + if (dev->refcount == 0) { + if (_shutdown_netfront(dev)) + return; - to_del = list; - if (to_del == dev_list) { - free(to_del); - dev_list = NULL; + if (dev == dev_list) { + dev_list = NULL; } else { - for (list = dev_list; list->next != to_del; list = list->next) + for (list = dev_list; list->next != dev; list = list->next) ; - list->next = to_del->next; - free(to_del); + list->next = dev->next; } + free_netfront(dev); } } -static void _shutdown_netfront(struct netfront_dev *dev) +static int _shutdown_netfront(struct netfront_dev *dev) { char* err = NULL, *err2; XenbusState state; @@ -692,24 +665,23 @@ close: err2 = xenbus_rm(XBT_NIL, nodename); free(err2); - if (!err) - free_netfront(dev); + return err ? -EBUSY : 0; } void suspend_netfront(void) { - struct netfront_dev_list *list; + struct netfront_dev *dev; - for (list = dev_list; list != NULL; list = list->next) - _shutdown_netfront(list->dev); + for (dev = dev_list; dev != NULL; dev = dev->next) + _shutdown_netfront(dev); } void resume_netfront(void) { - struct netfront_dev_list *list; + struct netfront_dev *dev; - for (list = dev_list; list != NULL; list = list->next) - _init_netfront(list->dev, NULL, NULL, NULL, NULL); + for (dev = dev_list; dev != NULL; dev = dev->next) + _init_netfront(dev); } void init_rx_buffers(struct netfront_dev *dev) -- 2.26.2
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |