From aa08671d9cd445a6ff181c83e9b077c51521f857 Mon Sep 17 00:00:00 2001 From: Les De Ridder Date: Tue, 9 Apr 2019 12:42:18 +0200 Subject: [PATCH] btrfs: partially implement filesystem initialization Change-Id: I7fb3340dc39b3331d30e5113b5860d936efab253 Reviewed-on: https://review.haiku-os.org/c/1395 Reviewed-by: Adrien Destugues --- .../kernel/file_systems/btrfs/Inode.cpp | 6 +- src/add-ons/kernel/file_systems/btrfs/Jamfile | 15 ++- .../kernel/file_systems/btrfs/Journal.h | 1 + .../kernel/file_systems/btrfs/Volume.cpp | 121 +++++++++++++++++- .../kernel/file_systems/btrfs/Volume.h | 3 + src/add-ons/kernel/file_systems/btrfs/btrfs.h | 31 +++-- .../file_systems/btrfs/btrfs_disk_system.cpp | 67 ++++++++++ .../file_systems/btrfs/btrfs_disk_system.h | 25 ++++ .../file_systems/btrfs/kernel_interface.cpp | 103 ++++++++++++++- .../file_systems/btrfs/system_dependencies.h | 2 + 10 files changed, 351 insertions(+), 23 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/btrfs/btrfs_disk_system.cpp create mode 100644 src/add-ons/kernel/file_systems/btrfs/btrfs_disk_system.h diff --git a/src/add-ons/kernel/file_systems/btrfs/Inode.cpp b/src/add-ons/kernel/file_systems/btrfs/Inode.cpp index 470cc5b921..3473ec31d8 100644 --- a/src/add-ons/kernel/file_systems/btrfs/Inode.cpp +++ b/src/add-ons/kernel/file_systems/btrfs/Inode.cpp @@ -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); diff --git a/src/add-ons/kernel/file_systems/btrfs/Jamfile b/src/add-ons/kernel/file_systems/btrfs/Jamfile index 1c76f14ad3..7789a606cf 100644 --- a/src/add-ons/kernel/file_systems/btrfs/Jamfile +++ b/src/add-ons/kernel/file_systems/btrfs/Jamfile @@ -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 ] ; diff --git a/src/add-ons/kernel/file_systems/btrfs/Journal.h b/src/add-ons/kernel/file_systems/btrfs/Journal.h index 77ccc7d417..23505195b3 100644 --- a/src/add-ons/kernel/file_systems/btrfs/Journal.h +++ b/src/add-ons/kernel/file_systems/btrfs/Journal.h @@ -45,6 +45,7 @@ public: Transaction(); ~Transaction(); + Journal* GetJournal() const { return fJournal; } int32 ID() const { return fJournal->TransactionID(); } uint64 SystemID() const { return fJournal->SystemTransactionID(); } diff --git a/src/add-ons/kernel/file_systems/btrfs/Volume.cpp b/src/add-ons/kernel/file_systems/btrfs/Volume.cpp index 0e3879eec4..4aff9ec0a7 100644 --- a/src/add-ons/kernel/file_systems/btrfs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/btrfs/Volume.cpp @@ -1,7 +1,9 @@ /* + * Copyright 2019, Les De Ridder, les@lesderid.net * Copyright 2017, Chế Vũ Gia Hy, cvghy116@gmail.com. * Copyright 2011, Jérôme Duval, korli@users.berlios.de. * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de. + * * 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 diff --git a/src/add-ons/kernel/file_systems/btrfs/Volume.h b/src/add-ons/kernel/file_systems/btrfs/Volume.h index 0ed952f820..a5ca3d2628 100644 --- a/src/add-ons/kernel/file_systems/btrfs/Volume.h +++ b/src/add-ons/kernel/file_systems/btrfs/Volume.h @@ -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; } diff --git a/src/add-ons/kernel/file_systems/btrfs/btrfs.h b/src/add-ons/kernel/file_systems/btrfs/btrfs.h index 337c118d67..0851452a8e 100644 --- a/src/add-ons/kernel/file_systems/btrfs/btrfs.h +++ b/src/add-ons/kernel/file_systems/btrfs/btrfs.h @@ -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 diff --git a/src/add-ons/kernel/file_systems/btrfs/btrfs_disk_system.cpp b/src/add-ons/kernel/file_systems/btrfs/btrfs_disk_system.cpp new file mode 100644 index 0000000000..64d457b748 --- /dev/null +++ b/src/add-ons/kernel/file_systems/btrfs/btrfs_disk_system.cpp @@ -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; +} + diff --git a/src/add-ons/kernel/file_systems/btrfs/btrfs_disk_system.h b/src/add-ons/kernel/file_systems/btrfs/btrfs_disk_system.h new file mode 100644 index 0000000000..b83c4d64dd --- /dev/null +++ b/src/add-ons/kernel/file_systems/btrfs/btrfs_disk_system.h @@ -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 diff --git a/src/add-ons/kernel/file_systems/btrfs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/btrfs/kernel_interface.cpp index a2d275b517..8fe9bd493c 100644 --- a/src/add-ons/kernel/file_systems/btrfs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/btrfs/kernel_interface.cpp @@ -1,7 +1,9 @@ /* + * Copyright 2019, Les De Ridder, les@lesderid.net * Copyright 2017, Chế Vũ 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 }; diff --git a/src/add-ons/kernel/file_systems/btrfs/system_dependencies.h b/src/add-ons/kernel/file_systems/btrfs/system_dependencies.h index 9f3b2d5c28..2723fdd3c6 100644 --- a/src/add-ons/kernel/file_systems/btrfs/system_dependencies.h +++ b/src/add-ons/kernel/file_systems/btrfs/system_dependencies.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ #include #include #include +#include #include #endif // !FS_SHELL