btrfs: partially implement filesystem initialization

Change-Id: I7fb3340dc39b3331d30e5113b5860d936efab253
Reviewed-on: https://review.haiku-os.org/c/1395
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
Les De Ridder
2019-04-21 13:39:46 +00:00
committed by Jérôme Duval
parent 9d6d044fdd
commit aa08671d9c
10 changed files with 351 additions and 23 deletions
@@ -121,7 +121,8 @@ Inode::Create(Transaction& transaction, ino_t id, Inode* parent, int32 mode,
TRACE("Inode::Create() id % " B_PRIu64 " mode %" B_PRId32 " flags %"
B_PRIu64"\n", id, flags, mode);
Volume* volume = parent->GetVolume();
Volume* volume = parent != NULL ?
parent->GetVolume() : transaction.GetJournal()->GetVolume();
uint64 nbytes = size; // allocated size
if (size > volume->MaxInlineSize())
nbytes = (size / volume->SectorSize() + 1) * volume->SectorSize();
@@ -135,7 +136,8 @@ Inode::Create(Transaction& transaction, ino_t id, Inode* parent, int32 mode,
inode.blockgroup = 0; // normal inode only
inode.num_links = B_HOST_TO_LENDIAN_INT32(1);
inode.uid = B_HOST_TO_LENDIAN_INT32(geteuid());
inode.gid = B_HOST_TO_LENDIAN_INT32(parent ? parent->GroupID() : getegid());
inode.gid = B_HOST_TO_LENDIAN_INT32(parent != NULL ?
parent->GroupID() : getegid());
inode.mode = B_HOST_TO_LENDIAN_INT32(mode);;
inode.rdev = 0; // normal file only
inode.flags = B_HOST_TO_LENDIAN_INT64(flags);
+13 -2
View File
@@ -1,24 +1,35 @@
SubDir HAIKU_TOP src add-ons kernel file_systems btrfs ;
UsePrivateHeaders [ FDirName kernel util ] ;
UsePrivateHeaders shared storage ;
UsePrivateHeaders shared storage file_systems ;
UsePrivateKernelHeaders ;
UseBuildFeatureHeaders zlib ;
DEFINES += DEBUG_APP="\\\"btrfs\\\"" ;
UseHeaders [ FDirName $(HAIKU_TOP) src libs uuid ] : true ;
Includes [ FGristFiles Inode.cpp ]
: [ BuildFeatureAttribute zlib : headers ] ;
KernelAddon btrfs :
btrfs_disk_system.cpp
kernel_interface.cpp
Attribute.cpp
AttributeIterator.cpp
BTree.cpp
Chunk.cpp
CRCTable.cpp
DebugSupport.cpp
DirectoryIterator.cpp
ExtentAllocator.cpp
Inode.cpp
Journal.cpp
Volume.cpp
: kernel_libz.a
:
kernel_libz.a
libuuid_kernel.a
;
SEARCH on [ FGristFiles DebugSupport.cpp ]
+= [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems shared ] ;
@@ -45,6 +45,7 @@ public:
Transaction();
~Transaction();
Journal* GetJournal() const { return fJournal; }
int32 ID() const { return fJournal->TransactionID(); }
uint64 SystemID() const
{ return fJournal->SystemTransactionID(); }
@@ -1,7 +1,9 @@
/*
* Copyright 2019, Les De Ridder, [email protected]
* Copyright 2017, Chế Vũ Gia Hy, [email protected].
* Copyright 2011, Jérôme Duval, [email protected].
* Copyright 2008-2010, Axel Dörfler, [email protected].
*
* This file may be used under the terms of the MIT License.
*/
@@ -13,9 +15,11 @@
#include "BTree.h"
#include "CachedBlock.h"
#include "Chunk.h"
#include "DebugSupport.h"
#include "ExtentAllocator.h"
#include "Inode.h"
#include "Journal.h"
#include "ExtentAllocator.h"
#include "Utility.h"
//#define TRACE_BTRFS
@@ -191,7 +195,7 @@ DeviceOpener::GetSize(off_t* _size, uint32* _blockSize)
bool
btrfs_super_block::IsValid()
btrfs_super_block::IsValid() const
{
// TODO: check some more values!
if (strncmp(magic, BTRFS_SUPER_BLOCK_MAGIC, sizeof(magic)) != 0)
@@ -201,6 +205,33 @@ btrfs_super_block::IsValid()
}
void
btrfs_super_block::Initialize(const char* name, off_t numBlocks,
uint32 blockSize, uint32 sectorSize)
{
memset(this, 0, sizeof(btrfs_super_block));
uuid_generate(fsid);
blocknum = B_HOST_TO_LENDIAN_INT64(BTRFS_SUPER_BLOCK_OFFSET);
num_devices = B_HOST_TO_LENDIAN_INT64(1);
strncpy(magic, BTRFS_SUPER_BLOCK_MAGIC_TEMPORARY, sizeof(magic));
generation = B_HOST_TO_LENDIAN_INT64(1);
root = B_HOST_TO_LENDIAN_INT64(BTRFS_RESERVED_SPACE_OFFSET + blockSize);
chunk_root = B_HOST_TO_LENDIAN_INT64(Root() + blockSize);
total_size = B_HOST_TO_LENDIAN_INT64(numBlocks * blockSize);
used_size = B_HOST_TO_LENDIAN_INT64(6 * blockSize);
sector_size = B_HOST_TO_LENDIAN_INT32(sectorSize);
leaf_size = B_HOST_TO_LENDIAN_INT32(blockSize);
node_size = B_HOST_TO_LENDIAN_INT32(blockSize);
stripe_size = B_HOST_TO_LENDIAN_INT32(blockSize);
checksum_type = B_HOST_TO_LENDIAN_INT32(BTRFS_CSUM_TYPE_CRC32);
chunk_root_generation = B_HOST_TO_LENDIAN_INT64(1);
// TODO(lesderid): Support configurable filesystem features
incompat_flags = B_HOST_TO_LENDIAN_INT64(0);
strlcpy(label, name, BTRFS_LABEL_SIZE);
}
// #pragma mark -
@@ -453,6 +484,78 @@ Volume::Mount(const char* deviceName, uint32 flags)
}
status_t
Volume::Initialize(int fd, const char* label, uint32 blockSize,
uint32 sectorSize)
{
TRACE("Volume::Initialize()\n");
// label must != NULL and may not contain '/' or '\\'
if (label == NULL
|| strchr(label, '/') != NULL || strchr(label, '\\') != NULL) {
return B_BAD_VALUE;
}
if ((blockSize != 1024 && blockSize != 2048 && blockSize != 4096
&& blockSize != 8192 && blockSize != 16384)
|| blockSize % sectorSize != 0) {
return B_BAD_VALUE;
}
DeviceOpener opener(fd, O_RDWR);
if (opener.Device() < B_OK)
return B_BAD_VALUE;
if (opener.IsReadOnly())
return B_READ_ONLY_DEVICE;
fDevice = opener.Device();
uint32 deviceBlockSize;
off_t deviceSize;
if (opener.GetSize(&deviceSize, &deviceBlockSize) < B_OK)
return B_ERROR;
off_t numBlocks = deviceSize / sectorSize;
// create valid superblock
fSuperBlock.Initialize(label, numBlocks, blockSize, sectorSize);
fBlockSize = fSuperBlock.BlockSize();
fSectorSize = fSuperBlock.SectorSize();
// TODO(lesderid): Initialize remaining core structures
// (extent tree, chunk tree, fs tree, etc.)
status_t status = WriteSuperBlock();
if (status < B_OK)
return status;
fBlockCache = opener.InitCache(fSuperBlock.TotalSize() / fBlockSize,
fBlockSize);
if (fBlockCache == NULL)
return B_ERROR;
fJournal = new(std::nothrow) Journal(this);
if (fJournal == NULL)
RETURN_ERROR(B_ERROR);
// TODO(lesderid): Perform secondary initialization (in transactions)
// (add block groups to extent tree, create root dir, etc.)
Transaction transaction(this);
// TODO(lesderid): Write all superblocks when transactions are committed
status = transaction.Done();
if (status < B_OK)
return status;
opener.RemoveCache(true);
TRACE("Volume::Initialize(): Done\n");
return B_OK;
}
status_t
Volume::Unmount()
{
@@ -546,6 +649,20 @@ Volume::FindBlock(off_t logical, off_t& physical)
}
status_t
Volume::WriteSuperBlock()
{
// TODO(lesderid): Calculate checksum
if (write_pos(fDevice, BTRFS_SUPER_BLOCK_OFFSET, &fSuperBlock,
sizeof(btrfs_super_block))
!= sizeof(btrfs_super_block))
return B_IO_ERROR;
return B_OK;
}
/* Wrapper function for allocating new block
*/
status_t
@@ -30,6 +30,8 @@ public:
status_t Mount(const char* device, uint32 flags);
status_t Unmount();
status_t Initialize(int fd, const char* label,
uint32 blockSize, uint32 sectorSize);
bool IsValidSuperBlock();
bool IsReadOnly() const
@@ -58,6 +60,7 @@ public:
btrfs_super_block& SuperBlock() { return fSuperBlock; }
status_t LoadSuperBlock();
status_t WriteSuperBlock();
// cache access
void* BlockCache() { return fBlockCache; }
+20 -11
View File
@@ -13,7 +13,11 @@
typedef uint64 fileblock_t; // file block number
typedef uint64 fsblock_t; // filesystem block number
#define BTRFS_SUPER_BLOCK_OFFSET 0x10000
#define BTRFS_LABEL_SIZE 256
#define BTRFS_SUPER_BLOCK_OFFSET 0x10000 // 64KiB
#define BTRFS_RESERVED_SPACE_OFFSET 0x100000 // 1MiB
#define BTRFS_NUM_ROOT_BACKUPS 4
@@ -93,10 +97,10 @@ struct btrfs_timespec {
struct btrfs_header {
uint8 checksum[32];
uint8 fsid[16];
uuid_t fsid;
uint64 logical_address;
uint64 flags;
uint8 chunk_tree_uuid[16];
uuid_t chunk_tree_uuid;
uint64 generation;
uint64 owner;
uint32 item_count;
@@ -162,7 +166,7 @@ struct btrfs_stream {
struct btrfs_stripe {
uint64 device_id;
uint64 offset;
uint8 device_uuid[16];
uuid_t device_uuid;
uint64 DeviceID() const { return B_LENDIAN_TO_HOST_INT64(device_id); }
uint64 Offset() const { return B_LENDIAN_TO_HOST_INT64(offset); }
} _PACKED;
@@ -208,14 +212,14 @@ struct btrfs_device {
uint32 group;
uint8 seek_speed;
uint8 bandwidth;
uint8 uuid[16];
uint8 fsid[16];
uuid_t uuid;
uuid_t fsid;
} _PACKED;
struct btrfs_super_block {
uint8 checksum[32];
uint8 fsid[16];
uuid_t fsid;
uint64 blocknum;
uint64 flags;
char magic[8];
@@ -242,13 +246,15 @@ struct btrfs_super_block {
uint8 chunk_root_level;
uint8 log_root_level;
btrfs_device device;
char label[256];
char label[BTRFS_LABEL_SIZE];
uint64 reserved[32];
uint8 system_chunk_array[2048];
btrfs_backup_roots backup_roots[BTRFS_NUM_ROOT_BACKUPS];
bool IsValid();
// implemented in Volume.cpp
// implemented in Volume.cpp:
bool IsValid() const;
void Initialize(const char* name, off_t numBlocks,
uint32 blockSize, uint32 sectorSize);
uint64 TotalSize() const { return B_LENDIAN_TO_HOST_INT64(total_size); }
uint32 BlockSize() const { return B_LENDIAN_TO_HOST_INT32(node_size); }
uint32 SectorSize() const { return B_LENDIAN_TO_HOST_INT32(sector_size); }
@@ -456,10 +462,13 @@ struct btrfs_extent_data_ref {
uint32 RefCount() const { return B_LENDIAN_TO_HOST_INT32(ref_count); }
} _PACKED;
#define BTRFS_SUPER_BLOCK_MAGIC "_BHRfS_M"
#define BTRFS_SUPER_BLOCK_MAGIC_TEMPORARY "!BHRfS_M"
#define BTRFS_FIRST_SUBVOLUME 256
#define BTRFS_CSUM_TYPE_CRC32 0
#define BTRFS_OBJECT_ID_ROOT_TREE 1
#define BTRFS_OBJECT_ID_EXTENT_TREE 2
#define BTRFS_OBJECT_ID_CHUNK_TREE 3
@@ -0,0 +1,67 @@
/*
* Copyright 2007-2008, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2019, Les De Ridder, les@lesderid.net
*
* Distributed under the terms of the MIT License.
*/
#include "btrfs_disk_system.h"
#include "btrfs.h"
#include "Volume.h"
status_t
parse_initialize_parameters(const char* parameterString,
initialize_parameters& parameters)
{
parameters.verbose = false;
void *handle = parse_driver_settings_string(parameterString);
if (handle == NULL)
return B_ERROR;
if (get_driver_boolean_parameter(handle, "verbose", false, true))
parameters.verbose = true;
const char *ss_string = get_driver_parameter(handle, "sector_size",
NULL, NULL);
uint32 sectorSize = B_PAGE_SIZE;
if (ss_string != NULL)
sectorSize = strtoul(ss_string, NULL, 0);
const char *bs_string = get_driver_parameter(handle, "block_size",
NULL, NULL);
uint32 blockSize = max_c(16384, B_PAGE_SIZE);
if (bs_string != NULL)
blockSize = strtoul(bs_string, NULL, 0);
// TODO(lesderid): accept more settings (allocation profiles, uuid, etc.)
delete_driver_settings(handle);
if ((blockSize != 1024 && blockSize != 2048 && blockSize != 4096
&& blockSize != 8192 && blockSize != 16384)
|| blockSize % sectorSize != 0) {
return B_BAD_VALUE;
}
parameters.sectorSize = sectorSize;
parameters.blockSize = blockSize;
return B_OK;
}
status_t
check_volume_name(const char* name)
{
if (name == NULL || strlen(name) >= BTRFS_LABEL_SIZE
|| strchr(name, '/') != NULL
|| strchr(name, '\\') != NULL) {
return B_BAD_VALUE;
}
return B_OK;
}
@@ -0,0 +1,25 @@
/*
* Copyright 2007, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2019, Les De Ridder, les@lesderid.net
*
* Distributed under the terms of the MIT License.
*/
#ifndef _BTRFS_DISK_SYSTEM_H
#define _BTRFS_DISK_SYSTEM_H
#include "system_dependencies.h"
struct initialize_parameters {
uint32 blockSize;
uint32 sectorSize;
bool verbose;
};
status_t parse_initialize_parameters(const char* parameterString,
initialize_parameters& parameters);
status_t check_volume_name(const char* name);
#endif // _BTRFS_DISK_SYSTEM_H
@@ -1,7 +1,9 @@
/*
* Copyright 2019, Les De Ridder, les@lesderid.net
* Copyright 2017, Chế Gia Hy, cvghy116@gmail.com.
* Copyright 2011, Jérôme Duval, korli@users.berlios.de.
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
*
* This file may be used under the terms of the MIT License.
*/
@@ -9,6 +11,8 @@
#include "Attribute.h"
#include "AttributeIterator.h"
#include "btrfs.h"
#include "btrfs_disk_system.h"
#include "DebugSupport.h"
#include "DirectoryIterator.h"
#include "Inode.h"
#include "Utility.h"
@@ -20,8 +24,6 @@
#else
# define TRACE(x...) ;
#endif
#define ERROR(x...) dprintf("\33[34mbtrfs:\33[0m " x)
#define BTRFS_IO_SIZE 65536
@@ -833,6 +835,85 @@ btrfs_remove_attr(fs_volume* _volume, fs_vnode* vnode,
return EROFS;
}
static uint32
btrfs_get_supported_operations(partition_data* partition, uint32 mask)
{
// TODO: We should at least check the partition size.
return B_DISK_SYSTEM_SUPPORTS_INITIALIZING
| B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME
// | B_DISK_SYSTEM_SUPPORTS_WRITING
;
}
static status_t
btrfs_initialize(int fd, partition_id partitionID, const char* name,
const char* parameterString, off_t partitionSize, disk_job_id job)
{
// check name
status_t status = check_volume_name(name);
if (status != B_OK)
return status;
// parse parameters
initialize_parameters parameters;
status = parse_initialize_parameters(parameterString, parameters);
if (status != B_OK)
return status;
update_disk_device_job_progress(job, 0);
// initialize the volume
Volume volume(NULL);
status = volume.Initialize(fd, name, parameters.blockSize,
parameters.sectorSize);
if (status < B_OK) {
INFORM("Initializing volume failed: %s\n", strerror(status));
return status;
}
// rescan partition
status = scan_partition(partitionID);
if (status != B_OK)
return status;
update_disk_device_job_progress(job, 1);
// print some info, if desired
if (parameters.verbose) {
btrfs_super_block super = volume.SuperBlock();
INFORM(("Disk was initialized successfully.\n"));
INFORM("\tlabel: \"%s\"\n", super.label);
INFORM("\tblock size: %u bytes\n", (unsigned)super.BlockSize());
INFORM("\tsector size: %u bytes\n", (unsigned)super.SectorSize());
}
return B_OK;
}
static status_t
btrfs_uninitialize(int fd, partition_id partitionID, off_t partitionSize,
uint32 blockSize, disk_job_id job)
{
if (blockSize == 0)
return B_BAD_VALUE;
update_disk_device_job_progress(job, 0.0);
// just overwrite the superblock
btrfs_super_block superBlock;
memset(&superBlock, 0, sizeof(superBlock));
if (write_pos(fd, BTRFS_SUPER_BLOCK_OFFSET, &superBlock,
sizeof(superBlock)) < 0)
return errno;
update_disk_device_job_progress(job, 1.0);
return B_OK;
}
// #pragma mark -
@@ -842,8 +923,12 @@ btrfs_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
init_debugging();
return B_OK;
case B_MODULE_UNINIT:
exit_debugging();
return B_OK;
default:
@@ -943,7 +1028,13 @@ static file_system_module_info sBtrfsFileSystem = {
"btrfs", // short_name
"Btrfs File System", // pretty_name
0, // DDM flags
// DDM flags
0
| B_DISK_SYSTEM_SUPPORTS_INITIALIZING
| B_DISK_SYSTEM_SUPPORTS_CONTENT_NAME
// | B_DISK_SYSTEM_SUPPORTS_WRITING
,
// scanning
btrfs_identify_partition,
@@ -955,7 +1046,7 @@ static file_system_module_info sBtrfsFileSystem = {
/* capability querying operations */
NULL,
&btrfs_get_supported_operations,
NULL, // validate_resize
NULL, // validate_move
@@ -973,8 +1064,8 @@ static file_system_module_info sBtrfsFileSystem = {
NULL, // move
NULL, // set_content_name
NULL, // set_content_parameters
NULL, // initialize
NULL // unitialize
btrfs_initialize,
btrfs_uninitialize
};
@@ -27,6 +27,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <ByteOrder.h>
#include <driver_settings.h>
#include <fs_cache.h>
#include <fs_interface.h>
#include <fs_info.h>
@@ -43,6 +44,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <uuid.h>
#include <zlib.h>
#endif // !FS_SHELL