[haiku-commits] Change in haiku[master]: xfs: Attempt at reading extent based files

  • From: Gerrit <review@xxxxxxxxxxxxxxxxxxx>
  • To: waddlesplash <waddlesplash@xxxxxxxxx>, haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 17 Aug 2020 17:14:54 +0000

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

Other related posts:

  • » [haiku-commits] Change in haiku[master]: xfs: Attempt at reading extent based files - Gerrit