Merge pull request #150 from plieven/for_upstream

For upstream
libnfs-4.0.0-vitalif
Ronnie Sahlberg 2016-06-03 05:07:45 -07:00
commit cdd1643c76
9 changed files with 91 additions and 77 deletions

View File

@ -82,6 +82,8 @@ struct rpc_queue {
#define HASHES 1024
#define NFS_RA_TIMEOUT 5
#define NFS_MAX_XFER_SIZE (1024 * 1024)
#define ZDR_ENCODE_OVERHEAD 1024
#define ZDR_ENCODEBUF_MINSIZE 4096
struct rpc_context {
uint32_t magic;
@ -97,10 +99,6 @@ struct rpc_context {
struct AUTH *auth;
uint32_t xid;
/* buffer used for encoding RPC PDU */
char *encodebuf;
int encodebuflen;
struct rpc_queue outqueue;
struct sockaddr_storage udp_src;
struct rpc_queue waitpdu[HASHES];
@ -156,6 +154,7 @@ void rpc_return_to_queue(struct rpc_queue *q, struct rpc_pdu *pdu);
unsigned int rpc_hash_xid(uint32_t xid);
struct rpc_pdu *rpc_allocate_pdu(struct rpc_context *rpc, int program, int version, int procedure, rpc_cb cb, void *private_data, zdrproc_t zdr_decode_fn, int zdr_bufsize);
struct rpc_pdu *rpc_allocate_pdu2(struct rpc_context *rpc, int program, int version, int procedure, rpc_cb cb, void *private_data, zdrproc_t zdr_decode_fn, int zdr_bufsize, size_t alloc_hint);
void rpc_free_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu);
int rpc_queue_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu);
uint32_t rpc_get_pdu_size(char *buf);

View File

@ -31,7 +31,7 @@ extern "C" {
struct rpc_data {
int size;
unsigned char *data;
char *data;
};
struct rpc_context;

View File

@ -62,17 +62,8 @@ struct rpc_context *rpc_init_context(void)
rpc->magic = RPC_CONTEXT_MAGIC;
/* Allow NFS_MAX_XFER_SIZE of data (for writes) and some */
rpc->encodebuflen = NFS_MAX_XFER_SIZE + 4096;
rpc->encodebuf = malloc(rpc->encodebuflen);
if (rpc->encodebuf == NULL) {
free(rpc);
return NULL;
}
rpc->auth = authunix_create_default();
if (rpc->auth == NULL) {
free(rpc->encodebuf);
free(rpc);
return NULL;
}
@ -126,15 +117,17 @@ void rpc_set_pagecache_ttl(struct rpc_context *rpc, uint32_t v) {
void rpc_set_readahead(struct rpc_context *rpc, uint32_t v)
{
assert(rpc->magic == RPC_CONTEXT_MAGIC);
uint32_t min_pagecache;
if (v) {
v = MAX(NFS_BLKSIZE, round_to_power_of_two(v));
}
RPC_LOG(rpc, 2, "readahead set to %d byte", v);
rpc->readahead = v;
if (v) {
min_pagecache = (2 * v) / NFS_BLKSIZE;
if (rpc->pagecache < min_pagecache) {
/* current pagecache implementation needs a pagecache bigger
* than the readahead size to avoid collisions */
rpc_set_pagecache(rpc, (2 * v) / NFS_BLKSIZE);
rpc_set_pagecache(rpc, min_pagecache);
}
}
@ -314,11 +307,6 @@ void rpc_destroy_context(struct rpc_context *rpc)
close(rpc->fd);
}
if (rpc->encodebuf != NULL) {
free(rpc->encodebuf);
rpc->encodebuf = NULL;
}
if (rpc->error_string != NULL) {
free(rpc->error_string);
rpc->error_string = NULL;

View File

@ -1707,39 +1707,39 @@ static int send_nfsd_probes(struct rpc_context *rpc, struct ifconf *ifc, struct
assert(rpc->magic == RPC_CONTEXT_MAGIC);
for (ptr =(char *)(ifc->ifc_buf); ptr < (char *)(ifc->ifc_buf) + ifc->ifc_len; ) {
struct ifreq *ifr;
struct ifreq ifr;
char bcdd[16];
ifr = (struct ifreq *)ptr;
memcpy(&ifr, ptr, sizeof(struct ifreq));
#ifdef HAVE_SOCKADDR_LEN
if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr)) {
ptr += sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
if (ifr.ifr_addr.sa_len > sizeof(struct sockaddr)) {
ptr += sizeof(ifr.ifr_name) + ifr.ifr_addr.sa_len;
} else {
ptr += sizeof(ifr->ifr_name) + sizeof(struct sockaddr);
ptr += sizeof(ifr.ifr_name) + sizeof(struct sockaddr);
}
#else
ptr += sizeof(struct ifreq);
#endif
if (ifr->ifr_addr.sa_family != AF_INET) {
if (ifr.ifr_addr.sa_family != AF_INET) {
continue;
}
if (ioctl(rpc_get_fd(rpc), SIOCGIFFLAGS, ifr) < 0) {
if (ioctl(rpc_get_fd(rpc), SIOCGIFFLAGS, &ifr) < 0) {
return -1;
}
if (!(ifr->ifr_flags & IFF_UP)) {
if (!(ifr.ifr_flags & IFF_UP)) {
continue;
}
if (ifr->ifr_flags & IFF_LOOPBACK) {
if (ifr.ifr_flags & IFF_LOOPBACK) {
continue;
}
if (!(ifr->ifr_flags & IFF_BROADCAST)) {
if (!(ifr.ifr_flags & IFF_BROADCAST)) {
continue;
}
if (ioctl(rpc_get_fd(rpc), SIOCGIFBRDADDR, ifr) < 0) {
if (ioctl(rpc_get_fd(rpc), SIOCGIFBRDADDR, &ifr) < 0) {
continue;
}
if (getnameinfo(&ifr->ifr_broadaddr, sizeof(struct sockaddr_in), &bcdd[0], sizeof(bcdd), NULL, 0, NI_NUMERICHOST) < 0) {
if (getnameinfo(&ifr.ifr_broadaddr, sizeof(struct sockaddr_in), &bcdd[0], sizeof(bcdd), NULL, 0, NI_NUMERICHOST) < 0) {
continue;
}
if (rpc_set_udp_destination(rpc, bcdd, 111, 1) < 0) {

View File

@ -108,15 +108,13 @@ bool_t libnfs_zdr_u_int(ZDR *zdrs, uint32_t *u)
switch (zdrs->x_op) {
case ZDR_ENCODE:
*(uint32_t *)&zdrs->buf[zdrs->pos] = htonl(*u);
*(uint32_t *)(void *)&zdrs->buf[zdrs->pos] = htonl(*u);
zdrs->pos += 4;
return TRUE;
break;
case ZDR_DECODE:
*u = ntohl(*(uint32_t *)&zdrs->buf[zdrs->pos]);
*u = ntohl(*(uint32_t *)(void *)&zdrs->buf[zdrs->pos]);
zdrs->pos += 4;
return TRUE;
break;
}
return FALSE;
@ -135,20 +133,18 @@ bool_t libnfs_zdr_uint64_t(ZDR *zdrs, uint64_t *u)
switch (zdrs->x_op) {
case ZDR_ENCODE:
*(uint32_t *)&zdrs->buf[zdrs->pos] = htonl((*u >> 32));
*(uint32_t *)(void *)&zdrs->buf[zdrs->pos] = htonl((*u >> 32));
zdrs->pos += 4;
*(uint32_t *)&zdrs->buf[zdrs->pos] = htonl((*u & 0xffffffff));
*(uint32_t *)(void *)&zdrs->buf[zdrs->pos] = htonl((*u & 0xffffffff));
zdrs->pos += 4;
return TRUE;
break;
case ZDR_DECODE:
*u = ntohl(*(uint32_t *)&zdrs->buf[zdrs->pos]);
*u = ntohl(*(uint32_t *)(void *)&zdrs->buf[zdrs->pos]);
zdrs->pos += 4;
*u <<= 32;
*u |= (uint32_t)ntohl(*(uint32_t *)&zdrs->buf[zdrs->pos]);
*u |= (uint32_t)ntohl(*(uint32_t *)(void *)&zdrs->buf[zdrs->pos]);
zdrs->pos += 4;
return TRUE;
break;
}
return FALSE;
@ -559,13 +555,13 @@ struct AUTH *libnfs_authunix_create(const char *host, uint32_t uid, uint32_t gid
auth->ah_cred.oa_base = malloc(size);
memset(auth->ah_cred.oa_base, 0x00, size);
buf = (uint32_t *)auth->ah_cred.oa_base;
buf = (uint32_t *)(void *)auth->ah_cred.oa_base;
idx = 0;
buf[idx++] = htonl(time(NULL));
buf[idx++] = htonl(strlen(host));
memcpy(&buf[2], host, strlen(host));
idx += (strlen(host) + 3) >> 2;
idx += (strlen(host) + 3) >> 2;
buf[idx++] = htonl(uid);
buf[idx++] = htonl(gid);
buf[idx++] = htonl(len);

View File

@ -204,7 +204,7 @@ static void nfs_dircache_drop(struct nfs_context *nfs, struct nfs_fh3 *fh)
}
static uint32_t nfs_pagecache_hash(struct nfs_pagecache *pagecache, uint64_t offset) {
return (2654435761 * (1 + ((uint32_t)(offset) / NFS_BLKSIZE))) & (pagecache->num_entries - 1);
return (2654435761UL * (1 + ((uint32_t)(offset) / NFS_BLKSIZE))) & (pagecache->num_entries - 1);
}
void nfs_pagecache_invalidate(struct nfs_context *nfs, struct nfsfh *nfsfh) {
@ -215,7 +215,7 @@ void nfs_pagecache_invalidate(struct nfs_context *nfs, struct nfsfh *nfsfh) {
}
void nfs_pagecache_put(struct nfs_pagecache *pagecache, uint64_t offset, char *buf, int len) {
time_t ts = time(NULL);
time_t ts = pagecache->ttl ? time(NULL) : 1;
if (!pagecache->num_entries) return;
while (len > 0) {
uint64_t page_offset = offset & ~(NFS_BLKSIZE - 1);
@ -274,6 +274,7 @@ struct nfs_cb_data {
int num_calls;
uint64_t offset, count, max_offset, org_offset, org_count;
char *buffer;
int not_my_buffer;
char *usrbuf;
int update_pos;
};
@ -650,7 +651,7 @@ static void rpc_connect_program_3_cb(struct rpc_context *rpc, int status, void *
switch (rpc->s.ss_family) {
case AF_INET:
rpc_port = *(uint32_t *)command_data;
rpc_port = *(uint32_t *)(void *)command_data;
break;
case AF_INET6:
/* ouch. portmapper and ipv6 are not great */
@ -798,7 +799,9 @@ static void free_nfs_cb_data(struct nfs_cb_data *data)
free(data->saved_path);
free(data->fh.data.data_val);
free(data->buffer);
if (!data->not_my_buffer) {
free(data->buffer);
}
free(data);
}
@ -2243,17 +2246,28 @@ static void nfs_pread_mcb(struct rpc_context *rpc, int status, void *command_dat
data->error = 1;
} else {
uint64_t count = res->READ3res_u.resok.count;
if (count < data->count && data->buffer == NULL) {
/* we need a reassembly buffer after all */
data->buffer = malloc(mdata->count);
if (data->buffer == NULL) {
data->oom = 1;
goto out;
}
}
if (count > 0) {
if (count <= mdata->count) {
if (count == data->count && data->buffer == NULL) {
data->buffer = res->READ3res_u.resok.data.data_val;
data->not_my_buffer = 1;
} else if (count <= mdata->count) {
/* copy data into reassembly buffer */
memcpy(&data->buffer[mdata->offset - data->offset], res->READ3res_u.resok.data.data_val, count);
if (data->max_offset < mdata->offset + count) {
data->max_offset = mdata->offset + count;
}
} else {
rpc_set_error(nfs->rpc, "NFS: Read overflow. Server has sent more data than requested!");
data->error = 1;
goto out;
}
if (data->max_offset < mdata->offset + count) {
data->max_offset = mdata->offset + count;
}
}
/* check if we have received a short read */
@ -2279,6 +2293,7 @@ static void nfs_pread_mcb(struct rpc_context *rpc, int status, void *command_dat
}
}
out:
free(mdata);
if (data->num_calls > 0) {
@ -2352,19 +2367,20 @@ static int nfs_pread_async_internal(struct nfs_context *nfs, struct nfsfh *nfsfh
data->offset = offset;
data->count = count;
nfsfh->ra.cur_ra = MAX(NFS_BLKSIZE, nfsfh->ra.cur_ra);
data->buffer = malloc(count + nfs->rpc->readahead);
if (data->buffer == NULL) {
free_nfs_cb_data(data);
return -ENOMEM;
}
if (nfsfh->pagecache.num_entries) {
while (count > 0) {
char *cdata = nfs_pagecache_get(&nfsfh->pagecache, offset);
if (!cdata) {
break;
}
/* we copy data from the pagecache so we need a reassembly buffer */
if (data->buffer == NULL) {
data->buffer = malloc(data->count);
if (data->buffer == NULL) {
free_nfs_cb_data(data);
return -ENOMEM;
}
}
memcpy(data->buffer + offset - data->offset, cdata, NFS_BLKSIZE);
offset += NFS_BLKSIZE;
count -= NFS_BLKSIZE;
@ -2381,6 +2397,7 @@ static int nfs_pread_async_internal(struct nfs_context *nfs, struct nfsfh *nfsfh
}
if (nfs->rpc->readahead) {
nfsfh->ra.cur_ra = MAX(NFS_BLKSIZE, nfsfh->ra.cur_ra);
if (offset >= nfsfh->ra.fh_offset &&
offset - NFS_BLKSIZE <= nfsfh->ra.fh_offset + nfsfh->ra.cur_ra) {
if (nfs->rpc->readahead > nfsfh->ra.cur_ra) {
@ -2393,6 +2410,17 @@ static int nfs_pread_async_internal(struct nfs_context *nfs, struct nfsfh *nfsfh
data->count += nfsfh->ra.cur_ra;
}
if ((data->count > nfs_get_readmax(nfs) || data->count > data->org_count) &&
(data->buffer == NULL || nfsfh->ra.cur_ra > 0)) {
/* we do readahead, a big read or aligned out the request so we
* need a (bigger) reassembly buffer */
data->buffer = realloc(data->buffer, data->count + nfsfh->ra.cur_ra);
if (data->buffer == NULL) {
free_nfs_cb_data(data);
return -ENOMEM;
}
}
data->max_offset = data->offset;
/* chop requests into chunks of at most READMAX bytes if necessary.

View File

@ -86,7 +86,7 @@ unsigned int rpc_hash_xid(uint32_t xid)
#define PAD_TO_8_BYTES(x) ((x + 0x07) & ~0x07)
struct rpc_pdu *rpc_allocate_pdu(struct rpc_context *rpc, int program, int version, int procedure, rpc_cb cb, void *private_data, zdrproc_t zdr_decode_fn, int zdr_decode_bufsize)
struct rpc_pdu *rpc_allocate_pdu2(struct rpc_context *rpc, int program, int version, int procedure, rpc_cb cb, void *private_data, zdrproc_t zdr_decode_fn, int zdr_decode_bufsize, size_t alloc_hint)
{
struct rpc_pdu *pdu;
struct rpc_msg msg;
@ -112,7 +112,13 @@ struct rpc_pdu *rpc_allocate_pdu(struct rpc_context *rpc, int program, int versi
pdu->zdr_decode_fn = zdr_decode_fn;
pdu->zdr_decode_bufsize = zdr_decode_bufsize;
zdrmem_create(&pdu->zdr, rpc->encodebuf, rpc->encodebuflen, ZDR_ENCODE);
pdu->outdata.data = malloc(ZDR_ENCODEBUF_MINSIZE + alloc_hint);
if (pdu->outdata.data == NULL) {
rpc_set_error(rpc, "Out of memory: Failed to allocate encode buffer");
return NULL;
}
zdrmem_create(&pdu->zdr, pdu->outdata.data, ZDR_ENCODEBUF_MINSIZE + alloc_hint, ZDR_ENCODE);
if (rpc->is_udp == 0) {
zdr_setpos(&pdu->zdr, 4); /* skip past the record marker */
}
@ -138,6 +144,11 @@ struct rpc_pdu *rpc_allocate_pdu(struct rpc_context *rpc, int program, int versi
return pdu;
}
struct rpc_pdu *rpc_allocate_pdu(struct rpc_context *rpc, int program, int version, int procedure, rpc_cb cb, void *private_data, zdrproc_t zdr_decode_fn, int zdr_decode_bufsize)
{
return rpc_allocate_pdu2(rpc, program, version, procedure, cb, private_data, zdr_decode_fn, zdr_decode_bufsize, 0);
}
void rpc_free_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu)
{
assert(rpc->magic == RPC_CONTEXT_MAGIC);
@ -175,7 +186,7 @@ int rpc_queue_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu)
unsigned int hash;
// XXX add a rpc->udp_dest_sock_size and get rid of sys/socket.h and netinet/in.h
if (sendto(rpc->fd, rpc->encodebuf, size, MSG_DONTWAIT, rpc->udp_dest, sizeof(struct sockaddr_in)) < 0) {
if (sendto(rpc->fd, pdu->zdr.buf, size, MSG_DONTWAIT, rpc->udp_dest, sizeof(struct sockaddr_in)) < 0) {
rpc_set_error(rpc, "Sendto failed with errno %s", strerror(errno));
rpc_free_pdu(rpc, pdu);
return -1;
@ -192,14 +203,6 @@ int rpc_queue_pdu(struct rpc_context *rpc, struct rpc_pdu *pdu)
zdr_int(&pdu->zdr, &recordmarker);
pdu->outdata.size = size;
pdu->outdata.data = malloc(pdu->outdata.size);
if (pdu->outdata.data == NULL) {
rpc_set_error(rpc, "Out of memory. Failed to allocate buffer for pdu\n");
rpc_free_pdu(rpc, pdu);
return -1;
}
memcpy(pdu->outdata.data, rpc->encodebuf, pdu->outdata.size);
rpc_enqueue(&rpc->outqueue, pdu);
return 0;
@ -209,7 +212,7 @@ uint32_t rpc_get_pdu_size(char *buf)
{
uint32_t size;
size = ntohl(*(uint32_t *)buf);
size = ntohl(*(uint32_t *)(void *)buf);
return (size & 0x7fffffff) + 4;
}

View File

@ -552,7 +552,7 @@ int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc
case AF_INET:
((struct sockaddr_in *)&rpc->s)->sin_family = ai->ai_family;
((struct sockaddr_in *)&rpc->s)->sin_port = htons(port);
((struct sockaddr_in *)&rpc->s)->sin_addr = ((struct sockaddr_in *)(ai->ai_addr))->sin_addr;
((struct sockaddr_in *)&rpc->s)->sin_addr = ((struct sockaddr_in *)(void *)(ai->ai_addr))->sin_addr;
#ifdef HAVE_SOCKADDR_LEN
((struct sockaddr_in *)&rpc->s)->sin_len = sizeof(struct sockaddr_in);
#endif
@ -560,7 +560,7 @@ int rpc_connect_async(struct rpc_context *rpc, const char *server, int port, rpc
case AF_INET6:
((struct sockaddr_in6 *)&rpc->s)->sin6_family = ai->ai_family;
((struct sockaddr_in6 *)&rpc->s)->sin6_port = htons(port);
((struct sockaddr_in6 *)&rpc->s)->sin6_addr = ((struct sockaddr_in6 *)(ai->ai_addr))->sin6_addr;
((struct sockaddr_in6 *)&rpc->s)->sin6_addr = ((struct sockaddr_in6 *)(void *)(ai->ai_addr))->sin6_addr;
#ifdef HAVE_SOCKADDR_LEN
((struct sockaddr_in6 *)&rpc->s)->sin6_len = sizeof(struct sockaddr_in6);
#endif

View File

@ -318,7 +318,7 @@ int rpc_nfs3_write_async(struct rpc_context *rpc, rpc_cb cb, struct WRITE3args *
{
struct rpc_pdu *pdu;
pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V3, NFS3_WRITE, cb, private_data, (zdrproc_t)zdr_WRITE3res, sizeof(WRITE3res));
pdu = rpc_allocate_pdu2(rpc, NFS_PROGRAM, NFS_V3, NFS3_WRITE, cb, private_data, (zdrproc_t)zdr_WRITE3res, sizeof(WRITE3res), args->count);
if (pdu == NULL) {
rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for NFS3/WRITE call");
return -1;
@ -1064,7 +1064,7 @@ int rpc_nfs2_write_async(struct rpc_context *rpc, rpc_cb cb, struct WRITE2args *
{
struct rpc_pdu *pdu;
pdu = rpc_allocate_pdu(rpc, NFS_PROGRAM, NFS_V2, NFS2_WRITE, cb, private_data, (zdrproc_t)zdr_WRITE2res, sizeof(WRITE2res));
pdu = rpc_allocate_pdu2(rpc, NFS_PROGRAM, NFS_V2, NFS2_WRITE, cb, private_data, (zdrproc_t)zdr_WRITE2res, sizeof(WRITE2res), args->totalcount);
if (pdu == NULL) {
rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for NFS2/WRITE call");
return -1;