9#include "pedigree/kernel/LockGuard.h"
10#include "pedigree/kernel/Log.h"
11#include "pedigree/kernel/syscallError.h"
12#include "pedigree/kernel/utilities/new"
13#include "pedigree/kernel/utilities/utility.h"
16#include "Ext2Filesystem.h"
22bool appendPrepared(
Vector<T>& values,
const T& value) {
24 !values.tryReserve(values.
size() ? values.
size() * 2 : 16)) {
25 SYSCALL_ERROR(OutOfMemory);
33Ext2Node::TrimPlan::TrimPlan(
Ext2Filesystem& filesystem) : filesystem(filesystem) {}
35Ext2Node::TrimPlan::~TrimPlan() {
36 for (
const MappingPage& page : pages) {
38 filesystem.unpinBlock(page.block);
42bool Ext2Node::collectMappingPages(uint32_t block,
unsigned depth,
size_t first,
size_t span,
46 const uintptr_t buffer = m_pExt2Fs->
readBlock(block);
48 SYSCALL_ERROR(IoError);
51 if (!appendPrepared(pages, MappingPage{block, buffer, first, span, depth})) {
52 m_pExt2Fs->unpinBlock(block);
57 const size_t entries = m_pExt2Fs->
m_BlockSize /
sizeof(uint32_t);
58 const size_t childSpan = span / entries;
59 const uint32_t* children =
reinterpret_cast<const uint32_t*
>(buffer);
60 for (
size_t i = 0; i < entries; ++i) {
61 if (!collectMappingPages(LITTLE_TO_HOST32(children[i]), depth - 1, first + i * childSpan,
68bool Ext2Node::prepareTrim(
size_t keep, TrimPlan& plan,
bool allocationLockHeld) {
69 if (!m_State->allocationValid) {
70 SYSCALL_ERROR(IoError);
74 const size_t entries = m_pExt2Fs->
m_BlockSize /
sizeof(uint32_t);
75 if (!collectMappingPages(LITTLE_TO_HOST32(m_pInode->i_block[12]), 1, 12, entries, plan.pages) ||
76 !collectMappingPages(LITTLE_TO_HOST32(m_pInode->i_block[13]), 2, 12 + entries,
77 entries * entries, plan.pages) ||
78 !collectMappingPages(LITTLE_TO_HOST32(m_pInode->i_block[14]), 3,
79 12 + entries + entries * entries, entries * entries * entries,
82 for (
size_t i = 0; i < 12; ++i) {
83 const uint32_t block = LITTLE_TO_HOST32(m_pInode->i_block[i]);
86 if (!appendPrepared(plan.retiredData, block))
93 for (
const MappingPage& page : plan.pages) {
96 const uint32_t* children =
reinterpret_cast<const uint32_t*
>(page.buffer);
97 for (
size_t i = 0; i < entries; ++i) {
98 const uint32_t block = LITTLE_TO_HOST32(children[i]);
100 if (page.first + i >= keep) {
101 if (!appendPrepared(plan.retiredData, block))
110 if (!m_pExt2Fs->prepareInodeWrite(getInodeNumber()))
112 for (uint32_t block : plan.retiredData) {
113 if (!m_pExt2Fs->prepareBlockReleaseLocked(block))
116 for (
const MappingPage& page : plan.pages) {
117 if (page.first >= keep && !m_pExt2Fs->prepareBlockReleaseLocked(page.block))
123void Ext2Node::commitTrim(TrimPlan& plan,
bool allocationLockHeld) {
124 const size_t keep = plan.keep;
125 const size_t entries = m_pExt2Fs->
m_BlockSize /
sizeof(uint32_t);
128 for (
size_t i = keep; i < 12; ++i)
129 m_pInode->i_block[i] = 0;
130 const size_t firstIndices[3] = {12, 12 + entries, 12 + entries + entries * entries};
131 for (
size_t i = 0; i < 3; ++i) {
132 if (firstIndices[i] >= keep)
133 m_pInode->i_block[12 + i] = 0;
135 size_t retainedMetadata = 0;
136 for (
const MappingPage& page : plan.pages) {
137 uint32_t* children =
reinterpret_cast<uint32_t*
>(page.buffer);
138 const size_t childSpan = page.span / entries;
139 for (
size_t i = 0; i < entries; ++i) {
140 if (page.first + i * childSpan >= keep)
143 if (page.first < keep) {
148 while (m_Blocks.
count() > keep)
150 m_nMetadataBlocks = retainedMetadata;
151 m_State->allocatedDataBlocks = plan.retainedData;
152 updateAllocatedSectorCount();
153 m_pExt2Fs->writeInode(getInodeNumber());
154 for (uint32_t block : plan.retiredData)
155 m_pExt2Fs->releaseBlockLocked(block, m_InodeNumber);
156 for (MappingPage& page : plan.pages) {
157 m_pExt2Fs->unpinBlock(page.block);
159 if (page.first >= keep)
164bool Ext2Node::trimToBlocks(
size_t keep,
bool allocationLockHeld) {
165 TrimPlan plan(*m_pExt2Fs);
166 if (!prepareTrim(keep, plan, allocationLockHeld))
168 commitTrim(plan, allocationLockHeld);
175 : node(node), size(size), trim(*node.m_pExt2Fs), tail(0), tailBlock(0) {}
178 node.m_pExt2Fs->unpinBlock(tailBlock);
182 node.commitTrim(trim);
184 const size_t within = size % node.m_pExt2Fs->m_BlockSize;
185 ByteSet(
reinterpret_cast<void*
>(tail + within), 0, node.m_pExt2Fs->m_BlockSize - within);
186 node.m_pExt2Fs->writeBlock(tailBlock);
189 node.m_pInode->i_size = HOST_TO_LITTLE32(size);
190 node.m_pExt2Fs->writeInode(node.getInodeNumber());
191 for (
Ext2File* alias : node.m_State->files)
192 alias->setSize(size);
202 DataShrinkPlan* plan =
new DataShrinkPlan(*
this, size);
205 SYSCALL_ERROR(OutOfMemory);
209 if (size % blockSize) {
210 const size_t index = size / blockSize;
211 if (index >= m_Blocks.
count() || !ensureBlockLoaded(index)) {
212 SYSCALL_ERROR(IoError);
215 plan->tailBlock = m_Blocks[index];
216 if (plan->tailBlock) {
217 plan->tail = m_pExt2Fs->
readBlock(plan->tailBlock);
219 SYSCALL_ERROR(IoError);
224 if (!prepareTrim(size / blockSize + (size % blockSize != 0), plan->trim))
226 prepared = pedigree_std::move(owner);
230bool Ext2Node::zeroRange(
size_t start,
size_t end) {
232 while (start < end) {
233 const size_t block = start / blockSize;
234 const size_t within = start % blockSize;
235 const size_t amount = (end - start < blockSize - within) ? end - start : blockSize - within;
236 if (block >= m_Blocks.
count() || !ensureBlockLoaded(block)) {
237 SYSCALL_ERROR(IoError);
240 if (m_Blocks[block]) {
241 const uintptr_t buffer = m_pExt2Fs->
readBlock(m_Blocks[block]);
243 SYSCALL_ERROR(IoError);
246 ByteSet(
reinterpret_cast<void*
>(buffer + within), 0, amount);
248 m_pExt2Fs->unpinBlock(m_Blocks[block]);
255bool Ext2Node::resizeData(
size_t size) {
256 if (size > 0xffffffffULL) {
257 SYSCALL_ERROR(FileTooLarge);
260 if (size > m_nSize) {
264 const size_t keep = size / blockSize + (size % blockSize != 0);
267 uint32_t tailBlock = 0;
268 if (size % blockSize) {
269 if (!ensureBlockLoaded(size / blockSize)) {
270 SYSCALL_ERROR(IoError);
273 tailBlock = m_Blocks[size / blockSize];
277 SYSCALL_ERROR(IoError);
282 if (!trimToBlocks(keep)) {
284 m_pExt2Fs->unpinBlock(tailBlock);
289 const size_t within = size % blockSize;
290 ByteSet(
reinterpret_cast<void*
>(tail + within), 0, blockSize - within);
292 m_pExt2Fs->unpinBlock(tailBlock);
295 m_pInode->i_size = HOST_TO_LITTLE32(size);
296 m_pExt2Fs->writeInode(getInodeNumber());
void writeBlock(uint32_t block)
uintptr_t readBlock(uint32_t block)
void releaseBlockLocked(uint32_t block, uint32_t inode=0)
bool ensureLargeEnough(size_t size, uint64_t location, uint64_t opsize, bool onlyBlocks=false, bool nozeroblocks=false)
static UniquePointer< T > adopt(T *pointer)
A vector / dynamic array.
void pushBack(const T &value)