diff --git a/src/add-ons/kernel/file_systems/nfs4/Filehandle.h b/src/add-ons/kernel/file_systems/nfs4/Filehandle.h new file mode 100644 index 0000000000..12baf07ef4 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/Filehandle.h @@ -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 + +#include + + +#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 + diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index b7149b08fc..c5f6e87e0e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -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() { diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h index a9386de8d2..d919c269d1 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h @@ -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 diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 329730f634..48329a1e1b 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -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) { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index b7a8528766..c631b95889 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -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 }; diff --git a/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h new file mode 100644 index 0000000000..3b8bc8d54b --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/InodeIdMap.h @@ -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 +#include + +#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 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::Iterator it = fMap.Find(id); + if (!it.HasCurrent()) + return B_BAD_VALUE; + + *fh = it.Current(); + return B_OK; +} + + +#endif // INODEIDMAP_H + diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h index 3ea863096f..c755dc6870 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Defs.h @@ -13,13 +13,7 @@ #include - -#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 diff --git a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h index 8eebf24b9e..173ace3ab8 100644 --- a/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h +++ b/src/add-ons/kernel/file_systems/nfs4/ReplyInterpreter.h @@ -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() { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp index 2e9bfe7f04..783999819e 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.cpp @@ -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) { diff --git a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h index 838d2ae82c..e784602a85 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h +++ b/src/add-ons/kernel/file_systems/nfs4/RequestBuilder.h @@ -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, diff --git a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp index 5d7b719382..db0e66e9a0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -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(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(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()