mirror of
https://github.com/genodelabs/genode.git
synced 2025-05-29 21:54:27 +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! */
|
/* FIXME error cleanup code leaks resources! */
|
||||||
|
|
||||||
if (!fd) {
|
if (!fd) {
|
||||||
handle->close();
|
VFS_THREAD_SAFE(handle->close());
|
||||||
errno = EMFILE;
|
errno = EMFILE;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -310,7 +310,7 @@ Libc::File_descriptor *Libc::Vfs_plugin::open(char const *path, int flags,
|
|||||||
/* FIXME error cleanup code leaks resources! */
|
/* FIXME error cleanup code leaks resources! */
|
||||||
|
|
||||||
if (!fd) {
|
if (!fd) {
|
||||||
handle->close();
|
VFS_THREAD_SAFE(handle->close());
|
||||||
errno = EMFILE;
|
errno = EMFILE;
|
||||||
return nullptr;
|
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);
|
fd->flags = flags & (O_ACCMODE|O_NONBLOCK|O_APPEND);
|
||||||
|
|
||||||
if ((flags & O_TRUNC) && (ftruncate(fd, 0) == -1)) {
|
if ((flags & O_TRUNC) && (ftruncate(fd, 0) == -1)) {
|
||||||
handle->close();
|
VFS_THREAD_SAFE(handle->close());
|
||||||
errno = EINVAL; /* XXX which error code fits best ? */
|
errno = EINVAL; /* XXX which error code fits best ? */
|
||||||
return nullptr;
|
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)
|
int Libc::Vfs_plugin::close(Libc::File_descriptor *fd)
|
||||||
{
|
{
|
||||||
Vfs::Vfs_handle *handle = vfs_handle(fd);
|
Vfs::Vfs_handle *handle = vfs_handle(fd);
|
||||||
/* XXX: mark the handle as requiring sync or not */
|
/* XXX: mark the handle as requiring sync or not */
|
||||||
_vfs_sync(handle);
|
_vfs_sync(*handle);
|
||||||
VFS_THREAD_SAFE(handle->close());
|
VFS_THREAD_SAFE(handle->close());
|
||||||
Libc::file_descriptor_allocator()->free(fd);
|
Libc::file_descriptor_allocator()->free(fd);
|
||||||
return 0;
|
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)
|
int Libc::Vfs_plugin::fstat(Libc::File_descriptor *fd, struct stat *buf)
|
||||||
{
|
{
|
||||||
Vfs::Vfs_handle *handle = vfs_handle(fd);
|
Vfs::Vfs_handle *handle = vfs_handle(fd);
|
||||||
_vfs_sync(handle);
|
_vfs_sync(*handle);
|
||||||
return stat(fd->fd_path, buf);
|
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)
|
int Libc::Vfs_plugin::ftruncate(Libc::File_descriptor *fd, ::off_t length)
|
||||||
{
|
{
|
||||||
Vfs::Vfs_handle *handle = vfs_handle(fd);
|
Vfs::Vfs_handle *handle = vfs_handle(fd);
|
||||||
_vfs_sync(handle);
|
_vfs_sync(*handle);
|
||||||
|
|
||||||
typedef Vfs::File_io_service::Ftruncate_result Result;
|
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)
|
int Libc::Vfs_plugin::fsync(Libc::File_descriptor *fd)
|
||||||
{
|
{
|
||||||
Vfs::Vfs_handle *handle = vfs_handle(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()' */
|
/* wake up threads blocking for 'queue_*()' or 'write()' */
|
||||||
Libc::resume_all();
|
Libc::resume_all();
|
||||||
|
|
||||||
_vfs_sync(handle);
|
_vfs_sync(*handle);
|
||||||
VFS_THREAD_SAFE(handle->close());
|
VFS_THREAD_SAFE(handle->close());
|
||||||
|
|
||||||
if (out_count != count)
|
if (out_count != count)
|
||||||
|
@ -81,72 +81,7 @@ class Libc::Vfs_plugin : public Libc::Plugin
|
|||||||
/**
|
/**
|
||||||
* Sync a handle and propagate errors
|
* Sync a handle and propagate errors
|
||||||
*/
|
*/
|
||||||
int _vfs_sync(Vfs::Vfs_handle *vfs_handle)
|
int _vfs_sync(Vfs::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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user