FAT: Prevent Tracker deadlock when copying files

* Don't write-lock the node when opening or closing a file unless the
  node is actually being modified.
* Incidentally, move code from dosfs_close to dosfs_free_cookie. This
  is not necessary to avoid this deadlock, but it is more consistent
  with the approach of the BFS driver.
* When dragging and dropping a large file (e.g. 100 MB) in Tracker, it
  is possible for BPoseView::AttributeChanged() to open the file in the
  middle of the operation, which will deadlock with MoveItem() if
  opening involves a write lock.

Change-Id: Ifc430e1e583cacff2eeb7283100417e16e3f1f5b
Reviewed-on: https://review.haiku-os.org/c/haiku/+/7881
Haiku-Format: Haiku-format Bot <[email protected]>
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
Jim906
2024-07-24 20:43:10 +00:00
committed by waddlesplash
parent 872c9528c7
commit 9e11f4e9a5
@@ -918,7 +918,7 @@ dosfs_remove_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter)
free(fatNode);
locker.Unlock();
locker.Detach();
rw_lock_destroy(&bsdNode->v_vnlock->haikuRW);
free(bsdNode);
@@ -2164,7 +2164,12 @@ dosfs_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie)
return B_BAD_VALUE;
}
WriteLocker locker(bsdNode->v_vnlock->haikuRW);
ReadLocker readLocker;
WriteLocker writeLocker;
if ((openMode & O_TRUNC) != 0)
writeLocker.SetTo(bsdNode->v_vnlock->haikuRW, false);
else
readLocker.SetTo(bsdNode->v_vnlock->haikuRW, false);
// Opening a directory read-only is allowed, although you can't read
// any data from it.
@@ -2200,7 +2205,8 @@ dosfs_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie)
rw_lock_write_unlock(&fatVolume->pm_fatlock.haikuRW);
if (status != B_OK)
RETURN_ERROR(status);
locker.Unlock();
writeLocker.Unlock();
status = file_cache_set_size(bsdNode->v_cache, 0);
if (status != B_OK)
RETURN_ERROR(status);
@@ -2214,6 +2220,15 @@ dosfs_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie)
static status_t
dosfs_close(fs_volume* volume, fs_vnode* vnode, void* cookie)
{
FUNCTION_START("%p\n", vnode->private_node);
return B_OK;
}
static status_t
dosfs_free_cookie(fs_volume* volume, fs_vnode* vnode, void* cookie)
{
struct vnode* bsdNode = reinterpret_cast<struct vnode*>(vnode->private_node);
denode* fatNode = reinterpret_cast<denode*>(bsdNode->v_data);
@@ -2221,7 +2236,24 @@ dosfs_close(fs_volume* volume, fs_vnode* vnode, void* cookie)
FUNCTION_START("%s (inode %" B_PRIu64 " at %p)\n", fatNode->de_Name, fatNode->de_inode,
bsdNode);
WriteLocker locker(bsdNode->v_vnlock->haikuRW);
ReadLocker readLocker;
WriteLocker writeLocker;
bool correctLock = false;
while (correctLock == false) {
if ((fatNode->de_flag & (DE_UPDATE | DE_ACCESS | DE_CREATE)) != 0) {
writeLocker.SetTo(bsdNode->v_vnlock->haikuRW, false);
if ((fatNode->de_flag & (DE_UPDATE | DE_ACCESS | DE_CREATE)) != 0)
correctLock = true;
else
writeLocker.Unlock();
} else {
readLocker.SetTo(bsdNode->v_vnlock->haikuRW, false);
if ((fatNode->de_flag & (DE_UPDATE | DE_ACCESS | DE_CREATE)) == 0)
correctLock = true;
else
readLocker.Unlock();
}
}
struct timespec timeSpec;
vfs_timestamp(&timeSpec);
@@ -2242,16 +2274,7 @@ dosfs_close(fs_volume* volume, fs_vnode* vnode, void* cookie)
if ((bsdNode->v_mount->mnt_flag & MNT_SYNCHRONOUS) != 0)
deupdat(fatNode, 1);
return B_OK;
}
static status_t
dosfs_free_cookie(fs_volume* volume, fs_vnode* vnode, void* cookie)
{
FUNCTION_START("%p\n", vnode->private_node);
delete reinterpret_cast<FileCookie*>(cookie);
delete fatCookie;
return B_OK;
}
@@ -3403,7 +3426,6 @@ dev_bsd_node_uninit(vnode* devNode)
free(listEntry);
}
rw_lock_write_unlock(&devNode->v_bufobj.bo_lock.haikuRW);
rw_lock_destroy(&devNode->v_bufobj.bo_lock.haikuRW);
free(devNode);