diff --git a/repos/dde_rump/lib/mk/vfs_rump.mk b/repos/dde_rump/lib/mk/vfs_rump.mk new file mode 100644 index 0000000000..ba23a9c2eb --- /dev/null +++ b/repos/dde_rump/lib/mk/vfs_rump.mk @@ -0,0 +1,6 @@ +SRC_CC = vfs_rump.cc random.cc +LIBS = rump rump_fs +INC_DIR += $(REP_DIR)/src/lib/vfs/rump +vpath %.cc $(REP_DIR)/src/lib/vfs/rump + +SHARED_LIB = yes diff --git a/repos/dde_rump/run/libc_vfs_ext2.run b/repos/dde_rump/run/libc_vfs_ext2.run new file mode 100644 index 0000000000..415eaa42e6 --- /dev/null +++ b/repos/dde_rump/run/libc_vfs_ext2.run @@ -0,0 +1,99 @@ +if {[have_spec arm]} { + assert_spec arm_v7 +} + +# +# Check used commands +# +set mke2fs [check_installed mke2fs] +set dd [check_installed dd] + +# +# Build +# +set build_components { + core init + drivers/timer + server/ram_blk + lib/vfs/rump + test/libc_vfs +} + +build $build_components + +# +# Build EXT2-file-system image +# +catch { exec $dd if=/dev/zero of=bin/ext2.raw bs=1M count=16 } +catch { exec $mke2fs -F bin/ext2.raw } + +create_boot_directory + +# +# Generate config +# +append config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +install_config $config + +# +# Boot modules +# + +# generic modules +set boot_modules { + core ld.lib.so init + libc.lib.so + libm.lib.so + ram_blk + rump_fs.lib.so + rump.lib.so + test-libc_vfs + timer + vfs_rump.lib.so + ext2.raw +} + +build_boot_image $boot_modules + +append qemu_args " -m 256 -nographic" + +run_genode_until {.*child "test-libc_vfs" exited with exit value 0.*} 60 + +exec rm -f bin/ext2.raw diff --git a/repos/dde_rump/run/libc_vfs_fs_ext2.run b/repos/dde_rump/run/libc_vfs_fs_ext2.run new file mode 100644 index 0000000000..e074fe6180 --- /dev/null +++ b/repos/dde_rump/run/libc_vfs_fs_ext2.run @@ -0,0 +1,109 @@ +if {[have_spec arm]} { + assert_spec arm_v7 +} + +# +# Check used commands +# +set mke2fs [check_installed mke2fs] +set dd [check_installed dd] + +# +# Build +# +set build_components { + core init + drivers/timer + server/ram_blk + lib/vfs/rump + server/vfs + test/libc_vfs +} + +build $build_components + +# +# Build EXT2-file-system image +# +catch { exec $dd if=/dev/zero of=bin/ext2.raw bs=1M count=16 } +catch { exec $mke2fs -F bin/ext2.raw } + +create_boot_directory + +# +# Generate config +# +append config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +install_config $config + +# +# Boot modules +# + +# generic modules +set boot_modules { + core ld.lib.so init + libc.lib.so + libm.lib.so + ram_blk + rump_fs.lib.so + rump.lib.so + test-libc_vfs + timer + vfs + vfs_rump.lib.so + ext2.raw +} + +build_boot_image $boot_modules + +append qemu_args " -m 256 -nographic" + +run_genode_until {.*child "test-libc_vfs" exited with exit value 0.*} 60 + +exec rm -f bin/ext2.raw diff --git a/repos/dde_rump/run/vfs_stress_ext2.run b/repos/dde_rump/run/vfs_stress_ext2.run new file mode 100644 index 0000000000..c069127757 --- /dev/null +++ b/repos/dde_rump/run/vfs_stress_ext2.run @@ -0,0 +1,69 @@ +# +# \brief VFS stress test +# \author Emery Hemingway +# \date 2015-08-30 +# + +# +# Check used commands +# +set mke2fs [check_installed mke2fs] +set dd [check_installed dd] + +build "core init drivers/timer test/vfs_stress server/ram_blk lib/vfs/rump" + +# +# Build EXT2-file-system image +# +catch { exec $dd if=/dev/zero of=bin/ext2.raw bs=1M count=16 } +catch { exec $mke2fs -F bin/ext2.raw } + +create_boot_directory + +install_config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +set boot_modules { + core init ld.lib.so timer vfs_stress + rump.lib.so rump_fs.lib.so vfs_rump.lib.so + ram_blk ext2.raw +} + +build_boot_image $boot_modules + +append qemu_args "-nographic -smp cpus=6" + +run_genode_until {child "vfs_stress" exited with exit value 0} 180 + +exec rm -f bin/ext2.raw diff --git a/repos/dde_rump/run/vfs_stress_rump_fs.run b/repos/dde_rump/run/vfs_stress_rump_fs.run new file mode 100644 index 0000000000..8768d76d1c --- /dev/null +++ b/repos/dde_rump/run/vfs_stress_rump_fs.run @@ -0,0 +1,76 @@ +# +# \brief VFS stress test +# \author Emery Hemingway +# \date 2015-08-30 +# + +# +# Check used commands +# +set mke2fs [check_installed mke2fs] +set dd [check_installed dd] + +build "core init drivers/timer test/vfs_stress server/ram_blk server/rump_fs" + +# +# Build EXT2-file-system image +# +catch { exec $dd if=/dev/zero of=bin/ext2.raw bs=1M count=16 } +catch { exec $mke2fs -F bin/ext2.raw } + +create_boot_directory + +install_config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +set boot_modules { + core init ld.lib.so timer vfs_stress + rump.lib.so rump_fs.lib.so rump_fs + ram_blk ext2.raw +} + +build_boot_image $boot_modules + +append qemu_args "-nographic -smp cpus=6" + +run_genode_until {child "vfs_stress" exited with exit value 0} 180 + +exec rm -f bin/ext2.raw diff --git a/repos/dde_rump/src/lib/vfs/rump/README b/repos/dde_rump/src/lib/vfs/rump/README new file mode 100644 index 0000000000..c8490ca1bb --- /dev/null +++ b/repos/dde_rump/src/lib/vfs/rump/README @@ -0,0 +1,5 @@ +The vfs_rump plugin enables access to block device backed file systems +supported by the rump kernel. A single rump kernel is in use for any +number of nodes. The configuration node takes two arguments: +'fs' specifies the file system type, and 'writeable' specifies if the +mount is read only or writeable, 'writeable' defaults to true. \ No newline at end of file diff --git a/repos/dde_rump/src/lib/vfs/rump/random.cc b/repos/dde_rump/src/lib/vfs/rump/random.cc new file mode 100644 index 0000000000..142de81d2d --- /dev/null +++ b/repos/dde_rump/src/lib/vfs/rump/random.cc @@ -0,0 +1,21 @@ +/** + * \brief Dummy random support + * \author Sebastian Sumpf + * \date 2015-02-16 + */ + +/* + * Copyright (C) 2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#include + + +int rumpuser_getrandom_backend(void *buf, Genode::size_t buflen, int flags, Genode::size_t *retp) +{ + *retp = buflen; + return 0; +} diff --git a/repos/dde_rump/src/lib/vfs/rump/target.mk b/repos/dde_rump/src/lib/vfs/rump/target.mk new file mode 100644 index 0000000000..233e2630ba --- /dev/null +++ b/repos/dde_rump/src/lib/vfs/rump/target.mk @@ -0,0 +1,2 @@ +TARGET = rump_plugin +LIBS = vfs_rump diff --git a/repos/dde_rump/src/lib/vfs/rump/vfs_rump.cc b/repos/dde_rump/src/lib/vfs/rump/vfs_rump.cc new file mode 100644 index 0000000000..87b26100d8 --- /dev/null +++ b/repos/dde_rump/src/lib/vfs/rump/vfs_rump.cc @@ -0,0 +1,550 @@ +/* + * \brief Rump VFS plugin + * \author Christian Helmuth + * \author Sebastian Sumpf + * \author Emery Hemingway + * \date 2015-09-05 + */ + +/* + * Copyright (C) 2014-2016 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include + +extern "C" { +#include +#include +#include +#include +#include +#include +#include +#include +#include +} + +extern int errno; + +namespace Vfs { struct Rump_file_system; }; + +static void _rump_sync() +{ + /* sync through front-end */ + rump_sys_sync(); + + /* sync Genode back-end */ + rump_io_backend_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 }; + +class Vfs::Rump_file_system : public File_system +{ + private: + + enum { BUFFER_SIZE = 4096 }; + + typedef Genode::Path Path; + + class Rump_vfs_handle : public Vfs_handle + { + private: + + int _fd; + + public: + + Rump_vfs_handle(File_system &fs, Allocator &alloc, + int status_flags, int fd) + : Vfs_handle(fs, fs, alloc, status_flags), _fd(fd) { } + + ~Rump_vfs_handle() { rump_sys_close(_fd); } + + int fd() const { return _fd; } + }; + + /** + * We define our own fs arg structure to fit all sizes, we assume that 'fspec' + * is the only valid argument and all other fields are unused. + */ + struct fs_args + { + char *fspec; + char pad[150]; + + fs_args() { Genode::memset(pad, 0, sizeof(pad)); } + }; + + static bool _check_type(char const *type) + { + for (int i = 0; fs_types[i]; i++) + if (!Genode::strcmp(type, fs_types[i])) + return true; + return false; + } + + void _print_types() + { + Genode::error("fs types:"); + for (int i = 0; fs_types[i]; ++i) + Genode::error("\t", fs_types[i]); + } + + static char *_buffer() + { + /* buffer for directory entries */ + static char buf[BUFFER_SIZE]; + return buf; + } + + Dirent_result _dirent(char const *path, + struct ::dirent *dent, Dirent &vfs_dir) + { + /* + * 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); + + if (S_ISREG(s.st_mode)) + vfs_dir.type = Dirent_type::DIRENT_TYPE_FILE; + else if (S_ISDIR(s.st_mode)) + vfs_dir.type = Dirent_type::DIRENT_TYPE_DIRECTORY; + else if (S_ISLNK(s.st_mode)) + vfs_dir.type = Dirent_type::DIRENT_TYPE_SYMLINK; + else if (S_ISBLK(s.st_mode)) + vfs_dir.type = Dirent_type::DIRENT_TYPE_BLOCKDEV; + else if (S_ISCHR(s.st_mode)) + vfs_dir.type = Dirent_type::DIRENT_TYPE_CHARDEV; + else if (S_ISFIFO(s.st_mode)) + vfs_dir.type = Dirent_type::DIRENT_TYPE_FIFO; + else + vfs_dir.type = Dirent_type::DIRENT_TYPE_FILE; + + strncpy(vfs_dir.name, dent->d_name, sizeof(Dirent::name)); + + return DIRENT_OK; + } + + public: + + Rump_file_system(Xml_node const &config) + { + typedef Genode::String<16> Fs_type; + + Fs_type fs_type = config.attribute_value("fs", Fs_type()); + + if (!_check_type(fs_type.string())) { + Genode::error("Invalid or no file system given (use \'\"/>)"); + _print_types(); + throw Genode::Exception(); + } + + /* mount into extra-terrestrial-file system */ + struct fs_args args; + int opts = config.attribute_value("writeable", true) ? + 0 : RUMP_MNT_RDONLY; + + args.fspec = (char *)GENODE_DEVICE; + if (rump_sys_mount(fs_type.string(), "/", opts, &args, sizeof(args)) == -1) { + Genode::error("Mounting '",fs_type,"' file system failed (",errno,")"); + throw Genode::Exception(); + } + + Genode::log(fs_type," file system mounted"); + } + + /*************************** + ** File_system interface ** + ***************************/ + + static char const *name() { return "rump"; } + + + /********************************* + ** Directory service interface ** + *********************************/ + + void sync(char const *path) override { + _rump_sync(); } + + Genode::Dataspace_capability dataspace(char const *path) override + { + int fd = rump_sys_open(path, O_RDONLY); + if (fd == -1) return Genode::Dataspace_capability(); + + struct stat s; + if (rump_sys_lstat(path, &s) != 0) return Genode::Dataspace_capability(); + size_t const ds_size = s.st_size; + + char *local_addr = nullptr; + Ram_dataspace_capability ds_cap; + try { + ds_cap = env()->ram_session()->alloc(ds_size); + + local_addr = env()->rm_session()->attach(ds_cap); + + enum { CHUNK_SIZE = 16U << 10 }; + + for (size_t i = 0; i < ds_size;) { + ssize_t n = rump_sys_read(fd, &local_addr[i], min(ds_size-i, CHUNK_SIZE)); + if (n == -1) + throw n; + i += n; + } + + env()->rm_session()->detach(local_addr); + } catch(...) { + if (local_addr) + env()->rm_session()->detach(local_addr); + env()->ram_session()->free(ds_cap); + } + rump_sys_close(fd); + return ds_cap; + } + + void release(char const *path, + Genode::Dataspace_capability ds_cap) override + { + if (ds_cap.valid()) + env()->ram_session()->free( + static_cap_cast(ds_cap)); + } + + file_size num_dirent(char const *path) override + { + file_size n = 0; + int fd = rump_sys_open(*path ? path : "/", O_RDONLY | O_DIRECTORY); + if (fd == -1) + return 0; + + rump_sys_lseek(fd, 0, SEEK_SET); + + int bytes = 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 *dent = (::dirent *)current; + if (strcmp(".", dent->d_name) && strcmp("..", dent->d_name)) + ++n; + } + } while(bytes); + + rump_sys_close(fd); + return n; + } + + bool directory(char const *path) override + { + struct stat s; + if (rump_sys_lstat(path, &s) != 0) return false; + return S_ISDIR(s.st_mode); + } + + char const *leaf_path(char const *path) override + { + struct stat s; + return (rump_sys_lstat(path, &s) == 0) ? path : 0; + } + + Mkdir_result mkdir(char const *path, unsigned mode) override + { + if (rump_sys_mkdir(path, mode|0777) != 0) switch (::errno) { + case ENAMETOOLONG: return MKDIR_ERR_NAME_TOO_LONG; + case EACCES: return MKDIR_ERR_NO_PERM; + case ENOENT: return MKDIR_ERR_NO_ENTRY; + case EEXIST: return MKDIR_ERR_EXISTS; + case ENOSPC: return MKDIR_ERR_NO_SPACE; + default: + return MKDIR_ERR_NO_PERM; + } + return MKDIR_OK; + } + + Open_result open(char const *path, unsigned mode, + Vfs_handle **handle, + Allocator &alloc) override + { + /* OPEN_MODE_CREATE (or O_EXC) will not work */ + if (mode & OPEN_MODE_CREATE) + mode |= O_CREAT; + + int fd = rump_sys_open(path, mode); + if (fd == -1) switch (errno) { + case ENAMETOOLONG: return OPEN_ERR_NAME_TOO_LONG; + case EACCES: return OPEN_ERR_NO_PERM; + case ENOENT: return OPEN_ERR_UNACCESSIBLE; + case EEXIST: return OPEN_ERR_EXISTS; + case ENOSPC: return OPEN_ERR_NO_SPACE; + default: + return OPEN_ERR_NO_PERM; + } + + *handle = new (alloc) Rump_vfs_handle(*this, alloc, mode, fd); + return OPEN_OK; + } + + void close(Vfs_handle *vfs_handle) override + { + Rump_vfs_handle *rump_handle = + static_cast(vfs_handle); + + if (rump_handle) + destroy(vfs_handle->alloc(), rump_handle); + } + + Stat_result stat(char const *path, Stat &stat) + { + struct stat sb; + if (rump_sys_lstat(path, &sb) != 0) return STAT_ERR_NO_ENTRY; + + stat.size = sb.st_size; + stat.mode = sb.st_mode; + stat.uid = sb.st_uid; + stat.gid = sb.st_gid; + stat.inode = sb.st_ino; + stat.device = sb.st_dev; + + return STAT_OK; + } + + Dirent_result dirent(char const *path, file_offset index_, + Dirent &vfs_dir) override + { + int fd = rump_sys_open(*path ? path : "/", O_RDONLY | O_DIRECTORY); + if (fd == -1) + return DIRENT_ERR_INVALID_PATH; + + rump_sys_lseek(fd, 0, SEEK_SET); + + int bytes; + unsigned const index = index_; + vfs_dir.fileno = 0; + char *buf = _buffer(); + struct ::dirent *dent = nullptr; + 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)) + { + dent = (::dirent *)current; + if (strcmp(".", dent->d_name) && strcmp("..", dent->d_name)) { + if (vfs_dir.fileno++ == index) { + Path newpath(dent->d_name, path); + rump_sys_close(fd); + return _dirent(newpath.base(), dent, vfs_dir); + } + } + } + } while (bytes > 0); + rump_sys_close(fd); + + vfs_dir.type = DIRENT_TYPE_END; + vfs_dir.name[0] = '\0'; + return DIRENT_OK; + } + + Unlink_result unlink(char const *path) override + { + struct stat s; + if (rump_sys_lstat(path, &s) == -1) + return UNLINK_ERR_NO_ENTRY; + + if (S_ISDIR(s.st_mode)) { + if (rump_sys_rmdir(path) == 0) return UNLINK_OK; + } else { + if (rump_sys_unlink(path) == 0) return UNLINK_OK; + } + switch (errno) { + case ENOENT: return UNLINK_ERR_NO_ENTRY; + case ENOTEMPTY: return UNLINK_ERR_NOT_EMPTY; + } + return UNLINK_ERR_NO_PERM; + } + + Readlink_result readlink(char const *path, char *buf, + file_size buf_size, file_size &out_len) override + { + ssize_t n = rump_sys_readlink(path, buf, buf_size); + if (n == -1) { + out_len = 0; + return READLINK_ERR_NO_ENTRY; + } + + out_len = n; + return READLINK_OK; + } + + Symlink_result symlink(char const *from, char const *to) override + { + if (rump_sys_symlink(from, to) != 0) switch (errno) { + case EEXIST: { + if (rump_sys_readlink(to, NULL, 0) == -1) + return SYMLINK_ERR_EXISTS; + rump_sys_unlink(to); + return rump_sys_symlink(from, to) == 0 ? + SYMLINK_OK : SYMLINK_ERR_EXISTS; + } + case ENOENT: return SYMLINK_ERR_NO_ENTRY; + case ENOSPC: return SYMLINK_ERR_NO_SPACE; + case EACCES: return SYMLINK_ERR_NO_PERM; + case ENAMETOOLONG: return SYMLINK_ERR_NAME_TOO_LONG; + default: + return SYMLINK_ERR_NO_PERM; + } + return SYMLINK_OK; + } + + Rename_result rename(char const *from, char const *to) override + { + if (rump_sys_rename(from, to) != 0) switch (errno) { + case ENOENT: return RENAME_ERR_NO_ENTRY; + case EXDEV: return RENAME_ERR_CROSS_FS; + case EACCES: return RENAME_ERR_NO_PERM; + } + return RENAME_OK; + } + + + /******************************* + ** File io service interface ** + *******************************/ + + Write_result write(Vfs_handle *vfs_handle, + char const *buf, file_size buf_size, + file_size &out_count) override + { + Rump_vfs_handle *handle = + static_cast(vfs_handle); + + ssize_t n = rump_sys_pwrite(handle->fd(), buf, buf_size, handle->seek()); + if (n == -1) switch (errno) { + case EWOULDBLOCK: return WRITE_ERR_WOULD_BLOCK; + case EINVAL: return WRITE_ERR_INVALID; + case EIO: return WRITE_ERR_IO; + case EINTR: return WRITE_ERR_INTERRUPT; + default: + return WRITE_ERR_IO; + } + out_count = n; + return WRITE_OK; + } + + Read_result read(Vfs_handle *vfs_handle, char *buf, file_size buf_size, + file_size &out_count) override + { + Rump_vfs_handle *handle = + static_cast(vfs_handle); + + ssize_t n = rump_sys_pread(handle->fd(), buf, buf_size, handle->seek()); + if (n == -1) switch (errno) { + case EWOULDBLOCK: return READ_ERR_WOULD_BLOCK; + case EINVAL: return READ_ERR_INVALID; + case EIO: return READ_ERR_IO; + case EINTR: return READ_ERR_INTERRUPT; + default: + return READ_ERR_IO; + } + out_count = n; + return READ_OK; + } + + Ftruncate_result ftruncate(Vfs_handle *vfs_handle, file_size len) override + { + Rump_vfs_handle *handle = + static_cast(vfs_handle); + + if (rump_sys_ftruncate(handle->fd(), len) != 0) switch (errno) { + case EACCES: return FTRUNCATE_ERR_NO_PERM; + case EINTR: return FTRUNCATE_ERR_INTERRUPT; + case ENOSPC: return FTRUNCATE_ERR_NO_SPACE; + default: + return FTRUNCATE_ERR_NO_PERM; + } + return FTRUNCATE_OK; + } +}; + + +class Rump_factory : public Vfs::File_system_factory +{ + private: + + Timer::Connection _timer; + Genode::Signal_handler _sync_handler; + + void _sync() { _rump_sync(); } + + public: + + Rump_factory(Genode::Env &env, Genode::Allocator &alloc) + : _timer(env, "rump-sync"), + _sync_handler(env.ep(), *this, &Rump_factory::_sync) + { + Rump::construct_env(env); + + rump_io_backend_init(); + + /* start rump kernel */ + rump_init(); + + /* register block device */ + rump_pub_etfs_register( + GENODE_DEVICE, GENODE_BLOCK_SESSION, RUMP_ETFS_BLK); + + /* set all bits but the stickies */ + rump_sys_umask(S_ISUID|S_ISGID|S_ISVTX); + + /* start syncing */ + enum { TEN_SEC = 10*1000*1000 }; + _timer.sigh(_sync_handler); + _timer.trigger_periodic(TEN_SEC); + + } + + Vfs::File_system *create(Genode::Env &env, + Genode::Allocator &alloc, + Genode::Xml_node config) override + { + return new (alloc) Vfs::Rump_file_system(config); + } +}; + + +extern "C" Vfs::File_system_factory *vfs_file_system_factory(void) +{ + struct Extern_factory : Vfs::File_system_factory + { + Vfs::File_system *create(Genode::Env &env, + Genode::Allocator &alloc, + Genode::Xml_node node) override + { + static Rump_factory factory(env, alloc); + return factory.create(env, alloc, node); + } + }; + + static Extern_factory factory; + return &factory; +} diff --git a/tool/autopilot.list b/tool/autopilot.list index b3de35b827..7d6237ad16 100644 --- a/tool/autopilot.list +++ b/tool/autopilot.list @@ -45,6 +45,7 @@ part_blk xml_generator blk_cache rump_ext2 +libc_vfs_ext2 thread pthread vbox_auto_win7