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:
parent
b38c5006d8
commit
52cc50174f
|
@ -116,22 +116,27 @@ class File_system::File : public Node
|
||||||
|
|
||||||
size_t read(char *dst, size_t len, seek_off_t seek_offset)
|
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;
|
return ret == -1 ? 0 : ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t write(char const *src, size_t len, seek_off_t seek_offset)
|
size_t write(char const *src, size_t len, seek_off_t seek_offset)
|
||||||
{
|
{
|
||||||
/* should we append? */
|
ssize_t ret;
|
||||||
if (seek_offset == ~0ULL) {
|
|
||||||
off_t off = rump_sys_lseek(_fd, 0, SEEK_END);
|
if (seek_offset == SEEK_TAIL)
|
||||||
if (off == -1)
|
ret = rump_sys_lseek(_fd, 0, SEEK_END) != -1 ?
|
||||||
return 0;
|
rump_sys_write(_fd, src, len) : 0;
|
||||||
seek_offset = off;
|
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;
|
return ret == -1 ? 0 : ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,18 @@ namespace File_system {
|
||||||
|
|
||||||
enum { MAX_NAME_LEN = 256, MAX_PATH_LEN = 1024 };
|
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_NAME_LEN> Name;
|
||||||
typedef Genode::Rpc_in_buffer<MAX_PATH_LEN> Path;
|
typedef Genode::Rpc_in_buffer<MAX_PATH_LEN> Path;
|
||||||
|
|
||||||
|
@ -129,11 +141,15 @@ class File_system::Packet_descriptor : public Genode::Packet_descriptor
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* 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,
|
Packet_descriptor(Packet_descriptor p,
|
||||||
Node_handle handle, Opcode op, size_t length,
|
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()),
|
Genode::Packet_descriptor(p.offset(), p.size()),
|
||||||
_handle(handle), _op(op),
|
_handle(handle), _op(op),
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#define _INCLUDE__RAM_FS__FILE_H_
|
#define _INCLUDE__RAM_FS__FILE_H_
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
|
#include <file_system_session/file_system_session.h>
|
||||||
#include <base/allocator.h>
|
#include <base/allocator.h>
|
||||||
|
|
||||||
/* local includes */
|
/* local includes */
|
||||||
|
@ -46,7 +47,9 @@ class File_system::File : public Node
|
||||||
{
|
{
|
||||||
file_size_t const chunk_used_size = _chunk.used_size();
|
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;
|
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)
|
size_t write(char const *src, size_t len, seek_off_t seek_offset)
|
||||||
{
|
{
|
||||||
if (seek_offset == (seek_off_t)(~0))
|
if (seek_offset == SEEK_TAIL)
|
||||||
seek_offset = _chunk.used_size();
|
seek_offset = _length;
|
||||||
|
|
||||||
if (seek_offset + len >= Chunk_level_0::SIZE) {
|
if (seek_offset + len >= Chunk_level_0::SIZE) {
|
||||||
len = (Chunk_level_0::SIZE-1) - seek_offset;
|
len = (Chunk_level_0::SIZE-1) - seek_offset;
|
||||||
|
|
|
@ -128,6 +128,7 @@ class Vfs_server::File : public Node
|
||||||
private:
|
private:
|
||||||
|
|
||||||
Vfs::Vfs_handle *_handle;
|
Vfs::Vfs_handle *_handle;
|
||||||
|
char const *_leaf_path; /* offset pointer to Node::_path */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
File(Vfs::File_system &vfs,
|
File(Vfs::File_system &vfs,
|
||||||
|
@ -140,7 +141,8 @@ class Vfs_server::File : public Node
|
||||||
unsigned vfs_mode =
|
unsigned vfs_mode =
|
||||||
(fs_mode-1) | (create ? Vfs::Directory_service::OPEN_MODE_CREATE : 0);
|
(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); }
|
~File() { _handle->ds().close(_handle); }
|
||||||
|
@ -160,6 +162,15 @@ class Vfs_server::File : public Node
|
||||||
{
|
{
|
||||||
Vfs::file_size res = 0;
|
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->seek(seek_offset);
|
||||||
_handle->fs().read(_handle, dst, len, res);
|
_handle->fs().read(_handle, dst, len, res);
|
||||||
return res;
|
return res;
|
||||||
|
@ -169,6 +180,15 @@ class Vfs_server::File : public Node
|
||||||
{
|
{
|
||||||
Vfs::file_size res = 0;
|
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->seek(seek_offset);
|
||||||
_handle->fs().write(_handle, src, len, res);
|
_handle->fs().write(_handle, src, len, res);
|
||||||
if (res)
|
if (res)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user