mirror of
https://github.com/linuxmint/timeshift.git
synced 2024-08-16 20:10:39 +03:00
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:
parent
af6fda5560
commit
54cb3a3784
@ -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(){
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 ();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user