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
111
112
113
114
115
116
117
|
The ["inode lookup"
ioctl](https://btrfs.readthedocs.io/en/latest/btrfs-ioctl.html#btrfs-ioc-ino-lookup)
allows you to request certain information for a given inode. This ioctl is a bit
special because it has two modes of operation.
First, you can provide both an inode and a tree ID. Doing this will allow
callers to retrieve the name that identifies the given inode on the tree
ID. Doing this requires `CAP_SYS_ADMIN` privileges. If you don't know which tree
ID to pick, you can also pick `0`, which selects the current subvolume you are
currently working with.
I have written a small example in the form of `ino_lookup.c`, which performs a
call to this ioctl. I do this with a mount point with four subvolumes like so:
```
# btrfs subvolume list mnt/
ID 256 gen 138 top level 5 path a
ID 257 gen 138 top level 5 path b
ID 258 gen 138 top level 5 path c
ID 259 gen 138 top level 5 path d
# tree --inodes --device mnt/
[ 256 55] mnt/
├── [ 256 46] a
│ ├── [ 257 46] a.txt
│ └── [ 258 46] b.txt
├── [ 257 55] a.txt
├── [ 256 47] b
│ └── [ 257 47] b.txt
├── [ 256 56] c
│ └── [ 257 56] c.txt
└── [ 256 57] d
└── [ 257 57] d.txt
```
The first argument to pass to this small program is the tree ID, and the second
is the inode. With this into account, I have written a small shell script that
runs this program with different arguments like so (output with `set -x`):
```
# ./lookup_test.sh
+ ./ino_lookup mnt 256 258
tree ID: 256
inode: 258
path: b.txt/
+ ./ino_lookup mnt 0 257
tree ID: 5
inode: 257
path: a.txt/
+ ./ino_lookup mnt 256 257
tree ID: 256
inode: 257
path: a.txt/
+ ./ino_lookup mnt 257 257
tree ID: 257
inode: 257
path: b.txt/
+ ./ino_lookup mnt/a 0 257
tree ID: 256
inode: 257
path: a.txt/
+ ./ino_lookup mnt/a 256 257
tree ID: 256
inode: 257
path: a.txt/
+ ./ino_lookup mnt/a 257 257
tree ID: 257
inode: 257
path: b.txt/
```
But, as I briefly mentioned earlier, this ioctl also has another mode of
operation. This mode of operation does not require `CAP_SYS_ADMIN` and you can
call it by setting the tree ID to 0, and passing the special
`BTRFS_FIRST_FREE_OBJECTID` constant as a value for the inode. With all of this
you will be able to fetch the tree ID for the targetted mount point. Hence:
```
$ ./ino_lookup mnt/ 0 --tree-id
tree ID: 5
inode: 256
path:
$ ./ino_lookup mnt/a 0 --tree-id
tree ID: 256
inode: 256
path:
$ ./ino_lookup mnt/b 0 --tree-id
tree ID: 257
inode: 256
path:
$ ./ino_lookup mnt/c 0 --tree-id
tree ID: 258
inode: 256
path:
$ ./ino_lookup mnt/d 0 --tree-id
tree ID: 259
inode: 256
path:
```
You will also notice that:
1. The inode is always set to `256`. This ioctl doesn't change the value, it
just happens to be the value of the `BTRFS_FIRST_FREE_OBJECTID` constant we
set for this mode of operation.
2. The path will be blank out on purpose.
## Patches sent to the Linux kernel as a result
I arrived to this ioctl pretty much out of nowhere as I was cruising through
another patch set I was working on. After looking into it later, I saw that a
bit of cleanup could be done on the kernel side. Then I worked on the patch and
pretty much forgot about it when I went into paternity leave :)
Once I got back and saw the patch as something to be sent, I rebased the patch
and submitted it. Read the discussion in
[lore.kernel.org](https://lore.kernel.org/all/20260629142056.309300-1-mssola@mssola.com/).
|