Completed vfs_bind_mount_directory() support

We don't need to explicitly track the covered/covering nodes per mount
after all. In fs_unmount() we iterate through all vnodes multiple times
anyway and can deal with the covers/covered_by vnodes there. Also, the
root vnode doesn't need to be handled specially anymore.
This commit is contained in:
Ingo Weinhold 2011-06-21 23:31:48 +02:00
parent 1b08a68a4f
commit 04999b6cf9

View File

@ -5034,8 +5034,6 @@ vfs_bind_mount_directory(dev_t mountID, ino_t nodeID, dev_t coveredMountID,
inc_vnode_ref_count(vnode);
inc_vnode_ref_count(coveredVnode);
// TODO: This relationship must be tracked, so it can be dissolved on unmount.
return B_OK;
}
@ -7473,11 +7471,20 @@ fs_unmount(char* path, dev_t mountID, uint32 flags, bool kernel)
// make sure all of them are not busy or have refs on them
VnodeList::Iterator iterator = mount->vnodes.GetIterator();
while (struct vnode* vnode = iterator.Next()) {
// The root vnode ref_count needs to be 1 here (the mount has a
// reference).
if (vnode->IsBusy()
|| ((vnode->ref_count != 0 && mount->root_vnode != vnode)
|| (vnode->ref_count != 1 && mount->root_vnode == vnode))) {
if (vnode->IsBusy()) {
busy = true;
break;
}
// check the vnode's ref count -- subtract additional references for
// covering
int32 refCount = vnode->ref_count;
if (vnode->covers != NULL)
refCount--;
if (vnode->covered_by != NULL)
refCount--;
if (refCount != 0) {
// there are still vnodes in use on this mount, so we cannot
// unmount yet
busy = true;
@ -7515,37 +7522,75 @@ fs_unmount(char* path, dev_t mountID, uint32 flags, bool kernel)
vnodesWriteLocker.Lock();
}
// we can safely continue, mark all of the vnodes busy and this mount
// structure in unmounting state
// We can safely continue. Mark all of the vnodes busy and this mount
// structure in unmounting state. Also undo the vnode covers/covered_by
// links.
mount->unmounting = true;
VnodeList::Iterator iterator = mount->vnodes.GetIterator();
while (struct vnode* vnode = iterator.Next()) {
// Remove all covers/covered_by links from other mounts' nodes to this
// vnode and adjust the node ref count accordingly. We will release the
// references to the external vnodes below.
if (Vnode* coveredNode = vnode->covers) {
if (Vnode* coveringNode = vnode->covered_by) {
// We have both covered and covering vnodes, so just remove us
// from the chain.
coveredNode->covered_by = coveringNode;
coveringNode->covers = coveredNode;
vnode->ref_count -= 2;
vnode->covered_by = NULL;
vnode->covers = NULL;
vnode->SetCovering(false);
vnode->SetCovered(false);
} else {
// We only have a covered vnode. Remove its link to us.
coveredNode->covered_by = NULL;
coveredNode->SetCovered(false);
vnode->ref_count--;
// If the other node is an external vnode, we keep its link
// link around so we can put the reference later on. Otherwise
// we get rid of it right now.
if (coveredNode->mount == mount) {
vnode->covers = NULL;
coveredNode->ref_count--;
}
}
} else if (Vnode* coveringNode = vnode->covered_by) {
// We only have a covering vnode. Remove its link to us.
coveringNode->covers = NULL;
coveringNode->SetCovering(false);
vnode->ref_count--;
// If the other node is an external vnode, we keep its link
// link around so we can put the reference later on. Otherwise
// we get rid of it right now.
if (coveringNode->mount == mount) {
vnode->covered_by = NULL;
coveringNode->ref_count--;
}
}
vnode->SetBusy(true);
vnode_to_be_freed(vnode);
}
// The ref_count of the root node is 1 at this point, see above why this is
mount->root_vnode->ref_count--;
vnode_to_be_freed(mount->root_vnode);
Vnode* coveredNode = mount->root_vnode->covers;
coveredNode->covered_by = mount->root_vnode->covered_by;
coveredNode->SetCovered(coveredNode->covered_by != NULL);
mount->root_vnode->covered_by = NULL;
mount->root_vnode->SetCovered(false);
mount->root_vnode->SetCovering(false);
vnodesWriteLocker.Unlock();
put_vnode(coveredNode);
// Free all vnodes associated with this mount.
// They will be removed from the mount list by free_vnode(), so
// we don't have to do this.
while (struct vnode* vnode = mount->vnodes.Head())
while (struct vnode* vnode = mount->vnodes.Head()) {
// Put the references to external covered/covering vnodes we kept above.
if (Vnode* coveredNode = vnode->covers)
put_vnode(coveredNode);
if (Vnode* coveringNode = vnode->covered_by)
put_vnode(coveringNode);
free_vnode(vnode, false);
}
// remove the mount structure from the hash table
mutex_lock(&sMountMutex);