hrev54636 adds 1 changeset to branch 'master'
old head: 3255108dde2c50590d5077cd33510935fb6ee5ac
new head: fc87b4a2846c207e2ad0817ab0c1eee66f63ba5b
overview:
https://git.haiku-os.org/haiku/log/?qt=range&q=fc87b4a2846c+%5E3255108dde2c
----------------------------------------------------------------------------
fc87b4a2846c: xfs: Read Block directories
Block directories can now be read.
Change-Id: I9aa898638e6ac39cb903f2dd58cd184785e1a06b
Reviewed-on: https://review.haiku-os.org/c/haiku/+/2992
Reviewed-by: Adrien Destugues <pulkomandy@xxxxxxxxx>
[ CruxBox <shubhambhagat111@xxxxxxxxx> ]
----------------------------------------------------------------------------
Revision: hrev54636
Commit: fc87b4a2846c207e2ad0817ab0c1eee66f63ba5b
URL: https://git.haiku-os.org/haiku/commit/?id=fc87b4a2846c
Author: CruxBox <shubhambhagat111@xxxxxxxxx>
Date: Sun Jul 5 20:49:34 2020 UTC
Committer: waddlesplash <waddlesplash@xxxxxxxxx>
Commit-Date: Sun Oct 11 16:00:26 2020 UTC
----------------------------------------------------------------------------
8 files changed, 217 insertions(+), 32 deletions(-)
src/add-ons/kernel/file_systems/xfs/Debug.h | 2 +-
.../kernel/file_systems/xfs/Directory.cpp | 16 +-
src/add-ons/kernel/file_systems/xfs/Extent.cpp | 185 ++++++++++++++++++-
src/add-ons/kernel/file_systems/xfs/Extent.h | 11 +-
src/add-ons/kernel/file_systems/xfs/Inode.cpp | 17 +-
src/add-ons/kernel/file_systems/xfs/Inode.h | 1 +
.../kernel/file_systems/xfs/ShortDirectory.cpp | 16 +-
.../kernel/file_systems/xfs/ShortDirectory.h | 1 -
----------------------------------------------------------------------------
diff --git a/src/add-ons/kernel/file_systems/xfs/Debug.h
b/src/add-ons/kernel/file_systems/xfs/Debug.h
index ac7413cce3..ec5a36b935 100644
--- a/src/add-ons/kernel/file_systems/xfs/Debug.h
+++ b/src/add-ons/kernel/file_systems/xfs/Debug.h
@@ -9,7 +9,7 @@
#ifndef _DEBUG_H_
#define _DEBUG_H_
-#define TRACE_XFS
+// #define TRACE_XFS
#ifdef TRACE_XFS
#define TRACE(x...) dprintf("\n\33[34mxfs:\33[0m " x)
#define ASSERT(x) \
diff --git a/src/add-ons/kernel/file_systems/xfs/Directory.cpp
b/src/add-ons/kernel/file_systems/xfs/Directory.cpp
index 1f8a9643a1..5d763710d2 100644
--- a/src/add-ons/kernel/file_systems/xfs/Directory.cpp
+++ b/src/add-ons/kernel/file_systems/xfs/Directory.cpp
@@ -62,15 +62,17 @@ DirectoryIterator::Init()
status_t
DirectoryIterator::GetNext(char* name, size_t* length, xfs_ino_t* ino)
{
+ status_t status;
if (fInode->Format() == XFS_DINODE_FMT_LOCAL) {
- status_t status = fShortDir->GetNext(name, length, ino);
+ status = fShortDir->GetNext(name, length, ino);
return status;
}
//TODO: Reading from extent based directories
if (fInode->Format() == XFS_DINODE_FMT_EXTENTS) {
TRACE("Iterator:GetNext: EXTENTS");
- return B_NOT_SUPPORTED;
+ status = fExtentDir->GetNext(name, length, ino);
+ return status;
}
//TODO: Reading from B+Trees based directories
@@ -87,19 +89,17 @@ DirectoryIterator::GetNext(char* name, size_t* length,
xfs_ino_t* ino)
status_t
DirectoryIterator::Lookup(const char* name, size_t length, xfs_ino_t* ino)
{
+ status_t status;
if (fInode->Format() == XFS_DINODE_FMT_LOCAL) {
- status_t status = fShortDir->Lookup(name, length, ino);
+ status = fShortDir->Lookup(name, length, ino);
return status;
}
//TODO: Reading from extent based dirs
if (fInode->Format() == XFS_DINODE_FMT_EXTENTS) {
TRACE("Iterator:Lookup: EXTENTS");
- #if 0
- status_t status = fExtentDir->Lookup(name, length, ino);
- return status;
- #endif
- return B_NOT_SUPPORTED;
+ status = fExtentDir->Lookup(name, length, ino);
+ return status;
}
//TODO: Reading from B+Tree based dirs
diff --git a/src/add-ons/kernel/file_systems/xfs/Extent.cpp
b/src/add-ons/kernel/file_systems/xfs/Extent.cpp
index 106c73756c..ed499e8860 100644
--- a/src/add-ons/kernel/file_systems/xfs/Extent.cpp
+++ b/src/add-ons/kernel/file_systems/xfs/Extent.cpp
@@ -9,7 +9,8 @@
Extent::Extent(Inode* inode)
:
- fInode(inode)
+ fInode(inode),
+ fOffset(0)
{
}
@@ -36,6 +37,37 @@ Extent::FillMapEntry(void* pointerToMap)
}
+status_t
+Extent::FillBlockBuffer()
+{
+ if (fMap->br_state != 0)
+ return B_BAD_VALUE;
+
+ int len = fInode->DirBlockSize();
+ fBlockBuffer = new(std::nothrow) char[len];
+ if (fBlockBuffer == NULL)
+ return B_NO_MEMORY;
+
+ Volume* volume = fInode->GetVolume();
+ xfs_agblock_t numberOfBlocksInAg = volume->AgBlocks();
+
+ uint64 agNo = FSBLOCKS_TO_AGNO(fMap->br_startblock, volume);
+ uint64 agBlockNo = FSBLOCKS_TO_AGBLOCKNO(fMap->br_startblock, volume);
+ xfs_fsblock_t blockToRead = FSBLOCKS_TO_BASICBLOCKS(volume->BlockLog(),
+ ((uint64)(agNo * numberOfBlocksInAg) + agBlockNo));
+
+ xfs_daddr_t readPos = blockToRead * (BASICBLOCKSIZE) +
fMap->br_startoff;
+
+ TRACE("blockToRead: (%ld), readPos: (%ld)\n", blockToRead, readPos);
+ if (read_pos(volume->Device(), readPos, fBlockBuffer, len) != len) {
+ ERROR("Extent::FillBlockBuffer(): IO Error");
+ return B_IO_ERROR;
+ }
+
+ return B_OK;
+}
+
+
status_t
Extent::Init()
{
@@ -46,16 +78,38 @@ Extent::Init()
ASSERT(BlockType() == true);
void* pointerToMap = DIR_DFORK_PTR(fInode->Buffer());
FillMapEntry(pointerToMap);
+ ASSERT(fMap->br_blockcount == 1);
+ //TODO: This is always true for block directories
+ //If we use this implementation for leaf directories, this is
not
+ //always true
+ status_t status = FillBlockBuffer();
+ ExtentDataHeader* header = (ExtentDataHeader*)fBlockBuffer;
+ if (B_BENDIAN_TO_HOST_INT32(header->magic) == DIR2_BLOCK_HEADER_MAGIC) {
+ status = B_OK;
+ TRACE("Extent:Init(): Block read successfully\n");
+ } else {
+ status = B_BAD_VALUE;
+ TRACE("Extent:Init(): Bad Block!\n");
+ }
- return B_NOT_SUPPORTED;
+ return status;
}
ExtentBlockTail*
-Extent::BlockTail(ExtentDataHeader* header)
+Extent::BlockTail()
{
return (ExtentBlockTail*)
- ((char*)header + fInode->DirBlockSize() -
sizeof(ExtentBlockTail));
+ (fBlockBuffer + fInode->DirBlockSize() -
sizeof(ExtentBlockTail));
+}
+
+
+uint32
+Extent::GetOffsetFromAddress(uint32 address)
+{
+ address = address * 8;
+ // block offset in eight bytes, hence multiple with 8
+ return address & (fInode->DirBlockSize() - 1);
}
@@ -75,5 +129,128 @@ Extent::BlockType()
if (fInode->Size() != fInode->DirBlockSize())
status = false;
return status;
+ //TODO: Checks: Fileoffset must be 0 and
+ //length = directory block size / filesystem block size
+}
+
+
+int
+Extent::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
+Extent::GetNext(char* name, size_t* length, xfs_ino_t* ino)
+{
+ TRACE("Extend::GetNext\n");
+ void* entry = (void*)((ExtentDataHeader*)fBlockBuffer + 1);
+ // This could be an unused entry so we should check
+
+ int numberOfEntries = B_BENDIAN_TO_HOST_INT32(BlockTail()->count);
+ TRACE("numberOfEntries:(%d)\n", numberOfEntries);
+
+ for (int i = 0; i < numberOfEntries; i++) {
+ TRACE("i:(%d)\n", i);
+ ExtentUnusedEntry* unusedEntry = (ExtentUnusedEntry*)entry;
+
+ if (B_BENDIAN_TO_HOST_INT16(unusedEntry->freetag) ==
DIR2_FREE_TAG) {
+ TRACE("Unused entry found\n");
+ entry = (void*)
+ ((char*)entry +
B_BENDIAN_TO_HOST_INT16(unusedEntry->length));
+ continue;
+ }
+ ExtentDataEntry* dataEntry = (ExtentDataEntry*) entry;
+
+ uint16 currentOffset = (char*)dataEntry - fBlockBuffer;
+ TRACE("GetNext: fOffset:(%d), currentOffset:(%d)\n",
+ fOffset, currentOffset);
+
+ if (fOffset >= currentOffset) {
+ entry = (void*)((char*)entry +
EntrySize(dataEntry->namelen));
+ continue;
+ }
+
+ if (dataEntry->namelen > *length)
+ return B_BUFFER_OVERFLOW;
+
+ fOffset = currentOffset;
+ 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
+Extent::Lookup(const char* name, size_t length, xfs_ino_t* ino)
+{
+ TRACE("Extent: Lookup\n");
+ TRACE("Name: %s\n", name);
+ uint32 hashValueOfRequest = hashfunction(name, length);
+ TRACE("Hashval:(%ld)\n", hashValueOfRequest);
+ ExtentBlockTail* blockTail = BlockTail();
+ ExtentLeafEntry* leafEntry = BlockFirstLeaf(blockTail);
+
+ int numberOfLeafEntries = B_BENDIAN_TO_HOST_INT32(blockTail->count);
+ int left = 0;
+ int mid;
+ int right = numberOfLeafEntries - 1;
+
+ /*
+ * 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 offset = GetOffsetFromAddress(address);
+ TRACE("offset:(%d)\n", offset);
+ ExtentDataEntry* entry = (ExtentDataEntry*)(fBlockBuffer +
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/Extent.h
b/src/add-ons/kernel/file_systems/xfs/Extent.h
index 39b4d28025..3f3d6012c0 100644
--- a/src/add-ons/kernel/file_systems/xfs/Extent.h
+++ b/src/add-ons/kernel/file_systems/xfs/Extent.h
@@ -12,9 +12,13 @@
#define DIR2_BLOCK_HEADER_MAGIC 0x58443242
// for v4 system
+#define DIR2_FREE_TAG 0xffff
#define XFS_DIR2_DATA_FD_COUNT 3
#define EXTENT_REC_SIZE 128
#define MASK(n) ((1UL << n) - 1)
+#define FSBLOCKS_TO_AGNO(n, volume) (n >> volume->AgBlocksLog())
+#define FSBLOCKS_TO_AGBLOCKNO(n, volume) (n & MASK(volume->AgBlocksLog()))
+
// xfs_exntst_t
@@ -97,10 +101,12 @@ public:
status_t Init();
bool BlockType();
void FillMapEntry(void*
pointerToMap);
- ExtentDataHeader* BlockHeader();
- ExtentBlockTail* BlockTail(ExtentDataHeader*
header);
+ status_t FillBlockBuffer();
+ ExtentBlockTail* BlockTail();
ExtentLeafEntry* BlockFirstLeaf(ExtentBlockTail*
tail);
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,
@@ -108,6 +114,7 @@ public:
private:
Inode* fInode;
ExtentMapEntry* fMap;
+ uint32 fOffset;
char* fBlockBuffer;
// This isn't inode data. It holds the
directory block.
};
diff --git a/src/add-ons/kernel/file_systems/xfs/Inode.cpp
b/src/add-ons/kernel/file_systems/xfs/Inode.cpp
index f855443e77..78d4a6ebea 100644
--- a/src/add-ons/kernel/file_systems/xfs/Inode.cpp
+++ b/src/add-ons/kernel/file_systems/xfs/Inode.cpp
@@ -160,6 +160,13 @@ Inode::Init()
}
+bool
+Inode::HasFileTypeField() const
+{
+ return fVolume->SuperBlockFeatures2() & XFS_SB_VERSION2_FTYPE;
+}
+
+
status_t
Inode::GetFromDisk()
{
@@ -209,17 +216,21 @@ Inode::~Inode()
}
+/*
+ * Basically take 4 characters at a time as long as you can, and xor with
+ * previous hashVal after rotating 4 bits of hashVal. Likewise, continue
+ * xor and rotating. This is quite a generic hash function.
+*/
uint32
hashfunction(const char* name, int length)
{
uint32 hashVal = 0;
-
int lengthCovered = 0;
int index = 0;
if (length >= 4) {
- for (; index <= length; index+=4)
+ for (;index < length && (length - index) >= 4; index += 4)
{
- lengthCovered = index;
+ lengthCovered += 4;
hashVal = (name[index] << 21) ^ (name[index+1] << 14)
^ (name[index+2] << 7) ^ (name[index+3] << 0)
^ ((hashVal << 28) | (hashVal >> (4)));
diff --git a/src/add-ons/kernel/file_systems/xfs/Inode.h
b/src/add-ons/kernel/file_systems/xfs/Inode.h
index 7a1f16ff66..6bf4c9f8e1 100644
--- a/src/add-ons/kernel/file_systems/xfs/Inode.h
+++ b/src/add-ons/kernel/file_systems/xfs/Inode.h
@@ -178,6 +178,7 @@ public:
uint32 UserId() const { return
fNode->UserId(); }
uint32 GroupId() const {
return fNode->GroupId(); }
+ bool HasFileTypeField()
const;
private:
status_t GetFromDisk();
diff --git a/src/add-ons/kernel/file_systems/xfs/ShortDirectory.cpp
b/src/add-ons/kernel/file_systems/xfs/ShortDirectory.cpp
index 3e34062c6e..ff3f6619e5 100644
--- a/src/add-ons/kernel/file_systems/xfs/ShortDirectory.cpp
+++ b/src/add-ons/kernel/file_systems/xfs/ShortDirectory.cpp
@@ -22,20 +22,10 @@ ShortDirectory::~ShortDirectory()
}
-bool
-ShortDirectory::HasFileTypeField()
-{
- if (fInode->GetVolume()->SuperBlockFeatures2() & XFS_SB_VERSION2_FTYPE)
- return true;
- else
- return false;
-}
-
-
uint8
ShortDirectory::GetFileType(ShortFormEntry* entry)
{
- ASSERT(HasFileTypeField() == true);
+ ASSERT(fInode->HasFileTypeField() == true);
return entry->name[entry->namelen];
}
@@ -70,7 +60,7 @@ ShortDirectory::GetIno(ShortFormInodeUnion* inum)
xfs_ino_t
ShortDirectory::GetEntryIno(ShortFormEntry* entry)
{
- if (HasFileTypeField())
+ if (fInode->HasFileTypeField())
return GetIno((ShortFormInodeUnion*)(entry->name
+ entry->namelen + sizeof(uint8)));
else
@@ -82,7 +72,7 @@ size_t
ShortDirectory::EntrySize(int namelen)
{
return sizeof(ShortFormEntry) + namelen
- + (HasFileTypeField()? sizeof(uint8) : 0)
+ + (fInode->HasFileTypeField()? sizeof(uint8) : 0)
+ (fHeader->i8count? sizeof(uint64):sizeof(uint32));
}
diff --git a/src/add-ons/kernel/file_systems/xfs/ShortDirectory.h
b/src/add-ons/kernel/file_systems/xfs/ShortDirectory.h
index 7507d3878b..316a3bda71 100644
--- a/src/add-ons/kernel/file_systems/xfs/ShortDirectory.h
+++ b/src/add-ons/kernel/file_systems/xfs/ShortDirectory.h
@@ -56,7 +56,6 @@ public:
ShortDirectory(Inode* inode);
~ShortDirectory();
size_t HeaderSize();
- bool HasFileTypeField();
uint8
GetFileType(ShortFormEntry* entry);
ShortFormEntry* FirstEntry();
xfs_ino_t
GetIno(ShortFormInodeUnion* inum);