nfs4: Add lookup() and get_vnode() hooks

get_vnode() needs a way to retrieve filehandle knowing only inode number.
Since NFS4 sever does not provide such services client manages its own mapping
between ino_t and filehandles.
This commit is contained in:
Pawel Dziepak
2012-06-29 02:14:27 +02:00
parent aefd79e6a7
commit 7bfa4fe805
11 changed files with 270 additions and 10 deletions
@@ -0,0 +1,56 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, [email protected]
*/
#ifndef FILEHANDLE_H
#define FILEHANDLE_H
#include <string.h>
#include <SupportDefs.h>
#define NFS4_FHSIZE 128
struct Filehandle {
uint8 fSize;
uint8 fFH[NFS4_FHSIZE];
inline Filehandle();
inline Filehandle(const Filehandle& fh);
inline Filehandle& operator=(const Filehandle& fh);
};
inline
Filehandle::Filehandle()
:
fSize(0)
{
}
inline
Filehandle::Filehandle(const Filehandle& fh)
:
fSize(fh.fSize)
{
memcpy(fFH, fh.fFH, fSize);
}
inline Filehandle&
Filehandle::operator=(const Filehandle& fh)
{
fSize = fh.fSize;
memcpy(fFH, fh.fFH, fSize);
return *this;
}
#endif // FILEHANDLE_H
@@ -123,6 +123,23 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath,
} }
status_t
Filesystem::GetInode(ino_t id, Inode** _inode)
{
Filehandle fh;
status_t result = fInoIdMap.GetFilehandle(&fh, id);
if (result != B_OK)
return result;
Inode* inode = new(std::nothrow)Inode(this, fh, NULL);
if (inode == NULL)
return B_NO_MEMORY;
*_inode = inode;
return B_OK;
}
Inode* Inode*
Filesystem::CreateRootInode() Filesystem::CreateRootInode()
{ {
@@ -9,11 +9,13 @@
#define FILESYSTEM_H #define FILESYSTEM_H
#include "InodeIdMap.h"
#include "NFS4Defs.h" #include "NFS4Defs.h"
#include "RPCServer.h" #include "RPCServer.h"
class Inode; class Inode;
class InodeIdMap;
class Filesystem { class Filesystem {
public: public:
@@ -21,6 +23,7 @@ public:
const char* path, dev_t id); const char* path, dev_t id);
~Filesystem(); ~Filesystem();
status_t GetInode(ino_t id, Inode** inode);
Inode* CreateRootInode(); Inode* CreateRootInode();
inline uint32 FHExpiryType() const; inline uint32 FHExpiryType() const;
@@ -28,6 +31,7 @@ public:
inline uint64 GetId(); inline uint64 GetId();
inline dev_t DevId() const; inline dev_t DevId() const;
inline InodeIdMap* InoIdMap();
private: private:
Filesystem(); Filesystem();
@@ -39,6 +43,8 @@ private:
vint64 fId; vint64 fId;
dev_t fDevId; dev_t fDevId;
InodeIdMap fInoIdMap;
}; };
@@ -63,5 +69,12 @@ Filesystem::DevId() const
} }
inline InodeIdMap*
Filesystem::InoIdMap()
{
return &fInoIdMap;
}
#endif // FILESYSTEM_H #endif // FILESYSTEM_H
@@ -59,6 +59,71 @@ Inode::Inode(Filesystem* fs, const Filehandle &fh, Inode* parent)
} }
// filesystems that do not provide fileid are currently unsupported
// client will have to be able to create its own mapping between file names
// and made up IDs
status_t
Inode::LookUp(const char* name, ino_t* id)
{
if (fType != NF4DIR)
return B_NOT_A_DIRECTORY;
if (!strcmp(name, ".")) {
*id = ID();
return B_OK;
}
RequestBuilder req(ProcCompound);
req.PutFH(fHandle);
if (!strcmp(name, ".."))
req.LookUpUp();
else
req.LookUp(name);
req.GetFH();
Attribute attr[] = { FATTR4_FILEID };
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
RPC::Reply *rpl;
fFilesystem->Server()->SendCall(req.Request(), &rpl);
ReplyInterpreter reply(rpl);
status_t result = reply.PutFH();
if (result != B_OK)
return result;
if (!strcmp(name, ".."))
result = reply.LookUpUp();
else
result = reply.LookUp();
if (result != B_OK)
return result;
Filehandle fh;
result = reply.GetFH(&fh);
if (result != B_OK)
return result;
AttrValue* values;
uint32 count;
result = reply.GetAttr(&values, &count);
if (result != B_OK)
return result;
if (count < 1 || values[0].fAttribute != FATTR4_FILEID) {
delete[] values;
return B_UNSUPPORTED;
}
*id = values[0].fData.fValue64;
delete[] values;
fFilesystem->InoIdMap()->AddEntry(fh, *id);
return B_OK;
}
status_t status_t
Inode::Stat(struct stat* st) Inode::Stat(struct stat* st)
{ {
+3 -1
View File
@@ -26,7 +26,9 @@ public:
inline ino_t ID() const; inline ino_t ID() const;
inline mode_t Type() const; inline mode_t Type() const;
status_t LookUp(const char* name, ino_t* id);
status_t Stat(struct stat* st); status_t Stat(struct stat* st);
status_t OpenDir(uint64* cookie); status_t OpenDir(uint64* cookie);
status_t ReadDir(void* buffer, uint32 size, status_t ReadDir(void* buffer, uint32 size,
uint32* count, uint64* cookie); uint32* count, uint64* cookie);
@@ -44,7 +46,7 @@ private:
Filehandle fHandle; Filehandle fHandle;
Filesystem* fFilesystem; Filesystem* fFilesystem;
Inode* fParent; Inode* fParent; // this will cause trouble
}; };
@@ -0,0 +1,51 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#ifndef INODEIDMAP_H
#define INODEIDMAP_H
#include <SupportDefs.h>
#include <util/AVLTreeMap.h>
#include "Filehandle.h"
class InodeIdMap {
public:
inline status_t AddEntry(const Filehandle& inode,
ino_t id);
inline status_t GetFilehandle(Filehandle* fh,
ino_t id);
private:
AVLTreeMap<ino_t, Filehandle> fMap;
};
inline status_t
InodeIdMap::AddEntry(const Filehandle& inode, ino_t id)
{
return fMap.Insert(id, inode);
}
inline status_t
InodeIdMap::GetFilehandle(Filehandle* fh, ino_t id)
{
AVLTreeMap<ino_t, Filehandle>::Iterator it = fMap.Find(id);
if (!it.HasCurrent())
return B_BAD_VALUE;
*fh = it.Current();
return B_OK;
}
#endif // INODEIDMAP_H
@@ -13,13 +13,7 @@
#include <SupportDefs.h> #include <SupportDefs.h>
#include "Filehandle.h"
#define NFS4_FHSIZE 128
struct Filehandle {
uint8 fSize;
uint8 fFH[NFS4_FHSIZE];
};
enum Procedure { enum Procedure {
ProcNull = 0, ProcNull = 0,
@@ -31,6 +25,7 @@ enum Opcode {
OpGetAttr = 9, OpGetAttr = 9,
OpGetFH = 10, OpGetFH = 10,
OpLookUp = 15, OpLookUp = 15,
OpLookUpUp = 16,
OpPutFH = 22, OpPutFH = 22,
OpPutRootFH = 24, OpPutRootFH = 24,
OpReadDir = 26 OpReadDir = 26
@@ -42,6 +42,7 @@ public:
status_t GetAttr(AttrValue** attrs, uint32* count); status_t GetAttr(AttrValue** attrs, uint32* count);
status_t GetFH(Filehandle* fh); status_t GetFH(Filehandle* fh);
inline status_t LookUp(); inline status_t LookUp();
inline status_t LookUpUp();
inline status_t PutFH(); inline status_t PutFH();
inline status_t PutRootFH(); inline status_t PutRootFH();
status_t ReadDir(uint64* cookie, DirEntry** dirents, status_t ReadDir(uint64* cookie, DirEntry** dirents,
@@ -65,6 +66,13 @@ ReplyInterpreter::LookUp()
} }
inline status_t
ReplyInterpreter::LookUpUp()
{
return _OperationError(OpLookUpUp);
}
inline status_t inline status_t
ReplyInterpreter::PutFH() ReplyInterpreter::PutFH()
{ {
@@ -103,6 +103,21 @@ RequestBuilder::LookUp(const char* name)
} }
status_t
RequestBuilder::LookUpUp()
{
if (fProcedure != ProcCompound)
return B_BAD_VALUE;
if (fRequest == NULL)
return B_NO_MEMORY;
fRequest->Stream().AddUInt(OpLookUpUp);
fOpCount++;
return B_OK;
}
status_t status_t
RequestBuilder::PutFH(const Filehandle& fh) RequestBuilder::PutFH(const Filehandle& fh)
{ {
@@ -25,6 +25,7 @@ public:
status_t GetAttr(Attribute* attrs, uint32 count); status_t GetAttr(Attribute* attrs, uint32 count);
status_t GetFH(); status_t GetFH();
status_t LookUp(const char* name); status_t LookUp(const char* name);
status_t LookUpUp();
status_t PutFH(const Filehandle& fh); status_t PutFH(const Filehandle& fh);
status_t PutRootFH(); status_t PutRootFH();
status_t ReadDir(uint32 count, uint64* cookie, status_t ReadDir(uint32 count, uint64* cookie,
@@ -65,6 +65,26 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags,
} }
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);
Inode* inode;
status_t result = fs->GetInode(id, &inode);
if (result != B_OK)
return result;
vnode->ops = &gNFSv4VnodeOps;
vnode->private_node = inode;
*_type = inode->Type();
*_flags = 0;
return B_OK;
}
static status_t static status_t
nfs4_unmount(fs_volume* volume) nfs4_unmount(fs_volume* volume)
{ {
@@ -78,6 +98,19 @@ nfs4_unmount(fs_volume* volume)
} }
static status_t
nfs4_lookup(fs_volume* volume, fs_vnode* dir, const char* name, ino_t* _id)
{
Inode* inode = reinterpret_cast<Inode*>(dir->private_node);
status_t result = inode->LookUp(name, _id);
if (result != B_OK)
return result;
void* ptr;
return get_vnode(volume, *_id, &ptr);
}
static status_t static status_t
nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter)
{ {
@@ -183,11 +216,15 @@ nfs4_std_ops(int32 op, ...)
fs_volume_ops gNFSv4VolumeOps = { fs_volume_ops gNFSv4VolumeOps = {
&nfs4_unmount nfs4_unmount,
NULL,
NULL,
NULL,
nfs4_get_vnode,
}; };
fs_vnode_ops gNFSv4VnodeOps = { fs_vnode_ops gNFSv4VnodeOps = {
NULL, // lookup() nfs4_lookup,
NULL, // get_vnode_name() NULL, // get_vnode_name()
nfs4_put_vnode, nfs4_put_vnode,
NULL, // remove_vnode() NULL, // remove_vnode()