mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 18:56:29 +00:00
parent
a89d61acf2
commit
36b6ebc030
@ -64,7 +64,7 @@ namespace Libc {
|
||||
/**
|
||||
* Virtual file system
|
||||
*/
|
||||
void init_vfs_plugin(Suspend &);
|
||||
void init_vfs_plugin(Monitor &);
|
||||
void init_file_operations(Cwd &);
|
||||
|
||||
/**
|
||||
|
@ -282,8 +282,7 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
|
||||
|
||||
void _monitors_handler()
|
||||
{
|
||||
_execute_monitors_pending = false;
|
||||
_monitors.execute_monitors();
|
||||
/* used to leave I/O-signal dispatcher only - handled afterwards */
|
||||
}
|
||||
|
||||
Constructible<Clone_connection> _clone_connection { };
|
||||
@ -452,6 +451,13 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
|
||||
_switch_to_user();
|
||||
}
|
||||
|
||||
if (_execute_monitors_pending) {
|
||||
|
||||
_execute_monitors_pending = false;
|
||||
_monitors.execute_monitors();
|
||||
|
||||
} else {
|
||||
|
||||
if (_dispatch_pending_io_signals) {
|
||||
/* dispatch pending signals but don't block */
|
||||
while (_env.ep().dispatch_pending_io_signal()) ;
|
||||
@ -460,6 +466,7 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
|
||||
_env.ep().wait_and_dispatch_one_io_signal();
|
||||
handle_io_progress();
|
||||
}
|
||||
}
|
||||
|
||||
if (!_kernel_routine && _resume_main_once && !_setjmp(_kernel_context))
|
||||
_switch_to_user();
|
||||
@ -562,6 +569,7 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
|
||||
{
|
||||
if (!_execute_monitors_pending) {
|
||||
_execute_monitors_pending = true;
|
||||
if (!_main_context())
|
||||
Signal_transmitter(*_execute_monitors).submit();
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,8 @@ namespace Libc {
|
||||
|
||||
virtual void deschedule_select() = 0;
|
||||
};
|
||||
|
||||
void select_notify_from_kernel();
|
||||
}
|
||||
|
||||
#endif /* _LIBC__INTERNAL__SELECT_H_ */
|
||||
|
@ -81,9 +81,9 @@ class Libc::Vfs_plugin : public Plugin
|
||||
bool const _pipe_configured;
|
||||
|
||||
/**
|
||||
* Sync a handle and propagate errors
|
||||
* Sync a handle
|
||||
*/
|
||||
int _vfs_sync(Vfs::Vfs_handle&);
|
||||
void _vfs_sync(Vfs::Vfs_handle&);
|
||||
|
||||
/**
|
||||
* Update modification time
|
||||
@ -158,12 +158,11 @@ class Libc::Vfs_plugin : public Plugin
|
||||
fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||
struct timeval *timeout) override;
|
||||
|
||||
File_descriptor *open(const char *, int, int libc_fd);
|
||||
|
||||
File_descriptor *open(const char *path, int flags) override
|
||||
{
|
||||
return open(path, flags, ANY_FD);
|
||||
}
|
||||
/* kernel-specific API without monitor */
|
||||
File_descriptor *open_from_kernel(const char *, int, int libc_fd);
|
||||
int close_from_kernel(File_descriptor *);
|
||||
::off_t lseek_from_kernel(File_descriptor *fd, ::off_t offset);
|
||||
int stat_from_kernel(const char *, struct stat *);
|
||||
|
||||
int access(char const *, int) override;
|
||||
int close(File_descriptor *) override;
|
||||
@ -178,6 +177,7 @@ class Libc::Vfs_plugin : public Plugin
|
||||
int ioctl(File_descriptor *, int , char *) override;
|
||||
::off_t lseek(File_descriptor *fd, ::off_t offset, int whence) override;
|
||||
int mkdir(const char *, mode_t) override;
|
||||
File_descriptor *open(const char *path, int flags) override;
|
||||
int pipe(File_descriptor *pipefdo[2]) override;
|
||||
bool poll(File_descriptor &fdo, struct pollfd &pfd) override;
|
||||
ssize_t read(File_descriptor *, void *, ::size_t) override;
|
||||
|
@ -116,27 +116,137 @@ void Libc::Kernel::reset_malloc_heap()
|
||||
|
||||
void Libc::Kernel::_init_file_descriptors()
|
||||
{
|
||||
/**
|
||||
* path element token
|
||||
*/
|
||||
struct Scanner_policy_path_element
|
||||
{
|
||||
static bool identifier_char(char c, unsigned /* i */)
|
||||
{
|
||||
return (c != '/') && (c != 0);
|
||||
}
|
||||
};
|
||||
typedef Genode::Token<Scanner_policy_path_element> Path_element_token;
|
||||
|
||||
auto resolve_symlinks = [&] (Absolute_path next_iteration_working_path, Absolute_path &resolved_path)
|
||||
{
|
||||
char path_element[PATH_MAX];
|
||||
char symlink_target[PATH_MAX];
|
||||
|
||||
Absolute_path current_iteration_working_path;
|
||||
|
||||
enum { FOLLOW_LIMIT = 10 };
|
||||
int follow_count = 0;
|
||||
bool symlink_resolved_in_this_iteration;
|
||||
do {
|
||||
if (follow_count++ == FOLLOW_LIMIT) {
|
||||
errno = ELOOP;
|
||||
throw Symlink_resolve_error();
|
||||
}
|
||||
|
||||
current_iteration_working_path = next_iteration_working_path;
|
||||
|
||||
next_iteration_working_path.import("");
|
||||
symlink_resolved_in_this_iteration = false;
|
||||
|
||||
Path_element_token t(current_iteration_working_path.base());
|
||||
|
||||
while (t) {
|
||||
if (t.type() != Path_element_token::IDENT) {
|
||||
t = t.next();
|
||||
continue;
|
||||
}
|
||||
|
||||
t.string(path_element, sizeof(path_element));
|
||||
|
||||
try {
|
||||
next_iteration_working_path.append_element(path_element);
|
||||
} catch (Path_base::Path_too_long) {
|
||||
errno = ENAMETOOLONG;
|
||||
throw Symlink_resolve_error();
|
||||
}
|
||||
|
||||
/*
|
||||
* If a symlink has been resolved in this iteration, the remaining
|
||||
* path elements get added and a new iteration starts.
|
||||
*/
|
||||
if (!symlink_resolved_in_this_iteration) {
|
||||
struct stat stat_buf;
|
||||
int res = _vfs.stat_from_kernel(next_iteration_working_path.base(), &stat_buf);
|
||||
if (res == -1) {
|
||||
throw Symlink_resolve_error();
|
||||
}
|
||||
if (S_ISLNK(stat_buf.st_mode)) {
|
||||
res = readlink(next_iteration_working_path.base(),
|
||||
symlink_target, sizeof(symlink_target) - 1);
|
||||
if (res < 1)
|
||||
throw Symlink_resolve_error();
|
||||
|
||||
/* zero terminate target */
|
||||
symlink_target[res] = 0;
|
||||
|
||||
if (symlink_target[0] == '/')
|
||||
/* absolute target */
|
||||
next_iteration_working_path.import(symlink_target, _cwd.base());
|
||||
else {
|
||||
/* relative target */
|
||||
next_iteration_working_path.strip_last_element();
|
||||
try {
|
||||
next_iteration_working_path.append_element(symlink_target);
|
||||
} catch (Path_base::Path_too_long) {
|
||||
errno = ENAMETOOLONG;
|
||||
throw Symlink_resolve_error();
|
||||
}
|
||||
}
|
||||
symlink_resolved_in_this_iteration = true;
|
||||
}
|
||||
}
|
||||
|
||||
t = t.next();
|
||||
}
|
||||
|
||||
} while (symlink_resolved_in_this_iteration);
|
||||
|
||||
resolved_path = next_iteration_working_path;
|
||||
resolved_path.remove_trailing('/');
|
||||
};
|
||||
|
||||
typedef String<Vfs::MAX_PATH_LEN> Path;
|
||||
|
||||
auto resolve_absolute_path = [&] (Path const &path)
|
||||
{
|
||||
Absolute_path abs_path { };
|
||||
Absolute_path abs_dir(path.string(), _cwd.base()); abs_dir.strip_last_element();
|
||||
Absolute_path dir_entry(path.string(), _cwd.base()); dir_entry.keep_only_last_element();
|
||||
|
||||
try {
|
||||
resolve_symlinks(abs_dir, abs_path);
|
||||
abs_path.append_element(dir_entry.string());
|
||||
return abs_path;
|
||||
} catch (Path_base::Path_too_long) { return Absolute_path(); }
|
||||
};
|
||||
|
||||
auto init_fd = [&] (Xml_node const &node, char const *attr,
|
||||
int libc_fd, unsigned flags)
|
||||
{
|
||||
if (!node.has_attribute(attr))
|
||||
return;
|
||||
|
||||
typedef String<Vfs::MAX_PATH_LEN> Path;
|
||||
Path const path = node.attribute_value(attr, Path());
|
||||
Absolute_path const path {
|
||||
resolve_absolute_path(node.attribute_value(attr, Path())) };
|
||||
|
||||
struct stat out_stat { };
|
||||
if (stat(path.string(), &out_stat) != 0)
|
||||
if (_vfs.stat_from_kernel(path.string(), &out_stat) != 0)
|
||||
return;
|
||||
|
||||
File_descriptor *fd = _vfs.open(path.string(), flags, libc_fd);
|
||||
File_descriptor *fd = _vfs.open_from_kernel(path.string(), flags, libc_fd);
|
||||
if (!fd)
|
||||
return;
|
||||
|
||||
if (fd->libc_fd != libc_fd) {
|
||||
error("could not allocate fd ",libc_fd," for ",path,", "
|
||||
"got fd ",fd->libc_fd);
|
||||
_vfs.close(fd);
|
||||
_vfs.close_from_kernel(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -151,14 +261,14 @@ void Libc::Kernel::_init_file_descriptors()
|
||||
warning("may leak former FD path memory");
|
||||
|
||||
{
|
||||
char *dst = (char *)_heap.alloc(path.length());
|
||||
copy_cstring(dst, path.string(), path.length());
|
||||
char *dst = (char *)_heap.alloc(path.max_len());
|
||||
copy_cstring(dst, path.string(), path.max_len());
|
||||
fd->fd_path = dst;
|
||||
}
|
||||
|
||||
::off_t const seek = node.attribute_value("seek", 0ULL);
|
||||
if (seek)
|
||||
_vfs.lseek(fd, seek, SEEK_SET);
|
||||
_vfs.lseek_from_kernel(fd, seek);
|
||||
};
|
||||
|
||||
if (_vfs.root_dir_has_dirents()) {
|
||||
@ -323,11 +433,16 @@ void Libc::Kernel::_clone_state_from_parent()
|
||||
}
|
||||
|
||||
|
||||
extern void (*libc_select_notify)();
|
||||
extern void (*libc_select_notify_from_kernel)();
|
||||
|
||||
|
||||
void Libc::Kernel::handle_io_progress()
|
||||
{
|
||||
if (_execute_monitors_pending) {
|
||||
_execute_monitors_pending = false;
|
||||
_monitors.execute_monitors();
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: make VFS I/O completion checks during
|
||||
* kernel time to avoid flapping between stacks
|
||||
@ -337,14 +452,14 @@ void Libc::Kernel::handle_io_progress()
|
||||
_io_ready = false;
|
||||
|
||||
/* some contexts may have been deblocked from select() */
|
||||
if (libc_select_notify)
|
||||
libc_select_notify();
|
||||
select_notify_from_kernel();
|
||||
|
||||
/*
|
||||
* resume all as any VFS context may have
|
||||
* been deblocked from blocking I/O
|
||||
*/
|
||||
Kernel::resume_all();
|
||||
_monitors.execute_monitors();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <signal.h>
|
||||
|
||||
/* libc-internal includes */
|
||||
#include <internal/kernel.h>
|
||||
#include <internal/init.h>
|
||||
#include <internal/signal.h>
|
||||
#include <internal/suspend.h>
|
||||
@ -207,7 +208,7 @@ static int selscan(int nfds,
|
||||
|
||||
|
||||
/* this function gets called by plugin backends when file descripors become ready */
|
||||
static void select_notify()
|
||||
void Libc::select_notify_from_kernel()
|
||||
{
|
||||
bool resume_all = false;
|
||||
fd_set tmp_readfds, tmp_writefds, tmp_exceptfds;
|
||||
@ -260,40 +261,35 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||
|
||||
Constructible<Select_cb> select_cb;
|
||||
|
||||
/* initialize the select notification function pointer */
|
||||
if (!libc_select_notify)
|
||||
libc_select_notify = select_notify;
|
||||
|
||||
if (readfds) in_readfds = *readfds; else FD_ZERO(&in_readfds);
|
||||
if (writefds) in_writefds = *writefds; else FD_ZERO(&in_writefds);
|
||||
if (exceptfds) in_exceptfds = *exceptfds; else FD_ZERO(&in_exceptfds);
|
||||
|
||||
{
|
||||
/*
|
||||
* We use the guard directly to atomically check if any descripor is
|
||||
* ready, but insert into select-callback list otherwise.
|
||||
* Insert callback first to avoid race after 'selscan()'
|
||||
*/
|
||||
Select_cb_list::Guard guard(select_cb_list());
|
||||
|
||||
select_cb.construct(nfds, in_readfds, in_writefds, in_exceptfds);
|
||||
select_cb_list().insert(&(*select_cb));
|
||||
|
||||
int const nready = selscan(nfds,
|
||||
&in_readfds, &in_writefds, &in_exceptfds,
|
||||
readfds, writefds, exceptfds);
|
||||
|
||||
/* return if any descripor is ready */
|
||||
if (nready)
|
||||
if (nready) {
|
||||
select_cb_list().remove(&(*select_cb));
|
||||
return nready;
|
||||
}
|
||||
|
||||
/* return on zero-timeout */
|
||||
if (tv && (tv->tv_sec) == 0 && (tv->tv_usec == 0))
|
||||
if (tv && (tv->tv_sec) == 0 && (tv->tv_usec == 0)) {
|
||||
select_cb_list().remove(&(*select_cb));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* suspend as we don't have any immediate events */
|
||||
|
||||
select_cb.construct(nfds, in_readfds, in_writefds, in_exceptfds);
|
||||
|
||||
select_cb_list().unsynchronized_insert(&(*select_cb));
|
||||
}
|
||||
|
||||
struct Timeout
|
||||
{
|
||||
timeval const *_tv;
|
||||
@ -352,7 +348,7 @@ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||
if (signal_occurred_during_select())
|
||||
return Errno(EINTR);
|
||||
|
||||
/* not timed out -> results have been stored in select_cb by select_notify() */
|
||||
/* not timed out -> results have been stored in select_cb by select_notify_from_kernel() */
|
||||
|
||||
if (readfds) *readfds = select_cb->readfds;
|
||||
if (writefds) *writefds = select_cb->writefds;
|
||||
@ -410,10 +406,6 @@ int Libc::Select_handler_base::select(int nfds, fd_set &readfds,
|
||||
{
|
||||
fd_set in_readfds, in_writefds, in_exceptfds;
|
||||
|
||||
/* initialize the select notification function pointer */
|
||||
if (!libc_select_notify)
|
||||
libc_select_notify = select_notify;
|
||||
|
||||
in_readfds = readfds;
|
||||
in_writefds = writefds;
|
||||
in_exceptfds = exceptfds;
|
||||
@ -424,7 +416,7 @@ int Libc::Select_handler_base::select(int nfds, fd_set &readfds,
|
||||
|
||||
{
|
||||
/*
|
||||
* We use the guard directly to atomically check is any descripor is
|
||||
* We use the guard directly to atomically check if any descripor is
|
||||
* ready, and insert into select-callback list otherwise.
|
||||
*/
|
||||
Select_cb_list::Guard guard(select_cb_list());
|
||||
|
@ -46,7 +46,7 @@
|
||||
|
||||
namespace Libc {
|
||||
extern char const *config_socket();
|
||||
bool read_ready(File_descriptor *);
|
||||
bool read_ready_from_kernel(File_descriptor *);
|
||||
}
|
||||
|
||||
|
||||
@ -180,7 +180,7 @@ struct Libc::Socket_fs::Context : Plugin_context
|
||||
bool _fd_read_ready(Fd type)
|
||||
{
|
||||
if (_fd[type].file)
|
||||
return Libc::read_ready(_fd[type].file);
|
||||
return Libc::read_ready_from_kernel(_fd[type].file);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user