Libc: wrap VFS sync's in VFS_THREAD_SAFE

Move the _vfs_sync implementation from vfs_plugin.h to vfs_plugin.cc and
wrap all VFS access in the VFS_THREAD_SAFE macro.

Syncing must be made thread safe because it often happens when closing
files and may require suspending the current thread for I/O signal
dispatching.

Ref #3409
This commit is contained in:
Emery Hemingway 2019-06-06 12:27:46 +02:00 committed by Christian Helmuth
parent c055986e38
commit 43315444a8
2 changed files with 77 additions and 74 deletions

View File

@ -229,7 +229,7 @@ Libc::File_descriptor *Libc::Vfs_plugin::open(char const *path, int flags,
/* FIXME error cleanup code leaks resources! */
if (!fd) {
handle->close();
VFS_THREAD_SAFE(handle->close());
errno = EMFILE;
return nullptr;
}
@ -310,7 +310,7 @@ Libc::File_descriptor *Libc::Vfs_plugin::open(char const *path, int flags,
/* FIXME error cleanup code leaks resources! */
if (!fd) {
handle->close();
VFS_THREAD_SAFE(handle->close());
errno = EMFILE;
return nullptr;
}
@ -319,7 +319,7 @@ Libc::File_descriptor *Libc::Vfs_plugin::open(char const *path, int flags,
fd->flags = flags & (O_ACCMODE|O_NONBLOCK|O_APPEND);
if ((flags & O_TRUNC) && (ftruncate(fd, 0) == -1)) {
handle->close();
VFS_THREAD_SAFE(handle->close());
errno = EINVAL; /* XXX which error code fits best ? */
return nullptr;
}
@ -328,11 +328,79 @@ Libc::File_descriptor *Libc::Vfs_plugin::open(char const *path, int flags,
}
int Libc::Vfs_plugin::_vfs_sync(Vfs::Vfs_handle &vfs_handle)
{
typedef Vfs::File_io_service::Sync_result Result;
Result result = Result::SYNC_QUEUED;
{
struct Check : Libc::Suspend_functor
{
bool retry { false };
Vfs::Vfs_handle &vfs_handle;
Check(Vfs::Vfs_handle &vfs_handle)
: vfs_handle(vfs_handle) { }
bool suspend() override
{
retry = !VFS_THREAD_SAFE(vfs_handle.fs().queue_sync(&vfs_handle));
return retry;
}
} check(vfs_handle);
/*
* Cannot call Libc::suspend() immediately, because the Libc kernel
* might not be running yet.
*/
if (!VFS_THREAD_SAFE(vfs_handle.fs().queue_sync(&vfs_handle))) {
do {
Libc::suspend(check);
} while (check.retry);
}
}
{
struct Check : Libc::Suspend_functor
{
bool retry { false };
Vfs::Vfs_handle &vfs_handle;
Result &result;
Check(Vfs::Vfs_handle &vfs_handle, Result &result)
: vfs_handle(vfs_handle), result(result) { }
bool suspend() override
{
result = VFS_THREAD_SAFE(vfs_handle.fs().complete_sync(&vfs_handle));
retry = result == Vfs::File_io_service::SYNC_QUEUED;
return retry;
}
} check(vfs_handle, result);
/*
* Cannot call Libc::suspend() immediately, because the Libc kernel
* might not be running yet.
*/
result = VFS_THREAD_SAFE(vfs_handle.fs().complete_sync(&vfs_handle));
if (result == Result::SYNC_QUEUED) {
do {
Libc::suspend(check);
} while (check.retry);
}
}
return result == Result::SYNC_OK ? 0 : Libc::Errno(EIO);
}
int Libc::Vfs_plugin::close(Libc::File_descriptor *fd)
{
Vfs::Vfs_handle *handle = vfs_handle(fd);
/* XXX: mark the handle as requiring sync or not */
_vfs_sync(handle);
_vfs_sync(*handle);
VFS_THREAD_SAFE(handle->close());
Libc::file_descriptor_allocator()->free(fd);
return 0;
@ -350,7 +418,7 @@ int Libc::Vfs_plugin::dup2(Libc::File_descriptor *fd,
int Libc::Vfs_plugin::fstat(Libc::File_descriptor *fd, struct stat *buf)
{
Vfs::Vfs_handle *handle = vfs_handle(fd);
_vfs_sync(handle);
_vfs_sync(*handle);
return stat(fd->fd_path, buf);
}
@ -884,7 +952,7 @@ int Libc::Vfs_plugin::ioctl(Libc::File_descriptor *fd, int request, char *argp)
int Libc::Vfs_plugin::ftruncate(Libc::File_descriptor *fd, ::off_t length)
{
Vfs::Vfs_handle *handle = vfs_handle(fd);
_vfs_sync(handle);
_vfs_sync(*handle);
typedef Vfs::File_io_service::Ftruncate_result Result;
@ -942,7 +1010,7 @@ int Libc::Vfs_plugin::fcntl(Libc::File_descriptor *fd, int cmd, long arg)
int Libc::Vfs_plugin::fsync(Libc::File_descriptor *fd)
{
Vfs::Vfs_handle *handle = vfs_handle(fd);
return _vfs_sync(handle);
return _vfs_sync(*handle);
}
@ -1014,7 +1082,7 @@ int Libc::Vfs_plugin::symlink(const char *oldpath, const char *newpath)
/* wake up threads blocking for 'queue_*()' or 'write()' */
Libc::resume_all();
_vfs_sync(handle);
_vfs_sync(*handle);
VFS_THREAD_SAFE(handle->close());
if (out_count != count)

View File

@ -81,72 +81,7 @@ class Libc::Vfs_plugin : public Libc::Plugin
/**
* Sync a handle and propagate errors
*/
int _vfs_sync(Vfs::Vfs_handle *vfs_handle)
{
typedef Vfs::File_io_service::Sync_result Result;
Result result = Result::SYNC_QUEUED;
{
struct Check : Libc::Suspend_functor
{
bool retry { false };
Vfs::Vfs_handle *vfs_handle;
Check(Vfs::Vfs_handle *vfs_handle)
: vfs_handle(vfs_handle) { }
bool suspend() override
{
retry = !vfs_handle->fs().queue_sync(vfs_handle);
return retry;
}
} check(vfs_handle);
/*
* Cannot call Libc::suspend() immediately, because the Libc kernel
* might not be running yet.
*/
if (!vfs_handle->fs().queue_sync(vfs_handle)) {
do {
Libc::suspend(check);
} while (check.retry);
}
}
{
struct Check : Libc::Suspend_functor
{
bool retry { false };
Vfs::Vfs_handle *vfs_handle;
Result &result;
Check(Vfs::Vfs_handle *vfs_handle, Result &result)
: vfs_handle(vfs_handle), result(result) { }
bool suspend() override
{
result = vfs_handle->fs().complete_sync(vfs_handle);
retry = result == Vfs::File_io_service::SYNC_QUEUED;
return retry;
}
} check(vfs_handle, result);
/*
* Cannot call Libc::suspend() immediately, because the Libc kernel
* might not be running yet.
*/
result = vfs_handle->fs().complete_sync(vfs_handle);
if (result == Result::SYNC_QUEUED) {
do {
Libc::suspend(check);
} while (check.retry);
}
}
return result == Result::SYNC_OK ? 0 : Libc::Errno(EIO);
}
int _vfs_sync(Vfs::Vfs_handle&);
public: