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:
+27
-11
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user