mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 18:56:29 +00:00
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:
parent
c055986e38
commit
43315444a8
@ -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)
|
||||
|
@ -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:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user