nfs4: Add full support for lease migration

This commit is contained in:
Pawel Dziepak
2012-06-29 02:15:31 +02:00
parent 6ebe67d0d0
commit 2f03ff09af
10 changed files with 278 additions and 145 deletions
@@ -16,7 +16,7 @@
#include <net/dns_resolver.h>
#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<char*>(fName));
free(const_cast<char*>(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<RootInode*>(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<NFS4Server*>(server->PrivateData());
old->RemoveFilesystem(this);
NFSServer()->AddFilesystem(this);
gRPCServerManager->Release(server);
return B_OK;
@@ -9,15 +9,13 @@
#define FILESYSTEM_H
#include <fs_info.h>
#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<Inode*>(fRoot);
}
inline uint32
Filesystem::OpenFilesCount()
{
+11 -11
View File
@@ -15,6 +15,7 @@
#include <NodeMonitor.h>
#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:
+1 -1
View File
@@ -68,7 +68,7 @@ public:
status_t ReleaseAllLocks(OpenFileCookie* cookie);
private:
protected:
Inode();
@@ -13,6 +13,7 @@ KernelAddon nfs4 :
ReplyInterpreter.cpp
Request.cpp
RequestBuilder.cpp
RootInode.cpp
RPCAuth.cpp
RPCCall.cpp
RPCReply.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;
@@ -23,6 +23,7 @@ public:
virtual ~NFS4Server();
uint64 ServerRebooted(uint64 clientId);
status_t FilesystemMigrated();
void AddFilesystem(Filesystem* fs);
void RemoveFilesystem(Filesystem* fs);
@@ -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 <string.h>
#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;
}
@@ -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 <fs_info.h>
#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
@@ -14,12 +14,13 @@
#include <fs_interface.h>
#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<Filesystem*>(volume->private_volume);
return fs->ReadInfo(info);
RootInode* inode = reinterpret_cast<RootInode*>(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<Filesystem*>(volume->private_volume);
Inode* inode = reinterpret_cast<Inode*>(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<Filesystem*>(volume->private_volume);
Inode* inode = reinterpret_cast<Inode*>(vnode->private_node);
if (fs->Root() == inode)
return B_OK;
inode->FileSystem()->InoIdMap()->RemoveEntry(inode->ID());
delete inode;