Skip to content

Commit

Permalink
NFSv4: add zero-copy write support for nfsv4
Browse files Browse the repository at this point in the history
We now have zero-cop write for both NFSv3 and v4. We also have (almost) zero-copy
read for both NFSv3 and v4.

Signed-off-by: Ronnie Sahlberg <[email protected]>
  • Loading branch information
sahlberg committed Nov 17, 2023
1 parent 6dc235a commit ab0216a
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 6 deletions.
1 change: 0 additions & 1 deletion README
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ TODOs:
* Fragmentation is currently broken
* All high level async functions (nfs_*async) should return a handle so that
they can be cancelled.
* Make zero-copy work for NFS4 writes

LIBNFS is a client library for accessing NFS shares over a network.

Expand Down
32 changes: 32 additions & 0 deletions include/nfsc/libnfs-raw.h
Original file line number Diff line number Diff line change
Expand Up @@ -2362,6 +2362,7 @@ rpc_nfs4_null_async(struct rpc_context *rpc, rpc_cb cb,

/*
* Call NFS4/COMPOUND
*
* Function returns
* pdu : The command was queued successfully. The callback will be invoked once
* the command completes.
Expand All @@ -2375,6 +2376,7 @@ rpc_nfs4_null_async(struct rpc_context *rpc, rpc_cb cb,
* data is the error string.
* RPC_STATUS_CANCEL : The command was cancelled.
* data is NULL.
* This function can NOT be used for compounds that contain OP_READ or OP_WRITE.
*/
struct COMPOUND4args;
EXTERN struct rpc_pdu *
Expand All @@ -2397,6 +2399,7 @@ rpc_nfs4_compound_async(struct rpc_context *rpc, rpc_cb cb,
* data is the error string.
* RPC_STATUS_CANCEL : The command was cancelled.
* data is NULL.
* This function can NOT be used for compounds that contain OP_READ or OP_WRITE.
*/
struct COMPOUND4args;
EXTERN struct rpc_pdu *
Expand All @@ -2421,12 +2424,41 @@ rpc_nfs4_compound_async2(struct rpc_context *rpc, rpc_cb cb,
* data is the error string.
* RPC_STATUS_CANCEL : The command was cancelled.
* data is NULL.
* If the compound contains OP_READ you must use this function and not
* rpc_nfs4_compound_async()
* The OP_READ must be the last operation in the compound.
*/
EXTERN struct rpc_pdu *
rpc_nfs4_read_async(struct rpc_context *rpc, rpc_cb cb,
void *buf, size_t count,
struct COMPOUND4args *args,
void *private_data);

/*
* Call NFS4/COMPOUND for write operations
*
* Function returns
* 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:
* RPC_STATUS_SUCCESS : We got a successful response from the server.
* data is COMPOUND4res *.
* RPC_STATUS_ERROR : The command failed with an error.
* data is the error string.
* RPC_STATUS_CANCEL : The command was cancelled.
* data is NULL.
* If the compound contains OP_WRITE you must use this function and not
* rpc_nfs4_compound_async()
* The OP_WRITE must be the last operation in the compound.
*/
EXTERN struct rpc_pdu *
rpc_nfs4_write_async(struct rpc_context *rpc, rpc_cb cb,
const void *buf, size_t count,
struct COMPOUND4args *args,
void *private_data);

/*
* Call <generic>/NULL
Expand Down
1 change: 1 addition & 0 deletions lib/libnfs-win32.def
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ rpc_nfs4_compound_async
rpc_nfs4_compound_async2
rpc_nfs4_null_async
rpc_nfs4_read_async
rpc_nfs4_write_async
rpc_nlm4_null_async
rpc_nlm4_test_async
rpc_nlm4_lock_async
Expand Down
4 changes: 2 additions & 2 deletions lib/nfs_v4.c
Original file line number Diff line number Diff line change
Expand Up @@ -3018,8 +3018,8 @@ nfs4_pwrite_async_internal(struct nfs_context *nfs, struct nfsfh *nfsfh,
args.argarray.argarray_len = i;
args.argarray.argarray_val = op;

if (rpc_nfs4_compound_async2(nfs->rpc, nfs4_pwrite_cb, &args,
data, count) == NULL) {
if (rpc_nfs4_write_async(nfs->rpc, nfs4_pwrite_cb, buf, count,
&args, data) == NULL) {
nfs_set_error(nfs, "PWRITE "
"failed: %s", rpc_get_error(nfs->rpc));
free_nfs4_cb_data(data);
Expand Down
3 changes: 1 addition & 2 deletions nfs/nfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@
#include "libnfs-private.h"
#include "libnfs-raw-nfs.h"

uint32_t zero_padding;

char *nfsstat3_to_str(int error)
{
switch (error) {
Expand Down Expand Up @@ -321,6 +319,7 @@ struct rpc_pdu *rpc_nfs3_write_async(struct rpc_context *rpc, rpc_cb cb,
{
struct rpc_pdu *pdu;
int start;
static uint32_t zero_padding;

pdu = rpc_allocate_pdu2(rpc, NFS_PROGRAM, NFS_V3, NFS3_WRITE, cb, private_data, (zdrproc_t)zdr_WRITE3res, sizeof(WRITE3res), 0);
if (pdu == NULL) {
Expand Down
1 change: 1 addition & 0 deletions nfs4/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,5 @@ compile_rpc:
-e "s/register int32_t \*buf;//" \
-e "s/int i;//" >> libnfs-raw-nfs4.c
sed -z -i -e "s/zdr_READ4resok/zzdr_READ4resok/" libnfs-raw-nfs4.c
sed -z -i -e "s/zdr_WRITE4args/zzdr_WRITE4args/" libnfs-raw-nfs4.c
cat libnfs-raw-nfs4.c.fragment >>libnfs-raw-nfs4.c
13 changes: 12 additions & 1 deletion nfs4/libnfs-raw-nfs4.c
Original file line number Diff line number Diff line change
Expand Up @@ -2705,7 +2705,7 @@ zdr_stable_how4 (ZDR *zdrs, stable_how4 *objp)
}

uint32_t
zdr_WRITE4args (ZDR *zdrs, WRITE4args *objp)
zzdr_WRITE4args (ZDR *zdrs, WRITE4args *objp)
{


Expand Down Expand Up @@ -4595,3 +4595,14 @@ zdr_READ4resok (ZDR *zdrs, READ4resok *objp)
return TRUE;
}

uint32_t
zdr_WRITE4args (ZDR *zdrs, WRITE4args *objp)
{
if (!zdr_stateid4 (zdrs, &objp->stateid))
return FALSE;
if (!zdr_offset4 (zdrs, &objp->offset))
return FALSE;
if (!zdr_stable_how4 (zdrs, &objp->stable))
return FALSE;
return TRUE;
}
11 changes: 11 additions & 0 deletions nfs4/libnfs-raw-nfs4.c.fragment
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,14 @@ zdr_READ4resok (ZDR *zdrs, READ4resok *objp)
return TRUE;
}

uint32_t
zdr_WRITE4args (ZDR *zdrs, WRITE4args *objp)
{
if (!zdr_stateid4 (zdrs, &objp->stateid))
return FALSE;
if (!zdr_offset4 (zdrs, &objp->offset))
return FALSE;
if (!zdr_stable_how4 (zdrs, &objp->stable))
return FALSE;
return TRUE;
}
69 changes: 69 additions & 0 deletions nfs4/nfs4.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,3 +278,72 @@ struct rpc_pdu *rpc_nfs4_read_async(struct rpc_context *rpc, rpc_cb cb,

return pdu;
}

struct rpc_pdu *rpc_nfs4_write_async(struct rpc_context *rpc, rpc_cb cb,
const void *buf, size_t count,
struct COMPOUND4args *args,
void *private_data)
{
struct rpc_pdu *pdu;
int start;
uint32_t len;
static uint32_t zero_padding;

pdu = rpc_allocate_pdu2(rpc, NFS4_PROGRAM, NFS_V4, NFSPROC4_COMPOUND,
cb, private_data, (zdrproc_t)zdr_COMPOUND4res,
sizeof(COMPOUND4res), 0);
if (pdu == NULL) {
rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for "
"NFS4/COMPOUND call");
return NULL;
}

start = zdr_getpos(&pdu->zdr);

if (zdr_COMPOUND4args(&pdu->zdr, args) == 0) {
rpc_set_error(rpc, "ZDR error: Failed to encode COMPOUND4args");
rpc_free_pdu(rpc, pdu);
return NULL;
}

/* Add an iovector for the COMPOUND4/.../WRITE4 header */
if (rpc_add_iovector(rpc, &pdu->out, &pdu->outdata.data[start + 4],
zdr_getpos(&pdu->zdr) - start, NULL) < 0) {
rpc_free_pdu(rpc, pdu);
return NULL;
}

/* Add an iovector for the length of the byte/array blob */
start = zdr_getpos(&pdu->zdr);
len = count;
zdr_u_int(&pdu->zdr, &len);
if (rpc_add_iovector(rpc, &pdu->out, &pdu->outdata.data[start + 4],
4, NULL) < 0) {
rpc_free_pdu(rpc, pdu);
return NULL;
}

/* Add an iovector for the data itself */
if (rpc_add_iovector(rpc, &pdu->out, buf, count, NULL) < 0) {
rpc_free_pdu(rpc, pdu);
return NULL;
}

/* We may need to pad this to 4 byte boundary */
if (count & 0x03) {
if (rpc_add_iovector(rpc, &pdu->out, (char *)&zero_padding,
4 - count & 0x03,
NULL) < 0) {
rpc_free_pdu(rpc, pdu);
return NULL;
}
}

if (rpc_queue_pdu(rpc, pdu) != 0) {
rpc_set_error(rpc, "Out of memory. Failed to queue pdu for "
"NFS4/COMPOUND4 call");
return NULL;
}

return pdu;
}

0 comments on commit ab0216a

Please sign in to comment.