summaryrefslogtreecommitdiff
path: root/src/shared/copy.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2021-02-26 10:27:00 +0100
committerLennart Poettering <lennart@poettering.net>2021-08-02 17:24:09 +0200
commit864e406256cd0eb2aed48cfe750efdec9c3d1e3a (patch)
treefdc0d464070a27f3d0570f930c8da5e1bd4b7fce /src/shared/copy.c
parent06a40b52d966143aa2d8e61e7fb6336f3f20e515 (diff)
downloadsystemd-864e406256cd0eb2aed48cfe750efdec9c3d1e3a.tar.gz
copy: add COPY_SYNCFS flag
When copying large directory trees it should be a better idea to sync the whole fs once when we are done instead of individually for each file, hence add COPY_SYNCFS. As opposed to COPY_FSYNC/COPY_FSYNC_FULL this only really applies to the top-level directory, after completion of the whole copy.
Diffstat (limited to 'src/shared/copy.c')
-rw-r--r--src/shared/copy.c38
1 files changed, 27 insertions, 11 deletions
diff --git a/src/shared/copy.c b/src/shared/copy.c
index 3ac904c6c9..e47b56ce91 100644
--- a/src/shared/copy.c
+++ b/src/shared/copy.c
@@ -984,7 +984,17 @@ int copy_tree_at_full(
if (r < 0)
return r;
- if (copy_flags & COPY_FSYNC_FULL) {
+ if (S_ISDIR(st.st_mode) && (copy_flags & COPY_SYNCFS)) {
+ /* If the top-level inode is a directory run syncfs() now. */
+ r = syncfs_path(fdt, to);
+ if (r < 0)
+ return r;
+ } else if ((copy_flags & (COPY_FSYNC_FULL|COPY_SYNCFS)) != 0) {
+ /* fsync() the parent dir of what we just copied if COPY_FSYNC_FULL is set. Also do this in
+ * case COPY_SYNCFS is set but the top-level inode wasn't actually a directory. We do this so that
+ * COPY_SYNCFS provides reasonable synchronization semantics on any kind of inode: when the
+ * copy operation is done the whole inode — regardless of its type — and all its children
+ * will be synchronized to disk. */
r = fsync_parent_at(fdt, to);
if (r < 0)
return r;
@@ -993,6 +1003,16 @@ int copy_tree_at_full(
return 0;
}
+static int sync_dir_by_flags(const char *path, CopyFlags copy_flags) {
+
+ if (copy_flags & COPY_SYNCFS)
+ return syncfs_path(AT_FDCWD, path);
+ if (copy_flags & COPY_FSYNC_FULL)
+ return fsync_parent_at(AT_FDCWD, path);
+
+ return 0;
+}
+
int copy_directory_fd_full(
int dirfd,
const char *to,
@@ -1029,11 +1049,9 @@ int copy_directory_fd_full(
if (r < 0)
return r;
- if (copy_flags & COPY_FSYNC_FULL) {
- r = fsync_parent_at(AT_FDCWD, to);
- if (r < 0)
- return r;
- }
+ r = sync_dir_by_flags(to, copy_flags);
+ if (r < 0)
+ return r;
return 0;
}
@@ -1074,11 +1092,9 @@ int copy_directory_full(
if (r < 0)
return r;
- if (copy_flags & COPY_FSYNC_FULL) {
- r = fsync_parent_at(AT_FDCWD, to);
- if (r < 0)
- return r;
- }
+ r = sync_dir_by_flags(to, copy_flags);
+ if (r < 0)
+ return r;
return 0;
}