2#include "fanotify-queue.h"
3#include "pedigree/kernel/LockGuard.h"
4#include "pedigree/kernel/utilities/utility.h"
7constexpr uint64_t Overflow = 0x4000;
12 uint16_t metadataLength;
22 uint32_t handleLength;
25static_assert(
sizeof(Metadata) == 24 &&
sizeof(FidInfo) == 20,
"Linux fanotify record layout");
28size_t FanotifyRecord::encodedSize()
const {
29 return sizeof(Metadata) + (mask == Overflow ? 0 : ((sizeof(FidInfo) + handle.length + 3) & ~3U));
32void FanotifyRecord::encode(
void* buffer)
const {
33 const size_t length = encodedSize();
34 Metadata metadata = {
static_cast<uint32_t
>(length), 3, 0,
sizeof(Metadata), mask, -1,
35 static_cast<int32_t
>(producer)};
36 ByteSet(buffer, 0, length);
37 MemoryCopy(buffer, &metadata,
sizeof(metadata));
41 1, 0,
static_cast<uint16_t
>(length -
sizeof(Metadata)), fsid, handle.length, handle.type};
42 auto* bytes =
static_cast<uint8_t*
>(buffer);
43 MemoryCopy(bytes +
sizeof(metadata), &info,
sizeof(info));
44 MemoryCopy(bytes +
sizeof(metadata) +
sizeof(info), handle.bytes, handle.length);
47bool FanotifyRecord::sameTarget(
const FanotifyRecord& other)
const {
48 if (mask == Overflow || other.mask == Overflow || mountId != other.mountId ||
49 producer != other.producer || handle.type != other.handle.type ||
50 handle.length != other.handle.length || handle.length >
sizeof(handle.bytes))
52 for (
size_t index = 0; index < handle.length; ++index) {
53 if (handle.bytes[index] != other.handle.bytes[index])
59FanotifyQueue::FanotifyQueue()
61FanotifyQueue::~FanotifyQueue() {
64bool FanotifyQueue::valid()
const {
65 return static_cast<bool>(m_Records);
69 bool readable =
false;
72 if (m_Closed || !m_Records || record.handle.length >
sizeof(record.handle.bytes))
75 auto& last = m_Records.get()[(m_Head + m_Count - 1) % (MaximumEvents + 1)];
76 if (last.sameTarget(record)) {
77 last.mask |= record.mask;
81 if (m_Count >= MaximumEvents && m_OverflowQueued)
83 auto& destination = m_Records.get()[(m_Head + m_Count) % (MaximumEvents + 1)];
84 if (m_Count >= MaximumEvents) {
86 destination.mask = Overflow;
87 m_OverflowQueued =
true;
91 readable = m_Count++ == 0;
101FanotifyQueue::Take FanotifyQueue::take(
FanotifyRecord& record,
size_t capacity,
bool canBlock) {
103 while (!m_Closed && !m_Count) {
108 ConditionVariable::Error error = ConditionVariable::NoError;
109 if (!m_Readers.
wait(m_Lock, error)) {
112 return error == ConditionVariable::Interrupted ||
113 error == ConditionVariable::TerminationDeferred
122 if (m_Records.get()[m_Head].encodedSize() > capacity) {
124 return Take::TooSmall;
126 record = m_Records.get()[m_Head];
127 m_Head = (m_Head + 1) % (MaximumEvents + 1);
129 if (record.mask == Overflow)
130 m_OverflowQueued =
false;
135void FanotifyQueue::close() {
142 m_OverflowQueued =
false;
148ReadyMask FanotifyQueue::queryReady() {
150 return m_Closed ? ReadyInvalid | ReadyHangup : (m_Count ? ReadyRead : ReadyNone);
154 return m_Generations;
156int FanotifyQueue::queuedMetadataBytes() {
159 return static_cast<int>(m_Count *
sizeof(Metadata));
MUST_USE_RESULT bool wait(Mutex &mutex, Time::Timestamp &timeout, Error &error, WaitQueue::StackDiscardCleanup onStackDiscard=nullptr, void *stackDiscardContext=nullptr)
static bool mutexAcquired(Error error)
ReadinessGenerations readinessGenerations() override
void notifyReadiness(ReadyMask mask)
void closeReadiness(ReadyMask mask=ReadyInvalid|ReadyHangup)
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)