libc: sync socket control files to check for write errors

Ref #2335
This commit is contained in:
Emery Hemingway 2017-12-12 17:32:49 -06:00 committed by Christian Helmuth
parent 8dda68a1bd
commit 88757a674a
3 changed files with 37 additions and 21 deletions

View File

@ -82,6 +82,8 @@ namespace Socket_fs {
struct Local_functor;
Plugin & plugin();
enum { MAX_CONTROL_PATH_LEN = 16 };
}
@ -447,7 +449,7 @@ extern "C" int socket_fs_accept(int libc_fd, sockaddr *addr, socklen_t *addrlen)
/* TODO EOPNOTSUPP - no SOCK_STREAM */
/* TODO ECONNABORTED */
char accept_socket[10];
char accept_socket[MAX_CONTROL_PATH_LEN];
{
int n = 0;
/* XXX currently reading accept may return without new connection */
@ -503,8 +505,9 @@ extern "C" int socket_fs_bind(int libc_fd, sockaddr const *addr, socklen_t addrl
int const len = strlen(addr_string.base());
int const n = write(context->bind_fd(), addr_string.base(), len);
if (n != len) return Errno(EACCES);
fsync(context->bind_fd());
return 0;
/* sync to block for write completion */
return fsync(context->bind_fd());
} catch (Socket_fs::Context::Inaccessible) {
return Errno(EINVAL);
}
@ -537,7 +540,8 @@ extern "C" int socket_fs_connect(int libc_fd, sockaddr const *addr, socklen_t ad
int const n = write(context->connect_fd(), addr_string.base(), len);
if (n != len) return Errno(ECONNREFUSED);
return 0;
/* sync to block for write completion */
return fsync(context->connect_fd());
}
@ -549,7 +553,7 @@ extern "C" int socket_fs_listen(int libc_fd, int backlog)
Socket_fs::Context *context = dynamic_cast<Socket_fs::Context *>(fd->context);
if (!context) return Errno(ENOTSOCK);
char buf[10];
char buf[MAX_CONTROL_PATH_LEN];
int const len = snprintf(buf, sizeof(buf), "%d", backlog);
int const n = write(context->listen_fd(), buf, len);
if (n != len) return Errno(EOPNOTSUPP);
@ -742,23 +746,23 @@ extern "C" int socket_fs_shutdown(int libc_fd, int how)
}
static Genode::String<16> new_socket(Absolute_path const &path)
static Genode::String<MAX_CONTROL_PATH_LEN> new_socket(Absolute_path const &path)
{
Absolute_path new_socket("new_socket", path.base());
int const fd = open(new_socket.base(), O_RDONLY);
if (fd == -1) {
Genode::error(__func__, ": new_socket file not accessible - socket fs not mounted?");
Genode::error(__func__, ": ", new_socket, " file not accessible - socket fs not mounted?");
throw New_socket_failed();
}
char buf[10];
char buf[MAX_CONTROL_PATH_LEN];
int const n = read(fd, buf, sizeof(buf));
close(fd);
if (n == -1 || !n || n >= (int)sizeof(buf) - 1)
throw New_socket_failed();
buf[n] = 0;
return Genode::String<16>(buf);
return Genode::String<MAX_CONTROL_PATH_LEN>(buf);
}
@ -789,7 +793,7 @@ extern "C" int socket_fs_socket(int domain, int type, int protocol)
case Proto::UDP: proto_path.append("/udp"); break;
}
Genode::String<16> socket_path = new_socket(proto_path);
auto socket_path = new_socket(proto_path);
path.append("/");
path.append(socket_path.string());
} catch (New_socket_failed) { return Errno(EACCES); }

View File

@ -884,8 +884,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);
_vfs_sync(handle);
return 0;
return _vfs_sync(handle);
}

View File

@ -18,7 +18,6 @@
/* Genode includes */
#include <libc/component.h>
#include "task.h"
/* libc includes */
#include <fcntl.h>
@ -28,6 +27,11 @@
#include <libc-plugin/plugin.h>
#include <libc-plugin/fd_alloc.h>
/* local includes */
#include "task.h"
#include "libc_errno.h"
namespace Libc { class Vfs_plugin; }
@ -76,8 +80,14 @@ class Libc::Vfs_plugin : public Libc::Plugin
}
}
void _vfs_sync(Vfs::Vfs_handle *vfs_handle)
/**
* 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
{
@ -112,29 +122,32 @@ class Libc::Vfs_plugin : public Libc::Plugin
bool retry { false };
Vfs::Vfs_handle *vfs_handle;
Result &result;
Check(Vfs::Vfs_handle *vfs_handle)
: vfs_handle(vfs_handle) { }
Check(Vfs::Vfs_handle *vfs_handle, Result &result)
: vfs_handle(vfs_handle), result(result) { }
bool suspend() override
{
retry = (vfs_handle->fs().complete_sync(vfs_handle) ==
Vfs::File_io_service::SYNC_QUEUED);
result = vfs_handle->fs().complete_sync(vfs_handle);
retry = result == Vfs::File_io_service::SYNC_QUEUED;
return retry;
}
} check(vfs_handle);
} check(vfs_handle, result);
/*
* Cannot call Libc::suspend() immediately, because the Libc kernel
* might not be running yet.
*/
if (vfs_handle->fs().complete_sync(vfs_handle) ==
Vfs::File_io_service::SYNC_QUEUED) {
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: