diff options
Diffstat (limited to 'xlators/features/leases/src/leases.c')
| -rw-r--r-- | xlators/features/leases/src/leases.c | 1168 |
1 files changed, 1168 insertions, 0 deletions
diff --git a/xlators/features/leases/src/leases.c b/xlators/features/leases/src/leases.c new file mode 100644 index 00000000000..04bee50ba3f --- /dev/null +++ b/xlators/features/leases/src/leases.c @@ -0,0 +1,1168 @@ +/* + Copyright (c) 2015-2016 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "leases.h" + +int32_t +leases_open_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd, dict_t *xdata) +{ + STACK_UNWIND_STRICT(open, frame, op_ret, op_errno, fd, xdata); + + return 0; +} + +int32_t +leases_open(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + fd_t *fd, dict_t *xdata) +{ + uint32_t fop_flags = 0; + int32_t op_errno = EINVAL; + int ret = 0; + lease_fd_ctx_t *fd_ctx = NULL; + char *lease_id = NULL; + + EXIT_IF_LEASES_OFF(this, out); + EXIT_IF_INTERNAL_FOP(frame, xdata, out); + + fd_ctx = GF_CALLOC(1, sizeof(*fd_ctx), gf_leases_mt_fd_ctx_t); + if (!fd_ctx) { + op_errno = ENOMEM; + goto err; + } + + fd_ctx->client_uid = gf_strdup(frame->root->client->client_uid); + if (!fd_ctx->client_uid) { + op_errno = ENOMEM; + goto err; + } + + GET_FLAGS(frame->root->op, flags); + GET_LEASE_ID(xdata, lease_id, frame->root->client->client_uid); + if (lease_id != NULL) + memcpy(fd_ctx->lease_id, lease_id, LEASE_ID_SIZE); + else + memset(fd_ctx->lease_id, 0, LEASE_ID_SIZE); + + ret = fd_ctx_set(fd, this, (uint64_t)(uintptr_t)fd_ctx); + if (ret) { + op_errno = ENOMEM; + goto err; + } + + ret = check_lease_conflict(frame, fd->inode, lease_id, fop_flags); + if (ret < 0) + goto err; + else if (ret == BLOCK_FOP) + goto block; + else if (ret == WIND_FOP) + goto out; + +block: + LEASE_BLOCK_FOP(fd->inode, open, frame, this, loc, flags, fd, xdata); + return 0; + +out: + STACK_WIND(frame, leases_open_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->open, loc, flags, fd, xdata); + return 0; + +err: + if (fd_ctx) { + GF_FREE(fd_ctx->client_uid); + GF_FREE(fd_ctx); + } + + STACK_UNWIND_STRICT(open, frame, -1, op_errno, NULL, NULL); + return 0; +} + +int32_t +leases_writev_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, + int op_errno, struct iatt *prebuf, struct iatt *postbuf, + dict_t *xdata) +{ + STACK_UNWIND_STRICT(writev, frame, op_ret, op_errno, prebuf, postbuf, + xdata); + + return 0; +} + +int32_t +leases_writev(call_frame_t *frame, xlator_t *this, fd_t *fd, + struct iovec *vector, int count, off_t off, uint32_t flags, + struct iobref *iobref, dict_t *xdata) +{ + uint32_t fop_flags = 0; + char *lease_id = NULL; + int ret = 0; + + EXIT_IF_LEASES_OFF(this, out); + EXIT_IF_INTERNAL_FOP(frame, xdata, out); + + GET_LEASE_ID(xdata, lease_id, frame->root->client->client_uid); + GET_FLAGS(frame->root->op, fd->flags); + + ret = check_lease_conflict(frame, fd->inode, lease_id, fop_flags); + if (ret < 0) + goto err; + else if (ret == BLOCK_FOP) + goto block; + else if (ret == WIND_FOP) + goto out; + +block: + LEASE_BLOCK_FOP(fd->inode, writev, frame, this, fd, vector, count, off, + flags, iobref, xdata); + return 0; + +out: + STACK_WIND(frame, leases_writev_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->writev, fd, vector, count, off, flags, + iobref, xdata); + return 0; + +err: + STACK_UNWIND_STRICT(writev, frame, -1, errno, NULL, NULL, NULL); + return 0; +} + +int32_t +leases_readv_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, + int op_errno, struct iovec *vector, int count, + struct iatt *stbuf, struct iobref *iobref, dict_t *xdata) +{ + STACK_UNWIND_STRICT(readv, frame, op_ret, op_errno, vector, count, stbuf, + iobref, xdata); + + return 0; +} + +int32_t +leases_readv(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, + off_t offset, uint32_t flags, dict_t *xdata) +{ + uint32_t fop_flags = 0; + char *lease_id = NULL; + int ret = 0; + + EXIT_IF_LEASES_OFF(this, out); + EXIT_IF_INTERNAL_FOP(frame, xdata, out); + + GET_LEASE_ID(xdata, lease_id, frame->root->client->client_uid); + GET_FLAGS(frame->root->op, fd->flags); + + ret = check_lease_conflict(frame, fd->inode, lease_id, fop_flags); + if (ret < 0) + goto err; + else if (ret == BLOCK_FOP) + goto block; + else if (ret == WIND_FOP) + goto out; + +block: + LEASE_BLOCK_FOP(fd->inode, readv, frame, this, fd, size, offset, flags, + xdata); + return 0; + +out: + STACK_WIND(frame, leases_readv_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->readv, fd, size, offset, flags, xdata); + return 0; + +err: + STACK_UNWIND_STRICT(readv, frame, -1, errno, NULL, 0, NULL, NULL, NULL); + return 0; +} + +int32_t +leases_lk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, + int32_t op_errno, struct gf_flock *lock, dict_t *xdata) +{ + STACK_UNWIND_STRICT(lk, frame, op_ret, op_errno, lock, xdata); + + return 0; +} + +int32_t +leases_lk(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t cmd, + struct gf_flock *flock, dict_t *xdata) +{ + uint32_t fop_flags = 0; + char *lease_id = NULL; + int ret = 0; + + EXIT_IF_LEASES_OFF(this, out); + EXIT_IF_INTERNAL_FOP(frame, xdata, out); + + GET_LEASE_ID(xdata, lease_id, frame->root->client->client_uid); + GET_FLAGS_LK(cmd, flock->l_type, fd->flags); + + ret = check_lease_conflict(frame, fd->inode, lease_id, fop_flags); + if (ret < 0) + goto err; + else if (ret == BLOCK_FOP) + goto block; + else if (ret == WIND_FOP) + goto out; + +block: + LEASE_BLOCK_FOP(fd->inode, lk, frame, this, fd, cmd, flock, xdata); + return 0; + +out: + STACK_WIND(frame, leases_lk_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->lk, fd, cmd, flock, xdata); + return 0; + +err: + STACK_UNWIND_STRICT(lk, frame, -1, errno, NULL, NULL); + return 0; +} + +int32_t +leases_lease(call_frame_t *frame, xlator_t *this, loc_t *loc, + struct gf_lease *lease, dict_t *xdata) +{ + int32_t op_errno = 0; + int ret = 0; + struct gf_lease nullease = { + 0, + }; + int32_t op_ret = 0; + + EXIT_IF_LEASES_OFF(this, out); + EXIT_IF_INTERNAL_FOP(frame, xdata, out); + + ret = process_lease_req(frame, this, loc->inode, lease); + if (ret < 0) { + op_errno = -ret; + op_ret = -1; + } + goto unwind; + +out: + gf_msg(this->name, GF_LOG_ERROR, EINVAL, LEASE_MSG_NOT_ENABLED, + "\"features/leases\" translator is not enabled. " + "You need to enable it for proper functioning of your " + "application"); + op_errno = ENOSYS; + op_ret = -1; + +unwind: + STACK_UNWIND_STRICT(lease, frame, op_ret, op_errno, + (op_errno == ENOSYS) ? &nullease : lease, xdata); + return 0; +} + +int32_t +leases_truncate_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +{ + STACK_UNWIND_STRICT(truncate, frame, op_ret, op_errno, prebuf, postbuf, + xdata); + + return 0; +} + +int32_t +leases_truncate(call_frame_t *frame, xlator_t *this, loc_t *loc, off_t offset, + dict_t *xdata) +{ + uint32_t fop_flags = 0; + char *lease_id = NULL; + int ret = 0; + + EXIT_IF_LEASES_OFF(this, out); + EXIT_IF_INTERNAL_FOP(frame, xdata, out); + + GET_LEASE_ID(xdata, lease_id, frame->root->client->client_uid); + GET_FLAGS(frame->root->op, 0); + + ret = check_lease_conflict(frame, loc->inode, lease_id, fop_flags); + if (ret < 0) + goto err; + else if (ret == BLOCK_FOP) + goto block; + else if (ret == WIND_FOP) + goto out; + +block: + LEASE_BLOCK_FOP(loc->inode, truncate, frame, this, loc, offset, xdata); + return 0; + +out: + STACK_WIND(frame, leases_truncate_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->truncate, loc, offset, xdata); + return 0; + +err: + STACK_UNWIND_STRICT(truncate, frame, -1, errno, NULL, NULL, NULL); + return 0; +} + +int32_t +leases_setattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, struct iatt *statpre, + struct iatt *statpost, dict_t *xdata) +{ + STACK_UNWIND_STRICT(setattr, frame, op_ret, op_errno, statpre, statpost, + xdata); + + return 0; +} + +int32_t +leases_setattr(call_frame_t *frame, xlator_t *this, loc_t *loc, + struct iatt *stbuf, int32_t valid, dict_t *xdata) +{ + uint32_t fop_flags = 0; + char *lease_id = NULL; + int ret = 0; + + EXIT_IF_LEASES_OFF(this, out); + EXIT_IF_INTERNAL_FOP(frame, xdata, out); + + GET_LEASE_ID(xdata, lease_id, frame->root->client->client_uid); + GET_FLAGS(frame->root->op, 0); + + ret = check_lease_conflict(frame, loc->inode, lease_id, fop_flags); + if (ret < 0) + goto err; + else if (ret == BLOCK_FOP) + goto block; + else if (ret == WIND_FOP) + goto out; + +block: + LEASE_BLOCK_FOP(loc->inode, setattr, frame, this, loc, stbuf, valid, xdata); + return 0; + +out: + STACK_WIND(frame, leases_setattr_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->setattr, loc, stbuf, valid, xdata); + return 0; + +err: + STACK_UNWIND_STRICT(setattr, frame, -1, errno, NULL, NULL, NULL); + return 0; +} + +int32_t +leases_rename_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *stbuf, + struct iatt *preoldparent, struct iatt *postoldparent, + struct iatt *prenewparent, struct iatt *postnewparent, + dict_t *xdata) +{ + STACK_UNWIND_STRICT(rename, frame, op_ret, op_errno, stbuf, preoldparent, + postoldparent, prenewparent, postnewparent, xdata); + + return 0; +} + +int32_t +leases_rename(call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, + dict_t *xdata) +{ + uint32_t fop_flags = 0; + char *lease_id = NULL; + int ret = 0; + + EXIT_IF_LEASES_OFF(this, out); + EXIT_IF_INTERNAL_FOP(frame, xdata, out); + + /* should the lease be also checked for newloc */ + GET_LEASE_ID(xdata, lease_id, frame->root->client->client_uid); + GET_FLAGS(frame->root->op, 0); + + ret = check_lease_conflict(frame, oldloc->inode, lease_id, fop_flags); + if (ret < 0) + goto err; + else if (ret == BLOCK_FOP) + goto block; + else if (ret == WIND_FOP) + goto out; + +block: + LEASE_BLOCK_FOP(oldloc->inode, rename, frame, this, oldloc, newloc, xdata); + return 0; + +out: + STACK_WIND(frame, leases_rename_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->rename, oldloc, newloc, xdata); + return 0; + +err: + STACK_UNWIND_STRICT(rename, frame, -1, errno, NULL, NULL, NULL, NULL, NULL, + NULL); + return 0; +} + +int32_t +leases_unlink_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, + int op_errno, struct iatt *preparent, struct iatt *postparent, + dict_t *xdata) +{ + STACK_UNWIND_STRICT(unlink, frame, op_ret, op_errno, preparent, postparent, + xdata); + + return 0; +} + +int32_t +leases_unlink(call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag, + dict_t *xdata) +{ + uint32_t fop_flags = 0; + char *lease_id = NULL; + int ret = 0; + + EXIT_IF_LEASES_OFF(this, out); + EXIT_IF_INTERNAL_FOP(frame, xdata, out); + + GET_LEASE_ID(xdata, lease_id, frame->root->client->client_uid); + GET_FLAGS(frame->root->op, 0); + + ret = check_lease_conflict(frame, loc->inode, lease_id, fop_flags); + if (ret < 0) + goto err; + else if (ret == BLOCK_FOP) + goto block; + else if (ret == WIND_FOP) + goto out; + +block: + LEASE_BLOCK_FOP(loc->inode, unlink, frame, this, loc, xflag, xdata); + return 0; + +out: + STACK_WIND(frame, leases_unlink_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->unlink, loc, xflag, xdata); + return 0; + +err: + STACK_UNWIND_STRICT(unlink, frame, -1, errno, NULL, NULL, NULL); + return 0; +} + +int32_t +leases_link_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, + int op_errno, inode_t *inode, struct iatt *stbuf, + struct iatt *preparent, struct iatt *postparent, dict_t *xdata) +{ + STACK_UNWIND_STRICT(link, frame, op_ret, op_errno, inode, stbuf, preparent, + postparent, xdata); + + return 0; +} + +int32_t +leases_link(call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, + dict_t *xdata) +{ + uint32_t fop_flags = 0; + char *lease_id = NULL; + int ret = 0; + + EXIT_IF_LEASES_OFF(this, out); + EXIT_IF_INTERNAL_FOP(frame, xdata, out); + + GET_LEASE_ID(xdata, lease_id, frame->root->client->client_uid); + GET_FLAGS(frame->root->op, 0); + + ret = check_lease_conflict(frame, oldloc->inode, lease_id, fop_flags); + if (ret < 0) + goto err; + else if (ret == BLOCK_FOP) + goto block; + else if (ret == WIND_FOP) + goto out; + +block: + LEASE_BLOCK_FOP(oldloc->inode, link, frame, this, oldloc, newloc, xdata); + return 0; +out: + STACK_WIND(frame, leases_link_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->link, oldloc, newloc, xdata); + return 0; + +err: + STACK_UNWIND_STRICT(link, frame, -1, errno, NULL, NULL, NULL, NULL, NULL); + return 0; +} + +int32_t +leases_create_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, + int op_errno, fd_t *fd, inode_t *inode, struct iatt *stbuf, + struct iatt *preparent, struct iatt *postparent, + dict_t *xdata) +{ + STACK_UNWIND_STRICT(create, frame, op_ret, op_errno, fd, inode, stbuf, + preparent, postparent, xdata); + + return 0; +} + +int32_t +leases_create(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + mode_t mode, mode_t umask, fd_t *fd, dict_t *xdata) +{ + uint32_t fop_flags = 0; + char *lease_id = NULL; + int ret = 0; + + EXIT_IF_LEASES_OFF(this, out); + EXIT_IF_INTERNAL_FOP(frame, xdata, out); + + GET_LEASE_ID(xdata, lease_id, frame->root->client->client_uid); + GET_FLAGS(frame->root->op, flags); + + ret = check_lease_conflict(frame, fd->inode, lease_id, fop_flags); + if (ret < 0) + goto err; + else if (ret == BLOCK_FOP) + goto block; + else if (ret == WIND_FOP) + goto out; + +block: + LEASE_BLOCK_FOP(fd->inode, create, frame, this, loc, flags, mode, umask, fd, + xdata); + return 0; + +out: + STACK_WIND(frame, leases_create_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->create, loc, flags, mode, umask, fd, + xdata); + return 0; + +err: + STACK_UNWIND_STRICT(create, frame, -1, errno, NULL, NULL, NULL, NULL, NULL, + NULL); + return 0; +} + +int32_t +leases_fsync_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +{ + STACK_UNWIND_STRICT(fsync, frame, op_ret, op_errno, prebuf, postbuf, xdata); + return 0; +} + +int32_t +leases_fsync(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags, + dict_t *xdata) +{ + uint32_t fop_flags = 0; + char *lease_id = NULL; + int ret = 0; + + EXIT_IF_LEASES_OFF(this, out); + EXIT_IF_INTERNAL_FOP(frame, xdata, out); + + GET_LEASE_ID(xdata, lease_id, frame->root->client->client_uid); + GET_FLAGS(frame->root->op, fd->flags); + + ret = check_lease_conflict(frame, fd->inode, lease_id, fop_flags); + if (ret < 0) + goto err; + else if (ret == BLOCK_FOP) + goto block; + else if (ret == WIND_FOP) + goto out; + +block: + LEASE_BLOCK_FOP(fd->inode, fsync, frame, this, fd, flags, xdata); + return 0; + +out: + STACK_WIND(frame, leases_fsync_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fsync, fd, flags, xdata); + return 0; +err: + STACK_UNWIND_STRICT(fsync, frame, -1, errno, NULL, NULL, NULL); + return 0; +} + +int32_t +leases_ftruncate_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +{ + STACK_UNWIND_STRICT(ftruncate, frame, op_ret, op_errno, prebuf, postbuf, + xdata); + return 0; +} + +int32_t +leases_ftruncate(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, + dict_t *xdata) +{ + uint32_t fop_flags = 0; + char *lease_id = NULL; + int ret = 0; + + EXIT_IF_LEASES_OFF(this, out); + EXIT_IF_INTERNAL_FOP(frame, xdata, out); + + GET_LEASE_ID(xdata, lease_id, frame->root->client->client_uid); + GET_FLAGS(frame->root->op, 0); /* TODO:fd->flags?*/ + + ret = check_lease_conflict(frame, fd->inode, lease_id, fop_flags); + if (ret < 0) + goto err; + else if (ret == BLOCK_FOP) + goto block; + else if (ret == WIND_FOP) + goto out; + +block: + LEASE_BLOCK_FOP(fd->inode, ftruncate, frame, this, fd, offset, xdata); + return 0; + +out: + STACK_WIND(frame, leases_ftruncate_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->ftruncate, fd, offset, xdata); + return 0; + +err: + STACK_UNWIND_STRICT(ftruncate, frame, -1, errno, NULL, NULL, NULL); + return 0; +} + +int32_t +leases_fsetattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *statpre, + struct iatt *statpost, dict_t *xdata) +{ + STACK_UNWIND_STRICT(fsetattr, frame, op_ret, op_errno, statpre, statpost, + xdata); + return 0; +} + +int32_t +leases_fsetattr(call_frame_t *frame, xlator_t *this, fd_t *fd, + struct iatt *stbuf, int32_t valid, dict_t *xdata) +{ + uint32_t fop_flags = 0; + char *lease_id = NULL; + int ret = 0; + + EXIT_IF_LEASES_OFF(this, out); + EXIT_IF_INTERNAL_FOP(frame, xdata, out); + + GET_LEASE_ID(xdata, lease_id, frame->root->client->client_uid); + GET_FLAGS(frame->root->op, fd->flags); + + ret = check_lease_conflict(frame, fd->inode, lease_id, fop_flags); + if (ret < 0) + goto err; + else if (ret == BLOCK_FOP) + goto block; + else if (ret == WIND_FOP) + goto out; + +block: + LEASE_BLOCK_FOP(fd->inode, fsetattr, frame, this, fd, stbuf, valid, xdata); + return 0; + +out: + STACK_WIND(frame, leases_fsetattr_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fsetattr, fd, stbuf, valid, xdata); + return 0; + +err: + STACK_UNWIND_STRICT(fsetattr, frame, -1, errno, NULL, NULL, NULL); + return 0; +} + +int32_t +leases_fallocate_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *pre, + struct iatt *post, dict_t *xdata) +{ + STACK_UNWIND_STRICT(fallocate, frame, op_ret, op_errno, pre, post, xdata); + + return 0; +} + +int32_t +leases_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t mode, + off_t offset, size_t len, dict_t *xdata) +{ + uint32_t fop_flags = 0; + char *lease_id = NULL; + int ret = 0; + + EXIT_IF_LEASES_OFF(this, out); + EXIT_IF_INTERNAL_FOP(frame, xdata, out); + + GET_LEASE_ID(xdata, lease_id, frame->root->client->client_uid); + GET_FLAGS(frame->root->op, fd->flags); + + ret = check_lease_conflict(frame, fd->inode, lease_id, fop_flags); + if (ret < 0) + goto err; + else if (ret == BLOCK_FOP) + goto block; + else if (ret == WIND_FOP) + goto out; + +block: + LEASE_BLOCK_FOP(fd->inode, fallocate, frame, this, fd, mode, offset, len, + xdata); + return 0; + +out: + STACK_WIND(frame, leases_fallocate_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fallocate, fd, mode, offset, len, + xdata); + return 0; + +err: + STACK_UNWIND_STRICT(fallocate, frame, -1, errno, NULL, NULL, NULL); + return 0; +} + +int32_t +leases_discard_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *pre, + struct iatt *post, dict_t *xdata) +{ + STACK_UNWIND_STRICT(discard, frame, op_ret, op_errno, pre, post, xdata); + + return 0; +} + +int32_t +leases_discard(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, + size_t len, dict_t *xdata) +{ + uint32_t fop_flags = 0; + char *lease_id = NULL; + int ret = 0; + + EXIT_IF_LEASES_OFF(this, out); + EXIT_IF_INTERNAL_FOP(frame, xdata, out); + + GET_LEASE_ID(xdata, lease_id, frame->root->client->client_uid); + GET_FLAGS(frame->root->op, fd->flags); + + ret = check_lease_conflict(frame, fd->inode, lease_id, fop_flags); + if (ret < 0) + goto err; + else if (ret == BLOCK_FOP) + goto block; + else if (ret == WIND_FOP) + goto out; + +block: + LEASE_BLOCK_FOP(fd->inode, discard, frame, this, fd, offset, len, xdata); + return 0; + +out: + STACK_WIND(frame, leases_discard_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->discard, fd, offset, len, xdata); + return 0; + +err: + STACK_UNWIND_STRICT(discard, frame, -1, errno, NULL, NULL, NULL); + return 0; +} + +int32_t +leases_zerofill_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *pre, + struct iatt *post, dict_t *xdata) +{ + STACK_UNWIND_STRICT(zerofill, frame, op_ret, op_errno, pre, post, xdata); + + return 0; +} + +int +leases_zerofill(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, + off_t len, dict_t *xdata) +{ + uint32_t fop_flags = 0; + char *lease_id = NULL; + int ret = 0; + + EXIT_IF_LEASES_OFF(this, out); + EXIT_IF_INTERNAL_FOP(frame, xdata, out); + + GET_LEASE_ID(xdata, lease_id, frame->root->client->client_uid); + GET_FLAGS(frame->root->op, fd->flags); + + ret = check_lease_conflict(frame, fd->inode, lease_id, fop_flags); + if (ret < 0) + goto err; + else if (ret == BLOCK_FOP) + goto block; + else if (ret == WIND_FOP) + goto out; + +block: + LEASE_BLOCK_FOP(fd->inode, zerofill, frame, this, fd, offset, len, xdata); + return 0; + +out: + STACK_WIND(frame, leases_zerofill_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->zerofill, fd, offset, len, xdata); + return 0; + +err: + STACK_UNWIND_STRICT(zerofill, frame, -1, errno, NULL, NULL, NULL); + return 0; +} + +int +leases_flush_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + STACK_UNWIND_STRICT(flush, frame, op_ret, op_errno, xdata); + + return 0; +} + +int +leases_flush(call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *xdata) +{ + uint32_t fop_flags = 0; + char *lease_id = NULL; + int ret = 0; + lease_fd_ctx_t *fd_ctx = NULL; + uint64_t ctx = 0; + + EXIT_IF_LEASES_OFF(this, out); + EXIT_IF_INTERNAL_FOP(frame, xdata, out); + + GET_LEASE_ID(xdata, lease_id, frame->root->client->client_uid); + GET_FLAGS(frame->root->op, fd->flags); + + ret = check_lease_conflict(frame, fd->inode, lease_id, fop_flags); + if (ret < 0) + goto err; + else if (ret == BLOCK_FOP) + goto block; + else if (ret == WIND_FOP) + goto out; + +block: + LEASE_BLOCK_FOP(fd->inode, flush, frame, this, fd, xdata); + return 0; + +out: + /* * + * currently release is not called after the close fop from the + * application. Hence lease fd ctx is reset on here. + * This is actually not the right way, since flush can be called + * not only from the close op. + * TODO : + * - Either identify the flush is called from close call on fd from + * from the application. + * OR + * - Find why release is not called post the last close call + */ + ret = fd_ctx_get(fd, this, &ctx); + if (ret == 0) { + fd_ctx = (lease_fd_ctx_t *)(long)ctx; + if (fd_ctx->client_uid) { + GF_FREE(fd_ctx->client_uid); + fd_ctx->client_uid = NULL; + } + memset(fd_ctx->lease_id, 0, LEASE_ID_SIZE); + } + STACK_WIND(frame, leases_flush_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->flush, fd, xdata); + return 0; + +err: + STACK_UNWIND_STRICT(create, frame, -1, errno, NULL, NULL, NULL, NULL, NULL, + NULL); + return 0; +} + +int32_t +mem_acct_init(xlator_t *this) +{ + int ret = -1; + + if (!this) + return ret; + + ret = xlator_mem_acct_init(this, gf_leases_mt_end + 1); + + if (ret != 0) { + gf_msg(this->name, GF_LOG_WARNING, ENOMEM, LEASE_MSG_NO_MEM, + "mem account init failed"); + return ret; + } + + return ret; +} + +static int +leases_init_priv(xlator_t *this) +{ + int ret = 0; + leases_private_t *priv = NULL; + + priv = this->private; + GF_ASSERT(priv); + + if (!priv->timer_wheel) { + priv->timer_wheel = glusterfs_ctx_tw_get(this->ctx); + if (!priv->timer_wheel) { + ret = -1; + goto out; + } + } + + if (!priv->inited_recall_thr) { + ret = gf_thread_create(&priv->recall_thr, NULL, expired_recall_cleanup, + this, "leasercl"); + if (!ret) + priv->inited_recall_thr = _gf_true; + } + +out: + return ret; +} + +int +reconfigure(xlator_t *this, dict_t *options) +{ + leases_private_t *priv = NULL; + int ret = -1; + + priv = this->private; + GF_ASSERT(priv); + + /* TODO: In case of reconfigure, if its enabling the leases + * its not an issue, but if its disabling the leases, there + * is more to it, like recall all the existing leases, wait + * for unlock of all the leases etc., hence not supporting the + * reconfigure for now. + + GF_OPTION_RECONF ("leases", priv->leases_enabled, + options, bool, out); + + if (priv->leases_enabled) { + ret = leases_init_priv (this); + if (ret) + goto out; + } + */ + + GF_OPTION_RECONF("lease-lock-recall-timeout", priv->recall_lease_timeout, + options, int32, out); + + ret = 0; +out: + return ret; +} + +int +init(xlator_t *this) +{ + int ret = -1; + leases_private_t *priv = NULL; + + priv = GF_CALLOC(1, sizeof(*priv), gf_leases_mt_private_t); + if (!priv) { + gf_msg(this->name, GF_LOG_WARNING, ENOMEM, LEASE_MSG_NO_MEM, + "Leases init failed"); + goto out; + } + + GF_OPTION_INIT("leases", priv->leases_enabled, bool, out); + GF_OPTION_INIT("lease-lock-recall-timeout", priv->recall_lease_timeout, + int32, out); + pthread_mutex_init(&priv->mutex, NULL); + INIT_LIST_HEAD(&priv->client_list); + INIT_LIST_HEAD(&priv->recall_list); + + this->private = priv; + + if (priv->leases_enabled) { + ret = leases_init_priv(this); + if (ret) + goto out; + } + + ret = 0; + +out: + if (ret) { + GF_FREE(priv); + this->private = NULL; + } + + return ret; +} + +void +fini(xlator_t *this) +{ + leases_private_t *priv = NULL; + + priv = this->private; + if (!priv) { + return; + } + this->private = NULL; + + priv->fini = _gf_true; + pthread_cond_broadcast(&priv->cond); + if (priv->recall_thr) { + gf_thread_cleanup_xint(priv->recall_thr); + priv->recall_thr = 0; + priv->inited_recall_thr = _gf_false; + } + + if (priv->timer_wheel) { + glusterfs_ctx_tw_put(this->ctx); + } + + GF_FREE(priv); + return; +} + +static int +leases_forget(xlator_t *this, inode_t *inode) +{ + /* TODO:leases_cleanup_inode_ctx (this, inode); */ + return 0; +} + +static int +leases_release(xlator_t *this, fd_t *fd) +{ + int ret = -1; + uint64_t tmp = 0; + lease_fd_ctx_t *fd_ctx = NULL; + + if (fd == NULL) { + goto out; + } + + gf_log(this->name, GF_LOG_TRACE, "Releasing all leases with fd %p", fd); + + ret = fd_ctx_del(fd, this, &tmp); + if (ret) { + gf_log(this->name, GF_LOG_DEBUG, "Could not get fdctx"); + goto out; + } + + fd_ctx = (lease_fd_ctx_t *)(long)tmp; + if (fd_ctx) + GF_FREE(fd_ctx); +out: + return ret; +} + +static int +leases_clnt_disconnect_cbk(xlator_t *this, client_t *client) +{ + int ret = 0; + + EXIT_IF_LEASES_OFF(this, out); + + ret = cleanup_client_leases(this, client->client_uid); +out: + return ret; +} + +struct xlator_fops fops = { + /* Metadata modifying fops */ + .fsetattr = leases_fsetattr, + .setattr = leases_setattr, + + /* File Data reading fops */ + .open = leases_open, + .readv = leases_readv, + + /* File Data modifying fops */ + .truncate = leases_truncate, + .ftruncate = leases_ftruncate, + .writev = leases_writev, + .zerofill = leases_zerofill, + .fallocate = leases_fallocate, + .discard = leases_discard, + .lk = leases_lk, + .fsync = leases_fsync, + .flush = leases_flush, + .lease = leases_lease, + + /* Directory Data modifying fops */ + .create = leases_create, + .rename = leases_rename, + .unlink = leases_unlink, + .link = leases_link, + +#ifdef NOT_SUPPORTED + /* internal lk fops */ + .inodelk = leases_inodelk, + .finodelk = leases_finodelk, + .entrylk = leases_entrylk, + .fentrylk = leases_fentrylk, + + /* Internal special fops*/ + .xattrop = leases_xattrop, + .fxattrop = leases_fxattrop, +#endif +}; + +struct xlator_cbks cbks = { + .forget = leases_forget, + .release = leases_release, + .client_disconnect = leases_clnt_disconnect_cbk, +}; + +struct volume_options options[] = { + {.key = {"leases"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "off", + .op_version = {GD_OP_VERSION_3_8_0}, + .flags = OPT_FLAG_SETTABLE | OPT_FLAG_DOC, + .description = "When \"on\", enables leases support"}, + {.key = {"lease-lock-recall-timeout"}, + .type = GF_OPTION_TYPE_INT, + .default_value = RECALL_LEASE_LK_TIMEOUT, + .op_version = {GD_OP_VERSION_3_8_0}, + .flags = OPT_FLAG_SETTABLE | OPT_FLAG_DOC, + .description = "After 'timeout' seconds since the recall_lease" + " request has been sent to the client, the lease lock" + " will be forcefully purged by the server."}, + {.key = {NULL}}, +}; + +xlator_api_t xlator_api = { + .init = init, + .fini = fini, + .reconfigure = reconfigure, + .mem_acct_init = mem_acct_init, + .op_version = {1}, /* Present from the initial version */ + .fops = &fops, + .cbks = &cbks, + .options = options, + .identifier = "leases", + .category = GF_MAINTAINED, +}; |
