From Shubham Bhagat <shubhambhagat111@xxxxxxxxx>:
Shubham Bhagat has uploaded this change for review. (
https://review.haiku-os.org/c/haiku/+/3154 ;)
Change subject: xfs: Attempt at reading extent based files
......................................................................
xfs: Attempt at reading extent based files
There are 2 issues right now. One is that I have to give cat command the
entire file size for it to print the entire file. The second issue is
that I am getting segmentation fault for some reason, and it doesn't
even have to do with xfs_read(). More info in the comment below.
---
M src/add-ons/kernel/file_systems/xfs/Debug.h
M src/add-ons/kernel/file_systems/xfs/Extent.h
M src/add-ons/kernel/file_systems/xfs/Inode.cpp
M src/add-ons/kernel/file_systems/xfs/Inode.h
A src/add-ons/kernel/file_systems/xfs/Utility.h
M src/add-ons/kernel/file_systems/xfs/kernel_interface.cpp
M src/add-ons/kernel/file_systems/xfs/xfs.h
7 files changed, 241 insertions(+), 22 deletions(-)
git pull ssh://git.haiku-os.org:22/haiku refs/changes/54/3154/1
diff --git a/src/add-ons/kernel/file_systems/xfs/Debug.h
b/src/add-ons/kernel/file_systems/xfs/Debug.h
index ec5a36b..ac7413c 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/Extent.h
b/src/add-ons/kernel/file_systems/xfs/Extent.h
index cdcb86b..b771485 100644
--- a/src/add-ons/kernel/file_systems/xfs/Extent.h
+++ b/src/add-ons/kernel/file_systems/xfs/Extent.h
@@ -82,18 +82,6 @@
};
-struct ExtentMapEntry {
- xfs_fileoff_t br_startoff;
- // logical file block offset
- xfs_fsblock_t br_startblock;
- // absolute block number
- xfs_filblks_t br_blockcount;
- // # of blocks
- uint8 br_state;
- // state of the extent
-};
-
-
class Extent
{
public:
diff --git a/src/add-ons/kernel/file_systems/xfs/Inode.cpp
b/src/add-ons/kernel/file_systems/xfs/Inode.cpp
index d872052..d594c86 100644
--- a/src/add-ons/kernel/file_systems/xfs/Inode.cpp
+++ b/src/add-ons/kernel/file_systems/xfs/Inode.cpp
@@ -141,9 +141,10 @@
Inode::Inode(Volume* volume, xfs_ino_t id)
:
fVolume(volume),
- fId(id)
+ fId(id),
+ fBuffer(NULL),
+ fExtents(NULL)
{
-
}
@@ -193,6 +194,133 @@
}
+void
+Inode::UnWrapExtentFromWrappedEntry(uint64 wrappedExtent[2],
+ ExtentMapEntry* entry)
+{
+ uint64 first = B_BENDIAN_TO_HOST_INT64(wrappedExtent[0]);
+ uint64 second = B_BENDIAN_TO_HOST_INT64(wrappedExtent[1]);
+ entry->br_state = first >> 63;
+ entry->br_startoff = (first & MASK(63)) >> 9;
+ entry->br_startblock = ((first & MASK(9)) << 43) | (second >>
21);
+ entry->br_blockcount = second & MASK(21);
+}
+
+
+status_t
+Inode::ReadExtents()
+{
+ if (Format() != XFS_DINODE_FMT_EXTENTS)
+ return B_NOT_SUPPORTED;
+ fExtents = new(std::nothrow) ExtentMapEntry[NoOfDataExtents()];
+ char* dataStart = (char*) DIR_DFORK_PTR(Buffer());
+ uint64 wrappedExtent[2];
+ for (int i = 0; i < NoOfDataExtents(); i++) {
+ wrappedExtent[0] = *(uint64*)(dataStart);
+ wrappedExtent[1] = *(uint64*)(dataStart + sizeof(uint64));
+ UnWrapExtentFromWrappedEntry(wrappedExtent, &fExtents[i]);
+ }
+ return B_OK;
+}
+
+
+int
+Inode::SearchMapInAllExtent(int blockNo)
+{
+ for (int i = 0; i < NoOfDataExtents() ; i++) {
+ if (fExtents[i].br_startoff <= blockNo
+ && (blockNo <= fExtents[i].br_startoff +
fExtents[i].br_blockcount - 1))
+ // Map found
+ return i;
+ }
+ return -1;
+}
+
+
+status_t
+Inode::ReadAt(off_t pos, uint8* buffer, size_t* length)
+{
+ TRACE("Inode::ReadAt: pos:(%ld), *length:(%ld)\n", pos, *length);
+ status_t status;
+ if (fExtents == NULL) {
+ status = ReadExtents();
+ if (status != B_OK)
+ return status;
+ }
+
+ // set/check boundaries for pos/length
+ if (pos < 0) {
+ ERROR("inode %" B_PRIdINO ": ReadAt failed(pos %" B_PRIdOFF
+ ", length %lu)\n", ID(), pos, length);
+ return B_BAD_VALUE;
+ }
+
+ if (pos >= Size() || length == 0) {
+ TRACE("inode %" B_PRIdINO ": ReadAt 0 (pos %" B_PRIdOFF
+ ", length %lu)\n", ID(), pos, length);
+ *length = 0;
+ return B_NO_ERROR;
+ }
+
+ uint32 blockNo = BLOCKNO_FROM_POSITION(pos, GetVolume());
+ uint32 offsetIntoBlock = BLOCKOFFSET_FROM_POSITION(pos, this);
+
+ size_t lengthOfBlock = BlockSize();
+ char* block = new(std::nothrow) char[lengthOfBlock];
+ if (block == NULL)
+ return B_NO_MEMORY;
+
+ size_t lengthRead = 0;
+ size_t lengthLeftInFile;
+ size_t lengthLeftInBlock;
+ size_t lengthToRead;
+ TRACE("What is blockLen:(%d)\n", lengthOfBlock);
+ while (*length > 0) {
+ TRACE("Inode::ReadAt: pos:(%ld), *length:(%ld)\n", pos,
*length);
+ // As long as you can read full blocks, read.
+ lengthLeftInFile = Size() - pos;
+ lengthLeftInBlock = lengthOfBlock - offsetIntoBlock;
+
+ // We could be almost at the end of the file
+ if (lengthLeftInFile <= lengthLeftInBlock)
+ lengthToRead = lengthLeftInFile;
+ else lengthToRead = lengthLeftInBlock;
+
+ // But we might not be able to read all of the
+ // data because of less buffer length
+ if (lengthToRead > *length)
+ lengthToRead = *length;
+
+ int indexForMap = SearchMapInAllExtent(blockNo);
+ if (indexForMap == -1)
+ return B_BAD_VALUE;
+
+ xfs_daddr_t readPos
+ =
FileSystemBlockToAddr(fExtents[indexForMap].br_startblock
+ + blockNo - fExtents[indexForMap].br_startoff);
+
+ if (read_pos(GetVolume()->Device(), readPos, block,
lengthOfBlock)
+ != lengthOfBlock) {
+ ERROR("TreeDirectory::FillBlockBuffer(): IO Error");
+ return B_IO_ERROR;
+ }
+
+
+ memcpy((void*) (buffer + lengthRead),
+ (void*)(block + offsetIntoBlock), lengthToRead);
+
+ pos += lengthToRead;
+ *length -= lengthToRead;
+ lengthRead += lengthToRead;
+ blockNo = BLOCKNO_FROM_POSITION(pos, GetVolume());
+ offsetIntoBlock = BLOCKOFFSET_FROM_POSITION(pos, this);
+ }
+ TRACE("lengthRead:(%d)\n", lengthRead);
+ *length = lengthRead;
+ return B_OK;
+}
+
+
status_t
Inode::GetFromDisk()
{
diff --git a/src/add-ons/kernel/file_systems/xfs/Inode.h
b/src/add-ons/kernel/file_systems/xfs/Inode.h
index 6337a5e..1639725 100644
--- a/src/add-ons/kernel/file_systems/xfs/Inode.h
+++ b/src/add-ons/kernel/file_systems/xfs/Inode.h
@@ -5,6 +5,7 @@
#ifndef _INODE_H_
#define _INODE_H_
+
#include "system_dependencies.h"
#include "Volume.h"
#include "xfs_types.h"
@@ -39,6 +40,9 @@
#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()))
+#define BLOCKNO_FROM_POSITION(n, volume) \
+ ((n) >> (volume->BlockLog()))
+#define BLOCKOFFSET_FROM_POSITION(n, inode) ((n) & (inode->BlockSize() - 1))
// xfs_da_blkinfo_t
@@ -50,6 +54,18 @@
};
+struct ExtentMapEntry {
+ xfs_fileoff_t br_startoff;
+ // logical file block offset
+ xfs_fsblock_t br_startblock;
+ // absolute block number
+ xfs_filblks_t br_blockcount;
+ // # of blocks
+ uint8 br_state;
+ // state of the extent
+};
+
+
uint32
hashfunction(const char* name, int length);
@@ -80,7 +96,6 @@
struct xfs_inode_t {
void SwapEndian();
int8 Version() const;
- //TODO: Check
mode_t Mode() const;
void
GetModificationTime(struct timespec&
timestamp);
@@ -180,6 +195,9 @@
uint32 DirBlockSize() const
{
return fVolume->DirBlockSize(); }
+ uint32 BlockSize() const
+ {
return fVolume->BlockSize(); }
+
void GetChangeTime(struct
timespec& timestamp) const
{
fNode->GetChangeTime(timestamp); }
@@ -199,7 +217,11 @@
uint64
FileSystemBlockToAddr(uint64 block);
uint8 ForkOffset() const
{
return fNode->ForkOffset(); }
-
+ status_t ReadExtents();
+ status_t ReadAt(off_t pos,
uint8* buffer, size_t* length);
+ int
SearchMapInAllExtent(int blockNo);
+ void
UnWrapExtentFromWrappedEntry(
+ uint64
wrappedExtent[2], ExtentMapEntry* entry);
private:
status_t GetFromDisk();
xfs_inode_t* fNode;
@@ -207,6 +229,7 @@
Volume* fVolume;
char* fBuffer;
// Contains the disk inode in BE format
+ ExtentMapEntry* fExtents;
};
#endif
diff --git a/src/add-ons/kernel/file_systems/xfs/Utility.h
b/src/add-ons/kernel/file_systems/xfs/Utility.h
new file mode 100644
index 0000000..fa0ccfa
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/xfs/Utility.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2001-2009, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
+ * Copyright 2020, Shubham Bhagat, shubhambhagat111@xxxxxxxxx
+ * This file may be used under the terms of the MIT License.
+ */
+#ifndef UTILITY_H
+#define UTILITY_H
+
+
+/*! Converts the open mode, the open flags given to xfs_open(), into
+ access modes, e.g. since O_RDONLY requires read access to the
+ file, it will be converted to R_OK.
+*/
+inline int
+open_mode_to_access(int openMode)
+{
+ openMode &= O_RWMASK;
+ if (openMode == O_RDONLY)
+ return R_OK;
+ if (openMode == O_WRONLY)
+ return W_OK;
+
+ return R_OK | W_OK;
+}
+
+
+#endif // UTILITY_H
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 e7116c4..a86953c 100644
--- a/src/add-ons/kernel/file_systems/xfs/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/xfs/kernel_interface.cpp
@@ -8,6 +8,7 @@
#include "system_dependencies.h"
#include "Directory.h"
#include "Inode.h"
+#include "Utility.h"
#include "Volume.h"
@@ -281,7 +282,33 @@
xfs_open(fs_volume * /*_volume*/, fs_vnode *_node, int openMode,
void **_cookie)
{
- return B_NOT_SUPPORTED;
+ TRACE("XFS_OPEN:\n");
+ Inode* inode = (Inode*)_node->private_node;
+
+ // opening a directory read-only is allowed, although you can't read
+ // any data from it.
+ if (inode->IsDirectory() && (openMode & O_RWMASK) != 0)
+ return B_IS_A_DIRECTORY;
+
+ status_t status = inode->CheckPermissions(open_mode_to_access(openMode)
+ | (openMode & O_TRUNC ? W_OK : 0));
+ if (status != B_OK)
+ return status;
+
+ // Prepare the cookie
+ file_cookie* cookie = new(std::nothrow) file_cookie;
+ if (cookie == NULL)
+ return B_NO_MEMORY;
+ ObjectDeleter<file_cookie> cookieDeleter(cookie);
+
+ cookie->open_mode = openMode & XFS_OPEN_MODE_USER_MASK;
+ cookie->last_size = inode->Size();
+ cookie->last_notification = system_time();
+
+ cookieDeleter.Detach();
+ *_cookie = cookie;
+
+ return B_OK;
}
@@ -289,21 +316,38 @@
xfs_read(fs_volume *_volume, fs_vnode *_node, void *_cookie, off_t pos,
void *buffer, size_t *_length)
{
- return B_NOT_SUPPORTED;
+ TRACE("Inode::ReadAt: pos:(%ld), *length:(%ld)\n", pos, *_length);
+ Inode* inode = (Inode*)_node->private_node;
+
+ if (!inode->IsFile()) {
+ *_length = 0;
+ return inode->IsDirectory() ? B_IS_A_DIRECTORY : B_BAD_VALUE;
+ }
+
+ return inode->ReadAt(pos, (uint8*)buffer, _length);
}
static status_t
xfs_close(fs_volume *_volume, fs_vnode *_node, void *_cookie)
{
- return B_NOT_SUPPORTED;
+ return B_OK;
}
static status_t
xfs_free_cookie(fs_volume *_volume, fs_vnode *_node, void *_cookie)
{
- return B_NOT_SUPPORTED;
+ TRACE("XFS_FREE_COOKIE:\n");
+ file_cookie* cookie = (file_cookie*)_cookie;
+ Volume* volume = (Volume*)_volume->private_volume;
+ Inode* inode = (Inode*)_node->private_node;
+
+ if (inode->Size() != cookie->last_size)
+ notify_stat_changed(volume->ID(), -1, inode->ID(), B_STAT_SIZE);
+
+ delete cookie;
+ return B_OK;
}
@@ -423,7 +467,7 @@
xfs_close_dir(fs_volume * /*_volume*/, fs_vnode * /*node*/,
void * /*_cookie*/)
{
- return B_NOT_SUPPORTED;
+ return B_OK;
}
diff --git a/src/add-ons/kernel/file_systems/xfs/xfs.h
b/src/add-ons/kernel/file_systems/xfs/xfs.h
index 617e6bb..4bc49e8 100644
--- a/src/add-ons/kernel/file_systems/xfs/xfs.h
+++ b/src/add-ons/kernel/file_systems/xfs/xfs.h
@@ -1,4 +1,5 @@
/*
+ * Copyright 2001-2017, Axel Dörfler, axeld@xxxxxxxxxxxxxxxx.
* Copyright 2020, Shubham Bhagat, shubhambhagat111@xxxxxxxxx
* All rights reserved. Distributed under the terms of the MIT License.
*/
@@ -29,6 +30,14 @@
// Log of block size should be 9
#define BASICBLOCKSIZE (1 << BASICBLOCKLOG)
// The size of a basic block should be 512
+#define XFS_OPEN_MODE_USER_MASK 0x7fffffff
+
+
+struct file_cookie {
+ bigtime_t last_notification;
+ off_t last_size;
+ int open_mode;
+};
/* Version 4 superblock definition */
--
To view, visit https://review.haiku-os.org/c/haiku/+/3154
To unsubscribe, or for help writing mail filters, visit
https://review.haiku-os.org/settings
Gerrit-Project: haiku
Gerrit-Branch: master
Gerrit-Change-Id: I8e3acd658730ed2339dabbd671820c409332f296
Gerrit-Change-Number: 3154
Gerrit-PatchSet: 1
Gerrit-Owner: Shubham Bhagat <shubhambhagat111@xxxxxxxxx>
Gerrit-MessageType: newchange