// SPDX-License-Identifier: GPL-3.0-or-later // Copyright (C) 2016 Andrea Mazzoleni #include "os/portable.h" #include "bw.h" void bw_init(struct snapraid_bw* bw, uint64_t limit) { bw->limit = limit; bw->total = 0; bw->start = os_tick_ms(); #if HAVE_THREAD thread_mutex_init(&bw->lock); #endif } void bw_done(struct snapraid_bw* bw) { #if HAVE_THREAD thread_mutex_destroy(&bw->lock); #else (void)bw; #endif } void bw_limit(struct snapraid_bw* bw, uint64_t bytes) { if (!bw || bw->limit == 0) return; #if HAVE_THREAD thread_mutex_lock(&bw->lock); #endif uint64_t start = bw->start; uint64_t now = os_tick_ms(); uint64_t elapsed = now - start; uint64_t done; uint64_t eta; bw->total += bytes; done = bw->total; eta = done * 1000 / bw->limit; /* * To prevent accumulating unlimited credit during long pauses * (such as CPU-bound hashing or metadata scanning), we cap the * maximum accumulated credit to 10 seconds. * If the elapsed time is more than 10 seconds ahead of the target ETA, * we advance the start time to align the credit to exactly 10 seconds. */ if (elapsed > eta + 10000) { bw->start = now - eta - 10000; elapsed = eta + 10000; } #if HAVE_THREAD thread_mutex_unlock(&bw->lock); #endif if (eta > elapsed) { eta -= elapsed; if (eta > 1000) eta = 1000; usleep((unsigned)eta * 1000); } }