all: remove code which is not being considered in build
These xlators are now removed from build as per discussion/announcement done at https://lists.gluster.org/pipermail/gluster-users/2018-July/034400.html * move rot-13 to playground, as it is used only as demo purpose, and is documented in many places. * Removed code of below xlators: - cluster/stripe - cluster/tier - features/changetimerecorder - features/glupy - performance/symlink-cache - encryption/crypt - storage/bd - experimental/posix2 - experimental/dht2 - experimental/fdl - experimental/jbr updates: bz#1635688 Change-Id: I1d2d63c32535e149bc8dcb2daa76236c707996e8 Signed-off-by: Amar Tumballi <amarts@redhat.com>
This commit is contained in:
parent
af7e957b49
commit
8293d21280
File diff suppressed because it is too large
Load Diff
@ -1,55 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2015 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 _TIER_COMMON_H_
|
||||
#define _TIER_COMMON_H_
|
||||
/* Function definitions */
|
||||
int
|
||||
tier_create_unlink_stale_linkto_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);
|
||||
|
||||
int
|
||||
tier_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);
|
||||
|
||||
int
|
||||
tier_create_linkfile_create_cbk(call_frame_t *frame, void *cookie,
|
||||
xlator_t *this, int32_t op_ret,
|
||||
int32_t op_errno, inode_t *inode,
|
||||
struct iatt *stbuf, struct iatt *preparent,
|
||||
struct iatt *postparent, dict_t *xdata);
|
||||
|
||||
int
|
||||
tier_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 *params);
|
||||
|
||||
int32_t
|
||||
tier_unlink(call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag,
|
||||
dict_t *xdata);
|
||||
|
||||
int32_t
|
||||
tier_readdirp(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size,
|
||||
off_t off, dict_t *dict);
|
||||
|
||||
int
|
||||
tier_readdir(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size,
|
||||
off_t yoff, dict_t *xdata);
|
||||
|
||||
int
|
||||
tier_link(call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc,
|
||||
dict_t *xdata);
|
||||
|
||||
int
|
||||
tier_statfs(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,110 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2015 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 _TIER_H_
|
||||
#define _TIER_H_
|
||||
|
||||
/******************************************************************************/
|
||||
/* This is from dht-rebalancer.c as we don't have dht-rebalancer.h */
|
||||
#include "dht-common.h"
|
||||
#include <glusterfs/xlator.h>
|
||||
#include <signal.h>
|
||||
#include <fnmatch.h>
|
||||
#include <signal.h>
|
||||
|
||||
/*
|
||||
* Size of timer wheel. We would not promote or demote less
|
||||
* frequently than this number.
|
||||
*/
|
||||
#define TIMER_SECS 3600
|
||||
|
||||
#include "gfdb_data_store.h"
|
||||
#include <ctype.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define PROMOTION_QFILE "promotequeryfile"
|
||||
#define DEMOTION_QFILE "demotequeryfile"
|
||||
|
||||
#define TIER_HASHED_SUBVOL conf->subvolumes[0]
|
||||
#define TIER_UNHASHED_SUBVOL conf->subvolumes[1]
|
||||
|
||||
#define GET_QFILE_PATH(is_promotion) \
|
||||
(is_promotion) ? promotion_qfile : demotion_qfile
|
||||
|
||||
typedef struct tier_qfile_array {
|
||||
int *fd_array;
|
||||
ssize_t array_size;
|
||||
ssize_t next_index;
|
||||
/* Indicate the number of exhuasted FDs*/
|
||||
ssize_t exhausted_count;
|
||||
} tier_qfile_array_t;
|
||||
|
||||
typedef struct _query_cbk_args {
|
||||
xlator_t *this;
|
||||
gf_defrag_info_t *defrag;
|
||||
/* This is write */
|
||||
int query_fd;
|
||||
int is_promotion;
|
||||
int is_compaction;
|
||||
/* This is for read */
|
||||
tier_qfile_array_t *qfile_array;
|
||||
} query_cbk_args_t;
|
||||
|
||||
int
|
||||
gf_run_tier(xlator_t *this, gf_defrag_info_t *defrag);
|
||||
|
||||
typedef struct gfdb_brick_info {
|
||||
gfdb_time_t *time_stamp;
|
||||
gf_boolean_t _gfdb_promote;
|
||||
query_cbk_args_t *_query_cbk_args;
|
||||
} gfdb_brick_info_t;
|
||||
|
||||
typedef struct brick_list {
|
||||
xlator_t *xlator;
|
||||
char *brick_db_path;
|
||||
char brick_name[NAME_MAX];
|
||||
char qfile_path[PATH_MAX];
|
||||
struct list_head list;
|
||||
} tier_brick_list_t;
|
||||
|
||||
typedef struct _dm_thread_args {
|
||||
xlator_t *this;
|
||||
gf_defrag_info_t *defrag;
|
||||
struct list_head *brick_list;
|
||||
int freq_time;
|
||||
int return_value;
|
||||
int is_promotion;
|
||||
int is_compaction;
|
||||
gf_boolean_t is_hot_tier;
|
||||
} migration_args_t;
|
||||
|
||||
typedef enum tier_watermark_op_ {
|
||||
TIER_WM_NONE = 0,
|
||||
TIER_WM_LOW,
|
||||
TIER_WM_HI,
|
||||
TIER_WM_MID
|
||||
} tier_watermark_op_t;
|
||||
|
||||
#define DEFAULT_PROMOTE_FREQ_SEC 120
|
||||
#define DEFAULT_DEMOTE_FREQ_SEC 120
|
||||
#define DEFAULT_HOT_COMPACT_FREQ_SEC 604800
|
||||
#define DEFAULT_COLD_COMPACT_FREQ_SEC 604800
|
||||
#define DEFAULT_DEMOTE_DEGRADED 1
|
||||
#define DEFAULT_WRITE_FREQ_SEC 0
|
||||
#define DEFAULT_READ_FREQ_SEC 0
|
||||
#define DEFAULT_WM_LOW 75
|
||||
#define DEFAULT_WM_HI 90
|
||||
#define DEFAULT_TIER_MODE TIER_MODE_TEST
|
||||
#define DEFAULT_COMP_MODE _gf_true
|
||||
#define DEFAULT_TIER_MAX_MIGRATE_MB 1000
|
||||
#define DEFAULT_TIER_MAX_MIGRATE_FILES 5000
|
||||
#define DEFAULT_TIER_QUERY_LIMIT 100
|
||||
|
||||
#endif
|
@ -1,9 +0,0 @@
|
||||
fops
|
||||
cbks
|
||||
class_methods
|
||||
dht_methods
|
||||
tier_methods
|
||||
options
|
||||
mem_acct_init
|
||||
reconfigure
|
||||
dumpops
|
@ -1,22 +0,0 @@
|
||||
xlator_LTLIBRARIES = stripe.la
|
||||
xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/cluster
|
||||
|
||||
stripe_la_LDFLAGS = -module $(GF_XLATOR_DEFAULT_LDFLAGS)
|
||||
|
||||
|
||||
stripe_la_SOURCES = stripe.c stripe-helpers.c \
|
||||
$(top_builddir)/xlators/lib/src/libxlator.c
|
||||
|
||||
stripe_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la
|
||||
|
||||
noinst_HEADERS = stripe.h stripe-mem-types.h \
|
||||
$(top_builddir)/xlators/lib/src/libxlator.h
|
||||
|
||||
AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \
|
||||
-I$(top_srcdir)/xlators/lib/src \
|
||||
-I$(top_srcdir)/rpc/xdr/src -I$(top_builddir)/rpc/xdr/src
|
||||
|
||||
AM_CFLAGS = -Wall $(GF_CFLAGS)
|
||||
|
||||
CLEANFILES =
|
||||
|
@ -1,658 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2008-2012 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.
|
||||
*/
|
||||
|
||||
#include <fnmatch.h>
|
||||
|
||||
#include "stripe.h"
|
||||
#include <glusterfs/byte-order.h>
|
||||
#include <glusterfs/mem-types.h>
|
||||
#include <glusterfs/logging.h>
|
||||
|
||||
void
|
||||
stripe_local_wipe(stripe_local_t *local)
|
||||
{
|
||||
if (!local)
|
||||
goto out;
|
||||
|
||||
loc_wipe(&local->loc);
|
||||
loc_wipe(&local->loc2);
|
||||
|
||||
if (local->fd)
|
||||
fd_unref(local->fd);
|
||||
|
||||
if (local->inode)
|
||||
inode_unref(local->inode);
|
||||
|
||||
if (local->xattr)
|
||||
dict_unref(local->xattr);
|
||||
|
||||
if (local->xdata)
|
||||
dict_unref(local->xdata);
|
||||
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
stripe_aggregate(dict_t *this, char *key, data_t *value, void *data)
|
||||
{
|
||||
dict_t *dst = NULL;
|
||||
int64_t *ptr = 0, *size = NULL;
|
||||
int32_t ret = -1;
|
||||
|
||||
dst = data;
|
||||
|
||||
if (strcmp(key, QUOTA_SIZE_KEY) == 0) {
|
||||
ret = dict_get_bin(dst, key, (void **)&size);
|
||||
if (ret < 0) {
|
||||
size = GF_CALLOC(1, sizeof(int64_t), gf_common_mt_char);
|
||||
if (size == NULL) {
|
||||
gf_log("stripe", GF_LOG_WARNING, "memory allocation failed");
|
||||
goto out;
|
||||
}
|
||||
ret = dict_set_bin(dst, key, size, sizeof(int64_t));
|
||||
if (ret < 0) {
|
||||
gf_log("stripe", GF_LOG_WARNING,
|
||||
"stripe aggregate dict set failed");
|
||||
GF_FREE(size);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ptr = data_to_bin(value);
|
||||
if (ptr == NULL) {
|
||||
gf_log("stripe", GF_LOG_WARNING, "data to bin failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
*size = hton64(ntoh64(*size) + ntoh64(*ptr));
|
||||
} else if (strcmp(key, GF_CONTENT_KEY)) {
|
||||
/* No need to aggregate 'CONTENT' data */
|
||||
ret = dict_set(dst, key, value);
|
||||
if (ret)
|
||||
gf_log("stripe", GF_LOG_WARNING, "xattr dict set failed");
|
||||
}
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
stripe_aggregate_xattr(dict_t *dst, dict_t *src)
|
||||
{
|
||||
if ((dst == NULL) || (src == NULL)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
dict_foreach(src, stripe_aggregate, dst);
|
||||
out:
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t
|
||||
stripe_xattr_aggregate(char *buffer, stripe_local_t *local, int32_t *total)
|
||||
{
|
||||
int32_t i = 0;
|
||||
int32_t ret = -1;
|
||||
int32_t len = 0;
|
||||
char *sbuf = NULL;
|
||||
stripe_xattr_sort_t *xattr = NULL;
|
||||
|
||||
if (!buffer || !local || !local->xattr_list)
|
||||
goto out;
|
||||
|
||||
sbuf = buffer;
|
||||
|
||||
for (i = 0; i < local->nallocs; i++) {
|
||||
xattr = local->xattr_list + i;
|
||||
len = xattr->xattr_len - 1; /* length includes \0 */
|
||||
|
||||
if (len && xattr && xattr->xattr_value) {
|
||||
memcpy(buffer, xattr->xattr_value, len);
|
||||
buffer += len;
|
||||
*buffer++ = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
*--buffer = '\0';
|
||||
if (total)
|
||||
*total = buffer - sbuf;
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t
|
||||
stripe_free_xattr_str(stripe_local_t *local)
|
||||
{
|
||||
int32_t i = 0;
|
||||
int32_t ret = -1;
|
||||
stripe_xattr_sort_t *xattr = NULL;
|
||||
|
||||
if (!local || !local->xattr_list)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < local->nallocs; i++) {
|
||||
xattr = local->xattr_list + i;
|
||||
|
||||
if (xattr && xattr->xattr_value)
|
||||
GF_FREE(xattr->xattr_value);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t
|
||||
stripe_fill_lockinfo_xattr(xlator_t *this, stripe_local_t *local,
|
||||
void **xattr_serz)
|
||||
{
|
||||
int32_t ret = -1, i = 0, len = 0;
|
||||
dict_t *tmp1 = NULL, *tmp2 = NULL;
|
||||
char *buf = NULL;
|
||||
stripe_xattr_sort_t *xattr = NULL;
|
||||
|
||||
if (xattr_serz == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmp2 = dict_new();
|
||||
|
||||
if (tmp2 == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < local->nallocs; i++) {
|
||||
xattr = local->xattr_list + i;
|
||||
len = xattr->xattr_len;
|
||||
|
||||
if (len && xattr && xattr->xattr_value) {
|
||||
ret = dict_reset(tmp2);
|
||||
if (ret < 0) {
|
||||
gf_log(this->name, GF_LOG_DEBUG, "dict_reset failed (%s)",
|
||||
strerror(-ret));
|
||||
}
|
||||
|
||||
ret = dict_unserialize(xattr->xattr_value, xattr->xattr_len, &tmp2);
|
||||
if (ret < 0) {
|
||||
gf_log(this->name, GF_LOG_WARNING,
|
||||
"dict_unserialize failed (%s)", strerror(-ret));
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tmp1 = dict_copy(tmp2, tmp1);
|
||||
if (tmp1 == NULL) {
|
||||
gf_log(this->name, GF_LOG_WARNING, "dict_copy failed (%s)",
|
||||
strerror(-ret));
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
len = dict_serialized_length(tmp1);
|
||||
if (len > 0) {
|
||||
buf = GF_CALLOC(1, len, gf_common_mt_dict_t);
|
||||
if (buf == NULL) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = dict_serialize(tmp1, buf);
|
||||
if (ret < 0) {
|
||||
gf_log(this->name, GF_LOG_WARNING, "dict_serialize failed (%s)",
|
||||
strerror(-ret));
|
||||
GF_FREE(buf);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
*xattr_serz = buf;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
if (tmp1 != NULL) {
|
||||
dict_unref(tmp1);
|
||||
}
|
||||
|
||||
if (tmp2 != NULL) {
|
||||
dict_unref(tmp2);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t
|
||||
stripe_fill_pathinfo_xattr(xlator_t *this, stripe_local_t *local,
|
||||
char **xattr_serz)
|
||||
{
|
||||
int ret = -1;
|
||||
int32_t padding = 0;
|
||||
int32_t tlen = 0;
|
||||
int len = 0;
|
||||
char stripe_size_str[20] = {
|
||||
0,
|
||||
};
|
||||
char *pathinfo_serz = NULL;
|
||||
|
||||
if (!local) {
|
||||
gf_log(this->name, GF_LOG_ERROR, "Possible NULL deref");
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = snprintf(stripe_size_str, sizeof(stripe_size_str), "%" PRId64,
|
||||
local->fctx ? local->fctx->stripe_size : 0);
|
||||
if (len < 0 || len >= sizeof(stripe_size_str))
|
||||
goto out;
|
||||
/* extra bytes for decorations (brackets and <>'s) */
|
||||
padding = strlen(this->name) + SLEN(STRIPE_PATHINFO_HEADER) + len + 7;
|
||||
local->xattr_total_len += (padding + 2);
|
||||
|
||||
pathinfo_serz = GF_MALLOC(local->xattr_total_len, gf_common_mt_char);
|
||||
if (!pathinfo_serz)
|
||||
goto out;
|
||||
|
||||
/* xlator info */
|
||||
(void)sprintf(pathinfo_serz, "(<" STRIPE_PATHINFO_HEADER "%s:[%s]> ",
|
||||
this->name, stripe_size_str);
|
||||
|
||||
ret = stripe_xattr_aggregate(pathinfo_serz + padding, local, &tlen);
|
||||
if (ret) {
|
||||
gf_log(this->name, GF_LOG_ERROR, "Cannot aggregate pathinfo list");
|
||||
GF_FREE(pathinfo_serz);
|
||||
goto out;
|
||||
}
|
||||
|
||||
*(pathinfo_serz + padding + tlen) = ')';
|
||||
*(pathinfo_serz + padding + tlen + 1) = '\0';
|
||||
|
||||
*xattr_serz = pathinfo_serz;
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* stripe_get_matching_bs - Get the matching block size for the given path.
|
||||
*/
|
||||
int32_t
|
||||
stripe_get_matching_bs(const char *path, stripe_private_t *priv)
|
||||
{
|
||||
struct stripe_options *trav = NULL;
|
||||
uint64_t block_size = 0;
|
||||
|
||||
GF_VALIDATE_OR_GOTO("stripe", priv, out);
|
||||
GF_VALIDATE_OR_GOTO("stripe", path, out);
|
||||
|
||||
LOCK(&priv->lock);
|
||||
{
|
||||
block_size = priv->block_size;
|
||||
trav = priv->pattern;
|
||||
while (trav) {
|
||||
if (!fnmatch(trav->path_pattern, path, FNM_NOESCAPE)) {
|
||||
block_size = trav->block_size;
|
||||
break;
|
||||
}
|
||||
trav = trav->next;
|
||||
}
|
||||
}
|
||||
UNLOCK(&priv->lock);
|
||||
|
||||
out:
|
||||
return block_size;
|
||||
}
|
||||
|
||||
int32_t
|
||||
stripe_ctx_handle(xlator_t *this, call_frame_t *prev, stripe_local_t *local,
|
||||
dict_t *dict)
|
||||
{
|
||||
char key[256] = {
|
||||
0,
|
||||
};
|
||||
data_t *data = NULL;
|
||||
int32_t index = 0;
|
||||
stripe_private_t *priv = NULL;
|
||||
|
||||
priv = this->private;
|
||||
|
||||
if (!local->fctx) {
|
||||
local->fctx = GF_CALLOC(1, sizeof(stripe_fd_ctx_t),
|
||||
gf_stripe_mt_stripe_fd_ctx_t);
|
||||
if (!local->fctx) {
|
||||
local->op_errno = ENOMEM;
|
||||
local->op_ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
local->fctx->static_array = 0;
|
||||
}
|
||||
/* Stripe block size */
|
||||
sprintf(key, "trusted.%s.stripe-size", this->name);
|
||||
data = dict_get(dict, key);
|
||||
if (!data) {
|
||||
local->xattr_self_heal_needed = 1;
|
||||
gf_log(this->name, GF_LOG_ERROR, "Failed to get stripe-size");
|
||||
goto out;
|
||||
} else {
|
||||
if (!local->fctx->stripe_size) {
|
||||
local->fctx->stripe_size = data_to_int64(data);
|
||||
}
|
||||
|
||||
if (local->fctx->stripe_size != data_to_int64(data)) {
|
||||
gf_log(this->name, GF_LOG_WARNING,
|
||||
"stripe-size mismatch in blocks");
|
||||
local->xattr_self_heal_needed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Stripe count */
|
||||
sprintf(key, "trusted.%s.stripe-count", this->name);
|
||||
data = dict_get(dict, key);
|
||||
|
||||
if (!data) {
|
||||
local->xattr_self_heal_needed = 1;
|
||||
gf_log(this->name, GF_LOG_ERROR, "Failed to get stripe-count");
|
||||
goto out;
|
||||
}
|
||||
if (!local->fctx->xl_array) {
|
||||
local->fctx->stripe_count = data_to_int32(data);
|
||||
if (!local->fctx->stripe_count) {
|
||||
gf_log(this->name, GF_LOG_ERROR, "error with stripe-count xattr");
|
||||
local->op_ret = -1;
|
||||
local->op_errno = EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
local->fctx->xl_array = GF_CALLOC(local->fctx->stripe_count,
|
||||
sizeof(xlator_t *),
|
||||
gf_stripe_mt_xlator_t);
|
||||
|
||||
if (!local->fctx->xl_array) {
|
||||
local->op_errno = ENOMEM;
|
||||
local->op_ret = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (local->fctx->stripe_count != data_to_int32(data)) {
|
||||
gf_log(this->name, GF_LOG_ERROR,
|
||||
"error with stripe-count xattr (%d != %d)",
|
||||
local->fctx->stripe_count, data_to_int32(data));
|
||||
local->op_ret = -1;
|
||||
local->op_errno = EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* index */
|
||||
sprintf(key, "trusted.%s.stripe-index", this->name);
|
||||
data = dict_get(dict, key);
|
||||
if (!data) {
|
||||
local->xattr_self_heal_needed = 1;
|
||||
gf_log(this->name, GF_LOG_ERROR, "Failed to get stripe-index");
|
||||
goto out;
|
||||
}
|
||||
index = data_to_int32(data);
|
||||
if (index > priv->child_count) {
|
||||
gf_log(this->name, GF_LOG_ERROR, "error with stripe-index xattr (%d)",
|
||||
index);
|
||||
local->op_ret = -1;
|
||||
local->op_errno = EIO;
|
||||
goto out;
|
||||
}
|
||||
if (local->fctx->xl_array) {
|
||||
if (!local->fctx->xl_array[index])
|
||||
local->fctx->xl_array[index] = prev->this;
|
||||
}
|
||||
|
||||
sprintf(key, "trusted.%s.stripe-coalesce", this->name);
|
||||
data = dict_get(dict, key);
|
||||
if (!data) {
|
||||
/*
|
||||
* The file was probably created prior to coalesce support.
|
||||
* Assume non-coalesce mode for this file to maintain backwards
|
||||
* compatibility.
|
||||
*/
|
||||
gf_log(this->name, GF_LOG_DEBUG,
|
||||
"missing stripe-coalesce "
|
||||
"attr, assume non-coalesce mode");
|
||||
local->fctx->stripe_coalesce = 0;
|
||||
} else {
|
||||
local->fctx->stripe_coalesce = data_to_int32(data);
|
||||
}
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
stripe_xattr_request_build(xlator_t *this, dict_t *dict, uint64_t stripe_size,
|
||||
uint32_t stripe_count, uint32_t stripe_index,
|
||||
uint32_t stripe_coalesce)
|
||||
{
|
||||
char key[256] = {
|
||||
0,
|
||||
};
|
||||
int32_t ret = -1;
|
||||
|
||||
sprintf(key, "trusted.%s.stripe-size", this->name);
|
||||
ret = dict_set_int64(dict, key, stripe_size);
|
||||
if (ret) {
|
||||
gf_log(this->name, GF_LOG_WARNING, "failed to set %s in xattr_req dict",
|
||||
key);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sprintf(key, "trusted.%s.stripe-count", this->name);
|
||||
ret = dict_set_int32(dict, key, stripe_count);
|
||||
if (ret) {
|
||||
gf_log(this->name, GF_LOG_WARNING, "failed to set %s in xattr_req dict",
|
||||
key);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sprintf(key, "trusted.%s.stripe-index", this->name);
|
||||
ret = dict_set_int32(dict, key, stripe_index);
|
||||
if (ret) {
|
||||
gf_log(this->name, GF_LOG_WARNING, "failed to set %s in xattr_req dict",
|
||||
key);
|
||||
goto out;
|
||||
}
|
||||
|
||||
sprintf(key, "trusted.%s.stripe-coalesce", this->name);
|
||||
ret = dict_set_int32(dict, key, stripe_coalesce);
|
||||
if (ret) {
|
||||
gf_log(this->name, GF_LOG_WARNING, "failed to set %s in xattr_req_dict",
|
||||
key);
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
set_default_block_size(stripe_private_t *priv, char *num)
|
||||
{
|
||||
int ret = -1;
|
||||
GF_VALIDATE_OR_GOTO("stripe", THIS, out);
|
||||
GF_VALIDATE_OR_GOTO(THIS->name, priv, out);
|
||||
GF_VALIDATE_OR_GOTO(THIS->name, num, out);
|
||||
|
||||
if (gf_string2bytesize_uint64(num, &priv->block_size) != 0) {
|
||||
gf_log(THIS->name, GF_LOG_ERROR, "invalid number format \"%s\"", num);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
set_stripe_block_size(xlator_t *this, stripe_private_t *priv, char *data)
|
||||
{
|
||||
int ret = -1;
|
||||
char *tmp_str = NULL;
|
||||
char *tmp_str1 = NULL;
|
||||
char *dup_str = NULL;
|
||||
char *stripe_str = NULL;
|
||||
char *pattern = NULL;
|
||||
char *num = NULL;
|
||||
struct stripe_options *temp_stripeopt = NULL;
|
||||
struct stripe_options *stripe_opt = NULL;
|
||||
|
||||
if (!this || !priv || !data)
|
||||
goto out;
|
||||
|
||||
/* Get the pattern for striping.
|
||||
"option block-size *avi:10MB" etc */
|
||||
stripe_str = strtok_r(data, ",", &tmp_str);
|
||||
while (stripe_str) {
|
||||
dup_str = gf_strdup(stripe_str);
|
||||
stripe_opt = GF_CALLOC(1, sizeof(struct stripe_options),
|
||||
gf_stripe_mt_stripe_options);
|
||||
if (!stripe_opt) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
pattern = strtok_r(dup_str, ":", &tmp_str1);
|
||||
num = strtok_r(NULL, ":", &tmp_str1);
|
||||
if (!num) {
|
||||
num = pattern;
|
||||
pattern = "*";
|
||||
ret = set_default_block_size(priv, num);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
if (gf_string2bytesize_uint64(num, &stripe_opt->block_size) != 0) {
|
||||
gf_log(this->name, GF_LOG_ERROR, "invalid number format \"%s\"",
|
||||
num);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (stripe_opt->block_size < STRIPE_MIN_BLOCK_SIZE) {
|
||||
gf_log(this->name, GF_LOG_ERROR,
|
||||
"Invalid Block-size: "
|
||||
"%s. Should be at least %llu bytes",
|
||||
num, STRIPE_MIN_BLOCK_SIZE);
|
||||
goto out;
|
||||
}
|
||||
if (stripe_opt->block_size % 512) {
|
||||
gf_log(this->name, GF_LOG_ERROR,
|
||||
"Block-size: %s should"
|
||||
" be a multiple of 512 bytes",
|
||||
num);
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(stripe_opt->path_pattern, pattern, strlen(pattern));
|
||||
|
||||
gf_log(this->name, GF_LOG_DEBUG,
|
||||
"block-size : pattern %s : size %" PRId64,
|
||||
stripe_opt->path_pattern, stripe_opt->block_size);
|
||||
|
||||
if (priv->pattern)
|
||||
temp_stripeopt = NULL;
|
||||
else
|
||||
temp_stripeopt = priv->pattern;
|
||||
|
||||
stripe_opt->next = temp_stripeopt;
|
||||
|
||||
priv->pattern = stripe_opt;
|
||||
stripe_opt = NULL;
|
||||
|
||||
GF_FREE(dup_str);
|
||||
dup_str = NULL;
|
||||
|
||||
stripe_str = strtok_r(NULL, ",", &tmp_str);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
|
||||
GF_FREE(dup_str);
|
||||
|
||||
GF_FREE(stripe_opt);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t
|
||||
stripe_iatt_merge(struct iatt *from, struct iatt *to)
|
||||
{
|
||||
if (to->ia_size < from->ia_size)
|
||||
to->ia_size = from->ia_size;
|
||||
if (to->ia_mtime < from->ia_mtime)
|
||||
to->ia_mtime = from->ia_mtime;
|
||||
if (to->ia_ctime < from->ia_ctime)
|
||||
to->ia_ctime = from->ia_ctime;
|
||||
if (to->ia_atime < from->ia_atime)
|
||||
to->ia_atime = from->ia_atime;
|
||||
return 0;
|
||||
}
|
||||
|
||||
off_t
|
||||
coalesced_offset(off_t offset, uint64_t stripe_size, int stripe_count)
|
||||
{
|
||||
size_t line_size = 0;
|
||||
uint64_t stripe_num = 0;
|
||||
off_t coalesced_offset = 0;
|
||||
|
||||
line_size = stripe_size * stripe_count;
|
||||
stripe_num = offset / line_size;
|
||||
|
||||
coalesced_offset = (stripe_num * stripe_size) + (offset % stripe_size);
|
||||
|
||||
return coalesced_offset;
|
||||
}
|
||||
|
||||
off_t
|
||||
uncoalesced_size(off_t size, uint64_t stripe_size, int stripe_count,
|
||||
int stripe_index)
|
||||
{
|
||||
uint64_t nr_full_stripe_chunks = 0, mod = 0;
|
||||
|
||||
if (!size)
|
||||
return size;
|
||||
|
||||
/*
|
||||
* Estimate the number of fully written stripes from the
|
||||
* local file size. Each stripe_size chunk corresponds to
|
||||
* a stripe.
|
||||
*/
|
||||
nr_full_stripe_chunks = (size / stripe_size) * stripe_count;
|
||||
mod = size % stripe_size;
|
||||
|
||||
if (!mod) {
|
||||
/*
|
||||
* There is no remainder, thus we could have overestimated
|
||||
* the size of the file in terms of chunks. Trim the number
|
||||
* of chunks by the following stripe members and leave it
|
||||
* up to those nodes to respond with a larger size (if
|
||||
* necessary).
|
||||
*/
|
||||
nr_full_stripe_chunks -= stripe_count - (stripe_index + 1);
|
||||
size = nr_full_stripe_chunks * stripe_size;
|
||||
} else {
|
||||
/*
|
||||
* There is a remainder and thus we own the last chunk of the
|
||||
* file. Add the preceding stripe members of the final stripe
|
||||
* along with the remainder to calculate the exact size.
|
||||
*/
|
||||
nr_full_stripe_chunks += stripe_index;
|
||||
size = nr_full_stripe_chunks * stripe_size + mod;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2008-2012 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 __STRIPE_MEM_TYPES_H__
|
||||
#define __STRIPE_MEM_TYPES_H__
|
||||
|
||||
#include <glusterfs/mem-types.h>
|
||||
|
||||
enum gf_stripe_mem_types_ {
|
||||
gf_stripe_mt_iovec = gf_common_mt_end + 1,
|
||||
gf_stripe_mt_stripe_replies,
|
||||
gf_stripe_mt_stripe_fd_ctx_t,
|
||||
gf_stripe_mt_char,
|
||||
gf_stripe_mt_int8_t,
|
||||
gf_stripe_mt_int32_t,
|
||||
gf_stripe_mt_xlator_t,
|
||||
gf_stripe_mt_stripe_private_t,
|
||||
gf_stripe_mt_stripe_options,
|
||||
gf_stripe_mt_xattr_sort_t,
|
||||
gf_stripe_mt_end
|
||||
};
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,291 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2008-2012 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 _STRIPE_H_
|
||||
#define _STRIPE_H_
|
||||
|
||||
#include <glusterfs/xlator.h>
|
||||
#include <glusterfs/logging.h>
|
||||
#include <glusterfs/defaults.h>
|
||||
#include <glusterfs/common-utils.h>
|
||||
#include <glusterfs/compat.h>
|
||||
#include <glusterfs/compat-errno.h>
|
||||
#include "stripe-mem-types.h"
|
||||
#include "libxlator.h"
|
||||
#include <fnmatch.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define STRIPE_PATHINFO_HEADER "STRIPE:"
|
||||
#define STRIPE_MIN_BLOCK_SIZE (16 * GF_UNIT_KB)
|
||||
|
||||
#define STRIPE_STACK_UNWIND(fop, frame, params...) \
|
||||
do { \
|
||||
stripe_local_t *__local = NULL; \
|
||||
if (frame) { \
|
||||
__local = frame->local; \
|
||||
frame->local = NULL; \
|
||||
} \
|
||||
STACK_UNWIND_STRICT(fop, frame, params); \
|
||||
if (__local) { \
|
||||
stripe_local_wipe(__local); \
|
||||
mem_put(__local); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define STRIPE_STACK_DESTROY(frame) \
|
||||
do { \
|
||||
stripe_local_t *__local = NULL; \
|
||||
__local = frame->local; \
|
||||
frame->local = NULL; \
|
||||
STACK_DESTROY(frame->root); \
|
||||
if (__local) { \
|
||||
stripe_local_wipe(__local); \
|
||||
mem_put(__local); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define STRIPE_VALIDATE_FCTX(fctx, label) \
|
||||
do { \
|
||||
int idx = 0; \
|
||||
if (!fctx) { \
|
||||
op_errno = EINVAL; \
|
||||
goto label; \
|
||||
} \
|
||||
for (idx = 0; idx < fctx->stripe_count; idx++) { \
|
||||
if (!fctx->xl_array[idx]) { \
|
||||
gf_log(this->name, GF_LOG_ERROR, "fctx->xl_array[%d] is NULL", \
|
||||
idx); \
|
||||
op_errno = ESTALE; \
|
||||
goto label; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
typedef struct stripe_xattr_sort {
|
||||
int pos;
|
||||
int xattr_len;
|
||||
char *xattr_value;
|
||||
} stripe_xattr_sort_t;
|
||||
|
||||
/**
|
||||
* struct stripe_options : This keeps the pattern and the block-size
|
||||
* information, which is used for striping on a file.
|
||||
*/
|
||||
struct stripe_options {
|
||||
struct stripe_options *next;
|
||||
char path_pattern[256];
|
||||
uint64_t block_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* Private structure for stripe translator
|
||||
*/
|
||||
struct stripe_private {
|
||||
struct stripe_options *pattern;
|
||||
xlator_t **xl_array;
|
||||
uint64_t block_size;
|
||||
gf_lock_t lock;
|
||||
uint8_t nodes_down;
|
||||
int8_t first_child_down;
|
||||
int *last_event;
|
||||
int8_t child_count;
|
||||
gf_boolean_t xattr_supported; /* default yes */
|
||||
gf_boolean_t coalesce;
|
||||
char vol_uuid[UUID_SIZE + 1];
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to keep info about the replies received from readv/writev calls
|
||||
*/
|
||||
struct stripe_replies {
|
||||
struct iovec *vector;
|
||||
int32_t count; // count of vector
|
||||
int32_t op_ret; // op_ret of readv
|
||||
int32_t op_errno;
|
||||
int32_t requested_size;
|
||||
struct iatt stbuf; /* 'stbuf' is also a part of reply */
|
||||
};
|
||||
|
||||
typedef struct _stripe_fd_ctx {
|
||||
off_t stripe_size;
|
||||
int stripe_count;
|
||||
int stripe_coalesce;
|
||||
int static_array;
|
||||
xlator_t **xl_array;
|
||||
} stripe_fd_ctx_t;
|
||||
|
||||
/**
|
||||
* Local structure to be passed with all the frames in case of STACK_WIND
|
||||
*/
|
||||
struct stripe_local; /* this itself is used inside the structure; */
|
||||
|
||||
struct stripe_local {
|
||||
struct stripe_local *next;
|
||||
call_frame_t *orig_frame;
|
||||
|
||||
stripe_fd_ctx_t *fctx;
|
||||
|
||||
/* Used by _cbk functions */
|
||||
struct iatt stbuf;
|
||||
struct iatt pre_buf;
|
||||
struct iatt post_buf;
|
||||
struct iatt preparent;
|
||||
struct iatt postparent;
|
||||
|
||||
off_t stbuf_size;
|
||||
off_t prebuf_size;
|
||||
off_t postbuf_size;
|
||||
off_t preparent_size;
|
||||
off_t postparent_size;
|
||||
|
||||
blkcnt_t stbuf_blocks;
|
||||
blkcnt_t prebuf_blocks;
|
||||
blkcnt_t postbuf_blocks;
|
||||
blkcnt_t preparent_blocks;
|
||||
blkcnt_t postparent_blocks;
|
||||
|
||||
struct stripe_replies *replies;
|
||||
struct statvfs statvfs_buf;
|
||||
dir_entry_t *entry;
|
||||
|
||||
int8_t revalidate;
|
||||
int8_t failed;
|
||||
int8_t unwind;
|
||||
|
||||
size_t readv_size;
|
||||
int32_t entry_count;
|
||||
int32_t node_index;
|
||||
int32_t call_count;
|
||||
int32_t wind_count; /* used instead of child_cound
|
||||
in case of read and write */
|
||||
int32_t op_ret;
|
||||
int32_t op_errno;
|
||||
int32_t count;
|
||||
int32_t flags;
|
||||
char *name;
|
||||
inode_t *inode;
|
||||
|
||||
loc_t loc;
|
||||
loc_t loc2;
|
||||
|
||||
mode_t mode;
|
||||
dev_t rdev;
|
||||
/* For File I/O fops */
|
||||
dict_t *xdata;
|
||||
|
||||
stripe_xattr_sort_t *xattr_list;
|
||||
int32_t xattr_total_len;
|
||||
int32_t nallocs;
|
||||
char xsel[256];
|
||||
|
||||
/* General usage */
|
||||
off_t offset;
|
||||
off_t stripe_size;
|
||||
|
||||
int xattr_self_heal_needed;
|
||||
int entry_self_heal_needed;
|
||||
|
||||
int8_t *list;
|
||||
struct gf_flock lock;
|
||||
fd_t *fd;
|
||||
void *value;
|
||||
struct iobref *iobref;
|
||||
gf_dirent_t entries;
|
||||
gf_dirent_t *dirent;
|
||||
dict_t *xattr;
|
||||
uuid_t ia_gfid;
|
||||
|
||||
int xflag;
|
||||
mode_t umask;
|
||||
};
|
||||
|
||||
typedef struct stripe_local stripe_local_t;
|
||||
typedef struct stripe_private stripe_private_t;
|
||||
|
||||
/*
|
||||
* Determine the stripe index of a particular frame based on the translator.
|
||||
*/
|
||||
static inline int32_t
|
||||
stripe_get_frame_index(stripe_fd_ctx_t *fctx, call_frame_t *prev)
|
||||
{
|
||||
int32_t i, idx = -1;
|
||||
|
||||
for (i = 0; i < fctx->stripe_count; i++) {
|
||||
if (fctx->xl_array[i] == prev->this) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
static inline void
|
||||
stripe_copy_xl_array(xlator_t **dst, xlator_t **src, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
dst[i] = src[i];
|
||||
}
|
||||
|
||||
void
|
||||
stripe_local_wipe(stripe_local_t *local);
|
||||
int32_t
|
||||
stripe_ctx_handle(xlator_t *this, call_frame_t *prev, stripe_local_t *local,
|
||||
dict_t *dict);
|
||||
void
|
||||
stripe_aggregate_xattr(dict_t *dst, dict_t *src);
|
||||
int32_t
|
||||
stripe_xattr_request_build(xlator_t *this, dict_t *dict, uint64_t stripe_size,
|
||||
uint32_t stripe_count, uint32_t stripe_index,
|
||||
uint32_t stripe_coalesce);
|
||||
int32_t
|
||||
stripe_get_matching_bs(const char *path, stripe_private_t *priv);
|
||||
int
|
||||
set_stripe_block_size(xlator_t *this, stripe_private_t *priv, char *data);
|
||||
int32_t
|
||||
stripe_iatt_merge(struct iatt *from, struct iatt *to);
|
||||
int32_t
|
||||
stripe_fill_pathinfo_xattr(xlator_t *this, stripe_local_t *local,
|
||||
char **xattr_serz);
|
||||
int32_t
|
||||
stripe_free_xattr_str(stripe_local_t *local);
|
||||
int32_t
|
||||
stripe_xattr_aggregate(char *buffer, stripe_local_t *local, int32_t *total);
|
||||
off_t
|
||||
coalesced_offset(off_t offset, uint64_t stripe_size, int stripe_count);
|
||||
off_t
|
||||
uncoalesced_size(off_t size, uint64_t stripe_size, int stripe_count,
|
||||
int stripe_index);
|
||||
int32_t
|
||||
stripe_fill_lockinfo_xattr(xlator_t *this, stripe_local_t *local,
|
||||
void **xattr_serz);
|
||||
|
||||
/*
|
||||
* Adjust the size attribute for files if coalesce is enabled.
|
||||
*/
|
||||
static inline void
|
||||
correct_file_size(struct iatt *buf, stripe_fd_ctx_t *fctx, call_frame_t *prev)
|
||||
{
|
||||
int index;
|
||||
|
||||
if (!IA_ISREG(buf->ia_type))
|
||||
return;
|
||||
|
||||
if (!fctx || !fctx->stripe_coalesce)
|
||||
return;
|
||||
|
||||
index = stripe_get_frame_index(fctx, prev);
|
||||
buf->ia_size = uncoalesced_size(buf->ia_size, fctx->stripe_size,
|
||||
fctx->stripe_count, index);
|
||||
}
|
||||
|
||||
#endif /* _STRIPE_H_ */
|
@ -1,3 +0,0 @@
|
||||
SUBDIRS = rot-13 crypt
|
||||
|
||||
CLEANFILES =
|
@ -1,3 +0,0 @@
|
||||
SUBDIRS = src
|
||||
|
||||
CLEANFILES =
|
@ -1,26 +0,0 @@
|
||||
if ENABLE_CRYPT_XLATOR
|
||||
|
||||
xlator_LTLIBRARIES = crypt.la
|
||||
xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/encryption
|
||||
|
||||
crypt_la_LDFLAGS = -module $(GF_XLATOR_DEFAULT_LDFLAGS)
|
||||
|
||||
crypt_la_SOURCES = keys.c data.c metadata.c atom.c crypt.c
|
||||
crypt_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la \
|
||||
-lssl -lcrypto
|
||||
|
||||
noinst_HEADERS = crypt-common.h crypt-mem-types.h crypt.h metadata.h
|
||||
|
||||
AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \
|
||||
-I$(top_srcdir)/rpc/xdr/src -I$(top_builddir)/rpc/xdr/src
|
||||
|
||||
AM_CFLAGS = -Wall $(GF_CFLAGS)
|
||||
|
||||
CLEANFILES =
|
||||
|
||||
else
|
||||
|
||||
noinst_DIST = keys.c data.c metadata.c atom.c crypt.c
|
||||
noinst_HEADERS = crypt-common.h crypt-mem-types.h crypt.h metadata.h
|
||||
|
||||
endif
|
@ -1,861 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2008-2013 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.
|
||||
*/
|
||||
|
||||
#include <glusterfs/defaults.h>
|
||||
#include "crypt-common.h"
|
||||
#include "crypt.h"
|
||||
|
||||
/*
|
||||
* Glossary
|
||||
*
|
||||
*
|
||||
* cblock (or cipher block). A logical unit in a file.
|
||||
* cblock size is defined as the number of bits
|
||||
* in an input (or output) block of the block
|
||||
* cipher (*). Cipher block size is a property of
|
||||
* cipher algorithm. E.g. cblock size is 64 bits
|
||||
* for DES, 128 bits for AES, etc.
|
||||
*
|
||||
* atomic cipher A cipher algorithm, which requires some chunks of
|
||||
* algorithm text to be padded at left and(or) right sides before
|
||||
* cipher transaform.
|
||||
*
|
||||
*
|
||||
* block (atom) Minimal chunk of file's data, which doesn't require
|
||||
* padding. We'll consider logical units in a file of
|
||||
* block size (atom size).
|
||||
*
|
||||
* cipher algorithm Atomic cipher algorithm, which requires the last
|
||||
* with EOF issue incomplete cblock in a file to be padded with some
|
||||
* data (usually zeros).
|
||||
*
|
||||
*
|
||||
* operation, which reading/writing from offset, which is not aligned to
|
||||
* forms a gap at to atom size
|
||||
* the beginning
|
||||
*
|
||||
*
|
||||
* operation, which reading/writing count bytes starting from offset off,
|
||||
* forms a gap at so that off+count is not aligned to atom_size
|
||||
* the end
|
||||
*
|
||||
* head block the first atom affected by an operation, which forms
|
||||
* a gap at the beginning, or(and) at the end.
|
||||
* Сomment. Head block has at least one gap (either at
|
||||
* the beginning, or at the end)
|
||||
*
|
||||
*
|
||||
* tail block the last atom different from head, affected by an
|
||||
* operation, which forms a gap at the end.
|
||||
* Сomment: Tail block has exactly one gap (at the end).
|
||||
*
|
||||
*
|
||||
* partial block head or tail block
|
||||
*
|
||||
*
|
||||
* full block block without gaps.
|
||||
*
|
||||
*
|
||||
* (*) Recommendation for Block Cipher Modes of Operation
|
||||
* Methods and Techniques
|
||||
* NIST Special Publication 800-38A Edition 2001
|
||||
*/
|
||||
|
||||
/*
|
||||
* atom->offset_at()
|
||||
*/
|
||||
static off_t
|
||||
offset_at_head(struct avec_config *conf)
|
||||
{
|
||||
return conf->aligned_offset;
|
||||
}
|
||||
|
||||
static off_t
|
||||
offset_at_hole_head(call_frame_t *frame, struct object_cipher_info *object)
|
||||
{
|
||||
return offset_at_head(get_hole_conf(frame));
|
||||
}
|
||||
|
||||
static off_t
|
||||
offset_at_data_head(call_frame_t *frame, struct object_cipher_info *object)
|
||||
{
|
||||
return offset_at_head(get_data_conf(frame));
|
||||
}
|
||||
|
||||
static off_t
|
||||
offset_at_tail(struct avec_config *conf, struct object_cipher_info *object)
|
||||
{
|
||||
return conf->aligned_offset +
|
||||
(conf->off_in_head ? get_atom_size(object) : 0) +
|
||||
(conf->nr_full_blocks << get_atom_bits(object));
|
||||
}
|
||||
|
||||
static off_t
|
||||
offset_at_hole_tail(call_frame_t *frame, struct object_cipher_info *object)
|
||||
{
|
||||
return offset_at_tail(get_hole_conf(frame), object);
|
||||
}
|
||||
|
||||
static off_t
|
||||
offset_at_data_tail(call_frame_t *frame, struct object_cipher_info *object)
|
||||
{
|
||||
return offset_at_tail(get_data_conf(frame), object);
|
||||
}
|
||||
|
||||
static off_t
|
||||
offset_at_full(struct avec_config *conf, struct object_cipher_info *object)
|
||||
{
|
||||
return conf->aligned_offset +
|
||||
(conf->off_in_head ? get_atom_size(object) : 0);
|
||||
}
|
||||
|
||||
static off_t
|
||||
offset_at_data_full(call_frame_t *frame, struct object_cipher_info *object)
|
||||
{
|
||||
return offset_at_full(get_data_conf(frame), object);
|
||||
}
|
||||
|
||||
static off_t
|
||||
offset_at_hole_full(call_frame_t *frame, struct object_cipher_info *object)
|
||||
{
|
||||
return offset_at_full(get_hole_conf(frame), object);
|
||||
}
|
||||
|
||||
/*
|
||||
* atom->io_size_nopad()
|
||||
*/
|
||||
|
||||
static uint32_t
|
||||
io_size_nopad_head(struct avec_config *conf, struct object_cipher_info *object)
|
||||
{
|
||||
uint32_t gap_at_beg;
|
||||
uint32_t gap_at_end;
|
||||
|
||||
check_head_block(conf);
|
||||
|
||||
gap_at_beg = conf->off_in_head;
|
||||
|
||||
if (has_tail_block(conf) || has_full_blocks(conf) || conf->off_in_tail == 0)
|
||||
gap_at_end = 0;
|
||||
else
|
||||
gap_at_end = get_atom_size(object) - conf->off_in_tail;
|
||||
|
||||
return get_atom_size(object) - (gap_at_beg + gap_at_end);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
io_size_nopad_tail(struct avec_config *conf, struct object_cipher_info *object)
|
||||
{
|
||||
check_tail_block(conf);
|
||||
return conf->off_in_tail;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
io_size_nopad_full(struct avec_config *conf, struct object_cipher_info *object)
|
||||
{
|
||||
check_full_block(conf);
|
||||
return get_atom_size(object);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
io_size_nopad_data_head(call_frame_t *frame, struct object_cipher_info *object)
|
||||
{
|
||||
return io_size_nopad_head(get_data_conf(frame), object);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
io_size_nopad_hole_head(call_frame_t *frame, struct object_cipher_info *object)
|
||||
{
|
||||
return io_size_nopad_head(get_hole_conf(frame), object);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
io_size_nopad_data_tail(call_frame_t *frame, struct object_cipher_info *object)
|
||||
{
|
||||
return io_size_nopad_tail(get_data_conf(frame), object);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
io_size_nopad_hole_tail(call_frame_t *frame, struct object_cipher_info *object)
|
||||
{
|
||||
return io_size_nopad_tail(get_hole_conf(frame), object);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
io_size_nopad_data_full(call_frame_t *frame, struct object_cipher_info *object)
|
||||
{
|
||||
return io_size_nopad_full(get_data_conf(frame), object);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
io_size_nopad_hole_full(call_frame_t *frame, struct object_cipher_info *object)
|
||||
{
|
||||
return io_size_nopad_full(get_hole_conf(frame), object);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
offset_in_head(struct avec_config *conf)
|
||||
{
|
||||
check_cursor_head(conf);
|
||||
|
||||
return conf->off_in_head;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
offset_in_tail(call_frame_t *frame, struct object_cipher_info *object)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
offset_in_full(struct avec_config *conf, struct object_cipher_info *object)
|
||||
{
|
||||
check_cursor_full(conf);
|
||||
|
||||
if (has_head_block(conf))
|
||||
return (conf->cursor - 1) << get_atom_bits(object);
|
||||
else
|
||||
return conf->cursor << get_atom_bits(object);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
offset_in_data_head(call_frame_t *frame, struct object_cipher_info *object)
|
||||
{
|
||||
return offset_in_head(get_data_conf(frame));
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
offset_in_hole_head(call_frame_t *frame, struct object_cipher_info *object)
|
||||
{
|
||||
return offset_in_head(get_hole_conf(frame));
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
offset_in_data_full(call_frame_t *frame, struct object_cipher_info *object)
|
||||
{
|
||||
return offset_in_full(get_data_conf(frame), object);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
offset_in_hole_full(call_frame_t *frame, struct object_cipher_info *object)
|
||||
{
|
||||
return offset_in_full(get_hole_conf(frame), object);
|
||||
}
|
||||
|
||||
/*
|
||||
* atom->rmw()
|
||||
*/
|
||||
/*
|
||||
* Pre-conditions:
|
||||
* @vec contains plain text of the latest
|
||||
* version.
|
||||
*
|
||||
* Uptodate gaps of the @partial block with
|
||||
* this plain text, encrypt the whole block
|
||||
* and write the result to disk.
|
||||
*/
|
||||
static int32_t
|
||||
rmw_partial_block(call_frame_t *frame, void *cookie, xlator_t *this,
|
||||
int32_t op_ret, int32_t op_errno, struct iovec *vec,
|
||||
int32_t count, struct iatt *stbuf, struct iobref *iobref,
|
||||
struct rmw_atom *atom)
|
||||
{
|
||||
size_t was_read = 0;
|
||||
uint64_t file_size;
|
||||
crypt_local_t *local = frame->local;
|
||||
struct object_cipher_info *object = &local->info->cinfo;
|
||||
|
||||
struct iovec *partial = atom->get_iovec(frame, 0);
|
||||
struct avec_config *conf = atom->get_config(frame);
|
||||
end_writeback_handler_t end_writeback_partial_block;
|
||||
#if DEBUG_CRYPT
|
||||
gf_boolean_t check_last_cblock = _gf_false;
|
||||
#endif
|
||||
local->op_ret = op_ret;
|
||||
local->op_errno = op_errno;
|
||||
|
||||
if (op_ret < 0)
|
||||
goto exit;
|
||||
|
||||
file_size = local->cur_file_size;
|
||||
was_read = op_ret;
|
||||
|
||||
if (atom->locality == HEAD_ATOM && conf->off_in_head) {
|
||||
/*
|
||||
* head atom with a non-uptodate gap
|
||||
* at the beginning
|
||||
*
|
||||
* fill the gap with plain text of the
|
||||
* latest version. Convert a part of hole
|
||||
* (if any) to zeros.
|
||||
*/
|
||||
int32_t i;
|
||||
int32_t copied = 0;
|
||||
int32_t to_gap; /* amount of data needed to uptodate
|
||||
the gap at the beginning */
|
||||
#if 0
|
||||
int32_t hole = 0; /* The part of the hole which
|
||||
* got in the head block */
|
||||
#endif /* 0 */
|
||||
to_gap = conf->off_in_head;
|
||||
|
||||
if (was_read < to_gap) {
|
||||
if (file_size > offset_at_head(conf) + was_read) {
|
||||
/*
|
||||
* It is impossible to uptodate
|
||||
* head block: too few bytes have
|
||||
* been read from disk, so that
|
||||
* partial write is impossible.
|
||||
*
|
||||
* It could happen because of many
|
||||
* reasons: IO errors, (meta)data
|
||||
* corruption in the local file system,
|
||||
* etc.
|
||||
*/
|
||||
gf_log(this->name, GF_LOG_WARNING,
|
||||
"Can not uptodate a gap at the beginning");
|
||||
local->op_ret = -1;
|
||||
local->op_errno = EIO;
|
||||
goto exit;
|
||||
}
|
||||
#if 0
|
||||
hole = to_gap - was_read;
|
||||
#endif /* 0 */
|
||||
to_gap = was_read;
|
||||
}
|
||||
/*
|
||||
* uptodate the gap at the beginning
|
||||
*/
|
||||
for (i = 0; i < count && copied < to_gap; i++) {
|
||||
int32_t to_copy;
|
||||
|
||||
to_copy = vec[i].iov_len;
|
||||
if (to_copy > to_gap - copied)
|
||||
to_copy = to_gap - copied;
|
||||
|
||||
memcpy(partial->iov_base, vec[i].iov_base, to_copy);
|
||||
copied += to_copy;
|
||||
}
|
||||
#if 0
|
||||
/*
|
||||
* If possible, convert part of the
|
||||
* hole, which got in the head block
|
||||
*/
|
||||
ret = TRY_LOCK(&local->hole_lock);
|
||||
if (!ret) {
|
||||
if (local->hole_handled)
|
||||
/*
|
||||
* already converted by
|
||||
* crypt_writev_cbk()
|
||||
*/
|
||||
UNLOCK(&local->hole_lock);
|
||||
else {
|
||||
/*
|
||||
* convert the part of the hole
|
||||
* which got in the head block
|
||||
* to zeros.
|
||||
*
|
||||
* Update the orig_offset to make
|
||||
* sure writev_cbk() won't care
|
||||
* about this part of the hole.
|
||||
*
|
||||
*/
|
||||
memset(partial->iov_base + to_gap, 0, hole);
|
||||
|
||||
conf->orig_offset -= hole;
|
||||
conf->orig_size += hole;
|
||||
UNLOCK(&local->hole_lock);
|
||||
}
|
||||
}
|
||||
else /*
|
||||
* conversion is being performed
|
||||
* by crypt_writev_cbk()
|
||||
*/
|
||||
;
|
||||
#endif /* 0 */
|
||||
}
|
||||
if (atom->locality == TAIL_ATOM ||
|
||||
(!has_tail_block(conf) && conf->off_in_tail)) {
|
||||
/*
|
||||
* tail atom, or head atom with a non-uptodate
|
||||
* gap at the end.
|
||||
*
|
||||
* fill the gap at the end of the block
|
||||
* with plain text of the latest version.
|
||||
* Pad the result, (if needed)
|
||||
*/
|
||||
int32_t i;
|
||||
int32_t to_gap;
|
||||
int copied;
|
||||
off_t off_in_tail;
|
||||
int32_t to_copy;
|
||||
|
||||
off_in_tail = conf->off_in_tail;
|
||||
to_gap = conf->gap_in_tail;
|
||||
|
||||
if (to_gap && was_read < off_in_tail + to_gap) {
|
||||
/*
|
||||
* It is impossible to uptodate
|
||||
* the gap at the end: too few bytes
|
||||
* have been read from disk, so that
|
||||
* partial write is impossible.
|
||||
*
|
||||
* It could happen because of many
|
||||
* reasons: IO errors, (meta)data
|
||||
* corruption in the local file system,
|
||||
* etc.
|
||||
*/
|
||||
gf_log(this->name, GF_LOG_WARNING,
|
||||
"Can not uptodate a gap at the end");
|
||||
local->op_ret = -1;
|
||||
local->op_errno = EIO;
|
||||
goto exit;
|
||||
}
|
||||
/*
|
||||
* uptodate the gap at the end
|
||||
*/
|
||||
copied = 0;
|
||||
to_copy = to_gap;
|
||||
for (i = count - 1; i >= 0 && to_copy > 0; i--) {
|
||||
uint32_t from_vec, off_in_vec;
|
||||
|
||||
off_in_vec = 0;
|
||||
from_vec = vec[i].iov_len;
|
||||
if (from_vec > to_copy) {
|
||||
off_in_vec = from_vec - to_copy;
|
||||
from_vec = to_copy;
|
||||
}
|
||||
memcpy(partial->iov_base + off_in_tail + to_gap - copied - from_vec,
|
||||
vec[i].iov_base + off_in_vec, from_vec);
|
||||
|
||||
gf_log(
|
||||
this->name, GF_LOG_DEBUG,
|
||||
"uptodate %d bytes at tail. Offset at target(source): %d(%d)",
|
||||
(int)from_vec, (int)off_in_tail + to_gap - copied - from_vec,
|
||||
(int)off_in_vec);
|
||||
|
||||
copied += from_vec;
|
||||
to_copy -= from_vec;
|
||||
}
|
||||
partial->iov_len = off_in_tail + to_gap;
|
||||
|
||||
if (object_alg_should_pad(object)) {
|
||||
int32_t resid = 0;
|
||||
resid = partial->iov_len & (object_alg_blksize(object) - 1);
|
||||
if (resid) {
|
||||
/*
|
||||
* append a new EOF padding
|
||||
*/
|
||||
local->eof_padding_size = object_alg_blksize(object) - resid;
|
||||
|
||||
gf_log(this->name, GF_LOG_DEBUG, "set padding size %d",
|
||||
local->eof_padding_size);
|
||||
|
||||
memset(partial->iov_base + partial->iov_len, 1,
|
||||
local->eof_padding_size);
|
||||
partial->iov_len += local->eof_padding_size;
|
||||
#if DEBUG_CRYPT
|
||||
gf_log(this->name, GF_LOG_DEBUG,
|
||||
"pad cblock with %d zeros:", local->eof_padding_size);
|
||||
dump_cblock(this, (unsigned char *)partial->iov_base +
|
||||
partial->iov_len -
|
||||
object_alg_blksize(object));
|
||||
check_last_cblock = _gf_true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* encrypt the whole block
|
||||
*/
|
||||
encrypt_aligned_iov(object, partial, 1, atom->offset_at(frame, object));
|
||||
#if DEBUG_CRYPT
|
||||
if (check_last_cblock == _gf_true) {
|
||||
gf_log(this->name, GF_LOG_DEBUG, "encrypt last cblock with offset %llu",
|
||||
(unsigned long long)atom->offset_at(frame, object));
|
||||
dump_cblock(this, (unsigned char *)partial->iov_base +
|
||||
partial->iov_len - object_alg_blksize(object));
|
||||
}
|
||||
#endif
|
||||
set_local_io_params_writev(frame, object, atom,
|
||||
atom->offset_at(frame, object),
|
||||
iov_length(partial, 1));
|
||||
/*
|
||||
* write the whole block to disk
|
||||
*/
|
||||
end_writeback_partial_block = dispatch_end_writeback(local->fop);
|
||||
conf->cursor++;
|
||||
STACK_WIND(frame, end_writeback_partial_block, FIRST_CHILD(this),
|
||||
FIRST_CHILD(this)->fops->writev, local->fd, partial, 1,
|
||||
atom->offset_at(frame, object), local->flags, local->iobref_data,
|
||||
local->xdata);
|
||||
|
||||
gf_log("crypt", GF_LOG_DEBUG,
|
||||
"submit partial block: %d bytes from %d offset",
|
||||
(int)iov_length(partial, 1), (int)atom->offset_at(frame, object));
|
||||
exit:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a (read-)modify-write sequence.
|
||||
* This should be performed only after approval
|
||||
* of upper server-side manager, i.e. the caller
|
||||
* needs to make sure this is his turn to rmw.
|
||||
*/
|
||||
void
|
||||
submit_partial(call_frame_t *frame, xlator_t *this, fd_t *fd,
|
||||
atom_locality_type ltype)
|
||||
{
|
||||
int32_t ret;
|
||||
dict_t *dict;
|
||||
struct rmw_atom *atom;
|
||||
crypt_local_t *local = frame->local;
|
||||
struct object_cipher_info *object = &local->info->cinfo;
|
||||
|
||||
atom = atom_by_types(local->active_setup, ltype);
|
||||
/*
|
||||
* To perform the "read" component of the read-modify-write
|
||||
* sequence the crypt translator does stack_wind to itself.
|
||||
*
|
||||
* Pass current file size to crypt_readv()
|
||||
*/
|
||||
dict = dict_new();
|
||||
if (!dict) {
|
||||
/*
|
||||
* FIXME: Handle the error
|
||||
*/
|
||||
gf_log("crypt", GF_LOG_WARNING, "Can not alloc dict");
|
||||
return;
|
||||
}
|
||||
ret = dict_set(dict, FSIZE_XATTR_PREFIX,
|
||||
data_from_uint64(local->cur_file_size));
|
||||
if (ret) {
|
||||
/*
|
||||
* FIXME: Handle the error
|
||||
*/
|
||||
dict_unref(dict);
|
||||
gf_log("crypt", GF_LOG_WARNING, "Can not set dict");
|
||||
goto exit;
|
||||
}
|
||||
STACK_WIND(frame, atom->rmw, this, this->fops->readv, /* crypt_readv */
|
||||
fd, atom->count_to_uptodate(frame, object), /* count */
|
||||
atom->offset_at(frame, object), /* offset to read from */
|
||||
0, dict);
|
||||
exit:
|
||||
dict_unref(dict);
|
||||
}
|
||||
|
||||
/*
|
||||
* submit blocks of FULL_ATOM type
|
||||
*/
|
||||
void
|
||||
submit_full(call_frame_t *frame, xlator_t *this)
|
||||
{
|
||||
crypt_local_t *local = frame->local;
|
||||
struct object_cipher_info *object = &local->info->cinfo;
|
||||
struct rmw_atom *atom = atom_by_types(local->active_setup, FULL_ATOM);
|
||||
uint32_t count; /* total number of full blocks to submit */
|
||||
uint32_t granularity; /* number of blocks to submit in one iteration */
|
||||
|
||||
uint64_t off_in_file; /* start offset in the file, bytes */
|
||||
uint32_t off_in_atom; /* start offset in the atom, blocks */
|
||||
uint32_t blocks_written = 0; /* blocks written for this submit */
|
||||
|
||||
struct avec_config *conf = atom->get_config(frame);
|
||||
end_writeback_handler_t end_writeback_full_block;
|
||||
/*
|
||||
* Write full blocks by groups of granularity size.
|
||||
*/
|
||||
end_writeback_full_block = dispatch_end_writeback(local->fop);
|
||||
|
||||
if (is_ordered_mode(frame)) {
|
||||
uint32_t skip = has_head_block(conf) ? 1 : 0;
|
||||
count = 1;
|
||||
granularity = 1;
|
||||
/*
|
||||
* calculate start offset using cursor value;
|
||||
* here we should take into account head block,
|
||||
* which corresponds to cursor value 0.
|
||||
*/
|
||||
off_in_file = atom->offset_at(frame, object) +
|
||||
((conf->cursor - skip) << get_atom_bits(object));
|
||||
off_in_atom = conf->cursor - skip;
|
||||
} else {
|
||||
/*
|
||||
* in parallel mode
|
||||
*/
|
||||
count = conf->nr_full_blocks;
|
||||
granularity = MAX_IOVEC;
|
||||
off_in_file = atom->offset_at(frame, object);
|
||||
off_in_atom = 0;
|
||||
}
|
||||
while (count) {
|
||||
uint32_t blocks_to_write = count;
|
||||
|
||||
if (blocks_to_write > granularity)
|
||||
blocks_to_write = granularity;
|
||||
if (conf->type == HOLE_ATOM)
|
||||
/*
|
||||
* reset iovec before encryption
|
||||
*/
|
||||
memset(atom->get_iovec(frame, 0)->iov_base, 0,
|
||||
get_atom_size(object));
|
||||
/*
|
||||
* encrypt the group
|
||||
*/
|
||||
encrypt_aligned_iov(
|
||||
object, atom->get_iovec(frame, off_in_atom + blocks_written),
|
||||
blocks_to_write,
|
||||
off_in_file + (blocks_written << get_atom_bits(object)));
|
||||
|
||||
set_local_io_params_writev(
|
||||
frame, object, atom,
|
||||
off_in_file + (blocks_written << get_atom_bits(object)),
|
||||
blocks_to_write << get_atom_bits(object));
|
||||
|
||||
conf->cursor += blocks_to_write;
|
||||
|
||||
STACK_WIND(frame, end_writeback_full_block, FIRST_CHILD(this),
|
||||
FIRST_CHILD(this)->fops->writev, local->fd,
|
||||
atom->get_iovec(frame, off_in_atom + blocks_written),
|
||||
blocks_to_write,
|
||||
off_in_file + (blocks_written << get_atom_bits(object)),
|
||||
local->flags,
|
||||
local->iobref_data ? local->iobref_data : local->iobref,
|
||||
local->xdata);
|
||||
|
||||
gf_log("crypt", GF_LOG_DEBUG, "submit %d full blocks from %d offset",
|
||||
blocks_to_write,
|
||||
(int)(off_in_file + (blocks_written << get_atom_bits(object))));
|
||||
|
||||
count -= blocks_to_write;
|
||||
blocks_written += blocks_to_write;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
rmw_data_head(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
|
||||
int32_t op_errno, struct iovec *vec, int32_t count,
|
||||
struct iatt *stbuf, struct iobref *iobref, dict_t *xdata)
|
||||
{
|
||||
return rmw_partial_block(frame, cookie, this, op_ret, op_errno, vec, count,
|
||||
stbuf, iobref,
|
||||
atom_by_types(DATA_ATOM, HEAD_ATOM));
|
||||
}
|
||||
|
||||
static int32_t
|
||||
rmw_data_tail(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
|
||||
int32_t op_errno, struct iovec *vec, int32_t count,
|
||||
struct iatt *stbuf, struct iobref *iobref, dict_t *xdata)
|
||||
{
|
||||
return rmw_partial_block(frame, cookie, this, op_ret, op_errno, vec, count,
|
||||
stbuf, iobref,
|
||||
atom_by_types(DATA_ATOM, TAIL_ATOM));
|
||||
}
|
||||
|
||||
static int32_t
|
||||
rmw_hole_head(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
|
||||
int32_t op_errno, struct iovec *vec, int32_t count,
|
||||
struct iatt *stbuf, struct iobref *iobref, dict_t *xdata)
|
||||
{
|
||||
return rmw_partial_block(frame, cookie, this, op_ret, op_errno, vec, count,
|
||||
stbuf, iobref,
|
||||
atom_by_types(HOLE_ATOM, HEAD_ATOM));
|
||||
}
|
||||
|
||||
static int32_t
|
||||
rmw_hole_tail(call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret,
|
||||
int32_t op_errno, struct iovec *vec, int32_t count,
|
||||
struct iatt *stbuf, struct iobref *iobref, dict_t *xdata)
|
||||
{
|
||||
return rmw_partial_block(frame, cookie, this, op_ret, op_errno, vec, count,
|
||||
stbuf, iobref,
|
||||
atom_by_types(HOLE_ATOM, TAIL_ATOM));
|
||||
}
|
||||
|
||||
/*
|
||||
* atom->count_to_uptodate()
|
||||
*/
|
||||
static uint32_t
|
||||
count_to_uptodate_head(struct avec_config *conf,
|
||||
struct object_cipher_info *object)
|
||||
{
|
||||
if (conf->acount == 1 && conf->off_in_tail)
|
||||
return get_atom_size(object);
|
||||
else
|
||||
/* there is no need to read the whole head block */
|
||||
return conf->off_in_head;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
count_to_uptodate_tail(struct avec_config *conf,
|
||||
struct object_cipher_info *object)
|
||||
{
|
||||
/* we need to read the whole tail block */
|
||||
return get_atom_size(object);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
count_to_uptodate_data_head(call_frame_t *frame,
|
||||
struct object_cipher_info *object)
|
||||
{
|
||||
return count_to_uptodate_head(get_data_conf(frame), object);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
count_to_uptodate_data_tail(call_frame_t *frame,
|
||||
struct object_cipher_info *object)
|
||||
{
|
||||
return count_to_uptodate_tail(get_data_conf(frame), object);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
count_to_uptodate_hole_head(call_frame_t *frame,
|
||||
struct object_cipher_info *object)
|
||||
{
|
||||
return count_to_uptodate_head(get_hole_conf(frame), object);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
count_to_uptodate_hole_tail(call_frame_t *frame,
|
||||
struct object_cipher_info *object)
|
||||
{
|
||||
return count_to_uptodate_tail(get_hole_conf(frame), object);
|
||||
}
|
||||
|
||||
/* atom->get_config() */
|
||||
|
||||
static struct avec_config *
|
||||
get_config_data(call_frame_t *frame)
|
||||
{
|
||||
return &((crypt_local_t *)frame->local)->data_conf;
|
||||
}
|
||||
|
||||
static struct avec_config *
|
||||
get_config_hole(call_frame_t *frame)
|
||||
{
|
||||
return &((crypt_local_t *)frame->local)->hole_conf;
|
||||
}
|
||||
|
||||
/*
|
||||
* atom->get_iovec()
|
||||
*/
|
||||
static struct iovec *
|
||||
get_iovec_hole_head(call_frame_t *frame, uint32_t count)
|
||||
{
|
||||
struct avec_config *conf = get_hole_conf(frame);
|
||||
|
||||
return conf->avec;
|
||||
}
|
||||
|
||||
static struct iovec *
|
||||
get_iovec_hole_full(call_frame_t *frame, uint32_t count)
|
||||
{
|
||||
struct avec_config *conf = get_hole_conf(frame);
|
||||
|
||||
return conf->avec + (conf->off_in_head ? 1 : 0);
|
||||
}
|
||||
|
||||
static struct iovec *
|
||||
get_iovec_hole_tail(call_frame_t *frame, uint32_t count)
|
||||
{
|
||||
struct avec_config *conf = get_hole_conf(frame);
|
||||
|
||||
return conf->avec + (conf->blocks_in_pool - 1);
|
||||
}
|
||||
|
||||
static struct iovec *
|
||||
get_iovec_data_head(call_frame_t *frame, uint32_t count)
|
||||
{
|
||||
struct avec_config *conf = get_data_conf(frame);
|
||||
|
||||
return conf->avec;
|
||||
}
|
||||
|
||||
static struct iovec *
|
||||
get_iovec_data_full(call_frame_t *frame, uint32_t count)
|
||||
{
|
||||
struct avec_config *conf = get_data_conf(frame);
|
||||
|
||||
return conf->avec + (conf->off_in_head ? 1 : 0) + count;
|
||||
}
|
||||
|
||||
static struct iovec *
|
||||
get_iovec_data_tail(call_frame_t *frame, uint32_t count)
|
||||
{
|
||||
struct avec_config *conf = get_data_conf(frame);
|
||||
|
||||
return conf->avec + (conf->off_in_head ? 1 : 0) + conf->nr_full_blocks;
|
||||
}
|
||||
|
||||
static struct rmw_atom atoms[LAST_DATA_TYPE][LAST_LOCALITY_TYPE] = {
|
||||
[DATA_ATOM][HEAD_ATOM] = {.locality = HEAD_ATOM,
|
||||
.rmw = rmw_data_head,
|
||||
.offset_at = offset_at_data_head,
|
||||
.offset_in = offset_in_data_head,
|
||||
.get_iovec = get_iovec_data_head,
|
||||
.io_size_nopad = io_size_nopad_data_head,
|
||||
.count_to_uptodate = count_to_uptodate_data_head,
|
||||
.get_config = get_config_data},
|
||||
[DATA_ATOM][TAIL_ATOM] = {.locality = TAIL_ATOM,
|
||||
.rmw = rmw_data_tail,
|
||||
.offset_at = offset_at_data_tail,
|
||||
.offset_in = offset_in_tail,
|
||||
.get_iovec = get_iovec_data_tail,
|
||||
.io_size_nopad = io_size_nopad_data_tail,
|
||||
.count_to_uptodate = count_to_uptodate_data_tail,
|
||||
.get_config = get_config_data},
|
||||
[DATA_ATOM][FULL_ATOM] = {.locality = FULL_ATOM,
|
||||
.offset_at = offset_at_data_full,
|
||||
.offset_in = offset_in_data_full,
|
||||
.get_iovec = get_iovec_data_full,
|
||||
.io_size_nopad = io_size_nopad_data_full,
|
||||
.get_config = get_config_data},
|
||||
[HOLE_ATOM][HEAD_ATOM] = {.locality = HEAD_ATOM,
|
||||
.rmw = rmw_hole_head,
|
||||
.offset_at = offset_at_hole_head,
|
||||
.offset_in = offset_in_hole_head,
|
||||
.get_iovec = get_iovec_hole_head,
|
||||
.io_size_nopad = io_size_nopad_hole_head,
|
||||
.count_to_uptodate = count_to_uptodate_hole_head,
|
||||
.get_config = get_config_hole},
|
||||
[HOLE_ATOM][TAIL_ATOM] = {.locality = TAIL_ATOM,
|
||||
.rmw = rmw_hole_tail,
|
||||
.offset_at = offset_at_hole_tail,
|
||||
.offset_in = offset_in_tail,
|
||||
.get_iovec = get_iovec_hole_tail,
|
||||
.io_size_nopad = io_size_nopad_hole_tail,
|
||||
.count_to_uptodate = count_to_uptodate_hole_tail,
|
||||
.get_config = get_config_hole},
|
||||
[HOLE_ATOM][FULL_ATOM] = {.locality = FULL_ATOM,
|
||||
.offset_at = offset_at_hole_full,
|
||||
.offset_in = offset_in_hole_full,
|
||||
.get_iovec = get_iovec_hole_full,
|
||||
.io_size_nopad = io_size_nopad_hole_full,
|
||||
.get_config = get_config_hole}};
|
||||
|
||||
struct rmw_atom *
|
||||
atom_by_types(atom_data_type data, atom_locality_type locality)
|
||||
{
|
||||
return &atoms[data][locality];
|
||||
}
|
||||
|
||||
/*
|
||||
Local variables:
|
||||
c-indentation-style: "K&R"
|
||||
mode-name: "LC"
|
||||
c-basic-offset: 8
|
||||
tab-width: 8
|
||||
fill-column: 80
|
||||
scroll-step: 1
|
||||
End:
|
||||
*/
|
@ -1,133 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2008-2013 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 __CRYPT_COMMON_H__
|
||||
#define __CRYPT_COMMON_H__
|
||||
|
||||
#define INVAL_SUBVERSION_NUMBER (0xff)
|
||||
#define CRYPT_INVAL_OP (GF_FOP_NULL)
|
||||
|
||||
#define CRYPTO_FORMAT_PREFIX "trusted.glusterfs.crypt.att.cfmt"
|
||||
#define FSIZE_XATTR_PREFIX "trusted.glusterfs.crypt.att.size"
|
||||
#define SUBREQ_PREFIX "trusted.glusterfs.crypt.msg.sreq"
|
||||
#define FSIZE_MSG_PREFIX "trusted.glusterfs.crypt.msg.size"
|
||||
#define DE_MSG_PREFIX "trusted.glusterfs.crypt.msg.dent"
|
||||
#define REQUEST_ID_PREFIX "trusted.glusterfs.crypt.msg.rqid"
|
||||
#define MSGFLAGS_PREFIX "trusted.glusterfs.crypt.msg.xfgs"
|
||||
|
||||
/* messages for crypt_open() */
|
||||
#define MSGFLAGS_REQUEST_MTD_RLOCK 1 /* take read lock and don't unlock */
|
||||
#define MSGFLAGS_REQUEST_MTD_WLOCK 2 /* take write lock and don't unlock */
|
||||
|
||||
#define AES_BLOCK_BITS (4) /* AES_BLOCK_SIZE == 1 << AES_BLOCK_BITS */
|
||||
|
||||
#define noop \
|
||||
do { \
|
||||
; \
|
||||
} while (0)
|
||||
#define cassert(cond) \
|
||||
({ \
|
||||
switch (-1) { \
|
||||
case (cond): \
|
||||
case 0: \
|
||||
break; \
|
||||
} \
|
||||
})
|
||||
#define __round_mask(x, y) ((__typeof__(x))((y)-1))
|
||||
#define round_up(x, y) ((((x)-1) | __round_mask(x, y)) + 1)
|
||||
|
||||
/*
|
||||
* Format of file's metadata
|
||||
*/
|
||||
struct crypt_format {
|
||||
uint8_t loader_id; /* version of metadata loader */
|
||||
uint8_t versioned[0]; /* file's metadata of specific version */
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef enum { AES_CIPHER_ALG, LAST_CIPHER_ALG } cipher_alg_t;
|
||||
|
||||
typedef enum { XTS_CIPHER_MODE, LAST_CIPHER_MODE } cipher_mode_t;
|
||||
|
||||
typedef enum { MTD_LOADER_V1, LAST_MTD_LOADER } mtd_loader_id;
|
||||
|
||||
static inline void
|
||||
msgflags_set_mtd_rlock(uint32_t *flags)
|
||||
{
|
||||
*flags |= MSGFLAGS_REQUEST_MTD_RLOCK;
|
||||
}
|
||||
|
||||
static inline void
|
||||
msgflags_set_mtd_wlock(uint32_t *flags)
|
||||
{
|
||||
*flags |= MSGFLAGS_REQUEST_MTD_WLOCK;
|
||||
}
|
||||
|
||||
static inline gf_boolean_t
|
||||
msgflags_check_mtd_rlock(uint32_t *flags)
|
||||
{
|
||||
return *flags & MSGFLAGS_REQUEST_MTD_RLOCK;
|
||||
}
|
||||
|
||||
static inline gf_boolean_t
|
||||
msgflags_check_mtd_wlock(uint32_t *flags)
|
||||
{
|
||||
return *flags & MSGFLAGS_REQUEST_MTD_WLOCK;
|
||||
}
|
||||
|
||||
static inline gf_boolean_t
|
||||
msgflags_check_mtd_lock(uint32_t *flags)
|
||||
{
|
||||
return msgflags_check_mtd_rlock(flags) || msgflags_check_mtd_wlock(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* returns number of logical blocks occupied
|
||||
* (maybe partially) by @count bytes
|
||||
* at offset @start.
|
||||
*/
|
||||
static inline off_t
|
||||
logical_blocks_occupied(uint64_t start, off_t count, int blkbits)
|
||||
{
|
||||
return ((start + count - 1) >> blkbits) - (start >> blkbits) + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* are two bytes (represented by offsets @off1
|
||||
* and @off2 respectively) in the same logical
|
||||
* block.
|
||||
*/
|
||||
static inline int
|
||||
in_same_lblock(uint64_t off1, uint64_t off2, int blkbits)
|
||||
{
|
||||
return off1 >> blkbits == off2 >> blkbits;
|
||||
}
|
||||
|
||||
static inline void
|
||||
dump_cblock(xlator_t *this, unsigned char *buf)
|
||||
{
|
||||
gf_log(this->name, GF_LOG_DEBUG,
|
||||
"dump cblock: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
|
||||
(buf)[0], (buf)[1], (buf)[2], (buf)[3], (buf)[4], (buf)[5], (buf)[6],
|
||||
(buf)[7], (buf)[8], (buf)[9], (buf)[10], (buf)[11], (buf)[12],
|
||||
(buf)[13], (buf)[14], (buf)[15]);
|
||||
}
|
||||
|
||||
#endif /* __CRYPT_COMMON_H__ */
|
||||
|
||||
/*
|
||||
Local variables:
|
||||
c-indentation-style: "K&R"
|
||||
mode-name: "LC"
|
||||
c-basic-offset: 8
|
||||
tab-width: 8
|
||||
fill-column: 80
|
||||
scroll-step: 1
|
||||
End:
|
||||
*/
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2008-2013 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 __CRYPT_MEM_TYPES_H__
|
||||
#define __CRYPT_MEM_TYPES_H__
|
||||
|
||||
#include <glusterfs/mem-types.h>
|
||||
|
||||
enum gf_crypt_mem_types_ {
|
||||
gf_crypt_mt_priv = gf_common_mt_end + 1,
|
||||
gf_crypt_mt_inode,
|
||||
gf_crypt_mt_data,
|
||||
gf_crypt_mt_mtd,
|
||||
gf_crypt_mt_loc,
|
||||
gf_crypt_mt_iatt,
|
||||
gf_crypt_mt_key,
|
||||
gf_crypt_mt_iovec,
|
||||
gf_crypt_mt_char,
|
||||
gf_crypt_mt_local,
|
||||
gf_crypt_mt_end,
|
||||
};
|
||||
|
||||
#endif /* __CRYPT_MEM_TYPES_H__ */
|
||||
|
||||
/*
|
||||
Local variables:
|
||||
c-indentation-style: "K&R"
|
||||
mode-name: "LC"
|
||||
c-basic-offset: 8
|
||||
tab-width: 8
|
||||
fill-column: 80
|
||||
scroll-step: 1
|
||||
End:
|
||||
*/
|
File diff suppressed because it is too large
Load Diff
@ -1,931 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2008-2012 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 __CRYPT_H__
|
||||
#define __CRYPT_H__
|
||||
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/cmac.h>
|
||||
#include <openssl/modes.h>
|
||||
#include "crypt-mem-types.h"
|
||||
#include <glusterfs/compat.h>
|
||||
|
||||
#define CRYPT_XLATOR_ID (0)
|
||||
|
||||
#define MAX_IOVEC_BITS (3)
|
||||
#define MAX_IOVEC (1 << MAX_IOVEC_BITS)
|
||||
#define KEY_FACTOR_BITS (6)
|
||||
|
||||
#define DEBUG_CRYPT (0)
|
||||
#define TRIVIAL_TFM (0)
|
||||
|
||||
#define CRYPT_MIN_BLOCK_BITS (9)
|
||||
#define CRYPT_MAX_BLOCK_BITS (12)
|
||||
|
||||
#define MASTER_VOL_KEY_SIZE (32)
|
||||
#define NMTD_VOL_KEY_SIZE (16)
|
||||
|
||||
#if !defined(GF_LINUX_HOST_OS)
|
||||
typedef off_t loff_t;
|
||||
#endif
|
||||
|
||||
struct crypt_key {
|
||||
uint32_t len;
|
||||
const char *label;
|
||||
};
|
||||
|
||||
/*
|
||||
* Add new key types to the end of this
|
||||
* enumeration but before LAST_KEY_TYPE
|
||||
*/
|
||||
typedef enum {
|
||||
MASTER_VOL_KEY,
|
||||
NMTD_VOL_KEY,
|
||||
NMTD_LINK_KEY,
|
||||
EMTD_FILE_KEY,
|
||||
DATA_FILE_KEY_256,
|
||||
DATA_FILE_KEY_512,
|
||||
LAST_KEY_TYPE
|
||||
} crypt_key_type;
|
||||
|
||||
struct kderive_context {
|
||||
const unsigned char *pkey; /* parent key */
|
||||
uint32_t pkey_len; /* parent key size, bits */
|
||||
uint32_t ckey_len; /* child key size, bits */
|
||||
unsigned char *fid; /* fixed input data, NIST 800-108, 5.1 */
|
||||
uint32_t fid_len; /* fid len, bytes */
|
||||
unsigned char *out; /* contains child keying material */
|
||||
uint32_t out_len; /* out len, bytes */
|
||||
};
|
||||
|
||||
typedef enum { DATA_ATOM, HOLE_ATOM, LAST_DATA_TYPE } atom_data_type;
|
||||
|
||||
typedef enum {
|
||||
HEAD_ATOM,
|
||||
TAIL_ATOM,
|
||||
FULL_ATOM,
|
||||
LAST_LOCALITY_TYPE
|
||||
} atom_locality_type;
|
||||
|
||||
typedef enum {
|
||||
MTD_CREATE,
|
||||
MTD_APPEND,
|
||||
MTD_OVERWRITE,
|
||||
MTD_CUT,
|
||||
MTD_LAST_OP
|
||||
} mtd_op_t;
|
||||
|
||||
struct xts128_context {
|
||||
void *key1, *key2;
|
||||
block128_f block1, block2;
|
||||
};
|
||||
|
||||
struct object_cipher_info {
|
||||
cipher_alg_t o_alg;
|
||||
cipher_mode_t o_mode;
|
||||
uint32_t o_block_bits;
|
||||
uint32_t o_dkey_size; /* raw data key size in bits */
|
||||
union {
|
||||
struct {
|
||||
unsigned char ivec[16];
|
||||
AES_KEY dkey[2];
|
||||
AES_KEY tkey; /* key used for tweaking */
|
||||
XTS128_CONTEXT xts;
|
||||
} aes_xts;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct master_cipher_info {
|
||||
/*
|
||||
* attributes inherited by newly created regular files
|
||||
*/
|
||||
cipher_alg_t m_alg;
|
||||
cipher_mode_t m_mode;
|
||||
uint32_t m_block_bits;
|
||||
uint32_t m_dkey_size; /* raw key size in bits */
|
||||
/*
|
||||
* master key
|
||||
*/
|
||||
unsigned char m_key[MASTER_VOL_KEY_SIZE];
|
||||
/*
|
||||
* volume key for oid authentication
|
||||
*/
|
||||
unsigned char m_nmtd_key[NMTD_VOL_KEY_SIZE];
|
||||
};
|
||||
|
||||
/*
|
||||
* This info is not changed during file's life
|
||||
*/
|
||||
struct crypt_inode_info {
|
||||
#if DEBUG_CRYPT
|
||||
loc_t *loc; /* pathname that the file has been
|
||||
opened, or created with */
|
||||
#endif
|
||||
uint16_t nr_minor;
|
||||
uuid_t oid;
|
||||
struct object_cipher_info cinfo;
|
||||
};
|
||||
|
||||
/*
|
||||
* this should locate in secure memory
|
||||
*/
|
||||
typedef struct {
|
||||
struct master_cipher_info master;
|
||||
} crypt_private_t;
|
||||
|
||||
static inline struct master_cipher_info *
|
||||
get_master_cinfo(crypt_private_t *priv)
|
||||
{
|
||||
return &priv->master;
|
||||
}
|
||||
|
||||
static inline struct object_cipher_info *
|
||||
get_object_cinfo(struct crypt_inode_info *info)
|
||||
{
|
||||
return &info->cinfo;
|
||||
}
|
||||
|
||||
/*
|
||||
* this describes layouts and properties
|
||||
* of atoms in an aligned vector
|
||||
*/
|
||||
struct avec_config {
|
||||
uint32_t atom_size;
|
||||
atom_data_type type;
|
||||
size_t orig_size;
|
||||
off_t orig_offset;
|
||||
size_t expanded_size;
|
||||
off_t aligned_offset;
|
||||
|
||||
uint32_t off_in_head;
|
||||
uint32_t off_in_tail;
|
||||
uint32_t gap_in_tail;
|
||||
uint32_t nr_full_blocks;
|
||||
|
||||
struct iovec *avec; /* aligned vector */
|
||||
uint32_t acount; /* number of avec components. The same
|
||||
* as number of occupied logical blocks */
|
||||
char **pool;
|
||||
uint32_t blocks_in_pool;
|
||||
uint32_t cursor; /* makes sense only for ordered writes,
|
||||
* so there is no races on this counter.
|
||||
*
|
||||
* Cursor is per-config object, we don't
|
||||
* reset cursor for atoms of different
|
||||
* localities (head, tail, full)
|
||||
*/
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
glusterfs_fop_t fop; /* code of FOP this local info built for */
|
||||
fd_t *fd;
|
||||
inode_t *inode;
|
||||
loc_t *loc;
|
||||
int32_t mac_idx;
|
||||
loc_t *newloc;
|
||||
int32_t flags;
|
||||
int32_t wbflags;
|
||||
struct crypt_inode_info *info;
|
||||
struct iobref *iobref;
|
||||
struct iobref *iobref_data;
|
||||
off_t offset;
|
||||
|
||||
uint64_t old_file_size; /* per FOP, retrieved under lock held */
|
||||
uint64_t cur_file_size; /* per iteration, before issuing IOs */
|
||||
uint64_t new_file_size; /* per iteration, after issuing IOs */
|
||||
|
||||
uint64_t io_offset; /* offset of IOs issued per iteration */
|
||||
uint64_t io_offset_nopad; /* offset of user's data in the atom */
|
||||
uint32_t io_size; /* size of IOs issued per iteration */
|
||||
uint32_t io_size_nopad; /* size of user's data in the IOs */
|
||||
uint32_t eof_padding_size; /* size od EOF padding in the IOs */
|
||||
|
||||
gf_lock_t call_lock; /* protect nr_calls from many cbks */
|
||||
int32_t nr_calls;
|
||||
|
||||
atom_data_type active_setup; /* which setup (hole or date)
|
||||
is currently active */
|
||||
/* data setup */
|
||||
struct avec_config data_conf;
|
||||
|
||||
/* hole setup */
|
||||
int hole_conv_in_proggress;
|
||||
gf_lock_t hole_lock; /* protect hole config from many cbks */
|
||||
int hole_handled;
|
||||
struct avec_config hole_conf;
|
||||
struct iatt buf;
|
||||
struct iatt prebuf;
|
||||
struct iatt postbuf;
|
||||
struct iatt *prenewparent;
|
||||
struct iatt *postnewparent;
|
||||
int32_t op_ret;
|
||||
int32_t op_errno;
|
||||
int32_t rw_count; /* total read or written */
|
||||
gf_lock_t rw_count_lock; /* protect the counter above */
|
||||
unsigned char *format; /* for create, update format string */
|
||||
uint32_t format_size;
|
||||
uint32_t msgflags; /* messages for crypt_open() */
|
||||
dict_t *xdata;
|
||||
dict_t *xattr;
|
||||
struct iovec vec; /* contains last file's atom for
|
||||
read-prune-write sequence */
|
||||
gf_boolean_t custom_mtd;
|
||||
/*
|
||||
* the next 3 fields are used by readdir and friends
|
||||
*/
|
||||
gf_dirent_t *de; /* directory entry */
|
||||
char *de_path; /* pathname of directory entry */
|
||||
uint32_t de_prefix_len; /* length of the parent's pathname */
|
||||
gf_dirent_t *entries;
|
||||
|
||||
uint32_t update_disk_file_size : 1;
|
||||
} crypt_local_t;
|
||||
|
||||
/* This represents a (read)modify-write atom */
|
||||
struct rmw_atom {
|
||||
atom_locality_type locality;
|
||||
/*
|
||||
* read-modify-write sequence of the atom
|
||||
*/
|
||||
int32_t (*rmw)(call_frame_t *frame, void *cookie, xlator_t *this,
|
||||
int32_t op_ret, int32_t op_errno, struct iovec *vec,
|
||||
int32_t count, struct iatt *stbuf, struct iobref *iobref,
|
||||
dict_t *xdata);
|
||||
/*
|
||||
* offset of the logical block in a file
|
||||
*/
|
||||
loff_t (*offset_at)(call_frame_t *frame, struct object_cipher_info *object);
|
||||
/*
|
||||
* IO offset in an atom
|
||||
*/
|
||||
uint32_t (*offset_in)(call_frame_t *frame,
|
||||
struct object_cipher_info *object);
|
||||
/*
|
||||
* number of bytes of plain text of this atom that user
|
||||
* wants to read/write.
|
||||
* It can be smaller than atom_size in the case of head
|
||||
* or tail atoms.
|
||||
*/
|
||||
uint32_t (*io_size_nopad)(call_frame_t *frame,
|
||||
struct object_cipher_info *object);
|
||||
/*
|
||||
* which iovec represents the atom
|
||||
*/
|
||||
struct iovec *(*get_iovec)(call_frame_t *frame, uint32_t count);
|
||||
/*
|
||||
* how many bytes of partial block should be uptodated by
|
||||
* reading from disk.
|
||||
* This is used to perform a read component of RMW (read-modify-write).
|
||||
*/
|
||||
uint32_t (*count_to_uptodate)(call_frame_t *frame,
|
||||
struct object_cipher_info *object);
|
||||
struct avec_config *(*get_config)(call_frame_t *frame);
|
||||
};
|
||||
|
||||
struct data_cipher_alg {
|
||||
gf_boolean_t atomic; /* true means that algorithm requires
|
||||
to pad data before cipher transform */
|
||||
gf_boolean_t should_pad; /* true means that algorithm requires
|
||||
to pad the end of file with extra-data */
|
||||
uint32_t blkbits; /* blksize = 1 << blkbits */
|
||||
/*
|
||||
* any preliminary sanity checks goes here
|
||||
*/
|
||||
int32_t (*init)(void);
|
||||
/*
|
||||
* set alg-mode specific inode info
|
||||
*/
|
||||
int32_t (*set_private)(struct crypt_inode_info *info,
|
||||
struct master_cipher_info *master);
|
||||
/*
|
||||
* check alg-mode specific data key
|
||||
*/
|
||||
int32_t (*check_key)(uint32_t key_size);
|
||||
void (*set_iv)(off_t offset, struct object_cipher_info *object);
|
||||
int32_t (*encrypt)(const unsigned char *from, unsigned char *to,
|
||||
size_t length, off_t offset, const int enc,
|
||||
struct object_cipher_info *object);
|
||||
};
|
||||
|
||||
/*
|
||||
* version-dependent metadata loader
|
||||
*/
|
||||
struct crypt_mtd_loader {
|
||||
/*
|
||||
* return core format size
|
||||
*/
|
||||
size_t (*format_size)(mtd_op_t op, size_t old_size);
|
||||
/*
|
||||
* pack version-specific metadata of an object
|
||||
* at ->create()
|
||||
*/
|
||||
int32_t (*create_format)(unsigned char *wire, loc_t *loc,
|
||||
struct crypt_inode_info *info,
|
||||
struct master_cipher_info *master);
|
||||
/*
|
||||
* extract version-specific metadata of an object
|
||||
* at ->open() time
|
||||
*/
|
||||
int32_t (*open_format)(unsigned char *wire, int32_t len, loc_t *loc,
|
||||
struct crypt_inode_info *info,
|
||||
struct master_cipher_info *master,
|
||||
crypt_local_t *local, gf_boolean_t load_info);
|
||||
int32_t (*update_format)(unsigned char *new, unsigned char *old,
|
||||
size_t old_len, int32_t mac_idx, mtd_op_t op,
|
||||
loc_t *loc, struct crypt_inode_info *info,
|
||||
struct master_cipher_info *master,
|
||||
crypt_local_t *local);
|
||||
};
|
||||
|
||||
typedef int32_t (*end_writeback_handler_t)(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);
|
||||
typedef void (*linkop_wind_handler_t)(call_frame_t *frame, xlator_t *this);
|
||||
typedef void (*linkop_unwind_handler_t)(call_frame_t *frame);
|
||||
|
||||
/* Declarations */
|
||||
|
||||
/* keys.c */
|
||||
extern struct crypt_key crypt_keys[LAST_KEY_TYPE];
|
||||
int32_t
|
||||
get_nmtd_vol_key(struct master_cipher_info *master);
|
||||
int32_t
|
||||
get_nmtd_link_key(loc_t *loc, struct master_cipher_info *master,
|
||||
unsigned char *result);
|
||||
int32_t
|
||||
get_emtd_file_key(struct crypt_inode_info *info,
|
||||
struct master_cipher_info *master, unsigned char *result);
|
||||
int32_t
|
||||
get_data_file_key(struct crypt_inode_info *info,
|
||||
struct master_cipher_info *master, uint32_t keysize,
|
||||
unsigned char *key);
|
||||
/* data.c */
|
||||
extern struct data_cipher_alg data_cipher_algs[LAST_CIPHER_ALG]
|
||||
[LAST_CIPHER_MODE];
|
||||
void
|
||||
encrypt_aligned_iov(struct object_cipher_info *object, struct iovec *vec,
|
||||
int count, off_t off);
|
||||
void
|
||||
decrypt_aligned_iov(struct object_cipher_info *object, struct iovec *vec,
|
||||
int count, off_t off);
|
||||
int32_t
|
||||
align_iov_by_atoms(xlator_t *this, crypt_local_t *local,
|
||||
struct object_cipher_info *object,
|
||||
struct iovec *vec /* input vector */,
|
||||
int32_t count /* number of vec components */,
|
||||
struct iovec *avec /* aligned vector */,
|
||||
char **blocks /* pool of blocks */,
|
||||
uint32_t *blocks_allocated, struct avec_config *conf);
|
||||
int32_t
|
||||
set_config_avec_data(xlator_t *this, crypt_local_t *local,
|
||||
struct avec_config *conf,
|
||||
struct object_cipher_info *object, struct iovec *vec,
|
||||
int32_t vec_count);
|
||||
int32_t
|
||||
set_config_avec_hole(xlator_t *this, crypt_local_t *local,
|
||||
struct avec_config *conf,
|
||||
struct object_cipher_info *object, glusterfs_fop_t fop);
|
||||
void
|
||||
set_gap_at_end(call_frame_t *frame, struct object_cipher_info *object,
|
||||
struct avec_config *conf, atom_data_type dtype);
|
||||
void
|
||||
set_config_offsets(call_frame_t *frame, xlator_t *this, uint64_t offset,
|
||||
uint64_t count, atom_data_type dtype,
|
||||
int32_t setup_gap_in_tail);
|
||||
|
||||
/* metadata.c */
|
||||
extern struct crypt_mtd_loader mtd_loaders[LAST_MTD_LOADER];
|
||||
|
||||
int32_t
|
||||
alloc_format(crypt_local_t *local, size_t size);
|
||||
int32_t
|
||||
alloc_format_create(crypt_local_t *local);
|
||||
void
|
||||
free_format(crypt_local_t *local);
|
||||
size_t
|
||||
format_size(mtd_op_t op, size_t old_size);
|
||||
size_t
|
||||
new_format_size(void);
|
||||
int32_t
|
||||
open_format(unsigned char *str, int32_t len, loc_t *loc,
|
||||
struct crypt_inode_info *info, struct master_cipher_info *master,
|
||||
crypt_local_t *local, gf_boolean_t load_info);
|
||||
int32_t
|
||||
update_format(unsigned char *new, unsigned char *old, size_t old_len,
|
||||
int32_t mac_idx, mtd_op_t op, loc_t *loc,
|
||||
struct crypt_inode_info *info, struct master_cipher_info *master,
|
||||
crypt_local_t *local);
|
||||
int32_t
|
||||
create_format(unsigned char *wire, loc_t *loc, struct crypt_inode_info *info,
|
||||
struct master_cipher_info *master);
|
||||
|
||||
/* atom.c */
|
||||
struct rmw_atom *
|
||||
atom_by_types(atom_data_type data, atom_locality_type locality);
|
||||
void
|
||||
submit_partial(call_frame_t *frame, xlator_t *this, fd_t *fd,
|
||||
atom_locality_type ltype);
|
||||
void
|
||||
submit_full(call_frame_t *frame, xlator_t *this);
|
||||
|
||||
/* crypt.c */
|
||||
|
||||
end_writeback_handler_t
|
||||
dispatch_end_writeback(glusterfs_fop_t fop);
|
||||
void
|
||||
set_local_io_params_writev(call_frame_t *frame,
|
||||
struct object_cipher_info *object,
|
||||
struct rmw_atom *atom, off_t io_offset,
|
||||
uint32_t io_size);
|
||||
void
|
||||
link_wind(call_frame_t *frame, xlator_t *this);
|
||||
void
|
||||
unlink_wind(call_frame_t *frame, xlator_t *this);
|
||||
void
|
||||
link_unwind(call_frame_t *frame);
|
||||
void
|
||||
unlink_unwind(call_frame_t *frame);
|
||||
void
|
||||
rename_wind(call_frame_t *frame, xlator_t *this);
|
||||
void
|
||||
rename_unwind(call_frame_t *frame);
|
||||
|
||||
/* Inline functions */
|
||||
|
||||
static inline int32_t
|
||||
crypt_xlator_id(void)
|
||||
{
|
||||
return CRYPT_XLATOR_ID;
|
||||
}
|
||||
|
||||
static inline mtd_loader_id
|
||||
current_mtd_loader(void)
|
||||
{
|
||||
return MTD_LOADER_V1;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
master_key_size(void)
|
||||
{
|
||||
return crypt_keys[MASTER_VOL_KEY].len >> 3;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
nmtd_vol_key_size(void)
|
||||
{
|
||||
return crypt_keys[NMTD_VOL_KEY].len >> 3;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
alg_mode_blkbits(cipher_alg_t alg, cipher_mode_t mode)
|
||||
{
|
||||
return data_cipher_algs[alg][mode].blkbits;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
alg_mode_blksize(cipher_alg_t alg, cipher_mode_t mode)
|
||||
{
|
||||
return 1 << alg_mode_blkbits(alg, mode);
|
||||
}
|
||||
|
||||
static inline gf_boolean_t
|
||||
alg_mode_atomic(cipher_alg_t alg, cipher_mode_t mode)
|
||||
{
|
||||
return data_cipher_algs[alg][mode].atomic;
|
||||
}
|
||||
|
||||
static inline gf_boolean_t
|
||||
alg_mode_should_pad(cipher_alg_t alg, cipher_mode_t mode)
|
||||
{
|
||||
return data_cipher_algs[alg][mode].should_pad;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
master_alg_blksize(struct master_cipher_info *mr)
|
||||
{
|
||||
return alg_mode_blksize(mr->m_alg, mr->m_mode);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
master_alg_blkbits(struct master_cipher_info *mr)
|
||||
{
|
||||
return alg_mode_blkbits(mr->m_alg, mr->m_mode);
|
||||
}
|
||||
|
||||
static inline gf_boolean_t
|
||||
master_alg_atomic(struct master_cipher_info *mr)
|
||||
{
|
||||
return alg_mode_atomic(mr->m_alg, mr->m_mode);
|
||||
}
|
||||
|
||||
static inline gf_boolean_t
|
||||
master_alg_should_pad(struct master_cipher_info *mr)
|
||||
{
|
||||
return alg_mode_should_pad(mr->m_alg, mr->m_mode);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
object_alg_blksize(struct object_cipher_info *ob)
|
||||
{
|
||||
return alg_mode_blksize(ob->o_alg, ob->o_mode);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
object_alg_blkbits(struct object_cipher_info *ob)
|
||||
{
|
||||
return alg_mode_blkbits(ob->o_alg, ob->o_mode);
|
||||
}
|
||||
|
||||
static inline gf_boolean_t
|
||||
object_alg_atomic(struct object_cipher_info *ob)
|
||||
{
|
||||
return alg_mode_atomic(ob->o_alg, ob->o_mode);
|
||||
}
|
||||
|
||||
static inline gf_boolean_t
|
||||
object_alg_should_pad(struct object_cipher_info *ob)
|
||||
{
|
||||
return alg_mode_should_pad(ob->o_alg, ob->o_mode);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
aes_raw_key_size(struct master_cipher_info *master)
|
||||
{
|
||||
return master->m_dkey_size >> 3;
|
||||
}
|
||||
|
||||
static inline struct avec_config *
|
||||
get_hole_conf(call_frame_t *frame)
|
||||
{
|
||||
return &(((crypt_local_t *)frame->local)->hole_conf);
|
||||
}
|
||||
|
||||
static inline struct avec_config *
|
||||
get_data_conf(call_frame_t *frame)
|
||||
{
|
||||
return &(((crypt_local_t *)frame->local)->data_conf);
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
get_atom_bits(struct object_cipher_info *object)
|
||||
{
|
||||
return object->o_block_bits;
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
get_atom_size(struct object_cipher_info *object)
|
||||
{
|
||||
return 1 << get_atom_bits(object);
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
has_head_block(struct avec_config *conf)
|
||||
{
|
||||
return conf->off_in_head || (conf->acount == 1 && conf->off_in_tail);
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
has_tail_block(struct avec_config *conf)
|
||||
{
|
||||
return conf->off_in_tail && conf->acount > 1;
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
has_full_blocks(struct avec_config *conf)
|
||||
{
|
||||
return conf->nr_full_blocks;
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
should_submit_head_block(struct avec_config *conf)
|
||||
{
|
||||
return has_head_block(conf) && (conf->cursor == 0);
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
should_submit_tail_block(struct avec_config *conf)
|
||||
{
|
||||
return has_tail_block(conf) && (conf->cursor == conf->acount - 1);
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
should_submit_full_block(struct avec_config *conf)
|
||||
{
|
||||
uint32_t start = has_head_block(conf) ? 1 : 0;
|
||||
|
||||
return has_full_blocks(conf) && conf->cursor >= start &&
|
||||
conf->cursor < start + conf->nr_full_blocks;
|
||||
}
|
||||
|
||||
#if DEBUG_CRYPT
|
||||
static inline void
|
||||
crypt_check_input_len(size_t len, struct object_cipher_info *object)
|
||||
{
|
||||
if (object_alg_should_pad(object) &&
|
||||
(len & (object_alg_blksize(object) - 1)))
|
||||
gf_log("crypt", GF_LOG_DEBUG, "bad input len: %d", (int)len);
|
||||
}
|
||||
|
||||
static inline void
|
||||
check_head_block(struct avec_config *conf)
|
||||
{
|
||||
if (!has_head_block(conf))
|
||||
gf_log("crypt", GF_LOG_DEBUG, "not a head atom");
|
||||
}
|
||||
|
||||
static inline void
|
||||
check_tail_block(struct avec_config *conf)
|
||||
{
|
||||
if (!has_tail_block(conf))
|
||||
gf_log("crypt", GF_LOG_DEBUG, "not a tail atom");
|
||||
}
|
||||
|
||||
static inline void
|
||||
check_full_block(struct avec_config *conf)
|
||||
{
|
||||
if (!has_full_blocks(conf))
|
||||
gf_log("crypt", GF_LOG_DEBUG, "not a full atom");
|
||||
}
|
||||
|
||||
static inline void
|
||||
check_cursor_head(struct avec_config *conf)
|
||||
{
|
||||
if (!has_head_block(conf))
|
||||
gf_log("crypt", GF_LOG_DEBUG, "Illegal call of head atom method");
|
||||
else if (conf->cursor != 0)
|
||||
gf_log("crypt", GF_LOG_DEBUG, "Cursor (%d) is not at head atom",
|
||||
conf->cursor);
|
||||
}
|
||||
|
||||
static inline void
|
||||
check_cursor_full(struct avec_config *conf)
|
||||
{
|
||||
if (!has_full_blocks(conf))
|
||||
gf_log("crypt", GF_LOG_DEBUG, "Illegal call of full atom method");
|
||||
if (has_head_block(conf) && (conf->cursor == 0))
|
||||
gf_log("crypt", GF_LOG_DEBUG, "Cursor is not at full atom");
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: use avec->iov_len to check setup
|
||||
*/
|
||||
static inline int
|
||||
data_local_invariant(crypt_local_t *local)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#define crypt_check_input_len(len, object) noop
|
||||
#define check_head_block(conf) noop
|
||||
#define check_tail_block(conf) noop
|
||||
#define check_full_block(conf) noop
|
||||
#define check_cursor_head(conf) noop
|
||||
#define check_cursor_full(conf) noop
|
||||
|
||||
#endif /* DEBUG_CRYPT */
|
||||
|
||||
static inline struct avec_config *
|
||||
conf_by_type(call_frame_t *frame, atom_data_type dtype)
|
||||
{
|
||||
struct avec_config *conf = NULL;
|
||||
|
||||
switch (dtype) {
|
||||
case HOLE_ATOM:
|
||||
conf = get_hole_conf(frame);
|
||||
break;
|
||||
case DATA_ATOM:
|
||||
conf = get_data_conf(frame);
|
||||
break;
|
||||
default:
|
||||
gf_log("crypt", GF_LOG_DEBUG, "bad atom type");
|
||||
}
|
||||
return conf;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
nr_calls_head(struct avec_config *conf)
|
||||
{
|
||||
return has_head_block(conf) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
nr_calls_tail(struct avec_config *conf)
|
||||
{
|
||||
return has_tail_block(conf) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
nr_calls_full(struct avec_config *conf)
|
||||
{
|
||||
switch (conf->type) {
|
||||
case HOLE_ATOM:
|
||||
return has_full_blocks(conf);
|
||||
case DATA_ATOM:
|
||||
return has_full_blocks(conf)
|
||||
? logical_blocks_occupied(0, conf->nr_full_blocks,
|
||||
MAX_IOVEC_BITS)
|
||||
: 0;
|
||||
default:
|
||||
gf_log("crypt", GF_LOG_DEBUG, "bad atom data type");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
nr_calls(struct avec_config *conf)
|
||||
{
|
||||
return nr_calls_head(conf) + nr_calls_tail(conf) + nr_calls_full(conf);
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
nr_calls_data(call_frame_t *frame)
|
||||
{
|
||||
return nr_calls(get_data_conf(frame));
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
nr_calls_hole(call_frame_t *frame)
|
||||
{
|
||||
return nr_calls(get_hole_conf(frame));
|
||||
}
|
||||
|
||||
static inline void
|
||||
get_one_call_nolock(call_frame_t *frame)
|
||||
{
|
||||
crypt_local_t *local = frame->local;
|
||||
|
||||
++local->nr_calls;
|
||||
|
||||
// gf_log("crypt", GF_LOG_DEBUG, "get %d calls", 1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
get_one_call(call_frame_t *frame)
|
||||
{
|
||||
crypt_local_t *local = frame->local;
|
||||
|
||||
LOCK(&local->call_lock);
|
||||
get_one_call_nolock(frame);
|
||||
UNLOCK(&local->call_lock);
|
||||
}
|
||||
|
||||
static inline void
|
||||
get_nr_calls_nolock(call_frame_t *frame, int32_t nr)
|
||||
{
|
||||
crypt_local_t *local = frame->local;
|
||||
|
||||
local->nr_calls += nr;
|
||||
|
||||
// gf_log("crypt", GF_LOG_DEBUG, "get %d calls", nr);
|
||||
}
|
||||
|
||||
static inline void
|
||||
get_nr_calls(call_frame_t *frame, int32_t nr)
|
||||
{
|
||||
crypt_local_t *local = frame->local;
|
||||
|
||||
LOCK(&local->call_lock);
|
||||
get_nr_calls_nolock(frame, nr);
|
||||
UNLOCK(&local->call_lock);
|
||||
}
|
||||
|
||||
static inline int
|
||||
put_one_call(crypt_local_t *local)
|
||||
{
|
||||
uint32_t last = 0;
|
||||
|
||||
LOCK(&local->call_lock);
|
||||
if (--local->nr_calls == 0)
|
||||
last = 1;
|
||||
|
||||
// gf_log("crypt", GF_LOG_DEBUG, "put %d calls", 1);
|
||||
|
||||
UNLOCK(&local->call_lock);
|
||||
return last;
|
||||
}
|
||||
|
||||
static inline int
|
||||
is_appended_write(call_frame_t *frame)
|
||||
{
|
||||
crypt_local_t *local = frame->local;
|
||||
struct avec_config *conf = get_data_conf(frame);
|
||||
|
||||
return conf->orig_offset + conf->orig_size > local->old_file_size;
|
||||
}
|
||||
|
||||
static inline int
|
||||
is_ordered_mode(call_frame_t *frame)
|
||||
{
|
||||
#if 0
|
||||
crypt_local_t *local = frame->local;
|
||||
return local->fop == GF_FOP_FTRUNCATE ||
|
||||
(local->fop == GF_FOP_WRITE && is_appended_write(frame));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
hole_conv_completed(crypt_local_t *local)
|
||||
{
|
||||
struct avec_config *conf = &local->hole_conf;
|
||||
return conf->cursor == conf->acount;
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
data_write_in_progress(crypt_local_t *local)
|
||||
{
|
||||
return local->active_setup == DATA_ATOM;
|
||||
}
|
||||
|
||||
static inline int32_t
|
||||
parent_is_crypt_xlator(call_frame_t *frame, xlator_t *this)
|
||||
{
|
||||
return frame->parent->this == this;
|
||||
}
|
||||
|
||||
static inline linkop_wind_handler_t
|
||||
linkop_wind_dispatch(glusterfs_fop_t fop)
|
||||
{
|
||||
switch (fop) {
|
||||
case GF_FOP_LINK:
|
||||
return link_wind;
|
||||
case GF_FOP_UNLINK:
|
||||
return unlink_wind;
|
||||
case GF_FOP_RENAME:
|
||||
return rename_wind;
|
||||
default:
|
||||
gf_log("crypt", GF_LOG_ERROR, "Bad link operation %d", fop);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline linkop_unwind_handler_t
|
||||
linkop_unwind_dispatch(glusterfs_fop_t fop)
|
||||
{
|
||||
switch (fop) {
|
||||
case GF_FOP_LINK:
|
||||
return link_unwind;
|
||||
case GF_FOP_UNLINK:
|
||||
return unlink_unwind;
|
||||
case GF_FOP_RENAME:
|
||||
return rename_unwind;
|
||||
default:
|
||||
gf_log("crypt", GF_LOG_ERROR, "Bad link operation %d", fop);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline mtd_op_t
|
||||
linkop_mtdop_dispatch(glusterfs_fop_t fop)
|
||||
{
|
||||
switch (fop) {
|
||||
case GF_FOP_LINK:
|
||||
return MTD_APPEND;
|
||||
case GF_FOP_UNLINK:
|
||||
return MTD_CUT;
|
||||
case GF_FOP_RENAME:
|
||||
return MTD_OVERWRITE;
|
||||
default:
|
||||
gf_log("crypt", GF_LOG_WARNING, "Bad link operation %d", fop);
|
||||
return MTD_LAST_OP;
|
||||
}
|
||||
}
|
||||
|
||||
#define CRYPT_STACK_UNWIND(fop, frame, params...) \
|
||||
do { \
|
||||
crypt_local_t *__local = NULL; \
|
||||
if (frame) { \
|
||||
__local = frame->local; \
|
||||
frame->local = NULL; \
|
||||
} \
|
||||
STACK_UNWIND_STRICT(fop, frame, params); \
|
||||
if (__local) { \
|
||||
GF_FREE(__local); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* __CRYPT_H__ */
|
||||
|
||||
/*
|
||||
Local variables:
|
||||
c-indentation-style: "K&R"
|
||||
mode-name: "LC"
|
||||
c-basic-offset: 8
|
||||
tab-width: 8
|
||||
fill-column: 80
|
||||
scroll-step: 1
|
||||
End:
|
||||
*/
|
@ -1,715 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2008-2013 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.
|
||||
*/
|
||||
|
||||
#include <glusterfs/defaults.h>
|
||||
#include "crypt-common.h"
|
||||
#include "crypt.h"
|
||||
|
||||
static void
|
||||
set_iv_aes_xts(off_t offset, struct object_cipher_info *object)
|
||||
{
|
||||
unsigned char *ivec;
|
||||
|
||||
ivec = object->u.aes_xts.ivec;
|
||||
|
||||
/* convert the tweak into a little-endian byte
|
||||
* array (IEEE P1619/D16, May 2007, section 5.1)
|
||||
*/
|
||||
|
||||
*((uint64_t *)ivec) = htole64(offset);
|
||||
|
||||
/* ivec is padded with zeroes */
|
||||
}
|
||||
|
||||
static int32_t
|
||||
aes_set_keys_common(unsigned char *raw_key, uint32_t key_size, AES_KEY *keys)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
ret = AES_set_encrypt_key(raw_key, key_size, &keys[AES_ENCRYPT]);
|
||||
if (ret) {
|
||||
gf_log("crypt", GF_LOG_ERROR, "Set encrypt key failed");
|
||||
return ret;
|
||||
}
|
||||
ret = AES_set_decrypt_key(raw_key, key_size, &keys[AES_DECRYPT]);
|
||||
if (ret) {
|
||||
gf_log("crypt", GF_LOG_ERROR, "Set decrypt key failed");
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* set private cipher info for xts mode
|
||||
*/
|
||||
static int32_t
|
||||
set_private_aes_xts(struct crypt_inode_info *info,
|
||||
struct master_cipher_info *master)
|
||||
{
|
||||
int ret;
|
||||
struct object_cipher_info *object = get_object_cinfo(info);
|
||||
unsigned char *data_key;
|
||||
uint32_t subkey_size;
|
||||
|
||||
/* init tweak value */
|
||||
memset(object->u.aes_xts.ivec, 0, 16);
|
||||
|
||||
data_key = GF_CALLOC(1, object->o_dkey_size, gf_crypt_mt_key);
|
||||
if (!data_key)
|
||||
return ENOMEM;
|
||||
|
||||
/*
|
||||
* retrieve data keying material
|
||||
*/
|
||||
ret = get_data_file_key(info, master, object->o_dkey_size, data_key);
|
||||
if (ret) {
|
||||
gf_log("crypt", GF_LOG_ERROR, "Failed to retrieve data key");
|
||||
GF_FREE(data_key);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* parse compound xts key
|
||||
*/
|
||||
subkey_size = object->o_dkey_size >> 4; /* (xts-key-size-in-bytes / 2) */
|
||||
/*
|
||||
* install key for data encryption
|
||||
*/
|
||||
ret = aes_set_keys_common(data_key, subkey_size << 3,
|
||||
object->u.aes_xts.dkey);
|
||||
if (ret) {
|
||||
GF_FREE(data_key);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* set up key used to encrypt tweaks
|
||||
*/
|
||||
ret = AES_set_encrypt_key(data_key + subkey_size, object->o_dkey_size / 2,
|
||||
&object->u.aes_xts.tkey);
|
||||
if (ret < 0)
|
||||
gf_log("crypt", GF_LOG_ERROR, "Set tweak key failed");
|
||||
|
||||
GF_FREE(data_key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
aes_xts_init(void)
|
||||
{
|
||||
cassert(AES_BLOCK_SIZE == (1 << AES_BLOCK_BITS));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
check_key_aes_xts(uint32_t keysize)
|
||||
{
|
||||
switch (keysize) {
|
||||
case 256:
|
||||
case 512:
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
encrypt_aes_xts(const unsigned char *from, unsigned char *to, size_t length,
|
||||
off_t offset, const int enc, struct object_cipher_info *object)
|
||||
{
|
||||
XTS128_CONTEXT ctx;
|
||||
if (enc) {
|
||||
ctx.key1 = &object->u.aes_xts.dkey[AES_ENCRYPT];
|
||||
ctx.block1 = (block128_f)AES_encrypt;
|
||||
} else {
|
||||
ctx.key1 = &object->u.aes_xts.dkey[AES_DECRYPT];
|
||||
ctx.block1 = (block128_f)AES_decrypt;
|
||||
}
|
||||
ctx.key2 = &object->u.aes_xts.tkey;
|
||||
ctx.block2 = (block128_f)AES_encrypt;
|
||||
|
||||
return CRYPTO_xts128_encrypt(&ctx, object->u.aes_xts.ivec, from, to, length,
|
||||
enc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cipher input chunk @from of length @len;
|
||||
* @to: result of cipher transform;
|
||||
* @off: offset in a file (must be cblock-aligned);
|
||||
*/
|
||||
static void
|
||||
cipher_data(struct object_cipher_info *object, char *from, char *to, off_t off,
|
||||
size_t len, const int enc)
|
||||
{
|
||||
crypt_check_input_len(len, object);
|
||||
|
||||
#if TRIVIAL_TFM && DEBUG_CRYPT
|
||||
return;
|
||||
#endif
|
||||
data_cipher_algs[object->o_alg][object->o_mode].set_iv(off, object);
|
||||
data_cipher_algs[object->o_alg][object->o_mode].encrypt(
|
||||
(const unsigned char *)from, (unsigned char *)to, len, off, enc,
|
||||
object);
|
||||
}
|
||||
|
||||
#define MAX_CIPHER_CHUNK (1 << 30)
|
||||
|
||||
/*
|
||||
* Do cipher (encryption/decryption) transform of a
|
||||
* continuous region of memory.
|
||||
*
|
||||
* @len: a number of bytes to transform;
|
||||
* @buf: data to transform;
|
||||
* @off: offset in a file, should be block-aligned
|
||||
* for atomic cipher modes and ksize-aligned
|
||||
* for other modes).
|
||||
* @dir: direction of transform (encrypt/decrypt).
|
||||
*/
|
||||
static void
|
||||
cipher_region(struct object_cipher_info *object, char *from, char *to,
|
||||
off_t off, size_t len, int dir)
|
||||
{
|
||||
while (len > 0) {
|
||||
size_t to_cipher;
|
||||
|
||||
to_cipher = len;
|
||||
if (to_cipher > MAX_CIPHER_CHUNK)
|
||||
to_cipher = MAX_CIPHER_CHUNK;
|
||||
|
||||
/* this will reset IV */
|
||||
cipher_data(object, from, to, off, to_cipher, dir);
|
||||
from += to_cipher;
|
||||
to += to_cipher;
|
||||
off += to_cipher;
|
||||
len -= to_cipher;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Do cipher transform (encryption/decryption) of
|
||||
* plaintext/ciphertext represented by @vec.
|
||||
*
|
||||
* Pre-conditions: @vec represents a continuous piece
|
||||
* of data in a file at offset @off to be ciphered
|
||||
* (encrypted/decrypted).
|
||||
* @count is the number of vec's components. All the
|
||||
* components must be block-aligned, the caller is
|
||||
* responsible for this. @dir is "direction" of
|
||||
* transform (encrypt/decrypt).
|
||||
*/
|
||||
static void
|
||||
cipher_aligned_iov(struct object_cipher_info *object, struct iovec *vec,
|
||||
int count, off_t off, int32_t dir)
|
||||
{
|
||||
int i;
|
||||
int len = 0;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
cipher_region(object, vec[i].iov_base, vec[i].iov_base, off + len,
|
||||
vec[i].iov_len, dir);
|
||||
len += vec[i].iov_len;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
encrypt_aligned_iov(struct object_cipher_info *object, struct iovec *vec,
|
||||
int count, off_t off)
|
||||
{
|
||||
cipher_aligned_iov(object, vec, count, off, 1);
|
||||
}
|
||||
|
||||
void
|
||||
decrypt_aligned_iov(struct object_cipher_info *object, struct iovec *vec,
|
||||
int count, off_t off)
|
||||
{
|
||||
cipher_aligned_iov(object, vec, count, off, 0);
|
||||
}
|
||||
|
||||
#if DEBUG_CRYPT
|
||||
static void
|
||||
compound_stream(struct iovec *vec, int count, char *buf, off_t skip)
|
||||
{
|
||||
int i;
|
||||
int off = 0;
|
||||
for (i = 0; i < count; i++) {
|
||||
memcpy(buf + off, vec[i].iov_base + skip, vec[i].iov_len - skip);
|
||||
|
||||
off += (vec[i].iov_len - skip);
|
||||
skip = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
check_iovecs(struct iovec *vec, int cnt, struct iovec *avec, int acnt,
|
||||
uint32_t off_in_head)
|
||||
{
|
||||
char *s1, *s2;
|
||||
uint32_t size, asize;
|
||||
|
||||
size = iov_length(vec, cnt);
|
||||
asize = iov_length(avec, acnt) - off_in_head;
|
||||
if (size != asize) {
|
||||
gf_log("crypt", GF_LOG_DEBUG, "size %d is not eq asize %d", size,
|
||||
asize);
|
||||
return;
|
||||
}
|
||||
s1 = GF_CALLOC(1, size, gf_crypt_mt_data);
|
||||
if (!s1) {
|
||||
gf_log("crypt", GF_LOG_DEBUG, "Can not allocate stream ");
|
||||
return;
|
||||
}
|
||||
s2 = GF_CALLOC(1, asize, gf_crypt_mt_data);
|
||||
if (!s2) {
|
||||
GF_FREE(s1);
|
||||
gf_log("crypt", GF_LOG_DEBUG, "Can not allocate stream ");
|
||||
return;
|
||||
}
|
||||
compound_stream(vec, cnt, s1, 0);
|
||||
compound_stream(avec, acnt, s2, off_in_head);
|
||||
if (memcmp(s1, s2, size))
|
||||
gf_log("crypt", GF_LOG_DEBUG, "chunks of different data");
|
||||
GF_FREE(s1);
|
||||
GF_FREE(s2);
|
||||
}
|
||||
|
||||
#else
|
||||
#define check_iovecs(vec, count, avec, avecn, off) noop
|
||||
#endif /* DEBUG_CRYPT */
|
||||
|
||||
static char *
|
||||
data_alloc_block(xlator_t *this, crypt_local_t *local, int32_t block_size)
|
||||
{
|
||||
struct iobuf *iobuf = NULL;
|
||||
|
||||
iobuf = iobuf_get2(this->ctx->iobuf_pool, block_size);
|
||||
if (!iobuf) {
|
||||
gf_log("crypt", GF_LOG_ERROR, "Failed to get iobuf");
|
||||
return NULL;
|
||||
}
|
||||
if (!local->iobref_data) {
|
||||
local->iobref_data = iobref_new();
|
||||
if (!local->iobref_data) {
|
||||
gf_log("crypt", GF_LOG_ERROR, "Failed to get iobref");
|
||||
iobuf_unref(iobuf);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
iobref_add(local->iobref_data, iobuf);
|
||||
return iobuf->ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compound @avec, which represent the same data
|
||||
* chunk as @vec, but has aligned components of
|
||||
* specified block size. Alloc blocks, if needed.
|
||||
* In particular, incomplete head and tail blocks
|
||||
* must be allocated.
|
||||
* Put number of allocated blocks to @num_blocks.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* input: data chunk represented by 4 components
|
||||
* [AB],[BC],[CD],[DE];
|
||||
* output: 5 logical blocks (0, 1, 2, 3, 4).
|
||||
*
|
||||
* A B C D E
|
||||
* *-----*+------*-+---*----+--------+-*
|
||||
* | || | | | | | |
|
||||
* *-+-----+*------+-*---+----*--------*-+------*
|
||||
* 0 1 2 3 4
|
||||
*
|
||||
* 0 - incomplete compound (head);
|
||||
* 1, 2 - full compound;
|
||||
* 3 - full non-compound (the case of reuse);
|
||||
* 4 - incomplete non-compound (tail).
|
||||
*/
|
||||
int32_t
|
||||
align_iov_by_atoms(xlator_t *this, crypt_local_t *local,
|
||||
struct object_cipher_info *object,
|
||||
struct iovec *vec /* input vector */,
|
||||
int32_t count /* number of vec components */,
|
||||
struct iovec *avec /* aligned vector */,
|
||||
char **blocks /* pool of blocks */,
|
||||
uint32_t *blocks_allocated, struct avec_config *conf)
|
||||
{
|
||||
int vecn = 0; /* number of the current component in vec */
|
||||
int avecn = 0; /* number of the current component in avec */
|
||||
off_t vec_off = 0; /* offset in the current vec component,
|
||||
* i.e. the number of bytes have already
|
||||
* been copied */
|
||||
int32_t block_size = get_atom_size(object);
|
||||
size_t to_process; /* number of vec's bytes to copy and(or) re-use */
|
||||
int32_t off_in_head = conf->off_in_head;
|
||||
|
||||
to_process = iov_length(vec, count);
|
||||
|
||||
while (to_process > 0) {
|
||||
if (off_in_head || vec[vecn].iov_len - vec_off < block_size) {
|
||||
/*
|
||||
* less than block_size:
|
||||
* the case of incomplete (head or tail),
|
||||
* or compound block
|
||||
*/
|
||||
size_t copied = 0;
|
||||
/*
|
||||
* populate the pool with a new block
|
||||
*/
|
||||
blocks[*blocks_allocated] = data_alloc_block(this, local,
|
||||
block_size);
|
||||
if (!blocks[*blocks_allocated])
|
||||
return -ENOMEM;
|
||||
memset(blocks[*blocks_allocated], 0, off_in_head);
|
||||
/*
|
||||
* fill the block with vec components
|
||||
*/
|
||||
do {
|
||||
size_t to_copy;
|
||||
|
||||
to_copy = vec[vecn].iov_len - vec_off;
|
||||
if (to_copy > block_size - off_in_head)
|
||||
to_copy = block_size - off_in_head;
|
||||
|
||||
memcpy(blocks[*blocks_allocated] + off_in_head + copied,
|
||||
vec[vecn].iov_base + vec_off, to_copy);
|
||||
|
||||
copied += to_copy;
|
||||
to_process -= to_copy;
|
||||
|
||||
vec_off += to_copy;
|
||||
if (vec_off == vec[vecn].iov_len) {
|
||||
/* finished with this vecn */
|
||||
vec_off = 0;
|
||||
vecn++;
|
||||
}
|
||||
} while (copied < (block_size - off_in_head) && to_process > 0);
|
||||
/*
|
||||
* update avec
|
||||
*/
|
||||
avec[avecn].iov_len = off_in_head + copied;
|
||||
avec[avecn].iov_base = blocks[*blocks_allocated];
|
||||
|
||||
(*blocks_allocated)++;
|
||||
off_in_head = 0;
|
||||
} else {
|
||||
/*
|
||||
* the rest of the current vec component
|
||||
* is not less than block_size, so reuse
|
||||
* the memory buffer of the component.
|
||||
*/
|
||||
size_t to_reuse;
|
||||
to_reuse = (to_process > block_size ? block_size : to_process);
|
||||
avec[avecn].iov_len = to_reuse;
|
||||
avec[avecn].iov_base = vec[vecn].iov_base + vec_off;
|
||||
|
||||
vec_off += to_reuse;
|
||||
if (vec_off == vec[vecn].iov_len) {
|
||||
/* finished with this vecn */
|
||||
vec_off = 0;
|
||||
vecn++;
|
||||
}
|
||||
to_process -= to_reuse;
|
||||
}
|
||||
avecn++;
|
||||
}
|
||||
check_iovecs(vec, count, avec, avecn, conf->off_in_head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate and setup aligned vector for data submission
|
||||
* Pre-condition: @conf is set.
|
||||
*/
|
||||
int32_t
|
||||
set_config_avec_data(xlator_t *this, crypt_local_t *local,
|
||||
struct avec_config *conf,
|
||||
struct object_cipher_info *object, struct iovec *vec,
|
||||
int32_t vec_count)
|
||||
{
|
||||
int32_t ret = ENOMEM;
|
||||
struct iovec *avec;
|
||||
char **pool;
|
||||
uint32_t blocks_in_pool = 0;
|
||||
|
||||
conf->type = DATA_ATOM;
|
||||
|
||||
avec = GF_CALLOC(conf->acount, sizeof(*avec), gf_crypt_mt_iovec);
|
||||
if (!avec)
|
||||
return ret;
|
||||
pool = GF_CALLOC(conf->acount, sizeof(*pool), gf_crypt_mt_char);
|
||||
if (!pool) {
|
||||
GF_FREE(avec);
|
||||
return ret;
|
||||
}
|
||||
if (!vec) {
|
||||
/*
|
||||
* degenerated case: no data
|
||||
*/
|
||||
pool[0] = data_alloc_block(this, local, get_atom_size(object));
|
||||
if (!pool[0])
|
||||
goto free;
|
||||
blocks_in_pool = 1;
|
||||
avec->iov_base = pool[0];
|
||||
avec->iov_len = conf->off_in_tail;
|
||||
} else {
|
||||
ret = align_iov_by_atoms(this, local, object, vec, vec_count, avec,
|
||||
pool, &blocks_in_pool, conf);
|
||||
if (ret)
|
||||
goto free;
|
||||
}
|
||||
conf->avec = avec;
|
||||
conf->pool = pool;
|
||||
conf->blocks_in_pool = blocks_in_pool;
|
||||
return 0;
|
||||
free:
|
||||
GF_FREE(avec);
|
||||
GF_FREE(pool);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* allocate and setup aligned vector for hole submission
|
||||
*/
|
||||
int32_t
|
||||
set_config_avec_hole(xlator_t *this, crypt_local_t *local,
|
||||
struct avec_config *conf,
|
||||
struct object_cipher_info *object, glusterfs_fop_t fop)
|
||||
{
|
||||
uint32_t i, idx;
|
||||
struct iovec *avec;
|
||||
char **pool;
|
||||
uint32_t num_blocks;
|
||||
uint32_t blocks_in_pool = 0;
|
||||
|
||||
conf->type = HOLE_ATOM;
|
||||
|
||||
num_blocks = conf->acount -
|
||||
(conf->nr_full_blocks ? conf->nr_full_blocks - 1 : 0);
|
||||
|
||||
switch (fop) {
|
||||
case GF_FOP_WRITE:
|
||||
/*
|
||||
* hole goes before data
|
||||
*/
|
||||
if (num_blocks == 1 && conf->off_in_tail != 0)
|
||||
/*
|
||||
* we won't submit a hole which fits into
|
||||
* a data atom: this part of hole will be
|
||||
* submitted with data write
|
||||
*/
|
||||
return 0;
|
||||
break;
|
||||
case GF_FOP_FTRUNCATE:
|
||||
/*
|
||||
* expanding truncate, hole goes after data,
|
||||
* and will be submitted in any case.
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
gf_log("crypt", GF_LOG_WARNING, "bad file operation %d", fop);
|
||||
return 0;
|
||||
}
|
||||
avec = GF_CALLOC(num_blocks, sizeof(*avec), gf_crypt_mt_iovec);
|
||||
if (!avec)
|
||||
return ENOMEM;
|
||||
pool = GF_CALLOC(num_blocks, sizeof(*pool), gf_crypt_mt_char);
|
||||
if (!pool) {
|
||||
GF_FREE(avec);
|
||||
return ENOMEM;
|
||||
}
|
||||
for (i = 0; i < num_blocks; i++) {
|
||||
pool[i] = data_alloc_block(this, local, get_atom_size(object));
|
||||
if (pool[i] == NULL)
|
||||
goto free;
|
||||
blocks_in_pool++;
|
||||
}
|
||||
if (has_head_block(conf)) {
|
||||
/* set head block */
|
||||
idx = 0;
|
||||
avec[idx].iov_base = pool[idx];
|
||||
avec[idx].iov_len = get_atom_size(object);
|
||||
memset(avec[idx].iov_base + conf->off_in_head, 0,
|
||||
get_atom_size(object) - conf->off_in_head);
|
||||
}
|
||||
if (has_tail_block(conf)) {
|
||||
/* set tail block */
|
||||
idx = num_blocks - 1;
|
||||
avec[idx].iov_base = pool[idx];
|
||||
avec[idx].iov_len = get_atom_size(object);
|
||||
memset(avec[idx].iov_base, 0, conf->off_in_tail);
|
||||
}
|
||||
if (has_full_blocks(conf)) {
|
||||
/* set full block */
|
||||
idx = conf->off_in_head ? 1 : 0;
|
||||
avec[idx].iov_base = pool[idx];
|
||||
avec[idx].iov_len = get_atom_size(object);
|
||||
/*
|
||||
* since we re-use the buffer,
|
||||
* zeroes will be set every time
|
||||
* before encryption, see submit_full()
|
||||
*/
|
||||
}
|
||||
conf->avec = avec;
|
||||
conf->pool = pool;
|
||||
conf->blocks_in_pool = blocks_in_pool;
|
||||
return 0;
|
||||
free:
|
||||
GF_FREE(avec);
|
||||
GF_FREE(pool);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
/* A helper for setting up config of partial atoms (which
|
||||
* participate in read-modify-write sequence).
|
||||
*
|
||||
* Calculate and setup precise amount of "extra-bytes"
|
||||
* that should be uptodated at the end of partial (not
|
||||
* necessarily tail!) block.
|
||||
*
|
||||
* Pre-condition: local->old_file_size is valid!
|
||||
* @conf contains setup, which is enough for correct calculation
|
||||
* of has_tail_block(), ->get_offset().
|
||||
*/
|
||||
void
|
||||
set_gap_at_end(call_frame_t *frame, struct object_cipher_info *object,
|
||||
struct avec_config *conf, atom_data_type dtype)
|
||||
{
|
||||
uint32_t to_block;
|
||||
crypt_local_t *local = frame->local;
|
||||
uint64_t old_file_size = local->old_file_size;
|
||||
struct rmw_atom *partial = atom_by_types(
|
||||
dtype, has_tail_block(conf) ? TAIL_ATOM : HEAD_ATOM);
|
||||
|
||||
if (old_file_size <= partial->offset_at(frame, object))
|
||||
to_block = 0;
|
||||
else {
|
||||
to_block = old_file_size - partial->offset_at(frame, object);
|
||||
if (to_block > get_atom_size(object))
|
||||
to_block = get_atom_size(object);
|
||||
}
|
||||
if (to_block > conf->off_in_tail)
|
||||
conf->gap_in_tail = to_block - conf->off_in_tail;
|
||||
else
|
||||
/*
|
||||
* nothing to uptodate
|
||||
*/
|
||||
conf->gap_in_tail = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* fill struct avec_config with offsets layouts
|
||||
*/
|
||||
void
|
||||
set_config_offsets(call_frame_t *frame, xlator_t *this, uint64_t offset,
|
||||
uint64_t count, atom_data_type dtype, int32_t set_gap)
|
||||
{
|
||||
crypt_local_t *local;
|
||||
struct object_cipher_info *object;
|
||||
struct avec_config *conf;
|
||||
uint32_t resid;
|
||||
|
||||
uint32_t atom_size;
|
||||
uint32_t atom_bits;
|
||||
|
||||
size_t orig_size;
|
||||
off_t orig_offset;
|
||||
size_t expanded_size;
|
||||
off_t aligned_offset;
|
||||
|
||||
uint32_t off_in_head = 0;
|
||||
uint32_t off_in_tail = 0;
|
||||
uint32_t nr_full_blocks;
|
||||
int32_t size_full_blocks;
|
||||
|
||||
uint32_t acount; /* number of aligned components to write.
|
||||
* The same as number of occupied logical
|
||||
* blocks (atoms)
|
||||
*/
|
||||
local = frame->local;
|
||||
object = &local->info->cinfo;
|
||||
conf = (dtype == DATA_ATOM ? get_data_conf(frame) : get_hole_conf(frame));
|
||||
|
||||
orig_offset = offset;
|
||||
orig_size = count;
|
||||
|
||||
atom_size = get_atom_size(object);
|
||||
atom_bits = get_atom_bits(object);
|
||||
|
||||
/*
|
||||
* Round-down the start,
|
||||
* round-up the end.
|
||||
*/
|
||||
resid = offset & (uint64_t)(atom_size - 1);
|
||||
|
||||
if (resid)
|
||||
off_in_head = resid;
|
||||
aligned_offset = offset - off_in_head;
|
||||
expanded_size = orig_size + off_in_head;
|
||||
|
||||
/* calculate tail,
|
||||
expand size forward */
|
||||
resid = (offset + orig_size) & (uint64_t)(atom_size - 1);
|
||||
|
||||
if (resid) {
|
||||
off_in_tail = resid;
|
||||
expanded_size += (atom_size - off_in_tail);
|
||||
}
|
||||
/*
|
||||
* calculate number of occupied blocks
|
||||
*/
|
||||
acount = expanded_size >> atom_bits;
|
||||
/*
|
||||
* calculate number of full blocks
|
||||
*/
|
||||
size_full_blocks = expanded_size;
|
||||
if (off_in_head)
|
||||
size_full_blocks -= atom_size;
|
||||
if (off_in_tail && size_full_blocks > 0)
|
||||
size_full_blocks -= atom_size;
|
||||
nr_full_blocks = size_full_blocks >> atom_bits;
|
||||
|
||||
conf->atom_size = atom_size;
|
||||
conf->orig_size = orig_size;
|
||||
conf->orig_offset = orig_offset;
|
||||
conf->expanded_size = expanded_size;
|
||||
conf->aligned_offset = aligned_offset;
|
||||
|
||||
conf->off_in_head = off_in_head;
|
||||
conf->off_in_tail = off_in_tail;
|
||||
conf->nr_full_blocks = nr_full_blocks;
|
||||
conf->acount = acount;
|
||||
/*
|
||||
* Finally, calculate precise amount of
|
||||
* "extra-bytes" that should be uptodated
|
||||
* at the end.
|
||||
* Only if RMW is expected.
|
||||
*/
|
||||
if (off_in_tail && set_gap)
|
||||
set_gap_at_end(frame, object, conf, dtype);
|
||||
}
|
||||
|
||||
struct data_cipher_alg data_cipher_algs[LAST_CIPHER_ALG][LAST_CIPHER_MODE] = {
|
||||
[AES_CIPHER_ALG][XTS_CIPHER_MODE] = {.atomic = _gf_true,
|
||||
.should_pad = _gf_true,
|
||||
.blkbits = AES_BLOCK_BITS,
|
||||
.init = aes_xts_init,
|
||||
.set_private = set_private_aes_xts,
|
||||
.check_key = check_key_aes_xts,
|
||||
.set_iv = set_iv_aes_xts,
|
||||
.encrypt = encrypt_aes_xts}};
|
||||
|
||||
/*
|
||||
Local variables:
|
||||
c-indentation-style: "K&R"
|
||||
mode-name: "LC"
|
||||
c-basic-offset: 8
|
||||
tab-width: 8
|
||||
fill-column: 80
|
||||
scroll-step: 1
|
||||
End:
|
||||
*/
|
@ -1,284 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2008-2013 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.
|
||||
*/
|
||||
|
||||
#include <glusterfs/defaults.h>
|
||||
#include "crypt-common.h"
|
||||
#include "crypt.h"
|
||||
|
||||
/* Key hierarchy
|
||||
|
||||
+----------------+
|
||||
| MASTER_VOL_KEY |
|
||||
+-------+--------+
|
||||
|
|
||||
|
|
||||
+----------------+----------------+
|
||||
| | |
|
||||
| | |
|
||||
+-------+------+ +-------+-------+ +------+--------+
|
||||
| NMTD_VOL_KEY | | EMTD_FILE_KEY | | DATA_FILE_KEY |
|
||||
+-------+------+ +---------------+ +---------------+
|
||||
|
|
||||
|
|
||||
+-------+-------+
|
||||
| NMTD_LINK_KEY |
|
||||
+---------------+
|
||||
|
||||
*/
|
||||
|
||||
#if DEBUG_CRYPT
|
||||
static void
|
||||
check_prf_iters(uint32_t num_iters)
|
||||
{
|
||||
if (num_iters == 0)
|
||||
gf_log("crypt", GF_LOG_DEBUG, "bad number of prf iterations : %d",
|
||||
num_iters);
|
||||
}
|
||||
#else
|
||||
#define check_prf_iters(num_iters) noop
|
||||
#endif /* DEBUG_CRYPT */
|
||||
|
||||
unsigned char crypt_fake_oid[16] = {0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
/*
|
||||
* derive key in the counter mode using
|
||||
* sha256-based HMAC as PRF, see
|
||||
* NIST Special Publication 800-108, 5.1)
|
||||
*/
|
||||
|
||||
#define PRF_OUTPUT_SIZE SHA256_DIGEST_LENGTH
|
||||
|
||||
static int32_t
|
||||
kderive_init(struct kderive_context *ctx,
|
||||
const unsigned char *pkey, /* parent key */
|
||||
uint32_t pkey_size, /* parent key size */
|
||||
const unsigned char *idctx, /* id-context */
|
||||
uint32_t idctx_size, crypt_key_type type /* type of child key */)
|
||||
{
|
||||
unsigned char *pos;
|
||||
uint32_t llen = strlen(crypt_keys[type].label);
|
||||
/*
|
||||
* Compoud the fixed input data for KDF:
|
||||
* [i]_2 || Label || 0x00 || Id-Context || [L]_2),
|
||||
* NIST SP 800-108, 5.1
|
||||
*/
|
||||
ctx->fid_len = sizeof(uint32_t) + llen + 1 + idctx_size + sizeof(uint32_t);
|
||||
|
||||
ctx->fid = GF_CALLOC(ctx->fid_len, 1, gf_crypt_mt_key);
|
||||
if (!ctx->fid)
|
||||
return ENOMEM;
|
||||
ctx->out_len = round_up(crypt_keys[type].len >> 3, PRF_OUTPUT_SIZE);
|
||||
ctx->out = GF_CALLOC(ctx->out_len, 1, gf_crypt_mt_key);
|
||||
if (!ctx->out) {
|
||||
GF_FREE(ctx->fid);
|
||||
return ENOMEM;
|
||||
}
|
||||
ctx->pkey = pkey;
|
||||
ctx->pkey_len = pkey_size;
|
||||
ctx->ckey_len = crypt_keys[type].len;
|
||||
|
||||
pos = ctx->fid;
|
||||
|
||||
/* counter will be set up in kderive_rfn() */
|
||||
pos += sizeof(uint32_t);
|
||||
|
||||
memcpy(pos, crypt_keys[type].label, llen);
|
||||
pos += llen;
|
||||
|
||||
/* set up zero octet */
|
||||
*pos = 0;
|
||||
pos += 1;
|
||||
|
||||
memcpy(pos, idctx, idctx_size);
|
||||
pos += idctx_size;
|
||||
|
||||
*((uint32_t *)pos) = htobe32(ctx->ckey_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
kderive_update(struct kderive_context *ctx)
|
||||
{
|
||||
uint32_t i;
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x1010002f)
|
||||
HMAC_CTX hctx;
|
||||
#endif
|
||||
HMAC_CTX *phctx = NULL;
|
||||
unsigned char *pos = ctx->out;
|
||||
uint32_t *p_iter = (uint32_t *)ctx->fid;
|
||||
uint32_t num_iters = ctx->out_len / PRF_OUTPUT_SIZE;
|
||||
|
||||
check_prf_iters(num_iters);
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x1010002f)
|
||||
HMAC_CTX_init(&hctx);
|
||||
phctx = &hctx;
|
||||
#else
|
||||
phctx = HMAC_CTX_new();
|
||||
/* I guess we presume it was successful? */
|
||||
#endif
|
||||
for (i = 0; i < num_iters; i++) {
|
||||
/*
|
||||
* update the iteration number in the fid
|
||||
*/
|
||||
*p_iter = htobe32(i);
|
||||
HMAC_Init_ex(phctx, ctx->pkey, ctx->pkey_len >> 3, EVP_sha256(), NULL);
|
||||
HMAC_Update(phctx, ctx->fid, ctx->fid_len);
|
||||
HMAC_Final(phctx, pos, NULL);
|
||||
|
||||
pos += PRF_OUTPUT_SIZE;
|
||||
}
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x1010002f)
|
||||
HMAC_CTX_cleanup(phctx);
|
||||
#else
|
||||
HMAC_CTX_free(phctx);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
kderive_final(struct kderive_context *ctx, unsigned char *child)
|
||||
{
|
||||
memcpy(child, ctx->out, ctx->ckey_len >> 3);
|
||||
GF_FREE(ctx->fid);
|
||||
GF_FREE(ctx->out);
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
}
|
||||
|
||||
/*
|
||||
* derive per-volume key for object ids aithentication
|
||||
*/
|
||||
int32_t
|
||||
get_nmtd_vol_key(struct master_cipher_info *master)
|
||||
{
|
||||
int32_t ret;
|
||||
struct kderive_context ctx;
|
||||
|
||||
ret = kderive_init(&ctx, master->m_key, master_key_size(), crypt_fake_oid,
|
||||
sizeof(uuid_t), NMTD_VOL_KEY);
|
||||
if (ret)
|
||||
return ret;
|
||||
kderive_update(&ctx);
|
||||
kderive_final(&ctx, master->m_nmtd_key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* derive per-link key for aithentication of non-encrypted
|
||||
* meta-data (nmtd)
|
||||
*/
|
||||
int32_t
|
||||
get_nmtd_link_key(loc_t *loc, struct master_cipher_info *master,
|
||||
unsigned char *result)
|
||||
{
|
||||
int32_t ret;
|
||||
struct kderive_context ctx;
|
||||
|
||||
ret = kderive_init(&ctx, master->m_nmtd_key, nmtd_vol_key_size(),
|
||||
(const unsigned char *)loc->path, strlen(loc->path),
|
||||
NMTD_LINK_KEY);
|
||||
if (ret)
|
||||
return ret;
|
||||
kderive_update(&ctx);
|
||||
kderive_final(&ctx, result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* derive per-file key for encryption and authentication
|
||||
* of encrypted part of metadata (emtd)
|
||||
*/
|
||||
int32_t
|
||||
get_emtd_file_key(struct crypt_inode_info *info,
|
||||
struct master_cipher_info *master, unsigned char *result)
|
||||
{
|
||||
int32_t ret;
|
||||
struct kderive_context ctx;
|
||||
|
||||
ret = kderive_init(&ctx, master->m_key, master_key_size(), info->oid,
|
||||
sizeof(uuid_t), EMTD_FILE_KEY);
|
||||
if (ret)
|
||||
return ret;
|
||||
kderive_update(&ctx);
|
||||
kderive_final(&ctx, result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
data_key_type_by_size(uint32_t keysize, crypt_key_type *type)
|
||||
{
|
||||
int32_t ret = 0;
|
||||
switch (keysize) {
|
||||
case 256:
|
||||
*type = DATA_FILE_KEY_256;
|
||||
break;
|
||||
case 512:
|
||||
*type = DATA_FILE_KEY_512;
|
||||
break;
|
||||
default:
|
||||
gf_log("crypt", GF_LOG_ERROR, "Unsupported data key size %d",
|
||||
keysize);
|
||||
ret = ENOTSUP;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* derive per-file key for data encryption
|
||||
*/
|
||||
int32_t
|
||||
get_data_file_key(struct crypt_inode_info *info,
|
||||
struct master_cipher_info *master, uint32_t keysize,
|
||||
unsigned char *key)
|
||||
{
|
||||
int32_t ret;
|
||||
struct kderive_context ctx;
|
||||
crypt_key_type type;
|
||||
|
||||
ret = data_key_type_by_size(keysize, &type);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = kderive_init(&ctx, master->m_key, master_key_size(), info->oid,
|
||||
sizeof(uuid_t), type);
|
||||
if (ret)
|
||||
return ret;
|
||||
kderive_update(&ctx);
|
||||
kderive_final(&ctx, key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: Don't change existing keys: it will break compatibility;
|
||||
*/
|
||||
struct crypt_key crypt_keys[LAST_KEY_TYPE] = {
|
||||
[MASTER_VOL_KEY] =
|
||||
{
|
||||
.len = MASTER_VOL_KEY_SIZE << 3,
|
||||
.label = "volume-master",
|
||||
},
|
||||
[NMTD_VOL_KEY] = {.len = NMTD_VOL_KEY_SIZE << 3,
|
||||
.label = "volume-nmtd-key-generation"},
|
||||
[NMTD_LINK_KEY] = {.len = 128, .label = "link-nmtd-authentication"},
|
||||
[EMTD_FILE_KEY] = {.len = 128, .label = "file-emtd-encryption-and-auth"},
|
||||
[DATA_FILE_KEY_256] = {.len = 256, .label = "file-data-encryption-256"},
|
||||
[DATA_FILE_KEY_512] = {.len = 512, .label = "file-data-encryption-512"}};
|
||||
|
||||
/*
|
||||
Local variables:
|
||||
c-indentation-style: "K&R"
|
||||
mode-name: "LC"
|
||||
c-basic-offset: 8
|
||||
tab-width: 8
|
||||
fill-column: 80
|
||||
scroll-step: 1
|
||||
End:
|
||||
*/
|
@ -1,575 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2008-2012 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.
|
||||
*/
|
||||
|
||||
#include <glusterfs/defaults.h>
|
||||
#include "crypt-common.h"
|
||||
#include "crypt.h"
|
||||
#include "metadata.h"
|
||||
|
||||
int32_t
|
||||
alloc_format(crypt_local_t *local, size_t size)
|
||||
{
|
||||
if (size > 0) {
|
||||
local->format = GF_CALLOC(1, size, gf_crypt_mt_mtd);
|
||||
if (!local->format)
|
||||
return ENOMEM;
|
||||
}
|
||||
local->format_size = size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
alloc_format_create(crypt_local_t *local)
|
||||
{
|
||||
return alloc_format(local, new_format_size());
|
||||
}
|
||||
|
||||
void
|
||||
free_format(crypt_local_t *local)
|
||||
{
|
||||
GF_FREE(local->format);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check compatibility with extracted metadata
|
||||
*/
|
||||
static int32_t
|
||||
check_file_metadata(struct crypt_inode_info *info)
|
||||
{
|
||||
struct object_cipher_info *object = &info->cinfo;
|
||||
|
||||
if (info->nr_minor != CRYPT_XLATOR_ID) {
|
||||
gf_log("crypt", GF_LOG_WARNING, "unsupported minor subversion %d",
|
||||
info->nr_minor);
|
||||
return EINVAL;
|
||||
}
|
||||
if (object->o_alg > LAST_CIPHER_ALG) {
|
||||
gf_log("crypt", GF_LOG_WARNING, "unsupported cipher algorithm %d",
|
||||
object->o_alg);
|
||||
return EINVAL;
|
||||
}
|
||||
if (object->o_mode > LAST_CIPHER_MODE) {
|
||||
gf_log("crypt", GF_LOG_WARNING, "unsupported cipher mode %d",
|
||||
object->o_mode);
|
||||
return EINVAL;
|
||||
}
|
||||
if (object->o_block_bits < CRYPT_MIN_BLOCK_BITS ||
|
||||
object->o_block_bits > CRYPT_MAX_BLOCK_BITS) {
|
||||
gf_log("crypt", GF_LOG_WARNING, "unsupported block bits %d",
|
||||
object->o_block_bits);
|
||||
return EINVAL;
|
||||
}
|
||||
/* TBD: check data key size */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t
|
||||
format_size_v1(mtd_op_t op, size_t old_size)
|
||||
{
|
||||
switch (op) {
|
||||
case MTD_CREATE:
|
||||
return sizeof(struct mtd_format_v1);
|
||||
case MTD_OVERWRITE:
|
||||
return old_size;
|
||||
case MTD_APPEND:
|
||||
return old_size + NMTD_8_MAC_SIZE;
|
||||
case MTD_CUT:
|
||||
if (old_size > sizeof(struct mtd_format_v1))
|
||||
return old_size - NMTD_8_MAC_SIZE;
|
||||
else
|
||||
return 0;
|
||||
default:
|
||||
gf_log("crypt", GF_LOG_WARNING, "Bad mtd operation");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate size of the updated format string.
|
||||
* Returned zero means that we don't need to update the format string.
|
||||
*/
|
||||
size_t
|
||||
format_size(mtd_op_t op, size_t old_size)
|
||||
{
|
||||
size_t versioned;
|
||||
|
||||
versioned = mtd_loaders[current_mtd_loader()].format_size(
|
||||
op, old_size - sizeof(struct crypt_format));
|
||||
if (versioned != 0)
|
||||
return versioned + sizeof(struct crypt_format);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* size of the format string of newly created file (nr_links = 1)
|
||||
*/
|
||||
size_t
|
||||
new_format_size(void)
|
||||
{
|
||||
return format_size(MTD_CREATE, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate per-link MAC by pathname
|
||||
*/
|
||||
static int32_t
|
||||
calc_link_mac_v1(struct mtd_format_v1 *fmt, loc_t *loc, unsigned char *result,
|
||||
struct crypt_inode_info *info,
|
||||
struct master_cipher_info *master)
|
||||
{
|
||||
int32_t ret;
|
||||
unsigned char nmtd_link_key[16];
|
||||
CMAC_CTX *cctx;
|
||||
size_t len;
|
||||
|
||||
ret = get_nmtd_link_key(loc, master, nmtd_link_key);
|
||||
if (ret) {
|
||||
gf_log("crypt", GF_LOG_ERROR, "Can not get nmtd link key");
|
||||
return -1;
|
||||
}
|
||||
cctx = CMAC_CTX_new();
|
||||
if (!cctx) {
|
||||
gf_log("crypt", GF_LOG_ERROR, "CMAC_CTX_new failed");
|
||||
return -1;
|
||||
}
|
||||
ret = CMAC_Init(cctx, nmtd_link_key, sizeof(nmtd_link_key),
|
||||
EVP_aes_128_cbc(), 0);
|
||||
if (!ret) {
|
||||
gf_log("crypt", GF_LOG_ERROR, "CMAC_Init failed");
|
||||
CMAC_CTX_free(cctx);
|
||||
return -1;
|
||||
}
|
||||
ret = CMAC_Update(cctx, get_NMTD_V1(info), SIZE_OF_NMTD_V1);
|
||||
if (!ret) {
|
||||
gf_log("crypt", GF_LOG_ERROR, "CMAC_Update failed");
|
||||
CMAC_CTX_free(cctx);
|
||||
return -1;
|
||||
}
|
||||
ret = CMAC_Final(cctx, result, &len);
|
||||
CMAC_CTX_free(cctx);
|
||||
if (!ret) {
|
||||
gf_log("crypt", GF_LOG_ERROR, "CMAC_Final failed");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create per-link MAC of index @idx by pathname
|
||||
*/
|
||||
static int32_t
|
||||
create_link_mac_v1(struct mtd_format_v1 *fmt, uint32_t idx, loc_t *loc,
|
||||
struct crypt_inode_info *info,
|
||||
struct master_cipher_info *master)
|
||||
{
|
||||
int32_t ret;
|
||||
unsigned char *mac;
|
||||
unsigned char cmac[16];
|
||||
|
||||
mac = get_NMTD_V1_MAC(fmt) + idx * SIZE_OF_NMTD_V1_MAC;
|
||||
|
||||
ret = calc_link_mac_v1(fmt, loc, cmac, info, master);
|
||||
if (ret)
|
||||
return -1;
|
||||
memcpy(mac, cmac, SIZE_OF_NMTD_V1_MAC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
create_format_v1(unsigned char *wire, loc_t *loc, struct crypt_inode_info *info,
|
||||
struct master_cipher_info *master)
|
||||
{
|
||||
int32_t ret;
|
||||
struct mtd_format_v1 *fmt;
|
||||
unsigned char mtd_key[16];
|
||||
AES_KEY EMTD_KEY;
|
||||
unsigned char nmtd_link_key[16];
|
||||
uint32_t ad;
|
||||
GCM128_CONTEXT *gctx;
|
||||
|
||||
fmt = (struct mtd_format_v1 *)wire;
|
||||
|
||||
fmt->minor_id = info->nr_minor;
|
||||
fmt->alg_id = AES_CIPHER_ALG;
|
||||
fmt->dkey_factor = master->m_dkey_size >> KEY_FACTOR_BITS;
|
||||
fmt->block_bits = master->m_block_bits;
|
||||
fmt->mode_id = master->m_mode;
|
||||
/*
|
||||
* retrieve keys for the parts of metadata
|
||||
*/
|
||||
ret = get_emtd_file_key(info, master, mtd_key);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = get_nmtd_link_key(loc, master, nmtd_link_key);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
AES_set_encrypt_key(mtd_key, sizeof(mtd_key) * 8, &EMTD_KEY);
|
||||
|
||||
gctx = CRYPTO_gcm128_new(&EMTD_KEY, (block128_f)AES_encrypt);
|
||||
|
||||
/* TBD: Check return values */
|
||||
|
||||
CRYPTO_gcm128_setiv(gctx, info->oid, sizeof(uuid_t));
|
||||
|
||||
ad = htole32(MTD_LOADER_V1);
|
||||
ret = CRYPTO_gcm128_aad(gctx, (const unsigned char *)&ad, sizeof(ad));
|
||||
if (ret) {
|
||||
gf_log("crypt", GF_LOG_ERROR, " CRYPTO_gcm128_aad failed");
|
||||
CRYPTO_gcm128_release(gctx);
|
||||
return ret;
|
||||
}
|
||||
ret = CRYPTO_gcm128_encrypt(gctx, get_EMTD_V1(fmt), get_EMTD_V1(fmt),
|
||||
SIZE_OF_EMTD_V1);
|
||||
if (ret) {
|
||||
gf_log("crypt", GF_LOG_ERROR, " CRYPTO_gcm128_encrypt failed");
|
||||
CRYPTO_gcm128_release(gctx);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* set MAC of encrypted part of metadata
|
||||
*/
|
||||
CRYPTO_gcm128_tag(gctx, get_EMTD_V1_MAC(fmt), SIZE_OF_EMTD_V1_MAC);
|
||||
CRYPTO_gcm128_release(gctx);
|
||||
/*
|
||||
* set the first MAC of non-encrypted part of metadata
|
||||
*/
|
||||
return create_link_mac_v1(fmt, 0, loc, info, master);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by fops:
|
||||
* ->create();
|
||||
* ->link();
|
||||
*
|
||||
* Pack common and version-specific parts of file's metadata
|
||||
* Pre-conditions: @info contains valid object-id.
|
||||
*/
|
||||
int32_t
|
||||
create_format(unsigned char *wire, loc_t *loc, struct crypt_inode_info *info,
|
||||
struct master_cipher_info *master)
|
||||
{
|
||||
struct crypt_format *fmt = (struct crypt_format *)wire;
|
||||
|
||||
fmt->loader_id = current_mtd_loader();
|
||||
|
||||
wire += sizeof(struct crypt_format);
|
||||
return mtd_loaders[current_mtd_loader()].create_format(wire, loc, info,
|
||||
master);
|
||||
}
|
||||
|
||||
/*
|
||||
* Append or overwrite per-link mac of @mac_idx index
|
||||
* in accordance with the new pathname
|
||||
*/
|
||||
int32_t
|
||||
appov_link_mac_v1(unsigned char *new, unsigned char *old, uint32_t old_size,
|
||||
int32_t mac_idx, loc_t *loc, struct crypt_inode_info *info,
|
||||
struct master_cipher_info *master, crypt_local_t *local)
|
||||
{
|
||||
memcpy(new, old, old_size);
|
||||
return create_link_mac_v1((struct mtd_format_v1 *)new, mac_idx, loc, info,
|
||||
master);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cut per-link mac of @mac_idx index
|
||||
*/
|
||||
static int32_t
|
||||
cut_link_mac_v1(unsigned char *new, unsigned char *old, uint32_t old_size,
|
||||
int32_t mac_idx, loc_t *loc, struct crypt_inode_info *info,
|
||||
struct master_cipher_info *master, crypt_local_t *local)
|
||||
{
|
||||
memcpy(new, old,
|
||||
sizeof(struct mtd_format_v1) + NMTD_8_MAC_SIZE * (mac_idx - 1));
|
||||
|
||||
memcpy(
|
||||
new + sizeof(struct mtd_format_v1) + NMTD_8_MAC_SIZE *(mac_idx - 1),
|
||||
old + sizeof(struct mtd_format_v1) + NMTD_8_MAC_SIZE * mac_idx,
|
||||
old_size - (sizeof(struct mtd_format_v1) + NMTD_8_MAC_SIZE * mac_idx));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
update_format_v1(unsigned char *new, unsigned char *old, size_t old_len,
|
||||
int32_t mac_idx, /* of old name */
|
||||
mtd_op_t op, loc_t *loc, struct crypt_inode_info *info,
|
||||
struct master_cipher_info *master, crypt_local_t *local)
|
||||
{
|
||||
switch (op) {
|
||||
case MTD_APPEND:
|
||||
mac_idx = 1 + (old_len - sizeof(struct mtd_format_v1)) / 8;
|
||||
case MTD_OVERWRITE:
|
||||
return appov_link_mac_v1(new, old, old_len, mac_idx, loc, info,
|
||||
master, local);
|
||||
case MTD_CUT:
|
||||
return cut_link_mac_v1(new, old, old_len, mac_idx, loc, info,
|
||||
master, local);
|
||||
default:
|
||||
gf_log("crypt", GF_LOG_ERROR, "Bad mtd operation %d", op);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Called by fops:
|
||||
*
|
||||
* ->link()
|
||||
* ->unlink()
|
||||
* ->rename()
|
||||
*
|
||||
*/
|
||||
int32_t
|
||||
update_format(unsigned char *new, unsigned char *old, size_t old_len,
|
||||
int32_t mac_idx, mtd_op_t op, loc_t *loc,
|
||||
struct crypt_inode_info *info, struct master_cipher_info *master,
|
||||
crypt_local_t *local)
|
||||
{
|
||||
if (!new)
|
||||
return 0;
|
||||
memcpy(new, old, sizeof(struct crypt_format));
|
||||
|
||||
old += sizeof(struct crypt_format);
|
||||
new += sizeof(struct crypt_format);
|
||||
old_len -= sizeof(struct crypt_format);
|
||||
|
||||
return mtd_loaders[current_mtd_loader()].update_format(
|
||||
new, old, old_len, mac_idx, op, loc, info, master, local);
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform preliminary checks of found metadata
|
||||
* Return < 0 on errors;
|
||||
* Return number of object-id MACs (>= 1) on success
|
||||
*/
|
||||
int32_t
|
||||
check_format_v1(uint32_t len, unsigned char *wire)
|
||||
{
|
||||
uint32_t nr_links;
|
||||
|
||||
if (len < sizeof(struct mtd_format_v1)) {
|
||||
gf_log("crypt", GF_LOG_ERROR, "v1-loader: bad metadata size %d", len);
|
||||
goto error;
|
||||
}
|
||||
len -= sizeof(struct mtd_format_v1);
|
||||
if (len % sizeof(nmtd_8_mac_t)) {
|
||||
gf_log("crypt", GF_LOG_ERROR, "v1-loader: bad metadata format");
|
||||
goto error;
|
||||
}
|
||||
nr_links = 1 + len / sizeof(nmtd_8_mac_t);
|
||||
if (nr_links > _POSIX_LINK_MAX)
|
||||
goto error;
|
||||
return nr_links;
|
||||
error:
|
||||
return EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify per-link MAC specified by index @idx
|
||||
*
|
||||
* return:
|
||||
* -1 on errors;
|
||||
* 0 on failed verification;
|
||||
* 1 on successful verification
|
||||
*/
|
||||
static int32_t
|
||||
verify_link_mac_v1(struct mtd_format_v1 *fmt,
|
||||
uint32_t idx /* index of the mac to verify */, loc_t *loc,
|
||||
struct crypt_inode_info *info,
|
||||
struct master_cipher_info *master)
|
||||
{
|
||||
int32_t ret;
|
||||
unsigned char *mac;
|
||||
unsigned char cmac[16];
|
||||
|
||||
mac = get_NMTD_V1_MAC(fmt) + idx * SIZE_OF_NMTD_V1_MAC;
|
||||
|
||||
ret = calc_link_mac_v1(fmt, loc, cmac, info, master);
|
||||
if (ret)
|
||||
return -1;
|
||||
if (memcmp(cmac, mac, SIZE_OF_NMTD_V1_MAC))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Lookup per-link MAC by pathname.
|
||||
*
|
||||
* return index of the MAC, if it was found;
|
||||
* return < 0 on errors, or if the MAC wasn't found
|
||||
*/
|
||||
static int32_t
|
||||
lookup_link_mac_v1(struct mtd_format_v1 *fmt, uint32_t nr_macs, loc_t *loc,
|
||||
struct crypt_inode_info *info,
|
||||
struct master_cipher_info *master)
|
||||
{
|
||||
int32_t ret;
|
||||
uint32_t idx;
|
||||
|
||||
for (idx = 0; idx < nr_macs; idx++) {
|
||||
ret = verify_link_mac_v1(fmt, idx, loc, info, master);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret > 0)
|
||||
return idx;
|
||||
}
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract version-specific part of metadata
|
||||
*/
|
||||
static int32_t
|
||||
open_format_v1(unsigned char *wire, int32_t len, loc_t *loc,
|
||||
struct crypt_inode_info *info, struct master_cipher_info *master,
|
||||
crypt_local_t *local, gf_boolean_t load_info)
|
||||
{
|
||||
int32_t ret;
|
||||
int32_t num_nmtd_macs;
|
||||
struct mtd_format_v1 *fmt;
|
||||
unsigned char mtd_key[16];
|
||||
AES_KEY EMTD_KEY;
|
||||
GCM128_CONTEXT *gctx;
|
||||
uint32_t ad;
|
||||
emtd_8_mac_t gmac;
|
||||
struct object_cipher_info *object;
|
||||
|
||||
num_nmtd_macs = check_format_v1(len, wire);
|
||||
if (num_nmtd_macs <= 0)
|
||||
return EIO;
|
||||
|
||||
ret = lookup_link_mac_v1((struct mtd_format_v1 *)wire, num_nmtd_macs, loc,
|
||||
info, master);
|
||||
if (ret < 0) {
|
||||
gf_log("crypt", GF_LOG_ERROR, "NMTD verification failed");
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
local->mac_idx = ret;
|
||||
if (load_info == _gf_false)
|
||||
/* the case of partial open */
|
||||
return 0;
|
||||
|
||||
fmt = GF_MALLOC(len, gf_crypt_mt_mtd);
|
||||
if (!fmt)
|
||||
return ENOMEM;
|
||||
memcpy(fmt, wire, len);
|
||||
|
||||
object = &info->cinfo;
|
||||
|
||||
ret = get_emtd_file_key(info, master, mtd_key);
|
||||
if (ret) {
|
||||
gf_log("crypt", GF_LOG_ERROR, "Can not retrieve metadata key");
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* decrypt encrypted meta-data
|
||||
*/
|
||||
ret = AES_set_encrypt_key(mtd_key, sizeof(mtd_key) * 8, &EMTD_KEY);
|
||||
if (ret < 0) {
|
||||
gf_log("crypt", GF_LOG_ERROR, "Can not set encrypt key");
|
||||
ret = EIO;
|
||||
goto out;
|
||||
}
|
||||
gctx = CRYPTO_gcm128_new(&EMTD_KEY, (block128_f)AES_encrypt);
|
||||
if (!gctx) {
|
||||
gf_log("crypt", GF_LOG_ERROR, "Can not alloc gcm context");
|
||||
ret = ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
CRYPTO_gcm128_setiv(gctx, info->oid, sizeof(uuid_t));
|
||||
|
||||
ad = htole32(MTD_LOADER_V1);
|
||||
ret = CRYPTO_gcm128_aad(gctx, (const unsigned char *)&ad, sizeof(ad));
|
||||
if (ret) {
|
||||
gf_log("crypt", GF_LOG_ERROR, " CRYPTO_gcm128_aad failed");
|
||||
CRYPTO_gcm128_release(gctx);
|
||||
ret = EIO;
|
||||
goto out;
|
||||
}
|
||||
ret = CRYPTO_gcm128_decrypt(gctx, get_EMTD_V1(fmt), get_EMTD_V1(fmt),
|
||||
SIZE_OF_EMTD_V1);
|
||||
if (ret) {
|
||||
gf_log("crypt", GF_LOG_ERROR, " CRYPTO_gcm128_decrypt failed");
|
||||
CRYPTO_gcm128_release(gctx);
|
||||
ret = EIO;
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* verify metadata
|
||||
*/
|
||||
CRYPTO_gcm128_tag(gctx, gmac, sizeof(gmac));
|
||||
CRYPTO_gcm128_release(gctx);
|
||||
if (memcmp(gmac, get_EMTD_V1_MAC(fmt), SIZE_OF_EMTD_V1_MAC)) {
|
||||
gf_log("crypt", GF_LOG_ERROR, "EMTD verification failed");
|
||||
ret = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* load verified metadata to the private part of inode
|
||||
*/
|
||||
info->nr_minor = fmt->minor_id;
|
||||
|
||||
object->o_alg = fmt->alg_id;
|
||||
object->o_dkey_size = fmt->dkey_factor << KEY_FACTOR_BITS;
|
||||
object->o_block_bits = fmt->block_bits;
|
||||
object->o_mode = fmt->mode_id;
|
||||
|
||||
ret = check_file_metadata(info);
|
||||
out:
|
||||
GF_FREE(fmt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* perform metadata authentication against @loc->path;
|
||||
* extract crypt-specific attribute and populate @info
|
||||
* with them (optional)
|
||||
*/
|
||||
int32_t
|
||||
open_format(unsigned char *str, int32_t len, loc_t *loc,
|
||||
struct crypt_inode_info *info, struct master_cipher_info *master,
|
||||
crypt_local_t *local, gf_boolean_t load_info)
|
||||
{
|
||||
struct crypt_format *fmt;
|
||||
if (len < sizeof(*fmt)) {
|
||||
gf_log("crypt", GF_LOG_ERROR, "Bad core format");
|
||||
return EIO;
|
||||
}
|
||||
fmt = (struct crypt_format *)str;
|
||||
|
||||
if (fmt->loader_id >= LAST_MTD_LOADER) {
|
||||
gf_log("crypt", GF_LOG_ERROR, "Unsupported loader id %d",
|
||||
fmt->loader_id);
|
||||
return EINVAL;
|
||||
}
|
||||
str += sizeof(*fmt);
|
||||
len -= sizeof(*fmt);
|
||||
|
||||
return mtd_loaders[fmt->loader_id].open_format(str, len, loc, info, master,
|
||||
local, load_info);
|
||||
}
|
||||
|
||||
struct crypt_mtd_loader mtd_loaders[LAST_MTD_LOADER] = {
|
||||
[MTD_LOADER_V1] = {.format_size = format_size_v1,
|
||||
.create_format = create_format_v1,
|
||||
.open_format = open_format_v1,
|
||||
.update_format = update_format_v1}};
|
||||
|
||||
/*
|
||||
Local variables:
|
||||
c-indentation-style: "K&R"
|
||||
mode-name: "LC"
|
||||
c-basic-offset: 8
|
||||
tab-width: 8
|
||||
fill-column: 80
|
||||
scroll-step: 1
|
||||
End:
|
||||
*/
|
@ -1,79 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2008-2013 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 __METADATA_H__
|
||||
#define __METADATA_H__
|
||||
|
||||
#define NMTD_8_MAC_SIZE (8)
|
||||
#define EMTD_8_MAC_SIZE (8)
|
||||
|
||||
typedef uint8_t nmtd_8_mac_t[NMTD_8_MAC_SIZE];
|
||||
typedef uint8_t emtd_8_mac_t[EMTD_8_MAC_SIZE];
|
||||
|
||||
/*
|
||||
* Version "v1" of file's metadata.
|
||||
* Metadata of this version has 4 components:
|
||||
*
|
||||
* 1) EMTD (Encrypted part of MeTaData);
|
||||
* 2) NMTD (Non-encrypted part of MeTaData);
|
||||
* 3) EMTD_MAC; (EMTD Message Authentication Code);
|
||||
* 4) Array of per-link NMTD MACs (for every (hard)link it includes
|
||||
* exactly one MAC)
|
||||
*/
|
||||
struct mtd_format_v1 {
|
||||
/* EMTD, encrypted part of meta-data */
|
||||
uint8_t alg_id; /* cipher algorithm id (only AES for now) */
|
||||
uint8_t mode_id; /* cipher mode id; (only XTS for now) */
|
||||
uint8_t block_bits; /* encoded block size */
|
||||
uint8_t minor_id; /* client translator id */
|
||||
uint8_t dkey_factor; /* encoded size of the data key */
|
||||
/* MACs */
|
||||
emtd_8_mac_t gmac; /* MAC of the encrypted meta-data, 8 bytes */
|
||||
nmtd_8_mac_t omac; /* per-link MACs of the non-encrypted
|
||||
* meta-data: at least one such MAC is always
|
||||
* present */
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* NMTD, the non-encrypted part of metadata of version "v1"
|
||||
* is file's gfid, which is generated on trusted machines.
|
||||
*/
|
||||
#define SIZE_OF_NMTD_V1 (sizeof(uuid_t))
|
||||
#define SIZE_OF_EMTD_V1 \
|
||||
(offsetof(struct mtd_format_v1, gmac) - \
|
||||
offsetof(struct mtd_format_v1, alg_id))
|
||||
#define SIZE_OF_NMTD_V1_MAC (NMTD_8_MAC_SIZE)
|
||||
#define SIZE_OF_EMTD_V1_MAC (EMTD_8_MAC_SIZE)
|
||||
|
||||
static inline unsigned char *
|
||||
get_EMTD_V1(struct mtd_format_v1 *format)
|
||||
{
|
||||
return &format->alg_id;
|
||||
}
|
||||
|
||||
static inline unsigned char *
|
||||
get_NMTD_V1(struct crypt_inode_info *info)
|
||||
{
|
||||
return info->oid;
|
||||
}
|
||||
|
||||
static inline unsigned char *
|
||||
get_EMTD_V1_MAC(struct mtd_format_v1 *format)
|
||||
{
|
||||
return format->gmac;
|
||||
}
|
||||
|
||||
static inline unsigned char *
|
||||
get_NMTD_V1_MAC(struct mtd_format_v1 *format)
|
||||
{
|
||||
return format->omac;
|
||||
}
|
||||
|
||||
#endif /* __METADATA_H__ */
|
@ -1,3 +0,0 @@
|
||||
SUBDIRS = src
|
||||
|
||||
CLEANFILES =
|
@ -1,3 +0,0 @@
|
||||
SUBDIRS = jbr-client jbr-server fdl dht2 posix2
|
||||
|
||||
CLEANFILES =
|
@ -1,107 +0,0 @@
|
||||
# Purpose of this directory
|
||||
|
||||
This directory is created to host experimental gluster translators. A new
|
||||
translator that is *experimental* in nature, would need to create its own
|
||||
subdirectory under this directory, to host/publish its work.
|
||||
|
||||
Example:
|
||||
The first commit should include the following changes
|
||||
1. xlators/experimental/Makefile.am
|
||||
NOTE: Add foobar to the list of SUBDIRS here
|
||||
2. xlators/experimental/foobar
|
||||
3. xlators/experimental/foobar/Makefle.am
|
||||
NOTE: Can be empty initially in the first commit
|
||||
4. configure.ac
|
||||
NOTE: Include your experimental Makefile under AC_CONFIG_FILES
|
||||
5. xlators/experimental/foobar/README.md
|
||||
NOTE: The readme should cover details as required for the translator to be
|
||||
accepted as experimental, primarily including a link to the specification
|
||||
under the gluster-specs repository [1]. Later the readme should suffice
|
||||
as an entry point for developers and users alike, who wish to experiment
|
||||
with the xlator under development
|
||||
6. xlators/experimental/foobar/TODO.md
|
||||
NOTE: This is a list of TODO's identified during the development process
|
||||
that needs addressing over time. These include exceptions granted during
|
||||
the review process, for things not addressed when commits are merged into
|
||||
the repository
|
||||
|
||||
# Why is it provided
|
||||
|
||||
Quite often translator development that happens out of tree, does not get
|
||||
enough eyeballs early in its development phase, has not undergone CI
|
||||
(regression/continuous integration testing), and at times is not well integrated
|
||||
with the rest of gluster stack.
|
||||
|
||||
Also, when such out of tree translators are submitted for acceptance, it is a
|
||||
bulk commit that makes review difficult and inefficient. Such submissions also
|
||||
have to be merged forward, and depending on the time spent in developing the
|
||||
translator the master branch could have moved far ahead, making this a painful
|
||||
activity.
|
||||
|
||||
Experimental is born out of such needs, to provide xlator developers,
|
||||
- Early access to CI
|
||||
- Ability to adapt to ongoing changes in other parts of gluster
|
||||
- More eye balls on the code and design aspects of the translator
|
||||
- TBD: What else?
|
||||
|
||||
and for maintainers,
|
||||
- Ability to look at smaller change sets in the review process
|
||||
- Ability to verify/check implementation against the specification provided
|
||||
|
||||
# General rules
|
||||
|
||||
1. If a new translator is added under here it should, at the very least, pass
|
||||
compilation.
|
||||
|
||||
2. All translators under the experimental directory are shipped as a part of
|
||||
gluster-experimental RPMs.
|
||||
TBD: Spec file and other artifacts for the gluster-experimental RPM needs to be
|
||||
fleshed out.
|
||||
|
||||
3. Experimental translators can leverage the CI framework as needed. Tests need
|
||||
to be hosted under xlators/experimental/tests initially, and later moved to the
|
||||
appropriate tests/ directory as the xlator matures. It is encouraged to provide
|
||||
tests for each commit or series of commits, so that code and tests can be
|
||||
inspected together.
|
||||
|
||||
4. If any experimental translator breaks CI, it is quarantined till demonstrable
|
||||
proof towards the contrary is provided. This is applicable as tests are moved
|
||||
out of experimental tests directory to the CI framework directory, as otherwise
|
||||
experimental tests are not a part of regular CI regression runs.
|
||||
|
||||
5. An experimental translator need not function at all, as a result commits can
|
||||
be merged pretty much at will as long as other rules as stated are not violated.
|
||||
|
||||
6. Experimental submissions will be assigned a existing maintainer, to aid
|
||||
merging commits and ensure aspects of gluster code submissions are respected.
|
||||
When an experimental xlator is proposed and the first commit posted
|
||||
a mail to gluster-devel@gluster.org requesting attention, will assign the
|
||||
maintainer buddy for the submission.
|
||||
NOTE: As we scale, this may change.
|
||||
|
||||
6. More?
|
||||
|
||||
# Getting out of the experimental jail
|
||||
|
||||
So you now think your xlator is ready to leave experimental and become part of
|
||||
mainline!
|
||||
- TBD: guidelines pending.
|
||||
|
||||
# FAQs
|
||||
|
||||
1. How do I submit/commit experimental framework changes outside of my
|
||||
experimental xlator?
|
||||
- Provide such framework changes as a separate commit
|
||||
- Conditionally ensure these are built or activated only when the experimental
|
||||
feature is activated, so as to prevent normal gluster workflow to function as
|
||||
before
|
||||
- TBD: guidelines and/or examples pending.
|
||||
|
||||
2. Ask your question either on gluster-devel@gluster.org or as a change request
|
||||
to this file in gluster gerrit [2] for an answer that will be assimilated into
|
||||
this readme.
|
||||
|
||||
# Links
|
||||
[1] http://review.gluster.org/#/q/project:glusterfs-specs
|
||||
|
||||
[2] http://review.gluster.org/#/q/project:glusterfs
|
@ -1,3 +0,0 @@
|
||||
SUBDIRS = dht2-client dht2-server
|
||||
|
||||
CLEANFILES =
|
@ -1,47 +0,0 @@
|
||||
# DHT2 Experimental README
|
||||
|
||||
DHT2 is the new distribution scheme being developed for Gluster, that
|
||||
aims to remove the subdirectory spread across all DHT subvolumes.
|
||||
|
||||
As a result of this work, the Gluster backend file layouts and on disk
|
||||
representation of directories and files are modified, thus making DHT2
|
||||
volumes incompatible to existing DHT based Gluster deployments.
|
||||
|
||||
This document presents interested users with relevant data to play around
|
||||
with DHT2 volumes and provide feedback towards the same.
|
||||
|
||||
REMOVEME: Design details currently under review here,
|
||||
- http://review.gluster.org/#/c/13395/
|
||||
|
||||
TODO: Add more information as relevant code is pulled in
|
||||
|
||||
# Directory strucutre elaborated
|
||||
|
||||
## dht2-server
|
||||
This directory contains code for the server side DHT2 xlator. This xlator is
|
||||
intended to run on the brick graph, and is responsible for FOP synchronization,
|
||||
redirection, transactions, and journal replays.
|
||||
|
||||
NOTE: The server side code also handles changes to volume/cluster map and
|
||||
also any rebalance activities.
|
||||
|
||||
## dht2-client
|
||||
This directory contains code for the client side DHT2 xlator. This xlator is
|
||||
intended to run on the client/access protocol/mount graph, and is responsible
|
||||
for FOP routing to the right DHT2 subvolume. It uses a volume/cluster wide map
|
||||
of the routing (layout), to achieve the same.
|
||||
|
||||
## dht2-common
|
||||
This directory contains code that is used in common across other parts of DHT2.
|
||||
For example, FOP routing store/consult abstractions that are common across the
|
||||
client and server side of DHT2.
|
||||
|
||||
## Issue: How to build dht2-common?
|
||||
1. Build a shared object
|
||||
- We cannot ship this as a part of both the client xlator RPM
|
||||
2. Build an archive
|
||||
- Symbol clashes? when both the client and server xlators are loaded as a
|
||||
part of the same graph
|
||||
3. Compile with other parts of the code that needs it
|
||||
- Not a very different from (2) above
|
||||
- This is what is chosen at present, and maybe would be revised later
|
@ -1,3 +0,0 @@
|
||||
# DHT2 TODO list
|
||||
|
||||
<Items will be added as code is pulled into the repository>
|
@ -1,3 +0,0 @@
|
||||
SUBDIRS = src
|
||||
|
||||
CLEANFILES =
|
@ -1,21 +0,0 @@
|
||||
xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/experimental
|
||||
xlator_LTLIBRARIES = dht2c.la
|
||||
|
||||
dht2c_sources = dht2-client-main.c
|
||||
|
||||
dht2common_sources = $(top_srcdir)/xlators/experimental/dht2/dht2-common/src/dht2-common-map.c
|
||||
|
||||
dht2c_la_SOURCES = $(dht2c_sources) $(dht2common_sources)
|
||||
dht2c_la_LDFLAGS = -module $(GF_XLATOR_DEFAULT_LDFLAGS)
|
||||
dht2c_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la
|
||||
|
||||
AM_CFLAGS = -Wall $(GF_CFLAGS)
|
||||
|
||||
AM_CPPFLAGS = $(GF_CPPFLAGS)
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/xlators/experimental/dht2/dht2-common/src/
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/libglusterfs/src
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/rpc/xdr/src
|
||||
AM_CPPFLAGS += -I$(top_builddir)/rpc/xdr/src
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/xlators/lib/src
|
||||
|
||||
CLEANFILES =
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 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.
|
||||
*/
|
||||
|
||||
/* File: dht2-client-main.c
|
||||
* This file contains the xlator loading functions, FOP entry points
|
||||
* and options.
|
||||
* The entire functionality including comments is TODO.
|
||||
*/
|
||||
|
||||
#include <glusterfs/glusterfs.h>
|
||||
#include <glusterfs/xlator.h>
|
||||
#include <glusterfs/logging.h>
|
||||
#include <glusterfs/statedump.h>
|
||||
|
||||
int32_t
|
||||
dht2_client_init(xlator_t *this)
|
||||
{
|
||||
if (!this->children) {
|
||||
gf_log(this->name, GF_LOG_ERROR,
|
||||
"Missing children in volume graph, this (%s) is"
|
||||
" not a leaf translator",
|
||||
this->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
dht2_client_fini(xlator_t *this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
class_methods_t class_methods = {
|
||||
.init = dht2_client_init,
|
||||
.fini = dht2_client_fini,
|
||||
};
|
||||
|
||||
struct xlator_fops fops = {};
|
||||
|
||||
struct xlator_cbks cbks = {};
|
||||
|
||||
/*
|
||||
struct xlator_dumpops dumpops = {
|
||||
};
|
||||
*/
|
||||
|
||||
struct volume_options options[] = {
|
||||
{.key = {NULL}},
|
||||
};
|
@ -1,19 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 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.
|
||||
*/
|
||||
|
||||
/* File: dht2-common-map.c
|
||||
* This file contains helper routines to store, consult, the volume map
|
||||
* for subvolume to GFID relations.
|
||||
* The entire functionality including comments is TODO.
|
||||
*/
|
||||
|
||||
#include <glusterfs/glusterfs.h>
|
||||
#include <glusterfs/logging.h>
|
||||
#include <glusterfs/statedump.h>
|
@ -1,3 +0,0 @@
|
||||
SUBDIRS = src
|
||||
|
||||
CLEANFILES =
|
@ -1,23 +0,0 @@
|
||||
if WITH_SERVER
|
||||
xlator_LTLIBRARIES = dht2s.la
|
||||
endif
|
||||
xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/experimental
|
||||
|
||||
dht2s_sources = dht2-server-main.c
|
||||
|
||||
dht2common_sources = $(top_srcdir)/xlators/experimental/dht2/dht2-common/src/dht2-common-map.c
|
||||
|
||||
dht2s_la_SOURCES = $(dht2s_sources) $(dht2common_sources)
|
||||
dht2s_la_LDFLAGS = -module $(GF_XLATOR_DEFAULT_LDFLAGS)
|
||||
dht2s_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la
|
||||
|
||||
AM_CFLAGS = -Wall $(GF_CFLAGS)
|
||||
|
||||
AM_CPPFLAGS = $(GF_CPPFLAGS)
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/xlators/experimental/dht2/dht2-common/src/
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/libglusterfs/src
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/rpc/xdr/src
|
||||
AM_CPPFLAGS += -I$(top_builddir)/rpc/xdr/src
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/xlators/lib/src
|
||||
|
||||
CLEANFILES =
|
@ -1,58 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 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.
|
||||
*/
|
||||
|
||||
/* File: dht2-server-main.c
|
||||
* This file contains the xlator loading functions, FOP entry points
|
||||
* and options.
|
||||
* The entire functionality including comments is TODO.
|
||||
*/
|
||||
|
||||
#include <glusterfs/glusterfs.h>
|
||||
#include <glusterfs/xlator.h>
|
||||
#include <glusterfs/logging.h>
|
||||
#include <glusterfs/statedump.h>
|
||||
|
||||
int32_t
|
||||
dht2_server_init(xlator_t *this)
|
||||
{
|
||||
if (!this->children) {
|
||||
gf_log(this->name, GF_LOG_ERROR,
|
||||
"Missing children in volume graph, this (%s) is"
|
||||
" not a leaf translator",
|
||||
this->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
dht2_server_fini(xlator_t *this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
class_methods_t class_methods = {
|
||||
.init = dht2_server_init,
|
||||
.fini = dht2_server_fini,
|
||||
};
|
||||
|
||||
struct xlator_fops fops = {};
|
||||
|
||||
struct xlator_cbks cbks = {};
|
||||
|
||||
/*
|
||||
struct xlator_dumpops dumpops = {
|
||||
};
|
||||
*/
|
||||
|
||||
struct volume_options options[] = {
|
||||
{.key = {NULL}},
|
||||
};
|
@ -1,3 +0,0 @@
|
||||
SUBDIRS = src
|
||||
|
||||
CLEANFILES =
|
@ -1,48 +0,0 @@
|
||||
xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/experimental
|
||||
if WITH_SERVER
|
||||
xlator_LTLIBRARIES = fdl.la
|
||||
endif
|
||||
|
||||
noinst_HEADERS = fdl.h
|
||||
|
||||
nodist_fdl_la_SOURCES = fdl.c
|
||||
fdl_la_LDFLAGS = -module $(GF_XLATOR_DEFAULT_LDFLAGS)
|
||||
fdl_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la
|
||||
|
||||
if WITH_SERVER
|
||||
sbin_PROGRAMS = gf_logdump gf_recon
|
||||
endif
|
||||
gf_logdump_SOURCES = logdump.c
|
||||
nodist_gf_logdump_SOURCES = libfdl.c
|
||||
gf_logdump_LDADD = $(top_builddir)/libglusterfs/src/libglusterfs.la \
|
||||
$(top_builddir)/api/src/libgfapi.la $(GFAPI_LIBS) $(UUID_LIBS)
|
||||
|
||||
# Eventually recon(ciliation) code will move elsewhere, but for now it's
|
||||
# easier to have it next to the similar logdump code.
|
||||
gf_recon_SOURCES = recon.c
|
||||
nodist_gf_recon_SOURCES = librecon.c
|
||||
gf_recon_LDADD = $(top_builddir)/libglusterfs/src/libglusterfs.la \
|
||||
$(top_builddir)/api/src/libgfapi.la $(GFAPI_LIBS) $(UUID_LIBS)
|
||||
|
||||
AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \
|
||||
-I$(top_srcdir)/rpc/xdr/src -I$(top_builddir)/rpc/xdr/src \
|
||||
-I$(top_srcdir)/api/src -fPIC \
|
||||
-D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -D$(GF_HOST_OS) \
|
||||
-DDATADIR=\"$(localstatedir)\"
|
||||
|
||||
AM_CFLAGS = -Wall $(GF_CFLAGS)
|
||||
|
||||
noinst_PYTHON = gen_fdl.py gen_dumper.py gen_recon.py
|
||||
EXTRA_DIST = fdl-tmpl.c.in dump-tmpl.c.in recon-tmpl.c.in
|
||||
|
||||
CLEANFILES = $(nodist_fdl_la_SOURCES) $(nodist_gf_logdump_SOURCES) \
|
||||
$(nodist_gf_recon_SOURCES)
|
||||
|
||||
fdl.c: fdl-tmpl.c.in gen_fdl.py
|
||||
$(PYTHON) $(srcdir)/gen_fdl.py $(srcdir)/fdl-tmpl.c.in > $@
|
||||
|
||||
libfdl.c: dump-tmpl.c.in gen_dumper.py
|
||||
$(PYTHON) $(srcdir)/gen_dumper.py $(srcdir)/dump-tmpl.c.in > $@
|
||||
|
||||
librecon.c: recon-tmpl.c.in gen_recon.py
|
||||
$(PYTHON) $(srcdir)/gen_recon.py $(srcdir)/recon-tmpl.c.in > $@
|
@ -1,177 +0,0 @@
|
||||
#pragma fragment PROLOG
|
||||
#ifndef _CONFIG_H
|
||||
#define _CONFIG_H
|
||||
#include "config.h"
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
|
||||
#include "glfs.h"
|
||||
#include "iatt.h"
|
||||
#include "xlator.h"
|
||||
#include "fdl.h"
|
||||
|
||||
/*
|
||||
* Returns 0 if the string is ASCII printable *
|
||||
* and -1 if it's not ASCII printable *
|
||||
*/
|
||||
int
|
||||
str_isprint(char *s)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (!s)
|
||||
goto out;
|
||||
|
||||
while (s[0] != '\0') {
|
||||
if (!isprint(s[0]))
|
||||
goto out;
|
||||
else
|
||||
s++;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#pragma fragment DICT
|
||||
{
|
||||
int key_len, data_len;
|
||||
char *key_ptr;
|
||||
char *key_val;
|
||||
printf("@ARGNAME@ = dict {\n");
|
||||
for (;;) {
|
||||
key_len = *((int *)new_meta);
|
||||
new_meta += sizeof(int);
|
||||
if (!key_len) {
|
||||
break;
|
||||
}
|
||||
key_ptr = new_meta;
|
||||
new_meta += key_len;
|
||||
data_len = *((int *)new_meta);
|
||||
key_val = new_meta + sizeof(int);
|
||||
new_meta += sizeof(int) + data_len;
|
||||
if (str_isprint(key_val))
|
||||
printf(" %s = <%d bytes>\n", key_ptr, data_len);
|
||||
else
|
||||
printf(" %s = %s <%d bytes>\n", key_ptr, key_val, data_len);
|
||||
}
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
#pragma fragment DOUBLE
|
||||
printf("@ARGNAME@ = @FORMAT@\n", *((uint64_t *)new_meta),
|
||||
*((uint64_t *)new_meta));
|
||||
new_meta += sizeof(uint64_t);
|
||||
|
||||
#pragma fragment GFID
|
||||
printf("@ARGNAME@ = <gfid %s>\n", uuid_utoa(*((uuid_t *)new_meta)));
|
||||
new_meta += 16;
|
||||
|
||||
#pragma fragment INTEGER
|
||||
printf("@ARGNAME@ = @FORMAT@\n", *((uint32_t *)new_meta),
|
||||
*((uint32_t *)new_meta));
|
||||
new_meta += sizeof(uint32_t);
|
||||
|
||||
#pragma fragment LOC
|
||||
printf("@ARGNAME@ = loc {\n");
|
||||
printf(" gfid = %s\n", uuid_utoa(*((uuid_t *)new_meta)));
|
||||
new_meta += 16;
|
||||
printf(" pargfid = %s\n", uuid_utoa(*((uuid_t *)new_meta)));
|
||||
new_meta += 16;
|
||||
if (*(new_meta++)) {
|
||||
printf(" name = %s\n", new_meta);
|
||||
new_meta += (strlen(new_meta) + 1);
|
||||
}
|
||||
printf("}\n");
|
||||
|
||||
#pragma fragment STRING
|
||||
if (*(new_meta++)) {
|
||||
printf("@ARGNAME@ = %s\n", new_meta);
|
||||
new_meta += (strlen(new_meta) + 1);
|
||||
}
|
||||
|
||||
#pragma fragment VECTOR
|
||||
{
|
||||
size_t len = *((size_t *)new_meta);
|
||||
new_meta += sizeof(len);
|
||||
printf("@ARGNAME@ = <%zu bytes>\n", len);
|
||||
new_data += len;
|
||||
}
|
||||
|
||||
#pragma fragment IATT
|
||||
{
|
||||
ia_prot_t *myprot = ((ia_prot_t *)new_meta);
|
||||
printf("@ARGNAME@ = iatt {\n");
|
||||
printf(" ia_prot = %c%c%c", myprot->suid ? 'S' : '-',
|
||||
myprot->sgid ? 'S' : '-', myprot->sticky ? 'T' : '-');
|
||||
printf("%c%c%c", myprot->owner.read ? 'r' : '-',
|
||||
myprot->owner.write ? 'w' : '-', myprot->owner.exec ? 'x' : '-');
|
||||
printf("%c%c%c", myprot->group.read ? 'r' : '-',
|
||||
myprot->group.write ? 'w' : '-', myprot->group.exec ? 'x' : '-');
|
||||
printf("%c%c%c\n", myprot->other.read ? 'r' : '-',
|
||||
myprot->other.write ? 'w' : '-', myprot->other.exec ? 'x' : '-');
|
||||
new_meta += sizeof(ia_prot_t);
|
||||
uint32_t *myints = (uint32_t *)new_meta;
|
||||
printf(" ia_uid = %u\n", myints[0]);
|
||||
printf(" ia_gid = %u\n", myints[1]);
|
||||
printf(" ia_atime = %u.%09u\n", myints[2], myints[3]);
|
||||
printf(" ia_mtime = %u.%09u\n", myints[4], myints[5]);
|
||||
new_meta += sizeof(*myints) * 6;
|
||||
}
|
||||
|
||||
#pragma fragment FOP
|
||||
void fdl_dump_@NAME@(char **old_meta, char **old_data)
|
||||
{
|
||||
char *new_meta = *old_meta;
|
||||
char *new_data = *old_data;
|
||||
|
||||
/* TBD: word size/endianness */
|
||||
@FUNCTION_BODY@
|
||||
|
||||
*old_meta = new_meta;
|
||||
*old_data = new_data;
|
||||
}
|
||||
|
||||
#pragma fragment CASE
|
||||
case GF_FOP_@UPNAME@:
|
||||
printf("=== GF_FOP_@UPNAME@\n");
|
||||
fdl_dump_@NAME@(&new_meta, &new_data);
|
||||
break;
|
||||
|
||||
#pragma fragment EPILOG
|
||||
int
|
||||
fdl_dump(char **old_meta, char **old_data)
|
||||
{
|
||||
char *new_meta = *old_meta;
|
||||
char *new_data = *old_data;
|
||||
static glfs_t *fs = NULL;
|
||||
int recognized = 1;
|
||||
event_header_t *eh;
|
||||
|
||||
/*
|
||||
* We don't really call anything else in GFAPI, but this is the most
|
||||
* convenient way to satisfy all of the spurious dependencies on how it
|
||||
* or glusterfsd initialize (e.g. setting up THIS).
|
||||
*/
|
||||
if (!fs) {
|
||||
fs = glfs_new("dummy");
|
||||
}
|
||||
|
||||
eh = (event_header_t *)new_meta;
|
||||
new_meta += sizeof(*eh);
|
||||
|
||||
/* TBD: check event_type instead of assuming NEW_REQUEST */
|
||||
|
||||
switch (eh->fop_type) {
|
||||
@SWITCH_BODY@
|
||||
|
||||
default :
|
||||
printf("unknown fop %u\n", eh->fop_type);
|
||||
recognized = 0;
|
||||
}
|
||||
|
||||
*old_meta = new_meta;
|
||||
*old_data = new_data;
|
||||
return recognized;
|
||||
}
|
@ -1,513 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2015 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 <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include "call-stub.h"
|
||||
#include "iatt.h"
|
||||
#include "defaults.h"
|
||||
#include "syscall.h"
|
||||
#include "xlator.h"
|
||||
#include "fdl.h"
|
||||
|
||||
/* TBD: make tunable */
|
||||
#define META_FILE_SIZE (1 << 20)
|
||||
#define DATA_FILE_SIZE (1 << 24)
|
||||
|
||||
enum gf_fdl { gf_fdl_mt_fdl_private_t = gf_common_mt_end + 1, gf_fdl_mt_end };
|
||||
|
||||
typedef struct {
|
||||
char *type;
|
||||
off_t size;
|
||||
char *path;
|
||||
int fd;
|
||||
void *ptr;
|
||||
off_t max_offset;
|
||||
} log_obj_t;
|
||||
|
||||
typedef struct {
|
||||
struct list_head reqs;
|
||||
pthread_mutex_t req_lock;
|
||||
pthread_cond_t req_cond;
|
||||
char *log_dir;
|
||||
pthread_t worker;
|
||||
gf_boolean_t should_stop;
|
||||
gf_boolean_t change_term;
|
||||
log_obj_t meta_log;
|
||||
log_obj_t data_log;
|
||||
int term;
|
||||
int first_term;
|
||||
} fdl_private_t;
|
||||
|
||||
int32_t
|
||||
fdl_ipc(call_frame_t *frame, xlator_t *this, int32_t op, dict_t *xdata);
|
||||
|
||||
void
|
||||
fdl_enqueue(xlator_t *this, call_stub_t *stub)
|
||||
{
|
||||
fdl_private_t *priv = this->private;
|
||||
|
||||
pthread_mutex_lock(&priv->req_lock);
|
||||
list_add_tail(&stub->list, &priv->reqs);
|
||||
pthread_mutex_unlock(&priv->req_lock);
|
||||
|
||||
pthread_cond_signal(&priv->req_cond);
|
||||
}
|
||||
|
||||
#pragma generate
|
||||
|
||||
char *
|
||||
fdl_open_term_log(xlator_t *this, log_obj_t *obj, int term)
|
||||
{
|
||||
fdl_private_t *priv = this->private;
|
||||
int ret;
|
||||
char *ptr = NULL;
|
||||
|
||||
/*
|
||||
* Use .jnl instead of .log so that we don't get test info (mistakenly)
|
||||
* appended to our journal files.
|
||||
*/
|
||||
if (this->ctx->cmd_args.log_ident) {
|
||||
ret = gf_asprintf(&obj->path, "%s/%s-%s-%d.jnl", priv->log_dir,
|
||||
this->ctx->cmd_args.log_ident, obj->type, term);
|
||||
} else {
|
||||
ret = gf_asprintf(&obj->path, "%s/fubar-%s-%d.jnl", priv->log_dir,
|
||||
obj->type, term);
|
||||
}
|
||||
if ((ret <= 0) || !obj->path) {
|
||||
gf_log(this->name, GF_LOG_ERROR, "failed to construct log-file path");
|
||||
goto err;
|
||||
}
|
||||
|
||||
gf_log(this->name, GF_LOG_INFO, "opening %s (size %" PRId64 ")", obj->path,
|
||||
obj->size);
|
||||
|
||||
obj->fd = open(obj->path, O_RDWR | O_CREAT | O_TRUNC, 0666);
|
||||
if (obj->fd < 0) {
|
||||
gf_log(this->name, GF_LOG_ERROR, "failed to open log file (%s)",
|
||||
strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
|
||||
#if !defined(GF_BSD_HOST_OS)
|
||||
/*
|
||||
* NetBSD can just go die in a fire. Even though it claims to support
|
||||
* fallocate/posix_fallocate they don't actually *do* anything so the
|
||||
* file size remains zero. Then mmap succeeds anyway, but any access
|
||||
* to the mmap'ed region will segfault. It would be acceptable for
|
||||
* fallocate to do what it says, for mmap to fail, or for access to
|
||||
* extend the file. NetBSD managed to hit the trifecta of Getting
|
||||
* Everything Wrong, and debugging in that environment to get this far
|
||||
* has already been painful enough (systems I worked on in 1990 were
|
||||
* better that way). We'll fall through to the lseek/write method, and
|
||||
* performance will be worse, and TOO BAD.
|
||||
*/
|
||||
if (sys_fallocate(obj->fd, 0, 0, obj->size) < 0)
|
||||
#endif
|
||||
{
|
||||
gf_log(this->name, GF_LOG_WARNING,
|
||||
"failed to fallocate space for log file");
|
||||
/* Have to do this the ugly page-faulty way. */
|
||||
(void)sys_lseek(obj->fd, obj->size - 1, SEEK_SET);
|
||||
(void)sys_write(obj->fd, "", 1);
|
||||
}
|
||||
|
||||
ptr = mmap(NULL, obj->size, PROT_WRITE, MAP_SHARED, obj->fd, 0);
|
||||
if (ptr == MAP_FAILED) {
|
||||
gf_log(this->name, GF_LOG_ERROR, "failed to mmap log (%s)",
|
||||
strerror(errno));
|
||||
goto err;
|
||||
}
|
||||
|
||||
obj->ptr = ptr;
|
||||
obj->max_offset = 0;
|
||||
return ptr;
|
||||
|
||||
err:
|
||||
if (obj->fd >= 0) {
|
||||
sys_close(obj->fd);
|
||||
obj->fd = (-1);
|
||||
}
|
||||
if (obj->path) {
|
||||
GF_FREE(obj->path);
|
||||
obj->path = NULL;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void
|
||||
fdl_close_term_log(xlator_t *this, log_obj_t *obj)
|
||||
{
|
||||
fdl_private_t *priv = this->private;
|
||||
|
||||
if (obj->ptr) {
|
||||
(void)munmap(obj->ptr, obj->size);
|
||||
obj->ptr = NULL;
|
||||
}
|
||||
|
||||
if (obj->fd >= 0) {
|
||||
gf_log(this->name, GF_LOG_INFO,
|
||||
"truncating term %d %s journal to %" PRId64,
|
||||
priv->term, obj->type, obj->max_offset);
|
||||
if (sys_ftruncate(obj->fd, obj->max_offset) < 0) {
|
||||
gf_log(this->name, GF_LOG_WARNING,
|
||||
"failed to truncate journal (%s)", strerror(errno));
|
||||
}
|
||||
sys_close(obj->fd);
|
||||
obj->fd = (-1);
|
||||
}
|
||||
|
||||
if (obj->path) {
|
||||
GF_FREE(obj->path);
|
||||
obj->path = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
gf_boolean_t
|
||||
fdl_change_term(xlator_t *this, char **meta_ptr, char **data_ptr)
|
||||
{
|
||||
fdl_private_t *priv = this->private;
|
||||
|
||||
fdl_close_term_log(this, &priv->meta_log);
|
||||
fdl_close_term_log(this, &priv->data_log);
|
||||
|
||||
++(priv->term);
|
||||
|
||||
*meta_ptr = fdl_open_term_log(this, &priv->meta_log, priv->term);
|
||||
if (!*meta_ptr) {
|
||||
return _gf_false;
|
||||
}
|
||||
|
||||
*data_ptr = fdl_open_term_log(this, &priv->data_log, priv->term);
|
||||
if (!*data_ptr) {
|
||||
return _gf_false;
|
||||
}
|
||||
|
||||
return _gf_true;
|
||||
}
|
||||
|
||||
void *
|
||||
fdl_worker(void *arg)
|
||||
{
|
||||
xlator_t *this = arg;
|
||||
fdl_private_t *priv = this->private;
|
||||
call_stub_t *stub;
|
||||
char *meta_ptr = NULL;
|
||||
off_t *meta_offset = &priv->meta_log.max_offset;
|
||||
char *data_ptr = NULL;
|
||||
off_t *data_offset = &priv->data_log.max_offset;
|
||||
unsigned long base_as_ul;
|
||||
void *msync_ptr;
|
||||
size_t msync_len;
|
||||
gf_boolean_t recycle;
|
||||
void *err_label = &&err_unlocked;
|
||||
|
||||
priv->meta_log.type = "meta";
|
||||
priv->meta_log.size = META_FILE_SIZE;
|
||||
priv->meta_log.path = NULL;
|
||||
priv->meta_log.fd = (-1);
|
||||
priv->meta_log.ptr = NULL;
|
||||
|
||||
priv->data_log.type = "data";
|
||||
priv->data_log.size = DATA_FILE_SIZE;
|
||||
priv->data_log.path = NULL;
|
||||
priv->data_log.fd = (-1);
|
||||
priv->data_log.ptr = NULL;
|
||||
|
||||
/* TBD: initial term should come from persistent storage (e.g. etcd) */
|
||||
priv->first_term = ++(priv->term);
|
||||
meta_ptr = fdl_open_term_log(this, &priv->meta_log, priv->term);
|
||||
if (!meta_ptr) {
|
||||
goto *err_label;
|
||||
}
|
||||
data_ptr = fdl_open_term_log(this, &priv->data_log, priv->term);
|
||||
if (!data_ptr) {
|
||||
fdl_close_term_log(this, &priv->meta_log);
|
||||
goto *err_label;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
pthread_mutex_lock(&priv->req_lock);
|
||||
err_label = &&err_locked;
|
||||
while (list_empty(&priv->reqs)) {
|
||||
pthread_cond_wait(&priv->req_cond, &priv->req_lock);
|
||||
if (priv->should_stop) {
|
||||
goto *err_label;
|
||||
}
|
||||
if (priv->change_term) {
|
||||
if (!fdl_change_term(this, &meta_ptr, &data_ptr)) {
|
||||
goto *err_label;
|
||||
}
|
||||
priv->change_term = _gf_false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
stub = list_entry(priv->reqs.next, call_stub_t, list);
|
||||
list_del_init(&stub->list);
|
||||
pthread_mutex_unlock(&priv->req_lock);
|
||||
err_label = &&err_unlocked;
|
||||
/*
|
||||
* TBD: batch requests
|
||||
*
|
||||
* What we should do here is gather up *all* of the requests
|
||||
* that have accumulated since we were last at this point,
|
||||
* blast them all out in one big writev, and then dispatch them
|
||||
* all before coming back for more. That maximizes throughput,
|
||||
* at some cost to latency (due to queuing effects at the log
|
||||
* stage). Note that we're likely to be above io-threads, so
|
||||
* the dispatch itself will be parallelized (at further cost to
|
||||
* latency). For now, we just do the simplest thing and handle
|
||||
* one request all the way through before fetching the next.
|
||||
*
|
||||
* So, why mmap/msync instead of writev/fdatasync? Because it's
|
||||
* faster. Much faster. So much faster that I half-suspect
|
||||
* cheating, but it's more convenient for now than having to
|
||||
* ensure that everything's page-aligned for O_DIRECT (the only
|
||||
* alternative that still might avoid ridiculous levels of
|
||||
* local-FS overhead).
|
||||
*
|
||||
* TBD: check that msync really does get our data to disk.
|
||||
*/
|
||||
gf_log(this->name, GF_LOG_DEBUG, "logging %u+%u bytes for op %d",
|
||||
stub->jnl_meta_len, stub->jnl_data_len, stub->fop);
|
||||
recycle = _gf_false;
|
||||
if ((*meta_offset + stub->jnl_meta_len) > priv->meta_log.size) {
|
||||
recycle = _gf_true;
|
||||
}
|
||||
if ((*data_offset + stub->jnl_data_len) > priv->data_log.size) {
|
||||
recycle = _gf_true;
|
||||
}
|
||||
if (recycle && !fdl_change_term(this, &meta_ptr, &data_ptr)) {
|
||||
goto *err_label;
|
||||
}
|
||||
meta_ptr = priv->meta_log.ptr;
|
||||
data_ptr = priv->data_log.ptr;
|
||||
gf_log(this->name, GF_LOG_DEBUG, "serializing to %p/%p",
|
||||
meta_ptr + *meta_offset, data_ptr + *data_offset);
|
||||
stub->serialize(stub, meta_ptr + *meta_offset, data_ptr + *data_offset);
|
||||
if (stub->jnl_meta_len > 0) {
|
||||
base_as_ul = (unsigned long)(meta_ptr + *meta_offset);
|
||||
msync_ptr = (void *)(base_as_ul & ~0x0fff);
|
||||
msync_len = (size_t)(base_as_ul & 0x0fff);
|
||||
if (msync(msync_ptr, msync_len + stub->jnl_meta_len, MS_SYNC) < 0) {
|
||||
gf_log(this->name, GF_LOG_WARNING,
|
||||
"failed to log request meta (%s)", strerror(errno));
|
||||
}
|
||||
*meta_offset += stub->jnl_meta_len;
|
||||
}
|
||||
if (stub->jnl_data_len > 0) {
|
||||
base_as_ul = (unsigned long)(data_ptr + *data_offset);
|
||||
msync_ptr = (void *)(base_as_ul & ~0x0fff);
|
||||
msync_len = (size_t)(base_as_ul & 0x0fff);
|
||||
if (msync(msync_ptr, msync_len + stub->jnl_data_len, MS_SYNC) < 0) {
|
||||
gf_log(this->name, GF_LOG_WARNING,
|
||||
"failed to log request data (%s)", strerror(errno));
|
||||
}
|
||||
*data_offset += stub->jnl_data_len;
|
||||
}
|
||||
call_resume(stub);
|
||||
}
|
||||
|
||||
err_locked:
|
||||
pthread_mutex_unlock(&priv->req_lock);
|
||||
err_unlocked:
|
||||
fdl_close_term_log(this, &priv->meta_log);
|
||||
fdl_close_term_log(this, &priv->data_log);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32_t
|
||||
fdl_ipc_continue(call_frame_t *frame, xlator_t *this, int32_t op, dict_t *xdata)
|
||||
{
|
||||
/*
|
||||
* Nothing to be done here. Just Unwind. *
|
||||
*/
|
||||
STACK_UNWIND_STRICT(ipc, frame, 0, 0, xdata);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
fdl_ipc(call_frame_t *frame, xlator_t *this, int32_t op, dict_t *xdata)
|
||||
{
|
||||
call_stub_t *stub;
|
||||
fdl_private_t *priv = this->private;
|
||||
dict_t *tdict;
|
||||
int32_t gt_err = EIO;
|
||||
|
||||
switch (op) {
|
||||
case FDL_IPC_CHANGE_TERM:
|
||||
gf_log(this->name, GF_LOG_INFO, "got CHANGE_TERM op");
|
||||
priv->change_term = _gf_true;
|
||||
pthread_cond_signal(&priv->req_cond);
|
||||
STACK_UNWIND_STRICT(ipc, frame, 0, 0, NULL);
|
||||
break;
|
||||
|
||||
case FDL_IPC_GET_TERMS:
|
||||
gf_log(this->name, GF_LOG_INFO, "got GET_TERMS op");
|
||||
tdict = dict_new();
|
||||
if (!tdict) {
|
||||
gt_err = ENOMEM;
|
||||
goto gt_done;
|
||||
}
|
||||
if (dict_set_int32(tdict, "first", priv->first_term) != 0) {
|
||||
goto gt_done;
|
||||
}
|
||||
if (dict_set_int32(tdict, "last", priv->term) != 0) {
|
||||
goto gt_done;
|
||||
}
|
||||
gt_err = 0;
|
||||
gt_done:
|
||||
if (gt_err) {
|
||||
STACK_UNWIND_STRICT(ipc, frame, -1, gt_err, NULL);
|
||||
} else {
|
||||
STACK_UNWIND_STRICT(ipc, frame, 0, 0, tdict);
|
||||
}
|
||||
if (tdict) {
|
||||
dict_unref(tdict);
|
||||
}
|
||||
break;
|
||||
|
||||
case FDL_IPC_JBR_SERVER_ROLLBACK:
|
||||
/*
|
||||
* In case of a rollback from jbr-server, dump *
|
||||
* the term and index number in the journal, *
|
||||
* which will later be used to rollback the fop *
|
||||
*/
|
||||
stub = fop_ipc_stub(frame, fdl_ipc_continue, op, xdata);
|
||||
fdl_len_ipc(stub);
|
||||
stub->serialize = fdl_serialize_ipc;
|
||||
fdl_enqueue(this, stub);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
STACK_WIND_TAIL(frame, FIRST_CHILD(this),
|
||||
FIRST_CHILD(this)->fops->ipc, op, xdata);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fdl_init(xlator_t *this)
|
||||
{
|
||||
fdl_private_t *priv = NULL;
|
||||
|
||||
priv = GF_CALLOC(1, sizeof(*priv), gf_fdl_mt_fdl_private_t);
|
||||
if (!priv) {
|
||||
gf_log(this->name, GF_LOG_ERROR, "failed to allocate fdl_private");
|
||||
goto err;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&priv->reqs);
|
||||
if (pthread_mutex_init(&priv->req_lock, NULL) != 0) {
|
||||
gf_log(this->name, GF_LOG_ERROR, "failed to initialize req_lock");
|
||||
goto err;
|
||||
}
|
||||
if (pthread_cond_init(&priv->req_cond, NULL) != 0) {
|
||||
gf_log(this->name, GF_LOG_ERROR, "failed to initialize req_cond");
|
||||
goto err;
|
||||
}
|
||||
|
||||
GF_OPTION_INIT("log-path", priv->log_dir, path, err);
|
||||
|
||||
this->private = priv;
|
||||
/*
|
||||
* The rest of the fop table is automatically generated, so this is a
|
||||
* bit cleaner than messing with the generation to add a hand-written
|
||||
* exception.
|
||||
*/
|
||||
|
||||
if (gf_thread_create(&priv->worker, NULL, fdl_worker, this, "fdlwrker") !=
|
||||
0) {
|
||||
gf_log(this->name, GF_LOG_ERROR, "failed to start fdl_worker");
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (priv) {
|
||||
GF_FREE(priv);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
fdl_fini(xlator_t *this)
|
||||
{
|
||||
fdl_private_t *priv = this->private;
|
||||
|
||||
if (priv) {
|
||||
priv->should_stop = _gf_true;
|
||||
pthread_cond_signal(&priv->req_cond);
|
||||
pthread_join(priv->worker, NULL);
|
||||
GF_FREE(priv);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
fdl_reconfigure(xlator_t *this, dict_t *options)
|
||||
{
|
||||
fdl_private_t *priv = this->private;
|
||||
|
||||
GF_OPTION_RECONF("log_dir", priv->log_dir, options, path, out);
|
||||
/* TBD: react if it changed */
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
mem_acct_init(xlator_t *this)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
GF_VALIDATE_OR_GOTO("fdl", this, out);
|
||||
|
||||
ret = xlator_mem_acct_init(this, gf_fdl_mt_end + 1);
|
||||
|
||||
if (ret != 0) {
|
||||
gf_log(this->name, GF_LOG_ERROR,
|
||||
"Memory accounting init"
|
||||
"failed");
|
||||
return ret;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
class_methods_t class_methods = {
|
||||
.init = fdl_init,
|
||||
.fini = fdl_fini,
|
||||
.reconfigure = fdl_reconfigure,
|
||||
.notify = default_notify,
|
||||
};
|
||||
|
||||
struct volume_options options[] = {
|
||||
{.key = {"log-path"},
|
||||
.type = GF_OPTION_TYPE_PATH,
|
||||
.default_value = DEFAULT_LOG_FILE_DIRECTORY,
|
||||
.description = "Directory for FDL files."},
|
||||
{.key = {NULL}},
|
||||
};
|
||||
|
||||
struct xlator_cbks cbks = {
|
||||
.release = default_release,
|
||||
.releasedir = default_releasedir,
|
||||
.forget = default_forget,
|
||||
};
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 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 _FDL_H_
|
||||
#define _FDL_H_
|
||||
|
||||
#define NEW_REQUEST (uint8_t)'N'
|
||||
|
||||
typedef struct {
|
||||
uint8_t event_type; /* e.g. NEW_REQUEST */
|
||||
uint8_t fop_type; /* e.g. GF_FOP_SETATTR */
|
||||
uint16_t request_id;
|
||||
uint32_t ext_length;
|
||||
} event_header_t;
|
||||
|
||||
enum {
|
||||
FDL_IPC_BASE = 0xfeedbee5, /* ... and they make honey */
|
||||
FDL_IPC_CHANGE_TERM,
|
||||
FDL_IPC_GET_TERMS,
|
||||
FDL_IPC_JBR_SERVER_ROLLBACK
|
||||
};
|
||||
|
||||
#endif /* _FDL_H_ */
|
@ -1,117 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
curdir = os.path.dirname (sys.argv[0])
|
||||
gendir = os.path.join (curdir, '../../../../libglusterfs/src')
|
||||
sys.path.append (gendir)
|
||||
from generator import ops, fop_subs, cbk_subs, generate
|
||||
|
||||
# See the big header comment at the start of gen_fdl.py to see how the stages
|
||||
# fit together. The big difference here is that *all* of the C code is in the
|
||||
# template file as labelled fragments, instead of as Python strings. That
|
||||
# makes it much easier to edit in one place, with proper syntax highlighting
|
||||
# and indentation.
|
||||
#
|
||||
# Stage 1 uses type-specific fragments to generate FUNCTION_BODY, instead of
|
||||
# LEN_*_TEMPLATE and SERLZ_*_TEMPLATE to generate LEN_CODE and SER_CODE.
|
||||
#
|
||||
# Stage 2 uses the FOP and CASE fragments instead of RECON_TEMPLATE and
|
||||
# FOP_TEMPLATE. The expanded FOP code (including FUNCTION_BODY substitution
|
||||
# in the middle of each function) is emitted immediately; the expanded CASE
|
||||
# code is saved for the next stage.
|
||||
#
|
||||
# Stage 3 uses the PROLOG and EPILOG fragments, with the expanded CASE code
|
||||
# in the middle of EPILOG, to generate the whole output file.
|
||||
#
|
||||
# Another way of looking at it is to consider how the fragments appear in
|
||||
# the final output:
|
||||
#
|
||||
# PROLOG
|
||||
# FOP (expanded for CREATE)
|
||||
# FOP before FUNCTION_BODY
|
||||
# LOC, INTEGER, GFID, etc. (one per arg, by type)
|
||||
# FOP after FUNCTION_BODY
|
||||
# FOP (expanded for WRITEV)
|
||||
# FOP before FUNCTION_BODY
|
||||
# GFID, VECTOR, etc. (on per arg, by type)
|
||||
# FOP after FUNCTION_BODY
|
||||
# (more FOPs)
|
||||
# EPILOG
|
||||
# EPILOG before CASE
|
||||
# CASE statements (one per fop)
|
||||
# EPILOG after CASE
|
||||
|
||||
typemap = {
|
||||
'dict_t *': ( "DICT", ""),
|
||||
'fd_t *': ( "GFID", ""),
|
||||
'dev_t': ( "DOUBLE", "%\"PRId64\" (0x%\"PRIx64\")"),
|
||||
'gf_xattrop_flags_t': ( "INTEGER", "%d (0x%x)"),
|
||||
'int32_t': ( "INTEGER", "%d (0x%x)"),
|
||||
'mode_t': ( "INTEGER", "%d (0x%x)"),
|
||||
'off_t': ( "DOUBLE", "%\"PRId64\" (0x%\"PRIx64\")"),
|
||||
'size_t': ( "DOUBLE", "%\"PRId64\" (0x%\"PRIx64\")"),
|
||||
'uint32_t': ( "INTEGER", "%d (0x%x)"),
|
||||
'loc_t *': ( "LOC", ""),
|
||||
'const char *': ( "STRING", ""),
|
||||
'struct iovec *': ( "VECTOR", ""),
|
||||
'struct iatt *': ( "IATT", ""),
|
||||
}
|
||||
|
||||
def get_special_subs (args):
|
||||
code = ""
|
||||
for arg in args:
|
||||
if (arg[0] != 'fop-arg') or (len(arg) < 4):
|
||||
continue
|
||||
recon_type, recon_fmt = typemap[arg[2]]
|
||||
code += fragments[recon_type].replace("@ARGNAME@", arg[3]) \
|
||||
.replace("@FORMAT@", recon_fmt)
|
||||
return code
|
||||
|
||||
def gen_functions ():
|
||||
code = ""
|
||||
for name, value in ops.items():
|
||||
if "journal" not in [ x[0] for x in value ]:
|
||||
continue
|
||||
fop_subs[name]["@FUNCTION_BODY@"] = get_special_subs(value)
|
||||
# Print the FOP fragment with @FUNCTION_BODY@ in the middle.
|
||||
code += generate(fragments["FOP"], name, fop_subs)
|
||||
return code
|
||||
|
||||
def gen_cases ():
|
||||
code = ""
|
||||
for name, value in ops.items():
|
||||
if "journal" not in [ x[0] for x in value ]:
|
||||
continue
|
||||
# Add the CASE fragment for this fop.
|
||||
code += generate(fragments["CASE"], name, fop_subs)
|
||||
return code
|
||||
|
||||
def load_fragments (path="recon-tmpl.c"):
|
||||
pragma_re = re.compile('pragma fragment (.*)')
|
||||
cur_symbol = None
|
||||
cur_value = ""
|
||||
result = {}
|
||||
for line in open(path, "r").readlines():
|
||||
m = pragma_re.search(line)
|
||||
if m:
|
||||
if cur_symbol:
|
||||
result[cur_symbol] = cur_value
|
||||
cur_symbol = m.group(1)
|
||||
cur_value = ""
|
||||
else:
|
||||
cur_value += line
|
||||
if cur_symbol:
|
||||
result[cur_symbol] = cur_value
|
||||
return result
|
||||
|
||||
if __name__ == "__main__":
|
||||
fragments = load_fragments(sys.argv[1])
|
||||
print("/* BEGIN GENERATED CODE - DO NOT MODIFY */")
|
||||
print(fragments["PROLOG"])
|
||||
print(gen_functions())
|
||||
print(fragments["EPILOG"].replace("@SWITCH_BODY@", gen_cases()))
|
||||
print("/* END GENERATED CODE */")
|
@ -1,354 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import sys
|
||||
|
||||
curdir = os.path.dirname (sys.argv[0])
|
||||
gendir = os.path.join (curdir, '../../../../libglusterfs/src')
|
||||
sys.path.append (gendir)
|
||||
from generator import ops, fop_subs, cbk_subs, generate
|
||||
|
||||
# Generation occurs in three stages. In this case, it actually makes more
|
||||
# sense to discuss them in the *opposite* order of that in which they
|
||||
# actually happen.
|
||||
#
|
||||
# Stage 3 is to insert all of the generated code into a file, replacing the
|
||||
# "#pragma generate" that's already there. The file can thus contain all
|
||||
# sorts of stuff that's not specific to one fop, either before or after the
|
||||
# generated code as appropriate.
|
||||
#
|
||||
# Stage 2 is to generate all of the code *for a particular fop*, using a
|
||||
# string-valued template plus a table of substitution values. Most of these
|
||||
# are built in to the generator itself. However, we also add a couple that
|
||||
# are specific to this particular translator - LEN_CODE and SER_CODE. These
|
||||
# are per-fop functions to get the length or the contents (respectively) of
|
||||
# what we'll put in the log. As with stage 3 allowing per-file boilerplate
|
||||
# before and after generated code, this allows per-fop boilerplate before and
|
||||
# after generated code.
|
||||
#
|
||||
# Stage 1, therefore, is to create the LEN_CODE and SER_CODE substitutions for
|
||||
# each fop, and put them in the same table where e.g. NAME and SHORT_ARGS
|
||||
# already are. We do this by looking at the fop-description table in the
|
||||
# generator module, then doing out own template substitution to plug each
|
||||
# specific argument name into another string-valued template.
|
||||
#
|
||||
# So, what does this leave us with in terms of variables and files?
|
||||
#
|
||||
# For stage 1, we have a series of LEN_*_TEMPLATE and SERLZ_*_TEMPLATE
|
||||
# strings, which are used to generate the length and serialization code for
|
||||
# each argument type.
|
||||
#
|
||||
# For stage 2, we have a bunch of *_TEMPLATE strings (no LEN_ or SERLZ_
|
||||
# prefix), which are used (along with the output from stage 1) to generate
|
||||
# whole functions.
|
||||
#
|
||||
# For stage 3, we have a whole separate file (fdl_tmpl.c) into which we insert
|
||||
# the collection of all functions defined in stage 2.
|
||||
|
||||
|
||||
LEN_TEMPLATE = """
|
||||
void
|
||||
fdl_len_@NAME@ (call_stub_t *stub)
|
||||
{
|
||||
uint32_t meta_len = sizeof (event_header_t);
|
||||
uint32_t data_len = 0;
|
||||
|
||||
/* TBD: global stuff, e.g. uid/gid */
|
||||
@LEN_CODE@
|
||||
|
||||
/* TBD: pad extension length */
|
||||
stub->jnl_meta_len = meta_len;
|
||||
stub->jnl_data_len = data_len;
|
||||
}
|
||||
"""
|
||||
|
||||
SER_TEMPLATE = """
|
||||
void
|
||||
fdl_serialize_@NAME@ (call_stub_t *stub, char *meta_buf, char *data_buf)
|
||||
{
|
||||
event_header_t *eh;
|
||||
unsigned long offset = 0;
|
||||
|
||||
/* TBD: word size/endianness */
|
||||
eh = (event_header_t *)meta_buf;
|
||||
eh->event_type = NEW_REQUEST;
|
||||
eh->fop_type = GF_FOP_@UPNAME@;
|
||||
eh->request_id = 0; // TBD
|
||||
meta_buf += sizeof (*eh);
|
||||
@SER_CODE@
|
||||
/* TBD: pad extension length */
|
||||
eh->ext_length = offset;
|
||||
}
|
||||
"""
|
||||
|
||||
CBK_TEMPLATE = """
|
||||
int32_t
|
||||
fdl_@NAME@_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
|
||||
int32_t op_ret, int32_t op_errno,
|
||||
@LONG_ARGS@)
|
||||
{
|
||||
STACK_UNWIND_STRICT (@NAME@, frame, op_ret, op_errno,
|
||||
@SHORT_ARGS@);
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
|
||||
CONTINUE_TEMPLATE = """
|
||||
int32_t
|
||||
fdl_@NAME@_continue (call_frame_t *frame, xlator_t *this,
|
||||
@LONG_ARGS@)
|
||||
{
|
||||
STACK_WIND (frame, fdl_@NAME@_cbk,
|
||||
FIRST_CHILD(this), FIRST_CHILD(this)->fops->@NAME@,
|
||||
@SHORT_ARGS@);
|
||||
return 0;
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
FOP_TEMPLATE = """
|
||||
int32_t
|
||||
fdl_@NAME@ (call_frame_t *frame, xlator_t *this,
|
||||
@LONG_ARGS@)
|
||||
{
|
||||
call_stub_t *stub;
|
||||
|
||||
stub = fop_@NAME@_stub (frame, default_@NAME@,
|
||||
@SHORT_ARGS@);
|
||||
fdl_len_@NAME@ (stub);
|
||||
stub->serialize = fdl_serialize_@NAME@;
|
||||
fdl_enqueue (this, stub);
|
||||
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
|
||||
LEN_DICT_TEMPLATE = """
|
||||
if (@SRC@) {
|
||||
data_pair_t *memb;
|
||||
for (memb = @SRC@->members_list; memb; memb = memb->next) {
|
||||
meta_len += sizeof(int);
|
||||
meta_len += strlen(memb->key) + 1;
|
||||
meta_len += sizeof(int);
|
||||
meta_len += memb->value->len;
|
||||
}
|
||||
}
|
||||
meta_len += sizeof(int);
|
||||
"""
|
||||
|
||||
LEN_GFID_TEMPLATE = """
|
||||
meta_len += 16;
|
||||
"""
|
||||
|
||||
LEN_INTEGER_TEMPLATE = """
|
||||
meta_len += sizeof (@SRC@);
|
||||
"""
|
||||
|
||||
# 16 for gfid, 16 for pargfid, 1 for flag, 0/1 for terminating NUL
|
||||
LEN_LOC_TEMPLATE = """
|
||||
if (@SRC@.name) {
|
||||
meta_len += (strlen (@SRC@.name) + 34);
|
||||
} else {
|
||||
meta_len += 33;
|
||||
}
|
||||
"""
|
||||
|
||||
LEN_STRING_TEMPLATE = """
|
||||
if (@SRC@) {
|
||||
meta_len += (strlen (@SRC@) + 1);
|
||||
} else {
|
||||
meta_len += 1;
|
||||
}
|
||||
"""
|
||||
|
||||
LEN_VECTOR_TEMPLATE = """
|
||||
meta_len += sizeof(size_t);
|
||||
data_len += iov_length (@VEC@, @CNT@);
|
||||
"""
|
||||
|
||||
LEN_IATT_TEMPLATE = """
|
||||
meta_len += sizeof(@SRC@.ia_prot);
|
||||
meta_len += sizeof(@SRC@.ia_uid);
|
||||
meta_len += sizeof(@SRC@.ia_gid);
|
||||
meta_len += sizeof(@SRC@.ia_atime);
|
||||
meta_len += sizeof(@SRC@.ia_atime_nsec);
|
||||
meta_len += sizeof(@SRC@.ia_mtime);
|
||||
meta_len += sizeof(@SRC@.ia_mtime_nsec);
|
||||
"""
|
||||
|
||||
SERLZ_DICT_TEMPLATE = """
|
||||
if (@SRC@) {
|
||||
data_pair_t *memb;
|
||||
for (memb = @SRC@->members_list; memb; memb = memb->next) {
|
||||
*((int *)(meta_buf+offset)) = strlen(memb->key) + 1;
|
||||
offset += sizeof(int);
|
||||
strcpy (meta_buf+offset, memb->key);
|
||||
offset += strlen(memb->key) + 1;
|
||||
*((int *)(meta_buf+offset)) = memb->value->len;
|
||||
offset += sizeof(int);
|
||||
memcpy (meta_buf+offset, memb->value->data, memb->value->len);
|
||||
offset += memb->value->len;
|
||||
}
|
||||
}
|
||||
*((int *)(meta_buf+offset)) = 0;
|
||||
offset += sizeof(int);
|
||||
"""
|
||||
|
||||
SERLZ_GFID_TEMPLATE = """
|
||||
memcpy (meta_buf+offset, @SRC@->inode->gfid, 16);
|
||||
offset += 16;
|
||||
"""
|
||||
|
||||
SERLZ_INTEGER_TEMPLATE = """
|
||||
memcpy (meta_buf+offset, &@SRC@, sizeof(@SRC@));
|
||||
offset += sizeof(@SRC@);
|
||||
"""
|
||||
|
||||
SERLZ_LOC_TEMPLATE = """
|
||||
memcpy (meta_buf+offset, @SRC@.gfid, 16);
|
||||
offset += 16;
|
||||
memcpy (meta_buf+offset, @SRC@.pargfid, 16);
|
||||
offset += 16;
|
||||
if (@SRC@.name) {
|
||||
*(meta_buf+offset) = 1;
|
||||
++offset;
|
||||
strcpy (meta_buf+offset, @SRC@.name);
|
||||
offset += (strlen (@SRC@.name) + 1);
|
||||
} else {
|
||||
*(meta_buf+offset) = 0;
|
||||
++offset;
|
||||
}
|
||||
"""
|
||||
|
||||
SERLZ_STRING_TEMPLATE = """
|
||||
if (@SRC@) {
|
||||
*(meta_buf+offset) = 1;
|
||||
++offset;
|
||||
strcpy (meta_buf+offset, @SRC@);
|
||||
offset += strlen(@SRC@);
|
||||
} else {
|
||||
*(meta_buf+offset) = 0;
|
||||
++offset;
|
||||
}
|
||||
"""
|
||||
|
||||
SERLZ_VECTOR_TEMPLATE = """
|
||||
*((size_t *)(meta_buf+offset)) = iov_length (@VEC@, @CNT@);
|
||||
offset += sizeof(size_t);
|
||||
int32_t i;
|
||||
for (i = 0; i < @CNT@; ++i) {
|
||||
memcpy (data_buf, @VEC@[i].iov_base, @VEC@[i].iov_len);
|
||||
data_buf += @VEC@[i].iov_len;
|
||||
}
|
||||
"""
|
||||
|
||||
# We don't need to save all of the fields - only those affected by chown,
|
||||
# chgrp, chmod, and utime.
|
||||
SERLZ_IATT_TEMPLATE = """
|
||||
*((ia_prot_t *)(meta_buf+offset)) = @SRC@.ia_prot;
|
||||
offset += sizeof(@SRC@.ia_prot);
|
||||
*((uint32_t *)(meta_buf+offset)) = @SRC@.ia_uid;
|
||||
offset += sizeof(@SRC@.ia_uid);
|
||||
*((uint32_t *)(meta_buf+offset)) = @SRC@.ia_gid;
|
||||
offset += sizeof(@SRC@.ia_gid);
|
||||
*((uint32_t *)(meta_buf+offset)) = @SRC@.ia_atime;
|
||||
offset += sizeof(@SRC@.ia_atime);
|
||||
*((uint32_t *)(meta_buf+offset)) = @SRC@.ia_atime_nsec;
|
||||
offset += sizeof(@SRC@.ia_atime_nsec);
|
||||
*((uint32_t *)(meta_buf+offset)) = @SRC@.ia_mtime;
|
||||
offset += sizeof(@SRC@.ia_mtime);
|
||||
*((uint32_t *)(meta_buf+offset)) = @SRC@.ia_mtime_nsec;
|
||||
offset += sizeof(@SRC@.ia_mtime_nsec);
|
||||
"""
|
||||
|
||||
typemap = {
|
||||
'dict_t *': ( LEN_DICT_TEMPLATE, SERLZ_DICT_TEMPLATE),
|
||||
'fd_t *': ( LEN_GFID_TEMPLATE, SERLZ_GFID_TEMPLATE),
|
||||
'dev_t': ( LEN_INTEGER_TEMPLATE, SERLZ_INTEGER_TEMPLATE),
|
||||
'gf_xattrop_flags_t': ( LEN_INTEGER_TEMPLATE, SERLZ_INTEGER_TEMPLATE),
|
||||
'int32_t': ( LEN_INTEGER_TEMPLATE, SERLZ_INTEGER_TEMPLATE),
|
||||
'mode_t': ( LEN_INTEGER_TEMPLATE, SERLZ_INTEGER_TEMPLATE),
|
||||
'off_t': ( LEN_INTEGER_TEMPLATE, SERLZ_INTEGER_TEMPLATE),
|
||||
'size_t': ( LEN_INTEGER_TEMPLATE, SERLZ_INTEGER_TEMPLATE),
|
||||
'uint32_t': ( LEN_INTEGER_TEMPLATE, SERLZ_INTEGER_TEMPLATE),
|
||||
'loc_t *': ( LEN_LOC_TEMPLATE, SERLZ_LOC_TEMPLATE),
|
||||
'const char *': ( LEN_STRING_TEMPLATE, SERLZ_STRING_TEMPLATE),
|
||||
'struct iatt *': ( LEN_IATT_TEMPLATE, SERLZ_IATT_TEMPLATE),
|
||||
}
|
||||
|
||||
def get_special_subs (args):
|
||||
len_code = ""
|
||||
ser_code = ""
|
||||
for arg in args:
|
||||
if (arg[0] != 'fop-arg') or (len(arg) < 4):
|
||||
continue
|
||||
# Let this throw an exception if we get an unknown field name. The
|
||||
# broken build will remind whoever messed with the stub code that a
|
||||
# corresponding update is needed here.
|
||||
if arg[3] == "vector":
|
||||
# Make it as obvious as possible that this is a special case.
|
||||
len_code += LEN_VECTOR_TEMPLATE \
|
||||
.replace("@VEC@", "stub->args.vector") \
|
||||
.replace("@CNT@", "stub->args.count")
|
||||
ser_code += SERLZ_VECTOR_TEMPLATE \
|
||||
.replace("@VEC@", "stub->args.vector") \
|
||||
.replace("@CNT@", "stub->args.count")
|
||||
else:
|
||||
len_tmpl, ser_tmpl = typemap[arg[2]]
|
||||
src = "stub->args.%s" % arg[3]
|
||||
len_code += len_tmpl.replace("@SRC@", src)
|
||||
ser_code += ser_tmpl.replace("@SRC@", src)
|
||||
return len_code, ser_code
|
||||
|
||||
# Mention those fops in the selective_generate table, for which
|
||||
# only a few common functions will be generated, and mention those
|
||||
# functions. Rest of the functions can be customized
|
||||
selective_generate = {
|
||||
"ipc": "len,serialize",
|
||||
}
|
||||
|
||||
def gen_fdl ():
|
||||
entrypoints = []
|
||||
for name, value in ops.items():
|
||||
if "journal" not in [ x[0] for x in value ]:
|
||||
continue
|
||||
|
||||
# generate all functions for all the fops
|
||||
# except for the ones in selective_generate for which
|
||||
# generate only the functions mentioned in the
|
||||
# selective_generate table
|
||||
gen_funcs = "len,serialize,callback,continue,fop"
|
||||
if name in selective_generate:
|
||||
gen_funcs = selective_generate[name].split(",")
|
||||
|
||||
len_code, ser_code = get_special_subs(value)
|
||||
fop_subs[name]["@LEN_CODE@"] = len_code[:-1]
|
||||
fop_subs[name]["@SER_CODE@"] = ser_code[:-1]
|
||||
if 'len' in gen_funcs:
|
||||
print(generate(LEN_TEMPLATE, name, fop_subs))
|
||||
if 'serialize' in gen_funcs:
|
||||
print(generate(SER_TEMPLATE, name, fop_subs))
|
||||
if name == 'writev':
|
||||
print("#define DESTAGE_ASYNC")
|
||||
if 'callback' in gen_funcs:
|
||||
print(generate(CBK_TEMPLATE, name, cbk_subs))
|
||||
if 'continue' in gen_funcs:
|
||||
print(generate(CONTINUE_TEMPLATE, name, fop_subs))
|
||||
if 'fop' in gen_funcs:
|
||||
print(generate(FOP_TEMPLATE, name, fop_subs))
|
||||
if name == 'writev':
|
||||
print("#undef DESTAGE_ASYNC")
|
||||
entrypoints.append(name)
|
||||
print("struct xlator_fops fops = {")
|
||||
for ep in entrypoints:
|
||||
print("\t.%s = fdl_%s," % (ep, ep))
|
||||
print("};")
|
||||
|
||||
for l in open(sys.argv[1], 'r').readlines():
|
||||
if l.find('#pragma generate') != -1:
|
||||
print("/* BEGIN GENERATED CODE - DO NOT MODIFY */")
|
||||
gen_fdl()
|
||||
print("/* END GENERATED CODE */")
|
||||
else:
|
||||
print(l[:-1])
|
@ -1,218 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import re
|
||||
import string
|
||||
import sys
|
||||
|
||||
curdir = os.path.dirname (sys.argv[0])
|
||||
gendir = os.path.join (curdir, '../../../../libglusterfs/src')
|
||||
sys.path.append (gendir)
|
||||
from generator import ops, fop_subs, cbk_subs, generate
|
||||
|
||||
# See the big header comment at the start of gen_fdl.py to see how the stages
|
||||
# fit together. The big difference here is that *all* of the C code is in the
|
||||
# template file as labelled fragments, instead of as Python strings. That
|
||||
# makes it much easier to edit in one place, with proper syntax highlighting
|
||||
# and indentation.
|
||||
#
|
||||
# Stage 1 uses type-specific fragments to generate FUNCTION_BODY, instead of
|
||||
# LEN_*_TEMPLATE and SERLZ_*_TEMPLATE to generate LEN_CODE and SER_CODE.
|
||||
#
|
||||
# Stage 2 uses the FOP and CASE fragments instead of RECON_TEMPLATE and
|
||||
# FOP_TEMPLATE. The expanded FOP code (including FUNCTION_BODY substitution
|
||||
# in the middle of each function) is emitted immediately; the expanded CASE
|
||||
# code is saved for the next stage.
|
||||
#
|
||||
# Stage 3 uses the PROLOG and EPILOG fragments, with the expanded CASE code
|
||||
# in the middle of EPILOG, to generate the whole output file.
|
||||
#
|
||||
# Another way of looking at it is to consider how the fragments appear in
|
||||
# the final output:
|
||||
#
|
||||
# PROLOG
|
||||
# FOP (expanded for CREATE)
|
||||
# FOP before FUNCTION_BODY
|
||||
# LOC, INTEGER, GFID, etc. (one per arg, by type)
|
||||
# FOP after FUNCTION_BODY
|
||||
# FOP (expanded for WRITEV)
|
||||
# FOP before FUNCTION_BODY
|
||||
# GFID, VECTOR, etc. (one per arg, by type)
|
||||
# FOP after FUNCTION_BODY
|
||||
# (more FOPs)
|
||||
# EPILOG
|
||||
# EPILOG before CASE
|
||||
# CASE statements (one per fop)
|
||||
# EPILOG after CASE
|
||||
|
||||
typemap = {
|
||||
'dict_t *': "DICT",
|
||||
'fd_t *': "FD",
|
||||
'dev_t': "DOUBLE",
|
||||
'gf_xattrop_flags_t': "INTEGER",
|
||||
'int32_t': "INTEGER",
|
||||
'mode_t': "INTEGER",
|
||||
'off_t': "DOUBLE",
|
||||
'size_t': "DOUBLE",
|
||||
'uint32_t': "INTEGER",
|
||||
'loc_t *': "LOC",
|
||||
'const char *': "STRING",
|
||||
'struct iovec *': "VECTOR",
|
||||
'struct iatt *': "IATT",
|
||||
'struct iobref *': "IOBREF",
|
||||
}
|
||||
|
||||
def get_special_subs (name, args, fop_type):
|
||||
code = ""
|
||||
cleanups = ""
|
||||
links = ""
|
||||
s_args = []
|
||||
for arg in args:
|
||||
if arg[0] == 'extra':
|
||||
code += "\t%s %s;\n\n" % (arg[2], arg[1])
|
||||
s_args.append(arg[3])
|
||||
continue
|
||||
if arg[0] == 'link':
|
||||
links += fragments["LINK"].replace("@INODE_ARG@", arg[1]) \
|
||||
.replace("@IATT_ARG@", arg[2])
|
||||
continue
|
||||
if arg[0] != 'fop-arg':
|
||||
continue
|
||||
if (name, arg[1]) == ('writev', 'count'):
|
||||
# Special case: just skip this. We can't mark it as 'nosync'
|
||||
# because of the way the translator and dumper generators look for
|
||||
# that after 'stub-name' which we don't define. Instead of adding a
|
||||
# bunch of generic infrastructure for this one case, just pound it
|
||||
# here.
|
||||
continue
|
||||
recon_type = typemap[arg[2]]
|
||||
# print "/* %s.%s => %s (%s)*/" % (name, arg[1], recon_type, fop_type)
|
||||
if (name == "create") and (arg[1] == "fd"):
|
||||
# Special case: fd for create is new, not looked up.
|
||||
# print "/* change to NEW_FD */"
|
||||
recon_type = "NEW_FD"
|
||||
elif (recon_type == "LOC") and (fop_type == "entry-op"):
|
||||
# Need to treat this differently for inode vs. entry ops.
|
||||
# Special case: link source is treated like inode-op.
|
||||
if (name != "link") or (arg[1] != "oldloc"):
|
||||
# print "/* change to PARENT_LOC */"
|
||||
recon_type = "PARENT_LOC"
|
||||
code += fragments[recon_type].replace("@ARGNAME@", arg[1]) \
|
||||
.replace("@ARGTYPE@", arg[2])
|
||||
cleanup_key = recon_type + "_CLEANUP"
|
||||
if cleanup_key in fragments:
|
||||
new_frag = fragments[cleanup_key].replace("@ARGNAME@", arg[1])
|
||||
# Make sure these get added in *reverse* order. Otherwise, a
|
||||
# failure for an earlier argument might goto a label that falls
|
||||
# through to the cleanup code for a variable associated with a
|
||||
# later argument, but that variable might not even have been
|
||||
# *declared* (let alone initialized) yet. Consider the following
|
||||
# case.
|
||||
#
|
||||
# process argument A (on failure goto cleanup_A)
|
||||
# set error label to cleanup_A
|
||||
#
|
||||
# declare pointer variable for argument B
|
||||
# process argument B (on failure goto cleanup_B)
|
||||
#
|
||||
# cleanup_A:
|
||||
# /* whatever */
|
||||
# cleanup_B:
|
||||
# free pointer variable <= "USED BUT NOT SET" error here
|
||||
#
|
||||
# By adding these in reverse order, we ensure that cleanup_B is
|
||||
# actually *before* cleanup_A, and nothing will try to do the free
|
||||
# until we've actually attempted processing of B.
|
||||
cleanups = new_frag + cleanups
|
||||
if 'nosync' in arg[4:]:
|
||||
code += "\t(void)%s;\n" % arg[1];
|
||||
continue
|
||||
if arg[2] in ("loc_t *", "struct iatt *"):
|
||||
# These are passed as pointers to the syncop, but they're actual
|
||||
# structures in the generated code.
|
||||
s_args.append("&"+arg[1]);
|
||||
else:
|
||||
s_args.append(arg[1])
|
||||
# We have to handle a couple of special cases here, because some n00b
|
||||
# defined the syncops with a different argument order than the fops they're
|
||||
# based on.
|
||||
if name == 'writev':
|
||||
# Swap 'flags' and 'iobref'. Also, we need to add the iov count, which
|
||||
# is not stored in or read from the journal. There are other ways to
|
||||
# do that, but this is the only place we need anything similar and we
|
||||
# already have to treat it as a special case so this is simplest.
|
||||
s_args_str = 'fd, &vector, 1, off, iobref, flags, &preop, &postop, xdata'
|
||||
elif name == 'symlink':
|
||||
# Swap 'linkpath' and 'loc'.
|
||||
s_args_str = '&loc, linkpath, &iatt, xdata'
|
||||
elif name == 'xattrop':
|
||||
s_args_str = '&loc, flags, dict, xdata, NULL'
|
||||
elif name == 'fxattrop':
|
||||
s_args_str = 'fd, flags, dict, xdata, NULL'
|
||||
else:
|
||||
s_args_str = ', '.join(s_args)
|
||||
return code, links, s_args_str, cleanups
|
||||
|
||||
# TBD: probably need to generate type-specific cleanup code as well - e.g.
|
||||
# fd_unref for an fd_t, loc_wipe for a loc_t, and so on. All of these
|
||||
# generated CLEANUP fragments will go at the end of the function, with goto
|
||||
# labels. Meanwhile, the error-checking part of each type-specific fragment
|
||||
# (e.g. LOC or FD) will need to update the indirect label that we jump to when
|
||||
# an error is detected. This will probably get messy.
|
||||
def gen_functions ():
|
||||
code = ""
|
||||
for name, value in ops.items():
|
||||
fop_type = [ x[1] for x in value if x[0] == "journal" ]
|
||||
if not fop_type:
|
||||
continue
|
||||
body, links, syncop_args, cleanups = get_special_subs (name, value,
|
||||
fop_type[0])
|
||||
fop_subs[name]["@FUNCTION_BODY@"] = body
|
||||
fop_subs[name]["@LINKS@"] = links
|
||||
fop_subs[name]["@SYNCOP_ARGS@"] = syncop_args
|
||||
fop_subs[name]["@CLEANUPS@"] = cleanups
|
||||
if name == "writev":
|
||||
# Take advantage of the fact that, *during reconciliation*, the
|
||||
# vector is always a single element. In normal I/O it's not.
|
||||
fop_subs[name]["@SUCCESS_VALUE@"] = "vector.iov_len"
|
||||
else:
|
||||
fop_subs[name]["@SUCCESS_VALUE@"] = "GFAPI_SUCCESS"
|
||||
# Print the FOP fragment with @FUNCTION_BODY@ in the middle.
|
||||
code += generate(fragments["FOP"], name, fop_subs)
|
||||
return code
|
||||
|
||||
def gen_cases ():
|
||||
code = ""
|
||||
for name, value in ops.items():
|
||||
if "journal" not in [ x[0] for x in value ]:
|
||||
continue
|
||||
# Add the CASE fragment for this fop.
|
||||
code += generate(fragments["CASE"], name, fop_subs)
|
||||
return code
|
||||
|
||||
def load_fragments (path="recon-tmpl.c"):
|
||||
pragma_re = re.compile('pragma fragment (.*)')
|
||||
cur_symbol = None
|
||||
cur_value = ""
|
||||
result = {}
|
||||
for line in open(path, "r").readlines():
|
||||
m = pragma_re.search(line)
|
||||
if m:
|
||||
if cur_symbol:
|
||||
result[cur_symbol] = cur_value
|
||||
cur_symbol = m.group(1)
|
||||
cur_value = ""
|
||||
else:
|
||||
cur_value += line
|
||||
if cur_symbol:
|
||||
result[cur_symbol] = cur_value
|
||||
return result
|
||||
|
||||
if __name__ == "__main__":
|
||||
fragments = load_fragments(sys.argv[1])
|
||||
print("/* BEGIN GENERATED CODE - DO NOT MODIFY */")
|
||||
print(fragments["PROLOG"])
|
||||
print(gen_functions())
|
||||
print(fragments["EPILOG"].replace("@SWITCH_BODY@", gen_cases()))
|
||||
print("/* END GENERATED CODE */")
|
@ -1,51 +0,0 @@
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
extern int
|
||||
fdl_dump(char **, char **);
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
int meta_fd = (-1);
|
||||
char *meta_buf = NULL;
|
||||
int data_fd = (-1);
|
||||
char *data_buf = NULL;
|
||||
|
||||
meta_fd = open(argv[1], O_RDONLY);
|
||||
if (meta_fd < 0) {
|
||||
perror("open");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* TBD: get proper length */
|
||||
meta_buf = mmap(NULL, 1048576, PROT_READ, MAP_PRIVATE, meta_fd, 0);
|
||||
if (meta_buf == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
data_fd = open(argv[2], O_RDONLY);
|
||||
if (data_fd < 0) {
|
||||
perror("open");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* TBD: get proper length */
|
||||
data_buf = mmap(NULL, 1048576, PROT_READ, MAP_PRIVATE, data_fd, 0);
|
||||
if (data_buf == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (!fdl_dump(&meta_buf, &data_buf)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,297 +0,0 @@
|
||||
#pragma fragment PROLOG
|
||||
#ifndef _CONFIG_H
|
||||
#define _CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "glusterfs.h"
|
||||
#include "iatt.h"
|
||||
#include "syncop.h"
|
||||
#include "xlator.h"
|
||||
#include "glfs-internal.h"
|
||||
|
||||
#include "fdl.h"
|
||||
|
||||
#define GFAPI_SUCCESS 0
|
||||
|
||||
inode_t *
|
||||
recon_get_inode(glfs_t *fs, uuid_t gfid)
|
||||
{
|
||||
inode_t *inode;
|
||||
loc_t loc = {
|
||||
NULL,
|
||||
};
|
||||
struct iatt iatt;
|
||||
int ret;
|
||||
inode_t *newinode;
|
||||
|
||||
inode = inode_find(fs->active_subvol->itable, gfid);
|
||||
if (inode) {
|
||||
printf("=== FOUND %s IN TABLE\n", uuid_utoa(gfid));
|
||||
return inode;
|
||||
}
|
||||
|
||||
loc.inode = inode_new(fs->active_subvol->itable);
|
||||
if (!loc.inode) {
|
||||
return NULL;
|
||||
}
|
||||
gf_uuid_copy(loc.inode->gfid, gfid);
|
||||
gf_uuid_copy(loc.gfid, gfid);
|
||||
|
||||
printf("=== DOING LOOKUP FOR %s\n", uuid_utoa(gfid));
|
||||
|
||||
ret = syncop_lookup(fs->active_subvol, &loc, &iatt, NULL, NULL, NULL);
|
||||
if (ret != GFAPI_SUCCESS) {
|
||||
fprintf(stderr, "syncop_lookup failed (%d)\n", ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
newinode = inode_link(loc.inode, NULL, NULL, &iatt);
|
||||
if (newinode) {
|
||||
inode_lookup(newinode);
|
||||
}
|
||||
|
||||
return newinode;
|
||||
}
|
||||
|
||||
#pragma fragment DICT
|
||||
dict_t *@ARGNAME@;
|
||||
|
||||
@ARGNAME@ = dict_new();
|
||||
if (!@ARGNAME@) {
|
||||
goto *err_label;
|
||||
}
|
||||
err_label = &&cleanup_@ARGNAME@;
|
||||
|
||||
{
|
||||
int key_len, data_len;
|
||||
char *key_ptr;
|
||||
int garbage;
|
||||
for (;;) {
|
||||
key_len = *((int *)new_meta);
|
||||
new_meta += sizeof(int);
|
||||
if (!key_len) {
|
||||
break;
|
||||
}
|
||||
key_ptr = new_meta;
|
||||
new_meta += key_len;
|
||||
data_len = *((int *)new_meta);
|
||||
new_meta += sizeof(int);
|
||||
garbage = dict_set_static_bin(@ARGNAME@, key_ptr, new_meta, data_len);
|
||||
/* TBD: check error from dict_set_static_bin */
|
||||
(void)garbage;
|
||||
new_meta += data_len;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma fragment DICT_CLEANUP
|
||||
cleanup_@ARGNAME@ : dict_unref(@ARGNAME@);
|
||||
|
||||
#pragma fragment DOUBLE
|
||||
@ARGTYPE@ @ARGNAME@ = *((@ARGTYPE@ *)new_meta);
|
||||
new_meta += sizeof(uint64_t);
|
||||
|
||||
#pragma fragment FD
|
||||
inode_t *@ARGNAME@_ino;
|
||||
fd_t *@ARGNAME@;
|
||||
|
||||
@ARGNAME@_ino = recon_get_inode(fs, *((uuid_t *)new_meta));
|
||||
new_meta += 16;
|
||||
if (!@ARGNAME@_ino) {
|
||||
goto *err_label;
|
||||
}
|
||||
err_label = &&cleanup_@ARGNAME@_ino;
|
||||
|
||||
@ARGNAME@ = fd_anonymous(@ARGNAME@_ino);
|
||||
if (!@ARGNAME@) {
|
||||
goto *err_label;
|
||||
}
|
||||
err_label = &&cleanup_@ARGNAME@;
|
||||
|
||||
#pragma fragment FD_CLEANUP
|
||||
cleanup_@ARGNAME@ : fd_unref(@ARGNAME@);
|
||||
cleanup_@ARGNAME@_ino : inode_unref(@ARGNAME@_ino);
|
||||
|
||||
#pragma fragment NEW_FD
|
||||
/*
|
||||
* This pseudo-type is only used for create, and in that case we know
|
||||
* we'll be using loc.inode, so it's not worth generalizing to take an
|
||||
* extra argument.
|
||||
*/
|
||||
fd_t *@ARGNAME@ = fd_anonymous(loc.inode);
|
||||
|
||||
if (!fd) {
|
||||
goto *err_label;
|
||||
}
|
||||
err_label = &&cleanup_@ARGNAME@;
|
||||
new_meta += 16;
|
||||
|
||||
#pragma fragment NEW_FD_CLEANUP
|
||||
cleanup_@ARGNAME@ : fd_unref(@ARGNAME@);
|
||||
|
||||
#pragma fragment INTEGER
|
||||
@ARGTYPE@ @ARGNAME@ = *((@ARGTYPE@ *)new_meta);
|
||||
|
||||
new_meta += sizeof(@ARGTYPE@);
|
||||
|
||||
#pragma fragment LOC
|
||||
loc_t @ARGNAME@ = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
@ARGNAME@.inode = recon_get_inode(fs, *((uuid_t *)new_meta));
|
||||
if (!@ARGNAME@.inode) {
|
||||
goto *err_label;
|
||||
}
|
||||
err_label = &&cleanup_@ARGNAME@;
|
||||
gf_uuid_copy(@ARGNAME@.gfid, @ARGNAME@.inode->gfid);
|
||||
new_meta += 16;
|
||||
new_meta += 16; /* skip over pargfid */
|
||||
if (*(new_meta++)) {
|
||||
@ARGNAME@.name = new_meta;
|
||||
new_meta += strlen(new_meta) + 1;
|
||||
}
|
||||
|
||||
#pragma fragment LOC_CLEANUP
|
||||
cleanup_@ARGNAME@ : loc_wipe(&@ARGNAME@);
|
||||
|
||||
#pragma fragment PARENT_LOC
|
||||
loc_t @ARGNAME@ = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
new_meta += 16; /* skip over gfid */
|
||||
@ARGNAME@.parent = recon_get_inode(fs, *((uuid_t *)new_meta));
|
||||
if (!@ARGNAME@.parent) {
|
||||
goto *err_label;
|
||||
}
|
||||
err_label = &&cleanup_@ARGNAME@;
|
||||
gf_uuid_copy(@ARGNAME@.pargfid, @ARGNAME@.parent->gfid);
|
||||
new_meta += 16;
|
||||
if (!*(new_meta++)) {
|
||||
goto *err_label;
|
||||
}
|
||||
@ARGNAME@.name = new_meta;
|
||||
new_meta += strlen(new_meta) + 1;
|
||||
|
||||
@ARGNAME@.inode = inode_new(fs->active_subvol->itable);
|
||||
if (!@ARGNAME@.inode) {
|
||||
goto *err_label;
|
||||
}
|
||||
|
||||
#pragma fragment PARENT_LOC_CLEANUP
|
||||
cleanup_@ARGNAME@ : loc_wipe(&@ARGNAME@);
|
||||
|
||||
#pragma fragment STRING
|
||||
char *@ARGNAME@;
|
||||
if (*(new_meta++)) {
|
||||
@ARGNAME@ = new_meta;
|
||||
new_meta += (strlen(new_meta) + 1);
|
||||
} else {
|
||||
goto *err_label;
|
||||
}
|
||||
|
||||
#pragma fragment VECTOR
|
||||
struct iovec @ARGNAME@;
|
||||
|
||||
@ARGNAME@.iov_len = *((size_t *)new_meta);
|
||||
new_meta += sizeof(@ARGNAME@.iov_len);
|
||||
@ARGNAME@.iov_base = new_data;
|
||||
new_data += @ARGNAME@.iov_len;
|
||||
|
||||
#pragma fragment IATT
|
||||
struct iatt @ARGNAME@;
|
||||
{
|
||||
@ARGNAME@.ia_prot = *((ia_prot_t *)new_meta);
|
||||
new_meta += sizeof(ia_prot_t);
|
||||
uint32_t *myints = (uint32_t *)new_meta;
|
||||
@ARGNAME@.ia_uid = myints[0];
|
||||
@ARGNAME@.ia_gid = myints[1];
|
||||
@ARGNAME@.ia_atime = myints[2];
|
||||
@ARGNAME@.ia_atime_nsec = myints[3];
|
||||
@ARGNAME@.ia_mtime = myints[4];
|
||||
@ARGNAME@.ia_mtime_nsec = myints[5];
|
||||
new_meta += sizeof(*myints) * 6;
|
||||
}
|
||||
|
||||
#pragma fragment IOBREF
|
||||
struct iobref *@ARGNAME@;
|
||||
|
||||
@ARGNAME@ = iobref_new();
|
||||
if (!@ARGNAME@) {
|
||||
goto *err_label;
|
||||
}
|
||||
err_label = &&cleanup_@ARGNAME@;
|
||||
|
||||
#pragma fragment IOBREF_CLEANUP
|
||||
cleanup_@ARGNAME@ : iobref_unref(@ARGNAME@);
|
||||
|
||||
#pragma fragment LINK
|
||||
/* TBD: check error */
|
||||
inode_t *new_inode = inode_link(@INODE_ARG@, NULL, NULL, @IATT_ARG@);
|
||||
if (new_inode) {
|
||||
inode_lookup(new_inode);
|
||||
}
|
||||
|
||||
#pragma fragment FOP
|
||||
int fdl_replay_@NAME@(glfs_t *fs, char **old_meta, char **old_data)
|
||||
{
|
||||
char *new_meta = *old_meta;
|
||||
char *new_data = *old_data;
|
||||
int ret;
|
||||
int status = 0xbad;
|
||||
void *err_label = &&done;
|
||||
|
||||
@FUNCTION_BODY@
|
||||
|
||||
ret = syncop_@NAME@(fs->active_subvol, @SYNCOP_ARGS@, NULL);
|
||||
if (ret !=@SUCCESS_VALUE@) {
|
||||
fprintf(stderr, "syncop_@NAME@ returned %d", ret);
|
||||
goto *err_label;
|
||||
}
|
||||
|
||||
@LINKS@
|
||||
|
||||
status = 0;
|
||||
|
||||
@CLEANUPS@
|
||||
|
||||
done : *old_meta = new_meta;
|
||||
*old_data = new_data;
|
||||
return status;
|
||||
}
|
||||
|
||||
#pragma fragment CASE
|
||||
case GF_FOP_@UPNAME@:
|
||||
printf("=== GF_FOP_@UPNAME@\n");
|
||||
if (fdl_replay_@NAME@(fs, &new_meta, &new_data) != 0) {
|
||||
goto done;
|
||||
}
|
||||
recognized = 1;
|
||||
break;
|
||||
|
||||
#pragma fragment EPILOG
|
||||
int
|
||||
recon_execute(glfs_t *fs, char **old_meta, char **old_data)
|
||||
{
|
||||
char *new_meta = *old_meta;
|
||||
char *new_data = *old_data;
|
||||
int recognized = 0;
|
||||
event_header_t *eh;
|
||||
|
||||
eh = (event_header_t *)new_meta;
|
||||
new_meta += sizeof(*eh);
|
||||
|
||||
/* TBD: check event_type instead of assuming NEW_REQUEST */
|
||||
|
||||
switch (eh->fop_type) {
|
||||
@SWITCH_BODY@
|
||||
|
||||
default : printf("unknown fop %u\n", eh->fop_type);
|
||||
}
|
||||
|
||||
done:
|
||||
*old_meta = new_meta;
|
||||
*old_data = new_data;
|
||||
return recognized;
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <glusterfs/glusterfs.h>
|
||||
#include <glusterfs/fd.h>
|
||||
#include <glusterfs/syncop.h>
|
||||
#include "glfs-internal.h"
|
||||
|
||||
#define GFAPI_SUCCESS 0
|
||||
|
||||
extern int
|
||||
recon_execute(glfs_t *, char **, char **);
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
glfs_t *fs;
|
||||
int ret;
|
||||
int meta_fd = (-1);
|
||||
char *meta_buf = NULL;
|
||||
int data_fd = (-1);
|
||||
char *data_buf = NULL;
|
||||
|
||||
fs = glfs_new("whocares");
|
||||
if (!fs) {
|
||||
fprintf(stderr, "glfs_new failed\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (getenv("RECON_DEBUG")) {
|
||||
ret = glfs_set_logging(fs, "/dev/stderr", 7);
|
||||
} else {
|
||||
ret = glfs_set_logging(fs, "/dev/null", 0);
|
||||
}
|
||||
|
||||
if (ret != GFAPI_SUCCESS) {
|
||||
fprintf(stderr, "glfs_set_logging failed (%d)\n", errno);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ret = glfs_set_volfile(fs, argv[1]);
|
||||
if (ret != GFAPI_SUCCESS) {
|
||||
fprintf(stderr, "glfs_set_volfile failed (%d)\n", errno);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
ret = glfs_init(fs);
|
||||
if (ret != GFAPI_SUCCESS) {
|
||||
fprintf(stderr, "glfs_init failed (%d)\n", errno);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
meta_fd = open(argv[2], O_RDONLY);
|
||||
if (meta_fd < 0) {
|
||||
perror("open");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* TBD: get proper length */
|
||||
meta_buf = mmap(NULL, 1048576, PROT_READ, MAP_PRIVATE, meta_fd, 0);
|
||||
if (meta_buf == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
data_fd = open(argv[3], O_RDONLY);
|
||||
if (data_fd < 0) {
|
||||
perror("open");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* TBD: get proper length */
|
||||
data_buf = mmap(NULL, 1048576, PROT_READ, MAP_PRIVATE, data_fd, 0);
|
||||
if (data_buf == MAP_FAILED) {
|
||||
perror("mmap");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (!recon_execute(fs, &meta_buf, &data_buf)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
SUBDIRS = src
|
||||
|
||||
CLEANFILES =
|
@ -1,34 +0,0 @@
|
||||
if WITH_SERVER
|
||||
xlator_LTLIBRARIES = jbrc.la
|
||||
endif
|
||||
xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/experimental
|
||||
|
||||
nodist_jbrc_la_SOURCES = jbrc-cg.c
|
||||
CLEANFILES = $(nodist_jbrc_la_SOURCES)
|
||||
|
||||
jbrc_la_LDFLAGS = -module $(GF_XLATOR_DEFAULT_LDFLAGS)
|
||||
jbrc_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la
|
||||
|
||||
noinst_HEADERS = $(top_srcdir)/xlators/lib/src/libxlator.h \
|
||||
$(top_srcdir)/glusterfsd/src/glusterfsd.h \
|
||||
jbrc.h jbr-messages.h
|
||||
|
||||
AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \
|
||||
-I$(top_srcdir)/xlators/lib/src \
|
||||
-I$(top_srcdir)/rpc/xdr/src -I$(top_builddir)/rpc/xdr/src \
|
||||
-I$(top_srcdir)/rpc/rpc-lib/src
|
||||
|
||||
AM_CFLAGS = -Wall $(GF_CFLAGS)
|
||||
|
||||
JBRC_PREFIX = $(top_srcdir)/xlators/experimental/jbr-client/src
|
||||
JBRC_GEN_FOPS = $(JBRC_PREFIX)/gen-fops.py
|
||||
JBRC_TEMPLATES = $(JBRC_PREFIX)/fop-template.c.in
|
||||
JBRC_WRAPPER = $(JBRC_PREFIX)/jbrc.c
|
||||
noinst_PYTHON = $(JBRC_GEN_FOPS)
|
||||
EXTRA_DIST = $(JBRC_TEMPLATES) $(JBRC_WRAPPER)
|
||||
|
||||
jbrc-cg.c: $(JBRC_GEN_FOPS) $(JBRC_TEMPLATES) $(JBRC_WRAPPER)
|
||||
$(PYTHON) $(JBRC_GEN_FOPS) $(JBRC_TEMPLATES) $(JBRC_WRAPPER) > $@
|
||||
|
||||
uninstall-local:
|
||||
rm -f $(DESTDIR)$(xlatordir)/jbr.so
|
@ -1,102 +0,0 @@
|
||||
/* template-name fop */
|
||||
int32_t jbrc_@NAME@(call_frame_t *frame, xlator_t *this, @LONG_ARGS@)
|
||||
{
|
||||
jbrc_local_t *local = NULL;
|
||||
xlator_t *target_xl = ACTIVE_CHILD(this);
|
||||
|
||||
local = mem_get(this->local_pool);
|
||||
if (!local) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
local->stub = fop_@NAME@_stub(frame, jbrc_@NAME@_continue, @SHORT_ARGS@);
|
||||
if (!local->stub) {
|
||||
goto err;
|
||||
}
|
||||
local->curr_xl = target_xl;
|
||||
local->scars = 0;
|
||||
|
||||
frame->local = local;
|
||||
STACK_WIND_COOKIE(frame, jbrc_@NAME@_cbk, target_xl, target_xl,
|
||||
target_xl->fops->@NAME@, @SHORT_ARGS@);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (local) {
|
||||
mem_put(local);
|
||||
}
|
||||
STACK_UNWIND_STRICT(@NAME@, frame, -1, ENOMEM, @ERROR_ARGS@);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* template-name cbk */
|
||||
int32_t jbrc_@NAME@_cbk(call_frame_t *frame, void *cookie, xlator_t *this,
|
||||
int32_t op_ret, int32_t op_errno, @LONG_ARGS@)
|
||||
{
|
||||
jbrc_local_t *local = frame->local;
|
||||
xlator_t *last_xl = cookie;
|
||||
xlator_t *next_xl;
|
||||
jbrc_private_t *priv = this->private;
|
||||
struct timespec spec;
|
||||
|
||||
if (op_ret != (-1)) {
|
||||
if (local->scars) {
|
||||
gf_msg(this->name, GF_LOG_INFO, 0, J_MSG_RETRY_MSG,
|
||||
HILITE("retried %p OK"), frame->local);
|
||||
}
|
||||
priv->active = last_xl;
|
||||
goto unwind;
|
||||
}
|
||||
if ((op_errno != EREMOTE) && (op_errno != ENOTCONN)) {
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
/* TBD: get leader ID from xdata? */
|
||||
next_xl = next_xlator(this, last_xl);
|
||||
/*
|
||||
* We can't just give up after we've tried all bricks, because it's
|
||||
* quite likely that a new leader election just hasn't finished yet.
|
||||
* We also shouldn't retry endlessly, and especially not at a high
|
||||
* rate, but that's good enough while we work on other things.
|
||||
*
|
||||
* TBD: implement slow/finite retry via a worker thread
|
||||
*/
|
||||
if (!next_xl || (local->scars >= SCAR_LIMIT)) {
|
||||
gf_msg(this->name, GF_LOG_DEBUG, 0, J_MSG_RETRY_MSG,
|
||||
HILITE("ran out of retries for %p"), frame->local);
|
||||
goto unwind;
|
||||
}
|
||||
|
||||
local->curr_xl = next_xl;
|
||||
local->scars += 1;
|
||||
spec.tv_sec = 1;
|
||||
spec.tv_nsec = 0;
|
||||
/*
|
||||
* WARNING
|
||||
*
|
||||
* Just calling gf_timer_call_after like this leaves open the
|
||||
* possibility that writes will get reordered, if a first write is
|
||||
* rescheduled and then a second comes along to find an updated
|
||||
* priv->active before the first actually executes. We might need to
|
||||
* implement a stricter (and more complicated) queuing mechanism to
|
||||
* ensure absolute consistency in this case.
|
||||
*/
|
||||
if (gf_timer_call_after(this->ctx, spec, jbrc_retry_cb, local)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unwind:
|
||||
call_stub_destroy(local->stub);
|
||||
STACK_UNWIND_STRICT(@NAME@, frame, op_ret, op_errno, @SHORT_ARGS@);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* template-name cont-func */
|
||||
int32_t jbrc_@NAME@_continue(call_frame_t *frame, xlator_t *this, @LONG_ARGS@)
|
||||
{
|
||||
jbrc_local_t *local = frame->local;
|
||||
|
||||
STACK_WIND_COOKIE(frame, jbrc_@NAME@_cbk, local->curr_xl, local->curr_xl,
|
||||
local->curr_xl->fops->@NAME@, @SHORT_ARGS@);
|
||||
return 0;
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import re
|
||||
import string
|
||||
import sys
|
||||
|
||||
curdir = os.path.dirname(sys.argv[0])
|
||||
gendir = os.path.join(curdir, '../../../../libglusterfs/src')
|
||||
sys.path.append(gendir)
|
||||
from generator import ops, fop_subs, cbk_subs, generate
|
||||
|
||||
# We really want the callback argument list, even when we're generating fop
|
||||
# code, so we propagate here.
|
||||
# TBD: this should probably be right in generate.py
|
||||
for k, v in cbk_subs.items():
|
||||
fop_subs[k]['@ERROR_ARGS@'] = v['@ERROR_ARGS@']
|
||||
|
||||
# Stolen from old codegen.py
|
||||
def load_templates (path):
|
||||
templates = {}
|
||||
tmpl_re = re.compile("/\* template-name (.*) \*/")
|
||||
templates = {}
|
||||
t_name = None
|
||||
for line in open(path, "r").readlines():
|
||||
if not line:
|
||||
break
|
||||
m = tmpl_re.match(line)
|
||||
if m:
|
||||
if t_name:
|
||||
templates[t_name] = ''.join(t_contents)
|
||||
t_name = m.group(1).strip()
|
||||
t_contents = []
|
||||
elif t_name:
|
||||
t_contents.append(line)
|
||||
if t_name:
|
||||
templates[t_name] = ''.join(t_contents)
|
||||
return templates
|
||||
|
||||
# Stolen from gen_fdl.py
|
||||
def gen_client (templates):
|
||||
for name, value in ops.items():
|
||||
if name == 'getspec':
|
||||
# It's not real if it doesn't have a stub function.
|
||||
continue
|
||||
print(generate(templates['cbk'], name, cbk_subs))
|
||||
print(generate(templates['cont-func'], name, fop_subs))
|
||||
print(generate(templates['fop'], name, fop_subs))
|
||||
|
||||
tmpl = load_templates(sys.argv[1])
|
||||
for l in open(sys.argv[2], 'r').readlines():
|
||||
if l.find('#pragma generate') != -1:
|
||||
print("/* BEGIN GENERATED CODE - DO NOT MODIFY */")
|
||||
gen_client(tmpl)
|
||||
print("/* END GENERATED CODE */")
|
||||
else:
|
||||
print(l[:-1])
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2015 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 _JBR_MESSAGES_H_
|
||||
#define _JBR_MESSAGES_H_
|
||||
|
||||
#include <glusterfs/glfs-message-id.h>
|
||||
|
||||
/* To add new message IDs, append new identifiers at the end of the list.
|
||||
*
|
||||
* Never remove a message ID. If it's not used anymore, you can rename it or
|
||||
* leave it as it is, but not delete it. This is to prevent reutilization of
|
||||
* IDs by other messages.
|
||||
*
|
||||
* The component name must match one of the entries defined in
|
||||
* glfs-message-id.h.
|
||||
*/
|
||||
|
||||
GLFS_MSGID(JBR, J_MSG_INIT_FAIL, J_MSG_RETRY_MSG, J_MSG_MEM_ERR, J_MSG_DICT_FLR,
|
||||
J_MSG_GENERIC, J_MSG_INVALID, J_MSG_NO_DATA, J_MSG_SYS_CALL_FAILURE,
|
||||
J_MSG_QUORUM_NOT_MET, J_MSG_LOCK_FAILURE);
|
||||
|
||||
#endif /* _JBR_MESSAGES_H_ */
|
@ -1,311 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
|
||||
|
||||
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 <glusterfs/call-stub.h>
|
||||
#include <glusterfs/defaults.h>
|
||||
#include <glusterfs/timer.h>
|
||||
#include <glusterfs/xlator.h>
|
||||
#include "jbr-messages.h"
|
||||
#include "jbrc.h"
|
||||
#include <glusterfs/statedump.h>
|
||||
|
||||
#define SCAR_LIMIT 20
|
||||
#define HILITE(x) ("[1;33m" x "[0m")
|
||||
|
||||
/*
|
||||
* The fops are actually generated by gen-fops.py; the rest was mostly copied
|
||||
* from defaults.c (commit cd253754 on 27 August 2013).
|
||||
*/
|
||||
|
||||
enum gf_dht_mem_types_ {
|
||||
gf_mt_jbrc_private_t = gf_common_mt_end + 1,
|
||||
gf_mt_jbrc_end
|
||||
};
|
||||
|
||||
char *JBRC_XATTR = "user.jbr.active";
|
||||
|
||||
static inline xlator_t *
|
||||
ACTIVE_CHILD(xlator_t *parent)
|
||||
{
|
||||
jbrc_private_t *priv = parent->private;
|
||||
|
||||
return priv ? priv->active : FIRST_CHILD(parent);
|
||||
}
|
||||
|
||||
xlator_t *
|
||||
next_xlator(xlator_t *this, xlator_t *prev)
|
||||
{
|
||||
xlator_list_t *trav;
|
||||
|
||||
for (trav = this->children; trav; trav = trav->next) {
|
||||
if (trav->xlator == prev) {
|
||||
return trav->next ? trav->next->xlator : this->children->xlator;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
jbrc_retry_cb(void *cb_arg)
|
||||
{
|
||||
jbrc_local_t *local = cb_arg;
|
||||
|
||||
gf_msg(__func__, GF_LOG_INFO, 0, J_MSG_RETRY_MSG, HILITE("retrying %p"),
|
||||
local);
|
||||
call_resume_wind(local->stub);
|
||||
}
|
||||
|
||||
#pragma generate
|
||||
|
||||
int32_t
|
||||
jbrc_forget(xlator_t *this, inode_t *inode)
|
||||
{
|
||||
gf_msg_callingfn(this->name, GF_LOG_WARNING, 0, J_MSG_INIT_FAIL,
|
||||
"xlator does not implement forget_cbk");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
jbrc_releasedir(xlator_t *this, fd_t *fd)
|
||||
{
|
||||
gf_msg_callingfn(this->name, GF_LOG_WARNING, 0, J_MSG_INIT_FAIL,
|
||||
"xlator does not implement releasedir_cbk");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
jbrc_release(xlator_t *this, fd_t *fd)
|
||||
{
|
||||
gf_msg_callingfn(this->name, GF_LOG_WARNING, 0, J_MSG_INIT_FAIL,
|
||||
"xlator does not implement release_cbk");
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct xlator_fops fops = {
|
||||
.lookup = jbrc_lookup,
|
||||
.stat = jbrc_stat,
|
||||
.fstat = jbrc_fstat,
|
||||
.truncate = jbrc_truncate,
|
||||
.ftruncate = jbrc_ftruncate,
|
||||
.access = jbrc_access,
|
||||
.readlink = jbrc_readlink,
|
||||
.mknod = jbrc_mknod,
|
||||
.mkdir = jbrc_mkdir,
|
||||
.unlink = jbrc_unlink,
|
||||
.rmdir = jbrc_rmdir,
|
||||
.symlink = jbrc_symlink,
|
||||
.rename = jbrc_rename,
|
||||
.link = jbrc_link,
|
||||
.create = jbrc_create,
|
||||
.open = jbrc_open,
|
||||
.readv = jbrc_readv,
|
||||
.writev = jbrc_writev,
|
||||
.flush = jbrc_flush,
|
||||
.fsync = jbrc_fsync,
|
||||
.opendir = jbrc_opendir,
|
||||
.readdir = jbrc_readdir,
|
||||
.readdirp = jbrc_readdirp,
|
||||
.fsyncdir = jbrc_fsyncdir,
|
||||
.statfs = jbrc_statfs,
|
||||
.setxattr = jbrc_setxattr,
|
||||
.getxattr = jbrc_getxattr,
|
||||
.fsetxattr = jbrc_fsetxattr,
|
||||
.fgetxattr = jbrc_fgetxattr,
|
||||
.removexattr = jbrc_removexattr,
|
||||
.fremovexattr = jbrc_fremovexattr,
|
||||
.lk = jbrc_lk,
|
||||
.inodelk = jbrc_inodelk,
|
||||
.finodelk = jbrc_finodelk,
|
||||
.entrylk = jbrc_entrylk,
|
||||
.fentrylk = jbrc_fentrylk,
|
||||
.rchecksum = jbrc_rchecksum,
|
||||
.xattrop = jbrc_xattrop,
|
||||
.fxattrop = jbrc_fxattrop,
|
||||
.setattr = jbrc_setattr,
|
||||
.fsetattr = jbrc_fsetattr,
|
||||
.fallocate = jbrc_fallocate,
|
||||
.discard = jbrc_discard,
|
||||
};
|
||||
|
||||
struct xlator_cbks cbks = {};
|
||||
|
||||
int32_t
|
||||
mem_acct_init(xlator_t *this)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
GF_VALIDATE_OR_GOTO("jbrc", this, out);
|
||||
|
||||
ret = xlator_mem_acct_init(this, gf_mt_jbrc_end + 1);
|
||||
|
||||
if (ret != 0) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, ENOMEM, J_MSG_MEM_ERR,
|
||||
"Memory accounting init failed");
|
||||
return ret;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t
|
||||
jbrc_init(xlator_t *this)
|
||||
{
|
||||
jbrc_private_t *priv = NULL;
|
||||
xlator_list_t *trav = NULL;
|
||||
|
||||
this->local_pool = mem_pool_new(jbrc_local_t, 128);
|
||||
if (!this->local_pool) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, ENOMEM, J_MSG_MEM_ERR,
|
||||
"failed to create jbrc_local_t pool");
|
||||
goto err;
|
||||
}
|
||||
|
||||
priv = GF_CALLOC(1, sizeof(*priv), gf_mt_jbrc_private_t);
|
||||
if (!priv) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (trav = this->children; trav; trav = trav->next) {
|
||||
++(priv->n_children);
|
||||
}
|
||||
|
||||
priv->active = FIRST_CHILD(this);
|
||||
this->private = priv;
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (priv) {
|
||||
GF_FREE(priv);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
jbrc_fini(xlator_t *this)
|
||||
{
|
||||
GF_FREE(this->private);
|
||||
}
|
||||
|
||||
int
|
||||
jbrc_get_child_index(xlator_t *this, xlator_t *kid)
|
||||
{
|
||||
xlator_list_t *trav;
|
||||
int retval = -1;
|
||||
|
||||
for (trav = this->children; trav; trav = trav->next) {
|
||||
++retval;
|
||||
if (trav->xlator == kid) {
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
jbrc_count_up_kids(jbrc_private_t *priv)
|
||||
{
|
||||
uint8_t retval = 0;
|
||||
uint8_t i;
|
||||
|
||||
for (i = 0; i < priv->n_children; ++i) {
|
||||
if (priv->kid_state & (1 << i)) {
|
||||
++retval;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int32_t
|
||||
jbrc_notify(xlator_t *this, int32_t event, void *data, ...)
|
||||
{
|
||||
int32_t ret = 0;
|
||||
int32_t index = 0;
|
||||
jbrc_private_t *priv = NULL;
|
||||
|
||||
GF_VALIDATE_OR_GOTO(THIS->name, this, out);
|
||||
priv = this->private;
|
||||
GF_VALIDATE_OR_GOTO(this->name, priv, out);
|
||||
|
||||
switch (event) {
|
||||
case GF_EVENT_CHILD_UP:
|
||||
index = jbrc_get_child_index(this, data);
|
||||
if (index >= 0) {
|
||||
priv->kid_state |= (1 << index);
|
||||
priv->up_children = jbrc_count_up_kids(priv);
|
||||
gf_msg(this->name, GF_LOG_INFO, 0, J_MSG_GENERIC,
|
||||
"got CHILD_UP for %s, now %u kids",
|
||||
((xlator_t *)data)->name, priv->up_children);
|
||||
}
|
||||
ret = default_notify(this, event, data);
|
||||
break;
|
||||
case GF_EVENT_CHILD_DOWN:
|
||||
index = jbrc_get_child_index(this, data);
|
||||
if (index >= 0) {
|
||||
priv->kid_state &= ~(1 << index);
|
||||
priv->up_children = jbrc_count_up_kids(priv);
|
||||
gf_msg(this->name, GF_LOG_INFO, 0, J_MSG_GENERIC,
|
||||
"got CHILD_DOWN for %s, now %u kids",
|
||||
((xlator_t *)data)->name, priv->up_children);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = default_notify(this, event, data);
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
jbrc_priv_dump(xlator_t *this)
|
||||
{
|
||||
jbrc_private_t *priv = NULL;
|
||||
char key_prefix[GF_DUMP_MAX_BUF_LEN];
|
||||
xlator_list_t *trav = NULL;
|
||||
int32_t i = -1;
|
||||
|
||||
GF_VALIDATE_OR_GOTO(THIS->name, this, out);
|
||||
priv = this->private;
|
||||
GF_VALIDATE_OR_GOTO(this->name, priv, out);
|
||||
|
||||
snprintf(key_prefix, GF_DUMP_MAX_BUF_LEN, "%s.%s", this->type, this->name);
|
||||
gf_proc_dump_add_section("%s", key_prefix);
|
||||
|
||||
gf_proc_dump_write("up_children", "%u", priv->up_children);
|
||||
|
||||
for (trav = this->children, i = 0; trav; trav = trav->next, i++) {
|
||||
snprintf(key_prefix, GF_DUMP_MAX_BUF_LEN, "child_%d", i);
|
||||
gf_proc_dump_write(key_prefix, "%s", trav->xlator->name);
|
||||
}
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct xlator_dumpops dumpops = {
|
||||
.priv = jbrc_priv_dump,
|
||||
};
|
||||
|
||||
class_methods_t class_methods = {
|
||||
.init = jbrc_init,
|
||||
.fini = jbrc_fini,
|
||||
.notify = jbrc_notify,
|
||||
};
|
||||
|
||||
struct volume_options options[] = {
|
||||
{.key = {NULL}},
|
||||
};
|
@ -1,27 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 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 _JBRC_H_
|
||||
#define _JBRC_H_
|
||||
|
||||
typedef struct {
|
||||
xlator_t *active;
|
||||
uint8_t up_children;
|
||||
uint8_t n_children;
|
||||
uint32_t kid_state;
|
||||
} jbrc_private_t;
|
||||
|
||||
typedef struct {
|
||||
call_stub_t *stub;
|
||||
xlator_t *curr_xl;
|
||||
uint16_t scars;
|
||||
} jbrc_local_t;
|
||||
|
||||
#endif /* _JBRC_H_ */
|
@ -1,3 +0,0 @@
|
||||
SUBDIRS = src
|
||||
|
||||
CLEANFILES =
|
@ -1,39 +0,0 @@
|
||||
if WITH_SERVER
|
||||
xlator_LTLIBRARIES = jbr.la
|
||||
endif
|
||||
xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/experimental
|
||||
|
||||
nodist_jbr_la_SOURCES = jbr-cg.c
|
||||
CLEANFILES = $(nodist_jbr_la_SOURCES)
|
||||
|
||||
jbr_la_LDFLAGS = -module $(GF_XLATOR_DEFAULT_LDFLAGS)
|
||||
jbr_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la \
|
||||
$(top_builddir)/api/src/libgfapi.la
|
||||
|
||||
noinst_HEADERS = jbr-internal.h \
|
||||
$(top_srcdir)/xlators/lib/src/libxlator.h \
|
||||
$(top_srcdir)/xlators/experimental/fdl/src/fdl.h \
|
||||
$(top_srcdir)/glusterfsd/src/glusterfsd.h
|
||||
|
||||
AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \
|
||||
-I$(top_srcdir)/rpc/xdr/src -I$(top_builddir)/rpc/xdr/src \
|
||||
-I$(top_srcdir)/xlators/lib/src -I$(top_srcdir)/rpc/rpc-lib/src \
|
||||
-I$(top_srcdir)/xlators/experimental/fdl/src/ \
|
||||
-DSBIN_DIR=\"$(sbindir)\" -I$(top_srcdir)/api/src \
|
||||
-DJBR_SCRIPT_PREFIX=\"$(jbrdir)\" \
|
||||
-I$(top_srcdir)/xlators/experimental/jbr-client/src/
|
||||
|
||||
AM_CFLAGS = -Wall $(GF_CFLAGS)
|
||||
|
||||
JBR_PREFIX = $(top_srcdir)/xlators/experimental/jbr-server/src
|
||||
JBR_GEN_FOPS = $(JBR_PREFIX)/gen-fops.py
|
||||
JBR_TEMPLATES = $(JBR_PREFIX)/all-templates.c.in
|
||||
JBR_WRAPPER = $(JBR_PREFIX)/jbr.c
|
||||
noinst_PYTHON = $(JBR_GEN_FOPS)
|
||||
EXTRA_DIST = $(JBR_TEMPLATES) $(JBR_WRAPPER)
|
||||
|
||||
jbr-cg.c: $(JBR_GEN_FOPS) $(JBR_TEMPLATES) $(JBR_WRAPPER)
|
||||
$(PYTHON) $(JBR_GEN_FOPS) $(JBR_TEMPLATES) $(JBR_WRAPPER) > $@
|
||||
|
||||
uninstall-local:
|
||||
rm -f $(DESTDIR)$(xlatordir)/jbr.so
|
@ -1,501 +0,0 @@
|
||||
/*
|
||||
* You can put anything here - it doesn't even have to be a comment - and it
|
||||
* will be ignored until we reach the first template-name comment.
|
||||
*/
|
||||
|
||||
/* template-name read-fop */
|
||||
int32_t jbr_@NAME@(call_frame_t *frame, xlator_t *this, @LONG_ARGS@)
|
||||
{
|
||||
jbr_private_t *priv = NULL;
|
||||
gf_boolean_t in_recon = _gf_false;
|
||||
int32_t op_errno = 0;
|
||||
int32_t recon_term, recon_index;
|
||||
|
||||
GF_VALIDATE_OR_GOTO("jbr", this, err);
|
||||
priv = this->private;
|
||||
GF_VALIDATE_OR_GOTO(this->name, priv, err);
|
||||
GF_VALIDATE_OR_GOTO(this->name, frame, err);
|
||||
|
||||
op_errno = EREMOTE;
|
||||
|
||||
/* allow reads during reconciliation *
|
||||
* TBD: allow "dirty" reads on non-leaders *
|
||||
*/
|
||||
if (xdata && (dict_get_int32(xdata, RECON_TERM_XATTR, &recon_term) == 0) &&
|
||||
(dict_get_int32(xdata, RECON_INDEX_XATTR, &recon_index) == 0)) {
|
||||
in_recon = _gf_true;
|
||||
}
|
||||
|
||||
if ((!priv->leader) && (in_recon == _gf_false)) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
STACK_WIND(frame, default_@NAME@_cbk, FIRST_CHILD(this),
|
||||
FIRST_CHILD(this)->fops->@NAME@, @SHORT_ARGS@);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
STACK_UNWIND_STRICT(@NAME@, frame, -1, op_errno, @ERROR_ARGS@);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* template-name read-perform_local_op */
|
||||
/* No "perform_local_op" function needed for @NAME@ */
|
||||
|
||||
/* template-name read-dispatch */
|
||||
/* No "dispatch" function needed for @NAME@ */
|
||||
|
||||
/* template-name read-call_dispatch */
|
||||
/* No "call_dispatch" function needed for @NAME@ */
|
||||
|
||||
/* template-name read-fan-in */
|
||||
/* No "fan-in" function needed for @NAME@ */
|
||||
|
||||
/* template-name read-continue */
|
||||
/* No "continue" function needed for @NAME@ */
|
||||
|
||||
/* template-name read-complete */
|
||||
/* No "complete" function needed for @NAME@ */
|
||||
|
||||
/* template-name write-fop */
|
||||
int32_t jbr_@NAME@(call_frame_t *frame, xlator_t *this, @LONG_ARGS@)
|
||||
{
|
||||
jbr_local_t *local = NULL;
|
||||
jbr_private_t *priv = NULL;
|
||||
int32_t ret = -1;
|
||||
int op_errno = ENOMEM;
|
||||
|
||||
GF_VALIDATE_OR_GOTO("jbr", this, err);
|
||||
priv = this->private;
|
||||
GF_VALIDATE_OR_GOTO(this->name, priv, err);
|
||||
GF_VALIDATE_OR_GOTO(this->name, frame, err);
|
||||
|
||||
#if defined(JBR_CG_NEED_FD)
|
||||
ret = jbr_leader_checks_and_init(frame, this, &op_errno, xdata, fd);
|
||||
#else
|
||||
ret = jbr_leader_checks_and_init(frame, this, &op_errno, xdata, NULL);
|
||||
#endif
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
local = frame->local;
|
||||
|
||||
/*
|
||||
* If we let it through despite not being the leader, then we just want
|
||||
* to pass it on down without all of the additional xattrs, queuing, and
|
||||
* so on. However, jbr_*_complete does depend on the initialization
|
||||
* immediately above this.
|
||||
*/
|
||||
if (!priv->leader) {
|
||||
STACK_WIND(frame, jbr_@NAME@_complete, FIRST_CHILD(this),
|
||||
FIRST_CHILD(this)->fops->@NAME@, @SHORT_ARGS@);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = jbr_initialize_xdata_set_attrs(this, &xdata);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
local->xdata = dict_ref(xdata);
|
||||
local->stub = fop_@NAME@_stub(frame, jbr_@NAME@_continue, @SHORT_ARGS@);
|
||||
if (!local->stub) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Can be used to just call_dispatch or be customised per fop to *
|
||||
* perform ops specific to that particular fop. *
|
||||
*/
|
||||
ret = jbr_@NAME@_perform_local_op(frame, this, &op_errno, @SHORT_ARGS@);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return ret;
|
||||
err:
|
||||
if (local) {
|
||||
if (local->stub) {
|
||||
call_stub_destroy(local->stub);
|
||||
}
|
||||
if (local->qstub) {
|
||||
call_stub_destroy(local->qstub);
|
||||
}
|
||||
if (local->fd) {
|
||||
fd_unref(local->fd);
|
||||
}
|
||||
mem_put(local);
|
||||
}
|
||||
STACK_UNWIND_STRICT(@NAME@, frame, -1, op_errno, @ERROR_ARGS@);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* template-name write-perform_local_op */
|
||||
int32_t jbr_@NAME@_perform_local_op(call_frame_t *frame, xlator_t *this,
|
||||
int *op_errno, @LONG_ARGS@)
|
||||
{
|
||||
int32_t ret = -1;
|
||||
|
||||
GF_VALIDATE_OR_GOTO("jbr", this, out);
|
||||
GF_VALIDATE_OR_GOTO(this->name, frame, out);
|
||||
GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
|
||||
|
||||
ret = jbr_@NAME@_call_dispatch(frame, this, op_errno, @SHORT_ARGS@);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* template-name write-call_dispatch */
|
||||
int32_t jbr_@NAME@_call_dispatch(call_frame_t *frame, xlator_t *this,
|
||||
int *op_errno, @LONG_ARGS@)
|
||||
{
|
||||
jbr_local_t *local = NULL;
|
||||
jbr_private_t *priv = NULL;
|
||||
int32_t ret = -1;
|
||||
|
||||
GF_VALIDATE_OR_GOTO("jbr", this, out);
|
||||
priv = this->private;
|
||||
GF_VALIDATE_OR_GOTO(this->name, priv, out);
|
||||
GF_VALIDATE_OR_GOTO(this->name, frame, out);
|
||||
local = frame->local;
|
||||
GF_VALIDATE_OR_GOTO(this->name, local, out);
|
||||
GF_VALIDATE_OR_GOTO(this->name, op_errno, out);
|
||||
|
||||
#if defined(JBR_CG_QUEUE)
|
||||
jbr_inode_ctx_t *ictx = jbr_get_inode_ctx(this, fd->inode);
|
||||
if (!ictx) {
|
||||
*op_errno = EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
LOCK(&ictx->lock);
|
||||
if (ictx->active) {
|
||||
gf_msg_debug(this->name, 0, "queuing request due to conflict");
|
||||
/*
|
||||
* TBD: enqueue only for real conflict
|
||||
*
|
||||
* Currently we just act like all writes are in
|
||||
* conflict with one another. What we should really do
|
||||
* is check the active/pending queues and defer only if
|
||||
* there's a conflict there.
|
||||
*
|
||||
* It's important to check the pending queue because we
|
||||
* might have an active request X which conflicts with
|
||||
* a pending request Y, and this request Z might
|
||||
* conflict with Y but not X. If we checked only the
|
||||
* active queue then Z could jump ahead of Y, which
|
||||
* would be incorrect.
|
||||
*/
|
||||
local->qstub = fop_@NAME@_stub(frame, jbr_@NAME@_dispatch,
|
||||
@SHORT_ARGS@);
|
||||
if (!local->qstub) {
|
||||
UNLOCK(&ictx->lock);
|
||||
goto out;
|
||||
}
|
||||
list_add_tail(&local->qlinks, &ictx->pqueue);
|
||||
++(ictx->pending);
|
||||
UNLOCK(&ictx->lock);
|
||||
ret = 0;
|
||||
goto out;
|
||||
} else {
|
||||
list_add_tail(&local->qlinks, &ictx->aqueue);
|
||||
++(ictx->active);
|
||||
}
|
||||
UNLOCK(&ictx->lock);
|
||||
#endif
|
||||
ret = jbr_@NAME@_dispatch(frame, this, @SHORT_ARGS@);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* template-name write-dispatch */
|
||||
int32_t jbr_@NAME@_dispatch(call_frame_t *frame, xlator_t *this, @LONG_ARGS@)
|
||||
{
|
||||
jbr_local_t *local = NULL;
|
||||
jbr_private_t *priv = NULL;
|
||||
int32_t ret = -1;
|
||||
xlator_list_t *trav;
|
||||
|
||||
GF_VALIDATE_OR_GOTO("jbr", this, out);
|
||||
priv = this->private;
|
||||
GF_VALIDATE_OR_GOTO(this->name, priv, out);
|
||||
GF_VALIDATE_OR_GOTO(this->name, frame, out);
|
||||
local = frame->local;
|
||||
GF_VALIDATE_OR_GOTO(this->name, local, out);
|
||||
|
||||
/*
|
||||
* TBD: unblock pending request(s) if we fail after this point but
|
||||
* before we get to jbr_@NAME@_complete (where that code currently
|
||||
* resides).
|
||||
*/
|
||||
|
||||
local->call_count = priv->n_children - 1;
|
||||
for (trav = this->children->next; trav; trav = trav->next) {
|
||||
STACK_WIND(frame, jbr_@NAME@_fan_in, trav->xlator,
|
||||
trav->xlator->fops->@NAME@, @SHORT_ARGS@);
|
||||
}
|
||||
|
||||
/* TBD: variable Issue count */
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* template-name write-fan-in */
|
||||
int32_t jbr_@NAME@_fan_in(call_frame_t *frame, void *cookie, xlator_t *this,
|
||||
int32_t op_ret, int32_t op_errno, @LONG_ARGS@)
|
||||
{
|
||||
jbr_local_t *local = NULL;
|
||||
int32_t ret = -1;
|
||||
uint8_t call_count;
|
||||
|
||||
GF_VALIDATE_OR_GOTO("jbr", this, out);
|
||||
GF_VALIDATE_OR_GOTO(this->name, frame, out);
|
||||
local = frame->local;
|
||||
GF_VALIDATE_OR_GOTO(this->name, local, out);
|
||||
|
||||
gf_msg_trace(this->name, 0, "op_ret = %d, op_errno = %d\n", op_ret,
|
||||
op_errno);
|
||||
|
||||
LOCK(&frame->lock);
|
||||
call_count = --(local->call_count);
|
||||
if (op_ret != -1) {
|
||||
/* Increment the number of successful acks *
|
||||
* received for the operation. *
|
||||
*/
|
||||
(local->successful_acks)++;
|
||||
local->successful_op_ret = op_ret;
|
||||
}
|
||||
gf_msg_debug(this->name, 0, "succ_acks = %d, op_ret = %d, op_errno = %d\n",
|
||||
op_ret, op_errno, local->successful_acks);
|
||||
UNLOCK(&frame->lock);
|
||||
|
||||
/* TBD: variable Completion count */
|
||||
if (call_count == 0) {
|
||||
call_resume(local->stub);
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* template-name write-continue */
|
||||
int32_t jbr_@NAME@_continue(call_frame_t *frame, xlator_t *this, @LONG_ARGS@)
|
||||
{
|
||||
int32_t ret = -1;
|
||||
gf_boolean_t result = _gf_false;
|
||||
jbr_local_t *local = NULL;
|
||||
jbr_local_t *new_local = NULL;
|
||||
jbr_private_t *priv = NULL;
|
||||
int32_t op_errno = 0;
|
||||
|
||||
GF_VALIDATE_OR_GOTO("jbr", this, out);
|
||||
GF_VALIDATE_OR_GOTO(this->name, frame, out);
|
||||
priv = this->private;
|
||||
local = frame->local;
|
||||
GF_VALIDATE_OR_GOTO(this->name, priv, out);
|
||||
GF_VALIDATE_OR_GOTO(this->name, local, out);
|
||||
|
||||
/* Perform quorum check to see if the leader needs *
|
||||
* to perform the operation. If the operation will not *
|
||||
* meet quorum irrespective of the leader's result *
|
||||
* there is no point in the leader performing the fop *
|
||||
*/
|
||||
result = fop_quorum_check(this, (double)priv->n_children,
|
||||
(double)local->successful_acks + 1);
|
||||
if (result == _gf_false) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, EROFS, J_MSG_QUORUM_NOT_MET,
|
||||
"Didn't receive enough acks "
|
||||
"to meet quorum. Failing the operation without trying "
|
||||
"it on the leader.");
|
||||
|
||||
#if defined(JBR_CG_QUEUE)
|
||||
/*
|
||||
* In case of a fop failure, before unwinding need to *
|
||||
* remove it from queue *
|
||||
*/
|
||||
ret = jbr_remove_from_queue(frame, this);
|
||||
if (ret) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0, J_MSG_GENERIC,
|
||||
"Failed to remove from queue.");
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* In this case, the quorum is not met on the followers *
|
||||
* So the operation will not be performed on the leader *
|
||||
* and a rollback will be sent via GF_FOP_IPC to all the *
|
||||
* followers, where this particular fop's term and index *
|
||||
* numbers will be journaled, and later used to rollback *
|
||||
*/
|
||||
call_frame_t *new_frame;
|
||||
|
||||
new_frame = copy_frame(frame);
|
||||
|
||||
if (new_frame) {
|
||||
new_local = mem_get0(this->local_pool);
|
||||
if (new_local) {
|
||||
INIT_LIST_HEAD(&new_local->qlinks);
|
||||
ret = dict_set_int32(local->xdata, "rollback-fop",
|
||||
GF_FOP_@UPNAME@);
|
||||
if (ret) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0, J_MSG_DICT_FLR,
|
||||
"failed to set rollback-fop");
|
||||
} else {
|
||||
new_local->xdata = dict_ref(local->xdata);
|
||||
new_frame->local = new_local;
|
||||
jbr_ipc_call_dispatch(new_frame, this, &op_errno,
|
||||
FDL_IPC_JBR_SERVER_ROLLBACK,
|
||||
new_local->xdata);
|
||||
}
|
||||
} else {
|
||||
gf_log(this->name, GF_LOG_WARNING,
|
||||
"Could not create local for new_frame");
|
||||
}
|
||||
} else {
|
||||
gf_log(this->name, GF_LOG_WARNING, "Could not send rollback ipc");
|
||||
}
|
||||
|
||||
STACK_UNWIND_STRICT(@NAME@, frame, -1, EROFS, @ERROR_ARGS@);
|
||||
} else {
|
||||
STACK_WIND(frame, jbr_@NAME@_complete, FIRST_CHILD(this),
|
||||
FIRST_CHILD(this)->fops->@NAME@, @SHORT_ARGS@);
|
||||
}
|
||||
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* template-name write-complete */
|
||||
int32_t jbr_@NAME@_complete(call_frame_t *frame, void *cookie, xlator_t *this,
|
||||
int32_t op_ret, int32_t op_errno, @LONG_ARGS@)
|
||||
{
|
||||
int32_t ret = -1;
|
||||
gf_boolean_t result = _gf_false;
|
||||
jbr_private_t *priv = NULL;
|
||||
jbr_local_t *local = NULL;
|
||||
jbr_local_t *new_local = NULL;
|
||||
|
||||
GF_VALIDATE_OR_GOTO("jbr", this, err);
|
||||
GF_VALIDATE_OR_GOTO(this->name, frame, err);
|
||||
priv = this->private;
|
||||
local = frame->local;
|
||||
GF_VALIDATE_OR_GOTO(this->name, priv, err);
|
||||
GF_VALIDATE_OR_GOTO(this->name, local, err);
|
||||
|
||||
/* If the fop failed on the leader, then reduce one successful ack
|
||||
* before calculating the fop quorum
|
||||
*/
|
||||
LOCK(&frame->lock);
|
||||
if (op_ret == -1)
|
||||
(local->successful_acks)--;
|
||||
UNLOCK(&frame->lock);
|
||||
|
||||
#if defined(JBR_CG_QUEUE)
|
||||
ret = jbr_remove_from_queue(frame, this);
|
||||
if (ret)
|
||||
goto err;
|
||||
#endif
|
||||
|
||||
#if defined(JBR_CG_FSYNC)
|
||||
jbr_mark_fd_dirty(this, local);
|
||||
#endif
|
||||
|
||||
#if defined(JBR_CG_NEED_FD)
|
||||
fd_unref(local->fd);
|
||||
#endif
|
||||
|
||||
/* After the leader completes the fop, a quorum check is *
|
||||
* performed, taking into account the outcome of the fop *
|
||||
* on the leader. Irrespective of the fop being successful *
|
||||
* or failing on the leader, the result of the quorum will *
|
||||
* determine if the overall fop is successful or not. For *
|
||||
* example, a fop might have succeeded on every node except *
|
||||
* the leader, in which case as quorum is being met, the fop *
|
||||
* will be treated as a successful fop, even though it failed *
|
||||
* on the leader. On follower nodes, no quorum check should *
|
||||
* be done, and the result is returned to the leader as is. *
|
||||
*/
|
||||
if (priv->leader) {
|
||||
result = fop_quorum_check(this, (double)priv->n_children,
|
||||
(double)local->successful_acks + 1);
|
||||
if (result == _gf_false) {
|
||||
op_ret = -1;
|
||||
op_errno = EROFS;
|
||||
gf_msg(this->name, GF_LOG_ERROR, EROFS, J_MSG_QUORUM_NOT_MET,
|
||||
"Quorum is not met. "
|
||||
"The operation has failed.");
|
||||
/*
|
||||
* In this case, the quorum is not met after the *
|
||||
* operation is performed on the leader. Hence a *
|
||||
* rollback will be sent via GF_FOP_IPC to the leader *
|
||||
* where this particular fop's term and index numbers *
|
||||
* will be journaled, and later used to rollback. *
|
||||
* The same will be done on all the followers *
|
||||
*/
|
||||
call_frame_t *new_frame;
|
||||
|
||||
new_frame = copy_frame(frame);
|
||||
if (new_frame) {
|
||||
new_local = mem_get0(this->local_pool);
|
||||
if (new_local) {
|
||||
INIT_LIST_HEAD(&new_local->qlinks);
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0, J_MSG_DICT_FLR,
|
||||
"op = %d", new_frame->op);
|
||||
ret = dict_set_int32(local->xdata, "rollback-fop",
|
||||
GF_FOP_@UPNAME@);
|
||||
if (ret) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0, J_MSG_DICT_FLR,
|
||||
"failed to set "
|
||||
"rollback-fop");
|
||||
} else {
|
||||
new_local->xdata = dict_ref(local->xdata);
|
||||
new_frame->local = new_local;
|
||||
/*
|
||||
* Calling STACK_WIND instead *
|
||||
* of jbr_ipc as it will not *
|
||||
* unwind to the previous *
|
||||
* translators like it will *
|
||||
* in case of jbr_ipc. *
|
||||
*/
|
||||
STACK_WIND(
|
||||
new_frame, jbr_ipc_complete, FIRST_CHILD(this),
|
||||
FIRST_CHILD(this)->fops->ipc,
|
||||
FDL_IPC_JBR_SERVER_ROLLBACK, new_local->xdata);
|
||||
}
|
||||
} else {
|
||||
gf_log(this->name, GF_LOG_WARNING,
|
||||
"Could not create local "
|
||||
"for new_frame");
|
||||
}
|
||||
} else {
|
||||
gf_log(this->name, GF_LOG_WARNING,
|
||||
"Could not send rollback ipc");
|
||||
}
|
||||
} else {
|
||||
#if defined(JBR_CG_NEED_FD)
|
||||
op_ret = local->successful_op_ret;
|
||||
#else
|
||||
op_ret = 0;
|
||||
#endif
|
||||
op_errno = 0;
|
||||
gf_msg_debug(this->name, 0,
|
||||
"Quorum has met. The operation has succeeded.");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Unrefing the reference taken in jbr_@NAME@ () *
|
||||
*/
|
||||
dict_unref(local->xdata);
|
||||
|
||||
STACK_UNWIND_STRICT(@NAME@, frame, op_ret, op_errno, @SHORT_ARGS@);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
STACK_UNWIND_STRICT(@NAME@, frame, -1, 0, @SHORT_ARGS@);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,181 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
# This script generates the boilerplate versions of most fops and cbks in the
|
||||
# server. This allows the details of leadership-status checking, sequencing
|
||||
# between leader and followers (including fan-out), and basic error checking
|
||||
# to be centralized one place, with per-operation code kept to a minimum.
|
||||
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import re
|
||||
import string
|
||||
import sys
|
||||
|
||||
curdir = os.path.dirname(sys.argv[0])
|
||||
gendir = os.path.join(curdir, '../../../../libglusterfs/src')
|
||||
sys.path.append(gendir)
|
||||
from generator import ops, fop_subs, cbk_subs, generate
|
||||
|
||||
# We really want the callback argument list, even when we're generating fop
|
||||
# code, so we propagate here.
|
||||
# TBD: this should probably be right in generate.py
|
||||
for k, v in cbk_subs.items():
|
||||
fop_subs[k]['@ERROR_ARGS@'] = v['@ERROR_ARGS@']
|
||||
|
||||
# Stolen from old codegen.py
|
||||
def load_templates (path):
|
||||
templates = {}
|
||||
tmpl_re = re.compile("/\* template-name (.*) \*/")
|
||||
templates = {}
|
||||
t_name = None
|
||||
for line in open(path, "r").readlines():
|
||||
if not line:
|
||||
break
|
||||
m = tmpl_re.match(line)
|
||||
if m:
|
||||
if t_name:
|
||||
templates[t_name] = ''.join(t_contents)
|
||||
t_name = m.group(1).strip()
|
||||
t_contents = []
|
||||
elif t_name:
|
||||
t_contents.append(line)
|
||||
if t_name:
|
||||
templates[t_name] = ''.join(t_contents)
|
||||
return templates
|
||||
|
||||
# We need two types of templates. The first, for pure read operations, just
|
||||
# needs to do a simple am-i-leader check (augmented to allow dirty reads).
|
||||
# The second, for pure writes, needs to do fan-out to followers between those
|
||||
# initial checks and local execution. There are other operations that don't
|
||||
# fit neatly into either category - e.g. lock ops or fsync - so we'll just have
|
||||
# to handle those manually. The table thus includes entries only for those we
|
||||
# can categorize. The special cases, plus any new operations we've never even
|
||||
# heard of, aren't in there.
|
||||
#
|
||||
# Various keywords can be used to define/undefine preprocessor symbols used
|
||||
# in the templates, on a per-function basis. For example, if the keyword here
|
||||
# is "fsync" (lowercase word or abbreviation) that will cause JBR_CG_FSYNC
|
||||
# (prefix plus uppercase version) to be defined above all of the generated code
|
||||
# for that fop.
|
||||
|
||||
fop_table = {
|
||||
"access": "read",
|
||||
"create": "write",
|
||||
"discard": "write",
|
||||
# "entrylk": "read",
|
||||
"fallocate": "write",
|
||||
# "fentrylk": "read",
|
||||
"fgetxattr": "read",
|
||||
# "finodelk": "read",
|
||||
# "flush": "read",
|
||||
"fremovexattr": "write",
|
||||
"fsetattr": "write",
|
||||
"fsetxattr": "write",
|
||||
"fstat": "read",
|
||||
# "fsync": "read",
|
||||
# "fsyncdir": "read",
|
||||
"ftruncate": "write",
|
||||
"fxattrop": "write",
|
||||
"getxattr": "read",
|
||||
# "inodelk": "read",
|
||||
"link": "write",
|
||||
"lk": "write,queue",
|
||||
# "lookup": "read",
|
||||
"mkdir": "write",
|
||||
"mknod": "write",
|
||||
"open": "write",
|
||||
"opendir": "read",
|
||||
"rchecksum": "read",
|
||||
"readdir": "read",
|
||||
"readdirp": "read",
|
||||
"readlink": "read",
|
||||
"readv": "read",
|
||||
"removexattr": "write",
|
||||
"rename": "write",
|
||||
"rmdir": "write",
|
||||
"setattr": "write",
|
||||
"setxattr": "write",
|
||||
"stat": "read",
|
||||
"statfs": "read",
|
||||
"symlink": "write",
|
||||
"truncate": "write",
|
||||
"unlink": "write",
|
||||
"writev": "write,fsync,queue",
|
||||
"xattrop": "write",
|
||||
"ipc": "write",
|
||||
}
|
||||
|
||||
# Mention those fops in the selective_generate table, for which
|
||||
# only a few common functions will be generated, and mention those
|
||||
# functions. Rest of the functions can be customized
|
||||
selective_generate = {
|
||||
"lk": "fop,dispatch,call_dispatch",
|
||||
"ipc": "dispatch,call_dispatch",
|
||||
}
|
||||
|
||||
# Stolen from gen_fdl.py
|
||||
def gen_server (templates):
|
||||
fops_done = []
|
||||
for name in fop_table.keys():
|
||||
info = fop_table[name].split(",")
|
||||
kind = info[0]
|
||||
flags = info[1:]
|
||||
|
||||
# generate all functions for the fops in fop_table
|
||||
# except for the ones in selective_generate for which
|
||||
# generate only the functions mentioned in the
|
||||
# selective_generate table
|
||||
gen_funcs = "fop,complete,continue,fan-in,dispatch, \
|
||||
call_dispatch,perform_local_op"
|
||||
if name in selective_generate:
|
||||
gen_funcs = selective_generate[name].split(",")
|
||||
|
||||
if ("fsync" in flags) or ("queue" in flags):
|
||||
flags.append("need_fd")
|
||||
for fname in flags:
|
||||
print("#define JBR_CG_%s" % fname.upper())
|
||||
|
||||
if 'complete' in gen_funcs:
|
||||
print(generate(templates[kind+"-complete"],
|
||||
name, cbk_subs))
|
||||
|
||||
if 'continue' in gen_funcs:
|
||||
print(generate(templates[kind+"-continue"],
|
||||
name, fop_subs))
|
||||
|
||||
if 'fan-in' in gen_funcs:
|
||||
print(generate(templates[kind+"-fan-in"],
|
||||
name, cbk_subs))
|
||||
|
||||
if 'dispatch' in gen_funcs:
|
||||
print(generate(templates[kind+"-dispatch"],
|
||||
name, fop_subs))
|
||||
|
||||
if 'call_dispatch' in gen_funcs:
|
||||
print(generate(templates[kind+"-call_dispatch"],
|
||||
name, fop_subs))
|
||||
|
||||
if 'perform_local_op' in gen_funcs:
|
||||
print(generate(templates[kind+"-perform_local_op"],
|
||||
name, fop_subs))
|
||||
|
||||
if 'fop' in gen_funcs:
|
||||
print(generate(templates[kind+"-fop"], name, fop_subs))
|
||||
|
||||
for fname in flags:
|
||||
print("#undef JBR_CG_%s" % fname.upper())
|
||||
fops_done.append(name)
|
||||
# Just for fun, emit the fops table too.
|
||||
print("struct xlator_fops fops = {")
|
||||
for x in fops_done:
|
||||
print((" .%s = jbr_%s,"%(x, x)))
|
||||
print("};")
|
||||
|
||||
tmpl = load_templates(sys.argv[1])
|
||||
for l in open(sys.argv[2], 'r').readlines():
|
||||
if l.find('#pragma generate') != -1:
|
||||
print("/* BEGIN GENERATED CODE - DO NOT MODIFY */")
|
||||
gen_server(tmpl)
|
||||
print("/* END GENERATED CODE */")
|
||||
else:
|
||||
print(l[:-1])
|
@ -1,118 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2013 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.
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define LEADER_XATTR "user.jbr.leader"
|
||||
#define SECOND_CHILD(xl) (xl->children->next->xlator)
|
||||
#define RECONCILER_PATH JBR_SCRIPT_PREFIX "/reconciler.py"
|
||||
#define CHANGELOG_ENTRY_SIZE 128
|
||||
|
||||
enum {
|
||||
gf_mt_jbr_private_t = gf_common_mt_end + 1,
|
||||
gf_mt_jbr_fd_ctx_t,
|
||||
gf_mt_jbr_inode_ctx_t,
|
||||
gf_mt_jbr_dirty_t,
|
||||
gf_mt_jbr_end
|
||||
};
|
||||
|
||||
typedef enum jbr_recon_notify_ev_id_t {
|
||||
JBR_RECON_SET_LEADER = 1,
|
||||
JBR_RECON_ADD_CHILD = 2
|
||||
} jbr_recon_notify_ev_id_t;
|
||||
|
||||
typedef struct _jbr_recon_notify_ev_s {
|
||||
jbr_recon_notify_ev_id_t id;
|
||||
uint32_t index; /* in case of add */
|
||||
struct list_head list;
|
||||
} jbr_recon_notify_ev_t;
|
||||
|
||||
typedef struct {
|
||||
/*
|
||||
* This is a hack to allow a non-leader to accept requests while the
|
||||
* leader is down, and it only works for n=2. The way it works is that
|
||||
* "config_leader" indicates the state from our options (via init or
|
||||
* reconfigure) but "leader" is what the fop code actually looks at. If
|
||||
* config_leader is true, then leader will *always* be true as well,
|
||||
* giving that brick precedence. If config_leader is false, then
|
||||
* leader will only be true if there is no connection to the other
|
||||
* brick (tracked in jbr_notify).
|
||||
*
|
||||
* TBD: implement real leader election
|
||||
*/
|
||||
gf_boolean_t config_leader;
|
||||
gf_boolean_t leader;
|
||||
uint8_t up_children;
|
||||
uint8_t n_children;
|
||||
char *vol_file;
|
||||
uint32_t current_term;
|
||||
uint32_t kid_state;
|
||||
gf_lock_t dirty_lock;
|
||||
struct list_head dirty_fds;
|
||||
uint32_t index;
|
||||
gf_lock_t index_lock;
|
||||
double quorum_pct;
|
||||
int term_fd;
|
||||
long term_total;
|
||||
long term_read;
|
||||
/*
|
||||
* This is a super-duper hack, but it will do for now. The reason it's
|
||||
* a hack is that we pass this to dict_set_static_bin, so we don't have
|
||||
* to mess around with allocating and freeing it on every single IPC
|
||||
* request, but it's totally not thread-safe. On the other hand, there
|
||||
* should only be one reconciliation thread running and calling these
|
||||
* functions at a time, so maybe that doesn't matter.
|
||||
*
|
||||
* TBD: re-evaluate how to manage this
|
||||
*/
|
||||
char term_buf[CHANGELOG_ENTRY_SIZE];
|
||||
gf_boolean_t child_up; /* To maintain the state of *
|
||||
* the translator */
|
||||
} jbr_private_t;
|
||||
|
||||
typedef struct {
|
||||
call_stub_t *stub;
|
||||
call_stub_t *qstub;
|
||||
uint32_t call_count;
|
||||
uint32_t successful_acks;
|
||||
uint32_t successful_op_ret;
|
||||
fd_t *fd;
|
||||
struct list_head qlinks;
|
||||
dict_t *xdata;
|
||||
} jbr_local_t;
|
||||
|
||||
/*
|
||||
* This should match whatever changelog returns on the pre-op for us to pass
|
||||
* when we're ready for our post-op.
|
||||
*/
|
||||
typedef uint32_t log_id_t;
|
||||
|
||||
typedef struct {
|
||||
struct list_head links;
|
||||
log_id_t id;
|
||||
} jbr_dirty_list_t;
|
||||
|
||||
typedef struct {
|
||||
fd_t *fd;
|
||||
struct list_head dirty_list;
|
||||
struct list_head fd_list;
|
||||
} jbr_fd_ctx_t;
|
||||
|
||||
typedef struct {
|
||||
gf_lock_t lock;
|
||||
uint32_t active;
|
||||
struct list_head aqueue;
|
||||
uint32_t pending;
|
||||
struct list_head pqueue;
|
||||
} jbr_inode_ctx_t;
|
||||
|
||||
void
|
||||
jbr_start_reconciler(xlator_t *this);
|
File diff suppressed because it is too large
Load Diff
@ -1,3 +0,0 @@
|
||||
SUBDIRS = common mds ds
|
||||
|
||||
CLEANFILES =
|
@ -1,7 +0,0 @@
|
||||
# POSIX2 Experimental README
|
||||
|
||||
POSIX2 is an implementation of modified storage translator to cater to DHT2
|
||||
on disk needs.
|
||||
|
||||
For further understanding, refer to xlators/experimental/dht2/README.md for
|
||||
details regarding POSIX2
|
@ -1,3 +0,0 @@
|
||||
# POSIX2 TODO List
|
||||
|
||||
<Items will be added as code is pulled into the repository>
|
@ -1,3 +0,0 @@
|
||||
SUBDIRS = src
|
||||
|
||||
CLEANFILES =
|
@ -1,16 +0,0 @@
|
||||
lib_LTLIBRARIES = libposix2common.la
|
||||
|
||||
posix2_common_sources = posix2-common.c
|
||||
|
||||
libposix2common_la_SOURCES = $(posix2_common_sources)
|
||||
libposix2common_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la
|
||||
|
||||
libposix2common_la_CFLAGS = -Wall $(GF_CFLAGS)
|
||||
|
||||
libposix2common_la_CPPFLAGS = $(GF_CPPFLAGS)
|
||||
libposix2common_la_CPPFLAGS += -I$(top_srcdir)/libglusterfs/src
|
||||
libposix2common_la_CPPFLAGS += -I$(top_srcdir)/rpc/xdr/src
|
||||
libposix2common_la_CPPFLAGS += -I$(top_builddir)/rpc/xdr/src
|
||||
|
||||
|
||||
CLEANFILES =
|
@ -1,18 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 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.
|
||||
*/
|
||||
|
||||
/* File: posix2-common.c
|
||||
* This file contains common routines across ds and mds posix xlators
|
||||
* The entire functionality including comments is TODO.
|
||||
*/
|
||||
|
||||
#include <glusterfs/glusterfs.h>
|
||||
#include <glusterfs/logging.h>
|
||||
#include <glusterfs/statedump.h>
|
@ -1,3 +0,0 @@
|
||||
SUBDIRS = src
|
||||
|
||||
CLEANFILES =
|
@ -1,22 +0,0 @@
|
||||
if WITH_SERVER
|
||||
xlator_LTLIBRARIES = posix2-ds.la
|
||||
endif
|
||||
xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/experimental
|
||||
|
||||
posix2_ds_sources = posix2-ds-main.c
|
||||
|
||||
posix2_ds_la_SOURCES = $(posix2_ds_sources)
|
||||
posix2_ds_la_LDFLAGS = -module $(GF_XLATOR_DEFAULT_LDFLAGS)
|
||||
posix2_ds_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la
|
||||
posix2_ds_la_LIBADD += $(top_builddir)/xlators/experimental/posix2/common/src/libposix2common.la
|
||||
|
||||
AM_CFLAGS = -Wall $(GF_CFLAGS)
|
||||
|
||||
AM_CPPFLAGS = $(GF_CPPFLAGS)
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/xlators/storage/posix2/common/src
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/libglusterfs/src
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/xlators/lib/src
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/rpc/xdr/src
|
||||
AM_CPPFLAGS += -I$(top_builddir)/rpc/xdr/src
|
||||
|
||||
CLEANFILES =
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 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.
|
||||
*/
|
||||
|
||||
/* File: posix2-ds-main.c
|
||||
* This file contains the xlator loading functions, FOP entry points
|
||||
* and options.
|
||||
* The entire functionality including comments is TODO.
|
||||
*/
|
||||
|
||||
#include <glusterfs/glusterfs.h>
|
||||
#include <glusterfs/xlator.h>
|
||||
#include <glusterfs/logging.h>
|
||||
#include <glusterfs/statedump.h>
|
||||
|
||||
int32_t
|
||||
posix2_ds_init(xlator_t *this)
|
||||
{
|
||||
if (this->children) {
|
||||
gf_log(this->name, GF_LOG_ERROR,
|
||||
"This (%s) is a leaf xlator, but found children", this->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
posix2_ds_fini(xlator_t *this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
class_methods_t class_methods = {
|
||||
.init = posix2_ds_init,
|
||||
.fini = posix2_ds_fini,
|
||||
};
|
||||
|
||||
struct xlator_fops fops = {};
|
||||
|
||||
struct xlator_cbks cbks = {};
|
||||
|
||||
/*
|
||||
struct xlator_dumpops dumpops = {
|
||||
};
|
||||
*/
|
||||
|
||||
struct volume_options options[] = {
|
||||
{.key = {NULL}},
|
||||
};
|
@ -1,3 +0,0 @@
|
||||
SUBDIRS = src
|
||||
|
||||
CLEANFILES =
|
@ -1,22 +0,0 @@
|
||||
if WITH_SERVER
|
||||
xlator_LTLIBRARIES = posix2-mds.la
|
||||
endif
|
||||
xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/experimental
|
||||
|
||||
posix2_mds_sources = posix2-mds-main.c
|
||||
|
||||
posix2_mds_la_SOURCES = $(posix2_mds_sources)
|
||||
posix2_mds_la_LDFLAGS = -module $(GF_XLATOR_DEFAULT_LDFLAGS)
|
||||
posix2_mds_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la
|
||||
posix2_mds_la_LIBADD += $(top_builddir)/xlators/experimental/posix2/common/src/libposix2common.la
|
||||
|
||||
AM_CFLAGS = -Wall $(GF_CFLAGS)
|
||||
|
||||
AM_CPPFLAGS = $(GF_CPPFLAGS)
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/xlators/storage/posix2/common/src
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/libglusterfs/src
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/xlators/lib/src
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/rpc/xdr/src
|
||||
AM_CPPFLAGS += -I$(top_builddir)/rpc/xdr/src
|
||||
|
||||
CLEANFILES =
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 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.
|
||||
*/
|
||||
|
||||
/* File: posix2-mds-main.c
|
||||
* This file contains the xlator loading functions, FOP entry points
|
||||
* and options.
|
||||
* The entire functionality including comments is TODO.
|
||||
*/
|
||||
|
||||
#include <glusterfs/glusterfs.h>
|
||||
#include <glusterfs/xlator.h>
|
||||
#include <glusterfs/logging.h>
|
||||
#include <glusterfs/statedump.h>
|
||||
|
||||
int32_t
|
||||
posix2_mds_init(xlator_t *this)
|
||||
{
|
||||
if (this->children) {
|
||||
gf_log(this->name, GF_LOG_ERROR,
|
||||
"This (%s) is a leaf xlator, but found children", this->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
posix2_mds_fini(xlator_t *this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
class_methods_t class_methods = {
|
||||
.init = posix2_mds_init,
|
||||
.fini = posix2_mds_fini,
|
||||
};
|
||||
|
||||
struct xlator_fops fops = {};
|
||||
|
||||
struct xlator_cbks cbks = {};
|
||||
|
||||
/*
|
||||
struct xlator_dumpops dumpops = {
|
||||
};
|
||||
*/
|
||||
|
||||
struct volume_options options[] = {
|
||||
{.key = {NULL}},
|
||||
};
|
@ -1,3 +0,0 @@
|
||||
SUBDIRS = src
|
||||
|
||||
CLEANFILES =
|
@ -1,26 +0,0 @@
|
||||
xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/features
|
||||
|
||||
# changetimerecorder can only get build when libgfdb is enabled
|
||||
if BUILD_GFDB
|
||||
xlator_LTLIBRARIES = changetimerecorder.la
|
||||
endif
|
||||
|
||||
changetimerecorder_la_LDFLAGS = -module $(GF_XLATOR_DEFAULT_LDFLAGS)
|
||||
|
||||
changetimerecorder_la_SOURCES = changetimerecorder.c \
|
||||
ctr-helper.c ctr-xlator-ctx.c
|
||||
|
||||
changetimerecorder_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la\
|
||||
$(top_builddir)/libglusterfs/src/gfdb/libgfdb.la
|
||||
|
||||
noinst_HEADERS = ctr-messages.h changetimerecorder.h ctr_mem_types.h \
|
||||
ctr-helper.h ctr-xlator-ctx.h
|
||||
|
||||
AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \
|
||||
-I$(top_srcdir)/libglusterfs/src/gfdb \
|
||||
-I$(top_srcdir)/rpc/xdr/src -I$(top_builddir)/rpc/xdr/src \
|
||||
-DDATADIR=\"$(localstatedir)\"
|
||||
|
||||
AM_CFLAGS = -Wall $(GF_CFLAGS) $(SQLITE_CFLAGS)
|
||||
|
||||
CLEANFILES =
|
File diff suppressed because it is too large
Load Diff
@ -1,21 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2006-2015 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 __CTR_H
|
||||
#define __CTR_H
|
||||
|
||||
#include <glusterfs/glusterfs.h>
|
||||
#include <glusterfs/xlator.h>
|
||||
#include <glusterfs/logging.h>
|
||||
#include <glusterfs/common-utils.h>
|
||||
#include "ctr_mem_types.h"
|
||||
#include "ctr-helper.h"
|
||||
|
||||
#endif /* __CTR_H */
|
@ -1,293 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2015 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.
|
||||
*/
|
||||
|
||||
#include "gfdb_sqlite3.h"
|
||||
#include "ctr-helper.h"
|
||||
#include "ctr-messages.h"
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Fill unwind into db record
|
||||
*
|
||||
******************************************************************************/
|
||||
int
|
||||
fill_db_record_for_unwind(xlator_t *this, gf_ctr_local_t *ctr_local,
|
||||
gfdb_fop_type_t fop_type, gfdb_fop_path_t fop_path)
|
||||
{
|
||||
int ret = -1;
|
||||
gfdb_time_t *ctr_uwtime = NULL;
|
||||
gf_ctr_private_t *_priv = NULL;
|
||||
|
||||
GF_ASSERT(this);
|
||||
_priv = this->private;
|
||||
GF_ASSERT(_priv);
|
||||
|
||||
GF_ASSERT(ctr_local);
|
||||
|
||||
/*If not unwind path error*/
|
||||
if (!isunwindpath(fop_path)) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0, CTR_MSG_WRONG_FOP_PATH,
|
||||
"Wrong fop_path. Should be unwind");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctr_uwtime = &CTR_DB_REC(ctr_local).gfdb_unwind_change_time;
|
||||
CTR_DB_REC(ctr_local).gfdb_fop_path = fop_path;
|
||||
CTR_DB_REC(ctr_local).gfdb_fop_type = fop_type;
|
||||
|
||||
ret = gettimeofday(ctr_uwtime, NULL);
|
||||
if (ret == -1) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, errno,
|
||||
CTR_MSG_FILL_UNWIND_TIME_REC_ERROR,
|
||||
"Error "
|
||||
"filling unwind time record %s",
|
||||
strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Special case i.e if its a tier rebalance
|
||||
* + cold tier brick
|
||||
* + its a create/mknod FOP
|
||||
* we record unwind time as zero */
|
||||
if (ctr_local->client_pid == GF_CLIENT_PID_TIER_DEFRAG &&
|
||||
(!_priv->ctr_hot_brick) && isdentrycreatefop(fop_type)) {
|
||||
memset(ctr_uwtime, 0, sizeof(*ctr_uwtime));
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* Fill wind into db record
|
||||
*
|
||||
******************************************************************************/
|
||||
int
|
||||
fill_db_record_for_wind(xlator_t *this, gf_ctr_local_t *ctr_local,
|
||||
gf_ctr_inode_context_t *ctr_inode_cx)
|
||||
{
|
||||
int ret = -1;
|
||||
gfdb_time_t *ctr_wtime = NULL;
|
||||
gf_ctr_private_t *_priv = NULL;
|
||||
|
||||
GF_ASSERT(this);
|
||||
_priv = this->private;
|
||||
GF_ASSERT(_priv);
|
||||
GF_ASSERT(ctr_local);
|
||||
IS_CTR_INODE_CX_SANE(ctr_inode_cx);
|
||||
|
||||
/*if not wind path error!*/
|
||||
if (!iswindpath(ctr_inode_cx->fop_path)) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0, CTR_MSG_WRONG_FOP_PATH,
|
||||
"Wrong fop_path. Should be wind");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctr_wtime = &CTR_DB_REC(ctr_local).gfdb_wind_change_time;
|
||||
CTR_DB_REC(ctr_local).gfdb_fop_path = ctr_inode_cx->fop_path;
|
||||
CTR_DB_REC(ctr_local).gfdb_fop_type = ctr_inode_cx->fop_type;
|
||||
CTR_DB_REC(ctr_local).link_consistency = _priv->ctr_link_consistency;
|
||||
|
||||
ret = gettimeofday(ctr_wtime, NULL);
|
||||
if (ret) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, errno,
|
||||
CTR_MSG_FILL_UNWIND_TIME_REC_ERROR,
|
||||
"Error filling wind time record %s", strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Special case i.e if its a tier rebalance
|
||||
* + cold tier brick
|
||||
* + its a create/mknod FOP
|
||||
* we record wind time as zero */
|
||||
if (ctr_local->client_pid == GF_CLIENT_PID_TIER_DEFRAG &&
|
||||
(!_priv->ctr_hot_brick) && isdentrycreatefop(ctr_inode_cx->fop_type)) {
|
||||
memset(ctr_wtime, 0, sizeof(*ctr_wtime));
|
||||
}
|
||||
|
||||
/* Copy gfid into db record */
|
||||
gf_uuid_copy(CTR_DB_REC(ctr_local).gfid, *(ctr_inode_cx->gfid));
|
||||
|
||||
/* Copy older gfid if any */
|
||||
if (ctr_inode_cx->old_gfid &&
|
||||
(!gf_uuid_is_null(*(ctr_inode_cx->old_gfid)))) {
|
||||
gf_uuid_copy(CTR_DB_REC(ctr_local).old_gfid, *(ctr_inode_cx->old_gfid));
|
||||
}
|
||||
|
||||
/*Hard Links*/
|
||||
if (isdentryfop(ctr_inode_cx->fop_type)) {
|
||||
/*new link fop*/
|
||||
if (NEW_LINK_CX(ctr_inode_cx)) {
|
||||
gf_uuid_copy(CTR_DB_REC(ctr_local).pargfid,
|
||||
*((NEW_LINK_CX(ctr_inode_cx))->pargfid));
|
||||
strcpy(CTR_DB_REC(ctr_local).file_name,
|
||||
NEW_LINK_CX(ctr_inode_cx)->basename);
|
||||
}
|
||||
/*rename fop*/
|
||||
if (OLD_LINK_CX(ctr_inode_cx)) {
|
||||
gf_uuid_copy(CTR_DB_REC(ctr_local).old_pargfid,
|
||||
*((OLD_LINK_CX(ctr_inode_cx))->pargfid));
|
||||
strcpy(CTR_DB_REC(ctr_local).old_file_name,
|
||||
OLD_LINK_CX(ctr_inode_cx)->basename);
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
/*On error roll back and clean the record*/
|
||||
if (ret == -1) {
|
||||
CLEAR_CTR_DB_RECORD(ctr_local);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* CTR xlator init related functions
|
||||
*
|
||||
*
|
||||
* ****************************************************************************/
|
||||
static int
|
||||
extract_sql_params(xlator_t *this, dict_t *params_dict)
|
||||
{
|
||||
int ret = -1;
|
||||
char *db_path = NULL;
|
||||
char *db_name = NULL;
|
||||
char *db_full_path = NULL;
|
||||
|
||||
GF_ASSERT(this);
|
||||
GF_ASSERT(params_dict);
|
||||
|
||||
/*Extract the path of the db*/
|
||||
db_path = NULL;
|
||||
GET_DB_PARAM_FROM_DICT_DEFAULT(this->name, this->options, "db-path",
|
||||
db_path, "/var/run/gluster/");
|
||||
|
||||
/*Extract the name of the db*/
|
||||
db_name = NULL;
|
||||
GET_DB_PARAM_FROM_DICT_DEFAULT(this->name, this->options, "db-name",
|
||||
db_name, "gf_ctr_db.db");
|
||||
|
||||
/*Construct full path of the db*/
|
||||
ret = gf_asprintf(&db_full_path, "%s/%s", db_path, db_name);
|
||||
if (ret < 0) {
|
||||
gf_msg(GFDB_DATA_STORE, GF_LOG_ERROR, 0,
|
||||
CTR_MSG_CONSTRUCT_DB_PATH_FAILED,
|
||||
"Construction of full db path failed!");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*Setting the SQL DB Path*/
|
||||
SET_DB_PARAM_TO_DICT(this->name, params_dict, GFDB_SQL_PARAM_DBPATH,
|
||||
db_full_path, ret, out);
|
||||
|
||||
/*Extract rest of the sql params*/
|
||||
ret = gfdb_set_sql_params(this->name, this->options, params_dict);
|
||||
if (ret) {
|
||||
gf_msg(GFDB_DATA_STORE, GF_LOG_ERROR, 0,
|
||||
CTR_MSG_SET_VALUE_TO_SQL_PARAM_FAILED,
|
||||
"Failed setting values to sql param dict!");
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
if (ret)
|
||||
GF_FREE(db_full_path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
extract_db_params(xlator_t *this, dict_t *params_dict, gfdb_db_type_t db_type)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
GF_ASSERT(this);
|
||||
GF_ASSERT(params_dict);
|
||||
|
||||
switch (db_type) {
|
||||
case GFDB_SQLITE3:
|
||||
ret = extract_sql_params(this, params_dict);
|
||||
if (ret)
|
||||
goto out;
|
||||
break;
|
||||
case GFDB_ROCKS_DB:
|
||||
case GFDB_HYPERDEX:
|
||||
case GFDB_HASH_FILE_STORE:
|
||||
case GFDB_INVALID_DB:
|
||||
case GFDB_DB_END:
|
||||
goto out;
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
extract_ctr_options(xlator_t *this, gf_ctr_private_t *_priv)
|
||||
{
|
||||
int ret = -1;
|
||||
char *_val_str = NULL;
|
||||
|
||||
GF_ASSERT(this);
|
||||
GF_ASSERT(_priv);
|
||||
|
||||
/*Checking if the CTR Translator is enabled. By default its disabled*/
|
||||
_priv->enabled = _gf_false;
|
||||
GF_OPTION_INIT("ctr-enabled", _priv->enabled, bool, out);
|
||||
if (!_priv->enabled) {
|
||||
gf_msg(GFDB_DATA_STORE, GF_LOG_INFO, 0, CTR_MSG_XLATOR_DISABLED,
|
||||
"CTR Xlator is disabled.");
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*Extract db type*/
|
||||
GF_OPTION_INIT("db-type", _val_str, str, out);
|
||||
_priv->gfdb_db_type = gf_string2gfdbdbtype(_val_str);
|
||||
|
||||
/*Extract flag for record on wind*/
|
||||
GF_OPTION_INIT("record-entry", _priv->ctr_record_wind, bool, out);
|
||||
|
||||
/*Extract flag for record on unwind*/
|
||||
GF_OPTION_INIT("record-exit", _priv->ctr_record_unwind, bool, out);
|
||||
|
||||
/*Extract flag for record on counters*/
|
||||
GF_OPTION_INIT("record-counters", _priv->ctr_record_counter, bool, out);
|
||||
|
||||
/* Extract flag for record metadata heat */
|
||||
GF_OPTION_INIT("ctr-record-metadata-heat", _priv->ctr_record_metadata_heat,
|
||||
bool, out);
|
||||
|
||||
/*Extract flag for link consistency*/
|
||||
GF_OPTION_INIT("ctr_link_consistency", _priv->ctr_link_consistency, bool,
|
||||
out);
|
||||
|
||||
/*Extract ctr_lookupheal_inode_timeout */
|
||||
GF_OPTION_INIT("ctr_lookupheal_inode_timeout",
|
||||
_priv->ctr_lookupheal_inode_timeout, uint64, out);
|
||||
|
||||
/*Extract ctr_lookupheal_link_timeout*/
|
||||
GF_OPTION_INIT("ctr_lookupheal_link_timeout",
|
||||
_priv->ctr_lookupheal_link_timeout, uint64, out);
|
||||
|
||||
/*Extract flag for hot tier brick*/
|
||||
GF_OPTION_INIT("hot-brick", _priv->ctr_hot_brick, bool, out);
|
||||
|
||||
/*Extract flag for sync mode*/
|
||||
GF_OPTION_INIT("db-sync", _val_str, str, out);
|
||||
_priv->gfdb_sync_type = gf_string2gfdbdbsync(_val_str);
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
@ -1,854 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2015 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 __CTR_HELPER_H
|
||||
#define __CTR_HELPER_H
|
||||
|
||||
#include <glusterfs/xlator.h>
|
||||
#include "ctr_mem_types.h"
|
||||
#include <glusterfs/iatt.h>
|
||||
#include <glusterfs/glusterfs.h>
|
||||
#include <glusterfs/xlator.h>
|
||||
#include <glusterfs/defaults.h>
|
||||
#include <glusterfs/logging.h>
|
||||
#include <glusterfs/common-utils.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "gfdb_data_store.h"
|
||||
#include "ctr-xlator-ctx.h"
|
||||
#include "ctr-messages.h"
|
||||
|
||||
#define CTR_DEFAULT_HARDLINK_EXP_PERIOD 300 /* Five mins */
|
||||
#define CTR_DEFAULT_INODE_EXP_PERIOD 300 /* Five mins */
|
||||
|
||||
typedef struct ctr_query_cbk_args {
|
||||
int query_fd;
|
||||
int count;
|
||||
} ctr_query_cbk_args_t;
|
||||
|
||||
/*CTR Xlator Private structure*/
|
||||
typedef struct gf_ctr_private {
|
||||
gf_boolean_t enabled;
|
||||
char *ctr_db_path;
|
||||
gf_boolean_t ctr_hot_brick;
|
||||
gf_boolean_t ctr_record_wind;
|
||||
gf_boolean_t ctr_record_unwind;
|
||||
gf_boolean_t ctr_record_counter;
|
||||
gf_boolean_t ctr_record_metadata_heat;
|
||||
gf_boolean_t ctr_link_consistency;
|
||||
gfdb_db_type_t gfdb_db_type;
|
||||
gfdb_sync_type_t gfdb_sync_type;
|
||||
gfdb_conn_node_t *_db_conn;
|
||||
uint64_t ctr_lookupheal_link_timeout;
|
||||
uint64_t ctr_lookupheal_inode_timeout;
|
||||
gf_boolean_t compact_active;
|
||||
gf_boolean_t compact_mode_switched;
|
||||
pthread_mutex_t compact_lock;
|
||||
} gf_ctr_private_t;
|
||||
|
||||
/*
|
||||
* gf_ctr_local_t is the ctr xlator local data structure that is stored in
|
||||
* the call_frame of each FOP.
|
||||
*
|
||||
* gfdb_db_record: The gf_ctr_local contains a gfdb_db_record object, which is
|
||||
* used by the insert_record() api from the libgfdb. The gfdb_db_record object
|
||||
* will contain all the inode and hardlink(only for dentry fops: create,
|
||||
* mknod,link, unlink, rename).The ctr_local is keep alive till the unwind
|
||||
* call and will be release during the unwind. The same gfdb_db_record will
|
||||
* used for the unwind insert_record() api, to record unwind in the database.
|
||||
*
|
||||
* ia_inode_type in gf_ctr_local will tell the type of the inode. This is
|
||||
* important for during the unwind path. As we will not have the inode during
|
||||
* the unwind path. We would have include this in the gfdb_db_record itself
|
||||
* but currently we record only file inode information.
|
||||
*
|
||||
* is_internal_fop in gf_ctr_local will tell us if this is a internal fop and
|
||||
* take special/no action. We don't record change/access times or increement
|
||||
* heat counter for internal fops from rebalancer.
|
||||
* */
|
||||
typedef struct gf_ctr_local {
|
||||
gfdb_db_record_t gfdb_db_record;
|
||||
ia_type_t ia_inode_type;
|
||||
gf_boolean_t is_internal_fop;
|
||||
gf_special_pid_t client_pid;
|
||||
} gf_ctr_local_t;
|
||||
/*
|
||||
* Easy access of gfdb_db_record of ctr_local
|
||||
* */
|
||||
#define CTR_DB_REC(ctr_local) (ctr_local->gfdb_db_record)
|
||||
|
||||
/*Clear db record*/
|
||||
#define CLEAR_CTR_DB_RECORD(ctr_local) \
|
||||
do { \
|
||||
ctr_local->gfdb_db_record.gfdb_fop_path = GFDB_FOP_INVALID; \
|
||||
memset(&(ctr_local->gfdb_db_record.gfdb_wind_change_time), 0, \
|
||||
sizeof(gfdb_time_t)); \
|
||||
memset(&(ctr_local->gfdb_db_record.gfdb_unwind_change_time), 0, \
|
||||
sizeof(gfdb_time_t)); \
|
||||
gf_uuid_clear(ctr_local->gfdb_db_record.gfid); \
|
||||
gf_uuid_clear(ctr_local->gfdb_db_record.pargfid); \
|
||||
memset(ctr_local->gfdb_db_record.file_name, 0, GF_NAME_MAX + 1); \
|
||||
memset(ctr_local->gfdb_db_record.old_file_name, 0, GF_NAME_MAX + 1); \
|
||||
ctr_local->gfdb_db_record.gfdb_fop_type = GFDB_FOP_INVALID_OP; \
|
||||
ctr_local->ia_inode_type = IA_INVAL; \
|
||||
} while (0)
|
||||
|
||||
static gf_ctr_local_t *
|
||||
init_ctr_local_t(xlator_t *this)
|
||||
{
|
||||
gf_ctr_local_t *ctr_local = NULL;
|
||||
|
||||
GF_ASSERT(this);
|
||||
|
||||
ctr_local = mem_get0(this->local_pool);
|
||||
if (!ctr_local) {
|
||||
gf_msg(GFDB_DATA_STORE, GF_LOG_ERROR, 0,
|
||||
CTR_MSG_CREATE_CTR_LOCAL_ERROR_WIND,
|
||||
"Error while creating ctr local");
|
||||
goto out;
|
||||
}
|
||||
|
||||
CLEAR_CTR_DB_RECORD(ctr_local);
|
||||
out:
|
||||
return ctr_local;
|
||||
}
|
||||
|
||||
static void
|
||||
free_ctr_local(gf_ctr_local_t *ctr_local)
|
||||
{
|
||||
if (ctr_local)
|
||||
mem_put(ctr_local);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
*
|
||||
* Context Carrier Structures
|
||||
*
|
||||
*
|
||||
* ****************************************************************************/
|
||||
|
||||
/*
|
||||
* Context Carrier structures are used to carry relevant information about
|
||||
* inodes and links from the fops calls to the ctr_insert_wind.
|
||||
* These structure just have pointers to the original data and donot
|
||||
* do a deep copy of any data. This info is deep copied to
|
||||
* ctr_local->gfdb_db_record and passed to insert_record() api of libgfdb. This
|
||||
* info remains persistent for the unwind in ctr_local->gfdb_db_record
|
||||
* and once used will be destroyed.
|
||||
*
|
||||
* gf_ctr_link_context_t : Context structure for hard links
|
||||
* gf_ctr_inode_context_t : Context structure for inodes
|
||||
*
|
||||
* */
|
||||
|
||||
/*Context Carrier Structure for hard links*/
|
||||
typedef struct gf_ctr_link_context {
|
||||
uuid_t *pargfid;
|
||||
const char *basename;
|
||||
} gf_ctr_link_context_t;
|
||||
|
||||
/*Context Carrier Structure for inodes*/
|
||||
typedef struct gf_ctr_inode_context {
|
||||
ia_type_t ia_type;
|
||||
uuid_t *gfid;
|
||||
uuid_t *old_gfid;
|
||||
gf_ctr_link_context_t *new_link_cx;
|
||||
gf_ctr_link_context_t *old_link_cx;
|
||||
gfdb_fop_type_t fop_type;
|
||||
gfdb_fop_path_t fop_path;
|
||||
gf_boolean_t is_internal_fop;
|
||||
/* Indicating metadata fops */
|
||||
gf_boolean_t is_metadata_fop;
|
||||
} gf_ctr_inode_context_t;
|
||||
|
||||
/*******************Util Macros for Context Carrier Structures*****************/
|
||||
|
||||
/*Checks if ctr_link_cx is sane!*/
|
||||
#define IS_CTR_LINK_CX_SANE(ctr_link_cx) \
|
||||
do { \
|
||||
if (ctr_link_cx) { \
|
||||
if (ctr_link_cx->pargfid) \
|
||||
GF_ASSERT(*(ctr_link_cx->pargfid)); \
|
||||
GF_ASSERT(ctr_link_cx->basename); \
|
||||
}; \
|
||||
} while (0)
|
||||
|
||||
/*Clear and fill the ctr_link_context with values*/
|
||||
#define FILL_CTR_LINK_CX(ctr_link_cx, _pargfid, _basename, label) \
|
||||
do { \
|
||||
GF_VALIDATE_OR_GOTO("ctr", ctr_link_cx, label); \
|
||||
GF_VALIDATE_OR_GOTO("ctr", _pargfid, label); \
|
||||
GF_VALIDATE_OR_GOTO("ctr", _basename, label); \
|
||||
memset(ctr_link_cx, 0, sizeof(*ctr_link_cx)); \
|
||||
ctr_link_cx->pargfid = &_pargfid; \
|
||||
ctr_link_cx->basename = _basename; \
|
||||
} while (0)
|
||||
|
||||
#define NEW_LINK_CX(ctr_inode_cx) ctr_inode_cx->new_link_cx
|
||||
|
||||
#define OLD_LINK_CX(ctr_inode_cx) ctr_inode_cx->old_link_cx
|
||||
|
||||
/*Checks if ctr_inode_cx is sane!*/
|
||||
#define IS_CTR_INODE_CX_SANE(ctr_inode_cx) \
|
||||
do { \
|
||||
GF_ASSERT(ctr_inode_cx); \
|
||||
GF_ASSERT(ctr_inode_cx->gfid); \
|
||||
GF_ASSERT(*(ctr_inode_cx->gfid)); \
|
||||
GF_ASSERT(ctr_inode_cx->fop_type != GFDB_FOP_INVALID_OP); \
|
||||
GF_ASSERT(ctr_inode_cx->fop_path != GFDB_FOP_INVALID); \
|
||||
IS_CTR_LINK_CX_SANE(NEW_LINK_CX(ctr_inode_cx)); \
|
||||
IS_CTR_LINK_CX_SANE(OLD_LINK_CX(ctr_inode_cx)); \
|
||||
} while (0)
|
||||
|
||||
/*Clear and fill the ctr_inode_context with values*/
|
||||
#define FILL_CTR_INODE_CONTEXT(ctr_inode_cx, _ia_type, _gfid, _new_link_cx, \
|
||||
_old_link_cx, _fop_type, _fop_path) \
|
||||
do { \
|
||||
GF_ASSERT(ctr_inode_cx); \
|
||||
GF_ASSERT(_gfid); \
|
||||
GF_ASSERT(_fop_type != GFDB_FOP_INVALID_OP); \
|
||||
GF_ASSERT(_fop_path != GFDB_FOP_INVALID); \
|
||||
memset(ctr_inode_cx, 0, sizeof(*ctr_inode_cx)); \
|
||||
ctr_inode_cx->ia_type = _ia_type; \
|
||||
ctr_inode_cx->gfid = &_gfid; \
|
||||
IS_CTR_LINK_CX_SANE(NEW_LINK_CX(ctr_inode_cx)); \
|
||||
if (_new_link_cx) \
|
||||
NEW_LINK_CX(ctr_inode_cx) = _new_link_cx; \
|
||||
IS_CTR_LINK_CX_SANE(OLD_LINK_CX(ctr_inode_cx)); \
|
||||
if (_old_link_cx) \
|
||||
OLD_LINK_CX(ctr_inode_cx) = _old_link_cx; \
|
||||
ctr_inode_cx->fop_type = _fop_type; \
|
||||
ctr_inode_cx->fop_path = _fop_path; \
|
||||
} while (0)
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Util functions or macros used by
|
||||
* insert wind and insert unwind
|
||||
*
|
||||
* ****************************************************************************/
|
||||
/* Free ctr frame local */
|
||||
static inline void
|
||||
ctr_free_frame_local(call_frame_t *frame)
|
||||
{
|
||||
if (frame) {
|
||||
free_ctr_local((gf_ctr_local_t *)frame->local);
|
||||
frame->local = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Setting GF_REQUEST_LINK_COUNT_XDATA in dict
|
||||
* that has to be sent to POSIX Xlator to send
|
||||
* link count in unwind path.
|
||||
* return 0 for success with not creation of dict
|
||||
* return 1 for success with creation of dict
|
||||
* return -1 for failure.
|
||||
* */
|
||||
static inline int
|
||||
set_posix_link_request(xlator_t *this, dict_t **xdata)
|
||||
{
|
||||
int ret = -1;
|
||||
gf_boolean_t is_created = _gf_false;
|
||||
|
||||
GF_VALIDATE_OR_GOTO("ctr", this, out);
|
||||
GF_VALIDATE_OR_GOTO(this->name, xdata, out);
|
||||
|
||||
/*create xdata if NULL*/
|
||||
if (!*xdata) {
|
||||
*xdata = dict_new();
|
||||
is_created = _gf_true;
|
||||
ret = 1;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
if (!*xdata) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0, CTR_MSG_XDATA_NULL,
|
||||
"xdata is NULL :Cannot send "
|
||||
"GF_REQUEST_LINK_COUNT_XDATA to posix");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = dict_set_int32(*xdata, GF_REQUEST_LINK_COUNT_XDATA, 1);
|
||||
if (ret) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0,
|
||||
CTR_MSG_SET_CTR_RESPONSE_LINK_COUNT_XDATA_FAILED,
|
||||
"Failed setting GF_REQUEST_LINK_COUNT_XDATA");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
if (ret == -1) {
|
||||
if (*xdata && is_created) {
|
||||
dict_unref(*xdata);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* If a bitrot fop
|
||||
* */
|
||||
#define BITROT_FOP(frame) \
|
||||
(frame->root->pid == GF_CLIENT_PID_BITD || \
|
||||
frame->root->pid == GF_CLIENT_PID_SCRUB)
|
||||
|
||||
/*
|
||||
* If a rebalancer fop
|
||||
* */
|
||||
#define REBALANCE_FOP(frame) (frame->root->pid == GF_CLIENT_PID_DEFRAG)
|
||||
|
||||
/*
|
||||
* If its a tiering rebalancer fop
|
||||
* */
|
||||
#define TIER_REBALANCE_FOP(frame) \
|
||||
(frame->root->pid == GF_CLIENT_PID_TIER_DEFRAG)
|
||||
|
||||
/*
|
||||
* If its a AFR SELF HEAL
|
||||
* */
|
||||
#define AFR_SELF_HEAL_FOP(frame) (frame->root->pid == GF_CLIENT_PID_SELF_HEALD)
|
||||
|
||||
/*
|
||||
* if a rebalancer fop goto
|
||||
* */
|
||||
#define CTR_IF_REBALANCE_FOP_THEN_GOTO(frame, label) \
|
||||
do { \
|
||||
if (REBALANCE_FOP(frame)) \
|
||||
goto label; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Internal fop
|
||||
*
|
||||
* */
|
||||
static inline gf_boolean_t
|
||||
is_internal_fop(call_frame_t *frame, dict_t *xdata)
|
||||
{
|
||||
gf_boolean_t ret = _gf_false;
|
||||
|
||||
GF_ASSERT(frame);
|
||||
GF_ASSERT(frame->root);
|
||||
|
||||
if (AFR_SELF_HEAL_FOP(frame)) {
|
||||
ret = _gf_true;
|
||||
}
|
||||
if (BITROT_FOP(frame)) {
|
||||
ret = _gf_true;
|
||||
}
|
||||
if (REBALANCE_FOP(frame) || TIER_REBALANCE_FOP(frame)) {
|
||||
ret = _gf_true;
|
||||
if (xdata && dict_get(xdata, CTR_ATTACH_TIER_LOOKUP)) {
|
||||
ret = _gf_false;
|
||||
}
|
||||
}
|
||||
if (xdata && dict_get(xdata, GLUSTERFS_INTERNAL_FOP_KEY)) {
|
||||
ret = _gf_true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define CTR_IF_INTERNAL_FOP_THEN_GOTO(frame, dict, label) \
|
||||
do { \
|
||||
if (is_internal_fop(frame, dict)) \
|
||||
goto label; \
|
||||
} while (0)
|
||||
|
||||
/* if fop has failed exit */
|
||||
#define CTR_IF_FOP_FAILED_THEN_GOTO(this, op_ret, op_errno, label) \
|
||||
do { \
|
||||
if (op_ret == -1) { \
|
||||
gf_msg_trace(this->name, 0, "Failed fop with %s", \
|
||||
strerror(op_errno)); \
|
||||
goto label; \
|
||||
}; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* IS CTR Xlator is disabled then goto to label
|
||||
* */
|
||||
#define CTR_IS_DISABLED_THEN_GOTO(this, label) \
|
||||
do { \
|
||||
gf_ctr_private_t *_priv = NULL; \
|
||||
GF_ASSERT(this); \
|
||||
GF_ASSERT(this->private); \
|
||||
_priv = this->private; \
|
||||
if (!_priv->_db_conn) \
|
||||
goto label; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* IS CTR record metadata heat is disabled then goto to label
|
||||
* */
|
||||
#define CTR_RECORD_METADATA_HEAT_IS_DISABLED_THEN_GOTO(this, label) \
|
||||
do { \
|
||||
gf_ctr_private_t *_priv = NULL; \
|
||||
GF_ASSERT(this); \
|
||||
GF_ASSERT(this->private); \
|
||||
_priv = this->private; \
|
||||
if (!_priv->ctr_record_metadata_heat) \
|
||||
goto label; \
|
||||
} while (0)
|
||||
|
||||
int
|
||||
fill_db_record_for_unwind(xlator_t *this, gf_ctr_local_t *ctr_local,
|
||||
gfdb_fop_type_t fop_type, gfdb_fop_path_t fop_path);
|
||||
|
||||
int
|
||||
fill_db_record_for_wind(xlator_t *this, gf_ctr_local_t *ctr_local,
|
||||
gf_ctr_inode_context_t *ctr_inode_cx);
|
||||
|
||||
/*******************************************************************************
|
||||
* CTR INSERT WIND
|
||||
* *****************************************************************************
|
||||
* Function used to insert/update record into the database during a wind fop
|
||||
* This function creates ctr_local structure into the frame of the fop
|
||||
* call.
|
||||
* ****************************************************************************/
|
||||
|
||||
static inline int
|
||||
ctr_insert_wind(call_frame_t *frame, xlator_t *this,
|
||||
gf_ctr_inode_context_t *ctr_inode_cx)
|
||||
{
|
||||
int ret = -1;
|
||||
gf_ctr_private_t *_priv = NULL;
|
||||
gf_ctr_local_t *ctr_local = NULL;
|
||||
|
||||
GF_ASSERT(frame);
|
||||
GF_ASSERT(frame->root);
|
||||
GF_ASSERT(this);
|
||||
IS_CTR_INODE_CX_SANE(ctr_inode_cx);
|
||||
|
||||
_priv = this->private;
|
||||
GF_ASSERT(_priv);
|
||||
|
||||
GF_ASSERT(_priv->_db_conn);
|
||||
|
||||
/*If record_wind option of CTR is on record wind for
|
||||
* regular files only*/
|
||||
if (_priv->ctr_record_wind && ctr_inode_cx->ia_type != IA_IFDIR) {
|
||||
frame->local = init_ctr_local_t(this);
|
||||
if (!frame->local) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0,
|
||||
CTR_MSG_CREATE_CTR_LOCAL_ERROR_WIND,
|
||||
"WIND: Error while creating ctr local");
|
||||
goto out;
|
||||
};
|
||||
ctr_local = frame->local;
|
||||
ctr_local->client_pid = frame->root->pid;
|
||||
ctr_local->is_internal_fop = ctr_inode_cx->is_internal_fop;
|
||||
|
||||
/* Decide whether to record counters or not */
|
||||
CTR_DB_REC(ctr_local).do_record_counters = _gf_false;
|
||||
/* If record counter is enabled */
|
||||
if (_priv->ctr_record_counter) {
|
||||
/* If not a internal fop */
|
||||
if (!(ctr_local->is_internal_fop)) {
|
||||
/* If its a metadata fop AND
|
||||
* record metadata heat
|
||||
* OR
|
||||
* its NOT a metadata fop */
|
||||
if ((ctr_inode_cx->is_metadata_fop &&
|
||||
_priv->ctr_record_metadata_heat) ||
|
||||
(!ctr_inode_cx->is_metadata_fop)) {
|
||||
CTR_DB_REC(ctr_local).do_record_counters = _gf_true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Decide whether to record times or not
|
||||
* For non internal FOPS record times as usual*/
|
||||
CTR_DB_REC(ctr_local).do_record_times = _gf_false;
|
||||
if (!ctr_local->is_internal_fop) {
|
||||
/* If its a metadata fop AND
|
||||
* record metadata heat
|
||||
* OR
|
||||
* its NOT a metadata fop */
|
||||
if ((ctr_inode_cx->is_metadata_fop &&
|
||||
_priv->ctr_record_metadata_heat) ||
|
||||
(!ctr_inode_cx->is_metadata_fop)) {
|
||||
CTR_DB_REC(ctr_local).do_record_times =
|
||||
(_priv->ctr_record_wind || _priv->ctr_record_unwind);
|
||||
}
|
||||
}
|
||||
/* when its a internal FOPS*/
|
||||
else {
|
||||
/* Record times only for create
|
||||
* i.e when the inode is created */
|
||||
CTR_DB_REC(ctr_local).do_record_times = (isdentrycreatefop(
|
||||
ctr_inode_cx->fop_type))
|
||||
? _gf_true
|
||||
: _gf_false;
|
||||
}
|
||||
|
||||
/*Fill the db record for insertion*/
|
||||
ret = fill_db_record_for_wind(this, ctr_local, ctr_inode_cx);
|
||||
if (ret) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0,
|
||||
CTR_MSG_FILL_CTR_LOCAL_ERROR_WIND,
|
||||
"WIND: Error filling ctr local");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*Insert the db record*/
|
||||
ret = insert_record(_priv->_db_conn, &ctr_local->gfdb_db_record);
|
||||
if (ret) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0,
|
||||
CTR_MSG_INSERT_RECORD_WIND_FAILED,
|
||||
"WIND: Inserting of record failed!");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
|
||||
if (ret) {
|
||||
free_ctr_local(ctr_local);
|
||||
frame->local = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* CTR INSERT UNWIND
|
||||
* *****************************************************************************
|
||||
* Function used to insert/update record into the database during a unwind fop
|
||||
* This function destroys ctr_local structure into the frame of the fop
|
||||
* call at the end.
|
||||
* ****************************************************************************/
|
||||
static inline int
|
||||
ctr_insert_unwind(call_frame_t *frame, xlator_t *this, gfdb_fop_type_t fop_type,
|
||||
gfdb_fop_path_t fop_path)
|
||||
{
|
||||
int ret = -1;
|
||||
gf_ctr_private_t *_priv = NULL;
|
||||
gf_ctr_local_t *ctr_local = NULL;
|
||||
|
||||
GF_ASSERT(frame);
|
||||
GF_ASSERT(this);
|
||||
|
||||
_priv = this->private;
|
||||
GF_ASSERT(_priv);
|
||||
|
||||
GF_ASSERT(_priv->_db_conn);
|
||||
|
||||
ctr_local = frame->local;
|
||||
|
||||
if (ctr_local && (_priv->ctr_record_unwind || isdentryfop(fop_type)) &&
|
||||
(ctr_local->ia_inode_type != IA_IFDIR)) {
|
||||
CTR_DB_REC(ctr_local).do_record_uwind_time = _priv->ctr_record_unwind;
|
||||
|
||||
ret = fill_db_record_for_unwind(this, ctr_local, fop_type, fop_path);
|
||||
if (ret == -1) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0,
|
||||
CTR_MSG_FILL_CTR_LOCAL_ERROR_UNWIND,
|
||||
"UNWIND: Error filling ctr local");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = insert_record(_priv->_db_conn, &ctr_local->gfdb_db_record);
|
||||
if (ret == -1) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0,
|
||||
CTR_MSG_FILL_CTR_LOCAL_ERROR_UNWIND,
|
||||
"UNWIND: Error filling ctr local");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Delete file/flink record/s from db
|
||||
* ****************************************************************************/
|
||||
static inline int
|
||||
ctr_delete_hard_link_from_db(xlator_t *this, uuid_t gfid, uuid_t pargfid,
|
||||
char *basename, gfdb_fop_type_t fop_type,
|
||||
gfdb_fop_path_t fop_path)
|
||||
{
|
||||
int ret = -1;
|
||||
gfdb_db_record_t gfdb_db_record;
|
||||
gf_ctr_private_t *_priv = NULL;
|
||||
|
||||
_priv = this->private;
|
||||
GF_VALIDATE_OR_GOTO(this->name, _priv, out);
|
||||
GF_VALIDATE_OR_GOTO(this->name, (!gf_uuid_is_null(gfid)), out);
|
||||
GF_VALIDATE_OR_GOTO(this->name, (!gf_uuid_is_null(pargfid)), out);
|
||||
GF_VALIDATE_OR_GOTO(this->name, (fop_type == GFDB_FOP_DENTRY_WRITE), out);
|
||||
GF_VALIDATE_OR_GOTO(
|
||||
this->name, (fop_path == GFDB_FOP_UNDEL || GFDB_FOP_UNDEL_ALL), out);
|
||||
|
||||
/* Set gfdb_db_record to 0 */
|
||||
memset(&gfdb_db_record, 0, sizeof(gfdb_db_record));
|
||||
|
||||
/* Copy basename */
|
||||
if (snprintf(gfdb_db_record.file_name, GF_NAME_MAX, "%s", basename) >=
|
||||
GF_NAME_MAX)
|
||||
goto out;
|
||||
|
||||
/* Copy gfid into db record */
|
||||
gf_uuid_copy(gfdb_db_record.gfid, gfid);
|
||||
|
||||
/* Copy pargid into db record */
|
||||
gf_uuid_copy(gfdb_db_record.pargfid, pargfid);
|
||||
|
||||
gfdb_db_record.gfdb_fop_path = fop_path;
|
||||
gfdb_db_record.gfdb_fop_type = fop_type;
|
||||
|
||||
/*send delete request to db*/
|
||||
ret = insert_record(_priv->_db_conn, &gfdb_db_record);
|
||||
if (ret) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0, CTR_MSG_INSERT_RECORD_WIND_FAILED,
|
||||
"Failed to delete record. %s", basename);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************* Hard link function ***************************/
|
||||
|
||||
static inline gf_boolean_t
|
||||
__is_inode_expired(ctr_xlator_ctx_t *ctr_xlator_ctx, gf_ctr_private_t *_priv,
|
||||
gfdb_time_t *current_time)
|
||||
{
|
||||
gf_boolean_t ret = _gf_false;
|
||||
uint64_t time_diff = 0;
|
||||
|
||||
GF_ASSERT(ctr_xlator_ctx);
|
||||
GF_ASSERT(_priv);
|
||||
GF_ASSERT(current_time);
|
||||
|
||||
time_diff = current_time->tv_sec - ctr_xlator_ctx->inode_heal_period;
|
||||
|
||||
ret = (time_diff >= _priv->ctr_lookupheal_inode_timeout) ? _gf_true
|
||||
: _gf_false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline gf_boolean_t
|
||||
__is_hardlink_expired(ctr_hard_link_t *ctr_hard_link, gf_ctr_private_t *_priv,
|
||||
gfdb_time_t *current_time)
|
||||
{
|
||||
gf_boolean_t ret = _gf_false;
|
||||
uint64_t time_diff = 0;
|
||||
|
||||
GF_ASSERT(ctr_hard_link);
|
||||
GF_ASSERT(_priv);
|
||||
GF_ASSERT(current_time);
|
||||
|
||||
time_diff = current_time->tv_sec - ctr_hard_link->hardlink_heal_period;
|
||||
|
||||
ret = ret || (time_diff >= _priv->ctr_lookupheal_link_timeout) ? _gf_true
|
||||
: _gf_false;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Return values of heal*/
|
||||
typedef enum ctr_heal_ret_val {
|
||||
CTR_CTX_ERROR = -1,
|
||||
/* No healing required */
|
||||
CTR_TRY_NO_HEAL = 0,
|
||||
/* Try healing hard link */
|
||||
CTR_TRY_HARDLINK_HEAL = 1,
|
||||
/* Try healing inode */
|
||||
CTR_TRY_INODE_HEAL = 2,
|
||||
} ctr_heal_ret_val_t;
|
||||
|
||||
/**
|
||||
* @brief Function to add hard link to the inode context variable.
|
||||
* The inode context maintainences a in-memory list. This is used
|
||||
* smart healing of database.
|
||||
* @param frame of the FOP
|
||||
* @param this is the Xlator instant
|
||||
* @param inode
|
||||
* @return Return ctr_heal_ret_val_t
|
||||
*/
|
||||
|
||||
static inline ctr_heal_ret_val_t
|
||||
add_hard_link_ctx(call_frame_t *frame, xlator_t *this, inode_t *inode)
|
||||
{
|
||||
ctr_heal_ret_val_t ret_val = CTR_TRY_NO_HEAL;
|
||||
int ret = -1;
|
||||
gf_ctr_local_t *ctr_local = NULL;
|
||||
ctr_xlator_ctx_t *ctr_xlator_ctx = NULL;
|
||||
ctr_hard_link_t *ctr_hard_link = NULL;
|
||||
gf_ctr_private_t *_priv = NULL;
|
||||
gfdb_time_t current_time = {0};
|
||||
|
||||
GF_ASSERT(frame);
|
||||
GF_ASSERT(this);
|
||||
GF_ASSERT(inode);
|
||||
GF_ASSERT(this->private);
|
||||
|
||||
_priv = this->private;
|
||||
|
||||
ctr_local = frame->local;
|
||||
if (!ctr_local) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctr_xlator_ctx = init_ctr_xlator_ctx(this, inode);
|
||||
if (!ctr_xlator_ctx) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0,
|
||||
CTR_MSG_ACCESS_CTR_INODE_CONTEXT_FAILED,
|
||||
"Failed accessing ctr inode context");
|
||||
goto out;
|
||||
}
|
||||
|
||||
LOCK(&ctr_xlator_ctx->lock);
|
||||
|
||||
/* Check if the hard link already exists
|
||||
* in the ctr inode context*/
|
||||
ctr_hard_link = ctr_search_hard_link_ctx(this, ctr_xlator_ctx,
|
||||
CTR_DB_REC(ctr_local).pargfid,
|
||||
CTR_DB_REC(ctr_local).file_name);
|
||||
/* if there then ignore */
|
||||
if (ctr_hard_link) {
|
||||
ret = gettimeofday(¤t_time, NULL);
|
||||
if (ret == -1) {
|
||||
gf_log(this->name, GF_LOG_ERROR, "Failed to get current time");
|
||||
ret_val = CTR_CTX_ERROR;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (__is_hardlink_expired(ctr_hard_link, _priv, ¤t_time)) {
|
||||
ctr_hard_link->hardlink_heal_period = current_time.tv_sec;
|
||||
ret_val = ret_val | CTR_TRY_HARDLINK_HEAL;
|
||||
}
|
||||
|
||||
if (__is_inode_expired(ctr_xlator_ctx, _priv, ¤t_time)) {
|
||||
ctr_xlator_ctx->inode_heal_period = current_time.tv_sec;
|
||||
ret_val = ret_val | CTR_TRY_INODE_HEAL;
|
||||
}
|
||||
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
/* Add the hard link to the list*/
|
||||
ret = ctr_add_hard_link(this, ctr_xlator_ctx, CTR_DB_REC(ctr_local).pargfid,
|
||||
CTR_DB_REC(ctr_local).file_name);
|
||||
if (ret) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0,
|
||||
CTR_MSG_ADD_HARDLINK_TO_CTR_INODE_CONTEXT_FAILED,
|
||||
"Failed to add hardlink to the ctr inode context");
|
||||
ret_val = CTR_CTX_ERROR;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
ret_val = CTR_TRY_NO_HEAL;
|
||||
unlock:
|
||||
UNLOCK(&ctr_xlator_ctx->lock);
|
||||
out:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static inline int
|
||||
delete_hard_link_ctx(call_frame_t *frame, xlator_t *this, inode_t *inode)
|
||||
{
|
||||
int ret = -1;
|
||||
ctr_xlator_ctx_t *ctr_xlator_ctx = NULL;
|
||||
gf_ctr_local_t *ctr_local = NULL;
|
||||
|
||||
GF_ASSERT(frame);
|
||||
GF_ASSERT(this);
|
||||
GF_ASSERT(inode);
|
||||
|
||||
ctr_local = frame->local;
|
||||
if (!ctr_local) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctr_xlator_ctx = get_ctr_xlator_ctx(this, inode);
|
||||
if (!ctr_xlator_ctx) {
|
||||
/* Since there is no ctr inode context so nothing more to do */
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ctr_delete_hard_link(this, ctr_xlator_ctx,
|
||||
CTR_DB_REC(ctr_local).pargfid,
|
||||
CTR_DB_REC(ctr_local).file_name);
|
||||
if (ret) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0, CTR_MSG_DELETE_HARDLINK_FAILED,
|
||||
"Failed to delete hard link");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
update_hard_link_ctx(call_frame_t *frame, xlator_t *this, inode_t *inode)
|
||||
{
|
||||
int ret = -1;
|
||||
ctr_xlator_ctx_t *ctr_xlator_ctx = NULL;
|
||||
gf_ctr_local_t *ctr_local = NULL;
|
||||
|
||||
GF_ASSERT(frame);
|
||||
GF_ASSERT(this);
|
||||
GF_ASSERT(inode);
|
||||
|
||||
ctr_local = frame->local;
|
||||
if (!ctr_local) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctr_xlator_ctx = init_ctr_xlator_ctx(this, inode);
|
||||
if (!ctr_xlator_ctx) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0,
|
||||
CTR_MSG_ACCESS_CTR_INODE_CONTEXT_FAILED,
|
||||
"Failed accessing ctr inode context");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ctr_update_hard_link(
|
||||
this, ctr_xlator_ctx, CTR_DB_REC(ctr_local).pargfid,
|
||||
CTR_DB_REC(ctr_local).file_name, CTR_DB_REC(ctr_local).old_pargfid,
|
||||
CTR_DB_REC(ctr_local).old_file_name);
|
||||
if (ret) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0, CTR_MSG_DELETE_HARDLINK_FAILED,
|
||||
"Failed to delete hard link");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* CTR xlator init related functions
|
||||
*
|
||||
*
|
||||
* ****************************************************************************/
|
||||
int
|
||||
extract_db_params(xlator_t *this, dict_t *params_dict, gfdb_db_type_t db_type);
|
||||
|
||||
int
|
||||
extract_ctr_options(xlator_t *this, gf_ctr_private_t *_priv);
|
||||
|
||||
#endif
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2013 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 _CTR_MESSAGES_H_
|
||||
#define _CTR_MESSAGES_H_
|
||||
|
||||
#include <glusterfs/glfs-message-id.h>
|
||||
|
||||
/* To add new message IDs, append new identifiers at the end of the list.
|
||||
*
|
||||
* Never remove a message ID. If it's not used anymore, you can rename it or
|
||||
* leave it as it is, but not delete it. This is to prevent reutilization of
|
||||
* IDs by other messages.
|
||||
*
|
||||
* The component name must match one of the entries defined in
|
||||
* glfs-message-id.h.
|
||||
*/
|
||||
|
||||
GLFS_MSGID(
|
||||
CTR, CTR_MSG_CREATE_CTR_LOCAL_ERROR_WIND,
|
||||
CTR_MSG_FILL_CTR_LOCAL_ERROR_UNWIND, CTR_MSG_FILL_CTR_LOCAL_ERROR_WIND,
|
||||
CTR_MSG_INSERT_LINK_WIND_FAILED, CTR_MSG_INSERT_WRITEV_WIND_FAILED,
|
||||
CTR_MSG_INSERT_WRITEV_UNWIND_FAILED, CTR_MSG_INSERT_SETATTR_WIND_FAILED,
|
||||
CTR_MSG_INSERT_SETATTR_UNWIND_FAILED,
|
||||
CTR_MSG_INSERT_FREMOVEXATTR_UNWIND_FAILED,
|
||||
CTR_MSG_INSERT_FREMOVEXATTR_WIND_FAILED,
|
||||
CTR_MSG_INSERT_REMOVEXATTR_WIND_FAILED,
|
||||
CTR_MSG_INSERT_REMOVEXATTR_UNWIND_FAILED,
|
||||
CTR_MSG_INSERT_TRUNCATE_WIND_FAILED, CTR_MSG_INSERT_TRUNCATE_UNWIND_FAILED,
|
||||
CTR_MSG_INSERT_FTRUNCATE_UNWIND_FAILED,
|
||||
CTR_MSG_INSERT_FTRUNCATE_WIND_FAILED, CTR_MSG_INSERT_RENAME_WIND_FAILED,
|
||||
CTR_MSG_INSERT_RENAME_UNWIND_FAILED,
|
||||
CTR_MSG_ACCESS_CTR_INODE_CONTEXT_FAILED, CTR_MSG_ADD_HARDLINK_FAILED,
|
||||
CTR_MSG_DELETE_HARDLINK_FAILED, CTR_MSG_UPDATE_HARDLINK_FAILED,
|
||||
CTR_MSG_GET_CTR_RESPONSE_LINK_COUNT_XDATA_FAILED,
|
||||
CTR_MSG_SET_CTR_RESPONSE_LINK_COUNT_XDATA_FAILED,
|
||||
CTR_MSG_INSERT_UNLINK_UNWIND_FAILED, CTR_MSG_INSERT_UNLINK_WIND_FAILED,
|
||||
CTR_MSG_XDATA_NULL, CTR_MSG_INSERT_FSYNC_WIND_FAILED,
|
||||
CTR_MSG_INSERT_FSYNC_UNWIND_FAILED, CTR_MSG_INSERT_MKNOD_UNWIND_FAILED,
|
||||
CTR_MSG_INSERT_MKNOD_WIND_FAILED, CTR_MSG_INSERT_CREATE_WIND_FAILED,
|
||||
CTR_MSG_INSERT_CREATE_UNWIND_FAILED, CTR_MSG_INSERT_RECORD_WIND_FAILED,
|
||||
CTR_MSG_INSERT_READV_WIND_FAILED, CTR_MSG_GET_GFID_FROM_DICT_FAILED,
|
||||
CTR_MSG_SET, CTR_MSG_FATAL_ERROR, CTR_MSG_DANGLING_VOLUME,
|
||||
CTR_MSG_CALLOC_FAILED, CTR_MSG_EXTRACT_CTR_XLATOR_OPTIONS_FAILED,
|
||||
CTR_MSG_INIT_DB_PARAMS_FAILED, CTR_MSG_CREATE_LOCAL_MEMORY_POOL_FAILED,
|
||||
CTR_MSG_MEM_ACC_INIT_FAILED, CTR_MSG_CLOSE_DB_CONN_FAILED,
|
||||
CTR_MSG_FILL_UNWIND_TIME_REC_ERROR, CTR_MSG_WRONG_FOP_PATH,
|
||||
CTR_MSG_CONSTRUCT_DB_PATH_FAILED, CTR_MSG_SET_VALUE_TO_SQL_PARAM_FAILED,
|
||||
CTR_MSG_XLATOR_DISABLED, CTR_MSG_HARDLINK_MISSING_IN_LIST,
|
||||
CTR_MSG_ADD_HARDLINK_TO_LIST_FAILED, CTR_MSG_INIT_LOCK_FAILED,
|
||||
CTR_MSG_COPY_FAILED, CTR_MSG_EXTRACT_DB_PARAM_OPTIONS_FAILED,
|
||||
CTR_MSG_ADD_HARDLINK_TO_CTR_INODE_CONTEXT_FAILED, CTR_MSG_NULL_LOCAL);
|
||||
|
||||
#endif /* !_CTR_MESSAGES_H_ */
|
@ -1,362 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2015 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.
|
||||
*/
|
||||
|
||||
#include "ctr-xlator-ctx.h"
|
||||
#include "ctr-messages.h"
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define IS_THE_ONLY_HARDLINK(ctr_hard_link) \
|
||||
(ctr_hard_link->list.next == ctr_hard_link->list.prev)
|
||||
|
||||
static void
|
||||
fini_ctr_hard_link(ctr_hard_link_t **ctr_hard_link)
|
||||
{
|
||||
GF_ASSERT(ctr_hard_link);
|
||||
|
||||
if (*ctr_hard_link)
|
||||
return;
|
||||
GF_FREE((*ctr_hard_link)->base_name);
|
||||
GF_FREE(*ctr_hard_link);
|
||||
*ctr_hard_link = NULL;
|
||||
}
|
||||
|
||||
/* Please lock the ctr_xlator_ctx before using this function */
|
||||
ctr_hard_link_t *
|
||||
ctr_search_hard_link_ctx(xlator_t *this, ctr_xlator_ctx_t *ctr_xlator_ctx,
|
||||
uuid_t pgfid, const char *base_name)
|
||||
{
|
||||
ctr_hard_link_t *_hard_link = NULL;
|
||||
ctr_hard_link_t *searched_hardlink = NULL;
|
||||
|
||||
GF_ASSERT(this);
|
||||
GF_ASSERT(ctr_xlator_ctx);
|
||||
|
||||
if (pgfid == NULL || base_name == NULL)
|
||||
goto out;
|
||||
|
||||
/*linear search*/
|
||||
list_for_each_entry(_hard_link, &ctr_xlator_ctx->hardlink_list, list)
|
||||
{
|
||||
if (gf_uuid_compare(_hard_link->pgfid, pgfid) == 0 &&
|
||||
_hard_link->base_name &&
|
||||
strcmp(_hard_link->base_name, base_name) == 0) {
|
||||
searched_hardlink = _hard_link;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return searched_hardlink;
|
||||
}
|
||||
|
||||
/* Please lock the ctr_xlator_ctx before using this function */
|
||||
int
|
||||
ctr_add_hard_link(xlator_t *this, ctr_xlator_ctx_t *ctr_xlator_ctx,
|
||||
uuid_t pgfid, const char *base_name)
|
||||
{
|
||||
int ret = -1;
|
||||
ctr_hard_link_t *ctr_hard_link = NULL;
|
||||
struct timeval current_time = {0};
|
||||
|
||||
GF_ASSERT(this);
|
||||
GF_ASSERT(ctr_xlator_ctx);
|
||||
|
||||
if (pgfid == NULL || base_name == NULL)
|
||||
goto out;
|
||||
|
||||
ctr_hard_link = GF_CALLOC(1, sizeof(*ctr_hard_link), gf_ctr_mt_hard_link_t);
|
||||
if (!ctr_hard_link) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, ENOMEM, CTR_MSG_CALLOC_FAILED,
|
||||
"Failed allocating "
|
||||
"ctr_hard_link");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*Initialize the ctr_hard_link object and
|
||||
* Assign the values : parent GFID and basename*/
|
||||
INIT_LIST_HEAD(&ctr_hard_link->list);
|
||||
gf_uuid_copy(ctr_hard_link->pgfid, pgfid);
|
||||
ret = gf_asprintf(&ctr_hard_link->base_name, "%s", base_name);
|
||||
if (ret < 0) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0, CTR_MSG_COPY_FAILED,
|
||||
"Failed copying basename"
|
||||
"to ctr_hard_link");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = gettimeofday(¤t_time, NULL);
|
||||
if (ret == -1) {
|
||||
gf_log(this->name, GF_LOG_ERROR, "Failed to get current time");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/*Add the hard link to the list*/
|
||||
list_add_tail(&ctr_hard_link->list, &ctr_xlator_ctx->hardlink_list);
|
||||
|
||||
ctr_hard_link->hardlink_heal_period = current_time.tv_sec;
|
||||
|
||||
/*aal izz well!*/
|
||||
ret = 0;
|
||||
goto out;
|
||||
error:
|
||||
GF_FREE(ctr_hard_link);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
__delete_hard_link_from_list(ctr_hard_link_t **ctr_hard_link)
|
||||
{
|
||||
GF_ASSERT(ctr_hard_link);
|
||||
GF_ASSERT(*ctr_hard_link);
|
||||
|
||||
/*Remove hard link from list*/
|
||||
list_del(&(*ctr_hard_link)->list);
|
||||
fini_ctr_hard_link(ctr_hard_link);
|
||||
}
|
||||
|
||||
int
|
||||
ctr_delete_hard_link(xlator_t *this, ctr_xlator_ctx_t *ctr_xlator_ctx,
|
||||
uuid_t pgfid, const char *base_name)
|
||||
{
|
||||
int ret = -1;
|
||||
ctr_hard_link_t *ctr_hard_link = NULL;
|
||||
|
||||
GF_ASSERT(this);
|
||||
GF_ASSERT(ctr_xlator_ctx);
|
||||
|
||||
LOCK(&ctr_xlator_ctx->lock);
|
||||
|
||||
/*Check if the hard link is present */
|
||||
ctr_hard_link = ctr_search_hard_link_ctx(this, ctr_xlator_ctx, pgfid,
|
||||
base_name);
|
||||
if (!ctr_hard_link) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0, CTR_MSG_HARDLINK_MISSING_IN_LIST,
|
||||
"Hard link doesn't exist in the list");
|
||||
goto out;
|
||||
}
|
||||
|
||||
__delete_hard_link_from_list(&ctr_hard_link);
|
||||
ctr_hard_link = NULL;
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
UNLOCK(&ctr_xlator_ctx->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
ctr_update_hard_link(xlator_t *this, ctr_xlator_ctx_t *ctr_xlator_ctx,
|
||||
uuid_t pgfid, const char *base_name, uuid_t old_pgfid,
|
||||
const char *old_base_name)
|
||||
{
|
||||
int ret = -1;
|
||||
ctr_hard_link_t *ctr_hard_link = NULL;
|
||||
struct timeval current_time = {0};
|
||||
|
||||
GF_ASSERT(this);
|
||||
GF_ASSERT(ctr_xlator_ctx);
|
||||
|
||||
LOCK(&ctr_xlator_ctx->lock);
|
||||
|
||||
/*Check if the hard link is present */
|
||||
ctr_hard_link = ctr_search_hard_link_ctx(this, ctr_xlator_ctx, old_pgfid,
|
||||
old_base_name);
|
||||
if (!ctr_hard_link) {
|
||||
gf_msg_trace(this->name, 0,
|
||||
"Hard link doesn't exist"
|
||||
" in the list");
|
||||
/* Since the hard link is not present in the list
|
||||
* we add it to the list */
|
||||
ret = ctr_add_hard_link(this, ctr_xlator_ctx, pgfid, base_name);
|
||||
if (ret) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0,
|
||||
CTR_MSG_ADD_HARDLINK_TO_LIST_FAILED,
|
||||
"Failed adding hard link to the list");
|
||||
goto out;
|
||||
}
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* update the hard link */
|
||||
gf_uuid_copy(ctr_hard_link->pgfid, pgfid);
|
||||
GF_FREE(ctr_hard_link->base_name);
|
||||
ret = gf_asprintf(&ctr_hard_link->base_name, "%s", base_name);
|
||||
if (ret < 0) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, 0, CTR_MSG_COPY_FAILED,
|
||||
"Failed copying basename"
|
||||
"to ctr_hard_link");
|
||||
/* delete the corrupted entry */
|
||||
__delete_hard_link_from_list(&ctr_hard_link);
|
||||
ctr_hard_link = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = gettimeofday(¤t_time, NULL);
|
||||
if (ret == -1) {
|
||||
gf_log(this->name, GF_LOG_ERROR, "Failed to get current time");
|
||||
ctr_hard_link->hardlink_heal_period = 0;
|
||||
} else {
|
||||
ctr_hard_link->hardlink_heal_period = current_time.tv_sec;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
UNLOCK(&ctr_xlator_ctx->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Delete all hardlinks */
|
||||
static int
|
||||
ctr_delete_all_hard_link(xlator_t *this, ctr_xlator_ctx_t *ctr_xlator_ctx)
|
||||
{
|
||||
int ret = -1;
|
||||
ctr_hard_link_t *ctr_hard_link = NULL;
|
||||
ctr_hard_link_t *tmp = NULL;
|
||||
|
||||
GF_ASSERT(ctr_xlator_ctx);
|
||||
|
||||
LOCK(&ctr_xlator_ctx->lock);
|
||||
|
||||
list_for_each_entry_safe(ctr_hard_link, tmp, &ctr_xlator_ctx->hardlink_list,
|
||||
list)
|
||||
{
|
||||
/*Remove hard link from list*/
|
||||
__delete_hard_link_from_list(&ctr_hard_link);
|
||||
ctr_hard_link = NULL;
|
||||
}
|
||||
|
||||
UNLOCK(&ctr_xlator_ctx->lock);
|
||||
|
||||
ret = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Please lock the inode before using this function */
|
||||
static ctr_xlator_ctx_t *
|
||||
__get_ctr_xlator_ctx(xlator_t *this, inode_t *inode)
|
||||
{
|
||||
int ret = 0;
|
||||
uint64_t _addr = 0;
|
||||
ctr_xlator_ctx_t *ctr_xlator_ctx = NULL;
|
||||
|
||||
GF_ASSERT(this);
|
||||
GF_ASSERT(inode);
|
||||
|
||||
ret = __inode_ctx_get(inode, this, &_addr);
|
||||
if (ret < 0)
|
||||
_addr = 0;
|
||||
if (_addr != 0) {
|
||||
ctr_xlator_ctx = (ctr_xlator_ctx_t *)(long)_addr;
|
||||
}
|
||||
|
||||
return ctr_xlator_ctx;
|
||||
}
|
||||
|
||||
ctr_xlator_ctx_t *
|
||||
init_ctr_xlator_ctx(xlator_t *this, inode_t *inode)
|
||||
{
|
||||
int ret = -1;
|
||||
uint64_t _addr = 0;
|
||||
ctr_xlator_ctx_t *ctr_xlator_ctx = NULL;
|
||||
struct timeval current_time = {0};
|
||||
|
||||
GF_ASSERT(this);
|
||||
GF_ASSERT(inode);
|
||||
|
||||
LOCK(&inode->lock);
|
||||
{
|
||||
ctr_xlator_ctx = __get_ctr_xlator_ctx(this, inode);
|
||||
if (ctr_xlator_ctx) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
ctr_xlator_ctx = GF_CALLOC(1, sizeof(*ctr_xlator_ctx),
|
||||
gf_ctr_mt_xlator_ctx);
|
||||
if (!ctr_xlator_ctx)
|
||||
goto out;
|
||||
|
||||
ret = LOCK_INIT(&ctr_xlator_ctx->lock);
|
||||
if (ret) {
|
||||
gf_msg(this->name, GF_LOG_ERROR, ret, CTR_MSG_INIT_LOCK_FAILED,
|
||||
"Failed init lock %s", strerror(ret));
|
||||
goto out;
|
||||
}
|
||||
_addr = (uint64_t)(uintptr_t)ctr_xlator_ctx;
|
||||
|
||||
ret = __inode_ctx_set(inode, this, &_addr);
|
||||
if (ret) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&ctr_xlator_ctx->hardlink_list);
|
||||
|
||||
ret = gettimeofday(¤t_time, NULL);
|
||||
if (ret == -1) {
|
||||
gf_log(this->name, GF_LOG_ERROR, "Failed to get current time");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctr_xlator_ctx->inode_heal_period = current_time.tv_sec;
|
||||
}
|
||||
ret = 0;
|
||||
out:
|
||||
if (ret) {
|
||||
GF_FREE(ctr_xlator_ctx);
|
||||
ctr_xlator_ctx = NULL;
|
||||
}
|
||||
|
||||
UNLOCK(&inode->lock);
|
||||
|
||||
return ctr_xlator_ctx;
|
||||
}
|
||||
|
||||
void
|
||||
fini_ctr_xlator_ctx(xlator_t *this, inode_t *inode)
|
||||
{
|
||||
int ret = 0;
|
||||
uint64_t _addr = 0;
|
||||
ctr_xlator_ctx_t *ctr_xlator_ctx = NULL;
|
||||
|
||||
inode_ctx_del(inode, this, &_addr);
|
||||
if (!_addr)
|
||||
return;
|
||||
|
||||
ctr_xlator_ctx = (ctr_xlator_ctx_t *)(long)_addr;
|
||||
|
||||
ret = ctr_delete_all_hard_link(this, ctr_xlator_ctx);
|
||||
if (ret) {
|
||||
gf_msg(this->name, GF_LOG_WARNING, 0, CTR_MSG_DELETE_HARDLINK_FAILED,
|
||||
"Failed deleting all "
|
||||
"hard links from inode context");
|
||||
}
|
||||
|
||||
LOCK_DESTROY(&ctr_xlator_ctx->lock);
|
||||
|
||||
GF_FREE(ctr_xlator_ctx);
|
||||
}
|
||||
|
||||
ctr_xlator_ctx_t *
|
||||
get_ctr_xlator_ctx(xlator_t *this, inode_t *inode)
|
||||
{
|
||||
ctr_xlator_ctx_t *ctr_xlator_ctx = NULL;
|
||||
|
||||
LOCK(&inode->lock);
|
||||
ctr_xlator_ctx = __get_ctr_xlator_ctx(this, inode);
|
||||
UNLOCK(&inode->lock);
|
||||
|
||||
return ctr_xlator_ctx;
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2015 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 __CTR_XLATOR_CTX_H
|
||||
#define __CTR_XLATOR_CTX_H
|
||||
|
||||
#include <glusterfs/xlator.h>
|
||||
#include "ctr_mem_types.h"
|
||||
#include <glusterfs/iatt.h>
|
||||
#include <glusterfs/glusterfs.h>
|
||||
#include <glusterfs/xlator.h>
|
||||
#include <glusterfs/logging.h>
|
||||
#include <glusterfs/locking.h>
|
||||
#include <glusterfs/common-utils.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
typedef struct ctr_hard_link {
|
||||
uuid_t pgfid;
|
||||
char *base_name;
|
||||
/* Hardlink expiry : Defines the expiry period after which a
|
||||
* database heal is attempted. */
|
||||
uint64_t hardlink_heal_period;
|
||||
struct list_head list;
|
||||
} ctr_hard_link_t;
|
||||
|
||||
typedef struct ctr_xlator_ctx {
|
||||
/* This represents the looked up hardlinks
|
||||
* NOTE: This doesn't represent all physical hardlinks of the inode*/
|
||||
struct list_head hardlink_list;
|
||||
uint64_t inode_heal_period;
|
||||
gf_lock_t lock;
|
||||
} ctr_xlator_ctx_t;
|
||||
|
||||
ctr_hard_link_t *
|
||||
ctr_search_hard_link_ctx(xlator_t *this, ctr_xlator_ctx_t *ctr_xlator_ctx,
|
||||
uuid_t pgfid, const char *base_name);
|
||||
|
||||
int
|
||||
ctr_add_hard_link(xlator_t *this, ctr_xlator_ctx_t *ctr_xlator_ctx,
|
||||
uuid_t pgfid, const char *base_name);
|
||||
|
||||
int
|
||||
ctr_delete_hard_link(xlator_t *this, ctr_xlator_ctx_t *ctr_xlator_ctx,
|
||||
uuid_t pgfid, const char *base_name);
|
||||
|
||||
int
|
||||
ctr_update_hard_link(xlator_t *this, ctr_xlator_ctx_t *ctr_xlator_ctx,
|
||||
uuid_t pgfid, const char *base_name, uuid_t old_pgfid,
|
||||
const char *old_base_name);
|
||||
|
||||
ctr_xlator_ctx_t *
|
||||
get_ctr_xlator_ctx(xlator_t *this, inode_t *inode);
|
||||
|
||||
ctr_xlator_ctx_t *
|
||||
init_ctr_xlator_ctx(xlator_t *this, inode_t *inode);
|
||||
|
||||
void
|
||||
fini_ctr_xlator_ctx(xlator_t *this, inode_t *inode);
|
||||
|
||||
#endif
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2008-2015 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 __CTR_MEM_TYPES_H__
|
||||
#define __CTR_MEM_TYPES_H__
|
||||
|
||||
#include "gfdb_mem-types.h"
|
||||
|
||||
enum gf_ctr_mem_types_ {
|
||||
gf_ctr_mt_private_t = gfdb_mt_end + 1,
|
||||
gf_ctr_mt_xlator_ctx,
|
||||
gf_ctr_mt_hard_link_t,
|
||||
gf_ctr_mt_end
|
||||
};
|
||||
#endif
|
@ -1,3 +0,0 @@
|
||||
SUBDIRS = src examples
|
||||
|
||||
CLEANFILES =
|
@ -1,44 +0,0 @@
|
||||
This is just the very start for a GlusterFS[1] meta-translator that will
|
||||
allow translator code to be written in Python. It's based on the standard
|
||||
Python embedding (not extending) techniques, plus a dash of the ctypes module.
|
||||
The interface is a pretty minimal adaptation of the dispatches and callbacks
|
||||
from the C API[2] to Python, as follows:
|
||||
|
||||
* Dispatch functions and callbacks must be defined on an "xlator" class
|
||||
derived from gluster.Translator so that they'll be auto-registered with
|
||||
the C translator during initialization.
|
||||
|
||||
* For each dispatch or callback function you want to intercept, you define a
|
||||
Python function using the xxx\_fop\_t or xxx\_cbk\_t decorator.
|
||||
|
||||
* The arguments for each operation are different, so you'll need to refer to
|
||||
the C API. GlusterFS-specific types are used (though only loc\_t is fully
|
||||
defined so far) and type correctness is enforced by ctypes.
|
||||
|
||||
* If you do intercept a dispatch function, it is your responsibility to call
|
||||
xxx\_wind (like STACK\_WIND in the C API but operation-specific) to pass
|
||||
the request to the next translator. If you do not intercept a function, it
|
||||
will default the same way as for C (pass through to the same operation with
|
||||
the same arguments on the first child translator).
|
||||
|
||||
* If you intercept a callback function, it is your responsibility to call
|
||||
xxx\_unwind (like STACK\_UNWIND\_STRICT in the C API) to pass the request back
|
||||
to the caller.
|
||||
|
||||
So far only the lookup and create operations are handled this way, to support
|
||||
the "negative lookup" example. Now that the basic infrastructure is in place,
|
||||
adding more functions should be very quick, though with that much boilerplate I
|
||||
might pause to write a code generator. I also plan to add structure
|
||||
definitions and interfaces for some of the utility functions in libglusterfs
|
||||
(especially those having to do with inode and fd context) in the fairly near
|
||||
future. Note that you can also use ctypes to get at anything not explicitly
|
||||
exposed to Python already.
|
||||
|
||||
_If you're coming here because of the Linux Journal article, please note that
|
||||
the code has evolved since that was written. The version that matches the
|
||||
article is here:_
|
||||
|
||||
https://github.com/jdarcy/glupy/tree/4bbae91ba459ea46ef32f2966562492e4ca9187a
|
||||
|
||||
[1] http://www.gluster.org
|
||||
[2] http://pl.atyp.us/hekafs.org/dist/xlator_api_2.html
|
@ -1,9 +0,0 @@
|
||||
Loading a translator written in Python using the glupy meta translator
|
||||
-------------------------------------------------------------------------------
|
||||
'test.vol' is a simple volfile with the debug-trace Python translator on top
|
||||
of a brick. The volfile can be mounted using the following command.
|
||||
|
||||
$ glusterfs --debug -f test.vol /path/to/mntpt
|
||||
|
||||
If then file operations are performed on the newly mounted file system, log
|
||||
output would be printed by the Python translator on the standard output.
|
@ -1,10 +0,0 @@
|
||||
volume vol-posix
|
||||
type storage/posix
|
||||
option directory /path/to/brick
|
||||
end-volume
|
||||
|
||||
volume vol-glupy
|
||||
type features/glupy
|
||||
option module-name debug-trace
|
||||
subvolumes vol-posix
|
||||
end-volume
|
@ -1,5 +0,0 @@
|
||||
xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/features
|
||||
|
||||
glupyexamplesdir = $(xlatordir)/glupy
|
||||
|
||||
glupyexamples_PYTHON = negative.py helloworld.py debug-trace.py
|
@ -1,777 +0,0 @@
|
||||
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
import stat
|
||||
from uuid import UUID
|
||||
from time import strftime, localtime
|
||||
from gluster.glupy import *
|
||||
|
||||
# This translator was written primarily to test the fop entry point definitions
|
||||
# and structure definitions in 'glupy.py'.
|
||||
|
||||
# It is similar to the C language debug-trace translator, which logs the
|
||||
# arguments passed to the fops and their corresponding cbk functions.
|
||||
|
||||
dl.get_id.restype = c_long
|
||||
dl.get_id.argtypes = [ POINTER(call_frame_t) ]
|
||||
|
||||
dl.get_rootunique.restype = c_uint64
|
||||
dl.get_rootunique.argtypes = [ POINTER(call_frame_t) ]
|
||||
|
||||
def uuid2str (gfid):
|
||||
return str(UUID(''.join(map("{0:02x}".format, gfid))))
|
||||
|
||||
|
||||
def st_mode_from_ia (prot, filetype):
|
||||
st_mode = 0
|
||||
type_bit = 0
|
||||
prot_bit = 0
|
||||
|
||||
if filetype == IA_IFREG:
|
||||
type_bit = stat.S_IFREG
|
||||
elif filetype == IA_IFDIR:
|
||||
type_bit = stat.S_IFDIR
|
||||
elif filetype == IA_IFLNK:
|
||||
type_bit = stat.S_IFLNK
|
||||
elif filetype == IA_IFBLK:
|
||||
type_bit = stat.S_IFBLK
|
||||
elif filetype == IA_IFCHR:
|
||||
type_bit = stat.S_IFCHR
|
||||
elif filetype == IA_IFIFO:
|
||||
type_bit = stat.S_IFIFO
|
||||
elif filetype == IA_IFSOCK:
|
||||
type_bit = stat.S_IFSOCK
|
||||
elif filetype == IA_INVAL:
|
||||
pass
|
||||
|
||||
|
||||
if prot.suid:
|
||||
prot_bit |= stat.S_ISUID
|
||||
if prot.sgid:
|
||||
prot_bit |= stat.S_ISGID
|
||||
if prot.sticky:
|
||||
prot_bit |= stat.S_ISVTX
|
||||
|
||||
if prot.owner.read:
|
||||
prot_bit |= stat.S_IRUSR
|
||||
if prot.owner.write:
|
||||
prot_bit |= stat.S_IWUSR
|
||||
if prot.owner.execn:
|
||||
prot_bit |= stat.S_IXUSR
|
||||
|
||||
if prot.group.read:
|
||||
prot_bit |= stat.S_IRGRP
|
||||
if prot.group.write:
|
||||
prot_bit |= stat.S_IWGRP
|
||||
if prot.group.execn:
|
||||
prot_bit |= stat.S_IXGRP
|
||||
|
||||
if prot.other.read:
|
||||
prot_bit |= stat.S_IROTH
|
||||
if prot.other.write:
|
||||
prot_bit |= stat.S_IWOTH
|
||||
if prot.other.execn:
|
||||
prot_bit |= stat.S_IXOTH
|
||||
|
||||
st_mode = (type_bit | prot_bit)
|
||||
|
||||
return st_mode
|
||||
|
||||
|
||||
def trace_stat2str (buf):
|
||||
gfid = uuid2str(buf.contents.ia_gfid)
|
||||
mode = st_mode_from_ia(buf.contents.ia_prot, buf.contents.ia_type)
|
||||
atime_buf = strftime("[%b %d %H:%M:%S]",
|
||||
localtime(buf.contents.ia_atime))
|
||||
mtime_buf = strftime("[%b %d %H:%M:%S]",
|
||||
localtime(buf.contents.ia_mtime))
|
||||
ctime_buf = strftime("[%b %d %H:%M:%S]",
|
||||
localtime(buf.contents.ia_ctime))
|
||||
return ("(gfid={0:s}, ino={1:d}, mode={2:o}, nlink={3:d}, uid ={4:d}, "+
|
||||
"gid ={5:d}, size={6:d}, blocks={7:d}, atime={8:s}, mtime={9:s}, "+
|
||||
"ctime={10:s})").format(gfid, buf.contents.ia_no, mode,
|
||||
buf.contents.ia_nlink,
|
||||
buf.contents.ia_uid,
|
||||
buf.contents.ia_gid,
|
||||
buf.contents.ia_size,
|
||||
buf.contents.ia_blocks,
|
||||
atime_buf, mtime_buf,
|
||||
ctime_buf)
|
||||
|
||||
class xlator(Translator):
|
||||
|
||||
def __init__(self, c_this):
|
||||
Translator.__init__(self, c_this)
|
||||
self.gfids = {}
|
||||
|
||||
def lookup_fop(self, frame, this, loc, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = uuid2str(loc.contents.gfid)
|
||||
print(("GLUPY TRACE LOOKUP FOP- {0:d}: gfid={1:s}; " +
|
||||
"path={2:s}").format(unique, gfid, loc.contents.path))
|
||||
self.gfids[key] = gfid
|
||||
dl.wind_lookup(frame, POINTER(xlator_t)(), loc, xdata)
|
||||
return 0
|
||||
|
||||
def lookup_cbk(self, frame, cookie, this, op_ret, op_errno,
|
||||
inode, buf, xdata, postparent):
|
||||
unique =dl.get_rootunique(frame)
|
||||
key =dl.get_id(frame)
|
||||
if op_ret == 0:
|
||||
gfid = uuid2str(buf.contents.ia_gfid)
|
||||
statstr = trace_stat2str(buf)
|
||||
postparentstr = trace_stat2str(postparent)
|
||||
print(("GLUPY TRACE LOOKUP CBK- {0:d}: gfid={1:s}; "+
|
||||
"op_ret={2:d}; *buf={3:s}; " +
|
||||
"*postparent={4:s}").format(unique, gfid,
|
||||
op_ret, statstr,
|
||||
postparentstr))
|
||||
else:
|
||||
gfid = self.gfids[key]
|
||||
print(("GLUPY TRACE LOOKUP CBK - {0:d}: gfid={1:s};" +
|
||||
" op_ret={2:d}; op_errno={3:d}").format(unique,
|
||||
gfid,
|
||||
op_ret,
|
||||
op_errno))
|
||||
del self.gfids[key]
|
||||
dl.unwind_lookup(frame, cookie, this, op_ret, op_errno,
|
||||
inode, buf, xdata, postparent)
|
||||
return 0
|
||||
|
||||
def create_fop(self, frame, this, loc, flags, mode, umask, fd,
|
||||
xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
gfid = uuid2str(loc.contents.gfid)
|
||||
print(("GLUPY TRACE CREATE FOP- {0:d}: gfid={1:s}; path={2:s}; " +
|
||||
"fd={3:s}; flags=0{4:o}; mode=0{5:o}; " +
|
||||
"umask=0{6:o}").format(unique, gfid, loc.contents.path,
|
||||
fd, flags, mode, umask))
|
||||
dl.wind_create(frame, POINTER(xlator_t)(), loc, flags, mode,
|
||||
umask, fd, xdata)
|
||||
return 0
|
||||
|
||||
def create_cbk(self, frame, cookie, this, op_ret, op_errno, fd,
|
||||
inode, buf, preparent, postparent, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
if op_ret >= 0:
|
||||
gfid = uuid2str(inode.contents.gfid)
|
||||
statstr = trace_stat2str(buf)
|
||||
preparentstr = trace_stat2str(preparent)
|
||||
postparentstr = trace_stat2str(postparent)
|
||||
print(("GLUPY TRACE CREATE CBK- {0:d}: gfid={1:s};" +
|
||||
" op_ret={2:d}; fd={3:s}; *stbuf={4:s}; " +
|
||||
"*preparent={5:s};" +
|
||||
" *postparent={6:s}").format(unique, gfid, op_ret,
|
||||
fd, statstr,
|
||||
preparentstr,
|
||||
postparentstr))
|
||||
else:
|
||||
print(("GLUPY TRACE CREATE CBK- {0:d}: op_ret={1:d}; " +
|
||||
"op_errno={2:d}").format(unique, op_ret, op_errno))
|
||||
dl.unwind_create(frame, cookie, this, op_ret, op_errno, fd,
|
||||
inode, buf, preparent, postparent, xdata)
|
||||
return 0
|
||||
|
||||
def open_fop(self, frame, this, loc, flags, fd, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = uuid2str(loc.contents.inode.contents.gfid)
|
||||
print(("GLUPY TRACE OPEN FOP- {0:d}: gfid={1:s}; path={2:s}; "+
|
||||
"flags={3:d}; fd={4:s}").format(unique, gfid,
|
||||
loc.contents.path, flags,
|
||||
fd))
|
||||
self.gfids[key] = gfid
|
||||
dl.wind_open(frame, POINTER(xlator_t)(), loc, flags, fd, xdata)
|
||||
return 0
|
||||
|
||||
def open_cbk(self, frame, cookie, this, op_ret, op_errno, fd, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = self.gfids[key]
|
||||
print(("GLUPY TRACE OPEN CBK- {0:d}: gfid={1:s}; op_ret={2:d}; "
|
||||
"op_errno={3:d}; *fd={4:s}").format(unique, gfid,
|
||||
op_ret, op_errno, fd))
|
||||
del self.gfids[key]
|
||||
dl.unwind_open(frame, cookie, this, op_ret, op_errno, fd,
|
||||
xdata)
|
||||
return 0
|
||||
|
||||
def readv_fop(self, frame, this, fd, size, offset, flags, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = uuid2str(fd.contents.inode.contents.gfid)
|
||||
print(("GLUPY TRACE READV FOP- {0:d}: gfid={1:s}; "+
|
||||
"fd={2:s}; size ={3:d}; offset={4:d}; " +
|
||||
"flags=0{5:x}").format(unique, gfid, fd, size, offset,
|
||||
flags))
|
||||
self.gfids[key] = gfid
|
||||
dl.wind_readv (frame, POINTER(xlator_t)(), fd, size, offset,
|
||||
flags, xdata)
|
||||
return 0
|
||||
|
||||
def readv_cbk(self, frame, cookie, this, op_ret, op_errno, vector,
|
||||
count, buf, iobref, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = self.gfids[key]
|
||||
if op_ret >= 0:
|
||||
statstr = trace_stat2str(buf)
|
||||
print(("GLUPY TRACE READV CBK- {0:d}: gfid={1:s}, "+
|
||||
"op_ret={2:d}; *buf={3:s};").format(unique, gfid,
|
||||
op_ret,
|
||||
statstr))
|
||||
|
||||
else:
|
||||
print(("GLUPY TRACE READV CBK- {0:d}: gfid={1:s}, "+
|
||||
"op_ret={2:d}; op_errno={3:d}").format(unique,
|
||||
gfid,
|
||||
op_ret,
|
||||
op_errno))
|
||||
del self.gfids[key]
|
||||
dl.unwind_readv (frame, cookie, this, op_ret, op_errno,
|
||||
vector, count, buf, iobref, xdata)
|
||||
return 0
|
||||
|
||||
def writev_fop(self, frame, this, fd, vector, count, offset, flags,
|
||||
iobref, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = uuid2str(fd.contents.inode.contents.gfid)
|
||||
print(("GLUPY TRACE WRITEV FOP- {0:d}: gfid={1:s}; " +
|
||||
"fd={2:s}; count={3:d}; offset={4:d}; " +
|
||||
"flags=0{5:x}").format(unique, gfid, fd, count, offset,
|
||||
flags))
|
||||
self.gfids[key] = gfid
|
||||
dl.wind_writev(frame, POINTER(xlator_t)(), fd, vector, count,
|
||||
offset, flags, iobref, xdata)
|
||||
return 0
|
||||
|
||||
def writev_cbk(self, frame, cookie, this, op_ret, op_errno, prebuf,
|
||||
postbuf, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
if op_ret >= 0:
|
||||
preopstr = trace_stat2str(prebuf)
|
||||
postopstr = trace_stat2str(postbuf)
|
||||
print(("GLUPY TRACE WRITEV CBK- {0:d}: op_ret={1:d}; " +
|
||||
"*prebuf={2:s}; " +
|
||||
"*postbuf={3:s}").format(unique, op_ret, preopstr,
|
||||
postopstr))
|
||||
else:
|
||||
gfid = self.gfids[key]
|
||||
print(("GLUPY TRACE WRITEV CBK- {0:d}: gfid={1:s}; "+
|
||||
"op_ret={2:d}; op_errno={3:d}").format(unique,
|
||||
gfid,
|
||||
op_ret,
|
||||
op_errno))
|
||||
del self.gfids[key]
|
||||
dl.unwind_writev (frame, cookie, this, op_ret, op_errno,
|
||||
prebuf, postbuf, xdata)
|
||||
return 0
|
||||
|
||||
def opendir_fop(self, frame, this, loc, fd, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = uuid2str(loc.contents.inode.contents.gfid)
|
||||
print(("GLUPY TRACE OPENDIR FOP- {0:d}: gfid={1:s}; path={2:s}; "+
|
||||
"fd={3:s}").format(unique, gfid, loc.contents.path, fd))
|
||||
self.gfids[key] = gfid
|
||||
dl.wind_opendir(frame, POINTER(xlator_t)(), loc, fd, xdata)
|
||||
return 0
|
||||
|
||||
def opendir_cbk(self, frame, cookie, this, op_ret, op_errno, fd,
|
||||
xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = self.gfids[key]
|
||||
print(("GLUPY TRACE OPENDIR CBK- {0:d}: gfid={1:s}; op_ret={2:d};"+
|
||||
" op_errno={3:d}; fd={4:s}").format(unique, gfid, op_ret,
|
||||
op_errno, fd))
|
||||
del self.gfids[key]
|
||||
dl.unwind_opendir(frame, cookie, this, op_ret, op_errno,
|
||||
fd, xdata)
|
||||
return 0
|
||||
|
||||
def readdir_fop(self, frame, this, fd, size, offset, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = uuid2str(fd.contents.inode.contents.gfid)
|
||||
print(("GLUPY TRACE READDIR FOP- {0:d}: gfid={1:s}; fd={2:s}; " +
|
||||
"size={3:d}; offset={4:d}").format(unique, gfid, fd, size,
|
||||
offset))
|
||||
self.gfids[key] = gfid
|
||||
dl.wind_readdir(frame, POINTER(xlator_t)(), fd, size, offset,
|
||||
xdata)
|
||||
return 0
|
||||
|
||||
def readdir_cbk(self, frame, cookie, this, op_ret, op_errno, buf,
|
||||
xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = self.gfids[key]
|
||||
print(("GLUPY TRACE READDIR CBK- {0:d}: gfid={1:s}; op_ret={2:d};"+
|
||||
" op_errno={3:d}").format(unique, gfid, op_ret, op_errno))
|
||||
del self.gfids[key]
|
||||
dl.unwind_readdir(frame, cookie, this, op_ret, op_errno, buf,
|
||||
xdata)
|
||||
return 0
|
||||
|
||||
def readdirp_fop(self, frame, this, fd, size, offset, dictionary):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = uuid2str(fd.contents.inode.contents.gfid)
|
||||
print(("GLUPY TRACE READDIRP FOP- {0:d}: gfid={1:s}; fd={2:s}; "+
|
||||
" size={3:d}; offset={4:d}").format(unique, gfid, fd, size,
|
||||
offset))
|
||||
self.gfids[key] = gfid
|
||||
dl.wind_readdirp(frame, POINTER(xlator_t)(), fd, size, offset,
|
||||
dictionary)
|
||||
return 0
|
||||
|
||||
def readdirp_cbk(self, frame, cookie, this, op_ret, op_errno, buf,
|
||||
xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = self.gfids[key]
|
||||
print(("GLUPY TRACE READDIRP CBK- {0:d}: gfid={1:s}; "+
|
||||
"op_ret={2:d}; op_errno={3:d}").format(unique, gfid,
|
||||
op_ret, op_errno))
|
||||
del self.gfids[key]
|
||||
dl.unwind_readdirp(frame, cookie, this, op_ret, op_errno, buf,
|
||||
xdata)
|
||||
return 0
|
||||
|
||||
def mkdir_fop(self, frame, this, loc, mode, umask, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
gfid = uuid2str(loc.contents.inode.contents.gfid)
|
||||
print(("GLUPY TRACE MKDIR FOP- {0:d}: gfid={1:s}; path={2:s}; " +
|
||||
"mode={3:d}; umask=0{4:o}").format(unique, gfid,
|
||||
loc.contents.path, mode,
|
||||
umask))
|
||||
dl.wind_mkdir(frame, POINTER(xlator_t)(), loc, mode, umask,
|
||||
xdata)
|
||||
return 0
|
||||
|
||||
def mkdir_cbk(self, frame, cookie, this, op_ret, op_errno, inode, buf,
|
||||
preparent, postparent, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
if op_ret == 0:
|
||||
gfid = uuid2str(inode.contents.gfid)
|
||||
statstr = trace_stat2str(buf)
|
||||
preparentstr = trace_stat2str(preparent)
|
||||
postparentstr = trace_stat2str(postparent)
|
||||
print(("GLUPY TRACE MKDIR CBK- {0:d}: gfid={1:s}; "+
|
||||
"op_ret={2:d}; *stbuf={3:s}; *prebuf={4:s}; "+
|
||||
"*postbuf={5:s} ").format(unique, gfid, op_ret,
|
||||
statstr,
|
||||
preparentstr,
|
||||
postparentstr))
|
||||
else:
|
||||
print(("GLUPY TRACE MKDIR CBK- {0:d}: op_ret={1:d}; "+
|
||||
"op_errno={2:d}").format(unique, op_ret, op_errno))
|
||||
dl.unwind_mkdir(frame, cookie, this, op_ret, op_errno, inode,
|
||||
buf, preparent, postparent, xdata)
|
||||
return 0
|
||||
|
||||
def rmdir_fop(self, frame, this, loc, flags, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = uuid2str(loc.contents.inode.contents.gfid)
|
||||
print(("GLUPY TRACE RMDIR FOP- {0:d}: gfid={1:s}; path={2:s}; "+
|
||||
"flags={3:d}").format(unique, gfid, loc.contents.path,
|
||||
flags))
|
||||
self.gfids[key] = gfid
|
||||
dl.wind_rmdir(frame, POINTER(xlator_t)(), loc, flags, xdata)
|
||||
return 0
|
||||
|
||||
def rmdir_cbk(self, frame, cookie, this, op_ret, op_errno, preparent,
|
||||
postparent, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = self.gfids[key]
|
||||
if op_ret == 0:
|
||||
preparentstr = trace_stat2str(preparent)
|
||||
postparentstr = trace_stat2str(postparent)
|
||||
print(("GLUPY TRACE RMDIR CBK- {0:d}: gfid={1:s}; "+
|
||||
"op_ret={2:d}; *prebuf={3:s}; "+
|
||||
"*postbuf={4:s}").format(unique, gfid, op_ret,
|
||||
preparentstr,
|
||||
postparentstr))
|
||||
else:
|
||||
print(("GLUPY TRACE RMDIR CBK- {0:d}: gfid={1:s}; "+
|
||||
"op_ret={2:d}; op_errno={3:d}").format(unique,
|
||||
gfid,
|
||||
op_ret,
|
||||
op_errno))
|
||||
del self.gfids[key]
|
||||
dl.unwind_rmdir(frame, cookie, this, op_ret, op_errno,
|
||||
preparent, postparent, xdata)
|
||||
return 0
|
||||
|
||||
def stat_fop(self, frame, this, loc, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = uuid2str(loc.contents.inode.contents.gfid)
|
||||
print(("GLUPY TRACE STAT FOP- {0:d}: gfid={1:s}; " +
|
||||
" path={2:s}").format(unique, gfid, loc.contents.path))
|
||||
self.gfids[key] = gfid
|
||||
dl.wind_stat(frame, POINTER(xlator_t)(), loc, xdata)
|
||||
return 0
|
||||
|
||||
def stat_cbk(self, frame, cookie, this, op_ret, op_errno, buf,
|
||||
xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = self.gfids[key]
|
||||
if op_ret == 0:
|
||||
statstr = trace_stat2str(buf)
|
||||
print(("GLUPY TRACE STAT CBK- {0:d}: gfid={1:s}; "+
|
||||
"op_ret={2:d}; *buf={3:s};").format(unique,
|
||||
gfid,
|
||||
op_ret,
|
||||
statstr))
|
||||
else:
|
||||
print(("GLUPY TRACE STAT CBK- {0:d}: gfid={1:s}; "+
|
||||
"op_ret={2:d}; op_errno={3:d}").format(unique,
|
||||
gfid,
|
||||
op_ret,
|
||||
op_errno))
|
||||
del self.gfids[key]
|
||||
dl.unwind_stat(frame, cookie, this, op_ret, op_errno,
|
||||
buf, xdata)
|
||||
return 0
|
||||
|
||||
def fstat_fop(self, frame, this, fd, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = uuid2str(fd.contents.inode.contents.gfid)
|
||||
print(("GLUPY TRACE FSTAT FOP- {0:d}: gfid={1:s}; " +
|
||||
"fd={2:s}").format(unique, gfid, fd))
|
||||
self.gfids[key] = gfid
|
||||
dl.wind_fstat(frame, POINTER(xlator_t)(), fd, xdata)
|
||||
return 0
|
||||
|
||||
def fstat_cbk(self, frame, cookie, this, op_ret, op_errno, buf,
|
||||
xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = self.gfids[key]
|
||||
if op_ret == 0:
|
||||
statstr = trace_stat2str(buf)
|
||||
print(("GLUPY TRACE FSTAT CBK- {0:d}: gfid={1:s} "+
|
||||
" op_ret={2:d}; *buf={3:s}").format(unique,
|
||||
gfid,
|
||||
op_ret,
|
||||
statstr))
|
||||
else:
|
||||
print(("GLUPY TRACE FSTAT CBK- {0:d}: gfid={1:s} "+
|
||||
"op_ret={2:d}; op_errno={3:d}").format(unique.
|
||||
gfid,
|
||||
op_ret,
|
||||
op_errno))
|
||||
del self.gfids[key]
|
||||
dl.unwind_fstat(frame, cookie, this, op_ret, op_errno,
|
||||
buf, xdata)
|
||||
return 0
|
||||
|
||||
def statfs_fop(self, frame, this, loc, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
if loc.contents.inode:
|
||||
gfid = uuid2str(loc.contents.inode.contents.gfid)
|
||||
else:
|
||||
gfid = "0"
|
||||
print(("GLUPY TRACE STATFS FOP- {0:d}: gfid={1:s}; "+
|
||||
"path={2:s}").format(unique, gfid, loc.contents.path))
|
||||
dl.wind_statfs(frame, POINTER(xlator_t)(), loc, xdata)
|
||||
return 0
|
||||
|
||||
def statfs_cbk(self, frame, cookie, this, op_ret, op_errno, buf,
|
||||
xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
if op_ret == 0:
|
||||
#TBD: print buf (pointer to an iovec type object)
|
||||
print(("GLUPY TRACE STATFS CBK {0:d}: "+
|
||||
"op_ret={1:d}").format(unique, op_ret))
|
||||
else:
|
||||
print(("GLUPY TRACE STATFS CBK- {0:d}"+
|
||||
"op_ret={1:d}; op_errno={2:d}").format(unique,
|
||||
op_ret,
|
||||
op_errno))
|
||||
dl.unwind_statfs(frame, cookie, this, op_ret, op_errno,
|
||||
buf, xdata)
|
||||
return 0
|
||||
|
||||
def getxattr_fop(self, frame, this, loc, name, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = uuid2str(loc.contents.inode.contents.gfid)
|
||||
print(("GLUPY TRACE GETXATTR FOP- {0:d}: gfid={1:s}; path={2:s};"+
|
||||
" name={3:s}").format(unique, gfid, loc.contents.path,
|
||||
name))
|
||||
self.gfids[key]=gfid
|
||||
dl.wind_getxattr(frame, POINTER(xlator_t)(), loc, name, xdata)
|
||||
return 0
|
||||
|
||||
def getxattr_cbk(self, frame, cookie, this, op_ret, op_errno,
|
||||
dictionary, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = self.gfids[key]
|
||||
print(("GLUPY TRACE GETXATTR CBK- {0:d}: gfid={1:s}; "+
|
||||
"op_ret={2:d}; op_errno={3:d}; "+
|
||||
" dictionary={4:s}").format(unique, gfid, op_ret, op_errno,
|
||||
dictionary))
|
||||
del self.gfids[key]
|
||||
dl.unwind_getxattr(frame, cookie, this, op_ret, op_errno,
|
||||
dictionary, xdata)
|
||||
return 0
|
||||
|
||||
def fgetxattr_fop(self, frame, this, fd, name, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = uuid2str(fd.contents.inode.contents.gfid)
|
||||
print(("GLUPY TRACE FGETXATTR FOP- {0:d}: gfid={1:s}; fd={2:s}; "+
|
||||
"name={3:s}").format(unique, gfid, fd, name))
|
||||
self.gfids[key] = gfid
|
||||
dl.wind_fgetxattr(frame, POINTER(xlator_t)(), fd, name, xdata)
|
||||
return 0
|
||||
|
||||
def fgetxattr_cbk(self, frame, cookie, this, op_ret, op_errno,
|
||||
dictionary, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = self.gfids[key]
|
||||
print(("GLUPY TRACE FGETXATTR CBK- {0:d}: gfid={1:s}; "+
|
||||
"op_ret={2:d}; op_errno={3:d};"+
|
||||
" dictionary={4:s}").format(unique, gfid, op_ret,
|
||||
op_errno, dictionary))
|
||||
del self.gfids[key]
|
||||
dl.unwind_fgetxattr(frame, cookie, this, op_ret, op_errno,
|
||||
dictionary, xdata)
|
||||
return 0
|
||||
|
||||
def setxattr_fop(self, frame, this, loc, dictionary, flags, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = uuid2str(loc.contents.inode.contents.gfid)
|
||||
print(("GLUPY TRACE SETXATTR FOP- {0:d}: gfid={1:s}; path={2:s};"+
|
||||
" flags={3:d}").format(unique, gfid, loc.contents.path,
|
||||
flags))
|
||||
self.gfids[key] = gfid
|
||||
dl.wind_setxattr(frame, POINTER(xlator_t)(), loc, dictionary,
|
||||
flags, xdata)
|
||||
return 0
|
||||
|
||||
def setxattr_cbk(self, frame, cookie, this, op_ret, op_errno, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = self.gfids[key]
|
||||
print(("GLUPY TRACE SETXATTR CBK- {0:d}: gfid={1:s}; "+
|
||||
"op_ret={2:d}; op_errno={3:d}").format(unique, gfid,
|
||||
op_ret, op_errno))
|
||||
del self.gfids[key]
|
||||
dl.unwind_setxattr(frame, cookie, this, op_ret, op_errno,
|
||||
xdata)
|
||||
return 0
|
||||
|
||||
def fsetxattr_fop(self, frame, this, fd, dictionary, flags, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = uuid2str(fd.contents.inode.contents.gfid)
|
||||
print(("GLUPY TRACE FSETXATTR FOP- {0:d}: gfid={1:s}; fd={2:p}; "+
|
||||
"flags={3:d}").format(unique, gfid, fd, flags))
|
||||
self.gfids[key] = gfid
|
||||
dl.wind_fsetxattr(frame, POINTER(xlator_t)(), fd, dictionary,
|
||||
flags, xdata)
|
||||
return 0
|
||||
|
||||
def fsetxattr_cbk(self, frame, cookie, this, op_ret, op_errno, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = self.gfids[key]
|
||||
print(("GLUPY TRACE FSETXATTR CBK- {0:d}: gfid={1:s}; "+
|
||||
"op_ret={2:d}; op_errno={3:d}").format(unique, gfid,
|
||||
op_ret, op_errno))
|
||||
del self.gfids[key]
|
||||
dl.unwind_fsetxattr(frame, cookie, this, op_ret, op_errno,
|
||||
xdata)
|
||||
return 0
|
||||
|
||||
def removexattr_fop(self, frame, this, loc, name, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = uuid2str(loc.contents.inode.contents.gfid)
|
||||
print(("GLUPY TRACE REMOVEXATTR FOP- {0:d}: gfid={1:s}; "+
|
||||
"path={2:s}; name={3:s}").format(unique, gfid,
|
||||
loc.contents.path,
|
||||
name))
|
||||
self.gfids[key] = gfid
|
||||
dl.wind_removexattr(frame, POINTER(xlator_t)(), loc, name,
|
||||
xdata)
|
||||
return 0
|
||||
|
||||
def removexattr_cbk(self, frame, cookie, this, op_ret, op_errno,
|
||||
xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = self.gfids[key]
|
||||
print(("GLUPY TRACE REMOVEXATTR CBK- {0:d}: gfid={1:s} "+
|
||||
" op_ret={2:d}; op_errno={3:d}").format(unique, gfid,
|
||||
op_ret, op_errno))
|
||||
del self.gfids[key]
|
||||
dl.unwind_removexattr(frame, cookie, this, op_ret, op_errno,
|
||||
xdata)
|
||||
return 0
|
||||
|
||||
def link_fop(self, frame, this, oldloc, newloc, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
if (newloc.contents.inode):
|
||||
newgfid = uuid2str(newloc.contents.inode.contents.gfid)
|
||||
else:
|
||||
newgfid = "0"
|
||||
oldgfid = uuid2str(oldloc.contents.inode.contents.gfid)
|
||||
print(("GLUPY TRACE LINK FOP-{0:d}: oldgfid={1:s}; oldpath={2:s};"+
|
||||
"newgfid={3:s};"+
|
||||
"newpath={4:s}").format(unique, oldgfid,
|
||||
oldloc.contents.path,
|
||||
newgfid,
|
||||
newloc.contents.path))
|
||||
self.gfids[key] = oldgfid
|
||||
dl.wind_link(frame, POINTER(xlator_t)(), oldloc, newloc,
|
||||
xdata)
|
||||
return 0
|
||||
|
||||
def link_cbk(self, frame, cookie, this, op_ret, op_errno, inode, buf,
|
||||
preparent, postparent, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = self.gfids[key]
|
||||
if op_ret == 0:
|
||||
statstr = trace_stat2str(buf)
|
||||
preparentstr = trace_stat2str(preparent)
|
||||
postparentstr = trace_stat2str(postparent)
|
||||
print(("GLUPY TRACE LINK CBK- {0:d}: op_ret={1:d} "+
|
||||
"*stbuf={2:s}; *prebuf={3:s}; "+
|
||||
"*postbuf={4:s} ").format(unique, op_ret, statstr,
|
||||
preparentstr,
|
||||
postparentstr))
|
||||
else:
|
||||
print(("GLUPY TRACE LINK CBK- {0:d}: gfid={1:s}; "+
|
||||
"op_ret={2:d}; "+
|
||||
"op_errno={3:d}").format(unique, gfid,
|
||||
op_ret, op_errno))
|
||||
del self.gfids[key]
|
||||
dl.unwind_link(frame, cookie, this, op_ret, op_errno, inode,
|
||||
buf, preparent, postparent, xdata)
|
||||
return 0
|
||||
|
||||
def unlink_fop(self, frame, this, loc, xflag, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = uuid2str(loc.contents.inode.contents.gfid)
|
||||
print(("GLUPY TRACE UNLINK FOP- {0:d}; gfid={1:s}; path={2:s}; "+
|
||||
"flag={3:d}").format(unique, gfid, loc.contents.path,
|
||||
xflag))
|
||||
self.gfids[key] = gfid
|
||||
dl.wind_unlink(frame, POINTER(xlator_t)(), loc, xflag,
|
||||
xdata)
|
||||
return 0
|
||||
|
||||
def unlink_cbk(self, frame, cookie, this, op_ret, op_errno,
|
||||
preparent, postparent, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = self.gfids[key]
|
||||
if op_ret == 0:
|
||||
preparentstr = trace_stat2str(preparent)
|
||||
postparentstr = trace_stat2str(postparent)
|
||||
print(("GLUPY TRACE UNLINK CBK- {0:d}: gfid ={1:s}; "+
|
||||
"op_ret={2:d}; *prebuf={3:s}; "+
|
||||
"*postbuf={4:s} ").format(unique, gfid, op_ret,
|
||||
preparentstr,
|
||||
postparentstr))
|
||||
else:
|
||||
print(("GLUPY TRACE UNLINK CBK: {0:d}: gfid ={1:s}; "+
|
||||
"op_ret={2:d}; "+
|
||||
"op_errno={3:d}").format(unique, gfid, op_ret,
|
||||
op_errno))
|
||||
del self.gfids[key]
|
||||
dl.unwind_unlink(frame, cookie, this, op_ret, op_errno,
|
||||
preparent, postparent, xdata)
|
||||
return 0
|
||||
|
||||
def readlink_fop(self, frame, this, loc, size, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = uuid2str(loc.contents.inode.contents.gfid)
|
||||
print(("GLUPY TRACE READLINK FOP- {0:d}: gfid={1:s}; path={2:s};"+
|
||||
" size={3:d}").format(unique, gfid, loc.contents.path,
|
||||
size))
|
||||
self.gfids[key] = gfid
|
||||
dl.wind_readlink(frame, POINTER(xlator_t)(), loc, size,
|
||||
xdata)
|
||||
return 0
|
||||
|
||||
def readlink_cbk(self, frame, cookie, this, op_ret, op_errno,
|
||||
buf, stbuf, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = self.gfids[key]
|
||||
if op_ret == 0:
|
||||
statstr = trace_stat2str(stbuf)
|
||||
print(("GLUPY TRACE READLINK CBK- {0:d}: gfid={1:s} "+
|
||||
" op_ret={2:d}; op_errno={3:d}; *prebuf={4:s}; "+
|
||||
"*postbuf={5:s} ").format(unique, gfid,
|
||||
op_ret, op_errno,
|
||||
buf, statstr))
|
||||
else:
|
||||
print(("GLUPY TRACE READLINK CBK- {0:d}: gfid={1:s} "+
|
||||
" op_ret={2:d}; op_errno={3:d}").format(unique,
|
||||
gfid,
|
||||
op_ret,
|
||||
op_errno))
|
||||
del self.gfids[key]
|
||||
dl.unwind_readlink(frame, cookie, this, op_ret, op_errno, buf,
|
||||
stbuf, xdata)
|
||||
return 0
|
||||
|
||||
def symlink_fop(self, frame, this, linkpath, loc, umask, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = uuid2str(loc.contents.inode.contents.gfid)
|
||||
print(("GLUPY TRACE SYMLINK FOP- {0:d}: gfid={1:s}; "+
|
||||
"linkpath={2:s}; path={3:s};"+
|
||||
"umask=0{4:o}").format(unique, gfid, linkpath,
|
||||
loc.contents.path, umask))
|
||||
self.gfids[key] = gfid
|
||||
dl.wind_symlink(frame, POINTER(xlator_t)(), linkpath, loc,
|
||||
umask, xdata)
|
||||
return 0
|
||||
|
||||
def symlink_cbk(self, frame, cookie, this, op_ret, op_errno,
|
||||
inode, buf, preparent, postparent, xdata):
|
||||
unique = dl.get_rootunique(frame)
|
||||
key = dl.get_id(frame)
|
||||
gfid = self.gfids[key]
|
||||
if op_ret == 0:
|
||||
statstr = trace_stat2str(buf)
|
||||
preparentstr = trace_stat2str(preparent)
|
||||
postparentstr = trace_stat2str(postparent)
|
||||
print(("GLUPY TRACE SYMLINK CBK- {0:d}: gfid={1:s}; "+
|
||||
"op_ret={2:d}; *stbuf={3:s}; *preparent={4:s}; "+
|
||||
"*postparent={5:s}").format(unique, gfid,
|
||||
op_ret, statstr,
|
||||
preparentstr,
|
||||
postparentstr))
|
||||
else:
|
||||
print(("GLUPY TRACE SYMLINK CBK- {0:d}: gfid={1:s}; "+
|
||||
"op_ret={2:d}; op_errno={3:d}").format(unique,
|
||||
gfid,
|
||||
op_ret,
|
||||
op_errno))
|
||||
del self.gfids[key]
|
||||
dl.unwind_symlink(frame, cookie, this, op_ret, op_errno,
|
||||
inode, buf, preparent, postparent, xdata)
|
||||
return 0
|
@ -1,21 +0,0 @@
|
||||
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
from gluster.glupy import *
|
||||
|
||||
class xlator (Translator):
|
||||
|
||||
def __init__(self, c_this):
|
||||
Translator.__init__(self, c_this)
|
||||
|
||||
def lookup_fop(self, frame, this, loc, xdata):
|
||||
print("Python xlator: Hello!")
|
||||
dl.wind_lookup(frame, POINTER(xlator_t)(), loc, xdata)
|
||||
return 0
|
||||
|
||||
def lookup_cbk(self, frame, cookie, this, op_ret, op_errno, inode, buf,
|
||||
xdata, postparent):
|
||||
print("Python xlator: Hello again!")
|
||||
dl.unwind_lookup(frame, cookie, this, op_ret, op_errno, inode, buf,
|
||||
xdata, postparent)
|
||||
return 0
|
@ -1,93 +0,0 @@
|
||||
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
from uuid import UUID
|
||||
from gluster.glupy import *
|
||||
|
||||
# Negative-lookup-caching example. If a file wasn't there the last time we
|
||||
# looked, it's probably still not there. This translator keeps track of
|
||||
# those failed lookups for us, and returns ENOENT without needing to pass the
|
||||
# call any further for repeated requests.
|
||||
|
||||
# If we were doing this for real, we'd need separate caches for each xlator
|
||||
# instance. The easiest way to do this would be to have xlator.__init__
|
||||
# "register" each instance in a module-global dict, with the key as the C
|
||||
# translator address and the value as the xlator object itself. For testing
|
||||
# and teaching, it's sufficient just to have one cache. The keys are parent
|
||||
# GFIDs, and the entries are lists of names within that parent that we know
|
||||
# don't exist.
|
||||
cache = {}
|
||||
|
||||
# TBD: we need a better way of handling per-request data (frame->local in C).
|
||||
dl.get_id.restype = c_long
|
||||
dl.get_id.argtypes = [ POINTER(call_frame_t) ]
|
||||
|
||||
def uuid2str (gfid):
|
||||
return str(UUID(''.join(map("{0:02x}".format, gfid))))
|
||||
|
||||
class xlator (Translator):
|
||||
|
||||
def __init__ (self, c_this):
|
||||
self.requests = {}
|
||||
Translator.__init__(self, c_this)
|
||||
|
||||
def lookup_fop (self, frame, this, loc, xdata):
|
||||
pargfid = uuid2str(loc.contents.pargfid)
|
||||
print("lookup FOP: %s:%s" % (pargfid, loc.contents.name))
|
||||
# Check the cache.
|
||||
if pargfid in cache:
|
||||
if loc.contents.name in cache[pargfid]:
|
||||
print("short-circuiting for %s:%s" % (pargfid,
|
||||
loc.contents.name))
|
||||
dl.unwind_lookup(frame, 0, this, -1, 2, None, None, None, None)
|
||||
return 0
|
||||
key = dl.get_id(frame)
|
||||
self.requests[key] = (pargfid, loc.contents.name[:])
|
||||
# TBD: get real child xl from init, pass it here
|
||||
dl.wind_lookup(frame, POINTER(xlator_t)(), loc, xdata)
|
||||
return 0
|
||||
|
||||
def lookup_cbk (self, frame, cookie, this, op_ret, op_errno, inode, buf,
|
||||
xdata, postparent):
|
||||
print("lookup CBK: %d (%d)" % (op_ret, op_errno))
|
||||
key = dl.get_id(frame)
|
||||
pargfid, name = self.requests[key]
|
||||
# Update the cache.
|
||||
if op_ret == 0:
|
||||
print("found %s, removing from cache" % name)
|
||||
if pargfid in cache:
|
||||
cache[pargfid].discard(name)
|
||||
elif op_errno == 2: # ENOENT
|
||||
print("failed to find %s, adding to cache" % name)
|
||||
if pargfid in cache:
|
||||
cache[pargfid].add(name)
|
||||
else:
|
||||
cache[pargfid] = {name}
|
||||
del self.requests[key]
|
||||
dl.unwind_lookup(frame, cookie, this, op_ret, op_errno,
|
||||
inode, buf, xdata, postparent)
|
||||
return 0
|
||||
|
||||
def create_fop (self, frame, this, loc, flags, mode, umask, fd, xdata):
|
||||
pargfid = uuid2str(loc.contents.pargfid)
|
||||
print("create FOP: %s:%s" % (pargfid, loc.contents.name))
|
||||
key = dl.get_id(frame)
|
||||
self.requests[key] = (pargfid, loc.contents.name[:])
|
||||
# TBD: get real child xl from init, pass it here
|
||||
dl.wind_create(frame, POINTER(xlator_t)(), loc, flags, mode, umask, fd, xdata)
|
||||
return 0
|
||||
|
||||
def create_cbk (self, frame, cookie, this, op_ret, op_errno, fd, inode,
|
||||
buf, preparent, postparent, xdata):
|
||||
print("create CBK: %d (%d)" % (op_ret, op_errno))
|
||||
key = dl.get_id(frame)
|
||||
pargfid, name = self.requests[key]
|
||||
# Update the cache.
|
||||
if op_ret == 0:
|
||||
print("created %s, removing from cache" % name)
|
||||
if pargfid in cache:
|
||||
cache[pargfid].discard(name)
|
||||
del self.requests[key]
|
||||
dl.unwind_create(frame, cookie, this, op_ret, op_errno, fd, inode, buf,
|
||||
preparent, postparent, xdata)
|
||||
return 0
|
@ -1,36 +0,0 @@
|
||||
xlator_LTLIBRARIES = glupy.la
|
||||
|
||||
# Ensure GLUSTER_PYTHON_PATH is passed to glupy.so
|
||||
xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/features
|
||||
glupydir = $(xlatordir)/glupy
|
||||
|
||||
AM_CPPFLAGS = $(GF_CPPFLAGS) \
|
||||
-I$(top_srcdir)/libglusterfs/src \
|
||||
-I$(top_srcdir)/rpc/xdr/src -I$(top_builddir)/rpc/xdr/src
|
||||
|
||||
AM_CFLAGS = -Wall -fno-strict-aliasing \
|
||||
-DGLUSTER_PYTHON_PATH=\"$(glupydir)\" \
|
||||
-DPATH_GLUSTERFS_GLUPY_MODULE=\"${xlatordir}/glupy${shrext_cmds}\" \
|
||||
$(GF_CFLAGS) $(PYTHON_CFLAGS)
|
||||
|
||||
# Flags to build glupy.so with
|
||||
glupy_la_LDFLAGS = -module -nostartfiles \
|
||||
-export-symbols $(top_srcdir)/xlators/features/glupy/src/glupy.sym \
|
||||
$(GF_XLATOR_LDFLAGS) $(PYTHON_LIBS)
|
||||
|
||||
glupy_la_SOURCES = glupy.c
|
||||
glupy_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la \
|
||||
-lpthread $(LIB_DL)
|
||||
|
||||
noinst_HEADERS = glupy.h
|
||||
|
||||
# Install __init__.py into the Python site-packages area
|
||||
pyglupydir = @BUILD_PYTHON_SITE_PACKAGES@/gluster
|
||||
pyglupy_PYTHON = __init__.py
|
||||
|
||||
# Install glupy/__init_-.py into the Python site-packages area
|
||||
SUBDIRS = glupy
|
||||
|
||||
CLEANFILES =
|
||||
|
||||
EXTRA_DIST = glupy.sym
|
@ -1,2 +0,0 @@
|
||||
from pkgutil import extend_path
|
||||
__path__ = extend_path(__path__, __name__)
|
File diff suppressed because it is too large
Load Diff
@ -1,56 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2006-2014 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 __GLUPY_H__
|
||||
#define __GLUPY_H__
|
||||
|
||||
#include <glusterfs/mem-types.h>
|
||||
|
||||
enum {
|
||||
GLUPY_LOOKUP = 0,
|
||||
GLUPY_CREATE,
|
||||
GLUPY_OPEN,
|
||||
GLUPY_READV,
|
||||
GLUPY_WRITEV,
|
||||
GLUPY_OPENDIR,
|
||||
GLUPY_READDIR,
|
||||
GLUPY_READDIRP,
|
||||
GLUPY_STAT,
|
||||
GLUPY_FSTAT,
|
||||
GLUPY_STATFS,
|
||||
GLUPY_SETXATTR,
|
||||
GLUPY_GETXATTR,
|
||||
GLUPY_FSETXATTR,
|
||||
GLUPY_FGETXATTR,
|
||||
GLUPY_REMOVEXATTR,
|
||||
GLUPY_FREMOVEXATTR,
|
||||
GLUPY_LINK,
|
||||
GLUPY_UNLINK,
|
||||
GLUPY_READLINK,
|
||||
GLUPY_SYMLINK,
|
||||
GLUPY_MKNOD,
|
||||
GLUPY_MKDIR,
|
||||
GLUPY_RMDIR,
|
||||
GLUPY_N_FUNCS
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
PyObject *py_module;
|
||||
PyObject *py_xlator;
|
||||
long fops[GLUPY_N_FUNCS];
|
||||
long cbks[GLUPY_N_FUNCS];
|
||||
} glupy_private_t;
|
||||
|
||||
enum gf_glupy_mem_types_ {
|
||||
gf_glupy_mt_priv = gf_common_mt_end + 1,
|
||||
gf_glupy_mt_end
|
||||
};
|
||||
|
||||
#endif /* __GLUPY_H__ */
|
@ -1,101 +0,0 @@
|
||||
init
|
||||
fini
|
||||
fops
|
||||
cbks
|
||||
options
|
||||
notify
|
||||
mem_acct_init
|
||||
reconfigure
|
||||
dumpops
|
||||
set_lookup_fop
|
||||
set_lookup_cbk
|
||||
set_create_fop
|
||||
set_create_cbk
|
||||
set_open_fop
|
||||
set_open_cbk
|
||||
set_readv_fop
|
||||
set_readv_cbk
|
||||
set_writev_fop
|
||||
set_writev_cbk
|
||||
set_opendir_fop
|
||||
set_opendir_cbk
|
||||
set_readdir_fop
|
||||
set_readdir_cbk
|
||||
set_readdirp_fop
|
||||
set_readdirp_cbk
|
||||
set_stat_fop
|
||||
set_stat_cbk
|
||||
set_fstat_fop
|
||||
set_fstat_cbk
|
||||
set_statfs_fop
|
||||
set_statfs_cbk
|
||||
set_setxattr_fop
|
||||
set_setxattr_cbk
|
||||
set_getxattr_fop
|
||||
set_getxattr_cbk
|
||||
set_fsetxattr_fop
|
||||
set_fsetxattr_cbk
|
||||
set_fgetxattr_fop
|
||||
set_fgetxattr_cbk
|
||||
set_removexattr_fop
|
||||
set_removexattr_cbk
|
||||
set_fremovexattr_fop
|
||||
set_fremovexattr_cbk
|
||||
set_link_fop
|
||||
set_link_cbk
|
||||
set_symlink_fop
|
||||
set_symlink_cbk
|
||||
set_readlink_fop
|
||||
set_readlink_cbk
|
||||
set_unlink_fop
|
||||
set_unlink_cbk
|
||||
set_mkdir_fop
|
||||
set_mkdir_cbk
|
||||
set_rmdir_fop
|
||||
set_rmdir_cbk
|
||||
wind_lookup
|
||||
wind_create
|
||||
wind_open
|
||||
wind_readv
|
||||
wind_writev
|
||||
wind_opendir
|
||||
wind_readdir
|
||||
wind_readdirp
|
||||
wind_stat
|
||||
wind_fstat
|
||||
wind_statfs
|
||||
wind_setxattr
|
||||
wind_getxattr
|
||||
wind_fsetxattr
|
||||
wind_fgetxattr
|
||||
wind_removexattr
|
||||
wind_fremovexattr
|
||||
wind_link
|
||||
wind_symlink
|
||||
wind_readlink
|
||||
wind_unlink
|
||||
wind_mkdir
|
||||
wind_rmdir
|
||||
unwind_lookup
|
||||
unwind_create
|
||||
unwind_open
|
||||
unwind_readv
|
||||
unwind_writev
|
||||
unwind_opendir
|
||||
unwind_readdir
|
||||
unwind_readdirp
|
||||
unwind_stat
|
||||
unwind_fstat
|
||||
unwind_statfs
|
||||
unwind_setxattr
|
||||
unwind_getxattr
|
||||
unwind_fsetxattr
|
||||
unwind_fgetxattr
|
||||
unwind_removexattr
|
||||
unwind_fremovexattr
|
||||
unwind_link
|
||||
unwind_symlink
|
||||
unwind_readlink
|
||||
unwind_unlink
|
||||
unwind_mkdir
|
||||
unwind_rmdir
|
@ -1,5 +0,0 @@
|
||||
# Install __init__.py into the Python site-packages area
|
||||
pyglupydir = @BUILD_PYTHON_SITE_PACKAGES@/gluster/glupy
|
||||
pyglupy_PYTHON = __init__.py
|
||||
|
||||
CLEANFILES =
|
@ -1,852 +0,0 @@
|
||||
##
|
||||
## Copyright (c) 2006-2014 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.
|
||||
##
|
||||
|
||||
import sys
|
||||
import os
|
||||
from ctypes import *
|
||||
|
||||
dl = CDLL(os.getenv("PATH_GLUSTERFS_GLUPY_MODULE", ""), RTLD_GLOBAL)
|
||||
|
||||
|
||||
class call_frame_t (Structure):
|
||||
pass
|
||||
|
||||
class dev_t (Structure):
|
||||
pass
|
||||
|
||||
|
||||
class dict_t (Structure):
|
||||
pass
|
||||
|
||||
|
||||
class gf_dirent_t (Structure):
|
||||
pass
|
||||
|
||||
|
||||
class iobref_t (Structure):
|
||||
pass
|
||||
|
||||
|
||||
class iovec_t (Structure):
|
||||
pass
|
||||
|
||||
|
||||
class list_head (Structure):
|
||||
pass
|
||||
|
||||
list_head._fields_ = [
|
||||
("next", POINTER(list_head)),
|
||||
("prev", POINTER(list_head))
|
||||
]
|
||||
|
||||
|
||||
class rwxperm_t (Structure):
|
||||
_fields_ = [
|
||||
("read", c_uint8, 1),
|
||||
("write", c_uint8, 1),
|
||||
("execn", c_uint8, 1)
|
||||
]
|
||||
|
||||
|
||||
class statvfs_t (Structure):
|
||||
pass
|
||||
|
||||
|
||||
class xlator_t (Structure):
|
||||
pass
|
||||
|
||||
|
||||
class ia_prot_t (Structure):
|
||||
_fields_ = [
|
||||
("suid", c_uint8, 1),
|
||||
("sgid", c_uint8, 1),
|
||||
("sticky", c_uint8, 1),
|
||||
("owner", rwxperm_t),
|
||||
("group", rwxperm_t),
|
||||
("other", rwxperm_t)
|
||||
]
|
||||
|
||||
# For checking file type.
|
||||
(IA_INVAL, IA_IFREG, IA_IFDIR, IA_IFLNK, IA_IFBLK, IA_IFCHR, IA_IFIFO,
|
||||
IA_IFSOCK) = range(8)
|
||||
|
||||
|
||||
class iatt_t (Structure):
|
||||
_fields_ = [
|
||||
("ia_no", c_uint64),
|
||||
("ia_gfid", c_ubyte * 16),
|
||||
("ia_dev", c_uint64),
|
||||
("ia_type", c_uint),
|
||||
("ia_prot", ia_prot_t),
|
||||
("ia_nlink", c_uint32),
|
||||
("ia_uid", c_uint32),
|
||||
("ia_gid", c_uint32),
|
||||
("ia_rdev", c_uint64),
|
||||
("ia_size", c_uint64),
|
||||
("ia_blksize", c_uint32),
|
||||
("ia_blocks", c_uint64),
|
||||
("ia_atime", c_uint32 ),
|
||||
("ia_atime_nsec", c_uint32),
|
||||
("ia_mtime", c_uint32),
|
||||
("ia_mtime_nsec", c_uint32),
|
||||
("ia_ctime", c_uint32),
|
||||
("ia_ctime_nsec", c_uint32)
|
||||
]
|
||||
|
||||
|
||||
class mem_pool (Structure):
|
||||
_fields_ = [
|
||||
("list", list_head),
|
||||
("hot_count", c_int),
|
||||
("cold_count", c_int),
|
||||
("lock", c_void_p),
|
||||
("padded_sizeof_type", c_ulong),
|
||||
("pool", c_void_p),
|
||||
("pool_end", c_void_p),
|
||||
("real_sizeof_type", c_int),
|
||||
("alloc_count", c_uint64),
|
||||
("pool_misses", c_uint64),
|
||||
("max_alloc", c_int),
|
||||
("curr_stdalloc", c_int),
|
||||
("max_stdalloc", c_int),
|
||||
("name", c_char_p),
|
||||
("global_list", list_head)
|
||||
]
|
||||
|
||||
|
||||
class U_ctx_key_inode (Union):
|
||||
_fields_ = [
|
||||
("key", c_uint64),
|
||||
("xl_key", POINTER(xlator_t))
|
||||
]
|
||||
|
||||
|
||||
class U_ctx_value1 (Union):
|
||||
_fields_ = [
|
||||
("value1", c_uint64),
|
||||
("ptr1", c_void_p)
|
||||
]
|
||||
|
||||
|
||||
class U_ctx_value2 (Union):
|
||||
_fields_ = [
|
||||
("value2", c_uint64),
|
||||
("ptr2", c_void_p)
|
||||
]
|
||||
|
||||
class inode_ctx (Structure):
|
||||
_anonymous_ = ("u_key", "u_value1", "u_value2",)
|
||||
_fields_ = [
|
||||
("u_key", U_ctx_key_inode),
|
||||
("u_value1", U_ctx_value1),
|
||||
("u_value2", U_ctx_value2)
|
||||
]
|
||||
|
||||
class inode_t (Structure):
|
||||
pass
|
||||
|
||||
class inode_table_t (Structure):
|
||||
_fields_ = [
|
||||
("lock", c_void_p),
|
||||
("hashsize", c_size_t),
|
||||
("name", c_char_p),
|
||||
("root", POINTER(inode_t)),
|
||||
("xl", POINTER(xlator_t)),
|
||||
("lru_limit", c_uint32),
|
||||
("inode_hash", POINTER(list_head)),
|
||||
("name_hash", POINTER(list_head)),
|
||||
("active", list_head),
|
||||
("active_size", c_uint32),
|
||||
("lru", list_head),
|
||||
("lru_size", c_uint32),
|
||||
("purge", list_head),
|
||||
("purge_size", c_uint32),
|
||||
("inode_pool", POINTER(mem_pool)),
|
||||
("dentry_pool", POINTER(mem_pool)),
|
||||
("fd_mem_pool", POINTER(mem_pool))
|
||||
]
|
||||
|
||||
inode_t._fields_ = [
|
||||
("table", POINTER(inode_table_t)),
|
||||
("gfid", c_ubyte * 16),
|
||||
("lock", c_void_p),
|
||||
("nlookup", c_uint64),
|
||||
("fd_count", c_uint32),
|
||||
("ref", c_uint32),
|
||||
("ia_type", c_uint),
|
||||
("fd_list", list_head),
|
||||
("dentry_list", list_head),
|
||||
("hashv", list_head),
|
||||
("listv", list_head),
|
||||
("ctx", POINTER(inode_ctx))
|
||||
]
|
||||
|
||||
|
||||
|
||||
class U_ctx_key_fd (Union):
|
||||
_fields_ = [
|
||||
("key", c_uint64),
|
||||
("xl_key", c_void_p)
|
||||
]
|
||||
|
||||
class fd_lk_ctx (Structure):
|
||||
_fields_ = [
|
||||
("lk_list", list_head),
|
||||
("ref", c_int),
|
||||
("lock", c_void_p)
|
||||
]
|
||||
|
||||
class fd_ctx (Structure):
|
||||
_anonymous_ = ("u_key", "u_value1")
|
||||
_fields_ = [
|
||||
("u_key", U_ctx_key_fd),
|
||||
("u_value1", U_ctx_value1)
|
||||
]
|
||||
|
||||
class fd_t (Structure):
|
||||
_fields_ = [
|
||||
("pid", c_uint64),
|
||||
("flags", c_int32),
|
||||
("refcount", c_int32),
|
||||
("inode_list", list_head),
|
||||
("inode", POINTER(inode_t)),
|
||||
("lock", c_void_p),
|
||||
("ctx", POINTER(fd_ctx)),
|
||||
("xl_count", c_int),
|
||||
("lk_ctx", POINTER(fd_lk_ctx)),
|
||||
("anonymous", c_uint)
|
||||
]
|
||||
|
||||
class loc_t (Structure):
|
||||
_fields_ = [
|
||||
("path", c_char_p),
|
||||
("name", c_char_p),
|
||||
("inode", POINTER(inode_t)),
|
||||
("parent", POINTER(inode_t)),
|
||||
("gfid", c_ubyte * 16),
|
||||
("pargfid", c_ubyte * 16),
|
||||
]
|
||||
|
||||
|
||||
|
||||
def _init_op (a_class, fop, cbk, wind, unwind):
|
||||
# Decorators, used by translators. We could pass the signatures as
|
||||
# parameters, but it's actually kind of nice to keep them around for
|
||||
# inspection.
|
||||
a_class.fop_type = CFUNCTYPE(*a_class.fop_sig)
|
||||
a_class.cbk_type = CFUNCTYPE(*a_class.cbk_sig)
|
||||
# Dispatch-function registration.
|
||||
fop.restype = None
|
||||
fop.argtypes = [ c_long, a_class.fop_type ]
|
||||
# Callback-function registration.
|
||||
cbk.restype = None
|
||||
cbk.argtypes = [ c_long, a_class.cbk_type ]
|
||||
# STACK_WIND function.
|
||||
wind.restype = None
|
||||
wind.argtypes = list(a_class.fop_sig[1:])
|
||||
# STACK_UNWIND function.
|
||||
unwind.restype = None
|
||||
unwind.argtypes = list(a_class.cbk_sig[1:])
|
||||
|
||||
class OpLookup:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(loc_t), POINTER(dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(inode_t), POINTER(iatt_t),
|
||||
POINTER(dict_t), POINTER(iatt_t))
|
||||
_init_op (OpLookup, dl.set_lookup_fop, dl.set_lookup_cbk,
|
||||
dl.wind_lookup, dl.unwind_lookup)
|
||||
|
||||
class OpCreate:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(loc_t), c_int, c_uint, c_uint, POINTER(fd_t),
|
||||
POINTER(dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(fd_t), POINTER(inode_t),
|
||||
POINTER(iatt_t), POINTER(iatt_t), POINTER(iatt_t),
|
||||
POINTER(dict_t))
|
||||
_init_op (OpCreate, dl.set_create_fop, dl.set_create_cbk,
|
||||
dl.wind_create, dl.unwind_create)
|
||||
|
||||
class OpOpen:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(loc_t), c_int, POINTER(fd_t), POINTER(dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(fd_t), POINTER(dict_t))
|
||||
_init_op (OpOpen, dl.set_open_fop, dl.set_open_cbk,
|
||||
dl.wind_open, dl.unwind_open)
|
||||
|
||||
class OpReadv:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(fd_t), c_size_t, c_long, c_uint32, POINTER(dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(iovec_t), c_int, POINTER(iatt_t),
|
||||
POINTER(iobref_t), POINTER(dict_t))
|
||||
_init_op (OpReadv, dl.set_readv_fop, dl.set_readv_cbk,
|
||||
dl.wind_readv, dl.unwind_readv)
|
||||
class OpWritev:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(fd_t), POINTER(iovec_t), c_int, c_long, c_uint32,
|
||||
POINTER(iobref_t), POINTER(dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(iatt_t), POINTER(iatt_t),
|
||||
POINTER(dict_t))
|
||||
_init_op (OpWritev, dl.set_writev_fop, dl.set_writev_cbk,
|
||||
dl.wind_writev, dl.unwind_writev)
|
||||
|
||||
class OpOpendir:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(loc_t), POINTER(fd_t), POINTER(dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(fd_t), POINTER(dict_t))
|
||||
_init_op (OpOpendir, dl.set_opendir_fop, dl.set_opendir_cbk,
|
||||
dl.wind_opendir, dl.unwind_opendir)
|
||||
|
||||
class OpReaddir:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(fd_t), c_size_t, c_long, POINTER(dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(gf_dirent_t), POINTER(dict_t))
|
||||
_init_op (OpReaddir, dl.set_readdir_fop, dl.set_readdir_cbk,
|
||||
dl.wind_readdir, dl.unwind_readdir)
|
||||
|
||||
class OpReaddirp:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(fd_t), c_size_t, c_long, POINTER(dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(gf_dirent_t), POINTER(dict_t))
|
||||
_init_op (OpReaddirp, dl.set_readdirp_fop, dl.set_readdirp_cbk,
|
||||
dl.wind_readdirp, dl.unwind_readdirp)
|
||||
|
||||
class OpStat:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(loc_t), POINTER(dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(iatt_t), POINTER(dict_t))
|
||||
_init_op (OpStat, dl.set_stat_fop, dl.set_stat_cbk,
|
||||
dl.wind_stat, dl.unwind_stat)
|
||||
|
||||
class OpFstat:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(fd_t), POINTER(dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(iatt_t), POINTER(dict_t))
|
||||
_init_op (OpFstat, dl.set_fstat_fop, dl.set_fstat_cbk,
|
||||
dl.wind_fstat, dl.unwind_fstat)
|
||||
|
||||
class OpStatfs:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(loc_t), POINTER(dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(statvfs_t), POINTER(dict_t))
|
||||
_init_op (OpStatfs, dl.set_statfs_fop, dl.set_statfs_cbk,
|
||||
dl.wind_statfs, dl.unwind_statfs)
|
||||
|
||||
|
||||
class OpSetxattr:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(loc_t), POINTER(dict_t), c_int32,
|
||||
POINTER (dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(dict_t))
|
||||
_init_op (OpSetxattr, dl.set_setxattr_fop, dl.set_setxattr_cbk,
|
||||
dl.wind_setxattr, dl.unwind_setxattr)
|
||||
|
||||
class OpGetxattr:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(loc_t), c_char_p, POINTER (dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(dict_t), POINTER(dict_t))
|
||||
_init_op (OpGetxattr, dl.set_getxattr_fop, dl.set_getxattr_cbk,
|
||||
dl.wind_getxattr, dl.unwind_getxattr)
|
||||
|
||||
class OpFsetxattr:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(fd_t), POINTER(dict_t), c_int32,
|
||||
POINTER (dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(dict_t))
|
||||
_init_op (OpFsetxattr, dl.set_fsetxattr_fop, dl.set_fsetxattr_cbk,
|
||||
dl.wind_fsetxattr, dl.unwind_fsetxattr)
|
||||
|
||||
class OpFgetxattr:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(fd_t), c_char_p, POINTER (dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(dict_t), POINTER(dict_t))
|
||||
_init_op (OpFgetxattr, dl.set_fgetxattr_fop, dl.set_fgetxattr_cbk,
|
||||
dl.wind_fgetxattr, dl.unwind_fgetxattr)
|
||||
|
||||
class OpRemovexattr:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(loc_t), c_char_p, POINTER(dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(dict_t))
|
||||
_init_op (OpRemovexattr, dl.set_removexattr_fop, dl.set_removexattr_cbk,
|
||||
dl.wind_removexattr, dl.unwind_removexattr)
|
||||
|
||||
|
||||
class OpFremovexattr:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(fd_t), c_char_p, POINTER(dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(dict_t))
|
||||
_init_op (OpFremovexattr, dl.set_fremovexattr_fop, dl.set_fremovexattr_cbk,
|
||||
dl.wind_fremovexattr, dl.unwind_fremovexattr)
|
||||
|
||||
class OpLink:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(loc_t), POINTER(loc_t), POINTER(dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(inode_t), POINTER(iatt_t),
|
||||
POINTER(iatt_t), POINTER(iatt_t), POINTER(dict_t))
|
||||
_init_op (OpLink, dl.set_link_fop, dl.set_link_cbk,
|
||||
dl.wind_link, dl.unwind_link)
|
||||
|
||||
class OpSymlink:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
c_char_p, POINTER(loc_t), c_uint, POINTER(dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(inode_t), POINTER(iatt_t),
|
||||
POINTER(iatt_t), POINTER(iatt_t), POINTER(dict_t))
|
||||
_init_op (OpSymlink, dl.set_symlink_fop, dl.set_symlink_cbk,
|
||||
dl.wind_symlink, dl.unwind_symlink)
|
||||
|
||||
class OpUnlink:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(loc_t), c_int, POINTER(dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(iatt_t), POINTER(iatt_t),
|
||||
POINTER(dict_t))
|
||||
_init_op (OpUnlink, dl.set_unlink_fop, dl.set_unlink_cbk,
|
||||
dl.wind_unlink, dl.unwind_unlink)
|
||||
|
||||
class OpReadlink:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(loc_t), c_size_t, POINTER(dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, c_char_p, POINTER(iatt_t), POINTER(dict_t))
|
||||
_init_op (OpReadlink, dl.set_readlink_fop, dl.set_readlink_cbk,
|
||||
dl.wind_readlink, dl.unwind_readlink)
|
||||
|
||||
class OpMkdir:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(loc_t), c_uint, c_uint, POINTER(dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(inode_t), POINTER(iatt_t),
|
||||
POINTER(iatt_t), POINTER(iatt_t), POINTER(dict_t))
|
||||
_init_op (OpMkdir, dl.set_mkdir_fop, dl.set_mkdir_cbk,
|
||||
dl.wind_mkdir, dl.unwind_mkdir)
|
||||
|
||||
class OpRmdir:
|
||||
fop_sig = (c_int, POINTER(call_frame_t), POINTER(xlator_t),
|
||||
POINTER(loc_t), c_int, POINTER(dict_t))
|
||||
cbk_sig = (c_int, POINTER(call_frame_t), c_long, POINTER(xlator_t),
|
||||
c_int, c_int, POINTER(iatt_t), POINTER(iatt_t),
|
||||
POINTER(dict_t))
|
||||
_init_op (OpRmdir, dl.set_rmdir_fop, dl.set_rmdir_cbk,
|
||||
dl.wind_rmdir, dl.unwind_rmdir)
|
||||
|
||||
|
||||
class Translator:
|
||||
def __init__ (self, c_this):
|
||||
# This is only here to keep references to the stubs we create,
|
||||
# because ctypes doesn't and glupy.so can't because it doesn't
|
||||
# get a pointer to the actual Python object. It's a dictionary
|
||||
# instead of a list in case we ever allow changing fops/cbks
|
||||
# after initialization and need to look them up.
|
||||
self.stub_refs = {}
|
||||
funcs = dir(self.__class__)
|
||||
if "lookup_fop" in funcs:
|
||||
@OpLookup.fop_type
|
||||
def stub (frame, this, loc, xdata, s=self):
|
||||
return s.lookup_fop (frame, this, loc, xdata)
|
||||
self.stub_refs["lookup_fop"] = stub
|
||||
dl.set_lookup_fop(c_this, stub)
|
||||
if "lookup_cbk" in funcs:
|
||||
@OpLookup.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno, inode,
|
||||
buf, xdata, postparent, s=self):
|
||||
return s.lookup_cbk(frame, cookie, this, op_ret,
|
||||
op_errno, inode, buf, xdata,
|
||||
postparent)
|
||||
self.stub_refs["lookup_cbk"] = stub
|
||||
dl.set_lookup_cbk(c_this, stub)
|
||||
if "create_fop" in funcs:
|
||||
@OpCreate.fop_type
|
||||
def stub (frame, this, loc, flags, mode, umask, fd,
|
||||
xdata, s=self):
|
||||
return s.create_fop (frame, this, loc, flags,
|
||||
mode, umask, fd, xdata)
|
||||
self.stub_refs["create_fop"] = stub
|
||||
dl.set_create_fop(c_this, stub)
|
||||
if "create_cbk" in funcs:
|
||||
@OpCreate.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno, fd,
|
||||
inode, buf, preparent, postparent, xdata,
|
||||
s=self):
|
||||
return s.create_cbk (frame, cookie, this,
|
||||
op_ret, op_errno, fd,
|
||||
inode, buf, preparent,
|
||||
postparent, xdata)
|
||||
self.stub_refs["create_cbk"] = stub
|
||||
dl.set_create_cbk(c_this, stub)
|
||||
if "open_fop" in funcs:
|
||||
@OpOpen.fop_type
|
||||
def stub (frame, this, loc, flags, fd,
|
||||
xdata, s=self):
|
||||
return s.open_fop (frame, this, loc, flags,
|
||||
fd, xdata)
|
||||
self.stub_refs["open_fop"] = stub
|
||||
dl.set_open_fop(c_this, stub)
|
||||
if "open_cbk" in funcs:
|
||||
@OpOpen.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno, fd,
|
||||
xdata, s=self):
|
||||
return s.open_cbk (frame, cookie, this,
|
||||
op_ret, op_errno, fd,
|
||||
xdata)
|
||||
self.stub_refs["open_cbk"] = stub
|
||||
dl.set_open_cbk(c_this, stub)
|
||||
if "readv_fop" in funcs:
|
||||
@OpReadv.fop_type
|
||||
def stub (frame, this, fd, size, offset, flags,
|
||||
xdata, s=self):
|
||||
return s.readv_fop (frame, this, fd, size,
|
||||
offset, flags, xdata)
|
||||
self.stub_refs["readv_fop"] = stub
|
||||
dl.set_readv_fop(c_this, stub)
|
||||
if "readv_cbk" in funcs:
|
||||
@OpReadv.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno,
|
||||
vector, count, stbuf, iobref, xdata,
|
||||
s=self):
|
||||
return s.readv_cbk (frame, cookie, this,
|
||||
op_ret, op_errno, vector,
|
||||
count, stbuf, iobref,
|
||||
xdata)
|
||||
self.stub_refs["readv_cbk"] = stub
|
||||
dl.set_readv_cbk(c_this, stub)
|
||||
if "writev_fop" in funcs:
|
||||
@OpWritev.fop_type
|
||||
def stub (frame, this, fd, vector, count,
|
||||
offset, flags, iobref, xdata, s=self):
|
||||
return s.writev_fop (frame, this, fd, vector,
|
||||
count, offset, flags,
|
||||
iobref, xdata)
|
||||
self.stub_refs["writev_fop"] = stub
|
||||
dl.set_writev_fop(c_this, stub)
|
||||
if "writev_cbk" in funcs:
|
||||
@OpWritev.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno,
|
||||
prebuf, postbuf, xdata, s=self):
|
||||
return s.writev_cbk (frame, cookie, this,
|
||||
op_ret, op_errno, prebuf,
|
||||
postbuf, xdata)
|
||||
self.stub_refs["writev_cbk"] = stub
|
||||
dl.set_writev_cbk(c_this, stub)
|
||||
if "opendir_fop" in funcs:
|
||||
@OpOpendir.fop_type
|
||||
def stub (frame, this, loc, fd, xdata, s=self):
|
||||
return s.opendir_fop (frame, this, loc, fd,
|
||||
xdata)
|
||||
self.stub_refs["opendir_fop"] = stub
|
||||
dl.set_opendir_fop(c_this, stub)
|
||||
if "opendir_cbk" in funcs:
|
||||
@OpOpendir.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno, fd,
|
||||
xdata, s=self):
|
||||
return s.opendir_cbk(frame, cookie, this,
|
||||
op_ret, op_errno, fd,
|
||||
xdata)
|
||||
self.stub_refs["opendir_cbk"] = stub
|
||||
dl.set_opendir_cbk(c_this, stub)
|
||||
if "readdir_fop" in funcs:
|
||||
@OpReaddir.fop_type
|
||||
def stub (frame, this, fd, size, offset, xdata, s=self):
|
||||
return s.readdir_fop (frame, this, fd, size,
|
||||
offset, xdata)
|
||||
self.stub_refs["readdir_fop"] = stub
|
||||
dl.set_readdir_fop(c_this, stub)
|
||||
if "readdir_cbk" in funcs:
|
||||
@OpReaddir.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno,
|
||||
entries, xdata, s=self):
|
||||
return s.readdir_cbk(frame, cookie, this,
|
||||
op_ret, op_errno, entries,
|
||||
xdata)
|
||||
self.stub_refs["readdir_cbk"] = stub
|
||||
dl.set_readdir_cbk(c_this, stub)
|
||||
if "readdirp_fop" in funcs:
|
||||
@OpReaddirp.fop_type
|
||||
def stub (frame, this, fd, size, offset, xdata, s=self):
|
||||
return s.readdirp_fop (frame, this, fd, size,
|
||||
offset, xdata)
|
||||
self.stub_refs["readdirp_fop"] = stub
|
||||
dl.set_readdirp_fop(c_this, stub)
|
||||
if "readdirp_cbk" in funcs:
|
||||
@OpReaddirp.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno,
|
||||
entries, xdata, s=self):
|
||||
return s.readdirp_cbk (frame, cookie, this,
|
||||
op_ret, op_errno,
|
||||
entries, xdata)
|
||||
self.stub_refs["readdirp_cbk"] = stub
|
||||
dl.set_readdirp_cbk(c_this, stub)
|
||||
if "stat_fop" in funcs:
|
||||
@OpStat.fop_type
|
||||
def stub (frame, this, loc, xdata, s=self):
|
||||
return s.stat_fop (frame, this, loc, xdata)
|
||||
self.stub_refs["stat_fop"] = stub
|
||||
dl.set_stat_fop(c_this, stub)
|
||||
if "stat_cbk" in funcs:
|
||||
@OpStat.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno, buf,
|
||||
xdata, s=self):
|
||||
return s.stat_cbk(frame, cookie, this, op_ret,
|
||||
op_errno, buf, xdata)
|
||||
self.stub_refs["stat_cbk"] = stub
|
||||
dl.set_stat_cbk(c_this, stub)
|
||||
if "fstat_fop" in funcs:
|
||||
@OpFstat.fop_type
|
||||
def stub (frame, this, fd, xdata, s=self):
|
||||
return s.fstat_fop (frame, this, fd, xdata)
|
||||
self.stub_refs["fstat_fop"] = stub
|
||||
dl.set_fstat_fop(c_this, stub)
|
||||
if "fstat_cbk" in funcs:
|
||||
@OpFstat.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno, buf,
|
||||
xdata, s=self):
|
||||
return s.fstat_cbk(frame, cookie, this, op_ret,
|
||||
op_errno, buf, xdata)
|
||||
self.stub_refs["fstat_cbk"] = stub
|
||||
dl.set_fstat_cbk(c_this, stub)
|
||||
if "statfs_fop" in funcs:
|
||||
@OpStatfs.fop_type
|
||||
def stub (frame, this, loc, xdata, s=self):
|
||||
return s.statfs_fop (frame, this, loc, xdata)
|
||||
self.stub_refs["statfs_fop"] = stub
|
||||
dl.set_statfs_fop(c_this, stub)
|
||||
if "statfs_cbk" in funcs:
|
||||
@OpStatfs.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno, buf,
|
||||
xdata, s=self):
|
||||
return s.statfs_cbk (frame, cookie, this,
|
||||
op_ret, op_errno, buf,
|
||||
xdata)
|
||||
self.stub_refs["statfs_cbk"] = stub
|
||||
dl.set_statfs_cbk(c_this, stub)
|
||||
if "setxattr_fop" in funcs:
|
||||
@OpSetxattr.fop_type
|
||||
def stub (frame, this, loc, dictionary, flags, xdata,
|
||||
s=self):
|
||||
return s.setxattr_fop (frame, this, loc,
|
||||
dictionary, flags,
|
||||
xdata)
|
||||
self.stub_refs["setxattr_fop"] = stub
|
||||
dl.set_setxattr_fop(c_this, stub)
|
||||
if "setxattr_cbk" in funcs:
|
||||
@OpSetxattr.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno, xdata,
|
||||
s=self):
|
||||
return s.setxattr_cbk(frame, cookie, this,
|
||||
op_ret, op_errno, xdata)
|
||||
self.stub_refs["setxattr_cbk"] = stub
|
||||
dl.set_setxattr_cbk(c_this, stub)
|
||||
if "getxattr_fop" in funcs:
|
||||
@OpGetxattr.fop_type
|
||||
def stub (frame, this, loc, name, xdata, s=self):
|
||||
return s.getxattr_fop (frame, this, loc, name,
|
||||
xdata)
|
||||
self.stub_refs["getxattr_fop"] = stub
|
||||
dl.set_getxattr_fop(c_this, stub)
|
||||
if "getxattr_cbk" in funcs:
|
||||
@OpGetxattr.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno,
|
||||
dictionary, xdata, s=self):
|
||||
return s.getxattr_cbk(frame, cookie, this,
|
||||
op_ret, op_errno,
|
||||
dictionary, xdata)
|
||||
self.stub_refs["getxattr_cbk"] = stub
|
||||
dl.set_getxattr_cbk(c_this, stub)
|
||||
if "fsetxattr_fop" in funcs:
|
||||
@OpFsetxattr.fop_type
|
||||
def stub (frame, this, fd, dictionary, flags, xdata,
|
||||
s=self):
|
||||
return s.fsetxattr_fop (frame, this, fd,
|
||||
dictionary, flags,
|
||||
xdata)
|
||||
self.stub_refs["fsetxattr_fop"] = stub
|
||||
dl.set_fsetxattr_fop(c_this, stub)
|
||||
if "fsetxattr_cbk" in funcs:
|
||||
@OpFsetxattr.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno, xdata,
|
||||
s=self):
|
||||
return s.fsetxattr_cbk(frame, cookie, this,
|
||||
op_ret, op_errno, xdata)
|
||||
self.stub_refs["fsetxattr_cbk"] = stub
|
||||
dl.set_fsetxattr_cbk(c_this, stub)
|
||||
if "fgetxattr_fop" in funcs:
|
||||
@OpFgetxattr.fop_type
|
||||
def stub (frame, this, fd, name, xdata, s=self):
|
||||
return s.fgetxattr_fop (frame, this, fd, name,
|
||||
xdata)
|
||||
self.stub_refs["fgetxattr_fop"] = stub
|
||||
dl.set_fgetxattr_fop(c_this, stub)
|
||||
if "fgetxattr_cbk" in funcs:
|
||||
@OpFgetxattr.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno,
|
||||
dictionary, xdata, s=self):
|
||||
return s.fgetxattr_cbk(frame, cookie, this,
|
||||
op_ret, op_errno,
|
||||
dictionary, xdata)
|
||||
self.stub_refs["fgetxattr_cbk"] = stub
|
||||
dl.set_fgetxattr_cbk(c_this, stub)
|
||||
if "removexattr_fop" in funcs:
|
||||
@OpRemovexattr.fop_type
|
||||
def stub (frame, this, loc, name, xdata, s=self):
|
||||
return s.removexattr_fop (frame, this, loc,
|
||||
name, xdata)
|
||||
self.stub_refs["removexattr_fop"] = stub
|
||||
dl.set_removexattr_fop(c_this, stub)
|
||||
if "removexattr_cbk" in funcs:
|
||||
@OpRemovexattr.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno,
|
||||
xdata, s=self):
|
||||
return s.removexattr_cbk(frame, cookie, this,
|
||||
op_ret, op_errno,
|
||||
xdata)
|
||||
self.stub_refs["removexattr_cbk"] = stub
|
||||
dl.set_removexattr_cbk(c_this, stub)
|
||||
if "fremovexattr_fop" in funcs:
|
||||
@OpFremovexattr.fop_type
|
||||
def stub (frame, this, fd, name, xdata, s=self):
|
||||
return s.fremovexattr_fop (frame, this, fd,
|
||||
name, xdata)
|
||||
self.stub_refs["fremovexattr_fop"] = stub
|
||||
dl.set_fremovexattr_fop(c_this, stub)
|
||||
if "fremovexattr_cbk" in funcs:
|
||||
@OpFremovexattr.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno,
|
||||
xdata, s=self):
|
||||
return s.fremovexattr_cbk(frame, cookie, this,
|
||||
op_ret, op_errno,
|
||||
xdata)
|
||||
self.stub_refs["fremovexattr_cbk"] = stub
|
||||
dl.set_fremovexattr_cbk(c_this, stub)
|
||||
if "link_fop" in funcs:
|
||||
@OpLink.fop_type
|
||||
def stub (frame, this, oldloc, newloc,
|
||||
xdata, s=self):
|
||||
return s.link_fop (frame, this, oldloc,
|
||||
newloc, xdata)
|
||||
self.stub_refs["link_fop"] = stub
|
||||
dl.set_link_fop(c_this, stub)
|
||||
if "link_cbk" in funcs:
|
||||
@OpLink.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno,
|
||||
inode, buf, preparent, postparent, xdata,
|
||||
s=self):
|
||||
return s.link_cbk (frame, cookie, this,
|
||||
op_ret, op_errno, inode,
|
||||
buf, preparent,
|
||||
postparent, xdata)
|
||||
self.stub_refs["link_cbk"] = stub
|
||||
dl.set_link_cbk(c_this, stub)
|
||||
if "symlink_fop" in funcs:
|
||||
@OpSymlink.fop_type
|
||||
def stub (frame, this, linkname, loc,
|
||||
umask, xdata, s=self):
|
||||
return s.symlink_fop (frame, this, linkname,
|
||||
loc, umask, xdata)
|
||||
self.stub_refs["symlink_fop"] = stub
|
||||
dl.set_symlink_fop(c_this, stub)
|
||||
if "symlink_cbk" in funcs:
|
||||
@OpSymlink.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno,
|
||||
inode, buf, preparent, postparent, xdata,
|
||||
s=self):
|
||||
return s.symlink_cbk (frame, cookie, this,
|
||||
op_ret, op_errno, inode,
|
||||
buf, preparent,
|
||||
postparent, xdata)
|
||||
self.stub_refs["symlink_cbk"] = stub
|
||||
dl.set_symlink_cbk(c_this, stub)
|
||||
if "unlink_fop" in funcs:
|
||||
@OpUnlink.fop_type
|
||||
def stub (frame, this, loc, xflags,
|
||||
xdata, s=self):
|
||||
return s.unlink_fop (frame, this, loc,
|
||||
xflags, xdata)
|
||||
self.stub_refs["unlink_fop"] = stub
|
||||
dl.set_unlink_fop(c_this, stub)
|
||||
if "unlink_cbk" in funcs:
|
||||
@OpUnlink.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno,
|
||||
preparent, postparent, xdata, s=self):
|
||||
return s.unlink_cbk (frame, cookie, this,
|
||||
op_ret, op_errno,
|
||||
preparent, postparent,
|
||||
xdata)
|
||||
self.stub_refs["unlink_cbk"] = stub
|
||||
dl.set_unlink_cbk(c_this, stub)
|
||||
if "readlink_fop" in funcs:
|
||||
@OpReadlink.fop_type
|
||||
def stub (frame, this, loc, size,
|
||||
xdata, s=self):
|
||||
return s.readlink_fop (frame, this, loc,
|
||||
size, xdata)
|
||||
self.stub_refs["readlink_fop"] = stub
|
||||
dl.set_readlink_fop(c_this, stub)
|
||||
if "readlink_cbk" in funcs:
|
||||
@OpReadlink.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno,
|
||||
path, buf, xdata, s=self):
|
||||
return s.readlink_cbk (frame, cookie, this,
|
||||
op_ret, op_errno,
|
||||
path, buf, xdata)
|
||||
self.stub_refs["readlink_cbk"] = stub
|
||||
dl.set_readlink_cbk(c_this, stub)
|
||||
if "mkdir_fop" in funcs:
|
||||
@OpMkdir.fop_type
|
||||
def stub (frame, this, loc, mode, umask, xdata,
|
||||
s=self):
|
||||
return s.mkdir_fop (frame, this, loc, mode,
|
||||
umask, xdata)
|
||||
self.stub_refs["mkdir_fop"] = stub
|
||||
dl.set_mkdir_fop(c_this, stub)
|
||||
if "mkdir_cbk" in funcs:
|
||||
@OpMkdir.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno, inode,
|
||||
buf, preparent, postparent, xdata, s=self):
|
||||
return s.mkdir_cbk (frame, cookie, this,
|
||||
op_ret, op_errno, inode,
|
||||
buf, preparent,
|
||||
postparent, xdata)
|
||||
self.stub_refs["mkdir_cbk"] = stub
|
||||
dl.set_mkdir_cbk(c_this, stub)
|
||||
if "rmdir_fop" in funcs:
|
||||
@OpRmdir.fop_type
|
||||
def stub (frame, this, loc, xflags,
|
||||
xdata, s=self):
|
||||
return s.rmdir_fop (frame, this, loc,
|
||||
xflags, xdata)
|
||||
self.stub_refs["rmdir_fop"] = stub
|
||||
dl.set_rmdir_fop(c_this, stub)
|
||||
if "rmdir_cbk" in funcs:
|
||||
@OpRmdir.cbk_type
|
||||
def stub (frame, cookie, this, op_ret, op_errno,
|
||||
preparent, postparent, xdata, s=self):
|
||||
return s.rmdir_cbk (frame, cookie, this,
|
||||
op_ret, op_errno,
|
||||
preparent, postparent,
|
||||
xdata)
|
||||
self.stub_refs["rmdir_cbk"] = stub
|
||||
dl.set_rmdir_cbk(c_this, stub)
|
@ -1,24 +0,0 @@
|
||||
from distutils.core import setup
|
||||
|
||||
DESC = """GlusterFS is a distributed file-system capable of scaling to
|
||||
several petabytes. It aggregates various storage bricks over Infiniband
|
||||
RDMA or TCP/IP interconnect into one large parallel network file system.
|
||||
GlusterFS is one of the most sophisticated file systems in terms of
|
||||
features and extensibility. It borrows a powerful concept called
|
||||
Translators from GNU Hurd kernel. Much of the code in GlusterFS is in
|
||||
user space and easily manageable.
|
||||
|
||||
This package contains Glupy, the Python translator interface for GlusterFS."""
|
||||
|
||||
setup(
|
||||
name='glusterfs-glupy',
|
||||
version='@PACKAGE_VERSION@',
|
||||
description='Glupy is the Python translator interface for GlusterFS',
|
||||
long_description=DESC,
|
||||
author='Gluster Community',
|
||||
author_email='gluster-devel@gluster.org',
|
||||
license='LGPLv3',
|
||||
url='http://gluster.org/',
|
||||
package_dir={'gluster':''},
|
||||
packages=['gluster']
|
||||
)
|
@ -1,3 +0,0 @@
|
||||
SUBDIRS = src
|
||||
|
||||
CLEANFILES =
|
@ -1,16 +0,0 @@
|
||||
xlator_LTLIBRARIES = symlink-cache.la
|
||||
xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/testing/performance
|
||||
|
||||
symlink_cache_la_LDFLAGS = -module $(GF_XLATOR_DEFAULT_LDFLAGS)
|
||||
|
||||
symlink_cache_la_SOURCES = symlink-cache.c
|
||||
symlink_cache_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la
|
||||
|
||||
noinst_HEADERS = symlink-cache-messages.h
|
||||
|
||||
AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \
|
||||
-I$(top_srcdir)/rpc/xdr/src -I$(top_builddir)/rpc/xdr/src
|
||||
|
||||
AM_CFLAGS = -Wall $(GF_CFLAGS)
|
||||
|
||||
CLEANFILES =
|
@ -1,30 +0,0 @@
|
||||
/*Copyright (c) 2015 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 _SYMLINK_CACHE_MESSAGES_H_
|
||||
#define _SYMLINK_CACHE_MESSAGES_H_
|
||||
|
||||
#include <glusterfs/glfs-message-id.h>
|
||||
|
||||
/* To add new message IDs, append new identifiers at the end of the list.
|
||||
*
|
||||
* Never remove a message ID. If it's not used anymore, you can rename it or
|
||||
* leave it as it is, but not delete it. This is to prevent reutilization of
|
||||
* IDs by other messages.
|
||||
*
|
||||
* The component name must match one of the entries defined in
|
||||
* glfs-message-id.h.
|
||||
*/
|
||||
|
||||
GLFS_MSGID(SYMLINK_CACHE, SYMLINK_CACHE_MSG_XLATOR_CHILD_MISCONFIGURED,
|
||||
SYMLINK_CACHE_MSG_VOL_MISCONFIGURED, SYMLINK_CACHE_MSG_NO_MEMORY,
|
||||
SYMLINK_CACHE_MSG_DICT_GET_FAILED,
|
||||
SYMLINK_CACHE_MSG_DICT_SET_FAILED);
|
||||
|
||||
#endif /* _SYMLINK_CACHE_MESSAGES_H_ */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user