chiark / gitweb /
swap: restore support for nofail
[elogind.git] / src / core / swap.c
index 019d32ed0d607afde9eaa06571156e68388f65b8..e509a633d02462addd6f337b751bc93a70c37a3d 100644 (file)
@@ -77,7 +77,7 @@ static int swap_set_devnode(Swap *s, const char *devnode) {
 
         assert(s);
 
-        r = hashmap_ensure_allocated(&UNIT(s)->manager->swaps_by_devnode, string_hash_func, string_compare_func);
+        r = hashmap_ensure_allocated(&UNIT(s)->manager->swaps_by_devnode, &string_hash_ops);
         if (r < 0)
                 return r;
 
@@ -152,6 +152,9 @@ static void swap_done(Unit *u) {
         free(s->parameters_fragment.what);
         s->parameters_fragment.what = NULL;
 
+        free(s->parameters_fragment.options);
+        s->parameters_fragment.options = NULL;
+
         s->exec_runtime = exec_runtime_unref(s->exec_runtime);
         exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
         s->control_command = NULL;
@@ -188,20 +191,16 @@ static int swap_arm_timer(Swap *s) {
 }
 
 static int swap_add_device_links(Swap *s) {
-        SwapParameters *p;
-
         assert(s);
 
         if (!s->what)
                 return 0;
 
-        if (s->from_fragment)
-                p = &s->parameters_fragment;
-        else
+        if (!s->from_fragment)
                 return 0;
 
         if (is_device_path(s->what))
-                return unit_add_node_link(UNIT(s), s->what, !p->noauto && UNIT(s)->manager->running_as == SYSTEMD_SYSTEM);
+                return unit_add_node_link(UNIT(s), s->what, UNIT(s)->manager->running_as == SYSTEMD_SYSTEM);
         else
                 /* File based swap devices need to be ordered after
                  * systemd-remount-fs.service, since they might need a
@@ -210,9 +209,6 @@ static int swap_add_device_links(Swap *s) {
 }
 
 static int swap_add_default_dependencies(Swap *s) {
-        bool nofail = false, noauto = false;
-        int r;
-
         assert(s);
 
         if (UNIT(s)->manager->running_as != SYSTEMD_SYSTEM)
@@ -221,27 +217,7 @@ static int swap_add_default_dependencies(Swap *s) {
         if (detect_container(NULL) > 0)
                 return 0;
 
-        r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
-        if (r < 0)
-                return r;
-
-        if (s->from_fragment) {
-                SwapParameters *p = &s->parameters_fragment;
-
-                nofail = p->nofail;
-                noauto = p->noauto;
-        }
-
-        if (!noauto) {
-                if (nofail)
-                        r = unit_add_dependency_by_name_inverse(UNIT(s), UNIT_WANTS, SPECIAL_SWAP_TARGET, NULL, true);
-                else
-                        r = unit_add_two_dependencies_by_name_inverse(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SWAP_TARGET, NULL, true);
-                if (r < 0)
-                        return r;
-        }
-
-        return 0;
+        return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
 }
 
 static int swap_verify(Swap *s) {
@@ -366,8 +342,6 @@ static int swap_add_one(
                 const char *what,
                 const char *what_proc_swaps,
                 int priority,
-                bool noauto,
-                bool nofail,
                 bool set_flags) {
 
         _cleanup_free_ char *e = NULL;
@@ -430,8 +404,6 @@ static int swap_add_one(
         SWAP(u)->from_proc_swaps = true;
 
         p->priority = priority;
-        p->noauto = noauto;
-        p->nofail = nofail;
 
         unit_add_to_dbus_queue(u);
 
@@ -455,7 +427,7 @@ static int swap_process_new_swap(Manager *m, const char *device, int prio, bool
 
         assert(m);
 
-        r = swap_add_one(m, device, device, prio, false, false, set_flags);
+        r = swap_add_one(m, device, device, prio, set_flags);
         if (r < 0)
                 return r;
 
@@ -471,7 +443,7 @@ static int swap_process_new_swap(Manager *m, const char *device, int prio, bool
         /* Add the main device node */
         dn = udev_device_get_devnode(d);
         if (dn && !streq(dn, device))
-                swap_add_one(m, dn, device, prio, false, false, set_flags);
+                swap_add_one(m, dn, device, prio, set_flags);
 
         /* Add additional units for all symlinks */
         first = udev_device_get_devlinks_list_entry(d);
@@ -492,7 +464,7 @@ static int swap_process_new_swap(Manager *m, const char *device, int prio, bool
                             st.st_rdev != udev_device_get_devnum(d))
                                 continue;
 
-                swap_add_one(m, p, device, prio, false, false, set_flags);
+                swap_add_one(m, p, device, prio, set_flags);
         }
 
         return r;
@@ -601,11 +573,9 @@ static void swap_dump(Unit *u, FILE *f, const char *prefix) {
         if (p)
                 fprintf(f,
                         "%sPriority: %i\n"
-                        "%sNoAuto: %s\n"
-                        "%sNoFail: %s\n",
+                        "%sOptions: %s\n",
                         prefix, p->priority,
-                        prefix, yes_no(p->noauto),
-                        prefix, yes_no(p->nofail));
+                        prefix, strempty(p->options));
 
         if (s->control_pid > 0)
                 fprintf(f,
@@ -643,6 +613,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
         exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
         exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
         exec_params.cgroup_path = UNIT(s)->cgroup_path;
+        exec_params.cgroup_delegate = s->cgroup_context.delegate;
         exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
         exec_params.unit_id = UNIT(s)->id;
 
@@ -703,7 +674,8 @@ static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
         r = unit_kill_context(
                         UNIT(s),
                         &s->kill_context,
-                        state != SWAP_ACTIVATING_SIGTERM && state != SWAP_DEACTIVATING_SIGTERM,
+                        (state != SWAP_ACTIVATING_SIGTERM && state != SWAP_DEACTIVATING_SIGTERM) ?
+                        KILL_KILL : KILL_TERMINATE,
                         -1,
                         s->control_pid,
                         false);
@@ -732,38 +704,115 @@ fail:
         swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
 }
 
+static int mount_find_pri(const char *options, int *ret) {
+        const char *opt;
+        char *end;
+        unsigned long r;
+
+        assert(ret);
+
+        if (!options)
+                return 0;
+
+        opt = mount_test_option(options, "pri");
+        if (!opt)
+                return 0;
+
+        opt += strlen("pri");
+        if (*opt != '=')
+                return -EINVAL;
+
+        errno = 0;
+        r = strtoul(opt + 1, &end, 10);
+        if (errno > 0)
+                return -errno;
+
+        if (end == opt + 1 || (*end != ',' && *end != 0))
+                return -EINVAL;
+
+        *ret = (int) r;
+        return 1;
+}
+
+static int mount_find_discard(const char *options, char **ret) {
+        const char *opt;
+        char *ans;
+        size_t len;
+
+        assert(ret);
+
+        if (!options)
+                return 0;
+
+        opt = mount_test_option(options, "discard");
+        if (!opt)
+                return 0;
+
+        opt += strlen("discard");
+        if (*opt == ',' || *opt == '\0')
+                ans = strdup("all");
+        else {
+                if (*opt != '=')
+                        return -EINVAL;
+
+                len = strcspn(opt + 1, ",");
+                if (len == 0)
+                        return -EINVAL;
+
+                ans = strndup(opt + 1, len);
+        }
+
+        if (!ans)
+                return -ENOMEM;
+
+        *ret = ans;
+        return 1;
+}
+
 static void swap_enter_activating(Swap *s) {
-        int r, priority;
+        _cleanup_free_ char *discard = NULL;
+        int r, priority = -1;
 
         assert(s);
 
         s->control_command_id = SWAP_EXEC_ACTIVATE;
         s->control_command = s->exec_command + SWAP_EXEC_ACTIVATE;
 
-        if (s->from_fragment)
+        if (s->from_fragment) {
+                mount_find_discard(s->parameters_fragment.options, &discard);
+
                 priority = s->parameters_fragment.priority;
-        else
-                priority = -1;
+                if (priority < 0)
+                        mount_find_pri(s->parameters_fragment.options, &priority);
+        }
+
+        r = exec_command_set(s->control_command, "/sbin/swapon", NULL);
+        if (r < 0)
+                goto fail;
 
         if (priority >= 0) {
                 char p[DECIMAL_STR_MAX(int)];
 
                 sprintf(p, "%i", priority);
+                r = exec_command_append(s->control_command, "-p", p, NULL);
+                if (r < 0)
+                        goto fail;
+        }
 
-                r = exec_command_set(
-                                s->control_command,
-                                "/sbin/swapon",
-                                "-p",
-                                p,
-                                s->what,
-                                NULL);
-        } else
-                r = exec_command_set(
-                                s->control_command,
-                                "/sbin/swapon",
-                                s->what,
-                                NULL);
+        if (discard && !streq(discard, "none")) {
+                const char *discard_arg;
+
+                if (streq(discard, "all"))
+                        discard_arg = "--discard";
+                else
+                        discard_arg = strappenda("--discard=", discard);
+
+                r = exec_command_append(s->control_command, discard_arg, NULL);
+                if (r < 0)
+                        goto fail;
+        }
 
+        r = exec_command_append(s->control_command, s->what, NULL);
         if (r < 0)
                 goto fail;
 
@@ -1193,11 +1242,25 @@ static Unit *swap_following(Unit *u) {
 
         assert(s);
 
-        if (streq_ptr(s->what, s->devnode))
+        /* If the user configured the swap through /etc/fstab or
+         * a device unit, follow that. */
+
+        if (s->from_fragment)
                 return NULL;
 
-        /* Make everybody follow the unit that's named after the swap
-         * device in the kernel */
+        LIST_FOREACH_AFTER(same_devnode, other, s)
+                if (other->from_fragment)
+                        return UNIT(other);
+
+        LIST_FOREACH_BEFORE(same_devnode, other, s)
+                if (other->from_fragment)
+                        return UNIT(other);
+
+        /* Otherwise make everybody follow the unit that's named after
+         * the swap device in the kernel */
+
+        if (streq_ptr(s->what, s->devnode))
+                return NULL;
 
         LIST_FOREACH_AFTER(same_devnode, other, s)
                 if (streq_ptr(other->what, other->devnode))
@@ -1210,6 +1273,7 @@ static Unit *swap_following(Unit *u) {
                 first = other;
         }
 
+        /* Fall back to the first on the list */
         return UNIT(first);
 }
 
@@ -1226,7 +1290,7 @@ static int swap_following_set(Unit *u, Set **_set) {
                 return 0;
         }
 
-        set = set_new(NULL, NULL);
+        set = set_new(NULL);
         if (!set)
                 return -ENOMEM;