Amend File_system session with SEEK_TAIL support

Used to read or write from the end of a file when multiple packets may
be in transit.

Supported by ram_fs, rump_fs, and vfs servers.

Fixes #1775
This commit is contained in:
Emery Hemingway 2016-04-26 16:28:07 +02:00 committed by Christian Helmuth
parent b38c5006d8
commit 52cc50174f
4 changed files with 59 additions and 15 deletions

View File

@ -116,22 +116,27 @@ class File_system::File : public Node
size_t read(char *dst, size_t len, seek_off_t seek_offset)
{
ssize_t ret = rump_sys_pread(_fd, dst, len, seek_offset);
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)
{
/* should we append? */
if (seek_offset == ~0ULL) {
off_t off = rump_sys_lseek(_fd, 0, SEEK_END);
if (off == -1)
return 0;
seek_offset = off;
}
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);
ssize_t ret = rump_sys_pwrite(_fd, src, len, seek_offset);
return ret == -1 ? 0 : ret;
}

View File

@ -40,6 +40,18 @@ namespace File_system {
enum { MAX_NAME_LEN = 256, MAX_PATH_LEN = 1024 };
/**
* File offset constant for reading or writing to the end of a file
*
* Clients are unable to reliably append to the end of a file where there
* may be other writes to the same offset in the queues of other clients.
* The SEEK_TAIL constant resolves this contention by aligning packet
* operations with the end of the file at the time the packet is dequeued.
*
* SEEK_TAIL behavior with directory and symlink nodes is undefined.
*/
enum { SEEK_TAIL = ~0ULL };
typedef Genode::Rpc_in_buffer<MAX_NAME_LEN> Name;
typedef Genode::Rpc_in_buffer<MAX_PATH_LEN> Path;
@ -129,11 +141,15 @@ class File_system::Packet_descriptor : public Genode::Packet_descriptor
/**
* Constructor
*
* \param position seek offset in bytes (by default, append)
* \param position seek offset in bytes
*
* Note, if 'position' is set to 'SEEK_TAIL' read operations will read
* 'length' bytes from the end of the file while write operations will
* append length bytes at the end of the file.
*/
Packet_descriptor(Packet_descriptor p,
Node_handle handle, Opcode op, size_t length,
seek_off_t position = ~0)
seek_off_t position = SEEK_TAIL)
:
Genode::Packet_descriptor(p.offset(), p.size()),
_handle(handle), _op(op),

View File

@ -15,6 +15,7 @@
#define _INCLUDE__RAM_FS__FILE_H_
/* Genode includes */
#include <file_system_session/file_system_session.h>
#include <base/allocator.h>
/* local includes */
@ -46,7 +47,9 @@ class File_system::File : public Node
{
file_size_t const chunk_used_size = _chunk.used_size();
if (seek_offset >= _length)
if (seek_offset == SEEK_TAIL)
seek_offset = (len < _length) ? (_length - len) : 0;
else if (seek_offset >= _length)
return 0;
/*
@ -78,8 +81,8 @@ class File_system::File : public Node
size_t write(char const *src, size_t len, seek_off_t seek_offset)
{
if (seek_offset == (seek_off_t)(~0))
seek_offset = _chunk.used_size();
if (seek_offset == SEEK_TAIL)
seek_offset = _length;
if (seek_offset + len >= Chunk_level_0::SIZE) {
len = (Chunk_level_0::SIZE-1) - seek_offset;

View File

@ -128,6 +128,7 @@ class Vfs_server::File : public Node
private:
Vfs::Vfs_handle *_handle;
char const *_leaf_path; /* offset pointer to Node::_path */
public:
File(Vfs::File_system &vfs,
@ -140,7 +141,8 @@ class Vfs_server::File : public Node
unsigned vfs_mode =
(fs_mode-1) | (create ? Vfs::Directory_service::OPEN_MODE_CREATE : 0);
assert_open(vfs.open(path(), vfs_mode, &_handle, alloc));
assert_open(vfs.open(file_path, vfs_mode, &_handle, alloc));
_leaf_path = vfs.leaf_path(file_path);
}
~File() { _handle->ds().close(_handle); }
@ -160,6 +162,15 @@ class Vfs_server::File : public Node
{
Vfs::file_size res = 0;
if (seek_offset == SEEK_TAIL) {
typedef Directory_service::Stat_result Result;
Vfs::Directory_service::Stat st;
/* if stat fails, try and see if the VFS will seek to the end */
seek_offset = (_handle->ds().stat(_leaf_path, st) == Result::STAT_OK) ?
((len < st.size) ? (st.size - len) : 0) : SEEK_TAIL;
}
_handle->seek(seek_offset);
_handle->fs().read(_handle, dst, len, res);
return res;
@ -169,6 +180,15 @@ class Vfs_server::File : public Node
{
Vfs::file_size res = 0;
if (seek_offset == SEEK_TAIL) {
typedef Directory_service::Stat_result Result;
Vfs::Directory_service::Stat st;
/* if stat fails, try and see if the VFS will seek to the end */
seek_offset = (_handle->ds().stat(_leaf_path, st) == Result::STAT_OK) ?
st.size : SEEK_TAIL;
}
_handle->seek(seek_offset);
_handle->fs().write(_handle, src, len, res);
if (res)