]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
copy: calculate bytes per second while copying, and pass to progress info
authorLennart Poettering <lennart@poettering.net>
Tue, 9 Sep 2025 15:05:05 +0000 (17:05 +0200)
committerLuca Boccassi <luca.boccassi@gmail.com>
Wed, 17 Sep 2025 18:48:08 +0000 (19:48 +0100)
Also, show it in import-fs/repart.

src/basic/forward.h
src/import/import-fs.c
src/repart/repart.c
src/shared/copy.c
src/shared/copy.h

index 53b217b07b5b550c226383037dae13ee37bfd965..66da2b13a57c5bcd7559f92b1ab9935488148a73 100644 (file)
@@ -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;
index a132ab64f06f17b5a5a6edb52b29a6960c71a775..783b0461ef45a0d56ee4af424bae35108e201ef5 100644 (file)
@@ -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;
index 0dae3f8610af9d2ce495466cfc336b99956692d5..49f7d0745c222ad865d85f3aeaea945c8371ce8d 100644 (file)
@@ -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;
 
index 6f415fe2078f27345b53fc7abd51dab83dc99167..981427214ba43d217ac09fcf31f1b90955f08789 100644 (file)
 #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;
                 }
index 1d17f9b01fa2cf437afe0e20a8eeaa9a6c19d6ff..a818510e1c359581c0cb80cd6ca4cf221cf950e4 100644 (file)
@@ -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);