The Pedigree Project 0.1
RawFsFile.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 "RawFsFile.h"
21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/machine/Disk.h"
23#include "pedigree/kernel/panic.h"
24#include "pedigree/kernel/processor/PhysicalMemoryManager.h"
25#include "pedigree/kernel/utilities/utility.h"
26
27#include "RawFs.h"
28
29class Filesystem;
30
31RawFsFile::RawFsFile(String name, RawFs* pFs, File* pParent, Disk* pDisk)
32 : File(name, 0 /* Accessed time */, 0 /* Modified time */, 0 /* Creation time */,
33 0 /* Inode number */, static_cast<Filesystem*>(pFs), 0 /* Size */, pParent),
34 m_pDisk(pDisk),
35 m_PageCache(),
36 m_PageCacheLock() {
37 m_PageCache.setCallback(cacheCallback, this);
38
39 // Owned by root:root
40 setUid(0);
41 setGid(0);
42
43 // RW for root, readable only by others.
44 uint32_t permissions = FILE_UR | FILE_UW | FILE_GR | FILE_OR;
45 setPermissions(permissions);
46
47 // Disk size.
48 setSize(m_pDisk->getSize());
49}
50
51RawFsFile::~RawFsFile() {
52 if (!shutdown())
53 panic("rawfs: file cache shutdown failed; unwritten data remains");
54}
55
57 return m_PageCache.syncAll();
58}
59
60bool RawFsFile::sync(size_t offset, bool async) {
61 if (offset >= getSize())
62 return false;
63 const size_t pageSize = PhysicalMemoryManager::getPageSize();
64 return m_PageCache.sync(offset - offset % pageSize, async);
65}
66
67bool RawFsFile::shutdown() {
68 return m_PageCache.shutdown();
69}
70
71bool RawFsFile::cacheCallback(CacheConstants::CallbackCause cause, uintptr_t location,
72 uintptr_t page, void* context) {
73 auto* file = static_cast<RawFsFile*>(context);
74 if (cause == CacheConstants::Eviction)
75 return File::writeCallback(cause, location, page, context);
76 if (cause != CacheConstants::WriteBack || !page || location >= file->getSize())
77 return false;
78 const size_t pageSize = PhysicalMemoryManager::getPageSize();
79 const size_t length = min(pageSize, static_cast<size_t>(file->getSize() - location));
80 const bool written =
81 file->m_pDisk->writeFrom(location, reinterpret_cast<const void*>(page), length);
82 // Successful partial writes still need a device barrier when another write failed.
83 const bool durable = file->m_pDisk->syncData();
84 return written && durable;
85}
86
88 // Disk block sizes describe internal I/O/readahead extents. File::readBlock
89 // owns one cache page, so VFS must never expose a larger unpinned range.
91}
92
93uintptr_t RawFsFile::readBlock(uint64_t location) {
94 LockGuard<Mutex> guard(m_PageCacheLock);
95 const size_t pageSize = PhysicalMemoryManager::getPageSize();
96 const uint64_t pageLocation = location - (location % pageSize);
97 const size_t pageOffset = location - pageLocation;
98 if (location >= getSize() || pageLocation >= getSize()) {
99 return 0;
100 }
101 const size_t validLength =
102 pageSize < (getSize() - pageLocation) ? pageSize : (getSize() - pageLocation);
103
104 uintptr_t buffer = m_PageCache.lookup(pageLocation);
105 if (buffer) {
106 return buffer + pageOffset;
107 }
108
109 bool didExist = false;
110 buffer = m_PageCache.insert(pageLocation, &didExist);
111 if (!buffer) {
112 return 0;
113 }
114
115 if (!didExist) {
116 ByteSet(reinterpret_cast<void*>(buffer), 0, pageSize);
117 size_t copied = 0;
118 while (copied < validLength) {
119 const uint64_t diskLocation = pageLocation + copied;
120 const BufferView source = m_pDisk->read(diskLocation);
121 if (!source) {
122 const bool discarded = m_PageCache.discardEditing(pageLocation);
123 (void)discarded;
124 return 0;
125 }
126
127 const size_t remaining = validLength - copied;
128 const size_t chunk = source.size() < remaining ? source.size() : remaining;
129 if (!chunk) {
130 m_pDisk->unpin(diskLocation);
131 const bool discarded = m_PageCache.discardEditing(pageLocation);
132 (void)discarded;
133 return 0;
134 }
135 MemoryCopy(reinterpret_cast<void*>(buffer + copied), source.data(), chunk);
136 m_pDisk->unpin(diskLocation);
137 copied += chunk;
138 }
139 m_PageCache.markNoLongerEditing(pageLocation);
140 }
141
142 buffer = m_PageCache.lookup(pageLocation);
143 return buffer ? buffer + pageOffset : 0;
144}
145
146void RawFsFile::writeBlock(uint64_t location, uintptr_t address) {
147 const size_t pageSize = PhysicalMemoryManager::getPageSize();
148 const uint64_t pageLocation = location - (location % pageSize);
149 if (!address || location >= getSize() || pageLocation >= getSize()) {
150 return;
151 }
152 const size_t validLength =
153 pageSize < (getSize() - pageLocation) ? pageSize : (getSize() - pageLocation);
154
155 const uintptr_t page = readBlock(pageLocation);
156 if (!page)
157 return;
158 if (page != address)
159 MemoryCopy(reinterpret_cast<void*>(page), reinterpret_cast<const void*>(address), validLength);
160 m_PageCache.markDirty(pageLocation);
161 m_PageCache.release(pageLocation);
162}
163
164bool RawFsFile::pinBlock(uint64_t location) {
165 const size_t pageSize = PhysicalMemoryManager::getPageSize();
166 if (location >= getSize()) {
167 return false;
168 }
169 return m_PageCache.pin(location - (location % pageSize));
170}
171
172void RawFsFile::unpinBlock(uint64_t location) {
173 const size_t pageSize = PhysicalMemoryManager::getPageSize();
174 if (location >= getSize()) {
175 return;
176 }
177 m_PageCache.release(location - (location % pageSize));
178}
MUST_USE_RESULT bool discardEditing(uintptr_t key)
Definition Cache.cc:1129
bool shutdown(ShutdownMode mode=ShutdownMode::WriteBack)
Definition Cache.cc:663
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
uintptr_t insert(uintptr_t key, bool *alreadyExisted=nullptr)
Definition Cache.cc:890
void markDirty(uintptr_t key)
Definition Cache.cc:2135
bool sync(uintptr_t key, bool async)
Definition Cache.cc:1627
void markNoLongerEditing(uintptr_t key, size_t length=0)
Definition Cache.cc:2646
uintptr_t lookup(uintptr_t key)
Definition Cache.cc:737
MUST_USE_RESULT bool pin(uintptr_t key)
Definition Cache.cc:1544
Definition Disk.h:35
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 void unpin(uint64_t location)=0
Definition File.h:75
static bool writeCallback(CacheConstants::CallbackCause cause, uintptr_t loc, uintptr_t page, void *meta)
Definition File.cc:116
Disk * m_pDisk
Definition Filesystem.h:188
RawFsFile(const RawFsFile &file)
virtual size_t getBlockSize() const
Definition RawFsFile.cc:87
virtual bool pinBlock(uint64_t location)
Definition RawFsFile.cc:164
virtual bool sync()
Definition RawFsFile.cc:56
virtual uintptr_t readBlock(uint64_t location)
Definition RawFsFile.cc:93
virtual void writeBlock(uint64_t location, uintptr_t address)
Definition RawFsFile.cc:146
virtual void unpinBlock(uint64_t location)
Definition RawFsFile.cc:172
Definition RawFs.h:33
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition panic.cc:118