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.
This commit is contained in:
Lennart Poettering
2021-08-02 17:24:09 +02:00
parent 06a40b52d9
commit 864e406256
2 changed files with 28 additions and 11 deletions
+27 -11
View File
@@ -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;
}
+1
View File
@@ -21,6 +21,7 @@ typedef enum CopyFlags {
COPY_HARDLINKS = 1 << 8, /* Try to reproduce hard links */
COPY_FSYNC = 1 << 9, /* fsync() after we are done */
COPY_FSYNC_FULL = 1 << 10, /* fsync_full() after we are done */
COPY_SYNCFS = 1 << 11, /* syncfs() the *top-level* dir after we are done */
} CopyFlags;
typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata);