The Pedigree Project 0.1
LoDisk.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 "LoDisk.h"
21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/Log.h"
23#include "pedigree/kernel/Service.h"
24#include "pedigree/kernel/ServiceFeatures.h"
25#include "pedigree/kernel/ServiceManager.h"
26#include "pedigree/kernel/TargetInfo.h"
27#include "pedigree/kernel/utilities/assert.h"
28#include "pedigree/kernel/utilities/utility.h"
29
30#include "modules/Module.h"
31#include "modules/system/vfs/VFS.h"
32
33FileDisk::FileDisk(String file, AccessType mode)
34 : m_pFile(0),
35 m_bVfsReference(false),
36 m_Mode(mode),
37 m_Cache(),
38 m_MemRegion("FileDisk"),
39 m_ReqMutex(),
40 m_nAlignPoints(0) {
41 Directory::ChildLease fileLease;
42 m_pFile = VFS::instance().findRetained(file, fileLease);
43 if (!m_pFile)
44 WARNING("FileDisk: '" << file << "' doesn't exist...");
45 else {
46 m_bVfsReference = m_pFile->retainVfsReference();
47 if (!m_bVfsReference) {
48 WARNING("FileDisk: '" << file << "' cannot be retained...");
49 m_pFile = nullptr;
50 return;
51 }
52
53 m_pFile->increaseRefCount(false);
54
55 // Chat to the partition service and let it pick up that we're around
56 // now
57 ServiceFeatures* pFeatures =
58 ServiceManager::instance().enumerateOperations(String("partition"));
59 Service* pService = ServiceManager::instance().getService(String("partition"));
60 NOTICE("Asking if the partition provider supports touch");
61 if (pFeatures->provides(ServiceFeatures::touch)) {
62 NOTICE(
63 "It does, attempting to inform the partitioner of our "
64 "presence...");
65 if (pService) {
66 if (pService->serve(ServiceFeatures::touch,
67 reinterpret_cast<void*>(static_cast<Disk*>(this)),
68 sizeof(*static_cast<Disk*>(this)))) {
69 NOTICE("Successful.");
70 } else
71 ERROR("Failed.");
72 } else
73 ERROR(
74 "FileDisk: Couldn't tell the partition service about the "
75 "new disk presence");
76 } else
77 ERROR("FileDisk: Partition service doesn't appear to support touch");
78 }
79}
80
81FileDisk::~FileDisk() {
82 m_Cache.shutdown();
83 if (m_pFile) {
84 m_pFile->decreaseRefCount(false);
85 if (m_bVfsReference) {
87 m_bVfsReference = false;
88 }
89 m_pFile = nullptr;
90 }
91}
92
93bool FileDisk::initialise() {
94 return (m_pFile != 0);
95}
96
97BufferView FileDisk::read(uint64_t location) {
98 LockGuard<Mutex> guard(m_ReqMutex);
99
100 if (location % 512)
101 FATAL("Read with location % 512.");
102
103 if (!m_pFile)
104 return BufferView();
105
106 const size_t pageSize = TargetInfo::getPageSize();
107
108 // Look through the align points.
109 uint64_t alignPoint = 0;
110 for (size_t i = 0; i < m_nAlignPoints; i++)
111 if (m_AlignPoints[i] <= location && m_AlignPoints[i] > alignPoint)
112 alignPoint = m_AlignPoints[i];
113 alignPoint %= pageSize;
114
115 // Determine which page the read is in
116 const uint64_t pageOffset = (location - alignPoint) % pageSize;
117 const uint64_t readPage = location - pageOffset;
118 const uint64_t fileSize = m_pFile->getSize();
119 if (location >= fileSize || readPage >= fileSize) {
120 return BufferView();
121 }
122 const size_t validLength = pageSize < (fileSize - readPage) ? pageSize : (fileSize - readPage);
123
124 uintptr_t buffer = m_Cache.lookup(readPage);
125
126 if (buffer)
127 return BufferView::fromAddress(buffer + pageOffset, validLength - pageOffset);
128
129 buffer = m_Cache.insert(readPage);
130 if (!buffer)
131 return BufferView();
132
133 // Read the data from the file itself
134 ByteSet(reinterpret_cast<void*>(buffer), 0, pageSize);
135 if (m_pFile->read(readPage, validLength, buffer) != validLength) {
136 const bool discarded = m_Cache.discardEditing(readPage);
137 (void)discarded;
138 return BufferView();
139 }
140
141 m_Cache.markNoLongerEditing(readPage);
142
143 buffer = m_Cache.lookup(readPage);
144 return buffer ? BufferView::fromAddress(buffer + pageOffset, validLength - pageOffset)
145 : BufferView();
146}
147
148void FileDisk::write(uint64_t location) {
149 LockGuard<Mutex> guard(m_ReqMutex);
150 if (!m_pFile)
151 return;
152
154}
155
156void FileDisk::align(uint64_t location) {
157 LockGuard<Mutex> guard(m_ReqMutex);
158 for (size_t i = 0; i < m_nAlignPoints; ++i) {
159 if (m_AlignPoints[i] == location) {
160 return;
161 }
162 }
163 assert(m_nAlignPoints < 8);
164 m_AlignPoints[m_nAlignPoints++] = location;
165}
166
167size_t FileDisk::getSize() const {
168 return m_pFile ? m_pFile->getSize() : 0;
169}
170
171bool FileDisk::pin(uint64_t location) {
172 LockGuard<Mutex> guard(m_ReqMutex);
173
174 const size_t pageSize = TargetInfo::getPageSize();
175
176 uint64_t alignPoint = 0;
177 for (size_t i = 0; i < m_nAlignPoints; i++)
178 if (m_AlignPoints[i] <= location && m_AlignPoints[i] > alignPoint)
179 alignPoint = m_AlignPoints[i];
180 alignPoint %= pageSize;
181
182 const uint64_t page = location - ((location - alignPoint) % pageSize);
183 const uint64_t fileSize = m_pFile ? m_pFile->getSize() : 0;
184 if (location >= fileSize || page >= fileSize) {
185 return false;
186 }
187 return m_Cache.pin(page);
188}
189
190void FileDisk::unpin(uint64_t location) {
191 LockGuard<Mutex> guard(m_ReqMutex);
192
193 const size_t pageSize = TargetInfo::getPageSize();
194
195 uint64_t alignPoint = 0;
196 for (size_t i = 0; i < m_nAlignPoints; i++)
197 if (m_AlignPoints[i] <= location && m_AlignPoints[i] > alignPoint)
198 alignPoint = m_AlignPoints[i];
199 alignPoint %= pageSize;
200
201 const uint64_t page = location - ((location - alignPoint) % pageSize);
202 const uint64_t fileSize = m_pFile ? m_pFile->getSize() : 0;
203 if (location >= fileSize || page >= fileSize) {
204 return;
205 }
206 m_Cache.release(page);
207}
208
209static bool init() {
210 return true;
211}
212
213static void destroy() {}
214
215MODULE_INFO("lodisk", &init, &destroy, "vfs");
MUST_USE_RESULT bool discardEditing(uintptr_t key)
Definition Cache.cc:1129
bool shutdown(ShutdownMode mode=ShutdownMode::WriteBack)
Definition Cache.cc:663
void release(uintptr_t key)
Definition Cache.cc:1570
uintptr_t insert(uintptr_t key, bool *alreadyExisted=nullptr)
Definition Cache.cc:890
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 bool pin(uint64_t location)
Pins a cache page.
Definition LoDisk.cc:171
virtual void align(uint64_t location)
Sets the page boundary alignment after a specific location on the disk.
Definition LoDisk.cc:156
bool m_bVfsReference
Whether this disk owns a persistent VFS reference to m_pFile.
Definition LoDisk.h:92
virtual size_t getSize() const
Gets the size of the disk.
Definition LoDisk.cc:167
virtual void write(uint64_t location)
Definition LoDisk.cc:148
virtual BufferView read(uint64_t location)
Definition LoDisk.cc:97
virtual void unpin(uint64_t location)
Definition LoDisk.cc:190
File * m_pFile
File we're using as a disk.
Definition LoDisk.h:89
virtual uint64_t read(uint64_t location, uint64_t size, uintptr_t buffer, bool bCanBlock=true) final
Definition File.cc:239
virtual void releaseVfsReference()
Definition File.cc:914
virtual bool provides(Type service)
Service * getService(const String &serviceName)
ServiceFeatures * enumerateOperations(const String &serviceName)
virtual bool serve(ServiceFeatures::Type type, void *pData, size_t dataLen)=0
static constexpr size_t getPageSize() noexcept
Definition TargetInfo.h:40
File * findRetained(const String &path, Directory::ChildLease &result, File *pStartNode=nullptr)
Definition VFS.cc:1042
static VFS & instance()
Definition VFS.cc:311