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
This commit is contained in:
Ingo Weinhold 2010-07-19 13:58:03 +00:00
parent d869a06172
commit 4b53c2ba4f
9 changed files with 250 additions and 103 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -52,3 +52,10 @@ SuperBlock::SetFreeBlocks(uint64 count)
{
freeBlocks = count;
}
void
SuperBlock::SetName(const char* name)
{
strlcpy(this->name, name, kCheckSumFSNameLength);
}

View File

@ -25,6 +25,7 @@ public:
void Initialize(Volume* volume);
void SetFreeBlocks(uint64 count);
void SetName(const char* name);
};

View File

@ -17,6 +17,9 @@
#include <fs_cache.h>
#include <AutoDeleter.h>
#include <util/AutoLock.h>
#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)
{

View File

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

View File

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