Fixed crashing bug in remove_vnode(): it freed the vnode, but it didn't

remove it from the hash, and thus, left a dead pointer around.
free_vnode() does now also remove the vnode from the hash - this is done
so that the file system is notified about removal/put of the vnode before
there is a chance that this vnode is recreated/reloaded (could make the
life of file system writers a bit easier).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13877 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2005-08-02 11:20:04 +00:00
parent bef4185e93
commit c50cfe23dd

View File

@ -641,7 +641,8 @@ create_new_vnode(struct vnode **_vnode, mount_id mountID, vnode_id vnodeID)
}
/** Frees the vnode and all resources it has acquired.
/** Frees the vnode and all resources it has acquired, and removes
* it from the vnode hash as well as from its mount structure.
* Will also make sure that any cache modifications are written back.
*/
@ -664,6 +665,12 @@ free_vnode(struct vnode *vnode, bool reenter)
FS_CALL(vnode, put_vnode)(vnode->mount->cookie, vnode->private_node, reenter);
}
// The file system has removed the resources of the vnode now, so we can
// make it available again (and remove the busy vnode from the hash)
mutex_lock(&sVnodeMutex);
hash_remove(sVnodeTable, vnode);
mutex_unlock(&sVnodeMutex);
// if we have a vm_cache attached, remove it
if (vnode->cache)
vm_cache_release_ref(vnode->cache);
@ -709,7 +716,6 @@ dec_vnode_ref_count(struct vnode *vnode, bool reenter)
// Just insert the vnode into an unused list if we don't need
// to delete it
if (vnode->remove) {
hash_remove(sVnodeTable, vnode);
vnode->busy = true;
freeNode = true;
} else {
@ -718,7 +724,6 @@ dec_vnode_ref_count(struct vnode *vnode, bool reenter)
// there are too many unused vnodes so we free the oldest one
// ToDo: evaluate this mechanism
vnode = (struct vnode *)list_remove_head_item(&sUnusedVnodeList);
hash_remove(sVnodeTable, vnode);
vnode->busy = true;
freeNode = true;
sUnusedVnodes--;
@ -1981,7 +1986,8 @@ get_new_fd(int type, struct fs_mount *mount, struct vnode *vnode,
extern "C" status_t
new_vnode(mount_id mountID, vnode_id vnodeID, fs_vnode privateNode)
{
FUNCTION(("new_vnode()\n"));
FUNCTION(("new_vnode(mountID = %ld, vnodeID = %Ld, node = %p)\n",
mountID, vnodeID, privateNode));
if (privateNode == NULL)
return B_BAD_VALUE;
@ -2074,6 +2080,7 @@ extern "C" status_t
remove_vnode(mount_id mountID, vnode_id vnodeID)
{
struct vnode *vnode;
bool remove = false;
mutex_lock(&sVnodeMutex);
@ -2081,13 +2088,20 @@ remove_vnode(mount_id mountID, vnode_id vnodeID)
if (vnode != NULL) {
vnode->remove = true;
if (vnode->unpublished) {
// if the vnode hasn't been published yet, we delete it here
atomic_add(&vnode->ref_count, -1);
free_vnode(vnode, true);
// prepare the vnode for deletion
vnode->busy = true;
remove = true;
}
}
mutex_unlock(&sVnodeMutex);
if (remove) {
// if the vnode hasn't been published yet, we delete it here
atomic_add(&vnode->ref_count, -1);
free_vnode(vnode, true);
}
return B_OK;
}
@ -2771,7 +2785,7 @@ vfs_bootstrap_file_systems(void)
if (status < B_OK) {
// this is no fatal exception at this point, as we may mount
// a real on disk file system later
dprintf("error mounting bootfs\n");
dprintf("Can't mount bootfs (will try disk file system later)\n");
}
// create some standard links on the rootfs
@ -4866,7 +4880,6 @@ fs_unmount(char *path, uint32 flags, bool kernel)
while ((vnode = (struct vnode *)list_get_next_item(&mount->vnodes, vnode)) != NULL) {
vnode->busy = true;
hash_remove(sVnodeTable, vnode);
}
mutex_unlock(&sVnodeMutex);
@ -4877,7 +4890,7 @@ fs_unmount(char *path, uint32 flags, bool kernel)
// 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 ((vnode = (struct vnode *)list_get_next_item(&mount->vnodes, NULL)) != NULL) {
while ((vnode = (struct vnode *)list_get_first_item(&mount->vnodes)) != NULL) {
free_vnode(vnode, false);
}