X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=lib%2Flibnfs.c;h=29a276fb5ee0b1d6f3ccfa06b696b428589efa92;hb=6a14f02fb2e18e66bbfd48ff3c5a7a5b677b51ed;hp=d924c296a2bb87057a450739b1d91e1529fe260b;hpb=ea98629aef9428ca270a76b77e8de49e523be0e4;p=deb_libnfs.git diff --git a/lib/libnfs.c b/lib/libnfs.c index d924c29..29a276f 100644 --- a/lib/libnfs.c +++ b/lib/libnfs.c @@ -17,21 +17,17 @@ /* * High level api to nfs filesystems */ - -#define _GNU_SOURCE - -#if defined(WIN32) -#include +#ifdef WIN32 +#include "win32_compat.h" #define DllExport -#define O_SYNC 0 -typedef int uid_t; -typedef int gid_t; #else #include #include #include #include -#endif +#endif/*WIN32*/ + +#define _GNU_SOURCE #include #include @@ -125,6 +121,11 @@ int nfs_get_fd(struct nfs_context *nfs) return rpc_get_fd(nfs->rpc); } +int nfs_queue_length(struct nfs_context *nfs) +{ + return rpc_queue_length(nfs->rpc); +} + int nfs_which_events(struct nfs_context *nfs) { return rpc_which_events(nfs->rpc); @@ -681,10 +682,10 @@ static void nfs_stat_1_cb(struct rpc_context *rpc _U_, int status, void *command st.st_gid = res->GETATTR3res_u.resok.obj_attributes.gid; st.st_rdev = 0; st.st_size = res->GETATTR3res_u.resok.obj_attributes.size; -#if !defined(WIN32) +#ifndef WIN32 st.st_blksize = 4096; st.st_blocks = res->GETATTR3res_u.resok.obj_attributes.size / 4096; -#endif +#endif//WIN32 st.st_atime = res->GETATTR3res_u.resok.obj_attributes.atime.seconds; st.st_mtime = res->GETATTR3res_u.resok.obj_attributes.mtime.seconds; st.st_ctime = res->GETATTR3res_u.resok.obj_attributes.ctime.seconds; @@ -1041,6 +1042,65 @@ static void nfs_pwrite_cb(struct rpc_context *rpc _U_, int status, void *command free_nfs_cb_data(data); } +static void nfs_pwrite_mcb(struct rpc_context *rpc _U_, int status, void *command_data, void *private_data) +{ + struct nfs_mcb_data *mdata = private_data; + struct nfs_cb_data *data = mdata->data; + struct nfs_context *nfs = data->nfs; + WRITE3res *res; + + data->num_calls--; + + if (status == RPC_STATUS_ERROR) { + /* flag the failure but do not invoke callback until we have received all responses */ + data->error = 1; + } + if (status == RPC_STATUS_CANCEL) { + /* flag the cancellation but do not invoke callback until we have received all responses */ + data->cancel = 1; + } + + if (status == RPC_STATUS_SUCCESS) { + res = command_data; + if (res->status != NFS3_OK) { + rpc_set_error(nfs->rpc, "NFS: Write failed with %s(%d)", nfsstat3_to_str(res->status), nfsstat3_to_errno(res->status)); + data->error = 1; + } else { + if (res->WRITE3res_u.resok.count > 0) { + if ((unsigned)data->max_offset < mdata->offset + res->WRITE3res_u.resok.count) { + data->max_offset = mdata->offset + res->WRITE3res_u.resok.count; + } + } + } + } + + if (data->num_calls > 0) { + /* still waiting for more replies */ + free(mdata); + return; + } + + if (data->error != 0) { + data->cb(-EFAULT, nfs, command_data, data->private_data); + free_nfs_cb_data(data); + free(mdata); + return; + } + if (data->cancel != 0) { + data->cb(-EINTR, nfs, "Command was cancelled", data->private_data); + free_nfs_cb_data(data); + free(mdata); + return; + } + + data->nfsfh->offset = data->max_offset; + data->cb(data->max_offset - data->start_offset, nfs, NULL, data->private_data); + + free_nfs_cb_data(data); + free(mdata); +} + + int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, size_t count, char *buf, nfs_cb cb, void *private_data) { struct nfs_cb_data *data; @@ -1057,12 +1117,54 @@ int nfs_pwrite_async(struct nfs_context *nfs, struct nfsfh *nfsfh, off_t offset, data->nfsfh = nfsfh; nfsfh->offset = offset; - if (rpc_nfs_write_async(nfs->rpc, nfs_pwrite_cb, &nfsfh->fh, buf, offset, count, nfsfh->is_sync?FILE_SYNC:UNSTABLE, data) != 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_nfs_cb_data(data); - return -1; + + if (count <= nfs_get_writemax(nfs)) { + if (rpc_nfs_write_async(nfs->rpc, nfs_pwrite_cb, &nfsfh->fh, buf, offset, count, nfsfh->is_sync?FILE_SYNC:UNSTABLE, data) != 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_nfs_cb_data(data); + return -1; + } + return 0; + } + + /* trying to write more than maximum server write size, we has to chop it up into smaller + * chunks. + * we send all writes in parallell so that performance is still good. + */ + data->max_offset = offset; + data->start_offset = offset; + + while (count > 0) { + size_t writecount = count; + struct nfs_mcb_data *mdata; + + if (writecount > nfs_get_writemax(nfs)) { + writecount = nfs_get_writemax(nfs); + } + + 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"); + return -1; + } + memset(mdata, 0, sizeof(struct nfs_mcb_data)); + mdata->data = data; + mdata->offset = offset; + mdata->count = writecount; + + if (rpc_nfs_write_async(nfs->rpc, nfs_pwrite_mcb, &nfsfh->fh, &buf[offset - data->start_offset], offset, writecount, nfsfh->is_sync?FILE_SYNC:UNSTABLE, 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); + return -1; + } + + count -= writecount; + offset += writecount; + data->num_calls++; } + return 0; } @@ -2903,7 +3005,11 @@ size_t nfs_get_readmax(struct nfs_context *nfs) */ size_t nfs_get_writemax(struct nfs_context *nfs) { - return nfs->writemax; + /* Some XDR libraries can not marshall PDUs bigger than this */ + if (nfs->writemax < 32768) { + return nfs->writemax; + } + return 32768; } void nfs_set_error(struct nfs_context *nfs, char *error_string, ...) @@ -2918,7 +3024,7 @@ void nfs_set_error(struct nfs_context *nfs, char *error_string, ...) free(nfs->rpc->error_string); } nfs->rpc->error_string = str; - va_end(ap); + va_end(ap); } @@ -3096,35 +3202,3 @@ const char *nfs_get_export(struct nfs_context *nfs) { return nfs->export; } - -#if defined(WIN32) -int poll(struct pollfd *fds, int nfsd, int timeout) -{ - fd_set rfds, wfds, efds; - int ret; - - FD_ZERO(&rfds); - FD_ZERO(&wfds); - FD_ZERO(&efds); - if (fds->events & POLLIN) { - FD_SET(fds->fd, &rfds); - } - if (fds->events & POLLOUT) { - FD_SET(fds->fd, &wfds); - } - FD_SET(fds->fd, &efds); - select(fds->fd + 1, &rfds, &wfds, &efds, NULL); - fds->revents = 0; - if (FD_ISSET(fds->fd, &rfds)) { - fds->revents |= POLLIN; - } - if (FD_ISSET(fds->fd, &wfds)) { - fds->revents |= POLLOUT; - } - if (FD_ISSET(fds->fd, &efds)) { - fds->revents |= POLLHUP; - } - return 1; -} -#endif -