Remove rump_fs server component

This patch replaces the use of the rump_fs server by the VFS server with
the Rump VFS plugin.

Issue #3512
This commit is contained in:
Norman Feske 2019-10-07 16:12:41 +02:00 committed by Christian Helmuth
parent 6e86d6d699
commit a8dd7dd2fa
17 changed files with 47 additions and 1717 deletions

View File

@ -14,7 +14,7 @@ PORT_DIR := $(call port_dir,$(REP_DIR)/ports/dde_rump)
MIRROR_FROM_REP_DIR := $(LIB_MK) \
lib/import/import-rump.mk \
src/lib src/server/rump_fs \
src/lib \
include/rump include/rump_fs \
include/util

View File

@ -14,7 +14,8 @@ set dd [installed_command dd]
set build_components {
core init timer
server/ram_block
server/rump_fs
server/vfs
lib/vfs/rump
test/libc_vfs
}
@ -56,10 +57,13 @@ append config {
<provides><service name="Block"/></provides>
<config file="ext2.raw" block_size="512"/>
</start>
<start name="rump_fs" caps="200">
<start name="vfs" caps="200">
<resource name="RAM" quantum="16M" />
<provides><service name="File_system"/></provides>
<config fs="ext2fs"><policy label_prefix="test-libc_vfs" root="/" writeable="yes"/></config>
<config>
<vfs> <rump fs="ext2fs" ram="10M"/> </vfs>
<policy label_prefix="test-libc_vfs" root="/" writeable="yes"/>
</config>
</start>
<start name="test-libc_vfs">
<resource name="RAM" quantum="4M"/>
@ -82,7 +86,7 @@ install_config $config
# generic modules
set boot_modules {
core ld.lib.so init timer test-libc_vfs ram_block
rump.lib.so rump_fs.lib.so rump_fs
rump.lib.so rump_fs.lib.so vfs vfs_rump.lib.so
ext2.raw libc.lib.so vfs.lib.so
}

View File

@ -14,7 +14,8 @@ set dd [installed_command dd]
set build_components {
core init timer
server/ram_block
server/rump_fs
server/vfs
lib/vfs/rump
test/libc_vfs
}
@ -56,20 +57,24 @@ append config {
<provides><service name="Block"/></provides>
<config file="fs.raw" block_size="512"/>
</start>
<start name="rump_fs" caps="200">
<start name="vfs" caps="200">
<resource name="RAM" quantum="10M" />
<provides><service name="File_system"/></provides>
<config fs="msdos"><default-policy root="/" writeable="yes"/></config>
<config>
<vfs>
<rump fs="msdos" ram="8M"/>
</vfs>
<default-policy root="/" writeable="yes"/>
</config>
</start>
<start name="test-libc_vfs">
<resource name="RAM" quantum="4M"/>
<config>
<libc stdout="/dev/log">
<vfs>
<dir name="dev"> <log/> </dir>
<fs/>
</vfs>
</libc>
<libc stdout="/dev/log"/>
<vfs>
<dir name="dev"> <log/> </dir>
<fs/>
</vfs>
</config>
</start>
</config>}
@ -83,7 +88,7 @@ install_config $config
# generic modules
set boot_modules {
core ld.lib.so init timer test-libc_vfs ram_block
rump.lib.so rump_fs.lib.so rump_fs
rump.lib.so rump_fs.lib.so vfs vfs_rump.lib.so
fs.raw libc.lib.so vfs.lib.so
}

View File

@ -14,7 +14,8 @@ set build_components {
core init timer
server/fs_rom
server/rom_block
server/rump_fs
server/vfs
lib/vfs/rump
test/iso
}
@ -49,10 +50,13 @@ append config {
<provides><service name="Block"/></provides>
<config file="fs.iso" block_size="2048"/>
</start>
<start name="rump_fs" caps="200">
<resource name="RAM" quantum="10M" />
<start name="vfs" caps="200">
<resource name="RAM" quantum="12M" />
<provides><service name="File_system"/></provides>
<config fs="cd9660"><policy label_prefix="fs_rom" root="/" writeable="no"/></config>
<config>
<vfs> <rump fs="cd9660" ram="10M" writeable="no"/> </vfs>
<policy label_prefix="fs_rom" root="/" writeable="no"/>
</config>
</start>
<start name="fs_rom">
<resource name="RAM" quantum="2M"/>
@ -88,7 +92,7 @@ install_config $config
#
set boot_modules {
core ld.lib.so init timer test-iso rom_block
rump.lib.so rump_fs.lib.so rump_fs
rump.lib.so rump_fs.lib.so vfs_rump.lib.so vfs vfs.lib.so
fs.iso fs_rom
}

View File

@ -10,7 +10,7 @@
set mke2fs [installed_command mke2fs]
set dd [installed_command dd]
build "core init timer test/vfs_stress server/ram_block server/rump_fs"
build "core init timer test/vfs_stress server/ram_block server/vfs lib/vfs/rump"
#
# Build EXT2-file-system image
@ -50,10 +50,11 @@ install_config {
<provides><service name="Block"/></provides>
<config file="ext2.raw" block_size="512"/>
</start>
<start name="rump_fs" caps="200">
<start name="vfs" caps="200">
<resource name="RAM" quantum="24M"/>
<provides> <service name="File_system"/> </provides>
<config fs="ext2fs">
<config>
<vfs> <rump fs="ext2fs" ram="20M"/> </vfs>
<default-policy root="/" writeable="yes"/>
</config>
</start>
@ -62,7 +63,7 @@ install_config {
set boot_modules {
core init ld.lib.so timer vfs_stress
rump.lib.so rump_fs.lib.so rump_fs
rump.lib.so rump_fs.lib.so vfs vfs_rump.lib.so
ram_block ext2.raw vfs.lib.so
}

View File

@ -1,312 +0,0 @@
/**
* \brief File-system directory node
* \author Norman Feske
* \author Christian Helmuth
* \author Sebastian Sumpf
* \date 2013-11-11
*/
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _DIRECTORY_H_
#define _DIRECTORY_H_
/* Genode include */
#include <os/path.h>
#include <file_system/util.h>
#include <base/log.h>
/* local includes */
#include "node.h"
#include "file.h"
#include "symlink.h"
namespace Rump_fs {
class Directory;
}
class Rump_fs::Directory : public Node
{
private:
enum { BUFFER_SIZE = 4096 };
typedef Genode::Path<MAX_PATH_LEN> Path;
int _fd;
Path _path;
Allocator &_alloc;
unsigned long _inode(char const *path, bool create)
{
int ret;
if (create) {
mode_t ugo = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
ret = rump_sys_mkdir(path, ugo);
if (ret == -1)
switch (errno) {
case ENAMETOOLONG: throw Name_too_long();
case EACCES: throw Permission_denied();
case ENOENT: throw Lookup_failed();
case EEXIST: throw Node_already_exists();
case ENOSPC:
default: throw No_space();
}
}
struct stat s;
ret = rump_sys_lstat(path, &s);
if (ret == -1)
throw Lookup_failed();
return s.st_ino;
}
int _open(char const *path)
{
struct stat s;
int ret = rump_sys_lstat(path, &s);
if (ret == -1 || !S_ISDIR(s.st_mode))
throw Lookup_failed();
int fd = rump_sys_open(path, O_RDONLY);
if (fd == -1)
throw Lookup_failed();
return fd;
}
static char *_buffer()
{
/* buffer for directory entries */
static char buf[BUFFER_SIZE];
return buf;
}
public:
Directory(Allocator &alloc, char const *path, bool create)
:
Node(_inode(path, create)),
_fd(_open(path)),
_path(path, "./"),
_alloc(alloc)
{
Node::name(basename(path));
}
virtual ~Directory()
{
rump_sys_close(_fd);
}
int fd() const override { return _fd; }
File * file(char const *name, Mode mode, bool create) override
{
return new (&_alloc) File(_fd, name, mode, create);
}
Symlink * symlink(char const *name, bool create) override
{
return new (&_alloc) Symlink(_path.base(), name, create);
}
Directory * subdir(char const *path, bool create)
{
Path dir_path(path, _path.base());
Directory *dir = new (&_alloc) Directory(_alloc, dir_path.base(), create);
return dir;
}
Node * node(char const *path)
{
Path node_path(path, _path.base());
struct stat s;
int ret = rump_sys_lstat(node_path.base(), &s);
if (ret == -1)
throw Lookup_failed();
Node *node = 0;
if (S_ISDIR(s.st_mode))
node = new (&_alloc) Directory(_alloc, node_path.base(), false);
else if (S_ISREG(s.st_mode))
node = new (&_alloc) File(node_path.base(), STAT_ONLY);
else if (S_ISLNK(s.st_mode))
node = new (&_alloc)Symlink(node_path.base());
else
throw Lookup_failed();
return node;
}
void update_modification_time(Timestamp const time) override
{
struct timespec ts[2] = {
{ .tv_sec = 0, .tv_nsec = 0 },
{ .tv_sec = time.value, .tv_nsec = 0 }
};
/* silently igore error */
rump_sys_futimens(_fd, (const timespec*)&ts);
}
size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{
if (len < sizeof(Directory_entry)) {
Genode::error("read buffer too small for directory entry");
return 0;
}
if (seek_offset % sizeof(Directory_entry)) {
Genode::error("seek offset not aligned to sizeof(Directory_entry)");
return 0;
}
seek_off_t index = seek_offset / sizeof(Directory_entry);
int bytes;
rump_sys_lseek(_fd, 0, SEEK_SET);
struct dirent *dent = 0;
seek_off_t i = 0;
char *buf = _buffer();
do {
bytes = rump_sys_getdents(_fd, buf, BUFFER_SIZE);
void *current, *end;
for (current = buf, end = &buf[bytes];
current < end;
current = _DIRENT_NEXT((dirent *)current))
{
struct ::dirent *d = (dirent*)current;
if (strcmp(".", d->d_name) && strcmp("..", d->d_name)) {
if (i == index) {
dent = d;
break;
}
++i;
}
}
} while(bytes && !dent);
if (!dent)
return 0;
/*
* Build absolute path, this becomes necessary as our 'Path' class strips
* trailing dots, which will not work for '.' and '..' directories.
*/
size_t base_len = strlen(_path.base());
char path[dent->d_namlen + base_len + 2];
memcpy(path, _path.base(), base_len);
path[base_len] = '/';
strncpy(path + base_len + 1, dent->d_name, dent->d_namlen + 1);
/*
* We cannot use 'd_type' member of 'dirent' here since the EXT2
* implementation sets the type to unkown. Hence we use stat.
*/
struct stat s;
rump_sys_lstat(path, &s);
auto type = [] (unsigned mode)
{
if (S_ISDIR(mode)) return Node_type::DIRECTORY;
else if (S_ISREG(mode)) return Node_type::CONTINUOUS_FILE;
else if (S_ISLNK(mode)) return Node_type::SYMLINK;
else return Node_type::CONTINUOUS_FILE;
};
Node_rwx const rwx { .readable = (s.st_mode & S_IRUSR),
.writeable = (s.st_mode & S_IWUSR),
.executable = (s.st_mode & S_IXUSR) };
Directory_entry &e = *(Directory_entry *)(dst);
e = {
.inode = s.st_ino,
.type = type(s.st_mode),
.rwx = rwx,
.name = { dent->d_name }
};
return sizeof(Directory_entry);
}
size_t write(char const *src, size_t len, seek_off_t seek_offset) override
{
/* writing to directory nodes is not supported */
return 0;
}
Status status() override
{
struct stat st;
if (rump_sys_fstat(_fd, &st) < 0)
st.st_mtime = 0;
return {
.size = num_entries() * sizeof (Directory_entry),
.type = File_system::Node_type::DIRECTORY,
.rwx = { .readable = (st.st_mode & S_IRUSR),
.writeable = (st.st_mode & S_IWUSR),
.executable = (st.st_mode & S_IXUSR) },
.inode = inode(),
.modification_time = { (int64_t)st.st_mtime }
};
}
size_t num_entries() const
{
int bytes = 0;
int count = 0;
rump_sys_lseek(_fd, 0, SEEK_SET);
char *buf = _buffer();
do {
bytes = rump_sys_getdents(_fd, buf, BUFFER_SIZE);
void *current, *end;
for (current = buf, end = &buf[bytes];
current < end;
current = _DIRENT_NEXT((dirent *)current))
{
struct ::dirent *d = (dirent*)current;
if (strcmp(".", d->d_name) && strcmp("..", d->d_name))
count++;
}
} while(bytes);
return count;
}
void unlink(char const *path) override
{
Path node_path(path, _path.base());
struct stat s;
int ret = rump_sys_lstat(node_path.base(), &s);
if (ret == -1)
throw Lookup_failed();
if (S_ISDIR(s.st_mode))
ret = rump_sys_rmdir(node_path.base());
else if (S_ISREG(s.st_mode) || S_ISLNK(s.st_mode))
ret = rump_sys_unlink(node_path.base());
else
throw Lookup_failed();
if (ret == -1)
Genode::error("error during unlink of ", node_path);
}
};
#endif /* _DIRECTORY_H_ */

View File

@ -1,181 +0,0 @@
/**
* \brief File node
* \author Norman Feske
* \author Christian Helmuth
* \auhtor Sebastian Sumpf
* \date 2013-11-11
*/
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _FILE_H_
#define _FILE_H_
/* Genode includes */
#include <file_system/util.h>
#include "node.h"
namespace Rump_fs {
class File;
}
class Rump_fs::File : public Node
{
private:
int _fd;
int _access_mode(Mode const &mode)
{
switch (mode) {
case STAT_ONLY:
case READ_ONLY: return O_RDONLY;
case WRITE_ONLY: return O_WRONLY;
case READ_WRITE: return O_RDWR;
default: return O_RDONLY;
}
}
unsigned long _inode(int dir, char const *name, bool create)
{
int ret;
if (create) {
mode_t ugo = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
ret = rump_sys_mknodat(dir, name, S_IFREG | ugo, 0);
if (ret == -1 && errno != EEXIST)
throw No_space();
}
struct stat s;
ret = rump_sys_fstatat(dir, name, &s, 0);
if (ret == -1)
throw Lookup_failed();
return s.st_ino;
}
unsigned long _inode_path(char const *path)
{
int ret;
struct stat s;
ret = rump_sys_stat(path, &s);
if (ret == -1)
throw Lookup_failed();
return s.st_ino;
}
int _open(int dir, char const *name, Mode mode)
{
int fd = rump_sys_openat(dir, name, _access_mode(mode));
if (fd == -1)
throw Lookup_failed();
return fd;
}
int _open_path(char const *path, Mode mode)
{
int fd = rump_sys_open(path, _access_mode(mode));
if (fd == -1)
throw Lookup_failed();
return fd;
}
public:
File(int dir,
char const *name,
Mode mode,
bool create)
: Node(_inode(dir, name, create)),
_fd(_open(dir, name, mode))
{
Node::name(name);
}
File(char const *path, Mode mode)
:
Node(_inode_path(path)),
_fd(_open_path(path, mode))
{
Node::name(basename(path));
}
virtual ~File() { rump_sys_close(_fd); }
void update_modification_time(Timestamp const time) override
{
struct timespec ts[2] = {
{ .tv_sec = 0, .tv_nsec = 0 },
{ .tv_sec = time.value, .tv_nsec = 0 }
};
/* silently igore error */
rump_sys_futimens(_fd, (const timespec*)&ts);
}
size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{
ssize_t ret;
if (seek_offset == SEEK_TAIL)
ret = rump_sys_lseek(_fd, -len, SEEK_END) != -1 ?
rump_sys_read(_fd, dst, len) : 0;
else
ret = rump_sys_pread(_fd, dst, len, seek_offset);
return ret == -1 ? 0 : ret;
}
size_t write(char const *src, size_t len, seek_off_t seek_offset) override
{
ssize_t ret;
if (seek_offset == SEEK_TAIL)
ret = rump_sys_lseek(_fd, 0, SEEK_END) != -1 ?
rump_sys_write(_fd, src, len) : 0;
else
ret = rump_sys_pwrite(_fd, src, len, seek_offset);
return ret == -1 ? 0 : ret;
}
virtual Status status() override
{
struct stat st { };
if (rump_sys_fstat(_fd, &st) < 0) {
st.st_size = 0;
st.st_mtime = 0;
}
return {
.size = (file_size_t)st.st_size,
.type = File_system::Node_type::CONTINUOUS_FILE,
.rwx = { .readable = (st.st_mode & S_IRUSR),
.writeable = (st.st_mode & S_IWUSR),
.executable = (st.st_mode & S_IXUSR) },
.inode = inode(),
.modification_time = { (int64_t)st.st_mtime }
};
}
void truncate(file_size_t size) override
{
rump_sys_ftruncate(_fd, size);
mark_as_updated();
}
};
#endif /* _FILE_H_ */

View File

@ -1,190 +0,0 @@
/*
* \brief Rump initialization
* \author Sebastian Sumpf
* \date 2014-01-17
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <rump/env.h>
#include <rump_fs/fs.h>
#include <util/string.h>
#include <util/hard_context.h>
#include <base/log.h>
#include <base/attached_rom_dataspace.h>
#include "file_system.h"
/**
* We define our own fs arg structure to fit all sizes used by the different
* file system implementations, we assume that 'fspec' * is the only valid
* argument and all other fields are unused.
*/
struct fs_args
{
char *fspec;
char pad[164];
fs_args() { Genode::memset(pad, 0, sizeof(pad)); }
};
namespace File_system { class Sync; };
static char const *fs_types[] = { RUMP_MOUNT_CD9660, RUMP_MOUNT_EXT2FS,
RUMP_MOUNT_FFS, RUMP_MOUNT_MSDOS,
RUMP_MOUNT_NTFS, RUMP_MOUNT_UDF, 0 };
typedef Genode::String<16> Fs_type;
static bool _supports_symlinks;
static bool _check_type(Fs_type const &type)
{
for (int i = 0; fs_types[i]; i++)
if (!Genode::strcmp(type.string(), fs_types[i]))
return true;
return false;
}
static void _print_types()
{
Genode::error("fs types:");
for (int i = 0; fs_types[i]; ++i)
Genode::error("\t", fs_types[i]);
}
static bool check_symlinks(Fs_type const &fs_type)
{
return (fs_type == RUMP_MOUNT_EXT2FS)
|| (fs_type == RUMP_MOUNT_FFS);
}
static bool check_read_only(Fs_type const &fs_type)
{
return fs_type == RUMP_MOUNT_CD9660;
}
void File_system::init()
{
Fs_type const fs_type = Rump::env().config_rom().xml().attribute_value("fs", Fs_type());
if (!_check_type(fs_type)) {
Genode::error("Invalid or no file system given (use \'<config fs=\"<fs type>\"/>)");
_print_types();
throw Genode::Exception();
}
Genode::log("Using ", fs_type, " as file system");
size_t const avail = Rump::env().env().pd().avail_ram().value;
rump_set_memlimit(avail);
/* start rump kernel */
try { rump_init(); }
catch (...) { throw Genode::Exception(); }
/* register block device */
rump_pub_etfs_register(GENODE_DEVICE, GENODE_BLOCK_SESSION, RUMP_ETFS_BLK);
/* create mount directory */
rump_sys_mkdir(GENODE_MOUNT_DIR, 0777);
/* check support for symlinks */
_supports_symlinks = check_symlinks(fs_type);
/*
* Try to mount the file system just to check if it
* is working as intended. In case it is not that gives
* us a change to react upon before any client may
* hang.
*/
try {
mount_fs();
unmount_fs();
} catch (...) {
Genode::error("dry mount attempt failed, aborting");
throw Genode::Exception();
}
}
static int root_fd = -42;
void File_system::mount_fs()
{
/* mount into extra-terrestrial-file system */
struct fs_args args;
args.fspec = (char *)GENODE_DEVICE;
Fs_type const fs_type = Rump::env().config_rom().xml().attribute_value("fs", Fs_type());
int opts = check_read_only(fs_type) ? RUMP_MNT_RDONLY : 0;
opts |= RUMP_MNT_NOATIME;
if (root_fd == -42) {
root_fd = rump_sys_open("/", O_DIRECTORY | O_RDONLY);
if (root_fd == -1) {
Genode::error("opening root directory failed");
throw Genode::Exception();
}
}
int err = rump_sys_mount(fs_type.string(), GENODE_MOUNT_DIR,
opts, &args, sizeof(args));
if (err == -1) {
Genode::error("mounting file system failed (errno ", errno, " )");
throw Genode::Exception();
}
int const mnt_fd = rump_sys_open(GENODE_MOUNT_DIR, O_DIRECTORY | O_RDONLY);
if (mnt_fd == -1) {
Genode::error("opening mnt directory failed");
throw Genode::Exception();
}
err = rump_sys_fchroot(mnt_fd);
if (err == -1) {
Genode::error("fchroot to '", GENODE_MOUNT_DIR, "' failed ",
"(errno ", errno, " )");
throw Genode::Exception();
}
}
void File_system::unmount_fs()
{
/* try to flush all outstanding modifications */
rump_sys_sync();
int err = rump_sys_fchroot(root_fd);
if (err == -1) {
Genode::error("fchroot to '/' failed ", "(errno ", errno, " )");
throw Genode::Exception();
}
bool const force = true;
err = rump_sys_unmount(GENODE_MOUNT_DIR, force ? RUMP_MNT_FORCE : 0);
if (err == -1) {
Genode::error("unmounting file system failed (errno ", errno, " )");
throw Genode::Exception();
}
}
bool File_system::supports_symlinks() { return _supports_symlinks; }

View File

@ -1,42 +0,0 @@
/**
* \brief Rump initialization and required header
* \author Sebastian Sumpf
* \date 2014-01-17
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _FILE_SYSTEM_H_
#define _FILE_SYSTEM_H_
/* Genode includes */
#include <util/xml_node.h>
#include <base/env.h>
#include <base/allocator.h>
extern "C" {
#include <sys/cdefs.h>
#include <sys/errno.h>
#include <fcntl.h>
#include <sys/dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/param.h>
#include <rump/rump.h>
#include <rump/rump_syscalls.h>
}
namespace File_system {
void init();
void mount_fs();
void unmount_fs();
bool supports_symlinks();
}
extern int errno;
#endif /* _FILE_SYSTEM_H_ */

View File

@ -1,626 +0,0 @@
/**
* \brief RUMP file system interface implementation
* \author Christian Helmuth
* \author Sebastian Sumpf
* \date 2014-01-14
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <timer_session/connection.h>
#include <file_system_session/rpc_object.h>
#include <base/attached_rom_dataspace.h>
#include <os/session_policy.h>
#include <root/component.h>
#include <base/component.h>
#include <base/heap.h>
#include "undef.h"
#include <rump/env.h>
#include <rump_fs/fs.h>
#include <sys/resource.h>
#include "file_system.h"
#include "directory.h"
#include "open_node.h"
namespace Rump_fs {
using File_system::Packet_descriptor;
using File_system::Path;
struct Main;
struct Root;
struct Session_component;
}
class Rump_fs::Session_component : public Session_rpc_object
{
private:
typedef File_system::Open_node<Node> Open_node;
Allocator &_md_alloc;
Directory &_root;
Id_space<File_system::Node> _open_node_registry;
bool _writable;
Signal_handler<Session_component> _process_packet_handler;
/******************************
** Packet-stream processing **
******************************/
/**
* Perform packet operation
*
* \return true on success, false on failure
*/
void _process_packet_op(Packet_descriptor &packet, Open_node &open_node)
{
size_t const length = packet.length();
/* resulting length */
size_t res_length = 0;
bool succeeded = false;
switch (packet.operation()) {
case Packet_descriptor::READ:
if (tx_sink()->packet_valid(packet) && packet.length() <= packet.size()) {
res_length = open_node.node().read((char *)tx_sink()->packet_content(packet),
length, packet.position());
/* read data or EOF is a success */
succeeded = res_length || (packet.position() >= open_node.node().status().size);
}
break;
case Packet_descriptor::WRITE:
if (tx_sink()->packet_valid(packet) && packet.length() <= packet.size()) {
res_length = open_node.node().write((char const *)tx_sink()->packet_content(packet),
length,
packet.position());
/* File system session can't handle partial writes */
if (res_length != length) {
Genode::error("partial write detected ",
res_length, " vs ", length);
/* don't acknowledge */
return;
}
succeeded = true;
}
break;
case Packet_descriptor::WRITE_TIMESTAMP:
if (tx_sink()->packet_valid(packet) && packet.length() <= packet.size()) {
packet.with_timestamp([&] (File_system::Timestamp const time) {
open_node.node().update_modification_time(time);
succeeded = true;
});
}
break;
case Packet_descriptor::CONTENT_CHANGED:
open_node.register_notify(*tx_sink());
/* notify_listeners may bounce the packet back*/
open_node.node().notify_listeners();
/* otherwise defer acknowledgement of this packet */
return;
case Packet_descriptor::READ_READY:
/* not supported */
succeeded = true;
break;
case Packet_descriptor::SYNC:
rump_sys_sync();
succeeded = true;
break;
}
packet.length(res_length);
packet.succeeded(succeeded);
tx_sink()->acknowledge_packet(packet);
}
void _process_packet()
{
Packet_descriptor packet = tx_sink()->get_packet();
/* assume failure by default */
packet.succeeded(false);
auto process_packet_fn = [&] (Open_node &open_node) {
_process_packet_op(packet, open_node);
};
try {
_open_node_registry.apply<Open_node>(packet.handle(), process_packet_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
Genode::error("Invalid_handle");
tx_sink()->acknowledge_packet(packet);
}
}
/**
* Called by signal dispatcher, executed in the context of the main
* thread (not serialized with the RPC functions)
*/
void _process_packets()
{
while (tx_sink()->packet_avail()) {
/*
* Make sure that the '_process_packet' function does not
* block.
*
* If the acknowledgement queue is full, we defer packet
* processing until the client processed pending
* acknowledgements and thereby emitted a ready-to-ack
* signal. Otherwise, the call of 'acknowledge_packet()'
* in '_process_packet' would infinitely block the context
* of the main thread. The main thread is however needed
* for receiving any subsequent 'ready-to-ack' signals.
*/
if (!tx_sink()->ready_to_ack())
return;
_process_packet();
}
}
/**
* Check if string represents a valid path (must start with '/')
*/
static void _assert_valid_path(char const *path)
{
if (!path || path[0] != '/')
throw Lookup_failed();
}
public:
/**
* Constructor
*/
Session_component(Genode::Env &env,
size_t tx_buf_size,
char const *root_dir,
bool writeable,
Allocator &md_alloc)
:
Session_rpc_object(env.ram().alloc(tx_buf_size), env.rm(), env.ep().rpc_ep()),
_md_alloc(md_alloc),
_root(*new (&_md_alloc) Directory(_md_alloc, root_dir, false)),
_writable(writeable),
_process_packet_handler(env.ep(), *this, &Session_component::_process_packets)
{
/*
* Register '_process_packets' dispatch function as signal
* handler for packet-avail and ready-to-ack signals.
*/
_tx.sigh_packet_avail(_process_packet_handler);
_tx.sigh_ready_to_ack(_process_packet_handler);
}
/**
* Destructor
*/
~Session_component()
{
Dataspace_capability ds = tx_sink()->dataspace();
Rump::env().env().ram().free(static_cap_cast<Ram_dataspace>(ds));
destroy(&_md_alloc, &_root);
}
/***************************
** File_system interface **
***************************/
File_handle file(Dir_handle dir_handle, Name const &name, Mode mode, bool create)
{
if (!valid_name(name.string()))
throw Invalid_name();
auto file_fn = [&] (Open_node &open_node) {
Node &dir = open_node.node();
if (!_writable)
if (create || (mode != STAT_ONLY && mode != READ_ONLY))
throw Permission_denied();
File *file = dir.file(name.string(), mode, create);
Open_node *open_file =
new (_md_alloc) Open_node(*file, _open_node_registry);
return open_file->id();
};
try {
return File_handle {
_open_node_registry.apply<Open_node>(dir_handle, file_fn).value
};
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
}
Symlink_handle symlink(Dir_handle dir_handle, Name const &name, bool create)
{
if (!File_system::supports_symlinks())
throw Permission_denied();
if (!valid_name(name.string()))
throw Invalid_name();
auto symlink_fn = [&] (Open_node &open_node) {
Node &dir = open_node.node();
if (create && !_writable)
throw Permission_denied();
Symlink *link = dir.symlink(name.string(), create);
Open_node *open_symlink =
new (_md_alloc) Open_node(*link, _open_node_registry);
return open_symlink->id();
};
try {
return Symlink_handle {
_open_node_registry.apply<Open_node>(dir_handle, symlink_fn).value
};
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
}
Dir_handle dir(Path const &path, bool create)
{
char const *path_str = path.string();
_assert_valid_path(path_str);
/* skip leading '/' */
path_str++;
if (!_writable && create)
throw Permission_denied();
if (!path.valid_string())
throw Name_too_long();
Directory *dir = _root.subdir(path_str, create);
Open_node *open_dir =
new (_md_alloc) Open_node(*dir, _open_node_registry);
return Dir_handle { open_dir->id().value };
}
Node_handle node(Path const &path)
{
char const *path_str = path.string();
_assert_valid_path(path_str);
Node *node = _root.node(path_str + 1);
Open_node *open_node =
new (_md_alloc) Open_node(*node, _open_node_registry);
return open_node->id();
}
void close(Node_handle handle)
{
auto close_fn = [&] (Open_node &open_node) {
Node &node = open_node.node();
destroy(_md_alloc, &open_node);
destroy(_md_alloc, &node);
};
try {
_open_node_registry.apply<Open_node>(handle, close_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
}
Status status(Node_handle node_handle)
{
auto status_fn = [&] (Open_node &open_node) {
return open_node.node().status();
};
try {
return _open_node_registry.apply<Open_node>(node_handle, status_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
}
void control(Node_handle, Control) override { }
void unlink(Dir_handle dir_handle, Name const &name)
{
if (!valid_name(name.string()))
throw Invalid_name();
if (!_writable)
throw Permission_denied();
auto unlink_fn = [&] (Open_node &open_node) {
Node &dir = open_node.node();
dir.unlink(name.string());
};
try {
_open_node_registry.apply<Open_node>(dir_handle, unlink_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
}
void truncate(File_handle file_handle, file_size_t size)
{
if (!_writable)
throw Permission_denied();
auto truncate_fn = [&] (Open_node &open_node) {
open_node.node().truncate(size);
};
try {
_open_node_registry.apply<Open_node>(file_handle, truncate_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
}
void move(Dir_handle from_dir_handle, Name const &from_name,
Dir_handle to_dir_handle, Name const &to_name)
{
if (!_writable)
throw Permission_denied();
auto move_fn = [&] (Open_node &open_from_dir_node) {
auto inner_move_fn = [&] (Open_node &open_to_dir_node) {
Node &from_dir = open_from_dir_node.node();
Node &to_dir = open_to_dir_node.node();
char const *from_str = from_name.string();
char const *to_str = to_name.string();
if (!(valid_name(from_str) && valid_name(to_str)))
throw Lookup_failed();
if (rump_sys_renameat(from_dir.fd(), from_str,
to_dir.fd(), to_str) == 0) {
from_dir.mark_as_updated();
from_dir.notify_listeners();
if (&from_dir != &to_dir) {
to_dir.mark_as_updated();
to_dir.notify_listeners();
}
return;
}
switch (errno) {
case ENOTEMPTY: throw Node_already_exists();
case ENOENT: throw Lookup_failed();
}
Genode::warning("renameat produced unhandled error ", errno, ", ", from_str, " -> ", to_str);
throw Permission_denied();
};
try {
_open_node_registry.apply<Open_node>(to_dir_handle, inner_move_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
};
try {
_open_node_registry.apply<Open_node>(from_dir_handle, move_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
}
};
class Rump_fs::Root : public Root_component<Session_component>
{
private:
Genode::Env &_env;
int _sessions { 0 };
Genode::Attached_rom_dataspace _config { _env, "config" };
protected:
Session_component *_create_session(const char *args)
{
using namespace Genode;
/*
* Determine client-specific policy defined implicitly by
* the client's label.
*/
Genode::Path<MAX_PATH_LEN> session_root;
bool writeable = false;
Session_label const label = label_from_args(args);
size_t ram_quota =
Arg_string::find_arg(args, "ram_quota").aligned_size();
size_t tx_buf_size =
Arg_string::find_arg(args, "tx_buf_size").aligned_size();
if (!tx_buf_size)
throw Service_denied();
/*
* Check if donated ram quota suffices for session data,
* and communication buffer.
*/
size_t session_size =
max((size_t)4096, sizeof(Session_component)) +
tx_buf_size;
if (session_size > ram_quota) {
Genode::error("insufficient 'ram_quota' from ", label.string(),
" got ", ram_quota, "need ", session_size);
throw Insufficient_ram_quota();
}
ram_quota -= session_size;
Session_policy const policy(label, _config.xml());
/* determine policy root offset */
typedef String<MAX_PATH_LEN> Root;
session_root.import(policy.attribute_value("root", Root()).string(), "/mnt");
/*
* Determine if the session is writeable.
* Policy overrides client argument, both default to false.
*/
if (policy.attribute_value("writeable", false))
writeable = Arg_string::find_arg(args, "writeable").bool_value(false);
/* apply client's root offset */
{
char tmp[MAX_PATH_LEN] { };
Arg_string::find_arg(args, "root").string(tmp, sizeof(tmp), "/");
if (Genode::strcmp("/", tmp, sizeof(tmp))) {
session_root.append("/");
session_root.append(tmp);
}
}
session_root.remove_trailing('/');
char const *root_dir = session_root.base();
try {
if (++_sessions == 1) { File_system::mount_fs(); }
} catch (...) {
Genode::error("could not mount file system");
throw Service_denied();
}
try {
return new (md_alloc())
Session_component(_env, tx_buf_size, root_dir, writeable, *md_alloc());
} catch (Lookup_failed) {
Genode::error("File system root directory \"", root_dir, "\" does not exist");
throw Service_denied();
}
}
void _destroy_session(Session_component *session)
{
Genode::destroy(md_alloc(), session);
try {
if (--_sessions == 0) { File_system::unmount_fs(); }
} catch (...) { }
}
public:
/**
* Constructor
*/
Root(Genode::Env &env, Allocator &md_alloc)
:
Root_component<Session_component>(env.ep(), md_alloc),
_env(env)
{ }
};
struct Rump_fs::Main
{
Genode::Env &env;
Timer::Connection _timer { env };
/* return immediately from resource requests */
void ignore_resource() { }
Genode::Signal_handler<Main> resource_handler
{ env.ep(), *this, &Main::ignore_resource };
/* periodic sync */
void sync()
{
/* sync through front-end */
rump_sys_sync();
/* sync Genode back-end */
rump_io_backend_sync();
}
Genode::Signal_handler<Main> sync_handler
{ env.ep(), *this, &Main::sync };
Heap heap { env.ram(), env.rm() };
/*
* Initialize root interface
*/
Sliced_heap sliced_heap { env.ram(), env.rm() };
Root fs_root { env, sliced_heap };
Main(Genode::Env &env) : env(env)
{
Rump::construct_env(env);
rump_io_backend_init();
File_system::init();
/* set all bits but the stickies */
rump_sys_umask(S_ISUID|S_ISGID|S_ISVTX);
/* set open file limit to maximum (256) */
struct rlimit rl { RLIM_INFINITY, RLIM_INFINITY };
if (rump_sys_setrlimit(RLIMIT_NOFILE, &rl) != 0)
Genode::error("rump_sys_setrlimit(RLIMIT_NOFILE, ...) failed, errno ", errno);
env.parent().announce(env.ep().manage(fs_root));
env.parent().resource_avail_sigh(resource_handler);
_timer.sigh(sync_handler);
_timer.trigger_periodic(2*1000*1000);
}
};
void Component::construct(Genode::Env &env)
{
/* XXX execute constructors of global statics (uses shared objects) */
env.exec_static_constructors();
static Rump_fs::Main inst(env);
}

View File

@ -1,98 +0,0 @@
/*
* \brief File-system node
* \author Norman Feske
* \author Christian Helmuth
* \author Sebastian Sumpf
* \date 2013-11-11
*/
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _NODE_H_
#define _NODE_H_
/* Genode includes */
#include <file_system/node.h>
#include <base/signal.h>
namespace Rump_fs {
using namespace File_system;
using namespace Genode;
using Genode::size_t;
class Node;
class File;
class Directory;
class Symlink;
}
class Rump_fs::Node : public Node_base
{
public:
typedef char Name[128];
private:
Name _name;
unsigned long const _inode;
public:
Node(unsigned long inode) : _inode(inode) { _name[0] = 0; }
unsigned long inode() const { return _inode; }
char const *name() const { return _name; }
/**
* Assign name
*/
void name(char const *name) { strncpy(_name, name, sizeof(_name)); }
virtual void update_modification_time(Timestamp const) = 0;
virtual size_t read(char *dst, size_t len, seek_off_t) = 0;
virtual size_t write(char const *src, size_t len, seek_off_t) = 0;
virtual Status status() = 0;
/*
* Directory functionality
*/
virtual int fd() const
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
return -1;
}
virtual File *file(char const *name, Mode mode, bool create)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
return nullptr;
}
virtual Symlink *symlink(char const *name, bool create)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
return nullptr;
}
virtual void unlink(char const *path)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-directory node");
}
/*
* File functionality
*/
virtual void truncate(file_size_t size)
{
Genode::error(__PRETTY_FUNCTION__, " called on a non-file node");
}
};
#endif /* _NODE_H_ */

View File

@ -1,95 +0,0 @@
/*
* \brief Representation of an open file system node within the component (deprecated)
* \author Christian Prochaska
* \date 2017-06-09
*/
/*
* Copyright (C) 2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _OPEN_NODE_H_
#define _OPEN_NODE_H_
/* Genode includes */
#include <file_system/listener.h>
#include <file_system_session/file_system_session.h>
namespace File_system {
/*
* \param NODE component-specific node type
*/
template <typename NODE> class Open_node;
}
template <typename NODE>
class File_system::Open_node : public File_system::Node
{
private:
Genode::Id_space<File_system::Node>::Element _element;
NODE &_node;
Genode::Constructible<File_system::Listener> _listener;
Listener::Version const _version_when_opened = _node.curr_version();
/*
* Flag to track whether the underlying file-system node was
* modified via this 'Open_node'. That is, if closing the 'Open_node'
* should notify listeners of the file.
*/
bool _was_written = false;
public:
Open_node(NODE &node, Genode::Id_space<File_system::Node> &id_space)
: _element(*this, id_space), _node(node) { }
~Open_node()
{
if (_listener.constructed()) {
_node.remove_listener(&*_listener);
_listener.destruct();
}
/*
* Notify remaining listeners about the changed file
*/
if (_was_written)
_node.notify_listeners();
}
NODE &node() { return _node; }
File_system::Listener &listener() { return *_listener; }
Genode::Id_space<File_system::Node>::Id id() { return _element.id(); }
/**
* Register packet stream sink to be notified of node changes
*/
void register_notify(File_system::Sink &sink)
{
/*
* If there was already a handler registered for the node,
* remove the old handler.
*/
if (_listener.constructed()) {
_node.remove_listener(&*_listener);
_listener.destruct();
}
/*
* Register new handler
*/
_listener.construct(sink, id(), _version_when_opened);
_node.add_listener(&*_listener);
}
void mark_as_written() { _was_written = true; }
};
#endif /* _OPEN_NODE_H_ */

View File

@ -1,21 +0,0 @@
/**
* \brief Dummy random support
* \author Sebastian Sumpf
* \date 2015-02-16
*/
/*
* Copyright (C) 2015-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <util/random.h>
int rumpuser_getrandom_backend(void *buf, Genode::size_t buflen, int flags, Genode::size_t *retp)
{
*retp = buflen;
return 0;
}

View File

@ -1,99 +0,0 @@
/**
* \brief Rump symlink node
* \author Sebastian Sumpf
* \date 2014-01-20
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _SYMLINK_H_
#define _SYMLINK_H_
/* Genode includes */
#include <file_system/util.h>
#include <os/path.h>
#include "node.h"
namespace Rump_fs {
class Symlink;
}
class Rump_fs::Symlink : public Node
{
private:
typedef Genode::Path<MAX_PATH_LEN> Path;
Path _path;
bool _create;
public:
Symlink(char const *dir, char const *name, bool create)
: Node(0), _path(name, dir), _create(create)
{
Node::name(name);
}
Symlink(char const *path)
: Node(0), _path(path), _create(false)
{
Node::name(basename(path));
}
void update_modification_time(Timestamp const time) override
{
/* XXX not handled for now: either dirfd or fd to _path is required */
}
size_t write(char const *src, size_t const len, seek_off_t seek_offset) override
{
/* Ideal symlink operations are atomic. */
if (!_create || seek_offset)
return 0;
/* src may not be null-terminated */
Genode::String<MAX_PATH_LEN> target(Genode::Cstring(src, len));
int ret = rump_sys_symlink(target.string(), _path.base());
return ret == -1 ? 0 : len;
}
size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{
int ret = rump_sys_readlink(_path.base(), dst, len);
return ret == -1 ? 0 : ret;
}
Status status() override
{
struct stat st;
if (rump_sys_lstat(_path.base(), &st) < 0) {
st.st_mtime = 0;
}
return {
.size = length(),
.type = File_system::Node_type::SYMLINK,
.rwx = { .readable = true,
.writeable = true,
.executable = true },
.inode = inode(),
.modification_time = { (int64_t)st.st_mtime }
};
}
file_size_t length()
{
char link_to[MAX_PATH_LEN];
return read(link_to, MAX_PATH_LEN, 0);
}
};
#endif /* _SYMLINK_H_ */

View File

@ -1,5 +0,0 @@
TARGET = rump_fs
SRC_CC = main.cc file_system.cc random.cc
LIBS = base rump rump_fs
CC_CXX_WARN_STRICT =

View File

@ -1,21 +0,0 @@
/**
* \brief Undef macro clashes
* \author Sebastian Sumpf
* \date 2014-01-24
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _UNDEF_H_
#define _UNDEF_H_
extern "C" {
#include <sys/cdefs.h>
}
#endif /* _UNDEF_H_ */

View File

@ -36,7 +36,8 @@ append build_components {
drivers/framebuffer
}
lappend_if [expr $use_rumpfs] build_components server/rump_fs
lappend_if [expr $use_rumpfs] build_components lib/vfs/rump
lappend_if [expr $use_rumpfs] build_components server/vfs
lappend_if [expr $use_vbox5] build_components virtualbox5
lappend_if [expr $use_ps2] build_components drivers/input
lappend_if [expr $use_usb] build_components drivers/usb
@ -130,9 +131,13 @@ append_if [have_spec nova] config {
append_if [expr $use_rumpfs] config {
<start name="rump_fs" priority="-1" caps="200">
<binary name="vfs"/>
<resource name="RAM" quantum="32M"/>
<provides><service name="File_system"/></provides>
<config ld_verbose="yes" fs="ext2fs">}
<config ld_verbose="yes">
<vfs>
<rump fs="ext2fs" ram="28M"/>
</vfs>}
append_if [expr $use_rumpfs && $use_ram_fs && $use_overlay_from_disk] config {
<policy label_prefix="overlay_from_disk" root="/ram" writeable="no"/>}
@ -363,7 +368,8 @@ append boot_modules {
lappend_if [expr $use_rumpfs] boot_modules rump.lib.so
lappend_if [expr $use_rumpfs] boot_modules rump_fs.lib.so
lappend_if [expr $use_rumpfs] boot_modules rump_fs
lappend_if [expr $use_rumpfs] boot_modules vfs_rump.lib.so
lappend_if [expr $use_rumpfs] boot_modules vfs
lappend_if [expr $use_vbox5] boot_modules $virtualbox5_binary
lappend_if [expr $use_ram_fs || $use_usb] boot_modules ram_fs
lappend_if [expr $use_ram_fs && !$use_overlay_from_disk] boot_modules $overlay_image