From 52cc50174f64ab2bca2973b57feddb4aece68442 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Tue, 26 Apr 2016 16:28:07 +0200 Subject: [PATCH] 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 --- repos/dde_rump/src/server/rump_fs/file.h | 23 +++++++++++-------- .../file_system_session/file_system_session.h | 20 ++++++++++++++-- repos/os/include/ram_fs/file.h | 9 +++++--- repos/os/src/server/vfs/node.h | 22 +++++++++++++++++- 4 files changed, 59 insertions(+), 15 deletions(-) diff --git a/repos/dde_rump/src/server/rump_fs/file.h b/repos/dde_rump/src/server/rump_fs/file.h index dd564d404b..a77d7113af 100644 --- a/repos/dde_rump/src/server/rump_fs/file.h +++ b/repos/dde_rump/src/server/rump_fs/file.h @@ -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; } diff --git a/repos/os/include/file_system_session/file_system_session.h b/repos/os/include/file_system_session/file_system_session.h index 6460b7e8b2..9527647d23 100644 --- a/repos/os/include/file_system_session/file_system_session.h +++ b/repos/os/include/file_system_session/file_system_session.h @@ -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 Name; typedef Genode::Rpc_in_buffer 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), diff --git a/repos/os/include/ram_fs/file.h b/repos/os/include/ram_fs/file.h index 7799504928..87af09c9d3 100644 --- a/repos/os/include/ram_fs/file.h +++ b/repos/os/include/ram_fs/file.h @@ -15,6 +15,7 @@ #define _INCLUDE__RAM_FS__FILE_H_ /* Genode includes */ +#include #include /* 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; diff --git a/repos/os/src/server/vfs/node.h b/repos/os/src/server/vfs/node.h index ba3b08cc83..c4116dd3fe 100644 --- a/repos/os/src/server/vfs/node.h +++ b/repos/os/src/server/vfs/node.h @@ -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)