Added node monitoring support.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37601 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
cc2a443dbd
commit
e828231248
@ -169,8 +169,11 @@ File::Read(off_t pos, void* buffer, size_t size, size_t& _bytesRead)
|
||||
|
||||
|
||||
status_t
|
||||
File::Write(off_t pos, const void* buffer, size_t size, size_t& _bytesWritten)
|
||||
File::Write(off_t pos, const void* buffer, size_t size, size_t& _bytesWritten,
|
||||
bool& _sizeChanged)
|
||||
{
|
||||
_sizeChanged = false;
|
||||
|
||||
if (size == 0) {
|
||||
_bytesWritten = 0;
|
||||
return B_OK;
|
||||
@ -208,6 +211,8 @@ File::Write(off_t pos, const void* buffer, size_t size, size_t& _bytesWritten)
|
||||
error = transaction.Commit();
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
_sizeChanged = true;
|
||||
}
|
||||
|
||||
// now the file has the right size -- do the write
|
||||
|
@ -28,7 +28,8 @@ public:
|
||||
virtual status_t Read(off_t pos, void* buffer, size_t size,
|
||||
size_t& _bytesRead);
|
||||
virtual status_t Write(off_t pos, const void* buffer,
|
||||
size_t size, size_t& _bytesWritten);
|
||||
size_t size, size_t& _bytesWritten,
|
||||
bool& _sizeChanged);
|
||||
virtual status_t Sync();
|
||||
|
||||
virtual void RevertNodeData(const checksumfs_node& nodeData);
|
||||
|
@ -22,6 +22,7 @@ HAIKU_CHECKSUM_FS_SOURCES =
|
||||
Directory.cpp
|
||||
File.cpp
|
||||
Node.cpp
|
||||
Notifications.cpp
|
||||
SuperBlock.cpp
|
||||
SymLink.cpp
|
||||
Transaction.cpp
|
||||
|
@ -99,7 +99,8 @@ Node::Read(off_t pos, void* buffer, size_t size, size_t& _bytesRead)
|
||||
|
||||
|
||||
status_t
|
||||
Node::Write(off_t pos, const void* buffer, size_t size, size_t& _bytesWritten)
|
||||
Node::Write(off_t pos, const void* buffer, size_t size, size_t& _bytesWritten,
|
||||
bool& _sizeChanged)
|
||||
{
|
||||
RETURN_ERROR(B_BAD_VALUE);
|
||||
}
|
||||
|
@ -42,7 +42,8 @@ public:
|
||||
virtual status_t Read(off_t pos, void* buffer, size_t size,
|
||||
size_t& _bytesRead);
|
||||
virtual status_t Write(off_t pos, const void* buffer,
|
||||
size_t size, size_t& _bytesWritten);
|
||||
size_t size, size_t& _bytesWritten,
|
||||
bool& _sizeChanged);
|
||||
virtual status_t Sync();
|
||||
|
||||
inline const checksumfs_node& NodeData() const { return fNode; }
|
||||
|
117
src/tests/system/kernel/file_corruption/fs/Notifications.cpp
Normal file
117
src/tests/system/kernel/file_corruption/fs/Notifications.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "Notifications.h"
|
||||
|
||||
#include "Directory.h"
|
||||
#include "Volume.h"
|
||||
|
||||
|
||||
// #pragma mark - EntryCreatedNotification
|
||||
|
||||
|
||||
EntryCreatedNotification::EntryCreatedNotification(Directory* directory,
|
||||
const char* name, Node* node)
|
||||
:
|
||||
fDirectory(directory),
|
||||
fName(name),
|
||||
fNode(node)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EntryCreatedNotification::NotifyPostCommit() const
|
||||
{
|
||||
notify_entry_created(fDirectory->GetVolume()->ID(),
|
||||
fDirectory->BlockIndex(), fName, fNode->BlockIndex());
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - EntryRemovedNotification
|
||||
|
||||
|
||||
EntryRemovedNotification::EntryRemovedNotification(Directory* directory,
|
||||
const char* name, Node* node)
|
||||
:
|
||||
fDirectory(directory),
|
||||
fName(name),
|
||||
fNode(node)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EntryRemovedNotification::NotifyPostCommit() const
|
||||
{
|
||||
notify_entry_removed(fDirectory->GetVolume()->ID(),
|
||||
fDirectory->BlockIndex(), fName, fNode->BlockIndex());
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - EntryMovedNotification
|
||||
|
||||
|
||||
EntryMovedNotification::EntryMovedNotification(Directory* fromDirectory,
|
||||
const char* fromName, Directory* toDirectory, const char* toName,
|
||||
Node* node)
|
||||
:
|
||||
fFromDirectory(fromDirectory),
|
||||
fFromName(fromName),
|
||||
fToDirectory(toDirectory),
|
||||
fToName(toName),
|
||||
fNode(node)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EntryMovedNotification::NotifyPostCommit() const
|
||||
{
|
||||
notify_entry_moved(fFromDirectory->GetVolume()->ID(),
|
||||
fFromDirectory->BlockIndex(), fFromName, fToDirectory->BlockIndex(),
|
||||
fToName, fNode->BlockIndex());
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - StatChangedNotification
|
||||
|
||||
|
||||
StatChangedNotification::StatChangedNotification(Node* node, uint32 statFields)
|
||||
:
|
||||
fNode(node),
|
||||
fStatFields(statFields)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StatChangedNotification::NotifyPostCommit() const
|
||||
{
|
||||
notify_stat_changed(fNode->GetVolume()->ID(), fNode->BlockIndex(),
|
||||
fStatFields);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - AttributeChangedNotification
|
||||
|
||||
|
||||
AttributeChangedNotification::AttributeChangedNotification(Node* node,
|
||||
const char* attribute, int32 cause)
|
||||
:
|
||||
fNode(node),
|
||||
fAttribute(attribute),
|
||||
fCause(cause)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AttributeChangedNotification::NotifyPostCommit() const
|
||||
{
|
||||
notify_attribute_changed(fNode->GetVolume()->ID(), fNode->BlockIndex(),
|
||||
fAttribute, fCause);
|
||||
}
|
88
src/tests/system/kernel/file_corruption/fs/Notifications.h
Normal file
88
src/tests/system/kernel/file_corruption/fs/Notifications.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef NOTIFICATIONS_H
|
||||
#define NOTIFICATIONS_H
|
||||
|
||||
|
||||
#include "Transaction.h"
|
||||
|
||||
|
||||
class Directory;
|
||||
|
||||
|
||||
class EntryCreatedNotification : public PostCommitNotification {
|
||||
public:
|
||||
EntryCreatedNotification(Directory* directory,
|
||||
const char* name, Node* node);
|
||||
|
||||
virtual void NotifyPostCommit() const;
|
||||
|
||||
private:
|
||||
Directory* fDirectory;
|
||||
const char* fName;
|
||||
Node* fNode;
|
||||
};
|
||||
|
||||
|
||||
class EntryRemovedNotification : public PostCommitNotification {
|
||||
public:
|
||||
EntryRemovedNotification(Directory* directory,
|
||||
const char* name, Node* node);
|
||||
|
||||
virtual void NotifyPostCommit() const;
|
||||
|
||||
private:
|
||||
Directory* fDirectory;
|
||||
const char* fName;
|
||||
Node* fNode;
|
||||
};
|
||||
|
||||
|
||||
class EntryMovedNotification : public PostCommitNotification {
|
||||
public:
|
||||
EntryMovedNotification(Directory* fromDirectory,
|
||||
const char* fromName,
|
||||
Directory* toDirectory, const char* toName,
|
||||
Node* node);
|
||||
|
||||
virtual void NotifyPostCommit() const;
|
||||
|
||||
private:
|
||||
Directory* fFromDirectory;
|
||||
const char* fFromName;
|
||||
Directory* fToDirectory;
|
||||
const char* fToName;
|
||||
Node* fNode;
|
||||
};
|
||||
|
||||
|
||||
class StatChangedNotification : public PostCommitNotification {
|
||||
public:
|
||||
StatChangedNotification(Node* node,
|
||||
uint32 statFields);
|
||||
|
||||
virtual void NotifyPostCommit() const;
|
||||
|
||||
private:
|
||||
Node* fNode;
|
||||
uint32 fStatFields;
|
||||
};
|
||||
|
||||
|
||||
class AttributeChangedNotification : public PostCommitNotification {
|
||||
public:
|
||||
AttributeChangedNotification(Node* node,
|
||||
const char* attribute, int32 cause);
|
||||
|
||||
virtual void NotifyPostCommit() const;
|
||||
|
||||
private:
|
||||
Node* fNode;
|
||||
const char* fAttribute;
|
||||
int32 fCause;
|
||||
};
|
||||
|
||||
|
||||
#endif // NOTIFICATIONS_H
|
@ -71,7 +71,7 @@ Transaction::StartAndAddNode(Node* node, uint32 flags = 0)
|
||||
|
||||
|
||||
status_t
|
||||
Transaction::Commit()
|
||||
Transaction::Commit(const PostCommitNotification* notification)
|
||||
{
|
||||
ASSERT(fID >= 0);
|
||||
|
||||
@ -93,6 +93,10 @@ Transaction::Commit()
|
||||
return error;
|
||||
}
|
||||
|
||||
// send notifications
|
||||
if (notification != NULL)
|
||||
notification->NotifyPostCommit();
|
||||
|
||||
// clean up
|
||||
_DeleteNodeInfosAndUnlock(false);
|
||||
|
||||
@ -206,3 +210,12 @@ Transaction::_DeleteNodeInfosAndUnlock(bool failed)
|
||||
delete info;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// #pragma mark - PostCommitNotification
|
||||
|
||||
|
||||
PostCommitNotification::~PostCommitNotification()
|
||||
{
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "Node.h"
|
||||
|
||||
|
||||
class PostCommitNotification;
|
||||
class Volume;
|
||||
|
||||
|
||||
@ -32,7 +33,11 @@ public:
|
||||
|
||||
status_t Start();
|
||||
status_t StartAndAddNode(Node* node, uint32 flags = 0);
|
||||
status_t Commit();
|
||||
status_t Commit(
|
||||
const PostCommitNotification* notification
|
||||
= NULL);
|
||||
inline status_t Commit(
|
||||
const PostCommitNotification& notification);
|
||||
void Abort();
|
||||
|
||||
status_t AddNode(Node* node, uint32 flags = 0);
|
||||
@ -62,4 +67,22 @@ private:
|
||||
};
|
||||
|
||||
|
||||
status_t
|
||||
Transaction::Commit(const PostCommitNotification& notification)
|
||||
{
|
||||
return Commit(¬ification);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
class PostCommitNotification {
|
||||
public:
|
||||
virtual ~PostCommitNotification();
|
||||
|
||||
virtual void NotifyPostCommit() const = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif // TRANSACTION_H
|
||||
|
@ -19,12 +19,14 @@
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include <debug.h>
|
||||
#include <util/AutoLock.h>
|
||||
|
||||
#include "checksumfs.h"
|
||||
#include "checksumfs_private.h"
|
||||
#include "DebugSupport.h"
|
||||
#include "Directory.h"
|
||||
#include "File.h"
|
||||
#include "Notifications.h"
|
||||
#include "SuperBlock.h"
|
||||
#include "SymLink.h"
|
||||
#include "Transaction.h"
|
||||
@ -35,17 +37,99 @@ static const char* const kCheckSumFSModuleName = "file_systems/checksumfs"
|
||||
B_CURRENT_FS_API_VERSION;
|
||||
static const char* const kCheckSumFSShortName = "checksumfs";
|
||||
|
||||
static const bigtime_t kModifiedInterimUpdateInterval = 500000;
|
||||
// wait at least 0.5s between interim modified updates
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
struct FileCookie {
|
||||
int openMode;
|
||||
mutex lock;
|
||||
int openMode;
|
||||
bigtime_t lastModifiedUpdate;
|
||||
bool modifiedNeedsUpdate;
|
||||
bool sizeChangedSinceUpdate;
|
||||
bool modifiedNeedsFinalUpdate;
|
||||
bool finalSizeChanged;
|
||||
|
||||
|
||||
FileCookie(int openMode)
|
||||
:
|
||||
openMode(openMode)
|
||||
openMode(openMode),
|
||||
lastModifiedUpdate(0),
|
||||
modifiedNeedsUpdate(false),
|
||||
sizeChangedSinceUpdate(false),
|
||||
modifiedNeedsFinalUpdate(false),
|
||||
finalSizeChanged(false)
|
||||
{
|
||||
mutex_init(&lock, "checksumfs file cookie");
|
||||
}
|
||||
|
||||
~FileCookie()
|
||||
{
|
||||
mutex_destroy(&lock);
|
||||
}
|
||||
|
||||
status_t UpdateModifiedIfNecessary(Node* node, bool finalUpdate)
|
||||
{
|
||||
MutexLocker locker(lock);
|
||||
|
||||
return _UpdateModifiedIfNecessary(node, finalUpdate);
|
||||
}
|
||||
|
||||
status_t FileModified(Node* node, bool sizeChanged)
|
||||
{
|
||||
MutexLocker locker(lock);
|
||||
|
||||
modifiedNeedsUpdate = true;
|
||||
modifiedNeedsFinalUpdate = true;
|
||||
sizeChangedSinceUpdate |= sizeChanged;
|
||||
finalSizeChanged |= sizeChanged;
|
||||
|
||||
return _UpdateModifiedIfNecessary(node, false);
|
||||
}
|
||||
|
||||
private:
|
||||
status_t _UpdateModifiedIfNecessary(Node* node, bool finalUpdate)
|
||||
{
|
||||
uint32 statFlags = B_STAT_MODIFICATION_TIME | B_STAT_CHANGE_TIME;
|
||||
|
||||
if (finalUpdate) {
|
||||
if (!modifiedNeedsFinalUpdate)
|
||||
return B_OK;
|
||||
if (finalSizeChanged)
|
||||
statFlags |= B_STAT_SIZE;
|
||||
} else {
|
||||
if (!modifiedNeedsUpdate)
|
||||
return B_OK;
|
||||
|
||||
if (system_time()
|
||||
< lastModifiedUpdate + kModifiedInterimUpdateInterval) {
|
||||
// not enough time passed -- postpone update
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
statFlags |= B_STAT_INTERIM_UPDATE
|
||||
| (sizeChangedSinceUpdate ? B_STAT_SIZE : 0);
|
||||
}
|
||||
|
||||
// do the update -- start a transaction, lock the node, and update
|
||||
Transaction transaction(node->GetVolume());
|
||||
status_t error = transaction.StartAndAddNode(node);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
node->Touched(NODE_MODIFIED);
|
||||
|
||||
error = transaction.Commit(StatChangedNotification(node, statFlags));
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
modifiedNeedsUpdate = false;
|
||||
lastModifiedUpdate = system_time();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
};
|
||||
|
||||
@ -308,7 +392,8 @@ remove_entry(fs_volume* fsVolume, fs_vnode* parent, const char* name,
|
||||
}
|
||||
|
||||
// commit the transaction
|
||||
return transaction.Commit();
|
||||
return transaction.Commit(EntryRemovedNotification(directory, name,
|
||||
childNode));
|
||||
}
|
||||
|
||||
|
||||
@ -723,7 +808,8 @@ checksumfs_create_symlink(fs_volume* fsVolume, fs_vnode* parent,
|
||||
directory->Touched(NODE_MODIFIED);
|
||||
|
||||
// commit the transaction
|
||||
return transaction.Commit();
|
||||
return transaction.Commit(EntryCreatedNotification(directory, name,
|
||||
newSymLink));
|
||||
}
|
||||
|
||||
|
||||
@ -773,7 +859,7 @@ checksumfs_link(fs_volume* fsVolume, fs_vnode* dir, const char* name,
|
||||
directory->Touched(NODE_MODIFIED);
|
||||
|
||||
// commit the transaction
|
||||
return transaction.Commit();
|
||||
return transaction.Commit(EntryCreatedNotification(directory, name, node));
|
||||
}
|
||||
|
||||
|
||||
@ -896,7 +982,8 @@ checksumfs_rename(fs_volume* fsVolume, fs_vnode* fromDir, const char* fromName,
|
||||
toDirectory->Touched(NODE_MODIFIED);
|
||||
|
||||
// commit the transaction
|
||||
return transaction.Commit();
|
||||
return transaction.Commit(EntryMovedNotification(fromDirectory, fromName,
|
||||
toDirectory, toName, node));
|
||||
}
|
||||
|
||||
|
||||
@ -1027,7 +1114,7 @@ checksumfs_write_stat(fs_volume* fsVolume, fs_vnode* vnode,
|
||||
node->Touched(NODE_ACCESSED);
|
||||
|
||||
// commit the transaction
|
||||
return transaction.Commit();
|
||||
return transaction.Commit(StatChangedNotification(node, statMask));
|
||||
}
|
||||
|
||||
|
||||
@ -1231,7 +1318,8 @@ checksumfs_create(fs_volume* fsVolume, fs_vnode* parent, const char* name,
|
||||
transaction.KeepNode(newFile);
|
||||
|
||||
// commit the transaction
|
||||
error = transaction.Commit();
|
||||
error = transaction.Commit(EntryCreatedNotification(directory, name,
|
||||
newFile));
|
||||
if (error != B_OK) {
|
||||
volume->RemoveNode(newFile);
|
||||
delete newFile;
|
||||
@ -1281,6 +1369,10 @@ static status_t
|
||||
checksumfs_free_cookie(fs_volume* fsVolume, fs_vnode* vnode, void* _cookie)
|
||||
{
|
||||
FileCookie* cookie = (FileCookie*)_cookie;
|
||||
Node* node = (Node*)vnode->private_node;
|
||||
|
||||
cookie->UpdateModifiedIfNecessary(node, true);
|
||||
|
||||
delete cookie;
|
||||
return B_OK;
|
||||
}
|
||||
@ -1330,8 +1422,16 @@ checksumfs_write(fs_volume* fsVolume, fs_vnode* vnode, void* _cookie, off_t pos,
|
||||
// special value handled by Write()
|
||||
}
|
||||
|
||||
RETURN_ERROR(node->Write(pos, buffer, *_length, *_length));
|
||||
// TODO: Modification time update!
|
||||
bool sizeChanged;
|
||||
status_t error = node->Write(pos, buffer, *_length, *_length, sizeChanged);
|
||||
if (error != B_OK)
|
||||
RETURN_ERROR(error);
|
||||
|
||||
// update the modification time and send out a notification from time to
|
||||
// time
|
||||
cookie->FileModified(node, sizeChanged);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -1384,7 +1484,8 @@ checksumfs_create_dir(fs_volume* fsVolume, fs_vnode* parent, const char* name,
|
||||
directory->Touched(NODE_MODIFIED);
|
||||
|
||||
// commit the transaction
|
||||
return transaction.Commit();
|
||||
return transaction.Commit(EntryCreatedNotification(directory, name,
|
||||
newDirectory));
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user