summaryrefslogtreecommitdiff
blob: 8e21581237bcab42986232a743ed8bbbf7efee79 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
Patch from:
https://github.com/knorrie/python-btrfs/commit/7d8dca5bf1211843d8fd5c02b118afddaa53bee8

From 7d8dca5bf1211843d8fd5c02b118afddaa53bee8 Mon Sep 17 00:00:00 2001
From: Hans van Kranenburg <hans@knorrie.org>
Date: Sun, 21 May 2023 17:46:06 +0200
Subject: [PATCH] WIP ctree,ioctl,utils: Add Block Group Tree

When the block_group_tree feature is enabled on a filesystem, we have to
look up Block Group metadata items in the new Block Group Tree, instead
of the Extent Tree, where they always were located before.

WIP: We don't want to call the get_features ioctl *every* time we look
up 1 block group object, but we also cannot just cache the result of it,
since some feature flags can change while the fs is mounted.

So, this needs some extra work in the features department first to make
this more nice.
--- a/btrfs/ctree.py
+++ b/btrfs/ctree.py
@@ -91,6 +91,7 @@ def _struct_format(s):
 QUOTA_TREE_OBJECTID = 8  #: Quota tree
 UUID_TREE_OBJECTID = 9  #: Subvolume UUID tree
 FREE_SPACE_TREE_OBJECTID = 10  #: Free space tree
+BLOCK_GROUP_TREE_OBJECTID = 11  #: Block group tree
 
 DEV_STATS_OBJECTID = 0  #: Object ID of device statistics in the Device tree.
 BALANCE_OBJECTID = ULL(-4)  #: Object ID to store balance status. (-4)
@@ -346,6 +347,7 @@ def _qgroup_objectid(level, subvid):
     QUOTA_TREE_OBJECTID: 'QUOTA_TREE',
     UUID_TREE_OBJECTID: 'UUID_TREE',
     FREE_SPACE_TREE_OBJECTID: 'FREE_SPACE_TREE',
+    BLOCK_GROUP_TREE_OBJECTID: 'BLOCK_GROUP_TREE',
     BALANCE_OBJECTID: 'BALANCE',
     ORPHAN_OBJECTID: 'ORPHAN',
     TREE_LOG_OBJECTID: 'TREE_LOG',
@@ -765,6 +767,11 @@ def __init__(self, path):
         self.fsid = _fs_info.fsid
         self.nodesize = _fs_info.nodesize
         self.sectorsize = _fs_info.sectorsize
+        # TEMP cached feature flag for block_group_tree TEMP
+        _features = self.features()
+        self._block_group_tree = self.features().compat_ro_flags & \
+                btrfs.ioctl.FEATURE_COMPAT_RO_BLOCK_GROUP_TREE != 0
+        # TEMP cached feature flag for block_group_tree TEMP
 
     def __enter__(self):
         return self
@@ -870,7 +877,10 @@ def block_group(self, vaddr, length=None):
         :raises: :class:`ItemNotFoundError` if no Block Group Item can be found
             at the address.
         """
-        tree = EXTENT_TREE_OBJECTID
+        if not self._block_group_tree:
+            tree = EXTENT_TREE_OBJECTID
+        else:
+            tree = BLOCK_GROUP_TREE_OBJECTID
         min_offset = length if length is not None else 0
         max_offset = length if length is not None else ULLONG_MAX
         min_key = Key(vaddr, BLOCK_GROUP_ITEM_KEY, min_offset)
@@ -1240,11 +1250,14 @@ class BlockGroupItem(ItemData):
     The `Block Group` has a 1 to 1 relationship with a `Chunk` and tracks some
     usage information about a range of virtual address space.
 
-    * Tree: `EXTENT_TREE_OBJECTID` (2)
+    * Tree: `EXTENT_TREE_OBJECTID` (2) or `BLOCK_GROUP_TREE_OBJECTID` (11)
     * Key objectid: Virtual address.
     * Key type: `BLOCK_GROUP_ITEM_KEY` (192)
     * Key offset: Block Group length.
 
+    If the block_group_tree feature is enabled on the filesystem, these items
+    can be found inside the Block Group Tree instead of the Extent Tree.
+
     :ivar int vaddr: Virtual address where the Bock Group starts (taken from
         the objectid field of the item key).
     :ivar int length: Block Group length in bytes (taken from the offset field
--- a/btrfs/ioctl.py
+++ b/btrfs/ioctl.py
@@ -1325,10 +1325,12 @@ def _compat_flags_str(flags):
 
 FEATURE_COMPAT_RO_FREE_SPACE_TREE = 1 << 0
 FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID = 1 << 1
+FEATURE_COMPAT_RO_BLOCK_GROUP_TREE = 1 << 3
 
 _feature_compat_ro_str_map = {
     FEATURE_COMPAT_RO_FREE_SPACE_TREE: 'free_space_tree',
     FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID: 'free_space_tree_valid',
+    FEATURE_COMPAT_RO_BLOCK_GROUP_TREE : 'block_group_tree',
 }
 
 
@@ -1383,6 +1385,7 @@ class FeatureFlags(object):
 
     - FEATURE_COMPAT_RO_FREE_SPACE_TREE
     - FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID
+    - FEATURE_COMPAT_RO_BLOCK_GROUP_TREE
 
     Known incompat_flags (available as attribute of this module) are:
 
--- a/btrfs/utils.py
+++ b/btrfs/utils.py
@@ -436,6 +436,7 @@ def embedded_text_for_str(text):
     'quota': btrfs.ctree.QUOTA_TREE_OBJECTID,
     'uuid': btrfs.ctree.UUID_TREE_OBJECTID,
     'free_space': btrfs.ctree.FREE_SPACE_TREE_OBJECTID,
+    'block_group': btrfs.ctree.BLOCK_GROUP_TREE_OBJECTID,
     'tree_log': btrfs.ctree.TREE_LOG_OBJECTID,
     'tree_log_fixup': btrfs.ctree.TREE_LOG_FIXUP_OBJECTID,
     'tree_reloc': btrfs.ctree.TREE_RELOC_OBJECTID,