summaryrefslogtreecommitdiffstats
path: root/src/home/homework.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/home/homework.c')
-rw-r--r--src/home/homework.c57
1 files changed, 53 insertions, 4 deletions
diff --git a/src/home/homework.c b/src/home/homework.c
index d35712c351..49533b2422 100644
--- a/src/home/homework.c
+++ b/src/home/homework.c
@@ -28,6 +28,7 @@
#include "rm-rf.h"
#include "stat-util.h"
#include "strv.h"
+#include "sync-util.h"
#include "tmpfile-util.h"
#include "user-util.h"
#include "virt.h"
@@ -283,6 +284,20 @@ int user_record_authenticate(
return 0;
}
+static void drop_caches_now(void) {
+ int r;
+
+ /* Drop file system caches now. See https://www.kernel.org/doc/Documentation/sysctl/vm.txt for
+ * details. We write "2" into /proc/sys/vm/drop_caches to ensure dentries/inodes are flushed, but not
+ * more. */
+
+ r = write_string_file("/proc/sys/vm/drop_caches", "2\n", WRITE_STRING_FILE_DISABLE_BUFFER);
+ if (r < 0)
+ log_warning_errno(r, "Failed to drop caches, ignoring: %m");
+ else
+ log_debug("Dropped caches.");
+}
+
int home_setup_undo(HomeSetup *setup) {
int r = 0, q;
@@ -295,6 +310,9 @@ int home_setup_undo(HomeSetup *setup) {
r = q;
}
+ if (syncfs(setup->root_fd) < 0)
+ log_debug_errno(errno, "Failed to synchronize home directory, ignoring: %m");
+
setup->root_fd = safe_close(setup->root_fd);
}
@@ -345,6 +363,9 @@ int home_setup_undo(HomeSetup *setup) {
setup->volume_key = mfree(setup->volume_key);
setup->volume_key_size = 0;
+ if (setup->do_drop_caches)
+ drop_caches_now();
+
return r;
}
@@ -367,6 +388,9 @@ int home_prepare(
/* Makes a home directory accessible (through the root_fd file descriptor, not by path!). */
+ if (!already_activated) /* If we set up the directory, we should also drop caches once we are done */
+ setup->do_drop_caches = setup->do_drop_caches || user_record_drop_caches(h);
+
switch (user_record_storage(h)) {
case USER_LUKS:
@@ -827,6 +851,13 @@ static int home_deactivate(UserRecord *h, bool force) {
return r;
}
+ /* Sync explicitly, so that the drop caches logic below can work as documented */
+ r = syncfs_path(AT_FDCWD, user_record_home_directory(h));
+ if (r < 0)
+ log_debug_errno(r, "Failed to synchronize home directory, ignoring: %m");
+ else
+ log_info("Syncing completed.");
+
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));
@@ -846,6 +877,9 @@ static int home_deactivate(UserRecord *h, bool force) {
if (!done)
return log_error_errno(SYNTHETIC_ERRNO(ENOEXEC), "Home is not active.");
+ if (user_record_drop_caches(h))
+ drop_caches_now();
+
log_info("Everything completed.");
return 0;
}
@@ -1268,9 +1302,21 @@ static int home_remove(UserRecord *h) {
if (unlink(ip) < 0) {
if (errno != ENOENT)
return log_error_errno(errno, "Failed to remove %s: %m", ip);
- } else
+ } else {
+ _cleanup_free_ char *parent = NULL;
+
deleted = true;
+ r = path_extract_directory(ip, &parent);
+ if (r < 0)
+ log_debug_errno(r, "Failed to determine parent directory of '%s': %m", ip);
+ else {
+ r = fsync_path_at(AT_FDCWD, parent);
+ if (r < 0)
+ log_debug_errno(r, "Failed to synchronize disk after deleting '%s', ignoring: %m", ip);
+ }
+ }
+
} else if (S_ISBLK(st.st_mode))
log_info("Not removing file system on block device %s.", ip);
else
@@ -1285,7 +1331,7 @@ static int home_remove(UserRecord *h) {
case USER_FSCRYPT:
assert(ip);
- r = rm_rf(ip, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
+ r = rm_rf(ip, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME|REMOVE_SYNCFS);
if (r < 0) {
if (r != -ENOENT)
return log_warning_errno(r, "Failed to remove %s: %m", ip);
@@ -1316,9 +1362,12 @@ static int home_remove(UserRecord *h) {
deleted = true;
}
- if (deleted)
+ if (deleted) {
+ if (user_record_drop_caches(h))
+ drop_caches_now();
+
log_info("Everything completed.");
- else
+ } else
return log_notice_errno(SYNTHETIC_ERRNO(EALREADY),
"Nothing to remove.");