The Pedigree Project 0.1
Ext2File.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 "Ext2File.h"
21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/machine/Disk.h"
23#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
24#include "pedigree/kernel/syscallError.h"
25#include "pedigree/kernel/utilities/utility.h"
26
27#include "Ext2Filesystem.h"
28#include "ext2.h"
29
30class Filesystem;
31
32Ext2File::Ext2File(const String& name, uintptr_t inode_num, Inode* inode, Ext2Filesystem* pFs,
33 File* pParent)
34 : File(name, LITTLE_TO_HOST32(inode->i_atime), LITTLE_TO_HOST32(inode->i_mtime),
35 LITTLE_TO_HOST32(inode->i_ctime), inode_num, static_cast<Filesystem*>(pFs),
36 LITTLE_TO_HOST32(inode->i_size),
37 pParent),
38 Ext2Node(inode_num, inode, pFs) {
39 LockGuard<Mutex> guard(m_State->dataLock);
40 if (!m_State->cache) {
41 m_State->cache = new CacheState;
42 if (!m_State->cache) {
43 return;
44 }
45 m_State->cache->fill.setDirtyTracking(Cache::DirtyTracking::Explicit);
46 m_State->cache->fill.setCallback(sharedFillCallback, m_State);
47 m_State->cache->fill.setBackgroundWriteback(sharedFillBatchCallback);
48 }
49 {
50 LockGuard<Mutex> writebackGuard(m_State->writebackLock);
51 if (!m_State->files.tryReserve(m_State->files.count() + 1)) {
52 return;
53 }
54 m_State->files.pushBack(this);
55 }
56 if (!m_State->futexIdentity) {
57 m_State->futexIdentity = File::futexIdentity();
58 }
59 uint32_t mode = LITTLE_TO_HOST32(inode->i_mode);
60 setPermissionsOnly(modeToPermissions(mode));
61 setUidOnly(Ext2Owner::uid(*inode));
62 setGidOnly(Ext2Owner::gid(*inode));
63 m_Initialized = true;
64}
65
67 LockGuard<Mutex> guard(m_State->dataLock);
68 {
69 LockGuard<Mutex> writebackGuard(m_State->writebackLock);
70 for (size_t i = 0; i < m_State->files.count(); ++i) {
71 if (m_State->files[i] == this) {
72 m_State->files.erase(i);
73 break;
74 }
75 }
76 }
77 // Linked inode state owns the cache after the last alias closes, so failed
78 // writebacks can retry without retaining an object in its destructor.
79 if (!m_State->files.count() && m_State->cache && m_State->cache->fill.empty()) {
80 delete m_State->cache;
81 m_State->cache = nullptr;
82 }
83}
84
85File::CacheState& Ext2File::cacheState() {
86 return *m_State->cache;
87}
88
90 EMIT_IF(VFS_NOMMU) {
91 return File::useFillCache();
92 }
93 else {
94 return true;
95 }
96}
97
98File::Attributes Ext2File::getAttributes() const {
99 return inodeAttributes();
100}
101
102void Ext2File::updateAttributes(const Attributes& attributes, uint32_t mask) {
103 updateInodeAttributes(attributes, mask);
104}
105
106bool Ext2File::prepareSharedMapping(size_t offset, size_t length) {
107 OperationBarrier::Lease operation;
108 if (!m_pExt2Fs->tryAcquireOperation(operation)) {
109 return false;
110 }
111 LockGuard<Mutex> dataGuard(m_State->dataLock);
112 LockGuard<Mutex> guard(m_State->writebackLock);
113 if (m_State->quotaFile) {
114 SYSCALL_ERROR(NotEnoughPermissions);
115 return false;
116 }
117 if (m_pExt2Fs->isReadOnly()) {
118 SYSCALL_ERROR(ReadOnlyFilesystem);
119 return false;
120 }
121 if (offset >= m_nSize) {
122 SYSCALL_ERROR(InvalidArgument);
123 return false;
124 }
125 if (length > m_nSize - offset) {
126 length = m_nSize - offset;
127 }
128 const bool success = ensureWritableRange(offset, length);
129 if (!useFillCache()) {
130 LockGuard<Mutex> indexGuard(cacheState().indexLock);
131 cacheState().data.clear();
132 }
133 return success;
134}
135
136bool Ext2File::prepareWrite(uint64_t location, uint64_t size) {
137 LockGuard<Mutex> guard(m_State->writebackLock);
138 if (m_State->quotaFile && !m_State->quotaInternalWrite) {
139 SYSCALL_ERROR(NotEnoughPermissions);
140 return false;
141 }
142 if (m_pExt2Fs->isReadOnly()) {
143 SYSCALL_ERROR(ReadOnlyFilesystem);
144 return false;
145 }
146 const size_t oldSize = m_nSize;
147 const size_t end = static_cast<size_t>(location + size);
148 if (!ensureLargeEnough(end, location, size)) {
149 return false;
150 }
151 if (end > oldSize && useFillCache()) {
152 const size_t pageSize = PhysicalMemoryManager::getPageSize();
153 const size_t within = oldSize % pageSize;
154 if (within) {
155 const size_t pageOffset = oldSize - within;
156 const uintptr_t page = cacheState().fill.lookup(pageOffset);
157 if (page) {
158 const size_t amount = end - oldSize < pageSize - within ? end - oldSize : pageSize - within;
159 ByteSet(reinterpret_cast<void*>(page + within), 0, amount);
160 cacheState().fill.markDirty(pageOffset);
161 cacheState().fill.release(pageOffset);
162 }
163 }
164 }
165 const bool success = ensureWritableRange(location, size);
166 if (!useFillCache()) {
167 LockGuard<Mutex> indexGuard(cacheState().indexLock);
168 cacheState().data.clear();
169 }
170 return success;
171}
172
173size_t Ext2File::getSize() {
174 return __atomic_load_n(&m_nSize, __ATOMIC_ACQUIRE);
175}
176
178 return Ext2Node::maximumFileSize();
179}
180
182 return m_State->futexIdentity;
183}
184
185Mutex& Ext2File::dataMutationLock() {
186 return m_State->dataLock;
187}
188
189Mutex& Ext2File::writeSerializationLock() {
190 return m_State->writeLock;
191}
192
193size_t& Ext2File::physicalPageLoans() {
194 return m_State->pageLoans;
195}
196
198 if (!m_State->dataLock.tryAcquire()) {
199 return false;
200 }
201 if (!m_State->writebackLock.tryAcquire()) {
202 m_State->dataLock.release();
203 return false;
204 }
205 m_State->writebackLock.release();
206 return true;
207}
208
209void Ext2File::preallocate(size_t expectedSize, bool zero) {
210 OperationBarrier::Lease operation;
211 if (!m_pExt2Fs->tryAcquireOperation(operation)) {
212 return;
213 }
214 LockGuard<Mutex> writeGuard(m_State->writeLock);
215 LockGuard<Mutex> dataGuard(m_State->dataLock);
216 LockGuard<Mutex> guard(m_State->writebackLock);
217 if (m_State->quotaFile) {
218 SYSCALL_ERROR(NotEnoughPermissions);
219 return;
220 }
221 // No need to change the actual file size, just allocate the blocks.
222 Ext2Node::ensureLargeEnough(expectedSize, 0, 0, true, !zero);
223}
224
225void Ext2File::extend(size_t newSize) {
226 OperationBarrier::Lease operation;
227 if (!m_pExt2Fs->tryAcquireOperation(operation)) {
228 return;
229 }
230 LockGuard<Mutex> guard(m_State->writebackLock);
231 if (m_State->quotaFile) {
232 SYSCALL_ERROR(NotEnoughPermissions);
233 return;
234 }
235 Ext2Node::extend(newSize, 0, 0);
236 m_Size = m_nSize;
237}
238
239void Ext2File::extend(size_t newSize, uint64_t location, uint64_t size) {
240 OperationBarrier::Lease operation;
241 if (!m_pExt2Fs->tryAcquireOperation(operation)) {
242 return;
243 }
244 LockGuard<Mutex> guard(m_State->writebackLock);
245 if (m_State->quotaFile) {
246 SYSCALL_ERROR(NotEnoughPermissions);
247 return;
248 }
249 Ext2Node::extend(newSize, location, size);
250 m_Size = m_nSize;
251}
252
254 OperationBarrier::Lease operation;
255 if (!m_pExt2Fs->tryAcquireOperation(operation)) {
256 return;
257 }
258 resize(0);
259}
260
261bool Ext2File::prepareShrink(const ShrinkContext& context,
263 // The generic fill cache is already drained. Do not retain this lock across
264 // the mapping journal's returnPhysicalPage calls, which acquire it too.
265 LockGuard<Mutex> guard(m_State->writebackLock);
266 return prepareDataShrink(context.newSize, prepared);
267}
268
269bool Ext2File::resizeFile(size_t size) {
270 LockGuard<Mutex> guard(m_State->writebackLock);
271 if (!resizeData(size)) {
272 return false;
273 }
274 for (Ext2File* alias : m_State->files) {
275 alias->setSize(m_nSize);
276 }
277 return true;
278}
279
281 LockGuard<Mutex> guard(m_State->writebackLock);
282 Ext2Node::fileAttributeChanged(getSize(), LITTLE_TO_HOST32(m_pInode->i_atime),
283 LITTLE_TO_HOST32(m_pInode->i_mtime),
284 LITTLE_TO_HOST32(m_pInode->i_ctime));
285}
286
287uintptr_t Ext2File::readBlock(uint64_t location) {
288 LockGuard<Mutex> guard(m_State->writebackLock);
289 return Ext2Node::readBlock(location);
290}
291
292bool Ext2File::readPage(uint64_t location, uintptr_t destination) {
293 LockGuard<Mutex> guard(m_State->writebackLock);
294 const size_t pageSize = PhysicalMemoryManager::getPageSize();
295 const size_t blockSize = m_pExt2Fs->m_BlockSize;
296 if (!destination || !blockSize || pageSize % blockSize || location % pageSize ||
297 !m_State->allocationValid || location >= m_nSize) {
298 SYSCALL_ERROR(IoError);
299 return false;
300 }
301 ByteSet(reinterpret_cast<void*>(destination), 0, pageSize);
302 const size_t remaining = m_nSize - location;
303 const size_t length = remaining < pageSize ? remaining : pageSize;
304 for (size_t offset = 0; offset < length; offset += blockSize) {
305 const size_t block = (location + offset) / blockSize;
306 if (block >= m_Blocks.count() || !ensureBlockLoaded(block)) {
307 SYSCALL_ERROR(IoError);
308 return false;
309 }
310 }
311 return transferBlocksLocked(m_State, location, destination, length, false);
312}
313
314bool Ext2File::readPages(ReadPage* pages, size_t count) {
315 if (count > MaxReadPages || (count && !pages)) {
316 SYSCALL_ERROR(IoError);
317 return false;
318 }
319 for (size_t i = 0; i < count; ++i)
320 pages[i].complete = false;
321 if (!count)
322 return true;
323 LockGuard<Mutex> guard(m_State->writebackLock);
324 Disk* disk = m_pExt2Fs->m_pDisk;
325 const size_t pageSize = PhysicalMemoryManager::getPageSize();
326 const size_t blockSize = m_pExt2Fs->m_BlockSize;
327 if (!disk || !blockSize || pageSize % blockSize || !m_State->allocationValid) {
328 SYSCALL_ERROR(IoError);
329 return false;
330 }
331
332 // Resolve mapping blocks before data transport. In particular, a later page's
333 // mapping failure must not prevent the demanded page from being populated.
334 for (size_t i = 0; i < count; ++i) {
335 if (!pages[i].buffer || pages[i].offset % pageSize || pages[i].offset >= m_nSize)
336 continue;
337 ByteSet(reinterpret_cast<void*>(pages[i].buffer), 0, pageSize);
338 const size_t remaining = m_nSize - pages[i].offset;
339 const size_t length = remaining < pageSize ? remaining : pageSize;
340 bool mapped = true;
341 for (size_t offset = 0; offset < length; offset += blockSize) {
342 const size_t block = (pages[i].offset + offset) / blockSize;
343 if (block >= m_Blocks.count() || !ensureBlockLoaded(block)) {
344 mapped = false;
345 break;
346 }
347 }
348 pages[i].complete = mapped;
349 }
350
351 Disk::ReadBuffer requests[Disk::MaxReadBuffers] = {};
352 size_t owners[Disk::MaxReadBuffers] = {};
353 size_t requestCount = 0;
354 auto transfer = [&] {
355 if (!requestCount)
356 return;
357 const bool allRead = disk->readIntoBatch(requests, requestCount);
358 (void)allRead;
359 for (size_t i = 0; i < requestCount; ++i)
360 pages[owners[i]].complete = requests[i].complete && pages[owners[i]].complete;
361 requestCount = 0;
362 };
363 for (size_t i = 0; i < count; ++i) {
364 if (!pages[i].complete)
365 continue;
366 const size_t remaining = m_nSize - pages[i].offset;
367 const size_t length = remaining < pageSize ? remaining : pageSize;
368 for (size_t offset = 0; offset < length;) {
369 const size_t block = (pages[i].offset + offset) / blockSize;
370 const uint32_t physical = m_Blocks[block];
371 size_t amount = length - offset < blockSize ? length - offset : blockSize;
372 if (!physical) {
373 offset += amount;
374 continue;
375 }
376 while (amount % blockSize == 0 && amount < length - offset) {
377 const size_t next = block + amount / blockSize;
378 if (next >= m_Blocks.count() || m_Blocks[next] == ~uint32_t{0} ||
379 static_cast<uint64_t>(m_Blocks[next]) !=
380 static_cast<uint64_t>(physical) + amount / blockSize)
381 break;
382 const size_t available = length - offset - amount;
383 amount += available < blockSize ? available : blockSize;
384 }
385 requests[requestCount] = {static_cast<uint64_t>(physical) * blockSize,
386 reinterpret_cast<void*>(pages[i].buffer + offset), amount, false};
387 owners[requestCount++] = i;
388 if (requestCount == Disk::MaxReadBuffers)
389 transfer();
390 offset += amount;
391 }
392 }
393 transfer();
394 bool succeeded = true;
395 for (size_t i = 0; i < count; ++i)
396 succeeded = pages[i].complete && succeeded;
397 if (!succeeded)
398 SYSCALL_ERROR(IoError);
399 return succeeded;
400}
401
402void Ext2File::writeBlock(uint64_t location, uintptr_t addr) {
403 if (useFillCache()) {
404 writeBlocks(location, addr, getBlockSize());
405 } else {
406 LockGuard<Mutex> guard(m_State->writebackLock);
407 Ext2Node::writeBlock(location);
408 }
409}
410
411void Ext2File::writeBlocks(uint64_t location, uintptr_t addr, size_t length) {
412 if (!useFillCache()) {
413 File::writeBlocks(location, addr, length);
414 return;
415 }
416
417 (void)addr;
418 if (!length || location > ~uint64_t{0} - (length - 1))
419 return;
420 const size_t pageSize = PhysicalMemoryManager::getPageSize();
421 const uint64_t last = location + length - 1;
422 uint64_t page = location - location % pageSize;
423 while (true) {
424 cacheState().fill.markDirty(page);
425 if (last - page < pageSize)
426 break;
427 page += pageSize;
428 }
429}
430
431bool Ext2File::sharedFillCallback(CacheConstants::CallbackCause cause, uintptr_t location,
432 uintptr_t page, void* metadata) {
433 Ext2InodeState* state = static_cast<Ext2InodeState*>(metadata);
434 if (cause == CacheConstants::Eviction) {
435 LockGuard<Mutex> guard(state->cache->indexLock);
436 state->cache->data.remove(DataCacheKey(location / PhysicalMemoryManager::getPageSize()));
437 return true;
438 }
439 if (cause != CacheConstants::WriteBack) {
440 return false;
441 }
442 OperationBarrier::Lease operation;
443 if (!state->filesystem->tryAcquireOperation(operation)) {
444 return false;
445 }
446 LockGuard<Mutex> guard(state->writebackLock);
447 if (state->orphan && !state->files.count() &&
448 !__atomic_load_n(&state->syncReferences, __ATOMIC_ACQUIRE)) {
449 return true;
450 }
451 Disk* disk = state->filesystem->m_pDisk;
452 if (!disk)
453 return false;
454 const bool written =
455 transferBlocksLocked(state, location, page, PhysicalMemoryManager::getPageSize(), true);
456 const bool durable = disk->syncData();
457 return written && durable;
458}
459
460bool Ext2File::sharedFillBatchCallback(const Cache::WritebackPage* pages, size_t count,
461 void* context) {
462 auto* state = static_cast<Ext2InodeState*>(context);
463 OperationBarrier::Lease operation;
464 if (!state->filesystem->tryAcquireOperation(operation)) {
465 return false;
466 }
467 LockGuard<Mutex> guard(state->writebackLock);
468 if (!count || (state->orphan && !state->files.count() &&
469 !__atomic_load_n(&state->syncReferences, __ATOMIC_ACQUIRE)))
470 return true;
471 Disk* disk = state->filesystem->m_pDisk;
472 const size_t pageSize = PhysicalMemoryManager::getPageSize();
473 if (!disk || !state->allocationValid)
474 return false;
475 bool succeeded = true;
476 Disk::WriteBuffer buffers[Disk::MaxWriteBuffers];
477 size_t pending = 0;
478 auto drain = [&] {
479 if (pending)
480 succeeded = disk->writeFromBatch(buffers, pending) && succeeded;
481 pending = 0;
482 };
483 for (size_t i = 0; i < count; ++i) {
484 const auto& page = pages[i];
485 if (state->filesystem->m_BlockSize != pageSize || page.key % pageSize ||
486 page.key >= state->size || state->size - page.key < pageSize) {
487 drain();
488 succeeded = transferBlocksLocked(state, page.key, page.location, pageSize, true) && succeeded;
489 continue;
490 }
491 const size_t block = page.key / pageSize;
492 if (block >= state->blocks.count() || state->blocks[block] == ~uint32_t{0}) {
493 succeeded = false;
494 continue;
495 }
496 if (!state->blocks[block])
497 continue;
498 buffers[pending++] = {static_cast<uint64_t>(state->blocks[block]) * pageSize,
499 reinterpret_cast<const void*>(page.location), pageSize, false};
500 if (pending == Disk::MaxWriteBuffers)
501 drain();
502 }
503 drain();
504 const bool durable = disk->syncData();
505 return succeeded && durable;
506}
507
508bool Ext2File::transferBlocksLocked(Ext2InodeState* state, uint64_t location, uintptr_t addr,
509 size_t length, bool write) {
510 Ext2Filesystem* filesystem = state->filesystem;
511 Disk* disk = filesystem->m_pDisk;
512 const size_t blockSize = filesystem->m_BlockSize;
513 if (!disk || !blockSize || !state->allocationValid || location % blockSize ||
514 location > ~uint64_t{0} - length)
515 return false;
516 if (location >= state->size)
517 return true;
518 const size_t remaining = state->size - location;
519 if (length > remaining)
520 length = remaining;
521
522 for (size_t offset = 0; offset < length;) {
523 const uint64_t blockLocation = location + offset;
524 const size_t block = blockLocation / blockSize;
525 if (block >= state->blocks.count() || state->blocks[block] == ~uint32_t(0))
526 return false;
527 const uint32_t physicalBlock = state->blocks[block];
528 size_t amount = length - offset < blockSize ? length - offset : blockSize;
529 if (!physicalBlock) {
530 offset += amount;
531 continue;
532 }
533
534 while (amount % blockSize == 0 && amount < length - offset) {
535 const size_t next = block + amount / blockSize;
536 if (next >= state->blocks.count() || state->blocks[next] == ~uint32_t(0) ||
537 static_cast<uint64_t>(state->blocks[next]) !=
538 static_cast<uint64_t>(physicalBlock) + amount / blockSize)
539 break;
540 const size_t available = length - offset - amount;
541 amount += available < blockSize ? available : blockSize;
542 }
543
544 const uint64_t diskOffset = static_cast<uint64_t>(physicalBlock) * blockSize;
545 const bool transferred =
546 write ? disk->writeFrom(diskOffset, reinterpret_cast<const void*>(addr + offset), amount)
547 : disk->readInto(diskOffset, reinterpret_cast<void*>(addr + offset), amount);
548 if (!transferred)
549 return false;
550 offset += amount;
551 }
552 return true;
553}
554
555bool Ext2File::pinBlock(uint64_t location) {
556 LockGuard<Mutex> guard(m_State->writebackLock);
557 return Ext2Node::pinBlock(location);
558}
559
560void Ext2File::unpinBlock(uint64_t location) {
561 LockGuard<Mutex> guard(m_State->writebackLock);
562 Ext2Node::unpinBlock(location);
563}
564
566 OperationBarrier::Lease operation;
567 if (!m_pExt2Fs->tryAcquireOperation(operation)) {
568 return false;
569 }
570 bool succeeded;
571 if (useFillCache()) {
572 LockGuard<Mutex> dataGuard(dataMutationLock());
573 succeeded = cacheState().fill.syncAll(sharedFillBatchCallback, m_State);
574 } else {
575 succeeded = File::sync();
576 }
577 LockGuard<Mutex> guard(m_State->writebackLock);
578 return m_pExt2Fs->syncInode(getInodeNumber(), *this) && succeeded;
579}
580
581bool Ext2File::sync(size_t offset, bool async) {
582 OperationBarrier::Lease operation;
583 if (!m_pExt2Fs->tryAcquireOperation(operation)) {
584 return false;
585 }
586 bool present = false;
587 if (useFillCache()) {
588 const bool succeeded = syncFillCache(offset, async, present);
589 if (present || m_pExt2Fs->isDeviceRemoved()) {
590 return succeeded;
591 }
592 }
593 LockGuard<Mutex> guard(m_State->writebackLock);
594 return Ext2Node::sync(offset, async);
595}
596
597bool Ext2File::syncPages(const uint64_t* offsets, size_t count) {
598 OperationBarrier::Lease operation;
599 if (!m_pExt2Fs->tryAcquireOperation(operation)) {
600 return false;
601 }
602 if (count > Disk::MaxSyncPages || (count && !offsets))
603 return false;
604 if (!count)
605 return true;
606 if (useFillCache()) {
607 const size_t pageSize = PhysicalMemoryManager::getPageSize();
608 uintptr_t keys[Disk::MaxSyncPages];
609 for (size_t i = 0; i < count; ++i) {
610 if (offsets[i] >= getSize() || offsets[i] % pageSize || offsets[i] > ~uintptr_t{0})
611 return false;
612 keys[i] = offsets[i];
613 }
614 // Claim the authoritative file pages before taking the inode lock: a
615 // callback already copying one of these pages may need that same lock.
616 return cacheState().fill.syncBatch(keys, count, sharedFillBatchCallback, m_State);
617 }
618
619 LockGuard<Mutex> guard(m_State->writebackLock);
620 Disk* disk = m_pExt2Fs->m_pDisk;
621 const size_t blockSize = m_pExt2Fs->m_BlockSize;
622 if (!disk || !blockSize)
623 return false;
624 for (size_t i = 0; i < count; ++i) {
625 if (offsets[i] >= m_nSize || (offsets[i] % blockSize) ||
626 offsets[i] / blockSize >= m_Blocks.count())
627 return false;
628 }
629 uint64_t locations[Disk::MaxSyncPages];
630 size_t locationCount = 0;
631 for (size_t i = 0; i < count; ++i) {
632 const size_t block = offsets[i] / blockSize;
633 if (!ensureBlockLoaded(block))
634 return false;
635 if (!m_Blocks[block])
636 continue;
637 const uint64_t location = static_cast<uint64_t>(m_Blocks[block]) * blockSize;
638 if (location >= disk->getSize())
639 return false;
640 locations[locationCount++] = location;
641 }
642 return disk->syncPages(locations, locationCount);
643}
644
646 return m_pExt2Fs->m_BlockSize;
647}
void setBackgroundWriteback(writeback_batch_t callback)
Definition Cache.cc:2414
MUST_USE_RESULT bool syncAll()
Definition Cache.cc:1687
void setCallback(writeback_t newCallback, void *meta)
Definition Cache.cc:2390
void release(uintptr_t key)
Definition Cache.cc:1570
bool empty()
Definition Cache.cc:1467
MUST_USE_RESULT bool syncBatch(const uintptr_t *keys, size_t count, writeback_batch_t callback, void *metadata)
Definition Cache.cc:1834
void markDirty(uintptr_t key)
Definition Cache.cc:2135
uintptr_t lookup(uintptr_t key)
Definition Cache.cc:737
void setDirtyTracking(DirtyTracking tracking)
Definition Cache.cc:2430
Definition Disk.h:35
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
virtual MUST_USE_RESULT bool writeFromBatch(WriteBuffer *buffers, size_t count)
Definition Disk.cc:285
virtual MUST_USE_RESULT bool syncPages(const uint64_t *locations, size_t count)
Definition Disk.cc:362
virtual MUST_USE_RESULT bool syncData()
Definition Disk.cc:299
virtual size_t getBlockSize() const override
Definition Ext2File.cc:645
virtual void writeBlock(uint64_t location, uintptr_t addr) override
Definition Ext2File.cc:402
bool syncPages(const uint64_t *offsets, size_t count) override
Definition Ext2File.cc:597
virtual uintptr_t readBlock(uint64_t location) override
Definition Ext2File.cc:287
virtual void extend(size_t newSize) override
Definition Ext2File.cc:225
bool readPage(uint64_t location, uintptr_t destination) override
Definition Ext2File.cc:292
virtual uintptr_t futexIdentity() override
Definition Ext2File.cc:181
virtual bool useFillCache() const override
Definition Ext2File.cc:89
virtual void writeBlocks(uint64_t location, uintptr_t addr, size_t length) override
Definition Ext2File.cc:411
virtual void unpinBlock(uint64_t location) override
Definition Ext2File.cc:560
virtual uint64_t maximumFileSize() const override
Definition Ext2File.cc:177
virtual bool pinBlock(uint64_t location) override
Definition Ext2File.cc:555
Ext2File(const Ext2File &file)
virtual void preallocate(size_t expectedSize, bool zero=true) override
Definition Ext2File.cc:209
bool readPages(ReadPage *pages, size_t count) override
Definition Ext2File.cc:314
virtual bool sync() override
Definition Ext2File.cc:565
virtual bool tryBeginMappingRelease() override
Definition Ext2File.cc:197
void fileAttributeChanged() override
Definition Ext2File.cc:280
virtual void truncate() override
Definition Ext2File.cc:253
virtual ~Ext2File() override
Definition Ext2File.cc:66
virtual bool prepareSharedMapping(size_t offset, size_t length) override
Definition Ext2File.cc:106
bool ensureLargeEnough(size_t size, uint64_t location, uint64_t opsize, bool onlyBlocks=false, bool nozeroblocks=false)
Definition Ext2Node.cc:258
void fileAttributeChanged(size_t size, size_t atime, size_t mtime, size_t ctime)
Definition Ext2Node.cc:567
Definition File.h:75
bool resize(size_t size)
Definition File.cc:1213
virtual uint64_t write(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) final
Definition File.cc:342
virtual void writeBlocks(uint64_t location, uintptr_t addr, size_t length)
Definition File.cc:1395
void setGidOnly(size_t gid)
Definition File.cc:1448
virtual uintptr_t futexIdentity()
Definition File.cc:75
virtual bool sync()
Definition File.cc:595
void setPermissionsOnly(uint32_t perms)
Definition File.cc:1440
virtual bool useFillCache() const
Definition File.cc:1746
void setUidOnly(size_t uid)
Definition File.cc:1444
bool syncFillCache(size_t offset, bool async, bool &present)
Definition File.cc:1771
Disk * m_pDisk
Definition Filesystem.h:188
bool isReadOnly()
Definition Filesystem.h:150
Definition Mutex.h:56
void release(size_t n=1)
Definition Semaphore.cc:549
bool tryAcquire(size_t n=1)
Definition Semaphore.cc:484
void erase(size_t index)
Definition Vector.h:389
void pushBack(const T &value)
Definition Vector.h:275
size_t count() const
Definition Vector.h:270
Definition ext2.h:152