ramfs: Rework NodeMTimeUpdater into NodeStatChangeNotifier.
This now does what notify_if_stat_changed used to, fixing a race: if some thread was modifying a file, and some other thread (or the same thread, in some other mtime-updating operation) updated that file and this called MarkUnmodified() before the first thread close()d it, then when the first thread called close(), no node monitor notification would've been sent, as fModified would've already been unset. So, now every time we are to mark a file "unmodified", we also send the node monitor notification at the same time. Fixes the remainder of #19910.
This commit is contained in:
@@ -135,6 +135,19 @@ Node::SetMTime(time_t mTime)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32
|
||||||
|
Node::MarkUnmodified()
|
||||||
|
{
|
||||||
|
uint32 modified = fModified;
|
||||||
|
if (modified) {
|
||||||
|
fCTime = time(NULL);
|
||||||
|
SetMTime(fCTime);
|
||||||
|
fModified = 0;
|
||||||
|
}
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Node::CheckPermissions(int mode) const
|
Node::CheckPermissions(int mode) const
|
||||||
{
|
{
|
||||||
@@ -317,3 +330,20 @@ Node::GetAllocationInfo(AllocationInfo &info)
|
|||||||
while (GetNextAttribute(&attribute) == B_OK)
|
while (GetNextAttribute(&attribute) == B_OK)
|
||||||
attribute->GetAllocationInfo(info);
|
attribute->GetAllocationInfo(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NodeStatChangeNotifier::~NodeStatChangeNotifier()
|
||||||
|
{
|
||||||
|
if (fNode == NULL || !fNode->IsModified())
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint32 statFields = fNode->MarkUnmodified();
|
||||||
|
for (Entry* entry = fNode->GetFirstReferrer(); entry != NULL;
|
||||||
|
entry = fNode->GetNextReferrer(entry)) {
|
||||||
|
ino_t parentID = -1;
|
||||||
|
if (entry->GetParent() != NULL)
|
||||||
|
parentID = ((Node*)entry->GetParent())->GetID();
|
||||||
|
notify_stat_changed(fNode->GetVolume()->GetID(), parentID,
|
||||||
|
fNode->GetID(), statFields);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -129,32 +129,15 @@ protected:
|
|||||||
DoublyLinkedList<Entry, GetNodeReferrerLink> fReferrers;
|
DoublyLinkedList<Entry, GetNodeReferrerLink> fReferrers;
|
||||||
};
|
};
|
||||||
|
|
||||||
// MarkUnmodified
|
|
||||||
inline
|
|
||||||
uint32
|
|
||||||
Node::MarkUnmodified()
|
|
||||||
{
|
|
||||||
uint32 modified = fModified;
|
|
||||||
if (modified) {
|
|
||||||
fCTime = time(NULL);
|
|
||||||
SetMTime(fCTime);
|
|
||||||
fModified = 0;
|
|
||||||
}
|
|
||||||
return modified;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NodeMTimeUpdater
|
class NodeStatChangeNotifier {
|
||||||
class NodeMTimeUpdater {
|
|
||||||
public:
|
public:
|
||||||
NodeMTimeUpdater(Node *node) : fNode(node) {}
|
NodeStatChangeNotifier(Node *node) : fNode(node) {}
|
||||||
~NodeMTimeUpdater()
|
~NodeStatChangeNotifier();
|
||||||
{
|
|
||||||
if (fNode && fNode->IsModified())
|
|
||||||
fNode->MarkUnmodified();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Node *fNode;
|
Node *fNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // NODE_H
|
#endif // NODE_H
|
||||||
|
|||||||
@@ -68,23 +68,6 @@ static const size_t kOptimalIOSize = 65536;
|
|||||||
static const bigtime_t kNotificationInterval = 1000000LL;
|
static const bigtime_t kNotificationInterval = 1000000LL;
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
notify_if_stat_changed(Volume *volume, Node *node)
|
|
||||||
{
|
|
||||||
if (volume == NULL || node == NULL || !node->IsModified())
|
|
||||||
return;
|
|
||||||
|
|
||||||
uint32 statFields = node->MarkUnmodified();
|
|
||||||
for (Entry* entry = node->GetFirstReferrer(); entry != NULL;
|
|
||||||
entry = node->GetNextReferrer(entry)) {
|
|
||||||
ino_t parentID = -1;
|
|
||||||
if (entry->GetParent() != NULL)
|
|
||||||
parentID = entry->GetParent()->GetID();
|
|
||||||
notify_stat_changed(volume->GetID(), parentID, node->GetID(), statFields);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - FS
|
// #pragma mark - FS
|
||||||
|
|
||||||
|
|
||||||
@@ -418,7 +401,7 @@ ramfs_create_symlink(fs_volume* _volume, fs_vnode* _dir, const char *name,
|
|||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
status_t error = B_OK;
|
status_t error = B_OK;
|
||||||
NodeMTimeUpdater mTimeUpdater(dir);
|
NodeStatChangeNotifier statNotifier(dir);
|
||||||
// directory deleted?
|
// directory deleted?
|
||||||
bool removed;
|
bool removed;
|
||||||
if (get_vnode_removed(volume->FSVolume(), dir->GetID(), &removed)
|
if (get_vnode_removed(volume->FSVolume(), dir->GetID(), &removed)
|
||||||
@@ -448,7 +431,7 @@ ramfs_create_symlink(fs_volume* _volume, fs_vnode* _dir, const char *name,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeMTimeUpdater mTimeUpdater2(node);
|
NodeStatChangeNotifier statNotifier2(node);
|
||||||
// notify listeners
|
// notify listeners
|
||||||
if (error == B_OK) {
|
if (error == B_OK) {
|
||||||
notify_entry_created(volume->GetID(), dir->GetID(), name,
|
notify_entry_created(volume->GetID(), dir->GetID(), name,
|
||||||
@@ -476,7 +459,7 @@ ramfs_link(fs_volume* _volume, fs_vnode* _dir, const char *name,
|
|||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
status_t error = B_OK;
|
status_t error = B_OK;
|
||||||
NodeMTimeUpdater mTimeUpdater(dir);
|
NodeStatChangeNotifier statNotifier(dir);
|
||||||
// directory deleted?
|
// directory deleted?
|
||||||
bool removed;
|
bool removed;
|
||||||
if (get_vnode_removed(volume->FSVolume(), dir->GetID(), &removed)
|
if (get_vnode_removed(volume->FSVolume(), dir->GetID(), &removed)
|
||||||
@@ -522,7 +505,7 @@ ramfs_unlink(fs_volume* _volume, fs_vnode* _dir, const char *name)
|
|||||||
if (!locker.IsLocked())
|
if (!locker.IsLocked())
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
NodeMTimeUpdater mTimeUpdater(dir);
|
NodeStatChangeNotifier statNotifier(dir);
|
||||||
// check directory write permissions
|
// check directory write permissions
|
||||||
error = dir->CheckPermissions(W_OK);
|
error = dir->CheckPermissions(W_OK);
|
||||||
ino_t nodeID = -1;
|
ino_t nodeID = -1;
|
||||||
@@ -568,8 +551,8 @@ ramfs_rename(fs_volume* _volume, fs_vnode* _oldDir, const char *oldName,
|
|||||||
|
|
||||||
status_t error = B_OK;
|
status_t error = B_OK;
|
||||||
|
|
||||||
NodeMTimeUpdater mTimeUpdater1(oldDir);
|
NodeStatChangeNotifier statNotifier1(oldDir);
|
||||||
NodeMTimeUpdater mTimeUpdater2(newDir);
|
NodeStatChangeNotifier statNotifier2(newDir);
|
||||||
|
|
||||||
// target directory deleted?
|
// target directory deleted?
|
||||||
bool removed;
|
bool removed;
|
||||||
@@ -733,7 +716,7 @@ ramfs_write_stat(fs_volume* _volume, fs_vnode* _node, const struct stat *st,
|
|||||||
mask, st) != B_OK)
|
mask, st) != B_OK)
|
||||||
RETURN_ERROR(B_NOT_ALLOWED);
|
RETURN_ERROR(B_NOT_ALLOWED);
|
||||||
|
|
||||||
NodeMTimeUpdater mTimeUpdater(node);
|
NodeStatChangeNotifier statNotifier(node);
|
||||||
status_t error = B_OK;
|
status_t error = B_OK;
|
||||||
|
|
||||||
if ((mask & B_STAT_SIZE) != 0)
|
if ((mask & B_STAT_SIZE) != 0)
|
||||||
@@ -759,10 +742,6 @@ ramfs_write_stat(fs_volume* _volume, fs_vnode* _node, const struct stat *st,
|
|||||||
node->SetCrTime(st->st_crtime);
|
node->SetCrTime(st->st_crtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// notify listeners
|
|
||||||
if (error == B_OK)
|
|
||||||
notify_if_stat_changed(volume, node);
|
|
||||||
|
|
||||||
RETURN_ERROR(error);
|
RETURN_ERROR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -814,7 +793,7 @@ ramfs_create(fs_volume* _volume, fs_vnode* _dir, const char *name, int openMode,
|
|||||||
if (!locker.IsLocked())
|
if (!locker.IsLocked())
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
NodeMTimeUpdater mTimeUpdater(dir);
|
NodeStatChangeNotifier statNotifier(dir);
|
||||||
status_t error = B_OK;
|
status_t error = B_OK;
|
||||||
|
|
||||||
// directory deleted?
|
// directory deleted?
|
||||||
@@ -879,7 +858,7 @@ ramfs_create(fs_volume* _volume, fs_vnode* _dir, const char *name, int openMode,
|
|||||||
else if (cookie)
|
else if (cookie)
|
||||||
delete cookie;
|
delete cookie;
|
||||||
}
|
}
|
||||||
NodeMTimeUpdater mTimeUpdater2(node);
|
NodeStatChangeNotifier statNotifier2(node);
|
||||||
// notify listeners
|
// notify listeners
|
||||||
if (error == B_OK)
|
if (error == B_OK)
|
||||||
notify_entry_created(volume->GetID(), dir->GetID(), name, *vnid);
|
notify_entry_created(volume->GetID(), dir->GetID(), name, *vnid);
|
||||||
@@ -906,7 +885,7 @@ ramfs_create_special_node(fs_volume *_volume, fs_vnode *_dir, const char *name,
|
|||||||
if (!locker.IsLocked())
|
if (!locker.IsLocked())
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
NodeMTimeUpdater mTimeUpdater(dir);
|
NodeStatChangeNotifier statNotifier(dir);
|
||||||
status_t error = B_OK;
|
status_t error = B_OK;
|
||||||
|
|
||||||
// directory deleted?
|
// directory deleted?
|
||||||
@@ -944,7 +923,7 @@ ramfs_create_special_node(fs_volume *_volume, fs_vnode *_dir, const char *name,
|
|||||||
RETURN_ERROR(error);
|
RETURN_ERROR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeMTimeUpdater mTimeUpdater2(node);
|
NodeStatChangeNotifier statNotifier2(node);
|
||||||
|
|
||||||
// notify listeners
|
// notify listeners
|
||||||
notify_entry_created(volume->GetID(), dir->GetID(), name, *vnid);
|
notify_entry_created(volume->GetID(), dir->GetID(), name, *vnid);
|
||||||
@@ -989,7 +968,7 @@ ramfs_open(fs_volume* _volume, fs_vnode* _node, int openMode, void** _cookie)
|
|||||||
VolumeWriteLocker writeLocker(volume);
|
VolumeWriteLocker writeLocker(volume);
|
||||||
|
|
||||||
error = node->SetSize(0);
|
error = node->SetSize(0);
|
||||||
NodeMTimeUpdater mTimeUpdater(node);
|
NodeStatChangeNotifier statNotifier(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set result / cleanup on failure
|
// set result / cleanup on failure
|
||||||
@@ -1011,15 +990,12 @@ ramfs_close(fs_volume* _volume, fs_vnode* _node, void* /*cookie*/)
|
|||||||
|
|
||||||
FUNCTION(("node: %lld\n", node->GetID()));
|
FUNCTION(("node: %lld\n", node->GetID()));
|
||||||
|
|
||||||
VolumeReadLocker locker(volume);
|
VolumeWriteLocker locker(volume);
|
||||||
if (!locker.IsLocked())
|
if (!locker.IsLocked())
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
status_t error = B_OK;
|
NodeStatChangeNotifier _(node);
|
||||||
// notify listeners
|
return B_OK;
|
||||||
notify_if_stat_changed(volume, node);
|
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1103,9 +1079,9 @@ ramfs_write(fs_volume* _volume, fs_vnode* _node, void* _cookie, off_t pos,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// notify listeners
|
// notify listeners
|
||||||
if (error == B_OK && cookie->NotificationIntervalElapsed(true))
|
if (error == B_OK && cookie->NotificationIntervalElapsed(true)) {
|
||||||
notify_if_stat_changed(volume, node);
|
NodeStatChangeNotifier _(node);
|
||||||
NodeMTimeUpdater mTimeUpdater(node);
|
}
|
||||||
RETURN_ERROR(error);
|
RETURN_ERROR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1210,7 +1186,7 @@ ramfs_create_dir(fs_volume* _volume, fs_vnode* _dir, const char *name, int mode)
|
|||||||
if (!locker.IsLocked())
|
if (!locker.IsLocked())
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
NodeMTimeUpdater mTimeUpdater(dir);
|
NodeStatChangeNotifier statNotifier(dir);
|
||||||
// directory deleted?
|
// directory deleted?
|
||||||
bool removed;
|
bool removed;
|
||||||
status_t error = B_OK;
|
status_t error = B_OK;
|
||||||
@@ -1241,7 +1217,7 @@ ramfs_create_dir(fs_volume* _volume, fs_vnode* _dir, const char *name, int mode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NodeMTimeUpdater mTimeUpdater2(node);
|
NodeStatChangeNotifier statNotifier2(node);
|
||||||
// notify listeners
|
// notify listeners
|
||||||
if (error == B_OK) {
|
if (error == B_OK) {
|
||||||
notify_entry_created(volume->GetID(), dir->GetID(), name,
|
notify_entry_created(volume->GetID(), dir->GetID(), name,
|
||||||
@@ -1268,7 +1244,7 @@ ramfs_remove_dir(fs_volume* _volume, fs_vnode* _dir, const char *name)
|
|||||||
if (!locker.IsLocked())
|
if (!locker.IsLocked())
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
NodeMTimeUpdater mTimeUpdater(dir);
|
NodeStatChangeNotifier statNotifier(dir);
|
||||||
// check directory write permissions
|
// check directory write permissions
|
||||||
status_t error = dir->CheckPermissions(W_OK);
|
status_t error = dir->CheckPermissions(W_OK);
|
||||||
ino_t nodeID = -1;
|
ino_t nodeID = -1;
|
||||||
@@ -1638,7 +1614,7 @@ ramfs_create_attr(fs_volume* _volume, fs_vnode* _node, const char *name,
|
|||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
NodeMTimeUpdater mTimeUpdater(node);
|
NodeStatChangeNotifier statNotifier(node);
|
||||||
|
|
||||||
// success
|
// success
|
||||||
cookieDeleter.Detach();
|
cookieDeleter.Detach();
|
||||||
@@ -1689,7 +1665,7 @@ ramfs_open_attr(fs_volume* _volume, fs_vnode* _node, const char *name,
|
|||||||
// truncate if requested
|
// truncate if requested
|
||||||
if (error == B_OK && (openMode & O_TRUNC))
|
if (error == B_OK && (openMode & O_TRUNC))
|
||||||
error = attribute->SetSize(0);
|
error = attribute->SetSize(0);
|
||||||
NodeMTimeUpdater mTimeUpdater(node);
|
NodeStatChangeNotifier statNotifier(node);
|
||||||
|
|
||||||
// set result / cleanup on failure
|
// set result / cleanup on failure
|
||||||
if (error == B_OK)
|
if (error == B_OK)
|
||||||
@@ -1713,8 +1689,7 @@ ramfs_close_attr(fs_volume* _volume, fs_vnode* _node, void* _cookie)
|
|||||||
if (!locker.IsLocked())
|
if (!locker.IsLocked())
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
// notify listeners
|
NodeStatChangeNotifier _(node);
|
||||||
notify_if_stat_changed(volume, node);
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1788,7 +1763,7 @@ ramfs_write_attr(fs_volume* _volume, fs_vnode* _node, void* _cookie,
|
|||||||
if (!locker.IsLocked())
|
if (!locker.IsLocked())
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
NodeMTimeUpdater mTimeUpdater(node);
|
NodeStatChangeNotifier statNotifier(node);
|
||||||
|
|
||||||
// find the attribute
|
// find the attribute
|
||||||
Attribute *attribute = NULL;
|
Attribute *attribute = NULL;
|
||||||
@@ -1864,7 +1839,7 @@ ramfs_remove_attr(fs_volume* _volume, fs_vnode* _node, const char *name)
|
|||||||
if (!locker.IsLocked())
|
if (!locker.IsLocked())
|
||||||
RETURN_ERROR(B_ERROR);
|
RETURN_ERROR(B_ERROR);
|
||||||
|
|
||||||
NodeMTimeUpdater mTimeUpdater(node);
|
NodeStatChangeNotifier statNotifier(node);
|
||||||
|
|
||||||
// check permissions
|
// check permissions
|
||||||
error = node->CheckPermissions(W_OK);
|
error = node->CheckPermissions(W_OK);
|
||||||
|
|||||||
Reference in New Issue
Block a user