Skip to content

Commit

Permalink
Import VFS FUSE plugin from ticket193_patch-1.zip
Browse files Browse the repository at this point in the history
  • Loading branch information
cnuke committed Dec 14, 2021
1 parent a15bbcc commit b4c5ebe
Show file tree
Hide file tree
Showing 7 changed files with 1,385 additions and 0 deletions.
62 changes: 62 additions & 0 deletions src/lib/vfs/fuse/README
@@ -0,0 +1,62 @@
The fuse vfs plug-in provides access to a FUSE based file system. Like other
vfs plug-ins, it may be either located directly in the client application, or
within a file-system server.

The plug-in implementation is independent from each
FUSE based file system. fuse vfs only calls the FUSE operation in question
directly. These operations are provided by the FUSE file system and Genode's
libfuse library makes sure, that each operation is executable, e.g. by using
a dummy function in case it is not provided by the FUSE file system.
Therefore, to utilize a FUSE file system, the FUSE file system is linked
against libfuse as well as vfs_fuse. For each fuse vfs plug-in there is
a binary (.e.g. 'world/src/lib/vfs/fuse/ext2').

Note: write-support is supported but considered to be experimantal at this
point and for now using it is NOT recommended.

To use the ext2_fuse plug-in the following config snippet may be used:

! <start name="fs">
! <resource name="RAM" quantum="8M"/> XXX
! <config>
! <policy label_prefix="noux -> fuse" root="/" writeable="no" /> XXXX
! <vfs>
! <dir name="dev">
! <block name="sda1"/> <!-- handles block session to real block device -->
! </dir>
! <dir name="fs">
! <fuse-ext2fs block_path="/dev/sda1"/>
! </dir>
! </vfs>
! </config>
! </start>


xxx///FIXME: we don't provide a setting to toggle r/o or r/w policy, unlike the previous implementation.. Should we?

This is a work-in-progress; among the tech debt that is still to be repaid to
bring it up to Genode standards, one should mention:

TODO:
- rename plug-in from "fuse" to "fuse-ntfs-3g" etc
- add support for ext2fs and exfat (in theory this should be straightfoward,
using as guidelines the diffs that enabled ntfs-3g support)
- stub out the remainder of LibC (the one that can be left out when running in
a libc-using host, but will be required when running in an fs server)


Additionally, during the course of migrating FUSE from a server to a vfs plug-in,
some ideas came up to make the test-suite even more robust:

TODO: test suite:
- add opendir tests
- add stat() tests after each mkdir()/rmdir() tests, to check for functions that return OK even though they didn't perform their task.
- repeatedly open()/close(), for ca. 256+10 time, to check for fd leaks (i.e. if the plug-in fails to release() file descriptors)



How to build:
(/// Remove this, build instructions are not generally provided in READMEs):
- make -C build/x86_64 KERNEL=nova BOARD=pc LIB=vfs_fuse
- make -C build/x86_64 KERNEL=nova BOARD=pc run/libc_vfs_ntfs-3g_fuse_fs

@@ -0,0 +1,165 @@
/*
* Copyright (C) 2021 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.
*/



#pragma once


#error give up on this -- it works well for reads, but wont handle non-aligned-writes... Use "VfsBlock.." system instead, which handles that for us


/* Genode includes */
#include <base/allocator.h>
#include <base/allocator_avl.h>
#include <base/log.h>
#include <block_session/connection.h>

/* libc includes */
#include <errno.h> // EACCESS etc




static void dump( const char * buf, int size )
{
for( int i = 0; i < size; i++ )
{
// Genode::log( buf[i] );
}
}


///ToDo: the Block::Connection API is deprecated (see ticket #193)
// use eg API used in this instead: os/src/server/part_block/partition_table.h

struct WholeBlock_Read
{
// Fuse-NTFS might request "partial" blocks in pread(), but a Block session
// is "all or nothing", it can only read whole blocks (i.e. multiples of
// 512 bytes), so delegate block access to this subclass, and the caller
// will call memcpy() on a subset of the whole block bytes if needed.
WholeBlock_Read(Block::Connection<> & block, int64_t bytecount, int64_t offset)
: _block( block ),
_packet(),
buffer( nullptr )
{
Genode::size_t const sector_size = _block.info().block_size;

// Calculate the "rounded" bytesize (might differ from bytecount)
//
Genode::size_t const sector_count = (bytecount + sector_size-1)/sector_size;// * _block.info().block_size;
Genode::size_t const bytesize = sector_count * sector_size;

// Genode::log( " reading ", sector_count, " blocks starting from block #", offset/sector_size );

//assert(offset);
if (offset % sector_size != 0)
Genode::error ("offset is not a multiple of sector size ! not implemented !");

_packet.construct(
_block.tx()->alloc_packet(bytesize),
Block::Packet_descriptor::READ,
offset/sector_size, // asserted above
sector_count);
_block.tx()->submit_packet(*_packet);
*_packet = _block.tx()->get_acked_packet();

if (_packet->succeeded() && _packet->size() == bytesize) {
buffer = _block.tx()->packet_content(*_packet);
} else {
Genode::error(__func__, " failed at sector ", offset/sector_size, " -- p.size: ", _packet->size());//sector, ", bytecount ", bytecount);
}
}

~WholeBlock_Read()
{
_block.tx()->release_packet(*_packet);
}

// in
Block::Connection<> & _block;

// out
Genode::Constructible<Block::Packet_descriptor> _packet;
const char * buffer;
};

struct Blockdev
{
Genode::Env &_env;
Genode::Allocator &_alloc;
Genode::Allocator_avl _tx_alloc { &_alloc };

Block::Connection<> _block { _env, &_tx_alloc, 512*1024 };
Block::Session::Info const _info { _block.info() };

Blockdev(Genode::Env &env, Genode::Allocator &alloc)
: _env(env), _alloc(alloc) { }

int pwrite(const void * buf, uint64_t bytesize, int64_t byteoffset)
{
if (!_block.info().writeable) { return 0; }

Genode::size_t const sector_size = _block.info().block_size;

//assert(writing exactly whole blocks);
//otherwise let's leave it to the CALLER to de-derp...
if (byteoffset % sector_size != 0)
Genode::error ("pwrite: offset is not a multiple of sector size ! not implemented !");
if (bytesize % sector_size != 0)
Genode::error ("pwrite: count is not a multiple of sector size ! not implemented !");

Block::Packet_descriptor p(_block.tx()->alloc_packet(bytesize),
Block::Packet_descriptor::WRITE,
byteoffset/sector_size, // asserted above
bytesize/sector_size);
_block.tx()->submit_packet(p);
p = _block.tx()->get_acked_packet();

if (p.succeeded() && p.size() == bytesize) {
//result = EOK;
} else {
Genode::error(__func__, " failed at sector ", byteoffset/sector_size, " -- p.size: ", p.size());
}

_block.tx()->release_packet(p);

return bytesize;
}

int pread(void * buf, int64_t count, int64_t offset)
{
//Genode::log( " reading ", count, " bytes at byte-offset: ", offset );

int result = 0; // default to failure (zero bytes read)
#if 0
if (p.succeeded() && p.size() == bytesize) {
char const * const content = _block.tx()->packet_content(p);
dump(content, bytesize);
Genode::memcpy(buf, content, bytesize);
result = bytesize;//0;//EOK;
} else {
Genode::error(__func__, " failed at sector ", offset/sector_size, " -- p.size: ", p.size());//sector, ", count ", count);
//Genode::error("could not read lba: ", lba, " count: ", count);
}
#else
WholeBlock_Read whole( _block, count, offset );
if (whole.buffer) {
dump(whole.buffer, count);
Genode::memcpy(buf, whole.buffer, count); // count is inferior or equal to packet.size()
return count;
} else {
//return 0;
}
#endif

return result;
}
};


@@ -0,0 +1,16 @@
if {[get_cmd_switch --autopilot] && [have_board riscv_qemu]} {
puts "Autopilot mode is not supported on this platform."
exit 0
}

set mkfs_cmd [error use mkfs.ntfs or such]
#set mkfs_cmd [installed_command mkfs.vfat]
#set mkfs_opts "-F32 -nlibc_vfs"

set test_build_components lib/vfs/fusefs-ntfs-3g
set test_vfs_config "<fusefs-ntfs-3g/>"
set test_boot_modules fusefs-ntfs-3g.lib.so

set use_vfs_server 1

source ${genode_dir}/repos/libports/run/libc_vfs_filesystem_test.inc

0 comments on commit b4c5ebe

Please sign in to comment.