-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathinode.h
More file actions
114 lines (96 loc) · 3 KB
/
inode.h
File metadata and controls
114 lines (96 loc) · 3 KB
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
#pragma once
// clang-format off
#include "vmlinux.h"
#include "kdev.h"
#include "types.h"
#include "maps.h"
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_helpers.h>
// clang-format on
#define BTRFS_SUPER_MAGIC 0x9123683E
/**
* Retrieve the inode and device numbers and return them as a new key.
*
* Different filesystems may `stat` files in different ways, if support
* for a new filesystem is needed, add it here.
*
* Most Linux filesystems use the following generic function to fill
* these fields when running `stat`:
* https://github.com/torvalds/linux/blob/7d0a66e4bb9081d75c82ec4957c50034cb0ea449/fs/stat.c#L82
*
* The method used to retrieve the device is different in btrfs and can
* be found here:
* https://github.com/torvalds/linux/blob/7d0a66e4bb9081d75c82ec4957c50034cb0ea449/fs/btrfs/inode.c#L8038
*/
__always_inline static inode_key_t inode_to_key(struct inode* inode) {
inode_key_t key = {0};
if (inode == NULL) {
return key;
}
unsigned long magic = BPF_CORE_READ(inode, i_sb, s_magic);
switch (magic) {
case BTRFS_SUPER_MAGIC:
if (bpf_core_type_exists(struct btrfs_inode)) {
struct btrfs_inode* btrfs_inode = container_of(inode, struct btrfs_inode, vfs_inode);
key.inode = BPF_CORE_READ(inode, i_ino);
key.dev = BPF_CORE_READ(btrfs_inode, root, anon_dev);
break;
}
// If the btrfs_inode does not exist, most likely it is not
// supported on the system. Fallback to the generic implementation
// just in case.
default:
key.inode = BPF_CORE_READ(inode, i_ino);
key.dev = BPF_CORE_READ(inode, i_sb, s_dev);
break;
}
// Encode the device so it matches with the result of `stat` in
// userspace
key.dev = new_encode_dev(key.dev);
return key;
}
__always_inline static inode_value_t* inode_get(const struct inode_key_t* inode) {
if (inode == NULL) {
return NULL;
}
return bpf_map_lookup_elem(&inode_map, inode);
}
__always_inline static long inode_add(struct inode_key_t* inode) {
if (inode == NULL) {
return -1;
}
inode_value_t value = 0;
return bpf_map_update_elem(&inode_map, inode, &value, BPF_ANY);
}
__always_inline static long inode_remove(struct inode_key_t* inode) {
if (inode == NULL) {
return 0;
}
return bpf_map_delete_elem(&inode_map, inode);
}
__always_inline static void inode_reset(struct inode_key_t* inode) {
inode->inode = 0;
inode->dev = 0;
}
typedef enum inode_monitored_t {
NOT_MONITORED = 0,
MONITORED,
PARENT_MONITORED,
} inode_monitored_t;
// Check if the provided inode or its parent is being monitored.
__always_inline static inode_monitored_t inode_is_monitored(const inode_value_t* volatile inode, const inode_value_t* volatile parent_inode) {
if (inode != NULL) {
return MONITORED;
}
if (parent_inode != NULL) {
return PARENT_MONITORED;
}
return NOT_MONITORED;
}
__always_inline static void inode_copy(inode_key_t* dst, const inode_key_t* src) {
if (dst == NULL) {
return;
}
dst->inode = src->inode;
dst->dev = src->dev;
}