From f390f181575faba29cdecdbd418bd646de26cd20 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Fri, 2 Sep 2011 20:27:01 +1000 Subject: [PATCH] nfs_opendir() switch to using READDIRPLUS3 instead of READDIR3 when reading directories. --- include/libnfs-raw.h | 18 +++++++++++++++++- lib/libnfs.c | 18 +++++++++--------- nfs/nfs.c | 35 ++++++++++++++++++++++++++++++++++- 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/include/libnfs-raw.h b/include/libnfs-raw.h index 1650a8a..573205c 100644 --- a/include/libnfs-raw.h +++ b/include/libnfs-raw.h @@ -444,7 +444,7 @@ int rpc_nfs_remove_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, /* - * Call NFS/REMOVE + * Call NFS/READDIR * Function returns * 0 : The call was initiated. The callback will be invoked when the call completes. * <0 : An error occured when trying to set up the call. The callback will not be invoked. @@ -459,6 +459,22 @@ int rpc_nfs_remove_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, */ int rpc_nfs_readdir_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, uint64_t cookie, char *cookieverf, int count, void *private_data); +/* + * Call NFS/READDIRPLUS + * Function returns + * 0 : The call was initiated. The callback will be invoked when the call completes. + * <0 : An error occured when trying to set up the call. The callback will not be invoked. + * + * When the callback is invoked, status indicates the result: + * RPC_STATUS_SUCCESS : We got a successful response from the nfs daemon. + * data is READDIRPLUS3res * + * RPC_STATUS_ERROR : An error occured when trying to contact the nfs daemon. + * data is the error string. + * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete. + * data is NULL. + */ +int rpc_nfs_readdirplus_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, uint64_t cookie, char *cookieverf, int count, void *private_data); + /* * Call NFS/FSSTAT * Function returns diff --git a/lib/libnfs.c b/lib/libnfs.c index 80a7394..2e504a4 100644 --- a/lib/libnfs.c +++ b/lib/libnfs.c @@ -1651,13 +1651,13 @@ int nfs_unlink_async(struct nfs_context *nfs, const char *path, nfs_cb cb, void */ static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) { - READDIR3res *res; + READDIRPLUS3res *res; struct nfs_cb_data *data = private_data; struct nfs_context *nfs = data->nfs; struct nfsdir *nfsdir = data->continue_data;; - struct entry3 *entry; + struct entryplus3 *entry; uint64_t cookie; - + if (status == RPC_STATUS_ERROR) { data->cb(-EFAULT, nfs, command_data, data->private_data); nfs_free_nfsdir(nfsdir); @@ -1683,7 +1683,7 @@ static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *comman return; } - entry =res->READDIR3res_u.resok.reply.entries; + entry =res->READDIRPLUS3res_u.resok.reply.entries; while (entry != NULL) { struct nfsdirent *nfsdirent; @@ -1712,9 +1712,9 @@ static void nfs_opendir_cb(struct rpc_context *rpc _U_, int status, void *comman entry = entry->nextentry; } - if (res->READDIR3res_u.resok.reply.eof == 0) { - if (rpc_nfs_readdir_async(nfs->rpc, nfs_opendir_cb, &data->fh, cookie, res->READDIR3res_u.resok.cookieverf, 20000, data) != 0) { - rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR call for %s", data->path); + if (res->READDIRPLUS3res_u.resok.reply.eof == 0) { + if (rpc_nfs_readdirplus_async(nfs->rpc, nfs_opendir_cb, &data->fh, cookie, res->READDIRPLUS3res_u.resok.cookieverf, 8192, data) != 0) { + rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIRPLUS call for %s", data->path); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); nfs_free_nfsdir(nfsdir); data->continue_data = NULL; @@ -1737,8 +1737,8 @@ static int nfs_opendir_continue_internal(struct nfs_context *nfs, struct nfs_cb_ cookieverf3 cv; bzero(cv, sizeof(cookieverf3)); - if (rpc_nfs_readdir_async(nfs->rpc, nfs_opendir_cb, &data->fh, 0, (char *)&cv, 20000, data) != 0) { - rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIR call for %s", data->path); + if (rpc_nfs_readdirplus_async(nfs->rpc, nfs_opendir_cb, &data->fh, 0, (char *)&cv, 8192, data) != 0) { + rpc_set_error(nfs->rpc, "RPC error: Failed to send READDIRPLUS call for %s", data->path); data->cb(-ENOMEM, nfs, rpc_get_error(nfs->rpc), data->private_data); free_nfs_cb_data(data); return -1; diff --git a/nfs/nfs.c b/nfs/nfs.c index a9775e7..5b655cb 100644 --- a/nfs/nfs.c +++ b/nfs/nfs.c @@ -476,7 +476,6 @@ int rpc_nfs_remove_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, return 0; } - int rpc_nfs_readdir_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, uint64_t cookie, char *cookieverf, int count, void *private_data) { struct rpc_pdu *pdu; @@ -510,6 +509,40 @@ int rpc_nfs_readdir_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh return 0; } +int rpc_nfs_readdirplus_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, uint64_t cookie, char *cookieverf, int count, void *private_data) +{ + struct rpc_pdu *pdu; + READDIRPLUS3args args; + + pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_READDIRPLUS, cb, private_data, (xdrproc_t)xdr_READDIRPLUS3res, sizeof(READDIRPLUS3res)); + if (pdu == NULL) { + rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for nfs/readdirplus call"); + return -1; + } + + bzero(&args, sizeof(READDIRPLUS3args)); + args.dir.data.data_len = fh->data.data_len; + args.dir.data.data_val = fh->data.data_val; + args.cookie = cookie; + memcpy(&args.cookieverf, cookieverf, sizeof(cookieverf3)); + args.dircount = count; + args.maxcount = count; + + if (xdr_READDIRPLUS3args(&pdu->xdr, &args) == 0) { + rpc_set_error(rpc, "XDR error: Failed to encode READDIRPLUS3args"); + rpc_free_pdu(rpc, pdu); + return -2; + } + + if (rpc_queue_pdu(rpc, pdu) != 0) { + rpc_set_error(rpc, "Out of memory. Failed to queue pdu for nfs/readdirplus call"); + rpc_free_pdu(rpc, pdu); + return -3; + } + + return 0; +} + int rpc_nfs_fsstat_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *fh, void *private_data) { struct rpc_pdu *pdu; -- 2.34.1