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-05-31 20:13:02 +02:00
parent aefd79e6a7
commit 7bfa4fe805
11 changed files with 270 additions and 10 deletions

View File

@ -0,0 +1,56 @@
/*
* Copyright 2012 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Paweł Dziepak, pdziepak@quarnos.org
*/
#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

View File

@ -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*
Filesystem::CreateRootInode()
{

View File

@ -9,11 +9,13 @@
#define FILESYSTEM_H
#include "InodeIdMap.h"
#include "NFS4Defs.h"
#include "RPCServer.h"
class Inode;
class InodeIdMap;
class Filesystem {
public:
@ -21,6 +23,7 @@ public:
const char* path, dev_t id);
~Filesystem();
status_t GetInode(ino_t id, Inode** inode);
Inode* CreateRootInode();
inline uint32 FHExpiryType() const;
@ -28,6 +31,7 @@ public:
inline uint64 GetId();
inline dev_t DevId() const;
inline InodeIdMap* InoIdMap();
private:
Filesystem();
@ -39,6 +43,8 @@ private:
vint64 fId;
dev_t fDevId;
InodeIdMap fInoIdMap;
};
@ -63,5 +69,12 @@ Filesystem::DevId() const
}
inline InodeIdMap*
Filesystem::InoIdMap()
{
return &fInoIdMap;
}
#endif // FILESYSTEM_H

View File

@ -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
Inode::Stat(struct stat* st)
{

View File

@ -26,7 +26,9 @@ public:
inline ino_t ID() const;
inline mode_t Type() const;
status_t LookUp(const char* name, ino_t* id);
status_t Stat(struct stat* st);
status_t OpenDir(uint64* cookie);
status_t ReadDir(void* buffer, uint32 size,
uint32* count, uint64* cookie);
@ -44,7 +46,7 @@ private:
Filehandle fHandle;
Filesystem* fFilesystem;
Inode* fParent;
Inode* fParent; // this will cause trouble
};

View File

@ -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

View File

@ -13,13 +13,7 @@
#include <SupportDefs.h>
#define NFS4_FHSIZE 128
struct Filehandle {
uint8 fSize;
uint8 fFH[NFS4_FHSIZE];
};
#include "Filehandle.h"
enum Procedure {
ProcNull = 0,
@ -31,6 +25,7 @@ enum Opcode {
OpGetAttr = 9,
OpGetFH = 10,
OpLookUp = 15,
OpLookUpUp = 16,
OpPutFH = 22,
OpPutRootFH = 24,
OpReadDir = 26

View File

@ -42,6 +42,7 @@ public:
status_t GetAttr(AttrValue** attrs, uint32* count);
status_t GetFH(Filehandle* fh);
inline status_t LookUp();
inline status_t LookUpUp();
inline status_t PutFH();
inline status_t PutRootFH();
status_t ReadDir(uint64* cookie, DirEntry** dirents,
@ -65,6 +66,13 @@ ReplyInterpreter::LookUp()
}
inline status_t
ReplyInterpreter::LookUpUp()
{
return _OperationError(OpLookUpUp);
}
inline status_t
ReplyInterpreter::PutFH()
{

View File

@ -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
RequestBuilder::PutFH(const Filehandle& fh)
{

View File

@ -25,6 +25,7 @@ public:
status_t GetAttr(Attribute* attrs, uint32 count);
status_t GetFH();
status_t LookUp(const char* name);
status_t LookUpUp();
status_t PutFH(const Filehandle& fh);
status_t PutRootFH();
status_t ReadDir(uint32 count, uint64* cookie,

View File

@ -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
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
nfs4_put_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter)
{
@ -183,11 +216,15 @@ nfs4_std_ops(int32 op, ...)
fs_volume_ops gNFSv4VolumeOps = {
&nfs4_unmount
nfs4_unmount,
NULL,
NULL,
NULL,
nfs4_get_vnode,
};
fs_vnode_ops gNFSv4VnodeOps = {
NULL, // lookup()
nfs4_lookup,
NULL, // get_vnode_name()
nfs4_put_vnode,
NULL, // remove_vnode()