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 <axeld@pinc-software.de>
Reviewed-by: Adrien Destugues <pulkomandy@gmail.com>
This commit is contained in:
Axel Dörfler 2020-06-11 21:50:36 +02:00 committed by waddlesplash
parent cc7b6b5870
commit 93845aec95
18 changed files with 425 additions and 349 deletions

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.
*/
#ifndef _FS_CACHE_H
@ -66,14 +66,14 @@ extern void block_cache_discard(void *cache, off_t blockNumber,
size_t numBlocks);
extern status_t block_cache_make_writable(void *cache, off_t blockNumber,
int32 transaction);
extern void *block_cache_get_writable_etc(void *cache, off_t blockNumber,
off_t base, off_t length, int32 transaction);
extern status_t block_cache_get_writable_etc(void *cache, off_t blockNumber,
off_t base, off_t length, int32 transaction, void** _block);
extern void *block_cache_get_writable(void *cache, off_t blockNumber,
int32 transaction);
extern void *block_cache_get_empty(void *cache, off_t blockNumber,
int32 transaction);
extern const void *block_cache_get_etc(void *cache, off_t blockNumber,
off_t base, off_t length);
extern status_t block_cache_get_etc(void *cache, off_t blockNumber,
off_t base, off_t length, const void** _block);
extern const void *block_cache_get(void *cache, off_t blockNumber);
extern status_t block_cache_set_dirty(void *cache, off_t blockNumber,
bool isDirty, int32 transaction);

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.
*/
#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);
extern fssh_status_t fssh_block_cache_make_writable(void *_cache,
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 length, int32_t transaction);
fssh_off_t length, int32_t transaction,
void **_block);
extern void * fssh_block_cache_get_writable(void *_cache,
fssh_off_t blockNumber, int32_t transaction);
extern void * fssh_block_cache_get_empty(void *_cache,
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 length);
fssh_off_t length, const void **_block);
extern const void * fssh_block_cache_get(void *_cache,
fssh_off_t blockNumber);
extern fssh_status_t fssh_block_cache_set_dirty(void *_cache,

View File

@ -1,5 +1,5 @@
/*
* Copyright 2004-2017, Axel Dörfler, axeld@pinc-software.de.
* Copyright 2004-2020, Axel Dörfler, axeld@pinc-software.de.
* 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
if (recursive_lock_lock(&fInode->SmallDataLock()) == B_OK) {
fNodeGetter.SetToNode(fInode);
if (fNodeGetter.Node() == NULL)
return B_IO_ERROR;
status_t status = fNodeGetter.SetTo(fInode);
if (status != B_OK)
return status;
fSmall = fInode->FindSmallData(fNodeGetter.Node(), (const char*)name);
if (fSmall != NULL)

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.
*/
@ -238,7 +238,7 @@ AllocationBlock::SetTo(AllocationGroup& group, uint16 block)
#ifdef DEBUG
fWritable = false;
#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
fWritable = true;
#endif
return CachedBlock::SetToWritable(transaction, group.Start() + block)
!= NULL ? B_OK : B_ERROR;
return CachedBlock::SetToWritable(transaction, group.Start() + block);
}

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.
*/
#ifndef CACHED_BLOCK_H
@ -24,27 +24,26 @@
class CachedBlock {
public:
CachedBlock(Volume* volume);
CachedBlock(Volume* volume, off_t block);
CachedBlock(Volume* volume, block_run run);
CachedBlock(CachedBlock* cached);
~CachedBlock();
inline void Keep();
inline void Unset();
inline const uint8* SetTo(off_t block, off_t base, size_t length);
inline const uint8* SetTo(off_t block);
inline const uint8* SetTo(block_run run);
inline uint8* SetToWritable(Transaction& transaction,
inline status_t SetTo(off_t block, off_t base, size_t length);
inline status_t SetTo(off_t block);
inline status_t SetTo(block_run run);
inline status_t SetToWritable(Transaction& transaction,
off_t block, off_t base, size_t length,
bool empty = false);
inline uint8* SetToWritable(Transaction& transaction,
inline status_t SetToWritable(Transaction& transaction,
off_t block, bool empty = false);
inline uint8* SetToWritable(Transaction& transaction,
inline status_t SetToWritable(Transaction& transaction,
block_run run, bool empty = false);
inline status_t MakeWritable(Transaction& transaction);
const uint8* Block() const { return fBlock; }
uint8* WritableBlock() const { return fBlock; }
off_t BlockNumber() const { return fBlockNumber; }
uint32 BlockSize() const
{ 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
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)
{
Unset();
fBlockNumber = block;
return fBlock = (uint8*)block_cache_get_etc(fVolume->BlockCache(),
block, base, length);
return block_cache_get_etc(fVolume->BlockCache(), block, base, length,
(const void**)&fBlock);
}
inline const uint8*
inline status_t
CachedBlock::SetTo(off_t block)
{
return SetTo(block, block, 1);
}
inline const uint8*
inline status_t
CachedBlock::SetTo(block_run run)
{
return SetTo(fVolume->ToBlock(run));
}
inline uint8*
inline status_t
CachedBlock::SetToWritable(Transaction& transaction, off_t block, off_t base,
size_t length, bool empty)
{
@ -167,23 +144,22 @@ CachedBlock::SetToWritable(Transaction& transaction, off_t block, off_t base,
if (empty) {
fBlock = (uint8*)block_cache_get_empty(fVolume->BlockCache(),
block, transaction.ID());
} else {
fBlock = (uint8*)block_cache_get_writable_etc(fVolume->BlockCache(),
block, base, length, transaction.ID());
return fBlock != NULL ? B_OK : B_NO_MEMORY;
}
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)
{
return SetToWritable(transaction, block, block, 1, empty);
}
inline uint8*
inline status_t
CachedBlock::SetToWritable(Transaction& transaction, block_run run, bool empty)
{
return SetToWritable(transaction, fVolume->ToBlock(run), empty);

View File

@ -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
* 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
if (inode->IsRegularNode()) {
RecursiveLocker locker(inode->SmallDataLock());
NodeGetter node(GetVolume(), inode);
if (node.Node() == NULL) {
NodeGetter node(GetVolume());
status_t status = node.SetTo(inode);
if (status != B_OK) {
Control().errors |= BFS_COULD_NOT_OPEN;
Control().status = B_IO_ERROR;
Control().status = status;
return B_OK;
}
@ -496,16 +497,17 @@ CheckVisitor::_CheckInodeBlocks(Inode* inode, const char* name)
if (data->max_indirect_range) {
status = _CheckAllocated(data->indirect, "indirect");
if (status < B_OK)
if (status != B_OK)
return status;
off_t block = GetVolume()->ToBlock(data->indirect);
for (int32 i = 0; i < data->indirect.Length(); i++) {
block_run* runs = (block_run*)cached.SetTo(block + i);
if (runs == NULL)
RETURN_ERROR(B_IO_ERROR);
status = cached.SetTo(block + i);
if (status != B_OK)
RETURN_ERROR(status);
block_run* runs = (block_run*)cached.Block();
int32 runsPerBlock = GetVolume()->BlockSize() / sizeof(block_run);
int32 index = 0;
for (; index < runsPerBlock; index++) {
@ -542,12 +544,12 @@ CheckVisitor::_CheckInodeBlocks(Inode* inode, const char* name)
for (int32 indirectIndex = 0; indirectIndex < runsPerArray;
indirectIndex++) {
// get the indirect array block
block_run* array = (block_run*)cached.SetTo(
GetVolume()->ToBlock(data->double_indirect)
status = cached.SetTo(GetVolume()->ToBlock(data->double_indirect)
+ indirectIndex / runsPerBlock);
if (array == NULL)
return B_IO_ERROR;
if (status != B_OK)
return status;
block_run* array = (block_run*)cached.Block();
block_run indirect = array[indirectIndex % runsPerBlock];
// are we finished yet?
if (indirect.IsZero())
@ -562,10 +564,12 @@ CheckVisitor::_CheckInodeBlocks(Inode* inode, const char* name)
/ sizeof(block_run);
for (int32 index = 0; index < maxIndex; ) {
block_run* runs = (block_run*)cachedDirect.SetTo(
GetVolume()->ToBlock(indirect) + index / runsPerBlock);
if (runs == NULL)
return B_IO_ERROR;
status = cachedDirect.SetTo(GetVolume()->ToBlock(indirect)
+ index / runsPerBlock);
if (status != B_OK)
return status;
block_run* runs = (block_run*)cachedDirect.Block();
do {
// are we finished yet?

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.
*/
@ -385,9 +385,11 @@ Inode::Inode(Volume* volume, Transaction& transaction, ino_t id, mode_t mode,
rw_lock_init(&fLock, "bfs inode");
recursive_lock_init(&fSmallDataLock, "bfs inode small data");
NodeGetter node(volume, transaction, this, true);
if (node.Node() == NULL) {
FATAL(("Could not read inode block %" B_PRId64 "!\n", BlockNumber()));
NodeGetter node(volume);
status_t status = node.SetToWritable(transaction, this, true);
if (status != B_OK) {
FATAL(("Could not read inode block %" B_PRId64 ": %s!\n", BlockNumber(),
strerror(status)));
return;
}
@ -491,9 +493,10 @@ Inode::WriteLockInTransaction(Transaction& transaction)
status_t
Inode::WriteBack(Transaction& transaction)
{
NodeGetter node(fVolume, transaction, this);
if (node.WritableNode() == NULL)
return B_IO_ERROR;
NodeGetter node(fVolume);
status_t status = node.SetToWritable(transaction, this);
if (status != B_OK)
return status;
memcpy(node.WritableNode(), &Node(), sizeof(bfs_inode));
return B_OK;
@ -503,11 +506,12 @@ Inode::WriteBack(Transaction& transaction)
status_t
Inode::UpdateNodeFromDisk()
{
NodeGetter node(fVolume, this);
if (node.Node() == NULL) {
FATAL(("Failed to read block %" B_PRId64 " from disk!\n",
BlockNumber()));
return B_IO_ERROR;
NodeGetter node(fVolume);
status_t status = node.SetTo(this);
if (status != B_OK) {
FATAL(("Failed to read block %" B_PRId64 " from disk: %s!\n",
BlockNumber(), strerror(status)));
return status;
}
memcpy(&fNode, node.Node(), sizeof(bfs_inode));
@ -677,9 +681,11 @@ Inode::_RemoveSmallData(Transaction& transaction, NodeGetter& nodeGetter,
if (item->IsLast(node))
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) {
Node().status_change_time = HOST_ENDIAN_TO_BFS_INT64(
bfs_inode::ToInode(real_time_clock_usecs()));
@ -718,7 +724,10 @@ Inode::_AddSmallData(Transaction& transaction, NodeGetter& nodeGetter,
if (spaceNeeded > fVolume->InodeSize() - sizeof(bfs_inode))
return B_DEVICE_FULL;
nodeGetter.MakeWritable(transaction);
status_t status = nodeGetter.MakeWritable(transaction);
if (status != B_OK)
return status;
RecursiveLocker locker(fSmallDataLock);
// 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
Inode::GetName(char* buffer, size_t size) const
{
NodeGetter node(fVolume, this);
if (node.Node() == NULL)
return B_IO_ERROR;
NodeGetter node(fVolume);
status_t status = node.SetTo(this);
if (status != B_OK)
return status;
RecursiveLocker locker(fSmallDataLock);
@ -961,9 +971,10 @@ Inode::SetName(Transaction& transaction, const char* name)
if (name == NULL || *name == '\0')
return B_BAD_VALUE;
NodeGetter node(fVolume, transaction, this);
if (node.Node() == NULL)
return B_IO_ERROR;
NodeGetter node(fVolume);
status_t status = node.SetToWritable(transaction, this);
if (status != B_OK)
return status;
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)
{
NodeGetter node(fVolume, this);
if (node.Node() == NULL)
return B_IO_ERROR;
NodeGetter node(fVolume);
status_t status = node.SetTo(this);
if (status != B_OK)
return status;
RecursiveLocker locker(fSmallDataLock);
@ -1107,9 +1119,10 @@ Inode::WriteAttribute(Transaction& transaction, const char* name, int32 type,
// No attribute inode exists yet
// save the old attribute data
NodeGetter node(fVolume, transaction, this);
if (node.Node() == NULL)
return B_IO_ERROR;
NodeGetter node(fVolume);
status = node.SetToWritable(transaction, this);
if (status != B_OK)
return status;
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
NodeGetter node(fVolume, transaction, this);
if (node.Node() == NULL)
return B_IO_ERROR;
NodeGetter node(fVolume);
status = node.SetToWritable(transaction, this);
if (status != B_OK)
return status;
status = _AddSmallData(transaction, node, name, type, pos, buffer,
*_length);
@ -1252,9 +1266,10 @@ Inode::RemoveAttribute(Transaction& transaction, const char* name)
{
Index index(fVolume);
bool hasIndex = index.SetTo(name) == B_OK;
NodeGetter node(fVolume, this);
if (node.Node() == NULL)
return B_IO_ERROR;
NodeGetter node(fVolume);
status_t status = node.SetTo(this);
if (status != B_OK)
return status;
// 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()) {
// remove the attribute file if it exists
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();
int32 index = start / indirectSize;
block_run* indirect = (block_run*)cached.SetTo(
fVolume->ToBlock(data->double_indirect) + index / runsPerBlock);
if (indirect == NULL)
RETURN_ERROR(B_ERROR);
status_t status = cached.SetTo(fVolume->ToBlock(
data->double_indirect) + index / runsPerBlock);
if (status != B_OK)
RETURN_ERROR(status);
block_run* indirect = (block_run*)cached.Block();
int32 current = (start % indirectSize) / directSize;
indirect = (block_run*)cached.SetTo(
fVolume->ToBlock(indirect[index % runsPerBlock])
+ current / runsPerBlock);
if (indirect == NULL)
RETURN_ERROR(B_ERROR);
status = cached.SetTo(fVolume->ToBlock(indirect[
index % runsPerBlock]) + current / runsPerBlock);
if (status != B_OK)
RETURN_ERROR(status);
indirect = (block_run*)cached.Block();
run = indirect[current % runsPerBlock];
if (run.Length() != data->double_indirect.Length())
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);
for (int32 i = 0; i < data->indirect.Length(); i++) {
block_run* indirect = (block_run*)cached.SetTo(block + i);
if (indirect == NULL)
RETURN_ERROR(B_IO_ERROR);
status_t status = cached.SetTo(block + i);
if (status != B_OK)
RETURN_ERROR(status);
block_run* indirect = (block_run*)cached.Block();
int32 current = -1;
while (++current < runsPerBlock) {
if (indirect[current].IsZero())
@ -1689,10 +1706,9 @@ Inode::_AllocateBlockArray(Transaction& transaction, block_run& run,
off_t block = fVolume->ToBlock(run);
for (int32 i = 0; i < run.Length(); i++) {
block_run* runs = (block_run*)cached.SetToWritable(transaction,
block + i, true);
if (runs == NULL)
return B_IO_ERROR;
status = cached.SetToWritable(transaction, block + i, true);
if (status != B_OK)
return status;
}
return B_OK;
}
@ -1851,7 +1867,11 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
data->max_indirect_range = HOST_ENDIAN_TO_BFS_INT64(
data->MaxDirectRange());
// 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 {
uint32 numberOfRuns = fVolume->BlockSize() / sizeof(block_run);
block = fVolume->ToBlock(data->indirect);
@ -1859,9 +1879,11 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
// search first empty entry
int32 i = 0;
for (; i < data->indirect.Length(); i++) {
if ((runs = (block_run*)cached.SetTo(block + i)) == NULL)
return B_IO_ERROR;
status = cached.SetTo(block + i);
if (status != B_OK)
return status;
runs = (block_run*)cached.Block();
for (free = 0; free < numberOfRuns; free++)
if (runs[free].IsZero())
break;
@ -1971,10 +1993,12 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
if (block >= minimum)
return EFBIG;
array = (block_run*)cached.SetTo(fVolume->ToBlock(
status = cached.SetTo(fVolume->ToBlock(
data->double_indirect) + block);
if (array == NULL)
return B_IO_ERROR;
if (status != B_OK)
return status;
array = (block_run*)cached.Block();
}
do {
@ -1989,11 +2013,13 @@ Inode::_GrowStream(Transaction& transaction, off_t size)
return status;
}
block_run* runs = (block_run*)cachedDirect.SetToWritable(
transaction, fVolume->ToBlock(array[indirectIndex
status = cachedDirect.SetToWritable(transaction,
fVolume->ToBlock(array[indirectIndex
% runsPerBlock]) + index / runsPerBlock);
if (runs == NULL)
return B_IO_ERROR;
if (status != B_OK)
return status;
block_run* runs = (block_run*)cachedDirect.Block();
do {
// insert the block_run into the array
@ -2079,10 +2105,11 @@ Inode::_FreeStaticStreamArray(Transaction& transaction, int32 level,
offset += (off_t)index * indirectSize;
for (int32 i = index / runsPerBlock; i < run.Length(); i++) {
block_run* array = (block_run*)cached.SetToWritable(transaction,
blockNumber + i);
if (array == NULL)
RETURN_ERROR(B_ERROR);
status_t status = cached.SetToWritable(transaction, blockNumber + i);
if (status != B_OK)
RETURN_ERROR(status);
block_run* array = (block_run*)cached.WritableBlock();
for (index = index % runsPerBlock; index < runsPerBlock; index++) {
if (array[index].IsZero()) {
@ -2201,10 +2228,11 @@ Inode::_ShrinkStream(Transaction& transaction, off_t size)
off_t offset = data->MaxDirectRange();
for (int32 i = 0; i < data->indirect.Length(); i++) {
block_run* array = (block_run*)cached.SetToWritable(transaction,
block + i);
if (array == NULL)
break;
status = cached.SetToWritable(transaction, block + i);
if (status != B_OK)
return status;
block_run* array = (block_run*)cached.WritableBlock();
off_t* maxIndirect = &data->max_indirect_range;
// 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&'"
status = _FreeStreamArray(transaction, data->direct, NUM_DIRECT_BLOCKS,
size, offset, *maxDirect);
if (status < B_OK)
if (status != B_OK)
return status;
}
@ -2392,9 +2420,11 @@ Inode::Sync()
int32 count = fVolume->BlockSize() / sizeof(block_run);
for (int32 j = 0; j < data->indirect.Length(); j++) {
block_run* runs = (block_run*)cached.SetTo(block + j);
if (runs == NULL)
break;
status = cached.SetTo(block + j);
if (status != B_OK)
return status;
block_run* runs = (block_run*)cached.Block();
for (int32 i = 0; i < count; i++) {
if (runs[i].IsZero())
@ -2415,10 +2445,11 @@ Inode::Sync()
off_t indirectBlock = fVolume->ToBlock(data->double_indirect);
for (int32 l = 0; l < data->double_indirect.Length(); l++) {
block_run* indirectRuns = (block_run*)cached.SetTo(indirectBlock + l);
if (indirectRuns == NULL)
return B_FILE_ERROR;
status = cached.SetTo(indirectBlock + l);
if (status != B_OK)
return status;
block_run* indirectRuns = (block_run*)cached.Block();
CachedBlock directCached(fVolume);
for (int32 k = 0; k < count; k++) {
@ -2427,9 +2458,11 @@ Inode::Sync()
block = fVolume->ToBlock(indirectRuns[k]);
for (int32 j = 0; j < indirectRuns[k].Length(); j++) {
block_run* runs = (block_run*)directCached.SetTo(block + j);
if (runs == NULL)
return B_FILE_ERROR;
status = directCached.SetTo(block + j);
if (status != B_OK)
return status;
block_run* runs = (block_run*)directCached.Block();
for (int32 i = 0; i < count; i++) {
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
if (fCurrentSmallData >= 0) {
NodeGetter nodeGetter(fInode->GetVolume(), fInode);
if (nodeGetter.Node() == NULL)
return B_IO_ERROR;
NodeGetter nodeGetter(fInode->GetVolume());
status_t status = nodeGetter.SetTo(fInode);
if (status != B_OK)
return status;
const bfs_inode* node = nodeGetter.Node();
const small_data* item = ((bfs_inode*)node)->SmallDataStart();

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.
*/
#ifndef INODE_H
@ -338,30 +338,25 @@ private:
class NodeGetter : public CachedBlock {
public:
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()
{
}
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(); }

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.
*/
@ -484,11 +484,11 @@ Journal::_ReplayRunArray(int32* _start)
CachedBlock cachedArray(fVolume);
const run_array* array = (const run_array*)cachedArray.SetTo(logOffset
+ firstBlockNumber);
if (array == NULL)
return B_IO_ERROR;
status_t status = cachedArray.SetTo(logOffset + firstBlockNumber);
if (status != B_OK)
return status;
const run_array* array = (const run_array*)cachedArray.Block();
if (_CheckRunArray(array) < B_OK)
return B_BAD_DATA;
@ -505,16 +505,16 @@ Journal::_ReplayRunArray(int32* _start)
off_t offset = fVolume->ToOffset(run);
for (int32 i = 0; i < run.Length(); i++) {
const uint8* data = cached.SetTo(logOffset + blockNumber);
if (data == NULL)
RETURN_ERROR(B_IO_ERROR);
status = cached.SetTo(logOffset + blockNumber);
if (status != status)
RETURN_ERROR(status);
// TODO: eventually check other well known offsets, like the
// root and index dirs
if (offset == 0) {
// This log entry writes over the superblock - check if
// it's valid!
if (Volume::CheckSuperBlock(data) != B_OK) {
if (Volume::CheckSuperBlock(cached.Block()) != B_OK) {
FATAL(("Log contains invalid superblock!\n"));
RETURN_ERROR(B_BAD_DATA);
}
@ -537,12 +537,12 @@ Journal::_ReplayRunArray(int32* _start)
off_t offset = fVolume->ToOffset(run);
for (int32 i = 0; i < run.Length(); i++) {
const uint8* data = cached.SetTo(logOffset + blockNumber);
if (data == NULL)
RETURN_ERROR(B_IO_ERROR);
status = cached.SetTo(logOffset + blockNumber);
if (status != B_OK)
RETURN_ERROR(status);
ssize_t written = write_pos(fVolume->Device(), offset, data,
blockSize);
ssize_t written = write_pos(fVolume->Device(), offset,
cached.Block(), blockSize);
if (written != blockSize)
RETURN_ERROR(B_IO_ERROR);

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.
* Copyright 2010, Clemens Zeidler <haiku@clemens-zeidler.de>
* 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);
} else if (!strcmp(fAttribute, "name")) {
// we need to lock before accessing Inode::Name()
nodeGetter.SetToNode(inode);
if (nodeGetter.Node() == NULL)
return B_IO_ERROR;
status_t status = nodeGetter.SetTo(inode);
if (status != B_OK)
return status;
recursive_lock_lock(&inode->SmallDataLock());
locked = true;
@ -417,9 +417,9 @@ Equation::Match(Inode* inode, const char* attributeName, int32 type,
} else {
// then for attributes in the small_data section, and finally for the
// real attributes
nodeGetter.SetToNode(inode);
if (nodeGetter.Node() == NULL)
return B_IO_ERROR;
status_t status = nodeGetter.SetTo(inode);
if (status != B_OK)
return status;
Inode* attribute;

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.
*/
@ -294,14 +294,16 @@ bfs_get_vnode(fs_volume* _volume, ino_t id, fs_vnode* _node, int* _type,
return B_ERROR;
}
CachedBlock cached(volume, id);
bfs_inode* node = (bfs_inode*)cached.Block();
if (node == NULL) {
FATAL(("could not read inode: %" B_PRIdINO "\n", id));
return B_IO_ERROR;
CachedBlock cached(volume);
status_t status = cached.SetTo(id);
if (status != B_OK) {
FATAL(("could not read inode: %" B_PRIdINO ": %s\n", id,
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 ((node->Flags() & INODE_DELETED) != 0) {
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();
}
}
if (status == B_OK) {
status = user_memcpy(buffer, &checker->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,
run.start, run.length));
for (int32 i = 0;i < run.length;i++) {
uint8* block = cached.SetToWritable(transaction, run);
if (block != NULL)
memset(block, 0, volume->BlockSize());
status_t status = cached.SetToWritable(transaction, run);
if (status == B_OK)
memset(cached.WritableBlock(), 0, volume->BlockSize());
}
}
return B_OK;

View File

@ -908,9 +908,11 @@ update_fsinfo(nspace *vol)
{
if (vol->fat_bits == 32 && vol->fsinfo_sector != 0xffff
&& (vol->flags & B_FS_IS_READONLY) == 0) {
uchar *buffer = (uchar *)block_cache_get_writable_etc(vol->fBlockCache,
vol->fsinfo_sector, 0, vol->bytes_per_sector, -1);
if (buffer != NULL) {
uchar *buffer;
status_t status = block_cache_get_writable_etc(vol->fBlockCache,
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)) {
//number of free clusters
buffer[0x1e8] = (vol->free_clusters & 0xff);
@ -929,8 +931,8 @@ update_fsinfo(nspace *vol)
}
block_cache_put(vol->fBlockCache, vol->fsinfo_sector);
} else {
dprintf("update_fsinfo: error getting fsinfo sector %x\n",
vol->fsinfo_sector);
dprintf("update_fsinfo: error getting fsinfo sector %x: %s\n",
vol->fsinfo_sector, strerror(status));
}
}
}
@ -940,14 +942,17 @@ static status_t
get_fsinfo(nspace *vol, uint32 *free_count, uint32 *last_allocated)
{
uchar *buffer;
int32 result;
status_t result;
if ((vol->fat_bits != 32) || (vol->fsinfo_sector == 0xffff))
return B_ERROR;
if ((buffer = (uchar *)block_cache_get_etc(vol->fBlockCache, vol->fsinfo_sector, 0, vol->bytes_per_sector)) == NULL) {
dprintf("get_fsinfo: error getting fsinfo sector %x\n", vol->fsinfo_sector);
return EIO;
result = block_cache_get_etc(vol->fBlockCache, vol->fsinfo_sector, 0,
vol->bytes_per_sector, &buffer);
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)) {
@ -1093,12 +1098,12 @@ dosfs_write_fs_stat(fs_volume *_vol, const struct fs_info * fss, uint32 mask)
if (vol->vol_entry == -1) {
// stored in the bpb
uchar *buffer = block_cache_get_writable_etc(vol->fBlockCache, 0, 0,
vol->bytes_per_sector, -1);
if (buffer == NULL) {
result = EIO;
uchar *buffer;
result = block_cache_get_writable_etc(vol->fBlockCache, 0,
0, vol->bytes_per_sector, -1, (void**)&buffer);
if (result != B_OK)
goto bi;
}
if ((vol->sectors_per_fat == 0 && (buffer[0x42] != 0x29
|| strncmp((const char *)buffer + 0x47, vol->vol_label, 11)
!= 0))

View File

@ -37,11 +37,15 @@ mirror_fats(nspace *vol, uint32 sector, uint8 *buffer)
for (i = 0; i < vol->fat_count; i++) {
char *blockData;
status_t status;
if (i == vol->active_fat)
continue;
blockData = block_cache_get_writable_etc(vol->fBlockCache, sector
+ i * vol->sectors_per_fat, 0, 1, -1);
status = block_cache_get_writable_etc(vol->fBlockCache,
sector + i * vol->sectors_per_fat, 0, 1, -1, &blockData);
if (status != B_OK)
return status;
memcpy(blockData, buffer, vol->bytes_per_sector);
block_cache_put(vol->fBlockCache, sector + i * vol->sectors_per_fat);
}

View File

@ -112,11 +112,17 @@ iter_csi(struct csi *csi, int sectors)
uint8 *
csi_get_block(struct csi *csi)
{
status_t status;
const void* block;
if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0)
return NULL;
return (uint8 *)block_cache_get_etc(csi->vol->fBlockCache,
csi_to_block(csi), 1, csi->vol->bytes_per_sector);
status = block_cache_get_etc(csi->vol->fBlockCache,
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++) {
char *blockData = block_cache_get_writable_etc(csi->vol->fBlockCache, i,
0, 1, -1);
char *blockData;
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);
buf += csi->vol->bytes_per_sector;
block_cache_put(csi->vol->fBlockCache, i);
@ -233,6 +243,7 @@ csi_write_blocks(struct csi *csi, uint8 *buffer, ssize_t len)
status_t
csi_write_block(struct csi *csi, uint8 *buffer)
{
status_t status;
off_t block;
char *blockData;
@ -242,8 +253,11 @@ csi_write_block(struct csi *csi, uint8 *buffer)
if (_validate_cs_(csi->vol, csi->cluster, csi->sector) != 0)
return EINVAL;
blockData = block_cache_get_writable_etc(csi->vol->fBlockCache, block, 0, 1,
-1);
status = block_cache_get_writable_etc(csi->vol->fBlockCache, block, 0, 1,
-1, &blockData);
if (status != B_OK)
return status;
memcpy(blockData, buffer, csi->vol->bytes_per_sector);
block_cache_put(csi->vol->fBlockCache, block);

View File

@ -1,7 +1,7 @@
/*
* Copyright 2008, Salvatore Benedetto, salvatore.benedetto@gmail.com
* 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.
*/
#ifndef _UDF_CACHED_BLOCK_H
@ -9,7 +9,7 @@
/*! \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
*/
@ -20,10 +20,10 @@
#include "UdfStructures.h"
#include "Volume.h"
class CachedBlock {
public:
CachedBlock(Volume *volume);
CachedBlock(Volume *volume, off_t block);
CachedBlock(CachedBlock *cached);
~CachedBlock();
@ -35,11 +35,12 @@ public:
inline void Keep();
inline void Unset();
inline uint8 *SetTo(off_t block);
inline uint8 *SetTo(off_t block, off_t base, size_t length);
inline uint8 *SetTo(long_address address);
inline status_t SetTo(off_t block);
inline status_t SetTo(off_t block, off_t base, size_t length);
inline status_t SetTo(long_address address);
template <class Accessor, class Descriptor>
inline uint8* SetTo(Accessor &accessor, Descriptor &descriptor);
inline status_t SetTo(Accessor &accessor,
Descriptor &descriptor);
protected:
uint8 *fBlock;
@ -59,17 +60,6 @@ CachedBlock::CachedBlock(Volume *volume)
inline
CachedBlock::CachedBlock(Volume *volume, off_t block)
:
fBlock(NULL),
fBlockNumber(0),
fVolume(volume)
{
SetTo(block);
}
inline
CachedBlock::CachedBlock(CachedBlock *cached)
:
fBlock(cached->fBlock),
@ -97,43 +87,43 @@ CachedBlock::Keep()
inline void
CachedBlock::Unset()
{
if (fBlock) {
if (fBlock != NULL) {
block_cache_put(fVolume->BlockCache(), fBlockNumber);
fBlock = NULL;
}
}
inline uint8*
inline status_t
CachedBlock::SetTo(off_t block)
{
return SetTo(block, block, 1);
}
inline uint8*
inline status_t
CachedBlock::SetTo(off_t block, off_t base, size_t length)
{
Unset();
fBlockNumber = block;
return fBlock = (uint8 *)block_cache_get_etc(fVolume->BlockCache(),
block, base, length);
return block_cache_get_etc(fVolume->BlockCache(), block, base, length,
(const void**)&fBlock);
}
inline uint8 *
inline status_t
CachedBlock::SetTo(long_address address)
{
off_t block;
if (fVolume->MapBlock(address, &block) == B_OK)
return SetTo(block, block, 1);
else
return NULL;
return B_BAD_VALUE;
}
template <class Accessor, class Descriptor>
inline uint8*
inline status_t
CachedBlock::SetTo(Accessor &accessor, Descriptor &descriptor)
{
// 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);
}
#endif // _UDF_CACHED_BLOCK_H

View File

@ -123,20 +123,24 @@ Icb::Icb(Volume *volume, long_address address)
off_t block;
status_t status = fVolume->MapBlock(address, &block);
if (!status) {
icb_header *header = (icb_header *)fData.SetTo(block);
if (header->tag().id() == TAGID_FILE_ENTRY) {
file_icb_entry *entry = (file_icb_entry *)header;
PDUMP(entry);
(void)entry; // warning death
} else if (header->tag().id() == TAGID_EXTENDED_FILE_ENTRY) {
extended_file_icb_entry *entry = (extended_file_icb_entry *)header;
PDUMP(entry);
(void)entry; // warning death
} else {
PDUMP(header);
if (status == B_OK) {
status = fData.SetTo(block);
if (status == B_OK) {
icb_header *header = (icb_header *)fData.Block();
if (header->tag().id() == TAGID_FILE_ENTRY) {
file_icb_entry *entry = (file_icb_entry *)header;
PDUMP(entry);
(void)entry; // warning death
} else if (header->tag().id() == TAGID_EXTENDED_FILE_ENTRY) {
extended_file_icb_entry *entry
= (extended_file_icb_entry *)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()) {
@ -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"
" block_cache_get_etc()\n", readLength, diskBlock));
uint8 *data = (uint8*)block_cache_get_etc(volume->BlockCache(),
diskBlock, 0, readLength);
if (data == NULL)
const uint8 *data;
status = block_cache_get_etc(volume->BlockCache(),
diskBlock, 0, readLength, (const void**)&data);
if (status != B_OK)
break;
memcpy(buffer, data + blockOffset, readLength);
block_cache_put(volume->BlockCache(), diskBlock);

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.
*/
@ -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
block is read in.
*/
static cached_block*
static status_t
get_cached_block(block_cache* cache, off_t blockNumber, bool* _allocated,
bool readBlock = true)
bool readBlock, cached_block** _block)
{
ASSERT_LOCKED_MUTEX(&cache->lock);
if (blockNumber < 0 || blockNumber >= cache->max_blocks) {
panic("get_cached_block: invalid block number %" B_PRIdOFF " (max %" B_PRIdOFF ")",
blockNumber, cache->max_blocks - 1);
return NULL;
return B_BAD_VALUE;
}
retry:
@ -1917,7 +1917,7 @@ retry:
// put block into cache
block = cache->NewBlock(blockNumber);
if (block == NULL)
return NULL;
return B_NO_MEMORY;
cache->hash->Insert(block);
*_allocated = true;
@ -1951,7 +1951,7 @@ retry:
TRACE_ALWAYS(("could not read block %" B_PRIdOFF ": bytesRead: %zd, error: %s\n",
blockNumber, bytesRead, strerror(errno)));
return NULL;
return errno;
}
TB(Read(cache, block));
@ -1961,7 +1961,8 @@ retry:
block->ref_count++;
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
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,
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",
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) {
panic("get_writable_cached_block: invalid block number %" B_PRIdOFF " (max %" B_PRIdOFF ")",
blockNumber, cache->max_blocks - 1);
return B_BAD_VALUE;
}
bool allocated;
cached_block* block = get_cached_block(cache, blockNumber, &allocated,
!cleared);
if (block == NULL)
return NULL;
cached_block* block;
status_t status = get_cached_block(cache, blockNumber, &allocated,
!cleared, &block);
if (status != B_OK)
return status;
if (block->busy_writing)
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));
return block->current_data;
*_block = block->current_data;
return B_OK;
}
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 "
"(transaction %" B_PRId32 ")\n", block->transaction->id);
put_cached_block(cache, block);
return NULL;
return B_BAD_VALUE;
}
if (transaction == NULL && transactionID != -1) {
// 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",
transactionID);
put_cached_block(cache, block);
return NULL;
return B_BAD_VALUE;
}
if (!transaction->open) {
panic("get_writable_cached_block(): transaction already done!\n");
put_cached_block(cache, block);
return NULL;
return B_BAD_VALUE;
}
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"));
FATAL(("could not allocate original_data\n"));
put_cached_block(cache, block);
return NULL;
return B_NO_MEMORY;
}
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"));
FATAL(("could not allocate parent\n"));
put_cached_block(cache, block);
return NULL;
return B_NO_MEMORY;
}
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));
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!
void* block = get_writable_cached_block(cache, blockNumber,
blockNumber, 1, transaction, false);
if (block != NULL) {
void* block;
status_t status = get_writable_cached_block(cache, blockNumber,
blockNumber, 1, transaction, false, &block);
if (status == B_OK) {
put_cached_block((block_cache*)_cache, blockNumber);
return B_OK;
}
return B_ERROR;
return status;
}
void*
status_t
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;
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!");
return get_writable_cached_block(cache, blockNumber, base, length,
transaction, false);
transaction, false, _block);
}
void*
block_cache_get_writable(void* _cache, off_t blockNumber, int32 transaction)
{
return block_cache_get_writable_etc(_cache, blockNumber,
blockNumber, 1, transaction);
void* block;
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)
panic("tried to get empty writable block on a read-only cache!");
return get_writable_cached_block((block_cache*)_cache, blockNumber,
blockNumber, 1, transaction, true);
void* block;
if (get_writable_cached_block((block_cache*)_cache, blockNumber,
blockNumber, 1, transaction, true, &block) == B_OK)
return block;
return NULL;
}
const void*
block_cache_get_etc(void* _cache, off_t blockNumber, off_t base, off_t length)
status_t
block_cache_get_etc(void* _cache, off_t blockNumber, off_t base, off_t length,
const void** _block)
{
block_cache* cache = (block_cache*)_cache;
MutexLocker locker(&cache->lock);
bool allocated;
cached_block* block = get_cached_block(cache, blockNumber, &allocated);
if (block == NULL)
return NULL;
cached_block* block;
status_t status = get_cached_block(cache, blockNumber, &allocated, true,
&block);
if (status != B_OK)
return status;
#if BLOCK_CACHE_DEBUG_CHANGED
if (block->compare == NULL)
@ -3654,14 +3671,20 @@ block_cache_get_etc(void* _cache, off_t blockNumber, off_t base, off_t length)
#endif
TB(Get(cache, block));
return block->current_data;
*_block = block->current_data;
return B_OK;
}
const void*
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;
}

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.
*/
@ -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
data.
*/
static cached_block*
static fssh_status_t
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) {
fssh_panic("get_cached_block: invalid block number %" FSSH_B_PRIdOFF
" (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,
@ -734,7 +734,7 @@ get_cached_block(block_cache* cache, fssh_off_t blockNumber, bool* _allocated,
// read block into cache
block = cache->NewBlock(blockNumber);
if (block == NULL)
return NULL;
return FSSH_B_NO_MEMORY;
hash_insert(cache->hash, block);
*_allocated = true;
@ -747,7 +747,7 @@ get_cached_block(block_cache* cache, fssh_off_t blockNumber, bool* _allocated,
blockSize) < blockSize) {
cache->RemoveBlock(block);
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->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
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,
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",
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_B_PRIdOFF " (max %" FSSH_B_PRIdOFF ")", blockNumber,
cache->max_blocks - 1);
return FSSH_B_BAD_VALUE;
}
bool allocated;
cached_block* block = get_cached_block(cache, blockNumber, &allocated,
!cleared);
if (block == NULL)
return NULL;
cached_block* block;
fssh_status_t status = get_cached_block(cache, blockNumber, &allocated,
!cleared, &block);
if (status != FSSH_B_OK)
return status;
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;
// mark the block as dirty
return block->current_data;
*_block = block->current_data;
return FSSH_B_OK;
}
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.
fssh_panic("get_writable_cached_block(): asked to get busy writable block (transaction %d)\n", (int)transaction->id);
put_cached_block(cache, block);
return NULL;
return FSSH_B_BAD_VALUE;
}
if (transaction == NULL && transactionID != -1) {
// 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",
(int)transactionID);
put_cached_block(cache, block);
return NULL;
return FSSH_B_BAD_VALUE;
}
if (!transaction->open) {
fssh_panic("get_writable_cached_block(): transaction already done!\n");
put_cached_block(cache, block);
return NULL;
return FSSH_B_BAD_VALUE;
}
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) {
FATAL(("could not allocate original_data\n"));
put_cached_block(cache, block);
return NULL;
return FSSH_B_NO_MEMORY;
}
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...
FATAL(("could not allocate parent\n"));
put_cached_block(cache, block);
return NULL;
return FSSH_B_NO_MEMORY;
}
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;
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!");
// TODO: this can be done better!
void* block = get_writable_cached_block(cache, blockNumber,
blockNumber, 1, transaction, false);
if (block != NULL) {
void* block;
fssh_status_t status = get_writable_cached_block(cache, blockNumber,
blockNumber, 1, transaction, false, &block);
if (status == FSSH_B_OK) {
put_cached_block((block_cache*)_cache, blockNumber);
return FSSH_B_OK;
}
return FSSH_B_ERROR;
return status;
}
void*
fssh_block_cache_get_writable_etc(void* _cache, fssh_off_t blockNumber, fssh_off_t base,
fssh_off_t length, int32_t transaction)
fssh_status_t
fssh_block_cache_get_writable_etc(void* _cache, fssh_off_t blockNumber,
fssh_off_t base, fssh_off_t length, int32_t transaction, void** _block)
{
block_cache* cache = (block_cache*)_cache;
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!");
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,
int32_t transaction)
{
return fssh_block_cache_get_writable_etc(_cache, blockNumber,
blockNumber, 1, transaction);
void* block;
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)
fssh_panic("tried to get empty writable block on a read-only cache!");
return get_writable_cached_block((block_cache*)_cache, blockNumber,
blockNumber, 1, transaction, true);
void* block;
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_off_t length)
fssh_off_t length, const void** _block)
{
block_cache* cache = (block_cache*)_cache;
MutexLocker locker(&cache->lock);
bool allocated;
cached_block* block = get_cached_block(cache, blockNumber, &allocated);
if (block == NULL)
return NULL;
cached_block* block;
fssh_status_t status = get_cached_block(cache, blockNumber, &allocated,
true, &block);
if (status != FSSH_B_OK)
return status;
#ifdef DEBUG_CHANGED
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)
memcpy(block->compare, block->current_data, cache->block_size);
#endif
return block->current_data;
*_block = block->current_data;
return FSSH_B_OK;
}
const void*
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;
}