[haiku-commits] haiku: hrev54336 - in src: add-ons/kernel/file_systems/bfs tools/fs_shell system/kernel/cache add-ons/kernel/file_systems/udf add-ons/kernel/file_systems/fat

  • From: waddlesplash <waddlesplash@xxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sat, 20 Jun 2020 14:10:09 -0400 (EDT)

hrev54336 adds 2 changesets to branch 'master'
old head: cc7b6b58707146d344bdbc92ce7542debc13329e
new head: 2d4d5317317a2b16d5a5c90aa2b00437f2cb2ce9
overview: 
https://git.haiku-os.org/haiku/log/?qt=range&q=2d4d5317317a+%5Ecc7b6b587071

----------------------------------------------------------------------------

93845aec95b7: 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@xxxxxxxxxxxxxxxx>
  Reviewed-by: Adrien Destugues <pulkomandy@xxxxxxxxx>

2d4d5317317a: bfs: CheckVisitor only deletes nodes on specific errors
  
  * This should prevent erroneously deleting any files in low memory
    situations.
  
  Change-Id: I21b1d042e5f7e03a5abfaaa567b6c679b95e3188
  Reviewed-on: https://review.haiku-os.org/c/haiku/+/2914
  Reviewed-by: Adrien Destugues <pulkomandy@xxxxxxxxx>

                                   [ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ]

----------------------------------------------------------------------------

18 files changed, 438 insertions(+), 355 deletions(-)
headers/os/drivers/fs_cache.h                    |  10 +-
headers/private/fs_shell/fssh_fs_cache.h         |  11 +-
.../kernel/file_systems/bfs/Attribute.cpp        |   8 +-
.../kernel/file_systems/bfs/BlockAllocator.cpp   |   7 +-
.../kernel/file_systems/bfs/CachedBlock.h        |  62 ++----
.../kernel/file_systems/bfs/CheckVisitor.cpp     |  59 +++---
src/add-ons/kernel/file_systems/bfs/Inode.cpp    | 196 +++++++++++--------
src/add-ons/kernel/file_systems/bfs/Inode.h      |  25 +--
src/add-ons/kernel/file_systems/bfs/Journal.cpp  |  28 +--
src/add-ons/kernel/file_systems/bfs/Query.cpp    |  14 +-
.../kernel/file_systems/bfs/kernel_interface.cpp |  24 +--
src/add-ons/kernel/file_systems/fat/dosfs.c      |  33 ++--
src/add-ons/kernel/file_systems/fat/fat.c        |   8 +-
src/add-ons/kernel/file_systems/fat/iter.c       |  26 ++-
.../kernel/file_systems/udf/CachedBlock.h        |  45 ++---
src/add-ons/kernel/file_systems/udf/Icb.cpp      |  37 ++--
src/system/kernel/cache/block_cache.cpp          |  99 ++++++----
src/tools/fs_shell/block_cache.cpp               | 101 ++++++----

############################################################################

Commit:      93845aec95b77093f17bb577b5fd8c6bc9f2d9e3
URL:         https://git.haiku-os.org/haiku/commit/?id=93845aec95b7
Author:      Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date:        Thu Jun 11 19:50:36 2020 UTC
Committer:   waddlesplash <waddlesplash@xxxxxxxxx>
Commit-Date: Sat Jun 20 18:10:03 2020 UTC

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@xxxxxxxxxxxxxxxx>
Reviewed-by: Adrien Destugues <pulkomandy@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/headers/os/drivers/fs_cache.h b/headers/os/drivers/fs_cache.h
index 8c8193c35d..fce3ea9042 100644
--- a/headers/os/drivers/fs_cache.h
+++ b/headers/os/drivers/fs_cache.h
@@ -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);
diff --git a/headers/private/fs_shell/fssh_fs_cache.h 
b/headers/private/fs_shell/fssh_fs_cache.h
index c27052c484..bbcd6b647d 100644
--- a/headers/private/fs_shell/fssh_fs_cache.h
+++ b/headers/private/fs_shell/fssh_fs_cache.h
@@ -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,
diff --git a/src/add-ons/kernel/file_systems/bfs/Attribute.cpp 
b/src/add-ons/kernel/file_systems/bfs/Attribute.cpp
index 3347e6414e..46339da610 100644
--- a/src/add-ons/kernel/file_systems/bfs/Attribute.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/Attribute.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2004-2017, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
+ * Copyright 2004-2020, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
  * 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)
diff --git a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp 
b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp
index 81a5840527..5f4fa0a70c 100644
--- a/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/BlockAllocator.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2001-2017, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
+ * Copyright 2001-2020, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
  * 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);
 }
 
 
diff --git a/src/add-ons/kernel/file_systems/bfs/CachedBlock.h 
b/src/add-ons/kernel/file_systems/bfs/CachedBlock.h
index 5bbc297dc0..07e8e7bcb4 100644
--- a/src/add-ons/kernel/file_systems/bfs/CachedBlock.h
+++ b/src/add-ons/kernel/file_systems/bfs/CachedBlock.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2001-2017, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
+ * Copyright 2001-2020, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
  * 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);
diff --git a/src/add-ons/kernel/file_systems/bfs/CheckVisitor.cpp 
b/src/add-ons/kernel/file_systems/bfs/CheckVisitor.cpp
index e8980e33d8..63bafa5cc9 100644
--- a/src/add-ons/kernel/file_systems/bfs/CheckVisitor.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/CheckVisitor.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2012, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
+ * Copyright 2002-2020, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
  * Copyright 2012, Andreas Henriksson, sausageboy@xxxxxxxxx
  * 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?
diff --git a/src/add-ons/kernel/file_systems/bfs/Inode.cpp 
b/src/add-ons/kernel/file_systems/bfs/Inode.cpp
index 1d1ce8d7b4..e8930a7950 100644
--- a/src/add-ons/kernel/file_systems/bfs/Inode.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/Inode.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2001-2017, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
+ * Copyright 2001-2020, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
  * 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();
diff --git a/src/add-ons/kernel/file_systems/bfs/Inode.h 
b/src/add-ons/kernel/file_systems/bfs/Inode.h
index 546f00da60..ef5afa053b 100644
--- a/src/add-ons/kernel/file_systems/bfs/Inode.h
+++ b/src/add-ons/kernel/file_systems/bfs/Inode.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2001-2017, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
+ * Copyright 2001-2020, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
  * 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)
-       {
-       }
-
-       NodeGetter(Volume* volume, const Inode* inode)
-               : CachedBlock(volume)
+               :
+               CachedBlock(volume)
        {
-               SetTo(volume->VnodeToBlock(inode->ID()));
        }
 
-       NodeGetter(Volume* volume, Transaction& transaction,
-                       const Inode* inode, bool empty = false)
-               : CachedBlock(volume)
+       ~NodeGetter()
        {
-               SetToWritable(transaction, volume->VnodeToBlock(inode->ID()), 
empty);
        }
 
-       ~NodeGetter()
+       status_t SetTo(const Inode* inode)
        {
+               return CachedBlock::SetTo(fVolume->VnodeToBlock(inode->ID()));
        }
 
-       const bfs_inode* SetToNode(const Inode* inode)
+       status_t SetToWritable(Transaction& transaction, const Inode* inode,
+               bool empty = false)
        {
-               return (const 
bfs_inode*)SetTo(fVolume->VnodeToBlock(inode->ID()));
+               return CachedBlock::SetToWritable(transaction,
+                       fVolume->VnodeToBlock(inode->ID()), empty);
        }
 
        const bfs_inode* Node() const { return (const bfs_inode*)Block(); }
diff --git a/src/add-ons/kernel/file_systems/bfs/Journal.cpp 
b/src/add-ons/kernel/file_systems/bfs/Journal.cpp
index f664a011f4..567607074a 100644
--- a/src/add-ons/kernel/file_systems/bfs/Journal.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/Journal.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2001-2017, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
+ * Copyright 2001-2020, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
  * 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);
 
diff --git a/src/add-ons/kernel/file_systems/bfs/Query.cpp 
b/src/add-ons/kernel/file_systems/bfs/Query.cpp
index 46026bfb43..7b9042a1e3 100644
--- a/src/add-ons/kernel/file_systems/bfs/Query.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/Query.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2001-2017, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
+ * Copyright 2001-2020, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
  * Copyright 2010, Clemens Zeidler <haiku@xxxxxxxxxxxxxxxxxx>
  * 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;
 
diff --git a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp 
b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp
index 90e8d2203e..699160b3b2 100644
--- a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2001-2017, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
+ * Copyright 2001-2020, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
  * 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;
diff --git a/src/add-ons/kernel/file_systems/fat/dosfs.c 
b/src/add-ons/kernel/file_systems/fat/dosfs.c
index f4062e4504..01d9696c0a 100644
--- a/src/add-ons/kernel/file_systems/fat/dosfs.c
+++ b/src/add-ons/kernel/file_systems/fat/dosfs.c
@@ -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))
diff --git a/src/add-ons/kernel/file_systems/fat/fat.c 
b/src/add-ons/kernel/file_systems/fat/fat.c
index 6abc26688b..c202145234 100644
--- a/src/add-ons/kernel/file_systems/fat/fat.c
+++ b/src/add-ons/kernel/file_systems/fat/fat.c
@@ -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);
        }
diff --git a/src/add-ons/kernel/file_systems/fat/iter.c 
b/src/add-ons/kernel/file_systems/fat/iter.c
index 90da4923a2..523d1d6b50 100644
--- a/src/add-ons/kernel/file_systems/fat/iter.c
+++ b/src/add-ons/kernel/file_systems/fat/iter.c
@@ -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);
 
diff --git a/src/add-ons/kernel/file_systems/udf/CachedBlock.h 
b/src/add-ons/kernel/file_systems/udf/CachedBlock.h
index 80513525a0..54e4a20970 100644
--- a/src/add-ons/kernel/file_systems/udf/CachedBlock.h
+++ b/src/add-ons/kernel/file_systems/udf/CachedBlock.h
@@ -1,7 +1,7 @@
 /*
  *     Copyright 2008, Salvatore Benedetto, salvatore.benedetto@xxxxxxxxx
  *     Copyright 2003, Tyler Dauwalder, tyler@xxxxxxxxxxxxx
- *     Copyright 2002, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx
+ *     Copyright 2002-2020, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx
  *     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@xxxxxxxxxxxxxxxx
 */
 
@@ -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
diff --git a/src/add-ons/kernel/file_systems/udf/Icb.cpp 
b/src/add-ons/kernel/file_systems/udf/Icb.cpp
index 4bd780685d..e60be96429 100644
--- a/src/add-ons/kernel/file_systems/udf/Icb.cpp
+++ b/src/add-ons/kernel/file_systems/udf/Icb.cpp
@@ -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);
diff --git a/src/system/kernel/cache/block_cache.cpp 
b/src/system/kernel/cache/block_cache.cpp
index 6b4ac88f1e..ca5c1125f7 100644
--- a/src/system/kernel/cache/block_cache.cpp
+++ b/src/system/kernel/cache/block_cache.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2004-2012, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
+ * Copyright 2004-2020, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
  * 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;
 }
 
 
diff --git a/src/tools/fs_shell/block_cache.cpp 
b/src/tools/fs_shell/block_cache.cpp
index 26132ec664..dea256172b 100644
--- a/src/tools/fs_shell/block_cache.cpp
+++ b/src/tools/fs_shell/block_cache.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2004-2008, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
+ * Copyright 2004-2020, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
  * 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;
 }
 
 

############################################################################

Revision:    hrev54336
Commit:      2d4d5317317a2b16d5a5c90aa2b00437f2cb2ce9
URL:         https://git.haiku-os.org/haiku/commit/?id=2d4d5317317a
Author:      Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date:        Sat Jun 13 16:36:18 2020 UTC
Committer:   waddlesplash <waddlesplash@xxxxxxxxx>
Commit-Date: Sat Jun 20 18:10:03 2020 UTC

bfs: CheckVisitor only deletes nodes on specific errors

* This should prevent erroneously deleting any files in low memory
  situations.

Change-Id: I21b1d042e5f7e03a5abfaaa567b6c679b95e3188
Reviewed-on: https://review.haiku-os.org/c/haiku/+/2914
Reviewed-by: Adrien Destugues <pulkomandy@xxxxxxxxx>

----------------------------------------------------------------------------

diff --git a/src/add-ons/kernel/file_systems/bfs/CheckVisitor.cpp 
b/src/add-ons/kernel/file_systems/bfs/CheckVisitor.cpp
index 63bafa5cc9..40b4635660 100644
--- a/src/add-ons/kernel/file_systems/bfs/CheckVisitor.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/CheckVisitor.cpp
@@ -336,7 +336,8 @@ status_t
 CheckVisitor::OpenInodeFailed(status_t reason, ino_t id, Inode* parent,
                char* treeName, TreeIterator* iterator)
 {
-       FATAL(("Could not open inode at %" B_PRIdOFF "\n", id));
+       FATAL(("Could not open inode at %" B_PRIdOFF ": %s\n", id,
+               strerror(reason)));
 
        if (treeName != NULL)
                strlcpy(Control().name, treeName, B_FILE_NAME_LENGTH);
@@ -346,13 +347,19 @@ CheckVisitor::OpenInodeFailed(status_t reason, ino_t id, 
Inode* parent,
        Control().inode = id;
        Control().errors = BFS_COULD_NOT_OPEN;
 
-       // remove inode from the tree if we can
-       if (parent != NULL && iterator != NULL
-               && (Control().flags & BFS_REMOVE_INVALID) != 0) {
-               Control().status = _RemoveInvalidNode(parent, iterator->Tree(), 
NULL,
-                       treeName);
-       } else
-               Control().status = B_ERROR;
+       // TODO: check other error codes; B_IO_ERROR might be a temporary
+       // issue, so it should be guarded by a force mode
+       if (reason == B_BAD_VALUE || reason == B_BAD_DATA || reason == 
B_IO_ERROR) {
+               // Remove inode from the tree if we can
+               if (parent != NULL && iterator != NULL
+                       && (Control().flags & BFS_REMOVE_INVALID) != 0) {
+                       Control().status = _RemoveInvalidNode(parent, 
iterator->Tree(),
+                               NULL, treeName);
+               } else
+                       Control().status = B_ERROR;
+       } else {
+               Control().status = B_OK;
+       }
 
        return B_OK;
 }


Other related posts:

  • » [haiku-commits] haiku: hrev54336 - in src: add-ons/kernel/file_systems/bfs tools/fs_shell system/kernel/cache add-ons/kernel/file_systems/udf add-ons/kernel/file_systems/fat - waddlesplash