-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathinode.h
More file actions
108 lines (93 loc) · 2.84 KB
/
inode.h
File metadata and controls
108 lines (93 loc) · 2.84 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
#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 = 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 = 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 = inode->i_ino;
key.dev = 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(struct inode_key_t* inode) {
if (inode == NULL) {
return NULL;
}
return bpf_map_lookup_elem(&inode_map, inode);
}
__always_inline static long inode_remove(struct inode_key_t* inode) {
if (inode == NULL) {
return 0;
}
return bpf_map_delete_elem(&inode_map, inode);
}
typedef enum inode_monitored_t {
NOT_MONITORED = 0,
MONITORED,
} inode_monitored_t;
/**
* Check if the provided inode is being monitored.
*
* The current implementation is very basic and might seem like
* overkill, but in the near future this function will be extended to
* check if the parent of the provided inode is monitored and provide
* different results for handling more complicated scenarios.
*/
__always_inline static inode_monitored_t inode_is_monitored(const inode_value_t* inode) {
if (inode != NULL) {
return MONITORED;
}
return NOT_MONITORED;
}
__always_inline static void inode_copy_or_reset(inode_key_t* dst, const inode_key_t* src) {
if (dst == NULL) {
return;
}
if (src != NULL) {
dst->inode = src->inode;
dst->dev = src->dev;
} else {
dst->inode = 0;
dst->dev = 0;
}
}