nfs4: support hard links properly

The main purpose of this patch is to prevent VFS from removing a vnode to early
what might have happened if the NFS client knew it had more than one name but
then one of them was deleted. Moreover, all discovered and still valid names
are stored what may be useful in proper file handle recovery when they are
volatile.

This patch fixes both #9558 and #9561.
This commit is contained in:
Pawel Dziepak 2013-03-26 02:31:31 +01:00
parent efc29cc57a
commit 469f13fdfe
16 changed files with 487 additions and 373 deletions

View File

@ -308,19 +308,6 @@ DirectoryCache::NotifyChanges(DirectoryCacheSnapshot* oldSnapshot,
} else {
notify_entry_created(fInode->GetFileSystem()->DevId(),
fInode->ID(), newCurrent->fName, newCurrent->fNode);
do {
FileInfo fi;
fi.fFileId = newCurrent->fNode;
fi.fParent = fInode->fInfo.fHandle;
status_t result = fi.CreateName(fInode->fInfo.fPath,
newCurrent->fName);
if (result != B_OK)
break;
fInode->GetFileSystem()->InoIdMap()->AddEntry(fi,
Inode::FileIdToInoT(newCurrent->fNode), true);
} while (false);
}
} else
oldSnapshot->fEntries.Remove(prev, oldCurrent);

View File

@ -13,80 +13,122 @@
#include "Request.h"
status_t
FileInfo::ParsePath(RequestBuilder& req, uint32& count, const char* _path,
bool getFileHandle)
InodeName::InodeName(InodeNames* parent, const char* name)
:
fParent(parent),
fName(strdup(name))
{
ASSERT(_path != NULL);
if (fParent != NULL)
fParent->AcquireReference();
}
char* path = strdup(_path);
if (path == NULL)
return B_NO_MEMORY;
char* pathStart = path;
char* pathEnd;
InodeName::~InodeName()
{
if (fParent != NULL)
fParent->ReleaseReference();
free(const_cast<char*>(fName));
}
while (pathStart != NULL) {
pathEnd = strchr(pathStart, '/');
if (pathEnd != NULL)
*pathEnd = '\0';
if (pathEnd != pathStart) {
if (!strcmp(pathStart, "..")) {
req.LookUpUp();
count++;
} else if (strcmp(pathStart, ".")) {
req.LookUp(pathStart);
if (getFileHandle)
req.GetFH();
count++;
}
}
InodeNames::InodeNames()
{
mutex_init(&fLock, NULL);
}
if (pathEnd != NULL && pathEnd[1] != '\0')
pathStart = pathEnd + 1;
else
pathStart = NULL;
}
free(path);
return B_OK;
InodeNames::~InodeNames()
{
while (!fNames.IsEmpty())
delete fNames.RemoveHead();
mutex_destroy(&fLock);
}
status_t
FileInfo::CreateName(const char* dirPath, const char* name)
InodeNames::AddName(InodeNames* parent, const char* name)
{
ASSERT(name != NULL);
MutexLocker _(fLock);
free(const_cast<char*>(fName));
fName = strdup(name);
if (fName == NULL)
InodeName* current = fNames.Head();
while (current != NULL) {
if (current->fParent == parent && !strcmp(current->fName, name))
return B_OK;
current = fNames.GetNext(current);
}
InodeName* newName = new InodeName(parent, name);
if (newName == NULL)
return B_NO_MEMORY;
free(const_cast<char*>(fPath));
fPath = NULL;
if (dirPath != NULL) {
char* path = reinterpret_cast<char*>(malloc(strlen(name) + 2
+ strlen(dirPath)));
if (path == NULL)
return B_NO_MEMORY;
strcpy(path, dirPath);
strcat(path, "/");
strcat(path, name);
fPath = path;
} else
fPath = strdup(name);
if (fPath == NULL)
return B_NO_MEMORY;
fNames.Add(newName);
return B_OK;
}
bool
InodeNames::RemoveName(InodeNames* parent, const char* name)
{
MutexLocker _(fLock);
InodeName* previous = NULL;
InodeName* current = fNames.Head();
while (current != NULL) {
if (current->fParent == parent && !strcmp(current->fName, name)) {
fNames.Remove(previous, current);
delete current;
break;
}
previous = current;
current = fNames.GetNext(current);
}
return fNames.IsEmpty();
}
FileInfo::FileInfo()
:
fFileId(0),
fNames(NULL)
{
}
FileInfo::~FileInfo()
{
if (fNames != NULL)
fNames->ReleaseReference();
}
FileInfo::FileInfo(const FileInfo& fi)
:
fFileId(fi.fFileId),
fHandle(fi.fHandle),
fNames(fi.fNames)
{
if (fNames != NULL)
fNames->AcquireReference();
}
FileInfo&
FileInfo::operator=(const FileInfo& fi)
{
fFileId = fi.fFileId;
fHandle = fi.fHandle;
if (fNames != NULL)
fNames->ReleaseReference();
fNames = fi.fNames;
if (fNames != NULL)
fNames->AcquireReference();
return *this;
}
status_t
FileInfo::UpdateFileHandles(FileSystem* fs)
{
@ -96,16 +138,41 @@ FileInfo::UpdateFileHandles(FileSystem* fs)
RequestBuilder& req = request.Builder();
req.PutRootFH();
req.GetFH();
uint32 lookupCount = 0;
status_t result = ParsePath(req, lookupCount, fs->Path(), true);
if (result != B_OK)
return result;
const char** path = fs->Path();
if (path != NULL) {
for (; path[lookupCount] != NULL; lookupCount++)
req.LookUp(path[lookupCount]);
}
result = ParsePath(req, lookupCount, fPath, true);
if (result != B_OK)
return result;
uint32 i;
InodeNames* names = fNames;
for (i = 0; names != NULL; i++)
names = names->fNames.Head()->fParent;
if (i > 0) {
names = fNames;
InodeNames** pathNames = new InodeNames*[i];
if (pathNames == NULL)
return B_NO_MEMORY;
for (i = 0; names != NULL; i++) {
pathNames[i] = names;
names = names->fNames.Head()->fParent;
}
for (; i > 0; i--) {
if (!strcmp(pathNames[i - 1]->fNames.Head()->fName, ""))
continue;
req.LookUp(pathNames[i - 1]->fNames.Head()->fName);
lookupCount++;
}
delete[] pathNames;
}
req.GetFH();
if (fs->IsAttrSupported(FATTR4_FILEID)) {
AttrValue attr;
@ -115,25 +182,20 @@ FileInfo::UpdateFileHandles(FileSystem* fs)
req.Verify(&attr, 1);
}
result = request.Send();
status_t result = request.Send();
if (result != B_OK)
return result;
ReplyInterpreter& reply = request.Reply();
FileHandle parent;
FileHandle child;
reply.PutRootFH();
reply.GetFH(&child);
parent = child;
for (uint32 i = 0; i < lookupCount; i++) {
for (uint32 i = 0; i < lookupCount; i++)
reply.LookUp();
parent = child;
result = reply.GetFH(&child);
if (result != B_OK)
return result;
}
FileHandle handle;
result = reply.GetFH(&handle);
if (result != B_OK)
return result;
if (fs->IsAttrSupported(FATTR4_FILEID)) {
result = reply.Verify();
@ -141,8 +203,8 @@ FileInfo::UpdateFileHandles(FileSystem* fs)
return result;
}
fHandle = child;
fParent = parent;
fHandle = handle;
fNames->fHandle = handle;
return B_OK;
}

View File

@ -12,7 +12,9 @@
#include <stdlib.h>
#include <string.h>
#include <lock.h>
#include <SupportDefs.h>
#include <util/KernelReferenceable.h>
#define NFS4_FHSIZE 128
@ -26,11 +28,34 @@ struct FileHandle {
inline FileHandle& operator=(const FileHandle& fh);
inline bool operator==(const FileHandle& handle) const;
inline bool operator!=(const FileHandle& handle) const;
inline bool operator>(const FileHandle& handle) const;
inline bool operator<(const FileHandle& handle) const;
};
class InodeNames;
struct InodeName : public SinglyLinkedListLinkImpl<InodeName> {
InodeName(InodeNames* parent, const char* name);
~InodeName();
InodeNames* fParent;
const char* fName;
};
struct InodeNames : public KernelReferenceable {
InodeNames();
~InodeNames();
status_t AddName(InodeNames* parent, const char* name);
bool RemoveName(InodeNames* parent,
const char* name);
mutex fLock;
SinglyLinkedList<InodeName> fNames;
FileHandle fHandle;
};
class FileSystem;
class RequestBuilder;
@ -42,23 +67,16 @@ struct FileInfo {
uint64 fFileId;
FileHandle fHandle;
FileHandle fParent;
const char* fName;
const char* fPath;
InodeNames* fNames;
FileHandle fAttrDir;
inline FileInfo();
inline ~FileInfo();
inline FileInfo(const FileInfo& fi);
inline FileInfo& operator=(const FileInfo& fi);
FileInfo();
~FileInfo();
FileInfo(const FileInfo& fi);
FileInfo& operator=(const FileInfo& fi);
status_t UpdateFileHandles(FileSystem* fs);
static status_t ParsePath(RequestBuilder& req, uint32& count,
const char* _path, bool getFileHandle = false);
status_t CreateName(const char* dirPath, const char* name);
};
struct FileSystemId {
@ -97,11 +115,18 @@ FileHandle::operator=(const FileHandle& fh)
inline bool
FileHandle::operator!=(const FileHandle& handle) const
FileHandle::operator==(const FileHandle& handle) const
{
if (fSize != handle.fSize)
return true;
return memcmp(fData, handle.fData, fSize) != 0;
return false;
return memcmp(fData, handle.fData, fSize) == 0;
}
inline bool
FileHandle::operator!=(const FileHandle& handle) const
{
return !operator==(handle);
}
@ -123,53 +148,6 @@ FileHandle::operator<(const FileHandle& handle) const
}
inline
FileInfo::FileInfo()
:
fFileId(0),
fName(NULL),
fPath(NULL)
{
}
inline
FileInfo::~FileInfo()
{
free(const_cast<char*>(fName));
free(const_cast<char*>(fPath));
}
inline
FileInfo::FileInfo(const FileInfo& fi)
:
fFileId(fi.fFileId),
fHandle(fi.fHandle),
fParent(fi.fParent),
fName(strdup(fi.fName)),
fPath(strdup(fi.fPath))
{
}
inline FileInfo&
FileInfo::operator=(const FileInfo& fi)
{
fFileId = fi.fFileId;
fHandle = fi.fHandle;
fParent = fi.fParent;
free(const_cast<char*>(fName));
fName = strdup(fi.fName);
free(const_cast<char*>(fPath));
fPath = strdup(fi.fPath);
return *this;
}
inline bool
FileSystemId::operator==(const FileSystemId& fsid) const
{

View File

@ -54,33 +54,74 @@ FileSystem::~FileSystem()
mutex_destroy(&fOpenOwnerLock);
mutex_destroy(&fCreateFileLock);
free(const_cast<char*>(fPath));
if (fPath != NULL) {
for (uint32 i = 0; fPath[i] != NULL; i++)
free(const_cast<char*>(fPath[i]));
}
delete[] fPath;
delete fRoot;
}
static const char*
GetPath(const char* root, const char* path)
static InodeNames*
GetInodeNames(const char** root, const char* _path)
{
ASSERT(path != NULL);
ASSERT(_path != NULL);
int slash = 0;
int i;
for (i = 0; path[i] != '\0'; i++) {
if (path[i] == '/')
slash = i;
char* path = strdup(_path);
if (path == NULL)
return NULL;
MemoryDeleter _(path);
if (root == NULL)
break;
if (root != NULL) {
for (i = 0; root[i] != NULL; i++) {
char* pathEnd = strchr(path, '/');
if (pathEnd == path) {
path++;
i--;
continue;
}
if (path[i] != root[i] || root[i] == '\0')
break;
if (pathEnd == NULL) {
path = NULL;
break;
} else
path = pathEnd + 1;
}
}
if (path[i] == '\0')
return NULL;
InodeNames* names = NULL;
if (path == NULL) {
names = new InodeNames;
if (names == NULL)
return NULL;
return path + slash;
names->AddName(NULL, "");
return names;
}
do {
char* pathEnd = strchr(path, '/');
if (pathEnd != NULL)
*pathEnd = '\0';
InodeNames* name = new InodeNames;
if (name == NULL) {
delete names;
return NULL;
}
name->AddName(names, path);
names = name;
if (pathEnd == NULL)
break;
path = pathEnd + 1;
} while (*path != '\0');
return names;
}
@ -103,7 +144,7 @@ FileSystem::Mount(FileSystem** _fs, RPC::Server* serv, const char* fsPath,
req.PutRootFH();
uint32 lookupCount = 0;
status_t result = FileInfo::ParsePath(req, lookupCount, fsPath);
status_t result = _ParsePath(req, lookupCount, fsPath);
if (result != B_OK)
return result;
@ -156,30 +197,25 @@ FileSystem::Mount(FileSystem** _fs, RPC::Server* serv, const char* fsPath,
FSLocations* locs
= reinterpret_cast<FSLocations*>(values[3].fData.fLocations);
fs->fPath = strdup(locs->fRootPath);
fs->fPath = locs->fRootPath;
locs->fRootPath = NULL;
} else
fs->fPath = NULL;
FileInfo fi;
const char* name;
if (fsPath != NULL && fsPath[0] == '/')
fsPath++;
fs->fServer = serv;
fs->fDevId = id;
fs->fFsId = *fsid;
fi.fHandle = fh;
fi.fParent = fh;
fi.fPath = strdup(GetPath(fs->fPath, fsPath));
if (fi.fPath != NULL) {
name = strrchr(fi.fPath, '/');
if (name != NULL) {
name++;
fi.fName = strdup(name);
}
fi.fNames = GetInodeNames(fs->fPath, fsPath);
if (fi.fNames == NULL) {
delete[] values;
return B_NO_MEMORY;
}
fi.fNames->fHandle = fh;
delete[] values;
@ -188,7 +224,7 @@ FileSystem::Mount(FileSystem** _fs, RPC::Server* serv, const char* fsPath,
if (result != B_OK)
return result;
name = strrchr(fsPath, '/');
char* name = strrchr(fsPath, '/');
if (name != NULL) {
name++;
reinterpret_cast<RootInode*>(inode)->SetName(name);
@ -263,8 +299,14 @@ FileSystem::Migrate(const RPC::Server* serv)
if (gRPCServerManager->Acquire(&fServer, &resolver,
CreateNFS4Server) == B_OK) {
free(const_cast<char*>(fPath));
fPath = strdup(locs->fLocations[i].fRootPath);
if (fPath != NULL) {
for (uint32 i = 0; fPath[i] != NULL; i++)
free(const_cast<char*>(fPath[i]));
}
delete[] fPath;
fPath = locs->fLocations[i].fRootPath;
locs->fLocations[i].fRootPath = NULL;
if (fPath == NULL) {
gRPCServerManager->Release(fServer);
@ -391,3 +433,41 @@ FileSystem::GetDelegation(const FileHandle& handle)
return it.Current();
}
status_t
FileSystem::_ParsePath(RequestBuilder& req, uint32& count, const char* _path)
{
ASSERT(_path != NULL);
char* path = strdup(_path);
if (path == NULL)
return B_NO_MEMORY;
char* pathStart = path;
char* pathEnd;
while (pathStart != NULL) {
pathEnd = strchr(pathStart, '/');
if (pathEnd != NULL)
*pathEnd = '\0';
if (pathEnd != pathStart) {
if (!strcmp(pathStart, "..")) {
req.LookUpUp();
count++;
} else if (strcmp(pathStart, ".")) {
req.LookUp(pathStart);
count++;
}
}
if (pathEnd != NULL && pathEnd[1] != '\0')
pathStart = pathEnd + 1;
else
pathStart = NULL;
}
free(path);
return B_OK;
}

View File

@ -59,7 +59,7 @@ public:
inline RPC::Server* Server();
inline NFS4Server* NFSServer();
inline const char* Path() const;
inline const char** Path() const;
inline const FileSystemId& FsId() const;
inline uint64 AllocFileId();
@ -80,6 +80,9 @@ public:
private:
FileSystem(const MountConfiguration& config);
static status_t _ParsePath(RequestBuilder& req, uint32& count,
const char* _path);
mutex fCreateFileLock;
mutex fDelegationLock;
@ -99,7 +102,7 @@ private:
bool fNamedAttrs;
FileSystemId fFsId;
const char* fPath;
const char** fPath;
RootInode* fRoot;
@ -158,7 +161,7 @@ FileSystem::NFSServer()
}
inline const char*
inline const char**
FileSystem::Path() const
{
ASSERT(fPath != NULL);

View File

@ -232,14 +232,7 @@ Inode::Link(Inode* dir, const char* name)
return result;
fFileSystem->Root()->MakeInfoInvalid();
FileInfo fi = fInfo;
fi.fParent = dir->fInfo.fHandle;
result = fi.CreateName(fInfo.fPath, name);
if (result != B_OK)
return result;
fFileSystem->InoIdMap()->AddEntry(fi, fInfo.fFileId);
fInfo.fNames->AddName(dir->fInfo.fNames, name);
dir->fCache->Lock();
if (dir->fCache->Valid()) {
@ -875,19 +868,17 @@ Inode::ChildAdded(const char* name, uint64 fileID,
FileInfo fi;
fi.fFileId = fileID;
fi.fHandle = fileHandle;
fi.fParent = fInfo.fHandle;
status_t result = fi.CreateName(fInfo.fPath, name);
if (result != B_OK)
return result;
return fFileSystem->InoIdMap()->AddEntry(fi, FileIdToInoT(fileID));
return fFileSystem->InoIdMap()->AddName(fi, fInfo.fNames, name,
FileIdToInoT(fileID));
}
const char*
Inode::Name() const
{
return fInfo.fName;
ASSERT(fInfo.fNames->fNames.Head() != NULL);
return fInfo.fNames->fNames.Head()->fName;
}

View File

@ -0,0 +1,81 @@
/*
* Copyright 2013 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#include "InodeIdMap.h"
status_t
InodeIdMap::AddName(FileInfo& fileInfo, InodeNames* parent,
const char* name, ino_t id)
{
MutexLocker _(fLock);
AVLTreeMap<ino_t, FileInfo>::Iterator iterator = fMap.Find(id);
if (iterator.HasCurrent()) {
if (fileInfo.fHandle == iterator.Current().fHandle) {
return iterator.CurrentValuePointer()->fNames->AddName(parent,
name);
}
}
fMap.Remove(id);
fileInfo.fNames = new InodeNames;
if (fileInfo.fNames == NULL)
return B_NO_MEMORY;
fileInfo.fNames->fHandle = fileInfo.fHandle;
status_t result = fileInfo.fNames->AddName(parent, name);
if (result != B_OK) {
delete fileInfo.fNames;
return result;
}
return fMap.Insert(id, fileInfo);
}
bool
InodeIdMap::RemoveName(ino_t id, InodeNames* parent, const char* name)
{
ASSERT(name != NULL);
MutexLocker _(fLock);
AVLTreeMap<ino_t, FileInfo>::Iterator iterator = fMap.Find(id);
if (!iterator.HasCurrent())
return true;
FileInfo* fileInfo = iterator.CurrentValuePointer();
return fileInfo->fNames->RemoveName(parent, name);
}
status_t
InodeIdMap::RemoveEntry(ino_t id)
{
MutexLocker _(fLock);
return fMap.Remove(id);
}
status_t
InodeIdMap::GetFileInfo(FileInfo* fileInfo, ino_t id)
{
ASSERT(fileInfo != NULL);
MutexLocker _(fLock);
AVLTreeMap<ino_t, FileInfo>::Iterator iterator = fMap.Find(id);
if (!iterator.HasCurrent())
return B_ENTRY_NOT_FOUND;
*fileInfo = iterator.Current();
if (fileInfo->fNames->fNames.IsEmpty())
return B_ENTRY_NOT_FOUND;
return B_OK;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Copyright 2012,2013 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -16,27 +16,24 @@
#include "FileInfo.h"
struct InodeIdMapEntry {
FileInfo fFileInfo;
bool fRemoved;
};
class InodeIdMap {
public:
inline InodeIdMap();
inline ~InodeIdMap();
inline status_t AddEntry(const FileInfo& fi,
ino_t id, bool weak = false);
inline status_t MarkRemoved(ino_t id);
inline status_t RemoveEntry(ino_t id);
inline status_t GetFileInfo(FileInfo* fi, ino_t id);
protected:
inline bool _IsEntryRemoved(ino_t id);
status_t AddName(FileInfo& fileInfo,
InodeNames* parent,
const char* name, ino_t id);
bool RemoveName(ino_t id,
InodeNames* parent,
const char* name);
status_t RemoveEntry(ino_t id);
status_t GetFileInfo(FileInfo* fileInfo,
ino_t id);
private:
AVLTreeMap<ino_t, InodeIdMapEntry> fMap;
AVLTreeMap<ino_t, FileInfo> fMap;
mutex fLock;
};
@ -56,71 +53,5 @@ InodeIdMap::~InodeIdMap()
}
inline status_t
InodeIdMap::AddEntry(const FileInfo& fi, ino_t id, bool weak)
{
InodeIdMapEntry entry;
MutexLocker _(fLock);
if (!weak || _IsEntryRemoved(id))
fMap.Remove(id);
entry.fFileInfo = fi;
entry.fRemoved = false;
return fMap.Insert(id, entry);
}
inline status_t
InodeIdMap::MarkRemoved(ino_t id)
{
MutexLocker _(fLock);
AVLTreeMap<ino_t, InodeIdMapEntry>::Iterator it = fMap.Find(id);
if (!it.HasCurrent())
return B_ENTRY_NOT_FOUND;
it.CurrentValuePointer()->fRemoved = true;
return B_OK;
}
inline status_t
InodeIdMap::RemoveEntry(ino_t id)
{
MutexLocker _(fLock);
if (_IsEntryRemoved(id))
return fMap.Remove(id);
return B_OK;
}
inline status_t
InodeIdMap::GetFileInfo(FileInfo* fi, ino_t id)
{
ASSERT(fi != NULL);
MutexLocker _(fLock);
AVLTreeMap<ino_t, InodeIdMapEntry>::Iterator it = fMap.Find(id);
if (!it.HasCurrent())
return B_ENTRY_NOT_FOUND;
*fi = it.Current().fFileInfo;
return B_OK;
}
// Caller must hold fLock
inline bool
InodeIdMap::_IsEntryRemoved(ino_t id)
{
AVLTreeMap<ino_t, InodeIdMapEntry>::Iterator it = fMap.Find(id);
if (!it.HasCurrent())
return true;
return it.Current().fRemoved;
}
#endif // INODEIDMAP_H

View File

@ -36,13 +36,12 @@ Inode::CreateState(const char* name, int mode, int perms, OpenState* state,
if (result != B_OK)
return result;
FileInfo fi;
fi.fFileId = fileID;
fi.fHandle = handle;
fi.fParent = fInfo.fHandle;
fi.CreateName(fInfo.fPath, name);
FileInfo fileInfo;
fileInfo.fFileId = fileID;
fileInfo.fHandle = handle;
fFileSystem->InoIdMap()->AddEntry(fi, FileIdToInoT(fileID));
fFileSystem->InoIdMap()->AddName(fileInfo, fInfo.fNames, name,
FileIdToInoT(fileID));
fCache->Lock();
if (fCache->Valid()) {
@ -56,7 +55,7 @@ Inode::CreateState(const char* name, int mode, int perms, OpenState* state,
fCache->Unlock();
state->fFileSystem = fFileSystem;
state->fInfo = fi;
state->fInfo = fileInfo;
state->fMode = mode & O_RWMASK;
return B_OK;
@ -253,8 +252,6 @@ Inode::OpenAttr(const char* _name, int mode, OpenAttrCookie* cookie,
if (state == NULL)
return B_NO_MEMORY;
state->fInfo.fName = strdup(name);
state->fInfo.fParent = fInfo.fAttrDir;
state->fFileSystem = fFileSystem;
result = NFS4Inode::OpenAttr(state, name, mode, &data, create);
if (result != B_OK) {

View File

@ -12,6 +12,7 @@ KernelAddon nfs4 :
FileSystem.cpp
IdMap.cpp
Inode.cpp
InodeIdMap.cpp
InodeDir.cpp
InodeRegular.cpp
kernel_interface.cpp

View File

@ -125,10 +125,8 @@ NFS4Inode::LookUp(const char* name, uint64* change, uint64* fileID,
Request request(serv, fFileSystem);
RequestBuilder& req = request.Builder();
if (parent)
req.PutFH(fInfo.fParent);
else
req.PutFH(fInfo.fHandle);
(void)parent; // TODO: add support for named attributes
req.PutFH(fInfo.fHandle);
if (change != NULL) {
Attribute dirAttr[] = { FATTR4_CHANGE };
@ -562,16 +560,16 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation)
// Since we are opening the file using a pair (parentFH, name) we
// need to check for race conditions.
if (fFileSystem->IsAttrSupported(FATTR4_FILEID)) {
req.PutFH(fInfo.fParent);
req.LookUp(fInfo.fName);
req.PutFH(fInfo.fNames->fNames.Head()->fParent->fHandle);
req.LookUp(fInfo.fNames->fNames.Head()->fName);
AttrValue attr;
attr.fAttribute = FATTR4_FILEID;
attr.fFreePointer = false;
attr.fData.fValue64 = fInfo.fFileId;
req.Verify(&attr, 1);
} else if (fFileSystem->ExpireType() == FH4_PERSISTENT) {
req.PutFH(fInfo.fParent);
req.LookUp(fInfo.fName);
req.PutFH(fInfo.fNames->fNames.Head()->fParent->fHandle);
req.LookUp(fInfo.fNames->fNames.Head()->fName);
AttrValue attr;
attr.fAttribute = FATTR4_FILEHANDLE;
attr.fFreePointer = true;
@ -580,9 +578,10 @@ NFS4Inode::OpenFile(OpenState* state, int mode, OpenDelegationData* delegation)
req.Verify(&attr, 1);
}
req.PutFH(fInfo.fParent);
req.PutFH(fInfo.fNames->fNames.Head()->fParent->fHandle);
req.Open(CLAIM_NULL, sequence, sModeToAccess(mode), state->fClientID,
OPEN4_NOCREATE, fFileSystem->OpenOwner(), fInfo.fName);
OPEN4_NOCREATE, fFileSystem->OpenOwner(),
fInfo.fNames->fNames.Head()->fName);
req.GetFH();
result = request.Send();
@ -796,10 +795,8 @@ NFS4Inode::CreateObject(const char* name, const char* path, int mode,
Request request(serv, fFileSystem);
RequestBuilder& req = request.Builder();
if (parent)
req.PutFH(fInfo.fParent);
else
req.PutFH(fInfo.fHandle);
(void)parent; // TODO: support named attributes
req.PutFH(fInfo.fHandle);
uint32 i = 0;
AttrValue cattr[1];

View File

@ -19,7 +19,12 @@
FSLocation::~FSLocation()
{
free(const_cast<char*>(fRootPath));
if (fRootPath != NULL) {
for (uint32 i = 0; fRootPath[i] != NULL; i++)
free(const_cast<char*>(fRootPath[i]));
}
delete[] fRootPath;
for (uint32 i = 0; i < fCount; i++)
free(const_cast<char*>(fLocations[i]));
delete[] fLocations;
@ -28,7 +33,12 @@ FSLocation::~FSLocation()
FSLocations::~FSLocations()
{
free(const_cast<char*>(fRootPath));
if (fRootPath != NULL) {
for (uint32 i = 0; fRootPath[i] != NULL; i++)
free(const_cast<char*>(fRootPath[i]));
}
delete[] fRootPath;
delete[] fLocations;
}
@ -528,27 +538,29 @@ ReplyInterpreter::Write(uint32* size)
}
const char*
ReplyInterpreter::_FlattenPathname(XDR::ReadStream& stream)
const char**
ReplyInterpreter::_GetPath(XDR::ReadStream& stream)
{
uint32 count = stream.GetUInt();
char* pathname = NULL;
uint32 size = 0;
for (uint32 i = 0; i < count; i++) {
const char* path = stream.GetString();
size += strlen(path) + 1;
if (pathname == NULL) {
pathname = reinterpret_cast<char*>(malloc(strlen(path) + 1));
pathname[0] = '\0';
} else {
*pathname++ = '/';
pathname = reinterpret_cast<char*>(realloc(pathname, size));
}
strcat(pathname, path);
free(const_cast<char*>(path));
}
char** path = new char*[count + 1];
if (path == NULL)
return NULL;
return pathname;
uint32 i;
for (i = 0; i < count; i++) {
path[i] = stream.GetString();
if (path[i] == NULL)
goto out;
}
path[count] = NULL;
return const_cast<const char**>(path);
out:
for (uint32 j = 0; j < i; j++)
free(path[i]);
delete[] path;
return NULL;
}
@ -662,11 +674,11 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs,
values[current].fAttribute = FATTR4_FS_LOCATIONS;
FSLocations* locs = new FSLocations;
locs->fRootPath = _FlattenPathname(stream);
locs->fRootPath = _GetPath(stream);
locs->fCount = stream.GetUInt();
locs->fLocations = new FSLocation[locs->fCount];
for (uint32 i = 0; i < locs->fCount; i++) {
locs->fLocations[i].fRootPath = _FlattenPathname(stream);
locs->fLocations[i].fRootPath = _GetPath(stream);
locs->fLocations[i].fCount = stream.GetUInt();
locs->fLocations[i].fLocations
= new const char*[locs->fLocations[i].fCount];

View File

@ -17,7 +17,8 @@
struct FSLocation {
const char* fRootPath;
const char** fRootPath;
const char** fLocations;
uint32 fCount;
@ -25,7 +26,8 @@ struct FSLocation {
};
struct FSLocations {
const char* fRootPath;
const char** fRootPath;
FSLocation* fLocations;
uint32 fCount;
@ -108,7 +110,7 @@ public:
private:
void _ParseHeader();
static const char* _FlattenPathname(XDR::ReadStream& stream);
static const char** _GetPath(XDR::ReadStream& stream);
status_t _DecodeAttrs(XDR::ReadStream& stream, AttrValue** attrs,
uint32* count);

View File

@ -27,15 +27,27 @@ void
VnodeToInode::Replace(Inode* newInode)
{
WriteLocker _(fLock);
if (fInode != NULL && !IsRoot()) {
fInode->GetFileSystem()->InoIdMap()->MarkRemoved(fID);
if (fInode != NULL && !IsRoot())
delete fInode;
}
fInode = newInode;
if (fInode != NULL) {
ASSERT(fFileSystem == fInode->GetFileSystem());
fInode->GetFileSystem()->InoIdMap()->AddEntry(fInode->fInfo, fID);
}
}
bool
VnodeToInode::Unlink(InodeNames* parent, const char* name)
{
WriteLocker _(fLock);
if (fInode != NULL && !IsRoot()) {
bool removed = fInode->GetFileSystem()->InoIdMap()->RemoveName(fID,
parent, name);
if (removed) {
delete fInode;
fInode = NULL;
}
return removed;
}
return false;
}

View File

@ -28,7 +28,7 @@ public:
Inode* Get();
void Replace(Inode* newInode);
inline void Remove();
bool Unlink(InodeNames* parent, const char* name);
inline void Clear();
inline ino_t ID() const;
@ -72,7 +72,7 @@ VnodeToInode::VnodeToInode(ino_t id, FileSystem* fileSystem)
inline
VnodeToInode::~VnodeToInode()
{
Remove();
Replace(NULL);
if (fFileSystem != NULL && !IsRoot())
fFileSystem->InoIdMap()->RemoveEntry(fID);
rw_lock_destroy(&fLock);
@ -93,13 +93,6 @@ VnodeToInode::Unlock()
}
inline void
VnodeToInode::Remove()
{
Replace(NULL);
}
inline void
VnodeToInode::Clear()
{

View File

@ -321,23 +321,6 @@ nfs4_lookup(fs_volume* volume, fs_vnode* dir, const char* name, ino_t* _id)
}
static status_t
nfs4_get_vnode_name(fs_volume* volume, fs_vnode* vnode, char* buffer,
size_t bufferSize)
{
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %" B_PRIi64, volume, vti->ID());
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
strncpy(buffer, inode->Name(), bufferSize);
return B_OK;
}
static status_t
nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter)
{
@ -606,11 +589,12 @@ nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name)
if (result == B_OK) {
result = get_vnode(volume, id, reinterpret_cast<void**>(&vti));
ASSERT(result == B_OK);
vti->Remove();
put_vnode(volume, id);
remove_vnode(volume, id);
if (vti->Unlink(inode->fInfo.fNames, name))
remove_vnode(volume, id);
put_vnode(volume, id);
put_vnode(volume, id);
}
return B_OK;
@ -654,9 +638,10 @@ nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName,
if (result == B_OK) {
result = get_vnode(volume, oldID, reinterpret_cast<void**>(&vti));
ASSERT(result == B_OK);
vti->Remove();
if (vti->Unlink(toInode->fInfo.fNames, toName))
remove_vnode(volume, oldID);
put_vnode(volume, oldID);
remove_vnode(volume, oldID);
put_vnode(volume, oldID);
}
}
@ -670,8 +655,8 @@ nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName,
}
unremove_vnode(volume, id);
child->fInfo.fParent = toInode->fInfo.fHandle;
child->fInfo.CreateName(toInode->fInfo.fPath, toName);
child->fInfo.fNames->RemoveName(fromInode->fInfo.fNames, fromName);
child->fInfo.fNames->AddName(toInode->fInfo.fNames, toName);
put_vnode(volume, id);
}
@ -998,11 +983,13 @@ nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name)
result = acquire_vnode(volume, id);
if (result == B_OK) {
ASSERT(get_vnode(volume, id, reinterpret_cast<void**>(&vti)) == B_OK);
vti->Remove();
put_vnode(volume, id);
remove_vnode(volume, id);
result = get_vnode(volume, id, reinterpret_cast<void**>(&vti));
ASSERT(result == B_OK);
if (vti->Unlink(inode->fInfo.fNames, name))
remove_vnode(volume, id);
put_vnode(volume, id);
put_vnode(volume, id);
}
@ -1444,7 +1431,7 @@ fs_volume_ops gNFSv4VolumeOps = {
fs_vnode_ops gNFSv4VnodeOps = {
nfs4_lookup,
nfs4_get_vnode_name,
NULL, // get_vnode_name()
nfs4_put_vnode,
nfs4_remove_vnode,