added 1 changeset to branch 'refs/remotes/pdziepak-github/nfs4' old head: 15a18a6b891de5945e958b4de54c0fbb462bc5fa new head: a0d5a922d6440c2d4df51536fab9ef5057e021f5 overview: https://github.com/pdziepak/Haiku/compare/15a18a6...a0d5a92 ---------------------------------------------------------------------------- a0d5a92: nfs4: Try connecting to all getaddrinfo() results before giving up [ Pawel Dziepak <pdziepak@xxxxxxxxxxx> ] ---------------------------------------------------------------------------- Commit: a0d5a922d6440c2d4df51536fab9ef5057e021f5 Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Tue Feb 5 02:20:37 2013 UTC ---------------------------------------------------------------------------- 6 files changed, 140 insertions(+), 39 deletions(-) .../kernel/file_systems/nfs4/Connection.cpp | 98 ++++++++++++++++---- .../kernel/file_systems/nfs4/Connection.h | 28 +++++- .../kernel/file_systems/nfs4/FileSystem.cpp | 7 +- .../kernel/file_systems/nfs4/RPCServer.cpp | 19 +++- src/add-ons/kernel/file_systems/nfs4/RPCServer.h | 4 +- .../file_systems/nfs4/kernel_interface.cpp | 23 +++-- ---------------------------------------------------------------------------- diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp index 371cc39..e9f8678 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.cpp @@ -189,17 +189,36 @@ PeerAddress::InAddrSize() const } +AddressResolver::AddressResolver(const char* name) + : + fHead(NULL), + fCurrent(NULL), + fForcedPort(htons(NFS4_PORT)), + fForcedProtocol(IPPROTO_TCP) +{ + fStatus = ResolveAddress(name); +} + + +AddressResolver::~AddressResolver() +{ + freeaddrinfo(fHead); +} + + status_t -PeerAddress::ResolveName(const char* name, PeerAddress* address) +AddressResolver::ResolveAddress(const char* name) { ASSERT(name != NULL); - ASSERT(address != NULL); - address->fProtocol = IPPROTO_TCP; + if (fHead != NULL) { + freeaddrinfo(fHead); + fHead = NULL; + fCurrent = NULL; + } // getaddrinfo() is very expensive when called from kernel, so we do not // want to call it unless there is no other choice. - struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); if (inet_aton(name, &addr.sin_addr) == 1) { @@ -207,35 +226,74 @@ PeerAddress::ResolveName(const char* name, PeerAddress* address) addr.sin_family = AF_INET; addr.sin_port = htons(NFS4_PORT); - memcpy(&address->fAddress, &addr, sizeof(addr)); + memcpy(&fAddress.fAddress, &addr, sizeof(addr)); + fAddress.fProtocol = IPPROTO_TCP; return B_OK; } - addrinfo* ai; - status_t result = getaddrinfo(name, NULL, NULL, &ai); - if (result != B_OK) - return result; + status_t result = getaddrinfo(name, NULL, NULL, &fHead); + fCurrent = fHead; + + return result; +} + + +void +AddressResolver::ForceProtocol(const char* protocol) +{ + ASSERT(protocol != NULL); + + if (strcmp(protocol, "tcp") == 0) + fForcedProtocol = IPPROTO_TCP; + else if (strcmp(protocol, "udp") == 0) + fForcedProtocol = IPPROTO_UDP; + + fAddress.SetProtocol(protocol); +} + + +void +AddressResolver::ForcePort(uint16 port) +{ + fForcedPort = htons(port); + fAddress.SetPort(port); +} + + +status_t +AddressResolver::GetNextAddress(PeerAddress* address) +{ + ASSERT(address != NULL); + + if (fStatus != B_OK) + return fStatus; + + if (fHead == NULL) { + *address = fAddress; + fStatus = B_NAME_NOT_FOUND; + return B_OK; + } + + address->fProtocol = fForcedProtocol; - addrinfo* current = ai; - while (current != NULL) { - if (current->ai_family == AF_INET) { - memcpy(&address->fAddress, current->ai_addr, sizeof(sockaddr_in)); + while (fCurrent != NULL) { + if (fCurrent->ai_family == AF_INET) { + memcpy(&address->fAddress, fCurrent->ai_addr, sizeof(sockaddr_in)); reinterpret_cast<sockaddr_in*>(&address->fAddress)->sin_port - = htons(NFS4_PORT); - } else if (current->ai_family == AF_INET6) { - memcpy(&address->fAddress, current->ai_addr, sizeof(sockaddr_in6)); + = fForcedPort; + } else if (fCurrent->ai_family == AF_INET6) { + memcpy(&address->fAddress, fCurrent->ai_addr, sizeof(sockaddr_in6)); reinterpret_cast<sockaddr_in6*>(&address->fAddress)->sin6_port - = htons(NFS4_PORT); + = fForcedPort; } else { - current = current->ai_next; + fCurrent = fCurrent->ai_next; continue; } - freeaddrinfo(ai); + fCurrent = fCurrent->ai_next; return B_OK; } - freeaddrinfo(ai); return B_NAME_NOT_FOUND; } diff --git a/src/add-ons/kernel/file_systems/nfs4/Connection.h b/src/add-ons/kernel/file_systems/nfs4/Connection.h index aceb2c0..16f8062 100644 --- a/src/add-ons/kernel/file_systems/nfs4/Connection.h +++ b/src/add-ons/kernel/file_systems/nfs4/Connection.h @@ -38,9 +38,33 @@ struct PeerAddress { const void* InAddr() const; size_t InAddrSize() const; +}; + +struct addrinfo; + +class AddressResolver { +public: + AddressResolver(const char* name); + ~AddressResolver(); + + status_t GetNextAddress(PeerAddress* address); + + void ForceProtocol(const char* protocol); + void ForcePort(uint16 port); + +protected: + status_t ResolveAddress(const char* name); + +private: + addrinfo* fHead; + addrinfo* fCurrent; + + PeerAddress fAddress; + + uint16 fForcedPort; + int fForcedProtocol; - static status_t ResolveName(const char* name, - PeerAddress* address); + status_t fStatus; }; class ConnectionBase { diff --git a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp index e76a010..a877cb9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/FileSystem.cpp @@ -257,14 +257,11 @@ FileSystem::Migrate(const RPC::Server* serv) = reinterpret_cast<FSLocations*>(values[0].fData.fLocations); RPC::Server* server = fServer; - PeerAddress addr = fServer->ID(); for (uint32 i = 0; i < locs->fCount; i++) { for (uint32 j = 0; j < locs->fLocations[i].fCount; j++) { - if (PeerAddress::ResolveName(locs->fLocations[i].fLocations[j], - &addr) != B_OK) - continue; + AddressResolver resolver(locs->fLocations[i].fLocations[j]); - if (gRPCServerManager->Acquire(&fServer, addr, + if (gRPCServerManager->Acquire(&fServer, &resolver, CreateNFS4Server) == B_OK) { free(const_cast<char*>(fPath)); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp index f80633e..13f6a5f 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.cpp @@ -312,7 +312,24 @@ ServerManager::~ServerManager() status_t -ServerManager::Acquire(Server** _server, const PeerAddress& address, +ServerManager::Acquire(Server** _server, AddressResolver* resolver, + ProgramData* (*createPrivateData)(Server*)) +{ + PeerAddress address; + status_t result; + + while ((result = resolver->GetNextAddress(&address)) == B_OK) { + result = _Acquire(_server, address, createPrivateData); + if (result == B_OK) + break; + } + + return result; +} + + +status_t +ServerManager::_Acquire(Server** _server, const PeerAddress& address, ProgramData* (*createPrivateData)(Server*)) { ASSERT(_server != NULL); diff --git a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h index 738162d..9421049 100644 --- a/src/add-ons/kernel/file_systems/nfs4/RPCServer.h +++ b/src/add-ons/kernel/file_systems/nfs4/RPCServer.h @@ -171,11 +171,13 @@ public: ServerManager(); ~ServerManager(); - status_t Acquire(Server** _server, const PeerAddress& address, + status_t Acquire(Server** _server, AddressResolver* resolver, ProgramData* (*createPrivateData)(Server*)); void Release(Server* server); private: + status_t _Acquire(Server** _server, const PeerAddress& address, + ProgramData* (*createPrivateData)(Server*)); ServerNode* _Find(const PeerAddress& address); void _Delete(ServerNode* node); 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 7abba1c..630e1e9 100644 --- a/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/nfs4/kernel_interface.cpp @@ -72,7 +72,7 @@ CreateNFS4Server(RPC::Server* serv) // port=X - connect to port X (default: 2049) // proto=X - user transport protocol X (default: tcp) static status_t -ParseArguments(const char* _args, PeerAddress* address, char** _path, +ParseArguments(const char* _args, AddressResolver** address, char** _path, MountConfiguration* conf) { if (_args == NULL) @@ -92,13 +92,15 @@ ParseArguments(const char* _args, PeerAddress* address, char** _path, return B_MISMATCHED_VALUES; *path++ = '\0'; - status_t result = PeerAddress::ResolveName(args, address); - if (result != B_OK) - return result; + *address = new AddressResolver(args); + if (*address == NULL) + return B_NO_MEMORY; *_path = strdup(path); - if (*_path == NULL) + if (*_path == NULL) { + delete *address; return B_NO_MEMORY; + } conf->fHard = false; conf->fRetryLimit = 5; @@ -127,10 +129,10 @@ ParseArguments(const char* _args, PeerAddress* address, char** _path, conf->fEmulateNamedAttrs = true; else if (strncmp(options, "port=", 5) == 0) { options += strlen("port="); - address->SetPort(atoi(options)); + (*address)->ForcePort(atoi(options)); } else if (strncmp(options, "proto=", 6) == 0) { options += strlen("proto="); - address->SetProtocol(options); + (*address)->ForceProtocol(options); } options = optionsEnd; @@ -165,16 +167,17 @@ nfs4_mount(fs_volume* volume, const char* device, uint32 flags, } locker.Unlock(); - PeerAddress address; + AddressResolver* resolver; MountConfiguration config; char* path; - result = ParseArguments(args, &address, &path, &config); + result = ParseArguments(args, &resolver, &path, &config); if (result != B_OK) return result; MemoryDeleter pathDeleter(path); RPC::Server* server; - result = gRPCServerManager->Acquire(&server, address, CreateNFS4Server); + result = gRPCServerManager->Acquire(&server, resolver, CreateNFS4Server); + delete resolver; if (result != B_OK) return result;