* The inode block wasn't written back when it was opened with O_TRUNC/B_ERASE_FILE

which could cause inconsistency of on-disk structures.
* Fixed copy&paste bug introduced by Ingo when he did the GCC 4 work-around: when
  shrinking the direct range, the new size was written to the indirect range.
* Some cleanup, renamed private Inode methods to have a leading '_' symbol.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16557 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-03-01 12:57:54 +00:00
parent e68c6184ca
commit b61fdf78c6
3 changed files with 85 additions and 68 deletions

View File

@ -325,7 +325,7 @@ Inode::CheckPermissions(int accessMode) const
void void
Inode::AddIterator(AttributeIterator *iterator) Inode::_AddIterator(AttributeIterator *iterator)
{ {
if (fSmallDataLock.Lock() < B_OK) if (fSmallDataLock.Lock() < B_OK)
return; return;
@ -337,7 +337,7 @@ Inode::AddIterator(AttributeIterator *iterator)
void void
Inode::RemoveIterator(AttributeIterator *iterator) Inode::_RemoveIterator(AttributeIterator *iterator)
{ {
if (fSmallDataLock.Lock() < B_OK) if (fSmallDataLock.Lock() < B_OK)
return; return;
@ -354,7 +354,8 @@ Inode::RemoveIterator(AttributeIterator *iterator)
*/ */
status_t status_t
Inode::MakeSpaceForSmallData(Transaction &transaction, bfs_inode *node, const char *name, int32 bytes) Inode::MakeSpaceForSmallData(Transaction &transaction, bfs_inode *node, const char *name,
int32 bytes)
{ {
ASSERT(fSmallDataLock.IsLocked()); ASSERT(fSmallDataLock.IsLocked());
@ -385,7 +386,8 @@ Inode::MakeSpaceForSmallData(Transaction &transaction, bfs_inode *node, const ch
// Luckily, this doesn't cause any index updates // Luckily, this doesn't cause any index updates
Inode *attribute; Inode *attribute;
status_t status = CreateAttribute(transaction, item->Name(), item->Type(), &attribute); status_t status = CreateAttribute(transaction, item->Name(), item->Type(),
&attribute);
if (status < B_OK) if (status < B_OK)
RETURN_ERROR(status); RETURN_ERROR(status);
@ -405,7 +407,7 @@ Inode::MakeSpaceForSmallData(Transaction &transaction, bfs_inode *node, const ch
RETURN_ERROR(status); RETURN_ERROR(status);
} }
RemoveSmallData(node, max, maxIndex); _RemoveSmallData(node, max, maxIndex);
} }
return B_OK; return B_OK;
} }
@ -417,7 +419,7 @@ Inode::MakeSpaceForSmallData(Transaction &transaction, bfs_inode *node, const ch
*/ */
status_t status_t
Inode::RemoveSmallData(bfs_inode *node, small_data *item, int32 index) Inode::_RemoveSmallData(bfs_inode *node, small_data *item, int32 index)
{ {
ASSERT(fSmallDataLock.IsLocked()); ASSERT(fSmallDataLock.IsLocked());
@ -477,7 +479,7 @@ Inode::RemoveSmallData(Transaction &transaction, NodeGetter &nodeGetter, const c
return B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND;
nodeGetter.MakeWritable(transaction); nodeGetter.MakeWritable(transaction);
return RemoveSmallData(node, item, index); return _RemoveSmallData(node, item, index);
} }
@ -581,7 +583,7 @@ Inode::AddSmallData(Transaction &transaction, NodeGetter &nodeGetter, const char
// Could not replace the old attribute, so remove it to let // Could not replace the old attribute, so remove it to let
// let the calling function create an attribute file for it // let the calling function create an attribute file for it
if (RemoveSmallData(node, item, index) < B_OK) if (_RemoveSmallData(node, item, index) < B_OK)
return B_ERROR; return B_ERROR;
return B_DEVICE_FULL; return B_DEVICE_FULL;
@ -898,7 +900,8 @@ Inode::RemoveAttribute(Transaction &transaction, const char *name)
uint32 length = smallData->DataSize(); uint32 length = smallData->DataSize();
if (length > BPLUSTREE_MAX_KEY_LENGTH) if (length > BPLUSTREE_MAX_KEY_LENGTH)
length = BPLUSTREE_MAX_KEY_LENGTH; length = BPLUSTREE_MAX_KEY_LENGTH;
index.Update(transaction, name, smallData->Type(), smallData->Data(), length, NULL, 0, this); index.Update(transaction, name, smallData->Type(), smallData->Data(),
length, NULL, 0, this);
} }
fSmallDataLock.Unlock(); fSmallDataLock.Unlock();
} }
@ -989,7 +992,8 @@ Inode::ReleaseAttribute(Inode *attribute)
status_t status_t
Inode::CreateAttribute(Transaction &transaction, const char *name, uint32 type, Inode **attribute) Inode::CreateAttribute(Transaction &transaction, const char *name, uint32 type,
Inode **attribute)
{ {
// do we need to create the attribute directory first? // do we need to create the attribute directory first?
if (Attributes().IsZero()) { if (Attributes().IsZero()) {
@ -1340,12 +1344,13 @@ Inode::FillGapWithZeros(off_t pos, off_t newSize)
*/ */
status_t status_t
Inode::AllocateBlockArray(Transaction &transaction, block_run &run) Inode::_AllocateBlockArray(Transaction &transaction, block_run &run)
{ {
if (!run.IsZero()) if (!run.IsZero())
return B_BAD_VALUE; return B_BAD_VALUE;
status_t status = fVolume->Allocate(transaction, this, NUM_ARRAY_BLOCKS, run, NUM_ARRAY_BLOCKS); status_t status = fVolume->Allocate(transaction, this, NUM_ARRAY_BLOCKS, run,
NUM_ARRAY_BLOCKS);
if (status < B_OK) if (status < B_OK)
return status; return status;
@ -1363,7 +1368,7 @@ Inode::AllocateBlockArray(Transaction &transaction, block_run &run)
status_t status_t
Inode::GrowStream(Transaction &transaction, off_t size) Inode::_GrowStream(Transaction &transaction, off_t size)
{ {
data_stream *data = &Node().data; data_stream *data = &Node().data;
@ -1465,7 +1470,7 @@ Inode::GrowStream(Transaction &transaction, off_t size)
// if there is no indirect block yet, create one // if there is no indirect block yet, create one
if (data->indirect.IsZero()) { if (data->indirect.IsZero()) {
status = AllocateBlockArray(transaction, data->indirect); status = _AllocateBlockArray(transaction, data->indirect);
if (status < B_OK) if (status < B_OK)
return status; return status;
@ -1540,7 +1545,7 @@ Inode::GrowStream(Transaction &transaction, off_t size)
// 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;
@ -1609,7 +1614,8 @@ Inode::GrowStream(Transaction &transaction, off_t size)
do { do {
// do we need a new array block? // do we need a new array block?
if (array[indirectIndex % runsPerBlock].IsZero()) { if (array[indirectIndex % runsPerBlock].IsZero()) {
status = AllocateBlockArray(transaction, array[indirectIndex % runsPerBlock]); status = _AllocateBlockArray(transaction,
array[indirectIndex % runsPerBlock]);
if (status < B_OK) if (status < B_OK)
return status; return status;
} }
@ -1653,7 +1659,7 @@ Inode::GrowStream(Transaction &transaction, off_t size)
status_t status_t
Inode::FreeStaticStreamArray(Transaction &transaction, int32 level, block_run run, Inode::_FreeStaticStreamArray(Transaction &transaction, int32 level, block_run run,
off_t size, off_t offset, off_t &max) off_t size, off_t offset, off_t &max)
{ {
int32 indirectSize = 0; int32 indirectSize = 0;
@ -1691,9 +1697,10 @@ Inode::FreeStaticStreamArray(Transaction &transaction, int32 level, block_run ru
} }
status_t status = B_OK; status_t status = B_OK;
if (level == 0) if (level == 0) {
status = FreeStaticStreamArray(transaction, 1, array[index], size, offset, max); status = _FreeStaticStreamArray(transaction, 1, array[index], size,
else if (offset >= size) offset, max);
} else if (offset >= size)
status = fVolume->Free(transaction, array[index]); status = fVolume->Free(transaction, array[index]);
else else
max = HOST_ENDIAN_TO_BFS_INT64(offset + indirectSize); max = HOST_ENDIAN_TO_BFS_INT64(offset + indirectSize);
@ -1721,9 +1728,12 @@ Inode::FreeStaticStreamArray(Transaction &transaction, int32 level, block_run ru
*/ */
status_t status_t
Inode::FreeStreamArray(Transaction &transaction, block_run *array, uint32 arrayLength, Inode::_FreeStreamArray(Transaction &transaction, block_run *array, uint32 arrayLength,
off_t size, off_t &offset, off_t &max) off_t size, off_t &offset, off_t &max)
{ {
PRINT(("FreeStreamArray: arrayLength %lu, size %Ld, offset %Ld, max %Ld\n",
arrayLength, size, offset, max));
off_t newOffset = offset; off_t newOffset = offset;
uint32 i = 0; uint32 i = 0;
for (; i < arrayLength; i++, offset = newOffset) { for (; i < arrayLength; i++, offset = newOffset) {
@ -1764,7 +1774,7 @@ Inode::FreeStreamArray(Transaction &transaction, block_run *array, uint32 arrayL
status_t status_t
Inode::ShrinkStream(Transaction &transaction, off_t size) Inode::_ShrinkStream(Transaction &transaction, off_t size)
{ {
data_stream *data = &Node().data; data_stream *data = &Node().data;
status_t status; status_t status;
@ -1773,7 +1783,7 @@ Inode::ShrinkStream(Transaction &transaction, off_t size)
off_t *maxDoubleIndirect = &data->max_double_indirect_range; off_t *maxDoubleIndirect = &data->max_double_indirect_range;
// gcc 4 work-around: "error: cannot bind packed field // gcc 4 work-around: "error: cannot bind packed field
// 'data->data_stream::max_double_indirect_range' to 'off_t&'" // 'data->data_stream::max_double_indirect_range' to 'off_t&'"
status = FreeStaticStreamArray(transaction, 0, data->double_indirect, size, status = _FreeStaticStreamArray(transaction, 0, data->double_indirect, size,
data->MaxIndirectRange(), *maxDoubleIndirect); data->MaxIndirectRange(), *maxDoubleIndirect);
if (status < B_OK) if (status < B_OK)
return status; return status;
@ -1784,6 +1794,7 @@ Inode::ShrinkStream(Transaction &transaction, off_t size)
data->max_double_indirect_range = 0; data->max_double_indirect_range = 0;
} }
} }
if (data->MaxIndirectRange() > size) { if (data->MaxIndirectRange() > size) {
CachedBlock cached(fVolume); CachedBlock cached(fVolume);
off_t block = fVolume->ToBlock(data->indirect); off_t block = fVolume->ToBlock(data->indirect);
@ -1797,7 +1808,7 @@ Inode::ShrinkStream(Transaction &transaction, off_t size)
off_t *maxIndirect = &data->max_indirect_range; off_t *maxIndirect = &data->max_indirect_range;
// gcc 4 work-around: "error: cannot bind packed field // gcc 4 work-around: "error: cannot bind packed field
// 'data->data_stream::max_indirect_range' to 'off_t&'" // 'data->data_stream::max_indirect_range' to 'off_t&'"
if (FreeStreamArray(transaction, array, fVolume->BlockSize() / sizeof(block_run), if (_FreeStreamArray(transaction, array, fVolume->BlockSize() / sizeof(block_run),
size, offset, *maxIndirect) != B_OK) size, offset, *maxIndirect) != B_OK)
return B_IO_ERROR; return B_IO_ERROR;
} }
@ -1807,12 +1818,13 @@ Inode::ShrinkStream(Transaction &transaction, off_t size)
data->max_indirect_range = 0; data->max_indirect_range = 0;
} }
} }
if (data->MaxDirectRange() > size) { if (data->MaxDirectRange() > size) {
off_t offset = 0; off_t offset = 0;
off_t *maxDirect = &data->max_indirect_range; off_t *maxDirect = &data->max_direct_range;
// gcc 4 work-around: "error: cannot bind packed field // gcc 4 work-around: "error: cannot bind packed field
// 'data->data_stream::max_direct_range' to 'off_t&'" // 'data->data_stream::max_direct_range' to 'off_t&'"
status = FreeStreamArray(transaction, data->direct, NUM_DIRECT_BLOCKS, status = _FreeStreamArray(transaction, data->direct, NUM_DIRECT_BLOCKS,
size, offset, *maxDirect); size, offset, *maxDirect);
if (status < B_OK) if (status < B_OK)
return status; return status;
@ -1837,14 +1849,14 @@ Inode::SetFileSize(Transaction &transaction, off_t size)
// should the data stream grow or shrink? // should the data stream grow or shrink?
status_t status; status_t status;
if (size > oldSize) { if (size > oldSize) {
status = GrowStream(transaction, size); status = _GrowStream(transaction, size);
if (status < B_OK) { if (status < B_OK) {
// if the growing of the stream fails, the whole operation // if the growing of the stream fails, the whole operation
// fails, so we should shrink the stream to its former size // fails, so we should shrink the stream to its former size
ShrinkStream(transaction, oldSize); _ShrinkStream(transaction, oldSize);
} }
} else } else
status = ShrinkStream(transaction, size); status = _ShrinkStream(transaction, size);
if (status < B_OK) if (status < B_OK)
return status; return status;
@ -1886,7 +1898,7 @@ Inode::NeedsTrimming()
status_t status_t
Inode::TrimPreallocation(Transaction &transaction) Inode::TrimPreallocation(Transaction &transaction)
{ {
status_t status = ShrinkStream(transaction, Size()); status_t status = _ShrinkStream(transaction, Size());
if (status < B_OK) if (status < B_OK)
return status; return status;
@ -2162,6 +2174,9 @@ Inode::Create(Transaction &transaction, Inode *parent, const char *name, int32 m
WriteLocked locked(inode->Lock()); WriteLocked locked(inode->Lock());
status_t status = inode->SetFileSize(transaction, 0); status_t status = inode->SetFileSize(transaction, 0);
if (status >= B_OK)
status = inode->WriteBack(transaction);
if (status < B_OK) if (status < B_OK)
return status; return status;
} }
@ -2305,7 +2320,7 @@ AttributeIterator::AttributeIterator(Inode *inode)
fIterator(NULL), fIterator(NULL),
fBuffer(NULL) fBuffer(NULL)
{ {
inode->AddIterator(this); inode->_AddIterator(this);
} }
@ -2315,7 +2330,7 @@ AttributeIterator::~AttributeIterator()
put_vnode(fAttributes->GetVolume()->ID(), fAttributes->ID()); put_vnode(fAttributes->GetVolume()->ID(), fAttributes->ID());
delete fIterator; delete fIterator;
fInode->RemoveIterator(this); fInode->_RemoveIterator(this);
} }

View File

@ -1,6 +1,6 @@
/* Inode - inode access functions /* Inode - inode access functions
* *
* Copyright 2001-2005, Axel Dörfler, axeld@pinc-software.de. * Copyright 2001-2006, Axel Dörfler, axeld@pinc-software.de.
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
#ifndef INODE_H #ifndef INODE_H
@ -156,22 +156,21 @@ class Inode {
Inode &operator=(const Inode &); Inode &operator=(const Inode &);
// no implementation // no implementation
friend void dump_inode(Inode &inode);
friend class AttributeIterator; friend class AttributeIterator;
friend class InodeAllocator; friend class InodeAllocator;
status_t RemoveSmallData(bfs_inode *node, small_data *item, int32 index); status_t _RemoveSmallData(bfs_inode *node, small_data *item, int32 index);
void AddIterator(AttributeIterator *iterator); void _AddIterator(AttributeIterator *iterator);
void RemoveIterator(AttributeIterator *iterator); void _RemoveIterator(AttributeIterator *iterator);
status_t FreeStaticStreamArray(Transaction &transaction, int32 level, block_run run, status_t _FreeStaticStreamArray(Transaction &transaction, int32 level,
off_t size, off_t offset, off_t &max); 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,
off_t size, off_t &offset, off_t &max); uint32 arrayLength, off_t size, off_t &offset, off_t &max);
status_t AllocateBlockArray(Transaction &transaction, block_run &run); status_t _AllocateBlockArray(Transaction &transaction, block_run &run);
status_t GrowStream(Transaction &transaction, off_t size); status_t _GrowStream(Transaction &transaction, off_t size);
status_t ShrinkStream(Transaction &transaction, off_t size); status_t _ShrinkStream(Transaction &transaction, off_t size);
private: private:
ReadWriteLock fLock; ReadWriteLock fLock;
@ -283,18 +282,18 @@ class AttributeIterator {
status_t Rewind(); status_t Rewind();
status_t GetNext(char *name, size_t *length, uint32 *type, vnode_id *id); status_t GetNext(char *name, size_t *length, uint32 *type, vnode_id *id);
private:
int32 fCurrentSmallData;
Inode *fInode, *fAttributes;
TreeIterator *fIterator;
void *fBuffer;
private: private:
friend class Chain<AttributeIterator>; friend class Chain<AttributeIterator>;
friend class Inode; friend class Inode;
void Update(uint16 index, int8 change); void Update(uint16 index, int8 change);
AttributeIterator *fNext; AttributeIterator *fNext;
private:
int32 fCurrentSmallData;
Inode *fInode, *fAttributes;
TreeIterator *fIterator;
void *fBuffer;
}; };

View File

@ -1137,6 +1137,9 @@ bfs_open(void *_fs, void *_node, int openMode, void **_cookie)
Transaction transaction(volume, inode->BlockNumber()); Transaction transaction(volume, inode->BlockNumber());
status_t status = inode->SetFileSize(transaction, 0); status_t status = inode->SetFileSize(transaction, 0);
if (status >= B_OK)
status = inode->WriteBack(transaction);
if (status < B_OK) { if (status < B_OK) {
// bfs_free_cookie() is only called if this function is successful // bfs_free_cookie() is only called if this function is successful
free(cookie); free(cookie);