2#include "pedigree/kernel/LockGuard.h"
3#include "pedigree/kernel/process/TerminationDeferral.h"
4#include "pedigree/kernel/process/Thread.h"
5#include "pedigree/kernel/processor/Processor.h"
6#include "pedigree/kernel/processor/ProcessorInformation.h"
7#include "pedigree/kernel/syscallError.h"
8#include "pedigree/kernel/utilities/utility.h"
10#include "fanotify-queue.h"
11#include "fanotify-syscalls.h"
12#include "file-handle-syscalls.h"
13#include "modules/subsys/posix/PosixSubsystem.h"
14#include "modules/system/vfs/File.h"
17constexpr size_t MaximumGroups = 64, MaximumMarks = 256, MaximumGlobalMarks = 4096;
18size_t groups = 0, marks = 0;
19constexpr FileEventMask Events = FileEvents::Modify | FileEvents::Attributes | FileEvents::Open |
20 FileEvents::CloseWrite | FileEvents::CloseNoWrite;
22bool charge(
size_t& counter,
size_t limit) {
23 size_t value = __atomic_load_n(&counter, __ATOMIC_RELAXED);
27 }
while (!__atomic_compare_exchange_n(&counter, &value, value + 1,
false, __ATOMIC_ACQ_REL,
35 : m_Queue(queue), m_Identity(
identity) {}
36 ~FanotifyObserver()
override {
40 bool arm(uint64_t mask) {
52 bool change(uint64_t mask,
bool remove) {
72 if (event.mask & FileEvents::SourceRetired) {
78 uint64_t selected = 0;
79 if (event.mask & FileEvents::Modify)
81 if (event.mask & FileEvents::Attributes)
83 if (event.mask & FileEvents::CloseWrite)
85 if (event.mask & FileEvents::CloseNoWrite)
87 if (event.mask & FileEvents::Open)
90 if (!m_Active || !selected)
93 record.mask = selected;
94 record.producer =
event.producerPid;
95 m_Queue->enqueue(record);
99 void releaseCharge() {
102 __atomic_sub_fetch(&marks, 1, __ATOMIC_ACQ_REL);
109 bool m_Active =
false, m_Retired =
false;
110 bool m_Charged =
true;
118 __atomic_sub_fetch(&marks, 1, __ATOMIC_ACQ_REL);
123 FanotifyObserver* concrete =
nullptr;
125 bool charged =
false;
138FanotifyInstance::FanotifyInstance() : m_State(new
FanotifyState) {}
139FanotifyInstance::~FanotifyInstance() {
140 lastDescriptorClosed();
144 if (!charge(groups, MaximumGroups)) {
145 SYSCALL_ERROR(ProcessFileLimit);
149 if (!instance || !instance->m_State || !instance->m_State->queue ||
150 !instance->m_State->queue->valid()) {
152 __atomic_sub_fetch(&groups, 1, __ATOMIC_ACQ_REL);
153 SYSCALL_ERROR(OutOfMemory);
156 instance->m_Quota =
true;
160void FanotifyInstance::reapMarks() {
164 for (
size_t index = 0; index < m_State->count;) {
165 if (m_State->marks[index].get()->concrete->active()) {
169 retiring[count++] = pedigree_std::move(m_State->marks[index]);
171 if (index != m_State->count)
172 m_State->marks[index] = pedigree_std::move(m_State->marks[m_State->count]);
187 if (m_State->closed) {
188 SYSCALL_ERROR(BadFileDescriptor);
191 for (
size_t index = 0; index < m_State->count; ++index) {
192 auto* mark = m_State->marks[index].get();
193 if (!mark->identity.sameTarget(
identity) || !mark->concrete->active())
195 if (!mark->concrete->change(mask, remove)) {
196 retiring = pedigree_std::move(m_State->marks[index]);
198 if (index != m_State->count)
199 m_State->marks[index] = pedigree_std::move(m_State->marks[m_State->count]);
204 SYSCALL_ERROR(DoesNotExist);
207 if (m_State->count == MaximumMarks || !charge(marks, MaximumGlobalMarks)) {
208 SYSCALL_ERROR(NoSpaceLeftOnDevice);
213 __atomic_sub_fetch(&marks, 1, __ATOMIC_ACQ_REL);
214 SYSCALL_ERROR(OutOfMemory);
217 auto* mark = candidate.get();
218 mark->charged =
true;
220 mark->mountIdentity = mount.identity();
221 mark->concrete =
new FanotifyObserver(m_State->queue,
identity);
222 if (!mark->concrete) {
223 SYSCALL_ERROR(OutOfMemory);
226 mark->observer.reset(mark->concrete);
229 mark->charged =
false;
231 target.subscribeInodeEvents(Events | FileEvents::SourceRetired, mark->observer, mark->inode);
232 if (status != FileHandleStatus::Success)
233 return posix_handle_error(status);
234 if (!mark->mountIdentity.subscribeRetirement(mark->observer, mark->mount)) {
235 SYSCALL_ERROR(OutOfMemory);
238 if (!mark->concrete->arm(mask)) {
239 SYSCALL_ERROR(DoesNotExist);
242 m_State->marks[m_State->count++] = pedigree_std::move(candidate);
246int FanotifyInstance::flushMarks() {
250 if (m_State->closed) {
251 SYSCALL_ERROR(BadFileDescriptor);
254 for (
size_t index = 0; index < m_State->count; ++index) {
255 m_State->marks[index].get()->concrete->deactivate();
256 retiring[index] = pedigree_std::move(m_State->marks[index]);
262void FanotifyInstance::lastDescriptorClosed() {
271 m_State->closed =
true;
272 for (
size_t index = 0; index < m_State->count; ++index) {
273 m_State->marks[index].get()->concrete->deactivate();
274 retiring[index] = pedigree_std::move(m_State->marks[index]);
279 __atomic_sub_fetch(&groups, 1, __ATOMIC_ACQ_REL);
283 m_State->queue->close();
286ssize_t FanotifyInstance::readToUser(
void* buffer,
size_t count,
bool canBlock) {
289 } cursor{
reinterpret_cast<uintptr_t
>(buffer)};
290 auto copy = [](
void* opaque,
const void* bytes,
size_t length) ->
bool {
291 auto* cursor =
static_cast<Cursor*
>(opaque);
292 if (length > ~uintptr_t(0) - cursor->address ||
295 cursor->address += length;
298 return readWithCopy(count, canBlock, copy, &cursor);
301ssize_t FanotifyInstance::readWithCopy(
size_t count,
bool canBlock, PosixDescriptorReadCopy copy,
305 auto queue = m_State->queue;
309 const auto result = queue->take(record, count - copied, canBlock && !copied);
310 if (result != FanotifyQueue::Take::Ready) {
315 syscallError(result == FanotifyQueue::Take::Empty ? Error::NoMoreProcesses
316 : result ==
FanotifyQueue::Take::TooSmall ? Error::InvalidArgument
317 : result ==
FanotifyQueue::Take::Interrupted ? Error::Interrupted
318 : Error::BadFileDescriptor);
321 uint8_t bytes[FanotifyQueue::MaximumRecordSize];
322 record.encode(bytes);
323 const size_t size = record.encodedSize();
326 if (!copy(opaque, bytes, size)) {
327 SYSCALL_ERROR(BadAddress);
334ReadyMask FanotifyInstance::queryReady() {
335 return m_State->queue->queryReady();
338 return m_State->queue.
get();
340int FanotifyInstance::queuedMetadataBytes() {
341 return m_State->queue->queuedMetadataBytes();
virtual void fileEvent(const FileEvent &event)=0
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static ProcessorInformation & information()