From 4b53c2ba4f0b774030e369fc2ec522309b12d1f7 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 19 Jul 2010 13:58:03 +0000 Subject: [PATCH] Implemented hooks write_fs_info(), sync(), set_flags(), fsync(), access(). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37595 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../system/kernel/file_corruption/fs/File.cpp | 7 + .../system/kernel/file_corruption/fs/File.h | 1 + .../system/kernel/file_corruption/fs/Node.cpp | 7 + .../system/kernel/file_corruption/fs/Node.h | 1 + .../kernel/file_corruption/fs/SuperBlock.cpp | 7 + .../kernel/file_corruption/fs/SuperBlock.h | 1 + .../kernel/file_corruption/fs/Volume.cpp | 55 +++- .../system/kernel/file_corruption/fs/Volume.h | 3 + .../kernel/file_corruption/fs/checksumfs.cpp | 271 +++++++++++------- 9 files changed, 250 insertions(+), 103 deletions(-) diff --git a/src/tests/system/kernel/file_corruption/fs/File.cpp b/src/tests/system/kernel/file_corruption/fs/File.cpp index 23ad4b0bad..8a98a25e2f 100644 --- a/src/tests/system/kernel/file_corruption/fs/File.cpp +++ b/src/tests/system/kernel/file_corruption/fs/File.cpp @@ -237,6 +237,13 @@ File::Write(off_t pos, const void* buffer, size_t size, size_t& _bytesWritten) } +status_t +File::Sync() +{ + return file_cache_sync(fFileCache); +} + + void File::RevertNodeData(const checksumfs_node& nodeData) { diff --git a/src/tests/system/kernel/file_corruption/fs/File.h b/src/tests/system/kernel/file_corruption/fs/File.h index 608523b054..9c958722b7 100644 --- a/src/tests/system/kernel/file_corruption/fs/File.h +++ b/src/tests/system/kernel/file_corruption/fs/File.h @@ -29,6 +29,7 @@ public: size_t& _bytesRead); virtual status_t Write(off_t pos, const void* buffer, size_t size, size_t& _bytesWritten); + virtual status_t Sync(); virtual void RevertNodeData(const checksumfs_node& nodeData); diff --git a/src/tests/system/kernel/file_corruption/fs/Node.cpp b/src/tests/system/kernel/file_corruption/fs/Node.cpp index ce1138361b..63fb42ad5b 100644 --- a/src/tests/system/kernel/file_corruption/fs/Node.cpp +++ b/src/tests/system/kernel/file_corruption/fs/Node.cpp @@ -105,6 +105,13 @@ Node::Write(off_t pos, const void* buffer, size_t size, size_t& _bytesWritten) } +status_t +Node::Sync() +{ + return B_OK; +} + + void Node::SetParentDirectory(uint32 blockIndex) { diff --git a/src/tests/system/kernel/file_corruption/fs/Node.h b/src/tests/system/kernel/file_corruption/fs/Node.h index 366c1f6962..6cfeb4efcb 100644 --- a/src/tests/system/kernel/file_corruption/fs/Node.h +++ b/src/tests/system/kernel/file_corruption/fs/Node.h @@ -43,6 +43,7 @@ public: size_t& _bytesRead); virtual status_t Write(off_t pos, const void* buffer, size_t size, size_t& _bytesWritten); + virtual status_t Sync(); inline const checksumfs_node& NodeData() const { return fNode; } inline Volume* GetVolume() const { return fVolume; } diff --git a/src/tests/system/kernel/file_corruption/fs/SuperBlock.cpp b/src/tests/system/kernel/file_corruption/fs/SuperBlock.cpp index 901af4cbd4..c1968409db 100644 --- a/src/tests/system/kernel/file_corruption/fs/SuperBlock.cpp +++ b/src/tests/system/kernel/file_corruption/fs/SuperBlock.cpp @@ -52,3 +52,10 @@ SuperBlock::SetFreeBlocks(uint64 count) { freeBlocks = count; } + + +void +SuperBlock::SetName(const char* name) +{ + strlcpy(this->name, name, kCheckSumFSNameLength); +} diff --git a/src/tests/system/kernel/file_corruption/fs/SuperBlock.h b/src/tests/system/kernel/file_corruption/fs/SuperBlock.h index 4ffc1781b5..195476c4fa 100644 --- a/src/tests/system/kernel/file_corruption/fs/SuperBlock.h +++ b/src/tests/system/kernel/file_corruption/fs/SuperBlock.h @@ -25,6 +25,7 @@ public: void Initialize(Volume* volume); void SetFreeBlocks(uint64 count); + void SetName(const char* name); }; diff --git a/src/tests/system/kernel/file_corruption/fs/Volume.cpp b/src/tests/system/kernel/file_corruption/fs/Volume.cpp index ca0ddf2ead..bd879f47e0 100644 --- a/src/tests/system/kernel/file_corruption/fs/Volume.cpp +++ b/src/tests/system/kernel/file_corruption/fs/Volume.cpp @@ -17,6 +17,9 @@ #include +#include +#include + #include "Block.h" #include "BlockAllocator.h" #include "checksumfs.h" @@ -40,6 +43,7 @@ Volume::Volume(uint32 flags) fBlockAllocator(NULL), fRootDirectory(NULL) { + mutex_init(&fLock, "checksumfs volume"); mutex_init(&fTransactionLock, "checksumfs transaction"); } @@ -58,6 +62,7 @@ Volume::~Volume() free(fName); mutex_destroy(&fTransactionLock); + mutex_destroy(&fLock); } @@ -217,6 +222,8 @@ Volume::Initialize(const char* name) void Volume::GetInfo(fs_info& info) { + MutexLocker locker(fLock); + info.flags = fFlags; info.block_size = B_PAGE_SIZE; info.io_size = B_PAGE_SIZE * 16; // random value @@ -225,7 +232,6 @@ Volume::GetInfo(fs_info& info) info.total_nodes = 1; // phew, who cares? info.free_nodes = info.free_blocks; strlcpy(info.volume_name, fName, sizeof(info.volume_name)); - // TODO: We need locking once we are able to change the name! } @@ -427,6 +433,53 @@ Volume::DeleteNode(Node* node) } +status_t +Volume::SetName(const char* name) +{ + if (name == NULL || strlen(name) > kCheckSumFSNameLength) + return B_BAD_VALUE; + + // clone the name + char* newName = strdup(name); + if (newName == NULL) + return B_NO_MEMORY; + MemoryDeleter newNameDeleter(newName); + + // start a transaction + Transaction transaction(this); + status_t error = transaction.Start(); + if (error != B_OK) + return error; + + // we lock the volume now, to keep the locking order (transaction -> volume) + MutexLocker locker(fLock); + + // update the super block + Block block; + if (!block.GetWritable(this, kCheckSumFSSuperBlockOffset / B_PAGE_SIZE, + transaction)) { + return B_ERROR; + } + + SuperBlock* superBlock = (SuperBlock*)block.Data(); + superBlock->SetName(newName); + + block.Put(); + + // commit the transaction + error = transaction.Commit(); + if (error != B_OK) + return error; + + // Everything went fine. We can replace the name. Since we still have the + // volume lock, there's no race condition. + free(fName); + fName = (char*)newNameDeleter.Detach(); + + return B_OK; +} + + status_t Volume::_Init(uint64 totalBlocks) { diff --git a/src/tests/system/kernel/file_corruption/fs/Volume.h b/src/tests/system/kernel/file_corruption/fs/Volume.h index 49ad64b670..3e5ab5a657 100644 --- a/src/tests/system/kernel/file_corruption/fs/Volume.h +++ b/src/tests/system/kernel/file_corruption/fs/Volume.h @@ -54,6 +54,8 @@ public: SymLink*& _symLink); status_t DeleteNode(Node* node); + status_t SetName(const char* name); + inline void TransactionStarted(); inline void TransactionFinished(); @@ -80,6 +82,7 @@ private: char* fName; BlockAllocator* fBlockAllocator; Directory* fRootDirectory; + mutex fLock; mutex fTransactionLock; }; diff --git a/src/tests/system/kernel/file_corruption/fs/checksumfs.cpp b/src/tests/system/kernel/file_corruption/fs/checksumfs.cpp index e1671b3e13..85b92995f1 100644 --- a/src/tests/system/kernel/file_corruption/fs/checksumfs.cpp +++ b/src/tests/system/kernel/file_corruption/fs/checksumfs.cpp @@ -36,6 +36,107 @@ static const char* const kCheckSumFSModuleName = "file_systems/checksumfs" static const char* const kCheckSumFSShortName = "checksumfs"; +// #pragma mark - + + +struct FileCookie { + int openMode; + + FileCookie(int openMode) + : + openMode(openMode) + { + } +}; + + +struct DirCookie { + DirCookie(Directory* directory) + : + fDirectory(directory) + { + Rewind(); + } + + Directory* GetDirectory() const + { + return fDirectory; + } + + status_t ReadNextEntry(struct dirent* buffer, size_t size, + uint32& _countRead) + { + const char* name; + size_t nameLength; + uint64 blockIndex; + + int nextIterationState = OTHERS; + switch (fIterationState) { + case DOT: + name = "."; + nameLength = 1; + blockIndex = fDirectory->BlockIndex(); + nextIterationState = DOT_DOT; + break; + case DOT_DOT: + name = ".."; + nameLength = 2; + blockIndex = fDirectory->ParentDirectory(); + break; + default: + { + status_t error = fDirectory->LookupNextEntry(fEntryName, + fEntryName, nameLength, blockIndex); + if (error != B_OK) { + if (error != B_ENTRY_NOT_FOUND) + return error; + + _countRead = 0; + return B_OK; + } + + name = fEntryName; + break; + } + } + + size_t entrySize = sizeof(dirent) + nameLength; + if (entrySize > size) + return B_BUFFER_OVERFLOW; + + buffer->d_dev = fDirectory->GetVolume()->ID(); + buffer->d_ino = blockIndex; + buffer->d_reclen = entrySize; + strcpy(buffer->d_name, name); + + fIterationState = nextIterationState; + + _countRead = 1; + return B_OK; + } + + void Rewind() + { + fIterationState = DOT; + fEntryName[0] = '\0'; + } + +private: + enum { + DOT, + DOT_DOT, + OTHERS + }; + + Directory* fDirectory; + int fIterationState; + char fEntryName[kCheckSumFSNameLength + 1]; +}; + + +// #pragma mark - + + static void set_timespec(timespec& time, uint64 nanos) { @@ -355,6 +456,31 @@ checksumfs_read_fs_info(fs_volume* fsVolume, struct fs_info* info) } +static status_t +checksumfs_write_fs_info(fs_volume* fsVolume, const struct fs_info* info, + uint32 mask) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + + if ((mask & FS_WRITE_FSINFO_NAME) != 0) { + status_t error = volume->SetName(info->volume_name); + if (error != B_OK) + return error; + } + + return B_OK; +} + + +static status_t +checksumfs_sync(fs_volume* fsVolume) +{ + Volume* volume = (Volume*)fsVolume->private_volume; + + return block_cache_sync(volume->BlockCache()); +} + + static status_t checksumfs_get_vnode(fs_volume* fsVolume, ino_t id, fs_vnode* vnode, int* _type, uint32* _flags, bool reenter) @@ -507,6 +633,31 @@ checksumfs_get_file_map(fs_volume* fsVolume, fs_vnode* vnode, off_t offset, // #pragma mark - common operations +static status_t +checksumfs_set_flags(fs_volume* fsVolume, fs_vnode* vnode, void* _cookie, + int flags) +{ + FileCookie* cookie = (FileCookie*)_cookie; + + cookie->openMode = (cookie->openMode & ~O_APPEND) | (flags & O_APPEND); + + // TODO: Also support O_NOCACHE! + + return B_OK; +} + + +static status_t +checksumfs_fsync(fs_volume* fsVolume, fs_vnode* vnode) +{ + Node* node = (Node*)vnode->private_node; + + NodeReadLocker nodeLocker(node); + + return node->Sync(); +} + + static status_t checksumfs_read_symlink(fs_volume* fsVolume, fs_vnode* vnode, char* buffer, size_t* _bufferSize) @@ -749,6 +900,17 @@ checksumfs_rename(fs_volume* fsVolume, fs_vnode* fromDir, const char* fromName, } +static status_t +checksumfs_access(fs_volume* fsVolume, fs_vnode* vnode, int mode) +{ + Node* node = (Node*)vnode->private_node; + + NodeReadLocker nodeLocker(node); + + return check_access(node, mode); +} + + static status_t checksumfs_read_stat(fs_volume* fsVolume, fs_vnode* vnode, struct stat* st) { @@ -872,17 +1034,6 @@ checksumfs_write_stat(fs_volume* fsVolume, fs_vnode* vnode, // #pragma mark - file operations -struct FileCookie { - int openMode; - - FileCookie(int openMode) - : - openMode(openMode) - { - } -}; - - /*! Opens the node according to the given open mode (if the permissions allow that) and creates a file cookie. The caller must either pass a \a transaction, which is already started and @@ -1187,90 +1338,6 @@ checksumfs_write(fs_volume* fsVolume, fs_vnode* vnode, void* _cookie, off_t pos, // #pragma mark - directory operations -struct DirCookie { - DirCookie(Directory* directory) - : - fDirectory(directory) - { - Rewind(); - } - - Directory* GetDirectory() const - { - return fDirectory; - } - - status_t ReadNextEntry(struct dirent* buffer, size_t size, - uint32& _countRead) - { - const char* name; - size_t nameLength; - uint64 blockIndex; - - int nextIterationState = OTHERS; - switch (fIterationState) { - case DOT: - name = "."; - nameLength = 1; - blockIndex = fDirectory->BlockIndex(); - nextIterationState = DOT_DOT; - break; - case DOT_DOT: - name = ".."; - nameLength = 2; - blockIndex = fDirectory->ParentDirectory(); - break; - default: - { - status_t error = fDirectory->LookupNextEntry(fEntryName, - fEntryName, nameLength, blockIndex); - if (error != B_OK) { - if (error != B_ENTRY_NOT_FOUND) - return error; - - _countRead = 0; - return B_OK; - } - - name = fEntryName; - break; - } - } - - size_t entrySize = sizeof(dirent) + nameLength; - if (entrySize > size) - return B_BUFFER_OVERFLOW; - - buffer->d_dev = fDirectory->GetVolume()->ID(); - buffer->d_ino = blockIndex; - buffer->d_reclen = entrySize; - strcpy(buffer->d_name, name); - - fIterationState = nextIterationState; - - _countRead = 1; - return B_OK; - } - - void Rewind() - { - fIterationState = DOT; - fEntryName[0] = '\0'; - } - -private: - enum { - DOT, - DOT_DOT, - OTHERS - }; - - Directory* fDirectory; - int fIterationState; - char fEntryName[kCheckSumFSNameLength + 1]; -}; - - status_t checksumfs_create_dir(fs_volume* fsVolume, fs_vnode* parent, const char* name, int perms) @@ -1469,8 +1536,8 @@ fs_volume_ops gCheckSumFSVolumeOps = { checksumfs_unmount, checksumfs_read_fs_info, - NULL, // write_fs_info - NULL, // sync + checksumfs_write_fs_info, + checksumfs_sync, checksumfs_get_vnode, @@ -1521,10 +1588,10 @@ fs_vnode_ops gCheckSumFSVnodeOps = { /* common operations */ NULL, // checksumfs_ioctl, - NULL, // checksumfs_set_flags, - NULL, // checksumfs_select, - NULL, // checksumfs_deselect, - NULL, // checksumfs_fsync, + checksumfs_set_flags, + NULL, // select + NULL, // deselect + checksumfs_fsync, checksumfs_read_symlink, checksumfs_create_symlink, @@ -1533,7 +1600,7 @@ fs_vnode_ops gCheckSumFSVnodeOps = { checksumfs_unlink, checksumfs_rename, - NULL, // checksumfs_access, + checksumfs_access, checksumfs_read_stat, checksumfs_write_stat,