Skip to content

Commit 00ce451

Browse files
authored
Check if qgroup exists before attempting to destroy it (#484)
When a btrfs subvolume is deleted, its associated qgroup is often automatically destroyed by btrfs. Timeshift would then attempt to explicitly destroy the qgroup and fail with an error message, even though the operation was successful. This change checks if the qgroup still exists before attempting to destroy it, eliminating the spurious error message. If the qgroup is already gone (auto-destroyed with the subvolume), we log a debug message instead. If the qgroup still exists, we attempt to destroy it and handle any race condition gracefully. Fixes the "Failed to destroy qgroup" error that occurs during snapshot deletion when quotas are enabled. Related: #354, #437
1 parent 61aaa19 commit 00ce451

1 file changed

Lines changed: 20 additions & 9 deletions

File tree

src/Core/Subvolume.vala

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -193,20 +193,31 @@ public class Subvolume : GLib.Object{
193193
sleep(1000);
194194
}
195195

196-
log_msg("%s: 0/%ld".printf(_("Destroying qgroup"), id));
197-
198-
cmd = "btrfs qgroup destroy 0/%ld '%s'".printf(id, repo.mount_paths[name]);
196+
// Check if qgroup still exists before trying to destroy it.
197+
// The qgroup may have been auto-destroyed when the subvolume was deleted.
198+
string qgroup_id = "0/%ld".printf(id);
199+
cmd = "btrfs qgroup show -f '%s'".printf(repo.mount_paths[name]);
199200
log_debug(cmd);
200201
ret_val = exec_sync(cmd, out std_out, out std_err);
201-
if (ret_val != 0){
202-
log_error(_("Failed to destroy qgroup") + ": '0/%ld'".printf(id));
203202

204-
// the subvolume is gone now. So this can be called a success.
205-
return true;
203+
bool qgroup_exists = (ret_val == 0) && (std_out.contains(qgroup_id));
204+
205+
if (!qgroup_exists) {
206+
log_debug("Qgroup %s already removed (auto-destroyed with subvolume)".printf(qgroup_id));
207+
} else {
208+
log_msg("%s: %s".printf(_("Destroying qgroup"), qgroup_id));
209+
210+
cmd = "btrfs qgroup destroy %s '%s'".printf(qgroup_id, repo.mount_paths[name]);
211+
log_debug(cmd);
212+
ret_val = exec_sync(cmd, out std_out, out std_err);
213+
if (ret_val != 0){
214+
// Qgroup may have been destroyed between our check and destroy attempt
215+
log_debug("Qgroup %s could not be destroyed (likely already removed): %s".printf(qgroup_id, std_err));
216+
} else {
217+
log_msg("%s: %s\n".printf(_("Destroyed qgroup"), qgroup_id));
218+
}
206219
}
207220

208-
log_msg("%s: 0/%ld\n".printf(_("Destroyed qgroup"), id));
209-
210221
log_debug("Rescanning quotas (post)...");
211222
while (exec_sync("btrfs quota rescan %s".printf(mount_path), out std_out, out std_err) != 0) {
212223
log_debug("Still rescanning quotas (post)... %s".printf(std_err));

0 commit comments

Comments
 (0)