From 8fd4aa74149411ab739e2075e1f7c0709b8a0342 Mon Sep 17 00:00:00 2001 From: Raghavendra G Date: Wed, 17 Oct 2012 16:10:28 +0530 Subject: features/locks: implement fgetxattr and fsetxattr implement xattrs for GF_XATTR_LOCKINFO_KEY, which will be used for posix-locks migration from old to new graph after a switch. fgetxattr (fd, GF_XATTR_LOCKINFO_KEY) will return a dict. This dict has a serialized dict stored for key GF_XATTR_LOCKINFO_KEY. This serialized dict in turn has fdnum value of locks acquired on this fd with modified pathinfo (containing hostname and base directory components) as key. fsetxattr (newfd, GF_XATTR_LOCKINFO_KEY, dict) has following semantics. dict can be the result of a previous fgetxattr with GF_XATTR_LOCKINFO_KEY. In that case, a dict_get on dict constructed using serialized buffer is done on modified pathinfo as key. If a value is got, that value is treated as fdnum and for every lock l on newfd->inode we do, if (l->fdnum == fdnum) { l->fdnum = fd_fdnum (newfd); l->transport = ; } Signed-off-by: Raghavendra G Change-Id: I73a8f43aa0b6077bc19f8de52205ba748f2d8bbe BUG: 808400 Reviewed-on: http://review.gluster.org/4120 Reviewed-by: Vijay Bellur Tested-by: Vijay Bellur --- libglusterfs/src/glusterfs.h | 1 + xlators/features/locks/src/locks.h | 1 + xlators/features/locks/src/posix.c | 341 +++++++++++++++++++++++++++++++++++++ 3 files changed, 343 insertions(+) diff --git a/libglusterfs/src/glusterfs.h b/libglusterfs/src/glusterfs.h index 92e481e04fc..61edd5ec7c9 100644 --- a/libglusterfs/src/glusterfs.h +++ b/libglusterfs/src/glusterfs.h @@ -82,6 +82,7 @@ #define GF_XATTR_PATHINFO_KEY "trusted.glusterfs.pathinfo" #define GF_XATTR_NODE_UUID_KEY "trusted.glusterfs.node-uuid" #define GF_XATTR_VOL_ID_KEY "trusted.glusterfs.volume-id" +#define GF_XATTR_LOCKINFO_KEY "trusted.glusterfs.lockinfo" #define GF_READDIR_SKIP_DIRS "readdir-filter-directories" diff --git a/xlators/features/locks/src/locks.h b/xlators/features/locks/src/locks.h index d2b47bffed7..7ffc67e1b88 100644 --- a/xlators/features/locks/src/locks.h +++ b/xlators/features/locks/src/locks.h @@ -149,6 +149,7 @@ typedef struct __pl_fd pl_fd_t; typedef struct { gf_boolean_t mandatory; /* if mandatory locking is enabled */ gf_boolean_t trace; /* trace lock requests in and out */ + char *brickname; } posix_locks_private_t; typedef struct { diff --git a/xlators/features/locks/src/posix.c b/xlators/features/locks/src/posix.c index 0fbe57e220e..34ac1cb6480 100644 --- a/xlators/features/locks/src/posix.c +++ b/xlators/features/locks/src/posix.c @@ -28,6 +28,8 @@ #include "common.h" #include "statedump.h" #include "clear.h" +#include "defaults.h" +#include "syncop.h" #ifndef LLONG_MAX #define LLONG_MAX LONG_LONG_MAX /* compat with old gcc */ @@ -479,6 +481,343 @@ usual: return 0; } +int +pl_lockinfo_get_brickname (xlator_t *this, inode_t *inode, int32_t *op_errno) +{ + int ret = -1; + loc_t loc = {0, }; + dict_t *dict = NULL; + posix_locks_private_t *priv = NULL; + char *brickname = NULL, *end = NULL; + + priv = this->private; + + uuid_copy (loc.gfid, inode->gfid); + loc.inode = inode_ref (inode); + + ret = syncop_getxattr (FIRST_CHILD(this), &loc, &dict, + GF_XATTR_PATHINFO_KEY); + if (ret < 0) { + *op_errno = errno; + goto out; + } + + ret = dict_get_str (dict, GF_XATTR_PATHINFO_KEY, &brickname); + if (brickname == NULL) { + goto out; + } + + end = strrchr (brickname, ':'); + if (!end) { + goto out; + } + + brickname = gf_strndup (brickname, (end - brickname)); + if (brickname == NULL) { + goto out; + } + + priv->brickname = brickname; + ret = 0; +out: + if (dict != NULL) { + dict_unref (dict); + } + + inode_unref (loc.inode); + + return ret; +} + +char * +pl_lockinfo_key (xlator_t *this, inode_t *inode, int32_t *op_errno) +{ + posix_locks_private_t *priv = NULL; + char *key = NULL; + int ret = 0; + + priv = this->private; + + if (priv->brickname == NULL) { + ret = pl_lockinfo_get_brickname (this, inode, op_errno); + if (ret < 0) { + gf_log (this->name, GF_LOG_WARNING, + "cannot get brickname"); + goto out; + } + } + + key = priv->brickname; +out: + return key; +} + +int32_t +pl_fgetxattr_handle_lockinfo (xlator_t *this, fd_t *fd, + dict_t *dict, int32_t *op_errno) +{ + pl_inode_t *pl_inode = NULL; + char *key = NULL, *buf = NULL; + int32_t op_ret = 0; + unsigned long fdnum = 0, len = 0; + dict_t *tmp = NULL; + + pl_inode = pl_inode_get (this, fd->inode); + + if (!pl_inode) { + gf_log (this->name, GF_LOG_DEBUG, "Could not get inode."); + *op_errno = EBADFD; + op_ret = -1; + goto out; + } + + if (!pl_locks_by_fd (pl_inode, fd)) { + op_ret = 0; + goto out; + } + + fdnum = fd_to_fdnum (fd); + + key = pl_lockinfo_key (this, fd->inode, op_errno); + if (key == NULL) { + op_ret = -1; + goto out; + } + + tmp = dict_new (); + if (tmp == NULL) { + op_ret = -1; + *op_errno = ENOMEM; + goto out; + } + + op_ret = dict_set_uint64 (tmp, key, fdnum); + if (op_ret < 0) { + *op_errno = -op_ret; + op_ret = -1; + gf_log (this->name, GF_LOG_WARNING, "setting lockinfo value " + "(%lu) for fd (ptr:%p inode-gfid:%s) failed (%s)", + fdnum, fd, uuid_utoa (fd->inode->gfid), + strerror (*op_errno)); + goto out; + } + + len = dict_serialized_length (tmp); + if (len < 0) { + *op_errno = -op_ret; + op_ret = -1; + gf_log (this->name, GF_LOG_WARNING, + "dict_serialized_length failed (%s) while handling " + "lockinfo for fd (ptr:%p inode-gfid:%s)", + strerror (*op_errno), fd, uuid_utoa (fd->inode->gfid)); + goto out; + } + + buf = GF_CALLOC (1, len, gf_common_mt_char); + if (buf == NULL) { + op_ret = -1; + *op_errno = ENOMEM; + goto out; + } + + op_ret = dict_serialize (tmp, buf); + if (op_ret < 0) { + *op_errno = -op_ret; + op_ret = -1; + gf_log (this->name, GF_LOG_WARNING, + "dict_serialize failed (%s) while handling lockinfo " + "for fd (ptr: %p inode-gfid:%s)", strerror (*op_errno), + fd, uuid_utoa (fd->inode->gfid)); + goto out; + } + + op_ret = dict_set_dynptr (dict, GF_XATTR_LOCKINFO_KEY, buf, len); + if (op_ret < 0) { + *op_errno = -op_ret; + op_ret = -1; + gf_log (this->name, GF_LOG_WARNING, "setting lockinfo value " + "(%lu) for fd (ptr:%p inode-gfid:%s) failed (%s)", + fdnum, fd, uuid_utoa (fd->inode->gfid), + strerror (*op_errno)); + goto out; + } + + buf = NULL; +out: + if (tmp != NULL) { + dict_unref (tmp); + } + + if (buf != NULL) { + GF_FREE (buf); + } + + return op_ret; +} + + +int32_t +pl_fgetxattr (call_frame_t *frame, xlator_t *this, fd_t *fd, + const char *name, dict_t *xdata) +{ + int32_t op_ret = 0, op_errno = 0; + dict_t *dict = NULL; + + if (!name) { + goto usual; + } + + if (strcmp (name, GF_XATTR_LOCKINFO_KEY) == 0) { + dict = dict_new (); + if (dict == NULL) { + op_ret = -1; + op_errno = ENOMEM; + goto unwind; + } + + op_ret = pl_fgetxattr_handle_lockinfo (this, fd, dict, + &op_errno); + if (op_ret < 0) { + gf_log (this->name, GF_LOG_WARNING, + "getting lockinfo on fd (ptr:%p inode-gfid:%s) " + "failed (%s)", fd, uuid_utoa (fd->inode->gfid), + strerror (op_errno)); + } + + goto unwind; + } else { + goto usual; + } + +unwind: + STACK_UNWIND_STRICT (fgetxattr, frame, op_ret, op_errno, dict, NULL); + if (dict != NULL) { + dict_unref (dict); + } + + return 0; + +usual: + STACK_WIND (frame, default_fgetxattr_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fgetxattr, fd, name, xdata); + return 0; +} + +int32_t +pl_migrate_locks (call_frame_t *frame, fd_t *newfd, uint64_t oldfd_num, + int32_t *op_errno) +{ + pl_inode_t *pl_inode = NULL; + uint64_t newfd_num = 0; + posix_lock_t *l = NULL; + int32_t op_ret = 0; + + newfd_num = fd_to_fdnum (newfd); + + pl_inode = pl_inode_get (frame->this, newfd->inode); + if (pl_inode == NULL) { + op_ret = -1; + *op_errno = EBADFD; + goto out; + } + + pthread_mutex_lock (&pl_inode->mutex); + { + list_for_each_entry (l, &pl_inode->ext_list, list) { + if (l->fd_num == oldfd_num) { + l->fd_num = newfd_num; + l->transport = frame->root->trans; + } + } + } + pthread_mutex_unlock (&pl_inode->mutex); + + op_ret = 0; +out: + return op_ret; +} + +int32_t +pl_fsetxattr_handle_lockinfo (call_frame_t *frame, fd_t *fd, char *lockinfo_buf, + int len, int32_t *op_errno) +{ + int32_t op_ret = -1; + dict_t *lockinfo = NULL; + uint64_t oldfd_num = 0; + char *key = NULL; + + lockinfo = dict_new (); + if (lockinfo == NULL) { + op_ret = -1; + *op_errno = ENOMEM; + goto out; + } + + op_ret = dict_unserialize (lockinfo_buf, len, &lockinfo); + if (op_ret < 0) { + *op_errno = -op_ret; + op_ret = -1; + goto out; + } + + key = pl_lockinfo_key (frame->this, fd->inode, op_errno); + if (key == NULL) { + op_ret = -1; + goto out; + } + + op_ret = dict_get_uint64 (lockinfo, key, &oldfd_num); + + if (oldfd_num == 0) { + op_ret = 0; + goto out; + } + + op_ret = pl_migrate_locks (frame, fd, oldfd_num, op_errno); + if (op_ret < 0) { + gf_log (frame->this->name, GF_LOG_WARNING, + "migration of locks from oldfd (ptr:%p) to newfd " + "(ptr:%p) (inode-gfid:%s)", (void *)oldfd_num, fd, + uuid_utoa (fd->inode->gfid)); + goto out; + } + +out: + dict_unref (lockinfo); + + return op_ret; +} + +int32_t +pl_fsetxattr (call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *dict, + int32_t flags, dict_t *xdata) +{ + int32_t op_ret = 0, op_errno = 0; + void *lockinfo_buf = NULL; + int len = 0; + + op_ret = dict_get_ptr_and_len (dict, GF_XATTR_LOCKINFO_KEY, + &lockinfo_buf, &len); + if (lockinfo_buf == NULL) { + goto usual; + } + + op_ret = pl_fsetxattr_handle_lockinfo (frame, fd, lockinfo_buf, len, + &op_errno); + if (op_ret < 0) { + goto unwind; + } + +usual: + STACK_WIND (frame, default_fsetxattr_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fsetxattr, fd, dict, flags, xdata); + return 0; + +unwind: + STACK_UNWIND_STRICT (fsetxattr, frame, op_ret, op_errno, NULL); + return 0; +} + int32_t pl_opendir_cbk (call_frame_t *frame, void *cookie, @@ -2177,6 +2516,8 @@ struct xlator_fops fops = { .opendir = pl_opendir, .readdirp = pl_readdirp, .getxattr = pl_getxattr, + .fgetxattr = pl_fgetxattr, + .fsetxattr = pl_fsetxattr, }; struct xlator_dumpops dumpops = { -- cgit