diff options
author | Felix Fietkau <nbd@openwrt.org> | 2011-10-03 01:56:37 +0200 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2011-10-03 01:56:37 +0200 |
commit | f6b38cb7c9ad0e7feba7cb7d2a1678af5e032000 (patch) | |
tree | bdd8833e10c25ebfc7d017e12d505619aac3ff6a /device.c | |
parent | 39f5ec857a31fe65e14cdf9b75927297e78015bb (diff) |
more changes for config reload handling
Diffstat (limited to 'device.c')
-rw-r--r-- | device.c | 76 |
1 files changed, 71 insertions, 5 deletions
@@ -298,15 +298,81 @@ device_free_unused(struct device *dev) __device_free_unused(dev); } +enum dev_change_type +device_reload_config(struct device *dev, struct blob_attr *attr) +{ + struct blob_attr *tb[__DEV_ATTR_MAX], *tb1[__DEV_ATTR_MAX]; + + blobmsg_parse(dev_attrs, __DEV_ATTR_MAX, tb, + blob_data(attr), blob_len(attr)); + blobmsg_parse(dev_attrs, __DEV_ATTR_MAX, tb1, + blob_data(dev->config), blob_len(dev->config)); + + if (!config_diff(tb, tb1, &device_attr_list, NULL)) + return DEV_CONFIG_NO_CHANGE; + + device_init_settings(dev, tb); + return DEV_CONFIG_APPLIED; +} + +static enum dev_change_type +device_check_config(struct device *dev, struct blob_attr *attr) +{ + if (dev->type->reload) + return dev->type->reload(dev, attr); + + return device_reload_config(dev, attr); +} + +static void +device_replace(struct device *dev, struct device *odev) +{ + struct device_user *dep, *tmp; + bool present = odev->present; + + if (present) + device_set_present(odev, false); + + list_for_each_entry_safe(dep, tmp, &odev->users, list) { + list_move_tail(&dep->list, &dev->users); + dep->dev = dev; + } + device_free(odev); + + if (present) + device_set_present(dev, true); +} + struct device * device_create(const char *name, const struct device_type *type, struct blob_attr *config) { - struct device *dev; + struct device *odev = NULL, *dev; + enum dev_change_type change; + + odev = device_get(name, false); + if (odev) { + change = device_check_config(odev, config); + switch (change) { + case DEV_CONFIG_APPLIED: + free(odev->config); + odev->config = config_memdup(config); + if (odev->present) { + device_set_present(odev, false); + device_set_present(odev, true); + } + /* fall through */ + case DEV_CONFIG_NO_CHANGE: + return odev; + case DEV_CONFIG_RECREATE: + break; + } + } - dev = device_get(name, false); - if (dev) - return dev; + dev = type->create(config); + dev->config = config_memdup(config); + if (odev) + device_replace(dev, odev); - return type->create(config); + return dev; } |