From 057a3b389f6c1148c01b4c1fb952421cb020298b Mon Sep 17 00:00:00 2001 From: Suhel Mehta Date: Sun, 26 Jul 2020 00:36:17 +0530 Subject: [PATCH] ufs2: Implementing read function Attempting to read data from direct blocks and single indirect blocks even if the data stored is not in continous blocks and DirectoryIterator now uses ReadAt to iterate through directories. Change-Id: I8156aba53782da8c2bb4481db611ae26d8881b35 Reviewed-on: https://review.haiku-os.org/c/haiku/+/3088 Reviewed-by: Adrien Destugues --- .../file_systems/ufs2/DirectoryIterator.cpp | 51 ++++--- .../kernel/file_systems/ufs2/Inode.cpp | 134 +++++++++++++++++- src/add-ons/kernel/file_systems/ufs2/Inode.h | 31 ++-- .../file_systems/ufs2/kernel_interface.cpp | 41 ++++-- src/add-ons/kernel/file_systems/ufs2/ufs2.h | 8 ++ 5 files changed, 209 insertions(+), 56 deletions(-) diff --git a/src/add-ons/kernel/file_systems/ufs2/DirectoryIterator.cpp b/src/add-ons/kernel/file_systems/ufs2/DirectoryIterator.cpp index 272be1ad8e..da326e2796 100644 --- a/src/add-ons/kernel/file_systems/ufs2/DirectoryIterator.cpp +++ b/src/add-ons/kernel/file_systems/ufs2/DirectoryIterator.cpp @@ -10,7 +10,7 @@ #include "Inode.h" -//#define TRACE_UFS2 +#define TRACE_UFS2 #ifdef TRACE_UFS2 # define TRACE(x...) dprintf("\33[34mufs2:\33[0m " x) #else @@ -24,8 +24,7 @@ DirectoryIterator::DirectoryIterator(Inode* inode) : fInode(inode) { - fOffset = fInode->GetBlockPointer() * MINBSIZE; - TRACE("DirectoryIterator::DirectoryIterator() \n"); + fOffset = 0; } @@ -67,32 +66,30 @@ status_t DirectoryIterator::GetNext(char* name, size_t* _nameLength, ino_t* _id) { dir direct; - int fd = fInode->GetVolume()->Device(); + size_t size = sizeof(dir); + status_t status = fInode->ReadAt(fOffset, (uint8_t*)&direct, &size); + if (status == B_OK) { + int remainder = direct.namlen % 4; + if(remainder != 0) { + remainder = 4 - remainder; + remainder = direct.namlen + remainder; + } else { + remainder = direct.namlen + 4; + } + + fOffset = fOffset + 8 + remainder; + + if (direct.next_ino > 0) { + strlcpy(name, direct.name, direct.namlen + 1); + *_id = direct.next_ino; + *_nameLength = direct.namlen; + return B_OK; + } + + return B_ENTRY_NOT_FOUND; - if (read_pos(fd, fOffset, &direct, sizeof(dir)) != sizeof(dir)) { - return B_BAD_DATA; } - int remainder = direct.namlen % 4; - if(remainder != 0) { - remainder = 4 - remainder; - remainder = direct.namlen + remainder; - } else { - remainder = direct.namlen + 4; - } - - fOffset = fOffset + 8 + remainder; - - if (direct.next_ino > 0) { - TRACE("direct.next_ino %d\n",direct.next_ino); - - strlcpy(name, direct.name, remainder); - *_id = direct.next_ino; - *_nameLength = direct.namlen; - return B_OK; - } - - return B_ENTRY_NOT_FOUND; - + return B_ERROR; } diff --git a/src/add-ons/kernel/file_systems/ufs2/Inode.cpp b/src/add-ons/kernel/file_systems/ufs2/Inode.cpp index 455e753d62..9ed6198d73 100644 --- a/src/add-ons/kernel/file_systems/ufs2/Inode.cpp +++ b/src/add-ons/kernel/file_systems/ufs2/Inode.cpp @@ -5,8 +5,11 @@ */ #include "Inode.h" +#include -#ifdef TRACE_ufs2 + +#define TRACE_UFS2 +#ifdef TRACE_UFS2 #define TRACE(x...) dprintf("\33[34mufs2:\33[0m " x) #else #define TRACE(x...) ; @@ -34,7 +37,7 @@ Inode::Inode(Volume* volume, ino_t id) ufs2_super_block* superblock = (ufs2_super_block* )&fVolume->SuperBlock(); int64_t fs_block = ino_to_fsba(superblock, id); int64_t offset_in_block = ino_to_fsbo(superblock, id); - int64_t offset = fs_block * MINBSIZE + offset_in_block * 256; + int64_t offset = fs_block * MINBSIZE + offset_in_block * sizeof(fNode); if (read_pos(fd, offset, (void*)&fNode, sizeof(fNode)) != sizeof(fNode)) ERROR("Inode::Inode(): IO Error\n"); @@ -85,3 +88,130 @@ Inode::InitCheck() { return fInitStatus; } + + +status_t +Inode::ReadAt(off_t file_offset, uint8* buffer, size_t* _length) +{ + int fd = fVolume->Device(); + ufs2_super_block super_block = fVolume->SuperBlock(); + int32_t blockSize = super_block.fs_bsize; + off_t pos; + int64_t size = Size(); + off_t startBlockNumber = file_offset / blockSize; + off_t endBlockNumber = (file_offset + *_length) / blockSize; + off_t blockOffset = file_offset % blockSize; + ssize_t length = 0; + if (startBlockNumber != endBlockNumber) { + ssize_t remainingLength = blockSize - blockOffset; + for (; startBlockNumber <= endBlockNumber; startBlockNumber++) { + //code for reading multiple blocks + pos = FindBlock(startBlockNumber, blockOffset); + length += read_pos(fd, pos, buffer, remainingLength); + blockOffset = 0; + remainingLength = *_length - length; + if (remainingLength > blockSize) + remainingLength = blockSize; + } + *_length = length; + return B_OK; + } + pos = FindBlock(startBlockNumber, blockOffset); + length = read_pos(fd, pos, buffer, *_length); + *_length = length; + return B_OK; + +} + + +off_t +Inode::FindBlock(off_t blockNumber, off_t blockOffset) +{ + int fd = fVolume->Device(); + ufs2_super_block super_block = fVolume->SuperBlock(); + int32_t blockSize = super_block.fs_bsize; + int32_t fragmentSize = super_block.fs_fsize; + off_t indirectOffset; + int64_t directBlock; + off_t numberOfBlockPointers = blockSize / 8; + const off_t numberOfIndirectBlocks = numberOfBlockPointers; + const off_t numberOfDoubleIndirectBlocks = numberOfBlockPointers + * numberOfBlockPointers; + if (blockNumber < 12) { + // read from direct block + return GetBlockPointer(blockNumber) * fragmentSize + blockOffset; + + } else if (blockNumber < numberOfIndirectBlocks + 12) { + //read from indirect block + blockNumber = blockNumber - 12; + indirectOffset = GetIndirectBlockPointer() * + fragmentSize + (8 * blockNumber); + read_pos(fd, indirectOffset, + (void*)&directBlock, sizeof(directBlock)); + + return directBlock * fragmentSize + blockOffset; + + } else if (blockNumber < numberOfDoubleIndirectBlocks + + numberOfIndirectBlocks + 12) { + // Data is in double indirect block + // Subract the already read blocks + blockNumber = blockNumber - numberOfBlockPointers - 12; + // Calculate indirect block inside double indirect block + off_t indirectBlockNumber = blockNumber / numberOfBlockPointers; + indirectOffset = GetDoubleIndirectBlockPtr() * + fragmentSize + (8 * indirectBlockNumber); + + int64_t indirectPointer; + read_pos(fd, indirectOffset, + (void*)&indirectPointer, sizeof(directBlock)); + + indirectOffset = indirectPointer * fragmentSize + + (8 * (blockNumber % numberOfBlockPointers)); + + read_pos(fd, indirectOffset, + (void*)&directBlock, sizeof(directBlock)); + + return directBlock * fragmentSize + blockOffset; + + } else if (blockNumber < (numberOfIndirectBlocks + * numberOfDoubleIndirectBlocks) + + (numberOfDoubleIndirectBlocks + numberOfBlockPointers + 12)) { + // Reading from triple indirect block + blockNumber = blockNumber - numberOfDoubleIndirectBlocks + - numberOfBlockPointers - 12; + + // Get double indirect block + // Double indirect block no + off_t indirectBlockNumber = blockNumber / numberOfDoubleIndirectBlocks; + + // offset to double indirect block ptr + indirectOffset = GetTripleIndirectBlockPtr() * + fragmentSize + (8 * indirectBlockNumber); + + int64_t indirectPointer; + // Get the double indirect block ptr + read_pos(fd, indirectOffset, + (void*)&indirectPointer, sizeof(directBlock)); + + // Get the indirect block + // number of indirect block ptr + indirectBlockNumber = blockNumber / numberOfBlockPointers; + // Indirect block ptr offset + indirectOffset = indirectPointer * fragmentSize + + (8 * indirectBlockNumber); + + read_pos(fd, indirectOffset, + (void*)&indirectPointer, sizeof(directBlock)); + + // Get direct block pointer + indirectOffset = indirectPointer * fragmentSize + + (8 * (blockNumber % numberOfBlockPointers)); + + read_pos(fd, indirectOffset, + (void*)&directBlock, sizeof(directBlock)); + + return directBlock * fragmentSize + blockOffset; + } + + return B_BAD_VALUE; +} diff --git a/src/add-ons/kernel/file_systems/ufs2/Inode.h b/src/add-ons/kernel/file_systems/ufs2/Inode.h index f76cd1a0f5..eedd031814 100644 --- a/src/add-ons/kernel/file_systems/ufs2/Inode.h +++ b/src/add-ons/kernel/file_systems/ufs2/Inode.h @@ -44,18 +44,7 @@ struct ufs2_inode { int64_t extendedBklPtr1; int64_t extendedBklPtr2; /* 12 direct block pointers */ - int64_t directBlkPtr1; - int64_t directBlkPtr2; - int64_t directBlkPtr3; - int64_t directBlkPtr4; - int64_t directBlkPtr5; - int64_t directBlkPtr6; - int64_t directBlkPtr7; - int64_t directBlkPtr8; - int64_t directBlkPtr9; - int64_t directBlkPtr10; - int64_t directBlkPtr11; - int64_t directBlkPtr12; + int64_t directBlkPtr[12]; int64_t indirectBlkPtr; /* 1 Indirect block pointer */ int64_t doubleIndriectBlkPtr; // 1 Double Indirect block pointer int64_t tripleIndriectBlkPtr; // 1 Triple Indirect block pointer @@ -118,12 +107,22 @@ class Inode { Volume* GetVolume() const { return fVolume; } - int64_t GetBlockPointer() { return fNode.directBlkPtr1; } + int64_t GetBlockPointer(int ptrNumber) + { return fNode.directBlkPtr[ptrNumber]; } + + int64_t GetIndirectBlockPointer() + { return fNode.indirectBlkPtr; } + + int64_t GetDoubleIndirectBlockPtr() + { return fNode.doubleIndriectBlkPtr; } + + int64_t GetTripleIndirectBlockPtr() + { return fNode.tripleIndriectBlkPtr; } + ino_t Parent(); -// status_t FindBlock(off_t logical, off_t& physical, -// off_t* _length = NULL); -// status_t ReadAt(off_t pos, uint8* buffer, size_t* length); + off_t FindBlock(off_t block_number, off_t block_offset); + status_t ReadAt(off_t pos, uint8* buffer, size_t* length); // status_t FillGapWithZeros(off_t start, off_t end); void* FileCache() const { return fCache; } diff --git a/src/add-ons/kernel/file_systems/ufs2/kernel_interface.cpp b/src/add-ons/kernel/file_systems/ufs2/kernel_interface.cpp index c97855353f..fb71f73394 100644 --- a/src/add-ons/kernel/file_systems/ufs2/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/ufs2/kernel_interface.cpp @@ -3,7 +3,6 @@ * All rights reserved. Distributed under the terms of the MIT License. */ - #include "DirectoryIterator.h" #include "Inode.h" #include "system_dependencies.h" @@ -26,6 +25,7 @@ struct identify_cookie }; +#if 0 //! ufs2_io() callback hook static status_t iterative_io_get_vecs_hook(void *cookie, io_request *request, off_t offset, @@ -42,6 +42,7 @@ iterative_io_finished_hook(void *cookie, io_request *request, status_t status, { return B_NOT_SUPPORTED; } +#endif // #pragma mark - Scanning @@ -196,7 +197,6 @@ static status_t ufs2_lookup(fs_volume *_volume, fs_vnode *_directory, const char *name, ino_t *_vnodeID) { - TRACE("UFS2_LOOKUP: %p (%s)\n", name, name); Volume* volume = (Volume*)_volume->private_volume; Inode* directory = (Inode*)_directory->private_node; @@ -207,7 +207,6 @@ ufs2_lookup(fs_volume *_volume, fs_vnode *_directory, const char *name, return status; status = get_vnode(volume->FSVolume(), *_vnodeID, NULL); - TRACE("get_vnode status: %s\n", strerror(status)); return status; } @@ -223,11 +222,9 @@ ufs2_ioctl(fs_volume *_volume, fs_vnode *_node, void *_cookie, uint32 cmd, static status_t ufs2_read_stat(fs_volume *_volume, fs_vnode *_node, struct stat *stat) { - TRACE("Reading stat...\n"); Inode* inode = (Inode*)_node->private_node; stat->st_dev = inode->GetVolume()->ID(); stat->st_ino = inode->ID(); - TRACE("stat->st_ino %ld\n",stat->st_ino); // TODO handle hardlinks which will have nlink > 1. Maybe linkCount in inode // structure may help? stat->st_nlink = 1; @@ -251,10 +248,27 @@ ufs2_read_stat(fs_volume *_volume, fs_vnode *_node, struct stat *stat) static status_t -ufs2_open(fs_volume * /*_volume*/, fs_vnode *_node, int openMode, +ufs2_open(fs_volume * _volume, fs_vnode *_node, int openMode, void **_cookie) { - return B_NOT_SUPPORTED; + //Volume* volume = (Volume*)_volume->private_volume; + Inode* inode = (Inode*)_node->private_node; + TRACE("in open %d \n", openMode); + if (inode->IsDirectory()) + return B_IS_A_DIRECTORY; + + file_cookie* cookie = new(std::nothrow) file_cookie; + if (cookie == NULL) + return B_NO_MEMORY; + ObjectDeleter cookieDeleter(cookie); + + cookie->last_size = inode->Size(); + cookie->last_notification = system_time(); + +// fileCacheEnabler.Detach(); + cookieDeleter.Detach(); + *_cookie = cookie; + return B_OK; } @@ -262,7 +276,14 @@ static status_t ufs2_read(fs_volume *_volume, fs_vnode *_node, void *_cookie, off_t pos, void *buffer, size_t *_length) { - return B_NOT_SUPPORTED; + 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); } @@ -340,14 +361,13 @@ static status_t ufs2_read_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie, struct dirent *dirent, size_t bufferSize, uint32 *_num) { - TRACE("read dir \n"); DirectoryIterator* iterator = (DirectoryIterator*)_cookie; Volume* volume = (Volume*)_volume->private_volume; uint32 maxCount = *_num; uint32 count = 0; - while (count < maxCount and (bufferSize > sizeof(struct dirent))) { + while (count < maxCount && (bufferSize > sizeof(struct dirent))) { size_t length = bufferSize - sizeof(struct dirent) + 1; ino_t iNodeNo; @@ -371,7 +391,6 @@ ufs2_read_dir(fs_volume *_volume, fs_vnode *_node, void *_cookie, } *_num = count; - TRACE("count is %d\n", count); return B_OK; } diff --git a/src/add-ons/kernel/file_systems/ufs2/ufs2.h b/src/add-ons/kernel/file_systems/ufs2/ufs2.h index 00366f99b2..473b8befa6 100644 --- a/src/add-ons/kernel/file_systems/ufs2/ufs2.h +++ b/src/add-ons/kernel/file_systems/ufs2/ufs2.h @@ -359,6 +359,14 @@ struct ufs2_super_block { CTASSERT(sizeof(struct fs) == 1376); #endif + +struct file_cookie { + bigtime_t last_notification; + off_t last_size; + int open_mode; +}; + + /* * Filesystem identification */