2#include "MemoryExtendedAttributes.h"
3#include "pedigree/kernel/LockGuard.h"
4#include "pedigree/kernel/process/TerminationDeferral.h"
5#include "pedigree/kernel/utilities/assert.h"
6#include "pedigree/kernel/utilities/new"
7#include "pedigree/kernel/utilities/utility.h"
12XattrStatus validateName(
const StringView& name) {
13 if (!name.length() || name.length() > Xattr::MaximumNameLength)
14 return XattrStatus::Range;
16 return XattrStatus::Invalid;
17 for (
size_t i = 0; i < name.length(); ++i)
19 return XattrStatus::Invalid;
20 if (name.length() < 5 || !name.substring(0, 5).compare(
"user.", 5))
21 return XattrStatus::Unsupported;
22 return name.length() == 5 ? XattrStatus::Invalid : XattrStatus::Success;
28 size_t nameLength, valueLength, bytes;
30 return reinterpret_cast<char*
>(
this + 1);
33 return name() + nameLength + 1;
35 static Entry* create(
const StringView& name,
const void* value,
size_t length) {
36 const size_t bytes =
sizeof(
Entry) + name.length() + 1 + length;
37 auto* storage =
new uint8_t[bytes];
40 auto* entry =
new (storage)
Entry{
nullptr, name.length(), length, bytes};
41 MemoryCopy(entry->name(), name.str(), name.length());
42 entry->name()[name.length()] = 0;
44 MemoryCopy(entry->value(), value, length);
47 static void destroy(
Entry* entry) {
51 delete[]
reinterpret_cast<uint8_t*
>(entry);
58 Entry::destroy(entry);
62size_t MemoryExtendedAttributes::Quota::used()
const {
63 return __atomic_load_n(&m_Used, __ATOMIC_ACQUIRE);
66bool MemoryExtendedAttributes::Quota::increase(
size_t amount) {
67 size_t previous = used();
69 if (previous > m_Limit || amount > m_Limit - previous)
71 }
while (!__atomic_compare_exchange_n(&m_Used, &previous, previous + amount,
false,
72 __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE));
76void MemoryExtendedAttributes::Quota::decrease(
size_t amount) {
77 const size_t previous = __atomic_fetch_sub(&m_Used, amount, __ATOMIC_ACQ_REL);
78 assert(previous >= amount);
85MemoryExtendedAttributes::MemoryExtendedAttributes(Quota& quota) : m_Lock(), m_Quota(quota) {}
87MemoryExtendedAttributes::~MemoryExtendedAttributes() {
90 Entry* next = m_Entries->next;
91 Entry::destroy(m_Entries);
94 m_Quota.decrease(m_Bytes);
98 Entry** slot = &m_Entries;
99 while (*slot && !name.compare((*slot)->name(), (*slot)->nameLength))
100 slot = &(*slot)->next;
104XattrStatus MemoryExtendedAttributes::get(
const StringView& name,
void* buffer,
size_t capacity,
108 const auto valid = validateName(name);
109 if (valid != XattrStatus::Success)
112 Entry* entry = *find(name);
114 return XattrStatus::Missing;
115 required = entry->valueLength;
117 return XattrStatus::Success;
118 if (capacity < required)
119 return XattrStatus::Range;
122 return XattrStatus::Invalid;
123 MemoryCopy(buffer, entry->value(), required);
125 return XattrStatus::Success;
128XattrStatus MemoryExtendedAttributes::list(
void* buffer,
size_t capacity,
size_t& required) {
132 for (Entry* entry = m_Entries; entry; entry = entry->next)
133 required += entry->nameLength + 1;
135 return XattrStatus::Success;
136 if (capacity < required)
137 return XattrStatus::Range;
138 if (required && !buffer)
139 return XattrStatus::Invalid;
140 auto* output =
static_cast<char*
>(buffer);
141 for (Entry* entry = m_Entries; entry; entry = entry->next) {
142 MemoryCopy(output, entry->name(), entry->nameLength + 1);
143 output += entry->nameLength + 1;
145 return XattrStatus::Success;
148XattrStatus MemoryExtendedAttributes::set(
const StringView& name,
const void* value,
size_t length,
151 if ((flags & ~(Xattr::Create | Xattr::Replace)) || (length && !value))
152 return XattrStatus::Invalid;
153 const auto valid = validateName(name);
154 if (valid != XattrStatus::Success)
156 if (length > Xattr::MaximumValueLength)
157 return XattrStatus::Range;
158 PreparedEntry prepared{Entry::create(name, value, length)};
160 return XattrStatus::NoMemory;
161 Entry* retired =
nullptr;
164 Entry** slot = find(name);
166 if (retired && (flags & Xattr::Create))
167 return XattrStatus::Exists;
168 if (!retired && (flags & Xattr::Replace))
169 return XattrStatus::Missing;
170 const size_t oldBytes = retired ? retired->bytes : 0;
171 const size_t newBytes = prepared.entry->bytes;
172 const size_t retainedBytes = m_Bytes - oldBytes;
173 if ((!retired && m_Count == MaximumEntries) || newBytes > MaximumStoreBytes - retainedBytes)
174 return XattrStatus::NoSpace;
175 if (newBytes > oldBytes && !m_Quota.increase(newBytes - oldBytes))
176 return XattrStatus::NoSpace;
177 prepared.entry->next = retired ? retired->next :
nullptr;
178 *slot = prepared.entry;
179 prepared.entry =
nullptr;
180 m_Bytes = retainedBytes + newBytes;
183 if (oldBytes > newBytes)
184 m_Quota.decrease(oldBytes - newBytes);
186 Entry::destroy(retired);
187 return XattrStatus::Success;
190XattrStatus MemoryExtendedAttributes::remove(
const StringView& name) {
192 const auto valid = validateName(name);
193 if (valid != XattrStatus::Success)
198 Entry** slot = find(name);
201 return XattrStatus::Missing;
202 *slot = retired->next;
204 m_Bytes -= retired->bytes;
205 m_Quota.decrease(retired->bytes);
207 Entry::destroy(retired);
208 return XattrStatus::Success;