ext2: Fix enabling/disabling the file cache
* Inode: - Rename {Enable,Disable}FileCache() to {Create,Delete}FileCache() and IsFileCacheDisabled() to HasFileCache(), since that is what they actually do. DeleteFileCache() now also sets the attributes to NULL, which makes fCached superfluous. - Introduce {Enable,Disable}FileCache(), which actually enable/disable the file cache. Use those methods for handling O_NOCACHE. * ext2_free_cookie(): Reenable the file cache in case of O_NOCACHE. Fixes crash when O_NOCACHE was used, since the file cache was deleted without clearing the attribute and Inode::ReadAt() would use the deleted object afterward.
This commit is contained in:
parent
05826ec74b
commit
26aef3ac62
|
@ -37,7 +37,6 @@ Inode::Inode(Volume* volume, ino_t id)
|
|||
fID(id),
|
||||
fCache(NULL),
|
||||
fMap(NULL),
|
||||
fCached(false),
|
||||
fHasExtraAttributes(false)
|
||||
{
|
||||
rw_lock_init(&fLock, "ext2 inode");
|
||||
|
@ -56,11 +55,9 @@ Inode::Inode(Volume* volume, ino_t id)
|
|||
|
||||
if (IsDirectory() || (IsSymLink() && Size() < 60)) {
|
||||
TRACE("Inode::Inode(): Not creating the file cache\n");
|
||||
fCached = false;
|
||||
|
||||
fInitStatus = B_OK;
|
||||
} else
|
||||
fInitStatus = EnableFileCache();
|
||||
fInitStatus = CreateFileCache();
|
||||
} else
|
||||
TRACE("Inode: Failed initialization\n");
|
||||
}
|
||||
|
@ -72,7 +69,6 @@ Inode::Inode(Volume* volume)
|
|||
fID(0),
|
||||
fCache(NULL),
|
||||
fMap(NULL),
|
||||
fCached(false),
|
||||
fInitStatus(B_NO_INIT)
|
||||
{
|
||||
rw_lock_init(&fLock, "ext2 inode");
|
||||
|
@ -89,11 +85,7 @@ Inode::~Inode()
|
|||
{
|
||||
TRACE("Inode destructor\n");
|
||||
|
||||
if (fCached) {
|
||||
TRACE("Deleting the file cache and file map\n");
|
||||
file_cache_delete(FileCache());
|
||||
file_map_delete(Map());
|
||||
}
|
||||
DeleteFileCache();
|
||||
|
||||
TRACE("Inode destructor: Done\n");
|
||||
}
|
||||
|
@ -269,7 +261,7 @@ Inode::WriteAt(Transaction& transaction, off_t pos, const uint8* buffer,
|
|||
buffer, _length, *_length);
|
||||
ReadLocker readLocker(fLock);
|
||||
|
||||
if (IsFileCacheDisabled())
|
||||
if (!HasFileCache())
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (pos < 0)
|
||||
|
@ -697,7 +689,7 @@ Inode::Create(Transaction& transaction, Inode* parent, const char* name,
|
|||
if (!inode->IsSymLink()) {
|
||||
// Vnode::Publish doesn't publish symlinks
|
||||
if (!inode->IsDirectory()) {
|
||||
status = inode->EnableFileCache();
|
||||
status = inode->CreateFileCache();
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
}
|
||||
|
@ -726,31 +718,59 @@ Inode::Create(Transaction& transaction, Inode* parent, const char* name,
|
|||
|
||||
|
||||
status_t
|
||||
Inode::EnableFileCache()
|
||||
Inode::CreateFileCache()
|
||||
{
|
||||
TRACE("Inode::EnableFileCache()\n");
|
||||
TRACE("Inode::CreateFileCache()\n");
|
||||
|
||||
if (fCached)
|
||||
if (fCache != NULL)
|
||||
return B_OK;
|
||||
if (fCache != NULL) {
|
||||
fCached = true;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
TRACE("Inode::EnableFileCache(): Creating file cache: %" B_PRIu32 ", %"
|
||||
TRACE("Inode::CreateFileCache(): Creating file cache: %" B_PRIu32 ", %"
|
||||
B_PRIdINO ", %" B_PRIdOFF "\n", fVolume->ID(), ID(), Size());
|
||||
fCache = file_cache_create(fVolume->ID(), ID(), Size());
|
||||
fMap = file_map_create(fVolume->ID(), ID(), Size());
|
||||
|
||||
fCache = file_cache_create(fVolume->ID(), ID(), Size());
|
||||
if (fCache == NULL) {
|
||||
ERROR("Inode::EnableFileCache(): Failed to create file cache\n");
|
||||
fCached = false;
|
||||
ERROR("Inode::CreateFileCache(): Failed to create file cache\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
fCached = true;
|
||||
TRACE("Inode::EnableFileCache(): Done\n");
|
||||
fMap = file_map_create(fVolume->ID(), ID(), Size());
|
||||
if (fMap == NULL) {
|
||||
ERROR("Inode::CreateFileCache(): Failed to create file map\n");
|
||||
file_cache_delete(fCache);
|
||||
fCache = NULL;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
TRACE("Inode::CreateFileCache(): Done\n");
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Inode::DeleteFileCache()
|
||||
{
|
||||
TRACE("Inode::DeleteFileCache()\n");
|
||||
|
||||
if (fCache == NULL)
|
||||
return;
|
||||
|
||||
file_cache_delete(fCache);
|
||||
file_map_delete(fMap);
|
||||
|
||||
fCache = NULL;
|
||||
fMap = NULL;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Inode::EnableFileCache()
|
||||
{
|
||||
if (fCache == NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
file_cache_enable(fCache);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
@ -758,15 +778,9 @@ Inode::EnableFileCache()
|
|||
status_t
|
||||
Inode::DisableFileCache()
|
||||
{
|
||||
TRACE("Inode::DisableFileCache()\n");
|
||||
|
||||
if (!fCached)
|
||||
return B_OK;
|
||||
|
||||
file_cache_delete(FileCache());
|
||||
file_map_delete(Map());
|
||||
|
||||
fCached = false;
|
||||
status_t error = file_cache_disable(fCache);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
@ -775,7 +789,7 @@ Inode::DisableFileCache()
|
|||
status_t
|
||||
Inode::Sync()
|
||||
{
|
||||
if (!IsFileCacheDisabled())
|
||||
if (HasFileCache())
|
||||
return file_cache_sync(fCache);
|
||||
|
||||
return B_OK;
|
||||
|
|
|
@ -112,9 +112,11 @@ public:
|
|||
|
||||
void* FileCache() const { return fCache; }
|
||||
void* Map() const { return fMap; }
|
||||
status_t CreateFileCache();
|
||||
void DeleteFileCache();
|
||||
bool HasFileCache() { return fCache != NULL; }
|
||||
status_t EnableFileCache();
|
||||
status_t DisableFileCache();
|
||||
bool IsFileCacheDisabled() const { return !fCached; }
|
||||
|
||||
status_t Sync();
|
||||
|
||||
|
@ -144,7 +146,6 @@ private:
|
|||
ino_t fID;
|
||||
void* fCache;
|
||||
void* fMap;
|
||||
bool fCached;
|
||||
bool fUnlinked;
|
||||
bool fHasExtraAttributes;
|
||||
ext2_inode fNode;
|
||||
|
|
|
@ -39,12 +39,11 @@ InodeJournal::InodeJournal(Inode* inode)
|
|||
fJournalVolume = volume;
|
||||
fJournalBlockCache = volume->BlockCache();
|
||||
|
||||
if (!inode->IsFileCacheDisabled())
|
||||
fInitStatus = inode->DisableFileCache();
|
||||
else
|
||||
if (inode->HasFileCache())
|
||||
inode->DeleteFileCache();
|
||||
|
||||
fInitStatus = B_OK;
|
||||
|
||||
if (fInitStatus == B_OK) {
|
||||
TRACE("InodeJournal::InodeJournal(): Inode's file cache disabled "
|
||||
"successfully\n");
|
||||
HashRevokeManager* revokeManager = new(std::nothrow)
|
||||
|
@ -66,7 +65,6 @@ InodeJournal::InodeJournal(Inode* inode)
|
|||
delete revokeManager;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -759,7 +759,7 @@ ext2_create(fs_volume* _volume, fs_vnode* _directory, const char* name,
|
|||
|
||||
TRACE("ext2_create(): Created inode\n");
|
||||
|
||||
if ((openMode & O_NOCACHE) != 0 && !inode->IsFileCacheDisabled()) {
|
||||
if ((openMode & O_NOCACHE) != 0) {
|
||||
status = inode->DisableFileCache();
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
@ -830,8 +830,8 @@ ext2_create_symlink(fs_volume* _volume, fs_vnode* _directory, const char* name,
|
|||
link->Mode(), 0);
|
||||
put_vnode(volume->FSVolume(), id);
|
||||
|
||||
if (link->IsFileCacheDisabled()) {
|
||||
status = link->EnableFileCache();
|
||||
if (!link->HasFileCache()) {
|
||||
status = link->CreateFileCache();
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
}
|
||||
|
@ -1132,10 +1132,12 @@ ext2_open(fs_volume* _volume, fs_vnode* _node, int openMode, void** _cookie)
|
|||
cookie->last_size = inode->Size();
|
||||
cookie->last_notification = system_time();
|
||||
|
||||
MethodDeleter<Inode, status_t> fileCacheEnabler(&Inode::EnableFileCache);
|
||||
if ((openMode & O_NOCACHE) != 0) {
|
||||
status = inode->DisableFileCache();
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
fileCacheEnabler.SetTo(inode);
|
||||
}
|
||||
|
||||
// Should we truncate the file?
|
||||
|
@ -1157,6 +1159,7 @@ ext2_open(fs_volume* _volume, fs_vnode* _node, int openMode, void** _cookie)
|
|||
// TODO: No need to notify file size changed?
|
||||
}
|
||||
|
||||
fileCacheEnabler.Detach();
|
||||
cookieDeleter.Detach();
|
||||
*_cookie = cookie;
|
||||
|
||||
|
@ -1246,6 +1249,9 @@ ext2_free_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie)
|
|||
if (inode->Size() != cookie->last_size)
|
||||
notify_stat_changed(volume->ID(), inode->ID(), B_STAT_SIZE);
|
||||
|
||||
if ((cookie->open_mode & O_NOCACHE) != 0)
|
||||
inode->EnableFileCache();
|
||||
|
||||
delete cookie;
|
||||
return B_OK;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue