git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24576 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-03-25 19:06:25 +00:00
parent 2f20bf154e
commit 8af46ac846
+93 -122
View File
@@ -369,11 +369,12 @@ Inode::Inode(Volume *volume, Transaction &transaction, ino_t id, mode_t mode,
Node().mode = HOST_ENDIAN_TO_BFS_INT32(mode); Node().mode = HOST_ENDIAN_TO_BFS_INT32(mode);
Node().flags = HOST_ENDIAN_TO_BFS_INT32(INODE_IN_USE); Node().flags = HOST_ENDIAN_TO_BFS_INT32(INODE_IN_USE);
Node().create_time = HOST_ENDIAN_TO_BFS_INT64((bigtime_t)time(NULL) << INODE_TIME_SHIFT); Node().create_time = HOST_ENDIAN_TO_BFS_INT64((bigtime_t)time(NULL)
<< INODE_TIME_SHIFT);
Node().last_modified_time = HOST_ENDIAN_TO_BFS_INT64(Node().create_time Node().last_modified_time = HOST_ENDIAN_TO_BFS_INT64(Node().create_time
| (volume->GetUniqueID() & INODE_TIME_MASK)); | (volume->GetUniqueID() & INODE_TIME_MASK));
// we use Volume::GetUniqueID() to avoid having too many duplicates in the // we use Volume::GetUniqueID() to avoid having too many duplicates
// last_modified index // in the last_modified index
Node().inode_size = HOST_ENDIAN_TO_BFS_INT32(volume->InodeSize()); Node().inode_size = HOST_ENDIAN_TO_BFS_INT32(volume->InodeSize());
@@ -498,8 +499,7 @@ Inode::_RemoveIterator(AttributeIterator *iterator)
} }
/*! /*! Tries to free up "bytes" space in the small_data section by moving
Tries to free up "bytes" space in the small_data section by moving
attributes to real files. Used for system attributes like the name. attributes to real files. Used for system attributes like the name.
You need to hold the fSmallDataLock when you call this method You need to hold the fSmallDataLock when you call this method
*/ */
@@ -522,7 +522,8 @@ Inode::_MakeSpaceForSmallData(Transaction &transaction, bfs_inode *node,
max = item; max = item;
} }
// remove the first one large enough to free the needed amount of bytes // Remove the first one large enough to free the needed amount of
// bytes
if (bytes < (int32)item->Size()) if (bytes < (int32)item->Size())
break; break;
} }
@@ -563,8 +564,7 @@ Inode::_MakeSpaceForSmallData(Transaction &transaction, bfs_inode *node,
} }
/*! /*! Private function which removes the given attribute from the small_data
Private function which removes the given attribute from the small_data
section. section.
You need to hold the fSmallDataLock when you call this method You need to hold the fSmallDataLock when you call this method
*/ */
@@ -581,7 +581,8 @@ Inode::_RemoveSmallData(bfs_inode *node, small_data *item, int32 index)
last = last->Next(); last = last->Next();
int32 size = (uint8 *)last - (uint8 *)next; int32 size = (uint8 *)last - (uint8 *)next;
if (size < 0 || size > (uint8 *)node + fVolume->BlockSize() - (uint8 *)next) if (size < 0
|| size > (uint8 *)node + fVolume->BlockSize() - (uint8 *)next)
return B_BAD_DATA; return B_BAD_DATA;
memmove(item, next, size); memmove(item, next, size);
@@ -635,17 +636,16 @@ Inode::_RemoveSmallData(Transaction &transaction, NodeGetter &nodeGetter,
} }
/*! /*! Try to place the given attribute in the small_data section - if the
Try to place the given attribute in the small_data section - if the
new attribute is too big to fit in that section, it returns B_DEVICE_FULL. new attribute is too big to fit in that section, it returns B_DEVICE_FULL.
In that case, the attribute should be written to a real attribute file; In that case, the attribute should be written to a real attribute file;
it's the caller's responsibility to remove any existing attributes in the small it's the caller's responsibility to remove any existing attributes in the
data section if that's the case. small data section if that's the case.
Note that you need to write back the inode yourself after having called that Note that you need to write back the inode yourself after having called that
method - it's a bad API decision that it needs a transaction but enforces you method - it's a bad API decision that it needs a transaction but enforces
to write back the inode all by yourself, but it's just more efficient in most you to write back the inode all by yourself, but it's just more efficient
cases... in most cases...
*/ */
status_t status_t
Inode::_AddSmallData(Transaction &transaction, NodeGetter &nodeGetter, Inode::_AddSmallData(Transaction &transaction, NodeGetter &nodeGetter,
@@ -685,16 +685,20 @@ Inode::_AddSmallData(Transaction &transaction, NodeGetter &nodeGetter,
// try to change the attributes value // try to change the attributes value
if (item->data_size > length if (item->data_size > length
|| force || force
|| ((uint8 *)last + length - item->DataSize()) <= ((uint8 *)node + fVolume->InodeSize())) { || ((uint8 *)last + length - item->DataSize())
// make room for the new attribute if needed (and we are forced to do so) <= ((uint8 *)node + fVolume->InodeSize())) {
if (force // Make room for the new attribute if needed (and we are forced
&& ((uint8 *)last + length - item->DataSize()) > ((uint8 *)node + fVolume->InodeSize())) { // to do so)
// We also take the free space at the end of the small_data section if (force && ((uint8 *)last + length - item->DataSize())
// into account, and request only what's really needed > ((uint8 *)node + fVolume->InodeSize())) {
// We also take the free space at the end of the small_data
// section into account, and request only what's really needed
uint32 needed = length - item->DataSize() - uint32 needed = length - item->DataSize() -
(uint32)((uint8 *)node + fVolume->InodeSize() - (uint8 *)last); (uint32)((uint8 *)node + fVolume->InodeSize()
- (uint8 *)last);
if (_MakeSpaceForSmallData(transaction, node, name, needed) < B_OK) if (_MakeSpaceForSmallData(transaction, node, name, needed)
< B_OK)
return B_ERROR; return B_ERROR;
// reset our pointers // reset our pointers
@@ -715,14 +719,19 @@ Inode::_AddSmallData(Transaction &transaction, NodeGetter &nodeGetter,
if (length != item->DataSize()) { if (length != item->DataSize()) {
// move the attributes after the current one // move the attributes after the current one
small_data *next = item->Next(); small_data *next = item->Next();
if (!next->IsLast(node)) if (!next->IsLast(node)) {
memmove((uint8 *)item + spaceNeeded, next, (uint8 *)last - (uint8 *)next); memmove((uint8 *)item + spaceNeeded, next,
(uint8 *)last - (uint8 *)next);
}
// Move the "last" one to its new location and // Move the "last" one to its new location and
// correctly terminate the small_data section // correctly terminate the small_data section
last = (small_data *)((uint8 *)last - ((uint8 *)next - ((uint8 *)item + spaceNeeded))); last = (small_data *)((uint8 *)last
if ((uint8 *)last < (uint8 *)node + fVolume->BlockSize()) - ((uint8 *)next - ((uint8 *)item + spaceNeeded)));
memset(last, 0, (uint8 *)node + fVolume->BlockSize() - (uint8 *)last); if ((uint8 *)last < (uint8 *)node + fVolume->BlockSize()) {
memset(last, 0, (uint8 *)node + fVolume->BlockSize()
- (uint8 *)last);
}
item->data_size = HOST_ENDIAN_TO_BFS_INT16(length); item->data_size = HOST_ENDIAN_TO_BFS_INT16(length);
} }
@@ -779,8 +788,7 @@ Inode::_AddSmallData(Transaction &transaction, NodeGetter &nodeGetter,
} }
/*! /*! Iterates through the small_data section of an inode.
Iterates through the small_data section of an inode.
To start at the beginning of this section, you let smallData To start at the beginning of this section, you let smallData
point to NULL, like: point to NULL, like:
small_data *data = NULL; small_data *data = NULL;
@@ -817,8 +825,7 @@ Inode::_GetNextSmallData(bfs_inode *node, small_data **_smallData) const
} }
/*! /*! Finds the attribute "name" in the small data section, and
Finds the attribute "name" in the small data section, and
returns a pointer to it (or NULL if it doesn't exist). returns a pointer to it (or NULL if it doesn't exist).
You need to hold the fSmallDataLock when you call this method You need to hold the fSmallDataLock when you call this method
*/ */
@@ -828,7 +835,8 @@ Inode::FindSmallData(const bfs_inode *node, const char *name) const
ASSERT(fSmallDataLock.IsLocked()); ASSERT(fSmallDataLock.IsLocked());
small_data *smallData = NULL; small_data *smallData = NULL;
while (_GetNextSmallData(const_cast<bfs_inode *>(node), &smallData) == B_OK) { while (_GetNextSmallData(const_cast<bfs_inode *>(node), &smallData)
== B_OK) {
if (!strcmp(smallData->Name(), name)) if (!strcmp(smallData->Name(), name))
return smallData; return smallData;
} }
@@ -836,8 +844,7 @@ Inode::FindSmallData(const bfs_inode *node, const char *name) const
} }
/*! /*! Returns a pointer to the node's name if present in the small data
Returns a pointer to the node's name if present in the small data
section, NULL otherwise. section, NULL otherwise.
You need to hold the fSmallDataLock when you call this method You need to hold the fSmallDataLock when you call this method
*/ */
@@ -856,8 +863,7 @@ Inode::Name(const bfs_inode *node) const
} }
/*! /*! Copies the node's name into the provided buffer.
Copies the node's name into the provided buffer.
The buffer should be B_FILE_NAME_LENGTH bytes large. The buffer should be B_FILE_NAME_LENGTH bytes large.
*/ */
status_t status_t
@@ -875,8 +881,7 @@ Inode::GetName(char *buffer, size_t size) const
} }
/*! /*! Changes or set the name of a file: in the inode small_data section only, it
Changes or set the name of a file: in the inode small_data section only, it
doesn't change it in the parent directory's b+tree. doesn't change it in the parent directory's b+tree.
Note that you need to write back the inode yourself after having called Note that you need to write back the inode yourself after having called
that method. It suffers from the same API decision as AddSmallData() does that method. It suffers from the same API decision as AddSmallData() does
@@ -943,8 +948,7 @@ Inode::_RemoveAttribute(Transaction &transaction, const char *name,
} }
/*! /*! Reads data from the specified attribute.
Reads data from the specified attribute.
This is a high-level attribute function that understands attributes This is a high-level attribute function that understands attributes
in the small_data section as well as real attribute files. in the small_data section as well as real attribute files.
*/ */
@@ -989,8 +993,7 @@ Inode::ReadAttribute(const char *name, int32 type, off_t pos, uint8 *buffer,
} }
/*! /*! Writes data to the specified attribute.
Writes data to the specified attribute.
This is a high-level attribute function that understands attributes This is a high-level attribute function that understands attributes
in the small_data section as well as real attribute files. in the small_data section as well as real attribute files.
*/ */
@@ -1005,8 +1008,9 @@ Inode::WriteAttribute(Transaction &transaction, const char *name, int32 type,
// TODO: we actually depend on that the contents of "buffer" are constant. // TODO: we actually depend on that the contents of "buffer" are constant.
// If they get changed during the write (hey, user programs), we may mess // If they get changed during the write (hey, user programs), we may mess
// up our index trees! // up our index trees!
// TODO: for attribute files, we need to log the first BPLUSTREE_MAX_KEY_LENGTH // TODO: for attribute files, we need to log the first
// bytes of the data stream, or the same as above might happen. // BPLUSTREE_MAX_KEY_LENGTH bytes of the data stream, or the same as above
// might happen.
Index index(fVolume); Index index(fVolume);
index.SetTo(name); index.SetTo(name);
@@ -1052,7 +1056,8 @@ Inode::WriteAttribute(Transaction &transaction, const char *name, int32 type,
if (attribute != NULL) { if (attribute != NULL) {
if (attribute->Lock().LockWrite() == B_OK) { if (attribute->Lock().LockWrite() == B_OK) {
// save the old attribute data (if this fails, oldLength will reflect it) // Save the old attribute data (if this fails, oldLength will
// reflect it)
if (fVolume->CheckForLiveQuery(name) && attribute->Size() > 0) { if (fVolume->CheckForLiveQuery(name) && attribute->Size() > 0) {
oldLength = BPLUSTREE_MAX_KEY_LENGTH; oldLength = BPLUSTREE_MAX_KEY_LENGTH;
if (attribute->ReadAt(0, oldBuffer, &oldLength) == B_OK) if (attribute->ReadAt(0, oldBuffer, &oldLength) == B_OK)
@@ -1094,8 +1099,9 @@ Inode::WriteAttribute(Transaction &transaction, const char *name, int32 type,
if (length > BPLUSTREE_MAX_KEY_LENGTH) if (length > BPLUSTREE_MAX_KEY_LENGTH)
length = BPLUSTREE_MAX_KEY_LENGTH; length = BPLUSTREE_MAX_KEY_LENGTH;
// Update index. Note, Index::Update() may be called even if initializing // Update index. Note, Index::Update() may be called even if
// the index failed - it will just update the live queries in this case // initializing the index failed - it will just update the live
// queries in this case
if (pos < length || pos < oldLength) { if (pos < length || pos < oldLength) {
index.Update(transaction, name, type, oldData, oldLength, buffer, index.Update(transaction, name, type, oldData, oldLength, buffer,
length, this); length, this);
@@ -1105,8 +1111,7 @@ Inode::WriteAttribute(Transaction &transaction, const char *name, int32 type,
} }
/*! /*! Removes the specified attribute from the inode.
Removes the specified attribute from the inode.
This is a high-level attribute function that understands attributes This is a high-level attribute function that understands attributes
in the small_data section as well as real attribute files. in the small_data section as well as real attribute files.
*/ */
@@ -1151,7 +1156,8 @@ Inode::GetAttribute(const char *name, Inode **_attribute)
Vnode vnode(fVolume, Attributes()); Vnode vnode(fVolume, Attributes());
Inode *attributes; Inode *attributes;
if (vnode.Get(&attributes) < B_OK) { if (vnode.Get(&attributes) < B_OK) {
FATAL(("get_vnode() failed in Inode::GetAttribute(name = \"%s\")\n", name)); FATAL(("get_vnode() failed in Inode::GetAttribute(name = \"%s\")\n",
name));
return B_ERROR; return B_ERROR;
} }
@@ -1211,8 +1217,7 @@ Inode::CreateAttribute(Transaction &transaction, const char *name, uint32 type,
// #pragma mark - directory tree // #pragma mark - directory tree
/*! /*! Gives the caller direct access to the b+tree for a given directory.
Gives the caller direct access to the b+tree for a given directory.
The tree is no longer created on demand, but when the inode is first The tree is no longer created on demand, but when the inode is first
created. That will report any potential errors upfront, saves locking, created. That will report any potential errors upfront, saves locking,
and should work as good (though a bit slower). and should work as good (though a bit slower).
@@ -1262,8 +1267,7 @@ Inode::IsEmpty()
// #pragma mark - data stream // #pragma mark - data stream
/*! /*! Finds the block_run where "pos" is located in the data_stream of
Finds the block_run where "pos" is located in the data_stream of
the inode. the inode.
If successful, "offset" will then be set to the file offset If successful, "offset" will then be set to the file offset
of the block_run returned; so "pos - offset" is for the block_run of the block_run returned; so "pos - offset" is for the block_run
@@ -1278,7 +1282,8 @@ Inode::FindBlockRun(off_t pos, block_run &run, off_t &offset)
// find matching block run // find matching block run
if (data->MaxDirectRange() > 0 && pos >= data->MaxDirectRange()) { if (data->MaxDirectRange() > 0 && pos >= data->MaxDirectRange()) {
if (data->MaxDoubleIndirectRange() > 0 && pos >= data->MaxIndirectRange()) { if (data->MaxDoubleIndirectRange() > 0
&& pos >= data->MaxIndirectRange()) {
// access to double indirect blocks // access to double indirect blocks
CachedBlock cached(fVolume); CachedBlock cached(fVolume);
@@ -1292,13 +1297,10 @@ Inode::FindBlockRun(off_t pos, block_run &run, off_t &offset)
int32 runsPerBlock = cached.BlockSize() / sizeof(block_run); int32 runsPerBlock = cached.BlockSize() / sizeof(block_run);
block_run *indirect = (block_run *)cached.SetTo( block_run *indirect = (block_run *)cached.SetTo(
fVolume->ToBlock(data->double_indirect) + index / runsPerBlock); fVolume->ToBlock(data->double_indirect) + index / runsPerBlock);
if (indirect == NULL) if (indirect == NULL)
RETURN_ERROR(B_ERROR); 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; int32 current = (start % indirectSize) / directSize;
indirect = (block_run *)cached.SetTo( indirect = (block_run *)cached.SetTo(
@@ -1310,7 +1312,6 @@ Inode::FindBlockRun(off_t pos, block_run &run, off_t &offset)
run = indirect[current % runsPerBlock]; run = indirect[current % runsPerBlock];
offset = data->MaxIndirectRange() + (index * indirectSize) offset = data->MaxIndirectRange() + (index * indirectSize)
+ (current * directSize); + (current * directSize);
//printf("\tfCurrent = %ld, fRunFileOffset = %Ld, fRunBlockEnd = %Ld, fRun = %ld,%d\n",fCurrent,fRunFileOffset,fRunBlockEnd,fRun.allocation_group,fRun.start);
} else { } else {
// access to indirect blocks // access to indirect blocks
@@ -1336,8 +1337,6 @@ Inode::FindBlockRun(off_t pos, block_run &run, off_t &offset)
run = indirect[current]; run = indirect[current];
offset = runBlockEnd - (run.Length() offset = runBlockEnd - (run.Length()
<< cached.BlockShift()); << 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 fVolume->ValidateBlockRun(run);
} }
} }
@@ -1359,12 +1358,10 @@ Inode::FindBlockRun(off_t pos, block_run &run, off_t &offset)
if (runBlockEnd > pos) { if (runBlockEnd > pos) {
run = data->direct[current]; run = data->direct[current];
offset = runBlockEnd - (run.Length() << fVolume->BlockShift()); 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); return fVolume->ValidateBlockRun(run);
} }
} }
//PRINT(("FindBlockRun() failed in direct range: size = %Ld, pos = %Ld\n",data->size,pos));
return B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND;
} }
return fVolume->ValidateBlockRun(run); return fVolume->ValidateBlockRun(run);
@@ -1457,8 +1454,7 @@ Inode::WriteAt(Transaction &transaction, off_t pos, const uint8 *buffer,
} }
/*! /*! Fills the gap between the old file size and the new file size
Fills the gap between the old file size and the new file size
with zeros. with zeros.
It's more or less a copy of Inode::WriteAt() but it can handle It's more or less a copy of Inode::WriteAt() but it can handle
length differences of more than just 4 GB, and it never uses length differences of more than just 4 GB, and it never uses
@@ -1485,8 +1481,7 @@ Inode::FillGapWithZeros(off_t pos, off_t newSize)
} }
/*! /*! Allocates NUM_ARRAY_BLOCKS blocks, and clears their contents. Growing
Allocates NUM_ARRAY_BLOCKS blocks, and clears their contents. Growing
the indirect and double indirect range uses this method. the indirect and double indirect range uses this method.
The allocated block_run is saved in "run" The allocated block_run is saved in "run"
*/ */
@@ -1534,7 +1529,8 @@ Inode::_GrowStream(Transaction &transaction, off_t size)
off_t bytes; off_t bytes;
if (data->Size() < data->MaxDoubleIndirectRange()) { if (data->Size() < data->MaxDoubleIndirectRange()) {
bytes = size - data->MaxDoubleIndirectRange(); bytes = size - data->MaxDoubleIndirectRange();
// the double indirect range can only handle multiple of NUM_ARRAY_BLOCKS // The double indirect range can only handle multiple of
// NUM_ARRAY_BLOCKS
minimum = NUM_ARRAY_BLOCKS; minimum = NUM_ARRAY_BLOCKS;
} else if (data->Size() < data->MaxIndirectRange()) } else if (data->Size() < data->MaxIndirectRange())
bytes = size - data->MaxIndirectRange(); bytes = size - data->MaxIndirectRange();
@@ -1558,7 +1554,8 @@ Inode::_GrowStream(Transaction &transaction, off_t size)
// Attributes, attribute directories, and long symlinks usually won't get // Attributes, attribute directories, and long symlinks usually won't get
// that big, and should stay close to the inode - preallocating could be // that big, and should stay close to the inode - preallocating could be
// counterproductive. // counterproductive.
// Also, if free disk space is tight, we probably don't want to do this as well. // Also, if free disk space is tight, we probably don't want to do this as
// well.
if (!IsAttribute() && !IsAttributeDirectory() && !IsSymLink() if (!IsAttribute() && !IsAttributeDirectory() && !IsSymLink()
&& blocksRequested < (65536 >> fVolume->BlockShift()) && blocksRequested < (65536 >> fVolume->BlockShift())
&& fVolume->FreeBlocks() > 128) && fVolume->FreeBlocks() > 128)
@@ -1607,7 +1604,8 @@ Inode::_GrowStream(Transaction &transaction, off_t size)
data->direct[free] = run; data->direct[free] = run;
data->max_direct_range = HOST_ENDIAN_TO_BFS_INT64( data->max_direct_range = HOST_ENDIAN_TO_BFS_INT64(
data->MaxDirectRange() + run.Length() * fVolume->BlockSize()); data->MaxDirectRange()
+ run.Length() * fVolume->BlockSize());
data->size = HOST_ENDIAN_TO_BFS_INT64(blocksNeeded > 0 data->size = HOST_ENDIAN_TO_BFS_INT64(blocksNeeded > 0
? data->max_direct_range : size); ? data->max_direct_range : size);
continue; continue;
@@ -1685,8 +1683,8 @@ Inode::_GrowStream(Transaction &transaction, off_t size)
// NUM_ARRAY_BLOCKS, so we have to change this. This can happen // NUM_ARRAY_BLOCKS, so we have to change this. This can happen
// the first time the stream grows into the double // the first time the stream grows into the double
// indirect range. // indirect range.
// First, free the remaining blocks that don't fit into a multiple // First, free the remaining blocks that don't fit into a
// of NUM_ARRAY_BLOCKS // multiple of NUM_ARRAY_BLOCKS
int32 rest = run.Length() % NUM_ARRAY_BLOCKS; int32 rest = run.Length() % NUM_ARRAY_BLOCKS;
run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - rest); run.length = HOST_ENDIAN_TO_BFS_INT16(run.Length() - rest);
@@ -1704,14 +1702,16 @@ Inode::_GrowStream(Transaction &transaction, off_t size)
// NUM_ARRAY_BLOCKS allocated, so if the allocation // NUM_ARRAY_BLOCKS allocated, so if the allocation
// succeeds, we don't run into an endless loop // succeeds, we don't run into an endless loop
// Are there any blocks left in the run? If not, allocate a new one // Are there any blocks left in the run? If not, allocate
// a new one
if (run.length == 0) if (run.length == 0)
continue; continue;
} }
// if there is no double indirect block yet, create one // if there is no double indirect block yet, create one
if (data->double_indirect.IsZero()) { if (data->double_indirect.IsZero()) {
status = _AllocateBlockArray(transaction, data->double_indirect); status = _AllocateBlockArray(transaction,
data->double_indirect);
if (status < B_OK) if (status < B_OK)
return status; return status;
@@ -1721,12 +1721,13 @@ Inode::_GrowStream(Transaction &transaction, off_t size)
// calculate the index where to insert the new blocks // calculate the index where to insert the new blocks
int32 runsPerBlock = fVolume->BlockSize() / sizeof(block_run); int32 runsPerBlock = fVolume->BlockSize() / sizeof(block_run);
int32 indirectSize = ((1L << INDIRECT_BLOCKS_SHIFT) << fVolume->BlockShift()) int32 indirectSize = ((1L << INDIRECT_BLOCKS_SHIFT)
* runsPerBlock; << fVolume->BlockShift()) * runsPerBlock;
int32 directSize = NUM_ARRAY_BLOCKS << fVolume->BlockShift(); int32 directSize = NUM_ARRAY_BLOCKS << fVolume->BlockShift();
int32 runsPerArray = runsPerBlock << ARRAY_BLOCKS_SHIFT; int32 runsPerArray = runsPerBlock << ARRAY_BLOCKS_SHIFT;
off_t start = data->MaxDoubleIndirectRange() - data->MaxIndirectRange(); off_t start = data->MaxDoubleIndirectRange()
- data->MaxIndirectRange();
int32 indirectIndex = start / indirectSize; int32 indirectIndex = start / indirectSize;
int32 index = start / directSize; int32 index = start / directSize;
@@ -1738,36 +1739,6 @@ Inode::_GrowStream(Transaction &transaction, off_t size)
block_run *array = NULL; block_run *array = NULL;
uint32 runLength = run.Length(); uint32 runLength = run.Length();
// TODO: the following code is commented - it could be used to
// preallocate all needed block arrays to see in advance if the
// allocation will succeed.
// I will probably remove it later, because it's no perfect solution
// either: if the allocation was broken up before (blocksNeeded != 0),
// it doesn't guarantee anything.
// And since failing in this case is not that common, it doesn't have
// to be optimized in that way.
// Anyway, I wanted to have it in CVS - all those lines, and they will
// be removed soon :-)
/*
// allocate new block arrays if needed
off_t block = -1;
for (int32 i = 0;i < needed;i++) {
// get the block to insert the run into
block = fVolume->ToBlock(data->double_indirect) + i + indirectIndex / runsPerBlock;
if (cached.BlockNumber() != block)
array = (block_run *)cached.SetTo(block);
if (array == NULL)
return B_ERROR;
status = AllocateBlockArray(transaction, array[i + indirectIndex % runsPerBlock]);
if (status < B_OK)
return status;
}
*/
while (run.length != 0) { while (run.length != 0) {
// get the indirect array block // get the indirect array block
if (array == NULL) { if (array == NULL) {
@@ -1892,8 +1863,7 @@ Inode::_FreeStaticStreamArray(Transaction &transaction, int32 level,
} }
/*! /*! Frees all block_runs in the array which come after the specified size.
Frees all block_runs in the array which come after the specified size.
It also trims the last block_run that contain the size. It also trims the last block_run that contain the size.
"offset" and "max" are maintained until the last block_run that doesn't "offset" and "max" are maintained until the last block_run that doesn't
have to be freed - after this, the values won't be correct anymore, but have to be freed - after this, the values won't be correct anymore, but
@@ -2057,8 +2027,7 @@ Inode::Append(Transaction &transaction, off_t bytes)
} }
/*! /*! Checks wether or not this inode's data stream needs to be trimmed
Checks wether or not this inode's data stream needs to be trimmed
because of an earlier preallocation. because of an earlier preallocation.
Returns true if there are any blocks to be trimmed. Returns true if there are any blocks to be trimmed.
*/ */
@@ -2311,8 +2280,7 @@ Inode::Remove(Transaction &transaction, const char *name, ino_t *_id,
} }
/*! /*! Creates the inode with the specified parent directory, and automatically
Creates the inode with the specified parent directory, and automatically
adds the created inode to that parent directory. If an attribute directory adds the created inode to that parent directory. If an attribute directory
is created, it will also automatically be added to the parent inode as is created, it will also automatically be added to the parent inode as
such. However, the indices root node, and the regular root node won't be such. However, the indices root node, and the regular root node won't be
@@ -2347,10 +2315,11 @@ Inode::Create(Transaction &transaction, Inode *parent, const char *name,
// the parent directory is locked during the whole inode creation // the parent directory is locked during the whole inode creation
if (tree != NULL) { if (tree != NULL) {
// does the file already exist? // Does the file already exist?
off_t offset; off_t offset;
if (tree->Find((uint8 *)name, (uint16)strlen(name), &offset) == B_OK) { if (tree->Find((uint8 *)name, (uint16)strlen(name), &offset) == B_OK) {
// return if the file should be a directory/link or opened in exclusive mode // Return if the file should be a directory/link or opened in
// exclusive mode
if (S_ISDIR(mode) || S_ISLNK(mode) || openMode & O_EXCL) if (S_ISDIR(mode) || S_ISLNK(mode) || openMode & O_EXCL)
return B_FILE_EXISTS; return B_FILE_EXISTS;
@@ -2394,7 +2363,8 @@ Inode::Create(Transaction &transaction, Inode *parent, const char *name,
if (_inode) if (_inode)
*_inode = inode; *_inode = inode;
// only keep the vnode in memory if the _id or _inode pointer is provided // Only keep the vnode in memory if the _id or _inode pointer is
// provided
if (_id != NULL || _inode != NULL) if (_id != NULL || _inode != NULL)
vnode.Keep(); vnode.Keep();
@@ -2443,7 +2413,8 @@ Inode::Create(Transaction &transaction, Inode *parent, const char *name,
// only add the name to regular files, directories, or symlinks // only add the name to regular files, directories, or symlinks
// don't add it to attributes, or indices // don't add it to attributes, or indices
if (tree && inode->IsRegularNode() && inode->SetName(transaction, name) < B_OK) if (tree && inode->IsRegularNode()
&& inode->SetName(transaction, name) < B_OK)
return B_ERROR; return B_ERROR;
// Initialize b+tree if it's a directory (and add "." & ".." if it's // Initialize b+tree if it's a directory (and add "." & ".." if it's
@@ -2496,8 +2467,8 @@ Inode::Create(Transaction &transaction, Inode *parent, const char *name,
// The "size" & "last_modified" indices don't contain directories // The "size" & "last_modified" indices don't contain directories
if (inode->IsFile() || inode->IsSymLink()) { if (inode->IsFile() || inode->IsSymLink()) {
// if adding to these indices fails, the inode creation will not be harmed; // if adding to these indices fails, the inode creation will not be
// they are considered less important than the "name" index // harmed; they are considered less important than the "name" index
if (inode->IsFile()) if (inode->IsFile())
index.InsertSize(transaction, inode); index.InsertSize(transaction, inode);
index.InsertLastModified(transaction, inode); index.InsertLastModified(transaction, inode);