diff options
-rw-r--r-- | src/core/device.c | 25 | ||||
-rw-r--r-- | src/core/manager.c | 7 | ||||
-rw-r--r-- | src/core/manager.h | 5 | ||||
-rw-r--r-- | src/core/swap.c | 181 | ||||
-rw-r--r-- | src/core/swap.h | 12 |
5 files changed, 179 insertions, 51 deletions
diff --git a/src/core/device.c b/src/core/device.c index 63d0302d3b..4ff7c37238 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -23,8 +23,6 @@ #include <sys/epoll.h> #include <libudev.h> -#include "unit.h" -#include "device.h" #include "strv.h" #include "log.h" #include "unit-name.h" @@ -32,6 +30,9 @@ #include "def.h" #include "path-util.h" #include "udev-util.h" +#include "unit.h" +#include "swap.h" +#include "device.h" static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = { [DEVICE_DEAD] = UNIT_INACTIVE, @@ -502,11 +503,6 @@ static void device_shutdown(Manager *m) { m->udev_monitor = NULL; } - if (m->udev) { - udev_unref(m->udev); - m->udev = NULL; - } - hashmap_free(m->devices_by_sysfs); m->devices_by_sysfs = NULL; } @@ -518,11 +514,7 @@ static int device_enumerate(Manager *m) { assert(m); - if (!m->udev) { - m->udev = udev_new(); - if (!m->udev) - return -ENOMEM; - + if (!m->udev_monitor) { m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); if (!m->udev_monitor) { r = -ENOMEM; @@ -607,11 +599,20 @@ static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, r = device_process_removed_device(m, dev); if (r < 0) log_error("Failed to process device remove event: %s", strerror(-r)); + + r = swap_process_removed_device(m, dev); + if (r < 0) + log_error("Failed to process swap device remove event: %s", strerror(-r)); + } else { r = device_process_new_device(m, dev); if (r < 0) log_error("Failed to process device new event: %s", strerror(-r)); + r = swap_process_new_device(m, dev); + if (r < 0) + log_error("Failed to process swap device new event: %s", strerror(-r)); + manager_dispatch_load_queue(m); device_set_path_plugged(m, dev); diff --git a/src/core/manager.c b/src/core/manager.c index ba4dab3b86..aa4baaacc8 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -490,6 +490,12 @@ int manager_new(SystemdRunningAs running_as, bool reexecuting, Manager **_m) { if (r < 0) goto fail; + m->udev = udev_new(); + if (!m->udev) { + r = -ENOMEM; + goto fail; + } + if (running_as == SYSTEMD_SYSTEM) try_bus_connect = reexecuting; else if (getenv("DBUS_SESSION_BUS_ADDRESS")) @@ -691,6 +697,7 @@ void manager_free(Manager *m) { manager_close_idle_pipe(m); + udev_unref(m->udev); sd_event_unref(m->event); free(m->notify_socket); diff --git a/src/core/manager.h b/src/core/manager.h index d6a6bce424..bf05812fc5 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -138,8 +138,9 @@ struct Manager { char *generator_unit_path_early; char *generator_unit_path_late; - /* Data specific to the device subsystem */ struct udev* udev; + + /* Data specific to the device subsystem */ struct udev_monitor* udev_monitor; sd_event_source *udev_event_source; Hashmap *devices_by_sysfs; @@ -151,7 +152,7 @@ struct Manager { /* Data specific to the swap filesystem */ FILE *proc_swaps; sd_event_source *swap_event_source; - Hashmap *swaps_by_proc_swaps; + Hashmap *swaps_by_devnode; /* Data specific to the D-Bus subsystem */ sd_bus *api_bus, *system_bus; diff --git a/src/core/swap.c b/src/core/swap.c index adcf78b717..4e65c701fd 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -59,29 +59,55 @@ static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userd static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata); static void swap_unset_proc_swaps(Swap *s) { + assert(s); + + if (!s->from_proc_swaps) + return; + + free(s->parameters_proc_swaps.what); + s->parameters_proc_swaps.what = NULL; + + s->from_proc_swaps = false; +} + +static int swap_set_devnode(Swap *s, const char *devnode) { Hashmap *swaps; Swap *first; + int r; assert(s); - if (!s->parameters_proc_swaps.what) - return; + r = hashmap_ensure_allocated(&UNIT(s)->manager->swaps_by_devnode, string_hash_func, string_compare_func); + if (r < 0) + return r; - /* Remove this unit from the chain of swaps which share the - * same kernel swap device. */ - swaps = UNIT(s)->manager->swaps_by_proc_swaps; - first = hashmap_get(swaps, s->parameters_proc_swaps.what); - LIST_REMOVE(same_proc_swaps, first, s); + swaps = UNIT(s)->manager->swaps_by_devnode; - if (first) - hashmap_remove_and_replace(swaps, s->parameters_proc_swaps.what, first->parameters_proc_swaps.what, first); - else - hashmap_remove(swaps, s->parameters_proc_swaps.what); + if (s->devnode) { + first = hashmap_get(swaps, s->devnode); - free(s->parameters_proc_swaps.what); - s->parameters_proc_swaps.what = NULL; + LIST_REMOVE(same_devnode, first, s); + if (first) + hashmap_replace(swaps, first->devnode, first); + else + hashmap_remove(swaps, s->devnode); - s->from_proc_swaps = false; + free(s->devnode); + s->devnode = NULL; + } + + if (devnode) { + s->devnode = strdup(devnode); + if (!s->devnode) + return -ENOMEM; + + first = hashmap_get(swaps, s->devnode); + LIST_PREPEND(same_devnode, first, s); + + return hashmap_replace(swaps, first->devnode, first); + } + + return 0; } static void swap_init(Unit *u) { @@ -121,6 +147,7 @@ static void swap_done(Unit *u) { assert(s); swap_unset_proc_swaps(s); + swap_set_devnode(s, NULL); free(s->what); s->what = NULL; @@ -242,6 +269,27 @@ static int swap_verify(Swap *s) { return 0; } +static int swap_load_devnode(Swap *s) { + _cleanup_udev_device_unref_ struct udev_device *d = NULL; + struct stat st; + const char *p; + + assert(s); + + if (stat(s->what, &st) < 0 || !S_ISBLK(st.st_mode)) + return 0; + + d = udev_device_new_from_devnum(UNIT(s)->manager->udev, 'b', st.st_rdev); + if (!d) + return 0; + + p = udev_device_get_devnode(d); + if (!p) + return 0; + + return swap_set_devnode(s, p); +} + static int swap_load(Unit *u) { int r; Swap *s = SWAP(u); @@ -290,6 +338,10 @@ static int swap_load(Unit *u) { if (r < 0) return r; + r = swap_load_devnode(s); + if (r < 0) + return r; + r = unit_add_default_slice(u); if (r < 0) return r; @@ -322,7 +374,6 @@ static int swap_add_one( Unit *u = NULL; int r; SwapParameters *p; - Swap *first; assert(m); assert(what); @@ -368,17 +419,6 @@ static int swap_add_one( r = -ENOMEM; goto fail; } - - r = hashmap_ensure_allocated(&m->swaps_by_proc_swaps, string_hash_func, string_compare_func); - if (r < 0) - goto fail; - - first = hashmap_get(m->swaps_by_proc_swaps, p->what); - LIST_PREPEND(same_proc_swaps, first, SWAP(u)); - - r = hashmap_replace(m->swaps_by_proc_swaps, p->what, first); - if (r < 0) - goto fail; } if (set_flags) { @@ -554,6 +594,9 @@ static void swap_dump(Unit *u, FILE *f, const char *prefix) { prefix, yes_no(s->from_proc_swaps), prefix, yes_no(s->from_fragment)); + if (s->devnode) + fprintf(f, "%sDevice Node: %s\n", prefix, s->devnode); + if (p) fprintf(f, "%sPriority: %i\n" @@ -1150,23 +1193,24 @@ static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, v } static Unit *swap_following(Unit *u) { + _cleanup_free_ char *p = NULL; Swap *s = SWAP(u); Swap *other, *first = NULL; assert(s); - if (streq_ptr(s->what, s->parameters_proc_swaps.what)) + if (streq_ptr(s->what, s->devnode)) return NULL; /* Make everybody follow the unit that's named after the swap * device in the kernel */ - LIST_FOREACH_AFTER(same_proc_swaps, other, s) - if (streq_ptr(other->what, other->parameters_proc_swaps.what)) + LIST_FOREACH_AFTER(same_devnode, other, s) + if (streq_ptr(other->what, other->devnode)) return UNIT(other); - LIST_FOREACH_BEFORE(same_proc_swaps, other, s) { - if (streq_ptr(other->what, other->parameters_proc_swaps.what)) + LIST_FOREACH_BEFORE(same_devnode, other, s) { + if (streq_ptr(other->what, other->devnode)) return UNIT(other); first = other; @@ -1183,7 +1227,7 @@ static int swap_following_set(Unit *u, Set **_set) { assert(s); assert(_set); - if (LIST_JUST_US(same_proc_swaps, s)) { + if (LIST_JUST_US(same_devnode, s)) { *_set = NULL; return 0; } @@ -1192,13 +1236,13 @@ static int swap_following_set(Unit *u, Set **_set) { if (!set) return -ENOMEM; - LIST_FOREACH_AFTER(same_proc_swaps, other, s) { + LIST_FOREACH_AFTER(same_devnode, other, s) { r = set_put(set, other); if (r < 0) goto fail; } - LIST_FOREACH_BEFORE(same_proc_swaps, other, s) { + LIST_FOREACH_BEFORE(same_devnode, other, s) { r = set_put(set, other); if (r < 0) goto fail; @@ -1222,12 +1266,13 @@ static void swap_shutdown(Manager *m) { m->proc_swaps = NULL; } - hashmap_free(m->swaps_by_proc_swaps); - m->swaps_by_proc_swaps = NULL; + hashmap_free(m->swaps_by_devnode); + m->swaps_by_devnode = NULL; } static int swap_enumerate(Manager *m) { int r; + assert(m); if (!m->proc_swaps) { @@ -1258,6 +1303,70 @@ fail: return r; } +int swap_process_new_device(Manager *m, struct udev_device *dev) { + struct udev_list_entry *item = NULL, *first = NULL; + _cleanup_free_ char *e = NULL; + const char *dn; + Swap *s; + int r = 0; + + assert(m); + assert(dev); + + dn = udev_device_get_devnode(dev); + if (!dn) + return 0; + + e = unit_name_from_path(dn, ".swap"); + if (!e) + return -ENOMEM; + + s = hashmap_get(m->units, e); + if (s) + r = swap_set_devnode(s, dn); + + first = udev_device_get_devlinks_list_entry(dev); + udev_list_entry_foreach(item, first) { + _cleanup_free_ char *n = NULL; + + n = unit_name_from_path(udev_list_entry_get_name(item), ".swap"); + if (!n) + return -ENOMEM; + + s = hashmap_get(m->units, n); + if (s) { + int q; + + q = swap_set_devnode(s, dn); + if (q < 0) + r = q; + } + } + + return r; +} + +int swap_process_removed_device(Manager *m, struct udev_device *dev) { + _cleanup_free_ char *e = NULL; + const char *dn; + int r = 0; + Swap *s; + + dn = udev_device_get_devnode(dev); + if (!dn) + return 0; + + while ((s = hashmap_get(m->swaps_by_devnode, dn))) { + int q; + + q = swap_set_devnode(s, NULL); + if (q < 0) + r = q; + } + + return r; +} + static void swap_reset_failed(Unit *u) { Swap *s = SWAP(u); diff --git a/src/core/swap.h b/src/core/swap.h index 313a195957..3005abb2d2 100644 --- a/src/core/swap.h +++ b/src/core/swap.h @@ -22,6 +22,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <libudev.h> + typedef struct Swap Swap; #include "unit.h" @@ -71,6 +73,11 @@ struct Swap { char *what; + /* If the device has already shown up, this is the device + * node, which might be different from what, due to + * symlinks */ + char *devnode; + SwapParameters parameters_proc_swaps; SwapParameters parameters_fragment; @@ -103,11 +110,14 @@ struct Swap { different device nodes we might end up creating multiple devices for the same swap. We chain them up here. */ - LIST_FIELDS(struct Swap, same_proc_swaps); + LIST_FIELDS(struct Swap, same_devnode); }; extern const UnitVTable swap_vtable; +int swap_process_new_device(Manager *m, struct udev_device *dev); +int swap_process_removed_device(Manager *m, struct udev_device *dev); + const char* swap_state_to_string(SwapState i) _const_; SwapState swap_state_from_string(const char *s) _pure_; |