Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <Kernel/Devices/BlockDevice.h>
8#include <Kernel/FileSystem/SysFS/Subsystems/DeviceIdentifiers/BlockDevicesDirectory.h>
9
10namespace Kernel {
11
12AsyncBlockDeviceRequest::AsyncBlockDeviceRequest(Device& block_device, RequestType request_type, u64 block_index, u32 block_count, UserOrKernelBuffer const& buffer, size_t buffer_size)
13 : AsyncDeviceRequest(block_device)
14 , m_block_device(static_cast<BlockDevice&>(block_device))
15 , m_request_type(request_type)
16 , m_block_index(block_index)
17 , m_block_count(block_count)
18 , m_buffer(buffer)
19 , m_buffer_size(buffer_size)
20{
21}
22
23void AsyncBlockDeviceRequest::start()
24{
25 m_block_device.start_request(*this);
26}
27
28BlockDevice::~BlockDevice() = default;
29
30void BlockDevice::after_inserting_add_symlink_to_device_identifier_directory()
31{
32 VERIFY(m_symlink_sysfs_component);
33 SysFSBlockDevicesDirectory::the().devices_list({}).with([&](auto& list) -> void {
34 list.append(*m_symlink_sysfs_component);
35 });
36}
37
38void BlockDevice::before_will_be_destroyed_remove_symlink_from_device_identifier_directory()
39{
40 VERIFY(m_symlink_sysfs_component);
41 SysFSBlockDevicesDirectory::the().devices_list({}).with([&](auto& list) -> void {
42 list.remove(*m_symlink_sysfs_component);
43 });
44}
45
46// FIXME: This method will be eventually removed after all nodes in /sys/dev/block/ are symlinks
47void BlockDevice::after_inserting_add_to_device_identifier_directory()
48{
49 VERIFY(m_sysfs_component);
50 SysFSBlockDevicesDirectory::the().devices_list({}).with([&](auto& list) -> void {
51 list.append(*m_sysfs_component);
52 });
53}
54
55// FIXME: This method will be eventually removed after all nodes in /sys/dev/block/ are symlinks
56void BlockDevice::before_will_be_destroyed_remove_from_device_identifier_directory()
57{
58 VERIFY(m_sysfs_component);
59 SysFSBlockDevicesDirectory::the().devices_list({}).with([&](auto& list) -> void {
60 list.remove(*m_sysfs_component);
61 });
62}
63
64bool BlockDevice::read_block(u64 index, UserOrKernelBuffer& buffer)
65{
66 auto read_request_or_error = try_make_request<AsyncBlockDeviceRequest>(AsyncBlockDeviceRequest::Read, index, 1, buffer, m_block_size);
67 if (read_request_or_error.is_error()) {
68 dbgln("BlockDevice::read_block({}): try_make_request failed", index);
69 return false;
70 }
71 auto read_request = read_request_or_error.release_value();
72 switch (read_request->wait().request_result()) {
73 case AsyncDeviceRequest::Success:
74 return true;
75 case AsyncDeviceRequest::Failure:
76 dbgln("BlockDevice::read_block({}) IO error", index);
77 break;
78 case AsyncDeviceRequest::MemoryFault:
79 dbgln("BlockDevice::read_block({}) EFAULT", index);
80 break;
81 case AsyncDeviceRequest::Cancelled:
82 dbgln("BlockDevice::read_block({}) cancelled", index);
83 break;
84 default:
85 VERIFY_NOT_REACHED();
86 }
87 return false;
88}
89
90bool BlockDevice::write_block(u64 index, UserOrKernelBuffer const& buffer)
91{
92 auto write_request_or_error = try_make_request<AsyncBlockDeviceRequest>(AsyncBlockDeviceRequest::Write, index, 1, buffer, m_block_size);
93 if (write_request_or_error.is_error()) {
94 dbgln("BlockDevice::write_block({}): try_make_request failed", index);
95 return false;
96 }
97 auto write_request = write_request_or_error.release_value();
98 switch (write_request->wait().request_result()) {
99 case AsyncDeviceRequest::Success:
100 return true;
101 case AsyncDeviceRequest::Failure:
102 dbgln("BlockDevice::write_block({}) IO error", index);
103 break;
104 case AsyncDeviceRequest::MemoryFault:
105 dbgln("BlockDevice::write_block({}) EFAULT", index);
106 break;
107 case AsyncDeviceRequest::Cancelled:
108 dbgln("BlockDevice::write_block({}) cancelled", index);
109 break;
110 default:
111 VERIFY_NOT_REACHED();
112 }
113 return false;
114}
115
116}