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),
|
fID(id),
|
||||||
fCache(NULL),
|
fCache(NULL),
|
||||||
fMap(NULL),
|
fMap(NULL),
|
||||||
fCached(false),
|
|
||||||
fHasExtraAttributes(false)
|
fHasExtraAttributes(false)
|
||||||
{
|
{
|
||||||
rw_lock_init(&fLock, "ext2 inode");
|
rw_lock_init(&fLock, "ext2 inode");
|
||||||
|
@ -56,11 +55,9 @@ Inode::Inode(Volume* volume, ino_t id)
|
||||||
|
|
||||||
if (IsDirectory() || (IsSymLink() && Size() < 60)) {
|
if (IsDirectory() || (IsSymLink() && Size() < 60)) {
|
||||||
TRACE("Inode::Inode(): Not creating the file cache\n");
|
TRACE("Inode::Inode(): Not creating the file cache\n");
|
||||||
fCached = false;
|
|
||||||
|
|
||||||
fInitStatus = B_OK;
|
fInitStatus = B_OK;
|
||||||
} else
|
} else
|
||||||
fInitStatus = EnableFileCache();
|
fInitStatus = CreateFileCache();
|
||||||
} else
|
} else
|
||||||
TRACE("Inode: Failed initialization\n");
|
TRACE("Inode: Failed initialization\n");
|
||||||
}
|
}
|
||||||
|
@ -72,7 +69,6 @@ Inode::Inode(Volume* volume)
|
||||||
fID(0),
|
fID(0),
|
||||||
fCache(NULL),
|
fCache(NULL),
|
||||||
fMap(NULL),
|
fMap(NULL),
|
||||||
fCached(false),
|
|
||||||
fInitStatus(B_NO_INIT)
|
fInitStatus(B_NO_INIT)
|
||||||
{
|
{
|
||||||
rw_lock_init(&fLock, "ext2 inode");
|
rw_lock_init(&fLock, "ext2 inode");
|
||||||
|
@ -89,11 +85,7 @@ Inode::~Inode()
|
||||||
{
|
{
|
||||||
TRACE("Inode destructor\n");
|
TRACE("Inode destructor\n");
|
||||||
|
|
||||||
if (fCached) {
|
DeleteFileCache();
|
||||||
TRACE("Deleting the file cache and file map\n");
|
|
||||||
file_cache_delete(FileCache());
|
|
||||||
file_map_delete(Map());
|
|
||||||
}
|
|
||||||
|
|
||||||
TRACE("Inode destructor: Done\n");
|
TRACE("Inode destructor: Done\n");
|
||||||
}
|
}
|
||||||
|
@ -269,7 +261,7 @@ Inode::WriteAt(Transaction& transaction, off_t pos, const uint8* buffer,
|
||||||
buffer, _length, *_length);
|
buffer, _length, *_length);
|
||||||
ReadLocker readLocker(fLock);
|
ReadLocker readLocker(fLock);
|
||||||
|
|
||||||
if (IsFileCacheDisabled())
|
if (!HasFileCache())
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
if (pos < 0)
|
if (pos < 0)
|
||||||
|
@ -697,7 +689,7 @@ Inode::Create(Transaction& transaction, Inode* parent, const char* name,
|
||||||
if (!inode->IsSymLink()) {
|
if (!inode->IsSymLink()) {
|
||||||
// Vnode::Publish doesn't publish symlinks
|
// Vnode::Publish doesn't publish symlinks
|
||||||
if (!inode->IsDirectory()) {
|
if (!inode->IsDirectory()) {
|
||||||
status = inode->EnableFileCache();
|
status = inode->CreateFileCache();
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -726,31 +718,59 @@ Inode::Create(Transaction& transaction, Inode* parent, const char* name,
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Inode::EnableFileCache()
|
Inode::CreateFileCache()
|
||||||
{
|
{
|
||||||
TRACE("Inode::EnableFileCache()\n");
|
TRACE("Inode::CreateFileCache()\n");
|
||||||
|
|
||||||
if (fCached)
|
if (fCache != NULL)
|
||||||
return B_OK;
|
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());
|
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) {
|
if (fCache == NULL) {
|
||||||
ERROR("Inode::EnableFileCache(): Failed to create file cache\n");
|
ERROR("Inode::CreateFileCache(): Failed to create file cache\n");
|
||||||
fCached = false;
|
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
fCached = true;
|
fMap = file_map_create(fVolume->ID(), ID(), Size());
|
||||||
TRACE("Inode::EnableFileCache(): Done\n");
|
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;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -758,15 +778,9 @@ Inode::EnableFileCache()
|
||||||
status_t
|
status_t
|
||||||
Inode::DisableFileCache()
|
Inode::DisableFileCache()
|
||||||
{
|
{
|
||||||
TRACE("Inode::DisableFileCache()\n");
|
status_t error = file_cache_disable(fCache);
|
||||||
|
if (error != B_OK)
|
||||||
if (!fCached)
|
return error;
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
file_cache_delete(FileCache());
|
|
||||||
file_map_delete(Map());
|
|
||||||
|
|
||||||
fCached = false;
|
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
@ -775,7 +789,7 @@ Inode::DisableFileCache()
|
||||||
status_t
|
status_t
|
||||||
Inode::Sync()
|
Inode::Sync()
|
||||||
{
|
{
|
||||||
if (!IsFileCacheDisabled())
|
if (HasFileCache())
|
||||||
return file_cache_sync(fCache);
|
return file_cache_sync(fCache);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
|
@ -112,9 +112,11 @@ public:
|
||||||
|
|
||||||
void* FileCache() const { return fCache; }
|
void* FileCache() const { return fCache; }
|
||||||
void* Map() const { return fMap; }
|
void* Map() const { return fMap; }
|
||||||
|
status_t CreateFileCache();
|
||||||
|
void DeleteFileCache();
|
||||||
|
bool HasFileCache() { return fCache != NULL; }
|
||||||
status_t EnableFileCache();
|
status_t EnableFileCache();
|
||||||
status_t DisableFileCache();
|
status_t DisableFileCache();
|
||||||
bool IsFileCacheDisabled() const { return !fCached; }
|
|
||||||
|
|
||||||
status_t Sync();
|
status_t Sync();
|
||||||
|
|
||||||
|
@ -144,7 +146,6 @@ private:
|
||||||
ino_t fID;
|
ino_t fID;
|
||||||
void* fCache;
|
void* fCache;
|
||||||
void* fMap;
|
void* fMap;
|
||||||
bool fCached;
|
|
||||||
bool fUnlinked;
|
bool fUnlinked;
|
||||||
bool fHasExtraAttributes;
|
bool fHasExtraAttributes;
|
||||||
ext2_inode fNode;
|
ext2_inode fNode;
|
||||||
|
|
|
@ -39,12 +39,11 @@ InodeJournal::InodeJournal(Inode* inode)
|
||||||
fJournalVolume = volume;
|
fJournalVolume = volume;
|
||||||
fJournalBlockCache = volume->BlockCache();
|
fJournalBlockCache = volume->BlockCache();
|
||||||
|
|
||||||
if (!inode->IsFileCacheDisabled())
|
if (inode->HasFileCache())
|
||||||
fInitStatus = inode->DisableFileCache();
|
inode->DeleteFileCache();
|
||||||
else
|
|
||||||
fInitStatus = B_OK;
|
fInitStatus = B_OK;
|
||||||
|
|
||||||
if (fInitStatus == B_OK) {
|
|
||||||
TRACE("InodeJournal::InodeJournal(): Inode's file cache disabled "
|
TRACE("InodeJournal::InodeJournal(): Inode's file cache disabled "
|
||||||
"successfully\n");
|
"successfully\n");
|
||||||
HashRevokeManager* revokeManager = new(std::nothrow)
|
HashRevokeManager* revokeManager = new(std::nothrow)
|
||||||
|
@ -66,7 +65,6 @@ InodeJournal::InodeJournal(Inode* inode)
|
||||||
delete revokeManager;
|
delete revokeManager;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -759,7 +759,7 @@ ext2_create(fs_volume* _volume, fs_vnode* _directory, const char* name,
|
||||||
|
|
||||||
TRACE("ext2_create(): Created inode\n");
|
TRACE("ext2_create(): Created inode\n");
|
||||||
|
|
||||||
if ((openMode & O_NOCACHE) != 0 && !inode->IsFileCacheDisabled()) {
|
if ((openMode & O_NOCACHE) != 0) {
|
||||||
status = inode->DisableFileCache();
|
status = inode->DisableFileCache();
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
@ -830,8 +830,8 @@ ext2_create_symlink(fs_volume* _volume, fs_vnode* _directory, const char* name,
|
||||||
link->Mode(), 0);
|
link->Mode(), 0);
|
||||||
put_vnode(volume->FSVolume(), id);
|
put_vnode(volume->FSVolume(), id);
|
||||||
|
|
||||||
if (link->IsFileCacheDisabled()) {
|
if (!link->HasFileCache()) {
|
||||||
status = link->EnableFileCache();
|
status = link->CreateFileCache();
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
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_size = inode->Size();
|
||||||
cookie->last_notification = system_time();
|
cookie->last_notification = system_time();
|
||||||
|
|
||||||
|
MethodDeleter<Inode, status_t> fileCacheEnabler(&Inode::EnableFileCache);
|
||||||
if ((openMode & O_NOCACHE) != 0) {
|
if ((openMode & O_NOCACHE) != 0) {
|
||||||
status = inode->DisableFileCache();
|
status = inode->DisableFileCache();
|
||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
fileCacheEnabler.SetTo(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should we truncate the file?
|
// 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?
|
// TODO: No need to notify file size changed?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fileCacheEnabler.Detach();
|
||||||
cookieDeleter.Detach();
|
cookieDeleter.Detach();
|
||||||
*_cookie = cookie;
|
*_cookie = cookie;
|
||||||
|
|
||||||
|
@ -1246,6 +1249,9 @@ ext2_free_cookie(fs_volume* _volume, fs_vnode* _node, void* _cookie)
|
||||||
if (inode->Size() != cookie->last_size)
|
if (inode->Size() != cookie->last_size)
|
||||||
notify_stat_changed(volume->ID(), inode->ID(), B_STAT_SIZE);
|
notify_stat_changed(volume->ID(), inode->ID(), B_STAT_SIZE);
|
||||||
|
|
||||||
|
if ((cookie->open_mode & O_NOCACHE) != 0)
|
||||||
|
inode->EnableFileCache();
|
||||||
|
|
||||||
delete cookie;
|
delete cookie;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue