mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-14 05:22:24 +00:00
Kernel/FUSE: Allow buffering multiple requests
It can be possible for a request to be blocked on another request, so this patch allows us to send more requests even when a request is already pending.
This commit is contained in:
parent
727881f3d1
commit
ef766b0b5f
Notes:
sideshowbarker
2024-07-17 01:23:08 +09:00
Author: https://github.com/implicitfield
Commit: ef766b0b5f
Pull-request: https://github.com/SerenityOS/serenity/pull/24281
Reviewed-by: https://github.com/ADKaster ✅
3 changed files with 70 additions and 80 deletions
|
@ -24,39 +24,38 @@ UNMAP_AFTER_INIT FUSEDevice::FUSEDevice()
|
||||||
|
|
||||||
UNMAP_AFTER_INIT FUSEDevice::~FUSEDevice() = default;
|
UNMAP_AFTER_INIT FUSEDevice::~FUSEDevice() = default;
|
||||||
|
|
||||||
ErrorOr<void> FUSEDevice::initialize_instance(OpenFileDescription const& fd)
|
ErrorOr<void> FUSEDevice::initialize_instance(OpenFileDescription const& description)
|
||||||
{
|
{
|
||||||
return m_instances.with([&](auto& instances) -> ErrorOr<void> {
|
return m_instances.with([&](auto& instances) -> ErrorOr<void> {
|
||||||
for (auto const& instance : instances)
|
VERIFY(!instances.contains(&description));
|
||||||
VERIFY(instance.fd != &fd);
|
TRY(instances.try_set(&description, {}));
|
||||||
|
|
||||||
TRY(instances.try_append({
|
|
||||||
&fd,
|
|
||||||
TRY(KBuffer::try_create_with_size("FUSE: Pending request buffer"sv, 0x21000)),
|
|
||||||
TRY(KBuffer::try_create_with_size("FUSE: Response buffer"sv, 0x21000)),
|
|
||||||
}));
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FUSEDevice::can_read(OpenFileDescription const& fd, u64) const
|
bool FUSEDevice::can_read(OpenFileDescription const& description, u64) const
|
||||||
{
|
{
|
||||||
|
bool drop = m_closing_instances.with([&](auto& closing_instances) {
|
||||||
|
auto iterator = closing_instances.find(&description);
|
||||||
|
return iterator != closing_instances.end();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (drop)
|
||||||
|
return true;
|
||||||
|
|
||||||
return m_instances.with([&](auto& instances) {
|
return m_instances.with([&](auto& instances) {
|
||||||
Optional<size_t> instance_index = {};
|
auto instance_iterator = instances.find(&description);
|
||||||
for (size_t i = 0; i < instances.size(); ++i) {
|
if (instance_iterator == instances.end()) {
|
||||||
if (instances[i].fd == &fd) {
|
|
||||||
instance_index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!instance_index.has_value()) {
|
|
||||||
VERIFY(instances.is_empty());
|
VERIFY(instances.is_empty());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& instance = instances[instance_index.value()];
|
auto const& requests_for_instance = (*instance_iterator).value;
|
||||||
return instance.buffer_ready || instance.drop_request;
|
for (auto const& request : requests_for_instance.in_reverse()) {
|
||||||
|
if (request.buffer_ready)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,56 +64,49 @@ bool FUSEDevice::can_write(OpenFileDescription const&, u64) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<size_t> FUSEDevice::read(OpenFileDescription& fd, u64, UserOrKernelBuffer& buffer, size_t size)
|
ErrorOr<size_t> FUSEDevice::read(OpenFileDescription& description, u64, UserOrKernelBuffer& buffer, size_t size)
|
||||||
{
|
{
|
||||||
|
TRY(m_closing_instances.with([&](auto& closing_instances) -> ErrorOr<void> {
|
||||||
|
bool removed = closing_instances.remove_first_matching([&](auto const* closing_description) { return closing_description == &description; });
|
||||||
|
if (removed)
|
||||||
|
return Error::from_errno(ENODEV);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (size < 0x21000)
|
||||||
|
return Error::from_errno(EIO);
|
||||||
|
|
||||||
return m_instances.with([&](auto& instances) -> ErrorOr<size_t> {
|
return m_instances.with([&](auto& instances) -> ErrorOr<size_t> {
|
||||||
Optional<size_t> instance_index = {};
|
auto instance_iterator = instances.find(&description);
|
||||||
for (size_t i = 0; i < instances.size(); ++i) {
|
if (instance_iterator == instances.end())
|
||||||
if (instances[i].fd == &fd) {
|
|
||||||
instance_index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!instance_index.has_value())
|
|
||||||
return Error::from_errno(ENODEV);
|
return Error::from_errno(ENODEV);
|
||||||
|
|
||||||
auto& instance = instances[instance_index.value()];
|
auto& requests_for_instance = (*instance_iterator).value;
|
||||||
|
|
||||||
if (instance.drop_request) {
|
for (auto& request : requests_for_instance.in_reverse()) {
|
||||||
instance.drop_request = false;
|
if (!request.buffer_ready)
|
||||||
|
continue;
|
||||||
|
|
||||||
instances.remove(instance_index.value());
|
TRY(buffer.write(request.pending_request->bytes()));
|
||||||
return Error::from_errno(ENODEV);
|
request.buffer_ready = false;
|
||||||
|
return request.pending_request->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size < 0x21000)
|
return Error::from_errno(ENOENT);
|
||||||
return Error::from_errno(EIO);
|
|
||||||
|
|
||||||
if (!instance.buffer_ready)
|
|
||||||
return Error::from_errno(ENOENT);
|
|
||||||
|
|
||||||
TRY(buffer.write(instance.pending_request->bytes()));
|
|
||||||
instance.buffer_ready = false;
|
|
||||||
return instance.pending_request->size();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<size_t> FUSEDevice::write(OpenFileDescription& description, u64, UserOrKernelBuffer const& buffer, size_t size)
|
ErrorOr<size_t> FUSEDevice::write(OpenFileDescription& description, u64, UserOrKernelBuffer const& buffer, size_t size)
|
||||||
{
|
{
|
||||||
return m_instances.with([&](auto& instances) -> ErrorOr<size_t> {
|
return m_instances.with([&](auto& instances) -> ErrorOr<size_t> {
|
||||||
Optional<size_t> instance_index = {};
|
auto instance_iterator = instances.find(&description);
|
||||||
for (size_t i = 0; i < instances.size(); ++i) {
|
|
||||||
if (instances[i].fd == &description) {
|
|
||||||
instance_index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!instance_index.has_value())
|
if (instance_iterator == instances.end())
|
||||||
return Error::from_errno(ENODEV);
|
return Error::from_errno(ENODEV);
|
||||||
|
|
||||||
auto& instance = instances[instance_index.value()];
|
auto& requests_for_instance = (*instance_iterator).value;
|
||||||
|
auto& instance = requests_for_instance.last();
|
||||||
|
|
||||||
if (instance.expecting_header) {
|
if (instance.expecting_header) {
|
||||||
memset(instance.response->data(), 0, instance.response->size());
|
memset(instance.response->data(), 0, instance.response->size());
|
||||||
|
@ -149,18 +141,18 @@ ErrorOr<size_t> FUSEDevice::write(OpenFileDescription& description, u64, UserOrK
|
||||||
ErrorOr<NonnullOwnPtr<KBuffer>> FUSEDevice::send_request_and_wait_for_a_reply(OpenFileDescription const& description, Bytes bytes)
|
ErrorOr<NonnullOwnPtr<KBuffer>> FUSEDevice::send_request_and_wait_for_a_reply(OpenFileDescription const& description, Bytes bytes)
|
||||||
{
|
{
|
||||||
return m_instances.with([&](auto& instances) -> ErrorOr<NonnullOwnPtr<KBuffer>> {
|
return m_instances.with([&](auto& instances) -> ErrorOr<NonnullOwnPtr<KBuffer>> {
|
||||||
Optional<size_t> instance_index = {};
|
auto instance_iterator = instances.find(&description);
|
||||||
for (size_t i = 0; i < instances.size(); ++i) {
|
VERIFY(instance_iterator != instances.end());
|
||||||
if (instances[i].fd == &description) {
|
auto& requests_for_instance = (*instance_iterator).value;
|
||||||
instance_index = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VERIFY(instance_index.has_value());
|
TRY(requests_for_instance.try_append({
|
||||||
auto& instance = instances[instance_index.value()];
|
&description,
|
||||||
|
TRY(KBuffer::try_create_with_size("FUSE: Pending request buffer"sv, 0x21000)),
|
||||||
|
TRY(KBuffer::try_create_with_size("FUSE: Response buffer"sv, 0x21000)),
|
||||||
|
}));
|
||||||
|
|
||||||
VERIFY(!instance.drop_request);
|
size_t instance_index = requests_for_instance.size() - 1;
|
||||||
|
auto& instance = requests_for_instance.last();
|
||||||
VERIFY(bytes.size() <= 0x21000);
|
VERIFY(bytes.size() <= 0x21000);
|
||||||
|
|
||||||
memset(instance.pending_request->data(), 0, instance.pending_request->size());
|
memset(instance.pending_request->data(), 0, instance.pending_request->size());
|
||||||
|
@ -172,7 +164,7 @@ ErrorOr<NonnullOwnPtr<KBuffer>> FUSEDevice::send_request_and_wait_for_a_reply(Op
|
||||||
(void)Thread::current()->sleep(Duration::from_microseconds(100));
|
(void)Thread::current()->sleep(Duration::from_microseconds(100));
|
||||||
|
|
||||||
auto result = KBuffer::try_create_with_bytes("FUSEDevice: Response"sv, instance.response->bytes());
|
auto result = KBuffer::try_create_with_bytes("FUSEDevice: Response"sv, instance.response->bytes());
|
||||||
instance.response_ready = false;
|
requests_for_instance.remove(instance_index);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
@ -181,15 +173,11 @@ ErrorOr<NonnullOwnPtr<KBuffer>> FUSEDevice::send_request_and_wait_for_a_reply(Op
|
||||||
void FUSEDevice::shutdown_for_description(OpenFileDescription const& description)
|
void FUSEDevice::shutdown_for_description(OpenFileDescription const& description)
|
||||||
{
|
{
|
||||||
m_instances.with([&](auto& instances) {
|
m_instances.with([&](auto& instances) {
|
||||||
Optional<size_t> instance_index = {};
|
VERIFY(instances.remove(&description));
|
||||||
for (size_t i = 0; i < instances.size(); ++i) {
|
});
|
||||||
if (instances[i].fd == &description) {
|
|
||||||
instance_index = i;
|
m_closing_instances.with([&](auto& closing_instances) {
|
||||||
break;
|
closing_instances.append(&description);
|
||||||
}
|
|
||||||
}
|
|
||||||
VERIFY(instance_index.has_value());
|
|
||||||
instances[instance_index.value()].drop_request = true;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
evaluate_block_conditions();
|
evaluate_block_conditions();
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Atomic.h>
|
#include <AK/HashMap.h>
|
||||||
#include <Kernel/Devices/CharacterDevice.h>
|
#include <Kernel/Devices/CharacterDevice.h>
|
||||||
#include <Kernel/Locking/Mutex.h>
|
#include <Kernel/Locking/Mutex.h>
|
||||||
#include <Kernel/Locking/SpinlockProtected.h>
|
#include <Kernel/Locking/SpinlockProtected.h>
|
||||||
|
@ -17,7 +17,6 @@ struct FUSEInstance {
|
||||||
OpenFileDescription const* fd = nullptr;
|
OpenFileDescription const* fd = nullptr;
|
||||||
NonnullOwnPtr<KBuffer> pending_request;
|
NonnullOwnPtr<KBuffer> pending_request;
|
||||||
NonnullOwnPtr<KBuffer> response;
|
NonnullOwnPtr<KBuffer> response;
|
||||||
bool drop_request = false;
|
|
||||||
bool buffer_ready = false;
|
bool buffer_ready = false;
|
||||||
bool response_ready = false;
|
bool response_ready = false;
|
||||||
bool expecting_header = true;
|
bool expecting_header = true;
|
||||||
|
@ -47,7 +46,8 @@ private:
|
||||||
virtual bool can_write(OpenFileDescription const&, u64) const override;
|
virtual bool can_write(OpenFileDescription const&, u64) const override;
|
||||||
virtual StringView class_name() const override { return "FUSEDevice"sv; }
|
virtual StringView class_name() const override { return "FUSEDevice"sv; }
|
||||||
|
|
||||||
SpinlockProtected<Vector<FUSEInstance>, LockRank::None> m_instances;
|
SpinlockProtected<HashMap<OpenFileDescription const*, Vector<FUSEInstance>>, LockRank::None> m_instances;
|
||||||
|
SpinlockProtected<Vector<OpenFileDescription const*>, LockRank::None> m_closing_instances;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Atomic.h>
|
||||||
#include <Kernel/FileSystem/FUSE/Definitions.h>
|
#include <Kernel/FileSystem/FUSE/Definitions.h>
|
||||||
#include <Kernel/FileSystem/OpenFileDescription.h>
|
#include <Kernel/FileSystem/OpenFileDescription.h>
|
||||||
#include <Kernel/Library/KBuffer.h>
|
#include <Kernel/Library/KBuffer.h>
|
||||||
|
@ -62,10 +63,11 @@ public:
|
||||||
if (!m_initialized)
|
if (!m_initialized)
|
||||||
TRY(handle_init());
|
TRY(handle_init());
|
||||||
|
|
||||||
auto request = TRY(create_request(opcode, nodeid, m_unique, request_body));
|
u32 unique = m_unique++;
|
||||||
|
auto request = TRY(create_request(opcode, nodeid, unique, request_body));
|
||||||
auto response = TRY(device->send_request_and_wait_for_a_reply(m_description, request->bytes()));
|
auto response = TRY(device->send_request_and_wait_for_a_reply(m_description, request->bytes()));
|
||||||
|
|
||||||
if (validate_response(*response, m_unique++).is_error())
|
if (validate_response(*response, unique).is_error())
|
||||||
return Error::from_errno(EIO);
|
return Error::from_errno(EIO);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
@ -134,7 +136,7 @@ private:
|
||||||
|
|
||||||
NonnullRefPtr<OpenFileDescription> m_description;
|
NonnullRefPtr<OpenFileDescription> m_description;
|
||||||
bool m_initialized { false };
|
bool m_initialized { false };
|
||||||
u32 m_unique { 0 };
|
Atomic<u32> m_unique { 0 };
|
||||||
|
|
||||||
u32 m_major { 0 };
|
u32 m_major { 0 };
|
||||||
u32 m_minor { 0 };
|
u32 m_minor { 0 };
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue