summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/device.c25
-rw-r--r--src/core/manager.c7
-rw-r--r--src/core/manager.h5
-rw-r--r--src/core/swap.c181
-rw-r--r--src/core/swap.h12
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_;