From bd80259af568280944308025226dba5bad2e70f0 Mon Sep 17 00:00:00 2001 From: Michael Lotz Date: Sat, 29 Aug 2009 16:24:33 +0000 Subject: [PATCH] If we create new nodes or modify existing ones, especially directories, we must ensure that these nodes are never put. As they keep all changes in memory, putting them and consequently freeing them destroys the modifications without a way to get them back from the underlaying filesystem. In case a created node was put but still had its entry in the parent directory this could also lead to the situation where an invalid node was requested from the underlaying filesystem, leading to #4347. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32815 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../layers/write_overlay/write_overlay.cpp | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/src/add-ons/kernel/file_systems/layers/write_overlay/write_overlay.cpp b/src/add-ons/kernel/file_systems/layers/write_overlay/write_overlay.cpp index 2f7c9d2d2a..49bdb8e48d 100644 --- a/src/add-ons/kernel/file_systems/layers/write_overlay/write_overlay.cpp +++ b/src/add-ons/kernel/file_systems/layers/write_overlay/write_overlay.cpp @@ -103,12 +103,14 @@ public: status_t InitCheck(); bool IsVirtual() { return fIsVirtual; } + bool IsModified() { return fIsModified; } fs_volume * Volume() { return fVolume->Volume(); } fs_volume * SuperVolume() { return fVolume->SuperVolume(); } fs_vnode * SuperVnode() { return &fSuperVnode; } ino_t InodeNumber() { return fInodeNumber; } + void SetModified(); void CreateCache(); void SetParentDir(OverlayInode *parentDir); @@ -167,6 +169,7 @@ private: bool fHasStat; bool fHasDirents; bool fIsVirtual; + bool fIsModified; void * fFileCache; }; @@ -202,6 +205,7 @@ OverlayInode::OverlayInode(OverlayVolume *volume, fs_vnode *superVnode, fHasStat(false), fHasDirents(false), fIsVirtual(superVnode == NULL), + fIsModified(false), fFileCache(NULL) { TRACE("inode created %lld\n", fInodeNumber); @@ -252,6 +256,19 @@ OverlayInode::InitCheck() } +void +OverlayInode::SetModified() +{ + // we must ensure that a modified node never get's put, as we cannot get it + // from the underlying filesystem, so we get an additional reference here + // and deliberately leak it + // TODO: what about non-force unmounting then? + void *unused = NULL; + get_vnode(Volume(), fInodeNumber, &unused); + fIsModified = true; +} + + void OverlayInode::CreateCache() { @@ -297,6 +314,8 @@ void OverlayInode::SetName(const char *name) { fName = name; + if (!fIsModified) + SetModified(); } @@ -370,6 +389,9 @@ OverlayInode::WriteStat(const struct stat *stat, uint32 statMask) statMask |= B_STAT_MODIFICATION_TIME; } + if (!fIsModified) + SetModified(); + notify_stat_changed(SuperVolume()->id, fInodeNumber, statMask); return B_OK; } @@ -422,8 +444,11 @@ OverlayInode::Open(int openMode, void **_cookie) fOriginalNodeLength = stat.st_size; } - if (openMode & O_TRUNC) + if (openMode & O_TRUNC) { fStat.st_size = 0; + if (!fIsModified) + SetModified(); + } openMode &= ~(O_RDWR | O_WRONLY | O_TRUNC | O_CREAT); status_t result = fSuperVnode.ops->open(SuperVolume(), &fSuperVnode, @@ -557,6 +582,9 @@ OverlayInode::Write(void *_cookie, off_t position, const void *buffer, position = fStat.st_size; } + if (!fIsModified) + SetModified(); + // find insertion point write_buffer **link = &fWriteBuffers; write_buffer *other = fWriteBuffers; @@ -787,6 +815,10 @@ OverlayInode::AddEntry(overlay_dirent *entry) fDirents = newDirents; fDirents[fDirentCount++] = entry; + + if (!fIsModified) + SetModified(); + return B_OK; } @@ -810,6 +842,9 @@ OverlayInode::RemoveEntry(const char *name, overlay_dirent **_entry) else entry->remove_and_dispose(Volume(), fInodeNumber); + if (!fIsModified) + SetModified(); + return B_OK; } } @@ -965,6 +1000,7 @@ OverlayInode::_CreateCommon(const char *name, int type, int perms, return result; } + node->SetModified(); node->CreateCache(); if (newInodeNumber != NULL) @@ -998,7 +1034,8 @@ overlay_put_vnode(fs_volume *volume, fs_vnode *vnode, bool reenter) { TRACE("put_vnode\n"); OverlayInode *node = (OverlayInode *)vnode->private_node; - if (node->IsVirtual()) { + if (node->IsVirtual() || node->IsModified()) { + panic("loosing virtual/modified node\n"); delete node; return B_OK; }