The Pedigree Project 0.1
MountView-mounts.cc
1/* Copyright (c) 2026, Pedigree Developers. */
2#include "pedigree/kernel/syscallError.h"
3
4#include "MountView-internal.h"
5
6bool VfsMountView::bind(const FilesystemContextRef& context, const FilesystemPathRef& source,
7 const FilesystemPathRef& target, bool recursive) {
8 struct Copy {
9 uint64_t original;
10 VfsAttachmentRow* row = nullptr;
11 };
12 struct StagedRows {
13 VfsAttachmentRow* first = nullptr;
14 ~StagedRows() {
15 while (first) {
16 auto* next = first->next;
17 delete first;
18 first = next;
19 }
20 }
21 } staged;
22 Vector<Copy> copies;
25 VFS::NamespaceMutation writer(m_Vfs);
26 auto* sourceView = fromPath(source);
27 auto* sourceState = sourceView ? sourceView->m_State : nullptr;
28 auto* from = sourceState ? sourceState->path(source) : nullptr;
29 auto* to = m_State->path(target);
30 if (fromContext(context) != this || !from || !to || !context->snapshot(snapshot) ||
31 !m_State->beneath(target, snapshot.root) ||
32 from->node()->isDirectory() != to->node()->isDirectory()) {
33 SYSCALL_ERROR(InvalidArgument);
34 return false;
35 }
36 if (!sourceState->contains(source) || !m_State->contains(target) || m_State->at(*to)) {
37 SYSCALL_ERROR(DeviceBusy);
38 return false;
39 }
40 if (!sourceState->snapshotRows(rows)) {
41 return false;
42 }
43 const size_t capacity = rows.count() + 1;
44 if (!copies.tryReserve(capacity)) {
45 SYSCALL_ERROR(OutOfMemory);
46 return false;
47 }
48 Copy primary;
49 primary.original = from->attachment->id;
50 primary.row = new VfsAttachmentRow;
51 if (primary.row) {
52 primary.row->next = staged.first;
53 staged.first = primary.row;
54 }
56 if (!primary.row || !covered ||
57 !covered->retain(to->node(), to->attachment->backing->pin.filesystem()) ||
58 !m_State->makeAttachment(from->attachment->backing, from->node(), from->attachment->flags,
59 primary.row->attachment)) {
60 SYSCALL_ERROR(OutOfMemory);
61 return false;
62 }
63 primary.row->parent = to->attachment;
64 primary.row->attachment->lockedFlags = from->attachment->lockedFlags;
65 if (sourceView->ownerNamespace() != ownerNamespace()) {
66 primary.row->attachment->lockedFlags |= from->attachment->flags;
67 }
68 primary.row->covered = covered;
69 copies.pushBack(pedigree_std::move(primary));
70 if (recursive && from->node()->isDirectory()) {
71 for (auto& item : rows) {
72 auto* row = &item;
73 if (row->attachment.get() == from->attachment.get()) {
74 continue;
75 }
76 FilesystemPathRef mounted;
77 if (!sourceState->makePath(row->attachment, row->attachment->root, mounted)) {
78 return false;
79 }
80 if (!sourceState->contains(mounted) || !sourceState->beneath(mounted, source)) {
81 continue;
82 }
83 Copy copied;
84 copied.original = row->attachment->id;
85 copied.row = new VfsAttachmentRow;
86 if (copied.row) {
87 copied.row->next = staged.first;
88 staged.first = copied.row;
89 }
90 if (!copied.row || !m_State->makeAttachment(row->attachment->backing, row->attachment->root,
91 row->attachment->flags, copied.row->attachment)) {
92 return false;
93 }
94 copied.row->covered = row->covered;
95 copied.row->attachment->lockedFlags = row->attachment->lockedFlags;
96 copied.row->attachment->lockedMount = row->attachment->lockedMount;
97 if (sourceView->ownerNamespace() != ownerNamespace()) {
98 copied.row->attachment->lockedFlags |= row->attachment->flags;
99 copied.row->attachment->lockedMount = true;
100 }
101 copies.pushBack(pedigree_std::move(copied));
102 }
103 for (size_t i = 1; i < copies.count(); ++i) {
104 VfsAttachmentRow* original = nullptr;
105 for (auto& row : rows) {
106 if (row.attachment->id == copies[i].original) {
107 original = &row;
108 break;
109 }
110 }
111 for (auto& parent : copies) {
112 if (original->parent && parent.original == original->parent->id) {
113 copies[i].row->parent = parent.row->attachment;
114 break;
115 }
116 }
117 if (!copies[i].row->parent) {
118 SYSCALL_ERROR(InvalidArgument);
119 return false;
120 }
121 }
122 }
123 {
124 LockGuard<Mutex> guard(m_State->graph);
125 for (auto& copy : copies) {
126 copy.row->next = m_State->attachments;
127 m_State->attachments = copy.row;
128 }
129 staged.first = nullptr;
130 ++m_State->topology;
131 }
132 return true;
133}
134
135uint64_t VfsMountView::mountFlags(const FilesystemPathRef& path) const {
136 auto* selected = m_State ? m_State->path(path) : nullptr;
137 return selected ? uint64_t(selected->attachment->flags) : 0;
138}
139
140VfsMountView::WriteLease::~WriteLease() {
141 if (auto* view = fromPath(m_Path)) {
142 auto* path = view->m_State->path(m_Path);
143 if (path) {
144 path->attachment->writers -= 1;
145 }
146 }
147}
148
149bool VfsMountView::WriteLease::acquire(const FilesystemPathRef& reference) {
150 if (m_Path) {
151 SYSCALL_ERROR(InvalidArgument);
152 return false;
153 }
154 auto* view = fromPath(reference);
155 if (!view) {
156 SYSCALL_ERROR(InvalidArgument);
157 return false;
158 }
159 LockGuard<Mutex> guard(view->m_State->graph);
160 if (!view->writable(reference)) {
161 return false;
162 }
163 auto* path = view->m_State->path(reference);
164 if (path) {
165 path->attachment->writers += 1;
166 }
167 m_Path = reference;
168 return true;
169}
170
171bool VfsMountView::retainWrite(const FilesystemPathRef& path,
173 auto lease = SharedPointer<FilesystemWriteLease>::tryAdopt(new WriteLease);
174 if (!lease) {
175 SYSCALL_ERROR(OutOfMemory);
176 return false;
177 }
178 if (!static_cast<WriteLease*>(lease.get())->acquire(path)) {
179 return false;
180 }
181 result = pedigree_std::move(lease);
182 return true;
183}
184
185bool VfsMountView::writable(const FilesystemPathRef& path) const {
186 if (!m_State || !m_State->nodePath(path)) {
187 SYSCALL_ERROR(InvalidArgument);
188 return false;
189 }
190 auto* filesystem = path->node()->getFilesystem();
191 if ((mountFlags(path) & ReadOnly) || (filesystem && filesystem->isReadOnly())) {
192 SYSCALL_ERROR(ReadOnlyFilesystem);
193 return false;
194 }
195 return true;
196}
197
198bool VfsMountView::remount(const FilesystemContextRef& context, const FilesystemPathRef& target,
199 uint64_t flags, bool recursive) {
200 if (flags & ~SupportedMountFlags) {
201 SYSCALL_ERROR(InvalidArgument);
202 return false;
203 }
207 VFS::NamespaceMutation writer(m_Vfs);
208 auto* mounted = m_State->path(target);
209 if (fromContext(context) != this || !mounted || !context->snapshot(snapshot) ||
210 mounted->node() != mounted->attachment->root || !m_State->contains(target) ||
211 !m_State->beneath(target, snapshot.root)) {
212 SYSCALL_ERROR(InvalidArgument);
213 return false;
214 }
215 if (!m_State->snapshotRows(rows)) {
216 return false;
217 }
218 for (auto& item : rows) {
219 auto* row = &item;
220 bool included = row->attachment.get() == mounted->attachment.get();
221 if (recursive && !included) {
222 for (auto* parent = row; parent && parent->parent;) {
223 if (parent->parent.get() == mounted->attachment.get()) {
224 included = true;
225 break;
226 }
227 VfsAttachmentRow* next = nullptr;
228 for (auto& candidate : rows) {
229 if (candidate.attachment.get() == parent->parent.get()) {
230 next = &candidate;
231 break;
232 }
233 }
234 parent = next;
235 }
236 }
237 if (included) {
238 if (!selected.tryReserve(selected.count() + 1)) {
239 SYSCALL_ERROR(OutOfMemory);
240 return false;
241 }
242 selected.pushBack(row->attachment);
243 }
244 }
245 {
246 LockGuard<Mutex> guard(m_State->graph);
247 for (auto& attachment : selected) {
248 if ((flags & attachment->lockedFlags) != attachment->lockedFlags) {
249 SYSCALL_ERROR(NotEnoughPermissions);
250 return false;
251 }
252 if ((flags & ReadOnly) && !(attachment->flags & ReadOnly) && attachment->writers) {
253 SYSCALL_ERROR(DeviceBusy);
254 return false;
255 }
256 }
257 for (auto& attachment : selected) {
258 auto* mountedAttachment = attachment.get();
259 if (!mountedAttachment) {
260 FATAL("Missing prepared mount attachment");
261 } else {
262 mountedAttachment->flags = flags;
263 }
264 }
265 ++m_State->topology;
266 }
267 return true;
268}
269
270bool VfsMountView::State::attach(const FilesystemPathRef& covered, VFS::FilesystemPin&& pin,
271 const VFS::NamespaceMutation& writer, BackingOwnership ownership,
272 uint64_t flags) {
273 VFS::MountOperation operation;
274 if (!pin.identity().acquire(operation)) {
275 SYSCALL_ERROR(DeviceDoesNotExist);
276 return false;
277 }
278 auto* point = path(covered);
279 if (!writer.protects(view.m_Vfs) || !point || !point->node()->isDirectory() || !pin) {
280 SYSCALL_ERROR(InvalidArgument);
281 return false;
282 }
283 if (Directory::fromFile(point->node())->isDetached()) {
284 SYSCALL_ERROR(DoesNotExist);
285 return false;
286 }
287 {
288 LockGuard<Mutex> guard(graph);
289 if (!contains(covered) || at(*point)) {
290 SYSCALL_ERROR(DeviceBusy);
291 return false;
292 }
293 }
294 auto backing = VfsBackingRef::tryAdopt(new VfsBacking(pedigree_std::move(pin)));
295 VfsAttachmentRef attachment;
296 if (!backing ||
297 !makeAttachment(backing, backing->pin.filesystem()->getRoot(), flags, attachment)) {
298 return false;
299 }
302 if (!attachment || !node || !row) {
303 SYSCALL_ERROR(OutOfMemory);
304 return false;
305 }
306 if (!node->retain(point->node(), point->attachment->backing->pin.filesystem())) {
307 SYSCALL_ERROR(DoesNotExist);
308 return false;
309 }
310 row.get()->attachment = attachment;
311 row.get()->parent = point->attachment;
312 row.get()->covered = node;
313 {
314 LockGuard<Mutex> guard(graph);
315 attachment->backing->owningRegistry =
316 ownership == BackingOwnership::Attachment ? &view.m_Vfs : nullptr;
317 row.get()->next = attachments;
318 attachments = row.releaseOwnership();
319 ++topology;
320 }
321 return true;
322}
323
324bool VfsMountView::attach(const FilesystemContextRef& context, const FilesystemPathRef& covered,
325 Filesystem* backing, BackingOwnership ownership, uint64_t flags) {
326 if (flags & ~SupportedMountFlags) {
327 SYSCALL_ERROR(InvalidArgument);
328 return false;
329 }
331 if (!m_State) {
332 ERROR("VfsMountView::attach: no internal state");
333 SYSCALL_ERROR(DoesNotExist);
334 return false;
335 }
336 if (!m_Vfs.pinFilesystem(backing, pin)) {
337 ERROR("VfsMountView::attach: failed to pin filesystem");
338 SYSCALL_ERROR(DoesNotExist);
339 return false;
340 }
342 VFS::NamespaceMutation writer(m_Vfs);
343 if (!context) {
344 ERROR("VfsMountView::attach: no context");
345 SYSCALL_ERROR(InvalidArgument);
346 return false;
347 }
348 if (!context->snapshot(snapshot)) {
349 ERROR("VfsMountView::attach: failed to snapshot");
350 SYSCALL_ERROR(InvalidArgument);
351 return false;
352 }
353 if (!m_State->beneath(covered, snapshot.root)) {
354 ERROR("VfsMountView::attach: not an ancestor of " << snapshot.root->node()->getFullPath());
355 SYSCALL_ERROR(InvalidArgument);
356 return false;
357 }
358
359 if (!m_State->attach(covered, pedigree_std::move(pin), writer, ownership, flags)) {
360 ERROR("VfsMountView::attach: internal attach failed");
361 return false;
362 }
363
364 return true;
365}
366
367void VfsMountView::State::reapDetached() {
368#if THREADS && !defined(STANDALONE_MUTEXES)
369 TerminationDeferral lifetime;
370#endif
371 VfsAttachmentRow* retired = nullptr;
372 {
373 LockGuard<Mutex> guard(graph);
374 // Graph rows own covered-node references, not user paths. A disconnected
375 // tree may drain only when none of its attachments has a retained path.
376 for (;;) {
377 VfsAttachmentRow* detached = nullptr;
378 for (auto* candidate = attachments; candidate; candidate = candidate->next) {
379 if (candidate->parent || candidate->attachment->id == rootId)
380 continue;
381 bool used = false;
382 for (auto* row = attachments; row && !used; row = row->next) {
383 auto* ancestor = row;
384 while (ancestor && ancestor != candidate)
385 ancestor = ancestor->parent ? find(ancestor->parent->id) : nullptr;
386 if (ancestor && row->attachment->paths)
387 used = true;
388 }
389 if (!used) {
390 detached = candidate;
391 break;
392 }
393 }
394 if (!detached)
395 break;
396 // Remove leaves first, keeping parent rows discoverable for the next
397 // ancestry check. Actual node/backing destruction happens after unlock.
398 while (true) {
399 VfsAttachmentRow** selected = nullptr;
400 for (auto** link = &attachments; *link; link = &(*link)->next) {
401 auto* row = *link;
402 auto* ancestor = row;
403 while (ancestor && ancestor != detached)
404 ancestor = ancestor->parent ? find(ancestor->parent->id) : nullptr;
405 if (!ancestor)
406 continue;
407 bool child = false;
408 for (auto* check = attachments; check; check = check->next)
409 if (check->parent.get() == row->attachment.get())
410 child = true;
411 if (!child) {
412 selected = link;
413 break;
414 }
415 }
416 if (!selected)
417 FATAL("Cyclic detached attachment graph");
418 auto* row = *selected;
419 const bool last = row == detached;
420 *selected = row->next;
421 row->next = retired;
422 retired = row;
423 if (last)
424 break;
425 }
426 ++topology;
427 }
428 }
429 while (retired) {
430 auto* next = retired->next;
431 delete retired;
432 retired = next;
433 }
434}
435
436bool VfsMountView::detach(const FilesystemContextRef& context, const String& target, bool lazy) {
437 if (!m_State || !context) {
438 SYSCALL_ERROR(InvalidArgument);
439 return false;
440 }
441 VfsAttachmentRef retiredParent;
442 SharedPointer<VfsNodeReference> retiredCovered;
443 FilesystemPathRef mounted;
445 VFS::NamespaceMutation writer(m_Vfs);
446 ResolveOptions options;
447 options.requireDirectory = false;
448 if (!context->snapshot(snapshot) ||
449 !m_State->resolve(snapshot, snapshot.cwd, target, options, mounted, &writer))
450 return false;
451 if (!m_State->cross(mounted, mounted)) {
452 return false;
453 }
454 auto* path = m_State->path(mounted);
455 {
456 LockGuard<Mutex> guard(m_State->graph);
457 auto* row = path ? m_State->find(path->attachment->id) : nullptr;
458 if (!row || !m_State->contains(mounted) || path->node() != path->attachment->root) {
459 SYSCALL_ERROR(InvalidArgument);
460 return false;
461 }
462 if (row->attachment->id == m_State->rootId) {
463 SYSCALL_ERROR(DeviceBusy);
464 return false;
465 }
466 if (row->attachment->lockedMount) {
467 SYSCALL_ERROR(NotEnoughPermissions);
468 return false;
469 }
470 if (!lazy) {
471 // The lookup above owns exactly one newly materialized mount-root path.
472 if (row->attachment->paths != 1 || mounted.refcount() != 1) {
473 SYSCALL_ERROR(DeviceBusy);
474 return false;
475 }
476 for (auto* child = m_State->attachments; child; child = child->next) {
477 if (child->parent.get() == row->attachment.get()) {
478 SYSCALL_ERROR(DeviceBusy);
479 return false;
480 }
481 }
482 }
483 retiredParent = pedigree_std::move(row->parent);
484 retiredCovered = pedigree_std::move(row->covered);
485 ++m_State->topology;
486 }
487 return true;
488}
489
490bool VfsMountView::pivot(const FilesystemContextRef& context, const String& newRoot,
491 const String& putOld) {
492 if (!m_State || !context) {
493 SYSCALL_ERROR(InvalidArgument);
494 return false;
495 }
496 // All ownership which may retire backend state precedes the writer guard.
498 FilesystemPathRef newPath, oldPath;
499 VfsAttachmentRef retiredNewParent, retiredOldParent;
500 SharedPointer<VfsNodeReference> retiredNewCovered, retiredOldCovered;
502 Vector<FilesystemPathRef> retiredPaths;
503 VFS::NamespaceMutation writer(m_Vfs);
504 ResolveOptions options;
505 options.requireDirectory = true;
506 if (!context->snapshot(snapshot) ||
507 !m_State->resolve(snapshot, snapshot.cwd, newRoot, options, newPath, &writer) ||
508 !m_State->resolve(snapshot, snapshot.cwd, putOld, options, oldPath, &writer))
509 return false;
510 auto* callerRoot = m_State->path(snapshot.root);
511 auto* nextRoot = m_State->path(newPath);
512 auto* oldMountpoint = m_State->path(oldPath);
513 if (!callerRoot || !nextRoot || !oldMountpoint) {
514 SYSCALL_ERROR(InvalidArgument);
515 return false;
516 }
517 const bool stacked = samePath(newPath, oldPath);
518 if (callerRoot->node() != callerRoot->attachment->root ||
519 nextRoot->node() != nextRoot->attachment->root ||
520 callerRoot->attachment.get() == nextRoot->attachment.get() ||
521 oldMountpoint->attachment.get() == callerRoot->attachment.get() ||
522 !m_State->beneath(newPath, snapshot.root) || !m_State->beneath(oldPath, newPath)) {
523 SYSCALL_ERROR(InvalidArgument);
524 return false;
525 }
526 if (Directory::fromFile(oldMountpoint->node())->isDetached()) {
527 SYSCALL_ERROR(DoesNotExist);
528 return false;
529 }
530 if (!stacked && oldMountpoint->node() == oldMountpoint->attachment->root) {
531 SYSCALL_ERROR(OperationNotSupported);
532 return false;
533 }
534 size_t count;
535 {
536 LockGuard<Mutex> guard(m_State->graph);
537 count = m_State->contextCount;
538 auto* previous = m_State->find(callerRoot->attachment->id);
539 auto* next = m_State->find(nextRoot->attachment->id);
540 if (next && next->attachment->lockedMount) {
541 SYSCALL_ERROR(NotEnoughPermissions);
542 return false;
543 }
544 if (!previous || !next || !m_State->contains(newPath) || !m_State->contains(oldPath) ||
545 m_State->at(*oldMountpoint)) {
546 SYSCALL_ERROR(DeviceBusy);
547 return false;
548 }
549 }
550 if (count > ~size_t(0) / 2 || !retiredPaths.tryReserve(count * 2)) {
551 SYSCALL_ERROR(OutOfMemory);
552 return false;
553 }
555 if (!putOldNode) {
556 SYSCALL_ERROR(OutOfMemory);
557 return false;
558 }
559 if (!putOldNode->retain(oldMountpoint->node(),
560 oldMountpoint->attachment->backing->pin.filesystem())) {
561 SYSCALL_ERROR(DoesNotExist);
562 return false;
563 }
564 {
565 LockGuard<Mutex> guard(m_State->graph);
566 auto* previous = m_State->find(callerRoot->attachment->id);
567 auto* next = m_State->find(nextRoot->attachment->id);
568 // Writer admission freezes graph edges, enrollment and backend ancestry.
569 // Every operation below is an existing reference increment or move.
570 retiredNewParent = pedigree_std::move(next->parent);
571 retiredNewCovered = pedigree_std::move(next->covered);
572 retiredOldParent = pedigree_std::move(previous->parent);
573 retiredOldCovered = pedigree_std::move(previous->covered);
574 next->parent = retiredOldParent;
575 next->covered = retiredOldCovered;
576 previous->parent = oldMountpoint->attachment;
577 previous->covered = putOldNode;
578 if (m_State->rootId == previous->attachment->id)
579 m_State->rootId = next->attachment->id;
580 for (auto* row = m_State->contexts; row; row = row->next) {
581 auto* fs = static_cast<VfsFilesystemContext*>(row->context.get());
582 bool changed = false;
583 if (samePath(fs->root, snapshot.root)) {
584 retiredPaths.pushBack(pedigree_std::move(fs->root));
585 fs->root = newPath;
586 changed = true;
587 }
588 if (samePath(fs->cwd, snapshot.root)) {
589 retiredPaths.pushBack(pedigree_std::move(fs->cwd));
590 fs->cwd = newPath;
591 changed = true;
592 }
593 if (changed)
594 ++fs->generation;
595 }
596 ++m_State->topology;
597 }
598 return true;
599}
600
601bool VfsMountView::detachBackingForShutdown(Filesystem* backing) {
602#if THREADS && !defined(STANDALONE_MUTEXES)
603 TerminationDeferral lifetime;
604#endif
605 if (!m_State || !backing)
606 return true;
607 VfsAttachmentRow* retired = nullptr;
608 {
609 VFS::NamespaceMutation writer(m_Vfs);
610 LockGuard<Mutex> guard(m_State->graph);
611 for (auto* row = m_State->attachments; row; row = row->next) {
612 if (row->attachment->backing->pin.filesystem() != backing)
613 continue;
614 if (row->attachment->id == m_State->rootId || row->attachment->paths) {
615 SYSCALL_ERROR(DeviceBusy);
616 return false;
617 }
618 for (auto* child = m_State->attachments; child; child = child->next) {
619 if (child->parent.get() == row->attachment.get() &&
620 child->attachment->backing->pin.filesystem() != backing) {
621 SYSCALL_ERROR(DeviceBusy);
622 return false;
623 }
624 }
625 }
626 for (auto** link = &m_State->attachments; *link;) {
627 auto* row = *link;
628 if (row->attachment->backing->pin.filesystem() != backing) {
629 link = &row->next;
630 continue;
631 }
632 *link = row->next;
633 row->next = retired;
634 retired = row;
635 }
636 ++m_State->topology;
637 }
638 while (retired) {
639 auto* next = retired->next;
640 delete retired;
641 retired = next;
642 }
643 return true;
644}
645
646bool VfsMountView::detachBackingForRemoval(Filesystem* backing) {
649 {
650 VFS::NamespaceMutation writer(m_Vfs);
651 LockGuard<Mutex> guard(m_State->graph);
652 for (auto* row = m_State->attachments; row; row = row->next) {
653 if (row->attachment->backing->pin.filesystem() != backing) {
654 continue;
655 }
656 if (row->attachment->id == m_State->rootId) {
657 SYSCALL_ERROR(DeviceBusy);
658 return false;
659 }
660 parents.pushBack(pedigree_std::move(row->parent));
661 covered.pushBack(pedigree_std::move(row->covered));
662 row->attachment->backing->owningRegistry = nullptr;
663 }
664 ++m_State->topology;
665 }
666 m_State->reapDetached();
667 return true;
668}
669
670bool VfsMountView::shutdown(Vector<Filesystem*>& ownedBackings) {
671 VfsAttachmentRow* retired;
672 {
673 VFS::NamespaceMutation writer(m_Vfs);
674 LockGuard<Mutex> guard(m_State->graph);
675 if (m_State->contexts || m_State->anonymousPaths) {
676 SYSCALL_ERROR(DeviceBusy);
677 return false;
678 }
679 size_t ownedCount = 0;
680 for (auto* row = m_State->attachments; row; row = row->next) {
681 if (row->attachment->paths) {
682 SYSCALL_ERROR(DeviceBusy);
683 return false;
684 }
685 size_t localOwners = 0;
686 for (auto* other = m_State->attachments; other; other = other->next) {
687 if (other->attachment->backing.get() == row->attachment->backing.get()) {
688 ++localOwners;
689 }
690 }
691 if (row->attachment->backing.refcount() > localOwners) {
692 SYSCALL_ERROR(DeviceBusy);
693 return false;
694 }
695 if (row->attachment->backing->owningRegistry)
696 ++ownedCount;
697 }
698 if (!ownedBackings.tryReserve(ownedBackings.count() + ownedCount)) {
699 SYSCALL_ERROR(OutOfMemory);
700 return false;
701 }
702 for (auto* row = m_State->attachments; row; row = row->next) {
703 if (row->attachment->backing->owningRegistry) {
704 ownedBackings.pushBack(row->attachment->backing->pin.filesystem());
705 // The terminal owner must check sync before deleting this backend.
706 // Clearing the shared attachment also handles multiple bind rows.
707 row->attachment->backing->owningRegistry = nullptr;
708 }
709 }
710 retired = m_State->attachments;
711 m_State->attachments = nullptr;
712 m_State->rootId = 0;
713 ++m_State->topology;
714 }
715 while (retired) {
716 auto* next = retired->next;
717 delete retired;
718 retired = next;
719 }
720 return true;
721}
static Directory * fromFile(File *pF)
Definition Directory.h:151
bool isDetached() const
Definition Directory.h:182
size_t refcount() const
static SharedPointer< T > tryAdopt(T *ptr)
T * get() const
static UniquePointer< T > adopt(T *pointer)
Definition Pointers.h:101
A vector / dynamic array.
Definition Vector.h:33
void pushBack(const T &value)
Definition Vector.h:275
size_t count() const
Definition Vector.h:270