From: Lennart Poettering Date: Tue, 9 Sep 2025 15:05:05 +0000 (+0200) Subject: copy: calculate bytes per second while copying, and pass to progress info X-Git-Tag: v259-rc1~551 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=acd49435289842e045fcc73cd27e2a42ce1db681;p=thirdparty%2Fsystemd.git copy: calculate bytes per second while copying, and pass to progress info Also, show it in import-fs/repart. --- diff --git a/src/basic/forward.h b/src/basic/forward.h index 53b217b07b5..66da2b13a57 100644 --- a/src/basic/forward.h +++ b/src/basic/forward.h @@ -236,7 +236,7 @@ typedef struct sd_hwdb sd_hwdb; /* shared/ forward declarations */ -typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata); +typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, uint64_t bytes_per_second, void *userdata); typedef int (*copy_progress_path_t)(const char *path, const struct stat *st, void *userdata); struct local_address; diff --git a/src/import/import-fs.c b/src/import/import-fs.c index a132ab64f06..783b0461ef4 100644 --- a/src/import/import-fs.c +++ b/src/import/import-fs.c @@ -45,6 +45,7 @@ typedef struct ProgressInfo { uint64_t size; bool started; bool logged_incomplete; + uint64_t bps; } ProgressInfo; static void progress_info_free(ProgressInfo *p) { @@ -72,8 +73,10 @@ static void progress_show(ProgressInfo *p) { if (p->size == 0) log_info("Copying tree, currently at '%s'...", p->path); - else + else if (p->bps == UINT64_MAX) log_info("Copying tree, currently at '%s' (@%s)...", p->path, FORMAT_BYTES(p->size)); + else + log_info("Copying tree, currently at '%s' (@%s, %s/s)...", p->path, FORMAT_BYTES(p->size), FORMAT_BYTES(p->bps)); } static int progress_path(const char *path, const struct stat *st, void *userdata) { @@ -90,12 +93,13 @@ static int progress_path(const char *path, const struct stat *st, void *userdata return 0; } -static int progress_bytes(uint64_t nbytes, void *userdata) { +static int progress_bytes(uint64_t nbytes, uint64_t bps, void *userdata) { ProgressInfo *p = ASSERT_PTR(userdata); assert(p->size != UINT64_MAX); p->size += nbytes; + p->bps = bps; progress_show(p); return 0; @@ -103,7 +107,7 @@ static int progress_bytes(uint64_t nbytes, void *userdata) { static int import_fs(int argc, char *argv[], void *userdata) { _cleanup_(rm_rf_subvolume_and_freep) char *temp_path = NULL; - _cleanup_(progress_info_free) ProgressInfo progress = {}; + _cleanup_(progress_info_free) ProgressInfo progress = { .bps = UINT64_MAX }; _cleanup_free_ char *l = NULL, *final_path = NULL; const char *path = NULL, *local = NULL, *dest = NULL; _cleanup_close_ int open_fd = -EBADF; diff --git a/src/repart/repart.c b/src/repart/repart.c index 0dae3f8610a..49f7d0745c2 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -5377,7 +5377,7 @@ static int partition_format_verity_sig(Context *context, Partition *p) { return 0; } -static int progress_bytes(uint64_t n_bytes, void *userdata) { +static int progress_bytes(uint64_t n_bytes, uint64_t bps, void *userdata) { Partition *p = ASSERT_PTR(userdata); unsigned percent; @@ -5395,14 +5395,25 @@ static int progress_bytes(uint64_t n_bytes, void *userdata) { if (!ratelimit_below(&p->progress_ratelimit)) return 0; - (void) draw_progress_barf( - percent, - "%s %s %s %s/%s", - strna(p->copy_blocks_path), - glyph(GLYPH_ARROW_RIGHT), - strna(p->definition_path), - FORMAT_BYTES(p->copy_blocks_done), - FORMAT_BYTES(p->copy_blocks_size)); + if (bps != UINT64_MAX) + (void) draw_progress_barf( + percent, + "%s %s %s %s/%s %s/s", + strna(p->copy_blocks_path), + glyph(GLYPH_ARROW_RIGHT), + strna(p->definition_path), + FORMAT_BYTES(p->copy_blocks_done), + FORMAT_BYTES(p->copy_blocks_size), + FORMAT_BYTES(bps)); + else + (void) draw_progress_barf( + percent, + "%s %s %s %s/%s", + strna(p->copy_blocks_path), + glyph(GLYPH_ARROW_RIGHT), + strna(p->definition_path), + FORMAT_BYTES(p->copy_blocks_done), + FORMAT_BYTES(p->copy_blocks_size)); p->last_percent = percent; diff --git a/src/shared/copy.c b/src/shared/copy.c index 6f415fe2078..981427214ba 100644 --- a/src/shared/copy.c +++ b/src/shared/copy.c @@ -26,12 +26,13 @@ #include "path-util.h" #include "rm-rf.h" #include "selinux-util.h" +#include "set.h" #include "signal-util.h" #include "stat-util.h" -#include "set.h" #include "stdio-util.h" #include "string-util.h" #include "sync-util.h" +#include "time-util.h" #include "tmpfile-util.h" #include "umask-util.h" #include "user-util.h" @@ -263,6 +264,10 @@ int copy_bytes_full( } } + usec_t start_timestamp = USEC_INFINITY; + if (progress) + start_timestamp = now(CLOCK_MONOTONIC); + for (;;) { ssize_t n; size_t m; @@ -511,7 +516,13 @@ int copy_bytes_full( try_sendfile = false; if (progress) { - r = progress(n, userdata); + usec_t t = now(CLOCK_MONOTONIC); + usec_t d = usec_sub_unsigned(t, start_timestamp); + uint64_t bps = UINT64_MAX; + if (d > USEC_PER_SEC * 3U) + bps = (uint64_t) (copied_total / ((double) d / USEC_PER_SEC)); + + r = progress(n, bps, userdata); if (r < 0) return r; } diff --git a/src/shared/copy.h b/src/shared/copy.h index 1d17f9b01fa..a818510e1c3 100644 --- a/src/shared/copy.h +++ b/src/shared/copy.h @@ -43,7 +43,7 @@ typedef enum DenyType { _DENY_TYPE_INVALID = -EINVAL, } DenyType; -typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata); +typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, uint64_t bytes_per_second, void *userdata); typedef int (*copy_progress_path_t)(const char *path, const struct stat *st, void *userdata); int copy_file_fd_at_full(int dir_fdf, const char *from, int to, CopyFlags copy_flags, copy_progress_bytes_t progress, void *userdata);