nfs4: Improve debug output
* Make more info available from Dump functions. * Allow locking to fail in Dump functions to avoid deadlocks caused by debug output. * Make corrections to the nfs4_unlink() changes in hrev59023. Change-Id: I8e5431baacb3cfa0baaedd2695c597549e746d2c Reviewed-on: https://review.haiku-os.org/c/haiku/+/9628 Tested-by: Commit checker robot <[email protected]> Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
@@ -31,20 +31,38 @@ int
|
|||||||
kprintf_inode(int argc, char** argv)
|
kprintf_inode(int argc, char** argv)
|
||||||
{
|
{
|
||||||
if ((argc == 1) || strcmp(argv[1], "--help") == 0) {
|
if ((argc == 1) || strcmp(argv[1], "--help") == 0) {
|
||||||
kprintf("usage: nfs4_inode <address(es) ...>\n"
|
kprintf("usage: nfs4_inode [-i] <address(es) ...>\n"
|
||||||
" address(es): address of one or more nfs4 private nodes (VnodeToInode), "
|
" -i specifies that the address is that of an Inode (rather than a VnodeToInode)\n"
|
||||||
|
" address(es): address of one or more objects of the same type, "
|
||||||
"separated by spaces\n"
|
"separated by spaces\n"
|
||||||
" Addresses can be found with the 'vnodes' command.\n");
|
" VnodeToInode addresses can be found with the 'vnodes' command.\n"
|
||||||
|
" Output of the 'nfs4' command refers to nodes by their Inode address.\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 1; i < argc; i++) {
|
int argIndex = 1;
|
||||||
VnodeToInode* node = reinterpret_cast<VnodeToInode*>(strtoul(argv[1], NULL, 0));
|
bool dumpVti = true;
|
||||||
if (node == NULL)
|
|
||||||
continue;
|
if (strcmp(argv[argIndex], "-i") == 0) {
|
||||||
node->Dump(kprintf);
|
dumpVti = false;
|
||||||
kprintf("----------\n");
|
++argIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; argIndex < argc; ++argIndex) {
|
||||||
|
if (dumpVti) {
|
||||||
|
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(strtoul(argv[argIndex], NULL, 0));
|
||||||
|
if (vti == NULL)
|
||||||
|
continue;
|
||||||
|
vti->Dump(kprintf);
|
||||||
|
} else {
|
||||||
|
Inode* inode = reinterpret_cast<Inode*>(strtoul(argv[argIndex], NULL, 0));
|
||||||
|
if (inode == NULL)
|
||||||
|
continue;
|
||||||
|
inode->Dump(kprintf);
|
||||||
|
}
|
||||||
|
kprintf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,13 +16,20 @@
|
|||||||
#include <DebugSupport.h>
|
#include <DebugSupport.h>
|
||||||
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
#define TRACE(x...) FUNCTION(x)
|
#define TRACE(x...) FUNCTION(x)
|
||||||
#define CALLED() FUNCTION_START()
|
#define CALLED() FUNCTION_START()
|
||||||
|
|
||||||
|
#if KDEBUG
|
||||||
|
# define ASSERT_WITH_DUMP(expr,obj) \
|
||||||
|
do { \
|
||||||
|
if (!(expr)) { \
|
||||||
|
obj->Dump(); \
|
||||||
|
panic("ASSERT FAILED (%s:%d): %s", __FILE__, __LINE__, #expr); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
#else
|
#else
|
||||||
#define TRACE(x...)
|
# define ASSERT_WITH_DUMP(expr,obj) do { } while(0)
|
||||||
#define CALLED()
|
#endif // KDEBUG
|
||||||
#endif
|
|
||||||
|
|
||||||
#if USER
|
#if USER
|
||||||
extern "C" void dprintf(const char *format, ...);
|
extern "C" void dprintf(const char *format, ...);
|
||||||
|
|||||||
@@ -39,6 +39,22 @@ Delegation::GiveUp(bool truncate)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Delegation::Dump(void (*xprintf)(const char*, ...)) const
|
||||||
|
{
|
||||||
|
xprintf("Delegation at %p for Inode at %p (ino %" B_PRIdINO ")\n", this, fInode, fInode->ID());
|
||||||
|
if (fData.fType == OPEN_DELEGATE_READ)
|
||||||
|
xprintf("\ttype OPEN_DELEGATE_READ, ");
|
||||||
|
else if (fData.fType == OPEN_DELEGATE_WRITE)
|
||||||
|
xprintf("\ttype OPEN_DELEGATE_WRITE, ");
|
||||||
|
xprintf("attribute %d, uid %" B_PRIu32 ", gid %" B_PRIu32 "\n", fAttribute, fUid, fGid);
|
||||||
|
xprintf("\tstate id and sequence %" B_PRIu32 " %" B_PRIu32 " %" B_PRIu32 " %" B_PRIu32 "\n",
|
||||||
|
fData.fStateID[0], fData.fStateID[1], fData.fStateID[2], fData.fStateSeq);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
Delegation::ReturnDelegation()
|
Delegation::ReturnDelegation()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,9 +26,11 @@ public:
|
|||||||
status_t GiveUp(bool truncate = false);
|
status_t GiveUp(bool truncate = false);
|
||||||
|
|
||||||
inline void SetData(const OpenDelegationData& data);
|
inline void SetData(const OpenDelegationData& data);
|
||||||
inline Inode* GetInode();
|
inline Inode* GetInode() const;
|
||||||
inline OpenDelegation Type();
|
inline OpenDelegation Type();
|
||||||
|
|
||||||
|
void Dump(void (*xprintf)(const char*, ...) = dprintf) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
status_t ReturnDelegation();
|
status_t ReturnDelegation();
|
||||||
|
|
||||||
@@ -50,7 +52,7 @@ Delegation::SetData(const OpenDelegationData& data)
|
|||||||
|
|
||||||
|
|
||||||
inline Inode*
|
inline Inode*
|
||||||
Delegation::GetInode()
|
Delegation::GetInode() const
|
||||||
{
|
{
|
||||||
return fInode;
|
return fInode;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ DirectoryCache::DirectoryCache(Inode* inode, bool attr)
|
|||||||
{
|
{
|
||||||
ASSERT(inode != NULL);
|
ASSERT(inode != NULL);
|
||||||
|
|
||||||
mutex_init(&fLock, NULL);
|
mutex_init(&fLock, "nfs4 DirectoryCache");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -299,7 +299,7 @@ DirectoryCache::_DumpLocked(void (*xprintf)(const char*, ...)) const
|
|||||||
|
|
||||||
for (SinglyLinkedList<NameCacheEntry>::ConstIterator it = fNameCache.GetIterator();
|
for (SinglyLinkedList<NameCacheEntry>::ConstIterator it = fNameCache.GetIterator();
|
||||||
const NameCacheEntry* entry = it.Next();) {
|
const NameCacheEntry* entry = it.Next();) {
|
||||||
xprintf("\t\tino: %" B_PRIdINO "\t", entry->fNode);
|
xprintf("\tino: %" B_PRIdINO "\t", entry->fNode);
|
||||||
if (entry->fName != NULL)
|
if (entry->fName != NULL)
|
||||||
xprintf("name: %s\n", entry->fName);
|
xprintf("name: %s\n", entry->fName);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ InodeNames::Dump(void (*xprintf)(const char*, ...))
|
|||||||
void
|
void
|
||||||
InodeNames::_DumpLocked(void (*xprintf)(const char*, ...)) const
|
InodeNames::_DumpLocked(void (*xprintf)(const char*, ...)) const
|
||||||
{
|
{
|
||||||
|
xprintf("InodeNames ");
|
||||||
for (SinglyLinkedList<InodeName>::ConstIterator it = fNames.GetIterator();
|
for (SinglyLinkedList<InodeName>::ConstIterator it = fNames.GetIterator();
|
||||||
const InodeName* name = it.Next();) {
|
const InodeName* name = it.Next();) {
|
||||||
if (name->fName != NULL)
|
if (name->fName != NULL)
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "Request.h"
|
#include "Request.h"
|
||||||
#include "RootInode.h"
|
#include "RootInode.h"
|
||||||
#include "VnodeToInode.h"
|
#include "VnodeToInode.h"
|
||||||
|
#include "WorkQueue.h"
|
||||||
|
|
||||||
|
|
||||||
extern RPC::ServerManager* gRPCServerManager;
|
extern RPC::ServerManager* gRPCServerManager;
|
||||||
@@ -37,10 +38,10 @@ FileSystem::FileSystem(const MountConfiguration& configuration)
|
|||||||
{
|
{
|
||||||
fOpenOwner = get_random<uint64>();
|
fOpenOwner = get_random<uint64>();
|
||||||
|
|
||||||
mutex_init(&fOpenOwnerLock, NULL);
|
mutex_init(&fOpenOwnerLock, "nfs4 FileSystem::fOpenOwnerLock");
|
||||||
mutex_init(&fOpenLock, NULL);
|
mutex_init(&fOpenLock, "nfs4 FileSystem::fOpenLock");
|
||||||
mutex_init(&fDelegationLock, NULL);
|
mutex_init(&fDelegationLock, "nfs4 FileSystem::fDelegationLock");
|
||||||
mutex_init(&fCreateFileLock, NULL);
|
mutex_init(&fCreateFileLock, "nfs4 FileSystem::fCreateFileLock");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -554,13 +555,32 @@ FileSystem::ServerUnlinkCleanup(ino_t id, Inode* parent, const char* missingName
|
|||||||
void
|
void
|
||||||
FileSystem::Dump(void (*xprintf)(const char*, ...))
|
FileSystem::Dump(void (*xprintf)(const char*, ...))
|
||||||
{
|
{
|
||||||
MutexLocker locker;
|
xprintf("FileSystem at %p\n", this);
|
||||||
if (xprintf != kprintf)
|
bool dumpDelegations = true;
|
||||||
locker.SetTo(fOpenLock, false);
|
bool dumpOpenFiles = true;
|
||||||
|
if (xprintf != kprintf) {
|
||||||
|
status_t status = mutex_trylock(&fDelegationLock);
|
||||||
|
if (status != B_OK)
|
||||||
|
dumpDelegations = false;
|
||||||
|
status = mutex_trylock(&fOpenLock);
|
||||||
|
if (status != B_OK)
|
||||||
|
dumpOpenFiles = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_DumpLocked(xprintf, dumpDelegations, dumpOpenFiles);
|
||||||
|
|
||||||
|
if (xprintf != kprintf) {
|
||||||
|
if (dumpDelegations)
|
||||||
|
mutex_unlock(&fDelegationLock);
|
||||||
|
if (dumpOpenFiles)
|
||||||
|
mutex_unlock(&fOpenLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
xprintf("\n");
|
||||||
fInoIdMap.Dump(xprintf);
|
fInoIdMap.Dump(xprintf);
|
||||||
|
|
||||||
_DumpLocked(xprintf);
|
xprintf("\n");
|
||||||
|
gWorkQueue->Dump(xprintf);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -607,17 +627,36 @@ FileSystem::_ParsePath(RequestBuilder& req, uint32& count, const char* _path)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
FileSystem::_DumpLocked(void (*xprintf)(const char*, ...)) const
|
FileSystem::_DumpLocked(void (*xprintf)(const char*, ...), bool dumpDelegations,
|
||||||
|
bool dumpOpenFiles) const
|
||||||
{
|
{
|
||||||
xprintf("fOpenFiles:\n", fOpenFiles);
|
xprintf("\tRootInode at %p\n", fRoot);
|
||||||
for (DoublyLinkedList<OpenState>::ConstIterator it = fOpenFiles.GetIterator();
|
|
||||||
const OpenState* state = it.Next();) {
|
xprintf("\tfOpenFiles\n", fOpenFiles);
|
||||||
xprintf("\tID\t\t%" B_PRIu64 "\n", state->fInfo.fFileId);
|
if (dumpOpenFiles) {
|
||||||
xprintf("\tFileHandle\t");
|
uint64 entries = 0;
|
||||||
state->fInfo.fHandle.Dump(xprintf);
|
for (DoublyLinkedList<OpenState>::ConstIterator it = fOpenFiles.GetIterator();
|
||||||
xprintf("\tInodeNames\t");
|
const OpenState* state = it.Next(); ++entries) {
|
||||||
state->fInfo.fNames->Dump(xprintf);
|
xprintf("\t\tOpenState at %p for ino %" B_PRIdINO "\n", state, state->fInfo.fFileId);
|
||||||
xprintf("\t----------\n");
|
}
|
||||||
|
if (entries == 0)
|
||||||
|
xprintf("\t\tNone\n");
|
||||||
|
} else {
|
||||||
|
xprintf("\tfOpenLock is locked\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
xprintf("\tDelegations\n");
|
||||||
|
if (dumpDelegations) {
|
||||||
|
uint64 entries = 0;
|
||||||
|
for (DoublyLinkedList<Delegation>::ConstIterator it = fDelegationList.GetIterator();
|
||||||
|
const Delegation* del = it.Next(); ++entries) {
|
||||||
|
xprintf("\t\tDelegation at %p for Inode at %p (ino %" B_PRIdINO ")\n", del,
|
||||||
|
del->GetInode(), del->GetInode()->ID());
|
||||||
|
}
|
||||||
|
if (entries == 0)
|
||||||
|
xprintf("\t\tNone");
|
||||||
|
} else {
|
||||||
|
xprintf("\tfDelegationLock is locked\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -98,7 +98,8 @@ private:
|
|||||||
static status_t _ParsePath(RequestBuilder& req, uint32& count,
|
static status_t _ParsePath(RequestBuilder& req, uint32& count,
|
||||||
const char* _path);
|
const char* _path);
|
||||||
|
|
||||||
void _DumpLocked(void (*xprintf)(const char*, ...)) const;
|
void _DumpLocked(void (*xprintf)(const char*, ...),
|
||||||
|
bool dumpDelegations, bool dumpOpenFiles) const;
|
||||||
|
|
||||||
mutex fCreateFileLock;
|
mutex fCreateFileLock;
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "IdMap.h"
|
#include "IdMap.h"
|
||||||
#include "Request.h"
|
#include "Request.h"
|
||||||
#include "RootInode.h"
|
#include "RootInode.h"
|
||||||
|
#include "WorkQueue.h"
|
||||||
|
|
||||||
|
|
||||||
Inode::Inode()
|
Inode::Inode()
|
||||||
@@ -35,11 +36,11 @@ Inode::Inode()
|
|||||||
fAIOCount(0),
|
fAIOCount(0),
|
||||||
fStale(false)
|
fStale(false)
|
||||||
{
|
{
|
||||||
rw_lock_init(&fDelegationLock, NULL);
|
rw_lock_init(&fDelegationLock, "nfs4 Inode::fDelegationLock");
|
||||||
mutex_init(&fStateLock, NULL);
|
mutex_init(&fStateLock, "nfs4 Inode::fStateLock");
|
||||||
mutex_init(&fFileCacheLock, NULL);
|
mutex_init(&fFileCacheLock, "nfs4 Inode::fFileCacheLock");
|
||||||
rw_lock_init(&fWriteLock, NULL);
|
rw_lock_init(&fWriteLock, "nfs4 Inode::fWriteLock");
|
||||||
mutex_init(&fAIOLock, NULL);
|
mutex_init(&fAIOLock, "nfs4 Inode::fAIOLock");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1051,14 +1052,81 @@ Inode::EndAIOOp()
|
|||||||
@pre The parent VnodeToInode is locked.
|
@pre The parent VnodeToInode is locked.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
Inode::Dump(void (*xprintf)(const char*, ...)) const
|
Inode::Dump(void (*xprintf)(const char*, ...))
|
||||||
{
|
{
|
||||||
xprintf("Inode\t%" B_PRIu64 " at %p\n", fInfo.fFileId, this);
|
bool dumpDelegation = true;
|
||||||
xprintf("FileHandle\t");
|
bool dumpAIO = true;
|
||||||
fInfo.fHandle.Dump(xprintf);
|
if (xprintf != kprintf) {
|
||||||
xprintf("InodeNames\t");
|
status_t status = rw_lock_read_lock_with_timeout(&fDelegationLock, B_RELATIVE_TIMEOUT, 0);
|
||||||
fInfo.fNames->Dump(xprintf);
|
if (status != B_OK)
|
||||||
|
dumpDelegation = false;
|
||||||
|
status = mutex_trylock(&fAIOLock);
|
||||||
|
if (status != B_OK)
|
||||||
|
dumpAIO = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_DumpLocked(xprintf, dumpDelegation, dumpAIO);
|
||||||
|
|
||||||
|
if (xprintf != kprintf) {
|
||||||
|
if (dumpDelegation)
|
||||||
|
rw_lock_read_unlock(&fDelegationLock);
|
||||||
|
if (dumpAIO)
|
||||||
|
mutex_unlock(&fAIOLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetFileSystem()->Root() != this)
|
||||||
|
fInfo.fNames->Dump(xprintf);
|
||||||
|
|
||||||
if (fCache != NULL)
|
if (fCache != NULL)
|
||||||
fCache->Dump(xprintf);
|
fCache->Dump(xprintf);
|
||||||
|
|
||||||
|
fMetaCache.Dump(xprintf);
|
||||||
|
|
||||||
|
if (fOpenState == NULL) {
|
||||||
|
xprintf("No OpenState\n");
|
||||||
|
} else {
|
||||||
|
status_t status = mutex_trylock(&fStateLock);
|
||||||
|
if (status == B_OK) {
|
||||||
|
fOpenState->Dump(xprintf);
|
||||||
|
mutex_unlock(&fStateLock);
|
||||||
|
} else {
|
||||||
|
xprintf("fStateLock locked\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gWorkQueue->Dump(xprintf);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Dump members that have const Dump methods or are dumped manually.
|
||||||
|
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
Inode::_DumpLocked(void (*xprintf)(const char*, ...), bool dumpDelegation, bool dumpAIO) const
|
||||||
|
{
|
||||||
|
if (GetFileSystem()->Root() == this)
|
||||||
|
xprintf("Root inode\t%" B_PRIu64 " at %p\n", fInfo.fFileId, this);
|
||||||
|
else
|
||||||
|
xprintf("Inode\t%" B_PRIu64 " at %p\n", fInfo.fFileId, this);
|
||||||
|
|
||||||
|
xprintf("FileHandle ");
|
||||||
|
fInfo.fHandle.Dump(xprintf);
|
||||||
|
|
||||||
|
xprintf("\tfType %" B_PRIu32 ", fChange %" B_PRIu64 ", fStale %d\n", fType, fChange, fStale);
|
||||||
|
|
||||||
|
if (dumpAIO)
|
||||||
|
xprintf("\tfAIOCount %" B_PRIu32 "\n", fAIOCount);
|
||||||
|
else
|
||||||
|
xprintf("\tAIO locked\n");
|
||||||
|
|
||||||
|
if (fDelegation == NULL)
|
||||||
|
xprintf("\tNo Delegation\n");
|
||||||
|
else if (dumpDelegation)
|
||||||
|
fDelegation->Dump();
|
||||||
|
else
|
||||||
|
xprintf("Delegation locked\n");
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ public:
|
|||||||
inline void SetStale(bool stale = true);
|
inline void SetStale(bool stale = true);
|
||||||
inline bool IsStale() const;
|
inline bool IsStale() const;
|
||||||
|
|
||||||
void Dump(void (*xprintf)(const char*, ...) = dprintf) const;
|
void Dump(void (*xprintf)(const char*, ...) = dprintf);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Inode();
|
Inode();
|
||||||
@@ -150,6 +150,9 @@ protected:
|
|||||||
|
|
||||||
static inline status_t CheckLockType(short ltype, uint32 mode);
|
static inline status_t CheckLockType(short ltype, uint32 mode);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _DumpLocked(void (*xprintf)(const char*, ...), bool dumpDelegation,
|
||||||
|
bool dumpAIO) const;
|
||||||
private:
|
private:
|
||||||
uint32 fType;
|
uint32 fType;
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ MetadataCache::MetadataCache(Inode* inode)
|
|||||||
fInited(false)
|
fInited(false)
|
||||||
{
|
{
|
||||||
ASSERT(inode != NULL);
|
ASSERT(inode != NULL);
|
||||||
mutex_init(&fLock, NULL);
|
mutex_init(&fLock, "nfs4 MetadataCache");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -148,6 +148,26 @@ MetadataCache::UnlockValid()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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
|
void
|
||||||
MetadataCache::NotifyChanges(const struct stat* oldStat,
|
MetadataCache::NotifyChanges(const struct stat* oldStat,
|
||||||
const struct stat* newStat)
|
const struct stat* newStat)
|
||||||
@@ -185,3 +205,23 @@ MetadataCache::NotifyChanges(const struct stat* oldStat,
|
|||||||
flags);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#include <util/AutoLock.h>
|
#include <util/AutoLock.h>
|
||||||
#include <util/AVLTreeMap.h>
|
#include <util/AVLTreeMap.h>
|
||||||
|
|
||||||
|
#include "Debug.h"
|
||||||
|
|
||||||
class Inode;
|
class Inode;
|
||||||
|
|
||||||
@@ -45,12 +46,17 @@ public:
|
|||||||
|
|
||||||
inline void Invalidate();
|
inline void Invalidate();
|
||||||
|
|
||||||
|
void Dump(void (*xprintf)(const char*, ...) = dprintf);
|
||||||
|
|
||||||
static const time_t kExpirationTime = 60;
|
static const time_t kExpirationTime = 60;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void NotifyChanges(const struct stat* oldStat,
|
void NotifyChanges(const struct stat* oldStat,
|
||||||
const struct stat* newStat);
|
const struct stat* newStat);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _DumpLocked(void (*xprintf)(const char*, ...)) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct stat fStatCache;
|
struct stat fStatCache;
|
||||||
time_t fExpire;
|
time_t fExpire;
|
||||||
|
|||||||
@@ -25,10 +25,10 @@ OpenState::OpenState()
|
|||||||
fUid(geteuid()),
|
fUid(geteuid()),
|
||||||
fGid(getegid())
|
fGid(getegid())
|
||||||
{
|
{
|
||||||
mutex_init(&fLock, NULL);
|
mutex_init(&fLock, "nfs4 OpenState::fLock");
|
||||||
|
|
||||||
mutex_init(&fLocksLock, NULL);
|
mutex_init(&fLocksLock, "nfs4 OpenState::fLocksLock");
|
||||||
mutex_init(&fOwnerLock, NULL);
|
mutex_init(&fOwnerLock, "nfs4 OpenState::fOwnerLock");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -330,3 +330,45 @@ OpenState::Close()
|
|||||||
} while (true);
|
} while (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
OpenState::Dump(void (*xprintf)(const char*, ...))
|
||||||
|
{
|
||||||
|
status_t status = B_OK;
|
||||||
|
if (xprintf != kprintf)
|
||||||
|
status = mutex_trylock(&fLock);
|
||||||
|
|
||||||
|
if (status == B_OK)
|
||||||
|
_DumpLocked(xprintf);
|
||||||
|
else
|
||||||
|
xprintf("OpenState at %p locked\n", this);
|
||||||
|
|
||||||
|
if (xprintf != kprintf && status == B_OK)
|
||||||
|
mutex_unlock(&fLock);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
OpenState::_DumpLocked(void (*xprintf)(const char*, ...)) const
|
||||||
|
{
|
||||||
|
xprintf("OpenState at %p for ino %" B_PRIdINO "\n", this, Inode::FileIdToInoT(fInfo.fFileId));
|
||||||
|
|
||||||
|
xprintf("\tFileHandle ");
|
||||||
|
fInfo.fHandle.Dump(xprintf);
|
||||||
|
|
||||||
|
xprintf("\t");
|
||||||
|
fInfo.fNames->Dump(xprintf);
|
||||||
|
|
||||||
|
xprintf("\tmode %x, opened %d, delegation %p, refs %" B_PRIu32 "\n",
|
||||||
|
static_cast<unsigned int>(fMode), fOpened, fDelegation, CountReferences());
|
||||||
|
|
||||||
|
xprintf("\tuid %" B_PRIu32 ", gid %" B_PRIu32 "\n", fUid, fGid);
|
||||||
|
|
||||||
|
xprintf("\tstate id and sequence %" B_PRIu32 " %" B_PRIu32 " %" B_PRIu32 " %" B_PRIu32 "\n",
|
||||||
|
fStateID[0], fStateID[1], fStateID[2], fStateSeq);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,10 +52,14 @@ struct OpenState : public NFS4Object, public KernelReferenceable,
|
|||||||
|
|
||||||
status_t Close();
|
status_t Close();
|
||||||
|
|
||||||
|
void Dump(void (*xprintf)(const char*, ...) = dprintf);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t _ReclaimOpen(uint64 newClientID);
|
status_t _ReclaimOpen(uint64 newClientID);
|
||||||
status_t _ReclaimLocks(uint64 newClientID);
|
status_t _ReclaimLocks(uint64 newClientID);
|
||||||
status_t _ReleaseLockOwner(LockOwner* owner);
|
status_t _ReleaseLockOwner(LockOwner* owner);
|
||||||
|
|
||||||
|
void _DumpLocked(void (*xprintf)(const char*, ...)) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -899,7 +899,13 @@ ReplyInterpreter::_OperationError(Opcode op)
|
|||||||
|
|
||||||
status_t result = _NFS4ErrorToHaiku(fReply->Stream().GetUInt());
|
status_t result = _NFS4ErrorToHaiku(fReply->Stream().GetUInt());
|
||||||
if (result != B_OK) {
|
if (result != B_OK) {
|
||||||
|
#if DEBUG
|
||||||
ERROR("NFS Error: %s\n", strerror(result));
|
ERROR("NFS Error: %s\n", strerror(result));
|
||||||
|
#else
|
||||||
|
// Lookup failures are routine. Reporting them could obscure more important error messages.
|
||||||
|
if (op != OpLookUp || result != B_ENTRY_NOT_FOUND)
|
||||||
|
ERROR("NFS Error: %s\n", strerror(result));
|
||||||
|
#endif
|
||||||
fDecodeError = true;
|
fDecodeError = true;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -17,6 +17,28 @@
|
|||||||
WorkQueue* gWorkQueue = NULL;
|
WorkQueue* gWorkQueue = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WorkQueueEntry::Dump(void (*xprintf)(const char*, ...)) const
|
||||||
|
{
|
||||||
|
if (fType == DelegationRecall) {
|
||||||
|
xprintf("\tType: DelegationRecall\n");
|
||||||
|
DelegationRecallArgs* args = reinterpret_cast<DelegationRecallArgs*>(fArguments);
|
||||||
|
xprintf("\t\tDelegation at %p for Inode at %p (ino %" B_PRIdINO "), truncate %d\n",
|
||||||
|
args->fDelegation, args->fDelegation->GetInode(), args->fDelegation->GetInode()->ID(),
|
||||||
|
args->fTruncate);
|
||||||
|
} else if (fType == IORequest) {
|
||||||
|
xprintf("\tType: IORequest\n");
|
||||||
|
IORequestArgs* args = reinterpret_cast<IORequestArgs*>(fArguments);
|
||||||
|
xprintf("\t\tFor Inode at %p (ino %" B_PRIdINO ")\n", args->fInode, args->fInode->ID());
|
||||||
|
xprintf("\t\twrite %d, offset %" B_PRIdOFF ", length %" B_PRIdOFF "\n",
|
||||||
|
io_request_is_write(args->fRequest), io_request_offset(args->fRequest),
|
||||||
|
io_request_length(args->fRequest));
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
WorkQueue::WorkQueue()
|
WorkQueue::WorkQueue()
|
||||||
:
|
:
|
||||||
fQueueSemaphore(create_sem(0, NULL)),
|
fQueueSemaphore(create_sem(0, NULL)),
|
||||||
@@ -76,6 +98,28 @@ WorkQueue::EnqueueJob(JobType type, void* args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WorkQueue::Dump(void (*xprintf)(const char*, ...))
|
||||||
|
{
|
||||||
|
xprintf("WorkQueue\n");
|
||||||
|
|
||||||
|
if (xprintf != kprintf) {
|
||||||
|
status_t status = mutex_trylock(&fQueueLock);
|
||||||
|
if (status != B_OK) {
|
||||||
|
xprintf("\t Locked\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_DumpLocked(xprintf);
|
||||||
|
|
||||||
|
if (xprintf != kprintf)
|
||||||
|
mutex_unlock(&fQueueLock);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
WorkQueue::LaunchWorkingThread(void* object)
|
WorkQueue::LaunchWorkingThread(void* object)
|
||||||
{
|
{
|
||||||
@@ -216,3 +260,19 @@ WorkQueue::JobIO(IORequestArgs* args)
|
|||||||
args->fInode->EndAIOOp();
|
args->fInode->EndAIOOp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
WorkQueue::_DumpLocked(void (*xprintf)(const char*, ...)) const
|
||||||
|
{
|
||||||
|
uint64 entries = 0;
|
||||||
|
for (DoublyLinkedList<WorkQueueEntry>::ConstIterator it = fQueue.GetIterator();
|
||||||
|
const WorkQueueEntry* entry = it.Next(); ++entries) {
|
||||||
|
entry->Dump(xprintf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entries == 0)
|
||||||
|
xprintf("\tEmpty\n");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ struct IORequestArgs {
|
|||||||
struct WorkQueueEntry : public DoublyLinkedListLinkImpl<WorkQueueEntry> {
|
struct WorkQueueEntry : public DoublyLinkedListLinkImpl<WorkQueueEntry> {
|
||||||
JobType fType;
|
JobType fType;
|
||||||
void* fArguments;
|
void* fArguments;
|
||||||
|
|
||||||
|
void Dump(void (*xprintf)(const char*, ...)) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WorkQueue {
|
class WorkQueue {
|
||||||
@@ -47,6 +49,8 @@ public:
|
|||||||
|
|
||||||
status_t EnqueueJob(JobType type, void* args);
|
status_t EnqueueJob(JobType type, void* args);
|
||||||
|
|
||||||
|
void Dump(void (*xprintf)(const char*, ...) = dprintf);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static status_t LaunchWorkingThread(void* object);
|
static status_t LaunchWorkingThread(void* object);
|
||||||
status_t WorkingThread();
|
status_t WorkingThread();
|
||||||
@@ -56,6 +60,9 @@ protected:
|
|||||||
void JobRecall(DelegationRecallArgs* args);
|
void JobRecall(DelegationRecallArgs* args);
|
||||||
void JobIO(IORequestArgs* args);
|
void JobIO(IORequestArgs* args);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _DumpLocked(void (*xprintf)(const char*, ...)) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t fInitError;
|
status_t fInitError;
|
||||||
|
|
||||||
|
|||||||
@@ -602,10 +602,15 @@ nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name)
|
|||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
ino_t id;
|
ino_t id;
|
||||||
inode->LookUp(name, &id);
|
status_t result = inode->LookUp(name, &id);
|
||||||
|
if (result != B_OK)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
VnodeToInode* childVti = NULL;
|
VnodeToInode* childVti = NULL;
|
||||||
status_t result = get_vnode(volume, id, reinterpret_cast<void**>(&childVti));
|
result = get_vnode(volume, id, reinterpret_cast<void**>(&childVti));
|
||||||
if (result == B_OK) {
|
if (result == B_OK) {
|
||||||
|
childVti->Get();
|
||||||
|
// Needed to ensure childVti::fInode is non-NULL prior to VnodeToInode::Unlink.
|
||||||
ino_t removedId;
|
ino_t removedId;
|
||||||
status_t result = inode->Remove(name, NF4REG, &removedId);
|
status_t result = inode->Remove(name, NF4REG, &removedId);
|
||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
@@ -613,7 +618,7 @@ nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name)
|
|||||||
ASSERT(removedId == id);
|
ASSERT(removedId == id);
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
if (vti->Unlink(inode->fInfo.fNames, name))
|
if (childVti->Unlink(inode->fInfo.fNames, name))
|
||||||
remove_vnode(volume, id);
|
remove_vnode(volume, id);
|
||||||
|
|
||||||
put_vnode(volume, id);
|
put_vnode(volume, id);
|
||||||
|
|||||||
Reference in New Issue
Block a user