Fixed the get_vnode()/new_vnode() race condition by introducing a new
function publish_vnode(). When calling new_vnode(), the node is only reserved, but not yet accessible for others. Only when you call publish_vnode(), it will become available. That simplifies new node handling/locking considerably. Note, you don't have to call new_vnode() before publish_vnode(); ie. publish_vnode() acts exactly like new_vnode() did before if used that way. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@11719 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
bade75a525
commit
4e08f1474d
@ -299,7 +299,7 @@ Volume::CreateNode(Inode *parent, const char *name, int32 type)
|
|||||||
InsertNode(inode);
|
InsertNode(inode);
|
||||||
|
|
||||||
hash_insert(fNodeHash, inode);
|
hash_insert(fNodeHash, inode);
|
||||||
new_vnode(ID(), inode->ID(), inode);
|
publish_vnode(ID(), inode->ID(), inode);
|
||||||
|
|
||||||
if (fRootNode != NULL)
|
if (fRootNode != NULL)
|
||||||
fRootNode->SetModificationTime(time(NULL));
|
fRootNode->SetModificationTime(time(NULL));
|
||||||
|
@ -82,8 +82,9 @@ struct vnode {
|
|||||||
struct fs_mount *mount;
|
struct fs_mount *mount;
|
||||||
struct vnode *covered_by;
|
struct vnode *covered_by;
|
||||||
int32 ref_count;
|
int32 ref_count;
|
||||||
bool delete_me;
|
uint8 remove : 1;
|
||||||
bool busy;
|
uint8 busy : 1;
|
||||||
|
uint8 unpublished : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vnode_hash_key {
|
struct vnode_hash_key {
|
||||||
@ -589,13 +590,15 @@ free_vnode(struct vnode *vnode, bool reenter)
|
|||||||
// if the vnode won't be deleted, in which case the changes
|
// if the vnode won't be deleted, in which case the changes
|
||||||
// will be discarded
|
// will be discarded
|
||||||
|
|
||||||
if (vnode->cache && !vnode->delete_me)
|
if (vnode->cache && !vnode->remove)
|
||||||
vm_cache_write_modified(vnode->cache);
|
vm_cache_write_modified(vnode->cache);
|
||||||
|
|
||||||
if (vnode->delete_me)
|
if (!vnode->unpublished) {
|
||||||
FS_CALL(vnode, remove_vnode)(vnode->mount->cookie, vnode->private_node, reenter);
|
if (vnode->remove)
|
||||||
else
|
FS_CALL(vnode, remove_vnode)(vnode->mount->cookie, vnode->private_node, reenter);
|
||||||
FS_CALL(vnode, put_vnode)(vnode->mount->cookie, vnode->private_node, reenter);
|
else
|
||||||
|
FS_CALL(vnode, put_vnode)(vnode->mount->cookie, vnode->private_node, reenter);
|
||||||
|
}
|
||||||
|
|
||||||
// if we have a vm_cache attached, remove it
|
// if we have a vm_cache attached, remove it
|
||||||
if (vnode->cache)
|
if (vnode->cache)
|
||||||
@ -641,7 +644,7 @@ 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->delete_me) {
|
if (vnode->remove) {
|
||||||
hash_remove(sVnodeTable, vnode);
|
hash_remove(sVnodeTable, vnode);
|
||||||
vnode->busy = true;
|
vnode->busy = true;
|
||||||
freeNode = true;
|
freeNode = true;
|
||||||
@ -1648,8 +1651,39 @@ new_vnode(mount_id mountID, vnode_id vnodeID, fs_vnode privateNode)
|
|||||||
panic("vnode %ld:%Ld already exists (node = %p, vnode->node = %p)!", mountID, vnodeID, privateNode, vnode->private_node);
|
panic("vnode %ld:%Ld already exists (node = %p, vnode->node = %p)!", mountID, vnodeID, privateNode, vnode->private_node);
|
||||||
|
|
||||||
status_t status = create_new_vnode(&vnode, mountID, vnodeID);
|
status_t status = create_new_vnode(&vnode, mountID, vnodeID);
|
||||||
if (status == B_OK)
|
if (status == B_OK) {
|
||||||
vnode->private_node = privateNode;
|
vnode->private_node = privateNode;
|
||||||
|
vnode->busy = true;
|
||||||
|
vnode->unpublished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT(("returns: %s\n", strerror(status)));
|
||||||
|
|
||||||
|
mutex_unlock(&sVnodeMutex);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" status_t
|
||||||
|
publish_vnode(mount_id mountID, vnode_id vnodeID, fs_vnode privateNode)
|
||||||
|
{
|
||||||
|
FUNCTION(("publish_vnode()\n"));
|
||||||
|
|
||||||
|
mutex_lock(&sVnodeMutex);
|
||||||
|
|
||||||
|
struct vnode *vnode = lookup_vnode(mountID, vnodeID);
|
||||||
|
status_t status = B_OK;
|
||||||
|
|
||||||
|
if (vnode != NULL && vnode->busy && vnode->unpublished
|
||||||
|
&& vnode->private_node == privateNode) {
|
||||||
|
vnode->busy = false;
|
||||||
|
vnode->unpublished = false;
|
||||||
|
} else if (vnode == NULL && privateNode != NULL) {
|
||||||
|
status = create_new_vnode(&vnode, mountID, vnodeID);
|
||||||
|
if (status == B_OK)
|
||||||
|
vnode->private_node = privateNode;
|
||||||
|
} else
|
||||||
|
status = B_BAD_VALUE;
|
||||||
|
|
||||||
PRINT(("returns: %s\n", strerror(status)));
|
PRINT(("returns: %s\n", strerror(status)));
|
||||||
|
|
||||||
@ -1696,8 +1730,14 @@ remove_vnode(mount_id mountID, vnode_id vnodeID)
|
|||||||
mutex_lock(&sVnodeMutex);
|
mutex_lock(&sVnodeMutex);
|
||||||
|
|
||||||
vnode = lookup_vnode(mountID, vnodeID);
|
vnode = lookup_vnode(mountID, vnodeID);
|
||||||
if (vnode)
|
if (vnode != NULL) {
|
||||||
vnode->delete_me = true;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mutex_unlock(&sVnodeMutex);
|
mutex_unlock(&sVnodeMutex);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@ -1713,7 +1753,7 @@ unremove_vnode(mount_id mountID, vnode_id vnodeID)
|
|||||||
|
|
||||||
vnode = lookup_vnode(mountID, vnodeID);
|
vnode = lookup_vnode(mountID, vnodeID);
|
||||||
if (vnode)
|
if (vnode)
|
||||||
vnode->delete_me = false;
|
vnode->remove = false;
|
||||||
|
|
||||||
mutex_unlock(&sVnodeMutex);
|
mutex_unlock(&sVnodeMutex);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
Loading…
Reference in New Issue
Block a user