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 = <connection identifier of connection on which fsetxattr came>;
      }

Signed-off-by: Raghavendra G <raghavendra@gluster.com>
Change-Id: I73a8f43aa0b6077bc19f8de52205ba748f2d8bbe
BUG: 808400
Reviewed-on: http://review.gluster.org/4120
Reviewed-by: Vijay Bellur <vbellur@redhat.com>
Tested-by: Vijay Bellur <vbellur@redhat.com>
This commit is contained in:
Raghavendra G 2012-10-17 16:10:28 +05:30 committed by Vijay Bellur
parent dbc0968db0
commit 8fd4aa7414
3 changed files with 343 additions and 0 deletions

View File

@ -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"

View File

@ -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 {

View File

@ -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 = {