diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp index 0f07306cd6..fc2a6d74b9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.cpp @@ -16,7 +16,7 @@ #include #include "Request.h" -#include "Inode.h" +#include "RootInode.h" extern RPC::ServerManager* gRPCServerManager; @@ -30,7 +30,7 @@ Filesystem::Filesystem() fOpenFiles(NULL), fOpenCount(0), fPath(NULL), - fName(NULL), + fRoot(NULL), fId(1) { mutex_init(&fOpenLock, NULL); @@ -43,8 +43,8 @@ Filesystem::~Filesystem() mutex_destroy(&fOpenLock); - free(const_cast(fName)); free(const_cast(fPath)); + delete fRoot; } @@ -155,33 +155,39 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath, } else fs->fPath = NULL; + FileInfo fi; const char* name; if (fsPath != NULL && fsPath[0] == '/') fsPath++; name = strrchr(fsPath, '/'); if (name != NULL) { name++; - fs->fName = strdup(name); + fi.fName = strdup(name); } else - fs->fName = strdup(fsPath); + fi.fName = strdup(fsPath); - memcpy(&fs->fRootFH, &fh, sizeof(Filehandle)); fs->fServer = serv; fs->fDevId = id; fs->fFsId = *fsid; - FileInfo fi; fi.fFH = fh; fi.fParent = fh; - fi.fName = strdup("/"); fi.fPath = strdup(sGetPath(fs->fPath, fsPath)); - fs->fRoot = fi; - - *pfs = fs; delete[] values; + Inode* inode; + result = Inode::CreateInode(fs, fi, &inode); + if (result != B_OK) { + delete fs; + return result; + } + + fs->fRoot = reinterpret_cast(inode); + fs->NFSServer()->AddFilesystem(fs); + *pfs = fs; + return B_OK; } @@ -207,115 +213,19 @@ Filesystem::GetInode(ino_t id, Inode** _inode) } -Inode* -Filesystem::CreateRootInode() -{ - Inode* inode; - status_t result = Inode::CreateInode(this, fRoot, &inode); - if (result == B_OK) - return inode; - else - return NULL; -} - - status_t -Filesystem::ReadInfo(struct fs_info* info) +Filesystem::Migrate(const RPC::Server* serv) { - Request request(fServer); - RequestBuilder& req = request.Builder(); - - req.PutFH(fRootFH); - Attribute attr[] = { FATTR4_FILES_FREE, FATTR4_FILES_TOTAL, - FATTR4_MAXREAD, FATTR4_MAXWRITE, FATTR4_SPACE_FREE, - FATTR4_SPACE_TOTAL }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - reply.PutFH(); - - AttrValue* values; - uint32 count, next = 0; - result = reply.GetAttr(&values, &count); - if (result != B_OK) - return result; - - if (count >= next && values[next].fAttribute == FATTR4_FILES_FREE) { - info->free_nodes = values[next].fData.fValue64; - next++; - } - - if (count >= next && values[next].fAttribute == FATTR4_FILES_TOTAL) { - info->total_nodes = values[next].fData.fValue64; - next++; - } - - uint64 io_size = LONGLONG_MAX; - if (count >= next && values[next].fAttribute == FATTR4_MAXREAD) { - io_size = min_c(io_size, values[next].fData.fValue64); - next++; - } - - if (count >= next && values[next].fAttribute == FATTR4_MAXWRITE) { - io_size = min_c(io_size, values[next].fData.fValue64); - next++; - } - - if (io_size == LONGLONG_MAX) - io_size = 32768; - info->io_size = io_size; - info->block_size = io_size; - - if (count >= next && values[next].fAttribute == FATTR4_SPACE_FREE) { - info->free_blocks = values[next].fData.fValue64 / io_size; - next++; - } - - if (count >= next && values[next].fAttribute == FATTR4_SPACE_TOTAL) { - info->total_blocks = values[next].fData.fValue64 / io_size; - next++; - } - - info->flags = B_FS_IS_READONLY; - strncpy(info->volume_name, fName, B_FILE_NAME_LENGTH); - - delete[] values; - - return B_OK; -} - - -status_t -Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv) -{ - MutexLocker _(fMigrationLock); + MutexLocker _(fOpenLock); if (serv != fServer) return B_OK; - Request request(fServer); - RequestBuilder& req = request.Builder(); - - req.PutFH(fh); - Attribute attr[] = { FATTR4_FS_LOCATIONS }; - req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); - - status_t result = request.Send(); - if (result != B_OK) - return result; - - ReplyInterpreter& reply = request.Reply(); - - reply.PutFH(); + if (!fRoot->ProbeMigration()) + return B_OK; AttrValue* values; - uint32 count; - result = reply.GetAttr(&values, &count); - if (result != B_OK || count < 1) + status_t result = fRoot->GetLocations(&values); + if (result != B_OK) return result; FSLocations* locs = @@ -358,6 +268,10 @@ Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv) if (server == fServer) return B_ERROR; + NFS4Server* old = reinterpret_cast(server->PrivateData()); + old->RemoveFilesystem(this); + NFSServer()->AddFilesystem(this); + gRPCServerManager->Release(server); return B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h index e115dd47ff..9073e67169 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Filesystem.h +++ b/src/add-ons/kernel/file_systems/nfs4/Filesystem.h @@ -9,15 +9,13 @@ #define FILESYSTEM_H -#include - #include "InodeIdMap.h" #include "NFS4Defs.h" #include "NFS4Server.h" class Inode; -class InodeIdMap; +class RootInode; class Filesystem { public: @@ -26,12 +24,9 @@ public: ~Filesystem(); status_t GetInode(ino_t id, Inode** inode); - Inode* CreateRootInode(); + inline Inode* Root(); - status_t ReadInfo(struct fs_info* info); - - status_t Migrate(const Filehandle& fh, - const RPC::Server* serv); + status_t Migrate(const RPC::Server* serv); OpenFileCookie* OpenFilesLock(); void OpenFilesUnlock(); @@ -67,11 +62,8 @@ private: FilesystemId fFsId; const char* fPath; - mutex fMigrationLock; - const char* fName; - FileInfo fRoot; - Filehandle fRootFH; + RootInode* fRoot; RPC::Server* fServer; @@ -82,6 +74,13 @@ private: }; +inline Inode* +Filesystem::Root() +{ + return reinterpret_cast(fRoot); +} + + inline uint32 Filesystem::OpenFilesCount() { diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp index 08a9fe8386..5c72de93c6 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.cpp @@ -15,6 +15,7 @@ #include #include "Request.h" +#include "RootInode.h" Inode::Inode() @@ -25,7 +26,12 @@ Inode::Inode() status_t Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode) { - Inode* inode = new(std::nothrow) Inode; + Inode* inode = NULL; + if (fs->Root() == NULL) + inode = new(std::nothrow) RootInode; + else + inode = new(std::nothrow) Inode; + if (inode == NULL) return B_NO_MEMORY; @@ -215,8 +221,7 @@ Inode::Link(Inode* dir, const char* name) // filesystem has been moved if (reply.NFS4Error() == NFS4ERR_MOVED) { - fFilesystem->Migrate(fHandle, serv); - dir->fFilesystem->Migrate(dir->fHandle, serv); + fFilesystem->Migrate(serv); continue; } @@ -321,8 +326,7 @@ Inode::Rename(Inode* from, Inode* to, const char* fromName, const char* toName) // filesystem has been moved if (reply.NFS4Error() == NFS4ERR_MOVED) { - from->fFilesystem->Migrate(from->fHandle, serv); - to->fFilesystem->Migrate(to->fHandle, serv); + from->fFilesystem->Migrate(serv); continue; } @@ -1557,13 +1561,9 @@ Inode::_HandleErrors(uint32 nfs4Error, RPC::Server* serv, return false; // filesystem has been moved - case NFS4ERR_MOVED: - fFilesystem->Migrate(fHandle, serv); - return true; - - // lease has been moved, provoke server to return NFS4ERR_MOVED case NFS4ERR_LEASE_MOVED: - Access(0); + case NFS4ERR_MOVED: + fFilesystem->Migrate(serv); return true; default: diff --git a/src/add-ons/kernel/file_systems/nfs4/Inode.h b/src/add-ons/kernel/file_systems/nfs4/Inode.h index 1cf1f11dce..56051913ca 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Inode.h +++ b/src/add-ons/kernel/file_systems/nfs4/Inode.h @@ -68,7 +68,7 @@ public: status_t ReleaseAllLocks(OpenFileCookie* cookie); -private: +protected: Inode(); diff --git a/src/add-ons/kernel/file_systems/nfs4/Jamfile b/src/add-ons/kernel/file_systems/nfs4/Jamfile index 6ee1391b40..70b6749ad5 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Jamfile +++ b/src/add-ons/kernel/file_systems/nfs4/Jamfile @@ -13,6 +13,7 @@ KernelAddon nfs4 : ReplyInterpreter.cpp Request.cpp RequestBuilder.cpp + RootInode.cpp RPCAuth.cpp RPCCall.cpp RPCReply.cpp diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp index 4c30554aa2..80a54b545f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.cpp @@ -213,6 +213,21 @@ NFS4Server::ClientId(uint64 prevId, bool forceNew) } +status_t +NFS4Server::FilesystemMigrated() +{ + // reclaim all opened files and held locks from all filesystems + MutexLocker _(fFSLock); + Filesystem* fs = fFilesystems; + while (fs != NULL) { + fs->Migrate(fServer); + fs = fs->fNext; + } + + return B_OK; +} + + status_t NFS4Server::_GetLeaseTime() { @@ -297,9 +312,14 @@ NFS4Server::_Renewal() request.Builder().Renew(fClientId); request.Send(); - if (request.Reply().NFS4Error() == NFS4ERR_STALE_CLIENTID) - ServerRebooted(clientId); - // TODO: support NFS4ERR_LEASE_MOVED + switch (request.Reply().NFS4Error()) { + case NFS4ERR_STALE_CLIENTID: + ServerRebooted(clientId); + break; + case NFS4ERR_LEASE_MOVED: + FilesystemMigrated(); + break; + } } return B_OK; diff --git a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h index a13f642584..feed4e0ce0 100644 --- a/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h +++ b/src/add-ons/kernel/file_systems/nfs4/NFS4Server.h @@ -23,6 +23,7 @@ public: virtual ~NFS4Server(); uint64 ServerRebooted(uint64 clientId); + status_t FilesystemMigrated(); void AddFilesystem(Filesystem* fs); void RemoveFilesystem(Filesystem* fs); diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp new file mode 100644 index 0000000000..073dee4346 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.cpp @@ -0,0 +1,160 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ + + +#include "RootInode.h" + +#include + +#include "Request.h" + + +status_t +RootInode::ReadInfo(struct fs_info* info) +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + Attribute attr[] = { FATTR4_FILES_FREE, FATTR4_FILES_TOTAL, + FATTR4_MAXREAD, FATTR4_MAXWRITE, FATTR4_SPACE_FREE, + FATTR4_SPACE_TOTAL }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (_HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + + AttrValue* values; + uint32 count, next = 0; + result = reply.GetAttr(&values, &count); + if (result != B_OK) + return result; + + if (count >= next && values[next].fAttribute == FATTR4_FILES_FREE) { + info->free_nodes = values[next].fData.fValue64; + next++; + } + + if (count >= next && values[next].fAttribute == FATTR4_FILES_TOTAL) { + info->total_nodes = values[next].fData.fValue64; + next++; + } + + uint64 io_size = LONGLONG_MAX; + if (count >= next && values[next].fAttribute == FATTR4_MAXREAD) { + io_size = min_c(io_size, values[next].fData.fValue64); + next++; + } + + if (count >= next && values[next].fAttribute == FATTR4_MAXWRITE) { + io_size = min_c(io_size, values[next].fData.fValue64); + next++; + } + + if (io_size == LONGLONG_MAX) + io_size = 32768; + info->io_size = io_size; + info->block_size = io_size; + + if (count >= next && values[next].fAttribute == FATTR4_SPACE_FREE) { + info->free_blocks = values[next].fData.fValue64 / io_size; + next++; + } + + if (count >= next && values[next].fAttribute == FATTR4_SPACE_TOTAL) { + info->total_blocks = values[next].fData.fValue64 / io_size; + next++; + } + + delete[] values; + + break; + } while (true); + + info->flags = 0; + strncpy(info->volume_name, fName, B_FILE_NAME_LENGTH); + + return B_OK; +} + + +bool +RootInode::ProbeMigration() +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + req.Access(); + + status_t result = request.Send(); + if (result != B_OK) + continue; + + ReplyInterpreter& reply = request.Reply(); + + if (reply.NFS4Error() == NFS4ERR_MOVED) + return true; + + if (_HandleErrors(reply.NFS4Error(), serv)) + continue; + + return false; + } while (true); +} + + + +status_t +RootInode::GetLocations(AttrValue** attrv) +{ + do { + RPC::Server* serv = fFilesystem->Server(); + Request request(serv); + RequestBuilder& req = request.Builder(); + + req.PutFH(fHandle); + Attribute attr[] = { FATTR4_FS_LOCATIONS }; + req.GetAttr(attr, sizeof(attr) / sizeof(Attribute)); + + status_t result = request.Send(); + if (result != B_OK) + return result; + + ReplyInterpreter& reply = request.Reply(); + + if (_HandleErrors(reply.NFS4Error(), serv)) + continue; + + reply.PutFH(); + + uint32 count; + result = reply.GetAttr(attrv, &count); + if (result != B_OK) + return result; + if (count < 1) + return B_ERROR; + return B_OK; + + } while (true); + + return B_OK; +} + diff --git a/src/add-ons/kernel/file_systems/nfs4/RootInode.h b/src/add-ons/kernel/file_systems/nfs4/RootInode.h new file mode 100644 index 0000000000..c2101875e8 --- /dev/null +++ b/src/add-ons/kernel/file_systems/nfs4/RootInode.h @@ -0,0 +1,28 @@ +/* + * Copyright 2012 Haiku, Inc. All rights reserved. + * Distributed under the terms of the MIT License. + * + * Authors: + * Paweł Dziepak, pdziepak@quarnos.org + */ +#ifndef ROOTINODE_H +#define ROOTINODE_H + + +#include + +#include "Inode.h" + + +class RootInode : public Inode { +public: + status_t ReadInfo(struct fs_info* info); + + bool ProbeMigration(); + status_t GetLocations(AttrValue** attr); + +}; + + +#endif // ROOTINODE_H + 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 9eee937ebd..b8519ffb0a 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -14,12 +14,13 @@ #include #include "Connection.h" -#include "RPCServer.h" -#include "NFS4Defs.h" +#include "Filesystem.h" #include "Inode.h" +#include "NFS4Defs.h" #include "RequestBuilder.h" #include "ReplyInterpreter.h" -#include "Filesystem.h" +#include "RootInode.h" +#include "RPCServer.h" extern fs_volume_ops gNFSv4VolumeOps; @@ -107,7 +108,7 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, return result; } - Inode* inode = fs->CreateRootInode(); + Inode* inode = fs->Root(); if (inode == NULL) { delete fs; gRPCServerManager->Release(server); @@ -166,7 +167,8 @@ static status_t nfs4_read_fs_info(fs_volume* volume, struct fs_info* info) { Filesystem* fs = reinterpret_cast(volume->private_volume); - return fs->ReadInfo(info); + RootInode* inode = reinterpret_cast(fs->Root()); + return inode->ReadInfo(info); } @@ -196,7 +198,11 @@ 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(volume->private_volume); Inode* inode = reinterpret_cast(vnode->private_node); + if (fs->Root() == inode) + return B_OK; + inode->FileSystem()->InoIdMap()->RemoveEntry(inode->ID()); delete inode; @@ -211,7 +217,11 @@ nfs4_remove_vnode(fs_volume* volume, fs_vnode* vnode, bool reenter) // side are only an attempt to simulate local filesystem. Hence, // this hook is the same as put_vnode(). + Filesystem* fs = reinterpret_cast(volume->private_volume); Inode* inode = reinterpret_cast(vnode->private_node); + if (fs->Root() == inode) + return B_OK; + inode->FileSystem()->InoIdMap()->RemoveEntry(inode->ID()); delete inode;