2#include "pedigree/kernel/Log.h"
3#include "pedigree/kernel/syscallError.h"
5#include "MountView-internal.h"
6#if THREADS && !defined(STANDALONE_MUTEXES)
7#include "pedigree/kernel/process/Thread.h"
8#include "pedigree/kernel/processor/Processor.h"
9#include "pedigree/kernel/processor/ProcessorInformation.h"
13 : m_Node(child.releaseOwnership()),
14 m_Ownership(m_Node ? Ownership::Tracked : Ownership::Borrowed) {}
16 : m_Node(other.m_Node), m_Ownership(other.m_Ownership) {
17 other.m_Node =
nullptr;
18 other.m_Ownership = Ownership::Borrowed;
23 m_Node = other.m_Node;
24 m_Ownership = other.m_Ownership;
25 other.m_Node =
nullptr;
26 other.m_Ownership = Ownership::Borrowed;
30VfsNodeReference::~VfsNodeReference() {
33void VfsNodeReference::reset() {
34 if (m_Ownership == Ownership::Borrowed) {
38#if THREADS && !defined(STANDALONE_MUTEXES)
42 const auto ownership = m_Ownership;
44 m_Ownership = Ownership::Borrowed;
45 if (ownership == Ownership::Tracked) {
48 node->releaseVfsReference();
52 if (m_Node || !node || !backing || node->getFilesystem() != backing)
54 const bool retained = node->retainVfsReference();
55 if (!retained && node != backing->
getRoot()) {
59 m_Ownership = retained ? Ownership::Virtual : Ownership::Borrowed;
63bool VfsNodeReference::retainAnonymous(
File* node) {
64 if (m_Node || !node || node->isDirectory() || !node->retainVfsReference())
67 m_Ownership = Ownership::Virtual;
71VfsBacking::~VfsBacking() {
72#if THREADS && !defined(STANDALONE_MUTEXES)
78 FATAL(
"Owned attachment lost its backing registration");
83 : kind(Kind::Mounted), view(owner), attachment(mounted), file(pedigree_std::move(retained)) {
85 attachment->paths += 1;
88 : kind(Kind::Anonymous), view(owner), attachment(), file(pedigree_std::move(retained)) {
90 view.m_State->anonymousPaths += 1;
93#if THREADS && !defined(STANDALONE_MUTEXES)
96 const size_t error = thread ? thread->
getErrno() : 0;
99 if (kind == Kind::Mounted) {
100 if ((attachment->paths -= 1) == 0)
101 view.m_State->reapDetached();
103 view.m_State->anonymousPaths -= 1;
106 lookupParent.
reset();
108#if THREADS && !defined(STANDALONE_MUTEXES)
114VfsMountView::VfsMountView(
VFS& vfs) : m_State(new State(*this)), m_Vfs(vfs) {}
115void VfsMountView::retain() {
116 __atomic_add_fetch(&m_References, 1, __ATOMIC_RELAXED);
118void VfsMountView::release() {
119 if (__atomic_sub_fetch(&m_References, 1, __ATOMIC_ACQ_REL) == 0 && m_Automatic) {
124 return context ?
static_cast<VfsMountView*
>(
const_cast<void*
>(context->provider())) : nullptr;
127 return path ?
static_cast<VfsMountView*
>(
const_cast<void*
>(path->provider())) : nullptr;
129VfsMountView::~VfsMountView() {
132VfsMountView::State::~State() {
133 if (contexts || anonymousPaths)
134 FATAL(
"Mount view destroyed with retained filesystem owners");
135 auto* row = attachments;
136 attachments =
nullptr;
138 if (row->attachment->paths)
139 FATAL(
"Mount view destroyed with retained paths");
140 auto* next = row->next;
147 for (
auto* row = attachments; row; row = row->next)
148 if (row->attachment->id ==
id)
153 for (
auto* row = attachments; row; row = row->next)
154 if (row->parent.get() == path.attachment.
get() && row->covered &&
155 row->covered->get() == path.node())
162 for (
auto* row = attachments; row; row = row->next) {
165 if (!result.tryReserve(count)) {
166 SYSCALL_ERROR(OutOfMemory);
169 for (
auto* row = attachments; row; row = row->next) {
175 auto* result = reference && reference->provider() == &view
178 return result && &result->view == &view ? result :
nullptr;
181 auto* selected = nodePath(reference);
182 return selected && selected->kind == VfsPath::Kind::Mounted ? selected :
nullptr;
185 auto* p = path(reference);
188 auto* row = find(p->attachment->id);
189 size_t remaining = 1;
190 for (
auto* entry = attachments; entry; entry = entry->next)
192 while (row && remaining--) {
193 if (row->attachment->id == rootId)
195 row = row->parent ? find(row->parent->id) : nullptr;
201 for (
auto* row = contexts; row; row = row->next) {
202 if (row->context.get() == reference.
get()) {
212 if (!attachment || !retained.retain(node, attachment->backing->pin.filesystem())) {
213 SYSCALL_ERROR(DoesNotExist);
216 return makePath(attachment, pedigree_std::move(retained), result);
219bool VfsMountView::State::makeAttachment(
const VfsBackingRef& backing,
File* root, uint64_t flags,
222 if (!backing || !retained.retain(root, backing->pin.filesystem())) {
223 SYSCALL_ERROR(DoesNotExist);
226 if (nextId > 0x7fffffffU) {
227 SYSCALL_ERROR(OutOfMemory);
231 new VfsAttachment(backing, nextId++, pedigree_std::move(retained), flags));
233 SYSCALL_ERROR(OutOfMemory);
236 result = pedigree_std::move(attachment);
242 if (fromContext(context) !=
this || result) {
243 SYSCALL_ERROR(InvalidArgument);
247 if (!clone || !clone.get()->m_State) {
248 SYSCALL_ERROR(OutOfMemory);
251 auto* destination = clone.get()->m_State;
252 clone.get()->m_OwnerNamespace = ownerNamespace;
257 if (!reference || !enrolled) {
258 SYSCALL_ERROR(OutOfMemory);
263 if (!context->snapshot(snapshot)) {
264 SYSCALL_ERROR(DoesNotExist);
267 if (!m_State->snapshotRows(rows)) {
272 for (
auto& item : rows) {
273 auto* source = &item;
275 if (!root.retain(source->attachment->root, source->attachment->backing->pin.filesystem())) {
276 SYSCALL_ERROR(DoesNotExist);
280 new VfsAttachment(source->attachment->backing, source->attachment->id,
281 pedigree_std::move(root), source->attachment->flags));
283 if (!attachment || !row) {
284 SYSCALL_ERROR(OutOfMemory);
287 attachment->lockedFlags = source->attachment->lockedFlags;
288 attachment->lockedMount = source->attachment->lockedMount;
289 if (ownerNamespace != m_OwnerNamespace) {
290 attachment->lockedFlags |= source->attachment->flags;
293 attachment->lockedMount = source->attachment->id != m_State->rootId;
295 row.get()->attachment = attachment;
296 row.
get()->covered = source->covered;
297 row.get()->next = destination->attachments;
298 destination->attachments = row.releaseOwnership();
300 for (
auto& item : rows) {
301 auto* source = &item;
302 if (source->parent) {
303 destination->find(source->attachment->id)->parent =
304 destination->find(source->parent->id)->attachment;
307 destination->rootId = m_State->rootId;
308 destination->nextId = m_State->nextId;
310 auto* root = m_State->path(snapshot.root);
311 auto* cwd = m_State->path(snapshot.cwd);
312 if (!root || !destination->makePath(destination->find(root->attachment->id)->attachment,
313 root->node(), created->root)) {
317 if (!destination->makePath(destination->find(cwd->attachment->id)->attachment, cwd->node(),
322 created->cwd = snapshot.cwd;
324 enrolled.get()->context = reference;
325 created->registration = enrolled.get();
326 destination->contexts = enrolled.releaseOwnership();
327 destination->contextCount = 1;
329 auto* published = clone.releaseOwnership();
330 published->m_Automatic =
true;
331 result = FilesystemContextOwner::adopt(pedigree_std::move(reference));
332 published->m_State->reapDetached();
333 published->release();
338 if (!attachment || !retained.get() ||
339 retained.get()->getFilesystem() != attachment->backing->pin.filesystem()) {
340 SYSCALL_ERROR(DoesNotExist);
346 SYSCALL_ERROR(OutOfMemory);
349 result = pedigree_std::move(path);
353bool VfsMountView::initialise(
Filesystem* bootRoot) {
354 if (!m_State || !bootRoot) {
355 SYSCALL_ERROR(OutOfMemory);
359 if (!m_Vfs.pinFilesystem(bootRoot, pin)) {
360 SYSCALL_ERROR(DoesNotExist);
365 if (!backing || !m_State->makeAttachment(backing, bootRoot->
getRoot(), 0, attachment)) {
369 if (!attachment || !row) {
370 SYSCALL_ERROR(OutOfMemory);
373 row.get()->attachment = attachment;
376 if (m_State->rootId) {
377 SYSCALL_ERROR(DeviceBusy);
382 m_State->attachments = row.releaseOwnership();
386#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
387bool VfsMountView::quiescentForHostedTest()
const {
391 if (m_State->contexts || m_State->anonymousPaths)
393 for (
auto* row = m_State->attachments; row; row = row->next)
394 if (row->attachment->paths)
406 auto* row = m_State->find(m_State->rootId);
409 attachment = row->attachment;
411 return m_State->makePath(attachment, attachment->root, result);
414 return m_State && m_State->createContext(
nullptr, result);
418#if THREADS && !defined(STANDALONE_MUTEXES)
422 SYSCALL_ERROR(InvalidArgument);
427 if (!reference || !row) {
428 SYSCALL_ERROR(OutOfMemory);
432 row.get()->context = reference;
441 auto* root = find(rootId);
443 SYSCALL_ERROR(DoesNotExist);
446 attachment = root->attachment;
448 if (!makePath(attachment, attachment->root, initial))
453 if (parent && !parent->registration) {
454 SYSCALL_ERROR(DoesNotExist);
457 created->root = parent ? parent->root : initial;
458 created->cwd = parent ? parent->cwd : initial;
459 created->registration = row.get();
460 row.get()->next = contexts;
461 contexts = row.releaseOwnership();
464 result = FilesystemContextOwner::adopt(pedigree_std::move(reference));
468VfsFilesystemContext::~VfsFilesystemContext() {
470 FATAL(
"Filesystem context destroyed before owner retirement");
482 replacement.root = root;
483 replacement.cwd = cwd;
484 replacement.contextGeneration = generation;
485 replacement.topologyGeneration = view.m_State->topology;
487 result = pedigree_std::move(replacement);
491 return view.m_State->createContext(
this, result);
493void VfsFilesystemContext::retireProcessOwner() {
494#if THREADS && !defined(STANDALONE_MUTEXES)
504 auto** link = &view.m_State->contexts;
505 while (*link && *link != registration)
506 link = &(*link)->next;
508 FATAL(
"Missing filesystem context enrollment");
510 *link = retired->next;
511 registration =
nullptr;
512 --view.m_State->contextCount;
513 retiredRoot = pedigree_std::move(root);
514 retiredCwd = pedigree_std::move(cwd);
520 auto* owner = fromPath(path);
521 if (!owner || !owner->m_State->path(path) || !path->node()->
isDirectory()) {
522 SYSCALL_ERROR(NotADirectory);
532 if (!m_State->context(context, target)) {
533 SYSCALL_ERROR(DoesNotExist);
536 retired = pedigree_std::move(target->cwd);
538 ++target->generation;
543 if (!m_State->path(path) || !path->node()->
isDirectory()) {
544 SYSCALL_ERROR(NotADirectory);
554 if (!m_State->context(context, target)) {
555 SYSCALL_ERROR(DoesNotExist);
558 retired = pedigree_std::move(target->root);
560 ++target->generation;
565 auto* concrete = m_State ? m_State->path(path) :
nullptr;
566 return concrete ? concrete->attachment->id : 0;
569 auto* first = m_State ? m_State->nodePath(a) :
nullptr;
570 auto* second = m_State ? m_State->nodePath(b) :
nullptr;
571 return first && second && first->kind == second->kind &&
572 first->attachment.get() == second->attachment.get() && first->node() == second->node();
576 if (!m_State || !retained.retainAnonymous(node)) {
577 SYSCALL_ERROR(NotADirectory);
582 SYSCALL_ERROR(OutOfMemory);
585 result = pedigree_std::move(path);
590 auto* path = m_State ? m_State->path(sameAttachment) :
nullptr;
592 SYSCALL_ERROR(InvalidArgument);
595 return m_State->makePath(path->attachment, node, result);
virtual bool isDirectory()
virtual File * getRoot() const =0
static ProcessorInformation & information()
static SharedPointer< VfsAttachment > tryAdopt(VfsAttachment *ptr)
void setErrno(size_t err)
static UniquePointer< T > adopt(T *pointer)
bool retireOwnedFilesystem(Filesystem *filesystem)
bool untrackFile(File *pFile, bool destroy=true)
static bool checkAccess(File *pFile, bool bRead, bool bWrite, bool bExecute)
A vector / dynamic array.
void pushBack(const T &value)