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
This commit is contained in:
Michael Lotz
2009-08-29 16:24:33 +00:00
parent 6a9eee5845
commit bd80259af5
@@ -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;
}