From 40f7fd6cf3371d69b9d78ca406058a93648cf18c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Thu, 8 Aug 2002 01:23:04 +0000 Subject: [PATCH] Implemented the basics to allow uncached file access under BeOS. This is needed for the VM swap file and if you want to mount disk images located on the BFS volume. There is now a BufferPool class that manages a pool of buffers, so that Inode::ReadAt()/Inode::WriteAt() can access a file without having to use the cache or malloc()/free(). The real uncached file access is not yet implemented, though. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@643 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/file_systems/bfs/BufferPool.cpp | 151 ++++++++++++++++++ .../kernel/file_systems/bfs/BufferPool.h | 31 ++++ src/add-ons/kernel/file_systems/bfs/Jamfile | 1 + src/add-ons/kernel/file_systems/bfs/Volume.h | 4 + .../file_systems/bfs/kernel_interface.cpp | 34 +++- 5 files changed, 218 insertions(+), 3 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/bfs/BufferPool.cpp create mode 100644 src/add-ons/kernel/file_systems/bfs/BufferPool.h diff --git a/src/add-ons/kernel/file_systems/bfs/BufferPool.cpp b/src/add-ons/kernel/file_systems/bfs/BufferPool.cpp new file mode 100644 index 0000000000..e6182e73aa --- /dev/null +++ b/src/add-ons/kernel/file_systems/bfs/BufferPool.cpp @@ -0,0 +1,151 @@ +/* BufferPool - a buffer pool for uncached file access +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include "BufferPool.h" +#include "cpp.h" + +#include + + +const uint32 kNumBuffers = 8; + + +BufferPool::BufferPool() + : + fFirstFree(NULL) +{ + fLock = create_sem(1, "buffer lock"); + fFreeBuffers = create_sem(0, "free buffers"); +} + + +BufferPool::~BufferPool() +{ + delete_sem(fLock); + delete_sem(fFreeBuffers); + + void **buffer = fFirstFree; + while (buffer != NULL) { + void **nextBuffer = (void **)*buffer; + free(buffer); + buffer = nextBuffer; + } +} + + +status_t +BufferPool::InitCheck() +{ + if (fLock < B_OK + || fFreeBuffers < B_OK) + return B_ERROR; + + return B_OK; +} + + +status_t +BufferPool::RequestBuffers(uint32 blockSize) +{ + void **buffers[kNumBuffers]; + + // allocate and connect buffers + + for (int32 i = 0; i < kNumBuffers; i++) { + buffers[i] = (void **)malloc(blockSize); + if (buffers[i] == NULL) { + // free already allocated buffers + for (;i-- > 0; i++) + free(buffers[i]); + return B_NO_MEMORY; + } + if (i > 0) + *(buffers[i]) = buffers[i - 1]; + } + + // add the buffers to the free buffers queue + + status_t status = acquire_sem(fLock); + if (status == B_OK) { + *(buffers[0]) = fFirstFree; + fFirstFree = buffers[kNumBuffers - 1]; + release_sem(fLock); + release_sem_etc(fFreeBuffers, kNumBuffers, B_DO_NOT_RESCHEDULE); + } else { + for (int32 i = 0; i < kNumBuffers; i++) + free(buffers[i]); + } + + return status; +} + + +status_t +BufferPool::ReleaseBuffers() +{ + status_t status = acquire_sem_etc(fFreeBuffers, kNumBuffers, 0, 0); + if (status < B_OK) + return status; + + status = acquire_sem(fLock); + if (status < B_OK) + return status; + + void **buffer = fFirstFree; + for (int32 i = 0; i < kNumBuffers && buffer; i++) { + void **nextBuffer = (void **)*buffer; + + free(buffer); + buffer = nextBuffer; + } + + release_sem(fLock); +} + + +status_t +BufferPool::GetBuffer(void **_buffer) +{ + status_t status = acquire_sem(fFreeBuffers); + if (status < B_OK) + return status; + + if ((status = acquire_sem(fLock)) < B_OK) { + release_sem(fFreeBuffers); + return status; + } + + void **buffer = fFirstFree; + fFirstFree = (void **)*buffer; + + release_sem(fLock); + + *_buffer = (void *)buffer; + return B_OK; +} + + +status_t +BufferPool::PutBuffer(void *_buffer) +{ + void **buffer = (void **)_buffer; + if (buffer == NULL) + return B_BAD_VALUE; + + status_t status = acquire_sem(fLock); + if (status < B_OK) + return status; + + *buffer = fFirstFree; + fFirstFree = buffer; + + release_sem(fLock); + release_sem(fFreeBuffers); + + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/bfs/BufferPool.h b/src/add-ons/kernel/file_systems/bfs/BufferPool.h new file mode 100644 index 0000000000..9e18ca27d2 --- /dev/null +++ b/src/add-ons/kernel/file_systems/bfs/BufferPool.h @@ -0,0 +1,31 @@ +#ifndef BUFFER_POOL_H +#define BUFFER_POOL_H +/* BufferPool - a buffer pool for uncached file access +** +** Initial version by Axel Dörfler, axeld@pinc-software.de +** This file may be used under the terms of the OpenBeOS License. +*/ + + +#include + + +class BufferPool { + public: + BufferPool(); + ~BufferPool(); + + status_t InitCheck(); + + status_t RequestBuffers(uint32 blockSize); + status_t ReleaseBuffers(); + + status_t GetBuffer(void **_buffer); + status_t PutBuffer(void *buffer); + + private: + sem_id fLock, fFreeBuffers; + void **fFirstFree; +}; + +#endif /* BUFFER_POOL_H */ diff --git a/src/add-ons/kernel/file_systems/bfs/Jamfile b/src/add-ons/kernel/file_systems/bfs/Jamfile index c7ec61aac5..427f5feb35 100644 --- a/src/add-ons/kernel/file_systems/bfs/Jamfile +++ b/src/add-ons/kernel/file_systems/bfs/Jamfile @@ -19,5 +19,6 @@ R5KernelAddon obfs : [ FDirName kernel file_systems bfs ] : Query.cpp Utility.cpp Volume.cpp + BufferPool.cpp ; diff --git a/src/add-ons/kernel/file_systems/bfs/Volume.h b/src/add-ons/kernel/file_systems/bfs/Volume.h index 1c6a143e10..aab8fcd147 100644 --- a/src/add-ons/kernel/file_systems/bfs/Volume.h +++ b/src/add-ons/kernel/file_systems/bfs/Volume.h @@ -20,6 +20,7 @@ extern "C" { #include "bfs.h" #include "BlockAllocator.h" +#include "BufferPool.h" #include "Chain.h" class Journal; @@ -86,6 +87,7 @@ class Volume { #ifdef DEBUG BlockAllocator &Allocator() { return fBlockAllocator; } #endif + BufferPool &Pool() { return fBufferPool; } status_t Sync(); Journal *GetJournal(off_t /*refBlock*/) const { return fJournal; } @@ -121,6 +123,8 @@ class Volume { int32 fUniqueID; uint32 fFlags; + + BufferPool fBufferPool; }; // inline functions diff --git a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp index 5dcaab7628..887a4ba44a 100644 --- a/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/bfs/kernel_interface.cpp @@ -524,9 +524,27 @@ bfs_ioctl(void *_ns, void *_node, void *_cookie, int cmd, void *buffer, size_t b switch (cmd) { case IOCTL_FILE_UNCACHED_IO: + { + // if the inode is already set up for uncached access, bail out + if (inode->Flags() & INODE_NO_CACHE) { + FATAL(("File %Ld is already uncached\n", inode->ID())); + return B_ERROR; + } if (inode != NULL) - PRINT(("trying to make access to inode %lx uncached. Not yet implemented!\n",inode->ID())); + PRINT(("trying to make access to inode %Ld uncached. Not yet implemented!\n",inode->ID())); + + // ToDo: sync the cache for this file! + // Unfortunately, we can't remove any blocks from the cache in BeOS, + // that means we can't guarantee consistency for the file contents + // spanning over both access modes. + + // request buffers for being able to access the file without + // using the cache or allocating memory + status_t status = volume->Pool().RequestBuffers(volume->BlockSize()); + if (status == B_OK) + inode->Node()->flags |= INODE_NO_CACHE; return B_ERROR; + } #ifdef DEBUG case 56742: { @@ -1015,6 +1033,10 @@ bfs_open(void *_ns, void *_node, int omode, void **_cookie) Volume *volume = (Volume *)_ns; Inode *inode = (Inode *)_node; + // we can't open a file which uses uncached access twice + if (inode->Flags() & INODE_NO_CACHE) + return B_BUSY; + // opening a directory read-only is allowed, although you can't read // any data from it. if (inode->IsDirectory() && omode & O_RWMASK) { @@ -1151,11 +1173,12 @@ bfs_close(void *_ns, void *_node, void *_cookie) file_cookie *cookie = (file_cookie *)_cookie; + Volume *volume = (Volume *)_ns; + Inode *inode = (Inode *)_node; + if (cookie->open_mode & O_RWMASK) { // trim the preallocated blocks and update the size, // and last_modified indices if needed - Volume *volume = (Volume *)_ns; - Inode *inode = (Inode *)_node; Transaction transaction(volume,inode->BlockNumber()); @@ -1173,6 +1196,11 @@ bfs_close(void *_ns, void *_node, void *_cookie) notify_listener(B_STAT_CHANGED,volume->ID(),0,0,inode->ID(),NULL); } + if (inode->Flags() & INODE_NO_CACHE) { + volume->Pool().ReleaseBuffers(); + inode->Node().flags &= ~INODE_NO_CACHE; + } + return B_OK; }