2#include "pedigree/kernel/LockGuard.h"
3#include "pedigree/kernel/Log.h"
4#include "pedigree/kernel/machine/Disk.h"
5#include "pedigree/kernel/utilities/Vector.h"
6#include "pedigree/kernel/utilities/assert.h"
8#include "Ext2Filesystem.h"
13Ext2Filesystem::AttributeRetirement::~AttributeRetirement() {
15 filesystem->unpinBlock(block);
20XattrStatus Ext2Filesystem::attributeFormatStatus()
const {
22 return XattrStatus::IoError;
26 (LITTLE_TO_HOST32(
m_pSuperblock->s_feature_incompat) & ~uint32_t(2)) ||
27 (LITTLE_TO_HOST32(
m_pSuperblock->s_feature_ro_compat) & ~uint32_t(7)))
28 return XattrStatus::Unsupported;
29 return XattrStatus::Success;
32XattrStatus Ext2Filesystem::readAttributeBlockLocked(
Inode* inode, AttributeRetirement& plan) {
33 plan.filesystem =
this;
34 plan.block = LITTLE_TO_HOST32(inode->i_file_acl);
36 return XattrStatus::Success;
37 const uint32_t first = LITTLE_TO_HOST32(
m_pSuperblock->s_first_data_block);
38 const uint32_t perGroup = LITTLE_TO_HOST32(
m_pSuperblock->s_blocks_per_group);
39 if (plan.block <= first || plan.block >= LITTLE_TO_HOST32(
m_pSuperblock->s_blocks_count) ||
41 return XattrStatus::IoError;
43 const uint32_t descriptorEnd =
45 if (plan.block < descriptorEnd)
46 return XattrStatus::IoError;
47 const uint32_t tableBlocks =
53 const uint32_t table = LITTLE_TO_HOST32(descriptor->bg_inode_table);
54 if (plan.block == LITTLE_TO_HOST32(descriptor->bg_block_bitmap) ||
55 plan.block == LITTLE_TO_HOST32(descriptor->bg_inode_bitmap) ||
56 (plan.block >= table && plan.block - table < tableBlocks))
57 return XattrStatus::IoError;
61 return XattrStatus::IoError;
62 return Ext2Ea::validate(
reinterpret_cast<void*
>(plan.buffer),
m_BlockSize);
65XattrStatus Ext2Filesystem::prepareAttributeRetirementLocked(
Inode* inode,
66 AttributeRetirement& plan) {
67 auto status = readAttributeBlockLocked(inode, plan);
68 if (status != XattrStatus::Success || !plan.block)
70 if (!prepareBlockReleaseLocked(plan.block))
71 return XattrStatus::IoError;
72 const uint32_t relative = plan.block - LITTLE_TO_HOST32(
m_pSuperblock->s_first_data_block);
73 const uint32_t perGroup = LITTLE_TO_HOST32(
m_pSuperblock->s_blocks_per_group);
74 const uint32_t index = relative % perGroup;
76 const auto*
byte =
reinterpret_cast<const uint8_t*
>(bitmap[(index / 8) /
m_BlockSize]);
77 if (!(
byte[(index / 8) %
m_BlockSize] & (1U << (index % 8))))
78 return XattrStatus::IoError;
79 return XattrStatus::Success;
82XattrStatus Ext2Filesystem::reserveAttributeWritesLocked(
size_t additional) {
83 if (additional > MaximumAttributeWrites)
84 return XattrStatus::NoSpace;
85 if (m_AttributeWriteCount + additional > MaximumAttributeWrites && !flushAttributeWritesLocked())
86 return XattrStatus::IoError;
87 return XattrStatus::Success;
90void Ext2Filesystem::recordAttributeWriteLocked(uint64_t location, AttributeWriteKind kind,
92 for (
size_t n = 0; n < m_AttributeWriteCount; ++n) {
93 if (m_AttributeWrites[n].location != location)
96 if (m_AttributeWrites[n].ownsPin)
99 m_AttributeWrites[n].ownsPin =
true;
103 assert(m_AttributeWriteCount < MaximumAttributeWrites);
104 m_AttributeWrites[m_AttributeWriteCount++] = {location, kind, adoptPin};
107void Ext2Filesystem::recordAttributeAllocationLocked(uint32_t block) {
108 const uint32_t first = LITTLE_TO_HOST32(
m_pSuperblock->s_first_data_block);
109 const uint32_t perGroup = LITTLE_TO_HOST32(
m_pSuperblock->s_blocks_per_group);
110 const uint32_t group = (block - first) / perGroup;
111 const uint32_t index = (block - first) % perGroup;
112 const uint32_t bitmap =
114 recordAttributeWriteLocked(
static_cast<uint64_t
>(bitmap) *
m_BlockSize,
115 AttributeWriteKind::Allocation);
117 recordAttributeWriteLocked(
static_cast<uint64_t
>(descriptor) *
m_BlockSize,
118 AttributeWriteKind::Allocation);
119 recordAttributeWriteLocked(1024, AttributeWriteKind::Allocation);
122void Ext2Filesystem::recordAttributeInodeLocked(uint32_t inode) {
123 const uint32_t perGroup = LITTLE_TO_HOST32(
m_pSuperblock->s_inodes_per_group);
124 const uint32_t group = (inode - 1) / perGroup, index = (inode - 1) % perGroup;
127 recordAttributeWriteLocked(
static_cast<uint64_t
>(block) *
m_BlockSize, AttributeWriteKind::Inode);
130void Ext2Filesystem::forgetAttributeBlockLocked(uint32_t block) {
131 const uint64_t location =
static_cast<uint64_t
>(block) *
m_BlockSize;
132 for (
size_t n = 0; n < m_AttributeWriteCount; ++n) {
133 if (m_AttributeWrites[n].location != location)
135 assert(m_AttributeWrites[n].kind == AttributeWriteKind::Payload);
136 if (m_AttributeWrites[n].ownsPin)
138 m_AttributeWrites[n] = m_AttributeWrites[--m_AttributeWriteCount];
143bool Ext2Filesystem::flushAttributeWritesLocked() {
144 const AttributeWriteKind order[] = {AttributeWriteKind::Payload, AttributeWriteKind::Allocation,
145 AttributeWriteKind::Inode};
146 for (
auto kind : order) {
147 for (
size_t n = 0; n < m_AttributeWriteCount; ++n) {
148 if (m_AttributeWrites[n].kind == kind && !
m_pDisk->
sync(m_AttributeWrites[n].location,
false))
152 for (
size_t n = 0; n < m_AttributeWriteCount; ++n) {
153 if (m_AttributeWrites[n].ownsPin)
156 m_AttributeWriteCount = 0;
160void Ext2Filesystem::drainAttributeWrites() {
162 if (flushAttributeWritesLocked())
164 ERROR(
"Ext2: attribute metadata writeback failed at filesystem teardown");
165 for (
size_t n = 0; n < m_AttributeWriteCount; ++n) {
166 if (m_AttributeWrites[n].ownsPin)
169 m_AttributeWriteCount = 0;
172XattrStatus Ext2Filesystem::allocateAttributeBlockLocked(uint32_t inode,
173 AttributeRetirement& plan) {
175 if (!block.tryReserve(1))
176 return XattrStatus::NoMemory;
177 const uint32_t perGroup = LITTLE_TO_HOST32(
m_pSuperblock->s_inodes_per_group);
179 return XattrStatus::IoError;
185 if (!ensureFreeBlockBitmapLoaded(group))
186 return XattrStatus::IoError;
189 plan.filesystem =
this;
190 plan.block = block[0];
195 return XattrStatus::IoError;
197 plan.provisional =
true;
198 return XattrStatus::Success;
200 return XattrStatus::NoSpace;
203void Ext2Filesystem::commitAttributeRetirementLocked(AttributeRetirement& plan) {
207 const uint32_t references = LITTLE_TO_HOST32(header->references);
209 if (references == 1) {
210 forgetAttributeBlockLocked(plan.block);
212 recordAttributeAllocationLocked(plan.block);
214 header->references = HOST_TO_LITTLE32(references - 1);
216 recordAttributeWriteLocked(
static_cast<uint64_t
>(plan.block) *
m_BlockSize,
217 AttributeWriteKind::Payload,
true);
virtual bool sync(uint64_t location, bool async)
virtual void unpin(uint64_t location)=0
size_t m_nGroupDescriptors
GroupDesc ** m_pGroupDescriptors
void writeBlock(uint32_t block)
uintptr_t readBlock(uint32_t block)
Vector< size_t > * m_pBlockBitmaps
void releaseBlockLocked(uint32_t block, uint32_t inode=0)
size_t findFreeBlocksInGroup(uint32_t group, size_t maxCount, Vector< uint32_t > &blocks)
Superblock * m_pSuperblock
A vector / dynamic array.