drivers/usb_block: treat SYNC as barrier

The commit implements the SYNC and TRIM as successful NOP, while
the former is handled as an barrier to all other out-standing
requests.

Fixes #4825.
This commit is contained in:
Josef Söntgen 2023-04-27 11:37:53 +02:00 committed by Christian Helmuth
parent 280724e6b5
commit bcc454aa89

View File

@ -64,7 +64,7 @@ struct Usb::Block_driver : Usb::Completion
size_t size { 0 };
bool completed { false };
Block_request(Request &request, Request_stream::Payload const &payload)
Block_request(Request const &request, Request_stream::Payload const &payload)
: block_request(request)
{
payload.with_content(request, [&](void *addr, size_t sz) {
@ -902,12 +902,20 @@ struct Usb::Block_driver : Usb::Completion
.writeable = _writeable };
}
Response submit(Request &block_request,
Response submit(Request const &block_request,
Request_stream::Payload const &payload)
{
if (device_plugged == false)
return Response::REJECTED;
/*
* Check if there is already a request pending and wait
* until it has finished. We do this check here to implement
* 'SYNC' as barrier that waits for out-standing requests.
*/
if (request_pending())
return Response::RETRY;
Operation const &op = block_request.operation;
/* read only */
@ -924,12 +932,16 @@ struct Usb::Block_driver : Usb::Completion
if (!force_cmd_16 && last >= ~0U)
return Response::REJECTED;
/* check if request is pending */
if (request_pending())
return Response::RETRY;
request.construct(block_request, payload);
/* operations currently handled as successful NOP */
if (request->block_request.operation.type == Operation::Type::TRIM
|| request->block_request.operation.type == Operation::Type::SYNC) {
request->block_request.success = true;
request->completed = true;
return Response::ACCEPTED;
}
/* execute */
send_cbw(op.block_number, op.count, request->read());
@ -1000,28 +1012,31 @@ struct Usb::Main : Rpc_object<Typed_root<Block::Session>>
{
if (!block_session.constructed()) return;
bool progress;
do {
progress = false;
/* ack and release possibly pending packet */
block_session->try_acknowledge([&] (Block_session_component::Ack &ack) {
driver.with_completed([&] (Block::Request &request) {
driver.with_completed([&] (Block::Request const &request) {
ack.submit(request);
progress = true;
});
});
block_session->with_requests([&] (Request request) {
/* only read/write for now */
if (Operation::has_payload(request.operation.type) == false) {
request.success = true;
return Response::REJECTED;
}
block_session->with_requests([&] (Request const request) {
Response response = Response::RETRY;
block_session->with_payload([&] (Request_stream::Payload const &payload) {
response = driver.submit(request, payload);
});
if (response != Response::RETRY)
progress = true;
return response;
});
} while (progress);
block_session->wakeup_client_if_needed();
}