]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
homework: run fitrim or fallocate on logout based on the new user record property
authorLennart Poettering <lennart@poettering.net>
Tue, 5 May 2020 13:13:20 +0000 (15:13 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 7 May 2020 14:13:07 +0000 (16:13 +0200)
src/home/homework-luks.c
src/home/homework-luks.h
src/home/homework.c
src/home/homework.h

index 5eb67bc2b3bb36237d386073cc785a43ba77d41d..694f215b30d5da5d0c3c5c037406badac1908197 100644 (file)
@@ -893,19 +893,19 @@ int home_store_header_identity_luks(
         return 1;
 }
 
-static int run_fitrim(int root_fd) {
+int run_fitrim(int root_fd) {
         char buf[FORMAT_BYTES_MAX];
         struct fstrim_range range = {
                 .len = UINT64_MAX,
         };
 
         /* If discarding is on, discard everything right after mounting, so that the discard setting takes
-         * effect on activation. */
+         * effect on activation. (Also, optionally, trim on logout) */
 
         assert(root_fd >= 0);
 
         if (ioctl(root_fd, FITRIM, &range) < 0) {
-                if (IN_SET(errno, ENOTTY, EOPNOTSUPP, EBADF)) {
+                if (ERRNO_IS_NOT_SUPPORTED(errno) || errno == EBADF) {
                         log_debug_errno(errno, "File system does not support FITRIM, not trimming.");
                         return 0;
                 }
@@ -918,15 +918,32 @@ static int run_fitrim(int root_fd) {
         return 1;
 }
 
-static int run_fallocate(int backing_fd, const struct stat *st) {
+int run_fitrim_by_path(const char *root_path) {
+        _cleanup_close_ int root_fd = -1;
+
+        root_fd = open(root_path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
+        if (root_fd < 0)
+                return log_error_errno(errno, "Failed to open file system '%s' for trimming: %m", root_path);
+
+        return run_fitrim(root_fd);
+}
+
+int run_fallocate(int backing_fd, const struct stat *st) {
         char buf[FORMAT_BYTES_MAX];
+        struct stat stbuf;
 
         assert(backing_fd >= 0);
-        assert(st);
 
         /* If discarding is off, let's allocate the whole image before mounting, so that the setting takes
          * effect on activation */
 
+        if (!st) {
+                if (fstat(backing_fd, &stbuf) < 0)
+                        return log_error_errno(errno, "Failed to fstat(): %m");
+
+                st = &stbuf;
+        }
+
         if (!S_ISREG(st->st_mode))
                 return 0;
 
@@ -955,6 +972,16 @@ static int run_fallocate(int backing_fd, const struct stat *st) {
         return 1;
 }
 
+int run_fallocate_by_path(const char *backing_path) {
+        _cleanup_close_ int backing_fd = -1;
+
+        backing_fd = open(backing_path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
+        if (backing_fd < 0)
+                return log_error_errno(errno, "Failed to open '%s' for fallocate(): %m", backing_path);
+
+        return run_fallocate(backing_fd, NULL);
+}
+
 int home_prepare_luks(
                 UserRecord *h,
                 bool already_activated,
@@ -1111,7 +1138,7 @@ int home_prepare_luks(
                                h->luks_volume_key_size,
                                h->password,
                                pkcs11_decrypted_passwords ? *pkcs11_decrypted_passwords : NULL,
-                               user_record_luks_discard(h),
+                               user_record_luks_discard(h) || user_record_luks_offline_discard(h),
                                &cd,
                                &found_luks_uuid,
                                &volume_key,
@@ -1147,6 +1174,9 @@ int home_prepare_luks(
 
                 if (user_record_luks_discard(h))
                         (void) run_fitrim(root_fd);
+
+                setup->image_fd = TAKE_FD(fd);
+                setup->do_offline_fallocate = !(setup->do_offline_fitrim = user_record_luks_offline_discard(h));
         }
 
         setup->loop = TAKE_PTR(loop);
@@ -1259,6 +1289,7 @@ int home_activate_luks(
                 return r;
 
         setup.undo_mount = false;
+        setup.do_offline_fitrim = false;
 
         loop_device_relinquish(setup.loop);
 
@@ -1267,6 +1298,7 @@ int home_activate_luks(
                 log_warning_errno(r, "Failed to relinquish DM device, ignoring: %m");
 
         setup.undo_dm = false;
+        setup.do_offline_fallocate = false;
 
         log_info("Everything completed.");
 
@@ -1279,6 +1311,7 @@ int home_activate_luks(
 int home_deactivate_luks(UserRecord *h) {
         _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
         _cleanup_free_ char *dm_name = NULL, *dm_node = NULL;
+        bool we_detached;
         int r;
 
         /* Note that the DM device and loopback device are set to auto-detach, hence strictly speaking we
@@ -1293,23 +1326,45 @@ int home_deactivate_luks(UserRecord *h) {
 
         r = crypt_init_by_name(&cd, dm_name);
         if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT)) {
-                log_debug_errno(r, "LUKS device %s is already detached.", dm_name);
-                return false;
+                log_debug_errno(r, "LUKS device %s has already been detached.", dm_name);
+                we_detached = false;
         } else if (r < 0)
                 return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", dm_name);
+        else {
+                log_info("Discovered used LUKS device %s.", dm_node);
+
+                crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
+
+                r = crypt_deactivate(cd, dm_name);
+                if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT)) {
+                        log_debug_errno(r, "LUKS device %s is already detached.", dm_node);
+                        we_detached = false;
+                } else if (r < 0)
+                        return log_info_errno(r, "LUKS device %s couldn't be deactivated: %m", dm_node);
+                else {
+                        log_info("LUKS device detaching completed.");
+                        we_detached = true;
+                }
+        }
 
-        log_info("Discovered used LUKS device %s.", dm_node);
+        if (user_record_luks_offline_discard(h))
+                log_debug("Not allocating on logout.");
+        else
+                (void) run_fallocate_by_path(user_record_image_path(h));
 
-        crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
+        return we_detached;
+}
 
-        r = crypt_deactivate(cd, dm_name);
-        if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT))
-                log_debug_errno(r, "LUKS device %s is already detached.", dm_node);
-        else if (r < 0)
-                return log_info_errno(r, "LUKS device %s couldn't be deactivated: %m", dm_node);
+int home_trim_luks(UserRecord *h) {
+        assert(h);
 
-        log_info("LUKS device detaching completed.");
-        return true;
+        if (!user_record_luks_offline_discard(h)) {
+                log_debug("Not trimming on logout.");
+                return 0;
+        }
+
+        (void) run_fitrim_by_path(user_record_home_directory(h));
+        return 0;
 }
 
 static int run_mkfs(
@@ -1918,7 +1973,9 @@ int home_create_luks(
                 if (asprintf(&disk_uuid_path, "/dev/disk/by-uuid/" SD_ID128_UUID_FORMAT_STR, SD_ID128_FORMAT_VAL(luks_uuid)) < 0)
                         return log_oom();
 
-                if (user_record_luks_discard(h)) {
+                if (user_record_luks_discard(h) || user_record_luks_offline_discard(h)) {
+                        /* If we want online or offline discard, discard once before we start using things. */
+
                         if (ioctl(image_fd, BLKDISCARD, (uint64_t[]) { 0, block_device_size }) < 0)
                                 log_full_errno(errno == EOPNOTSUPP ? LOG_DEBUG : LOG_WARNING, errno,
                                                "Failed to issue full-device BLKDISCARD on device, ignoring: %m");
@@ -2004,7 +2061,7 @@ int home_create_luks(
                         user_record_user_name_and_realm(h),
                         pkcs11_decrypted_passwords,
                         effective_passwords,
-                        user_record_luks_discard(h),
+                        user_record_luks_discard(h) || user_record_luks_offline_discard(h),
                         h,
                         &cd);
         if (r < 0)
@@ -2084,6 +2141,12 @@ int home_create_luks(
                 goto fail;
         }
 
+        if (user_record_luks_offline_discard(h)) {
+                r = run_fitrim(root_fd);
+                if (r < 0)
+                        goto fail;
+        }
+
         root_fd = safe_close(root_fd);
 
         r = umount_verbose("/run/systemd/user-home-mount");
@@ -2102,6 +2165,12 @@ int home_create_luks(
 
         loop = loop_device_unref(loop);
 
+        if (!user_record_luks_offline_discard(h)) {
+                r = run_fallocate(image_fd, NULL /* refresh stat() data */);
+                if (r < 0)
+                        goto fail;
+        }
+
         if (disk_uuid_path)
                 (void) ioctl(image_fd, BLKRRPART, 0);
 
index 581255a223aba392168fdfe221821143f632a4fe..bd51f5da50ae753065ca216fbd98350892e749ab 100644 (file)
@@ -9,6 +9,7 @@ int home_prepare_luks(UserRecord *h, bool already_activated, const char *force_i
 
 int home_activate_luks(UserRecord *h, char ***pkcs11_decrypted_passwords, UserRecord **ret_home);
 int home_deactivate_luks(UserRecord *h);
+int home_trim_luks(UserRecord *h);
 
 int home_store_header_identity_luks(UserRecord *h, HomeSetup *setup, UserRecord *old_home);
 
@@ -36,3 +37,8 @@ static inline uint64_t luks_volume_key_size_convert(struct crypt_device *cd) {
 
         return (uint64_t) k;
 }
+
+int run_fitrim(int root_fd);
+int run_fitrim_by_path(const char *root_path);
+int run_fallocate(int backing_fd, const struct stat *st);
+int run_fallocate_by_path(const char *backing_path);
index 38b740729c505394c79c8af3b073ec2273dbafcf..77afc402d383936ad89c32a03f8e6be29fb4fc8b 100644 (file)
@@ -163,7 +163,15 @@ int home_setup_undo(HomeSetup *setup) {
 
         assert(setup);
 
-        setup->root_fd = safe_close(setup->root_fd);
+        if (setup->root_fd >= 0) {
+                if (setup->do_offline_fitrim) {
+                        q = run_fitrim(setup->root_fd);
+                        if (q < 0)
+                                r = q;
+                }
+
+                setup->root_fd = safe_close(setup->root_fd);
+        }
 
         if (setup->undo_mount) {
                 q = umount_verbose("/run/systemd/user-home-mount");
@@ -177,8 +185,20 @@ int home_setup_undo(HomeSetup *setup) {
                         r = q;
         }
 
+        if (setup->image_fd >= 0) {
+                if (setup->do_offline_fallocate) {
+                        q = run_fallocate(setup->image_fd, NULL);
+                        if (q < 0)
+                                r = q;
+                }
+
+                setup->image_fd = safe_close(setup->image_fd);
+        }
+
         setup->undo_mount = false;
         setup->undo_dm = false;
+        setup->do_offline_fitrim = false;
+        setup->do_offline_fallocate = false;
 
         setup->dm_name = mfree(setup->dm_name);
         setup->dm_node = mfree(setup->dm_node);
@@ -666,6 +686,12 @@ static int home_deactivate(UserRecord *h, bool force) {
         if (r < 0)
                 return r;
         if (r == USER_TEST_MOUNTED) {
+                if (user_record_storage(h) == USER_LUKS) {
+                        r = home_trim_luks(h);
+                        if (r < 0)
+                                return r;
+                }
+
                 if (umount2(user_record_home_directory(h), UMOUNT_NOFOLLOW | (force ? MNT_FORCE|MNT_DETACH : 0)) < 0)
                         return log_error_errno(errno, "Failed to unmount %s: %m", user_record_home_directory(h));
 
index 81698b760149dc78dc7ee8b0342cbb82a41b013d..3bcf3ad9b01a0ac43fbd4253edd2354cecc5a4c5 100644 (file)
@@ -17,6 +17,7 @@ typedef struct HomeSetup {
         LoopDevice *loop;
         struct crypt_device *crypt_device;
         int root_fd;
+        int image_fd;
         sd_id128_t found_partition_uuid;
         sd_id128_t found_luks_uuid;
         sd_id128_t found_fs_uuid;
@@ -28,6 +29,8 @@ typedef struct HomeSetup {
 
         bool undo_dm;
         bool undo_mount;
+        bool do_offline_fitrim;
+        bool do_offline_fallocate;
 
         uint64_t partition_offset;
         uint64_t partition_size;
@@ -36,6 +39,7 @@ typedef struct HomeSetup {
 #define HOME_SETUP_INIT                                 \
         {                                               \
                 .root_fd = -1,                          \
+                .image_fd = -1,                         \
                 .partition_offset = UINT64_MAX,         \
                 .partition_size = UINT64_MAX,           \
         }