-
Notifications
You must be signed in to change notification settings - Fork 185
Expand file tree
/
Copy pathfdtable.cpp
More file actions
185 lines (154 loc) · 5.29 KB
/
fdtable.cpp
File metadata and controls
185 lines (154 loc) · 5.29 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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2025 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _WIN32
#include <algorithm>
#endif
#include <cinttypes>
#include <libsinsp/fdtable.h>
#include <libsinsp/sinsp_int.h>
#include <libscap/scap-int.h>
static const auto s_fdtable_static_fields = sinsp_fdinfo::get_static_fields();
sinsp_fdtable::sinsp_fdtable(const std::shared_ptr<ctor_params>& params):
extensible_table{type_tag<sinsp_fdinfo>{}, "file_descriptors", &s_fdtable_static_fields},
m_params{params},
m_tid{0} {
reset_cache();
}
inline const std::shared_ptr<sinsp_fdinfo>& sinsp_fdtable::find_ref(int64_t fd) {
//
// Try looking up in our simple cache
//
if(m_last_accessed_fd != -1 && fd == m_last_accessed_fd) {
if(m_params->m_sinsp_stats_v2) {
m_params->m_sinsp_stats_v2->m_n_cached_fd_lookups++;
}
return m_last_accessed_fdinfo;
}
//
// Caching failed, do a real lookup
//
auto fdit = m_table.find(fd);
if(fdit == m_table.end()) {
if(m_params->m_sinsp_stats_v2) {
m_params->m_sinsp_stats_v2->m_n_failed_fd_lookups++;
}
return m_nullptr_ret;
} else {
if(m_params->m_sinsp_stats_v2 != nullptr) {
m_params->m_sinsp_stats_v2->m_n_noncached_fd_lookups++;
}
m_last_accessed_fd = fd;
m_last_accessed_fdinfo = fdit->second;
lookup_device(*m_last_accessed_fdinfo);
return m_last_accessed_fdinfo;
}
}
inline const std::shared_ptr<sinsp_fdinfo>& sinsp_fdtable::add_ref(
int64_t fd,
std::shared_ptr<sinsp_fdinfo>&& fdinfo) {
fdinfo->m_fd = fd;
const auto it = m_table.find(fd);
// Three possible exits here:
// 1. fd is not on the table
// a. the table size is under the limit so create a new entry
// b. table size is over the limit, discard the fd
// 2. fd is already in the table, replace it
if(it == m_table.end()) {
if(m_table.size() == m_params->m_max_table_size) {
return m_nullptr_ret;
}
// No entry in the table, this is the normal case.
m_last_accessed_fd = -1;
if(m_params->m_sinsp_stats_v2 != nullptr) {
m_params->m_sinsp_stats_v2->m_n_added_fds++;
}
return m_table.emplace(fd, std::move(fdinfo)).first->second;
}
// the fd is already in the table. This can happen if:
// - the event is a dup2 or dup3 that overwrites an existing FD (perfectly legal)
// - a close() has been dropped when capturing
// - an fd has been closed by clone() or execve() (it happens when the fd is opened
// with the FD_CLOEXEC flag,
// which we don't currently parse.
// In either case, removing the old fd, replacing it with the new one and keeping going
// is a reasonable choice. We include an assertion to catch the situation.
//
// XXX Can't have this enabled until the FD_CLOEXEC flag is supported
// ASSERT(false);
// Replace the fd as a struct copy.
m_last_accessed_fd = -1;
it->second = std::move(fdinfo);
return it->second;
}
bool sinsp_fdtable::erase(int64_t fd) {
auto fdit = m_table.find(fd);
if(fd == m_last_accessed_fd) {
m_last_accessed_fd = -1;
}
if(fdit == m_table.end()) {
//
// Looks like there's no fd to remove.
// Either the fd creation event was dropped or (more likely) our logic doesn't support the
// call that created this fd. The assertion will detect it, while in release mode we just
// keep going.
//
if(m_params->m_sinsp_stats_v2 != nullptr) {
m_params->m_sinsp_stats_v2->m_n_failed_fd_lookups++;
}
return false;
} else {
m_table.erase(fdit);
if(m_params->m_sinsp_stats_v2 != nullptr) {
m_params->m_sinsp_stats_v2->m_n_noncached_fd_lookups++;
m_params->m_sinsp_stats_v2->m_n_removed_fds++;
}
return true;
}
}
void sinsp_fdtable::clear() {
m_table.clear();
}
size_t sinsp_fdtable::size() const {
return m_table.size();
}
void sinsp_fdtable::reset_cache() {
m_last_accessed_fd = -1;
}
void sinsp_fdtable::lookup_device(sinsp_fdinfo& fdi) const {
#ifndef _WIN32
if(m_params->m_sinsp_mode.is_offline() ||
(m_params->m_sinsp_mode.is_plugin() && !is_syscall_plugin_enabled())) {
return;
}
if(m_tid != 0 && m_tid != static_cast<uint64_t>(-1) && fdi.is_file() && fdi.m_dev == 0 &&
fdi.m_mount_id != 0) {
char procdir[SCAP_MAX_PATH_SIZE];
snprintf(procdir, sizeof(procdir), "%s/proc/%" PRIu64 "/", scap_get_host_root(), m_tid);
fdi.m_dev = scap_get_device_by_mount_id(m_params->m_scap_platform, procdir, fdi.m_mount_id);
fdi.m_mount_id = 0; // don't try again
}
#endif // _WIN32
}
sinsp_fdinfo* sinsp_fdtable::find(const int64_t fd) {
return find_ref(fd).get();
}
sinsp_fdinfo* sinsp_fdtable::add(const int64_t fd, std::shared_ptr<sinsp_fdinfo>&& fdinfo) {
return add_ref(fd, std::move(fdinfo)).get();
}
std::unique_ptr<libsinsp::state::table_entry> sinsp_fdtable::new_entry() const {
return m_params->m_fdinfo_factory.create();
};
std::shared_ptr<libsinsp::state::table_entry> sinsp_fdtable::get_entry(const int64_t& key) {
return find_ref(key);
}