7#include "pedigree/kernel/machine/Disk.h"
8#include "pedigree/kernel/machine/DiskPaging.h"
9#include "pedigree/kernel/panic.h"
10#include "pedigree/kernel/process/TerminationDeferral.h"
11#include "pedigree/kernel/process/Thread.h"
12#include "pedigree/kernel/process/WaitQueue.h"
13#include "pedigree/kernel/processor/Processor.h"
14#include "pedigree/kernel/processor/ProcessorInformation.h"
21 bool published =
false;
22 bool retiring =
false;
24 bool preparing =
false;
34uint32_t nextEndpointId = 1;
45DiskUse::DiskUse() : m_Endpoint(nullptr) {}
46DiskUse::DiskUse(
DiskUse&& other) noexcept : m_Endpoint(other.m_Endpoint) {
47 other.m_Endpoint =
nullptr;
55 m_Endpoint = other.m_Endpoint;
56 other.m_Endpoint =
nullptr;
60void DiskUse::reset() {
63 auto guard = endpointWaiters.acquire();
67 panic(
"Disk endpoint admission underflow");
71Disk* DiskUse::get()
const {
72 return m_Endpoint ? m_Endpoint->disk :
nullptr;
74DiskUse::operator bool()
const {
75 return m_Endpoint !=
nullptr;
79 auto guard = endpointWaiters.acquire();
81 if (!disk || nextEndpointId > 0xfffff)
83 for (
auto& endpoint : endpoints) {
87 endpoint.id = nextEndpointId++;
96 auto guard = endpointWaiters.acquire();
97 if (!endpoint->retiring) {
98 endpoint->bytes = endpoint->disk->
getSize();
99 endpoint->published =
true;
104 auto guard = endpointWaiters.acquire();
105 if (!endpoint || endpoint->disk != disk || endpoint->retiring || endpoint->removal ||
106 endpoint->preparing || endpoint->channel || endpoint->users == ~
static_cast<size_t>(0))
109 use.m_Endpoint = endpoint;
112bool DiskEndpoints::acquire(uint32_t
id,
DiskUse& use) {
114 auto guard = endpointWaiters.acquire();
115 for (
auto& endpoint : endpoints) {
116 if (endpoint.id !=
id || !endpoint.disk || !endpoint.published || endpoint.retiring)
118 if (endpoint.removal || endpoint.preparing || endpoint.channel ||
119 endpoint.users == ~
static_cast<size_t>(0))
122 use.m_Endpoint = &endpoint;
128 auto guard = endpointWaiters.acquire();
129 return endpoint && endpoint->disk == disk && !endpoint->retiring ? endpoint->id : 0;
131bool DiskEndpoints::describe(uint32_t
id, uint64_t& bytes) {
132 auto guard = endpointWaiters.acquire();
133 for (
const auto& endpoint : endpoints) {
134 if (endpoint.id ==
id && endpoint.disk && endpoint.published && !endpoint.retiring) {
135 bytes = endpoint.bytes;
142size_t DiskEndpoints::snapshot(uint32_t* ids,
size_t capacity) {
145 auto guard = endpointWaiters.acquire();
147 for (
const auto& endpoint : endpoints) {
148 if (endpoint.disk && endpoint.published && !endpoint.retiring && count < capacity)
149 ids[count++] = endpoint.id;
154 auto guard = endpointWaiters.acquire();
155 if (!endpoint || endpoint->disk != disk || endpoint->retiring || endpoint->users ||
156 endpoint->preparing || endpoint->channel)
158 endpoint->removal =
true;
162 auto guard = endpointWaiters.acquire();
163 if (endpoint && endpoint->disk == disk && !endpoint->retiring)
164 endpoint->removal =
false;
171 auto guard = endpointWaiters.acquire();
172 if (endpoint->disk != disk)
174 endpoint->published =
false;
175 endpoint->retiring =
true;
176 if (!endpoint->users && !endpoint->preparing && !endpoint->channel) {
177 endpoint->disk =
nullptr;
186PagingChannel::PagingChannel() : m_Endpoint(nullptr) {}
187PagingChannel::~PagingChannel() {
190PagingStatus DiskEndpoints::prepare(uint32_t
id,
PagingChannel& channel) {
192 return PagingStatus::Busy;
196 auto guard = endpointWaiters.acquire();
197 if (channel.m_Endpoint)
198 return PagingStatus::Busy;
199 for (
auto& endpoint : endpoints) {
200 if (endpoint.id !=
id || !endpoint.disk || !endpoint.published || endpoint.retiring)
202 if (endpoint.removal || endpoint.users || endpoint.preparing || endpoint.channel)
203 return PagingStatus::Busy;
204 endpoint.preparing =
true;
205 selected = &endpoint;
210 return PagingStatus::Closed;
214 auto guard = endpointWaiters.acquire();
215 if (result == PagingStatus::Success && transport && !selected->retiring) {
216 selected->transport = transport;
217 selected->channel = &channel;
218 channel.m_Endpoint = selected;
219 selected->preparing =
false;
221 return PagingStatus::Success;
227 transport->release();
229 auto guard = endpointWaiters.acquire();
230 selected->preparing =
false;
233 return result == PagingStatus::Success ? PagingStatus::Closed : result;
235PagingStatus PagingChannel::transfer(PagingOperation operation, uint64_t offset,
void* page) {
237 return PagingStatus::Busy;
242 auto guard = endpointWaiters.acquire();
243 endpoint = m_Endpoint;
244 if (!endpoint || endpoint->channel !=
this || endpoint->closing)
245 return PagingStatus::Closed;
246 if (operation != PagingOperation::Flush &&
247 (!page || (offset % PageBytes) || offset > endpoint->bytes ||
248 PageBytes > endpoint->bytes - offset))
249 return PagingStatus::Invalid;
250 if (endpoint->transfers == ~
static_cast<size_t>(0))
251 return PagingStatus::Busy;
252 ++endpoint->transfers;
253 transport = endpoint->transport;
255 const PagingStatus result = transport->transfer(operation, offset, page);
257 auto guard = endpointWaiters.acquire();
258 --endpoint->transfers;
263PagingStatus PagingChannel::readPage(uint64_t offset,
void* page) {
264 return transfer(PagingOperation::Read, offset, page);
266PagingStatus PagingChannel::writePage(uint64_t offset,
const void* page) {
267 return transfer(PagingOperation::Write, offset,
const_cast<void*
>(page));
269PagingStatus PagingChannel::flush() {
270 return transfer(PagingOperation::Flush, 0,
nullptr);
272void PagingChannel::reset() {
276 bool ownsClosure =
false;
278 auto guard = endpointWaiters.acquire();
279 endpoint = m_Endpoint;
282 if (!endpoint->closing) {
283 endpoint->closing =
true;
286 if (ownsClosure && !endpoint->transfers) {
287 transport = endpoint->transport;
294 transport->release();
295 auto guard = endpointWaiters.acquire();
296 endpoint->transport =
nullptr;
297 endpoint->channel =
nullptr;
298 endpoint->closing =
false;
299 m_Endpoint =
nullptr;
302uint32_t PagingChannel::endpointId()
const {
303 auto guard = endpointWaiters.acquire();
304 return m_Endpoint ? m_Endpoint->id : 0;
306uint64_t PagingChannel::size()
const {
307 auto guard = endpointWaiters.acquire();
308 return m_Endpoint ? m_Endpoint->bytes : 0;
310PagingChannel::operator bool()
const {
311 auto guard = endpointWaiters.acquire();
312 return m_Endpoint !=
nullptr;
virtual size_t getSize() const
Gets the size of the disk.
virtual PagingStatus preparePagingTransport(PagingTransport *&transport)
static bool getInterrupts()
static ProcessorInformation & information()
void EXPORTED_PUBLIC panic(const char *msg) NORETURN