From 551a9b9a01ded2752e40a36576650713e4447c05 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Wed, 20 Nov 2024 18:03:09 -0500 Subject: [PATCH] BFS: Keep references to vnodes during asynchronous I/O. IORequest notifications begin by notifying the "finished" condition, then invoking the request callback, then invoking the parent callback. vfs_{read|write}_pages wait on the "finished" condition and then return at once, potentially releasing their references to the vnode in question, before the request callback is even invoked. The request callback is what (eventually) invokes iterative_io_finished_hook, which meant that we were accessing the Inode object after our reference to it had already been released. We can't really change IORequest notification order, as any one of the notifications could delete the request, and indeed the first one does here. So the solution is just to acquire another reference to the vnode and release it in the finished hook. Fixes #19122 and #8405. --- src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp index c240187cfb..381293805e 100644 --- a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp @@ -113,6 +113,7 @@ iterative_io_finished_hook(void* cookie, io_request* request, status_t status, { Inode* inode = (Inode*)cookie; rw_lock_read_unlock(&inode->Lock()); + put_vnode(inode->GetVolume()->FSVolume(), inode->ID()); return B_OK; } @@ -522,6 +523,12 @@ bfs_io(fs_volume* _volume, fs_vnode* _node, void* _cookie, io_request* request) // We lock the node here and will unlock it in the "finished" hook. rw_lock_read_lock(&inode->Lock()); + // Due to how I/O request notifications work, it is possible that + // some other thread could be notified that the request completed + // before we have a chance to release the read lock. We thus need + // our own reference to the vnode. + acquire_vnode(_volume, inode->ID()); + return do_iterative_fd_io(volume->Device(), request, iterative_io_get_vecs_hook, iterative_io_finished_hook, inode); }