Big update while moving over completely to the Haiku kernel:
- Ported over BFS to the new cache API - Inode no longer inherits from CachedBlock, and therefore, no longer keeps the whole inode block in memory. It now has a copy of the bfs_inode structure in memory instead. This has a number of advantages but also some disadvantages, so it might be reverted later, even if it's unlikely. - Added a NodeGetter class that can be used whenever the real block needs to be accessed (ie. for attributes) - Changed *transaction to &transaction where possible - Removed support for KEEP_WRONG_DIRENT_RECLEN - Removed support for uncached file access since that's no longer needed - Fixed some endian issues in bfs_write_stat() - Removed the install BFS rules, since they don't make any sense anymore (unless you are running Haiku ;-)) Note, logged streams are not supported anymore right now. Also, the transaction code is pretty simple and slow - it will be improved later on. Attribute code is pretty much untested in the new environment. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10053 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
04c79aa160
commit
fb02804a89
@ -1,11 +1,11 @@
|
||||
/* BPlusTree - BFS B+Tree implementation
|
||||
**
|
||||
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||
** Roughly based on 'btlib' written by Marcus J. Ranum
|
||||
**
|
||||
** Copyright (c) 2001-2004 pinc Software. All Rights Reserved.
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
*
|
||||
* Roughly based on 'btlib' written by Marcus J. Ranum - it shares
|
||||
* no code but achieves binary compatibility with the on disk format.
|
||||
*
|
||||
* Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "Debug.h"
|
||||
@ -43,6 +43,7 @@ class NodeChecker {
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
// Node Caching for the BPlusTree class
|
||||
//
|
||||
// With write support, there is the need for a function that allocates new
|
||||
@ -55,16 +56,30 @@ class NodeChecker {
|
||||
// Since BFS supports block sizes of 1024 bytes or greater, and the node size
|
||||
// is hard-coded to 1024 bytes, that's not an issue now.
|
||||
|
||||
void
|
||||
CachedNode::UnsetUnchanged(Transaction &transaction)
|
||||
{
|
||||
if (fTree == NULL || fTree->fStream == NULL)
|
||||
return;
|
||||
|
||||
if (fNode != NULL) {
|
||||
void *cache = fTree->fStream->GetVolume()->BlockCache();
|
||||
|
||||
block_cache_set_dirty(cache, fBlockNumber, false, transaction.ID());
|
||||
block_cache_put(cache, fBlockNumber);
|
||||
fNode = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CachedNode::Unset()
|
||||
{
|
||||
if (fTree == NULL || fTree->fStream == NULL)
|
||||
return;
|
||||
|
||||
if (fBlock != NULL) {
|
||||
release_block(fTree->fStream->GetVolume()->Device(), fBlockNumber);
|
||||
|
||||
fBlock = NULL;
|
||||
if (fNode != NULL) {
|
||||
block_cache_put(fTree->fStream->GetVolume()->BlockCache(), fBlockNumber);
|
||||
fNode = NULL;
|
||||
}
|
||||
}
|
||||
@ -88,14 +103,9 @@ CachedNode::SetTo(off_t offset, bool check)
|
||||
|| (offset % fTree->fNodeSize) != 0)
|
||||
return NULL;
|
||||
|
||||
if (InternalSetTo(offset) != NULL && check) {
|
||||
if (InternalSetTo(NULL, offset) != NULL && check) {
|
||||
// sanity checks (links, all_key_count)
|
||||
bplustree_header *header = fTree->fHeader;
|
||||
if (!header->IsValidLink(fNode->LeftLink())
|
||||
|| !header->IsValidLink(fNode->RightLink())
|
||||
|| !header->IsValidLink(fNode->OverflowLink())
|
||||
|| (int8 *)fNode->Values() + fNode->NumKeys() * sizeof(off_t) >
|
||||
(int8 *)fNode + fTree->fNodeSize) {
|
||||
if (!fTree->fHeader->CheckNode(fNode)) {
|
||||
FATAL(("invalid node read from offset %Ld, inode at %Ld\n",
|
||||
offset, fTree->fStream->ID()));
|
||||
return NULL;
|
||||
@ -105,6 +115,47 @@ CachedNode::SetTo(off_t offset, bool check)
|
||||
}
|
||||
|
||||
|
||||
bplustree_node *
|
||||
CachedNode::SetToWritable(Transaction &transaction, off_t offset, bool check)
|
||||
{
|
||||
if (fTree == NULL || fTree->fStream == NULL) {
|
||||
REPORT_ERROR(B_BAD_VALUE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Unset();
|
||||
|
||||
// You can only ask for nodes at valid positions - you can't
|
||||
// even access the b+tree header with this method (use SetToHeader()
|
||||
// instead)
|
||||
if (offset > fTree->fHeader->MaximumSize() - fTree->fNodeSize
|
||||
|| offset <= 0
|
||||
|| (offset % fTree->fNodeSize) != 0)
|
||||
return NULL;
|
||||
|
||||
if (InternalSetTo(&transaction, offset) != NULL && check) {
|
||||
// sanity checks (links, all_key_count)
|
||||
if (!fTree->fHeader->CheckNode(fNode)) {
|
||||
FATAL(("invalid node read from offset %Ld, inode at %Ld\n",
|
||||
offset, fTree->fStream->ID()));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return fNode;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
CachedNode::MakeWritable(Transaction &transaction)
|
||||
{
|
||||
if (fNode == NULL)
|
||||
return B_NO_INIT;
|
||||
|
||||
return block_cache_make_writable(transaction.GetVolume()->BlockCache(),
|
||||
fBlockNumber, transaction.ID());
|
||||
}
|
||||
|
||||
|
||||
bplustree_header *
|
||||
CachedNode::SetToHeader()
|
||||
{
|
||||
@ -114,16 +165,32 @@ CachedNode::SetToHeader()
|
||||
}
|
||||
|
||||
Unset();
|
||||
|
||||
InternalSetTo(0LL);
|
||||
|
||||
InternalSetTo(NULL, 0LL);
|
||||
return (bplustree_header *)fNode;
|
||||
}
|
||||
|
||||
|
||||
bplustree_header *
|
||||
CachedNode::SetToWritableHeader(Transaction &transaction)
|
||||
{
|
||||
if (fTree == NULL || fTree->fStream == NULL) {
|
||||
REPORT_ERROR(B_BAD_VALUE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Unset();
|
||||
|
||||
InternalSetTo(&transaction, 0LL);
|
||||
return (bplustree_header *)fNode;
|
||||
}
|
||||
|
||||
|
||||
bplustree_node *
|
||||
CachedNode::InternalSetTo(off_t offset)
|
||||
CachedNode::InternalSetTo(Transaction *transaction, off_t offset)
|
||||
{
|
||||
fNode = NULL;
|
||||
fOffset = offset;
|
||||
|
||||
off_t fileOffset;
|
||||
block_run run;
|
||||
@ -133,12 +200,20 @@ CachedNode::InternalSetTo(off_t offset)
|
||||
|
||||
int32 blockOffset = (offset - fileOffset) / volume->BlockSize();
|
||||
fBlockNumber = volume->ToBlock(run) + blockOffset;
|
||||
uint8 *block;
|
||||
|
||||
fBlock = (uint8 *)get_block(volume->Device(), fBlockNumber, volume->BlockSize());
|
||||
if (fBlock) {
|
||||
if (transaction != NULL) {
|
||||
block = (uint8 *)block_cache_get_writable(volume->BlockCache(), fBlockNumber, transaction->ID());
|
||||
fWritable = true;
|
||||
} else {
|
||||
block = (uint8 *)block_cache_get(volume->BlockCache(), fBlockNumber);
|
||||
fWritable = false;
|
||||
}
|
||||
|
||||
if (block) {
|
||||
// the node is somewhere in that block... (confusing offset calculation)
|
||||
fNode = (bplustree_node *)(fBlock + offset -
|
||||
(fileOffset + blockOffset * volume->BlockSize()));
|
||||
fNode = (bplustree_node *)(block + offset -
|
||||
(fileOffset + (blockOffset << volume->BlockShift())));
|
||||
} else
|
||||
REPORT_ERROR(B_IO_ERROR);
|
||||
}
|
||||
@ -147,10 +222,9 @@ CachedNode::InternalSetTo(off_t offset)
|
||||
|
||||
|
||||
status_t
|
||||
CachedNode::Free(Transaction *transaction, off_t offset)
|
||||
CachedNode::Free(Transaction &transaction, off_t offset)
|
||||
{
|
||||
if (transaction == NULL || fTree == NULL || fTree->fStream == NULL
|
||||
|| offset == BPLUSTREE_NULL)
|
||||
if (fTree == NULL || fTree->fStream == NULL || offset == BPLUSTREE_NULL)
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
|
||||
// ToDo: scan the free nodes list and remove all nodes at the end
|
||||
@ -158,91 +232,80 @@ CachedNode::Free(Transaction *transaction, off_t offset)
|
||||
// function is called, perhaps it should be done when the directory
|
||||
// inode is closed or based on some calculation or whatever...
|
||||
|
||||
bplustree_header *header = fTree->fHeader;
|
||||
if (fTree->fCachedHeader.MakeWritable(transaction) != B_OK)
|
||||
return B_IO_ERROR;
|
||||
|
||||
// if the node is the last one in the tree, we shrink
|
||||
// the tree and file size by one node
|
||||
off_t lastOffset = fTree->fHeader->MaximumSize() - fTree->fNodeSize;
|
||||
off_t lastOffset = header->MaximumSize() - fTree->fNodeSize;
|
||||
if (offset == lastOffset) {
|
||||
fTree->fHeader->maximum_size = HOST_ENDIAN_TO_BFS_INT64(lastOffset);
|
||||
|
||||
status_t status = fTree->fStream->SetFileSize(transaction, lastOffset);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
return fTree->fCachedHeader.WriteBack(transaction);
|
||||
header->maximum_size = HOST_ENDIAN_TO_BFS_INT64(lastOffset);
|
||||
return fTree->fStream->SetFileSize(transaction, lastOffset);
|
||||
}
|
||||
|
||||
// add the node to the free nodes list
|
||||
fNode->left_link = fTree->fHeader->free_node_pointer;
|
||||
fNode->left_link = header->free_node_pointer;
|
||||
fNode->overflow_link = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_FREE);
|
||||
|
||||
if (WriteBack(transaction) == B_OK) {
|
||||
fTree->fHeader->free_node_pointer = HOST_ENDIAN_TO_BFS_INT64(offset);
|
||||
return fTree->fCachedHeader.WriteBack(transaction);
|
||||
}
|
||||
return B_ERROR;
|
||||
header->free_node_pointer = HOST_ENDIAN_TO_BFS_INT64(offset);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
CachedNode::Allocate(Transaction *transaction, bplustree_node **_node, off_t *_offset)
|
||||
CachedNode::Allocate(Transaction &transaction, bplustree_node **_node, off_t *_offset)
|
||||
{
|
||||
if (transaction == NULL || fTree == NULL || fTree->fHeader == NULL
|
||||
|| fTree->fStream == NULL) {
|
||||
if (fTree == NULL || fTree->fHeader == NULL || fTree->fStream == NULL)
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
}
|
||||
|
||||
Unset();
|
||||
|
||||
bplustree_header *header = fTree->fHeader;
|
||||
status_t status;
|
||||
|
||||
// if there are any free nodes, recycle them
|
||||
if (SetTo(fTree->fHeader->FreeNode(), false) != NULL) {
|
||||
*_offset = fTree->fHeader->FreeNode();
|
||||
|
||||
if (SetToWritable(transaction, header->FreeNode(), false) != NULL) {
|
||||
if (fTree->fCachedHeader.MakeWritable(transaction) != B_OK)
|
||||
return B_IO_ERROR;
|
||||
|
||||
// set new free node pointer
|
||||
fTree->fHeader->free_node_pointer = fNode->left_link;
|
||||
if ((status = fTree->fCachedHeader.WriteBack(transaction)) == B_OK) {
|
||||
fNode->Initialize();
|
||||
*_node = fNode;
|
||||
return B_OK;
|
||||
}
|
||||
return status;
|
||||
header->free_node_pointer = fNode->left_link;
|
||||
fNode->Initialize();
|
||||
|
||||
*_offset = header->FreeNode();
|
||||
*_node = fNode;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// allocate space for a new node
|
||||
Inode *stream = fTree->fStream;
|
||||
if ((status = stream->Append(transaction, fTree->fNodeSize)) < B_OK)
|
||||
return status;
|
||||
|
||||
if (fTree->fCachedHeader.MakeWritable(transaction) != B_OK)
|
||||
return B_IO_ERROR;
|
||||
|
||||
// the maximum_size has to be changed before the call to SetTo() - or
|
||||
// else it will fail because the requested node is out of bounds
|
||||
off_t offset = fTree->fHeader->MaximumSize();
|
||||
fTree->fHeader->maximum_size = HOST_ENDIAN_TO_BFS_INT64(fTree->fHeader->MaximumSize() + fTree->fNodeSize);
|
||||
off_t offset = header->MaximumSize();
|
||||
header->maximum_size = HOST_ENDIAN_TO_BFS_INT64(header->MaximumSize() + fTree->fNodeSize);
|
||||
|
||||
if (SetToWritable(transaction, offset, false) != NULL) {
|
||||
fNode->Initialize();
|
||||
|
||||
if (SetTo(offset, false) != NULL) {
|
||||
*_offset = offset;
|
||||
|
||||
if (fTree->fCachedHeader.WriteBack(transaction) >= B_OK) {
|
||||
fNode->Initialize();
|
||||
*_node = fNode;
|
||||
return B_OK;
|
||||
}
|
||||
*_node = fNode;
|
||||
return B_OK;
|
||||
}
|
||||
RETURN_ERROR(B_ERROR);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
CachedNode::WriteBack(Transaction *transaction)
|
||||
{
|
||||
if (transaction == NULL || fTree == NULL || fTree->fStream == NULL || fNode == NULL)
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
|
||||
return transaction->WriteBlocks(fBlockNumber, fBlock);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
BPlusTree::BPlusTree(Transaction *transaction, Inode *stream, int32 nodeSize)
|
||||
BPlusTree::BPlusTree(Transaction &transaction, Inode *stream, int32 nodeSize)
|
||||
:
|
||||
fStream(NULL),
|
||||
fHeader(NULL),
|
||||
@ -293,21 +356,20 @@ BPlusTree::~BPlusTree()
|
||||
/** Create a new B+Tree on the specified stream */
|
||||
|
||||
status_t
|
||||
BPlusTree::SetTo(Transaction *transaction, Inode *stream, int32 nodeSize)
|
||||
BPlusTree::SetTo(Transaction &transaction, Inode *stream, int32 nodeSize)
|
||||
{
|
||||
// initializes in-memory B+Tree
|
||||
|
||||
fCachedHeader.Unset();
|
||||
fStream = stream;
|
||||
|
||||
fHeader = fCachedHeader.SetToHeader();
|
||||
fHeader = fCachedHeader.SetToWritableHeader(transaction);
|
||||
if (fHeader == NULL) {
|
||||
// allocate space for new header + node!
|
||||
fStatus = stream->SetFileSize(transaction, nodeSize * 2);
|
||||
if (fStatus < B_OK)
|
||||
RETURN_ERROR(fStatus);
|
||||
|
||||
fHeader = fCachedHeader.SetToHeader();
|
||||
|
||||
fHeader = fCachedHeader.SetToWritableHeader(transaction);
|
||||
if (fHeader == NULL)
|
||||
RETURN_ERROR(fStatus = B_ERROR);
|
||||
}
|
||||
@ -327,23 +389,22 @@ BPlusTree::SetTo(Transaction *transaction, Inode *stream, int32 nodeSize)
|
||||
fHeader->free_node_pointer = HOST_ENDIAN_TO_BFS_INT64((uint64)BPLUSTREE_NULL);
|
||||
fHeader->maximum_size = HOST_ENDIAN_TO_BFS_INT64(nodeSize * 2);
|
||||
|
||||
if (fCachedHeader.WriteBack(transaction) < B_OK)
|
||||
RETURN_ERROR(fStatus = B_ERROR);
|
||||
|
||||
// initialize b+tree root node
|
||||
CachedNode cached(this, fHeader->RootNode(), false);
|
||||
CachedNode cached(this);
|
||||
cached.SetToWritable(transaction, fHeader->RootNode(), false);
|
||||
if (cached.Node() == NULL)
|
||||
RETURN_ERROR(B_ERROR);
|
||||
RETURN_ERROR(B_IO_ERROR);
|
||||
|
||||
cached.Node()->Initialize();
|
||||
return fStatus = cached.WriteBack(transaction);
|
||||
|
||||
return fStatus = B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BPlusTree::SetTo(Inode *stream)
|
||||
{
|
||||
if (stream == NULL || stream->Node() == NULL)
|
||||
if (stream == NULL)
|
||||
RETURN_ERROR(fStatus = B_BAD_VALUE);
|
||||
|
||||
// get on-disk B+Tree header
|
||||
@ -620,9 +681,13 @@ BPlusTree::SeekDown(Stack<node_and_key> &stack, const uint8 *key, uint16 keyLeng
|
||||
}
|
||||
|
||||
|
||||
/** This will find a free duplicate fragment in the given bplustree_node.
|
||||
* The CachedNode will be set to the readable fragment on success.
|
||||
*/
|
||||
|
||||
status_t
|
||||
BPlusTree::FindFreeDuplicateFragment(bplustree_node *node, CachedNode *cached, off_t *_offset,
|
||||
bplustree_node **_fragment, uint32 *_index)
|
||||
BPlusTree::FindFreeDuplicateFragment(bplustree_node *node, CachedNode &cached,
|
||||
off_t *_offset, bplustree_node **_fragment, uint32 *_index)
|
||||
{
|
||||
off_t *values = node->Values();
|
||||
for (int32 i = 0; i < node->NumKeys(); i++) {
|
||||
@ -630,12 +695,12 @@ BPlusTree::FindFreeDuplicateFragment(bplustree_node *node, CachedNode *cached, o
|
||||
if (bplustree_node::LinkType(values[i]) != BPLUSTREE_DUPLICATE_FRAGMENT)
|
||||
continue;
|
||||
|
||||
bplustree_node *fragment = cached->SetTo(bplustree_node::FragmentOffset(values[i]), false);
|
||||
bplustree_node *fragment = cached.SetTo(bplustree_node::FragmentOffset(values[i]), false);
|
||||
if (fragment == NULL) {
|
||||
FATAL(("Could not get duplicate fragment at %Ld\n", values[i]));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// see if there is some space left for us
|
||||
int32 num = (fNodeSize >> 3) / (NUM_FRAGMENT_VALUES + 1);
|
||||
for (int32 j = 0;j < num;j++) {
|
||||
@ -654,7 +719,7 @@ BPlusTree::FindFreeDuplicateFragment(bplustree_node *node, CachedNode *cached, o
|
||||
|
||||
|
||||
status_t
|
||||
BPlusTree::InsertDuplicate(Transaction *transaction, CachedNode *cached, bplustree_node *node,
|
||||
BPlusTree::InsertDuplicate(Transaction &transaction, CachedNode &cached, bplustree_node *node,
|
||||
uint16 index, off_t value)
|
||||
{
|
||||
CachedNode cachedDuplicate(this);
|
||||
@ -669,7 +734,8 @@ BPlusTree::InsertDuplicate(Transaction *transaction, CachedNode *cached, bplustr
|
||||
// doesn't fit anymore, create a new duplicate node
|
||||
//
|
||||
if (bplustree_node::LinkType(oldValue) == BPLUSTREE_DUPLICATE_FRAGMENT) {
|
||||
bplustree_node *duplicate = cachedDuplicate.SetTo(bplustree_node::FragmentOffset(oldValue), false);
|
||||
bplustree_node *duplicate = cachedDuplicate.SetToWritable(transaction,
|
||||
bplustree_node::FragmentOffset(oldValue), false);
|
||||
if (duplicate == NULL)
|
||||
return B_IO_ERROR;
|
||||
|
||||
@ -699,9 +765,12 @@ BPlusTree::InsertDuplicate(Transaction *transaction, CachedNode *cached, bplustr
|
||||
array->Insert(value);
|
||||
} else {
|
||||
// create a new duplicate node
|
||||
CachedNode cachedNewDuplicate(this);
|
||||
|
||||
cachedDuplicate.UnsetUnchanged(transaction);
|
||||
// the old duplicate has not been touched, so we can reuse it
|
||||
|
||||
bplustree_node *newDuplicate;
|
||||
status = cachedNewDuplicate.Allocate(transaction, &newDuplicate, &offset);
|
||||
status = cachedDuplicate.Allocate(transaction, &newDuplicate, &offset);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
@ -714,21 +783,16 @@ BPlusTree::InsertDuplicate(Transaction *transaction, CachedNode *cached, bplustr
|
||||
|
||||
array = newDuplicate->DuplicateArray();
|
||||
array->Insert(value);
|
||||
|
||||
// if this fails, the old fragments node will contain wrong
|
||||
// data... (but since it couldn't be written, it shouldn't
|
||||
// be fatal)
|
||||
if ((status = cachedNewDuplicate.WriteBack(transaction)) < B_OK)
|
||||
return status;
|
||||
}
|
||||
|
||||
// update the main pointer to link to a duplicate node
|
||||
if (cached.MakeWritable(transaction) != B_OK)
|
||||
return B_IO_ERROR;
|
||||
|
||||
values[index] = bplustree_node::MakeLink(BPLUSTREE_DUPLICATE_NODE, offset);
|
||||
if ((status = cached->WriteBack(transaction)) < B_OK)
|
||||
return status;
|
||||
}
|
||||
|
||||
return cachedDuplicate.WriteBack(transaction);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
//
|
||||
@ -755,29 +819,27 @@ BPlusTree::InsertDuplicate(Transaction *transaction, CachedNode *cached, bplustr
|
||||
&& (oldValue = duplicate->RightLink()) != BPLUSTREE_NULL);
|
||||
|
||||
if (array->count < NUM_DUPLICATE_VALUES) {
|
||||
cachedDuplicate.MakeWritable(transaction);
|
||||
array = duplicate->DuplicateArray();
|
||||
|
||||
array->Insert(value);
|
||||
} else {
|
||||
// no space left - add a new duplicate node
|
||||
|
||||
CachedNode cachedNewDuplicate(this);
|
||||
bplustree_node *newDuplicate;
|
||||
status = cachedNewDuplicate.Allocate(transaction, &newDuplicate, &offset);
|
||||
status = cachedDuplicate.Allocate(transaction, &newDuplicate, &offset);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
// link the two nodes together
|
||||
duplicate->right_link = HOST_ENDIAN_TO_BFS_INT64(offset);
|
||||
newDuplicate->left_link = HOST_ENDIAN_TO_BFS_INT64(duplicateOffset);
|
||||
|
||||
|
||||
array = newDuplicate->DuplicateArray();
|
||||
array->count = 0;
|
||||
array->Insert(value);
|
||||
|
||||
status = cachedNewDuplicate.WriteBack(transaction);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
}
|
||||
return cachedDuplicate.WriteBack(transaction);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
//
|
||||
@ -787,23 +849,27 @@ BPlusTree::InsertDuplicate(Transaction *transaction, CachedNode *cached, bplustr
|
||||
|
||||
uint32 fragmentIndex = 0;
|
||||
bplustree_node *fragment;
|
||||
if (FindFreeDuplicateFragment(node, &cachedDuplicate, &offset, &fragment, &fragmentIndex) < B_OK) {
|
||||
if (FindFreeDuplicateFragment(node, cachedDuplicate, &offset, &fragment, &fragmentIndex) == B_OK) {
|
||||
if (cachedDuplicate.MakeWritable(transaction) != B_OK)
|
||||
return B_IO_ERROR;
|
||||
} else {
|
||||
// allocate a new duplicate fragment node
|
||||
if ((status = cachedDuplicate.Allocate(transaction, &fragment, &offset)) < B_OK)
|
||||
return status;
|
||||
|
||||
memset(fragment, 0, fNodeSize);
|
||||
}
|
||||
|
||||
duplicate_array *array = fragment->FragmentAt(fragmentIndex);
|
||||
array->Insert(oldValue);
|
||||
array->Insert(value);
|
||||
|
||||
if ((status = cachedDuplicate.WriteBack(transaction)) < B_OK)
|
||||
return status;
|
||||
if (cached.MakeWritable(transaction) != B_OK)
|
||||
return B_IO_ERROR;
|
||||
|
||||
values[index] = bplustree_node::MakeLink(BPLUSTREE_DUPLICATE_FRAGMENT, offset, fragmentIndex);
|
||||
|
||||
return cached->WriteBack(transaction);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -1070,8 +1136,12 @@ BPlusTree::SplitNode(bplustree_node *node, off_t nodeOffset, bplustree_node *oth
|
||||
}
|
||||
|
||||
|
||||
/** This inserts a key into the tree. The changes made to the tree will
|
||||
* all be part of the \a transaction.
|
||||
*/
|
||||
|
||||
status_t
|
||||
BPlusTree::Insert(Transaction *transaction, const uint8 *key, uint16 keyLength, off_t value)
|
||||
BPlusTree::Insert(Transaction &transaction, const uint8 *key, uint16 keyLength, off_t value)
|
||||
{
|
||||
if (keyLength < BPLUSTREE_MIN_KEY_LENGTH || keyLength > BPLUSTREE_MAX_KEY_LENGTH)
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
@ -1103,12 +1173,15 @@ BPlusTree::Insert(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
// is this a duplicate entry?
|
||||
if (status == B_OK) {
|
||||
if (fAllowDuplicates)
|
||||
return InsertDuplicate(transaction, &cached, node, nodeAndKey.keyIndex, value);
|
||||
return InsertDuplicate(transaction, cached, node, nodeAndKey.keyIndex, value);
|
||||
|
||||
RETURN_ERROR(B_NAME_IN_USE);
|
||||
}
|
||||
}
|
||||
|
||||
if (cached.MakeWritable(transaction) != B_OK)
|
||||
return B_IO_ERROR;
|
||||
|
||||
// is the node big enough to hold the pair?
|
||||
if (int32(round_up(sizeof(bplustree_node) + node->AllKeyLength() + keyLength)
|
||||
+ (node->NumKeys() + 1) * (sizeof(uint16) + sizeof(off_t))) < fNodeSize)
|
||||
@ -1116,7 +1189,7 @@ BPlusTree::Insert(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
InsertKey(node, nodeAndKey.keyIndex, keyBuffer, keyLength, value);
|
||||
UpdateIterators(nodeAndKey.nodeOffset, BPLUSTREE_NULL, nodeAndKey.keyIndex, 0, 1);
|
||||
|
||||
return cached.WriteBack(transaction);
|
||||
return B_OK;
|
||||
} else {
|
||||
CachedNode cachedNewRoot(this);
|
||||
CachedNode cachedOther(this);
|
||||
@ -1156,20 +1229,12 @@ BPlusTree::Insert(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
RETURN_ERROR(B_ERROR);
|
||||
}
|
||||
|
||||
// write the updated nodes back
|
||||
|
||||
if (cached.WriteBack(transaction) < B_OK
|
||||
|| cachedOther.WriteBack(transaction) < B_OK)
|
||||
RETURN_ERROR(B_ERROR);
|
||||
|
||||
UpdateIterators(nodeAndKey.nodeOffset, otherOffset, nodeAndKey.keyIndex,
|
||||
node->NumKeys(), 1);
|
||||
|
||||
// update the right link of the node in the left of the new node
|
||||
if ((other = cachedOther.SetTo(other->LeftLink())) != NULL) {
|
||||
if ((other = cachedOther.SetToWritable(transaction, other->LeftLink())) != NULL) {
|
||||
other->right_link = HOST_ENDIAN_TO_BFS_INT64(otherOffset);
|
||||
if (cachedOther.WriteBack(transaction) < B_OK)
|
||||
RETURN_ERROR(B_ERROR);
|
||||
}
|
||||
|
||||
// create a new root if necessary
|
||||
@ -1179,14 +1244,15 @@ BPlusTree::Insert(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
InsertKey(root, 0, keyBuffer, keyLength, node->LeftLink());
|
||||
root->overflow_link = HOST_ENDIAN_TO_BFS_INT64(nodeAndKey.nodeOffset);
|
||||
|
||||
if (cachedNewRoot.WriteBack(transaction) < B_OK)
|
||||
RETURN_ERROR(B_ERROR);
|
||||
bplustree_header *header = fCachedHeader.SetToWritableHeader(transaction);
|
||||
if (header == NULL)
|
||||
return B_IO_ERROR;
|
||||
|
||||
// finally, update header to point to the new root
|
||||
fHeader->root_node_pointer = HOST_ENDIAN_TO_BFS_INT64(newRoot);
|
||||
fHeader->max_number_of_levels = HOST_ENDIAN_TO_BFS_INT32(fHeader->MaxNumberOfLevels() + 1);
|
||||
header->root_node_pointer = HOST_ENDIAN_TO_BFS_INT64(newRoot);
|
||||
header->max_number_of_levels = HOST_ENDIAN_TO_BFS_INT32(header->MaxNumberOfLevels() + 1);
|
||||
|
||||
return fCachedHeader.WriteBack(transaction);
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1194,17 +1260,20 @@ BPlusTree::Insert(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
}
|
||||
|
||||
|
||||
/** Removes the duplicate index/value pair from the tree.
|
||||
* It's part of the private tree interface.
|
||||
*/
|
||||
|
||||
status_t
|
||||
BPlusTree::RemoveDuplicate(Transaction *transaction, bplustree_node *node, CachedNode *cached,
|
||||
BPlusTree::RemoveDuplicate(Transaction &transaction, bplustree_node *node, CachedNode &cached,
|
||||
uint16 index, off_t value)
|
||||
{
|
||||
CachedNode cachedDuplicate(this);
|
||||
off_t *values = node->Values();
|
||||
off_t oldValue = values[index];
|
||||
status_t status;
|
||||
|
||||
CachedNode cachedDuplicate(this);
|
||||
off_t duplicateOffset = bplustree_node::FragmentOffset(oldValue);
|
||||
bplustree_node *duplicate = cachedDuplicate.SetTo(duplicateOffset, false);
|
||||
bplustree_node *duplicate = cachedDuplicate.SetToWritable(transaction, duplicateOffset, false);
|
||||
if (duplicate == NULL)
|
||||
return B_IO_ERROR;
|
||||
|
||||
@ -1225,22 +1294,21 @@ BPlusTree::RemoveDuplicate(Transaction *transaction, bplustree_node *node, Cache
|
||||
// remove the array from the fragment node if it is empty
|
||||
if (array->count == 1) {
|
||||
// set the link to the remaining value
|
||||
if (cached.MakeWritable(transaction) != B_OK)
|
||||
return B_IO_ERROR;
|
||||
|
||||
values[index] = array->values[0];
|
||||
|
||||
// Remove the whole fragment node, if this was the only array,
|
||||
// otherwise free the array and write the changes back
|
||||
if (duplicate->FragmentsUsed(fNodeSize) == 1)
|
||||
status = cachedDuplicate.Free(transaction, duplicateOffset);
|
||||
else {
|
||||
if (duplicate->FragmentsUsed(fNodeSize) == 1) {
|
||||
status_t status = cachedDuplicate.Free(transaction, duplicateOffset);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
} else
|
||||
array->count = 0;
|
||||
status = cachedDuplicate.WriteBack(transaction);
|
||||
}
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
return cached->WriteBack(transaction);
|
||||
}
|
||||
return cachedDuplicate.WriteBack(transaction);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
//
|
||||
@ -1269,8 +1337,9 @@ BPlusTree::RemoveDuplicate(Transaction *transaction, bplustree_node *node, Cache
|
||||
|
||||
if ((duplicateOffset = duplicate->RightLink()) == BPLUSTREE_NULL)
|
||||
RETURN_ERROR(B_ENTRY_NOT_FOUND);
|
||||
|
||||
duplicate = cachedDuplicate.SetTo(duplicateOffset, false);
|
||||
|
||||
cachedDuplicate.UnsetUnchanged(transaction);
|
||||
duplicate = cachedDuplicate.SetToWritable(transaction, duplicateOffset, false);
|
||||
}
|
||||
if (duplicate == NULL)
|
||||
RETURN_ERROR(B_IO_ERROR);
|
||||
@ -1287,22 +1356,23 @@ BPlusTree::RemoveDuplicate(Transaction *transaction, bplustree_node *node, Cache
|
||||
|
||||
if (duplicateOffset == bplustree_node::FragmentOffset(oldValue)
|
||||
|| array->count == 1) {
|
||||
if (cached.MakeWritable(transaction) != B_OK)
|
||||
return B_IO_ERROR;
|
||||
|
||||
if (array->count == 1 && isLast)
|
||||
values[index] = array->values[0];
|
||||
else if (isLast) {
|
||||
FATAL(("removed last value from duplicate!\n"));
|
||||
} else
|
||||
values[index] = bplustree_node::MakeLink(BPLUSTREE_DUPLICATE_NODE, right);
|
||||
|
||||
if ((status = cached->WriteBack(transaction)) < B_OK)
|
||||
return status;
|
||||
}
|
||||
|
||||
status_t status;
|
||||
if ((status = cachedDuplicate.Free(transaction, duplicateOffset)) < B_OK)
|
||||
return status;
|
||||
|
||||
if (left != BPLUSTREE_NULL
|
||||
&& (duplicate = cachedDuplicate.SetTo(left, false)) != NULL) {
|
||||
&& (duplicate = cachedDuplicate.SetToWritable(transaction, left, false)) != NULL) {
|
||||
duplicate->right_link = HOST_ENDIAN_TO_BFS_INT64(right);
|
||||
|
||||
// If the next node is the last node, we need to free that node
|
||||
@ -1312,13 +1382,9 @@ BPlusTree::RemoveDuplicate(Transaction *transaction, bplustree_node *node, Cache
|
||||
duplicateOffset = left;
|
||||
continue;
|
||||
}
|
||||
|
||||
status = cachedDuplicate.WriteBack(transaction);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
}
|
||||
if (right != BPLUSTREE_NULL
|
||||
&& (duplicate = cachedDuplicate.SetTo(right, false)) != NULL) {
|
||||
&& (duplicate = cachedDuplicate.SetToWritable(transaction, right, false)) != NULL) {
|
||||
duplicate->left_link = HOST_ENDIAN_TO_BFS_INT64(left);
|
||||
|
||||
// Again, we may need to turn the duplicate entry back into a normal entry
|
||||
@ -1328,43 +1394,41 @@ BPlusTree::RemoveDuplicate(Transaction *transaction, bplustree_node *node, Cache
|
||||
duplicateOffset = right;
|
||||
continue;
|
||||
}
|
||||
|
||||
return cachedDuplicate.WriteBack(transaction);
|
||||
}
|
||||
return status;
|
||||
return B_OK;
|
||||
} else if (isLast && array->count <= NUM_FRAGMENT_VALUES) {
|
||||
// If the number of entries fits in a duplicate fragment, then
|
||||
// either find a free fragment node, or convert this node to a
|
||||
// fragment node.
|
||||
CachedNode cachedOther(this);
|
||||
|
||||
|
||||
bplustree_node *fragment = NULL;
|
||||
uint32 fragmentIndex = 0;
|
||||
off_t offset;
|
||||
if (FindFreeDuplicateFragment(node, &cachedOther, &offset,
|
||||
&fragment, &fragmentIndex) < B_OK) {
|
||||
// convert node
|
||||
memmove(duplicate, array, (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
|
||||
memset((off_t *)duplicate + NUM_FRAGMENT_VALUES + 1, 0,
|
||||
fNodeSize - (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
|
||||
} else {
|
||||
if (FindFreeDuplicateFragment(node, cachedOther, &offset, &fragment, &fragmentIndex) == B_OK) {
|
||||
// move to other node
|
||||
if (cachedOther.MakeWritable(transaction) != B_OK)
|
||||
return B_IO_ERROR;
|
||||
|
||||
duplicate_array *target = fragment->FragmentAt(fragmentIndex);
|
||||
memcpy(target, array, (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
|
||||
|
||||
cachedDuplicate.Free(transaction, duplicateOffset);
|
||||
duplicateOffset = offset;
|
||||
} else {
|
||||
// convert node
|
||||
memmove(duplicate, array, (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
|
||||
memset((off_t *)duplicate + NUM_FRAGMENT_VALUES + 1, 0,
|
||||
fNodeSize - (NUM_FRAGMENT_VALUES + 1) * sizeof(off_t));
|
||||
}
|
||||
|
||||
if (cached.MakeWritable(transaction) != B_OK)
|
||||
return B_IO_ERROR;
|
||||
|
||||
values[index] = bplustree_node::MakeLink(BPLUSTREE_DUPLICATE_FRAGMENT,
|
||||
duplicateOffset, fragmentIndex);
|
||||
|
||||
if ((status = cached->WriteBack(transaction)) < B_OK)
|
||||
return status;
|
||||
|
||||
if (fragment != NULL)
|
||||
return cachedOther.WriteBack(transaction);
|
||||
}
|
||||
return cachedDuplicate.WriteBack(transaction);
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1434,7 +1498,7 @@ BPlusTree::RemoveKey(bplustree_node *node, uint16 index)
|
||||
*/
|
||||
|
||||
status_t
|
||||
BPlusTree::Remove(Transaction *transaction, const uint8 *key, uint16 keyLength, off_t value)
|
||||
BPlusTree::Remove(Transaction &transaction, const uint8 *key, uint16 keyLength, off_t value)
|
||||
{
|
||||
if (keyLength < BPLUSTREE_MIN_KEY_LENGTH || keyLength > BPLUSTREE_MAX_KEY_LENGTH)
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
@ -1471,12 +1535,17 @@ BPlusTree::Remove(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
// is this a duplicate entry?
|
||||
if (bplustree_node::IsDuplicate(node->Values()[nodeAndKey.keyIndex])) {
|
||||
if (fAllowDuplicates)
|
||||
return RemoveDuplicate(transaction, node, &cached, nodeAndKey.keyIndex, value);
|
||||
else
|
||||
RETURN_ERROR(B_NAME_IN_USE);
|
||||
return RemoveDuplicate(transaction, node, cached, nodeAndKey.keyIndex, value);
|
||||
else {
|
||||
FATAL(("dupliate node found where no duplicates are allowed!\n"));
|
||||
RETURN_ERROR(B_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cached.MakeWritable(transaction) != B_OK)
|
||||
return B_IO_ERROR;
|
||||
|
||||
// if it's an empty root node, we have to convert it
|
||||
// to a leaf node by dropping the overflow link, or,
|
||||
// if it's a leaf node, just empty it
|
||||
@ -1487,14 +1556,13 @@ BPlusTree::Remove(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
node->all_key_count = 0;
|
||||
node->all_key_length = 0;
|
||||
|
||||
if (cached.WriteBack(transaction) < B_OK)
|
||||
return B_IO_ERROR;
|
||||
|
||||
// if we've cleared the root node, reset the maximum
|
||||
// number of levels in the header
|
||||
if (nodeAndKey.nodeOffset == fHeader->RootNode()) {
|
||||
if (fCachedHeader.MakeWritable(transaction) != B_OK)
|
||||
return B_IO_ERROR;
|
||||
|
||||
fHeader->max_number_of_levels = HOST_ENDIAN_TO_BFS_INT32(1);
|
||||
return fCachedHeader.WriteBack(transaction);
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
@ -1505,25 +1573,19 @@ BPlusTree::Remove(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
if (node->NumKeys() > 1
|
||||
|| !node->IsLeaf() && node->NumKeys() == 1) {
|
||||
RemoveKey(node, nodeAndKey.keyIndex);
|
||||
return cached.WriteBack(transaction);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// when we are here, we can just free the node, but
|
||||
// we have to update the right/left link of the
|
||||
// siblings first
|
||||
CachedNode otherCached(this);
|
||||
bplustree_node *other = otherCached.SetTo(node->LeftLink());
|
||||
if (other != NULL) {
|
||||
bplustree_node *other = otherCached.SetToWritable(transaction, node->LeftLink());
|
||||
if (other != NULL)
|
||||
other->right_link = node->right_link;
|
||||
if (otherCached.WriteBack(transaction) < B_OK)
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
if ((other = otherCached.SetTo(node->RightLink())) != NULL) {
|
||||
if ((other = otherCached.SetToWritable(transaction, node->RightLink())) != NULL)
|
||||
other->left_link = node->left_link;
|
||||
if (otherCached.WriteBack(transaction) < B_OK)
|
||||
return B_IO_ERROR;
|
||||
}
|
||||
|
||||
cached.Free(transaction, nodeAndKey.nodeOffset);
|
||||
}
|
||||
@ -1541,7 +1603,7 @@ BPlusTree::Remove(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
*/
|
||||
|
||||
status_t
|
||||
BPlusTree::Replace(Transaction *transaction, const uint8 *key, uint16 keyLength, off_t value)
|
||||
BPlusTree::Replace(Transaction &transaction, const uint8 *key, uint16 keyLength, off_t value)
|
||||
{
|
||||
if (keyLength < BPLUSTREE_MIN_KEY_LENGTH || keyLength > BPLUSTREE_MAX_KEY_LENGTH
|
||||
|| key == NULL)
|
||||
@ -1564,8 +1626,9 @@ BPlusTree::Replace(Transaction *transaction, const uint8 *key, uint16 keyLength,
|
||||
|
||||
if (node->OverflowLink() == BPLUSTREE_NULL) {
|
||||
if (status == B_OK) {
|
||||
node->Values()[keyIndex] = value;
|
||||
return cached.WriteBack(transaction);
|
||||
status = cached.MakeWritable(transaction);
|
||||
if (status == B_OK)
|
||||
node->Values()[keyIndex] = value;
|
||||
}
|
||||
|
||||
return status;
|
||||
|
@ -1,13 +1,13 @@
|
||||
/* BPlusTree - BFS B+Tree implementation
|
||||
*
|
||||
* Roughly based on 'btlib' written by Marcus J. Ranum - it shares
|
||||
* no code but achieves binary compatibility with the on disk format.
|
||||
*
|
||||
* Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef B_PLUS_TREE_H
|
||||
#define B_PLUS_TREE_H
|
||||
/* BPlusTree - BFS B+Tree implementation
|
||||
**
|
||||
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||
** Roughly based on 'btlib' written by Marcus J. Ranum
|
||||
**
|
||||
** Copyright (c) 2001-2004 pinc Software. All Rights Reserved.
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include "bfs.h"
|
||||
@ -19,6 +19,8 @@
|
||||
|
||||
//****************** on-disk structures ********************
|
||||
|
||||
struct bplustree_node;
|
||||
|
||||
#define BPLUSTREE_NULL -1LL
|
||||
#define BPLUSTREE_FREE -2LL
|
||||
|
||||
@ -39,6 +41,7 @@ struct bplustree_header {
|
||||
off_t MaximumSize() const { return BFS_ENDIAN_TO_HOST_INT64(maximum_size); }
|
||||
uint32 MaxNumberOfLevels() const { return BFS_ENDIAN_TO_HOST_INT32(max_number_of_levels); }
|
||||
|
||||
inline bool CheckNode(bplustree_node *node);
|
||||
inline bool IsValidLink(off_t link);
|
||||
} _PACKED;
|
||||
|
||||
@ -139,16 +142,14 @@ class CachedNode {
|
||||
CachedNode(BPlusTree *tree)
|
||||
:
|
||||
fTree(tree),
|
||||
fNode(NULL),
|
||||
fBlock(NULL)
|
||||
fNode(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
CachedNode(BPlusTree *tree, off_t offset, bool check = true)
|
||||
:
|
||||
fTree(tree),
|
||||
fNode(NULL),
|
||||
fBlock(NULL)
|
||||
fNode(NULL)
|
||||
{
|
||||
SetTo(offset, check);
|
||||
}
|
||||
@ -159,22 +160,27 @@ class CachedNode {
|
||||
}
|
||||
|
||||
bplustree_node *SetTo(off_t offset, bool check = true);
|
||||
bplustree_node *SetToWritable(Transaction &transaction, off_t offset, bool check = true);
|
||||
bplustree_header *SetToWritableHeader(Transaction &transaction);
|
||||
bplustree_header *SetToHeader();
|
||||
status_t MakeWritable(Transaction &transaction);
|
||||
void UnsetUnchanged(Transaction &transaction);
|
||||
void Unset();
|
||||
|
||||
status_t Free(Transaction *transaction, off_t offset);
|
||||
status_t Allocate(Transaction *transaction, bplustree_node **node, off_t *offset);
|
||||
status_t WriteBack(Transaction *transaction);
|
||||
status_t Free(Transaction &transaction, off_t offset);
|
||||
status_t Allocate(Transaction &transaction, bplustree_node **node, off_t *offset);
|
||||
|
||||
bool IsWritable() const { return fWritable; }
|
||||
bplustree_node *Node() const { return fNode; }
|
||||
|
||||
protected:
|
||||
bplustree_node *InternalSetTo(off_t offset);
|
||||
bplustree_node *InternalSetTo(Transaction *transaction, off_t offset);
|
||||
|
||||
BPlusTree *fTree;
|
||||
bplustree_node *fNode;
|
||||
uint8 *fBlock;
|
||||
off_t fOffset;
|
||||
off_t fBlockNumber;
|
||||
bool fWritable;
|
||||
};
|
||||
|
||||
|
||||
@ -182,31 +188,31 @@ class CachedNode {
|
||||
|
||||
class BPlusTree {
|
||||
public:
|
||||
BPlusTree(Transaction *transaction, Inode *stream, int32 nodeSize = BPLUSTREE_NODE_SIZE);
|
||||
BPlusTree(Transaction &transaction, Inode *stream, int32 nodeSize = BPLUSTREE_NODE_SIZE);
|
||||
BPlusTree(Inode *stream);
|
||||
BPlusTree();
|
||||
~BPlusTree();
|
||||
|
||||
status_t SetTo(Transaction *transaction, Inode *stream, int32 nodeSize = BPLUSTREE_NODE_SIZE);
|
||||
status_t SetTo(Transaction &transaction, Inode *stream, int32 nodeSize = BPLUSTREE_NODE_SIZE);
|
||||
status_t SetTo(Inode *stream);
|
||||
status_t SetStream(Inode *stream);
|
||||
|
||||
status_t InitCheck();
|
||||
status_t Validate();
|
||||
|
||||
status_t Remove(Transaction *transaction, const uint8 *key, uint16 keyLength, off_t value);
|
||||
status_t Insert(Transaction *transaction, const uint8 *key, uint16 keyLength, off_t value);
|
||||
status_t Remove(Transaction &transaction, const uint8 *key, uint16 keyLength, off_t value);
|
||||
status_t Insert(Transaction &transaction, const uint8 *key, uint16 keyLength, off_t value);
|
||||
|
||||
status_t Remove(Transaction *transaction, const char *key, off_t value);
|
||||
status_t Insert(Transaction *transaction, const char *key, off_t value);
|
||||
status_t Insert(Transaction *transaction, int32 key, off_t value);
|
||||
status_t Insert(Transaction *transaction, uint32 key, off_t value);
|
||||
status_t Insert(Transaction *transaction, int64 key, off_t value);
|
||||
status_t Insert(Transaction *transaction, uint64 key, off_t value);
|
||||
status_t Insert(Transaction *transaction, float key, off_t value);
|
||||
status_t Insert(Transaction *transaction, double key, off_t value);
|
||||
status_t Remove(Transaction &transaction, const char *key, off_t value);
|
||||
status_t Insert(Transaction &transaction, const char *key, off_t value);
|
||||
status_t Insert(Transaction &transaction, int32 key, off_t value);
|
||||
status_t Insert(Transaction &transaction, uint32 key, off_t value);
|
||||
status_t Insert(Transaction &transaction, int64 key, off_t value);
|
||||
status_t Insert(Transaction &transaction, uint64 key, off_t value);
|
||||
status_t Insert(Transaction &transaction, float key, off_t value);
|
||||
status_t Insert(Transaction &transaction, double key, off_t value);
|
||||
|
||||
status_t Replace(Transaction *transaction, const uint8 *key, uint16 keyLength, off_t value);
|
||||
status_t Replace(Transaction &transaction, const uint8 *key, uint16 keyLength, off_t value);
|
||||
status_t Find(const uint8 *key, uint16 keyLength, off_t *value);
|
||||
|
||||
static int32 TypeCodeToKeyType(type_code code);
|
||||
@ -222,9 +228,9 @@ class BPlusTree {
|
||||
uint16 *index = NULL, off_t *next = NULL);
|
||||
status_t SeekDown(Stack<node_and_key> &stack, const uint8 *key, uint16 keyLength);
|
||||
|
||||
status_t FindFreeDuplicateFragment(bplustree_node *node, CachedNode *cached,
|
||||
status_t FindFreeDuplicateFragment(bplustree_node *node, CachedNode &cached,
|
||||
off_t *_offset, bplustree_node **_fragment, uint32 *_index);
|
||||
status_t InsertDuplicate(Transaction *transaction, CachedNode *cached,
|
||||
status_t InsertDuplicate(Transaction &transaction, CachedNode &cached,
|
||||
bplustree_node *node, uint16 index, off_t value);
|
||||
void InsertKey(bplustree_node *node, uint16 index, uint8 *key, uint16 keyLength,
|
||||
off_t value);
|
||||
@ -232,8 +238,8 @@ class BPlusTree {
|
||||
off_t otherOffset, uint16 *_keyIndex, uint8 *key, uint16 *_keyLength,
|
||||
off_t *_value);
|
||||
|
||||
status_t RemoveDuplicate(Transaction *transaction, bplustree_node *node,
|
||||
CachedNode *cached, uint16 keyIndex, off_t value);
|
||||
status_t RemoveDuplicate(Transaction &transaction, bplustree_node *node,
|
||||
CachedNode &cached, uint16 keyIndex, off_t value);
|
||||
void RemoveKey(bplustree_node *node, uint16 index);
|
||||
|
||||
void UpdateIterators(off_t offset, off_t nextOffset, uint16 keyIndex,
|
||||
@ -303,7 +309,7 @@ class TreeIterator {
|
||||
// BPlusTree's inline functions (most of them may not be needed)
|
||||
|
||||
inline status_t
|
||||
BPlusTree::Remove(Transaction *transaction, const char *key, off_t value)
|
||||
BPlusTree::Remove(Transaction &transaction, const char *key, off_t value)
|
||||
{
|
||||
if (fHeader->data_type != BPLUSTREE_STRING_TYPE)
|
||||
return B_BAD_TYPE;
|
||||
@ -311,7 +317,7 @@ BPlusTree::Remove(Transaction *transaction, const char *key, off_t value)
|
||||
}
|
||||
|
||||
inline status_t
|
||||
BPlusTree::Insert(Transaction *transaction, const char *key, off_t value)
|
||||
BPlusTree::Insert(Transaction &transaction, const char *key, off_t value)
|
||||
{
|
||||
if (fHeader->data_type != BPLUSTREE_STRING_TYPE)
|
||||
return B_BAD_TYPE;
|
||||
@ -319,7 +325,7 @@ BPlusTree::Insert(Transaction *transaction, const char *key, off_t value)
|
||||
}
|
||||
|
||||
inline status_t
|
||||
BPlusTree::Insert(Transaction *transaction, int32 key, off_t value)
|
||||
BPlusTree::Insert(Transaction &transaction, int32 key, off_t value)
|
||||
{
|
||||
if (fHeader->data_type != BPLUSTREE_INT32_TYPE)
|
||||
return B_BAD_TYPE;
|
||||
@ -327,7 +333,7 @@ BPlusTree::Insert(Transaction *transaction, int32 key, off_t value)
|
||||
}
|
||||
|
||||
inline status_t
|
||||
BPlusTree::Insert(Transaction *transaction, uint32 key, off_t value)
|
||||
BPlusTree::Insert(Transaction &transaction, uint32 key, off_t value)
|
||||
{
|
||||
if (fHeader->data_type != BPLUSTREE_UINT32_TYPE)
|
||||
return B_BAD_TYPE;
|
||||
@ -335,7 +341,7 @@ BPlusTree::Insert(Transaction *transaction, uint32 key, off_t value)
|
||||
}
|
||||
|
||||
inline status_t
|
||||
BPlusTree::Insert(Transaction *transaction, int64 key, off_t value)
|
||||
BPlusTree::Insert(Transaction &transaction, int64 key, off_t value)
|
||||
{
|
||||
if (fHeader->data_type != BPLUSTREE_INT64_TYPE)
|
||||
return B_BAD_TYPE;
|
||||
@ -343,7 +349,7 @@ BPlusTree::Insert(Transaction *transaction, int64 key, off_t value)
|
||||
}
|
||||
|
||||
inline status_t
|
||||
BPlusTree::Insert(Transaction *transaction, uint64 key, off_t value)
|
||||
BPlusTree::Insert(Transaction &transaction, uint64 key, off_t value)
|
||||
{
|
||||
if (fHeader->data_type != BPLUSTREE_UINT64_TYPE)
|
||||
return B_BAD_TYPE;
|
||||
@ -351,7 +357,7 @@ BPlusTree::Insert(Transaction *transaction, uint64 key, off_t value)
|
||||
}
|
||||
|
||||
inline status_t
|
||||
BPlusTree::Insert(Transaction *transaction, float key, off_t value)
|
||||
BPlusTree::Insert(Transaction &transaction, float key, off_t value)
|
||||
{
|
||||
if (fHeader->data_type != BPLUSTREE_FLOAT_TYPE)
|
||||
return B_BAD_TYPE;
|
||||
@ -359,7 +365,7 @@ BPlusTree::Insert(Transaction *transaction, float key, off_t value)
|
||||
}
|
||||
|
||||
inline status_t
|
||||
BPlusTree::Insert(Transaction *transaction, double key, off_t value)
|
||||
BPlusTree::Insert(Transaction &transaction, double key, off_t value)
|
||||
{
|
||||
if (fHeader->data_type != BPLUSTREE_DOUBLE_TYPE)
|
||||
return B_BAD_TYPE;
|
||||
@ -394,6 +400,17 @@ TreeIterator::GetPreviousEntry(void *key, uint16 *keyLength, uint16 maxLength,
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
inline bool
|
||||
bplustree_header::CheckNode(bplustree_node *node)
|
||||
{
|
||||
// sanity checks (links, all_key_count)
|
||||
return IsValidLink(node->LeftLink())
|
||||
&& IsValidLink(node->RightLink())
|
||||
&& IsValidLink(node->OverflowLink())
|
||||
&& (int8 *)node->Values() + node->NumKeys() * sizeof(off_t) <= (int8 *)node + NodeSize();
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
bplustree_header::IsValidLink(off_t link)
|
||||
{
|
||||
|
@ -1,8 +1,8 @@
|
||||
/* BlockAllocator - block bitmap handling and allocation policies
|
||||
**
|
||||
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
*
|
||||
* Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "Debug.h"
|
||||
@ -62,12 +62,16 @@ class AllocationBlock : public CachedBlock {
|
||||
inline bool IsUsed(uint16 block);
|
||||
|
||||
status_t SetTo(AllocationGroup &group, uint16 block);
|
||||
status_t SetToWritable(Transaction &transaction, AllocationGroup &group, uint16 block);
|
||||
|
||||
uint32 NumBlockBits() const { return fNumBits; }
|
||||
uint32 &Block(int32 index) { return ((uint32 *)fBlock)[index]; }
|
||||
|
||||
private:
|
||||
uint32 fNumBits;
|
||||
uint32 fNumBits;
|
||||
#ifdef DEBUG
|
||||
bool fWritable;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@ -78,8 +82,8 @@ class AllocationGroup {
|
||||
void AddFreeRange(int32 start, int32 blocks);
|
||||
bool IsFull() const { return fFreeBits == 0; }
|
||||
|
||||
status_t Allocate(Transaction *transaction, uint16 start, int32 length);
|
||||
status_t Free(Transaction *transaction, uint16 start, int32 length);
|
||||
status_t Allocate(Transaction &transaction, uint16 start, int32 length);
|
||||
status_t Free(Transaction &transaction, uint16 start, int32 length);
|
||||
|
||||
uint32 fNumBits;
|
||||
int32 fStart;
|
||||
@ -104,10 +108,29 @@ AllocationBlock::SetTo(AllocationGroup &group, uint16 block)
|
||||
if ((block + 1) * fNumBits > group.fNumBits)
|
||||
fNumBits = group.fNumBits % fNumBits;
|
||||
|
||||
#ifdef DEBUG
|
||||
fWritable = false;
|
||||
#endif
|
||||
return CachedBlock::SetTo(group.fStart + block) != NULL ? B_OK : B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AllocationBlock::SetToWritable(Transaction &transaction, AllocationGroup &group, uint16 block)
|
||||
{
|
||||
// 8 blocks per byte
|
||||
fNumBits = fVolume->BlockSize() << 3;
|
||||
// the last group may have less bits in the last block
|
||||
if ((block + 1) * fNumBits > group.fNumBits)
|
||||
fNumBits = group.fNumBits % fNumBits;
|
||||
|
||||
#ifdef DEBUG
|
||||
fWritable = true;
|
||||
#endif
|
||||
return CachedBlock::SetToWritable(transaction, group.fStart + block) != NULL ? B_OK : B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AllocationBlock::IsUsed(uint16 block)
|
||||
{
|
||||
@ -123,6 +146,9 @@ AllocationBlock::Allocate(uint16 start, uint16 numBlocks)
|
||||
{
|
||||
ASSERT(start < fNumBits);
|
||||
ASSERT(uint32(start + numBlocks) <= fNumBits);
|
||||
#ifdef DEBUG
|
||||
ASSERT(fWritable);
|
||||
#endif
|
||||
|
||||
if (uint32(start + numBlocks) > fNumBits) {
|
||||
FATAL(("Allocation::Allocate(): tried to allocate too many blocks: %u (numBlocks = %lu)!\n", numBlocks, fNumBits));
|
||||
@ -154,6 +180,9 @@ AllocationBlock::Free(uint16 start, uint16 numBlocks)
|
||||
{
|
||||
ASSERT(start < fNumBits);
|
||||
ASSERT(uint32(start + numBlocks) <= fNumBits);
|
||||
#ifdef DEBUG
|
||||
ASSERT(fWritable);
|
||||
#endif
|
||||
|
||||
if (uint32(start + numBlocks) > fNumBits) {
|
||||
FATAL(("Allocation::Free(): tried to free too many blocks: %u (numBlocks = %lu)!\n", numBlocks, fNumBits));
|
||||
@ -214,7 +243,7 @@ AllocationGroup::AddFreeRange(int32 start, int32 blocks)
|
||||
*/
|
||||
|
||||
status_t
|
||||
AllocationGroup::Allocate(Transaction *transaction, uint16 start, int32 length)
|
||||
AllocationGroup::Allocate(Transaction &transaction, uint16 start, int32 length)
|
||||
{
|
||||
if (start > fNumBits)
|
||||
return B_ERROR;
|
||||
@ -226,7 +255,7 @@ AllocationGroup::Allocate(Transaction *transaction, uint16 start, int32 length)
|
||||
fFirstFree = start + length;
|
||||
fFreeBits -= length;
|
||||
|
||||
Volume *volume = transaction->GetVolume();
|
||||
Volume *volume = transaction.GetVolume();
|
||||
|
||||
// calculate block in the block bitmap and position within
|
||||
uint32 bitsPerBlock = volume->BlockSize() << 3;
|
||||
@ -236,7 +265,7 @@ AllocationGroup::Allocate(Transaction *transaction, uint16 start, int32 length)
|
||||
AllocationBlock cached(volume);
|
||||
|
||||
while (length > 0) {
|
||||
if (cached.SetTo(*this, block) < B_OK)
|
||||
if (cached.SetToWritable(transaction, *this, block) < B_OK)
|
||||
RETURN_ERROR(B_IO_ERROR);
|
||||
|
||||
uint32 numBlocks = length;
|
||||
@ -245,9 +274,6 @@ AllocationGroup::Allocate(Transaction *transaction, uint16 start, int32 length)
|
||||
|
||||
cached.Allocate(start, numBlocks);
|
||||
|
||||
if (cached.WriteBack(transaction) < B_OK)
|
||||
return B_IO_ERROR;
|
||||
|
||||
length -= numBlocks;
|
||||
start = 0;
|
||||
block++;
|
||||
@ -267,7 +293,7 @@ AllocationGroup::Allocate(Transaction *transaction, uint16 start, int32 length)
|
||||
*/
|
||||
|
||||
status_t
|
||||
AllocationGroup::Free(Transaction *transaction, uint16 start, int32 length)
|
||||
AllocationGroup::Free(Transaction &transaction, uint16 start, int32 length)
|
||||
{
|
||||
if (start > fNumBits)
|
||||
return B_ERROR;
|
||||
@ -278,7 +304,7 @@ AllocationGroup::Free(Transaction *transaction, uint16 start, int32 length)
|
||||
fFirstFree = start;
|
||||
fFreeBits += length;
|
||||
|
||||
Volume *volume = transaction->GetVolume();
|
||||
Volume *volume = transaction.GetVolume();
|
||||
|
||||
// calculate block in the block bitmap and position within
|
||||
uint32 bitsPerBlock = volume->BlockSize() << 3;
|
||||
@ -288,7 +314,7 @@ AllocationGroup::Free(Transaction *transaction, uint16 start, int32 length)
|
||||
AllocationBlock cached(volume);
|
||||
|
||||
while (length > 0) {
|
||||
if (cached.SetTo(*this, block) < B_OK)
|
||||
if (cached.SetToWritable(transaction, *this, block) < B_OK)
|
||||
RETURN_ERROR(B_IO_ERROR);
|
||||
|
||||
uint16 freeLength = length;
|
||||
@ -297,9 +323,6 @@ AllocationGroup::Free(Transaction *transaction, uint16 start, int32 length)
|
||||
|
||||
cached.Free(start, freeLength);
|
||||
|
||||
if (cached.WriteBack(transaction) < B_OK)
|
||||
return B_IO_ERROR;
|
||||
|
||||
length -= freeLength;
|
||||
start = 0;
|
||||
block++;
|
||||
@ -363,6 +386,7 @@ BlockAllocator::InitializeAndClearBitmap(Transaction &transaction)
|
||||
|
||||
uint32 blocks = fBlocksPerGroup;
|
||||
uint32 numBits = 8 * blocks * fVolume->BlockSize();
|
||||
uint32 blockShift = fVolume->BlockShift();
|
||||
|
||||
uint32 *buffer = (uint32 *)malloc(numBits >> 3);
|
||||
if (buffer == NULL)
|
||||
@ -375,7 +399,7 @@ BlockAllocator::InitializeAndClearBitmap(Transaction &transaction)
|
||||
// initialize the AllocationGroup objects and clear the on-disk bitmap
|
||||
|
||||
for (int32 i = 0; i < fNumGroups; i++) {
|
||||
if (cached_write(fVolume->Device(), offset, buffer, blocks, fVolume->BlockSize()) < B_OK)
|
||||
if (write_pos(fVolume->Device(), offset << blockShift, buffer, blocks << blockShift) < B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
// the last allocation group may contain less blocks than the others
|
||||
@ -391,7 +415,7 @@ BlockAllocator::InitializeAndClearBitmap(Transaction &transaction)
|
||||
// reserve the boot block, the log area, and the block bitmap itself
|
||||
uint32 reservedBlocks = fVolume->Log().Start() + fVolume->Log().Length();
|
||||
|
||||
if (fGroups[0].Allocate(&transaction, 0, reservedBlocks) < B_OK) {
|
||||
if (fGroups[0].Allocate(transaction, 0, reservedBlocks) < B_OK) {
|
||||
FATAL(("could not allocate reserved space for block bitmap/log!\n"));
|
||||
return B_ERROR;
|
||||
}
|
||||
@ -409,6 +433,7 @@ BlockAllocator::initialize(BlockAllocator *allocator)
|
||||
Volume *volume = allocator->fVolume;
|
||||
uint32 blocks = allocator->fBlocksPerGroup;
|
||||
uint32 numBits = 8 * blocks * volume->BlockSize();
|
||||
uint32 blockShift = volume->BlockShift();
|
||||
off_t freeBlocks = 0;
|
||||
|
||||
uint32 *buffer = (uint32 *)malloc(numBits >> 3);
|
||||
@ -421,8 +446,8 @@ BlockAllocator::initialize(BlockAllocator *allocator)
|
||||
off_t offset = 1;
|
||||
int32 num = allocator->fNumGroups;
|
||||
|
||||
for (int32 i = 0;i < num;i++) {
|
||||
if (cached_read(volume->Device(), offset, buffer, blocks, volume->BlockSize()) < B_OK)
|
||||
for (int32 i = 0; i < num; i++) {
|
||||
if (read_pos(volume->Device(), offset << blockShift, buffer, blocks << blockShift) < B_OK)
|
||||
break;
|
||||
|
||||
// the last allocation group may contain less blocks than the others
|
||||
@ -457,7 +482,7 @@ BlockAllocator::initialize(BlockAllocator *allocator)
|
||||
uint32 reservedBlocks = volume->Log().Start() + volume->Log().Length();
|
||||
if (allocator->CheckBlockRun(block_run::Run(0, 0, reservedBlocks)) < B_OK) {
|
||||
Transaction transaction(volume, 0);
|
||||
if (groups[0].Allocate(&transaction, 0, reservedBlocks) < B_OK) {
|
||||
if (groups[0].Allocate(transaction, 0, reservedBlocks) < B_OK) {
|
||||
FATAL(("could not allocate reserved space for block bitmap/log!\n"));
|
||||
volume->Panic();
|
||||
} else {
|
||||
@ -481,7 +506,7 @@ BlockAllocator::initialize(BlockAllocator *allocator)
|
||||
|
||||
|
||||
status_t
|
||||
BlockAllocator::AllocateBlocks(Transaction *transaction, int32 group, uint16 start,
|
||||
BlockAllocator::AllocateBlocks(Transaction &transaction, int32 group, uint16 start,
|
||||
uint16 maximum, uint16 minimum, block_run &run)
|
||||
{
|
||||
if (maximum == 0)
|
||||
@ -586,7 +611,7 @@ BlockAllocator::AllocateBlocks(Transaction *transaction, int32 group, uint16 sta
|
||||
|
||||
|
||||
status_t
|
||||
BlockAllocator::AllocateForInode(Transaction *transaction, const block_run *parent,
|
||||
BlockAllocator::AllocateForInode(Transaction &transaction, const block_run *parent,
|
||||
mode_t type, block_run &run)
|
||||
{
|
||||
// apply some allocation policies here (AllocateBlocks() will break them
|
||||
@ -604,7 +629,7 @@ BlockAllocator::AllocateForInode(Transaction *transaction, const block_run *pare
|
||||
|
||||
|
||||
status_t
|
||||
BlockAllocator::Allocate(Transaction *transaction, const Inode *inode, off_t numBlocks,
|
||||
BlockAllocator::Allocate(Transaction &transaction, Inode *inode, off_t numBlocks,
|
||||
block_run &run, uint16 minimum)
|
||||
{
|
||||
if (numBlocks <= 0)
|
||||
@ -633,19 +658,19 @@ BlockAllocator::Allocate(Transaction *transaction, const Inode *inode, off_t num
|
||||
|
||||
// are there already allocated blocks? (then just try to allocate near the last one)
|
||||
if (inode->Size() > 0) {
|
||||
data_stream *data = &inode->Node()->data;
|
||||
const data_stream &data = inode->Node().data;
|
||||
// ToDo: we currently don't care for when the data stream
|
||||
// is already grown into the indirect ranges
|
||||
if (data->max_double_indirect_range == 0
|
||||
&& data->max_indirect_range == 0) {
|
||||
if (data.max_double_indirect_range == 0
|
||||
&& data.max_indirect_range == 0) {
|
||||
// Since size > 0, there must be a valid block run in this stream
|
||||
int32 last = 0;
|
||||
for (; last < NUM_DIRECT_BLOCKS - 1; last++)
|
||||
if (data->direct[last + 1].IsZero())
|
||||
if (data.direct[last + 1].IsZero())
|
||||
break;
|
||||
|
||||
group = data->direct[last].AllocationGroup();
|
||||
start = data->direct[last].Start() + data->direct[last].Length();
|
||||
group = data.direct[last].AllocationGroup();
|
||||
start = data.direct[last].Start() + data.direct[last].Length();
|
||||
}
|
||||
} else if (inode->IsContainer() || inode->IsSymLink()) {
|
||||
// directory and symbolic link data will go in the same allocation
|
||||
@ -661,7 +686,7 @@ BlockAllocator::Allocate(Transaction *transaction, const Inode *inode, off_t num
|
||||
|
||||
|
||||
status_t
|
||||
BlockAllocator::Free(Transaction *transaction, block_run run)
|
||||
BlockAllocator::Free(Transaction &transaction, block_run run)
|
||||
{
|
||||
Locker lock(fLock);
|
||||
|
||||
@ -955,8 +980,9 @@ BlockAllocator::CheckNextNode(check_control *control)
|
||||
// check if the inode's name is the same as in the b+tree
|
||||
if (inode->IsRegularNode()) {
|
||||
SimpleLocker locker(inode->SmallDataLock());
|
||||
NodeGetter node(fVolume, inode);
|
||||
|
||||
const char *localName = inode->Name();
|
||||
const char *localName = inode->Name(node.Node());
|
||||
if (localName == NULL || strcmp(localName, name)) {
|
||||
control->errors |= BFS_NAMES_DONT_MATCH;
|
||||
FATAL(("Names differ: tree \"%s\", inode \"%s\"\n", name, localName));
|
||||
@ -986,8 +1012,8 @@ BlockAllocator::CheckNextNode(check_control *control)
|
||||
// the bitmap anyway
|
||||
Transaction transaction(fVolume, cookie->parent->BlockNumber());
|
||||
|
||||
inode->Node()->flags |= INODE_DONT_FREE_SPACE;
|
||||
status = cookie->parent->Remove(&transaction, name, NULL, inode->IsContainer());
|
||||
inode->Node().flags |= HOST_ENDIAN_TO_BFS_INT32(INODE_DONT_FREE_SPACE);
|
||||
status = cookie->parent->Remove(transaction, name, NULL, inode->IsContainer());
|
||||
if (status == B_OK)
|
||||
transaction.Done();
|
||||
} else
|
||||
@ -1140,7 +1166,7 @@ BlockAllocator::CheckInode(Inode *inode, check_control *control)
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
data_stream *data = &inode->Node()->data;
|
||||
data_stream *data = &inode->Node().data;
|
||||
|
||||
// check the direct range
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
/* BlockAllocator - block bitmap handling and allocation policies
|
||||
*
|
||||
* Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef BLOCK_ALLOCATOR_H
|
||||
#define BLOCK_ALLOCATOR_H
|
||||
/* BlockAllocator - block bitmap handling and allocation policies
|
||||
**
|
||||
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include "Lock.h"
|
||||
@ -28,13 +28,13 @@ class BlockAllocator {
|
||||
status_t Initialize(bool full = true);
|
||||
status_t InitializeAndClearBitmap(Transaction &transaction);
|
||||
|
||||
status_t AllocateForInode(Transaction *transaction, const block_run *parent,
|
||||
status_t AllocateForInode(Transaction &transaction, const block_run *parent,
|
||||
mode_t type, block_run &run);
|
||||
status_t Allocate(Transaction *transaction, const Inode *inode, off_t numBlocks,
|
||||
status_t Allocate(Transaction &transaction, Inode *inode, off_t numBlocks,
|
||||
block_run &run, uint16 minimum = 1);
|
||||
status_t Free(Transaction *transaction, block_run run);
|
||||
status_t Free(Transaction &transaction, block_run run);
|
||||
|
||||
status_t AllocateBlocks(Transaction *transaction, int32 group, uint16 start,
|
||||
status_t AllocateBlocks(Transaction &transaction, int32 group, uint16 start,
|
||||
uint16 numBlocks, uint16 minimum, block_run &run);
|
||||
|
||||
status_t StartChecking(check_control *control);
|
||||
|
@ -1,162 +0,0 @@
|
||||
/* BufferPool - a buffer pool for uncached file access
|
||||
**
|
||||
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include "BufferPool.h"
|
||||
#include "Debug.h"
|
||||
|
||||
#include <util/kernel_cpp.h>
|
||||
|
||||
|
||||
const uint32 kNumBuffers = 8;
|
||||
|
||||
|
||||
BufferPool::BufferPool()
|
||||
:
|
||||
fFirstFree(NULL)
|
||||
{
|
||||
fLock = create_sem(1, "buffer lock");
|
||||
fFreeBuffers = create_sem(0, "free buffers");
|
||||
|
||||
#ifndef USER
|
||||
set_sem_owner(fLock, B_SYSTEM_TEAM);
|
||||
set_sem_owner(fFreeBuffers, B_SYSTEM_TEAM);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
BufferPool::~BufferPool()
|
||||
{
|
||||
delete_sem(fFreeBuffers);
|
||||
|
||||
acquire_sem(fLock);
|
||||
// the return value doesn't interest us anymore
|
||||
|
||||
void **buffer = fFirstFree;
|
||||
while (buffer != NULL) {
|
||||
void **nextBuffer = (void **)*buffer;
|
||||
free(buffer);
|
||||
buffer = nextBuffer;
|
||||
}
|
||||
|
||||
delete_sem(fLock);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BufferPool::InitCheck()
|
||||
{
|
||||
if (fLock < B_OK
|
||||
|| fFreeBuffers < B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BufferPool::RequestBuffers(uint32 blockSize)
|
||||
{
|
||||
void **buffers[kNumBuffers];
|
||||
|
||||
// allocate and connect buffers
|
||||
|
||||
for (uint32 i = 0; i < kNumBuffers; i++) {
|
||||
buffers[i] = (void **)malloc(blockSize);
|
||||
if (buffers[i] == NULL) {
|
||||
// free already allocated buffers
|
||||
for (;i-- > 0; i++)
|
||||
free(buffers[i]);
|
||||
RETURN_ERROR(B_NO_MEMORY);
|
||||
}
|
||||
if (i > 0)
|
||||
*(buffers[i]) = buffers[i - 1];
|
||||
}
|
||||
|
||||
// add the buffers to the free buffers queue
|
||||
|
||||
status_t status = acquire_sem(fLock);
|
||||
if (status == B_OK) {
|
||||
*(buffers[0]) = fFirstFree;
|
||||
fFirstFree = buffers[kNumBuffers - 1];
|
||||
release_sem(fLock);
|
||||
release_sem_etc(fFreeBuffers, kNumBuffers, B_DO_NOT_RESCHEDULE);
|
||||
} else {
|
||||
for (uint32 i = 0; i < kNumBuffers; i++)
|
||||
free(buffers[i]);
|
||||
}
|
||||
|
||||
RETURN_ERROR(status);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BufferPool::ReleaseBuffers()
|
||||
{
|
||||
status_t status = acquire_sem_etc(fFreeBuffers, kNumBuffers, 0, 0);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
status = acquire_sem(fLock);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
void **buffer = fFirstFree;
|
||||
for (uint32 i = 0; i < kNumBuffers && buffer; i++) {
|
||||
void **nextBuffer = (void **)*buffer;
|
||||
|
||||
free(buffer);
|
||||
buffer = nextBuffer;
|
||||
}
|
||||
fFirstFree = buffer;
|
||||
|
||||
release_sem(fLock);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BufferPool::GetBuffer(void **_buffer)
|
||||
{
|
||||
status_t status = acquire_sem(fFreeBuffers);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
if ((status = acquire_sem(fLock)) < B_OK) {
|
||||
release_sem(fFreeBuffers);
|
||||
return status;
|
||||
}
|
||||
|
||||
void **buffer = fFirstFree;
|
||||
fFirstFree = (void **)*buffer;
|
||||
|
||||
release_sem(fLock);
|
||||
|
||||
*_buffer = (void *)buffer;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BufferPool::PutBuffer(void *_buffer)
|
||||
{
|
||||
void **buffer = (void **)_buffer;
|
||||
if (buffer == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
status_t status = acquire_sem(fLock);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
*buffer = fFirstFree;
|
||||
fFirstFree = buffer;
|
||||
|
||||
release_sem(fLock);
|
||||
release_sem(fFreeBuffers);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -1,31 +0,0 @@
|
||||
#ifndef BUFFER_POOL_H
|
||||
#define BUFFER_POOL_H
|
||||
/* BufferPool - a buffer pool for uncached file access
|
||||
**
|
||||
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
|
||||
class BufferPool {
|
||||
public:
|
||||
BufferPool();
|
||||
~BufferPool();
|
||||
|
||||
status_t InitCheck();
|
||||
|
||||
status_t RequestBuffers(uint32 blockSize);
|
||||
status_t ReleaseBuffers();
|
||||
|
||||
status_t GetBuffer(void **_buffer);
|
||||
status_t PutBuffer(void *buffer);
|
||||
|
||||
private:
|
||||
sem_id fLock, fFreeBuffers;
|
||||
void **fFirstFree;
|
||||
};
|
||||
|
||||
#endif /* BUFFER_POOL_H */
|
194
src/add-ons/kernel/file_systems/bfs/CachedBlock.h
Normal file
194
src/add-ons/kernel/file_systems/bfs/CachedBlock.h
Normal file
@ -0,0 +1,194 @@
|
||||
/* CachedBlock - interface for the block cache
|
||||
*
|
||||
* Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef CACHED_BLOCK_H
|
||||
#define CACHED_BLOCK_H
|
||||
|
||||
|
||||
#include <KernelExport.h>
|
||||
#ifdef USER
|
||||
# include "myfs.h"
|
||||
# include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "Volume.h"
|
||||
#include "Journal.h"
|
||||
#include "Lock.h"
|
||||
#include "Chain.h"
|
||||
#include "Debug.h"
|
||||
|
||||
|
||||
// The CachedBlock class is completely implemented as inlines.
|
||||
// It should be used when cache single blocks to make sure they
|
||||
// will be properly released after use (and it's also very
|
||||
// convenient to use them).
|
||||
|
||||
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, off_t block, off_t base, size_t length, bool empty = false);
|
||||
inline uint8 *SetToWritable(Transaction &transaction, off_t block, bool empty = false);
|
||||
inline uint8 *SetToWritable(Transaction &transaction, block_run run, bool empty = false);
|
||||
inline status_t MakeWritable(Transaction &transaction);
|
||||
|
||||
const uint8 *Block() const { return fBlock; }
|
||||
off_t BlockNumber() const { return fBlockNumber; }
|
||||
uint32 BlockSize() const { return fVolume->BlockSize(); }
|
||||
uint32 BlockShift() const { return fVolume->BlockShift(); }
|
||||
|
||||
private:
|
||||
CachedBlock(const CachedBlock &);
|
||||
CachedBlock &operator=(const CachedBlock &);
|
||||
// no implementation
|
||||
|
||||
protected:
|
||||
Volume *fVolume;
|
||||
off_t fBlockNumber;
|
||||
uint8 *fBlock;
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
// inlines
|
||||
|
||||
|
||||
inline
|
||||
CachedBlock::CachedBlock(Volume *volume)
|
||||
:
|
||||
fVolume(volume),
|
||||
fBlock(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
CachedBlock::CachedBlock(Volume *volume, off_t block)
|
||||
:
|
||||
fVolume(volume),
|
||||
fBlock(NULL)
|
||||
{
|
||||
SetTo(block);
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
CachedBlock::CachedBlock(Volume *volume, block_run run)
|
||||
:
|
||||
fVolume(volume),
|
||||
fBlock(NULL)
|
||||
{
|
||||
SetTo(volume->ToBlock(run));
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
CachedBlock::CachedBlock(CachedBlock *cached)
|
||||
:
|
||||
fVolume(cached->fVolume),
|
||||
fBlockNumber(cached->BlockNumber()),
|
||||
fBlock(cached->fBlock)
|
||||
{
|
||||
cached->Keep();
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
CachedBlock::~CachedBlock()
|
||||
{
|
||||
Unset();
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
CachedBlock::Keep()
|
||||
{
|
||||
fBlock = NULL;
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
CachedBlock::Unset()
|
||||
{
|
||||
if (fBlock != NULL)
|
||||
block_cache_put(fVolume->BlockCache(), fBlockNumber);
|
||||
}
|
||||
|
||||
|
||||
inline const uint8 *
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
inline const uint8 *
|
||||
CachedBlock::SetTo(off_t block)
|
||||
{
|
||||
return SetTo(block, block, 1);
|
||||
}
|
||||
|
||||
|
||||
inline const uint8 *
|
||||
CachedBlock::SetTo(block_run run)
|
||||
{
|
||||
return SetTo(fVolume->ToBlock(run));
|
||||
}
|
||||
|
||||
|
||||
inline uint8 *
|
||||
CachedBlock::SetToWritable(Transaction &transaction, off_t block, off_t base, size_t length, bool empty)
|
||||
{
|
||||
Unset();
|
||||
fBlockNumber = block;
|
||||
|
||||
if (empty)
|
||||
return fBlock = (uint8 *)block_cache_get_empty(fVolume->BlockCache(), block, transaction.ID());
|
||||
|
||||
return fBlock = (uint8 *)block_cache_get_writable_etc(fVolume->BlockCache(),
|
||||
block, base, length, transaction.ID());
|
||||
}
|
||||
|
||||
|
||||
inline uint8 *
|
||||
CachedBlock::SetToWritable(Transaction &transaction, off_t block, bool empty)
|
||||
{
|
||||
return SetToWritable(transaction, block, block, 1, empty);
|
||||
}
|
||||
|
||||
|
||||
inline uint8 *
|
||||
CachedBlock::SetToWritable(Transaction &transaction, block_run run, bool empty)
|
||||
{
|
||||
return SetToWritable(transaction, fVolume->ToBlock(run), empty);
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
CachedBlock::MakeWritable(Transaction &transaction)
|
||||
{
|
||||
if (fBlock == NULL)
|
||||
return B_NO_INIT;
|
||||
|
||||
return block_cache_make_writable(fVolume->BlockCache(), fBlockNumber, transaction.ID());
|
||||
}
|
||||
|
||||
|
||||
#endif /* CACHED_BLOCK_H */
|
@ -1,10 +1,10 @@
|
||||
/* Debug - debug stuff
|
||||
**
|
||||
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||
** Some code is based on work previously done by Marcus Overhagen
|
||||
**
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
*
|
||||
* Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Some code is based on work previously done by Marcus Overhagen.
|
||||
*
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "Debug.h"
|
||||
@ -44,13 +44,12 @@ dump_block_run(const char *prefix, block_run &run)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
void
|
||||
dump_inode(Inode &inode)
|
||||
{
|
||||
Print("Inode (%p) {\n", &inode);
|
||||
Print("\tfVolume = %p\n", inode.fVolume);
|
||||
Print("\tfBlockNumber = 0x%16Lx\n", inode.fBlockNumber);
|
||||
Print("\tfNode = %p\n", inode.Node());
|
||||
Print("\tfBlockNumber = 0x%16Lx\n", inode.BlockNumber());
|
||||
Print("\tfTree = %p\n", inode.fTree);
|
||||
Print("\tfAttributes = %p\n", inode.fAttributes);
|
||||
Print("\tfOldSize = 0x%16Lx\n", inode.fOldSize);
|
||||
@ -261,13 +260,12 @@ dump_bplustree_node(bplustree_node *node,bplustree_header *header,Volume *volume
|
||||
|
||||
|
||||
#ifndef USER
|
||||
//#warn Don't mount more than once... would register twice the debugger commands!
|
||||
|
||||
static int
|
||||
dbg_inode(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) {
|
||||
kprintf("usage: obfsinode ptr-to-inode\n");
|
||||
kprintf("usage: bfsinode ptr-to-inode\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -283,7 +281,7 @@ void
|
||||
remove_debugger_commands()
|
||||
{
|
||||
#ifndef USER
|
||||
remove_debugger_command("obfsinode", dbg_inode);
|
||||
remove_debugger_command("bfsinode", dbg_inode);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -292,7 +290,7 @@ void
|
||||
add_debugger_commands()
|
||||
{
|
||||
#ifndef USER
|
||||
add_debugger_command("obfsinode", dbg_inode, "dump an Inode object");
|
||||
add_debugger_command("bfsinode", dbg_inode, "dump an Inode object");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
/* Debug - debug stuff
|
||||
*
|
||||
* Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef DEBUG_H
|
||||
#define DEBUG_H
|
||||
/* Debug - debug stuff
|
||||
**
|
||||
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include <KernelExport.h>
|
||||
@ -71,7 +71,7 @@
|
||||
#define PRINT(x) ;
|
||||
#define REPORT_ERROR(status) ;
|
||||
#define RETURN_ERROR(status) return status;
|
||||
#define FATAL(x) { __out("bfs: "); __out x; }
|
||||
#define FATAL(x) { __out("bfs: "); __out x; panic("BFS!\n"); }
|
||||
#define INFORM(x) { __out("bfs: "); __out x; }
|
||||
#define FUNCTION() ;
|
||||
#define FUNCTION_START(x) ;
|
||||
|
@ -1,8 +1,8 @@
|
||||
/* Index - index access functions
|
||||
**
|
||||
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
*
|
||||
* Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "Debug.h"
|
||||
@ -57,7 +57,7 @@ Index::Unset()
|
||||
* the updated attribute.
|
||||
*/
|
||||
|
||||
status_t
|
||||
status_t
|
||||
Index::SetTo(const char *name)
|
||||
{
|
||||
// remove the old node, if the index is set for the second time
|
||||
@ -102,7 +102,7 @@ Index::SetTo(const char *name)
|
||||
* corrupted somehow or not that of an index).
|
||||
*/
|
||||
|
||||
uint32
|
||||
uint32
|
||||
Index::Type()
|
||||
{
|
||||
if (fNode == NULL)
|
||||
@ -161,7 +161,7 @@ Index::KeySize()
|
||||
|
||||
|
||||
status_t
|
||||
Index::Create(Transaction *transaction, const char *name, uint32 type)
|
||||
Index::Create(Transaction &transaction, const char *name, uint32 type)
|
||||
{
|
||||
Unset();
|
||||
|
||||
@ -217,7 +217,7 @@ Index::Create(Transaction *transaction, const char *name, uint32 type)
|
||||
*/
|
||||
|
||||
status_t
|
||||
Index::Update(Transaction *transaction, const char *name, int32 type, const uint8 *oldKey,
|
||||
Index::Update(Transaction &transaction, const char *name, int32 type, const uint8 *oldKey,
|
||||
uint16 oldLength, const uint8 *newKey, uint16 newLength, Inode *inode)
|
||||
{
|
||||
if (name == NULL
|
||||
@ -277,22 +277,22 @@ Index::Update(Transaction *transaction, const char *name, int32 type, const uint
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Index::InsertName(Transaction *transaction, const char *name, Inode *inode)
|
||||
status_t
|
||||
Index::InsertName(Transaction &transaction, const char *name, Inode *inode)
|
||||
{
|
||||
return UpdateName(transaction, NULL, name, inode);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Index::RemoveName(Transaction *transaction, const char *name, Inode *inode)
|
||||
status_t
|
||||
Index::RemoveName(Transaction &transaction, const char *name, Inode *inode)
|
||||
{
|
||||
return UpdateName(transaction, name, NULL, inode);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Index::UpdateName(Transaction *transaction, const char *oldName, const char *newName, Inode *inode)
|
||||
status_t
|
||||
Index::UpdateName(Transaction &transaction, const char *oldName, const char *newName, Inode *inode)
|
||||
{
|
||||
uint16 oldLength = oldName ? strlen(oldName) : 0;
|
||||
uint16 newLength = newName ? strlen(newName) : 0;
|
||||
@ -301,16 +301,16 @@ Index::UpdateName(Transaction *transaction, const char *oldName, const char *new
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Index::InsertSize(Transaction *transaction, Inode *inode)
|
||||
status_t
|
||||
Index::InsertSize(Transaction &transaction, Inode *inode)
|
||||
{
|
||||
off_t size = inode->Size();
|
||||
return Update(transaction, "size", B_INT64_TYPE, NULL, 0, (uint8 *)&size, sizeof(int64), inode);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Index::RemoveSize(Transaction *transaction, Inode *inode)
|
||||
status_t
|
||||
Index::RemoveSize(Transaction &transaction, Inode *inode)
|
||||
{
|
||||
// Inode::OldSize() is the size that's in the index
|
||||
off_t size = inode->OldSize();
|
||||
@ -319,7 +319,7 @@ Index::RemoveSize(Transaction *transaction, Inode *inode)
|
||||
|
||||
|
||||
status_t
|
||||
Index::UpdateSize(Transaction *transaction, Inode *inode)
|
||||
Index::UpdateSize(Transaction &transaction, Inode *inode)
|
||||
{
|
||||
off_t oldSize = inode->OldSize();
|
||||
off_t newSize = inode->Size();
|
||||
@ -333,8 +333,8 @@ Index::UpdateSize(Transaction *transaction, Inode *inode)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Index::InsertLastModified(Transaction *transaction, Inode *inode)
|
||||
status_t
|
||||
Index::InsertLastModified(Transaction &transaction, Inode *inode)
|
||||
{
|
||||
off_t modified = inode->LastModified();
|
||||
return Update(transaction, "last_modified", B_INT64_TYPE, NULL, 0,
|
||||
@ -342,8 +342,8 @@ Index::InsertLastModified(Transaction *transaction, Inode *inode)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Index::RemoveLastModified(Transaction *transaction, Inode *inode)
|
||||
status_t
|
||||
Index::RemoveLastModified(Transaction &transaction, Inode *inode)
|
||||
{
|
||||
// Inode::OldLastModified() is the value which is in the index
|
||||
off_t modified = inode->OldLastModified();
|
||||
@ -352,8 +352,8 @@ Index::RemoveLastModified(Transaction *transaction, Inode *inode)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Index::UpdateLastModified(Transaction *transaction, Inode *inode, off_t modified)
|
||||
status_t
|
||||
Index::UpdateLastModified(Transaction &transaction, Inode *inode, off_t modified)
|
||||
{
|
||||
off_t oldModified = inode->OldLastModified();
|
||||
if (modified == -1)
|
||||
@ -363,7 +363,7 @@ Index::UpdateLastModified(Transaction *transaction, Inode *inode, off_t modified
|
||||
status_t status = Update(transaction, "last_modified", B_INT64_TYPE, (uint8 *)&oldModified,
|
||||
sizeof(int64), (uint8 *)&modified, sizeof(int64), inode);
|
||||
|
||||
inode->Node()->last_modified_time = modified;
|
||||
inode->Node().last_modified_time = HOST_ENDIAN_TO_BFS_INT64(modified);
|
||||
if (status == B_OK)
|
||||
inode->UpdateOldLastModified();
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
/* Index - index access functions
|
||||
*
|
||||
* Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef INDEX_H
|
||||
#define INDEX_H
|
||||
/* Index - index access functions
|
||||
**
|
||||
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include <KernelExport.h>
|
||||
@ -26,21 +26,23 @@ class Index {
|
||||
uint32 Type();
|
||||
size_t KeySize();
|
||||
|
||||
status_t Create(Transaction *transaction, const char *name, uint32 type);
|
||||
status_t Create(Transaction &transaction, const char *name, uint32 type);
|
||||
|
||||
status_t Update(Transaction *transaction, const char *name, int32 type, const uint8 *oldKey, uint16 oldLength, const uint8 *newKey, uint16 newLength, Inode *inode);
|
||||
status_t Update(Transaction &transaction, const char *name, int32 type, const uint8 *oldKey,
|
||||
uint16 oldLength, const uint8 *newKey, uint16 newLength, Inode *inode);
|
||||
|
||||
status_t InsertName(Transaction *transaction,const char *name,Inode *inode);
|
||||
status_t RemoveName(Transaction *transaction,const char *name,Inode *inode);
|
||||
status_t UpdateName(Transaction *transaction,const char *oldName,const char *newName,Inode *inode);
|
||||
status_t InsertName(Transaction &transaction, const char *name, Inode *inode);
|
||||
status_t RemoveName(Transaction &transaction, const char *name, Inode *inode);
|
||||
status_t UpdateName(Transaction &transaction, const char *oldName, const char *newName,
|
||||
Inode *inode);
|
||||
|
||||
status_t InsertSize(Transaction *transaction, Inode *inode);
|
||||
status_t RemoveSize(Transaction *transaction, Inode *inode);
|
||||
status_t UpdateSize(Transaction *transaction, Inode *inode);
|
||||
status_t InsertSize(Transaction &transaction, Inode *inode);
|
||||
status_t RemoveSize(Transaction &transaction, Inode *inode);
|
||||
status_t UpdateSize(Transaction &transaction, Inode *inode);
|
||||
|
||||
status_t InsertLastModified(Transaction *transaction, Inode *inode);
|
||||
status_t RemoveLastModified(Transaction *transaction, Inode *inode);
|
||||
status_t UpdateLastModified(Transaction *transaction, Inode *inode,off_t modified = -1);
|
||||
status_t InsertLastModified(Transaction &transaction, Inode *inode);
|
||||
status_t RemoveLastModified(Transaction &transaction, Inode *inode);
|
||||
status_t UpdateLastModified(Transaction &transaction, Inode *inode, off_t modified = -1);
|
||||
|
||||
private:
|
||||
Index(const Index &);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,10 +1,10 @@
|
||||
/* Inode - inode access functions
|
||||
*
|
||||
* Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef INODE_H
|
||||
#define INODE_H
|
||||
/* Inode - inode access functions
|
||||
**
|
||||
** Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include <KernelExport.h>
|
||||
@ -17,9 +17,6 @@
|
||||
# define _IMPEXP_KERNEL
|
||||
#endif
|
||||
|
||||
#include <lock.h>
|
||||
#include <cache.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
@ -28,12 +25,14 @@
|
||||
#include "Lock.h"
|
||||
#include "Chain.h"
|
||||
#include "Debug.h"
|
||||
#include "CachedBlock.h"
|
||||
|
||||
|
||||
class BPlusTree;
|
||||
class TreeIterator;
|
||||
class AttributeIterator;
|
||||
class InodeAllocator;
|
||||
class NodeGetter;
|
||||
|
||||
|
||||
enum inode_type {
|
||||
@ -46,59 +45,21 @@ enum inode_type {
|
||||
| S_ULONG_LONG_INDEX | S_FLOAT_INDEX | S_DOUBLE_INDEX)
|
||||
};
|
||||
|
||||
|
||||
// The CachedBlock class is completely implemented as inlines.
|
||||
// It should be used when cache single blocks to make sure they
|
||||
// will be properly released after use (and it's also very
|
||||
// convenient to use them).
|
||||
|
||||
class CachedBlock {
|
||||
class Inode {
|
||||
public:
|
||||
CachedBlock(Volume *volume);
|
||||
CachedBlock(Volume *volume, off_t block, bool empty = false);
|
||||
CachedBlock(Volume *volume, block_run run, bool empty = false);
|
||||
CachedBlock(CachedBlock *cached);
|
||||
~CachedBlock();
|
||||
|
||||
inline void Keep();
|
||||
inline void Unset();
|
||||
inline uint8 *SetTo(off_t block, bool empty = false);
|
||||
inline uint8 *SetTo(block_run run, bool empty = false);
|
||||
inline status_t WriteBack(Transaction *transaction);
|
||||
|
||||
uint8 *Block() const { return fBlock; }
|
||||
off_t BlockNumber() const { return fBlockNumber; }
|
||||
uint32 BlockSize() const { return fVolume->BlockSize(); }
|
||||
uint32 BlockShift() const { return fVolume->BlockShift(); }
|
||||
|
||||
private:
|
||||
CachedBlock(const CachedBlock &);
|
||||
CachedBlock &operator=(const CachedBlock &);
|
||||
// no implementation
|
||||
|
||||
protected:
|
||||
Volume *fVolume;
|
||||
off_t fBlockNumber;
|
||||
uint8 *fBlock;
|
||||
};
|
||||
|
||||
//--------------------------------------
|
||||
|
||||
class Inode : public CachedBlock {
|
||||
public:
|
||||
Inode(Volume *volume, vnode_id id, bool empty = false, uint8 reenter = 0);
|
||||
Inode(CachedBlock *cached);
|
||||
Inode(Volume *volume, vnode_id id);
|
||||
Inode(Volume *volume, Transaction &transaction, vnode_id id, mode_t mode, block_run &run);
|
||||
//Inode(CachedBlock *cached);
|
||||
~Inode();
|
||||
|
||||
bfs_inode *Node() const { return (bfs_inode *)fBlock; }
|
||||
vnode_id ID() const { return fVolume->ToVnode(fBlockNumber); }
|
||||
//bfs_inode *Node() const { return (bfs_inode *)fBlock; }
|
||||
vnode_id ID() const { return fID; }
|
||||
off_t BlockNumber() const { return fVolume->VnodeToBlock(fID); }
|
||||
|
||||
ReadWriteLock &Lock() { return fLock; }
|
||||
SimpleLock &SmallDataLock() { return fSmallDataLock; }
|
||||
status_t WriteBack(Transaction &transaction);
|
||||
|
||||
mode_t Mode() const { return Node()->Mode(); }
|
||||
uint32 Type() const { return Node()->Type(); }
|
||||
int32 Flags() const { return Node()->Flags(); }
|
||||
bool IsContainer() const { return Mode() & (S_DIRECTORY | S_INDEX_DIR | S_ATTR_DIR); }
|
||||
// note, that this test will also be true for S_IFBLK (not that it's used in the fs :)
|
||||
bool IsDirectory() const { return (Mode() & (S_DIRECTORY | S_INDEX_DIR | S_ATTR_DIR)) == S_DIRECTORY; }
|
||||
@ -113,12 +74,17 @@ class Inode : public CachedBlock {
|
||||
bool HasUserAccessableStream() const { return S_ISREG(Mode()); }
|
||||
// currently only files can be accessed with bfs_read()/bfs_write()
|
||||
|
||||
off_t Size() const { return Node()->data.Size(); }
|
||||
off_t LastModified() const { return Node()->last_modified_time; }
|
||||
mode_t Mode() const { return fNode.Mode(); }
|
||||
uint32 Type() const { return fNode.Type(); }
|
||||
int32 Flags() const { return fNode.Flags(); }
|
||||
|
||||
off_t Size() const { return fNode.data.Size(); }
|
||||
off_t LastModified() const { return fNode.last_modified_time; }
|
||||
|
||||
const block_run &BlockRun() const { return fNode.inode_num; }
|
||||
block_run &Parent() { return fNode.parent; }
|
||||
block_run &Attributes() { return fNode.attributes; }
|
||||
|
||||
block_run &BlockRun() const { return Node()->inode_num; }
|
||||
block_run &Parent() const { return Node()->parent; }
|
||||
block_run &Attributes() const { return Node()->attributes; }
|
||||
Volume *GetVolume() const { return fVolume; }
|
||||
|
||||
status_t InitCheck(bool checkNode = true);
|
||||
@ -126,25 +92,25 @@ class Inode : public CachedBlock {
|
||||
status_t CheckPermissions(int accessMode) const;
|
||||
|
||||
// small_data access methods
|
||||
status_t MakeSpaceForSmallData(Transaction *transaction, const char *name, int32 length);
|
||||
status_t RemoveSmallData(Transaction *transaction, const char *name);
|
||||
status_t AddSmallData(Transaction *transaction, const char *name, uint32 type,
|
||||
status_t MakeSpaceForSmallData(Transaction &transaction, bfs_inode *node, const char *name, int32 length);
|
||||
status_t RemoveSmallData(Transaction &transaction, NodeGetter &node, const char *name);
|
||||
status_t AddSmallData(Transaction &transaction, NodeGetter &node, const char *name, uint32 type,
|
||||
const uint8 *data, size_t length, bool force = false);
|
||||
status_t GetNextSmallData(small_data **_smallData) const;
|
||||
small_data *FindSmallData(const char *name) const;
|
||||
const char *Name() const;
|
||||
status_t GetNextSmallData(bfs_inode *node, small_data **_smallData) const;
|
||||
small_data *FindSmallData(const bfs_inode *node, const char *name) const;
|
||||
const char *Name(const bfs_inode *node) const;
|
||||
status_t GetName(char *buffer) const;
|
||||
status_t SetName(Transaction *transaction, const char *name);
|
||||
status_t SetName(Transaction &transaction, const char *name);
|
||||
|
||||
// high-level attribute methods
|
||||
status_t ReadAttribute(const char *name, int32 type, off_t pos, uint8 *buffer, size_t *_length);
|
||||
status_t WriteAttribute(Transaction *transaction, const char *name, int32 type, off_t pos, const uint8 *buffer, size_t *_length);
|
||||
status_t RemoveAttribute(Transaction *transaction, const char *name);
|
||||
status_t WriteAttribute(Transaction &transaction, const char *name, int32 type, off_t pos, const uint8 *buffer, size_t *_length);
|
||||
status_t RemoveAttribute(Transaction &transaction, const char *name);
|
||||
|
||||
// attribute methods
|
||||
status_t GetAttribute(const char *name, Inode **attribute);
|
||||
void ReleaseAttribute(Inode *attribute);
|
||||
status_t CreateAttribute(Transaction *transaction, const char *name, uint32 type, Inode **attribute);
|
||||
status_t CreateAttribute(Transaction &transaction, const char *name, uint32 type, Inode **attribute);
|
||||
|
||||
// for directories only:
|
||||
status_t GetTree(BPlusTree **);
|
||||
@ -154,25 +120,27 @@ class Inode : public CachedBlock {
|
||||
status_t FindBlockRun(off_t pos, block_run &run, off_t &offset);
|
||||
|
||||
status_t ReadAt(off_t pos, uint8 *buffer, size_t *length);
|
||||
status_t WriteAt(Transaction *transaction, off_t pos, const uint8 *buffer, size_t *length);
|
||||
status_t WriteAt(Transaction &transaction, off_t pos, const uint8 *buffer, size_t *length);
|
||||
status_t FillGapWithZeros(off_t oldSize, off_t newSize);
|
||||
|
||||
status_t SetFileSize(Transaction *transaction, off_t size);
|
||||
status_t Append(Transaction *transaction, off_t bytes);
|
||||
status_t Trim(Transaction *transaction);
|
||||
status_t SetFileSize(Transaction &transaction, off_t size);
|
||||
status_t Append(Transaction &transaction, off_t bytes);
|
||||
status_t Trim(Transaction &transaction);
|
||||
|
||||
status_t Free(Transaction *transaction);
|
||||
status_t Free(Transaction &transaction);
|
||||
status_t Sync();
|
||||
|
||||
bfs_inode &Node() { return fNode; }
|
||||
|
||||
// create/remove inodes
|
||||
status_t Remove(Transaction *transaction, const char *name, off_t *_id = NULL,
|
||||
status_t Remove(Transaction &transaction, const char *name, off_t *_id = NULL,
|
||||
bool isDirectory = false);
|
||||
static status_t Create(Transaction *transaction, Inode *parent, const char *name,
|
||||
static status_t Create(Transaction &transaction, Inode *parent, const char *name,
|
||||
int32 mode, int omode, uint32 type, off_t *_id = NULL, Inode **_inode = NULL);
|
||||
|
||||
// index maintaining helper
|
||||
void UpdateOldSize() { fOldSize = Size(); }
|
||||
void UpdateOldLastModified() { fOldLastModified = Node()->LastModifiedTime(); }
|
||||
void UpdateOldLastModified() { fOldLastModified = Node().LastModifiedTime(); }
|
||||
off_t OldSize() { return fOldSize; }
|
||||
off_t OldLastModified() { return fOldLastModified; }
|
||||
|
||||
@ -186,36 +154,72 @@ class Inode : public CachedBlock {
|
||||
// no implementation
|
||||
|
||||
friend void dump_inode(Inode &inode);
|
||||
friend AttributeIterator;
|
||||
friend InodeAllocator;
|
||||
friend class AttributeIterator;
|
||||
friend class InodeAllocator;
|
||||
|
||||
void Initialize();
|
||||
|
||||
status_t RemoveSmallData(small_data *item, int32 index);
|
||||
status_t RemoveSmallData(bfs_inode *node, small_data *item, int32 index);
|
||||
|
||||
void AddIterator(AttributeIterator *iterator);
|
||||
void RemoveIterator(AttributeIterator *iterator);
|
||||
|
||||
status_t FreeStaticStreamArray(Transaction *transaction, int32 level, block_run run,
|
||||
status_t FreeStaticStreamArray(Transaction &transaction, int32 level, block_run run,
|
||||
off_t size, off_t offset, off_t &max);
|
||||
status_t FreeStreamArray(Transaction *transaction, block_run *array, uint32 arrayLength,
|
||||
status_t FreeStreamArray(Transaction &transaction, block_run *array, uint32 arrayLength,
|
||||
off_t size, off_t &offset, off_t &max);
|
||||
status_t AllocateBlockArray(Transaction *transaction, block_run &run);
|
||||
status_t GrowStream(Transaction *transaction, off_t size);
|
||||
status_t ShrinkStream(Transaction *transaction, off_t size);
|
||||
status_t AllocateBlockArray(Transaction &transaction, block_run &run);
|
||||
status_t GrowStream(Transaction &transaction, off_t size);
|
||||
status_t ShrinkStream(Transaction &transaction, off_t size);
|
||||
|
||||
private:
|
||||
ReadWriteLock fLock;
|
||||
Volume *fVolume;
|
||||
vnode_id fID;
|
||||
BPlusTree *fTree;
|
||||
Inode *fAttributes;
|
||||
ReadWriteLock fLock;
|
||||
void *fCache;
|
||||
bfs_inode fNode;
|
||||
off_t fOldSize; // we need those values to ensure we will remove
|
||||
off_t fOldLastModified; // the correct keys from the indices
|
||||
void *fCache;
|
||||
|
||||
mutable SimpleLock fSmallDataLock;
|
||||
Chain<AttributeIterator> fIterators;
|
||||
};
|
||||
|
||||
|
||||
class NodeGetter : public CachedBlock {
|
||||
public:
|
||||
NodeGetter(Volume *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)
|
||||
{
|
||||
return (const bfs_inode *)SetTo(fVolume->VnodeToBlock(inode->ID()));
|
||||
}
|
||||
|
||||
const bfs_inode *Node() const { return (const bfs_inode *)Block(); }
|
||||
bfs_inode *WritableNode() const { return (bfs_inode *)Block(); }
|
||||
};
|
||||
|
||||
|
||||
// The Vnode class provides a convenience layer upon get_vnode(), so that
|
||||
// you don't have to call put_vnode() anymore, which may make code more
|
||||
// readable in some cases
|
||||
@ -241,13 +245,13 @@ class Vnode {
|
||||
Put();
|
||||
}
|
||||
|
||||
status_t Get(Inode **inode)
|
||||
status_t Get(Inode **_inode)
|
||||
{
|
||||
// should we check inode against NULL here? it should not be necessary
|
||||
#ifdef UNSAFE_GET_VNODE
|
||||
RecursiveLocker locker(fVolume->Lock());
|
||||
#endif
|
||||
return get_vnode(fVolume->ID(), fID, (void **)inode);
|
||||
return get_vnode(fVolume->ID(), fID, (void **)_inode);
|
||||
}
|
||||
|
||||
void Put()
|
||||
@ -291,113 +295,20 @@ class AttributeIterator {
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------
|
||||
// inlines
|
||||
|
||||
|
||||
inline
|
||||
CachedBlock::CachedBlock(Volume *volume)
|
||||
:
|
||||
fVolume(volume),
|
||||
fBlock(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
CachedBlock::CachedBlock(Volume *volume, off_t block, bool empty)
|
||||
:
|
||||
fVolume(volume),
|
||||
fBlock(NULL)
|
||||
{
|
||||
SetTo(block, empty);
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
CachedBlock::CachedBlock(Volume *volume, block_run run, bool empty)
|
||||
:
|
||||
fVolume(volume),
|
||||
fBlock(NULL)
|
||||
{
|
||||
SetTo(volume->ToBlock(run), empty);
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
CachedBlock::CachedBlock(CachedBlock *cached)
|
||||
:
|
||||
fVolume(cached->fVolume),
|
||||
fBlockNumber(cached->BlockNumber()),
|
||||
fBlock(cached->fBlock)
|
||||
{
|
||||
cached->Keep();
|
||||
}
|
||||
|
||||
|
||||
inline
|
||||
CachedBlock::~CachedBlock()
|
||||
{
|
||||
Unset();
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
CachedBlock::Keep()
|
||||
{
|
||||
fBlock = NULL;
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
CachedBlock::Unset()
|
||||
{
|
||||
if (fBlock != NULL)
|
||||
release_block(fVolume->Device(), fBlockNumber);
|
||||
}
|
||||
|
||||
|
||||
inline uint8 *
|
||||
CachedBlock::SetTo(off_t block, bool empty)
|
||||
{
|
||||
Unset();
|
||||
fBlockNumber = block;
|
||||
return fBlock = empty ? (uint8 *)get_empty_block(fVolume->Device(), block, BlockSize())
|
||||
: (uint8 *)get_block(fVolume->Device(), block, BlockSize());
|
||||
}
|
||||
|
||||
|
||||
inline uint8 *
|
||||
CachedBlock::SetTo(block_run run, bool empty)
|
||||
{
|
||||
return SetTo(fVolume->ToBlock(run), empty);
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
CachedBlock::WriteBack(Transaction *transaction)
|
||||
{
|
||||
if (transaction == NULL || fBlock == NULL)
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
|
||||
return transaction->WriteBlocks(fBlockNumber, fBlock);
|
||||
}
|
||||
|
||||
|
||||
/** Converts the "omode", the open flags given to bfs_open(), into
|
||||
/** Converts the open mode, the open flags given to bfs_open(), into
|
||||
* access modes, e.g. since O_RDONLY requires read access to the
|
||||
* file, it will be converted to R_OK.
|
||||
*/
|
||||
|
||||
inline int
|
||||
oModeToAccess(int omode)
|
||||
openModeToAccess(int openMode)
|
||||
{
|
||||
omode &= O_RWMASK;
|
||||
if (omode == O_RDONLY)
|
||||
openMode &= O_RWMASK;
|
||||
if (openMode == O_RDONLY)
|
||||
return R_OK;
|
||||
else if (omode == O_WRONLY)
|
||||
else if (openMode == O_WRONLY)
|
||||
return W_OK;
|
||||
|
||||
|
||||
return R_OK | W_OK;
|
||||
}
|
||||
|
||||
|
@ -3,28 +3,20 @@ SubDir OBOS_TOP src add-ons kernel file_systems bfs ;
|
||||
# save original optimization level
|
||||
oldOPTIM = $(OPTIM) ;
|
||||
|
||||
# R5 support is currently disabled!
|
||||
#
|
||||
# Have a look in src/tests/add-ons/kernel/file_systems/bfs/r5/
|
||||
# for an R5 compatible version.
|
||||
# In order to make the current BFS version R5 compatible again,
|
||||
# we would need to port over the Haiku cache API to R5.
|
||||
|
||||
# set some additional defines
|
||||
{
|
||||
local defines =
|
||||
KEEP_WRONG_DIRENT_RECLEN
|
||||
UNSAFE_GET_VNODE
|
||||
#BFS_BIG_ENDIAN_ONLY
|
||||
;
|
||||
|
||||
# By default, the R5 API version is used unless you define this
|
||||
if $(COMPILE_FOR_ZETA) {
|
||||
defines += COMPILE_FOR_ZETA ;
|
||||
}
|
||||
|
||||
# Enable OpenBFS to be compiled as a full BFS replacement. Will
|
||||
# report itself as "bfs" instead of "obfs" (only R5 version)
|
||||
if $(BFS_REPLACEMENT) {
|
||||
defines += BFS_REPLACEMENT ;
|
||||
bfsAddOnName = bfs ;
|
||||
} else {
|
||||
bfsAddOnName = obfs ;
|
||||
}
|
||||
|
||||
if $(DEBUG) = 0 {
|
||||
# the gcc on BeOS doesn't compile BFS correctly with -O2 or more
|
||||
OPTIM = -O1 ;
|
||||
@ -39,7 +31,7 @@ UsePrivateHeaders [ FDirName kernel ] ; # For kernel_cpp.cpp
|
||||
UsePrivateHeaders [ FDirName kernel disk_device_manager ] ;
|
||||
UsePrivateHeaders [ FDirName storage ] ;
|
||||
|
||||
KernelStaticLibrary libbfs :
|
||||
KernelAddon bfs : kernel file_systems :
|
||||
BlockAllocator.cpp
|
||||
BPlusTree.cpp
|
||||
kernel_cpp.cpp
|
||||
@ -50,37 +42,14 @@ KernelStaticLibrary libbfs :
|
||||
Query.cpp
|
||||
Utility.cpp
|
||||
Volume.cpp
|
||||
BufferPool.cpp
|
||||
;
|
||||
|
||||
KernelAddon bfs : kernel file_systems :
|
||||
kernel_interface.cpp
|
||||
disk_device_interface.cpp
|
||||
: libbfs.a
|
||||
;
|
||||
|
||||
R5KernelAddon $(bfsAddOnName)_r5 : kernel file_systems :
|
||||
kernel_interface_r5.cpp
|
||||
: libbfs.a
|
||||
;
|
||||
|
||||
SEARCH on [ FGristFiles
|
||||
kernel_cpp.cpp
|
||||
] = [ FDirName $(OBOS_TOP) src kernel core util ] ;
|
||||
|
||||
#-----------------------------------------------------
|
||||
|
||||
rule InstallBFS
|
||||
{
|
||||
Depends $(<) : $(>) ;
|
||||
}
|
||||
|
||||
actions ignore InstallBFS
|
||||
{
|
||||
cp $(>) /boot/home/config/add-ons/kernel/file_systems/
|
||||
}
|
||||
|
||||
InstallBFS install : obfs ;
|
||||
|
||||
# restore original optimization level
|
||||
OPTIM = $(oldOPTIM) ;
|
||||
|
@ -1,8 +1,8 @@
|
||||
/* Journal - transaction and logging
|
||||
**
|
||||
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
*
|
||||
* Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "Journal.h"
|
||||
@ -11,6 +11,7 @@
|
||||
|
||||
#include <Drivers.h>
|
||||
#include <util/kernel_cpp.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
Journal::Journal(Volume *volume)
|
||||
@ -50,7 +51,7 @@ Journal::InitCheck()
|
||||
|
||||
|
||||
status_t
|
||||
Journal::CheckLogEntry(int32 count, off_t *array)
|
||||
Journal::CheckLogEntry(int32 count, const off_t *array)
|
||||
{
|
||||
// ToDo: check log entry integrity (block numbers and entry size)
|
||||
PRINT(("Log entry has %ld entries (%Ld)\n", count, array[0]));
|
||||
@ -58,6 +59,11 @@ Journal::CheckLogEntry(int32 count, off_t *array)
|
||||
}
|
||||
|
||||
|
||||
/** Replays an entry in the log.
|
||||
* \a _start points to the entry in the log, and will be bumped to the next
|
||||
* one if replaying succeeded.
|
||||
*/
|
||||
|
||||
status_t
|
||||
Journal::ReplayLogEntry(int32 *_start)
|
||||
{
|
||||
@ -72,8 +78,9 @@ Journal::ReplayLogEntry(int32 *_start)
|
||||
bool first = true;
|
||||
|
||||
CachedBlock cached(fVolume);
|
||||
|
||||
while (count > 0) {
|
||||
off_t *array = (off_t *)cached.SetTo(arrayBlock);
|
||||
const off_t *array = (const off_t *)cached.SetTo(arrayBlock);
|
||||
if (array == NULL)
|
||||
return B_IO_ERROR;
|
||||
|
||||
@ -102,7 +109,7 @@ Journal::ReplayLogEntry(int32 *_start)
|
||||
for (; index < valuesInBlock && count-- > 0; index++) {
|
||||
PRINT(("replay block %Ld in log at %Ld!\n", array[index], blockNumber));
|
||||
|
||||
uint8 *copy = cachedCopy.SetTo(logOffset + blockNumber);
|
||||
const uint8 *copy = cachedCopy.SetTo(logOffset + blockNumber);
|
||||
if (copy == NULL)
|
||||
RETURN_ERROR(B_IO_ERROR);
|
||||
|
||||
@ -170,16 +177,10 @@ Journal::ReplayLog()
|
||||
*/
|
||||
|
||||
void
|
||||
Journal::blockNotify(off_t blockNumber, size_t numBlocks, void *arg)
|
||||
Journal::blockNotify(int32 transactionID, void *arg)
|
||||
{
|
||||
log_entry *logEntry = (log_entry *)arg;
|
||||
|
||||
logEntry->cached_blocks -= numBlocks;
|
||||
if (logEntry->cached_blocks > 0) {
|
||||
// nothing to do yet...
|
||||
return;
|
||||
}
|
||||
|
||||
Journal *journal = logEntry->journal;
|
||||
disk_super_block &superBlock = journal->fVolume->SuperBlock();
|
||||
bool update = false;
|
||||
@ -222,13 +223,24 @@ Journal::WriteLogEntry()
|
||||
fTransactionsInEntry = 0;
|
||||
fHasChangedBlocks = false;
|
||||
|
||||
// insert all changed blocks into the log array
|
||||
uint32 cookie = 0;
|
||||
{
|
||||
off_t blockNumber;
|
||||
while (cache_next_block_in_transaction(fVolume->BlockCache(), fTransactionID, &cookie,
|
||||
&blockNumber, NULL, NULL) == B_OK) {
|
||||
fArray.Insert(blockNumber);
|
||||
}
|
||||
}
|
||||
|
||||
sorted_array *array = fArray.Array();
|
||||
if (array == NULL || array->count == 0)
|
||||
return B_OK;
|
||||
|
||||
// Make sure there is enough space in the log.
|
||||
// If that fails for whatever reason, panic!
|
||||
force_cache_flush(fVolume->Device(), false);
|
||||
// ToDo:
|
||||
/* force_cache_flush(fVolume->Device(), false);
|
||||
int32 tries = fLogSize / 2 + 1;
|
||||
while (TransactionSize() > FreeLogBlocks() && tries-- > 0)
|
||||
force_cache_flush(fVolume->Device(), true);
|
||||
@ -237,7 +249,7 @@ Journal::WriteLogEntry()
|
||||
fVolume->Panic();
|
||||
return B_BAD_DATA;
|
||||
}
|
||||
|
||||
*/
|
||||
int32 blockShift = fVolume->BlockShift();
|
||||
off_t logOffset = fVolume->ToBlock(fVolume->Log()) << blockShift;
|
||||
off_t logStart = fVolume->LogEnd();
|
||||
@ -257,14 +269,11 @@ Journal::WriteLogEntry()
|
||||
|
||||
// Write logged blocks into the log
|
||||
|
||||
CachedBlock cached(fVolume);
|
||||
for (int32 i = 0;i < array->count;i++) {
|
||||
cookie = 0;
|
||||
const uint8 *block;
|
||||
while (cache_next_block_in_transaction(fVolume->BlockCache(), fTransactionID, &cookie,
|
||||
NULL, (void **)&block, NULL) == B_OK) {
|
||||
// ToDo: combine blocks if possible (using iovecs)!
|
||||
|
||||
uint8 *block = cached.SetTo(array->values[i]);
|
||||
if (block == NULL)
|
||||
return B_IO_ERROR;
|
||||
|
||||
write_pos(fVolume->Device(), logOffset + (logPosition << blockShift),
|
||||
block, fVolume->BlockSize());
|
||||
logPosition = (logPosition + 1) % fLogSize;
|
||||
@ -283,10 +292,10 @@ Journal::WriteLogEntry()
|
||||
|
||||
fCurrent = logEntry;
|
||||
fUsed += logEntry->length;
|
||||
|
||||
set_blocks_info(fVolume->Device(), &array->values[0], array->count, blockNotify, logEntry);
|
||||
}
|
||||
|
||||
cache_end_transaction(fVolume->BlockCache(), fTransactionID, blockNotify, fCurrent);
|
||||
|
||||
// If the log goes to the next round (the log is written as a
|
||||
// circular buffer), all blocks will be flushed out which is
|
||||
// possible because we don't have any locked blocks at this
|
||||
@ -318,7 +327,7 @@ Journal::FlushLogAndBlocks()
|
||||
return status;
|
||||
|
||||
// write the current log entry to disk
|
||||
|
||||
|
||||
if (TransactionSize() != 0) {
|
||||
status = WriteLogEntry();
|
||||
if (status < B_OK)
|
||||
@ -341,9 +350,17 @@ Journal::Lock(Transaction *owner)
|
||||
if (status == B_OK)
|
||||
fOwner = owner;
|
||||
|
||||
/* ToDo:
|
||||
// if the last transaction is older than 2 secs, start a new one
|
||||
if (fTransactionsInEntry != 0 && system_time() - fTimestamp > 2000000L)
|
||||
WriteLogEntry();
|
||||
*/
|
||||
|
||||
fTransactionID = cache_start_transaction(fVolume->BlockCache());
|
||||
if (fTransactionID < B_OK) {
|
||||
fLock.Unlock();
|
||||
return fTransactionID;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@ -357,6 +374,7 @@ Journal::Unlock(Transaction *owner, bool success)
|
||||
|
||||
TransactionDone(success);
|
||||
|
||||
fTransactionID = -1;
|
||||
fTimestamp = system_time();
|
||||
fOwner = NULL;
|
||||
fLock.Unlock();
|
||||
@ -383,6 +401,13 @@ Journal::CurrentTransaction()
|
||||
status_t
|
||||
Journal::TransactionDone(bool success)
|
||||
{
|
||||
if (!success) {
|
||||
cache_abort_transaction(fVolume->BlockCache(), fTransactionID);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// ToDo:
|
||||
/*
|
||||
if (!success && fTransactionsInEntry == 0) {
|
||||
// we can safely abort the transaction
|
||||
sorted_array *array = fArray.Array();
|
||||
@ -404,6 +429,7 @@ Journal::TransactionDone(bool success)
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
*/
|
||||
|
||||
return WriteLogEntry();
|
||||
}
|
||||
@ -412,6 +438,8 @@ Journal::TransactionDone(bool success)
|
||||
status_t
|
||||
Journal::LogBlocks(off_t blockNumber, const uint8 *buffer, size_t numBlocks)
|
||||
{
|
||||
panic("LogBlocks() called!\n");
|
||||
|
||||
// ToDo: that's for now - we should change the log file size here
|
||||
if (TransactionSize() + numBlocks + 1 > fLogSize)
|
||||
return B_DEVICE_FULL;
|
||||
@ -425,25 +453,29 @@ Journal::LogBlocks(off_t blockNumber, const uint8 *buffer, size_t numBlocks)
|
||||
// Note, this is only necessary if this method is called with a buffer
|
||||
// different from the cached block buffer - which is unlikely but
|
||||
// we'll make sure this way (costs one cache lookup, though).
|
||||
status_t status = cached_write(fVolume->Device(), blockNumber, buffer, 1, blockSize);
|
||||
// ToDo:
|
||||
/* status_t status = cached_write(fVolume->Device(), blockNumber, buffer, 1, blockSize);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
// Insert the block into the transaction's array, and write the changes
|
||||
// back into the locked cache buffer
|
||||
fArray.Insert(blockNumber);
|
||||
status_t status = cached_write_locked(fVolume->Device(), blockNumber, buffer, 1, blockSize);
|
||||
|
||||
// ToDo:
|
||||
/* status_t status = cached_write_locked(fVolume->Device(), blockNumber, buffer, 1, blockSize);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
}
|
||||
*/ }
|
||||
|
||||
// ToDo:
|
||||
// If necessary, flush the log, so that we have enough space for this transaction
|
||||
if (TransactionSize() > FreeLogBlocks())
|
||||
/* if (TransactionSize() > FreeLogBlocks())
|
||||
force_cache_flush(fVolume->Device(), true);
|
||||
|
||||
*/
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
/* Journal - transaction and logging
|
||||
*
|
||||
* Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef JOURNAL_H
|
||||
#define JOURNAL_H
|
||||
/* Journal - transaction and logging
|
||||
**
|
||||
** Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include <KernelExport.h>
|
||||
@ -18,9 +18,6 @@
|
||||
# define _IMPEXP_KERNEL
|
||||
#endif
|
||||
|
||||
#include <lock.h>
|
||||
#include <cache.h>
|
||||
|
||||
#include "Volume.h"
|
||||
#include "Chain.h"
|
||||
#include "Utility.h"
|
||||
@ -52,7 +49,7 @@ class Journal {
|
||||
status_t Lock(Transaction *owner);
|
||||
void Unlock(Transaction *owner, bool success);
|
||||
|
||||
status_t CheckLogEntry(int32 count, off_t *array);
|
||||
status_t CheckLogEntry(int32 count, const off_t *array);
|
||||
status_t ReplayLogEntry(int32 *start);
|
||||
status_t ReplayLog();
|
||||
|
||||
@ -64,13 +61,14 @@ class Journal {
|
||||
|
||||
status_t FlushLogAndBlocks();
|
||||
Volume *GetVolume() const { return fVolume; }
|
||||
int32 TransactionID() const { return fTransactionID; }
|
||||
|
||||
inline uint32 FreeLogBlocks() const;
|
||||
|
||||
private:
|
||||
friend log_entry;
|
||||
|
||||
static void blockNotify(off_t blockNumber, size_t numBlocks, void *arg);
|
||||
static void blockNotify(int32 transactionID, void *arg);
|
||||
status_t TransactionDone(bool success);
|
||||
|
||||
Volume *fVolume;
|
||||
@ -84,6 +82,7 @@ class Journal {
|
||||
log_entry *fCurrent;
|
||||
bool fHasChangedBlocks;
|
||||
bigtime_t fTimestamp;
|
||||
int32 fTransactionID;
|
||||
};
|
||||
|
||||
|
||||
@ -143,10 +142,15 @@ class Transaction {
|
||||
if (fJournal == NULL)
|
||||
return B_NO_INIT;
|
||||
|
||||
// ToDo: implement this properly!
|
||||
#if 0
|
||||
return fJournal->LogBlocks(blockNumber, buffer, numBlocks);
|
||||
#endif
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
Volume *GetVolume() { return fJournal != NULL ? fJournal->GetVolume() : NULL; }
|
||||
int32 ID() const { return fJournal->TransactionID(); }
|
||||
|
||||
private:
|
||||
Transaction(const Transaction &);
|
||||
|
@ -1,636 +0,0 @@
|
||||
/* Stream - inode stream access functions
|
||||
**
|
||||
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include <Inode.h>
|
||||
|
||||
|
||||
// The classes in the namespace "Access" provide different type of access
|
||||
// to the inode's data stream.
|
||||
// Uncached accesses the underlaying device directly, Cached uses the
|
||||
// standard cache, while Logged directs write accesses through the log.
|
||||
//
|
||||
// The classes interface is similar to the one of the CachedBlock class,
|
||||
// but adds two other (static) functions for reading/writing several
|
||||
// blocks at once.
|
||||
// We don't use a real pure virtual interface as the class base, but we
|
||||
// provide the same mechanism using templates.
|
||||
|
||||
namespace Access {
|
||||
|
||||
class Uncached {
|
||||
public:
|
||||
Uncached(Volume *volume);
|
||||
Uncached(Volume *volume, off_t block, bool empty = false);
|
||||
Uncached(Volume *volume, block_run run, bool empty = false);
|
||||
~Uncached();
|
||||
|
||||
void Unset();
|
||||
uint8 *SetTo(off_t block, bool empty = false);
|
||||
uint8 *SetTo(block_run run, bool empty = false);
|
||||
status_t WriteBack(Transaction *transaction);
|
||||
|
||||
uint8 *Block() const { return fBlock; }
|
||||
off_t BlockNumber() const { return fBlockNumber; }
|
||||
uint32 BlockSize() const { return fVolume->BlockSize(); }
|
||||
uint32 BlockShift() const { return fVolume->BlockShift(); }
|
||||
|
||||
static status_t Read(Volume *volume, block_run run, uint8 *buffer);
|
||||
static status_t Write(Transaction *transaction, Volume *volume, block_run run, const uint8 *buffer);
|
||||
|
||||
private:
|
||||
Volume *fVolume;
|
||||
off_t fBlockNumber;
|
||||
uint8 *fBlock;
|
||||
};
|
||||
|
||||
class Cached : public CachedBlock {
|
||||
public:
|
||||
Cached(Volume *volume);
|
||||
Cached(Volume *volume, off_t block, bool empty = false);
|
||||
Cached(Volume *volume, block_run run, bool empty = false);
|
||||
|
||||
status_t WriteBack(Transaction *transaction);
|
||||
static status_t Read(Volume *volume, block_run run, uint8 *buffer);
|
||||
static status_t Write(Transaction *transaction, Volume *volume, block_run run, const uint8 *buffer);
|
||||
};
|
||||
|
||||
class Logged : public CachedBlock {
|
||||
public:
|
||||
Logged(Volume *volume);
|
||||
Logged(Volume *volume,off_t block, bool empty = false);
|
||||
Logged(Volume *volume, block_run run, bool empty = false);
|
||||
|
||||
static status_t Read(Volume *volume, block_run run, uint8 *buffer);
|
||||
static status_t Write(Transaction *transaction, Volume *volume, block_run run, const uint8 *buffer);
|
||||
};
|
||||
|
||||
|
||||
Uncached::Uncached(Volume *volume)
|
||||
:
|
||||
fVolume(volume),
|
||||
fBlock(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Uncached::Uncached(Volume *volume,off_t block, bool empty)
|
||||
:
|
||||
fVolume(volume),
|
||||
fBlock(NULL)
|
||||
{
|
||||
SetTo(block,empty);
|
||||
}
|
||||
|
||||
|
||||
Uncached::Uncached(Volume *volume,block_run run,bool empty)
|
||||
:
|
||||
fVolume(volume),
|
||||
fBlock(NULL)
|
||||
{
|
||||
SetTo(volume->ToBlock(run),empty);
|
||||
}
|
||||
|
||||
|
||||
Uncached::~Uncached()
|
||||
{
|
||||
Unset();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Uncached::Unset()
|
||||
{
|
||||
if (fBlock != NULL)
|
||||
fVolume->Pool().PutBuffer((void *)fBlock);
|
||||
}
|
||||
|
||||
|
||||
uint8 *
|
||||
Uncached::SetTo(off_t block, bool empty)
|
||||
{
|
||||
Unset();
|
||||
fBlockNumber = block;
|
||||
if (fVolume->Pool().GetBuffer((void **)&fBlock) < B_OK)
|
||||
return NULL;
|
||||
|
||||
if (empty)
|
||||
memset(fBlock, 0, BlockSize());
|
||||
else
|
||||
read_pos(fVolume->Device(), fBlockNumber << BlockShift(), fBlock, BlockSize());
|
||||
|
||||
return fBlock;
|
||||
}
|
||||
|
||||
|
||||
uint8 *
|
||||
Uncached::SetTo(block_run run, bool empty)
|
||||
{
|
||||
return SetTo(fVolume->ToBlock(run), empty);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Uncached::WriteBack(Transaction *transaction)
|
||||
{
|
||||
if (fBlock == NULL)
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
|
||||
return write_pos(fVolume->Device(), fBlockNumber << BlockShift(), fBlock, BlockSize());
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Uncached::Read(Volume *volume, block_run run, uint8 *buffer)
|
||||
{
|
||||
return read_pos(volume->Device(), volume->ToBlock(run) << volume->BlockShift(), buffer, run.Length() << volume->BlockShift());
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Uncached::Write(Transaction *transaction, Volume *volume, block_run run, const uint8 *buffer)
|
||||
{
|
||||
return write_pos(volume->Device(), volume->ToBlock(run) << volume->BlockShift(), buffer, run.Length() << volume->BlockShift());
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
Cached::Cached(Volume *volume)
|
||||
: CachedBlock(volume)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Cached::Cached(Volume *volume,off_t block,bool empty)
|
||||
: CachedBlock(volume, block, empty)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Cached::Cached(Volume *volume,block_run run,bool empty)
|
||||
: CachedBlock(volume, run, empty)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Cached::WriteBack(Transaction *transaction)
|
||||
{
|
||||
if (transaction == NULL || fBlock == NULL)
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
|
||||
return fVolume->WriteBlocks(fBlockNumber, fBlock, 1);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Cached::Read(Volume *volume, block_run run, uint8 *buffer)
|
||||
{
|
||||
return cached_read(volume->Device(), volume->ToBlock(run), buffer, run.Length(), volume->BlockSize());
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Cached::Write(Transaction *transaction, Volume *volume, block_run run, const uint8 *buffer)
|
||||
{
|
||||
return volume->WriteBlocks(volume->ToBlock(run), buffer, run.Length());
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
Logged::Logged(Volume *volume)
|
||||
: CachedBlock(volume)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Logged::Logged(Volume *volume, off_t block, bool empty)
|
||||
: CachedBlock(volume, block, empty)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Logged::Logged(Volume *volume, block_run run, bool empty)
|
||||
: CachedBlock(volume, run, empty)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Logged::Read(Volume *volume, block_run run, uint8 *buffer)
|
||||
{
|
||||
return cached_read(volume->Device(), volume->ToBlock(run), buffer, run.Length(), volume->BlockSize());
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Logged::Write(Transaction *transaction, Volume *volume, block_run run, const uint8 *buffer)
|
||||
{
|
||||
return transaction->WriteBlocks(volume->ToBlock(run), buffer, run.Length());
|
||||
}
|
||||
|
||||
}; // namespace Access
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
// The Stream template class allows to have only one straight-forward
|
||||
// implementation of the FindBlockRun(), ReadAt(), and WriteAt() methods.
|
||||
// They will access the disk through the given cache class only, which
|
||||
// means either uncached, cached, or logged (see above).
|
||||
|
||||
template<class Cache>
|
||||
class Stream : public Inode {
|
||||
private:
|
||||
// The constructor only exists to make the compiler happy - it
|
||||
// is never called in the code itself
|
||||
Stream() : Inode(NULL, -1) {}
|
||||
|
||||
public:
|
||||
status_t FindBlockRun(off_t pos, block_run &run, off_t &offset);
|
||||
status_t ReadAt(off_t pos, uint8 *buffer, size_t *length);
|
||||
status_t WriteAt(Transaction *transaction, off_t pos, const uint8 *buffer, size_t *length);
|
||||
};
|
||||
|
||||
|
||||
/** see Inode::FindBlockRun() for the documentation of this method */
|
||||
|
||||
template<class Cache>
|
||||
status_t
|
||||
Stream<Cache>::FindBlockRun(off_t pos, block_run &run, off_t &offset)
|
||||
{
|
||||
data_stream *data = &Node()->data;
|
||||
|
||||
// find matching block run
|
||||
|
||||
if (data->MaxDirectRange() > 0 && pos >= data->MaxDirectRange()) {
|
||||
if (data->MaxDoubleIndirectRange() > 0 && pos >= data->MaxIndirectRange()) {
|
||||
// access to double indirect blocks
|
||||
|
||||
Cache cached(fVolume);
|
||||
|
||||
off_t start = pos - data->MaxIndirectRange();
|
||||
int32 indirectSize = (1L << (INDIRECT_BLOCKS_SHIFT + cached.BlockShift()))
|
||||
* (fVolume->BlockSize() / sizeof(block_run));
|
||||
int32 directSize = NUM_ARRAY_BLOCKS << cached.BlockShift();
|
||||
int32 index = start / indirectSize;
|
||||
int32 runsPerBlock = cached.BlockSize() / sizeof(block_run);
|
||||
|
||||
block_run *indirect = (block_run *)cached.SetTo(
|
||||
fVolume->ToBlock(data->double_indirect) + index / runsPerBlock);
|
||||
if (indirect == NULL)
|
||||
RETURN_ERROR(B_ERROR);
|
||||
|
||||
//printf("\tstart = %Ld, indirectSize = %ld, directSize = %ld, index = %ld\n",start,indirectSize,directSize,index);
|
||||
//printf("\tlook for indirect block at %ld,%d\n",indirect[index].allocation_group,indirect[index].start);
|
||||
|
||||
int32 current = (start % indirectSize) / directSize;
|
||||
|
||||
indirect = (block_run *)cached.SetTo(
|
||||
fVolume->ToBlock(indirect[index % runsPerBlock]) + current / runsPerBlock);
|
||||
if (indirect == NULL)
|
||||
RETURN_ERROR(B_ERROR);
|
||||
|
||||
run = indirect[current % runsPerBlock];
|
||||
offset = data->MaxIndirectRange() + (index * indirectSize) + (current * directSize);
|
||||
//printf("\tfCurrent = %ld, fRunFileOffset = %Ld, fRunBlockEnd = %Ld, fRun = %ld,%d\n",fCurrent,fRunFileOffset,fRunBlockEnd,fRun.allocation_group,fRun.start);
|
||||
} else {
|
||||
// access to indirect blocks
|
||||
|
||||
int32 runsPerBlock = fVolume->BlockSize() / sizeof(block_run);
|
||||
off_t runBlockEnd = data->MaxDirectRange();
|
||||
|
||||
Cache cached(fVolume);
|
||||
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);
|
||||
|
||||
int32 current = -1;
|
||||
while (++current < runsPerBlock) {
|
||||
if (indirect[current].IsZero())
|
||||
break;
|
||||
|
||||
runBlockEnd += indirect[current].Length() << cached.BlockShift();
|
||||
if (runBlockEnd > pos) {
|
||||
run = indirect[current];
|
||||
offset = runBlockEnd - (run.Length() << cached.BlockShift());
|
||||
//printf("reading from indirect block: %ld,%d\n",fRun.allocation_group,fRun.start);
|
||||
//printf("### indirect-run[%ld] = (%ld,%d,%d), offset = %Ld\n",fCurrent,fRun.allocation_group,fRun.start,fRun.Length(),fRunFileOffset);
|
||||
return fVolume->ValidateBlockRun(run);
|
||||
}
|
||||
}
|
||||
}
|
||||
RETURN_ERROR(B_ERROR);
|
||||
}
|
||||
} else {
|
||||
// access from direct blocks
|
||||
|
||||
off_t runBlockEnd = 0LL;
|
||||
int32 current = -1;
|
||||
|
||||
while (++current < NUM_DIRECT_BLOCKS) {
|
||||
if (data->direct[current].IsZero())
|
||||
break;
|
||||
|
||||
runBlockEnd += data->direct[current].Length() << fVolume->BlockShift();
|
||||
if (runBlockEnd > pos) {
|
||||
run = data->direct[current];
|
||||
offset = runBlockEnd - (run.Length() << fVolume->BlockShift());
|
||||
//printf("### run[%ld] = (%ld,%d,%d), offset = %Ld\n",fCurrent,fRun.allocation_group,fRun.start,fRun.Length(),fRunFileOffset);
|
||||
return fVolume->ValidateBlockRun(run);
|
||||
}
|
||||
}
|
||||
//PRINT(("FindBlockRun() failed in direct range: size = %Ld, pos = %Ld\n",data->size,pos));
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
return fVolume->ValidateBlockRun(run);
|
||||
}
|
||||
|
||||
|
||||
template<class Cache>
|
||||
status_t
|
||||
Stream<Cache>::ReadAt(off_t pos, uint8 *buffer, size_t *_length)
|
||||
{
|
||||
size_t length = *_length;
|
||||
|
||||
// set/check boundaries for pos/length
|
||||
if (pos < 0)
|
||||
return B_BAD_VALUE;
|
||||
if (pos >= Node()->data.Size() || length == 0) {
|
||||
*_length = 0;
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
|
||||
if (pos + length > Node()->data.Size())
|
||||
length = Node()->data.Size() - pos;
|
||||
|
||||
block_run run;
|
||||
off_t offset;
|
||||
if (FindBlockRun(pos, run, offset) < B_OK) {
|
||||
*_length = 0;
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
}
|
||||
|
||||
uint32 bytesRead = 0;
|
||||
uint32 blockSize = fVolume->BlockSize();
|
||||
uint32 blockShift = fVolume->BlockShift();
|
||||
uint8 *block;
|
||||
|
||||
// the first block_run we read could not be aligned to the block_size boundary
|
||||
// (read partial block at the beginning)
|
||||
|
||||
// pos % block_size == (pos - offset) % block_size, offset % block_size == 0
|
||||
if (pos % blockSize != 0) {
|
||||
run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start() + ((pos - offset) >> blockShift));
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - ((pos - offset) >> blockShift));
|
||||
|
||||
Cache cached(fVolume,run);
|
||||
if ((block = cached.Block()) == NULL) {
|
||||
*_length = 0;
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
}
|
||||
|
||||
bytesRead = blockSize - (pos % blockSize);
|
||||
if (length < bytesRead)
|
||||
bytesRead = length;
|
||||
|
||||
memcpy(buffer, block + (pos % blockSize), bytesRead);
|
||||
pos += bytesRead;
|
||||
|
||||
length -= bytesRead;
|
||||
if (length == 0) {
|
||||
*_length = bytesRead;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
if (FindBlockRun(pos, run, offset) < B_OK) {
|
||||
*_length = bytesRead;
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
// the first block_run is already filled in at this point
|
||||
// read the following complete blocks using cached_read(),
|
||||
// the last partial block is read using the generic Cache class
|
||||
|
||||
bool partial = false;
|
||||
|
||||
while (length > 0) {
|
||||
// offset is the offset to the current pos in the block_run
|
||||
run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start() + ((pos - offset) >> blockShift));
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - ((pos - offset) >> blockShift));
|
||||
|
||||
if (uint32(run.Length() << blockShift) > length) {
|
||||
if (length < blockSize) {
|
||||
Cache cached(fVolume, run);
|
||||
if ((block = cached.Block()) == NULL) {
|
||||
*_length = bytesRead;
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
}
|
||||
memcpy(buffer + bytesRead, block, length);
|
||||
bytesRead += length;
|
||||
break;
|
||||
}
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(length >> blockShift);
|
||||
partial = true;
|
||||
}
|
||||
|
||||
if (Cache::Read(fVolume, run, buffer + bytesRead) < B_OK) {
|
||||
*_length = bytesRead;
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
}
|
||||
|
||||
int32 bytes = run.Length() << blockShift;
|
||||
#ifdef DEBUG
|
||||
if ((uint32)bytes > length)
|
||||
DEBUGGER(("bytes greater than length"));
|
||||
#endif
|
||||
length -= bytes;
|
||||
bytesRead += bytes;
|
||||
if (length == 0)
|
||||
break;
|
||||
|
||||
pos += bytes;
|
||||
|
||||
if (partial) {
|
||||
// if the last block was read only partially, point block_run
|
||||
// to the remaining part
|
||||
run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start() + run.Length());
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(1);
|
||||
offset = pos;
|
||||
} else if (FindBlockRun(pos, run, offset) < B_OK) {
|
||||
*_length = bytesRead;
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
*_length = bytesRead;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
template<class Cache>
|
||||
status_t
|
||||
Stream<Cache>::WriteAt(Transaction *transaction, off_t pos, const uint8 *buffer, size_t *_length)
|
||||
{
|
||||
size_t length = *_length;
|
||||
|
||||
// set/check boundaries for pos/length
|
||||
if (pos < 0)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (pos + length > Size()) {
|
||||
off_t oldSize = Size();
|
||||
|
||||
// uncached files can't be resized (Inode::SetFileSize() also
|
||||
// doesn't allow this, but this way we don't have to start a
|
||||
// transaction to find out).
|
||||
if (Flags() & INODE_NO_CACHE)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// the transaction doesn't have to be started already
|
||||
// ToDo: what's that INODE_NO_TRANSACTION flag good for again?
|
||||
if ((Flags() & INODE_NO_TRANSACTION) == 0
|
||||
&& !transaction->IsStarted())
|
||||
transaction->Start(fVolume, BlockNumber());
|
||||
|
||||
// let's grow the data stream to the size needed
|
||||
status_t status = SetFileSize(transaction, pos + length);
|
||||
if (status < B_OK) {
|
||||
*_length = 0;
|
||||
RETURN_ERROR(status);
|
||||
}
|
||||
// If the position of the write was beyond the file size, we
|
||||
// have to fill the gap between that position and the old file
|
||||
// size with zeros.
|
||||
FillGapWithZeros(oldSize, pos);
|
||||
}
|
||||
|
||||
// If we don't want to write anything, we can now return (we may
|
||||
// just have changed the file size using the position parameter)
|
||||
if (length == 0)
|
||||
return B_OK;
|
||||
|
||||
block_run run;
|
||||
off_t offset;
|
||||
if (FindBlockRun(pos, run, offset) < B_OK) {
|
||||
*_length = 0;
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
}
|
||||
|
||||
bool logStream = (Flags() & INODE_LOGGED) == INODE_LOGGED;
|
||||
if (logStream
|
||||
&& !transaction->IsStarted())
|
||||
transaction->Start(fVolume, BlockNumber());
|
||||
|
||||
uint32 bytesWritten = 0;
|
||||
uint32 blockSize = fVolume->BlockSize();
|
||||
uint32 blockShift = fVolume->BlockShift();
|
||||
uint8 *block;
|
||||
|
||||
// the first block_run we write could not be aligned to the block_size boundary
|
||||
// (write partial block at the beginning)
|
||||
|
||||
// pos % block_size == (pos - offset) % block_size, offset % block_size == 0
|
||||
if (pos % blockSize != 0) {
|
||||
run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start() + ((pos - offset) >> blockShift));
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - ((pos - offset) >> blockShift));
|
||||
|
||||
Cache cached(fVolume, run);
|
||||
if ((block = cached.Block()) == NULL) {
|
||||
*_length = 0;
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
}
|
||||
|
||||
bytesWritten = blockSize - (pos % blockSize);
|
||||
if (length < bytesWritten)
|
||||
bytesWritten = length;
|
||||
|
||||
memcpy(block + (pos % blockSize),buffer,bytesWritten);
|
||||
|
||||
cached.WriteBack(transaction);
|
||||
|
||||
pos += bytesWritten;
|
||||
|
||||
length -= bytesWritten;
|
||||
if (length == 0) {
|
||||
*_length = bytesWritten;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
if (FindBlockRun(pos, run, offset) < B_OK) {
|
||||
*_length = bytesWritten;
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
// the first block_run is already filled in at this point
|
||||
// write the following complete blocks using Volume::WriteBlocks(),
|
||||
// the last partial block is written using the generic Cache class
|
||||
|
||||
bool partial = false;
|
||||
|
||||
while (length > 0) {
|
||||
// offset is the offset to the current pos in the block_run
|
||||
run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start() + ((pos - offset) >> blockShift));
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - ((pos - offset) >> blockShift));
|
||||
|
||||
if (uint32(run.Length() << blockShift) > length) {
|
||||
if (length < blockSize) {
|
||||
Cache cached(fVolume,run);
|
||||
if ((block = cached.Block()) == NULL) {
|
||||
*_length = bytesWritten;
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
}
|
||||
memcpy(block, buffer + bytesWritten, length);
|
||||
|
||||
cached.WriteBack(transaction);
|
||||
|
||||
bytesWritten += length;
|
||||
break;
|
||||
}
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(length >> blockShift);
|
||||
partial = true;
|
||||
}
|
||||
|
||||
if (Cache::Write(transaction, fVolume, run, buffer + bytesWritten) < B_OK) {
|
||||
*_length = bytesWritten;
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
}
|
||||
|
||||
int32 bytes = run.Length() << blockShift;
|
||||
length -= bytes;
|
||||
bytesWritten += bytes;
|
||||
if (length == 0)
|
||||
break;
|
||||
|
||||
pos += bytes;
|
||||
|
||||
if (partial) {
|
||||
// if the last block was written only partially, point block_run
|
||||
// to the remaining part
|
||||
run.start = HOST_ENDIAN_TO_BFS_INT16(run.Start() + run.Length());
|
||||
run.length = HOST_ENDIAN_TO_BFS_INT16(1);
|
||||
offset = pos;
|
||||
} else if (FindBlockRun(pos, run, offset) < B_OK) {
|
||||
*_length = bytesWritten;
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
*_length = bytesWritten;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
BFS - ToDo, May 26th, 2003
|
||||
BFS - ToDo, November 12th, 2004
|
||||
-----
|
||||
|
||||
BlockAllocator
|
||||
@ -76,7 +76,6 @@ kernel_interface
|
||||
general stuff
|
||||
|
||||
- There are also some comments with a leading "ToDo:" directly in the code which may not be mentioned here.
|
||||
- implement mkbfs (try to do it in OpenBeOS style directly - only write the super block from user space)
|
||||
|
||||
|
||||
-----
|
||||
|
@ -1,8 +1,8 @@
|
||||
/* Volume - BFS super block, mounting, etc.
|
||||
**
|
||||
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
*
|
||||
* Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "Debug.h"
|
||||
@ -40,8 +40,8 @@ class DeviceOpener {
|
||||
~DeviceOpener();
|
||||
|
||||
int Open(const char *device, int mode);
|
||||
status_t InitCache(off_t numBlocks);
|
||||
void RemoveCache(int mode);
|
||||
void *InitCache(off_t numBlocks, uint32 blockSize);
|
||||
void RemoveCache(bool allowWrites);
|
||||
|
||||
void Keep();
|
||||
|
||||
@ -51,13 +51,13 @@ class DeviceOpener {
|
||||
|
||||
private:
|
||||
int fDevice;
|
||||
bool fCached;
|
||||
void *fBlockCache;
|
||||
};
|
||||
|
||||
|
||||
DeviceOpener::DeviceOpener(const char *device, int mode)
|
||||
:
|
||||
fCached(false)
|
||||
fBlockCache(NULL)
|
||||
{
|
||||
Open(device, mode);
|
||||
}
|
||||
@ -66,14 +66,13 @@ DeviceOpener::DeviceOpener(const char *device, int mode)
|
||||
DeviceOpener::~DeviceOpener()
|
||||
{
|
||||
if (fDevice >= B_OK) {
|
||||
RemoveCache(false);
|
||||
close(fDevice);
|
||||
if (fCached)
|
||||
remove_cached_device_blocks(fDevice, NO_WRITES);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
int
|
||||
DeviceOpener::Open(const char *device, int mode)
|
||||
{
|
||||
fDevice = open(device, mode);
|
||||
@ -81,30 +80,25 @@ DeviceOpener::Open(const char *device, int mode)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DeviceOpener::InitCache(off_t numBlocks)
|
||||
void *
|
||||
DeviceOpener::InitCache(off_t numBlocks, uint32 blockSize)
|
||||
{
|
||||
if (init_cache_for_device(fDevice, numBlocks) == B_OK) {
|
||||
fCached = true;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
return block_cache_create(fDevice, numBlocks, blockSize);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DeviceOpener::RemoveCache(int mode)
|
||||
void
|
||||
DeviceOpener::RemoveCache(bool allowWrites)
|
||||
{
|
||||
if (!fCached)
|
||||
if (fBlockCache == NULL)
|
||||
return;
|
||||
|
||||
remove_cached_device_blocks(fDevice, mode);
|
||||
fCached = false;
|
||||
block_cache_delete(fBlockCache, allowWrites);
|
||||
fBlockCache = NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
void
|
||||
DeviceOpener::Keep()
|
||||
{
|
||||
fDevice = -1;
|
||||
@ -115,7 +109,7 @@ DeviceOpener::Keep()
|
||||
* to compute the size, or fstat() if that failed.
|
||||
*/
|
||||
|
||||
status_t
|
||||
status_t
|
||||
DeviceOpener::GetSize(off_t *_size, uint32 *_blockSize)
|
||||
{
|
||||
device_geometry geometry;
|
||||
@ -247,7 +241,7 @@ Volume::IsValidSuperBlock()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
void
|
||||
Volume::Panic()
|
||||
{
|
||||
FATAL(("we have to panic... switch to read-only mode!\n"));
|
||||
@ -325,7 +319,7 @@ Volume::Mount(const char *deviceName, uint32 flags)
|
||||
fLogStart = fSuperBlock.LogStart();
|
||||
fLogEnd = fSuperBlock.LogEnd();
|
||||
|
||||
if (opener.InitCache(NumBlocks()) != B_OK)
|
||||
if ((fBlockCache = opener.InitCache(NumBlocks(), fBlockSize)) == NULL)
|
||||
return B_ERROR;
|
||||
|
||||
fJournal = new Journal(this);
|
||||
@ -392,14 +386,14 @@ Volume::Unmount()
|
||||
|
||||
delete fIndicesNode;
|
||||
|
||||
remove_cached_device_blocks(fDevice, IsReadOnly() ? NO_WRITES : ALLOW_WRITES);
|
||||
block_cache_delete(fBlockCache, !IsReadOnly());
|
||||
close(fDevice);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
status_t
|
||||
Volume::Sync()
|
||||
{
|
||||
return fJournal->FlushLogAndBlocks();
|
||||
@ -421,7 +415,7 @@ Volume::ValidateBlockRun(block_run run)
|
||||
}
|
||||
|
||||
|
||||
block_run
|
||||
block_run
|
||||
Volume::ToBlockRun(off_t block) const
|
||||
{
|
||||
block_run run;
|
||||
@ -433,7 +427,7 @@ Volume::ToBlockRun(off_t block) const
|
||||
|
||||
|
||||
status_t
|
||||
Volume::CreateIndicesRoot(Transaction *transaction)
|
||||
Volume::CreateIndicesRoot(Transaction &transaction)
|
||||
{
|
||||
off_t id;
|
||||
status_t status = Inode::Create(transaction, NULL, NULL,
|
||||
@ -446,14 +440,14 @@ Volume::CreateIndicesRoot(Transaction *transaction)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Volume::AllocateForInode(Transaction *transaction, const Inode *parent, mode_t type, block_run &run)
|
||||
status_t
|
||||
Volume::AllocateForInode(Transaction &transaction, const Inode *parent, mode_t type, block_run &run)
|
||||
{
|
||||
return fBlockAllocator.AllocateForInode(transaction, &parent->BlockRun(), type, run);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
status_t
|
||||
Volume::WriteSuperBlock()
|
||||
{
|
||||
if (write_pos(fDevice, 512, &fSuperBlock, sizeof(disk_super_block)) != sizeof(disk_super_block))
|
||||
@ -484,7 +478,7 @@ Volume::UpdateLiveQueries(Inode *inode, const char *attribute, int32 type, const
|
||||
* the queries - it wouldn't safe you anything in this case.
|
||||
*/
|
||||
|
||||
bool
|
||||
bool
|
||||
Volume::CheckForLiveQuery(const char *attribute)
|
||||
{
|
||||
// ToDo: check for a live query that depends on the specified attribute
|
||||
@ -492,7 +486,7 @@ Volume::CheckForLiveQuery(const char *attribute)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
void
|
||||
Volume::AddQuery(Query *query)
|
||||
{
|
||||
if (fQueryLock.Lock() < B_OK)
|
||||
@ -504,7 +498,7 @@ Volume::AddQuery(Query *query)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
void
|
||||
Volume::RemoveQuery(Query *query)
|
||||
{
|
||||
if (fQueryLock.Lock() < B_OK)
|
||||
|
@ -1,26 +1,18 @@
|
||||
/* Volume - BFS super block, mounting, etc.
|
||||
*
|
||||
* Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef VOLUME_H
|
||||
#define VOLUME_H
|
||||
/* Volume - BFS super block, mounting, etc.
|
||||
**
|
||||
** Initial version by Axel Dörfler, axeld@pinc-software.de
|
||||
** This file may be used under the terms of the OpenBeOS License.
|
||||
*/
|
||||
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <fs_interface.h>
|
||||
|
||||
extern "C" {
|
||||
#ifndef _IMPEXP_KERNEL
|
||||
# define _IMPEXP_KERNEL
|
||||
#endif
|
||||
#include "lock.h"
|
||||
#include "cache.h"
|
||||
}
|
||||
#include <fs_cache.h>
|
||||
|
||||
#include "bfs.h"
|
||||
#include "BlockAllocator.h"
|
||||
#include "BufferPool.h"
|
||||
#include "Chain.h"
|
||||
|
||||
class Journal;
|
||||
@ -82,22 +74,20 @@ class Volume {
|
||||
off_t ToVnode(off_t block) const { return block; }
|
||||
off_t VnodeToBlock(vnode_id id) const { return (off_t)id; }
|
||||
|
||||
status_t CreateIndicesRoot(Transaction *transaction);
|
||||
status_t CreateIndicesRoot(Transaction &transaction);
|
||||
|
||||
// block bitmap
|
||||
BlockAllocator &Allocator();
|
||||
status_t AllocateForInode(Transaction *transaction, const Inode *parent,
|
||||
status_t AllocateForInode(Transaction &transaction, const Inode *parent,
|
||||
mode_t type, block_run &run);
|
||||
status_t AllocateForInode(Transaction *transaction, const block_run *parent,
|
||||
status_t AllocateForInode(Transaction &transaction, const block_run *parent,
|
||||
mode_t type, block_run &run);
|
||||
status_t Allocate(Transaction *transaction,const Inode *inode,
|
||||
status_t Allocate(Transaction &transaction, Inode *inode,
|
||||
off_t numBlocks, block_run &run, uint16 minimum = 1);
|
||||
status_t Free(Transaction *transaction, block_run run);
|
||||
status_t Free(Transaction &transaction, block_run run);
|
||||
|
||||
// cache access
|
||||
status_t WriteSuperBlock();
|
||||
status_t WriteBlocks(off_t blockNumber, const uint8 *block, uint32 numBlocks);
|
||||
void WriteCachedBlocksIfNecessary();
|
||||
status_t FlushDevice();
|
||||
|
||||
// queries
|
||||
@ -111,7 +101,7 @@ class Volume {
|
||||
status_t Sync();
|
||||
Journal *GetJournal(off_t refBlock) const;
|
||||
|
||||
BufferPool &Pool();
|
||||
void *BlockCache() { return fBlockCache; }
|
||||
|
||||
uint32 GetUniqueID();
|
||||
|
||||
@ -142,13 +132,13 @@ class Volume {
|
||||
int32 fUniqueID;
|
||||
uint32 fFlags;
|
||||
|
||||
BufferPool fBufferPool;
|
||||
void *fBlockCache;
|
||||
};
|
||||
|
||||
|
||||
// inline functions
|
||||
|
||||
inline bool
|
||||
inline bool
|
||||
Volume::IsReadOnly() const
|
||||
{
|
||||
return fFlags & VOLUME_READ_ONLY;
|
||||
@ -169,51 +159,31 @@ Volume::Allocator()
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
Volume::AllocateForInode(Transaction *transaction, const block_run *parent, mode_t type, block_run &run)
|
||||
inline status_t
|
||||
Volume::AllocateForInode(Transaction &transaction, const block_run *parent, mode_t type, block_run &run)
|
||||
{
|
||||
return fBlockAllocator.AllocateForInode(transaction, parent, type, run);
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
Volume::Allocate(Transaction *transaction, const Inode *inode, off_t numBlocks, block_run &run, uint16 minimum)
|
||||
inline status_t
|
||||
Volume::Allocate(Transaction &transaction, Inode *inode, off_t numBlocks, block_run &run, uint16 minimum)
|
||||
{
|
||||
return fBlockAllocator.Allocate(transaction, inode, numBlocks, run, minimum);
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
Volume::Free(Transaction *transaction, block_run run)
|
||||
inline status_t
|
||||
Volume::Free(Transaction &transaction, block_run run)
|
||||
{
|
||||
return fBlockAllocator.Free(transaction, run);
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
Volume::WriteBlocks(off_t blockNumber, const uint8 *block, uint32 numBlocks)
|
||||
{
|
||||
atomic_add(&fDirtyCachedBlocks, numBlocks);
|
||||
return cached_write(fDevice, blockNumber, block, numBlocks, fSuperBlock.block_size);
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
Volume::WriteCachedBlocksIfNecessary()
|
||||
{
|
||||
// the specific values are only valid for the current BeOS cache
|
||||
if (fDirtyCachedBlocks > 128) {
|
||||
force_cache_flush(fDevice, false);
|
||||
atomic_add(&fDirtyCachedBlocks, -64);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
inline status_t
|
||||
Volume::FlushDevice()
|
||||
{
|
||||
fDirtyCachedBlocks = 0;
|
||||
return flush_device(fDevice, 0);
|
||||
return block_cache_sync(fBlockCache);
|
||||
}
|
||||
|
||||
|
||||
@ -224,14 +194,7 @@ Volume::GetJournal(off_t /*refBlock*/) const
|
||||
}
|
||||
|
||||
|
||||
inline BufferPool &
|
||||
Volume::Pool()
|
||||
{
|
||||
return fBufferPool;
|
||||
}
|
||||
|
||||
|
||||
inline uint32
|
||||
inline uint32
|
||||
Volume::GetUniqueID()
|
||||
{
|
||||
return atomic_add(&fUniqueID, 1);
|
||||
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
|
||||
#ifndef _CACHE_H_
|
||||
#define _CACHE_H_
|
||||
|
||||
#include <BeBuild.h>
|
||||
|
||||
#define ALLOW_WRITES 1
|
||||
#define NO_WRITES 0
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern int init_block_cache(int max_blocks, int flags);
|
||||
extern void shutdown_block_cache(void);
|
||||
|
||||
extern void force_cache_flush(int dev, int prefer_log_blocks);
|
||||
extern int flush_blocks(int dev, off_t bnum, int nblocks);
|
||||
extern int flush_device(int dev, int warn_locked);
|
||||
|
||||
extern int init_cache_for_device(int fd, off_t max_blocks);
|
||||
extern int remove_cached_device_blocks(int dev, int allow_write);
|
||||
|
||||
extern void *get_block(int dev, off_t bnum, int bsize);
|
||||
extern void *get_empty_block(int dev, off_t bnum, int bsize);
|
||||
extern int release_block(int dev, off_t bnum);
|
||||
extern int mark_blocks_dirty(int dev, off_t bnum, int nblocks);
|
||||
|
||||
|
||||
extern int cached_read(int dev, off_t bnum, void *data, off_t num_blocks, int bsize);
|
||||
extern int cached_write(int dev, off_t bnum, const void *data,
|
||||
off_t num_blocks, int bsize);
|
||||
extern int cached_write_locked(int dev, off_t bnum, const void *data,
|
||||
off_t num_blocks, int bsize);
|
||||
extern int set_blocks_info(int dev, off_t *blocks, int nblocks,
|
||||
void (*func)(off_t bnum, size_t nblocks, void *arg),
|
||||
void *arg);
|
||||
|
||||
extern size_t read_phys_blocks (int fd, off_t bnum, void *data, uint num_blocks, int bsize);
|
||||
extern size_t write_phys_blocks(int fd, off_t bnum, void *data, uint num_blocks, int bsize);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _CACHE_H_ */
|
@ -1,247 +0,0 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
|
||||
#ifndef _FSPROTO_H
|
||||
#define _FSPROTO_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <iovec.h>
|
||||
|
||||
#include <OS.h>
|
||||
#include <NodeMonitor.h>
|
||||
#include <fs_attr.h>
|
||||
#include <fs_info.h>
|
||||
#include <BeBuild.h>
|
||||
#include <Drivers.h>
|
||||
|
||||
typedef dev_t nspace_id;
|
||||
typedef ino_t vnode_id;
|
||||
|
||||
/*
|
||||
* PUBLIC PART OF THE FILE SYSTEM PROTOCOL
|
||||
*/
|
||||
|
||||
#define WSTAT_MODE 0x0001
|
||||
#define WSTAT_UID 0x0002
|
||||
#define WSTAT_GID 0x0004
|
||||
#define WSTAT_SIZE 0x0008
|
||||
#define WSTAT_ATIME 0x0010
|
||||
#define WSTAT_MTIME 0x0020
|
||||
#define WSTAT_CRTIME 0x0040
|
||||
|
||||
#define WFSSTAT_NAME 0x0001
|
||||
|
||||
#define SELECT_READ 1
|
||||
#define SELECT_WRITE 2
|
||||
#define SELECT_EXCEPTION 3
|
||||
|
||||
// missing ioctl() call added
|
||||
#define IOCTL_FILE_UNCACHED_IO 10000
|
||||
#define IOCTL_CREATE_TIME 10002
|
||||
#define IOCTL_MODIFIED_TIME 10003
|
||||
|
||||
|
||||
// B_CUR_FS_API_VERSION is 2 for R5, but 3 on Zeta and Dano, because
|
||||
// of the added calls for power management - so it's set to 3 here
|
||||
// because that's a requirement to let Dano boot from our fs...
|
||||
#ifdef COMPILE_FOR_ZETA
|
||||
# define B_CUR_FS_API_VERSION 3
|
||||
#else
|
||||
# define B_CUR_FS_API_VERSION 2
|
||||
#endif
|
||||
|
||||
struct attr_info;
|
||||
struct index_info;
|
||||
|
||||
typedef int op_read_vnode(void *ns, vnode_id vnid, char r, void **node);
|
||||
typedef int op_write_vnode(void *ns, void *node, char r);
|
||||
typedef int op_remove_vnode(void *ns, void *node, char r);
|
||||
typedef int op_secure_vnode(void *ns, void *node);
|
||||
typedef int op_wake_vnode(void *ns, void *node);
|
||||
typedef int op_suspend_vnode(void *ns, void *node);
|
||||
|
||||
typedef int op_walk(void *ns, void *base, const char *file, char **newpath,
|
||||
vnode_id *vnid);
|
||||
|
||||
typedef int op_access(void *ns, void *node, int mode);
|
||||
|
||||
typedef int op_create(void *ns, void *dir, const char *name,
|
||||
int omode, int perms, vnode_id *vnid, void **cookie);
|
||||
typedef int op_mkdir(void *ns, void *dir, const char *name, int perms);
|
||||
typedef int op_symlink(void *ns, void *dir, const char *name,
|
||||
const char *path);
|
||||
typedef int op_link(void *ns, void *dir, const char *name, void *node);
|
||||
|
||||
typedef int op_rename(void *ns, void *olddir, const char *oldname,
|
||||
void *newdir, const char *newname);
|
||||
typedef int op_unlink(void *ns, void *dir, const char *name);
|
||||
typedef int op_rmdir(void *ns, void *dir, const char *name);
|
||||
|
||||
typedef int op_readlink(void *ns, void *node, char *buf, size_t *bufsize);
|
||||
|
||||
typedef int op_opendir(void *ns, void *node, void **cookie);
|
||||
typedef int op_closedir(void *ns, void *node, void *cookie);
|
||||
typedef int op_rewinddir(void *ns, void *node, void *cookie);
|
||||
typedef int op_readdir(void *ns, void *node, void *cookie, long *num,
|
||||
struct dirent *buf, size_t bufsize);
|
||||
|
||||
typedef int op_open(void *ns, void *node, int omode, void **cookie);
|
||||
typedef int op_close(void *ns, void *node, void *cookie);
|
||||
typedef int op_free_cookie(void *ns, void *node, void *cookie);
|
||||
typedef int op_read(void *ns, void *node, void *cookie, off_t pos, void *buf,
|
||||
size_t *len);
|
||||
typedef int op_write(void *ns, void *node, void *cookie, off_t pos,
|
||||
const void *buf, size_t *len);
|
||||
typedef int op_readv(void *ns, void *node, void *cookie, off_t pos, const iovec *vec,
|
||||
size_t count, size_t *len);
|
||||
typedef int op_writev(void *ns, void *node, void *cookie, off_t pos, const iovec *vec,
|
||||
size_t count, size_t *len);
|
||||
typedef int op_ioctl(void *ns, void *node, void *cookie, int cmd, void *buf,
|
||||
size_t len);
|
||||
typedef int op_setflags(void *ns, void *node, void *cookie, int flags);
|
||||
|
||||
typedef int op_rstat(void *ns, void *node, struct stat *);
|
||||
typedef int op_wstat(void *ns, void *node, struct stat *, long mask);
|
||||
typedef int op_fsync(void *ns, void *node);
|
||||
|
||||
typedef int op_select(void *ns, void *node, void *cookie, uint8 event,
|
||||
uint32 ref, selectsync *sync);
|
||||
typedef int op_deselect(void *ns, void *node, void *cookie, uint8 event,
|
||||
selectsync *sync);
|
||||
|
||||
typedef int op_initialize(const char *devname, void *parms, size_t len);
|
||||
typedef int op_mount(nspace_id nsid, const char *devname, ulong flags,
|
||||
void *parms, size_t len, void **data, vnode_id *vnid);
|
||||
typedef int op_unmount(void *ns);
|
||||
typedef int op_sync(void *ns);
|
||||
typedef int op_rfsstat(void *ns, struct fs_info *);
|
||||
typedef int op_wfsstat(void *ns, struct fs_info *, long mask);
|
||||
|
||||
|
||||
typedef int op_open_attrdir(void *ns, void *node, void **cookie);
|
||||
typedef int op_close_attrdir(void *ns, void *node, void *cookie);
|
||||
typedef int op_rewind_attrdir(void *ns, void *node, void *cookie);
|
||||
typedef int op_read_attrdir(void *ns, void *node, void *cookie, long *num,
|
||||
struct dirent *buf, size_t bufsize);
|
||||
typedef int op_remove_attr(void *ns, void *node, const char *name);
|
||||
typedef int op_rename_attr(void *ns, void *node, const char *oldname,
|
||||
const char *newname);
|
||||
typedef int op_stat_attr(void *ns, void *node, const char *name,
|
||||
struct attr_info *buf);
|
||||
|
||||
typedef int op_write_attr(void *ns, void *node, const char *name, int type,
|
||||
const void *buf, size_t *len, off_t pos);
|
||||
typedef int op_read_attr(void *ns, void *node, const char *name, int type,
|
||||
void *buf, size_t *len, off_t pos);
|
||||
|
||||
typedef int op_open_indexdir(void *ns, void **cookie);
|
||||
typedef int op_close_indexdir(void *ns, void *cookie);
|
||||
typedef int op_rewind_indexdir(void *ns, void *cookie);
|
||||
typedef int op_read_indexdir(void *ns, void *cookie, long *num,
|
||||
struct dirent *buf, size_t bufsize);
|
||||
typedef int op_create_index(void *ns, const char *name, int type, int flags);
|
||||
typedef int op_remove_index(void *ns, const char *name);
|
||||
typedef int op_rename_index(void *ns, const char *oldname,
|
||||
const char *newname);
|
||||
typedef int op_stat_index(void *ns, const char *name, struct index_info *buf);
|
||||
|
||||
typedef int op_open_query(void *ns, const char *query, ulong flags,
|
||||
port_id port, long token, void **cookie);
|
||||
typedef int op_close_query(void *ns, void *cookie);
|
||||
typedef int op_read_query(void *ns, void *cookie, long *num,
|
||||
struct dirent *buf, size_t bufsize);
|
||||
|
||||
typedef struct vnode_ops {
|
||||
op_read_vnode (*read_vnode);
|
||||
op_write_vnode (*write_vnode);
|
||||
op_remove_vnode (*remove_vnode);
|
||||
op_secure_vnode (*secure_vnode);
|
||||
op_walk (*walk);
|
||||
op_access (*access);
|
||||
op_create (*create);
|
||||
op_mkdir (*mkdir);
|
||||
op_symlink (*symlink);
|
||||
op_link (*link);
|
||||
op_rename (*rename);
|
||||
op_unlink (*unlink);
|
||||
op_rmdir (*rmdir);
|
||||
op_readlink (*readlink);
|
||||
op_opendir (*opendir);
|
||||
op_closedir (*closedir);
|
||||
op_free_cookie (*free_dircookie);
|
||||
op_rewinddir (*rewinddir);
|
||||
op_readdir (*readdir);
|
||||
op_open (*open);
|
||||
op_close (*close);
|
||||
op_free_cookie (*free_cookie);
|
||||
op_read (*read);
|
||||
op_write (*write);
|
||||
op_readv (*readv);
|
||||
op_writev (*writev);
|
||||
op_ioctl (*ioctl);
|
||||
op_setflags (*setflags);
|
||||
op_rstat (*rstat);
|
||||
op_wstat (*wstat);
|
||||
op_fsync (*fsync);
|
||||
op_initialize (*initialize);
|
||||
op_mount (*mount);
|
||||
op_unmount (*unmount);
|
||||
op_sync (*sync);
|
||||
op_rfsstat (*rfsstat);
|
||||
op_wfsstat (*wfsstat);
|
||||
op_select (*select);
|
||||
op_deselect (*deselect);
|
||||
op_open_indexdir (*open_indexdir);
|
||||
op_close_indexdir (*close_indexdir);
|
||||
op_free_cookie (*free_indexdircookie);
|
||||
op_rewind_indexdir (*rewind_indexdir);
|
||||
op_read_indexdir (*read_indexdir);
|
||||
op_create_index (*create_index);
|
||||
op_remove_index (*remove_index);
|
||||
op_rename_index (*rename_index);
|
||||
op_stat_index (*stat_index);
|
||||
op_open_attrdir (*open_attrdir);
|
||||
op_close_attrdir (*close_attrdir);
|
||||
op_free_cookie (*free_attrdircookie);
|
||||
op_rewind_attrdir (*rewind_attrdir);
|
||||
op_read_attrdir (*read_attrdir);
|
||||
op_write_attr (*write_attr);
|
||||
op_read_attr (*read_attr);
|
||||
op_remove_attr (*remove_attr);
|
||||
op_rename_attr (*rename_attr);
|
||||
op_stat_attr (*stat_attr);
|
||||
op_open_query (*open_query);
|
||||
op_close_query (*close_query);
|
||||
op_free_cookie (*free_querycookie);
|
||||
op_read_query (*read_query);
|
||||
// for Dano compatibility only
|
||||
op_wake_vnode (*wake_vnode);
|
||||
op_suspend_vnode (*suspend_vnode);
|
||||
} vnode_ops;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern _IMPEXP_KERNEL int new_path(const char *path, char **copy);
|
||||
extern _IMPEXP_KERNEL void free_path(char *p);
|
||||
|
||||
extern _IMPEXP_KERNEL void notify_select_event(selectsync *sync, uint32 ref);
|
||||
extern _IMPEXP_KERNEL status_t is_vnode_removed(nspace_id nsid, vnode_id vnid);
|
||||
|
||||
// The missing prototypes can be found in the fs_interface.h file.
|
||||
// That part of the VFS is still compatible with BeOS :)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
extern _EXPORT vnode_ops fs_entry;
|
||||
extern _EXPORT int32 api_version;
|
||||
|
||||
#endif /* _FSPROTO_H */
|
@ -1,8 +1,8 @@
|
||||
/* kernel_interface - file system interface to BeOS' vnode layer
|
||||
**
|
||||
** Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de
|
||||
** This file may be used under the terms of the Haiku License.
|
||||
*/
|
||||
*
|
||||
* Copyright 2001-2004, Axel Dörfler, axeld@pinc-software.de.
|
||||
* This file may be used under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "Debug.h"
|
||||
@ -23,13 +23,6 @@
|
||||
#include <fs_interface.h>
|
||||
#include <fs_cache.h>
|
||||
|
||||
#ifndef _IMPEXP_KERNEL
|
||||
# define _IMPEXP_KERNEL
|
||||
#endif
|
||||
|
||||
#include <cache.h>
|
||||
#include <lock.h>
|
||||
|
||||
#include <fs_attr.h>
|
||||
#include <fs_info.h>
|
||||
#include <fs_index.h>
|
||||
@ -53,7 +46,8 @@ strtod(const char */*start*/, char **/*end*/)
|
||||
|
||||
|
||||
static status_t
|
||||
bfs_mount(mount_id mountID, const char *device, uint32 flags, const char *args, void **data, vnode_id *rootID)
|
||||
bfs_mount(mount_id mountID, const char *device, uint32 flags, const char *args,
|
||||
void **_data, vnode_id *_rootID)
|
||||
{
|
||||
FUNCTION();
|
||||
|
||||
@ -62,11 +56,11 @@ bfs_mount(mount_id mountID, const char *device, uint32 flags, const char *args,
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t status;
|
||||
if ((status = volume->Mount(device, B_MOUNT_READ_ONLY/*flags*/)) == B_OK) {
|
||||
*data = volume;
|
||||
*rootID = volume->ToVnode(volume->Root());
|
||||
if ((status = volume->Mount(device, flags)) == B_OK) {
|
||||
*_data = volume;
|
||||
*_rootID = volume->ToVnode(volume->Root());
|
||||
INFORM(("mounted \"%s\" (root node at %Ld, device = %s)\n",
|
||||
volume->Name(), *rootID, device));
|
||||
volume->Name(), *_rootID, device));
|
||||
}
|
||||
else
|
||||
delete volume;
|
||||
@ -232,7 +226,7 @@ restartIfBusy:
|
||||
// If not, we create a new one here
|
||||
|
||||
if (inode == NULL) {
|
||||
inode = new Inode(&cached);
|
||||
inode = new Inode(volume, id);
|
||||
if (inode == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
@ -242,12 +236,8 @@ restartIfBusy:
|
||||
} else
|
||||
status = inode->InitCheck(false);
|
||||
|
||||
if (status == B_OK) {
|
||||
if (inode->IsFile() && inode->FileCache() == NULL)
|
||||
inode->SetFileCache(file_cache_create(volume->ID(), inode->ID(), inode->Size(), volume->Device()));
|
||||
|
||||
if (status == B_OK)
|
||||
*_node = inode;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -299,7 +289,7 @@ bfs_remove_vnode(void *_ns, void *_node, bool reenter)
|
||||
localTransaction.Start(volume, inode->BlockNumber());
|
||||
}
|
||||
|
||||
status_t status = inode->Free(transaction);
|
||||
status_t status = inode->Free(*transaction);
|
||||
if (status == B_OK) {
|
||||
if (transaction == &localTransaction)
|
||||
localTransaction.Done();
|
||||
@ -471,31 +461,6 @@ bfs_ioctl(void *_ns, void *_node, void *_cookie, ulong cmd, void *buffer, size_t
|
||||
Inode *inode = (Inode *)_node;
|
||||
|
||||
switch (cmd) {
|
||||
case IOCTL_FILE_UNCACHED_IO:
|
||||
{
|
||||
if (inode == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// if the inode is already set up for uncached access, bail out
|
||||
if (inode->Flags() & INODE_NO_CACHE) {
|
||||
FATAL(("File %Ld is already uncached\n", inode->ID()));
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
PRINT(("uncached access to inode %Ld\n", inode->ID()));
|
||||
|
||||
// ToDo: sync the cache for this file!
|
||||
// Unfortunately, we can't remove any blocks from the cache in BeOS,
|
||||
// that means we can't guarantee consistency for the file contents
|
||||
// spanning over both access modes.
|
||||
|
||||
// request buffers for being able to access the file without
|
||||
// using the cache or allocating memory
|
||||
status_t status = volume->Pool().RequestBuffers(volume->BlockSize());
|
||||
if (status == B_OK)
|
||||
inode->Node()->flags |= HOST_ENDIAN_TO_BFS_INT32(INODE_NO_CACHE);
|
||||
return status;
|
||||
}
|
||||
case BFS_IOCTL_VERSION:
|
||||
{
|
||||
uint32 *version = (uint32 *)buffer;
|
||||
@ -511,7 +476,7 @@ bfs_ioctl(void *_ns, void *_node, void *_cookie, ulong cmd, void *buffer, size_t
|
||||
|
||||
status_t status = allocator.StartChecking(control);
|
||||
if (status == B_OK && inode != NULL)
|
||||
inode->Node()->flags |= HOST_ENDIAN_TO_BFS_INT32(INODE_CHKBFS_RUNNING);
|
||||
inode->Node().flags |= HOST_ENDIAN_TO_BFS_INT32(INODE_CHKBFS_RUNNING);
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -523,7 +488,7 @@ bfs_ioctl(void *_ns, void *_node, void *_cookie, ulong cmd, void *buffer, size_t
|
||||
|
||||
status_t status = allocator.StopChecking(control);
|
||||
if (status == B_OK && inode != NULL)
|
||||
inode->Node()->flags &= HOST_ENDIAN_TO_BFS_INT32(~INODE_CHKBFS_RUNNING);
|
||||
inode->Node().flags &= HOST_ENDIAN_TO_BFS_INT32(~INODE_CHKBFS_RUNNING);
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -543,14 +508,12 @@ bfs_ioctl(void *_ns, void *_node, void *_cookie, ulong cmd, void *buffer, size_t
|
||||
Transaction transaction(volume, 0);
|
||||
CachedBlock cached(volume);
|
||||
block_run run;
|
||||
while (allocator.AllocateBlocks(&transaction, 8, 0, 64, 1, run) == B_OK) {
|
||||
while (allocator.AllocateBlocks(transaction, 8, 0, 64, 1, run) == B_OK) {
|
||||
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.SetTo(run);
|
||||
if (block != NULL) {
|
||||
uint8 *block = cached.SetToWritable(transaction, run);
|
||||
if (block != NULL)
|
||||
memset(block, 0, volume->BlockSize());
|
||||
cached.WriteBack(&transaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
return B_OK;
|
||||
@ -560,11 +523,13 @@ bfs_ioctl(void *_ns, void *_node, void *_cookie, ulong cmd, void *buffer, size_t
|
||||
return B_OK;
|
||||
case 56744:
|
||||
if (inode != NULL)
|
||||
dump_inode(inode->Node());
|
||||
dump_inode(&inode->Node());
|
||||
return B_OK;
|
||||
case 56745:
|
||||
if (inode != NULL)
|
||||
dump_block((const char *)inode->Node(), volume->BlockSize());
|
||||
if (inode != NULL) {
|
||||
NodeGetter node(volume, inode);
|
||||
dump_block((const char *)node.Node(), volume->BlockSize());
|
||||
}
|
||||
return B_OK;
|
||||
#endif
|
||||
}
|
||||
@ -630,26 +595,27 @@ bfs_read_stat(void *_ns, void *_node, struct stat *st)
|
||||
|
||||
Volume *volume = (Volume *)_ns;
|
||||
Inode *inode = (Inode *)_node;
|
||||
bfs_inode *node = inode->Node();
|
||||
|
||||
const bfs_inode &node = inode->Node();
|
||||
|
||||
st->st_dev = volume->ID();
|
||||
st->st_ino = inode->ID();
|
||||
st->st_nlink = 1;
|
||||
st->st_blksize = BFS_IO_SIZE;
|
||||
|
||||
st->st_uid = node->UserID();
|
||||
st->st_gid = node->GroupID();
|
||||
st->st_mode = node->Mode();
|
||||
st->st_uid = node.UserID();
|
||||
st->st_gid = node.GroupID();
|
||||
st->st_mode = node.Mode();
|
||||
|
||||
if (inode->IsSymLink() && (node->Flags() & INODE_LONG_SYMLINK) == 0) {
|
||||
if (inode->IsSymLink() && (node.Flags() & INODE_LONG_SYMLINK) == 0) {
|
||||
// symlinks report the size of the link here
|
||||
st->st_size = strlen(node->short_symlink) + 1;
|
||||
st->st_size = strlen(node.short_symlink) + 1;
|
||||
} else
|
||||
st->st_size = node->data.Size();
|
||||
st->st_size = inode->Size();
|
||||
|
||||
st->st_atime = time(NULL);
|
||||
st->st_mtime = st->st_ctime = (time_t)(node->LastModifiedTime() >> INODE_TIME_SHIFT);
|
||||
st->st_crtime = (time_t)(node->CreateTime() >> INODE_TIME_SHIFT);
|
||||
st->st_mtime = st->st_ctime = (time_t)(node.LastModifiedTime() >> INODE_TIME_SHIFT);
|
||||
st->st_crtime = (time_t)(node.CreateTime() >> INODE_TIME_SHIFT);
|
||||
|
||||
return B_NO_ERROR;
|
||||
}
|
||||
@ -684,7 +650,7 @@ bfs_write_stat(void *_ns, void *_node, const struct stat *stat, uint32 mask)
|
||||
|
||||
Transaction transaction(volume, inode->BlockNumber());
|
||||
|
||||
bfs_inode *node = inode->Node();
|
||||
bfs_inode &node = inode->Node();
|
||||
|
||||
if (mask & FS_WRITE_STAT_SIZE) {
|
||||
// Since WSTAT_SIZE is the only thing that can fail directly, we
|
||||
@ -694,7 +660,7 @@ bfs_write_stat(void *_ns, void *_node, const struct stat *stat, uint32 mask)
|
||||
return B_IS_A_DIRECTORY;
|
||||
|
||||
if (inode->Size() != stat->st_size) {
|
||||
status = inode->SetFileSize(&transaction, stat->st_size);
|
||||
status = inode->SetFileSize(transaction, stat->st_size);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
@ -702,34 +668,34 @@ bfs_write_stat(void *_ns, void *_node, const struct stat *stat, uint32 mask)
|
||||
inode->FillGapWithZeros(inode->OldSize(), inode->Size());
|
||||
|
||||
Index index(volume);
|
||||
index.UpdateSize(&transaction, inode);
|
||||
index.UpdateSize(transaction, inode);
|
||||
|
||||
if ((mask & FS_WRITE_STAT_MTIME) == 0)
|
||||
index.UpdateLastModified(&transaction, inode);
|
||||
index.UpdateLastModified(transaction, inode);
|
||||
}
|
||||
}
|
||||
|
||||
if (mask & FS_WRITE_STAT_MODE) {
|
||||
PRINT(("original mode = %ld, stat->st_mode = %d\n", node->mode, stat->st_mode));
|
||||
node->mode = node->mode & ~S_IUMSK | stat->st_mode & S_IUMSK;
|
||||
PRINT(("original mode = %ld, stat->st_mode = %d\n", node.Mode(), stat->st_mode));
|
||||
node.mode = HOST_ENDIAN_TO_BFS_INT32(node.Mode() & ~S_IUMSK | stat->st_mode & S_IUMSK);
|
||||
}
|
||||
|
||||
if (mask & FS_WRITE_STAT_UID)
|
||||
node->uid = stat->st_uid;
|
||||
node.uid = HOST_ENDIAN_TO_BFS_INT32(stat->st_uid);
|
||||
if (mask & FS_WRITE_STAT_GID)
|
||||
node->gid = stat->st_gid;
|
||||
node.gid = HOST_ENDIAN_TO_BFS_INT32(stat->st_gid);
|
||||
|
||||
if (mask & FS_WRITE_STAT_MTIME) {
|
||||
// Index::UpdateLastModified() will set the new time in the inode
|
||||
Index index(volume);
|
||||
index.UpdateLastModified(&transaction, inode,
|
||||
index.UpdateLastModified(transaction, inode,
|
||||
(bigtime_t)stat->st_mtime << INODE_TIME_SHIFT);
|
||||
}
|
||||
if (mask & FS_WRITE_STAT_CRTIME) {
|
||||
node->create_time = (bigtime_t)stat->st_crtime << INODE_TIME_SHIFT;
|
||||
node.create_time = HOST_ENDIAN_TO_BFS_INT64((bigtime_t)stat->st_crtime << INODE_TIME_SHIFT);
|
||||
}
|
||||
|
||||
if ((status = inode->WriteBack(&transaction)) == B_OK)
|
||||
if ((status = inode->WriteBack(transaction)) == B_OK)
|
||||
transaction.Done();
|
||||
|
||||
notify_listener(B_STAT_CHANGED, volume->ID(), 0, 0, inode->ID(), NULL);
|
||||
@ -774,7 +740,7 @@ bfs_create(void *_ns, void *_directory, const char *name, int omode, int mode,
|
||||
#endif
|
||||
Transaction transaction(volume, directory->BlockNumber());
|
||||
|
||||
status = Inode::Create(&transaction, directory, name, S_FILE | (mode & S_IUMSK),
|
||||
status = Inode::Create(transaction, directory, name, S_FILE | (mode & S_IUMSK),
|
||||
omode, 0, vnodeID);
|
||||
|
||||
if (status >= B_OK) {
|
||||
@ -817,23 +783,25 @@ bfs_create_symlink(void *_ns, void *_directory, const char *name, const char *pa
|
||||
|
||||
Inode *link;
|
||||
off_t id;
|
||||
status = Inode::Create(&transaction, directory, name, S_SYMLINK | 0777, 0, 0, &id, &link);
|
||||
status = Inode::Create(transaction, directory, name, S_SYMLINK | 0777, 0, 0, &id, &link);
|
||||
if (status < B_OK)
|
||||
RETURN_ERROR(status);
|
||||
|
||||
size_t length = strlen(path);
|
||||
if (length < SHORT_SYMLINK_NAME_LENGTH) {
|
||||
strcpy(link->Node()->short_symlink, path);
|
||||
status = link->WriteBack(&transaction);
|
||||
strcpy(link->Node().short_symlink, path);
|
||||
} else {
|
||||
link->Node()->flags |= HOST_ENDIAN_TO_BFS_INT32(INODE_LONG_SYMLINK | INODE_LOGGED);
|
||||
link->Node().flags |= HOST_ENDIAN_TO_BFS_INT32(INODE_LONG_SYMLINK | INODE_LOGGED);
|
||||
// The following call will have to write the inode back, so
|
||||
// we don't have to do that here...
|
||||
status = link->WriteAt(&transaction, 0, (const uint8 *)path, &length);
|
||||
status = link->WriteAt(transaction, 0, (const uint8 *)path, &length);
|
||||
}
|
||||
// ToDo: would be nice if Inode::Create() would let the INODE_NOT_READY
|
||||
// flag set until here, so that it can be accessed directly
|
||||
|
||||
if (status == B_OK)
|
||||
status = link->WriteBack(transaction);
|
||||
|
||||
// Inode::Create() left the inode locked in memory
|
||||
put_vnode(volume->ID(), id);
|
||||
|
||||
@ -881,7 +849,7 @@ bfs_unlink(void *_ns, void *_directory, const char *name)
|
||||
Transaction transaction(volume, directory->BlockNumber());
|
||||
|
||||
off_t id;
|
||||
if ((status = directory->Remove(&transaction, name, &id)) == B_OK) {
|
||||
if ((status = directory->Remove(transaction, name, &id)) == B_OK) {
|
||||
transaction.Done();
|
||||
|
||||
notify_listener(B_ENTRY_REMOVED, volume->ID(), directory->ID(), 0, id, NULL);
|
||||
@ -968,7 +936,7 @@ bfs_rename(void *_ns, void *_oldDir, const char *oldName, void *_newDir, const c
|
||||
RETURN_ERROR(status);
|
||||
}
|
||||
|
||||
status = newTree->Insert(&transaction, (const uint8 *)newName, strlen(newName), id);
|
||||
status = newTree->Insert(transaction, (const uint8 *)newName, strlen(newName), id);
|
||||
if (status == B_NAME_IN_USE) {
|
||||
// If there is already a file with that name, we have to remove
|
||||
// it, as long it's not a directory with files in it
|
||||
@ -983,13 +951,13 @@ bfs_rename(void *_ns, void *_oldDir, const char *oldName, void *_newDir, const c
|
||||
if (vnode.Get(&other) < B_OK)
|
||||
return B_NAME_IN_USE;
|
||||
|
||||
status = newDirectory->Remove(&transaction, newName, NULL, other->IsDirectory());
|
||||
status = newDirectory->Remove(transaction, newName, NULL, other->IsDirectory());
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
notify_listener(B_ENTRY_REMOVED, volume->ID(), newDirectory->ID(), 0, clobber, NULL);
|
||||
|
||||
status = newTree->Insert(&transaction, (const uint8 *)newName, strlen(newName), id);
|
||||
status = newTree->Insert(transaction, (const uint8 *)newName, strlen(newName), id);
|
||||
}
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
@ -1001,18 +969,18 @@ bfs_rename(void *_ns, void *_oldDir, const char *oldName, void *_newDir, const c
|
||||
// update the name only when they differ
|
||||
bool nameUpdated = false;
|
||||
if (strcmp(oldName, newName)) {
|
||||
status = inode->SetName(&transaction, newName);
|
||||
status = inode->SetName(transaction, newName);
|
||||
if (status == B_OK) {
|
||||
Index index(volume);
|
||||
index.UpdateName(&transaction, oldName, newName, inode);
|
||||
index.UpdateName(transaction, oldName, newName, inode);
|
||||
nameUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (status == B_OK) {
|
||||
status = tree->Remove(&transaction, (const uint8 *)oldName, strlen(oldName), id);
|
||||
status = tree->Remove(transaction, (const uint8 *)oldName, strlen(oldName), id);
|
||||
if (status == B_OK) {
|
||||
inode->Node()->parent = newDirectory->BlockRun();
|
||||
inode->Parent() = newDirectory->BlockRun();
|
||||
|
||||
// if it's a directory, update the parent directory pointer
|
||||
// in its tree if necessary
|
||||
@ -1020,17 +988,17 @@ bfs_rename(void *_ns, void *_oldDir, const char *oldName, void *_newDir, const c
|
||||
if (oldDirectory != newDirectory
|
||||
&& inode->IsDirectory()
|
||||
&& (status = inode->GetTree(&movedTree)) == B_OK)
|
||||
status = movedTree->Replace(&transaction, (const uint8 *)"..", 2, newDirectory->ID());
|
||||
status = movedTree->Replace(transaction, (const uint8 *)"..", 2, newDirectory->ID());
|
||||
|
||||
if (status == B_OK)
|
||||
status = inode->WriteBack(transaction);
|
||||
|
||||
if (status == B_OK) {
|
||||
status = inode->WriteBack(&transaction);
|
||||
if (status == B_OK) {
|
||||
transaction.Done();
|
||||
transaction.Done();
|
||||
|
||||
notify_listener(B_ENTRY_MOVED, volume->ID(), oldDirectory->ID(),
|
||||
newDirectory->ID(), id, newName);
|
||||
return B_OK;
|
||||
}
|
||||
notify_listener(B_ENTRY_MOVED, volume->ID(), oldDirectory->ID(),
|
||||
newDirectory->ID(), id, newName);
|
||||
return B_OK;
|
||||
}
|
||||
// If we get here, something has gone wrong already!
|
||||
|
||||
@ -1039,25 +1007,25 @@ bfs_rename(void *_ns, void *_oldDir, const char *oldName, void *_newDir, const c
|
||||
// for us)
|
||||
// Anyway, if we overwrote a file in the target directory
|
||||
// this is lost now (only in-memory, not on-disk)...
|
||||
bailStatus = tree->Insert(&transaction, (const uint8 *)oldName, strlen(oldName), id);
|
||||
bailStatus = tree->Insert(transaction, (const uint8 *)oldName, strlen(oldName), id);
|
||||
if (movedTree != NULL)
|
||||
movedTree->Replace(&transaction, (const uint8 *)"..", 2, oldDirectory->ID());
|
||||
movedTree->Replace(transaction, (const uint8 *)"..", 2, oldDirectory->ID());
|
||||
}
|
||||
}
|
||||
|
||||
if (bailStatus == B_OK && nameUpdated) {
|
||||
bailStatus = inode->SetName(&transaction, oldName);
|
||||
bailStatus = inode->SetName(transaction, oldName);
|
||||
if (status == B_OK) {
|
||||
// update inode and index
|
||||
inode->WriteBack(&transaction);
|
||||
inode->WriteBack(transaction);
|
||||
|
||||
Index index(volume);
|
||||
index.UpdateName(&transaction, newName, oldName, inode);
|
||||
index.UpdateName(transaction, newName, oldName, inode);
|
||||
}
|
||||
}
|
||||
|
||||
if (bailStatus == B_OK)
|
||||
bailStatus = newTree->Remove(&transaction, (const uint8 *)newName, strlen(newName), id);
|
||||
bailStatus = newTree->Remove(transaction, (const uint8 *)newName, strlen(newName), id);
|
||||
|
||||
if (bailStatus < B_OK)
|
||||
volume->Panic();
|
||||
@ -1092,7 +1060,7 @@ bfs_open(void *_ns, void *_node, int omode, void **_cookie)
|
||||
//return B_IS_A_DIRECTORY;
|
||||
}
|
||||
|
||||
status_t status = inode->CheckPermissions(oModeToAccess(omode));
|
||||
status_t status = inode->CheckPermissions(openModeToAccess(omode));
|
||||
if (status < B_OK)
|
||||
RETURN_ERROR(status);
|
||||
|
||||
@ -1119,7 +1087,7 @@ bfs_open(void *_ns, void *_node, int omode, void **_cookie)
|
||||
WriteLocked locked(inode->Lock());
|
||||
Transaction transaction(volume, inode->BlockNumber());
|
||||
|
||||
status_t status = inode->SetFileSize(&transaction, 0);
|
||||
status_t status = inode->SetFileSize(transaction, 0);
|
||||
if (status < B_OK) {
|
||||
// bfs_free_cookie() is only called if this function is successful
|
||||
free(cookie);
|
||||
@ -1150,7 +1118,7 @@ bfs_read(void *_ns, void *_node, void *_cookie, off_t pos, void *buffer, size_t
|
||||
}
|
||||
|
||||
ReadLocked locked(inode->Lock());
|
||||
return file_cache_read(inode->FileCache(), pos, buffer, _length);
|
||||
return inode->ReadAt(pos, (uint8 *)buffer, _length);
|
||||
}
|
||||
|
||||
|
||||
@ -1184,7 +1152,7 @@ bfs_write(void *_ns, void *_node, void *_cookie, off_t pos, const void *buffer,
|
||||
// it might not be needed at all (the contents of
|
||||
// regular files aren't logged)
|
||||
|
||||
status_t status = inode->WriteAt(&transaction, pos, (const uint8 *)buffer, _length);
|
||||
status_t status = inode->WriteAt(transaction, pos, (const uint8 *)buffer, _length);
|
||||
|
||||
if (status == B_OK)
|
||||
transaction.Done();
|
||||
@ -1201,12 +1169,6 @@ bfs_write(void *_ns, void *_node, void *_cookie, off_t pos, const void *buffer,
|
||||
cookie->last_size = inode->Size();
|
||||
cookie->last_notification = system_time();
|
||||
}
|
||||
|
||||
// This will flush the dirty blocks to disk from time to time.
|
||||
// It's done here and not in Inode::WriteAt() so that it won't
|
||||
// add to the duration of a transaction - it might even be a
|
||||
// good idea to offload those calls to another thread
|
||||
volume->WriteCachedBlocksIfNecessary();
|
||||
}
|
||||
|
||||
return status;
|
||||
@ -1256,19 +1218,19 @@ bfs_free_cookie(void *_ns, void *_node, void *_cookie)
|
||||
Index index(volume);
|
||||
|
||||
if (inode->OldSize() != inode->Size()) {
|
||||
status = inode->Trim(&transaction);
|
||||
status = inode->Trim(transaction);
|
||||
if (status < B_OK)
|
||||
FATAL(("Could not trim preallocated blocks!"));
|
||||
|
||||
index.UpdateSize(&transaction, inode);
|
||||
index.UpdateSize(transaction, inode);
|
||||
changed = true;
|
||||
}
|
||||
if (inode->OldLastModified() != inode->LastModified()) {
|
||||
index.UpdateLastModified(&transaction, inode, inode->LastModified());
|
||||
index.UpdateLastModified(transaction, inode, inode->LastModified());
|
||||
changed = true;
|
||||
|
||||
|
||||
// updating the index doesn't write back the inode
|
||||
inode->WriteBack(&transaction);
|
||||
inode->WriteBack(transaction);
|
||||
}
|
||||
|
||||
if (status == B_OK)
|
||||
@ -1278,14 +1240,6 @@ bfs_free_cookie(void *_ns, void *_node, void *_cookie)
|
||||
notify_listener(B_STAT_CHANGED, volume->ID(), 0, 0, inode->ID(), NULL);
|
||||
}
|
||||
|
||||
if (inode->Flags() & INODE_NO_CACHE) {
|
||||
volume->Pool().ReleaseBuffers();
|
||||
inode->Node()->flags &= HOST_ENDIAN_TO_BFS_INT32(~INODE_NO_CACHE);
|
||||
// We don't need to save the inode, because INODE_NO_CACHE is a
|
||||
// non-permanent flag which will be removed when the inode is loaded
|
||||
// into memory.
|
||||
}
|
||||
|
||||
if (inode->Flags() & INODE_CHKBFS_RUNNING) {
|
||||
// "chkbfs" exited abnormally, so we have to stop it here...
|
||||
FATAL(("check process was aborted!\n"));
|
||||
@ -1340,7 +1294,7 @@ bfs_read_link(void *_ns, void *_node, char *buffer, size_t bufferSize)
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
if (strlcpy(buffer, inode->Node()->short_symlink, bufferSize) > bufferSize)
|
||||
if (strlcpy(buffer, inode->Node().short_symlink, bufferSize) > bufferSize)
|
||||
return B_BUFFER_OVERFLOW;
|
||||
|
||||
return B_OK;
|
||||
@ -1378,7 +1332,7 @@ bfs_create_dir(void *_ns, void *_directory, const char *name, int mode, vnode_id
|
||||
// Inode::Create() locks the inode if we pass the "id" parameter, but we
|
||||
// need it anyway
|
||||
off_t id;
|
||||
status = Inode::Create(&transaction, directory, name, S_DIRECTORY | (mode & S_IUMSK), 0, 0, &id);
|
||||
status = Inode::Create(transaction, directory, name, S_DIRECTORY | (mode & S_IUMSK), 0, 0, &id);
|
||||
if (status == B_OK) {
|
||||
*_newVnodeID = id;
|
||||
put_vnode(volume->ID(), id);
|
||||
@ -1408,7 +1362,7 @@ bfs_remove_dir(void *_ns, void *_directory, const char *name)
|
||||
Transaction transaction(volume, directory->BlockNumber());
|
||||
|
||||
off_t id;
|
||||
status_t status = directory->Remove(&transaction, name, &id, true);
|
||||
status_t status = directory->Remove(transaction, name, &id, true);
|
||||
if (status == B_OK) {
|
||||
transaction.Done();
|
||||
|
||||
@ -1475,11 +1429,7 @@ bfs_read_dir(void *_ns, void *_node, void *_cookie, struct dirent *dirent,
|
||||
dirent->d_dev = volume->ID();
|
||||
dirent->d_ino = id;
|
||||
|
||||
#ifdef KEEP_WRONG_DIRENT_RECLEN
|
||||
dirent->d_reclen = length;
|
||||
#else
|
||||
dirent->d_reclen = sizeof(struct dirent) + length;
|
||||
#endif
|
||||
|
||||
*_num = 1;
|
||||
return B_OK;
|
||||
@ -1602,11 +1552,7 @@ bfs_read_attrdir(void *_ns, void *node, void *_cookie, long *num, struct dirent
|
||||
Volume *volume = (Volume *)_ns;
|
||||
|
||||
dirent->d_dev = volume->ID();
|
||||
#ifdef KEEP_WRONG_DIRENT_RECLEN
|
||||
dirent->d_reclen = length;
|
||||
#else
|
||||
dirent->d_reclen = sizeof(struct dirent) + length;
|
||||
#endif
|
||||
|
||||
*num = 1;
|
||||
return B_OK;
|
||||
@ -1633,7 +1579,7 @@ bfs_remove_attr(void *_ns, void *_node, const char *name)
|
||||
#endif
|
||||
Transaction transaction(volume, inode->BlockNumber());
|
||||
|
||||
status = inode->RemoveAttribute(&transaction, name);
|
||||
status = inode->RemoveAttribute(transaction, name);
|
||||
if (status == B_OK) {
|
||||
transaction.Done();
|
||||
|
||||
@ -1725,7 +1671,7 @@ bfs_write_attr(void *_ns, void *_node, const char *name, int type, const void *b
|
||||
#endif
|
||||
Transaction transaction(volume, inode->BlockNumber());
|
||||
|
||||
status = inode->WriteAttribute(&transaction, name, type, pos, (const uint8 *)buffer, _length);
|
||||
status = inode->WriteAttribute(transaction, name, type, pos, (const uint8 *)buffer, _length);
|
||||
if (status == B_OK) {
|
||||
transaction.Done();
|
||||
|
||||
@ -1830,7 +1776,7 @@ bfs_read_indexdir(fs_volume _fs, fs_cookie _cookie, struct dirent *dirent, size_
|
||||
static status_t
|
||||
bfs_create_index(fs_volume _fs, const char *name, uint32 type, uint32 flags)
|
||||
{
|
||||
FUNCTION_START(("name = \"%s\", type = %d, flags = %d\n", name, type, flags));
|
||||
FUNCTION_START(("name = \"%s\", type = %ld, flags = %ld\n", name, type, flags));
|
||||
if (_fs == NULL || name == NULL || *name == '\0')
|
||||
return B_BAD_VALUE;
|
||||
|
||||
@ -1849,7 +1795,7 @@ bfs_create_index(fs_volume _fs, const char *name, uint32 type, uint32 flags)
|
||||
Transaction transaction(volume, volume->Indices());
|
||||
|
||||
Index index(volume);
|
||||
status_t status = index.Create(&transaction, name, type);
|
||||
status_t status = index.Create(transaction, name, type);
|
||||
|
||||
if (status == B_OK)
|
||||
transaction.Done();
|
||||
@ -1883,7 +1829,7 @@ bfs_remove_index(void *_ns, const char *name)
|
||||
#endif
|
||||
Transaction transaction(volume, volume->Indices());
|
||||
|
||||
status_t status = indices->Remove(&transaction, name);
|
||||
status_t status = indices->Remove(transaction, name);
|
||||
if (status == B_OK)
|
||||
transaction.Done();
|
||||
|
||||
@ -1904,21 +1850,21 @@ bfs_stat_index(fs_volume _fs, const char *name, struct stat *stat)
|
||||
if (status < B_OK)
|
||||
RETURN_ERROR(status);
|
||||
|
||||
bfs_inode *node = index.Node()->Node();
|
||||
bfs_inode &node = index.Node()->Node();
|
||||
|
||||
stat->st_type = index.Type();
|
||||
stat->st_size = node->data.Size();
|
||||
stat->st_mode = node->Mode();
|
||||
stat->st_size = node.data.Size();
|
||||
stat->st_mode = node.Mode();
|
||||
|
||||
stat->st_nlink = 1;
|
||||
stat->st_blksize = 65536;
|
||||
|
||||
stat->st_uid = node->UserID();
|
||||
stat->st_gid = node->GroupID();
|
||||
stat->st_uid = node.UserID();
|
||||
stat->st_gid = node.GroupID();
|
||||
|
||||
stat->st_atime = time(NULL);
|
||||
stat->st_mtime = stat->st_ctime = (time_t)(node->LastModifiedTime() >> INODE_TIME_SHIFT);
|
||||
stat->st_crtime = (time_t)(node->CreateTime() >> INODE_TIME_SHIFT);
|
||||
stat->st_mtime = stat->st_ctime = (time_t)(node.LastModifiedTime() >> INODE_TIME_SHIFT);
|
||||
stat->st_crtime = (time_t)(node.CreateTime() >> INODE_TIME_SHIFT);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,51 +0,0 @@
|
||||
/*
|
||||
Copyright 1999-2001, Be Incorporated. All Rights Reserved.
|
||||
This file may be used under the terms of the Be Sample Code License.
|
||||
*/
|
||||
|
||||
#ifndef _LOCK_H
|
||||
#define _LOCK_H
|
||||
|
||||
#include <BeBuild.h>
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#else
|
||||
typedef struct lock lock;
|
||||
typedef struct mlock mlock;
|
||||
#endif
|
||||
|
||||
|
||||
struct lock {
|
||||
sem_id s;
|
||||
long c;
|
||||
};
|
||||
|
||||
struct mlock {
|
||||
sem_id s;
|
||||
};
|
||||
|
||||
extern _IMPEXP_KERNEL int new_lock(lock *l, const char *name);
|
||||
extern _IMPEXP_KERNEL int free_lock(lock *l);
|
||||
|
||||
#ifdef LOCK
|
||||
#undef LOCK
|
||||
#endif
|
||||
|
||||
#define LOCK(l) if (atomic_add(&l.c, -1) <= 0) acquire_sem(l.s);
|
||||
#define UNLOCK(l) if (atomic_add(&l.c, 1) < 0) release_sem(l.s);
|
||||
|
||||
extern _IMPEXP_KERNEL int new_mlock(mlock *l, long c, const char *name);
|
||||
extern _IMPEXP_KERNEL int free_mlock(mlock *l);
|
||||
|
||||
#define LOCKM(l,cnt) acquire_sem_etc(l.s, cnt, 0, 0)
|
||||
#define UNLOCKM(l,cnt) release_sem_etc(l.s, cnt, 0)
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user