Author: bonefish Date: 2010-07-19 17:31:08 +0200 (Mon, 19 Jul 2010) New Revision: 37601 Changeset: http://dev.haiku-os.org/changeset/37601 Added: haiku/trunk/src/tests/system/kernel/file_corruption/fs/Notifications.cpp haiku/trunk/src/tests/system/kernel/file_corruption/fs/Notifications.h Modified: haiku/trunk/src/tests/system/kernel/file_corruption/fs/File.cpp haiku/trunk/src/tests/system/kernel/file_corruption/fs/File.h haiku/trunk/src/tests/system/kernel/file_corruption/fs/Jamfile haiku/trunk/src/tests/system/kernel/file_corruption/fs/Node.cpp haiku/trunk/src/tests/system/kernel/file_corruption/fs/Node.h haiku/trunk/src/tests/system/kernel/file_corruption/fs/Transaction.cpp haiku/trunk/src/tests/system/kernel/file_corruption/fs/Transaction.h haiku/trunk/src/tests/system/kernel/file_corruption/fs/checksumfs.cpp Log: Added node monitoring support. Modified: haiku/trunk/src/tests/system/kernel/file_corruption/fs/File.cpp =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/fs/File.cpp 2010-07-19 15:24:36 UTC (rev 37600) +++ haiku/trunk/src/tests/system/kernel/file_corruption/fs/File.cpp 2010-07-19 15:31:08 UTC (rev 37601) @@ -169,8 +169,11 @@ 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 @@ error = transaction.Commit(); if (error != B_OK) RETURN_ERROR(error); + + _sizeChanged = true; } // now the file has the right size -- do the write Modified: haiku/trunk/src/tests/system/kernel/file_corruption/fs/File.h =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/fs/File.h 2010-07-19 15:24:36 UTC (rev 37600) +++ haiku/trunk/src/tests/system/kernel/file_corruption/fs/File.h 2010-07-19 15:31:08 UTC (rev 37601) @@ -28,7 +28,8 @@ 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); Modified: haiku/trunk/src/tests/system/kernel/file_corruption/fs/Jamfile =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/fs/Jamfile 2010-07-19 15:24:36 UTC (rev 37600) +++ haiku/trunk/src/tests/system/kernel/file_corruption/fs/Jamfile 2010-07-19 15:31:08 UTC (rev 37601) @@ -22,6 +22,7 @@ Directory.cpp File.cpp Node.cpp + Notifications.cpp SuperBlock.cpp SymLink.cpp Transaction.cpp Modified: haiku/trunk/src/tests/system/kernel/file_corruption/fs/Node.cpp =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/fs/Node.cpp 2010-07-19 15:24:36 UTC (rev 37600) +++ haiku/trunk/src/tests/system/kernel/file_corruption/fs/Node.cpp 2010-07-19 15:31:08 UTC (rev 37601) @@ -99,7 +99,8 @@ 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); } Modified: haiku/trunk/src/tests/system/kernel/file_corruption/fs/Node.h =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/fs/Node.h 2010-07-19 15:24:36 UTC (rev 37600) +++ haiku/trunk/src/tests/system/kernel/file_corruption/fs/Node.h 2010-07-19 15:31:08 UTC (rev 37601) @@ -42,7 +42,8 @@ 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; } Added: haiku/trunk/src/tests/system/kernel/file_corruption/fs/Notifications.cpp =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/fs/Notifications.cpp (rev 0) +++ haiku/trunk/src/tests/system/kernel/file_corruption/fs/Notifications.cpp 2010-07-19 15:31:08 UTC (rev 37601) @@ -0,0 +1,117 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@xxxxxxx + * 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); +} Added: haiku/trunk/src/tests/system/kernel/file_corruption/fs/Notifications.h =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/fs/Notifications.h (rev 0) +++ haiku/trunk/src/tests/system/kernel/file_corruption/fs/Notifications.h 2010-07-19 15:31:08 UTC (rev 37601) @@ -0,0 +1,88 @@ +/* + * Copyright 2010, Ingo Weinhold, ingo_weinhold@xxxxxxx + * 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 Modified: haiku/trunk/src/tests/system/kernel/file_corruption/fs/Transaction.cpp =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/fs/Transaction.cpp 2010-07-19 15:24:36 UTC (rev 37600) +++ haiku/trunk/src/tests/system/kernel/file_corruption/fs/Transaction.cpp 2010-07-19 15:31:08 UTC (rev 37601) @@ -71,7 +71,7 @@ status_t -Transaction::Commit() +Transaction::Commit(const PostCommitNotification* notification) { ASSERT(fID >= 0); @@ -93,6 +93,10 @@ return error; } + // send notifications + if (notification != NULL) + notification->NotifyPostCommit(); + // clean up _DeleteNodeInfosAndUnlock(false); @@ -206,3 +210,12 @@ delete info; } } + + + +// #pragma mark - PostCommitNotification + + +PostCommitNotification::~PostCommitNotification() +{ +} Modified: haiku/trunk/src/tests/system/kernel/file_corruption/fs/Transaction.h =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/fs/Transaction.h 2010-07-19 15:24:36 UTC (rev 37600) +++ haiku/trunk/src/tests/system/kernel/file_corruption/fs/Transaction.h 2010-07-19 15:31:08 UTC (rev 37601) @@ -13,6 +13,7 @@ #include "Node.h" +class PostCommitNotification; class Volume; @@ -32,7 +33,11 @@ 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 @@ }; +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 Modified: haiku/trunk/src/tests/system/kernel/file_corruption/fs/checksumfs.cpp =================================================================== --- haiku/trunk/src/tests/system/kernel/file_corruption/fs/checksumfs.cpp 2010-07-19 15:24:36 UTC (rev 37600) +++ haiku/trunk/src/tests/system/kernel/file_corruption/fs/checksumfs.cpp 2010-07-19 15:31:08 UTC (rev 37601) @@ -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,18 +37,100 @@ 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 @@ } // commit the transaction - return transaction.Commit(); + return transaction.Commit(EntryRemovedNotification(directory, name, + childNode)); } @@ -723,7 +808,8 @@ directory->Touched(NODE_MODIFIED); // commit the transaction - return transaction.Commit(); + return transaction.Commit(EntryCreatedNotification(directory, name, + newSymLink)); } @@ -773,7 +859,7 @@ directory->Touched(NODE_MODIFIED); // commit the transaction - return transaction.Commit(); + return transaction.Commit(EntryCreatedNotification(directory, name, node)); } @@ -896,7 +982,8 @@ toDirectory->Touched(NODE_MODIFIED); // commit the transaction - return transaction.Commit(); + return transaction.Commit(EntryMovedNotification(fromDirectory, fromName, + toDirectory, toName, node)); } @@ -1027,7 +1114,7 @@ node->Touched(NODE_ACCESSED); // commit the transaction - return transaction.Commit(); + return transaction.Commit(StatChangedNotification(node, statMask)); } @@ -1231,7 +1318,8 @@ 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 @@ 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 @@ // 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 @@ directory->Touched(NODE_MODIFIED); // commit the transaction - return transaction.Commit(); + return transaction.Commit(EntryCreatedNotification(directory, name, + newDirectory)); }