[haiku-commits] BRANCH pdziepak-github.nfs4 - src/add-ons/kernel/file_systems/nfs4

  • From: pdziepak-github.nfs4 <community@xxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Tue, 5 Feb 2013 03:30:47 +0100 (CET)

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;
        


Other related posts: