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);
|
||||
|
||||
hash_insert(fNodeHash, inode);
|
||||
new_vnode(ID(), inode->ID(), inode);
|
||||
publish_vnode(ID(), inode->ID(), inode);
|
||||
|
||||
if (fRootNode != NULL)
|
||||
fRootNode->SetModificationTime(time(NULL));
|
||||
|
@ -82,8 +82,9 @@ struct vnode {
|
||||
struct fs_mount *mount;
|
||||
struct vnode *covered_by;
|
||||
int32 ref_count;
|
||||
bool delete_me;
|
||||
bool busy;
|
||||
uint8 remove : 1;
|
||||
uint8 busy : 1;
|
||||
uint8 unpublished : 1;
|
||||
};
|
||||
|
||||
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
|
||||
// will be discarded
|
||||
|
||||
if (vnode->cache && !vnode->delete_me)
|
||||
if (vnode->cache && !vnode->remove)
|
||||
vm_cache_write_modified(vnode->cache);
|
||||
|
||||
if (vnode->delete_me)
|
||||
FS_CALL(vnode, remove_vnode)(vnode->mount->cookie, vnode->private_node, reenter);
|
||||
else
|
||||
FS_CALL(vnode, put_vnode)(vnode->mount->cookie, vnode->private_node, reenter);
|
||||
if (!vnode->unpublished) {
|
||||
if (vnode->remove)
|
||||
FS_CALL(vnode, remove_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 (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
|
||||
// to delete it
|
||||
if (vnode->delete_me) {
|
||||
if (vnode->remove) {
|
||||
hash_remove(sVnodeTable, vnode);
|
||||
vnode->busy = 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);
|
||||
|
||||
status_t status = create_new_vnode(&vnode, mountID, vnodeID);
|
||||
if (status == B_OK)
|
||||
if (status == B_OK) {
|
||||
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)));
|
||||
|
||||
@ -1696,8 +1730,14 @@ remove_vnode(mount_id mountID, vnode_id vnodeID)
|
||||
mutex_lock(&sVnodeMutex);
|
||||
|
||||
vnode = lookup_vnode(mountID, vnodeID);
|
||||
if (vnode)
|
||||
vnode->delete_me = true;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&sVnodeMutex);
|
||||
return B_OK;
|
||||
@ -1713,7 +1753,7 @@ unremove_vnode(mount_id mountID, vnode_id vnodeID)
|
||||
|
||||
vnode = lookup_vnode(mountID, vnodeID);
|
||||
if (vnode)
|
||||
vnode->delete_me = false;
|
||||
vnode->remove = false;
|
||||
|
||||
mutex_unlock(&sVnodeMutex);
|
||||
return B_OK;
|
||||
|
Loading…
Reference in New Issue
Block a user