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:
parent
e57d105cfe
commit
40f7fd6cf3
151
src/add-ons/kernel/file_systems/bfs/BufferPool.cpp
Normal file
151
src/add-ons/kernel/file_systems/bfs/BufferPool.cpp
Normal 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;
|
||||
}
|
||||
|
31
src/add-ons/kernel/file_systems/bfs/BufferPool.h
Normal file
31
src/add-ons/kernel/file_systems/bfs/BufferPool.h
Normal 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 */
|
@ -19,5 +19,6 @@ R5KernelAddon obfs : [ FDirName kernel file_systems bfs ] :
|
||||
Query.cpp
|
||||
Utility.cpp
|
||||
Volume.cpp
|
||||
BufferPool.cpp
|
||||
;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user