aboutsummaryrefslogtreecommitdiff
path: root/fs/btrfs/ino_lookup/README.md
blob: b4cfb15a4108ebd352e70bfd8f1162b232582027 (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
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/).