mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-18 21:27:56 +00:00
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user