Moved the functionality of Volume::IsSuperBlockValid() into the new
disk_super_block::IsValid() method. There is now a disk_super_block::Initialize() method that sets up a super block for creating a new file system on it - it's currently hard coded to produce correct results for 10 MB images, though; the allocation group stuff has to be done a bit more flexible :) Added a DeviceOpener class that simplifies Volume::Mount() a bit and fixes some problems of it (forgot to call close() once or twice). Implemented the new Volume::Initialize() method that completely covers the mkbfs functionality. Fixed the broken Volume::ToBlockRun() method - AFAICT it has only be used by Volume::CreateIndicesRoot() and in dump_bplustree_node so far (should not have been critical, as the former was probably never called yet [only if you had tried to create an index on a BFS volume that didn't have indices yet]). git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6313 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -20,11 +20,176 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceOpener {
|
||||||
|
public:
|
||||||
|
DeviceOpener(const char *device, int mode);
|
||||||
|
~DeviceOpener();
|
||||||
|
|
||||||
|
int Open(const char *device, int mode);
|
||||||
|
status_t InitCache(off_t numBlocks);
|
||||||
|
void RemoveCache(int mode);
|
||||||
|
|
||||||
|
void Keep();
|
||||||
|
|
||||||
|
int Device() const { return fDevice; }
|
||||||
|
|
||||||
|
status_t GetSize(off_t *_size, uint32 *_blockSize = NULL);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int fDevice;
|
||||||
|
bool fCached;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
DeviceOpener::DeviceOpener(const char *device, int mode)
|
||||||
|
:
|
||||||
|
fCached(false)
|
||||||
|
{
|
||||||
|
Open(device, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DeviceOpener::~DeviceOpener()
|
||||||
|
{
|
||||||
|
if (fDevice >= B_OK) {
|
||||||
|
close(fDevice);
|
||||||
|
if (fCached)
|
||||||
|
remove_cached_device_blocks(fDevice, NO_WRITES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
DeviceOpener::Open(const char *device, int mode)
|
||||||
|
{
|
||||||
|
fDevice = open(device, mode);
|
||||||
|
return fDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
DeviceOpener::InitCache(off_t numBlocks)
|
||||||
|
{
|
||||||
|
if (init_cache_for_device(fDevice, numBlocks) == B_OK) {
|
||||||
|
fCached = true;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DeviceOpener::RemoveCache(int mode)
|
||||||
|
{
|
||||||
|
if (!fCached)
|
||||||
|
return;
|
||||||
|
|
||||||
|
remove_cached_device_blocks(fDevice, mode);
|
||||||
|
fCached = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DeviceOpener::Keep()
|
||||||
|
{
|
||||||
|
fDevice = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Returns the size of the device in bytes. It uses B_GET_GEOMETRY
|
||||||
|
* to compute the size, or fstat() if that failed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
status_t
|
||||||
|
DeviceOpener::GetSize(off_t *_size, uint32 *_blockSize)
|
||||||
|
{
|
||||||
|
device_geometry geometry;
|
||||||
|
if (ioctl(fDevice, B_GET_GEOMETRY, &geometry) < 0) {
|
||||||
|
// maybe it's just a file
|
||||||
|
struct stat stat;
|
||||||
|
if (fstat(fDevice, &stat) < 0)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
if (_size)
|
||||||
|
*_size = stat.st_size;
|
||||||
|
if (_blockSize) // that shouldn't cause us any problems
|
||||||
|
*_blockSize = 512;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_size)
|
||||||
|
*_size = geometry.head_count * geometry.cylinder_count * geometry.sectors_per_track;
|
||||||
|
if (_blockSize)
|
||||||
|
*_blockSize = geometry.bytes_per_sector;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
disk_super_block::IsValid()
|
||||||
|
{
|
||||||
|
if (Magic1() != (int32)SUPER_BLOCK_MAGIC1
|
||||||
|
|| Magic2() != (int32)SUPER_BLOCK_MAGIC2
|
||||||
|
|| Magic3() != (int32)SUPER_BLOCK_MAGIC3
|
||||||
|
|| (int32)block_size != inode_size
|
||||||
|
|| ByteOrder() != SUPER_BLOCK_FS_LENDIAN
|
||||||
|
|| (1UL << BlockShift()) != BlockSize()
|
||||||
|
|| AllocationGroups() < 1
|
||||||
|
|| AllocationGroupShift() < 1
|
||||||
|
|| BlocksPerAllocationGroup() < 1
|
||||||
|
|| NumBlocks() < 10
|
||||||
|
|| AllocationGroups() != divide_roundup(NumBlocks(),
|
||||||
|
1L << AllocationGroupShift()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
disk_super_block::Initialize(const char *diskName, off_t numBlocks, uint32 blockSize)
|
||||||
|
{
|
||||||
|
memset(this, 0, sizeof(disk_super_block));
|
||||||
|
|
||||||
|
magic1 = HOST_ENDIAN_TO_BFS_INT32(SUPER_BLOCK_MAGIC1);
|
||||||
|
magic2 = HOST_ENDIAN_TO_BFS_INT32(SUPER_BLOCK_MAGIC2);
|
||||||
|
magic3 = HOST_ENDIAN_TO_BFS_INT32(SUPER_BLOCK_MAGIC3);
|
||||||
|
fs_byte_order = SUPER_BLOCK_FS_LENDIAN;
|
||||||
|
flags = SUPER_BLOCK_DISK_CLEAN;
|
||||||
|
|
||||||
|
strlcpy(name, diskName, sizeof(name));
|
||||||
|
|
||||||
|
block_size = inode_size = HOST_ENDIAN_TO_BFS_INT32(blockSize);
|
||||||
|
for (block_shift = 9; (1UL << block_shift) < blockSize; block_shift++);
|
||||||
|
|
||||||
|
num_blocks = numBlocks;
|
||||||
|
used_blocks = 0;
|
||||||
|
|
||||||
|
// ToDo: set allocation group stuff for real (this is hardcoded for a 10 MB file)!!!
|
||||||
|
|
||||||
|
blocks_per_ag = 1;
|
||||||
|
num_ags = 2;
|
||||||
|
ag_shift = 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
Volume::Volume(nspace_id id)
|
Volume::Volume(nspace_id id)
|
||||||
:
|
:
|
||||||
fID(id),
|
fID(id),
|
||||||
fBlockAllocator(this),
|
fBlockAllocator(this),
|
||||||
fLock("bfs volume"),
|
fLock("bfs volume"),
|
||||||
|
fRootNode(NULL),
|
||||||
|
fIndicesNode(NULL),
|
||||||
fDirtyCachedBlocks(0),
|
fDirtyCachedBlocks(0),
|
||||||
fUniqueID(0),
|
fUniqueID(0),
|
||||||
fFlags(0)
|
fFlags(0)
|
||||||
@@ -40,21 +205,7 @@ Volume::~Volume()
|
|||||||
bool
|
bool
|
||||||
Volume::IsValidSuperBlock()
|
Volume::IsValidSuperBlock()
|
||||||
{
|
{
|
||||||
if (fSuperBlock.Magic1() != (int32)SUPER_BLOCK_MAGIC1
|
return fSuperBlock.IsValid();
|
||||||
|| fSuperBlock.Magic2() != (int32)SUPER_BLOCK_MAGIC2
|
|
||||||
|| fSuperBlock.Magic3() != (int32)SUPER_BLOCK_MAGIC3
|
|
||||||
|| (int32)fSuperBlock.block_size != fSuperBlock.inode_size
|
|
||||||
|| fSuperBlock.ByteOrder() != SUPER_BLOCK_FS_LENDIAN
|
|
||||||
|| (1UL << fSuperBlock.BlockShift()) != fSuperBlock.BlockSize()
|
|
||||||
|| fSuperBlock.AllocationGroups() < 1
|
|
||||||
|| fSuperBlock.AllocationGroupShift() < 1
|
|
||||||
|| fSuperBlock.BlocksPerAllocationGroup() < 1
|
|
||||||
|| fSuperBlock.NumBlocks() < 10
|
|
||||||
|| fSuperBlock.AllocationGroups() != divide_roundup(fSuperBlock.NumBlocks(),
|
|
||||||
1L << fSuperBlock.AllocationGroupShift()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -84,14 +235,15 @@ Volume::Mount(const char *deviceName, uint32 flags)
|
|||||||
flags |= B_MOUNT_READ_ONLY;
|
flags |= B_MOUNT_READ_ONLY;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fDevice = open(deviceName, flags & B_MOUNT_READ_ONLY ? O_RDONLY : O_RDWR);
|
DeviceOpener opener(deviceName, flags & B_MOUNT_READ_ONLY ? O_RDONLY : O_RDWR);
|
||||||
|
|
||||||
// if we couldn't open the device, try read-only (don't rely on a specific error code)
|
// if we couldn't open the device, try read-only (don't rely on a specific error code)
|
||||||
if (fDevice < B_OK && (flags & B_MOUNT_READ_ONLY) == 0) {
|
if (opener.Device() < B_OK && (flags & B_MOUNT_READ_ONLY) == 0) {
|
||||||
fDevice = open(deviceName, O_RDONLY);
|
opener.Open(deviceName, O_RDONLY);
|
||||||
fFlags |= VOLUME_READ_ONLY;
|
fFlags |= VOLUME_READ_ONLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fDevice = opener.Device();
|
||||||
if (fDevice < B_OK)
|
if (fDevice < B_OK)
|
||||||
RETURN_ERROR(fDevice);
|
RETURN_ERROR(fDevice);
|
||||||
|
|
||||||
@@ -126,81 +278,79 @@ Volume::Mount(const char *deviceName, uint32 flags)
|
|||||||
if (!IsValidSuperBlock()) {
|
if (!IsValidSuperBlock()) {
|
||||||
#ifndef BFS_LITTLE_ENDIAN_ONLY
|
#ifndef BFS_LITTLE_ENDIAN_ONLY
|
||||||
memcpy(&fSuperBlock, buffer, sizeof(disk_super_block));
|
memcpy(&fSuperBlock, buffer, sizeof(disk_super_block));
|
||||||
if (!IsValidSuperBlock()) {
|
if (!IsValidSuperBlock())
|
||||||
close(fDevice);
|
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
#else
|
||||||
#else
|
|
||||||
close(fDevice);
|
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsValidSuperBlock()) {
|
if (!IsValidSuperBlock()) {
|
||||||
// set the current log pointers, so that journaling will work correctly
|
FATAL(("invalid super block!\n"));
|
||||||
fLogStart = fSuperBlock.LogStart();
|
return B_BAD_VALUE;
|
||||||
fLogEnd = fSuperBlock.LogEnd();
|
}
|
||||||
|
|
||||||
// initialize short hands to the super block (to save byte swapping)
|
// check if the device size is large enough to hold the file system
|
||||||
fBlockSize = fSuperBlock.BlockSize();
|
off_t diskSize;
|
||||||
fBlockShift = fSuperBlock.BlockShift();
|
if (opener.GetSize(&diskSize) < B_OK)
|
||||||
fAllocationGroupShift = fSuperBlock.AllocationGroupShift();
|
RETURN_ERROR(B_ERROR);
|
||||||
|
if (diskSize < (NumBlocks() << BlockShift()))
|
||||||
|
RETURN_ERROR(B_BAD_VALUE);
|
||||||
|
|
||||||
if (init_cache_for_device(fDevice, NumBlocks()) == B_OK) {
|
// set the current log pointers, so that journaling will work correctly
|
||||||
fJournal = new Journal(this);
|
fLogStart = fSuperBlock.LogStart();
|
||||||
// replaying the log is the first thing we will do on this disk
|
fLogEnd = fSuperBlock.LogEnd();
|
||||||
if (fJournal && fJournal->InitCheck() == B_OK
|
|
||||||
&& fBlockAllocator.Initialize() == B_OK) {
|
|
||||||
fRootNode = new Inode(this, ToVnode(Root()));
|
|
||||||
|
|
||||||
if (fRootNode && fRootNode->InitCheck() == B_OK) {
|
// initialize short hands to the super block (to save byte swapping)
|
||||||
if (new_vnode(fID, ToVnode(Root()), (void *)fRootNode) == B_OK) {
|
fBlockSize = fSuperBlock.BlockSize();
|
||||||
// try to get indices root dir
|
fBlockShift = fSuperBlock.BlockShift();
|
||||||
|
fAllocationGroupShift = fSuperBlock.AllocationGroupShift();
|
||||||
|
|
||||||
// question: why doesn't get_vnode() work here??
|
if (opener.InitCache(NumBlocks()) != B_OK)
|
||||||
// answer: we have not yet backpropagated the pointer to the
|
return B_ERROR;
|
||||||
// volume in bfs_mount(), so bfs_read_vnode() can't get it.
|
|
||||||
// But it's not needed to do that anyway.
|
|
||||||
|
|
||||||
fIndicesNode = new Inode(this, ToVnode(Indices()));
|
fJournal = new Journal(this);
|
||||||
if (fIndicesNode == NULL
|
// replaying the log is the first thing we will do on this disk
|
||||||
|| fIndicesNode->InitCheck() < B_OK
|
if (fJournal && fJournal->InitCheck() < B_OK
|
||||||
|| !fIndicesNode->IsContainer()) {
|
&& fBlockAllocator.Initialize() < B_OK) {
|
||||||
INFORM(("bfs: volume doesn't have indices!\n"));
|
// ToDo: improve error reporting for a bad journal
|
||||||
|
FATAL(("could not initialize journal/block bitmap allocator!\n"));
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
if (fIndicesNode) {
|
fRootNode = new Inode(this, ToVnode(Root()));
|
||||||
// if this is the case, the index root node is gone bad, and
|
if (fRootNode && fRootNode->InitCheck() == B_OK) {
|
||||||
// BFS switch to read-only mode
|
if (new_vnode(fID, ToVnode(Root()), (void *)fRootNode) == B_OK) {
|
||||||
fFlags |= VOLUME_READ_ONLY;
|
// try to get indices root dir
|
||||||
fIndicesNode = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// all went fine
|
// question: why doesn't get_vnode() work here??
|
||||||
return B_OK;
|
// answer: we have not yet backpropagated the pointer to the
|
||||||
} else
|
// volume in bfs_mount(), so bfs_read_vnode() can't get it.
|
||||||
status = B_NO_MEMORY;
|
// But it's not needed to do that anyway.
|
||||||
} else
|
|
||||||
status = B_BAD_VALUE;
|
|
||||||
|
|
||||||
FATAL(("could not create root node: new_vnode() failed!\n"));
|
fIndicesNode = new Inode(this, ToVnode(Indices()));
|
||||||
} else {
|
if (fIndicesNode == NULL
|
||||||
// ToDo: improve error reporting for a bad journal
|
|| fIndicesNode->InitCheck() < B_OK
|
||||||
status = B_NO_MEMORY;
|
|| !fIndicesNode->IsContainer()) {
|
||||||
FATAL(("could not initialize journal/block bitmap allocator!\n"));
|
INFORM(("bfs: volume doesn't have indices!\n"));
|
||||||
|
|
||||||
|
if (fIndicesNode) {
|
||||||
|
// if this is the case, the index root node is gone bad, and
|
||||||
|
// BFS switch to read-only mode
|
||||||
|
fFlags |= VOLUME_READ_ONLY;
|
||||||
|
fIndicesNode = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
remove_cached_device_blocks(fDevice, NO_WRITES);
|
// all went fine
|
||||||
} else {
|
opener.Keep();
|
||||||
FATAL(("could not initialize cache!\n"));
|
return B_OK;
|
||||||
status = B_IO_ERROR;
|
} else
|
||||||
}
|
status = B_NO_MEMORY;
|
||||||
FATAL(("invalid super block!\n"));
|
} else
|
||||||
}
|
|
||||||
else
|
|
||||||
status = B_BAD_VALUE;
|
status = B_BAD_VALUE;
|
||||||
|
|
||||||
close(fDevice);
|
FATAL(("could not create root node: new_vnode() failed!\n"));
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -249,8 +399,9 @@ Volume::ToBlockRun(off_t block) const
|
|||||||
{
|
{
|
||||||
block_run run;
|
block_run run;
|
||||||
run.allocation_group = HOST_ENDIAN_TO_BFS_INT32(block >> AllocationGroupShift());
|
run.allocation_group = HOST_ENDIAN_TO_BFS_INT32(block >> AllocationGroupShift());
|
||||||
run.start = HOST_ENDIAN_TO_BFS_INT16(block & ~((1LL << AllocationGroupShift()) - 1));
|
run.start = HOST_ENDIAN_TO_BFS_INT16(block & ((1LL << AllocationGroupShift()) - 1));
|
||||||
run.length = HOST_ENDIAN_TO_BFS_INT16(1);
|
run.length = HOST_ENDIAN_TO_BFS_INT16(1);
|
||||||
|
__out("block %Ld -> (%lu, %u) %ld (%lu)\n", block, run.AllocationGroup(), run.Start(), AllocationGroupShift(), ((1UL << AllocationGroupShift()) - 1));
|
||||||
return run;
|
return run;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,3 +489,95 @@ Volume::RemoveQuery(Query *query)
|
|||||||
fQueryLock.Unlock();
|
fQueryLock.Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
// Disk initialization
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Volume::Initialize(const char *device, const char *name, uint32 blockSize, uint32 flags)
|
||||||
|
{
|
||||||
|
// although there is no really good reason for it, we won't
|
||||||
|
// accept '/' in disk names (mkbfs does this, too - and since
|
||||||
|
// Tracker names mounted volumes like their name)
|
||||||
|
if (strchr(name, '/') != NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (blockSize != 1024 && blockSize != 2048 && blockSize != 4096 && blockSize != 8192)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
DeviceOpener opener(device, O_RDWR);
|
||||||
|
if (opener.Device() < B_OK)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
fDevice = opener.Device();
|
||||||
|
|
||||||
|
uint32 deviceBlockSize;
|
||||||
|
off_t deviceSize;
|
||||||
|
if (opener.GetSize(&deviceSize, &deviceBlockSize) < B_OK)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
off_t numBlocks = deviceSize / blockSize;
|
||||||
|
|
||||||
|
// create valid super block
|
||||||
|
|
||||||
|
fSuperBlock.Initialize(name, numBlocks, blockSize);
|
||||||
|
|
||||||
|
// initialize short hands to the super block (to save byte swapping)
|
||||||
|
fBlockSize = fSuperBlock.BlockSize();
|
||||||
|
fBlockShift = fSuperBlock.BlockShift();
|
||||||
|
fAllocationGroupShift = fSuperBlock.AllocationGroupShift();
|
||||||
|
|
||||||
|
// since the allocator has not been initialized yet, we
|
||||||
|
// cannot use BlockAllocator::BitmapSize() here
|
||||||
|
fSuperBlock.log_blocks = ToBlockRun(AllocationGroups()
|
||||||
|
* fSuperBlock.BlocksPerAllocationGroup() + 1);
|
||||||
|
fSuperBlock.log_blocks.length = 4096;
|
||||||
|
// ToDo: set the log size depending on the disk size
|
||||||
|
fSuperBlock.log_start = fSuperBlock.log_end = HOST_ENDIAN_TO_BFS_INT64(ToBlock(Log()));
|
||||||
|
|
||||||
|
// set the current log pointers, so that journaling will work correctly
|
||||||
|
fLogStart = fSuperBlock.LogStart();
|
||||||
|
fLogEnd = fSuperBlock.LogEnd();
|
||||||
|
|
||||||
|
if (!IsValidSuperBlock())
|
||||||
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
|
if (opener.InitCache(numBlocks) != B_OK)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
fJournal = new Journal(this);
|
||||||
|
if (fJournal == NULL || fJournal->InitCheck() < B_OK)
|
||||||
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
|
// ready to write data to disk
|
||||||
|
|
||||||
|
Transaction transaction(this, 0);
|
||||||
|
|
||||||
|
if (fBlockAllocator.InitializeAndClearBitmap(transaction) < B_OK)
|
||||||
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
|
off_t id;
|
||||||
|
status_t status = Inode::Create(&transaction, NULL, NULL,
|
||||||
|
S_DIRECTORY | 0777, 0, 0, &id, &fRootNode);
|
||||||
|
if (status < B_OK)
|
||||||
|
RETURN_ERROR(status);
|
||||||
|
|
||||||
|
fSuperBlock.root_dir = ToBlockRun(id);
|
||||||
|
|
||||||
|
if ((flags & VOLUME_NO_INDICES) == 0) {
|
||||||
|
if ((status = CreateIndicesRoot(&transaction)) < B_OK)
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteSuperBlock();
|
||||||
|
transaction.Done();
|
||||||
|
|
||||||
|
put_vnode(ID(), fRootNode->ID());
|
||||||
|
if (fIndicesNode != NULL)
|
||||||
|
put_vnode(ID(), fIndicesNode->ID());
|
||||||
|
|
||||||
|
Sync();
|
||||||
|
opener.RemoveCache(ALLOW_WRITES);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ enum volume_flags {
|
|||||||
VOLUME_READ_ONLY = 0x0001
|
VOLUME_READ_ONLY = 0x0001
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum volume_initialize_flags {
|
||||||
|
VOLUME_NO_INDICES = 0x0001,
|
||||||
|
};
|
||||||
|
|
||||||
class Volume {
|
class Volume {
|
||||||
public:
|
public:
|
||||||
@@ -39,6 +42,8 @@ class Volume {
|
|||||||
|
|
||||||
status_t Mount(const char *device, uint32 flags);
|
status_t Mount(const char *device, uint32 flags);
|
||||||
status_t Unmount();
|
status_t Unmount();
|
||||||
|
status_t Initialize(const char *device, const char *name,
|
||||||
|
uint32 blockSize, uint32 flags);
|
||||||
|
|
||||||
bool IsValidSuperBlock();
|
bool IsValidSuperBlock();
|
||||||
bool IsReadOnly() const;
|
bool IsReadOnly() const;
|
||||||
|
|||||||
@@ -88,6 +88,10 @@ struct disk_super_block {
|
|||||||
int32 Flags() const { return BFS_ENDIAN_TO_HOST_INT32(flags); }
|
int32 Flags() const { return BFS_ENDIAN_TO_HOST_INT32(flags); }
|
||||||
off_t LogStart() const { return BFS_ENDIAN_TO_HOST_INT64(log_start); }
|
off_t LogStart() const { return BFS_ENDIAN_TO_HOST_INT64(log_start); }
|
||||||
off_t LogEnd() const { return BFS_ENDIAN_TO_HOST_INT64(log_end); }
|
off_t LogEnd() const { return BFS_ENDIAN_TO_HOST_INT64(log_end); }
|
||||||
|
|
||||||
|
// implemented in Volume.cpp:
|
||||||
|
bool IsValid();
|
||||||
|
void Initialize(const char *name, off_t numBlocks, uint32 blockSize);
|
||||||
} _PACKED;
|
} _PACKED;
|
||||||
|
|
||||||
#define SUPER_BLOCK_FS_LENDIAN 'BIGE' /* BIGE */
|
#define SUPER_BLOCK_FS_LENDIAN 'BIGE' /* BIGE */
|
||||||
|
|||||||
Reference in New Issue
Block a user