From 9e63589591dc0aae7828a0cac4a7ee1d196e4b6f Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Sat, 29 Dec 2018 13:56:29 +1000 Subject: [PATCH] add nfs_umount() which will unregister the client from the mount daemon This is only implemented for v3 since there is no mount protocol in v4. Signed-off-by: Ronnie Sahlberg --- examples/nfs-fh.c | 1 + include/libnfs-private.h | 1 + include/nfsc/libnfs.h | 33 +++++++++++++++ lib/libnfs-sync.c | 51 ++++++++++++++++++++++++ lib/libnfs-win32.def | 2 + lib/libnfs.c | 20 ++++++++++ lib/nfs_v3.c | 86 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 194 insertions(+) diff --git a/examples/nfs-fh.c b/examples/nfs-fh.c index c7d07bc..bfd5540 100644 --- a/examples/nfs-fh.c +++ b/examples/nfs-fh.c @@ -122,6 +122,7 @@ int main(int argc, char *argv[]) if (nfsfh) { nfs_close(nfs, nfsfh); } + nfs_umount(nfs); if (url) { nfs_destroy_url(url); } diff --git a/include/libnfs-private.h b/include/libnfs-private.h index e906636..f145e16 100644 --- a/include/libnfs-private.h +++ b/include/libnfs-private.h @@ -469,6 +469,7 @@ int nfs3_symlink_async(struct nfs_context *nfs, const char *oldpath, const char *newpath, nfs_cb cb, void *private_data); int nfs3_truncate_async(struct nfs_context *nfs, const char *path, uint64_t length, nfs_cb cb, void *private_data); +int nfs3_umount_async(struct nfs_context *nfs, nfs_cb cb, void *private_data); int nfs3_unlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void *private_data); int nfs3_utime_async(struct nfs_context *nfs, const char *path, diff --git a/include/nfsc/libnfs.h b/include/nfsc/libnfs.h index e82681e..88fde5c 100755 --- a/include/nfsc/libnfs.h +++ b/include/nfsc/libnfs.h @@ -316,6 +316,39 @@ EXTERN int nfs_mount(struct nfs_context *nfs, const char *server, const char *exportname); +/* + * UNMOUNT THE EXPORT + */ +/* + * Async nfs umount. + * For NFSv4 this is a NO-OP. + * For NFSv3 this function returns unregisters the mount from the MOUNT Daemon. + * + * 0 : The command was queued successfully. The callback will be invoked once + * the command completes. + * <0 : An error occured when trying to queue the command. + * The callback will not be invoked. + * + * When the callback is invoked, status indicates the result: + * 0 : Success. + * data is NULL + * -errno : An error occured. + * data is the error string. + */ +EXTERN int nfs_umount_async(struct nfs_context *nfs, nfs_cb cb, + void *private_data); +/* + * Sync nfs umount. + * For NFSv4 this is a NO-OP. + * For NFSv3 this function returns unregisters the mount from the MOUNT Daemon. + * + * Function returns + * 0 : The operation was successful. + * -errno : The command failed. + */ +EXTERN int nfs_umount(struct nfs_context *nfs); + + /* diff --git a/lib/libnfs-sync.c b/lib/libnfs-sync.c index 4947eba..313e0a9 100644 --- a/lib/libnfs-sync.c +++ b/lib/libnfs-sync.c @@ -228,6 +228,57 @@ nfs_mount(struct nfs_context *nfs, const char *server, const char *export) } +/* + * unregister the mount + */ +static void +umount_cb(int status, struct nfs_context *nfs, void *data, void *private_data) +{ + struct sync_cb_data *cb_data = private_data; + + cb_data->is_finished = 1; + cb_data->status = status; + + if (status < 0) { + nfs_set_error(nfs, "%s: %s", + __FUNCTION__, nfs_get_error(nfs)); + return; + } +} + +int +nfs_umount(struct nfs_context *nfs) +{ + struct sync_cb_data cb_data; + struct rpc_context *rpc = nfs_get_rpc_context(nfs); + + assert(rpc->magic == RPC_CONTEXT_MAGIC); + + cb_data.is_finished = 0; + + if (nfs_umount_async(nfs, umount_cb, &cb_data) != 0) { + nfs_set_error(nfs, "nfs_umount_async failed. %s", + nfs_get_error(nfs)); + return -1; + } + + wait_for_nfs_reply(nfs, &cb_data); + + /* Dont want any more callbacks even if the socket is closed */ + rpc->connect_cb = NULL; + + /* Ensure that no RPCs are pending. In error case (e.g. timeout in + * wait_for_nfs_reply()) we can disconnect; in success case all RPCs + * are completed by definition. + */ + if (cb_data.status) { + rpc_disconnect(rpc, "failed mount"); + } + + return cb_data.status; +} + + /* * stat() */ diff --git a/lib/libnfs-win32.def b/lib/libnfs-win32.def index c00ec43..f38ebe6 100644 --- a/lib/libnfs-win32.def +++ b/lib/libnfs-win32.def @@ -101,6 +101,8 @@ nfs_symlink nfs_symlink_async nfs_truncate nfs_truncate_async +nfs_umount +nfs_umount_async nfs_unlink nfs_unlink_async nfs_utime diff --git a/lib/libnfs.c b/lib/libnfs.c index a32aff1..ac53a40 100755 --- a/lib/libnfs.c +++ b/lib/libnfs.c @@ -865,6 +865,26 @@ nfs_mount_async(struct nfs_context *nfs, const char *server, } } +/* + * Async call for umounting an nfs share + */ +int +nfs_umount_async(struct nfs_context *nfs, nfs_cb cb, void *private_data) +{ + switch (nfs->version) { + case NFS_V3: + return nfs3_umount_async(nfs, cb, private_data); + case NFS_V4: + /* umount is a no-op in v4 */ + (*cb)(0, nfs, NULL, private_data); + return 0; + default: + nfs_set_error(nfs, "%s does not support NFSv%d", + __FUNCTION__, nfs->version); + return -1; + } +} + int nfs_normalize_path(struct nfs_context *nfs, char *path) { diff --git a/lib/nfs_v3.c b/lib/nfs_v3.c index 74cf358..1ac7f23 100644 --- a/lib/nfs_v3.c +++ b/lib/nfs_v3.c @@ -1152,6 +1152,92 @@ nfs3_mount_async(struct nfs_context *nfs, const char *server, return 0; } +static void +nfs3_umount_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 (check_nfs3_error(nfs, status, data, command_data)) { + free_nfs_cb_data(data); + return; + } + + rpc_disconnect(rpc, "umount"); + data->cb(0, nfs, NULL, data->private_data); + free_nfs_cb_data(data); +} + +static void +nfs3_umount_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); + + if (check_nfs3_error(nfs, status, data, command_data)) { + free_nfs_cb_data(data); + return; + } + + if (rpc_mount3_umnt_async(rpc, nfs3_umount_2_cb, nfs->export, + data) != 0) { + nfs_set_error(nfs, "%s: %s.", __FUNCTION__, nfs_get_error(nfs)); + data->cb(-ENOMEM, nfs, nfs_get_error(nfs), data->private_data); + free_nfs_cb_data(data); + return; + } +} + +int +nfs3_umount_async(struct nfs_context *nfs, nfs_cb cb, void *private_data) +{ + struct nfs_cb_data *data; + + data = malloc(sizeof(struct nfs_cb_data)); + if (data == NULL) { + nfs_set_error(nfs, "out of memory. failed to allocate " + "memory for nfs mount data"); + return -1; + } + memset(data, 0, sizeof(struct nfs_cb_data)); + + data->nfs = nfs; + data->cb = cb; + data->private_data = private_data; + + rpc_disconnect(nfs->rpc, "umount"); + + if (nfs->mountport) { + if (rpc_connect_port_async(nfs->rpc, nfs->server, + nfs->mountport, + MOUNT_PROGRAM, MOUNT_V3, + nfs3_umount_1_cb, data) != 0) { + nfs_set_error(nfs, "Failed to start connection. %s", + nfs_get_error(nfs)); + free_nfs_cb_data(data); + return -1; + } + return 0; + } + + if (rpc_connect_program_async(nfs->rpc, nfs->server, + MOUNT_PROGRAM, MOUNT_V3, + nfs3_umount_1_cb, data) != 0) { + nfs_set_error(nfs, "Failed to start connection. %s", + nfs_get_error(nfs)); + free_nfs_cb_data(data); + return -1; + } + + return 0; +} + struct nfs_link_data { char *oldpath;