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:
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user