* There is now a list of removed vnodes in Volume - while asking the VFS for
this seemed to be a good idea, there is one race condition that cannot be solved otherwise (the vnode must be added/removed to that list while holding the transaction lock, and we cannot guarantee that in the VFS). * We are using an unused area of the in-memory bfs_inode to store the list links (bfs_inode::pad - this will also work on 64 bit platforms). * Inode no longer adds a singly linked list link - the transaction list now shares the doubly linked list with the removed vnodes list. * Added an in-memory flag INODE_IN_TRANSACTION to avoid searching an inode to be added in the list. * Removing an attribute directory did not hold its write lock. * If removing an attribute failed for some reason, the INODE_DELETED flag was not removed (the transaction would not have failed because of that). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30203 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1147,7 +1147,7 @@ BlockAllocator::StartChecking(check_control* control)
|
|||||||
// Lock the volume's journal
|
// Lock the volume's journal
|
||||||
|
|
||||||
status_t status = mutex_lock(&fLock);
|
status_t status = mutex_lock(&fLock);
|
||||||
if (status < B_OK) {
|
if (status != B_OK) {
|
||||||
fVolume->GetJournal(0)->Unlock(NULL, true);
|
fVolume->GetJournal(0)->Unlock(NULL, true);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -1185,16 +1185,12 @@ BlockAllocator::StartChecking(check_control* control)
|
|||||||
fCheckCookie = cookie;
|
fCheckCookie = cookie;
|
||||||
// to be able to restore nicely if "chkbfs" exited abnormally
|
// to be able to restore nicely if "chkbfs" exited abnormally
|
||||||
|
|
||||||
#if !BFS_SHELL
|
|
||||||
// Put removed vnodes to the stack -- they are not reachable by traversing
|
// Put removed vnodes to the stack -- they are not reachable by traversing
|
||||||
// the file system anymore.
|
// the file system anymore.
|
||||||
void* inode = NULL;
|
InodeList::Iterator iterator = fVolume->RemovedInodes().GetIterator();
|
||||||
ino_t nodeID;
|
while (Inode* inode = iterator.Next()) {
|
||||||
while (get_next_removed_vnode(fVolume->FSVolume(), &nodeID, &inode)
|
cookie->stack.Push(inode->BlockRun());
|
||||||
== B_OK) {
|
|
||||||
cookie->stack.Push(fVolume->ToBlockRun(nodeID));
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// TODO: check reserved area in bitmap!
|
// TODO: check reserved area in bitmap!
|
||||||
|
|
||||||
|
|||||||
@@ -127,7 +127,6 @@ dump_inode(const bfs_inode* inode)
|
|||||||
dump_block_run( " attributes = ", inode->attributes);
|
dump_block_run( " attributes = ", inode->attributes);
|
||||||
Print(" type = %u\n", (unsigned)inode->Type());
|
Print(" type = %u\n", (unsigned)inode->Type());
|
||||||
Print(" inode_size = %u\n", (unsigned)inode->InodeSize());
|
Print(" inode_size = %u\n", (unsigned)inode->InodeSize());
|
||||||
Print(" etc = %#08x\n", (int)inode->etc);
|
|
||||||
Print(" short_symlink = %s\n",
|
Print(" short_symlink = %s\n",
|
||||||
S_ISLNK(inode->Mode()) && (inode->Flags() & INODE_LONG_SYMLINK) == 0
|
S_ISLNK(inode->Mode()) && (inode->Flags() & INODE_LONG_SYMLINK) == 0
|
||||||
? inode->short_symlink : "-");
|
? inode->short_symlink : "-");
|
||||||
|
|||||||
@@ -335,6 +335,7 @@ Inode::Inode(Volume* volume, ino_t id)
|
|||||||
|
|
||||||
NodeGetter node(volume, this);
|
NodeGetter node(volume, this);
|
||||||
memcpy(&fNode, node.Node(), sizeof(bfs_inode));
|
memcpy(&fNode, node.Node(), sizeof(bfs_inode));
|
||||||
|
fNode.flags &= HOST_ENDIAN_TO_BFS_INT32(INODE_PERMANENT_FLAGS);
|
||||||
|
|
||||||
char lockName[B_OS_NAME_LENGTH];
|
char lockName[B_OS_NAME_LENGTH];
|
||||||
snprintf(lockName, sizeof(lockName), "bfs inode %d.%d",
|
snprintf(lockName, sizeof(lockName), "bfs inode %d.%d",
|
||||||
@@ -411,6 +412,9 @@ Inode::~Inode()
|
|||||||
file_map_delete(Map());
|
file_map_delete(Map());
|
||||||
delete fTree;
|
delete fTree;
|
||||||
|
|
||||||
|
if ((Flags() & INODE_DELETED) != 0)
|
||||||
|
fVolume->RemovedInodes().Remove(this);
|
||||||
|
|
||||||
rw_lock_destroy(&fLock);
|
rw_lock_destroy(&fLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,7 +428,7 @@ Inode::InitCheck(bool checkNode)
|
|||||||
if (status == B_BUSY)
|
if (status == B_BUSY)
|
||||||
return B_BUSY;
|
return B_BUSY;
|
||||||
|
|
||||||
if (status < B_OK) {
|
if (status != B_OK) {
|
||||||
FATAL(("inode at block %Ld corrupt!\n", BlockNumber()));
|
FATAL(("inode at block %Ld corrupt!\n", BlockNumber()));
|
||||||
RETURN_ERROR(B_BAD_DATA);
|
RETURN_ERROR(B_BAD_DATA);
|
||||||
}
|
}
|
||||||
@@ -436,7 +440,7 @@ Inode::InitCheck(bool checkNode)
|
|||||||
RETURN_ERROR(B_NO_MEMORY);
|
RETURN_ERROR(B_NO_MEMORY);
|
||||||
|
|
||||||
status_t status = fTree->InitCheck();
|
status_t status = fTree->InitCheck();
|
||||||
if (status < B_OK) {
|
if (status != B_OK) {
|
||||||
FATAL(("inode tree at block %Ld corrupt!\n", BlockNumber()));
|
FATAL(("inode tree at block %Ld corrupt!\n", BlockNumber()));
|
||||||
RETURN_ERROR(B_BAD_DATA);
|
RETURN_ERROR(B_BAD_DATA);
|
||||||
}
|
}
|
||||||
@@ -551,7 +555,7 @@ Inode::_MakeSpaceForSmallData(Transaction& transaction, bfs_inode* node,
|
|||||||
Inode* attribute;
|
Inode* attribute;
|
||||||
status_t status = CreateAttribute(transaction, item->Name(),
|
status_t status = CreateAttribute(transaction, item->Name(),
|
||||||
item->Type(), &attribute);
|
item->Type(), &attribute);
|
||||||
if (status < B_OK)
|
if (status != B_OK)
|
||||||
RETURN_ERROR(status);
|
RETURN_ERROR(status);
|
||||||
|
|
||||||
size_t length = item->DataSize();
|
size_t length = item->DataSize();
|
||||||
@@ -559,7 +563,7 @@ Inode::_MakeSpaceForSmallData(Transaction& transaction, bfs_inode* node,
|
|||||||
|
|
||||||
ReleaseAttribute(attribute);
|
ReleaseAttribute(attribute);
|
||||||
|
|
||||||
if (status < B_OK) {
|
if (status != B_OK) {
|
||||||
Vnode vnode(fVolume, Attributes());
|
Vnode vnode(fVolume, Attributes());
|
||||||
Inode* attributes;
|
Inode* attributes;
|
||||||
if (vnode.Get(&attributes) < B_OK
|
if (vnode.Get(&attributes) < B_OK
|
||||||
@@ -947,6 +951,8 @@ Inode::_RemoveAttribute(Transaction& transaction, const char* name,
|
|||||||
return status;
|
return status;
|
||||||
|
|
||||||
if (attributes->IsEmpty()) {
|
if (attributes->IsEmpty()) {
|
||||||
|
attributes->WriteLockInTransaction(transaction);
|
||||||
|
|
||||||
// remove attribute directory (don't fail if that can't be done)
|
// remove attribute directory (don't fail if that can't be done)
|
||||||
if (remove_vnode(fVolume->FSVolume(), attributes->ID()) == B_OK) {
|
if (remove_vnode(fVolume->FSVolume(), attributes->ID()) == B_OK) {
|
||||||
// update the inode, so that no one will ever doubt it's deleted :-)
|
// update the inode, so that no one will ever doubt it's deleted :-)
|
||||||
@@ -954,8 +960,11 @@ Inode::_RemoveAttribute(Transaction& transaction, const char* name,
|
|||||||
if (attributes->WriteBack(transaction) == B_OK) {
|
if (attributes->WriteBack(transaction) == B_OK) {
|
||||||
Attributes().SetTo(0, 0, 0);
|
Attributes().SetTo(0, 0, 0);
|
||||||
WriteBack(transaction);
|
WriteBack(transaction);
|
||||||
} else
|
} else {
|
||||||
unremove_vnode(fVolume->FSVolume(), attributes->ID());
|
unremove_vnode(fVolume->FSVolume(), attributes->ID());
|
||||||
|
attributes->Node().flags
|
||||||
|
&= ~HOST_ENDIAN_TO_BFS_INT32(INODE_DELETED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2001-2008, Axel Dörfler, [email protected].
|
* Copyright 2001-2009, Axel Dörfler, [email protected].
|
||||||
* 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
|
||||||
@@ -24,7 +24,9 @@ class NodeGetter;
|
|||||||
class Transaction;
|
class Transaction;
|
||||||
|
|
||||||
|
|
||||||
class Inode : public SinglyLinkedListLinkImpl<Inode> {
|
class Inode {
|
||||||
|
typedef DoublyLinkedListLink<Inode> Link;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Inode(Volume* volume, ino_t id);
|
Inode(Volume* volume, ino_t id);
|
||||||
Inode(Volume* volume, Transaction& transaction,
|
Inode(Volume* volume, Transaction& transaction,
|
||||||
@@ -174,6 +176,11 @@ public:
|
|||||||
{ ASSERT_WRITE_LOCKED_RW_LOCK(&fLock); }
|
{ ASSERT_WRITE_LOCKED_RW_LOCK(&fLock); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Link* GetDoublyLinkedListLink()
|
||||||
|
{ return (Link*)&fNode.pad[0]; }
|
||||||
|
const Link* GetDoublyLinkedListLink() const
|
||||||
|
{ return (Link*)&fNode.pad[0]; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Inode(const Inode& other);
|
Inode(const Inode& other);
|
||||||
Inode& operator=(const Inode& other);
|
Inode& operator=(const Inode& other);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2001-2008, Axel Dörfler, [email protected].
|
* Copyright 2001-2009, Axel Dörfler, [email protected].
|
||||||
* This file may be used under the terms of the MIT License.
|
* This file may be used under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -1091,18 +1091,21 @@ Transaction::AddInode(Inode* inode)
|
|||||||
if (fJournal == NULL)
|
if (fJournal == NULL)
|
||||||
panic("Transaction is not running!");
|
panic("Transaction is not running!");
|
||||||
|
|
||||||
InodeList::Iterator iterator = fLockedInodes.GetIterator();
|
// These flags can only change while holding the transaction lock
|
||||||
while (iterator.HasNext()) {
|
if ((inode->Flags() & INODE_IN_TRANSACTION) != 0)
|
||||||
if (iterator.Next() == inode) {
|
return;
|
||||||
//dprintf(" inode %Ld already in transaction\n", inode->ID());
|
|
||||||
return;
|
// We share the same list link with the removed list, so we have to remove
|
||||||
}
|
// the inode from that list here (and add it back when we no longer need it)
|
||||||
}
|
if ((inode->Flags() & INODE_DELETED) != 0)
|
||||||
|
GetVolume()->RemovedInodes().Remove(inode);
|
||||||
|
|
||||||
if (!GetVolume()->IsInitializing())
|
if (!GetVolume()->IsInitializing())
|
||||||
acquire_vnode(GetVolume()->FSVolume(), inode->ID());
|
acquire_vnode(GetVolume()->FSVolume(), inode->ID());
|
||||||
|
|
||||||
rw_lock_write_lock(&inode->fLock);
|
rw_lock_write_lock(&inode->fLock);
|
||||||
fLockedInodes.Add(inode);
|
fLockedInodes.Add(inode);
|
||||||
|
inode->Node().flags |= HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1112,8 +1115,14 @@ Transaction::RemoveInode(Inode* inode)
|
|||||||
if (fJournal == NULL)
|
if (fJournal == NULL)
|
||||||
panic("Transaction is not running!");
|
panic("Transaction is not running!");
|
||||||
|
|
||||||
|
inode->Node().flags &= ~HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION);
|
||||||
fLockedInodes.Remove(inode);
|
fLockedInodes.Remove(inode);
|
||||||
rw_lock_write_unlock(&inode->fLock);
|
rw_lock_write_unlock(&inode->fLock);
|
||||||
|
|
||||||
|
// See AddInode() why we do this here
|
||||||
|
if ((inode->Flags() & INODE_DELETED) != 0)
|
||||||
|
GetVolume()->RemovedInodes().Add(inode);
|
||||||
|
|
||||||
if (!GetVolume()->IsInitializing())
|
if (!GetVolume()->IsInitializing())
|
||||||
put_vnode(GetVolume()->FSVolume(), inode->ID());
|
put_vnode(GetVolume()->FSVolume(), inode->ID());
|
||||||
}
|
}
|
||||||
@@ -1123,7 +1132,13 @@ void
|
|||||||
Transaction::_UnlockInodes()
|
Transaction::_UnlockInodes()
|
||||||
{
|
{
|
||||||
while (Inode* inode = fLockedInodes.RemoveHead()) {
|
while (Inode* inode = fLockedInodes.RemoveHead()) {
|
||||||
|
inode->Node().flags &= ~HOST_ENDIAN_TO_BFS_INT32(INODE_IN_TRANSACTION);
|
||||||
rw_lock_write_unlock(&inode->fLock);
|
rw_lock_write_unlock(&inode->fLock);
|
||||||
|
|
||||||
|
// See AddInode() why we do this here
|
||||||
|
if ((inode->Flags() & INODE_DELETED) != 0)
|
||||||
|
GetVolume()->RemovedInodes().Add(inode);
|
||||||
|
|
||||||
if (!GetVolume()->IsInitializing())
|
if (!GetVolume()->IsInitializing())
|
||||||
put_vnode(GetVolume()->FSVolume(), inode->ID());
|
put_vnode(GetVolume()->FSVolume(), inode->ID());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ struct run_array;
|
|||||||
class Inode;
|
class Inode;
|
||||||
class LogEntry;
|
class LogEntry;
|
||||||
typedef DoublyLinkedList<LogEntry> LogEntryList;
|
typedef DoublyLinkedList<LogEntry> LogEntryList;
|
||||||
typedef SinglyLinkedList<Inode> InodeList;
|
|
||||||
|
|
||||||
|
|
||||||
class Journal {
|
class Journal {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2001-2008, Axel Dörfler, [email protected].
|
* Copyright 2001-2009, Axel Dörfler, [email protected].
|
||||||
* 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 VOLUME_H
|
#ifndef VOLUME_H
|
||||||
@@ -23,6 +23,8 @@ enum volume_initialize_flags {
|
|||||||
VOLUME_NO_INDICES = 0x0001,
|
VOLUME_NO_INDICES = 0x0001,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef DoublyLinkedList<Inode> InodeList;
|
||||||
|
|
||||||
class Volume {
|
class Volume {
|
||||||
public:
|
public:
|
||||||
Volume(fs_volume* volume);
|
Volume(fs_volume* volume);
|
||||||
@@ -86,6 +88,9 @@ public:
|
|||||||
|
|
||||||
status_t CreateIndicesRoot(Transaction& transaction);
|
status_t CreateIndicesRoot(Transaction& transaction);
|
||||||
|
|
||||||
|
InodeList& RemovedInodes() { return fRemovedInodes; }
|
||||||
|
// This list is guarded by the transaction lock
|
||||||
|
|
||||||
// block bitmap
|
// block bitmap
|
||||||
BlockAllocator& Allocator();
|
BlockAllocator& Allocator();
|
||||||
status_t AllocateForInode(Transaction& transaction,
|
status_t AllocateForInode(Transaction& transaction,
|
||||||
@@ -127,7 +132,7 @@ public:
|
|||||||
uint32* _offset = NULL);
|
uint32* _offset = NULL);
|
||||||
static status_t Identify(int fd, disk_super_block* superBlock);
|
static status_t Identify(int fd, disk_super_block* superBlock);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
fs_volume* fVolume;
|
fs_volume* fVolume;
|
||||||
int fDevice;
|
int fDevice;
|
||||||
disk_super_block fSuperBlock;
|
disk_super_block fSuperBlock;
|
||||||
@@ -155,6 +160,8 @@ public:
|
|||||||
|
|
||||||
void* fBlockCache;
|
void* fBlockCache;
|
||||||
thread_id fCheckingThread;
|
thread_id fCheckingThread;
|
||||||
|
|
||||||
|
InodeList fRemovedInodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2001-2008, Axel Dörfler, [email protected].
|
* Copyright 2001-2009, Axel Dörfler, [email protected].
|
||||||
* Parts of this code is based on work previously done by Marcus Overhagen.
|
* Parts of this code is based on work previously done by Marcus Overhagen.
|
||||||
*
|
*
|
||||||
* This file may be used under the terms of the MIT License.
|
* This file may be used under the terms of the MIT License.
|
||||||
@@ -165,7 +165,8 @@ struct small_data {
|
|||||||
|
|
||||||
class Volume;
|
class Volume;
|
||||||
|
|
||||||
#define SHORT_SYMLINK_NAME_LENGTH 144 // length incl. terminating '\0'
|
#define SHORT_SYMLINK_NAME_LENGTH 144
|
||||||
|
// length incl. terminating '\0'
|
||||||
|
|
||||||
struct bfs_inode {
|
struct bfs_inode {
|
||||||
int32 magic1;
|
int32 magic1;
|
||||||
@@ -181,13 +182,14 @@ struct bfs_inode {
|
|||||||
uint32 type; // attribute type
|
uint32 type; // attribute type
|
||||||
|
|
||||||
int32 inode_size;
|
int32 inode_size;
|
||||||
uint32 etc; // a pointer to the Inode object during construction
|
uint32 etc;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
data_stream data;
|
data_stream data;
|
||||||
char short_symlink[SHORT_SYMLINK_NAME_LENGTH];
|
char short_symlink[SHORT_SYMLINK_NAME_LENGTH];
|
||||||
};
|
};
|
||||||
int32 pad[4];
|
int32 pad[4];
|
||||||
|
// we use this member as a doubly linked list link
|
||||||
|
|
||||||
small_data small_data_start[0];
|
small_data small_data_start[0];
|
||||||
|
|
||||||
@@ -222,6 +224,8 @@ enum inode_flags {
|
|||||||
INODE_PERMANENT_FLAGS = 0x0000ffff,
|
INODE_PERMANENT_FLAGS = 0x0000ffff,
|
||||||
|
|
||||||
INODE_WAS_WRITTEN = 0x00020000,
|
INODE_WAS_WRITTEN = 0x00020000,
|
||||||
|
INODE_IN_TRANSACTION = 0x00040000,
|
||||||
|
|
||||||
// The rest is only used by the file system check functionality
|
// The rest is only used by the file system check functionality
|
||||||
INODE_DONT_FREE_SPACE = 0x00080000
|
INODE_DONT_FREE_SPACE = 0x00080000
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ bfs_get_vnode(fs_volume* _volume, ino_t id, fs_vnode* _node, int* _type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
status_t status = node->InitCheck(volume);
|
status_t status = node->InitCheck(volume);
|
||||||
if (status < B_OK) {
|
if (status != B_OK) {
|
||||||
if ((node->Flags() & INODE_DELETED) != 0) {
|
if ((node->Flags() & INODE_DELETED) != 0) {
|
||||||
INFORM(("inode at %Ld is already deleted!\n", id));
|
INFORM(("inode at %Ld is already deleted!\n", id));
|
||||||
} else {
|
} else {
|
||||||
@@ -281,7 +281,7 @@ bfs_get_vnode(fs_volume* _volume, ino_t id, fs_vnode* _node, int* _type,
|
|||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
status = inode->InitCheck(false);
|
status = inode->InitCheck(false);
|
||||||
if (status < B_OK)
|
if (status != B_OK)
|
||||||
delete inode;
|
delete inode;
|
||||||
|
|
||||||
if (status == B_OK) {
|
if (status == B_OK) {
|
||||||
@@ -328,20 +328,20 @@ bfs_remove_vnode(fs_volume* _volume, fs_vnode* _node, bool reenter)
|
|||||||
Volume* volume = (Volume*)_volume->private_volume;
|
Volume* volume = (Volume*)_volume->private_volume;
|
||||||
Inode* inode = (Inode*)_node->private_node;
|
Inode* inode = (Inode*)_node->private_node;
|
||||||
|
|
||||||
// The "chkbfs" functionality uses this flag to prevent the space used
|
|
||||||
// up by the inode from being freed - this flag is set only in situations
|
|
||||||
// where this is a good idea... (the block bitmap will get fixed anyway
|
|
||||||
// in this case).
|
|
||||||
if (inode->Flags() & INODE_DONT_FREE_SPACE) {
|
|
||||||
delete inode;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the inode isn't in use anymore, we were called before
|
// If the inode isn't in use anymore, we were called before
|
||||||
// bfs_unlink() returns - in this case, we can just use the
|
// bfs_unlink() returns - in this case, we can just use the
|
||||||
// transaction which has already deleted the inode.
|
// transaction which has already deleted the inode.
|
||||||
Transaction transaction(volume, volume->ToBlock(inode->Parent()));
|
Transaction transaction(volume, volume->ToBlock(inode->Parent()));
|
||||||
|
|
||||||
|
// The "chkbfs" functionality uses this flag to prevent the space used
|
||||||
|
// up by the inode from being freed - this flag is set only in situations
|
||||||
|
// where this is a good idea... (the block bitmap will get fixed anyway
|
||||||
|
// in this case).
|
||||||
|
if ((inode->Flags() & INODE_DONT_FREE_SPACE) != 0) {
|
||||||
|
delete inode;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
status_t status = inode->Free(transaction);
|
status_t status = inode->Free(transaction);
|
||||||
if (status == B_OK) {
|
if (status == B_OK) {
|
||||||
transaction.Done();
|
transaction.Done();
|
||||||
|
|||||||
Reference in New Issue
Block a user