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
This commit is contained in:
Axel Dörfler 2002-08-08 01:23:04 +00:00
parent e57d105cfe
commit 40f7fd6cf3
5 changed files with 218 additions and 3 deletions

View File

@ -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 <stdlib.h>
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;
}

View File

@ -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 <OS.h>
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 */

View File

@ -19,5 +19,6 @@ R5KernelAddon obfs : [ FDirName kernel file_systems bfs ] :
Query.cpp
Utility.cpp
Volume.cpp
BufferPool.cpp
;

View File

@ -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

View File

@ -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;
}