block_cache: Change signature of *_etc() functions

* This allows file systems to retrieve the actual error code on a
  failure, and report it to the user.
* All affected file systems have been adjusted to the API change.
  This is a binary incompatible change.

Change-Id: Id73392aaf9c6cb7d643ff9adcb8bf80f3037874c
Reviewed-on: https://review.haiku-os.org/c/haiku/+/2913
Reviewed-by: Axel Dörfler <[email protected]>
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
Axel Dörfler
2020-06-20 18:10:03 +00:00
committed by waddlesplash
parent cc7b6b5870
commit 93845aec95
18 changed files with 425 additions and 349 deletions
+5 -5
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2004-2008, Haiku Inc. All Rights Reserved. * Copyright 2004-2020, Haiku Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _FS_CACHE_H #ifndef _FS_CACHE_H
@@ -66,14 +66,14 @@ extern void block_cache_discard(void *cache, off_t blockNumber,
size_t numBlocks); size_t numBlocks);
extern status_t block_cache_make_writable(void *cache, off_t blockNumber, extern status_t block_cache_make_writable(void *cache, off_t blockNumber,
int32 transaction); int32 transaction);
extern void *block_cache_get_writable_etc(void *cache, off_t blockNumber, extern status_t block_cache_get_writable_etc(void *cache, off_t blockNumber,
off_t base, off_t length, int32 transaction); off_t base, off_t length, int32 transaction, void** _block);
extern void *block_cache_get_writable(void *cache, off_t blockNumber, extern void *block_cache_get_writable(void *cache, off_t blockNumber,
int32 transaction); int32 transaction);
extern void *block_cache_get_empty(void *cache, off_t blockNumber, extern void *block_cache_get_empty(void *cache, off_t blockNumber,
int32 transaction); int32 transaction);
extern const void *block_cache_get_etc(void *cache, off_t blockNumber, extern status_t block_cache_get_etc(void *cache, off_t blockNumber,
off_t base, off_t length); off_t base, off_t length, const void** _block);
extern const void *block_cache_get(void *cache, off_t blockNumber); extern const void *block_cache_get(void *cache, off_t blockNumber);
extern status_t block_cache_set_dirty(void *cache, off_t blockNumber, extern status_t block_cache_set_dirty(void *cache, off_t blockNumber,
bool isDirty, int32 transaction); bool isDirty, int32 transaction);
+6 -5
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2004-2008, Haiku Inc. All Rights Reserved. * Copyright 2004-2020, Haiku Inc. All Rights Reserved.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _FSSH_FS_CACHE_H #ifndef _FSSH_FS_CACHE_H
@@ -76,16 +76,17 @@ extern void fssh_block_cache_discard(void *_cache,
fssh_off_t blockNumber, fssh_size_t numBlocks); fssh_off_t blockNumber, fssh_size_t numBlocks);
extern fssh_status_t fssh_block_cache_make_writable(void *_cache, extern fssh_status_t fssh_block_cache_make_writable(void *_cache,
fssh_off_t blockNumber, int32_t transaction); fssh_off_t blockNumber, int32_t transaction);
extern void * fssh_block_cache_get_writable_etc(void *_cache, extern fssh_status_t fssh_block_cache_get_writable_etc(void *_cache,
fssh_off_t blockNumber, fssh_off_t base, fssh_off_t blockNumber, fssh_off_t base,
fssh_off_t length, int32_t transaction); fssh_off_t length, int32_t transaction,
void **_block);
extern void * fssh_block_cache_get_writable(void *_cache, extern void * fssh_block_cache_get_writable(void *_cache,
fssh_off_t blockNumber, int32_t transaction); fssh_off_t blockNumber, int32_t transaction);
extern void * fssh_block_cache_get_empty(void *_cache, extern void * fssh_block_cache_get_empty(void *_cache,
fssh_off_t blockNumber, int32_t transaction); fssh_off_t blockNumber, int32_t transaction);
extern const void * fssh_block_cache_get_etc(void *_cache, extern fssh_status_t fssh_block_cache_get_etc(void *_cache,
fssh_off_t blockNumber, fssh_off_t base, fssh_off_t blockNumber, fssh_off_t base,
fssh_off_t length); fssh_off_t length, const void **_block);
extern const void * fssh_block_cache_get(void *_cache, extern const void * fssh_block_cache_get(void *_cache,
fssh_off_t blockNumber); fssh_off_t blockNumber);
extern fssh_status_t fssh_block_cache_set_dirty(void *_cache, extern fssh_status_t fssh_block_cache_set_dirty(void *_cache,
@@ -1,5 +1,5 @@
/* /*
* Copyright 2004-2017, Axel Dörfler, [email protected]. * Copyright 2004-2020, Axel Dörfler, [email protected].
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
@@ -83,9 +83,9 @@ Attribute::Get(const char* name)
// try to find it in the small data region // try to find it in the small data region
if (recursive_lock_lock(&fInode->SmallDataLock()) == B_OK) { if (recursive_lock_lock(&fInode->SmallDataLock()) == B_OK) {
fNodeGetter.SetToNode(fInode); status_t status = fNodeGetter.SetTo(fInode);
if (fNodeGetter.Node() == NULL) if (status != B_OK)
return B_IO_ERROR; return status;
fSmall = fInode->FindSmallData(fNodeGetter.Node(), (const char*)name); fSmall = fInode->FindSmallData(fNodeGetter.Node(), (const char*)name);
if (fSmall != NULL) if (fSmall != NULL)
@@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2017, Axel Dörfler, [email protected]. * Copyright 2001-2020, Axel Dörfler, [email protected].
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
@@ -238,7 +238,7 @@ AllocationBlock::SetTo(AllocationGroup& group, uint16 block)
#ifdef DEBUG #ifdef DEBUG
fWritable = false; fWritable = false;
#endif #endif
return CachedBlock::SetTo(group.Start() + block) != NULL ? B_OK : B_ERROR; return CachedBlock::SetTo(group.Start() + block);
} }
@@ -255,8 +255,7 @@ AllocationBlock::SetToWritable(Transaction& transaction, AllocationGroup& group,
#ifdef DEBUG #ifdef DEBUG
fWritable = true; fWritable = true;
#endif #endif
return CachedBlock::SetToWritable(transaction, group.Start() + block) return CachedBlock::SetToWritable(transaction, group.Start() + block);
!= NULL ? B_OK : B_ERROR;
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2017, Axel Dörfler, axeld@pinc-software.de. * Copyright 2001-2020, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
#ifndef CACHED_BLOCK_H #ifndef CACHED_BLOCK_H
@@ -24,27 +24,26 @@
class CachedBlock { class CachedBlock {
public: public:
CachedBlock(Volume* volume); CachedBlock(Volume* volume);
CachedBlock(Volume* volume, off_t block);
CachedBlock(Volume* volume, block_run run);
CachedBlock(CachedBlock* cached); CachedBlock(CachedBlock* cached);
~CachedBlock(); ~CachedBlock();
inline void Keep(); inline void Keep();
inline void Unset(); inline void Unset();
inline const uint8* SetTo(off_t block, off_t base, size_t length); inline status_t SetTo(off_t block, off_t base, size_t length);
inline const uint8* SetTo(off_t block); inline status_t SetTo(off_t block);
inline const uint8* SetTo(block_run run); inline status_t SetTo(block_run run);
inline uint8* SetToWritable(Transaction& transaction, inline status_t SetToWritable(Transaction& transaction,
off_t block, off_t base, size_t length, off_t block, off_t base, size_t length,
bool empty = false); bool empty = false);
inline uint8* SetToWritable(Transaction& transaction, inline status_t SetToWritable(Transaction& transaction,
off_t block, bool empty = false); off_t block, bool empty = false);
inline uint8* SetToWritable(Transaction& transaction, inline status_t SetToWritable(Transaction& transaction,
block_run run, bool empty = false); block_run run, bool empty = false);
inline status_t MakeWritable(Transaction& transaction); inline status_t MakeWritable(Transaction& transaction);
const uint8* Block() const { return fBlock; } const uint8* Block() const { return fBlock; }
uint8* WritableBlock() const { return fBlock; }
off_t BlockNumber() const { return fBlockNumber; } off_t BlockNumber() const { return fBlockNumber; }
uint32 BlockSize() const uint32 BlockSize() const
{ return fVolume->BlockSize(); } { return fVolume->BlockSize(); }
@@ -76,28 +75,6 @@ CachedBlock::CachedBlock(Volume* volume)
} }
inline
CachedBlock::CachedBlock(Volume* volume, off_t block)
:
fVolume(volume),
fBlockNumber(0),
fBlock(NULL)
{
SetTo(block);
}
inline
CachedBlock::CachedBlock(Volume* volume, block_run run)
:
fVolume(volume),
fBlockNumber(0),
fBlock(NULL)
{
SetTo(volume->ToBlock(run));
}
inline inline
CachedBlock::CachedBlock(CachedBlock* cached) CachedBlock::CachedBlock(CachedBlock* cached)
: :
@@ -133,31 +110,31 @@ CachedBlock::Unset()
} }
inline const uint8* inline status_t
CachedBlock::SetTo(off_t block, off_t base, size_t length) CachedBlock::SetTo(off_t block, off_t base, size_t length)
{ {
Unset(); Unset();
fBlockNumber = block; fBlockNumber = block;
return fBlock = (uint8*)block_cache_get_etc(fVolume->BlockCache(), return block_cache_get_etc(fVolume->BlockCache(), block, base, length,
block, base, length); (const void**)&fBlock);
} }
inline const uint8* inline status_t
CachedBlock::SetTo(off_t block) CachedBlock::SetTo(off_t block)
{ {
return SetTo(block, block, 1); return SetTo(block, block, 1);
} }
inline const uint8* inline status_t
CachedBlock::SetTo(block_run run) CachedBlock::SetTo(block_run run)
{ {
return SetTo(fVolume->ToBlock(run)); return SetTo(fVolume->ToBlock(run));
} }
inline uint8* inline status_t
CachedBlock::SetToWritable(Transaction& transaction, off_t block, off_t base, CachedBlock::SetToWritable(Transaction& transaction, off_t block, off_t base,
size_t length, bool empty) size_t length, bool empty)
{ {
@@ -167,23 +144,22 @@ CachedBlock::SetToWritable(Transaction& transaction, off_t block, off_t base,
if (empty) { if (empty) {
fBlock = (uint8*)block_cache_get_empty(fVolume->BlockCache(), fBlock = (uint8*)block_cache_get_empty(fVolume->BlockCache(),
block, transaction.ID()); block, transaction.ID());
} else { return fBlock != NULL ? B_OK : B_NO_MEMORY;
fBlock = (uint8*)block_cache_get_writable_etc(fVolume->BlockCache(),
block, base, length, transaction.ID());
} }
return fBlock; return block_cache_get_writable_etc(fVolume->BlockCache(),
block, base, length, transaction.ID(), (void**)&fBlock);
} }
inline uint8* inline status_t
CachedBlock::SetToWritable(Transaction& transaction, off_t block, bool empty) CachedBlock::SetToWritable(Transaction& transaction, off_t block, bool empty)
{ {
return SetToWritable(transaction, block, block, 1, empty); return SetToWritable(transaction, block, block, 1, empty);
} }
inline uint8* inline status_t
CachedBlock::SetToWritable(Transaction& transaction, block_run run, bool empty) CachedBlock::SetToWritable(Transaction& transaction, block_run run, bool empty)
{ {
return SetToWritable(transaction, fVolume->ToBlock(run), empty); return SetToWritable(transaction, fVolume->ToBlock(run), empty);
@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2012, Axel Dörfler, axeld@pinc-software.de. * Copyright 2002-2020, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2012, Andreas Henriksson, sausageboy@gmail.com * Copyright 2012, Andreas Henriksson, sausageboy@gmail.com
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
@@ -211,10 +211,11 @@ CheckVisitor::VisitDirectoryEntry(Inode* inode, Inode* parent,
// check if the inode's name is the same as in the b+tree // check if the inode's name is the same as in the b+tree
if (inode->IsRegularNode()) { if (inode->IsRegularNode()) {
RecursiveLocker locker(inode->SmallDataLock()); RecursiveLocker locker(inode->SmallDataLock());
NodeGetter node(GetVolume(), inode); NodeGetter node(GetVolume());
if (node.Node() == NULL) { status_t status = node.SetTo(inode);
if (status != B_OK) {
Control().errors |= BFS_COULD_NOT_OPEN; Control().errors |= BFS_COULD_NOT_OPEN;
Control().status = B_IO_ERROR; Control().status = status;
return B_OK; return B_OK;
} }
@@ -496,16 +497,17 @@ CheckVisitor::_CheckInodeBlocks(Inode* inode, const char* name)
if (data->max_indirect_range) { if (data->max_indirect_range) {
status = _CheckAllocated(data->indirect, "indirect"); status = _CheckAllocated(data->indirect, "indirect");
if (status < B_OK) if (status != B_OK)
return status; return status;
off_t block = GetVolume()->ToBlock(data->indirect); off_t block = GetVolume()->ToBlock(data->indirect);
for (int32 i = 0; i < data->indirect.Length(); i++) { for (int32 i = 0; i < data->indirect.Length(); i++) {
block_run* runs = (block_run*)cached.SetTo(block + i); status = cached.SetTo(block + i);
if (runs == NULL) if (status != B_OK)
RETURN_ERROR(B_IO_ERROR); RETURN_ERROR(status);
block_run* runs = (block_run*)cached.Block();
int32 runsPerBlock = GetVolume()->BlockSize() / sizeof(block_run); int32 runsPerBlock = GetVolume()->BlockSize() / sizeof(block_run);
int32 index = 0; int32 index = 0;
for (; index < runsPerBlock; index++) { for (; index < runsPerBlock; index++) {
@@ -542,12 +544,12 @@ CheckVisitor::_CheckInodeBlocks(Inode* inode, const char* name)
for (int32 indirectIndex = 0; indirectIndex < runsPerArray; for (int32 indirectIndex = 0; indirectIndex < runsPerArray;
indirectIndex++) { indirectIndex++) {
// get the indirect array block // get the indirect array block
block_run* array = (block_run*)cached.SetTo( status = cached.SetTo(GetVolume()->ToBlock(data->double_indirect)
GetVolume()->ToBlock(data->double_indirect)
+ indirectIndex / runsPerBlock); + indirectIndex / runsPerBlock);
if (array == NULL) if (status != B_OK)
return B_IO_ERROR; return status;
block_run* array = (block_run*)cached.Block();
block_run indirect = array[indirectIndex % runsPerBlock]; block_run indirect = array[indirectIndex % runsPerBlock];
// are we finished yet? // are we finished yet?
if (indirect.IsZero()) if (indirect.IsZero())
@@ -562,10 +564,12 @@ CheckVisitor::_CheckInodeBlocks(Inode* inode, const char* name)
/ sizeof(block_run); / sizeof(block_run);
for (int32 index = 0; index < maxIndex; ) { for (int32 index = 0; index < maxIndex; ) {
block_run* runs = (block_run*)cachedDirect.SetTo( status = cachedDirect.SetTo(GetVolume()->ToBlock(indirect)
GetVolume()->ToBlock(indirect) + index / runsPerBlock); + index / runsPerBlock);
if (runs == NULL) if (status != B_OK)
return B_IO_ERROR; return status;
block_run* runs = (block_run*)cachedDirect.Block();
do { do {
// are we finished yet? // are we finished yet?
+115 -81
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2017, Axel Dörfler, axeld@pinc-software.de. * Copyright 2001-2020, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
@@ -385,9 +385,11 @@ Inode::Inode(Volume* volume, Transaction& transaction, ino_t id, mode_t mode,
rw_lock_init(&fLock, "bfs inode"); rw_lock_init(&fLock, "bfs inode");
recursive_lock_init(&fSmallDataLock, "bfs inode small data"); recursive_lock_init(&fSmallDataLock, "bfs inode small data");
NodeGetter node(volume, transaction, this, true); NodeGetter node(volume);
if (node.Node() == NULL) { status_t status = node.SetToWritable(transaction, this, true);
FATAL(("Could not read inode block %" B_PRId64 "!\n", BlockNumber())); if (status != B_OK) {
FATAL(("Could not read inode block %" B_PRId64 ": %s!\n", BlockNumber(),
strerror(status)));
return; return;
} }
@@ -491,9 +493,10 @@ Inode::WriteLockInTransaction(Transaction& transaction)
status_t status_t
Inode::WriteBack(Transaction& transaction) Inode::WriteBack(Transaction& transaction)
{ {
NodeGetter node(fVolume, transaction, this); NodeGetter node(fVolume);
if (node.WritableNode() == NULL) status_t status = node.SetToWritable(transaction, this);
return B_IO_ERROR; if (status != B_OK)
return status;
memcpy(node.WritableNode(), &Node(), sizeof(bfs_inode)); memcpy(node.WritableNode(), &Node(), sizeof(bfs_inode));
return B_OK; return B_OK;
@@ -503,11 +506,12 @@ Inode::WriteBack(Transaction& transaction)
status_t status_t
Inode::UpdateNodeFromDisk() Inode::UpdateNodeFromDisk()
{ {
NodeGetter node(fVolume, this); NodeGetter node(fVolume);
if (node.Node() == NULL) { status_t status = node.SetTo(this);
FATAL(("Failed to read block %" B_PRId64 " from disk!\n", if (status != B_OK) {
BlockNumber())); FATAL(("Failed to read block %" B_PRId64 " from disk: %s!\n",
return B_IO_ERROR; BlockNumber(), strerror(status)));
return status;
} }
memcpy(&fNode, node.Node(), sizeof(bfs_inode)); memcpy(&fNode, node.Node(), sizeof(bfs_inode));
@@ -677,9 +681,11 @@ Inode::_RemoveSmallData(Transaction& transaction, NodeGetter& nodeGetter,
if (item->IsLast(node)) if (item->IsLast(node))
return B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND;
nodeGetter.MakeWritable(transaction); status_t status = nodeGetter.MakeWritable(transaction);
if (status != B_OK)
return status;
status_t status = _RemoveSmallData(node, item, index); status = _RemoveSmallData(node, item, index);
if (status == B_OK) { if (status == B_OK) {
Node().status_change_time = HOST_ENDIAN_TO_BFS_INT64( Node().status_change_time = HOST_ENDIAN_TO_BFS_INT64(
bfs_inode::ToInode(real_time_clock_usecs())); bfs_inode::ToInode(real_time_clock_usecs()));
@@ -718,7 +724,10 @@ Inode::_AddSmallData(Transaction& transaction, NodeGetter& nodeGetter,
if (spaceNeeded > fVolume->InodeSize() - sizeof(bfs_inode)) if (spaceNeeded > fVolume->InodeSize() - sizeof(bfs_inode))
return B_DEVICE_FULL; return B_DEVICE_FULL;
nodeGetter.MakeWritable(transaction); status_t status = nodeGetter.MakeWritable(transaction);
if (status != B_OK)
return status;
RecursiveLocker locker(fSmallDataLock); RecursiveLocker locker(fSmallDataLock);
// Find the last item or one with the same name we have to add // Find the last item or one with the same name we have to add
@@ -934,9 +943,10 @@ Inode::Name(const bfs_inode* node) const
status_t status_t
Inode::GetName(char* buffer, size_t size) const Inode::GetName(char* buffer, size_t size) const
{ {
NodeGetter node(fVolume, this); NodeGetter node(fVolume);
if (node.Node() == NULL) status_t status = node.SetTo(this);
return B_IO_ERROR; if (status != B_OK)
return status;
RecursiveLocker locker(fSmallDataLock); RecursiveLocker locker(fSmallDataLock);
@@ -961,9 +971,10 @@ Inode::SetName(Transaction& transaction, const char* name)
if (name == NULL || *name == '\0') if (name == NULL || *name == '\0')
return B_BAD_VALUE; return B_BAD_VALUE;
NodeGetter node(fVolume, transaction, this); NodeGetter node(fVolume);
if (node.Node() == NULL) status_t status = node.SetToWritable(transaction, this);
return B_IO_ERROR; if (status != B_OK)
return status;
const char nameTag[2] = {FILE_NAME_NAME, 0}; const char nameTag[2] = {FILE_NAME_NAME, 0};
@@ -1037,9 +1048,10 @@ Inode::ReadAttribute(const char* name, int32 type, off_t pos, uint8* buffer,
// search in the small_data section (which has to be locked first) // search in the small_data section (which has to be locked first)
{ {
NodeGetter node(fVolume, this); NodeGetter node(fVolume);
if (node.Node() == NULL) status_t status = node.SetTo(this);
return B_IO_ERROR; if (status != B_OK)
return status;
RecursiveLocker locker(fSmallDataLock); RecursiveLocker locker(fSmallDataLock);
@@ -1107,9 +1119,10 @@ Inode::WriteAttribute(Transaction& transaction, const char* name, int32 type,
// No attribute inode exists yet // No attribute inode exists yet
// save the old attribute data // save the old attribute data
NodeGetter node(fVolume, transaction, this); NodeGetter node(fVolume);
if (node.Node() == NULL) status = node.SetToWritable(transaction, this);
return B_IO_ERROR; if (status != B_OK)
return status;
recursive_lock_lock(&fSmallDataLock); recursive_lock_lock(&fSmallDataLock);
@@ -1179,9 +1192,10 @@ Inode::WriteAttribute(Transaction& transaction, const char* name, int32 type,
} }
// check if the data fits into the small_data section again // check if the data fits into the small_data section again
NodeGetter node(fVolume, transaction, this); NodeGetter node(fVolume);
if (node.Node() == NULL) status = node.SetToWritable(transaction, this);
return B_IO_ERROR; if (status != B_OK)
return status;
status = _AddSmallData(transaction, node, name, type, pos, buffer, status = _AddSmallData(transaction, node, name, type, pos, buffer,
*_length); *_length);
@@ -1252,9 +1266,10 @@ Inode::RemoveAttribute(Transaction& transaction, const char* name)
{ {
Index index(fVolume); Index index(fVolume);
bool hasIndex = index.SetTo(name) == B_OK; bool hasIndex = index.SetTo(name) == B_OK;
NodeGetter node(fVolume, this); NodeGetter node(fVolume);
if (node.Node() == NULL) status_t status = node.SetTo(this);
return B_IO_ERROR; if (status != B_OK)
return status;
// update index for attributes in the small_data section // update index for attributes in the small_data section
{ {
@@ -1270,7 +1285,7 @@ Inode::RemoveAttribute(Transaction& transaction, const char* name)
} }
} }
status_t status = _RemoveSmallData(transaction, node, name); status = _RemoveSmallData(transaction, node, name);
if (status == B_ENTRY_NOT_FOUND && !Attributes().IsZero()) { if (status == B_ENTRY_NOT_FOUND && !Attributes().IsZero()) {
// remove the attribute file if it exists // remove the attribute file if it exists
status = _RemoveAttribute(transaction, name, hasIndex, &index); status = _RemoveAttribute(transaction, name, hasIndex, &index);
@@ -1477,19 +1492,20 @@ Inode::FindBlockRun(off_t pos, block_run& run, off_t& offset)
off_t start = pos - data->MaxIndirectRange(); off_t start = pos - data->MaxIndirectRange();
int32 index = start / indirectSize; int32 index = start / indirectSize;
block_run* indirect = (block_run*)cached.SetTo( status_t status = cached.SetTo(fVolume->ToBlock(
fVolume->ToBlock(data->double_indirect) + index / runsPerBlock); data->double_indirect) + index / runsPerBlock);
if (indirect == NULL) if (status != B_OK)
RETURN_ERROR(B_ERROR); RETURN_ERROR(status);
block_run* indirect = (block_run*)cached.Block();
int32 current = (start % indirectSize) / directSize; int32 current = (start % indirectSize) / directSize;
indirect = (block_run*)cached.SetTo( status = cached.SetTo(fVolume->ToBlock(indirect[
fVolume->ToBlock(indirect[index % runsPerBlock]) index % runsPerBlock]) + current / runsPerBlock);
+ current / runsPerBlock); if (status != B_OK)
if (indirect == NULL) RETURN_ERROR(status);
RETURN_ERROR(B_ERROR);
indirect = (block_run*)cached.Block();
run = indirect[current % runsPerBlock]; run = indirect[current % runsPerBlock];
if (run.Length() != data->double_indirect.Length()) if (run.Length() != data->double_indirect.Length())
RETURN_ERROR(B_BAD_DATA); RETURN_ERROR(B_BAD_DATA);
@@ -1506,10 +1522,11 @@ Inode::FindBlockRun(off_t pos, block_run& run, off_t& offset)
off_t block = fVolume->ToBlock(data->indirect); off_t block = fVolume->ToBlock(data->indirect);
for (int32 i = 0; i < data->indirect.Length(); i++) { for (int32 i = 0; i < data->indirect.Length(); i++) {
block_run* indirect = (block_run*)cached.SetTo(block + i); status_t status = cached.SetTo(block + i);
if (indirect == NULL) if (status != B_OK)
RETURN_ERROR(B_IO_ERROR); RETURN_ERROR(status);
block_run* indirect = (block_run*)cached.Block();
int32 current = -1; int32 current = -1;
while (++current < runsPerBlock) { while (++current < runsPerBlock) {
if (indirect[current].IsZero()) if (indirect[current].IsZero())
@@ -1689,10 +1706,9 @@ Inode::_AllocateBlockArray(Transaction& transaction, block_run& run,
off_t block = fVolume->ToBlock(run); off_t block = fVolume->ToBlock(run);
for (int32 i = 0; i < run.Length(); i++) { for (int32 i = 0; i < run.Length(); i++) {
block_run* runs = (block_run*)cached.SetToWritable(transaction, status = cached.SetToWritable(transaction, block + i, true);
block + i, true); if (status != B_OK)
if (runs == NULL) return status;
return B_IO_ERROR;
} }
return B_OK; return B_OK;
} }
@@ -1851,7 +1867,11 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
data->max_indirect_range = HOST_ENDIAN_TO_BFS_INT64( data->max_indirect_range = HOST_ENDIAN_TO_BFS_INT64(
data->MaxDirectRange()); data->MaxDirectRange());
// insert the block_run in the first block // insert the block_run in the first block
runs = (block_run*)cached.SetTo(data->indirect); status = cached.SetTo(data->indirect);
if (status != B_OK)
return status;
runs = (block_run*)cached.Block();
} else { } else {
uint32 numberOfRuns = fVolume->BlockSize() / sizeof(block_run); uint32 numberOfRuns = fVolume->BlockSize() / sizeof(block_run);
block = fVolume->ToBlock(data->indirect); block = fVolume->ToBlock(data->indirect);
@@ -1859,9 +1879,11 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
// search first empty entry // search first empty entry
int32 i = 0; int32 i = 0;
for (; i < data->indirect.Length(); i++) { for (; i < data->indirect.Length(); i++) {
if ((runs = (block_run*)cached.SetTo(block + i)) == NULL) status = cached.SetTo(block + i);
return B_IO_ERROR; if (status != B_OK)
return status;
runs = (block_run*)cached.Block();
for (free = 0; free < numberOfRuns; free++) for (free = 0; free < numberOfRuns; free++)
if (runs[free].IsZero()) if (runs[free].IsZero())
break; break;
@@ -1971,10 +1993,12 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
if (block >= minimum) if (block >= minimum)
return EFBIG; return EFBIG;
array = (block_run*)cached.SetTo(fVolume->ToBlock( status = cached.SetTo(fVolume->ToBlock(
data->double_indirect) + block); data->double_indirect) + block);
if (array == NULL) if (status != B_OK)
return B_IO_ERROR; return status;
array = (block_run*)cached.Block();
} }
do { do {
@@ -1989,11 +2013,13 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
return status; return status;
} }
block_run* runs = (block_run*)cachedDirect.SetToWritable( status = cachedDirect.SetToWritable(transaction,
transaction, fVolume->ToBlock(array[indirectIndex fVolume->ToBlock(array[indirectIndex
% runsPerBlock]) + index / runsPerBlock); % runsPerBlock]) + index / runsPerBlock);
if (runs == NULL) if (status != B_OK)
return B_IO_ERROR; return status;
block_run* runs = (block_run*)cachedDirect.Block();
do { do {
// insert the block_run into the array // insert the block_run into the array
@@ -2079,10 +2105,11 @@ Inode::_FreeStaticStreamArray(Transaction& transaction, int32 level,
offset += (off_t)index * indirectSize; offset += (off_t)index * indirectSize;
for (int32 i = index / runsPerBlock; i < run.Length(); i++) { for (int32 i = index / runsPerBlock; i < run.Length(); i++) {
block_run* array = (block_run*)cached.SetToWritable(transaction, status_t status = cached.SetToWritable(transaction, blockNumber + i);
blockNumber + i); if (status != B_OK)
if (array == NULL) RETURN_ERROR(status);
RETURN_ERROR(B_ERROR);
block_run* array = (block_run*)cached.WritableBlock();
for (index = index % runsPerBlock; index < runsPerBlock; index++) { for (index = index % runsPerBlock; index < runsPerBlock; index++) {
if (array[index].IsZero()) { if (array[index].IsZero()) {
@@ -2201,10 +2228,11 @@ Inode::_ShrinkStream(Transaction& transaction, off_t size)
off_t offset = data->MaxDirectRange(); off_t offset = data->MaxDirectRange();
for (int32 i = 0; i < data->indirect.Length(); i++) { for (int32 i = 0; i < data->indirect.Length(); i++) {
block_run* array = (block_run*)cached.SetToWritable(transaction, status = cached.SetToWritable(transaction, block + i);
block + i); if (status != B_OK)
if (array == NULL) return status;
break;
block_run* array = (block_run*)cached.WritableBlock();
off_t* maxIndirect = &data->max_indirect_range; off_t* maxIndirect = &data->max_indirect_range;
// gcc 4 work-around: "error: cannot bind packed field // gcc 4 work-around: "error: cannot bind packed field
@@ -2227,7 +2255,7 @@ Inode::_ShrinkStream(Transaction& transaction, off_t size)
// 'data->data_stream::max_direct_range' to 'off_t&'" // 'data->data_stream::max_direct_range' to 'off_t&'"
status = _FreeStreamArray(transaction, data->direct, NUM_DIRECT_BLOCKS, status = _FreeStreamArray(transaction, data->direct, NUM_DIRECT_BLOCKS,
size, offset, *maxDirect); size, offset, *maxDirect);
if (status < B_OK) if (status != B_OK)
return status; return status;
} }
@@ -2392,9 +2420,11 @@ Inode::Sync()
int32 count = fVolume->BlockSize() / sizeof(block_run); int32 count = fVolume->BlockSize() / sizeof(block_run);
for (int32 j = 0; j < data->indirect.Length(); j++) { for (int32 j = 0; j < data->indirect.Length(); j++) {
block_run* runs = (block_run*)cached.SetTo(block + j); status = cached.SetTo(block + j);
if (runs == NULL) if (status != B_OK)
break; return status;
block_run* runs = (block_run*)cached.Block();
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count; i++) {
if (runs[i].IsZero()) if (runs[i].IsZero())
@@ -2415,10 +2445,11 @@ Inode::Sync()
off_t indirectBlock = fVolume->ToBlock(data->double_indirect); off_t indirectBlock = fVolume->ToBlock(data->double_indirect);
for (int32 l = 0; l < data->double_indirect.Length(); l++) { for (int32 l = 0; l < data->double_indirect.Length(); l++) {
block_run* indirectRuns = (block_run*)cached.SetTo(indirectBlock + l); status = cached.SetTo(indirectBlock + l);
if (indirectRuns == NULL) if (status != B_OK)
return B_FILE_ERROR; return status;
block_run* indirectRuns = (block_run*)cached.Block();
CachedBlock directCached(fVolume); CachedBlock directCached(fVolume);
for (int32 k = 0; k < count; k++) { for (int32 k = 0; k < count; k++) {
@@ -2427,9 +2458,11 @@ Inode::Sync()
block = fVolume->ToBlock(indirectRuns[k]); block = fVolume->ToBlock(indirectRuns[k]);
for (int32 j = 0; j < indirectRuns[k].Length(); j++) { for (int32 j = 0; j < indirectRuns[k].Length(); j++) {
block_run* runs = (block_run*)directCached.SetTo(block + j); status = directCached.SetTo(block + j);
if (runs == NULL) if (status != B_OK)
return B_FILE_ERROR; return status;
block_run* runs = (block_run*)directCached.Block();
for (int32 i = 0; i < count; i++) { for (int32 i = 0; i < count; i++) {
if (runs[i].IsZero()) if (runs[i].IsZero())
@@ -2848,9 +2881,10 @@ AttributeIterator::GetNext(char* name, size_t* _length, uint32* _type,
// read attributes out of the small data section // read attributes out of the small data section
if (fCurrentSmallData >= 0) { if (fCurrentSmallData >= 0) {
NodeGetter nodeGetter(fInode->GetVolume(), fInode); NodeGetter nodeGetter(fInode->GetVolume());
if (nodeGetter.Node() == NULL) status_t status = nodeGetter.SetTo(fInode);
return B_IO_ERROR; if (status != B_OK)
return status;
const bfs_inode* node = nodeGetter.Node(); const bfs_inode* node = nodeGetter.Node();
const small_data* item = ((bfs_inode*)node)->SmallDataStart(); const small_data* item = ((bfs_inode*)node)->SmallDataStart();
+12 -17
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2017, Axel Dörfler, axeld@pinc-software.de. * Copyright 2001-2020, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
#ifndef INODE_H #ifndef INODE_H
@@ -338,30 +338,25 @@ private:
class NodeGetter : public CachedBlock { class NodeGetter : public CachedBlock {
public: public:
NodeGetter(Volume* volume) NodeGetter(Volume* volume)
: CachedBlock(volume) :
CachedBlock(volume)
{ {
} }
NodeGetter(Volume* volume, const Inode* inode)
: CachedBlock(volume)
{
SetTo(volume->VnodeToBlock(inode->ID()));
}
NodeGetter(Volume* volume, Transaction& transaction,
const Inode* inode, bool empty = false)
: CachedBlock(volume)
{
SetToWritable(transaction, volume->VnodeToBlock(inode->ID()), empty);
}
~NodeGetter() ~NodeGetter()
{ {
} }
const bfs_inode* SetToNode(const Inode* inode) status_t SetTo(const Inode* inode)
{ {
return (const bfs_inode*)SetTo(fVolume->VnodeToBlock(inode->ID())); return CachedBlock::SetTo(fVolume->VnodeToBlock(inode->ID()));
}
status_t SetToWritable(Transaction& transaction, const Inode* inode,
bool empty = false)
{
return CachedBlock::SetToWritable(transaction,
fVolume->VnodeToBlock(inode->ID()), empty);
} }
const bfs_inode* Node() const { return (const bfs_inode*)Block(); } const bfs_inode* Node() const { return (const bfs_inode*)Block(); }
+14 -14
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2017, Axel Dörfler, axeld@pinc-software.de. * Copyright 2001-2020, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
@@ -484,11 +484,11 @@ Journal::_ReplayRunArray(int32* _start)
CachedBlock cachedArray(fVolume); CachedBlock cachedArray(fVolume);
const run_array* array = (const run_array*)cachedArray.SetTo(logOffset status_t status = cachedArray.SetTo(logOffset + firstBlockNumber);
+ firstBlockNumber); if (status != B_OK)
if (array == NULL) return status;
return B_IO_ERROR;
const run_array* array = (const run_array*)cachedArray.Block();
if (_CheckRunArray(array) < B_OK) if (_CheckRunArray(array) < B_OK)
return B_BAD_DATA; return B_BAD_DATA;
@@ -505,16 +505,16 @@ Journal::_ReplayRunArray(int32* _start)
off_t offset = fVolume->ToOffset(run); off_t offset = fVolume->ToOffset(run);
for (int32 i = 0; i < run.Length(); i++) { for (int32 i = 0; i < run.Length(); i++) {
const uint8* data = cached.SetTo(logOffset + blockNumber); status = cached.SetTo(logOffset + blockNumber);
if (data == NULL) if (status != status)
RETURN_ERROR(B_IO_ERROR); RETURN_ERROR(status);
// TODO: eventually check other well known offsets, like the // TODO: eventually check other well known offsets, like the
// root and index dirs // root and index dirs
if (offset == 0) { if (offset == 0) {
// This log entry writes over the superblock - check if // This log entry writes over the superblock - check if
// it's valid! // it's valid!
if (Volume::CheckSuperBlock(data) != B_OK) { if (Volume::CheckSuperBlock(cached.Block()) != B_OK) {
FATAL(("Log contains invalid superblock!\n")); FATAL(("Log contains invalid superblock!\n"));
RETURN_ERROR(B_BAD_DATA); RETURN_ERROR(B_BAD_DATA);
} }
@@ -537,12 +537,12 @@ Journal::_ReplayRunArray(int32* _start)
off_t offset = fVolume->ToOffset(run); off_t offset = fVolume->ToOffset(run);
for (int32 i = 0; i < run.Length(); i++) { for (int32 i = 0; i < run.Length(); i++) {
const uint8* data = cached.SetTo(logOffset + blockNumber); status = cached.SetTo(logOffset + blockNumber);
if (data == NULL) if (status != B_OK)
RETURN_ERROR(B_IO_ERROR); RETURN_ERROR(status);
ssize_t written = write_pos(fVolume->Device(), offset, data, ssize_t written = write_pos(fVolume->Device(), offset,
blockSize); cached.Block(), blockSize);
if (written != blockSize) if (written != blockSize)
RETURN_ERROR(B_IO_ERROR); RETURN_ERROR(B_IO_ERROR);
@@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2017, Axel Dörfler, axeld@pinc-software.de. * Copyright 2001-2020, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de> * Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de>
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
@@ -384,9 +384,9 @@ Equation::Match(Inode* inode, const char* attributeName, int32 type,
buffer = const_cast<uint8*>(key); buffer = const_cast<uint8*>(key);
} else if (!strcmp(fAttribute, "name")) { } else if (!strcmp(fAttribute, "name")) {
// we need to lock before accessing Inode::Name() // we need to lock before accessing Inode::Name()
nodeGetter.SetToNode(inode); status_t status = nodeGetter.SetTo(inode);
if (nodeGetter.Node() == NULL) if (status != B_OK)
return B_IO_ERROR; return status;
recursive_lock_lock(&inode->SmallDataLock()); recursive_lock_lock(&inode->SmallDataLock());
locked = true; locked = true;
@@ -417,9 +417,9 @@ Equation::Match(Inode* inode, const char* attributeName, int32 type,
} else { } else {
// then for attributes in the small_data section, and finally for the // then for attributes in the small_data section, and finally for the
// real attributes // real attributes
nodeGetter.SetToNode(inode); status_t status = nodeGetter.SetTo(inode);
if (nodeGetter.Node() == NULL) if (status != B_OK)
return B_IO_ERROR; return status;
Inode* attribute; Inode* attribute;
@@ -1,5 +1,5 @@
/* /*
* Copyright 2001-2017, Axel Dörfler, axeld@pinc-software.de. * Copyright 2001-2020, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
@@ -294,14 +294,16 @@ bfs_get_vnode(fs_volume* _volume, ino_t id, fs_vnode* _node, int* _type,
return B_ERROR; return B_ERROR;
} }
CachedBlock cached(volume, id); CachedBlock cached(volume);
bfs_inode* node = (bfs_inode*)cached.Block(); status_t status = cached.SetTo(id);
if (node == NULL) { if (status != B_OK) {
FATAL(("could not read inode: %" B_PRIdINO "\n", id)); FATAL(("could not read inode: %" B_PRIdINO ": %s\n", id,
return B_IO_ERROR; strerror(status)));
return status;
} }
bfs_inode* node = (bfs_inode*)cached.Block();
status_t status = node->InitCheck(volume); status = node->InitCheck(volume);
if (status != B_OK) { if (status != B_OK) {
if ((node->Flags() & INODE_DELETED) != 0) { if ((node->Flags() & INODE_DELETED) != 0) {
INFORM(("inode at %" B_PRIdINO " is already deleted!\n", id)); INFORM(("inode at %" B_PRIdINO " is already deleted!\n", id));
@@ -736,7 +738,7 @@ bfs_ioctl(fs_volume* _volume, fs_vnode* _node, void* _cookie, uint32 cmd,
status = checker->StartIndexPass(); status = checker->StartIndexPass();
} }
} }
if (status == B_OK) { if (status == B_OK) {
status = user_memcpy(buffer, &checker->Control(), status = user_memcpy(buffer, &checker->Control(),
sizeof(check_control)); sizeof(check_control));
@@ -803,9 +805,9 @@ bfs_ioctl(fs_volume* _volume, fs_vnode* _node, void* _cookie, uint32 cmd,
PRINT(("write block_run(%ld, %d, %d)\n", run.allocation_group, PRINT(("write block_run(%ld, %d, %d)\n", run.allocation_group,
run.start, run.length)); run.start, run.length));
for (int32 i = 0;i < run.length;i++) { for (int32 i = 0;i < run.length;i++) {
uint8* block = cached.SetToWritable(transaction, run); status_t status = cached.SetToWritable(transaction, run);
if (block != NULL) if (status == B_OK)
memset(block, 0, volume->BlockSize()); memset(cached.WritableBlock(), 0, volume->BlockSize());
} }
} }
return B_OK; return B_OK;
+19 -14
View File
@@ -908,9 +908,11 @@ update_fsinfo(nspace *vol)
{ {
if (vol->fat_bits == 32 && vol->fsinfo_sector != 0xffff if (vol->fat_bits == 32 && vol->fsinfo_sector != 0xffff
&& (vol->flags & B_FS_IS_READONLY) == 0) { && (vol->flags & B_FS_IS_READONLY) == 0) {
uchar *buffer = (uchar *)block_cache_get_writable_etc(vol->fBlockCache, uchar *buffer;
vol->fsinfo_sector, 0, vol->bytes_per_sector, -1); status_t status = block_cache_get_writable_etc(vol->fBlockCache,
if (buffer != NULL) { vol->fsinfo_sector, 0, vol->bytes_per_sector, -1,
(void**)&buffer);
if (status == B_OK) {
if ((read32(buffer,0) == 0x41615252) && (read32(buffer,0x1e4) == 0x61417272) && (read16(buffer,0x1fe) == 0xaa55)) { if ((read32(buffer,0) == 0x41615252) && (read32(buffer,0x1e4) == 0x61417272) && (read16(buffer,0x1fe) == 0xaa55)) {
//number of free clusters //number of free clusters
buffer[0x1e8] = (vol->free_clusters & 0xff); buffer[0x1e8] = (vol->free_clusters & 0xff);
@@ -929,8 +931,8 @@ update_fsinfo(nspace *vol)
} }
block_cache_put(vol->fBlockCache, vol->fsinfo_sector); block_cache_put(vol->fBlockCache, vol->fsinfo_sector);
} else { } else {
dprintf("update_fsinfo: error getting fsinfo sector %x\n", dprintf("update_fsinfo: error getting fsinfo sector %x: %s\n",
vol->fsinfo_sector); vol->fsinfo_sector, strerror(status));
} }
} }
} }
@@ -940,14 +942,17 @@ static status_t
get_fsinfo(nspace *vol, uint32 *free_count, uint32 *last_allocated) get_fsinfo(nspace *vol, uint32 *free_count, uint32 *last_allocated)
{ {
uchar *buffer; uchar *buffer;
int32 result; status_t result;
if ((vol->fat_bits != 32) || (vol->fsinfo_sector == 0xffff)) if ((vol->fat_bits != 32) || (vol->fsinfo_sector == 0xffff))
return B_ERROR; return B_ERROR;
if ((buffer = (uchar *)block_cache_get_etc(vol->fBlockCache, vol->fsinfo_sector, 0, vol->bytes_per_sector)) == NULL) { result = block_cache_get_etc(vol->fBlockCache, vol->fsinfo_sector, 0,
dprintf("get_fsinfo: error getting fsinfo sector %x\n", vol->fsinfo_sector); vol->bytes_per_sector, &buffer);
return EIO; if (result != B_OK) {
dprintf("get_fsinfo: error getting fsinfo sector %x: %s\n",
vol->fsinfo_sector, strerror(result));
return result;
} }
if ((read32(buffer,0) == 0x41615252) && (read32(buffer,0x1e4) == 0x61417272) && (read16(buffer,0x1fe) == 0xaa55)) { if ((read32(buffer,0) == 0x41615252) && (read32(buffer,0x1e4) == 0x61417272) && (read16(buffer,0x1fe) == 0xaa55)) {
@@ -1093,12 +1098,12 @@ dosfs_write_fs_stat(fs_volume *_vol, const struct fs_info * fss, uint32 mask)
if (vol->vol_entry == -1) { if (vol->vol_entry == -1) {
// stored in the bpb // stored in the bpb
uchar *buffer = block_cache_get_writable_etc(vol->fBlockCache, 0, 0, uchar *buffer;
vol->bytes_per_sector, -1); result = block_cache_get_writable_etc(vol->fBlockCache, 0,
if (buffer == NULL) { 0, vol->bytes_per_sector, -1, (void**)&buffer);
result = EIO; if (result != B_OK)
goto bi; goto bi;
}
if ((vol->sectors_per_fat == 0 && (buffer[0x42] != 0x29 if ((vol->sectors_per_fat == 0 && (buffer[0x42] != 0x29
|| strncmp((const char *)buffer + 0x47, vol->vol_label, 11) || strncmp((const char *)buffer + 0x47, vol->vol_label, 11)
!= 0)) != 0))
+6 -2
View File
@@ -37,11 +37,15 @@ mirror_fats(nspace *vol, uint32 sector, uint8 *buffer)
for (i = 0; i < vol->fat_count; i++) { for (i = 0; i < vol->fat_count; i++) {
char *blockData; char *blockData;
status_t status;
if (i == vol->active_fat) if (i == vol->active_fat)
continue; continue;
blockData = block_cache_get_writable_etc(vol->fBlockCache, sector status = block_cache_get_writable_etc(vol->fBlockCache,
+ i * vol->sectors_per_fat, 0, 1, -1); sector + i * vol->sectors_per_fat, 0, 1, -1, &blockData);
if (status != B_OK)
return status;
memcpy(blockData, buffer, vol->bytes_per_sector); memcpy(blockData, buffer, vol->bytes_per_sector);
block_cache_put(vol->fBlockCache, sector + i * vol->sectors_per_fat); block_cache_put(vol->fBlockCache, sector + i * vol->sectors_per_fat);
} }
+20 -6
View File
@@ -112,11 +112,17 @@ iter_csi(struct csi *csi, int sectors)
uint8 * uint8 *
csi_get_block(struct csi *csi) csi_get_block(struct csi *csi)
{ {
status_t status;
const void* block;
if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0) if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0)
return NULL; return NULL;
return (uint8 *)block_cache_get_etc(csi->vol->fBlockCache, status = block_cache_get_etc(csi->vol->fBlockCache,
csi_to_block(csi), 1, csi->vol->bytes_per_sector); csi_to_block(csi), 1, csi->vol->bytes_per_sector, &block);
if (status != B_OK)
return NULL;
return (uint8 *)block;
} }
@@ -214,8 +220,12 @@ csi_write_blocks(struct csi *csi, uint8 *buffer, ssize_t len)
} }
for (i = block; i < block + sectors; i++) { for (i = block; i < block + sectors; i++) {
char *blockData = block_cache_get_writable_etc(csi->vol->fBlockCache, i, char *blockData;
0, 1, -1); status_t status = block_cache_get_writable_etc(csi->vol->fBlockCache,
i, 0, 1, -1, &blockData);
if (status != B_OK)
return status;
memcpy(blockData, buf, csi->vol->bytes_per_sector); memcpy(blockData, buf, csi->vol->bytes_per_sector);
buf += csi->vol->bytes_per_sector; buf += csi->vol->bytes_per_sector;
block_cache_put(csi->vol->fBlockCache, i); block_cache_put(csi->vol->fBlockCache, i);
@@ -233,6 +243,7 @@ csi_write_blocks(struct csi *csi, uint8 *buffer, ssize_t len)
status_t status_t
csi_write_block(struct csi *csi, uint8 *buffer) csi_write_block(struct csi *csi, uint8 *buffer)
{ {
status_t status;
off_t block; off_t block;
char *blockData; char *blockData;
@@ -242,8 +253,11 @@ csi_write_block(struct csi *csi, uint8 *buffer)
if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0) if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0)
return EINVAL; return EINVAL;
blockData = block_cache_get_writable_etc(csi->vol->fBlockCache, block, 0, 1, status = block_cache_get_writable_etc(csi->vol->fBlockCache, block, 0, 1,
-1); -1, &blockData);
if (status != B_OK)
return status;
memcpy(blockData, buffer, csi->vol->bytes_per_sector); memcpy(blockData, buffer, csi->vol->bytes_per_sector);
block_cache_put(csi->vol->fBlockCache, block); block_cache_put(csi->vol->fBlockCache, block);
@@ -1,7 +1,7 @@
/* /*
* Copyright 2008, Salvatore Benedetto, salvatore.benedetto@gmail.com * Copyright 2008, Salvatore Benedetto, salvatore.benedetto@gmail.com
* Copyright 2003, Tyler Dauwalder, tyler@dauwalder.net * Copyright 2003, Tyler Dauwalder, tyler@dauwalder.net
* Copyright 2002, Axel Dörfler, axeld@pinc-software.de * Copyright 2002-2020, Axel Dörfler, axeld@pinc-software.de
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#ifndef _UDF_CACHED_BLOCK_H #ifndef _UDF_CACHED_BLOCK_H
@@ -9,7 +9,7 @@
/*! \file CachedBlock.h /*! \file CachedBlock.h
Based on the CachedBlock class from OpenBFS, written by Based on the CachedBlock class from BFS, written by
Axel Dörfler, axeld@pinc-software.de Axel Dörfler, axeld@pinc-software.de
*/ */
@@ -20,10 +20,10 @@
#include "UdfStructures.h" #include "UdfStructures.h"
#include "Volume.h" #include "Volume.h"
class CachedBlock { class CachedBlock {
public: public:
CachedBlock(Volume *volume); CachedBlock(Volume *volume);
CachedBlock(Volume *volume, off_t block);
CachedBlock(CachedBlock *cached); CachedBlock(CachedBlock *cached);
~CachedBlock(); ~CachedBlock();
@@ -35,11 +35,12 @@ public:
inline void Keep(); inline void Keep();
inline void Unset(); inline void Unset();
inline uint8 *SetTo(off_t block); inline status_t SetTo(off_t block);
inline uint8 *SetTo(off_t block, off_t base, size_t length); inline status_t SetTo(off_t block, off_t base, size_t length);
inline uint8 *SetTo(long_address address); inline status_t SetTo(long_address address);
template <class Accessor, class Descriptor> template <class Accessor, class Descriptor>
inline uint8* SetTo(Accessor &accessor, Descriptor &descriptor); inline status_t SetTo(Accessor &accessor,
Descriptor &descriptor);
protected: protected:
uint8 *fBlock; uint8 *fBlock;
@@ -59,17 +60,6 @@ CachedBlock::CachedBlock(Volume *volume)
inline inline
CachedBlock::CachedBlock(Volume *volume, off_t block)
:
fBlock(NULL),
fBlockNumber(0),
fVolume(volume)
{
SetTo(block);
}
inline
CachedBlock::CachedBlock(CachedBlock *cached) CachedBlock::CachedBlock(CachedBlock *cached)
: :
fBlock(cached->fBlock), fBlock(cached->fBlock),
@@ -97,43 +87,43 @@ CachedBlock::Keep()
inline void inline void
CachedBlock::Unset() CachedBlock::Unset()
{ {
if (fBlock) { if (fBlock != NULL) {
block_cache_put(fVolume->BlockCache(), fBlockNumber); block_cache_put(fVolume->BlockCache(), fBlockNumber);
fBlock = NULL; fBlock = NULL;
} }
} }
inline uint8* inline status_t
CachedBlock::SetTo(off_t block) CachedBlock::SetTo(off_t block)
{ {
return SetTo(block, block, 1); return SetTo(block, block, 1);
} }
inline uint8* inline status_t
CachedBlock::SetTo(off_t block, off_t base, size_t length) CachedBlock::SetTo(off_t block, off_t base, size_t length)
{ {
Unset(); Unset();
fBlockNumber = block; fBlockNumber = block;
return fBlock = (uint8 *)block_cache_get_etc(fVolume->BlockCache(), return block_cache_get_etc(fVolume->BlockCache(), block, base, length,
block, base, length); (const void**)&fBlock);
} }
inline uint8 * inline status_t
CachedBlock::SetTo(long_address address) CachedBlock::SetTo(long_address address)
{ {
off_t block; off_t block;
if (fVolume->MapBlock(address, &block) == B_OK) if (fVolume->MapBlock(address, &block) == B_OK)
return SetTo(block, block, 1); return SetTo(block, block, 1);
else
return NULL; return B_BAD_VALUE;
} }
template <class Accessor, class Descriptor> template <class Accessor, class Descriptor>
inline uint8* inline status_t
CachedBlock::SetTo(Accessor &accessor, Descriptor &descriptor) CachedBlock::SetTo(Accessor &accessor, Descriptor &descriptor)
{ {
// Make a long_address out of the descriptor and call it a day // Make a long_address out of the descriptor and call it a day
@@ -143,4 +133,5 @@ CachedBlock::SetTo(Accessor &accessor, Descriptor &descriptor)
return SetTo(address); return SetTo(address);
} }
#endif // _UDF_CACHED_BLOCK_H #endif // _UDF_CACHED_BLOCK_H
+21 -16
View File
@@ -123,20 +123,24 @@ Icb::Icb(Volume *volume, long_address address)
off_t block; off_t block;
status_t status = fVolume->MapBlock(address, &block); status_t status = fVolume->MapBlock(address, &block);
if (!status) { if (status == B_OK) {
icb_header *header = (icb_header *)fData.SetTo(block); status = fData.SetTo(block);
if (header->tag().id() == TAGID_FILE_ENTRY) { if (status == B_OK) {
file_icb_entry *entry = (file_icb_entry *)header; icb_header *header = (icb_header *)fData.Block();
PDUMP(entry); if (header->tag().id() == TAGID_FILE_ENTRY) {
(void)entry; // warning death file_icb_entry *entry = (file_icb_entry *)header;
} else if (header->tag().id() == TAGID_EXTENDED_FILE_ENTRY) { PDUMP(entry);
extended_file_icb_entry *entry = (extended_file_icb_entry *)header; (void)entry; // warning death
PDUMP(entry); } else if (header->tag().id() == TAGID_EXTENDED_FILE_ENTRY) {
(void)entry; // warning death extended_file_icb_entry *entry
} else { = (extended_file_icb_entry *)header;
PDUMP(header); PDUMP(entry);
(void)entry; // warning death
} else {
PDUMP(header);
}
status = header->tag().init_check(address.block());
} }
status = header->tag().init_check(address.block());
} }
if (IsFile()) { if (IsFile()) {
@@ -447,9 +451,10 @@ Icb::_Read(DescriptorList &list, off_t pos, void *_buffer, size_t *length, uint3
TRACE(("Icb::_Read: %ld bytes from disk block %" B_PRIdOFF " using" TRACE(("Icb::_Read: %ld bytes from disk block %" B_PRIdOFF " using"
" block_cache_get_etc()\n", readLength, diskBlock)); " block_cache_get_etc()\n", readLength, diskBlock));
uint8 *data = (uint8*)block_cache_get_etc(volume->BlockCache(), const uint8 *data;
diskBlock, 0, readLength); status = block_cache_get_etc(volume->BlockCache(),
if (data == NULL) diskBlock, 0, readLength, (const void**)&data);
if (status != B_OK)
break; break;
memcpy(buffer, data + blockOffset, readLength); memcpy(buffer, data + blockOffset, readLength);
block_cache_put(volume->BlockCache(), diskBlock); block_cache_put(volume->BlockCache(), diskBlock);
+61 -38
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2004-2012, Axel Dörfler, axeld@pinc-software.de. * Copyright 2004-2020, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -1897,16 +1897,16 @@ put_cached_block(block_cache* cache, off_t blockNumber)
data. If \c true, the cache will be temporarily unlocked while the data. If \c true, the cache will be temporarily unlocked while the
block is read in. block is read in.
*/ */
static cached_block* static status_t
get_cached_block(block_cache* cache, off_t blockNumber, bool* _allocated, get_cached_block(block_cache* cache, off_t blockNumber, bool* _allocated,
bool readBlock = true) bool readBlock, cached_block** _block)
{ {
ASSERT_LOCKED_MUTEX(&cache->lock); ASSERT_LOCKED_MUTEX(&cache->lock);
if (blockNumber < 0 || blockNumber >= cache->max_blocks) { if (blockNumber < 0 || blockNumber >= cache->max_blocks) {
panic("get_cached_block: invalid block number %" B_PRIdOFF " (max %" B_PRIdOFF ")", panic("get_cached_block: invalid block number %" B_PRIdOFF " (max %" B_PRIdOFF ")",
blockNumber, cache->max_blocks - 1); blockNumber, cache->max_blocks - 1);
return NULL; return B_BAD_VALUE;
} }
retry: retry:
@@ -1917,7 +1917,7 @@ retry:
// put block into cache // put block into cache
block = cache->NewBlock(blockNumber); block = cache->NewBlock(blockNumber);
if (block == NULL) if (block == NULL)
return NULL; return B_NO_MEMORY;
cache->hash->Insert(block); cache->hash->Insert(block);
*_allocated = true; *_allocated = true;
@@ -1951,7 +1951,7 @@ retry:
TRACE_ALWAYS(("could not read block %" B_PRIdOFF ": bytesRead: %zd, error: %s\n", TRACE_ALWAYS(("could not read block %" B_PRIdOFF ": bytesRead: %zd, error: %s\n",
blockNumber, bytesRead, strerror(errno))); blockNumber, bytesRead, strerror(errno)));
return NULL; return errno;
} }
TB(Read(cache, block)); TB(Read(cache, block));
@@ -1961,7 +1961,8 @@ retry:
block->ref_count++; block->ref_count++;
block->last_accessed = system_time() / 1000000L; block->last_accessed = system_time() / 1000000L;
return block; *_block = block;
return B_OK;
} }
@@ -1972,9 +1973,9 @@ retry:
This is the only method to insert a block into a transaction. It makes This is the only method to insert a block into a transaction. It makes
sure that the previous block contents are preserved in that case. sure that the previous block contents are preserved in that case.
*/ */
static void* static status_t
get_writable_cached_block(block_cache* cache, off_t blockNumber, off_t base, get_writable_cached_block(block_cache* cache, off_t blockNumber, off_t base,
off_t length, int32 transactionID, bool cleared) off_t length, int32 transactionID, bool cleared, void** _block)
{ {
TRACE(("get_writable_cached_block(blockNumber = %" B_PRIdOFF ", transaction = %" B_PRId32 ")\n", TRACE(("get_writable_cached_block(blockNumber = %" B_PRIdOFF ", transaction = %" B_PRId32 ")\n",
blockNumber, transactionID)); blockNumber, transactionID));
@@ -1982,13 +1983,15 @@ get_writable_cached_block(block_cache* cache, off_t blockNumber, off_t base,
if (blockNumber < 0 || blockNumber >= cache->max_blocks) { if (blockNumber < 0 || blockNumber >= cache->max_blocks) {
panic("get_writable_cached_block: invalid block number %" B_PRIdOFF " (max %" B_PRIdOFF ")", panic("get_writable_cached_block: invalid block number %" B_PRIdOFF " (max %" B_PRIdOFF ")",
blockNumber, cache->max_blocks - 1); blockNumber, cache->max_blocks - 1);
return B_BAD_VALUE;
} }
bool allocated; bool allocated;
cached_block* block = get_cached_block(cache, blockNumber, &allocated, cached_block* block;
!cleared); status_t status = get_cached_block(cache, blockNumber, &allocated,
if (block == NULL) !cleared, &block);
return NULL; if (status != B_OK)
return status;
if (block->busy_writing) if (block->busy_writing)
wait_for_busy_writing_block(cache, block); wait_for_busy_writing_block(cache, block);
@@ -2016,7 +2019,8 @@ get_writable_cached_block(block_cache* cache, off_t blockNumber, off_t base,
} }
TB(Get(cache, block)); TB(Get(cache, block));
return block->current_data; *_block = block->current_data;
return B_OK;
} }
cache_transaction* transaction = block->transaction; cache_transaction* transaction = block->transaction;
@@ -2027,7 +2031,7 @@ get_writable_cached_block(block_cache* cache, off_t blockNumber, off_t base,
panic("get_writable_cached_block(): asked to get busy writable block " panic("get_writable_cached_block(): asked to get busy writable block "
"(transaction %" B_PRId32 ")\n", block->transaction->id); "(transaction %" B_PRId32 ")\n", block->transaction->id);
put_cached_block(cache, block); put_cached_block(cache, block);
return NULL; return B_BAD_VALUE;
} }
if (transaction == NULL && transactionID != -1) { if (transaction == NULL && transactionID != -1) {
// get new transaction // get new transaction
@@ -2036,12 +2040,12 @@ get_writable_cached_block(block_cache* cache, off_t blockNumber, off_t base,
panic("get_writable_cached_block(): invalid transaction %" B_PRId32 "!\n", panic("get_writable_cached_block(): invalid transaction %" B_PRId32 "!\n",
transactionID); transactionID);
put_cached_block(cache, block); put_cached_block(cache, block);
return NULL; return B_BAD_VALUE;
} }
if (!transaction->open) { if (!transaction->open) {
panic("get_writable_cached_block(): transaction already done!\n"); panic("get_writable_cached_block(): transaction already done!\n");
put_cached_block(cache, block); put_cached_block(cache, block);
return NULL; return B_BAD_VALUE;
} }
block->transaction = transaction; block->transaction = transaction;
@@ -2064,7 +2068,7 @@ get_writable_cached_block(block_cache* cache, off_t blockNumber, off_t base,
TB(Error(cache, blockNumber, "allocate original failed")); TB(Error(cache, blockNumber, "allocate original failed"));
FATAL(("could not allocate original_data\n")); FATAL(("could not allocate original_data\n"));
put_cached_block(cache, block); put_cached_block(cache, block);
return NULL; return B_NO_MEMORY;
} }
mark_block_busy_reading(cache, block); mark_block_busy_reading(cache, block);
@@ -2084,7 +2088,7 @@ get_writable_cached_block(block_cache* cache, off_t blockNumber, off_t base,
TB(Error(cache, blockNumber, "allocate parent failed")); TB(Error(cache, blockNumber, "allocate parent failed"));
FATAL(("could not allocate parent\n")); FATAL(("could not allocate parent\n"));
put_cached_block(cache, block); put_cached_block(cache, block);
return NULL; return B_NO_MEMORY;
} }
mark_block_busy_reading(cache, block); mark_block_busy_reading(cache, block);
@@ -2114,7 +2118,8 @@ get_writable_cached_block(block_cache* cache, off_t blockNumber, off_t base,
TB(Get(cache, block)); TB(Get(cache, block));
TB2(BlockData(cache, block, "get writable")); TB2(BlockData(cache, block, "get writable"));
return block->current_data; *_block = block->current_data;
return B_OK;
} }
@@ -3583,20 +3588,21 @@ block_cache_make_writable(void* _cache, off_t blockNumber, int32 transaction)
} }
// TODO: this can be done better! // TODO: this can be done better!
void* block = get_writable_cached_block(cache, blockNumber, void* block;
blockNumber, 1, transaction, false); status_t status = get_writable_cached_block(cache, blockNumber,
if (block != NULL) { blockNumber, 1, transaction, false, &block);
if (status == B_OK) {
put_cached_block((block_cache*)_cache, blockNumber); put_cached_block((block_cache*)_cache, blockNumber);
return B_OK; return B_OK;
} }
return B_ERROR; return status;
} }
void* status_t
block_cache_get_writable_etc(void* _cache, off_t blockNumber, off_t base, block_cache_get_writable_etc(void* _cache, off_t blockNumber, off_t base,
off_t length, int32 transaction) off_t length, int32 transaction, void** _block)
{ {
block_cache* cache = (block_cache*)_cache; block_cache* cache = (block_cache*)_cache;
MutexLocker locker(&cache->lock); MutexLocker locker(&cache->lock);
@@ -3607,15 +3613,19 @@ block_cache_get_writable_etc(void* _cache, off_t blockNumber, off_t base,
panic("tried to get writable block on a read-only cache!"); panic("tried to get writable block on a read-only cache!");
return get_writable_cached_block(cache, blockNumber, base, length, return get_writable_cached_block(cache, blockNumber, base, length,
transaction, false); transaction, false, _block);
} }
void* void*
block_cache_get_writable(void* _cache, off_t blockNumber, int32 transaction) block_cache_get_writable(void* _cache, off_t blockNumber, int32 transaction)
{ {
return block_cache_get_writable_etc(_cache, blockNumber, void* block;
blockNumber, 1, transaction); if (block_cache_get_writable_etc(_cache, blockNumber,
blockNumber, 1, transaction, &block) == B_OK)
return block;
return NULL;
} }
@@ -3630,21 +3640,28 @@ block_cache_get_empty(void* _cache, off_t blockNumber, int32 transaction)
if (cache->read_only) if (cache->read_only)
panic("tried to get empty writable block on a read-only cache!"); panic("tried to get empty writable block on a read-only cache!");
return get_writable_cached_block((block_cache*)_cache, blockNumber, void* block;
blockNumber, 1, transaction, true); if (get_writable_cached_block((block_cache*)_cache, blockNumber,
blockNumber, 1, transaction, true, &block) == B_OK)
return block;
return NULL;
} }
const void* status_t
block_cache_get_etc(void* _cache, off_t blockNumber, off_t base, off_t length) block_cache_get_etc(void* _cache, off_t blockNumber, off_t base, off_t length,
const void** _block)
{ {
block_cache* cache = (block_cache*)_cache; block_cache* cache = (block_cache*)_cache;
MutexLocker locker(&cache->lock); MutexLocker locker(&cache->lock);
bool allocated; bool allocated;
cached_block* block = get_cached_block(cache, blockNumber, &allocated); cached_block* block;
if (block == NULL) status_t status = get_cached_block(cache, blockNumber, &allocated, true,
return NULL; &block);
if (status != B_OK)
return status;
#if BLOCK_CACHE_DEBUG_CHANGED #if BLOCK_CACHE_DEBUG_CHANGED
if (block->compare == NULL) if (block->compare == NULL)
@@ -3654,14 +3671,20 @@ block_cache_get_etc(void* _cache, off_t blockNumber, off_t base, off_t length)
#endif #endif
TB(Get(cache, block)); TB(Get(cache, block));
return block->current_data; *_block = block->current_data;
return B_OK;
} }
const void* const void*
block_cache_get(void* _cache, off_t blockNumber) block_cache_get(void* _cache, off_t blockNumber)
{ {
return block_cache_get_etc(_cache, blockNumber, blockNumber, 1); const void* block;
if (block_cache_get_etc(_cache, blockNumber, blockNumber, 1, &block)
== B_OK)
return block;
return NULL;
} }
+62 -39
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. * Copyright 2004-2020, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -716,14 +716,14 @@ put_cached_block(block_cache* cache, fssh_off_t blockNumber)
not already in the cache. The block you retrieve may contain random not already in the cache. The block you retrieve may contain random
data. data.
*/ */
static cached_block* static fssh_status_t
get_cached_block(block_cache* cache, fssh_off_t blockNumber, bool* _allocated, get_cached_block(block_cache* cache, fssh_off_t blockNumber, bool* _allocated,
bool readBlock = true) bool readBlock, cached_block** _block)
{ {
if (blockNumber < 0 || blockNumber >= cache->max_blocks) { if (blockNumber < 0 || blockNumber >= cache->max_blocks) {
fssh_panic("get_cached_block: invalid block number %" FSSH_B_PRIdOFF fssh_panic("get_cached_block: invalid block number %" FSSH_B_PRIdOFF
" (max %" FSSH_B_PRIdOFF ")", blockNumber, cache->max_blocks - 1); " (max %" FSSH_B_PRIdOFF ")", blockNumber, cache->max_blocks - 1);
return NULL; return FSSH_B_BAD_VALUE;
} }
cached_block* block = (cached_block*)hash_lookup(cache->hash, cached_block* block = (cached_block*)hash_lookup(cache->hash,
@@ -734,7 +734,7 @@ get_cached_block(block_cache* cache, fssh_off_t blockNumber, bool* _allocated,
// read block into cache // read block into cache
block = cache->NewBlock(blockNumber); block = cache->NewBlock(blockNumber);
if (block == NULL) if (block == NULL)
return NULL; return FSSH_B_NO_MEMORY;
hash_insert(cache->hash, block); hash_insert(cache->hash, block);
*_allocated = true; *_allocated = true;
@@ -747,7 +747,7 @@ get_cached_block(block_cache* cache, fssh_off_t blockNumber, bool* _allocated,
blockSize) < blockSize) { blockSize) < blockSize) {
cache->RemoveBlock(block); cache->RemoveBlock(block);
FATAL(("could not read block %" FSSH_B_PRIdOFF "\n", blockNumber)); FATAL(("could not read block %" FSSH_B_PRIdOFF "\n", blockNumber));
return NULL; return fssh_errno;
} }
} }
@@ -760,7 +760,8 @@ get_cached_block(block_cache* cache, fssh_off_t blockNumber, bool* _allocated,
block->ref_count++; block->ref_count++;
block->accessed++; block->accessed++;
return block; *_block = block;
return FSSH_B_OK;
} }
@@ -771,9 +772,9 @@ get_cached_block(block_cache* cache, fssh_off_t blockNumber, bool* _allocated,
This is the only method to insert a block into a transaction. It makes This is the only method to insert a block into a transaction. It makes
sure that the previous block contents are preserved in that case. sure that the previous block contents are preserved in that case.
*/ */
static void* static fssh_status_t
get_writable_cached_block(block_cache* cache, fssh_off_t blockNumber, fssh_off_t base, get_writable_cached_block(block_cache* cache, fssh_off_t blockNumber, fssh_off_t base,
fssh_off_t length, int32_t transactionID, bool cleared) fssh_off_t length, int32_t transactionID, bool cleared, void** _block)
{ {
TRACE(("get_writable_cached_block(blockNumber = %Ld, transaction = %d)\n", TRACE(("get_writable_cached_block(blockNumber = %Ld, transaction = %d)\n",
blockNumber, transactionID)); blockNumber, transactionID));
@@ -782,13 +783,15 @@ get_writable_cached_block(block_cache* cache, fssh_off_t blockNumber, fssh_off_t
fssh_panic("get_writable_cached_block: invalid block number %" fssh_panic("get_writable_cached_block: invalid block number %"
FSSH_B_PRIdOFF " (max %" FSSH_B_PRIdOFF ")", blockNumber, FSSH_B_PRIdOFF " (max %" FSSH_B_PRIdOFF ")", blockNumber,
cache->max_blocks - 1); cache->max_blocks - 1);
return FSSH_B_BAD_VALUE;
} }
bool allocated; bool allocated;
cached_block* block = get_cached_block(cache, blockNumber, &allocated, cached_block* block;
!cleared); fssh_status_t status = get_cached_block(cache, blockNumber, &allocated,
if (block == NULL) !cleared, &block);
return NULL; if (status != FSSH_B_OK)
return status;
block->discard = false; block->discard = false;
@@ -800,7 +803,8 @@ get_writable_cached_block(block_cache* cache, fssh_off_t blockNumber, fssh_off_t
block->is_dirty = true; block->is_dirty = true;
// mark the block as dirty // mark the block as dirty
return block->current_data; *_block = block->current_data;
return FSSH_B_OK;
} }
cache_transaction* transaction = block->transaction; cache_transaction* transaction = block->transaction;
@@ -810,7 +814,7 @@ get_writable_cached_block(block_cache* cache, fssh_off_t blockNumber, fssh_off_t
// Maybe we should even panic, since we can't prevent any deadlocks. // Maybe we should even panic, since we can't prevent any deadlocks.
fssh_panic("get_writable_cached_block(): asked to get busy writable block (transaction %d)\n", (int)transaction->id); fssh_panic("get_writable_cached_block(): asked to get busy writable block (transaction %d)\n", (int)transaction->id);
put_cached_block(cache, block); put_cached_block(cache, block);
return NULL; return FSSH_B_BAD_VALUE;
} }
if (transaction == NULL && transactionID != -1) { if (transaction == NULL && transactionID != -1) {
// get new transaction // get new transaction
@@ -819,12 +823,12 @@ get_writable_cached_block(block_cache* cache, fssh_off_t blockNumber, fssh_off_t
fssh_panic("get_writable_cached_block(): invalid transaction %d!\n", fssh_panic("get_writable_cached_block(): invalid transaction %d!\n",
(int)transactionID); (int)transactionID);
put_cached_block(cache, block); put_cached_block(cache, block);
return NULL; return FSSH_B_BAD_VALUE;
} }
if (!transaction->open) { if (!transaction->open) {
fssh_panic("get_writable_cached_block(): transaction already done!\n"); fssh_panic("get_writable_cached_block(): transaction already done!\n");
put_cached_block(cache, block); put_cached_block(cache, block);
return NULL; return FSSH_B_BAD_VALUE;
} }
block->transaction = transaction; block->transaction = transaction;
@@ -844,7 +848,7 @@ get_writable_cached_block(block_cache* cache, fssh_off_t blockNumber, fssh_off_t
if (block->original_data == NULL) { if (block->original_data == NULL) {
FATAL(("could not allocate original_data\n")); FATAL(("could not allocate original_data\n"));
put_cached_block(cache, block); put_cached_block(cache, block);
return NULL; return FSSH_B_NO_MEMORY;
} }
fssh_memcpy(block->original_data, block->current_data, cache->block_size); fssh_memcpy(block->original_data, block->current_data, cache->block_size);
@@ -856,7 +860,7 @@ get_writable_cached_block(block_cache* cache, fssh_off_t blockNumber, fssh_off_t
// TODO: maybe we should just continue the current transaction in this case... // TODO: maybe we should just continue the current transaction in this case...
FATAL(("could not allocate parent\n")); FATAL(("could not allocate parent\n"));
put_cached_block(cache, block); put_cached_block(cache, block);
return NULL; return FSSH_B_NO_MEMORY;
} }
fssh_memcpy(block->parent_data, block->current_data, cache->block_size); fssh_memcpy(block->parent_data, block->current_data, cache->block_size);
@@ -870,7 +874,8 @@ get_writable_cached_block(block_cache* cache, fssh_off_t blockNumber, fssh_off_t
block->is_dirty = true; block->is_dirty = true;
return block->current_data; *_block = block->current_data;
return FSSH_B_OK;
} }
@@ -1634,20 +1639,21 @@ fssh_block_cache_make_writable(void* _cache, fssh_off_t blockNumber,
fssh_panic("tried to make block writable on a read-only cache!"); fssh_panic("tried to make block writable on a read-only cache!");
// TODO: this can be done better! // TODO: this can be done better!
void* block = get_writable_cached_block(cache, blockNumber, void* block;
blockNumber, 1, transaction, false); fssh_status_t status = get_writable_cached_block(cache, blockNumber,
if (block != NULL) { blockNumber, 1, transaction, false, &block);
if (status == FSSH_B_OK) {
put_cached_block((block_cache*)_cache, blockNumber); put_cached_block((block_cache*)_cache, blockNumber);
return FSSH_B_OK; return FSSH_B_OK;
} }
return FSSH_B_ERROR; return status;
} }
void* fssh_status_t
fssh_block_cache_get_writable_etc(void* _cache, fssh_off_t blockNumber, fssh_off_t base, fssh_block_cache_get_writable_etc(void* _cache, fssh_off_t blockNumber,
fssh_off_t length, int32_t transaction) fssh_off_t base, fssh_off_t length, int32_t transaction, void** _block)
{ {
block_cache* cache = (block_cache*)_cache; block_cache* cache = (block_cache*)_cache;
MutexLocker locker(&cache->lock); MutexLocker locker(&cache->lock);
@@ -1658,7 +1664,7 @@ fssh_block_cache_get_writable_etc(void* _cache, fssh_off_t blockNumber, fssh_off
fssh_panic("tried to get writable block on a read-only cache!"); fssh_panic("tried to get writable block on a read-only cache!");
return get_writable_cached_block(cache, blockNumber, base, length, return get_writable_cached_block(cache, blockNumber, base, length,
transaction, false); transaction, false, _block);
} }
@@ -1666,8 +1672,13 @@ void*
fssh_block_cache_get_writable(void* _cache, fssh_off_t blockNumber, fssh_block_cache_get_writable(void* _cache, fssh_off_t blockNumber,
int32_t transaction) int32_t transaction)
{ {
return fssh_block_cache_get_writable_etc(_cache, blockNumber, void* block;
blockNumber, 1, transaction); fssh_status_t status = fssh_block_cache_get_writable_etc(_cache,
blockNumber, blockNumber, 1, transaction, &block);
if (status == FSSH_B_OK)
return block;
return NULL;
} }
@@ -1683,22 +1694,28 @@ fssh_block_cache_get_empty(void* _cache, fssh_off_t blockNumber,
if (cache->read_only) if (cache->read_only)
fssh_panic("tried to get empty writable block on a read-only cache!"); fssh_panic("tried to get empty writable block on a read-only cache!");
return get_writable_cached_block((block_cache*)_cache, blockNumber, void* block;
blockNumber, 1, transaction, true); if (get_writable_cached_block((block_cache*)_cache, blockNumber,
blockNumber, 1, transaction, true, &block) == FSSH_B_OK)
return block;
return NULL;
} }
const void* fssh_status_t
fssh_block_cache_get_etc(void* _cache, fssh_off_t blockNumber, fssh_off_t base, fssh_block_cache_get_etc(void* _cache, fssh_off_t blockNumber, fssh_off_t base,
fssh_off_t length) fssh_off_t length, const void** _block)
{ {
block_cache* cache = (block_cache*)_cache; block_cache* cache = (block_cache*)_cache;
MutexLocker locker(&cache->lock); MutexLocker locker(&cache->lock);
bool allocated; bool allocated;
cached_block* block = get_cached_block(cache, blockNumber, &allocated); cached_block* block;
if (block == NULL) fssh_status_t status = get_cached_block(cache, blockNumber, &allocated,
return NULL; true, &block);
if (status != FSSH_B_OK)
return status;
#ifdef DEBUG_CHANGED #ifdef DEBUG_CHANGED
if (block->compare == NULL) if (block->compare == NULL)
@@ -1706,14 +1723,20 @@ fssh_block_cache_get_etc(void* _cache, fssh_off_t blockNumber, fssh_off_t base,
if (block->compare != NULL) if (block->compare != NULL)
memcpy(block->compare, block->current_data, cache->block_size); memcpy(block->compare, block->current_data, cache->block_size);
#endif #endif
return block->current_data; *_block = block->current_data;
return FSSH_B_OK;
} }
const void* const void*
fssh_block_cache_get(void* _cache, fssh_off_t blockNumber) fssh_block_cache_get(void* _cache, fssh_off_t blockNumber)
{ {
return fssh_block_cache_get_etc(_cache, blockNumber, blockNumber, 1); const void* block;
if (fssh_block_cache_get_etc(_cache, blockNumber, blockNumber, 1, &block)
== FSSH_B_OK)
return block;
return NULL;
} }