ramfs: Correct "reference" (link) counting of Node objects.

* RemoveReference() could delete us immediately, thus we must do
   all important work before invoking it.

 * Add assertions about fRefCount and remove a spurious add.

 * Do not use Link but PublishVNode on the root, as we manually manage
   when this object is published/deleted.

Fixes #18032.
This commit is contained in:
Augustin Cavalier 2022-11-30 00:23:47 -05:00
parent 6a8bb0562e
commit 605ecac1ee
2 changed files with 9 additions and 6 deletions

View File

@ -66,6 +66,8 @@ Node::Node(Volume *volume, uint8 type)
// destructor
Node::~Node()
{
ASSERT(fRefCount == 0);
// delete all attributes
while (Attribute *attribute = fAttributes.First()) {
status_t error = DeleteAttribute(attribute);
@ -104,9 +106,10 @@ Node::AddReference()
void
Node::RemoveReference()
{
ASSERT(fRefCount > 0);
if (--fRefCount == 0) {
GetVolume()->RemoveVNode(this);
fRefCount++;
// RemoveVNode can potentially delete us immediately!
}
}
@ -114,7 +117,7 @@ Node::RemoveReference()
status_t
Node::Link(Entry *entry)
{
PRINT("Node[%Ld]::Link(): %" B_PRId32 " ->...\n", fID, fRefCount);
PRINT("Node[%" B_PRIdINO "]::Link(): %" B_PRId32 " ->...\n", fID, fRefCount);
fReferrers.Insert(entry);
status_t error = AddReference();
@ -128,10 +131,10 @@ PRINT("Node[%Ld]::Link(): %" B_PRId32 " ->...\n", fID, fRefCount);
status_t
Node::Unlink(Entry *entry)
{
PRINT("Node[%Ld]::Unlink(): %" B_PRId32 " ->...\n", fID, fRefCount);
RemoveReference();
PRINT("Node[%" B_PRIdINO "]::Unlink(): %" B_PRId32 " ->...\n", fID, fRefCount);
fReferrers.Remove(entry);
RemoveReference();
return B_OK;
}
@ -358,4 +361,3 @@ Node::GetAllocationInfo(AllocationInfo &info)
while (GetNextAttribute(&attribute) == B_OK)
attribute->GetAllocationInfo(info);
}

View File

@ -205,7 +205,7 @@ Volume::Mount(uint32 flags)
// set permissions: -rwxr-xr-x
fRootDirectory->SetMode(
S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
error = fRootDirectory->Link(NULL);
error = PublishVNode(fRootDirectory);
} else
SET_ERROR(error, B_NO_MEMORY);
}
@ -357,6 +357,7 @@ Volume::RemoveVNode(Node *node)
{
if (fMounted)
return remove_vnode(FSVolume(), node->GetID());
status_t error = NodeRemoved(node);
if (error == B_OK)
delete node;