NFSv4: Add support (and tests) for open(O_APPEND)

Signed-off-by: Ronnie Sahlberg <ronniesahlberg@gmail.com>
libnfs-4.0.0-vitalif
Ronnie Sahlberg 2017-08-03 20:23:08 +10:00
parent 2ce8890458
commit 65de83140a
5 changed files with 153 additions and 5 deletions

View File

@ -498,6 +498,9 @@ int nfs4_stat64_async(struct nfs_context *nfs, const char *path,
int no_follow, nfs_cb cb, void *private_data);
int nfs4_symlink_async(struct nfs_context *nfs, const char *oldpath,
const char *newpath, nfs_cb cb, void *private_data);
int nfs4_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh,
uint64_t count, const void *buf, nfs_cb cb,
void *private_data);
#ifdef __cplusplus
}

View File

@ -513,8 +513,6 @@ EXTERN uint16_t nfs_umask(struct nfs_context *nfs, uint16_t mask);
* mode is a combination of the flags :
* O_RDONLY, O_WRONLY, O_RDWR , O_SYNC, O_APPEND, O_TRUNC, O_NOFOLLOW
*
* ( O_APPEND is not yet supported for NFSv4. )
*
* Function returns
* 0 : The command was queued successfully. The callback will be invoked once
* the command completes.

View File

@ -1052,9 +1052,8 @@ nfs_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count,
return nfs3_write_async(nfs, nfsfh, count, buf,
cb, private_data);
case NFS_V4:
return nfs4_pwrite_async_internal(nfs, nfsfh, nfsfh->offset,
(size_t)count, buf,
cb, private_data, 1);
return nfs4_write_async(nfs, nfsfh, count, buf,
cb, private_data);
default:
nfs_set_error(nfs, "%s does not support NFSv%d",
__FUNCTION__, nfs->version);

View File

@ -1535,6 +1535,10 @@ nfs4_open_cb(struct rpc_context *rpc, int status, void *command_data,
fh->is_sync = 1;
}
if (data->filler.flags & O_APPEND) {
fh->is_append = 1;
}
fh->fh.len = gresok->object.nfs_fh4_len;
fh->fh.val = malloc(fh->fh.len);
if (fh->fh.val == NULL) {
@ -1779,6 +1783,10 @@ nfs4_open_async(struct nfs_context *nfs, const char *orig_path, int flags,
flags &= ~O_TRUNC;
}
if (flags & O_APPEND && !(flags & (O_RDWR|O_WRONLY))) {
flags &= ~O_APPEND;
}
data = malloc(sizeof(*data));
if (data == NULL) {
nfs_set_error(nfs, "Out of memory. Failed to allocate "
@ -2322,3 +2330,120 @@ nfs4_pwrite_async_internal(struct nfs_context *nfs, struct nfsfh *nfsfh,
return 0;
}
static void
nfs4_write_append_cb(struct rpc_context *rpc, int status, void *command_data,
void *private_data)
{
struct nfs4_cb_data *data = private_data;
struct nfs_context *nfs = data->nfs;
COMPOUND4res *res = command_data;
GETATTR4resok *garesok = NULL;
struct nfsfh *nfsfh;
int i;
uint64_t offset;
char *buf;
uint32_t count;
assert(rpc->magic == RPC_CONTEXT_MAGIC);
nfsfh = data->filler.blob0.val;
data->filler.blob0.val = NULL;
buf = data->filler.blob1.val;
count = data->filler.blob1.len;
data->filler.blob1.val = NULL;
if (check_nfs4_error(nfs, status, data, res, "GETATTR")) {
free_nfs4_cb_data(data);
return;
}
if ((i = nfs4_find_op(nfs, data, res, OP_GETATTR, "GETATTR")) < 0) {
return;
}
garesok = &res->resarray.resarray_val[i].nfs_resop4_u.opgetattr.GETATTR4res_u.resok4;
if (garesok->obj_attributes.attr_vals.attrlist4_len < 8) {
data->cb(-EINVAL, nfs, nfs_get_error(nfs), data->private_data);
free_nfs4_cb_data(data);
return;
}
offset = nfs_pntoh64((uint32_t *)(void *)garesok->obj_attributes.attr_vals.attrlist4_val);
if (nfs4_pwrite_async_internal(nfs, nfsfh, offset,
(size_t)count, buf,
data->cb, data->private_data, 1) < 0) {
free_nfs4_cb_data(data);
data->cb(-ENOMEM, nfs, nfs_get_error(nfs), data->private_data);
return;
}
free_nfs4_cb_data(data);
}
int
nfs4_write_async(struct nfs_context *nfs, struct nfsfh *nfsfh, uint64_t count,
const void *buf, nfs_cb cb, void *private_data)
{
if (nfsfh->is_append) {
COMPOUND4args args;
nfs_argop4 op[2];
PUTFH4args *pfargs;
GETATTR4args *gaargs;
static uint32_t attributes = 1 << FATTR4_SIZE;
struct nfs4_cb_data *data;
data = malloc(sizeof(*data));
if (data == NULL) {
nfs_set_error(nfs, "Out of memory. Failed to allocate "
"cb data");
return -1;
}
memset(data, 0, sizeof(*data));
data->nfs = nfs;
data->cb = cb;
data->private_data = private_data;
data->filler.blob0.val = nfsfh;
memset(op, 0, sizeof(op));
op[0].argop = OP_PUTFH;
pfargs = &op[0].nfs_argop4_u.opputfh;
pfargs->object.nfs_fh4_len = nfsfh->fh.len;
pfargs->object.nfs_fh4_val = nfsfh->fh.val;
op[1].argop = OP_GETATTR;
gaargs = &op[1].nfs_argop4_u.opgetattr;
memset(gaargs, 0, sizeof(*gaargs));
gaargs->attr_request.bitmap4_len = 1;
gaargs->attr_request.bitmap4_val = &attributes;
memset(&args, 0, sizeof(args));
args.argarray.argarray_len = sizeof(op) / sizeof(nfs_argop4);
args.argarray.argarray_val = op;
data->filler.blob0.val = nfsfh;
data->filler.blob1.val = discard_const(buf);
data->filler.blob1.len = count;
if (rpc_nfs4_compound_async(nfs->rpc, nfs4_write_append_cb,
&args, data) != 0) {
data->filler.blob0.val = NULL;
data->filler.blob1.val = NULL;
free_nfs4_cb_data(data);
return -1;
}
return 0;
}
return nfs4_pwrite_async_internal(nfs, nfsfh, nfsfh->offset,
(size_t)count, buf,
cb, private_data, 1);
}

View File

@ -0,0 +1,23 @@
#!/bin/sh
. ./functions.sh
echo "NFSv${VERS} Open(O_APPEND) test."
start_share
mkdir "${TESTDIR}/subdir"
echo -n "test open(O_APPEND) (1) ... "
echo -n "GOAT:" > "${TESTDIR}/open1"
./prog_open_write "${TESTURL}/?version=${VERS}" "." /open1 O_WRONLY,O_APPEND "NieR" >/dev/null || failure
./prog_open_write "${TESTURL}/?version=${VERS}" "." /open1 O_WRONLY,O_APPEND "Automata" >/dev/null || failure
success
echo -n "verify it got appended ... "
grep "GOAT:NieRAutomata" "${TESTDIR}/open1" >/dev/null || failure
success
stop_share
exit 0