/* * Copyright 2012-2016 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Paweł Dziepak, pdziepak@quarnos.org */ #include "MetadataCache.h" #include #include "Inode.h" MetadataCache::MetadataCache(Inode* inode) : fExpire(0), fForceValid(false), fInode(inode), fInited(false) { ASSERT(inode != NULL); mutex_init(&fLock, "nfs4 MetadataCache"); } MetadataCache::~MetadataCache() { mutex_destroy(&fLock); } status_t MetadataCache::GetStat(struct stat* st) { ASSERT(st != NULL); MutexLocker _(fLock); if (fForceValid || fExpire > time(NULL)) { // Do not touch other members of struct stat st->st_size = fStatCache.st_size; st->st_mode = fStatCache.st_mode; st->st_nlink = fStatCache.st_nlink; st->st_uid = fStatCache.st_uid; st->st_gid = fStatCache.st_gid; st->st_atim = fStatCache.st_atim; st->st_ctim = fStatCache.st_ctim; st->st_crtim = fStatCache.st_crtim; st->st_mtim = fStatCache.st_mtim; st->st_blksize = fStatCache.st_blksize; st->st_blocks = fStatCache.st_blocks; return B_OK; } return B_ERROR; } void MetadataCache::SetStat(const struct stat& st) { MutexLocker _(fLock); if (fInited) NotifyChanges(&fStatCache, &st); fStatCache = st; fExpire = time(NULL) + kExpirationTime; fInited = true; } void MetadataCache::GrowFile(size_t newSize) { MutexLocker _(fLock); off_t oldSize = fStatCache.st_size; fStatCache.st_size = max_c((off_t)newSize, fStatCache.st_size); if (oldSize != fStatCache.st_size) { notify_stat_changed(fInode->GetFileSystem()->DevId(), -1, fInode->ID(), B_STAT_SIZE); } } status_t MetadataCache::GetAccess(uid_t uid, uint32* allowed) { ASSERT(allowed != NULL); MutexLocker _(fLock); AVLTreeMap::Iterator it = fAccessCache.Find(uid); if (!it.HasCurrent()) return B_ENTRY_NOT_FOUND; if (!fForceValid) it.CurrentValuePointer()->fForceValid = false; if (!it.Current().fForceValid && it.Current().fExpire < time(NULL)) { it.Remove(); return B_ERROR; } *allowed = it.Current().fAllowed; return B_OK; } void MetadataCache::SetAccess(uid_t uid, uint32 allowed) { MutexLocker _(fLock); AVLTreeMap::Iterator it = fAccessCache.Find(uid); if (it.HasCurrent()) it.Remove(); AccessEntry entry; entry.fAllowed = allowed; entry.fExpire = time(NULL) + kExpirationTime; entry.fForceValid = fForceValid; fAccessCache.Insert(uid, entry); } status_t MetadataCache::LockValid() { MutexLocker _(fLock); if (fForceValid || fExpire > time(NULL)) { fForceValid = true; return B_OK; } return B_ERROR; } void MetadataCache::UnlockValid() { MutexLocker _(fLock); fExpire = time(NULL) + kExpirationTime; fForceValid = false; } void MetadataCache::Dump(void (*xprintf)(const char*, ...)) { if (xprintf != kprintf) { status_t status = mutex_trylock(&fLock); if (status != B_OK) { xprintf("MetadataCache at %p locked\n", this); return; } } _DumpLocked(xprintf); if (xprintf != kprintf) mutex_unlock(&fLock); return; } void MetadataCache::NotifyChanges(const struct stat* oldStat, const struct stat* newStat) { ASSERT(oldStat != NULL); ASSERT(newStat != NULL); uint32 flags = 0; if (oldStat->st_size != newStat->st_size) flags |= B_STAT_SIZE; if (oldStat->st_mode != newStat->st_mode) flags |= B_STAT_MODE; if (oldStat->st_uid != newStat->st_uid) flags |= B_STAT_UID; if (oldStat->st_gid != newStat->st_gid) flags |= B_STAT_GID; if (memcmp(&oldStat->st_atim, &newStat->st_atim, sizeof(struct timespec)) == 0) flags |= B_STAT_ACCESS_TIME; if (memcmp(&oldStat->st_ctim, &newStat->st_ctim, sizeof(struct timespec)) == 0) flags |= B_STAT_CHANGE_TIME; if (memcmp(&oldStat->st_crtim, &newStat->st_crtim, sizeof(struct timespec)) == 0) flags |= B_STAT_CREATION_TIME; if (memcmp(&oldStat->st_mtim, &newStat->st_mtim, sizeof(struct timespec)) == 0) flags |= B_STAT_MODIFICATION_TIME; notify_stat_changed(fInode->GetFileSystem()->DevId(), -1, fInode->ID(), flags); } void MetadataCache::_DumpLocked(void (*xprintf)(const char*, ...)) const { xprintf("MetadataCache at %p for Inode at %p\n", this, fInode); xprintf("\tfInited %d, fForceValid %d\n", fInited, fForceValid); if (time(NULL) < fExpire) xprintf("\tExpires at %" B_PRIdTIME "\n", fExpire); else xprintf("\tExpired\n"); xprintf("\tst_mode %" B_PRIo32 "\n", fStatCache.st_mode); xprintf("\tst_nlink %" B_PRId32 "\n", fStatCache.st_nlink); xprintf("\tst_uid %" B_PRIu32 "\n", fStatCache.st_uid); xprintf("\tst_gid %" B_PRIu32 "\n", fStatCache.st_gid); xprintf("\tst_size %" B_PRIdOFF "\n", fStatCache.st_size); return; }