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:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user