diff options
author | Lennart Poettering <lennart@poettering.net> | 2021-02-26 10:27:00 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2021-08-02 17:24:09 +0200 |
commit | 864e406256cd0eb2aed48cfe750efdec9c3d1e3a (patch) | |
tree | fdc0d464070a27f3d0570f930c8da5e1bd4b7fce /src/shared/copy.c | |
parent | 06a40b52d966143aa2d8e61e7fb6336f3f20e515 (diff) | |
download | systemd-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.c | 38 |
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; } |