GETEXPORT: Use rpc_connect_program_async() flow during list exports
[deb_libnfs.git] / lib / libnfs.c
index 9fdbd0d549e393a4353fe3ac975494ccec9e70be..f38a8ca1fdb8ae6c0e25a5dd8ec0b423d9ffe268 100644 (file)
@@ -394,6 +394,30 @@ void free_rpc_cb_data(struct rpc_cb_data *data)
        free(data);
 }
 
+static void rpc_connect_program_5_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
+{
+       struct rpc_cb_data *data = private_data;
+
+       assert(rpc->magic == RPC_CONTEXT_MAGIC);
+
+       /* Dont want any more callbacks even if the socket is closed */
+       rpc->connect_cb = NULL;
+
+       if (status == RPC_STATUS_ERROR) {
+               data->cb(rpc, status, command_data, data->private_data);
+               free_rpc_cb_data(data);
+               return;
+       }
+       if (status == RPC_STATUS_CANCEL) {
+               data->cb(rpc, status, "Command was cancelled", data->private_data);
+               free_rpc_cb_data(data);
+               return;
+       }
+
+       data->cb(rpc, status, NULL, data->private_data);
+       free_rpc_cb_data(data);
+}
+
 static void rpc_connect_program_4_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        struct rpc_cb_data *data = private_data;
@@ -414,6 +438,25 @@ static void rpc_connect_program_4_cb(struct rpc_context *rpc, int status, void *
                return;
        }
 
+       switch (data->program) {
+       case MOUNT_PROGRAM:
+               if (rpc_mount3_null_async(rpc, rpc_connect_program_5_cb,
+                                       data) != 0) {
+                       data->cb(rpc, status, command_data, data->private_data);
+                       free_rpc_cb_data(data);
+                       return;
+               }
+               return;
+       case NFS_PROGRAM:
+               if (rpc_nfs3_null_async(rpc, rpc_connect_program_5_cb,
+                                       data) != 0) {
+                       data->cb(rpc, status, command_data, data->private_data);
+                       free_rpc_cb_data(data);
+                       return;
+               }
+               return;
+       }
+
        data->cb(rpc, status, NULL, data->private_data);
        free_rpc_cb_data(data);
 }
@@ -469,7 +512,7 @@ static void rpc_connect_program_2_cb(struct rpc_context *rpc, int status, void *
                return;
        }
 
-       if (rpc_pmap_getport_async(rpc, data->program, data->version, IPPROTO_TCP, rpc_connect_program_3_cb, private_data) != 0) {
+       if (rpc_pmap2_getport_async(rpc, data->program, data->version, IPPROTO_TCP, rpc_connect_program_3_cb, private_data) != 0) {
                data->cb(rpc, status, command_data, data->private_data);
                free_rpc_cb_data(data);
                return;
@@ -496,14 +539,14 @@ static void rpc_connect_program_1_cb(struct rpc_context *rpc, int status, void *
                return;
        }
 
-       if (rpc_pmap_null_async(rpc, rpc_connect_program_2_cb, data) != 0) {
+       if (rpc_pmap2_null_async(rpc, rpc_connect_program_2_cb, data) != 0) {
                data->cb(rpc, status, command_data, data->private_data);
                free_rpc_cb_data(data);
                return;
        }
 }
 
-int rpc_connect_program_async(struct rpc_context *rpc, char *server, int program, int version, rpc_cb cb, void *private_data)
+int rpc_connect_program_async(struct rpc_context *rpc, const char *server, int program, int version, rpc_cb cb, void *private_data)
 {
        struct rpc_cb_data *data;
 
@@ -627,36 +670,6 @@ static void nfs_mount_8_cb(struct rpc_context *rpc, int status, void *command_da
        }
 }
 
-
-static void nfs_mount_7_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct nfs_cb_data *data = private_data;
-       struct nfs_context *nfs = data->nfs;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       /* Dont want any more callbacks even if the socket is closed */
-       rpc->connect_cb = NULL;
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(-EFAULT, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-
-       if (rpc_nfs3_null_async(rpc, nfs_mount_8_cb, data) != 0) {
-               data->cb(-ENOMEM, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-}
-
-
 static void nfs_mount_6_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
 {
        struct nfs_cb_data *data = private_data;
@@ -695,11 +708,13 @@ static void nfs_mount_6_cb(struct rpc_context *rpc, int status, void *command_da
        memcpy(nfs->rootfh.data.data_val, res->mountres3_u.mountinfo.fhandle.fhandle3_val, nfs->rootfh.data.data_len);
 
        rpc_disconnect(rpc, "normal disconnect");
-       if (rpc_connect_async(rpc, nfs->server, 2049, nfs_mount_7_cb, data) != 0) {
+
+       if (rpc_connect_program_async(nfs->rpc, nfs->server, NFS_PROGRAM, NFS_V3, nfs_mount_8_cb, data) != 0) {
                data->cb(-ENOMEM, nfs, command_data, data->private_data);
                free_nfs_cb_data(data);
                return;
        }
+
        /* NFS TCP connections we want to autoreconnect after sessions are torn down (due to inactivity or error) */
        rpc_set_autoreconnect(rpc);
 }
@@ -730,123 +745,6 @@ static void nfs_mount_5_cb(struct rpc_context *rpc, int status, void *command_da
        }
 }
 
-static void nfs_mount_4_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct nfs_cb_data *data = private_data;
-       struct nfs_context *nfs = data->nfs;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       /* Dont want any more callbacks even if the socket is closed */
-       rpc->connect_cb = NULL;
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(-EFAULT, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-
-       if (rpc_mount3_null_async(rpc, nfs_mount_5_cb, data) != 0) {
-               data->cb(-ENOMEM, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-}
-
-static void nfs_mount_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct nfs_cb_data *data = private_data;
-       struct nfs_context *nfs = data->nfs;
-       uint32_t mount_port;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(-EFAULT, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-
-       mount_port = *(uint32_t *)command_data;
-       if (mount_port == 0) {
-               rpc_set_error(rpc, "RPC error. Mount program is not available on %s", nfs->server);
-               data->cb(-ENOENT, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-
-       rpc_disconnect(rpc, "normal disconnect");
-       if (rpc_connect_async(rpc, nfs->server, mount_port, nfs_mount_4_cb, data) != 0) {
-               data->cb(-ENOMEM, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-}
-
-
-static void nfs_mount_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct nfs_cb_data *data = private_data;
-       struct nfs_context *nfs = data->nfs;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(-EFAULT, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-
-       if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, IPPROTO_TCP, nfs_mount_3_cb, private_data) != 0) {
-               data->cb(-ENOMEM, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-}
-
-static void nfs_mount_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct nfs_cb_data *data = private_data;
-       struct nfs_context *nfs = data->nfs;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       /* Dont want any more callbacks even if the socket is closed */
-       rpc->connect_cb = NULL;
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(-EFAULT, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(-EINTR, nfs, "Command was cancelled", data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-
-       if (rpc_pmap_null_async(rpc, nfs_mount_2_cb, data) != 0) {
-               data->cb(-ENOMEM, nfs, command_data, data->private_data);
-               free_nfs_cb_data(data);
-               return;
-       }
-}
-
 /*
  * Async call for mounting an nfs share and geting the root filehandle
  */
@@ -875,7 +773,7 @@ int nfs_mount_async(struct nfs_context *nfs, const char *server, const char *exp
        data->cb           = cb;
        data->private_data = private_data;
 
-       if (rpc_connect_async(nfs->rpc, server, 111, nfs_mount_1_cb, data) != 0) {
+       if (rpc_connect_program_async(nfs->rpc, server, MOUNT_PROGRAM, MOUNT_V3, nfs_mount_5_cb, data) != 0) {
                rpc_set_error(nfs->rpc, "Failed to start connection");
                free_nfs_cb_data(data);
                return -1;
@@ -1605,7 +1503,7 @@ static void nfs_pread_mcb(struct rpc_context *rpc, int status, void *command_dat
                                                return;
                                        } else {
                                                rpc_set_error(nfs->rpc, "RPC error: Failed to send READ call for %s", data->path);
-                                               data->error = 1;
+                                               data->oom = 1;
                                        }
                                }
                        }
@@ -1664,8 +1562,7 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offse
 
        assert(data->num_calls == 0);
 
-       /* trying to read more than maximum server read size, we has to chop it up into smaller
-        * reads and collect into a reassembly buffer.
+       /* chop requests into chunks of at most READMAX bytes if necessary.
         * we send all reads in parallel so that performance is still good.
         */
        data->max_offset = offset;
@@ -1683,9 +1580,12 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offse
                mdata = malloc(sizeof(struct nfs_mcb_data));
                if (mdata == NULL) {
                        rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_mcb_data structure");
-                       if (data->num_calls == 0)
+                       if (data->num_calls == 0) {
                                free_nfs_cb_data(data);
-                       return -1;
+                               return -1;
+                       }
+                       data->oom = 1;
+                       break;
                }
                memset(mdata, 0, sizeof(struct nfs_mcb_data));
                mdata->data   = data;
@@ -1696,11 +1596,13 @@ int nfs_pread_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offse
 
                if (rpc_nfs3_read_async(nfs->rpc, nfs_pread_mcb, &args, mdata) != 0) {
                        rpc_set_error(nfs->rpc, "RPC error: Failed to send READ call for %s", data->path);
-                       data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
                        free(mdata);
-                       if (data->num_calls == 0)
+                       if (data->num_calls == 0) {
                                free_nfs_cb_data(data);
-                       return -1;
+                               return -1;
+                       }
+                       data->oom = 1;
+                       break;
                }
 
                count               -= readcount;
@@ -1778,7 +1680,7 @@ static void nfs_pwrite_mcb(struct rpc_context *rpc, int status, void *command_da
                                                return;
                                        } else {
                                                rpc_set_error(nfs->rpc, "RPC error: Failed to send WRITE call for %s", data->path);
-                                               data->error = 1;
+                                               data->oom = 1;
                                        }
                                }
                        }
@@ -1796,7 +1698,11 @@ static void nfs_pwrite_mcb(struct rpc_context *rpc, int status, void *command_da
                /* still waiting for more replies */
                return;
        }
-
+       if (data->oom != 0) {
+               data->cb(-ENOMEM, nfs, command_data, data->private_data);
+               free_nfs_cb_data(data);
+               return;
+       }
        if (data->error != 0) {
                data->cb(-EFAULT, nfs, command_data, data->private_data);
                free_nfs_cb_data(data);
@@ -1836,8 +1742,7 @@ int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offs
        /* hello, clang-analyzer */
        assert(data->num_calls == 0);
 
-       /* trying to write more than maximum server write size, we has to chop it up into smaller
-        * chunks.
+       /* chop requests into chunks of at most WRITEMAX bytes if necessary.
         * we send all writes in parallel so that performance is still good.
         */
        data->max_offset = offset;
@@ -1855,9 +1760,12 @@ int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offs
                mdata = malloc(sizeof(struct nfs_mcb_data));
                if (mdata == NULL) {
                        rpc_set_error(nfs->rpc, "out of memory: failed to allocate nfs_mcb_data structure");
-                       if (data->num_calls == 0)
+                       if (data->num_calls == 0) {
                                free_nfs_cb_data(data);
-                       return -1;
+                               return -1;
+                       }
+                       data->oom = 1;
+                       break;
                }
                memset(mdata, 0, sizeof(struct nfs_mcb_data));
                mdata->data   = data;
@@ -1868,12 +1776,13 @@ int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t offs
 
                if (rpc_nfs3_write_async(nfs->rpc, nfs_pwrite_mcb, &args, mdata) != 0) {
                        rpc_set_error(nfs->rpc, "RPC error: Failed to send WRITE call for %s", data->path);
-                       data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data);
                        free(mdata);
-                       if (data->num_calls == 0)
+                       if (data->num_calls == 0) {
                                free_nfs_cb_data(data);
-
-                       return -1;
+                               return -1;
+                       }
+                       data->oom = 1;
+                       break;
                }
 
                count               -= writecount;
@@ -4306,91 +4215,6 @@ static void mount_export_4_cb(struct rpc_context *rpc, int status, void *command
        }
 }
 
-static void mount_export_3_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct mount_cb_data *data = private_data;
-       uint32_t mount_port;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(rpc, -EFAULT, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-
-       mount_port = *(uint32_t *)command_data;
-       if (mount_port == 0) {
-               rpc_set_error(rpc, "RPC error. Mount program is not available");
-               data->cb(rpc, -ENOENT, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-
-       rpc_disconnect(rpc, "normal disconnect");
-       if (rpc_connect_async(rpc, data->server, mount_port, mount_export_4_cb, data) != 0) {
-               data->cb(rpc, -ENOMEM, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-}
-
-static void mount_export_2_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct mount_cb_data *data = private_data;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(rpc, -EFAULT, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-
-       if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, IPPROTO_TCP, mount_export_3_cb, private_data) != 0) {
-               data->cb(rpc, -ENOMEM, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-}
-
-static void mount_export_1_cb(struct rpc_context *rpc, int status, void *command_data, void *private_data)
-{
-       struct mount_cb_data *data = private_data;
-
-       assert(rpc->magic == RPC_CONTEXT_MAGIC);
-
-       /* Dont want any more callbacks even if the socket is closed */
-       rpc->connect_cb = NULL;
-
-       if (status == RPC_STATUS_ERROR) {
-               data->cb(rpc, -EFAULT, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-       if (status == RPC_STATUS_CANCEL) {
-               data->cb(rpc, -EINTR, "Command was cancelled", data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-
-       if (rpc_pmap_null_async(rpc, mount_export_2_cb, data) != 0) {
-               data->cb(rpc, -ENOMEM, command_data, data->private_data);
-               free_mount_cb_data(data);
-               return;
-       }
-}
-
 int mount_getexports_async(struct rpc_context *rpc, const char *server, rpc_cb cb, void *private_data)
 {
        struct mount_cb_data *data;
@@ -4409,7 +4233,8 @@ int mount_getexports_async(struct rpc_context *rpc, const char *server, rpc_cb c
                free_mount_cb_data(data);
                return -1;
        }
-       if (rpc_connect_async(rpc, data->server, 111, mount_export_1_cb, data) != 0) {
+       if (rpc_connect_program_async(rpc, data->server, MOUNT_PROGRAM, MOUNT_V3, mount_export_4_cb, data) != 0) {
+               rpc_set_error(rpc, "Failed to start connection");
                free_mount_cb_data(data);
                return -1;
        }