vfs: simplify File_io_service::write return values

This patch removes the 'Insufficient_buffer' exception by returning the
WRITE_ERR_WOULD_BLOCK result value instead. It also eliminates the
superfluous WRITE_ERR_AGAIN and WRITE_ERR_INTERRUPT codes.

Issue #4697
This commit is contained in:
Norman Feske 2022-12-06 17:04:26 +01:00 committed by Christian Helmuth
parent d9f5dda322
commit cf87b0fadb
20 changed files with 228 additions and 321 deletions

View File

@ -159,7 +159,7 @@ class Vfs::Rump_file_system : public File_system
case EWOULDBLOCK: return WRITE_ERR_WOULD_BLOCK; case EWOULDBLOCK: return WRITE_ERR_WOULD_BLOCK;
case EINVAL: return WRITE_ERR_INVALID; case EINVAL: return WRITE_ERR_INVALID;
case EIO: return WRITE_ERR_IO; case EIO: return WRITE_ERR_IO;
case EINTR: return WRITE_ERR_INTERRUPT; case EINTR: return WRITE_ERR_IO;
default: default:
Genode::error(__func__, ": unhandled rump error ", errno); Genode::error(__func__, ": unhandled rump error ", errno);
return WRITE_ERR_IO; return WRITE_ERR_IO;

View File

@ -174,31 +174,25 @@ namespace Util {
bool completed = false; bool completed = false;
file_size out = 0; file_size out = 0;
Result result = Result::WRITE_ERR_INVALID;
try {
result = _handle.fs().write(&_handle,
_data + _current_offset,
_current_count, out);
} catch (Vfs::File_io_service::Insufficient_buffer) {
return progress;
}
if ( result == Result::WRITE_ERR_AGAIN Result const result =
|| result == Result::WRITE_ERR_INTERRUPT _handle.fs().write(&_handle, _data + _current_offset,
|| result == Result::WRITE_ERR_WOULD_BLOCK) { _current_count, out);
switch (result) {
case Result::WRITE_ERR_WOULD_BLOCK:
return progress; return progress;
} else
if (result == Result::WRITE_OK) { case Result::WRITE_OK:
_current_offset += out; _current_offset += out;
_current_count -= out; _current_count -= out;
_success = true; _success = true;
} else break;
if ( result == Result::WRITE_ERR_IO case Result::WRITE_ERR_IO:
|| result == Result::WRITE_ERR_INVALID) { case Result::WRITE_ERR_INVALID:
_success = false; _success = false;
completed = true; completed = true;
break;
} }
if (_current_count == 0 || completed || (out == 0 && _allow_partial)) { if (_current_count == 0 || completed || (out == 0 && _allow_partial)) {

View File

@ -70,15 +70,16 @@ Crypto::Result Crypto::add_key(Key const &key)
_add_key_handle.seek(0); _add_key_handle.seek(0);
file_size nr_of_written_bytes { 0 }; file_size nr_of_written_bytes { 0 };
try {
_add_key_handle.fs().write(
&_add_key_handle, buffer, sizeof (buffer),
nr_of_written_bytes);
} catch (File_io_service::Insufficient_buffer) { using Write_result = Vfs::File_io_service::Write_result;
Write_result const result =
_add_key_handle.fs().write(&_add_key_handle, buffer, sizeof (buffer),
nr_of_written_bytes);
if (result == Write_result::WRITE_ERR_WOULD_BLOCK)
return Result::RETRY_LATER; return Result::RETRY_LATER;
}
Key_directory &key_dir { _get_unused_key_dir() }; Key_directory &key_dir { _get_unused_key_dir() };
key_dir.encrypt_handle = &vfs_open_rw( key_dir.encrypt_handle = &vfs_open_rw(
@ -98,17 +99,17 @@ Crypto::Result Crypto::remove_key(Cbe::Key::Id key_id)
{ {
Vfs::file_size written = 0; Vfs::file_size written = 0;
_remove_key_handle.seek(0); _remove_key_handle.seek(0);
try {
using Write_result = Vfs::File_io_service::Write_result;
Write_result const result =
_remove_key_handle.fs().write(&_remove_key_handle, _remove_key_handle.fs().write(&_remove_key_handle,
(char const*)&key_id.value, (char const*)&key_id.value,
sizeof (key_id.value), sizeof (key_id.value),
written); written);
(void)written;
} catch (Vfs::File_io_service::Insufficient_buffer) {
if (result == Write_result::WRITE_ERR_WOULD_BLOCK)
return Result::RETRY_LATER; return Result::RETRY_LATER;
}
Key_directory &key_dir { _lookup_key_dir(key_id.value) }; Key_directory &key_dir { _lookup_key_dir(key_id.value) };
_env.root_dir().close(key_dir.encrypt_handle); _env.root_dir().close(key_dir.encrypt_handle);
key_dir.encrypt_handle = nullptr; key_dir.encrypt_handle = nullptr;
@ -200,22 +201,17 @@ void Crypto::_execute_decrypt_block(Job &job,
{ {
job.handle->seek(job.request.block_number() * Cbe::BLOCK_SIZE); job.handle->seek(job.request.block_number() * Cbe::BLOCK_SIZE);
file_size nr_of_written_bytes { 0 }; file_size nr_of_written_bytes { 0 };
try {
job.handle->fs().write(
job.handle,
reinterpret_cast<char const*>(
&cipher_buf.item(job.cipher_buf_idx)),
file_size(sizeof (Cbe::Block_data)),
nr_of_written_bytes);
job.state = Job_state::OP_WRITTEN_TO_VFS_HANDLE; job.handle->fs().write(
progress = true; job.handle,
return; reinterpret_cast<char const*>(
&cipher_buf.item(job.cipher_buf_idx)),
file_size(sizeof (Cbe::Block_data)),
nr_of_written_bytes);
} catch (Vfs::File_io_service::Insufficient_buffer) { job.state = Job_state::OP_WRITTEN_TO_VFS_HANDLE;
progress = true;
return; return;
}
} }
case Job_state::OP_WRITTEN_TO_VFS_HANDLE: case Job_state::OP_WRITTEN_TO_VFS_HANDLE:
{ {
@ -271,22 +267,17 @@ void Crypto::_execute_encrypt_block(Job &job,
{ {
job.handle->seek(job.request.block_number() * Cbe::BLOCK_SIZE); job.handle->seek(job.request.block_number() * Cbe::BLOCK_SIZE);
file_size nr_of_written_bytes { 0 }; file_size nr_of_written_bytes { 0 };
try {
job.handle->fs().write(
job.handle,
reinterpret_cast<char const*>(
&plain_buf.item(job.plain_buf_idx)),
file_size(sizeof (Cbe::Block_data)),
nr_of_written_bytes);
job.state = Job_state::OP_WRITTEN_TO_VFS_HANDLE; job.handle->fs().write(
progress = true; job.handle,
return; reinterpret_cast<char const*>(
&plain_buf.item(job.plain_buf_idx)),
file_size(sizeof (Cbe::Block_data)),
nr_of_written_bytes);
} catch (Vfs::File_io_service::Insufficient_buffer) { job.state = Job_state::OP_WRITTEN_TO_VFS_HANDLE;
progress = true;
return; return;
}
} }
case Job_state::OP_WRITTEN_TO_VFS_HANDLE: case Job_state::OP_WRITTEN_TO_VFS_HANDLE:
{ {

View File

@ -393,22 +393,14 @@ class Vfs_block_io_job
reinterpret_cast<char *>( reinterpret_cast<char *>(
&io_data.item(_cbe_req_io_buf_idx(_cbe_req))) }; &io_data.item(_cbe_req_io_buf_idx(_cbe_req))) };
Result result; Result const result =
try { _handle.fs().write(&_handle,
result = _handle.fs().write(&_handle, data + _nr_of_processed_bytes,
data + _nr_of_processed_bytes, _nr_of_remaining_bytes,
_nr_of_remaining_bytes, nr_of_written_bytes);
nr_of_written_bytes);
} catch (Vfs::File_io_service::Insufficient_buffer) {
return;
}
switch (result) { switch (result) {
case Result::WRITE_ERR_AGAIN:
case Result::WRITE_ERR_INTERRUPT:
case Result::WRITE_ERR_WOULD_BLOCK: case Result::WRITE_ERR_WOULD_BLOCK:
return; return;
case Result::WRITE_OK: case Result::WRITE_OK:

View File

@ -37,22 +37,12 @@ void Trust_anchor::_execute_write_read_operation(Vfs_handle &file,
case Job_state::WRITE_IN_PROGRESS: case Job_state::WRITE_IN_PROGRESS:
{ {
file_size nr_of_written_bytes { 0 }; file_size nr_of_written_bytes { 0 };
Write_result result { Write_result::WRITE_ERR_INVALID }; Write_result const result =
try { file.fs().write(&file, write_buf + _job.fl_offset,
result = _job.fl_size, nr_of_written_bytes);
file.fs().write(
&file, write_buf + _job.fl_offset,
_job.fl_size, nr_of_written_bytes);
} catch (Vfs::File_io_service::Insufficient_buffer) {
return;
}
switch (result) { switch (result) {
case Write_result::WRITE_ERR_AGAIN:
case Write_result::WRITE_ERR_INTERRUPT:
case Write_result::WRITE_ERR_WOULD_BLOCK:
case Write_result::WRITE_ERR_WOULD_BLOCK:
return; return;
case Write_result::WRITE_OK: case Write_result::WRITE_OK:
@ -155,22 +145,14 @@ void Trust_anchor::_execute_write_operation(Vfs_handle &file,
case Job_state::WRITE_IN_PROGRESS: case Job_state::WRITE_IN_PROGRESS:
{ {
file_size nr_of_written_bytes { 0 }; file_size nr_of_written_bytes { 0 };
Write_result result { Write_result::WRITE_ERR_INVALID }; Write_result const result =
try { file.fs().write(
result = &file, write_buf + _job.fl_offset,
file.fs().write( _job.fl_size, nr_of_written_bytes);
&file, write_buf + _job.fl_offset,
_job.fl_size, nr_of_written_bytes);
} catch (Vfs::File_io_service::Insufficient_buffer) {
return;
}
switch (result) { switch (result) {
case Write_result::WRITE_ERR_AGAIN:
case Write_result::WRITE_ERR_INTERRUPT:
case Write_result::WRITE_ERR_WOULD_BLOCK:
case Write_result::WRITE_ERR_WOULD_BLOCK:
return; return;
case Write_result::WRITE_OK: case Write_result::WRITE_OK:

View File

@ -248,30 +248,27 @@ class Vfs_replay
bool completed = false; bool completed = false;
file_size out = 0; file_size out = 0;
Result result = Result::WRITE_ERR_INVALID; Result const result =
try { _vfs_handle->fs().write(_vfs_handle,
result = _vfs_handle->fs().write(_vfs_handle, _write_buffer.local_addr<char>(),
_write_buffer.local_addr<char>(), request.current_count, out);
request.current_count, out); switch (result) {
} catch (Vfs::File_io_service::Insufficient_buffer) { case Result::WRITE_ERR_WOULD_BLOCK:
return progress; return progress;
}
if ( result == Result::WRITE_ERR_AGAIN case Result::WRITE_OK:
|| result == Result::WRITE_ERR_INTERRUPT
|| result == Result::WRITE_ERR_WOULD_BLOCK) {
return progress;
}
if (result == Result::WRITE_OK) {
request.current_offset += out; request.current_offset += out;
request.current_count -= out; request.current_count -= out;
request.success = true; request.success = true;
} break;
if ( result == Result::WRITE_ERR_IO case Result::WRITE_ERR_IO:
|| result == Result::WRITE_ERR_INVALID) { case Result::WRITE_ERR_INVALID:
request.success = false; request.success = false;
completed = true; completed = true;
break;
} }
if (request.current_count == 0 || completed) { if (request.current_count == 0 || completed) {
request.state = Request::State::WRITE_COMPLETE; request.state = Request::State::WRITE_COMPLETE;
} else { } else {

View File

@ -233,7 +233,7 @@ class Vfs_audit::File_system : public Vfs::File_system
if (result == WRITE_OK) if (result == WRITE_OK)
_log("wrote to ", h.path, " ", out, " / ", len); _log("wrote to ", h.path, " ", out, " / ", len);
else if (result == WRITE_ERR_WOULD_BLOCK || result == WRITE_ERR_AGAIN) else if (result == WRITE_ERR_WOULD_BLOCK)
_log("write stalled for ", h.path); _log("write stalled for ", h.path);
else else
_log("write failed for ", h.path); _log("write failed for ", h.path);

View File

@ -152,33 +152,27 @@ namespace Vfs_cbe {
bool completed = false; bool completed = false;
file_size out = 0; file_size out = 0;
Result result = Result::WRITE_ERR_INVALID; char const * const data =
try { reinterpret_cast<char const * const>(&io_data.item(_index));
char const * const data =
reinterpret_cast<char const * const>(&io_data.item(_index));
result = _handle.fs().write(&_handle,
data + _current_offset,
_current_count, out);
} catch (Vfs::File_io_service::Insufficient_buffer) {
return progress;
}
if ( result == Result::WRITE_ERR_AGAIN Result const result =
|| result == Result::WRITE_ERR_INTERRUPT _handle.fs().write(&_handle, data + _current_offset,
|| result == Result::WRITE_ERR_WOULD_BLOCK) { _current_count, out);
switch (result) {
case Result::WRITE_ERR_WOULD_BLOCK:
return progress; return progress;
} else
if (result == Result::WRITE_OK) { case Result::WRITE_OK:
_current_offset += out; _current_offset += out;
_current_count -= out; _current_count -= out;
_success = true; _success = true;
} else break;
if ( result == Result::WRITE_ERR_IO case Result::WRITE_ERR_IO:
|| result == Result::WRITE_ERR_INVALID) { case Result::WRITE_ERR_INVALID:
_success = false; _success = false;
completed = true; completed = true;
break;
} }
if (_current_count == 0 || completed) { if (_current_count == 0 || completed) {

View File

@ -1185,14 +1185,15 @@ class Vfs_cbe::Wrapper
file_size written = 0; file_size written = 0;
_add_key_handle->seek(0); _add_key_handle->seek(0);
try {
using Write_result = Vfs::File_io_service::Write_result;
Write_result const result =
_add_key_handle->fs().write(_add_key_handle, _add_key_handle->fs().write(_add_key_handle,
buffer, sizeof (buffer), written); buffer, sizeof (buffer), written);
(void)written;
} catch (Vfs::File_io_service::Insufficient_buffer) { if (result == Write_result::WRITE_ERR_WOULD_BLOCK)
/* try again later */ break; /* try again later */
break;
}
/* /*
* Instead of acknowledge the CBE's request before we write * Instead of acknowledge the CBE's request before we write
@ -1278,16 +1279,17 @@ class Vfs_cbe::Wrapper
file_size written = 0; file_size written = 0;
_remove_key_handle->seek(0); _remove_key_handle->seek(0);
try {
using Write_result = Vfs::File_io_service::Write_result;
Write_result const result =
_remove_key_handle->fs().write(_remove_key_handle, _remove_key_handle->fs().write(_remove_key_handle,
(char const*)&key_id.value, (char const*)&key_id.value,
sizeof (key_id.value), sizeof (key_id.value),
written); written);
(void)written;
} catch (Vfs::File_io_service::Insufficient_buffer) { if (result == Write_result::WRITE_ERR_WOULD_BLOCK)
/* try again later */ break; /* try again later */
break;
}
Crypto_file *cf = nullptr; Crypto_file *cf = nullptr;
try { try {
@ -1395,14 +1397,13 @@ class Vfs_cbe::Wrapper
case Crypto_job::State::IDLE: case Crypto_job::State::IDLE:
break; break;
case Crypto_job::State::SUBMITTED: case Crypto_job::State::SUBMITTED:
try { {
char const *data = nullptr; char const *data = nullptr;
if (op == Crypto_job::Operation::ENCRYPT) { if (op == Crypto_job::Operation::ENCRYPT) {
data = reinterpret_cast<char const*>(&plain.item(plain_index)); data = reinterpret_cast<char const*>(&plain.item(plain_index));
} else }
else if (op == Crypto_job::Operation::DECRYPT) {
if (op == Crypto_job::Operation::DECRYPT) {
data = reinterpret_cast<char const*>(&cipher.item(cipher_index)); data = reinterpret_cast<char const*>(&cipher.item(cipher_index));
} }
@ -1413,16 +1414,14 @@ class Vfs_cbe::Wrapper
if (op == Crypto_job::Operation::ENCRYPT) { if (op == Crypto_job::Operation::ENCRYPT) {
cbe.crypto_cipher_data_requested(plain_index); cbe.crypto_cipher_data_requested(plain_index);
} else }
else if (op == Crypto_job::Operation::DECRYPT) {
if (op == Crypto_job::Operation::DECRYPT) {
cbe.crypto_plain_data_requested(cipher_index); cbe.crypto_plain_data_requested(cipher_index);
} }
state = Crypto_job::State::PENDING; state = Crypto_job::State::PENDING;
result.progress |= true; result.progress |= true;
} catch (Vfs::File_io_service::Insufficient_buffer) { } }
[[fallthrough]]; [[fallthrough]];
case Crypto_job::State::PENDING: case Crypto_job::State::PENDING:
@ -1939,9 +1938,9 @@ class Vfs_cbe::Data_file_system : public Single_file_system
State state = _w.frontend_request().state; State state = _w.frontend_request().state;
if (state == State::NONE) { if (state == State::NONE) {
if (!_w.client_request_acceptable()) { if (!_w.client_request_acceptable())
throw Insufficient_buffer(); return Write_result::WRITE_ERR_WOULD_BLOCK;
}
using Op = Cbe::Request::Operation; using Op = Cbe::Request::Operation;
bool const accepted = bool const accepted =
@ -1956,7 +1955,7 @@ class Vfs_cbe::Data_file_system : public Single_file_system
if ( state == State::PENDING if ( state == State::PENDING
|| state == State::IN_PROGRESS) { || state == State::IN_PROGRESS) {
_w.enqueue_handle(*this); _w.enqueue_handle(*this);
throw Insufficient_buffer(); return WRITE_ERR_WOULD_BLOCK;
} }
if (state == State::COMPLETE) { if (state == State::COMPLETE) {

View File

@ -98,7 +98,6 @@ class Vfs_import::File_system : public Vfs::File_system
dst_handle, target.string(), count, out_count); dst_handle, target.string(), count, out_count);
switch (wres) { switch (wres) {
case WRITE_ERR_AGAIN:
case WRITE_ERR_WOULD_BLOCK: case WRITE_ERR_WOULD_BLOCK:
break; break;
default: default:
@ -151,41 +150,35 @@ class Vfs_import::File_system : public Vfs::File_system
if (!bytes_from_source) break; if (!bytes_from_source) break;
bool stalled { false };
bool write_error { false }; bool write_error { false };
Vfs::file_size remaining_bytes { bytes_from_source }; Vfs::file_size remaining_bytes { bytes_from_source };
char const *src { buf }; char const *src { buf };
while (remaining_bytes > 0 && !write_error) { while (remaining_bytes > 0 && !write_error) {
try { Vfs::file_size out_count { 0 };
Vfs::file_size out_count { 0 };
switch (dst_handle->fs().write(dst_handle, src,
remaining_bytes,
out_count)) {
case WRITE_ERR_AGAIN:
case WRITE_ERR_WOULD_BLOCK:
stalled = true;
break;
case Write_result::WRITE_ERR_INVALID:
case Write_result::WRITE_ERR_IO:
case Write_result::WRITE_ERR_INTERRUPT:
env.root_dir().unlink(path.string());
write_error = true;
break;
case WRITE_OK:
out_count = min(remaining_bytes, out_count);
remaining_bytes -= out_count;
src += out_count;
at.value += out_count;
dst_handle->advance_seek(out_count);
break;
}
} catch (Vfs::File_io_service::Insufficient_buffer) {
stalled = true; }
if (stalled) switch (dst_handle->fs().write(dst_handle, src,
env.env().ep().wait_and_dispatch_one_io_signal(); remaining_bytes,
out_count)) {
case WRITE_ERR_WOULD_BLOCK:
env.io().commit_and_wait();
break;
case Write_result::WRITE_ERR_INVALID:
case Write_result::WRITE_ERR_IO:
env.root_dir().unlink(path.string());
write_error = true;
break;
case WRITE_OK:
out_count = min(remaining_bytes, out_count);
remaining_bytes -= out_count;
src += out_count;
at.value += out_count;
dst_handle->advance_seek(out_count);
break;
}
} }
if (write_error) if (write_error)
break; break;

View File

@ -844,9 +844,7 @@ ssize_t Libc::Vfs_plugin::write(File_descriptor *fd, const void *buf,
if (nonblocking) { if (nonblocking) {
monitor().monitor([&] { monitor().monitor([&] {
try { out_result = handle->fs().write(handle, (char const *)buf, count, out_count);
out_result = handle->fs().write(handle, (char const *)buf, count, out_count);
} catch (Vfs::File_io_service::Insufficient_buffer) { }
return Fn::COMPLETE; return Fn::COMPLETE;
}); });
} else { } else {
@ -886,23 +884,21 @@ ssize_t Libc::Vfs_plugin::write(File_descriptor *fd, const void *buf,
/* number of bytes written in one iteration */ /* number of bytes written in one iteration */
Vfs::file_size partial_out_count = 0; Vfs::file_size partial_out_count = 0;
try { char const * const src = (char const *)_buf + _offset;
char const * const src = (char const *)_buf + _offset; _out_result = _handle->fs().write(_handle, src, _count, partial_out_count);
_out_result = _handle->fs().write(_handle, src, _count, partial_out_count); if (_out_result == Result::WRITE_ERR_WOULD_BLOCK)
} catch (Vfs::File_io_service::Insufficient_buffer) { return Fn::INCOMPLETE; } return Fn::INCOMPLETE;
if (_out_result != Result::WRITE_OK) { if (_out_result != Result::WRITE_OK)
return Fn::COMPLETE; return Fn::COMPLETE;
}
/* increment byte count reported to caller */ /* increment byte count reported to caller */
_out_count += partial_out_count; _out_count += partial_out_count;
bool const write_complete = (partial_out_count == _count); bool const write_complete = (partial_out_count == _count);
if (write_complete) { if (write_complete)
return Fn::COMPLETE; return Fn::COMPLETE;
}
/* /*
* If the write has not consumed all bytes, set up * If the write has not consumed all bytes, set up
@ -941,11 +937,9 @@ ssize_t Libc::Vfs_plugin::write(File_descriptor *fd, const void *buf,
Plugin::resume_all(); Plugin::resume_all();
switch (out_result) { switch (out_result) {
case Result::WRITE_ERR_AGAIN: return Errno(EAGAIN);
case Result::WRITE_ERR_WOULD_BLOCK: return Errno(EWOULDBLOCK); case Result::WRITE_ERR_WOULD_BLOCK: return Errno(EWOULDBLOCK);
case Result::WRITE_ERR_INVALID: return Errno(EINVAL); case Result::WRITE_ERR_INVALID: return Errno(EINVAL);
case Result::WRITE_ERR_IO: return Errno(EIO); case Result::WRITE_ERR_IO: return Errno(EIO);
case Result::WRITE_ERR_INTERRUPT: return Errno(EINTR);
case Result::WRITE_OK: break; case Result::WRITE_OK: break;
} }
@ -2283,12 +2277,15 @@ int Libc::Vfs_plugin::symlink(const char *target_path, const char *link_path)
case Stage::WRITE: case Stage::WRITE:
{ {
try { typedef Vfs::File_io_service::Write_result Result;
handle->fs().write(handle, target_path, count, out_count);
} catch (Vfs::File_io_service::Insufficient_buffer) { Result result = handle->fs().write(handle, target_path,
count, out_count);
if (result == Result::WRITE_ERR_WOULD_BLOCK)
return Fn::INCOMPLETE; return Fn::INCOMPLETE;
} }
} stage = Stage::SYNC; [[fallthrough]]; stage = Stage::SYNC;
[[fallthrough]];
case Stage::SYNC: case Stage::SYNC:
{ {

View File

@ -2013,16 +2013,15 @@ class Lwip::File_system final : public Vfs::File_system, public Lwip::Directory
char const *src, file_size count, char const *src, file_size count,
file_size &out_count) override file_size &out_count) override
{ {
Write_result res = Write_result::WRITE_ERR_INVALID;
out_count = 0; out_count = 0;
if ((vfs_handle->status_flags() & OPEN_MODE_ACCMODE) == OPEN_MODE_RDONLY) if ((vfs_handle->status_flags() & OPEN_MODE_ACCMODE) == OPEN_MODE_RDONLY)
return Write_result::WRITE_ERR_INVALID; return Write_result::WRITE_ERR_INVALID;
if (Lwip_handle *handle = dynamic_cast<Lwip_handle*>(vfs_handle)) {
res = handle->write(src, count, out_count); if (Lwip_handle *handle = dynamic_cast<Lwip_handle*>(vfs_handle))
if (res == WRITE_ERR_WOULD_BLOCK) throw Insufficient_buffer(); return handle->write(src, count, out_count);
}
return res; return Write_result::WRITE_ERR_INVALID;
} }
Read_result complete_read(Vfs_handle *vfs_handle, Read_result complete_read(Vfs_handle *vfs_handle,

View File

@ -188,6 +188,8 @@ struct Vfs::Oss_file_system::Audio
} }
}; };
using Write_result = Vfs::File_io_service::Write_result;
private: private:
Audio(Audio const &); Audio(Audio const &);
@ -509,14 +511,14 @@ struct Vfs::Oss_file_system::Audio
return true; return true;
} }
bool write(char const *buf, file_size buf_size, file_size &out_size) Write_result write(char const *buf, file_size buf_size, file_size &out_size)
{ {
using namespace Genode; using namespace Genode;
out_size = 0; out_size = 0;
if (_info.ofrag_bytes == 0) if (_info.ofrag_bytes == 0)
throw Vfs::File_io_service::Insufficient_buffer(); return Write_result::WRITE_ERR_WOULD_BLOCK;
bool block_write = false; bool block_write = false;
@ -527,10 +529,8 @@ struct Vfs::Oss_file_system::Audio
unsigned stream_samples_to_write = buf_size / CHANNELS / sizeof(int16_t); unsigned stream_samples_to_write = buf_size / CHANNELS / sizeof(int16_t);
if (stream_samples_to_write == 0) { if (stream_samples_to_write == 0)
/* invalid argument */ return Write_result::WRITE_ERR_INVALID;
return false;
}
_start_output(); _start_output();
@ -554,18 +554,18 @@ struct Vfs::Oss_file_system::Audio
_out[0]->stream()->reset(); _out[0]->stream()->reset();
} }
} }
} else { } else {
/* /*
* Look up the previously allocated packet. * Look up the previously allocated packet.
* The tail pointer got incremented after allocation, * The tail pointer got incremented after allocation,
* so we need to decrement by 1. * so we need to decrement by 1.
*/ */
unsigned const tail = unsigned const tail =
(_out[0]->stream()->tail() + (_out[0]->stream()->tail() +
Audio_out::QUEUE_SIZE - 1) % Audio_out::QUEUE_SIZE - 1) %
Audio_out::QUEUE_SIZE; Audio_out::QUEUE_SIZE;
lp = _out[0]->stream()->get(tail); lp = _out[0]->stream()->get(tail);
} }
unsigned const pos = _out[0]->stream()->packet_position(lp); unsigned const pos = _out[0]->stream()->packet_position(lp);
Audio_out::Packet *rp = _out[1]->stream()->get(pos); Audio_out::Packet *rp = _out[1]->stream()->get(pos);
@ -602,14 +602,15 @@ struct Vfs::Oss_file_system::Audio
/* update info */ /* update info */
update_info_ofrag_avail_from_optr_fifo_samples(); update_info_ofrag_avail_from_optr_fifo_samples();
if (block_write) { throw Vfs::File_io_service::Insufficient_buffer(); } if (block_write)
return Write_result::WRITE_ERR_WOULD_BLOCK;
return true; return Write_result::WRITE_OK;
} }
} }
} }
return true; return Write_result::WRITE_OK;
} }
}; };
@ -665,12 +666,13 @@ class Vfs::Oss_file_system::Data_file_system : public Single_file_system
Write_result write(char const *buf, file_size buf_size, Write_result write(char const *buf, file_size buf_size,
file_size &out_count) override file_size &out_count) override
{ {
try { Write_result const result = _audio.write(buf, buf_size, out_count);
return _audio.write(buf, buf_size, out_count) ? WRITE_OK : WRITE_ERR_INVALID;
} catch (Vfs::File_io_service::Insufficient_buffer) { if (result == Write_result::WRITE_ERR_WOULD_BLOCK) {
blocked = true; blocked = true;
return WRITE_OK; return WRITE_OK;
} }
return result;
} }
bool read_ready() override bool read_ready() override

View File

@ -755,35 +755,28 @@ class Genode::Writeable_file : Noncopyable
bool stalled = false; bool stalled = false;
try { Vfs::file_size out_count = 0;
Vfs::file_size out_count = 0;
using Write_result = Vfs::File_io_service::Write_result; using Write_result = Vfs::File_io_service::Write_result;
switch (handle.fs().write(&handle, src, remaining_bytes, switch (handle.fs().write(&handle, src, remaining_bytes, out_count)) {
out_count)) {
case Write_result::WRITE_ERR_AGAIN: case Write_result::WRITE_ERR_WOULD_BLOCK:
case Write_result::WRITE_ERR_WOULD_BLOCK: stalled = true;
stalled = true; break;
break;
case Write_result::WRITE_ERR_INVALID: case Write_result::WRITE_ERR_INVALID:
case Write_result::WRITE_ERR_IO: case Write_result::WRITE_ERR_IO:
case Write_result::WRITE_ERR_INTERRUPT: write_error = true;
write_error = true; break;
break;
case Write_result::WRITE_OK: case Write_result::WRITE_OK:
out_count = min((Vfs::file_size)remaining_bytes, out_count); out_count = min((Vfs::file_size)remaining_bytes, out_count);
remaining_bytes -= (size_t)out_count; remaining_bytes -= (size_t)out_count;
src += out_count; src += out_count;
handle.advance_seek(out_count); handle.advance_seek(out_count);
break; break;
}; };
}
catch (Vfs::File_io_service::Insufficient_buffer) {
stalled = true; }
if (stalled) if (stalled)
io.commit_and_wait(); io.commit_and_wait();

View File

@ -30,16 +30,8 @@ struct Vfs::File_io_service : Interface
** Write ** ** Write **
***********/ ***********/
/* enum Write_result { WRITE_ERR_WOULD_BLOCK, WRITE_ERR_INVALID,
* Exception, thrown when, for example, 'alloc_packet()' or WRITE_ERR_IO, WRITE_OK };
* 'submit_packet()' failed in the VFS plugin. The caller can try again
* after a previous VFS request is completed.
*/
struct Insufficient_buffer { };
enum Write_result { WRITE_ERR_AGAIN, WRITE_ERR_WOULD_BLOCK,
WRITE_ERR_INVALID, WRITE_ERR_IO,
WRITE_ERR_INTERRUPT, WRITE_OK };
virtual Write_result write(Vfs_handle *vfs_handle, virtual Write_result write(Vfs_handle *vfs_handle,
char const *buf, file_size buf_size, char const *buf, file_size buf_size,

View File

@ -133,11 +133,9 @@ static inline void print(Genode::Output &output, Vfs::File_io_service::Write_res
switch (r) { switch (r) {
CASE_PRINT(WRITE_OK); CASE_PRINT(WRITE_OK);
CASE_PRINT(WRITE_ERR_AGAIN);
CASE_PRINT(WRITE_ERR_WOULD_BLOCK); CASE_PRINT(WRITE_ERR_WOULD_BLOCK);
CASE_PRINT(WRITE_ERR_INVALID); CASE_PRINT(WRITE_ERR_INVALID);
CASE_PRINT(WRITE_ERR_IO); CASE_PRINT(WRITE_ERR_IO);
CASE_PRINT(WRITE_ERR_INTERRUPT);
} }
#undef CASE_PRINT #undef CASE_PRINT

View File

@ -504,8 +504,8 @@ class Vfs::Fs_file_system : public File_system, private Remote_io
return read_num_bytes; return read_num_bytes;
} }
file_size _write(Fs_vfs_handle &handle, Write_result _write(Fs_vfs_handle &handle, file_size const seek_offset,
const char *buf, file_size count, file_size seek_offset) const char *buf, file_size count, file_size &out_count)
{ {
/* /*
* TODO * TODO
@ -524,7 +524,7 @@ class Vfs::Fs_file_system : public File_system, private Remote_io
if (!source.ready_to_submit()) { if (!source.ready_to_submit()) {
if (!handle.enqueued()) if (!handle.enqueued())
_congested_handles.enqueue(handle); _congested_handles.enqueue(handle);
throw Insufficient_buffer(); return Write_result::WRITE_ERR_WOULD_BLOCK;
} }
try { try {
@ -537,15 +537,18 @@ class Vfs::Fs_file_system : public File_system, private Remote_io
memcpy(source.packet_content(packet_in), buf, (size_t)count); memcpy(source.packet_content(packet_in), buf, (size_t)count);
_submit_packet(packet_in); _submit_packet(packet_in);
} catch (::File_system::Session::Tx::Source::Packet_alloc_failed) { }
catch (::File_system::Session::Tx::Source::Packet_alloc_failed) {
if (!handle.enqueued()) if (!handle.enqueued())
_congested_handles.enqueue(handle); _congested_handles.enqueue(handle);
throw Insufficient_buffer(); return Write_result::WRITE_ERR_WOULD_BLOCK;
} catch (...) {
Genode::error("unhandled exception");
return 0;
} }
return count; catch (...) {
Genode::error("unhandled exception");
return Write_result::WRITE_ERR_IO;
}
out_count = count;
return Write_result::WRITE_OK;
} }
void _handle_ack() void _handle_ack()
@ -967,12 +970,11 @@ class Vfs::Fs_file_system : public File_system, private Remote_io
********************************/ ********************************/
Write_result write(Vfs_handle *vfs_handle, char const *buf, Write_result write(Vfs_handle *vfs_handle, char const *buf,
file_size buf_size, file_size &out_count) override file_size count, file_size &out_count) override
{ {
Fs_vfs_handle &handle = static_cast<Fs_vfs_handle &>(*vfs_handle); Fs_vfs_handle &handle = static_cast<Fs_vfs_handle &>(*vfs_handle);
out_count = _write(handle, buf, buf_size, handle.seek()); return _write(handle, handle.seek(), buf, count, out_count);
return WRITE_OK;
} }
bool queue_read(Vfs_handle *vfs_handle, file_size count) override bool queue_read(Vfs_handle *vfs_handle, file_size count) override

View File

@ -408,25 +408,20 @@ class Vfs_server::Io_node : public Vfs_server::Node,
seek_off_t write_pos) seek_off_t write_pos)
{ {
file_size out_count = 0; file_size out_count = 0;
try { _handle.seek(_initial_write_seek_offset + write_pos);
_handle.seek(_initial_write_seek_offset + write_pos);
switch (_handle.fs().write(&_handle, src_ptr, length, out_count)) { switch (_handle.fs().write(&_handle, src_ptr, length, out_count)) {
case Write_result::WRITE_ERR_AGAIN: case Write_result::WRITE_ERR_WOULD_BLOCK:
case Write_result::WRITE_ERR_WOULD_BLOCK: break;
break;
case Write_result::WRITE_ERR_INVALID: case Write_result::WRITE_ERR_INVALID:
case Write_result::WRITE_ERR_IO: case Write_result::WRITE_ERR_IO:
case Write_result::WRITE_ERR_INTERRUPT: _acknowledge_as_failure();
_acknowledge_as_failure(); break;
break;
case Write_result::WRITE_OK: case Write_result::WRITE_OK:
break; break;
}
} }
catch (Vfs::File_io_service::Insufficient_buffer) { /* re-execute */ }
_modified = true; _modified = true;
@ -452,14 +447,11 @@ class Vfs_server::Io_node : public Vfs_server::Node,
void _execute_write_timestamp() void _execute_write_timestamp()
{ {
try { _packet.with_timestamp([&] (::File_system::Timestamp const time) {
_packet.with_timestamp([&] (::File_system::Timestamp const time) { Vfs::Timestamp ts { .value = time.value };
Vfs::Timestamp ts { .value = time.value }; _handle.fs().update_modification_timestamp(&_handle, ts);
_handle.fs().update_modification_timestamp(&_handle, ts); });
}); _acknowledge_as_success(0);
_acknowledge_as_success(0);
}
catch (Vfs::File_io_service::Insufficient_buffer) { }
_modified = true; _modified = true;
} }

View File

@ -137,6 +137,7 @@ namespace Vfs_block {
_handle.seek(base_offset + current_offset); _handle.seek(base_offset + current_offset);
state = State::IN_PROGRESS; state = State::IN_PROGRESS;
progress = true; progress = true;
[[fallthrough]]; [[fallthrough]];
case State::IN_PROGRESS: case State::IN_PROGRESS:
{ {
@ -145,31 +146,24 @@ namespace Vfs_block {
bool completed = false; bool completed = false;
file_size out = 0; file_size out = 0;
Result result = Result::WRITE_ERR_INVALID; Result result = _handle.fs().write(&_handle,
try { data + current_offset,
result = _handle.fs().write(&_handle, current_count, out);
data + current_offset, switch (result) {
current_count, out); case Result::WRITE_ERR_WOULD_BLOCK:
} catch (Vfs::File_io_service::Insufficient_buffer) {
return progress; return progress;
}
if ( result == Result::WRITE_ERR_AGAIN case Result::WRITE_OK:
|| result == Result::WRITE_ERR_INTERRUPT
|| result == Result::WRITE_ERR_WOULD_BLOCK) {
return progress;
} else
if (result == Result::WRITE_OK) {
current_offset += out; current_offset += out;
current_count -= out; current_count -= out;
success = true; success = true;
} else break;
if ( result == Result::WRITE_ERR_IO case Result::WRITE_ERR_IO:
|| result == Result::WRITE_ERR_INVALID) { case Result::WRITE_ERR_INVALID:
success = false; success = false;
completed = true; completed = true;
break;
} }
if (current_count == 0 || completed) { if (current_count == 0 || completed) {

View File

@ -95,16 +95,12 @@ inline void assert_write(Vfs::File_io_service::Write_result r)
typedef Vfs::File_io_service::Write_result Result; typedef Vfs::File_io_service::Write_result Result;
switch (r) { switch (r) {
case Result::WRITE_OK: return; case Result::WRITE_OK: return;
case Result::WRITE_ERR_AGAIN:
error("WRITE_ERR_AGAIN"); break;
case Result::WRITE_ERR_WOULD_BLOCK: case Result::WRITE_ERR_WOULD_BLOCK:
error("WRITE_ERR_WOULD_BLOCK"); break; error("WRITE_ERR_WOULD_BLOCK"); break;
case Result::WRITE_ERR_INVALID: case Result::WRITE_ERR_INVALID:
error("WRITE_ERR_INVALID"); break; error("WRITE_ERR_INVALID"); break;
case Result::WRITE_ERR_IO: case Result::WRITE_ERR_IO:
error("WRITE_ERR_IO"); break; error("WRITE_ERR_IO"); break;
case Result::WRITE_ERR_INTERRUPT:
error("WRITE_ERR_INTERRUPT"); break;
} }
throw Exception(); throw Exception();
} }