The Pedigree Project 0.1
FatFile.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 "FatFile.h"
21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/syscallError.h"
23
24#include "FatFilesystem.h"
25
26FatFile::FatFile(String name, Time::Timestamp accessedTime, Time::Timestamp modifiedTime,
27 Time::Timestamp creationTime, uintptr_t inode, class Filesystem* pFs, size_t size,
28 uint32_t dirClus, uint32_t dirOffset, File* pParent)
29 : File(name, accessedTime, modifiedTime, creationTime, inode, pFs, size, pParent),
30 m_State(static_cast<FatFilesystem*>(pFs)->acquireFileState(
31 this, inode, size, dirClus, dirOffset, accessedTime, modifiedTime, creationTime)),
32 m_DirClus(m_State->directoryCluster),
33 m_DirOffset(m_State->directoryOffset),
34 m_MetadataDirty(m_State->metadataDirty),
35 m_TrimPending(m_State->trimPending),
36 m_RetiredClusters(m_State->retiredClusters) {
37 {
38 LockGuard<Mutex> registry(static_cast<FatFilesystem*>(pFs)->m_StateLock);
39 m_NextAlias = m_State->aliases;
40 m_State->aliases = this;
41 }
42 copyStateAttributes();
43 File::setInode(m_State->inode);
44 File::setSize(m_State->size);
45 setPermissionsOnly(FILE_UR | FILE_UW | FILE_UX | FILE_GR | FILE_GW | FILE_GX | FILE_OR | FILE_OW |
46 FILE_OX);
47}
48
49FatFile::FatFile(State& state)
50 : File(String(), state.accessed, state.modified, state.changed, state.inode, state.filesystem,
51 state.size, nullptr),
52 m_State(&state),
53 m_Proxy(true),
54 m_DirClus(state.directoryCluster),
55 m_DirOffset(state.directoryOffset),
56 m_MetadataDirty(state.metadataDirty),
57 m_TrimPending(state.trimPending),
58 m_RetiredClusters(state.retiredClusters) {}
59
61 if (!m_Proxy)
62 m_State->filesystem->releaseFileState(this);
63}
64
65File::CacheState& FatFile::cacheState() {
66 return m_State->cache;
67}
68Mutex& FatFile::dataMutationLock() {
69 return m_State->dataLock;
70}
71Mutex& FatFile::writeSerializationLock() {
72 return m_State->writeLock;
73}
74size_t& FatFile::physicalPageLoans() {
75 return m_State->pageLoans;
76}
77size_t FatFile::getSize() {
78 return m_State->size;
79}
81 return reinterpret_cast<uintptr_t>(m_State);
82}
83
84void FatFile::setInode(uintptr_t inode) {
85 LockGuard<Mutex> registry(m_State->filesystem->m_StateLock);
86 m_State->inode = inode;
87 m_State->chainRevision = 0;
88 File::setInode(inode);
89 for (FatFile* alias = m_State->aliases; alias; alias = alias->m_NextAlias)
90 alias->File::setInode(inode);
91}
92
93uintptr_t FatFile::readBlock(uint64_t location) {
94 LockGuard<Mutex> guard(cacheState().fillLock);
95 location -= location % getBlockSize();
96
97 uintptr_t buffer = cacheState().fill.lookup(location);
98 if (buffer) {
99 return buffer;
100 }
101
102 bool didExist = false;
103 buffer = cacheState().fill.insert(location, &didExist);
104 if (!buffer) {
105 return 0;
106 }
107
108 if (!didExist) {
109 if (!readPage(location, buffer)) {
110 if (!cacheState().fill.discardEditing(location)) {
111 WARNING("FatFile::readBlock could not discard a failed fill at " << location);
112 }
113 return 0;
114 }
115 cacheState().fill.markNoLongerEditing(location);
116 }
117
118 return cacheState().fill.lookup(location);
119}
120
122 EMIT_IF(VFS_NOMMU) {
123#if defined(PEDIGREE_BUILDUTILS)
124 return m_bForceFillCache;
125#else
126 return false;
127#endif
128 }
129 else {
130 return true;
131 }
132}
133
134bool FatFile::readPage(uint64_t location, uintptr_t destination) {
135 const size_t pageSize = getBlockSize();
136 ByteSet(reinterpret_cast<void*>(destination), 0, pageSize);
137 const size_t size = getSize();
138 if (location >= size)
139 return false;
140 const size_t expected = size - location < pageSize ? size - location : pageSize;
141 FatFilesystem* filesystem = static_cast<FatFilesystem*>(m_pFilesystem);
142 return filesystem->read(this, location, expected, destination) == expected;
143}
144
145void FatFile::writeBlock(uint64_t location, uintptr_t addr) {
146 // The producer page remains authoritative until checked writeback completes.
147 cacheState().fill.markDirty(location - location % getBlockSize());
148}
149
150bool FatFile::checkedWriteCallback(CacheConstants::CallbackCause cause, uintptr_t location,
151 uintptr_t page, void* meta) {
152 State* state = static_cast<State*>(meta);
153 if (cause == CacheConstants::Eviction) {
154 FatFile file(*state);
155 return File::fillCacheCallback(cause, location, page, &file);
156 }
157 if (cause != CacheConstants::WriteBack)
158 return true;
159 Cache::WritebackPage entry{location, page};
160 return state->filesystem->writeCachedPages(*state, &entry, 1);
161}
162
163bool FatFile::checkedBatchCallback(const Cache::WritebackPage* pages, size_t count, void* meta) {
164 State* state = static_cast<State*>(meta);
165 return state->filesystem->writeCachedPages(*state, pages, count);
166}
167
169 OperationBarrier::Lease operation;
170 if (!m_pFilesystem->tryAcquireOperation(operation)) {
171 return false;
172 }
173 LockGuard<Mutex> data(m_State->dataLock);
174 const bool succeeded = cacheState().fill.syncAll(checkedBatchCallback, m_State);
175 return m_State->filesystem->syncFileMetadata(this) && succeeded;
176}
177
178bool FatFile::sync(size_t offset, bool async) {
179 OperationBarrier::Lease operation;
180 if (!m_pFilesystem->tryAcquireOperation(operation)) {
181 return false;
182 }
183 offset -= offset % getBlockSize();
184 if (async)
185 return cacheState().fill.sync(offset, true);
186 const uintptr_t key = offset;
187 const bool succeeded = cacheState().fill.syncBatch(&key, 1, checkedBatchCallback, m_State);
188 return m_State->filesystem->syncFileMetadata(this) && succeeded;
189}
190
191bool FatFile::syncPages(const uint64_t* offsets, size_t count) {
192 OperationBarrier::Lease operation;
193 if (!m_pFilesystem->tryAcquireOperation(operation)) {
194 return false;
195 }
196 if (count > Cache::MaxWritebackPages || (count && !offsets))
197 return false;
198 uintptr_t keys[Cache::MaxWritebackPages];
199 for (size_t i = 0; i < count; ++i)
200 keys[i] = offsets[i] - offsets[i] % getBlockSize();
201 const bool succeeded = cacheState().fill.syncBatch(keys, count, checkedBatchCallback, m_State);
202 return m_State->filesystem->syncFileMetadata(this) && succeeded;
203}
204
205File::Attributes FatFile::getAttributes() const {
206 FatFile* file = const_cast<FatFile*>(this);
207 LockGuard<Mutex> dataGuard(file->dataMutationLock());
208 FatFilesystem* filesystem = static_cast<FatFilesystem*>(m_pFilesystem);
209 LockGuard<Mutex> guard(filesystem->m_FileMutationLock);
210 Attributes attributes = File::getAttributes();
211 attributes.accessed = m_State->accessed;
212 attributes.modified = m_State->modified;
213 attributes.changed = m_State->changed;
214 attributes.inode = m_State->identifier;
215 attributes.blocks = filesystem->allocatedBlocks(file);
216 return attributes;
217}
218
219bool FatFile::pinBlock(uint64_t location) {
220 return cacheState().fill.pin(location - location % getBlockSize());
221}
222
223void FatFile::unpinBlock(uint64_t location) {
224 cacheState().fill.release(location - location % getBlockSize());
225}
226
227void FatFile::copyStateAttributes() {
228 LockGuard<Mutex> metadata(m_MetadataLock);
229 m_AccessedTime = m_State->accessed;
230 m_ModifiedTime = m_State->modified;
231 m_CreationTime = m_State->changed;
232}
MUST_USE_RESULT bool syncAll()
Definition Cache.cc:1687
void release(uintptr_t key)
Definition Cache.cc:1570
uintptr_t insert(uintptr_t key, bool *alreadyExisted=nullptr)
Definition Cache.cc:890
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
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
uintptr_t readBlock(uint64_t location) override
Definition FatFile.cc:93
FatFile(const File &file)
bool syncPages(const uint64_t *offsets, size_t count) override
Definition FatFile.cc:191
uintptr_t futexIdentity() override
Definition FatFile.cc:80
bool readPage(uint64_t location, uintptr_t destination) override
Definition FatFile.cc:134
bool useFillCache() const override
Definition FatFile.cc:121
~FatFile() override
Definition FatFile.cc:60
bool pinBlock(uint64_t location) override
Definition FatFile.cc:219
void writeBlock(uint64_t location, uintptr_t addr) override
Definition FatFile.cc:145
void unpinBlock(uint64_t location) override
Definition FatFile.cc:223
bool sync() override
Definition FatFile.cc:168
Mutex m_FileMutationLock
Definition File.h:75
void setPermissionsOnly(uint32_t perms)
Definition File.cc:1440
virtual size_t getBlockSize() const
Definition File.cc:1077
Definition Mutex.h:56