nfs4: Introduce VnodeToInode mapping

VnodeToInode is another abstraction layer between VFS vnodes and NFS nodes.
It simplifies dealing with race conditions as well as faking some guarantees
VFS expects but NFS does not provide.
This commit is contained in:
Pawel Dziepak
2012-12-03 22:47:18 +01:00
parent fa5d300d6b
commit b352cbf6ca
10 changed files with 584 additions and 158 deletions
@@ -41,7 +41,6 @@ FileSystem::FileSystem(const MountConfiguration& configuration)
mutex_init(&fOpenOwnerLock, NULL);
mutex_init(&fOpenLock, NULL);
mutex_init(&fDelegationLock, NULL);
rw_lock_init(&fRemoveNodeLock, NULL);
}
@@ -49,7 +48,6 @@ FileSystem::~FileSystem()
{
NFSServer()->RemoveFileSystem(this);
rw_lock_destroy(&fRemoveNodeLock);
mutex_destroy(&fDelegationLock);
mutex_destroy(&fOpenLock);
mutex_destroy(&fOpenOwnerLock);
@@ -78,8 +78,6 @@ public:
FileSystem* fNext;
FileSystem* fPrev;
rw_lock fRemoveNodeLock;
private:
FileSystem(const MountConfiguration& config);
+5 -10
View File
@@ -184,11 +184,6 @@ Inode::LookUp(const char* name, ino_t* id)
if (fType != NF4DIR)
return B_NOT_A_DIRECTORY;
if (!strcmp(name, ".")) {
*id = ID();
return B_OK;
}
uint64 change;
uint64 fileID;
FileHandle handle;
@@ -281,8 +276,6 @@ Inode::Remove(const char* name, FileType type, ino_t* id)
status_t result = NFS4Inode::RemoveObject(name, type, &changeInfo, &fileID);
if (result != B_OK)
return result;
if (type != NF4NAMEDATTR)
fFileSystem->InoIdMap()->MarkRemoved(fileID);
DirectoryCache* cache = type != NF4NAMEDATTR ? fCache : fAttrCache;
cache->Lock();
@@ -395,14 +388,15 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName,
status_t
Inode::CreateLink(const char* name, const char* path, int mode)
Inode::CreateLink(const char* name, const char* path, int mode, ino_t* id)
{
return CreateObject(name, path, mode, NF4LNK);
return CreateObject(name, path, mode, NF4LNK, id);
}
status_t
Inode::CreateObject(const char* name, const char* path, int mode, FileType type)
Inode::CreateObject(const char* name, const char* path, int mode, FileType type,
ino_t* id)
{
ASSERT(name != NULL);
ASSERT(type != NF4LNK || path != NULL);
@@ -435,6 +429,7 @@ Inode::CreateObject(const char* name, const char* path, int mode, FileType type)
notify_entry_created(fFileSystem->DevId(), ID(), name,
FileIdToInoT(fileID));
*id = FileIdToInoT(fileID);
return B_OK;
}
+4 -3
View File
@@ -51,10 +51,10 @@ public:
status_t SyncAndCommit(bool force = false);
status_t CreateObject(const char* name, const char* path,
int mode, FileType type);
int mode, FileType type, ino_t* id);
status_t CreateLink(const char* name, const char* path,
int mode);
int mode, ino_t* id);
status_t Link(Inode* dir, const char* name);
status_t Remove(const char* name, FileType type,
@@ -89,7 +89,8 @@ public:
status_t WriteDirect(OpenStateCookie* cookie, off_t pos,
const void* buffer, size_t* _length);
status_t CreateDir(const char* name, int mode);
status_t CreateDir(const char* name, int mode,
ino_t* id);
status_t OpenDir(OpenDirCookie* cookie);
status_t ReadDir(void* buffer, uint32 size,
uint32* count, OpenDirCookie* cookie);
@@ -18,9 +18,9 @@
status_t
Inode::CreateDir(const char* name, int mode)
Inode::CreateDir(const char* name, int mode, ino_t* id)
{
return CreateObject(name, NULL, mode, NF4DIR);
return CreateObject(name, NULL, mode, NF4DIR, id);
}
@@ -62,7 +62,7 @@ InodeIdMap::AddEntry(const FileInfo& fi, ino_t id, bool weak)
InodeIdMapEntry entry;
MutexLocker _(fLock);
if (weak || _IsEntryRemoved(id))
if (!weak || _IsEntryRemoved(id))
fMap.Remove(id);
entry.fFileInfo = fi;
@@ -35,6 +35,7 @@ KernelAddon nfs4 :
RPCCallbackServer.cpp
RPCReply.cpp
RPCServer.cpp
VnodeToInode.cpp
WorkQueue.cpp
XDR.cpp
;
@@ -0,0 +1,40 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, [email protected]
*/
#include "VnodeToInode.h"
Inode*
VnodeToInode::Get()
{
if (fInode == NULL) {
status_t result = fFileSystem->GetInode(fID, &fInode);
if (result != B_OK)
fInode = NULL;
}
return fInode;
}
void
VnodeToInode::Replace(Inode* newInode)
{
WriteLocker _(fLock);
if (fInode != NULL)
fInode->GetFileSystem()->InoIdMap()->MarkRemoved(fID);
delete fInode;
fInode = newInode;
if (fInode != NULL) {
ASSERT(fFileSystem == fInode->GetFileSystem());
fInode->GetFileSystem()->InoIdMap()->AddEntry(fInode->fInfo, fID);
}
}
@@ -0,0 +1,115 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, [email protected]
*/
#ifndef VNODETOINODE_H
#define VNODETOINODE_H
#include <lock.h>
#include <SupportDefs.h>
#include <util/AutoLock.h>
#include "Inode.h"
#include "InodeIdMap.h"
class VnodeToInode {
public:
inline VnodeToInode(ino_t id, FileSystem* fileSystem);
inline ~VnodeToInode();
inline void Lock();
inline void Unlock();
Inode* Get();
void Replace(Inode* newInode);
inline void Remove();
inline void Clear();
inline ino_t ID();
private:
ino_t fID;
rw_lock fLock;
Inode* fInode;
FileSystem* fFileSystem;
};
class VnodeToInodeLocking {
public:
inline bool Lock(VnodeToInode* vti)
{
vti->Lock();
return true;
}
inline void Unlock(VnodeToInode* vti)
{
vti->Unlock();
}
};
typedef AutoLocker<VnodeToInode, VnodeToInodeLocking> VnodeToInodeLocker;
inline
VnodeToInode::VnodeToInode(ino_t id, FileSystem* fileSystem)
:
fID(id),
fInode(NULL),
fFileSystem(fileSystem)
{
rw_lock_init(&fLock, NULL);
}
inline
VnodeToInode::~VnodeToInode()
{
Remove();
if (fFileSystem != NULL)
fFileSystem->InoIdMap()->RemoveEntry(fID);
rw_lock_destroy(&fLock);
}
inline void
VnodeToInode::Lock()
{
rw_lock_read_lock(&fLock);
}
inline void
VnodeToInode::Unlock()
{
rw_lock_read_unlock(&fLock);
}
inline void
VnodeToInode::Remove()
{
Replace(NULL);
}
inline void
VnodeToInode::Clear()
{
WriteLocker _(fLock);
delete fInode;
fInode = NULL;
}
inline ino_t
VnodeToInode::ID()
{
return fID;
}
#endif // VNODETOINODE_H
@@ -23,6 +23,7 @@
#include "RootInode.h"
#include "RPCCallbackServer.h"
#include "RPCServer.h"
#include "VnodeToInode.h"
#include "WorkQueue.h"
#ifdef DEBUG
@@ -190,7 +191,15 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags,
volume->private_volume = fs;
volume->ops = &gNFSv4VolumeOps;
result = publish_vnode(volume, inode->ID(), inode, &gNFSv4VnodeOps,
VnodeToInode* vti = new VnodeToInode(inode->ID(), fs);
if (vti == NULL) {
delete fs;
gRPCServerManager->Release(server);
return B_NO_MEMORY;
}
vti->Replace(inode);
result = publish_vnode(volume, inode->ID(), vti, &gNFSv4VnodeOps,
inode->Type(), 0);
if (result != B_OK)
return result;
@@ -207,16 +216,21 @@ static status_t
nfs4_get_vnode(fs_volume* volume, ino_t id, fs_vnode* vnode, int* _type,
uint32* _flags, bool reenter)
{
FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
TRACE("volume = %p, id = %llu", volume, id);
FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
VnodeToInode* vnodeToInode = new VnodeToInode(id, fs);
if (vnodeToInode == NULL)
return B_NO_MEMORY;
Inode* inode;
status_t result = fs->GetInode(id, &inode);
if (result != B_OK)
return result;
vnodeToInode->Replace(inode);
vnode->ops = &gNFSv4VnodeOps;
vnode->private_node = inode;
vnode->private_node = vnodeToInode;
*_type = inode->Type();
*_flags = 0;
@@ -253,22 +267,39 @@ nfs4_read_fs_info(fs_volume* volume, struct fs_info* info)
static status_t
nfs4_lookup(fs_volume* volume, fs_vnode* dir, const char* name, ino_t* _id)
{
FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
Inode* inode = reinterpret_cast<Inode*>(dir->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(dir->private_node);
TRACE("volume = %p, dir = %llu, name = %s", volume, inode->ID(), name);
if (!strcmp(name, ".")) {
*_id = vti->ID();
void* ptr;
return get_vnode(volume, *_id, &ptr);
}
ReadLocker(fs->fRemoveNodeLock);
VnodeToInodeLocker locker(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
TRACE("volume = %p, dir = %llu, name = %s", volume, vti->ID(), name);
status_t result = inode->LookUp(name, _id);
if (result != B_OK)
return result;
void* ptr;
locker.Unlock();
TRACE("*_id = %llu", *_id);
// If VTI holds an outdated Inode next operation performed on it will
// return either ERR_STALE or ERR_FHEXPIRED. Both of these error codes
// will cause FileInfo data to be updated (the former will also cause Inode
// object to be recreated). We are taking an optimistic (an lazy) approach
// here. The following code just ensures VTI won't be removed too soon.
void* ptr;
result = get_vnode(volume, *_id, &ptr);
unremove_vnode(volume, *_id);
if (result == B_OK)
unremove_vnode(volume, *_id);
return result;
}
@@ -277,9 +308,13 @@ static status_t
nfs4_get_vnode_name(fs_volume* volume, fs_vnode* vnode, char* buffer,
size_t bufferSize)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu", volume, vti->ID());
TRACE("volume = %p, vnode = %llu", volume, inode->ID());
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
strncpy(buffer, inode->Name(), bufferSize);
return B_OK;
@@ -289,17 +324,10 @@ nfs4_get_vnode_name(fs_volume* volume, fs_vnode* vnode, char* buffer,
static status_t
nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter)
{
FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu", volume, inode->ID());
if (fs->Root() == inode)
return B_OK;
inode->GetFileSystem()->InoIdMap()->RemoveEntry(inode->ID());
delete inode;
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu", volume, vti->ID());
delete vti;
return B_OK;
}
@@ -307,20 +335,15 @@ nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter)
static status_t
nfs4_remove_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter)
{
// It is the server that actually deletes a node. Nodes on client
// side are only an attempt to simulate local filesystem. Hence,
// this hook is the same as put_vnode().
FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu", volume, vti->ID());
TRACE("volume = %p, vnode = %llu", volume, inode->ID());
if (fs->Root() == inode)
if (fs->Root() == vti->Get())
return B_OK;
inode->GetFileSystem()->InoIdMap()->RemoveEntry(inode->ID());
delete inode;
ASSERT(vti->Get() == NULL);
delete vti;
return B_OK;
}
@@ -330,12 +353,16 @@ static status_t
nfs4_read_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos,
const iovec* vecs, size_t count, size_t* _numBytes)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu, cookie = %p, pos = %llu, " \
"count = %lu, numBytes = %lu", _volume, inode->ID(), _cookie, pos,
"count = %lu, numBytes = %lu", _volume, vti->ID(), _cookie, pos,
count, *_numBytes);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
status_t result;
@@ -370,12 +397,16 @@ static status_t
nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos,
const iovec* vecs, size_t count, size_t* _numBytes)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu, cookie = %p, pos = %llu, " \
"count = %lu, numBytes = %lu", _volume, inode->ID(), _cookie, pos,
"count = %lu, numBytes = %lu", _volume, vti->ID(), _cookie, pos,
count, *_numBytes);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
status_t result;
@@ -406,11 +437,15 @@ nfs4_write_pages(fs_volume* _volume, fs_vnode* vnode, void* _cookie, off_t pos,
static status_t
nfs4_io(fs_volume* volume, fs_vnode* vnode, void* cookie, io_request* request)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu, cookie = %p", volume, inode->ID(),
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu, cookie = %p", volume, vti->ID(),
cookie);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
IORequestArgs* args = new(std::nothrow) IORequestArgs;
if (args == NULL) {
notify_io_request(request, B_NO_MEMORY);
@@ -439,7 +474,8 @@ static status_t
nfs4_set_flags(fs_volume* volume, fs_vnode* vnode, void* _cookie, int flags)
{
TRACE("volume = %p, vnode = %llu, cookie = %p, flags = %d", volume,
reinterpret_cast<Inode*>(vnode->private_node)->ID(), _cookie, flags);
reinterpret_cast<VnodeToInode*>(vnode->private_node)->ID(), _cookie,
flags);
OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
cookie->fMode = (cookie->fMode & ~(O_APPEND | O_NONBLOCK)) | flags;
@@ -450,8 +486,14 @@ nfs4_set_flags(fs_volume* volume, fs_vnode* vnode, void* _cookie, int flags)
static status_t
nfs4_fsync(fs_volume* volume, fs_vnode* vnode)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu", volume, inode->ID());
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu", volume, vti->ID());
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
return inode->SyncAndCommit();
}
@@ -460,8 +502,14 @@ static status_t
nfs4_read_symlink(fs_volume* volume, fs_vnode* link, char* buffer,
size_t* _bufferSize)
{
Inode* inode = reinterpret_cast<Inode*>(link->private_node);
TRACE("volume = %p, link = %llu", volume, inode->ID());
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(link->private_node);
TRACE("volume = %p, link = %llu", volume, vti->ID());
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
return inode->ReadLink(buffer, _bufferSize);
}
@@ -470,20 +518,46 @@ static status_t
nfs4_create_symlink(fs_volume* volume, fs_vnode* dir, const char* name,
const char* path, int mode)
{
Inode* inode = reinterpret_cast<Inode*>(dir->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(dir->private_node);
TRACE("volume = %p, dir = %llu, name = %s, path = %s, mode = %d", volume,
inode->ID(), name, path, mode);
return inode->CreateLink(name, path, mode);
vti->ID(), name, path, mode);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
ino_t id;
status_t result = inode->CreateLink(name, path, mode, &id);
if (result != B_OK)
return result;
result = get_vnode(volume, id, reinterpret_cast<void**>(&vti));
if (result == B_OK)
vti->Clear();
return B_OK;
}
static status_t
nfs4_link(fs_volume* volume, fs_vnode* dir, const char* name, fs_vnode* vnode)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
Inode* dirInode = reinterpret_cast<Inode*>(dir->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
VnodeToInode* dirVti = reinterpret_cast<VnodeToInode*>(dir->private_node);
TRACE("volume = %p, dir = %llu, name = %s, vnode = %llu", volume,
dirInode->ID(), name, inode->ID());
dirVti->ID(), name, vti->ID());
VnodeToInodeLocker _dir(dirVti);
Inode* dirInode = dirVti->Get();
if (dirInode == NULL)
return B_ENTRY_NOT_FOUND;
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
return inode->Link(dirInode, name);
}
@@ -491,17 +565,27 @@ nfs4_link(fs_volume* volume, fs_vnode* dir, const char* name, fs_vnode* vnode)
static status_t
nfs4_unlink(fs_volume* volume, fs_vnode* dir, const char* name)
{
Inode* inode = reinterpret_cast<Inode*>(dir->private_node);
FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(dir->private_node);
TRACE("volume = %p, dir = %llu, name = %s", volume, inode->ID(), name);
VnodeToInodeLocker locker(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
WriteLocker(fs->fRemoveNodeLock);
TRACE("volume = %p, dir = %llu, name = %s", volume, vti->ID(), name);
ino_t id;
status_t result = inode->Remove(name, NF4REG, &id);
if (result != B_OK)
return result;
locker.Unlock();
void* ptr;
result = get_vnode(volume, id, &ptr);
if (result == B_OK) {
vti = reinterpret_cast<VnodeToInode*>(ptr);
vti->Remove();
}
return remove_vnode(volume, id);
}
@@ -511,15 +595,23 @@ static status_t
nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName,
fs_vnode* toDir, const char* toName)
{
Inode* fromInode = reinterpret_cast<Inode*>(fromDir->private_node);
Inode* toInode = reinterpret_cast<Inode*>(toDir->private_node);
FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
VnodeToInode* fromVti
= reinterpret_cast<VnodeToInode*>(fromDir->private_node);
VnodeToInode* toVti = reinterpret_cast<VnodeToInode*>(toDir->private_node);
TRACE("volume = %p, fromDir = %llu, toDir = %llu, fromName = %s, " \
"toName = %s", volume, fromInode->ID(), toInode->ID(), fromName,
"toName = %s", volume, fromVti->ID(), toVti->ID(), fromName,
toName);
ReadLocker(fs->fRemoveNodeLock);
VnodeToInodeLocker _from(fromVti);
Inode* fromInode = fromVti->Get();
if (fromInode == NULL)
return B_ENTRY_NOT_FOUND;
VnodeToInodeLocker _to(toVti);
Inode* toInode = toVti->Get();
if (toInode == NULL)
return B_ENTRY_NOT_FOUND;
ino_t id;
status_t result = Inode::Rename(fromInode, toInode, fromName, toName, false,
@@ -543,8 +635,14 @@ nfs4_rename(fs_volume* volume, fs_vnode* fromDir, const char* fromName,
static status_t
nfs4_access(fs_volume* volume, fs_vnode* vnode, int mode)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu, mode = %d", volume, inode->ID(), mode);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu, mode = %d", volume, vti->ID(), mode);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
return inode->Access(mode);
}
@@ -552,8 +650,14 @@ nfs4_access(fs_volume* volume, fs_vnode* vnode, int mode)
static status_t
nfs4_read_stat(fs_volume* volume, fs_vnode* vnode, struct stat* stat)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu", volume, inode->ID());
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu", volume, vti->ID());
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
return inode->Stat(stat);
}
@@ -562,13 +666,66 @@ static status_t
nfs4_write_stat(fs_volume* volume, fs_vnode* vnode, const struct stat* stat,
uint32 statMask)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu, statMask = %lu", volume, inode->ID(),
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu, statMask = %lu", volume, vti->ID(),
statMask);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
return inode->WriteStat(stat, statMask);
}
static status_t
get_new_vnode(fs_volume* volume, ino_t id, VnodeToInode** _vti)
{
FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
Inode* inode;
VnodeToInode* vti;
status_t result = get_vnode(volume, id, reinterpret_cast<void**>(_vti));
if (result == B_OK) {
vti = *_vti;
// FIXME: race condition vti->Get() == NULL and vti->Replace(inode)
if (vti->Get() == NULL) {
result = fs->GetInode(id, &inode);
if (result != B_OK)
return result;
vti->Replace(inode);
unremove_vnode(volume, id);
}
return B_OK;
}
vti = new VnodeToInode(id, fs);
if (vti == NULL)
return B_NO_MEMORY;
*_vti = vti;
result = fs->GetInode(id, &inode);
if (result != B_OK) {
delete vti;
return result;
}
vti->Replace(inode);
result = new_vnode(volume, id, vti, &gNFSv4VnodeOps);
if (result != B_OK) {
delete vti;
delete inode;
}
return B_OK;
}
static status_t
nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode,
int perms, void** _cookie, ino_t* _newVnodeID)
@@ -578,13 +735,14 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode,
return B_NO_MEMORY;
*_cookie = cookie;
Inode* inode = reinterpret_cast<Inode*>(dir->private_node);
FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(dir->private_node);
TRACE("volume = %p, dir = %llu, name = %s, openMode = %d, perms = %d",
volume, inode->ID(), name, openMode, perms);
volume, vti->ID(), name, openMode, perms);
ReadLocker(fs->fRemoveNodeLock);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
OpenDelegationData data;
status_t result = inode->Create(name, openMode, perms, cookie, &data,
@@ -594,23 +752,18 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode,
return result;
}
Inode* child;
result = get_vnode(volume, *_newVnodeID, reinterpret_cast<void**>(&child));
result = get_new_vnode(volume, *_newVnodeID, &vti);
if (result != B_OK) {
result = inode->GetFileSystem()->GetInode(*_newVnodeID, &child);
if (result != B_OK) {
delete cookie;
return result;
}
delete cookie;
return result;
}
result = new_vnode(volume, *_newVnodeID, child, &gNFSv4VnodeOps);
if (result != B_OK) {
delete child;
delete cookie;
return result;
}
} else
unremove_vnode(volume, *_newVnodeID);
VnodeToInodeLocker _child(vti);
Inode* child = vti->Get();
if (child == NULL) {
delete cookie;
return B_ENTRY_NOT_FOUND;
}
child->SetOpenState(cookie->fOpenState);
@@ -626,7 +779,6 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode,
}
TRACE("*cookie = %p, *newVnodeID = %llu", *_cookie, *_newVnodeID);
return result;
}
@@ -634,11 +786,15 @@ nfs4_create(fs_volume* volume, fs_vnode* dir, const char* name, int openMode,
static status_t
nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu, openMode = %d", volume, inode->ID(),
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu, openMode = %d", volume, vti->ID(),
openMode);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK) {
*_cookie = NULL;
return B_OK;
@@ -662,11 +818,17 @@ nfs4_open(fs_volume* volume, fs_vnode* vnode, int openMode, void** _cookie)
static status_t
nfs4_close(fs_volume* volume, fs_vnode* vnode, void* _cookie)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu, cookie = %p", volume, inode->ID(),
TRACE("volume = %p, vnode = %llu, cookie = %p", volume, vti->ID(),
_cookie);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK)
return B_OK;
@@ -678,11 +840,16 @@ nfs4_close(fs_volume* volume, fs_vnode* vnode, void* _cookie)
static status_t
nfs4_free_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu, cookie = %p", volume, inode->ID(),
TRACE("volume = %p, vnode = %llu, cookie = %p", volume, vti->ID(),
_cookie);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK)
return B_OK;
@@ -699,10 +866,14 @@ static status_t
nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
void* buffer, size_t* length)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu, cookie = %p, pos = %llu, length = %lu",
volume, inode->ID(), _cookie, pos, *length);
volume, vti->ID(), _cookie, pos, *length);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
if (inode->Type() == S_IFDIR)
return B_IS_A_DIRECTORY;
@@ -712,7 +883,7 @@ nfs4_read(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
return inode->Read(cookie, pos, buffer, length);
return inode->Read(cookie, pos, buffer, length);;
}
@@ -720,10 +891,14 @@ static status_t
nfs4_write(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
const void* _buffer, size_t* length)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu, cookie = %p, pos = %llu, length = %lu",
volume, inode->ID(), _cookie, pos, *length);
volume, vti->ID(), _cookie, pos, *length);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
if (inode->Type() == S_IFDIR)
return B_IS_A_DIRECTORY;
@@ -741,20 +916,36 @@ static status_t
nfs4_create_dir(fs_volume* volume, fs_vnode* parent, const char* name,
int mode)
{
Inode* inode = reinterpret_cast<Inode*>(parent->private_node);
TRACE("volume = %p, parent = %llu, mode = %d", volume, inode->ID(), mode);
return inode->CreateDir(name, mode);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(parent->private_node);
TRACE("volume = %p, parent = %llu, mode = %d", volume, vti->ID(), mode);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
ino_t id;
status_t result = inode->CreateDir(name, mode, &id);
if (result != B_OK)
return result;
result = get_vnode(volume, id, reinterpret_cast<void**>(&vti));
if (result == B_OK)
vti->Clear();
return B_OK;
}
static status_t
nfs4_remove_dir(fs_volume* volume, fs_vnode* parent, const char* name)
{
Inode* inode = reinterpret_cast<Inode*>(parent->private_node);
FileSystem* fs = reinterpret_cast<FileSystem*>(volume->private_volume);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(parent->private_node);
TRACE("volume = %p, parent = %llu, name = %s", volume, vti->ID(), name);
TRACE("volume = %p, parent = %llu, name = %s", volume, inode->ID(), name);
WriteLocker(fs->fRemoveNodeLock);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
ino_t id;
status_t result = inode->Remove(name, NF4DIR, &id);
@@ -772,8 +963,14 @@ nfs4_open_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie)
return B_NO_MEMORY;
*_cookie = cookie;
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu", volume, inode->ID());
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu", volume, vti->ID());
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
status_t result = inode->OpenDir(cookie);
if (result != B_OK)
delete cookie;
@@ -788,7 +985,7 @@ static status_t
nfs4_close_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie)
{
TRACE("volume = %p, vnode = %llu, cookie = %p", volume,
reinterpret_cast<Inode*>(vnode->private_node)->ID(), _cookie);
reinterpret_cast<VnodeToInode*>(vnode->private_node)->ID(), _cookie);
Cookie* cookie = reinterpret_cast<Cookie*>(_cookie);
return cookie->CancelAll();
@@ -799,7 +996,7 @@ static status_t
nfs4_free_dir_cookie(fs_volume* volume, fs_vnode* vnode, void* cookie)
{
TRACE("volume = %p, vnode = %llu, cookie = %p", volume,
reinterpret_cast<Inode*>(vnode->private_node)->ID(), cookie);
reinterpret_cast<VnodeToInode*>(vnode->private_node)->ID(), cookie);
delete reinterpret_cast<OpenDirCookie*>(cookie);
return B_OK;
@@ -811,11 +1008,15 @@ nfs4_read_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie,
struct dirent* buffer, size_t bufferSize, uint32* _num)
{
OpenDirCookie* cookie = reinterpret_cast<OpenDirCookie*>(_cookie);
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu, cookie = %p", volume, inode->ID(),
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu, cookie = %p", volume, vti->ID(),
_cookie);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
return inode->ReadDir(buffer, bufferSize, _num, cookie);
}
@@ -824,7 +1025,7 @@ static status_t
nfs4_rewind_dir(fs_volume* volume, fs_vnode* vnode, void* _cookie)
{
TRACE("volume = %p, vnode = %llu, cookie = %p", volume,
reinterpret_cast<Inode*>(vnode->private_node)->ID(), _cookie);
reinterpret_cast<VnodeToInode*>(vnode->private_node)->ID(), _cookie);
OpenDirCookie* cookie = reinterpret_cast<OpenDirCookie*>(_cookie);
cookie->fSpecial = 0;
@@ -843,8 +1044,14 @@ nfs4_open_attr_dir(fs_volume* volume, fs_vnode* vnode, void** _cookie)
return B_NO_MEMORY;
*_cookie = cookie;
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu", volume, inode->ID());
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu", volume, vti->ID());
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
status_t result = inode->OpenAttrDir(cookie);
if (result != B_OK)
delete cookie;
@@ -886,7 +1093,12 @@ static status_t
nfs4_create_attr(fs_volume* volume, fs_vnode* vnode, const char* name,
uint32 type, int openMode, void** _cookie)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
OpenAttrCookie* cookie = new OpenAttrCookie;
if (cookie == NULL)
@@ -905,7 +1117,12 @@ static status_t
nfs4_open_attr(fs_volume* volume, fs_vnode* vnode, const char* name,
int openMode, void** _cookie)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
OpenAttrCookie* cookie = new OpenAttrCookie;
if (cookie == NULL)
@@ -931,7 +1148,12 @@ nfs4_close_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie)
static status_t
nfs4_free_attr_cookie(fs_volume* volume, fs_vnode* vnode, void* _cookie)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie);
inode->CloseAttr(cookie);
@@ -945,9 +1167,15 @@ static status_t
nfs4_read_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
void* buffer, size_t* length)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie);
bool eof;
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
return inode->ReadDirect(cookie, pos, buffer, length, &eof);
}
@@ -956,8 +1184,14 @@ static status_t
nfs4_write_attr(fs_volume* volume, fs_vnode* vnode, void* _cookie, off_t pos,
const void* buffer, size_t* length)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
return inode->WriteDirect(cookie, pos, buffer, length);
}
@@ -966,8 +1200,14 @@ static status_t
nfs4_read_attr_stat(fs_volume* volume, fs_vnode* vnode, void* _cookie,
struct stat* stat)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
return inode->Stat(stat, cookie);
}
@@ -976,8 +1216,14 @@ static status_t
nfs4_write_attr_stat(fs_volume* volume, fs_vnode* vnode, void* _cookie,
const struct stat* stat, int statMask)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
OpenAttrCookie* cookie = reinterpret_cast<OpenAttrCookie*>(_cookie);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
return inode->WriteStat(stat, statMask, cookie);
}
@@ -986,8 +1232,18 @@ static status_t
nfs4_rename_attr(fs_volume* volume, fs_vnode* fromVnode, const char* fromName,
fs_vnode* toVnode, const char* toName)
{
Inode* fromInode = reinterpret_cast<Inode*>(fromVnode->private_node);
Inode* toInode = reinterpret_cast<Inode*>(toVnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(toVnode->private_node);
VnodeToInodeLocker to(vti);
Inode* toInode = vti->Get();
if (toInode == NULL)
return B_ENTRY_NOT_FOUND;
vti = reinterpret_cast<VnodeToInode*>(fromVnode->private_node);
VnodeToInodeLocker from(vti);
Inode* fromInode = vti->Get();
if (fromInode == NULL)
return B_ENTRY_NOT_FOUND;
return Inode::Rename(fromInode, toInode, fromName, toName, true);
}
@@ -995,7 +1251,13 @@ nfs4_rename_attr(fs_volume* volume, fs_vnode* fromVnode, const char* fromName,
static status_t
nfs4_remove_attr(fs_volume* volume, fs_vnode* vnode, const char* name)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
return inode->Remove(name, NF4NAMEDATTR, NULL);
}
@@ -1004,10 +1266,16 @@ static status_t
nfs4_test_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie,
struct flock* lock)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
TRACE("volume = %p, vnode = %llu, cookie = %p, lock = %p", volume,
inode->ID(), _cookie, lock);
vti->ID(), _cookie, lock);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
return inode->TestLock(cookie, lock);
}
@@ -1016,13 +1284,18 @@ static status_t
nfs4_acquire_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie,
const struct flock* lock, bool wait)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
OpenFileCookie* cookie = reinterpret_cast<OpenFileCookie*>(_cookie);
TRACE("volume = %p, vnode = %llu, cookie = %p, lock = %p", volume,
inode->ID(), _cookie, lock);
vti->ID(), _cookie, lock);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
inode->RevalidateFileCache();
return inode->AcquireLock(cookie, lock, wait);
}
@@ -1031,9 +1304,14 @@ static status_t
nfs4_release_lock(fs_volume* volume, fs_vnode* vnode, void* _cookie,
const struct flock* lock)
{
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
VnodeToInode* vti = reinterpret_cast<VnodeToInode*>(vnode->private_node);
TRACE("volume = %p, vnode = %llu, cookie = %p, lock = %p", volume,
inode->ID(), _cookie, lock);
vti->ID(), _cookie, lock);
VnodeToInodeLocker _(vti);
Inode* inode = vti->Get();
if (inode == NULL)
return B_ENTRY_NOT_FOUND;
if (inode->Type() == S_IFDIR || inode->Type() == S_IFLNK)
return B_OK;