nfs4: Add support for server migration

This commit is contained in:
Pawel Dziepak
2012-06-29 02:15:00 +02:00
parent 47c4ae3751
commit 19df56ac66
6 changed files with 351 additions and 46 deletions
@@ -11,14 +11,21 @@
#include <string.h>
#include "Request.h"
#include <arpa/inet.h>
#include <net/dns_resolver.h>
#include "Request.h"
#include "Inode.h"
extern RPC::ServerManager* gRPCServerManager;
extern RPC::ProgramData* CreateNFS4Server(RPC::Server* serv);
Filesystem::Filesystem()
:
fPath(NULL),
fName(NULL),
fId(1)
{
}
@@ -26,10 +33,27 @@ Filesystem::Filesystem()
Filesystem::~Filesystem()
{
free(const_cast<char*>(fName));
free(const_cast<char*>(fPath));
}
static const char*
sGetPath(const char* root, const char* path)
{
int slash = 0;
for (int i = 0; path[i] != '\0'; i++) {
if (path[i] != root[i] || root[i] == '\0')
break;
if (path[i] == '/')
slash = i;
}
return path + slash;
}
status_t
Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath,
dev_t id)
@@ -67,7 +91,7 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath,
req.GetFH();
req.Access();
Attribute attr[] = { FATTR4_FSID };
Attribute attr[] = { FATTR4_FSID, FATTR4_FS_LOCATIONS };
req.GetAttr(attr, sizeof(attr) / sizeof(Attribute));
status_t result = request.Send();
@@ -110,15 +134,39 @@ Filesystem::Mount(Filesystem** pfs, RPC::Server* serv, const char* fsPath,
reinterpret_cast<FilesystemId*>(values[0].fData.fPointer);
Filesystem* fs = new(std::nothrow) Filesystem;
if (count == 2 && values[1].fAttribute == FATTR4_FS_LOCATIONS) {
FSLocations* locs =
reinterpret_cast<FSLocations*>(values[1].fData.fLocations);
fs->fPath = strdup(locs->fRootPath);
delete locs;
} else
fs->fPath = NULL;
const char* name;
if (fsPath != NULL && fsPath[0] == '/')
fs->fPath = strdup(fsPath + 1);
else
fs->fPath = strdup(fsPath + 1);
fsPath++;
name = strrchr(fsPath, '/');
if (name != NULL) {
name++;
fs->fName = strdup(name);
} else
fs->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;
return B_OK;
@@ -149,14 +197,8 @@ Filesystem::GetInode(ino_t id, Inode** _inode)
Inode*
Filesystem::CreateRootInode()
{
FileInfo fi;
fi.fFH = fRootFH;
fi.fParent = fRootFH;
fi.fName = strdup("/");
fi.fPath = strdup(fPath);
Inode* inode;
status_t result = Inode::CreateInode(this, fi, &inode);
status_t result = Inode::CreateInode(this, fRoot, &inode);
if (result == B_OK)
return inode;
else
@@ -229,12 +271,95 @@ Filesystem::ReadInfo(struct fs_info* info)
}
info->flags = B_FS_IS_READONLY;
const char* name = strrchr(fPath, '/');
if (name != NULL) {
name++;
strncpy(info->volume_name, name, B_FILE_NAME_LENGTH);
} else
strncpy(info->volume_name, fPath, B_FILE_NAME_LENGTH);
strncpy(info->volume_name, fName, B_FILE_NAME_LENGTH);
return B_OK;
}
status_t
Filesystem::Migrate(const Filehandle& fh, const RPC::Server* serv)
{
mutex_lock(&fMigrationLock);
if (serv != fServer) {
mutex_unlock(&fMigrationLock);
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) {
mutex_unlock(&fMigrationLock);
return result;
}
ReplyInterpreter& reply = request.Reply();
result = reply.PutFH();
if (result != B_OK) {
mutex_unlock(&fMigrationLock);
return result;
}
AttrValue* values;
uint32 count;
result = reply.GetAttr(&values, &count);
if (result != B_OK || count < 1) {
mutex_unlock(&fMigrationLock);
return result;
}
FSLocations* locs =
reinterpret_cast<FSLocations*>(values[0].fData.fLocations);
dns_resolver_module* dns;
result = get_module(DNS_RESOLVER_MODULE_NAME,
reinterpret_cast<module_info**>(&dns));
if (result != B_OK) {
mutex_unlock(&fMigrationLock);
return result;
}
RPC::Server* server = fServer;
for (uint32 i = 0; i < locs->fCount; i++) {
for (uint32 j = 0; j < locs->fLocations[i].fCount; j++) {
uint32 ip;
struct in_addr addr;
if (inet_aton(locs->fLocations[i].fLocations[j], &addr) == 0) {
result = dns->dns_resolve(locs->fLocations[i].fLocations[j],
&ip);
if (result != B_OK)
continue;
} else
ip = addr.s_addr;
if (gRPCServerManager->Acquire(&fServer, ip, 2049,
ProtocolUDP, CreateNFS4Server) == B_OK) {
free(const_cast<char*>(fPath));
fPath = strdup(locs->fLocations[j].fRootPath);
break;
}
}
}
put_module(DNS_RESOLVER_MODULE_NAME);
delete locs;
if (server == fServer) {
mutex_unlock(&fMigrationLock);
return B_ERROR;
}
gRPCServerManager->Release(server);
mutex_unlock(&fMigrationLock);
return B_OK;
}
@@ -30,9 +30,13 @@ public:
status_t ReadInfo(struct fs_info* info);
status_t Migrate(const Filehandle& fh,
const RPC::Server* serv);
inline RPC::Server* Server();
inline NFS4Server* NFSServer();
inline const char* Path() const;
inline const FilesystemId& FsId() const;
inline uint64 AllocFileId();
@@ -42,9 +46,12 @@ public:
private:
Filesystem();
const char* fPath;
FilesystemId fFsId;
const char* fPath;
mutex fMigrationLock;
const char* fName;
FileInfo fRoot;
Filehandle fRootFH;
RPC::Server* fServer;
@@ -70,6 +77,13 @@ Filesystem::NFSServer()
}
inline const char*
Filesystem::Path() const
{
return fPath;
}
inline const FilesystemId&
Filesystem::FsId() const
{
+109 -21
View File
@@ -37,7 +37,8 @@ Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode)
inode->fPath = strdup(fi.fPath);
do {
Request request(fs->Server());
RPC::Server* serv = fs->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(inode->fHandle);
@@ -57,6 +58,12 @@ Inode::CreateInode(Filesystem* fs, const FileInfo &fi, Inode** _inode)
continue;
}
// filesystem has been moved
if (reply.NFS4Error() == NFS4ERR_MOVED) {
fs->Migrate(inode->fHandle, serv);
continue;
}
result = reply.PutFH();
if (result != B_OK)
return result;
@@ -113,7 +120,8 @@ Inode::LookUp(const char* name, ino_t* id)
}
do {
Request request(fFilesystem->Server());
RPC::Server* serv = fFilesystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(fHandle);
@@ -140,6 +148,12 @@ Inode::LookUp(const char* name, ino_t* id)
continue;
}
// filesystem has been moved
if (reply.NFS4Error() == NFS4ERR_MOVED) {
fFilesystem->Migrate(fHandle, serv);
continue;
}
result = reply.PutFH();
if (result != B_OK)
return result;
@@ -206,7 +220,8 @@ Inode::ReadLink(void* buffer, size_t* length)
return B_BAD_VALUE;
do {
Request request(fFilesystem->Server());
RPC::Server* serv = fFilesystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(fHandle);
@@ -224,6 +239,12 @@ Inode::ReadLink(void* buffer, size_t* length)
continue;
}
// filesystem has been moved
if (reply.NFS4Error() == NFS4ERR_MOVED) {
fFilesystem->Migrate(fHandle, serv);
continue;
}
result = reply.PutFH();
if (result != B_OK)
return result;
@@ -241,7 +262,8 @@ status_t
Inode::Access(int mode)
{
do {
Request request(fFilesystem->Server());
RPC::Server* serv = fFilesystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(fHandle);
@@ -259,6 +281,12 @@ Inode::Access(int mode)
continue;
}
// filesystem has been moved
if (reply.NFS4Error() == NFS4ERR_MOVED) {
fFilesystem->Migrate(fHandle, serv);
continue;
}
result = reply.PutFH();
if (result != B_OK)
return result;
@@ -293,7 +321,8 @@ status_t
Inode::Stat(struct stat* st)
{
do {
Request request(fFilesystem->Server());
RPC::Server* serv = fFilesystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(fHandle);
@@ -315,6 +344,12 @@ Inode::Stat(struct stat* st)
continue;
}
// filesystem has been moved
if (reply.NFS4Error() == NFS4ERR_MOVED) {
fFilesystem->Migrate(fHandle, serv);
continue;
}
result = reply.PutFH();
if (result != B_OK)
return result;
@@ -419,7 +454,8 @@ Inode::Open(int mode, OpenFileCookie* cookie)
do {
cookie->fClientId = fFilesystem->NFSServer()->ClientId();
Request request(fFilesystem->Server());
RPC::Server* serv = fFilesystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
cookie->fOwnerId = atomic_add64(&cookie->fLastOwnerId, 1);
@@ -440,6 +476,12 @@ Inode::Open(int mode, OpenFileCookie* cookie)
continue;
}
// filesystem has been moved
if (reply.NFS4Error() == NFS4ERR_MOVED) {
fFilesystem->Migrate(fHandle, serv);
continue;
}
// server is in grace period, we need to wait
if (reply.NFS4Error() == NFS4ERR_GRACE) {
fFilesystem->NFSServer()->ReleaseCID(cookie->fClientId);
@@ -501,7 +543,8 @@ Inode::Close(OpenFileCookie* cookie)
fFilesystem->NFSServer()->RemoveOpenFile(cookie);
do {
Request request(fFilesystem->Server());
RPC::Server* serv = fFilesystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(fHandle);
@@ -520,6 +563,12 @@ Inode::Close(OpenFileCookie* cookie)
continue;
}
// filesystem has been moved
if (reply.NFS4Error() == NFS4ERR_MOVED) {
fFilesystem->Migrate(fHandle, serv);
continue;
}
// server is in grace period, we need to wait
if (reply.NFS4Error() == NFS4ERR_GRACE) {
snooze_etc(fFilesystem->NFSServer()->LeaseTime() / 3,
@@ -553,7 +602,8 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length)
while (size < *_length && !eof) {
do {
Request request(fFilesystem->Server());
RPC::Server* serv = fFilesystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(fHandle);
@@ -572,6 +622,12 @@ Inode::Read(OpenFileCookie* cookie, off_t pos, void* buffer, size_t* _length)
continue;
}
// filesystem has been moved
if (reply.NFS4Error() == NFS4ERR_MOVED) {
fFilesystem->Migrate(fHandle, serv);
continue;
}
// server is in grace period, we need to wait
if (reply.NFS4Error() == NFS4ERR_GRACE) {
snooze_etc(fFilesystem->NFSServer()->LeaseTime() / 3,
@@ -614,7 +670,8 @@ Inode::OpenDir(uint64* cookie)
return B_NOT_A_DIRECTORY;
do {
Request request(fFilesystem->Server());
RPC::Server* serv = fFilesystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(fHandle);
@@ -632,6 +689,12 @@ Inode::OpenDir(uint64* cookie)
continue;
}
// filesystem has been moved
if (reply.NFS4Error() == NFS4ERR_MOVED) {
fFilesystem->Migrate(fHandle, serv);
continue;
}
result = reply.PutFH();
if (result != B_OK)
return result;
@@ -657,7 +720,8 @@ Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, uint64* cookie,
bool* eof)
{
do {
Request request(fFilesystem->Server());
RPC::Server* serv = fFilesystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(fHandle);
@@ -677,6 +741,12 @@ Inode::_ReadDirOnce(DirEntry** dirents, uint32* count, uint64* cookie,
continue;
}
// filesystem has been moved
if (reply.NFS4Error() == NFS4ERR_MOVED) {
fFilesystem->Migrate(fHandle, serv);
continue;
}
result = reply.PutFH();
if (result != B_OK)
return result;
@@ -712,7 +782,8 @@ status_t
Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
{
do {
Request request(fFilesystem->Server());
RPC::Server* serv = fFilesystem->Server();
Request request(serv);
RequestBuilder& req = request.Builder();
req.PutFH(fHandle);
@@ -733,6 +804,12 @@ Inode::_ReadDirUp(struct dirent* de, uint32 pos, uint32 size)
continue;
}
// filesystem has been moved
if (reply.NFS4Error() == NFS4ERR_MOVED) {
fFilesystem->Migrate(fHandle, serv);
continue;
}
result = reply.PutFH();
if (result != B_OK)
return result;
@@ -849,16 +926,10 @@ Inode::ReadDir(void* _buffer, uint32 size, uint32* _count, uint64* cookie)
}
status_t
Inode::_LookUpFilehandle()
static status_t
sParsePath(RequestBuilder& req, uint32* count, const char* _path)
{
Request request(fFilesystem->Server());
RequestBuilder& req = request.Builder();
req.PutRootFH();
uint32 lookupCount = 0;
char* path = strdup(fPath);
char* path = strdup(_path);
char* pathStart = path;
char* pathEnd;
while (pathStart != NULL) {
@@ -873,10 +944,27 @@ Inode::_LookUpFilehandle()
else
pathStart = NULL;
lookupCount++;
(*count)++;
}
free(path);
return B_OK;
}
status_t
Inode::_LookUpFilehandle()
{
Request request(fFilesystem->Server());
RequestBuilder& req = request.Builder();
req.PutRootFH();
uint32 lookupCount = 0;
sParsePath(req, &lookupCount, fFilesystem->Path());
sParsePath(req, &lookupCount, fPath);
req.GetFH();
status_t result = request.Send();
@@ -14,6 +14,22 @@
#include <util/kernel_cpp.h>
FSLocation::~FSLocation()
{
free(const_cast<char*>(fRootPath));
for (uint32 i = 0; i < fCount; i++)
free(const_cast<char*>(fLocations[i]));
delete[] fLocations;
}
FSLocations::~FSLocations()
{
free(const_cast<char*>(fRootPath));
delete[] fLocations;
}
AttrValue::AttrValue()
:
fFreePointer(false)
@@ -25,6 +41,8 @@ AttrValue::~AttrValue()
{
if (fFreePointer)
free(fData.fPointer);
if (fAttribute == FATTR4_FS_LOCATIONS)
delete fData.fLocations;
}
@@ -285,6 +303,30 @@ ReplyInterpreter::SetClientID(uint64* clientid, uint64* verifier)
}
static const char*
sFlattenPathname(XDR::ReadStream& str)
{
uint32 count = str.GetUInt();
char* pathname = NULL;
uint32 size = 0;
for (uint32 i = 0; i < count; i++) {
const char* path = str.GetString();
size += strlen(path) + 1;
if (pathname == NULL) {
pathname = reinterpret_cast<char*>(malloc(strlen(path + 1)));
pathname[0] = '\0';
} else {
*pathname++ = '/';
pathname = reinterpret_cast<char*>(realloc(pathname, size));
}
strcat(pathname, path);
free(const_cast<char*>(path));
}
return pathname;
}
status_t
ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs,
uint32* count)
@@ -374,6 +416,25 @@ ReplyInterpreter::_DecodeAttrs(XDR::ReadStream& str, AttrValue** attrs,
current++;
}
if (sIsAttrSet(FATTR4_FS_LOCATIONS, bitmap, bcount)) {
values[current].fAttribute = FATTR4_FS_LOCATIONS;
FSLocations* locs = new FSLocations;
locs->fRootPath = sFlattenPathname(stream);
locs->fCount = stream.GetUInt();
locs->fLocations = new FSLocation[locs->fCount];
for (uint32 i = 0; i < locs->fCount; i++) {
locs->fLocations[i].fRootPath = sFlattenPathname(stream);
locs->fLocations[i].fCount = stream.GetUInt();
locs->fLocations[i].fLocations =
new const char*[locs->fLocations[i].fCount];
for (uint32 j = 0; j < locs->fLocations[i].fCount; j++)
locs->fLocations[i].fLocations[j] = stream.GetString();
}
values[current].fData.fLocations = locs;
current++;
}
if (sIsAttrSet(FATTR4_MAXREAD, bitmap, bcount)) {
values[current].fAttribute = FATTR4_MAXREAD;
values[current].fData.fValue64 = stream.GetUHyper();
@@ -15,6 +15,22 @@
#include "RPCReply.h"
struct FSLocation {
const char* fRootPath;
const char** fLocations;
uint32 fCount;
~FSLocation();
};
struct FSLocations {
const char* fRootPath;
FSLocation* fLocations;
uint32 fCount;
~FSLocations();
};
struct AttrValue {
AttrValue();
~AttrValue();
@@ -25,6 +41,7 @@ struct AttrValue {
uint32 fValue32;
uint64 fValue64;
void* fPointer;
FSLocations* fLocations;
} fData;
};
@@ -32,8 +32,8 @@ dprintf(const char* format, ...);
RPC::ServerManager* gRPCServerManager;
static RPC::ProgramData*
sCreateNFS4Server(RPC::Server* serv)
RPC::ProgramData*
CreateNFS4Server(RPC::Server* serv)
{
return new NFS4Server(serv);
}
@@ -96,7 +96,7 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags,
RPC::Server *server;
result = gRPCServerManager->Acquire(&server, ip, 2049, ProtocolUDP,
sCreateNFS4Server);
CreateNFS4Server);
if (result != B_OK)
return result;