Skip to content

Commit

Permalink
NFSv4: add lockf emulation
Browse files Browse the repository at this point in the history
Signed-off-by: Ronnie Sahlberg <ronniesahlberg@gmail.com>
  • Loading branch information
sahlberg committed Jan 6, 2018
1 parent f5ccc53 commit 208dd08
Show file tree
Hide file tree
Showing 6 changed files with 294 additions and 0 deletions.
7 changes: 7 additions & 0 deletions include/libnfs-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,10 @@ struct nfsfh {

/* NFSv4 */
struct stateid stateid;
/* locking */
int has_lock;
uint32_t lock_seqid;
struct stateid lock_stateid;
};

const struct nfs_fh *nfs_get_rootfh(struct nfs_context *nfs);
Expand Down Expand Up @@ -502,6 +506,9 @@ int nfs4_link_async(struct nfs_context *nfs, const char *oldpath,
const char *newpath, nfs_cb cb, void *private_data);
int nfs4_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh,
int64_t offset, int whence, nfs_cb cb, void *private_data);
int nfs4_lockf_async(struct nfs_context *nfs, struct nfsfh *nfsfh,
enum nfs4_lock_op op, uint64_t count,
nfs_cb cb, void *private_data);
int nfs4_mkdir2_async(struct nfs_context *nfs, const char *path, int mode,
nfs_cb cb, void *private_data);
int nfs4_mknod_async(struct nfs_context *nfs, const char *path, int mode,
Expand Down
35 changes: 35 additions & 0 deletions include/nfsc/libnfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,41 @@ EXTERN int nfs_lseek(struct nfs_context *nfs, struct nfsfh *nfsfh,
int64_t offset, int whence, uint64_t *current_offset);


/*
* LOCKF()
*/
/*
* Async lockf()
*
* 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_lock_op {
NFS4_F_LOCK = 0,
NFS4_F_TLOCK = 1,
NFS4_F_ULOCK = 2,
NFS4_F_TEST = 3,
};
EXTERN int nfs_lockf_async(struct nfs_context *nfs, struct nfsfh *nfsfh,
enum nfs4_lock_op op, uint64_t count,
nfs_cb cb, void *private_data);
/*
* Sync lockf()
* Function returns
* 0 : Success.
* -errno : An error occured.
*/
EXTERN int nfs_lockf(struct nfs_context *nfs, struct nfsfh *nfsfh,
enum nfs4_lock_op op, uint64_t count);

/*
* FSYNC()
*/
Expand Down
37 changes: 37 additions & 0 deletions lib/libnfs-sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,43 @@ nfs_lseek(struct nfs_context *nfs, struct nfsfh *nfsfh, int64_t offset, int when
}


/*
* lockf()
*/
static void
lockf_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, "lockf call failed with \"%s\"",
nfs_get_error(nfs));
return;
}
}

int
nfs_lockf(struct nfs_context *nfs, struct nfsfh *nfsfh,
enum nfs4_lock_op cmd, uint64_t count)
{
struct sync_cb_data cb_data;

cb_data.is_finished = 0;

if (nfs_lockf_async(nfs, nfsfh, cmd, count,
lockf_cb, &cb_data) != 0) {
nfs_set_error(nfs, "nfs_lockf_async failed. %s",
nfs_get_error(nfs));
return -1;
}

wait_for_nfs_reply(nfs, &cb_data);

return cb_data.status;
}

/*
* statvfs()
Expand Down
2 changes: 2 additions & 0 deletions lib/libnfs-win32.def
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ nfs_get_timeout
nfs_init_context
nfs_link
nfs_link_async
nfs_lockf
nfs_lockf_async
nfs_lseek
nfs_lseek_async
nfs_mkdir
Expand Down
16 changes: 16 additions & 0 deletions lib/libnfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1358,6 +1358,22 @@ nfs_lseek_async(struct nfs_context *nfs, struct nfsfh *nfsfh, int64_t offset,
}
}

int
nfs_lockf_async(struct nfs_context *nfs, struct nfsfh *nfsfh,
enum nfs4_lock_op op, uint64_t count,
nfs_cb cb, void *private_data)
{
switch (nfs->version) {
case NFS_V4:
return nfs4_lockf_async(nfs, nfsfh, op, count,
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)
Expand Down
197 changes: 197 additions & 0 deletions lib/nfs_v4.c
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,90 @@ nfs4_op_putfh(struct nfs_context *nfs, nfs_argop4 *op, struct nfsfh *nfsfh)
return 1;
}

static int
nfs4_op_lock(struct nfs_context *nfs, nfs_argop4 *op, struct nfsfh *fh,
nfs_opnum4 cmd, nfs_lock_type4 locktype,
int reclaim, uint64_t offset, length4 length)
{
LOCK4args *largs;
op[0].argop = cmd;

largs = &op[0].nfs_argop4_u.oplock;
largs->locktype = locktype;
largs->reclaim = reclaim;
largs->offset = offset;
largs->length = length;

if (fh->has_lock) {
largs->locker.new_lock_owner = 0;
largs->locker.locker4_u.lock_owner.lock_stateid.seqid =
fh->lock_stateid.seqid;
memcpy(largs->locker.locker4_u.lock_owner.lock_stateid.other,
fh->lock_stateid.other, 12);
largs->locker.locker4_u.lock_owner.lock_seqid =
fh->lock_seqid;
} else {
largs->locker.new_lock_owner = 1;
largs->locker.locker4_u.open_owner.open_seqid =
nfs->seqid;
largs->locker.locker4_u.open_owner.open_stateid.seqid =
fh->stateid.seqid;
memcpy(largs->locker.locker4_u.open_owner.open_stateid.other,
fh->stateid.other, 12);
largs->locker.locker4_u.open_owner.lock_owner.clientid =
nfs->clientid;
largs->locker.locker4_u.open_owner.lock_owner.owner.owner_len =
strlen(nfs->client_name);
largs->locker.locker4_u.open_owner.lock_owner.owner.owner_val =
nfs->client_name;
largs->locker.locker4_u.open_owner.lock_seqid =
fh->lock_seqid;
}
fh->lock_seqid++;

return 1;
}

static int
nfs4_op_locku(struct nfs_context *nfs, nfs_argop4 *op, struct nfsfh *fh,
nfs_lock_type4 locktype, uint64_t offset, length4 length)
{
LOCKU4args *luargs;
op[0].argop = OP_LOCKU;

luargs = &op[0].nfs_argop4_u.oplocku;
luargs->locktype = locktype;
luargs->offset = offset;
luargs->length = length;

luargs->seqid = fh->lock_seqid;
luargs->lock_stateid.seqid = fh->lock_stateid.seqid;
memcpy(luargs->lock_stateid.other, fh->lock_stateid.other, 12);

fh->lock_seqid++;

return 1;
}

static int
nfs4_op_lockt(struct nfs_context *nfs, nfs_argop4 *op, struct nfsfh *fh,
nfs_lock_type4 locktype, uint64_t offset, length4 length)
{
LOCKT4args *ltargs;
op[0].argop = OP_LOCKT;

ltargs = &op[0].nfs_argop4_u.oplockt;
ltargs->locktype = locktype;
ltargs->offset = offset;
ltargs->length = length;

ltargs->owner.clientid = nfs->clientid;
ltargs->owner.owner.owner_len = strlen(nfs->client_name);
ltargs->owner.owner.owner_val = nfs->client_name;

return 1;
}

static int
nfs4_op_lookup(struct nfs_context *nfs, nfs_argop4 *op, const char *path)
{
Expand Down Expand Up @@ -3790,6 +3874,119 @@ nfs4_lseek_async(struct nfs_context *nfs, struct nfsfh *fh, int64_t offset,
return 0;
}

static void
nfs4_lockf_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;
LOCKU4res *lures = NULL;
struct nfsfh *fh = data->filler.blob0.val;
enum nfs4_lock_op cmd;
int i;

assert(rpc->magic == RPC_CONTEXT_MAGIC);

cmd = data->filler.blob1.len;

if (check_nfs4_error(nfs, status, data, res, "LOCKF")) {
return;
}

switch (cmd) {
case NFS4_F_LOCK:
case NFS4_F_TLOCK:
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;
fh->has_lock = 1;
fh->lock_stateid.seqid = lresok->lock_stateid.seqid;
memcpy(fh->lock_stateid.other, lresok->lock_stateid.other, 12);
break;
case NFS4_F_ULOCK:
if ((i = nfs4_find_op(nfs, data, res, OP_LOCKU, "LOCKU")) < 0) {
return;
}
lures = &res->resarray.resarray_val[i].nfs_resop4_u.oplocku;
fh->lock_stateid.seqid = lures->LOCKU4res_u.lock_stateid.seqid;
memcpy(fh->lock_stateid.other,
lures->LOCKU4res_u.lock_stateid.other, 12);
break;
case NFS4_F_TEST:
break;
}

data->cb(0, nfs, NULL, data->private_data);

free_nfs4_cb_data(data);
}

/* blob0.val is nfsfh
* blob1.len is cmd
*/
int
nfs4_lockf_async(struct nfs_context *nfs, struct nfsfh *fh,
enum nfs4_lock_op cmd, uint64_t count,
nfs_cb cb, void *private_data)
{
COMPOUND4args args;
nfs_argop4 op[2];
struct nfs4_cb_data *data;
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;

i = nfs4_op_putfh(nfs, &op[0], fh);
switch (cmd) {
case NFS4_F_LOCK:
i += nfs4_op_lock(nfs, &op[i], fh, OP_LOCK, WRITEW_LT,
0, fh->offset, count);
break;
case NFS4_F_TLOCK:
i += nfs4_op_lock(nfs, &op[i], fh, OP_LOCK, WRITE_LT,
0, fh->offset, count);
break;
case NFS4_F_ULOCK:
i += nfs4_op_locku(nfs, &op[i], fh, WRITE_LT,
fh->offset, count);
break;
case NFS4_F_TEST:
i += nfs4_op_lockt(nfs, &op[i], fh, WRITEW_LT,
fh->offset, count);
break;
}

memset(&args, 0, sizeof(args));
args.argarray.argarray_len = i;
args.argarray.argarray_val = op;

if (rpc_nfs4_compound_async(nfs->rpc, nfs4_lockf_cb, &args,
data) != 0) {
free_nfs4_cb_data(data);
return -1;
}

return 0;
}

static int
nfs_parse_statvfs(struct nfs_context *nfs, struct nfs4_cb_data *data,
struct statvfs *svfs, const char *buf, int len)
Expand Down

0 comments on commit 208dd08

Please sign in to comment.