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:
Amar Tumballi 2018-12-06 12:29:25 +05:30
parent af7e957b49
commit 8293d21280
113 changed files with 0 additions and 37439 deletions

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -1,9 +0,0 @@
fops
cbks
class_methods
dht_methods
tier_methods
options
mem_acct_init
reconfigure
dumpops

View File

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

View File

@ -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;
}

View File

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

View File

@ -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_ */

View File

@ -1,3 +0,0 @@
SUBDIRS = rot-13 crypt
CLEANFILES =

View File

@ -1,3 +0,0 @@
SUBDIRS = src
CLEANFILES =

View File

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

View File

@ -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:
*/

View File

@ -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:
*/

View File

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

View File

@ -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:
*/

View File

@ -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:
*/

View File

@ -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:
*/

View File

@ -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:
*/

View File

@ -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__ */

View File

@ -1,3 +0,0 @@
SUBDIRS = src
CLEANFILES =

View File

@ -1,3 +0,0 @@
SUBDIRS = jbr-client jbr-server fdl dht2 posix2
CLEANFILES =

View File

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

View File

@ -1,3 +0,0 @@
SUBDIRS = dht2-client dht2-server
CLEANFILES =

View File

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

View File

@ -1,3 +0,0 @@
# DHT2 TODO list
<Items will be added as code is pulled into the repository>

View File

@ -1,3 +0,0 @@
SUBDIRS = src
CLEANFILES =

View File

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

View File

@ -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}},
};

View File

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

View File

@ -1,3 +0,0 @@
SUBDIRS = src
CLEANFILES =

View File

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

View File

@ -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}},
};

View File

@ -1,3 +0,0 @@
SUBDIRS = src
CLEANFILES =

View File

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

View File

@ -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;
}

View File

@ -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,
};

View File

@ -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_ */

View File

@ -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 */")

View File

@ -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])

View File

@ -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 */")

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -1,3 +0,0 @@
SUBDIRS = src
CLEANFILES =

View File

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

View File

@ -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;
}

View File

@ -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])

View File

@ -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_ */

View File

@ -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) ("" x "")
/*
* 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}},
};

View File

@ -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_ */

View File

@ -1,3 +0,0 @@
SUBDIRS = src
CLEANFILES =

View File

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

View File

@ -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;
}

View File

@ -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])

View File

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

View File

@ -1,3 +0,0 @@
SUBDIRS = common mds ds
CLEANFILES =

View File

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

View File

@ -1,3 +0,0 @@
# POSIX2 TODO List
<Items will be added as code is pulled into the repository>

View File

@ -1,3 +0,0 @@
SUBDIRS = src
CLEANFILES =

View File

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

View File

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

View File

@ -1,3 +0,0 @@
SUBDIRS = src
CLEANFILES =

View File

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

View File

@ -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}},
};

View File

@ -1,3 +0,0 @@
SUBDIRS = src
CLEANFILES =

View File

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

View File

@ -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}},
};

View File

@ -1,3 +0,0 @@
SUBDIRS = src
CLEANFILES =

View File

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

View File

@ -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 */

View File

@ -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;
}

View File

@ -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(&current_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, &current_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, &current_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

View File

@ -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_ */

View File

@ -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(&current_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(&current_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(&current_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;
}

View File

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

View File

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

View File

@ -1,3 +0,0 @@
SUBDIRS = src examples
CLEANFILES =

View File

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

View File

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

View File

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

View File

@ -1,5 +0,0 @@
xlatordir = $(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator/features
glupyexamplesdir = $(xlatordir)/glupy
glupyexamples_PYTHON = negative.py helloworld.py debug-trace.py

View File

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

View File

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

View File

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

View File

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

View File

@ -1,2 +0,0 @@
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)

File diff suppressed because it is too large Load Diff

View File

@ -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__ */

View File

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

View File

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

View File

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

View File

@ -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']
)

View File

@ -1,3 +0,0 @@
SUBDIRS = src
CLEANFILES =

View File

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

View File

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