Restore btrfs qgroups size & unshared size columns

Restored calculation and display, which was deleted in commit 8d77b18f.

However, the behavior has been changed slightly:

* We try to determine the sizes using `btrfs qgroup show`
* This is only successful on systems with enabled qgroups
* If so, we enable the columns
* Otherwise, we hide them

I did not restore the methods for enabling quota.
But I restored destroying qgroups on snapshot removal.

This also fixes a bug, I encountered on a system with enabled qgroups:

Since the removal of the now restored behavior, I encountered lots of 0.00B qgroups,
because they seem to have been created all along, but they have no longer been removed:

```
$ sudo btrfs qgroup show .
qgroupid         rfer         excl
--------         ----         ----
0/5          92.00KiB     92.00KiB
0/262         4.00GiB      4.00GiB
0/798       135.20GiB    334.31MiB
0/799        14.07GiB    254.51MiB
0/1657          0.00B        0.00B
0/1658          0.00B        0.00B
0/1665          0.00B        0.00B
0/1666          0.00B        0.00B
0/1691          0.00B        0.00B
0/1692          0.00B        0.00B
0/1721          0.00B        0.00B
0/1722          0.00B        0.00B
0/1723          0.00B        0.00B
0/1724          0.00B        0.00B
0/1727          0.00B        0.00B
…
```
This commit is contained in:
Thomas Praxl 2022-11-10 13:31:08 +01:00 committed by Michael Webster
parent af6fda5560
commit 54cb3a3784
3 changed files with 183 additions and 0 deletions

View File

@ -50,6 +50,7 @@ public class Main : GLib.Object{
public string backup_parent_uuid = "";
public bool btrfs_mode = true;
public bool btrfs_qgroups_enabled = false;
public bool include_btrfs_home_for_backup = false;
public bool include_btrfs_home_for_restore = false;
@ -3980,6 +3981,9 @@ public class Main : GLib.Object{
return;
}
//query quota
btrfs_qgroups_enabled = query_subvolume_quotas();
thread_subvol_info_success = true;
thread_subvol_info_running = false;
return;
@ -4054,6 +4058,114 @@ public class Main : GLib.Object{
return true;
}
public bool query_subvolume_quotas(){
bool ok = query_subvolume_quota("@");
if (repo.device.uuid != repo.device_home.uuid){
ok = ok && query_subvolume_quota("@home");
}
return ok;
}
public bool query_subvolume_quota(string subvol_name){
log_debug("query_subvolume_quota():%s".printf(subvol_name));
string cmd = "";
string std_out;
string std_err;
int ret_val;
string options = use_option_raw ? "--raw" : "";
cmd = "btrfs qgroup show %s '%s'".printf(options, repo.mount_paths[subvol_name]);
log_debug(cmd);
ret_val = exec_sync(cmd, out std_out, out std_err);
if (ret_val != 0){
if (use_option_raw){
use_option_raw = false;
// try again without --raw option
cmd = "btrfs qgroup show '%s'".printf(repo.mount_paths[subvol_name]);
log_debug(cmd);
ret_val = exec_sync(cmd, out std_out, out std_err);
}
if (ret_val != 0){
log_error (std_err);
log_error(_("btrfs returned an error") + ": %d".printf(ret_val));
log_error(_("Failed to query subvolume quota"));
return false;
}
}
/* Sample Output:
*
qgroupid rfer excl
-------- ---- ----
0/5 106496 106496
0/257 3825262592 557056
0/258 12689408 49152
* */
foreach(string line in std_out.split("\n")){
if (line == null) { continue; }
string[] parts = line.split(" ");
if (parts.length < 3) { continue; }
if (parts[0].split("/").length < 2) { continue; }
int subvol_id = int.parse(parts[0].split("/")[1]);
Subvolume subvol = null;
if ((sys_subvolumes.size > 0) && (sys_subvolumes["@"].id == subvol_id)){
subvol = sys_subvolumes["@"];
}
else if ((sys_subvolumes.size > 0)
&& sys_subvolumes.has_key("@home")
&& (sys_subvolumes["@home"].id == subvol_id)){
subvol = sys_subvolumes["@home"];
}
else {
foreach(var bak in repo.snapshots){
foreach(var sub in bak.subvolumes.values){
if (sub.id == subvol_id){
subvol = sub;
}
}
}
}
if (subvol != null){
int part_num = -1;
foreach(string part in parts){
if (part.strip().length > 0){
part_num ++;
switch (part_num){
case 1:
subvol.total_bytes = int64.parse(part);
break;
case 2:
subvol.unshared_bytes = int64.parse(part);
break;
default:
//ignore
break;
}
}
}
}
}
foreach(var bak in repo.snapshots){
bak.update_control_file();
}
return true;
}
// cron jobs
public void cron_job_update(){

View File

@ -166,6 +166,22 @@ public class Subvolume : GLib.Object{
log_msg("%s: %s (Id:%ld)\n".printf(_("Deleted subvolume"), name, id));
if (App.btrfs_qgroups_enabled) {
if ((id > 0) && (repo != null)){
log_msg("%s: 0/%ld".printf(_("Destroying qgroup"), id));
cmd = "btrfs qgroup destroy 0/%ld '%s'".printf(id, repo.mount_paths[name]);
log_debug(cmd);
ret_val = exec_sync(cmd, out std_out, out std_err);
if (ret_val != 0){
log_error(_("Failed to destroy qgroup") + ": '0/%ld'".printf(id));
return false;
}
log_msg("%s: 0/%ld\n".printf(_("Destroyed qgroup"), id));
}
}
return true;
}

View File

@ -37,6 +37,8 @@ class SnapshotListBox : Gtk.Box{
public Gtk.TreeView treeview;
private Gtk.TreeViewColumn col_date;
private Gtk.TreeViewColumn col_tags;
private Gtk.TreeViewColumn col_size;
private Gtk.TreeViewColumn col_unshared;
private Gtk.TreeViewColumn col_system;
private Gtk.TreeViewColumn col_desc;
private int treeview_sort_column_index = 0;
@ -167,6 +169,56 @@ class SnapshotListBox : Gtk.Box{
refresh();
});
//col_size
var col = new TreeViewColumn();
col.title = _("Size");
col.resizable = true;
col.min_width = 80;
col.clickable = true;
var cell_size = new CellRendererText ();
cell_size.ellipsize = Pango.EllipsizeMode.END;
cell_size.xalign = (float) 1.0;
col.pack_start (cell_size, false);
col.set_cell_data_func (cell_size, cell_size_render);
col_size = col;
treeview.append_column(col_size);
col_size.clicked.connect(() => {
if(treeview_sort_column_index == 2){
treeview_sort_column_desc = !treeview_sort_column_desc;
}
else{
treeview_sort_column_index = 2;
treeview_sort_column_desc = false;
}
refresh();
});
//col_unshared
col = new TreeViewColumn();
col.title = _("Unshared");
col.resizable = true;
col.min_width = 80;
col.clickable = true;
var cell_unshared = new CellRendererText ();
cell_unshared.ellipsize = Pango.EllipsizeMode.END;
cell_unshared.xalign = (float) 1.0;
col.pack_start (cell_unshared, false);
col.set_cell_data_func (cell_unshared, cell_unshared_render);
col_unshared = col;
treeview.append_column(col_unshared);
col_unshared.clicked.connect(() => {
if(treeview_sort_column_index == 2){
treeview_sort_column_desc = !treeview_sort_column_desc;
}
else{
treeview_sort_column_index = 2;
treeview_sort_column_desc = false;
}
refresh();
});
//cell_desc
col_desc = new TreeViewColumn();
col_desc.title = _("Comments (click to edit)");
@ -568,6 +620,9 @@ class SnapshotListBox : Gtk.Box{
model.set (iter, 0, bak);
}
col_size.visible = App.btrfs_qgroups_enabled;
col_unshared.visible = App.btrfs_qgroups_enabled;
treeview.set_model (model);
treeview.columns_autosize ();
}