NFSv4: add support for fcntl locking

Signed-off-by: Ronnie Sahlberg <ronniesahlberg@gmail.com>
libnfs-4.0.0-vitalif
Ronnie Sahlberg 2018-01-08 14:37:55 +10:00
parent 09f8a621fb
commit 50068b8432
6 changed files with 324 additions and 0 deletions

View File

@ -496,6 +496,9 @@ int nfs4_fchmod_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int mode,
nfs_cb cb, void *private_data);
int nfs4_fchown_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int uid,
int gid, nfs_cb cb, void *private_data);
int nfs4_fcntl_async(struct nfs_context *nfs, struct nfsfh *nfsfh,
enum nfs4_fcntl_op cmd, void *arg,
nfs_cb cb, void *private_data);
int nfs4_fstat64_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb,
void *private_data);
int nfs4_fsync_async(struct nfs_context *nfs, struct nfsfh *nfsfh, nfs_cb cb,

View File

@ -778,6 +778,50 @@ EXTERN int nfs_lockf_async(struct nfs_context *nfs, struct nfsfh *nfsfh,
EXTERN int nfs_lockf(struct nfs_context *nfs, struct nfsfh *nfsfh,
enum nfs4_lock_op op, uint64_t count);
/*
* FCNTL()
*/
/*
* Async fcntl()
* Supported commands are :
* NFS4_F_SETLK
* NFS4_F_SETLKW
*
* 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:
* 0 : Success.
* -errno : An error occured.
* data is the error string.
*/
enum nfs4_fcntl_op {
NFS4_F_SETLK = 0,
NFS4_F_SETLKW,
};
struct nfs4_flock {
int l_type; /* F_RDLCK, F_WRLCK or F_UNLCK */
int l_whence; /* SEEK_SET, SEEK_CUR or SEEK_END */
uint32_t l_pid;
uint64_t l_start;
uint64_t l_len;
};
EXTERN int nfs_fcntl_async(struct nfs_context *nfs, struct nfsfh *nfsfh,
enum nfs4_fcntl_op cmd, void *arg,
nfs_cb cb, void *private_data);
/*
* Sync lockf()
* Function returns
* 0 : Success.
* -errno : An error occured.
*/
EXTERN int nfs_fcntl(struct nfs_context *nfs, struct nfsfh *nfsfh,
enum nfs4_fcntl_op cmd, void *arg);
/*
* FSYNC()
*/

View File

@ -1089,6 +1089,44 @@ nfs_lockf(struct nfs_context *nfs, struct nfsfh *nfsfh,
return cb_data.status;
}
/*
* fcntl()
*/
static void
fcntl_cb(int status, struct nfs_context *nfs, void *data, void *private_data)
{
struct sync_cb_data *cb_data = private_data;
cb_data->is_finished = 1;
cb_data->status = status;
if (status < 0) {
nfs_set_error(nfs, "fcntl call failed with \"%s\"",
nfs_get_error(nfs));
return;
}
}
int
nfs_fcntl(struct nfs_context *nfs, struct nfsfh *nfsfh,
enum nfs4_fcntl_op cmd, void *arg)
{
struct sync_cb_data cb_data;
cb_data.is_finished = 0;
if (nfs_fcntl_async(nfs, nfsfh, cmd, arg,
fcntl_cb, &cb_data) != 0) {
nfs_set_error(nfs, "nfs_fcntl_async failed. %s",
nfs_get_error(nfs));
return -1;
}
wait_for_nfs_reply(nfs, &cb_data);
return cb_data.status;
}
/*
* statvfs()
*/

View File

@ -22,6 +22,8 @@ nfs_fchmod
nfs_fchmod_async
nfs_fchown
nfs_fchown_async
nfs_fcntl
nfs_fcntl_async
nfs_fstat
nfs_fstat_async
nfs_fsync

View File

@ -1374,6 +1374,22 @@ nfs_lockf_async(struct nfs_context *nfs, struct nfsfh *nfsfh,
}
}
int
nfs_fcntl_async(struct nfs_context *nfs, struct nfsfh *nfsfh,
enum nfs4_fcntl_op cmd, void *arg,
nfs_cb cb, void *private_data)
{
switch (nfs->version) {
case NFS_V4:
return nfs4_fcntl_async(nfs, nfsfh, cmd, arg,
cb, private_data);
default:
nfs_set_error(nfs, "%s does not support NFSv%d",
__FUNCTION__, nfs->version);
return -1;
}
}
int
nfs_statvfs_async(struct nfs_context *nfs, const char *path, nfs_cb cb,
void *private_data)

View File

@ -3987,6 +3987,227 @@ nfs4_lockf_async(struct nfs_context *nfs, struct nfsfh *fh,
return 0;
}
static void
nfs4_fcntl_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;
LOCK4resok *lresok = NULL;
struct nfsfh *fh = data->filler.blob0.val;
enum nfs4_fcntl_op cmd;
struct nfs4_flock *fl;
int i;
assert(rpc->magic == RPC_CONTEXT_MAGIC);
cmd = data->filler.blob1.len;
if (check_nfs4_error(nfs, status, data, res, "FCNTL")) {
return;
}
switch (cmd) {
case NFS4_F_SETLK:
case NFS4_F_SETLKW:
fl = (struct nfs4_flock *)data->filler.blob1.val;
switch (fl->l_type) {
case F_RDLCK:
case F_WRLCK:
if ((i = nfs4_find_op(nfs, data, res, OP_LOCK,
"LOCK")) < 0) {
return;
}
lresok = &res->resarray.resarray_val[i].nfs_resop4_u.oplock.LOCK4res_u.resok4;
nfs->has_lock_owner = 1;
fh->lock_stateid.seqid = lresok->lock_stateid.seqid;
memcpy(fh->lock_stateid.other,
lresok->lock_stateid.other, 12);
break;
case F_UNLCK:
if ((i = nfs4_find_op(nfs, data, res, OP_LOCKU,
"UNLOCK")) < 0) {
return;
}
break;
}
break;
}
data->cb(0, nfs, NULL, data->private_data);
free_nfs4_cb_data(data);
}
static int
nfs4_fcntl_async_internal(struct nfs_context *nfs, struct nfsfh *fh,
struct nfs4_cb_data *data)
{
COMPOUND4args args;
nfs_argop4 op[2];
struct nfs4_flock *fl;
enum nfs4_fcntl_op cmd;
int i, lock_type;
cmd = data->filler.blob1.len;
i = nfs4_op_putfh(nfs, &op[0], fh);
switch (cmd) {
case NFS4_F_SETLK:
case NFS4_F_SETLKW:
fl = data->filler.blob1.val;
switch (fl->l_type) {
case F_RDLCK:
lock_type = cmd == NFS4_F_SETLK ? READ_LT : READW_LT;
i += nfs4_op_lock(nfs, &op[i], fh, OP_LOCK, lock_type,
0, fl->l_start, fl->l_len);
break;
case F_WRLCK:
lock_type = cmd == NFS4_F_SETLK ? WRITE_LT : WRITEW_LT;
i += nfs4_op_lock(nfs, &op[i], fh, OP_LOCK, lock_type,
0, fl->l_start, fl->l_len);
break;
case F_UNLCK:
i += nfs4_op_locku(nfs, &op[i], fh, WRITE_LT,
fl->l_start, fl->l_len);
break;
}
break;
}
memset(&args, 0, sizeof(args));
args.argarray.argarray_len = i;
args.argarray.argarray_val = op;
if (rpc_nfs4_compound_async(nfs->rpc, nfs4_fcntl_cb, &args,
data) != 0) {
free_nfs4_cb_data(data);
return -1;
}
return 0;
}
static void
nfs4_fcntl_stat_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;
struct nfsfh *fh = data->filler.blob0.val;
enum nfs4_fcntl_op cmd = data->filler.blob1.len;
COMPOUND4res *res = command_data;
GETATTR4resok *garesok;
struct nfs4_flock *fl;
struct nfs_stat_64 st;
int i;
if (check_nfs4_error(nfs, status, data, res, "STAT64")) {
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;
memset(&st, 0, sizeof(st));
if (nfs_parse_attributes(nfs, data, &st,
garesok->obj_attributes.attr_vals.attrlist4_val,
garesok->obj_attributes.attr_vals.attrlist4_len) < 0) {
data->cb(-EINVAL, nfs, nfs_get_error(nfs), data->private_data);
free_nfs4_cb_data(data);
}
switch (cmd) {
case NFS4_F_SETLK:
case NFS4_F_SETLKW:
fl = data->filler.blob1.val;
fl->l_whence = SEEK_SET;
fl->l_start = st.nfs_size + fl->l_start;
if (nfs4_fcntl_async_internal(nfs, fh, data)) {
data->cb(-ENOMEM, nfs, nfs_get_error(nfs),
data->private_data);
free_nfs4_cb_data(data);
}
}
}
/* blob0.val is nfsfh
* blob1.len is cmd
* blob1.val is arg
*/
int
nfs4_fcntl_async(struct nfs_context *nfs, struct nfsfh *fh,
enum nfs4_fcntl_op cmd, void *arg,
nfs_cb cb, void *private_data)
{
struct nfs4_cb_data *data;
struct nfs4_flock *fl;
COMPOUND4args args;
nfs_argop4 op[2];
int i;
data = malloc(sizeof(*data));
if (data == NULL) {
nfs_set_error(nfs, "Out of memory.");
return -1;
}
memset(data, 0, sizeof(*data));
data->nfs = nfs;
data->cb = cb;
data->private_data = private_data;
data->filler.blob0.val = fh;
data->filler.blob0.free = NULL;
data->filler.blob1.len = cmd;
data->filler.blob1.val = arg;
data->filler.blob1.free = NULL;
switch (cmd) {
case NFS4_F_SETLK:
case NFS4_F_SETLKW:
fl = arg;
switch (fl->l_whence) {
case SEEK_SET:
return nfs4_fcntl_async_internal(nfs, fh, data);
case SEEK_CUR:
fl->l_whence = SEEK_SET;
fl->l_start = fh->offset + fl->l_start;
return nfs4_fcntl_async_internal(nfs, fh, data);
case SEEK_END:
i = nfs4_op_putfh(nfs, &op[0], fh);
i += nfs4_op_getattr(nfs, &op[i], standard_attributes,
2);
memset(&args, 0, sizeof(args));
args.argarray.argarray_len = i;
args.argarray.argarray_val = op;
if (rpc_nfs4_compound_async(nfs->rpc,
nfs4_fcntl_stat_cb,
&args, data) != 0) {
free_nfs4_cb_data(data);
return -1;
}
return 0;
}
nfs_set_error(nfs, "fcntl: unknown fl->whence:%d\n",
fl->l_whence);
free_nfs4_cb_data(data);
return -1;
}
nfs_set_error(nfs, "fcntl: unknown cmd:%d\n", cmd);
free_nfs4_cb_data(data);
return -1;
}
static int
nfs_parse_statvfs(struct nfs_context *nfs, struct nfs4_cb_data *data,
struct statvfs *svfs, const char *buf, int len)