I’ve been using the writedisk crate (crates.io) for a while now to write disk images to USB drives. The interface is much nicer than using dd
manually and it presents a list of USB devices and their human readable names to select from.
One thing that irked me was that there was a progress bar for copying the files but not for the filesystem sync afterwards so I decided to implement it myself.
Unfortunately it seemed to be a bit more complicated than I originally anticipated. There didn’t seem to be a good way to get the progress of a sync
command (stackexchange.com) outside of monitoring dirty pages. Additionally there didn’t seem to be a good way to get the dirty pages of just a single disk meaning we’ll need to rely on the OS dirty pages to get the job done.
I chose to use the procfs crate (crates.io) to read /proc/meminfo
which exposes it simply via:
let myprocfs = procfs::Meminfo::new();
myprocfs.dirty
Since we can’t get the exact amount of dirty pages left for the UBB sync I decided we could flub it a bit by monitoring the dirty bits as they approached zero:
// Get dirty pages after copy
let meminfo = procfs::Meminfo::new().unwrap();
let dirty_after_copy = meminfo.dirty - dirty_before_copy;
thread::spawn(move || loop {
let meminfo = procfs::Meminfo::new().unwrap();
let percent = 100 - (meminfo.dirty) / (dirty_after_copy / 100));
/* Update progress bar */
});
dst.sync_data().unwrap(); // sync data and block until done
One problem with this solution is that on a busy system there may already be dirty pages before the copy so your progress bar would never be exactly correct making as it approaches zero a mediocre metric to use.
Therefore I decided that instead of using zero I would use the dirty bits before copy as my progress bar’s “goal”:
// Get dirty pages before copy
let meminfo = procfs::Meminfo::new().unwrap();
let dirty_before_copy = meminfo.dirty;
/* Code that copies image to USB here */
// Get dirty pages after copy
let meminfo = procfs::Meminfo::new().unwrap();
let dirty_after_copy = meminfo.dirty - dirty_before_copy;
thread::spawn(move || loop {
let meminfo = procfs::Meminfo::new().unwrap();
let percent = 100 - ((meminfo.dirty.saturating_sub(dirty_before_copy)) / (dirty_after_copy / 100));
/* Update progress bar */
});
dst.sync_data().unwrap(); // sync data and block until done
And there we go - now we have a progress bar for disk syncing.
The code still needed a bit of cleaning up and organization as a lot of it was written inline in main()
, but the progress bar works!
If you’re interested in seeing the code or the feedback I got on it you can view my PR here: https://github.com/nicholasbishop/writedisk/pull/5