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:
parent
bef4185e93
commit
c50cfe23dd
@ -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.
|
* 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);
|
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 we have a vm_cache attached, remove it
|
||||||
if (vnode->cache)
|
if (vnode->cache)
|
||||||
vm_cache_release_ref(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
|
// Just insert the vnode into an unused list if we don't need
|
||||||
// to delete it
|
// to delete it
|
||||||
if (vnode->remove) {
|
if (vnode->remove) {
|
||||||
hash_remove(sVnodeTable, vnode);
|
|
||||||
vnode->busy = true;
|
vnode->busy = true;
|
||||||
freeNode = true;
|
freeNode = true;
|
||||||
} else {
|
} 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
|
// there are too many unused vnodes so we free the oldest one
|
||||||
// ToDo: evaluate this mechanism
|
// ToDo: evaluate this mechanism
|
||||||
vnode = (struct vnode *)list_remove_head_item(&sUnusedVnodeList);
|
vnode = (struct vnode *)list_remove_head_item(&sUnusedVnodeList);
|
||||||
hash_remove(sVnodeTable, vnode);
|
|
||||||
vnode->busy = true;
|
vnode->busy = true;
|
||||||
freeNode = true;
|
freeNode = true;
|
||||||
sUnusedVnodes--;
|
sUnusedVnodes--;
|
||||||
@ -1981,7 +1986,8 @@ get_new_fd(int type, struct fs_mount *mount, struct vnode *vnode,
|
|||||||
extern "C" status_t
|
extern "C" status_t
|
||||||
new_vnode(mount_id mountID, vnode_id vnodeID, fs_vnode privateNode)
|
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)
|
if (privateNode == NULL)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@ -2074,6 +2080,7 @@ extern "C" status_t
|
|||||||
remove_vnode(mount_id mountID, vnode_id vnodeID)
|
remove_vnode(mount_id mountID, vnode_id vnodeID)
|
||||||
{
|
{
|
||||||
struct vnode *vnode;
|
struct vnode *vnode;
|
||||||
|
bool remove = false;
|
||||||
|
|
||||||
mutex_lock(&sVnodeMutex);
|
mutex_lock(&sVnodeMutex);
|
||||||
|
|
||||||
@ -2081,13 +2088,20 @@ remove_vnode(mount_id mountID, vnode_id vnodeID)
|
|||||||
if (vnode != NULL) {
|
if (vnode != NULL) {
|
||||||
vnode->remove = true;
|
vnode->remove = true;
|
||||||
if (vnode->unpublished) {
|
if (vnode->unpublished) {
|
||||||
// if the vnode hasn't been published yet, we delete it here
|
// prepare the vnode for deletion
|
||||||
atomic_add(&vnode->ref_count, -1);
|
vnode->busy = true;
|
||||||
free_vnode(vnode, true);
|
remove = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&sVnodeMutex);
|
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;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2771,7 +2785,7 @@ vfs_bootstrap_file_systems(void)
|
|||||||
if (status < B_OK) {
|
if (status < B_OK) {
|
||||||
// this is no fatal exception at this point, as we may mount
|
// this is no fatal exception at this point, as we may mount
|
||||||
// a real on disk file system later
|
// 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
|
// 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) {
|
while ((vnode = (struct vnode *)list_get_next_item(&mount->vnodes, vnode)) != NULL) {
|
||||||
vnode->busy = true;
|
vnode->busy = true;
|
||||||
hash_remove(sVnodeTable, vnode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&sVnodeMutex);
|
mutex_unlock(&sVnodeMutex);
|
||||||
@ -4877,7 +4890,7 @@ fs_unmount(char *path, uint32 flags, bool kernel)
|
|||||||
// Free all vnodes associated with this mount.
|
// Free all vnodes associated with this mount.
|
||||||
// They will be removed from the mount list by free_vnode(), so
|
// They will be removed from the mount list by free_vnode(), so
|
||||||
// we don't have to do this.
|
// 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);
|
free_vnode(vnode, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user