From bd0708fd41781cc3b044540634c7832716863551 Mon Sep 17 00:00:00 2001 From: CruxBox Date: Sun, 12 Jul 2020 19:45:11 +0530 Subject: [PATCH] xfs: Attempt at reading Leaf Directories We can read leaf directories now but I've only checked for a single block working right now. I might make a few more changes in an upcoming patch. Change-Id: I325de8a6fad4ef9298e7810256cba47a87c45187 Reviewed-on: https://review.haiku-os.org/c/haiku/+/3027 Reviewed-by: Adrien Destugues --- src/add-ons/kernel/file_systems/xfs/Debug.h | 4 +- .../kernel/file_systems/xfs/Directory.cpp | 41 ++- .../kernel/file_systems/xfs/Directory.h | 4 + .../kernel/file_systems/xfs/Extent.cpp | 16 +- src/add-ons/kernel/file_systems/xfs/Extent.h | 40 +- src/add-ons/kernel/file_systems/xfs/Inode.cpp | 11 +- src/add-ons/kernel/file_systems/xfs/Inode.h | 9 +- src/add-ons/kernel/file_systems/xfs/Jamfile | 1 + .../kernel/file_systems/xfs/LeafDirectory.cpp | 345 ++++++++++++++++++ .../kernel/file_systems/xfs/LeafDirectory.h | 76 ++++ src/add-ons/kernel/file_systems/xfs/Volume.h | 3 + .../file_systems/xfs/kernel_interface.cpp | 2 +- src/add-ons/kernel/file_systems/xfs/xfs.cpp | 7 + src/add-ons/kernel/file_systems/xfs/xfs.h | 3 +- .../kernel/file_systems/xfs/xfs_shell/Jamfile | 1 + 15 files changed, 523 insertions(+), 40 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/xfs/LeafDirectory.cpp create mode 100644 src/add-ons/kernel/file_systems/xfs/LeafDirectory.h diff --git a/src/add-ons/kernel/file_systems/xfs/Debug.h b/src/add-ons/kernel/file_systems/xfs/Debug.h index ec5a36b935..ec9038a75c 100644 --- a/src/add-ons/kernel/file_systems/xfs/Debug.h +++ b/src/add-ons/kernel/file_systems/xfs/Debug.h @@ -15,8 +15,8 @@ #define ASSERT(x) \ { if (!(x)) kernel_debugger("xfs: assert failed: " #x "\n"); } #else -#define TRACE(x...) ; -#define ASSERT(x) ; +#define TRACE(x...) +#define ASSERT(x) #endif #define ERROR(x...) dprintf("\n\33[34mxfs:\33[0m " x) diff --git a/src/add-ons/kernel/file_systems/xfs/Directory.cpp b/src/add-ons/kernel/file_systems/xfs/Directory.cpp index 5d763710d2..dd48d5f523 100644 --- a/src/add-ons/kernel/file_systems/xfs/Directory.cpp +++ b/src/add-ons/kernel/file_systems/xfs/Directory.cpp @@ -8,15 +8,20 @@ DirectoryIterator::DirectoryIterator(Inode* inode) + : + fInode(inode), + fShortDir(NULL), + fExtentDir(NULL), + fLeafDir(NULL) { - fInode = inode; - fShortDir = NULL; } DirectoryIterator::~DirectoryIterator() { delete fShortDir; + delete fLeafDir; + delete fExtentDir; } @@ -35,8 +40,22 @@ DirectoryIterator::Init() fExtentDir = new(std::nothrow) Extent(fInode); if (fExtentDir == NULL) return B_NO_MEMORY; - status_t status = fExtentDir->Init(); - return status; + if (fExtentDir->IsBlockType()) + return fExtentDir->Init(); + + delete fExtentDir; + fExtentDir = NULL; + + fLeafDir = new(std::nothrow) LeafDirectory(fInode); + if (fLeafDir == NULL) + return B_NO_MEMORY; + status_t status = fLeafDir->Init(); + if (status != B_OK) + return status; + if (fLeafDir->IsLeafType() == false) { + delete fLeafDir; + fLeafDir = NULL; + } } /* Return B_OK so even if the shortform directory has an extent directory @@ -71,7 +90,12 @@ DirectoryIterator::GetNext(char* name, size_t* length, xfs_ino_t* ino) //TODO: Reading from extent based directories if (fInode->Format() == XFS_DINODE_FMT_EXTENTS) { TRACE("Iterator:GetNext: EXTENTS"); - status = fExtentDir->GetNext(name, length, ino); + if (fExtentDir != NULL) + status = fExtentDir->GetNext(name, length, ino); + else if (fLeafDir != NULL) + status = fLeafDir->GetNext(name, length, ino); + else + return B_BAD_VALUE; return status; } @@ -98,7 +122,12 @@ DirectoryIterator::Lookup(const char* name, size_t length, xfs_ino_t* ino) //TODO: Reading from extent based dirs if (fInode->Format() == XFS_DINODE_FMT_EXTENTS) { TRACE("Iterator:Lookup: EXTENTS"); - status = fExtentDir->Lookup(name, length, ino); + if (fExtentDir != NULL) + status = fExtentDir->Lookup(name, length, ino); + else if (fLeafDir != NULL) + status = fLeafDir->Lookup(name, length, ino); + else + return B_BAD_VALUE; return status; } diff --git a/src/add-ons/kernel/file_systems/xfs/Directory.h b/src/add-ons/kernel/file_systems/xfs/Directory.h index 342cf4adbe..4a4d05e0e4 100644 --- a/src/add-ons/kernel/file_systems/xfs/Directory.h +++ b/src/add-ons/kernel/file_systems/xfs/Directory.h @@ -8,6 +8,7 @@ #include "Extent.h" #include "Inode.h" +#include "LeafDirectory.h" #include "ShortDirectory.h" @@ -32,6 +33,9 @@ private: // Short form Directory type Extent* fExtentDir; // Extent form Directory type + // TODO: Rename all to block type + LeafDirectory* fLeafDir; + // Extent based leaf directory }; diff --git a/src/add-ons/kernel/file_systems/xfs/Extent.cpp b/src/add-ons/kernel/file_systems/xfs/Extent.cpp index ed499e8860..a71862b412 100644 --- a/src/add-ons/kernel/file_systems/xfs/Extent.cpp +++ b/src/add-ons/kernel/file_systems/xfs/Extent.cpp @@ -15,6 +15,11 @@ Extent::Extent(Inode* inode) } +Extent::~Extent() +{ +} + + void Extent::FillMapEntry(void* pointerToMap) { @@ -56,7 +61,7 @@ Extent::FillBlockBuffer() xfs_fsblock_t blockToRead = FSBLOCKS_TO_BASICBLOCKS(volume->BlockLog(), ((uint64)(agNo * numberOfBlocksInAg) + agBlockNo)); - xfs_daddr_t readPos = blockToRead * (BASICBLOCKSIZE) + fMap->br_startoff; + xfs_daddr_t readPos = blockToRead * BASICBLOCKSIZE; TRACE("blockToRead: (%ld), readPos: (%ld)\n", blockToRead, readPos); if (read_pos(volume->Device(), readPos, fBlockBuffer, len) != len) { @@ -75,7 +80,7 @@ Extent::Init() if (fMap == NULL) return B_NO_MEMORY; - ASSERT(BlockType() == true); + ASSERT(IsBlockType() == true); void* pointerToMap = DIR_DFORK_PTR(fInode->Buffer()); FillMapEntry(pointerToMap); ASSERT(fMap->br_blockcount == 1); @@ -121,10 +126,10 @@ Extent::BlockFirstLeaf(ExtentBlockTail* tail) bool -Extent::BlockType() +Extent::IsBlockType() { bool status = true; - if (fInode->NoOfBlocks() != 1) + if (fInode->BlockCount() != 1) status = false; if (fInode->Size() != fInode->DirBlockSize()) status = false; @@ -158,11 +163,12 @@ Extent::GetNext(char* name, size_t* length, xfs_ino_t* ino) TRACE("numberOfEntries:(%d)\n", numberOfEntries); for (int i = 0; i < numberOfEntries; i++) { - TRACE("i:(%d)\n", i); + TRACE("EntryNumber:(%d)\n", i); ExtentUnusedEntry* unusedEntry = (ExtentUnusedEntry*)entry; if (B_BENDIAN_TO_HOST_INT16(unusedEntry->freetag) == DIR2_FREE_TAG) { TRACE("Unused entry found\n"); + i--; entry = (void*) ((char*)entry + B_BENDIAN_TO_HOST_INT16(unusedEntry->length)); continue; diff --git a/src/add-ons/kernel/file_systems/xfs/Extent.h b/src/add-ons/kernel/file_systems/xfs/Extent.h index 3f3d6012c0..6a3cf5745f 100644 --- a/src/add-ons/kernel/file_systems/xfs/Extent.h +++ b/src/add-ons/kernel/file_systems/xfs/Extent.h @@ -31,23 +31,23 @@ enum ExtentState { // xfs_dir2_data_free_t struct FreeRegion { - uint16 offset; - uint16 length; + uint16 offset; + uint16 length; }; // xfs_dir2_data_hdr_t struct ExtentDataHeader { - uint32 magic; - FreeRegion bestfree[XFS_DIR2_DATA_FD_COUNT]; + uint32 magic; + FreeRegion bestfree[XFS_DIR2_DATA_FD_COUNT]; }; // xfs_dir2_data_entry_t struct ExtentDataEntry { - xfs_ino_t inumber; - uint8 namelen; - uint8 name[]; + xfs_ino_t inumber; + uint8 namelen; + uint8 name[]; // Followed by a file type (8bit) if applicable and a 16bit tag // tag is the offset from start of the block @@ -56,28 +56,28 @@ struct ExtentDataEntry { // xfs_dir2_data_unused_t struct ExtentUnusedEntry { - uint16 freetag; - // takes the value 0xffff - uint16 length; - // freetag+length overrides the inumber of an entry - uint16 tag; + uint16 freetag; + // takes the value 0xffff + uint16 length; + // freetag+length overrides the inumber of an entry + uint16 tag; }; // xfs_dir2_leaf_entry_t struct ExtentLeafEntry { - uint32 hashval; - uint32 address; - // offset into block after >> 3 + uint32 hashval; + uint32 address; + // offset into block after >> 3 }; // xfs_dir2_block_tail_t struct ExtentBlockTail { - uint32 count; - // # of entries in leaf - uint32 stale; - // # of free leaf entries + uint32 count; + // # of entries in leaf + uint32 stale; + // # of free leaf entries }; @@ -99,7 +99,7 @@ public: Extent(Inode* inode); ~Extent(); status_t Init(); - bool BlockType(); + bool IsBlockType(); void FillMapEntry(void* pointerToMap); status_t FillBlockBuffer(); ExtentBlockTail* BlockTail(); diff --git a/src/add-ons/kernel/file_systems/xfs/Inode.cpp b/src/add-ons/kernel/file_systems/xfs/Inode.cpp index 78d4a6ebea..4d354b24a1 100644 --- a/src/add-ons/kernel/file_systems/xfs/Inode.cpp +++ b/src/add-ons/kernel/file_systems/xfs/Inode.cpp @@ -38,7 +38,7 @@ xfs_inode_t::SwapEndian() xfs_rfsblock_t -xfs_inode_t::NoOfBlocks() const +xfs_inode_t::BlockCount() const { return di_nblocks; } @@ -124,6 +124,13 @@ xfs_inode_t::Format() const } +xfs_extnum_t +xfs_inode_t::DataExtentsCount() const +{ + return di_nextents; +} + + Inode::Inode(Volume* volume, xfs_ino_t id) : fVolume(volume), @@ -195,7 +202,7 @@ Inode::GetFromDisk() xfs_fsblock_t blockToRead = FSBLOCKS_TO_BASICBLOCKS(fVolume->BlockLog(), ((uint64)(agNo * numberOfBlocksInAg) + agBlock)); - xfs_daddr_t readPos = blockToRead * (BASICBLOCKSIZE) + offset * len; + xfs_daddr_t readPos = blockToRead * BASICBLOCKSIZE + offset * len; if (read_pos(fVolume->Device(), readPos, fBuffer, len) != len) { ERROR("Inode::Inode(): IO Error"); diff --git a/src/add-ons/kernel/file_systems/xfs/Inode.h b/src/add-ons/kernel/file_systems/xfs/Inode.h index 6bf4c9f8e1..33e1836a2c 100644 --- a/src/add-ons/kernel/file_systems/xfs/Inode.h +++ b/src/add-ons/kernel/file_systems/xfs/Inode.h @@ -77,11 +77,12 @@ struct xfs_inode_t { int8 Format() const; // The format of the inode xfs_fsize_t Size() const; - xfs_rfsblock_t NoOfBlocks() const; + xfs_rfsblock_t BlockCount() const; uint32 NLink() const; uint16 Flags() const; uint32 UserId() const; uint32 GroupId() const; + xfs_extnum_t DataExtentsCount() const; uint16 di_magic; uint16 di_mode; @@ -154,8 +155,8 @@ public: int8 Version() const { return fNode->Version(); } - xfs_rfsblock_t NoOfBlocks() const - { return fNode->NoOfBlocks(); } + xfs_rfsblock_t BlockCount() const + { return fNode->BlockCount(); } char* Buffer() { return fBuffer; } @@ -179,6 +180,8 @@ public: uint32 UserId() const { return fNode->UserId(); } uint32 GroupId() const { return fNode->GroupId(); } bool HasFileTypeField() const; + xfs_extnum_t DataExtentsCount() const + { return fNode->DataExtentsCount(); } private: status_t GetFromDisk(); diff --git a/src/add-ons/kernel/file_systems/xfs/Jamfile b/src/add-ons/kernel/file_systems/xfs/Jamfile index e1857d2be5..554aae567f 100644 --- a/src/add-ons/kernel/file_systems/xfs/Jamfile +++ b/src/add-ons/kernel/file_systems/xfs/Jamfile @@ -26,6 +26,7 @@ local xfsSources = Inode.cpp kernel_cpp.cpp kernel_interface.cpp + LeafDirectory.cpp ShortDirectory.cpp Volume.cpp xfs.cpp diff --git a/src/add-ons/kernel/file_systems/xfs/LeafDirectory.cpp b/src/add-ons/kernel/file_systems/xfs/LeafDirectory.cpp new file mode 100644 index 0000000000..92dc2c13ca --- /dev/null +++ b/src/add-ons/kernel/file_systems/xfs/LeafDirectory.cpp @@ -0,0 +1,345 @@ +/* + * Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com + * All rights reserved. Distributed under the terms of the MIT License. + */ + + +#include "LeafDirectory.h" + + +LeafDirectory::LeafDirectory(Inode* inode) + : + fInode(inode), + fOffset(0), + fDataBuffer(NULL), + fLeafBuffer(NULL), + fLeafMap(NULL), + fDataMap(NULL), + fCurBlockNumber(-1) +{ +} + + +LeafDirectory::~LeafDirectory() +{ + delete fDataMap; + delete fLeafMap; + delete fDataBuffer; + delete fLeafBuffer; +} + + +status_t +LeafDirectory::Init() +{ + fLeafMap = new(std::nothrow) ExtentMapEntry; + if (fLeafMap == NULL) + return B_NO_MEMORY; + + fDataMap = new(std::nothrow) ExtentMapEntry; + if (fDataMap == NULL) + return B_NO_MEMORY; + + FillMapEntry(fInode->DataExtentsCount()-1, fLeafMap); + FillMapEntry(0, fDataMap); + return B_OK; +} + + +bool +LeafDirectory::IsLeafType() +{ + bool status = true; + if (fInode->BlockCount() == 1 + || fInode->DataExtentsCount() == 1 + || fInode->Size() != + (fInode->BlockCount() - 1) * fInode->DirBlockSize()) + status = false; + + if (status == false) + return status; + + FillMapEntry(fInode->DataExtentsCount() - 1, fLeafMap); + TRACE("leaf_Startoffset:(%ld)\n", + LEAF_STARTOFFSET(fInode->GetVolume()->BlockLog())); + + if (fLeafMap->br_startoff + != LEAF_STARTOFFSET(fInode->GetVolume()->BlockLog())) + status = false; + + return status; +} + + +void +LeafDirectory::FillMapEntry(int num, ExtentMapEntry* fMap) +{ + void* directoryFork = DIR_DFORK_PTR(fInode->Buffer()); + uint64* pointerToMap = (uint64*)((char*)directoryFork + num * EXTENT_SIZE); + uint64 firstHalf = pointerToMap[0]; + uint64 secondHalf = pointerToMap[1]; + //dividing the 128 bits into 2 parts. + + firstHalf = B_BENDIAN_TO_HOST_INT64(firstHalf); + secondHalf = B_BENDIAN_TO_HOST_INT64(secondHalf); + fMap->br_state = firstHalf >> 63; + fMap->br_startoff = (firstHalf & MASK(63)) >> 9; + fMap->br_startblock = ((firstHalf & MASK(9)) << 43) | (secondHalf >> 21); + fMap->br_blockcount = secondHalf & MASK(21); + TRACE("FillMapEntry: startoff:(%ld), startblock:(%ld), blockcount:(%ld)," + "state:(%d)\n", fMap->br_startoff, fMap->br_startblock, + fMap->br_blockcount, fMap->br_state); +} + + +status_t +LeafDirectory::FillBuffer(int type, char* blockBuffer) +{ + TRACE("FILLBUFFER\n"); + ExtentMapEntry* map; + if (type == DATA) + map = fDataMap; + + if (type == LEAF) + map = fLeafMap; + + if (map->br_state !=0) + return B_BAD_VALUE; + + int len = fInode->DirBlockSize(); + if (blockBuffer == NULL) { + blockBuffer = new(std::nothrow) char[len]; + if (blockBuffer == NULL) + return B_NO_MEMORY; + } + + Volume* volume = fInode->GetVolume(); + xfs_agblock_t numberOfBlocksInAg = volume->AgBlocks(); + + uint64 agNo = FSBLOCKS_TO_AGNO(map->br_startblock, volume); + uint64 agBlockNo = FSBLOCKS_TO_AGBLOCKNO(map->br_startblock, volume); + xfs_fsblock_t blockToRead = FSBLOCKS_TO_BASICBLOCKS(volume->BlockLog(), + (agNo * numberOfBlocksInAg + agBlockNo)); + + xfs_daddr_t readPos = blockToRead * BASICBLOCKSIZE; + + TRACE("blockToRead: (%ld), readPos: (%ld)\n", blockToRead, readPos); + if (read_pos(volume->Device(), readPos, blockBuffer, len) != len) { + ERROR("Extent::FillBlockBuffer(): IO Error"); + return B_IO_ERROR; + } + + if (type == DATA) + fDataBuffer = blockBuffer; + + if (type == LEAF) + fLeafBuffer = blockBuffer; + + if (type == LEAF) { + ExtentLeafHeader* header = (ExtentLeafHeader*) fLeafBuffer; + TRACE("NumberOfEntries in leaf: (%d)\n", + B_BENDIAN_TO_HOST_INT16(header->count)); + } + if (type == DATA) { + ExtentDataHeader* header = (ExtentDataHeader*) fDataBuffer; + if (B_BENDIAN_TO_HOST_INT32(header->magic) == HEADER_MAGIC) + TRACE("DATA BLOCK VALID\n"); + else { + TRACE("DATA BLOCK INVALID\n"); + return B_BAD_VALUE; + } + } + return B_OK; +} + + +uint32 +LeafDirectory::GetOffsetFromAddress(uint32 address) +{ + address = address * 8; + // block offset in eight bytes, hence multiply with 8 + return address & (fInode->DirBlockSize() - 1); +} + + +ExtentLeafEntry* +LeafDirectory::FirstLeaf() +{ + TRACE("LeafDirectory: FirstLeaf\n"); + if (fLeafBuffer == NULL) { + ASSERT(fLeafMap != NULL); + status_t status = FillBuffer(LEAF, fLeafBuffer); + if (status != B_OK) + return NULL; + } + return (ExtentLeafEntry*)((char*)fLeafBuffer + sizeof(ExtentLeafHeader)); +} + + +int +LeafDirectory::EntrySize(int len) const +{ + int entrySize= sizeof(xfs_ino_t) + sizeof(uint8) + len + sizeof(uint16); + // uint16 is for the tag + if (fInode->HasFileTypeField()) + entrySize += sizeof(uint8); + + return (entrySize + 7) & -8; + // rounding off to closest multiple of 8 +} + + +status_t +LeafDirectory::GetNext(char* name, size_t* length, xfs_ino_t* ino) +{ + TRACE("LeafDirectory::GetNext\n"); + status_t status; + + if (fDataBuffer == NULL) { + status = FillBuffer(DATA, fDataBuffer); + if (status != B_OK) + return status; + } + + Volume* volume = fInode->GetVolume(); + void* entry = (void*)((ExtentDataHeader*)fDataBuffer + 1); + // This could be an unused entry so we should check + + if (BLOCKNO_FROM_ADDRESS(fOffset, volume) == fCurBlockNumber + && fOffset != 0) + entry = (void*)(fDataBuffer + + BLOCKOFFSET_FROM_ADDRESS(fOffset, fInode)); + // This gets us a little faster to the next entry + + ExtentLeafHeader* leafHeader = (ExtentLeafHeader*)(void*)fLeafBuffer; + uint32 curDirectorySize = fInode->Size(); + + while (fOffset != curDirectorySize) { + TRACE("fOffset:(%d)\n", fOffset); + if (fCurBlockNumber != BLOCKNO_FROM_ADDRESS(fOffset, volume)) { + fCurBlockNumber = BLOCKNO_FROM_ADDRESS(fOffset, volume); + FillMapEntry(fCurBlockNumber, fDataMap); + status = FillBuffer(DATA, fDataBuffer); + if (status != B_OK) + return status; + entry = (void*)((ExtentDataHeader*)fDataBuffer + 1); + fOffset = fOffset + sizeof(ExtentDataHeader); + } + + ExtentUnusedEntry* unusedEntry = (ExtentUnusedEntry*)entry; + + if (B_BENDIAN_TO_HOST_INT16(unusedEntry->freetag) == DIR2_FREE_TAG) { + TRACE("Unused entry found\n"); + fOffset = fOffset + B_BENDIAN_TO_HOST_INT16(unusedEntry->length); + entry = (void*) + ((char*)entry + B_BENDIAN_TO_HOST_INT16(unusedEntry->length)); + continue; + } + ExtentDataEntry* dataEntry = (ExtentDataEntry*) entry; + + uint16 currentOffset = (char*)dataEntry - fDataBuffer; + TRACE("GetNext: fOffset:(%d), currentOffset:(%d)\n", + BLOCKOFFSET_FROM_ADDRESS(fOffset, fInode), currentOffset); + + if (BLOCKOFFSET_FROM_ADDRESS(fOffset, fInode) > currentOffset) { + entry = (void*)((char*)entry + EntrySize(dataEntry->namelen)); + continue; + } + + if (dataEntry->namelen > *length) + return B_BUFFER_OVERFLOW; + + fOffset = fOffset + EntrySize(dataEntry->namelen); + memcpy(name, dataEntry->name, dataEntry->namelen); + name[dataEntry->namelen] = '\0'; + *length = dataEntry->namelen + 1; + *ino = B_BENDIAN_TO_HOST_INT64(dataEntry->inumber); + + TRACE("Entry found. Name: (%s), Length: (%ld),ino: (%ld)\n", name, + *length, *ino); + return B_OK; + } + + return B_ENTRY_NOT_FOUND; +} + + +status_t +LeafDirectory::Lookup(const char* name, size_t length, xfs_ino_t* ino) +{ + TRACE("LeafDirectory: Lookup\n"); + TRACE("Name: %s\n", name); + uint32 hashValueOfRequest = hashfunction(name, length); + TRACE("Hashval:(%ld)\n", hashValueOfRequest); + + status_t status; + if (fLeafBuffer == NULL) + status = FillBuffer(LEAF, fLeafBuffer); + if (status != B_OK) + return status; + + ExtentLeafHeader* leafHeader = (ExtentLeafHeader*)(void*)fLeafBuffer; + ExtentLeafEntry* leafEntry = FirstLeaf(); + if (leafEntry == NULL) + return B_NO_MEMORY; + + int numberOfLeafEntries = B_BENDIAN_TO_HOST_INT16(leafHeader->count); + TRACE("numberOfLeafEntries:(%d)\n", numberOfLeafEntries); + int left = 0; + int mid; + int right = numberOfLeafEntries - 1; + Volume* volume = fInode->GetVolume(); + + /* + * Trying to find the lowerbound of hashValueOfRequest + * This is slightly different from bsearch(), as we want the first + * instance of hashValueOfRequest and not any instance. + */ + while (left < right) { + mid = (left+right)/2; + uint32 hashval = B_BENDIAN_TO_HOST_INT32(leafEntry[mid].hashval); + if (hashval >= hashValueOfRequest) { + right = mid; + continue; + } + if (hashval < hashValueOfRequest) { + left = mid+1; + } + } + TRACE("left:(%d), right:(%d)\n", left, right); + + while (B_BENDIAN_TO_HOST_INT32(leafEntry[left].hashval) + == hashValueOfRequest) { + + uint32 address = B_BENDIAN_TO_HOST_INT32(leafEntry[left].address); + if (address == 0) { + left++; + continue; + } + + uint32 dataBlockNumber = BLOCKNO_FROM_ADDRESS(address * 8, volume); + uint32 offset = BLOCKOFFSET_FROM_ADDRESS(address * 8, fInode); + + TRACE("DataBlockNumber:(%d), offset:(%d)\n", dataBlockNumber, offset); + if (dataBlockNumber != fCurBlockNumber) { + fCurBlockNumber = dataBlockNumber; + FillMapEntry(dataBlockNumber, fDataMap); + status = FillBuffer(DATA, fDataBuffer); + if (status != B_OK) + return B_OK; + } + + TRACE("offset:(%d)\n", offset); + ExtentDataEntry* entry = (ExtentDataEntry*)(fDataBuffer + offset); + + int retVal = strncmp(name, (char*)entry->name, entry->namelen); + if (retVal == 0) { + *ino = B_BENDIAN_TO_HOST_INT64(entry->inumber); + TRACE("ino:(%d)\n", *ino); + return B_OK; + } + left++; + } + + return B_ENTRY_NOT_FOUND; +} diff --git a/src/add-ons/kernel/file_systems/xfs/LeafDirectory.h b/src/add-ons/kernel/file_systems/xfs/LeafDirectory.h new file mode 100644 index 0000000000..fd28d0ca7f --- /dev/null +++ b/src/add-ons/kernel/file_systems/xfs/LeafDirectory.h @@ -0,0 +1,76 @@ +/* + * Copyright 2020, Shubham Bhagat, shubhambhagat111@yahoo.com + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef _LEAFDIRECTORY_H_ +#define _LEAFDIRECTORY_H_ + + +#include "Extent.h" +#include "Inode.h" +#include "system_dependencies.h" + + +#define EXTENT_SIZE 16 +#define BLOCKNO_FROM_ADDRESS(n, volume) \ + (n >> (volume->BlockLog() + volume->DirBlockLog())) +#define BLOCKOFFSET_FROM_ADDRESS(n, inode) (n & (inode->DirBlockSize() - 1)) +#define HEADER_MAGIC 0x58443244 +#define LEAF_STARTOFFSET(n) 1UL << (35 - n) + +enum ContentType { DATA, LEAF }; + + +// xfs_da_blkinfo_t +struct BlockInfo { + uint32 forw; + uint32 back; + uint16 magic; + uint16 pad; +}; + + +//xfs_dir2_leaf_hdr_t +struct ExtentLeafHeader { + BlockInfo info; + uint16 count; + uint16 stale; +}; + + +// xfs_dir2_leaf_tail_t +struct ExtentLeafTail { + uint32 bestcount; + // # of best free entries +}; + + +class LeafDirectory { +public: + LeafDirectory(Inode* inode); + ~LeafDirectory(); + status_t Init(); + bool IsLeafType(); + void FillMapEntry(int num, ExtentMapEntry* map); + status_t FillBuffer(int type, char* buffer); + ExtentLeafEntry* FirstLeaf(); + xfs_ino_t GetIno(); + uint32 GetOffsetFromAddress(uint32 address); + int EntrySize(int len) const; + status_t GetNext(char* name, size_t* length, + xfs_ino_t* ino); + status_t Lookup(const char* name, size_t length, + xfs_ino_t* id); +private: + Inode* fInode; + ExtentMapEntry* fDataMap; + ExtentMapEntry* fLeafMap; + uint32 fOffset; + char* fDataBuffer; + // This isn't inode data. It holds the directory block. + char* fLeafBuffer; + uint32 fCurBlockNumber; +}; + + +#endif diff --git a/src/add-ons/kernel/file_systems/xfs/Volume.h b/src/add-ons/kernel/file_systems/xfs/Volume.h index 46631fc580..408d68eb98 100644 --- a/src/add-ons/kernel/file_systems/xfs/Volume.h +++ b/src/add-ons/kernel/file_systems/xfs/Volume.h @@ -56,6 +56,9 @@ public: uint32 DirBlockSize() const { return fSuperBlock.DirBlockSize(); } + uint32 DirBlockLog() const + { return fSuperBlock.DirBlockLog(); } + uint8 AgInodeBits() const { return fSuperBlock.AgInodeBits(); } diff --git a/src/add-ons/kernel/file_systems/xfs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/xfs/kernel_interface.cpp index b652f4cf6e..b149edcebf 100644 --- a/src/add-ons/kernel/file_systems/xfs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/xfs/kernel_interface.cpp @@ -261,7 +261,7 @@ xfs_read_stat(fs_volume *_volume, fs_vnode *_node, struct stat *stat) stat->st_type = 0; // TODO stat->st_size = inode->Size(); - stat->st_blocks = inode->NoOfBlocks(); + stat->st_blocks = inode->BlockCount(); inode->GetAccessTime(stat->st_atim); inode->GetModificationTime(stat->st_mtim); diff --git a/src/add-ons/kernel/file_systems/xfs/xfs.cpp b/src/add-ons/kernel/file_systems/xfs/xfs.cpp index 2c3f90ef8a..04267a2223 100644 --- a/src/add-ons/kernel/file_systems/xfs/xfs.cpp +++ b/src/add-ons/kernel/file_systems/xfs/xfs.cpp @@ -52,6 +52,13 @@ XfsSuperBlock::BlockSize() const } +uint32 +XfsSuperBlock::DirBlockLog() const +{ + return sb_dirblklog; +} + + uint8 XfsSuperBlock::BlockLog() const { diff --git a/src/add-ons/kernel/file_systems/xfs/xfs.h b/src/add-ons/kernel/file_systems/xfs/xfs.h index 603dc7274f..617e6bbcfa 100644 --- a/src/add-ons/kernel/file_systems/xfs/xfs.h +++ b/src/add-ons/kernel/file_systems/xfs/xfs.h @@ -27,7 +27,7 @@ extern fs_volume_ops gxfsVolumeOps; #define XFS_SB_MAXSIZE 512 #define BASICBLOCKLOG 9 // Log of block size should be 9 -#define BASICBLOCKSIZE 1 << BASICBLOCKLOG +#define BASICBLOCKSIZE (1 << BASICBLOCKLOG) // The size of a basic block should be 512 @@ -41,6 +41,7 @@ public: uint8 BlockLog() const; uint32 DirBlockSize() const; // maximum 65536 + uint32 DirBlockLog() const; uint8 AgInodeBits() const; uint8 InodesPerBlkLog() const; uint8 AgBlocksLog() const; diff --git a/src/tests/add-ons/kernel/file_systems/xfs/xfs_shell/Jamfile b/src/tests/add-ons/kernel/file_systems/xfs/xfs_shell/Jamfile index 1f3f52b17f..8f6dbac0fc 100644 --- a/src/tests/add-ons/kernel/file_systems/xfs/xfs_shell/Jamfile +++ b/src/tests/add-ons/kernel/file_systems/xfs/xfs_shell/Jamfile @@ -44,6 +44,7 @@ local xfsSource = Extent.cpp Inode.cpp kernel_interface.cpp + LeafDirectory.cpp ShortDirectory.cpp Volume.cpp xfs.cpp