The Pedigree Project 0.1
Disk.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "pedigree/kernel/machine/Disk.h"
21#include "pedigree/kernel/process/TerminationDeferral.h"
22#include "pedigree/kernel/utilities/String.h"
23
24DiskReadView::DiskReadView()
25 : m_Owner(nullptr), m_Location(0), m_Data(nullptr), m_Size(0), m_Writable(false), m_Use() {}
26
27DiskReadView::DiskReadView(Disk* owner, uint64_t location, BufferView view, bool writable,
28 DiskUse&& use)
29 : m_Owner(owner),
30 m_Location(location),
31 m_Data(static_cast<const uint8_t*>(view.data())),
32 m_Size(view.size()),
33 m_Writable(writable),
34 m_Use(static_cast<DiskUse&&>(use)) {}
35
36DiskReadView::DiskReadView(DiskReadView&& other) noexcept : DiskReadView() {
37 *this = static_cast<DiskReadView&&>(other);
38}
39
40DiskReadView& DiskReadView::operator=(DiskReadView&& other) noexcept {
41 if (this != &other) {
42 reset();
43 m_Owner = other.m_Owner;
44 m_Location = other.m_Location;
45 m_Data = other.m_Data;
46 m_Size = other.m_Size;
47 m_Writable = other.m_Writable;
48 m_Use = static_cast<DiskUse&&>(other.m_Use);
49 other.m_Owner = nullptr;
50 other.m_Data = nullptr;
51 other.m_Size = 0;
52 }
53 return *this;
54}
55
56DiskReadView::~DiskReadView() {
57 reset();
58}
59
60DiskReadView DiskReadView::borrowed(const void* data, size_t size) {
61 DiskReadView view;
62 if (data) {
63 view.m_Data = static_cast<const uint8_t*>(data);
64 view.m_Size = size;
65 }
66 return view;
67}
68
69void DiskReadView::reset() {
70 if (m_Owner) {
71 TerminationDeferral lifetime;
72 m_Owner->releaseView(m_Location, m_Writable);
73 m_Owner = nullptr;
74 m_Data = nullptr;
75 m_Size = 0;
76 m_Use.reset();
77 return;
78 }
79 m_Data = nullptr;
80 m_Size = 0;
81 m_Use.reset();
82}
83
84Disk::Disk() : m_Endpoint(nullptr) {
85 m_SpecificType.assign("Generic Disk", 13);
86}
87
88Disk::Disk(Device* p) : Device(p), m_Endpoint(nullptr) {}
89
90Disk::~Disk() {
92}
93
94Disk* Disk::physicalDisk() {
95 return this;
96}
97
98bool Disk::acquireUse(DiskUse& use) {
99 Disk* physical = physicalDisk();
100 if (!physical) {
101 use.reset();
102 return false;
103 }
104 if (!physical->m_Endpoint) {
105 use.reset();
106 return true;
107 }
108 return DiskEndpoints::acquire(physical->m_Endpoint, physical, use);
109}
110
111uint32_t Disk::endpointId() {
112 Disk* physical = physicalDisk();
113 return physical ? DiskEndpoints::id(physical->m_Endpoint, physical) : 0;
114}
115
117 uuid.clear();
118 return false;
119}
120
121bool Disk::getPartitionLabel(String& label) const {
122 label.clear();
123 return false;
124}
125
126void Disk::reserveEndpoint() {
127 if (!m_Endpoint)
128 m_Endpoint = DiskEndpoints::reserve(this);
129}
130void Disk::publishEndpoint() {
131 DiskEndpoints::publish(m_Endpoint);
132}
134 DiskEndpoints::retire(m_Endpoint, this);
135}
136bool Disk::tryCloseEndpoint() {
137 return DiskEndpoints::tryClose(m_Endpoint, this);
138}
139void Disk::reopenEndpoint() {
140 DiskEndpoints::reopen(m_Endpoint, this);
141}
143 transport = nullptr;
144 return PagingStatus::Unsupported;
145}
146
150
151Disk::SubType Disk::getSubType() {
152 return ATA;
153}
154
156 str.assign("Generic disk", 13);
157}
158
159void Disk::dump(String& str) {
160 str.assign("Generic disk", 13);
161}
162
163BufferView Disk::read(uint64_t location) {
164 return BufferView();
165}
166
167DiskReadView Disk::readView(uint64_t location) {
168 TerminationDeferral lifetime;
169 DiskUse use;
170 if (!acquireUse(use))
171 return {};
172 uint64_t token = location;
173 const auto view = acquireView(location, false, token);
174 return view ? DiskReadView(this, token, view, false, static_cast<DiskUse&&>(use))
175 : DiskReadView();
176}
177
178DiskWriteView Disk::writeView(uint64_t location) {
179 TerminationDeferral lifetime;
180 DiskUse use;
181 if (!acquireUse(use))
182 return {};
183 uint64_t token = location;
184 const auto view = acquireView(location, true, token);
185 return view ? DiskWriteView(this, token, view, static_cast<DiskUse&&>(use)) : DiskWriteView();
186}
187
188BufferView Disk::acquireView(uint64_t location, bool writable, uint64_t& token) {
189 token = location;
190 return read(location);
191}
192
193void Disk::releaseView(uint64_t location, bool writable) {
194 if (writable)
195 write(location);
196 unpin(location);
197}
198
199bool Disk::readIntoBatch(ReadBuffer* buffers, size_t count) {
200 if (count > MaxReadBuffers || (count && !buffers))
201 return false;
202 for (size_t i = 0; i < count; ++i)
203 buffers[i].complete = false;
204 if (!count)
205 return true;
206 TerminationDeferral lifetime;
207 DiskUse diskUse;
208 if (!acquireUse(diskUse))
209 return false;
210 bool success = true;
211 for (size_t i = 0; i < count; ++i) {
212 auto& request = buffers[i];
213 request.complete = readInto(request.location, request.buffer, request.length);
214 success &= request.complete;
215 }
216 return success;
217}
218
219bool Disk::readInto(uint64_t location, void* buffer, size_t length) {
220 TerminationDeferral lifetime;
221 DiskUse diskUse;
222 if (!acquireUse(diskUse))
223 return false;
224 if ((!buffer && length) || location > getSize() || length > getSize() - location)
225 return false;
226 if (!length)
227 return true;
228
229 auto* output = static_cast<uint8_t*>(buffer);
230 while (length) {
231 const uint64_t aligned = location - location % 512;
232 const size_t offset = location - aligned;
233 const DiskReadView view = readView(aligned);
234 if (!view)
235 return false;
236 if (view.size() <= offset) {
237 return false;
238 }
239 const size_t available = view.size() - offset;
240 const size_t chunk = length < available ? length : available;
241 view.copyTo(output, chunk, offset);
242 output += chunk;
243 location += chunk;
244 length -= chunk;
245 }
246 return true;
247}
248
249bool Disk::writeFrom(uint64_t location, const void* buffer, size_t length) {
250 TerminationDeferral lifetime;
251 DiskUse diskUse;
252 if (!acquireUse(diskUse))
253 return false;
254 if ((!buffer && length) || location > getSize() || length > getSize() - location)
255 return false;
256 if (!length)
257 return true;
258
259 const auto* input = static_cast<const uint8_t*>(buffer);
260 while (length) {
261 const uint64_t aligned = location - location % 512;
262 const size_t offset = location - aligned;
263 const BufferView view = read(aligned);
264 if (!view)
265 return false;
266 if (view.size() <= offset) {
267 unpin(aligned);
268 return false;
269 }
270 const size_t available = view.size() - offset;
271 const size_t chunk = length < available ? length : available;
272 MemoryCopy(view.subview(offset, chunk).data(), input, chunk);
273 write(aligned);
274 const bool written = sync(aligned, false);
275 unpin(aligned);
276 if (!written)
277 return false;
278 input += chunk;
279 location += chunk;
280 length -= chunk;
281 }
282 return true;
283}
284
285bool Disk::writeFromBatch(WriteBuffer* buffers, size_t count) {
286 if (count > MaxWriteBuffers || (count && !buffers))
287 return false;
288 for (size_t i = 0; i < count; ++i)
289 buffers[i].complete = false;
290 bool succeeded = true;
291 for (size_t i = 0; i < count; ++i) {
292 auto& buffer = buffers[i];
293 buffer.complete = writeFrom(buffer.location, buffer.buffer, buffer.length);
294 succeeded = buffer.complete && succeeded;
295 }
296 return succeeded;
297}
298
300 return true;
301}
302
303bool Disk::readViews(uint64_t location, size_t length, BufferViewSequence& views) {
304 if (!views.empty() || location > getSize() || length > (getSize() - location)) {
305 return false;
306 }
307
308 size_t remaining = length;
309 uint64_t current = location;
310 while (remaining) {
311 const BufferView view = read(current);
312 if (!view || view.empty()) {
313 unpinViews(location, views);
314 return false;
315 }
316
317 const size_t chunk = view.size() < remaining ? view.size() : remaining;
318 if (!views.append(view.first(chunk))) {
319 unpin(current);
320 unpinViews(location, views);
321 return false;
322 }
323
324 current += chunk;
325 remaining -= chunk;
326 }
327 return true;
328}
329
330void Disk::unpinViews(uint64_t location, BufferViewSequence& views) {
331 uint64_t current = location;
332 for (size_t i = 0; i < views.count(); ++i) {
333 const BufferView view = views[i];
334 unpin(current);
335 current += view.size();
336 }
337 views.clear();
338}
339
340void Disk::write(uint64_t location) {}
341
342void Disk::align(uint64_t location) {}
343
344size_t Disk::getSize() const {
345 return 0;
346}
347
348size_t Disk::getBlockSize() const {
349 return 0;
350}
351
353 return false;
354}
355
356void Disk::flush(uint64_t location) {}
357
358bool Disk::sync(uint64_t location, bool async) {
359 return false;
360}
361
362bool Disk::syncPages(const uint64_t* locations, size_t count) {
363 if (count > MaxSyncPages || (count && !locations))
364 return false;
365 for (size_t i = 0; i < count; ++i) {
366 if (locations[i] >= getSize())
367 return false;
368 }
369 bool succeeded = true;
370 for (size_t i = 0; i < count; ++i)
371 succeeded = sync(locations[i], false) && succeeded;
372 return succeeded;
373}
374
376 return false;
377}
378
379bool Disk::retireCachePage(uint64_t location) {
380 return false;
381}
382
384 return 512;
385}
386
387bool Disk::zero(uint64_t location, size_t length) {
388 if (location > getSize() || length > getSize() - location)
389 return false;
390 while (length) {
391 const uint64_t base = location - location % 512;
392 const size_t within = location - base;
393 auto view = read(base);
394 if (!view)
395 return false;
396 if (within >= view.size()) {
397 unpin(base);
398 return false;
399 }
400 const size_t available = view.size() - within;
401 const size_t amount = length < available ? length : available;
402 ByteSet(reinterpret_cast<void*>(view.address() + within), 0, amount);
403 write(base);
404 unpin(base);
405 location += amount;
406 length -= amount;
407 }
408 return true;
409}
@ Disk
A disk device - a block device in UNIX terms.
Definition Device.h:75
static DiskReadView borrowed(const void *data, size_t size)
Definition Disk.cc:60
Definition Disk.h:35
virtual bool sync(uint64_t location, bool async)
Definition Disk.cc:358
virtual bool getPartitionUuid(String &uuid) const
Definition Disk.cc:116
virtual void align(uint64_t location)
Sets the page boundary alignment after a specific location on the disk.
Definition Disk.cc:342
void unpinViews(uint64_t location, BufferViewSequence &views)
Definition Disk.cc:330
virtual void dump(String &str)
Definition Disk.cc:159
virtual BufferView read(uint64_t location)
Definition Disk.cc:163
virtual size_t getSize() const
Gets the size of the disk.
Definition Disk.cc:344
virtual MUST_USE_RESULT bool readIntoBatch(ReadBuffer *buffers, size_t count)
Definition Disk.cc:199
void retireEndpoint()
Definition Disk.cc:133
virtual void getName(String &str)
Definition Disk.cc:155
virtual MUST_USE_RESULT bool zero(uint64_t location, size_t length)
Definition Disk.cc:387
virtual void unpin(uint64_t location)=0
virtual MUST_USE_RESULT bool writeFromBatch(WriteBuffer *buffers, size_t count)
Definition Disk.cc:285
virtual MUST_USE_RESULT bool readInto(uint64_t location, void *buffer, size_t length)
Definition Disk.cc:219
virtual MUST_USE_RESULT bool syncPages(const uint64_t *locations, size_t count)
Definition Disk.cc:362
virtual PagingStatus preparePagingTransport(PagingTransport *&transport)
Definition Disk.cc:142
MUST_USE_RESULT bool readViews(uint64_t location, size_t length, BufferViewSequence &views)
Definition Disk.cc:303
virtual Type getType()
Definition Disk.cc:147
virtual void write(uint64_t location)
Definition Disk.cc:340
virtual void flush(uint64_t location)
Flush a cached page to disk.
Definition Disk.cc:356
virtual size_t getNativeBlockSize() const
Definition Disk.cc:383
virtual DiskReadView readView(uint64_t location)
Definition Disk.cc:167
virtual size_t getBlockSize() const
Gets the preferred I/O extent of the disk.
Definition Disk.cc:348
virtual MUST_USE_RESULT bool retireCachePage(uint64_t location)
Definition Disk.cc:379
virtual MUST_USE_RESULT bool syncData()
Definition Disk.cc:299
virtual MUST_USE_RESULT bool syncAll()
Definition Disk.cc:375
virtual bool cacheIsCritical()
Whether or not the cache is critical and cannot be flushed or deleted.
Definition Disk.cc:352