diff options
Diffstat (limited to 'libglusterfs/src')
49 files changed, 4624 insertions, 346 deletions
diff --git a/libglusterfs/src/Makefile.am b/libglusterfs/src/Makefile.am index d0a617e7b..907399ae6 100644 --- a/libglusterfs/src/Makefile.am +++ b/libglusterfs/src/Makefile.am @@ -4,7 +4,7 @@ libglusterfs_la_CFLAGS = -Wall $(GF_CFLAGS) \ libglusterfs_la_CPPFLAGS = $(GF_CPPFLAGS) -D__USE_FILE_OFFSET64 \ -DXLATORDIR=\"$(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator\" \ - -I$(CONTRIBDIR)/rbtree + -I$(top_srcdir)/rpc/rpc-lib/src/ -I$(CONTRIBDIR)/rbtree libglusterfs_la_LIBADD = @LEXLIB@ @@ -15,42 +15,42 @@ CONTRIB_BUILDDIR = $(top_builddir)/contrib libglusterfs_la_SOURCES = dict.c xlator.c logging.c \ hashfn.c defaults.c common-utils.c timer.c inode.c call-stub.c \ compat.c fd.c compat-errno.c event.c mem-pool.c gf-dirent.c syscall.c \ - iobuf.c globals.c statedump.c stack.c checksum.c daemon.c \ - $(CONTRIBDIR)/rbtree/rb.c rbthash.c latency.c \ + iobuf.c globals.c statedump.c stack.c checksum.c daemon.c timespec.c \ + $(CONTRIBDIR)/rbtree/rb.c rbthash.c store.c latency.c \ graph.c $(CONTRIBDIR)/uuid/clear.c $(CONTRIBDIR)/uuid/copy.c \ $(CONTRIBDIR)/uuid/gen_uuid.c $(CONTRIBDIR)/uuid/pack.c \ $(CONTRIBDIR)/uuid/parse.c $(CONTRIBDIR)/uuid/unparse.c \ $(CONTRIBDIR)/uuid/uuid_time.c $(CONTRIBDIR)/uuid/compare.c \ $(CONTRIBDIR)/uuid/isnull.c $(CONTRIBDIR)/uuid/unpack.c syncop.c \ graph-print.c trie.c run.c options.c fd-lk.c circ-buff.c \ - event-history.c gidcache.c ctx.c \ + event-history.c gidcache.c ctx.c client_t.c event-poll.c event-epoll.c \ $(CONTRIBDIR)/libgen/basename_r.c $(CONTRIBDIR)/libgen/dirname_r.c \ - $(CONTRIBDIR)/stdlib/gf_mkostemp.c \ - event-poll.c event-epoll.c + $(CONTRIBDIR)/stdlib/gf_mkostemp.c -nodist_libglusterfs_la_SOURCES = y.tab.c graph.lex.c +nodist_libglusterfs_la_SOURCES = y.tab.c graph.lex.c gf-error-codes.h BUILT_SOURCES = graph.lex.c -noinst_HEADERS = common-utils.h defaults.h dict.h glusterfs.h hashfn.h \ +noinst_HEADERS = common-utils.h defaults.h dict.h glusterfs.h hashfn.h timespec.h \ logging.h xlator.h stack.h timer.h list.h inode.h call-stub.h compat.h \ fd.h revision.h compat-errno.h event.h mem-pool.h byte-order.h \ gf-dirent.h locking.h syscall.h iobuf.h globals.h statedump.h \ - checksum.h daemon.h $(CONTRIBDIR)/rbtree/rb.h \ + checksum.h daemon.h $(CONTRIBDIR)/rbtree/rb.h store.h\ rbthash.h iatt.h latency.h mem-types.h $(CONTRIBDIR)/uuid/uuidd.h \ $(CONTRIBDIR)/uuid/uuid.h $(CONTRIBDIR)/uuid/uuidP.h \ - $(CONTRIB_BUILDDIR)/uuid/uuid_types.h syncop.h graph-utils.h trie.h run.h \ - options.h lkowner.h fd-lk.h circ-buff.h event-history.h gidcache.h + $(CONTRIB_BUILDDIR)/uuid/uuid_types.h syncop.h graph-utils.h trie.h \ + run.h options.h lkowner.h fd-lk.h circ-buff.h event-history.h \ + gidcache.h client_t.h glusterfs-acl.h EXTRA_DIST = graph.l graph.y graph.lex.c: graph.l y.tab.h - $(LEX) -t $(srcdir)/graph.l > $@ + $(LEX) -Pgraphyy -t $(srcdir)/graph.l > $@ y.tab.c: y.tab.h y.tab.h: graph.y - $(YACC) -d $(srcdir)/graph.y + $(YACC) -p graphyy -d $(srcdir)/graph.y CLEANFILES = graph.lex.c y.tab.c y.tab.h CONFIG_CLEAN_FILES = $(CONTRIB_BUILDDIR)/uuid/uuid_types.h diff --git a/libglusterfs/src/call-stub.c b/libglusterfs/src/call-stub.c index bd81c4ed2..ac79cf071 100644 --- a/libglusterfs/src/call-stub.c +++ b/libglusterfs/src/call-stub.c @@ -2130,6 +2130,172 @@ out: return stub; } +call_stub_t * +fop_fallocate_cbk_stub(call_frame_t *frame, fop_fallocate_cbk_t fn, + int32_t op_ret, int32_t op_errno, + struct iatt *statpre, struct iatt *statpost, + dict_t *xdata) +{ + call_stub_t *stub = NULL; + + GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + + stub = stub_new (frame, 0, GF_FOP_FALLOCATE); + GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + + stub->fn_cbk.fallocate = fn; + + stub->args_cbk.op_ret = op_ret; + stub->args_cbk.op_errno = op_errno; + + if (statpre) + stub->args_cbk.prestat = *statpre; + if (statpost) + stub->args_cbk.poststat = *statpost; + if (xdata) + stub->args_cbk.xdata = dict_ref (xdata); +out: + return stub; +} + +call_stub_t * +fop_fallocate_stub(call_frame_t *frame, fop_fallocate_t fn, fd_t *fd, + int32_t mode, off_t offset, size_t len, dict_t *xdata) +{ + call_stub_t *stub = NULL; + + GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + GF_VALIDATE_OR_GOTO ("call-stub", fn, out); + + stub = stub_new (frame, 1, GF_FOP_FALLOCATE); + GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + + stub->fn.fallocate = fn; + + if (fd) + stub->args.fd = fd_ref (fd); + + stub->args.flags = mode; + stub->args.offset = offset; + stub->args.size = len; + + if (xdata) + stub->args.xdata = dict_ref (xdata); +out: + return stub; + +} + +call_stub_t * +fop_discard_cbk_stub(call_frame_t *frame, fop_discard_cbk_t fn, + int32_t op_ret, int32_t op_errno, + struct iatt *statpre, struct iatt *statpost, + dict_t *xdata) +{ + call_stub_t *stub = NULL; + + GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + + stub = stub_new (frame, 0, GF_FOP_DISCARD); + GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + + stub->fn_cbk.discard = fn; + + stub->args_cbk.op_ret = op_ret; + stub->args_cbk.op_errno = op_errno; + + if (statpre) + stub->args_cbk.prestat = *statpre; + if (statpost) + stub->args_cbk.poststat = *statpost; + if (xdata) + stub->args_cbk.xdata = dict_ref (xdata); +out: + return stub; +} + +call_stub_t * +fop_discard_stub(call_frame_t *frame, fop_discard_t fn, fd_t *fd, + off_t offset, size_t len, dict_t *xdata) +{ + call_stub_t *stub = NULL; + + GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + GF_VALIDATE_OR_GOTO ("call-stub", fn, out); + + stub = stub_new (frame, 1, GF_FOP_DISCARD); + GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + + stub->fn.discard = fn; + + if (fd) + stub->args.fd = fd_ref (fd); + + stub->args.offset = offset; + stub->args.size = len; + + if (xdata) + stub->args.xdata = dict_ref (xdata); +out: + return stub; + +} + +call_stub_t * +fop_zerofill_cbk_stub(call_frame_t *frame, fop_zerofill_cbk_t fn, + int32_t op_ret, int32_t op_errno, + struct iatt *statpre, struct iatt *statpost, + dict_t *xdata) +{ + call_stub_t *stub = NULL; + + GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + + stub = stub_new (frame, 0, GF_FOP_ZEROFILL); + GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + + stub->fn_cbk.zerofill = fn; + + stub->args_cbk.op_ret = op_ret; + stub->args_cbk.op_errno = op_errno; + + if (statpre) + stub->args_cbk.prestat = *statpre; + if (statpost) + stub->args_cbk.poststat = *statpost; + if (xdata) + stub->args_cbk.xdata = dict_ref (xdata); +out: + return stub; +} + +call_stub_t * +fop_zerofill_stub(call_frame_t *frame, fop_zerofill_t fn, fd_t *fd, + off_t offset, size_t len, dict_t *xdata) +{ + call_stub_t *stub = NULL; + + GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + GF_VALIDATE_OR_GOTO ("call-stub", fn, out); + + stub = stub_new (frame, 1, GF_FOP_ZEROFILL); + GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + + stub->fn.zerofill = fn; + + if (fd) + stub->args.fd = fd_ref (fd); + + stub->args.offset = offset; + stub->args.size = len; + + if (xdata) + stub->args.xdata = dict_ref (xdata); +out: + return stub; + +} + static void call_resume_wind (call_stub_t *stub) @@ -2347,6 +2513,23 @@ call_resume_wind (call_stub_t *stub) stub->args.fd, &stub->args.stat, stub->args.valid, stub->args.xdata); break; + case GF_FOP_FALLOCATE: + stub->fn.fallocate(stub->frame, stub->frame->this, + stub->args.fd, stub->args.flags, + stub->args.offset, stub->args.size, + stub->args.xdata); + break; + case GF_FOP_DISCARD: + stub->fn.discard(stub->frame, stub->frame->this, + stub->args.fd, stub->args.offset, + stub->args.size, stub->args.xdata); + break; + case GF_FOP_ZEROFILL: + stub->fn.zerofill(stub->frame, stub->frame->this, + stub->args.fd, stub->args.offset, + stub->args.size, stub->args.xdata); + break; + default: gf_log_callingfn ("call-stub", GF_LOG_ERROR, "Invalid value of FOP (%d)", @@ -2541,6 +2724,19 @@ call_resume_unwind (call_stub_t *stub) STUB_UNWIND (stub, fsetattr, &stub->args_cbk.prestat, &stub->args_cbk.poststat, stub->args_cbk.xdata); break; + case GF_FOP_FALLOCATE: + STUB_UNWIND(stub, fallocate, &stub->args_cbk.prestat, + &stub->args_cbk.poststat, stub->args_cbk.xdata); + break; + case GF_FOP_DISCARD: + STUB_UNWIND(stub, discard, &stub->args_cbk.prestat, + &stub->args_cbk.poststat, stub->args_cbk.xdata); + break; + case GF_FOP_ZEROFILL: + STUB_UNWIND(stub, zerofill, &stub->args_cbk.prestat, + &stub->args_cbk.poststat, stub->args_cbk.xdata); + break; + default: gf_log_callingfn ("call-stub", GF_LOG_ERROR, "Invalid value of FOP (%d)", diff --git a/libglusterfs/src/call-stub.h b/libglusterfs/src/call-stub.h index 335111835..45bef8044 100644 --- a/libglusterfs/src/call-stub.h +++ b/libglusterfs/src/call-stub.h @@ -69,6 +69,9 @@ typedef struct { fop_fxattrop_t fxattrop; fop_setattr_t setattr; fop_fsetattr_t fsetattr; + fop_fallocate_t fallocate; + fop_discard_t discard; + fop_zerofill_t zerofill; } fn; union { @@ -113,6 +116,9 @@ typedef struct { fop_fxattrop_cbk_t fxattrop; fop_setattr_cbk_t setattr; fop_fsetattr_cbk_t fsetattr; + fop_fallocate_cbk_t fallocate; + fop_discard_cbk_t discard; + fop_zerofill_cbk_t zerofill; } fn_cbk; struct { @@ -713,6 +719,48 @@ fop_fsetattr_cbk_stub (call_frame_t *frame, struct iatt *statpre, struct iatt *statpost, dict_t *xdata); +call_stub_t * +fop_fallocate_stub(call_frame_t *frame, + fop_fallocate_t fn, + fd_t *fd, + int32_t mode, off_t offset, + size_t len, dict_t *xdata); + +call_stub_t * +fop_fallocate_cbk_stub(call_frame_t *frame, + fop_fallocate_cbk_t fn, + int32_t op_ret, int32_t op_errno, + struct iatt *statpre, struct iatt *statpost, + dict_t *xdata); + +call_stub_t * +fop_discard_stub(call_frame_t *frame, + fop_discard_t fn, + fd_t *fd, + off_t offset, + size_t len, dict_t *xdata); + +call_stub_t * +fop_discard_cbk_stub(call_frame_t *frame, + fop_discard_cbk_t fn, + int32_t op_ret, int32_t op_errno, + struct iatt *statpre, struct iatt *statpost, + dict_t *xdata); + +call_stub_t * +fop_zerofill_stub(call_frame_t *frame, + fop_zerofill_t fn, + fd_t *fd, + off_t offset, + size_t len, dict_t *xdata); + +call_stub_t * +fop_zerofill_cbk_stub(call_frame_t *frame, + fop_zerofill_cbk_t fn, + int32_t op_ret, int32_t op_errno, + struct iatt *statpre, struct iatt *statpost, + dict_t *xdata); + void call_resume (call_stub_t *stub); void call_stub_destroy (call_stub_t *stub); void call_unwind_error (call_stub_t *stub, int op_ret, int op_errno); diff --git a/libglusterfs/src/circ-buff.c b/libglusterfs/src/circ-buff.c index 65bbd5d45..484ce7dc9 100644 --- a/libglusterfs/src/circ-buff.c +++ b/libglusterfs/src/circ-buff.c @@ -10,6 +10,17 @@ #include "circ-buff.h" +void +cb_destroy_data (circular_buffer_t *cb, + void (*destroy_buffer_data) (void *data)) +{ + if (destroy_buffer_data) + destroy_buffer_data (cb->data); + GF_FREE (cb->data); + return; +} + + /* hold lock while calling this function */ int __cb_add_entry_buffer (buffer_t *buffer, void *item) @@ -29,7 +40,8 @@ __cb_add_entry_buffer (buffer_t *buffer, void *item) if (buffer->cb[buffer->w_index]) { ptr = buffer->cb[buffer->w_index]; if (ptr->data) { - GF_FREE (ptr->data); + cb_destroy_data (ptr, + buffer->destroy_buffer_data); ptr->data = NULL; GF_FREE (ptr); } @@ -50,7 +62,7 @@ __cb_add_entry_buffer (buffer_t *buffer, void *item) gf_log_callingfn ("", GF_LOG_WARNING, "getting time of" "the day failed"); buffer->w_index++; - buffer->w_index %= buffer->size_buffer - 1; + buffer->w_index %= buffer->size_buffer; //used_buffer size cannot be greater than the total buffer size if (buffer->used_len < buffer->size_buffer) @@ -90,22 +102,35 @@ void cb_buffer_dump (buffer_t *buffer, void *data, int (fn) (circular_buffer_t *buffer, void *data)) { - int i = 0; + int index = 0; circular_buffer_t *entry = NULL; int entries = 0; + int ul = 0; + int w_ind = 0; + int size_buff = 0; + int i = 0; + + ul = buffer->used_len; + w_ind = buffer->w_index; + size_buff = buffer->size_buffer; pthread_mutex_lock (&buffer->lock); { if (buffer->use_once == _gf_false) { - for (i = (buffer->w_index - 1) ; entries < - buffer->used_len ; entries++) { - entry = buffer->cb[i]; + index = (size_buff + (w_ind - ul))%size_buff; + for (entries = 0; entries < buffer->used_len; + entries++) { + entry = buffer->cb[index]; if (entry) fn (entry, data); - if (0 == i) - i = buffer->used_len - 1; else - i = (i - 1) % (buffer->used_len - 1); + gf_log_callingfn ("", GF_LOG_WARNING, + "Null entry in " + "circular buffer at " + "index %d.", index); + + index++; + index %= buffer->size_buffer; } } else { for (i = 0; i < buffer->used_len ; i++) { @@ -118,7 +143,8 @@ cb_buffer_dump (buffer_t *buffer, void *data, } buffer_t * -cb_buffer_new (size_t buffer_size, gf_boolean_t use_once) +cb_buffer_new (size_t buffer_size, gf_boolean_t use_once, + void (*destroy_buffer_data) (void *data)) { buffer_t *buffer = NULL; @@ -144,6 +170,7 @@ cb_buffer_new (size_t buffer_size, gf_boolean_t use_once) buffer->size_buffer = buffer_size; buffer->use_once = use_once; buffer->used_len = 0; + buffer->destroy_buffer_data = destroy_buffer_data; pthread_mutex_init (&buffer->lock, NULL); out: @@ -153,12 +180,18 @@ out: void cb_buffer_destroy (buffer_t *buffer) { - int i = 0; - + int i = 0; + circular_buffer_t *ptr = NULL; if (buffer) { if (buffer->cb) { for (i = 0; i < buffer->used_len ; i++) { - GF_FREE (buffer->cb[i]); + ptr = buffer->cb[i]; + if (ptr->data) { + cb_destroy_data (ptr, + buffer->destroy_buffer_data); + ptr->data = NULL; + GF_FREE (ptr); + } } GF_FREE (buffer->cb); } diff --git a/libglusterfs/src/circ-buff.h b/libglusterfs/src/circ-buff.h index 5b5acc387..e3459f5e3 100644 --- a/libglusterfs/src/circ-buff.h +++ b/libglusterfs/src/circ-buff.h @@ -38,7 +38,7 @@ struct _buffer { /* indicates the amount of circular buffer used. */ circular_buffer_t **cb; - + void (*destroy_buffer_data) (void *data); pthread_mutex_t lock; }; @@ -51,7 +51,8 @@ void cb_buffer_show (buffer_t *buffer); buffer_t * -cb_buffer_new (size_t buffer_size,gf_boolean_t use_buffer_once); +cb_buffer_new (size_t buffer_size,gf_boolean_t use_buffer_once, + void (*destroy_data) (void *data)); void cb_buffer_destroy (buffer_t *buffer); diff --git a/libglusterfs/src/client_t.c b/libglusterfs/src/client_t.c new file mode 100644 index 000000000..06447dc5d --- /dev/null +++ b/libglusterfs/src/client_t.c @@ -0,0 +1,890 @@ +/* + 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.h" +#include "dict.h" +#include "statedump.h" +#include "client_t.h" +#include "list.h" +#include "rpcsvc.h" + + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + + +static int +gf_client_chain_client_entries (cliententry_t *entries, uint32_t startidx, + uint32_t endcount) +{ + uint32_t i = 0; + + if (!entries) { + gf_log_callingfn ("client_t", GF_LOG_WARNING, "!entries"); + return -1; + } + + /* Chain only till the second to last entry because we want to + * ensure that the last entry has GF_CLIENTTABLE_END. + */ + for (i = startidx; i < (endcount - 1); i++) + entries[i].next_free = i + 1; + + /* i has already been incremented upto the last entry. */ + entries[i].next_free = GF_CLIENTTABLE_END; + + return 0; +} + + +static int +gf_client_clienttable_expand (clienttable_t *clienttable, uint32_t nr) +{ + cliententry_t *oldclients = NULL; + uint32_t oldmax_clients = -1; + int ret = -1; + + if (clienttable == NULL || nr < 0) { + gf_log_callingfn ("client_t", GF_LOG_ERROR, "invalid argument"); + ret = EINVAL; + goto out; + } + + /* expand size by power-of-two... + this originally came from .../xlators/protocol/server/src/server.c + where it was not commented */ + nr /= (1024 / sizeof (cliententry_t)); + nr = gf_roundup_next_power_of_two (nr + 1); + nr *= (1024 / sizeof (cliententry_t)); + + oldclients = clienttable->cliententries; + oldmax_clients = clienttable->max_clients; + + clienttable->cliententries = GF_CALLOC (nr, sizeof (cliententry_t), + gf_common_mt_cliententry_t); + if (!clienttable->cliententries) { + ret = ENOMEM; + goto out; + } + clienttable->max_clients = nr; + + if (oldclients) { + uint32_t cpy = oldmax_clients * sizeof (cliententry_t); + memcpy (clienttable->cliententries, oldclients, cpy); + } + + gf_client_chain_client_entries (clienttable->cliententries, oldmax_clients, + clienttable->max_clients); + + /* Now that expansion is done, we must update the client list + * head pointer so that the client allocation functions can continue + * using the expanded table. + */ + clienttable->first_free = oldmax_clients; + GF_FREE (oldclients); + ret = 0; +out: + return ret; +} + + +clienttable_t * +gf_clienttable_alloc (void) +{ + clienttable_t *clienttable = NULL; + + clienttable = + GF_CALLOC (1, sizeof (clienttable_t), gf_common_mt_clienttable_t); + if (!clienttable) + return NULL; + + LOCK_INIT (&clienttable->lock); + gf_client_clienttable_expand (clienttable, GF_CLIENTTABLE_INITIAL_SIZE); + return clienttable; +} + + +void +gf_client_clienttable_destroy (clienttable_t *clienttable) +{ + client_t *client = NULL; + cliententry_t *cliententries = NULL; + uint32_t client_count = 0; + int32_t i = 0; + + if (!clienttable) { + gf_log_callingfn ("client_t", GF_LOG_WARNING, "!clienttable"); + return; + } + + LOCK (&clienttable->lock); + { + client_count = clienttable->max_clients; + clienttable->max_clients = 0; + cliententries = clienttable->cliententries; + clienttable->cliententries = NULL; + } + UNLOCK (&clienttable->lock); + + if (cliententries != NULL) { + for (i = 0; i < client_count; i++) { + client = cliententries[i].client; + if (client != NULL) { + gf_client_unref (client); + } + } + + GF_FREE (cliententries); + LOCK_DESTROY (&clienttable->lock); + GF_FREE (clienttable); + } +} + +client_t * +gf_client_get (xlator_t *this, struct rpcsvc_auth_data *cred, char *client_uid) +{ + client_t *client = NULL; + cliententry_t *cliententry = NULL; + clienttable_t *clienttable = NULL; + unsigned int i = 0; + + if (this == NULL || client_uid == NULL) { + gf_log_callingfn ("client_t", GF_LOG_ERROR, "invalid argument"); + errno = EINVAL; + return NULL; + } + + gf_log (this->name, GF_LOG_INFO, "client_uid=%s", client_uid); + + clienttable = this->ctx->clienttable; + + LOCK (&clienttable->lock); + { + for (; i < clienttable->max_clients; i++) { + client = clienttable->cliententries[i].client; + if (client == NULL) + continue; + /* + * look for matching client_uid, _and_ + * if auth was used, matching auth flavour and data + */ + if (strcmp (client_uid, client->client_uid) == 0 && + (cred->flavour != AUTH_NONE && + (cred->flavour == client->auth.flavour && + (size_t) cred->datalen == client->auth.len && + memcmp (cred->authdata, + client->auth.data, + client->auth.len) == 0))) { +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) + __sync_add_and_fetch(&client->ref.bind, 1); +#else + LOCK (&client->ref.lock); + { + ++client->ref.bind; + } + UNLOCK (&client->ref.lock); +#endif + break; + } + } + if (client) { + gf_client_ref (client); + goto unlock; + } + client = GF_CALLOC (1, sizeof(client_t), gf_common_mt_client_t); + if (client == NULL) { + errno = ENOMEM; + goto unlock; + } + + client->this = this; + + LOCK_INIT (&client->scratch_ctx.lock); + LOCK_INIT (&client->ref.lock); + + client->client_uid = gf_strdup (client_uid); + if (client->client_uid == NULL) { + GF_FREE (client); + client = NULL; + errno = ENOMEM; + goto unlock; + } + client->scratch_ctx.count = GF_CLIENTCTX_INITIAL_SIZE; + client->scratch_ctx.ctx = + GF_CALLOC (GF_CLIENTCTX_INITIAL_SIZE, + sizeof (struct client_ctx), + gf_common_mt_client_ctx); + if (client->scratch_ctx.ctx == NULL) { + GF_FREE (client->client_uid); + GF_FREE (client); + client = NULL; + errno = ENOMEM; + goto unlock; + } + + /* no need to do these atomically here */ + client->ref.bind = client->ref.count = 1; + + client->auth.flavour = cred->flavour; + if (cred->flavour != AUTH_NONE) { + client->auth.data = + GF_CALLOC (1, cred->datalen, + gf_common_mt_client_t); + if (client->auth.data == NULL) { + GF_FREE (client->scratch_ctx.ctx); + GF_FREE (client->client_uid); + GF_FREE (client); + client = NULL; + errno = ENOMEM; + goto unlock; + } + memcpy (client->auth.data, cred->authdata, + cred->datalen); + client->auth.len = cred->datalen; + } + + client->tbl_index = clienttable->first_free; + cliententry = &clienttable->cliententries[client->tbl_index]; + cliententry->client = client; + clienttable->first_free = cliententry->next_free; + cliententry->next_free = GF_CLIENTENTRY_ALLOCATED; + gf_client_ref (client); + } +unlock: + UNLOCK (&clienttable->lock); + + return client; +} + +void +gf_client_put (client_t *client, gf_boolean_t *detached) +{ + gf_boolean_t unref = _gf_false; + int bind_ref; + + if (detached) + *detached = _gf_false; + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) + bind_ref = __sync_sub_and_fetch(&client->ref.bind, 1); +#else + LOCK (&client->ref.lock); + { + bind_ref = --client->ref.bind; + } + UNLOCK (&client->ref.lock); +#endif + if (bind_ref == 0) + unref = _gf_true; + + if (unref) { + gf_log (THIS->name, GF_LOG_INFO, "Shutting down connection %s", + client->client_uid); + if (detached) + *detached = _gf_true; + gf_client_unref (client); + } +} + + +client_t * +gf_client_ref (client_t *client) +{ + if (!client) { + gf_log_callingfn ("client_t", GF_LOG_ERROR, "null client"); + return NULL; + } + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) + __sync_add_and_fetch(&client->ref.count, 1); +#else + LOCK (&client->ref.lock); + { + ++client->ref.count; + } + UNLOCK (&client->ref.lock); +#endif + return client; +} + + +static void +client_destroy (client_t *client) +{ + clienttable_t *clienttable = NULL; + glusterfs_graph_t *gtrav = NULL; + xlator_t *xtrav = NULL; + + if (client == NULL){ + gf_log_callingfn ("xlator", GF_LOG_ERROR, "invalid argument"); + goto out; + } + + clienttable = client->this->ctx->clienttable; + + LOCK_DESTROY (&client->scratch_ctx.lock); + LOCK_DESTROY (&client->ref.lock); + + LOCK (&clienttable->lock); + { + clienttable->cliententries[client->tbl_index].client = NULL; + clienttable->cliententries[client->tbl_index].next_free = + clienttable->first_free; + clienttable->first_free = client->tbl_index; + } + UNLOCK (&clienttable->lock); + + list_for_each_entry (gtrav, &client->this->ctx->graphs, list) { + xtrav = gtrav->top; + while (xtrav != NULL) { + if (xtrav->cbks->client_destroy != NULL) + xtrav->cbks->client_destroy (xtrav, client); + xtrav = xtrav->next; + } + } + GF_FREE (client->auth.data); + GF_FREE (client->scratch_ctx.ctx); + GF_FREE (client->client_uid); + GF_FREE (client); +out: + return; +} + + +int +gf_client_disconnect (client_t *client) +{ + int ret = 0; + glusterfs_graph_t *gtrav = NULL; + xlator_t *xtrav = NULL; + + list_for_each_entry (gtrav, &client->this->ctx->graphs, list) { + xtrav = gtrav->top; + while (xtrav != NULL) { + if (xtrav->cbks->client_disconnect != NULL) + if (xtrav->cbks->client_disconnect (xtrav, client) != 0) + ret = -1; + xtrav = xtrav->next; + } + } + + return ret; +} + + +void +gf_client_unref (client_t *client) +{ + int refcount; + + if (!client) { + gf_log_callingfn ("client_t", GF_LOG_ERROR, "client is NULL"); + return; + } + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) + refcount = __sync_sub_and_fetch(&client->ref.count, 1); +#else + LOCK (&client->ref.lock); + { + refcount = --client->ref.count; + } + UNLOCK (&client->ref.lock); +#endif + if (refcount == 0) { + client_destroy (client); + } +} + + +static int +client_ctx_set_int (client_t *client, void *key, void *value) +{ + int index = 0; + int ret = 0; + int set_idx = -1; + + for (index = 0; index < client->scratch_ctx.count; index++) { + if (!client->scratch_ctx.ctx[index].ctx_key) { + if (set_idx == -1) + set_idx = index; + /* dont break, to check if key already exists + further on */ + } + if (client->scratch_ctx.ctx[index].ctx_key == key) { + set_idx = index; + break; + } + } + + if (set_idx == -1) { + ret = -1; + goto out; + } + + client->scratch_ctx.ctx[set_idx].ctx_key = key; + client->scratch_ctx.ctx[set_idx].ctx_value = value; + +out: + return ret; +} + + +int +client_ctx_set (client_t *client, void *key, void *value) +{ + int ret = 0; + + if (!client || !key) + return -1; + + LOCK (&client->scratch_ctx.lock); + { + ret = client_ctx_set_int (client, key, value); + } + UNLOCK (&client->scratch_ctx.lock); + + return ret; +} + + +static int +client_ctx_get_int (client_t *client, void *key, void **value) +{ + int index = 0; + int ret = 0; + + for (index = 0; index < client->scratch_ctx.count; index++) { + if (client->scratch_ctx.ctx[index].ctx_key == key) + break; + } + + if (index == client->scratch_ctx.count) { + ret = -1; + goto out; + } + + if (value) + *value = client->scratch_ctx.ctx[index].ctx_value; + +out: + return ret; +} + + +int +client_ctx_get (client_t *client, void *key, void **value) +{ + int ret = 0; + + if (!client || !key) + return -1; + + LOCK (&client->scratch_ctx.lock); + { + ret = client_ctx_get_int (client, key, value); + } + UNLOCK (&client->scratch_ctx.lock); + + return ret; +} + + +static int +client_ctx_del_int (client_t *client, void *key, void **value) +{ + int index = 0; + int ret = 0; + + for (index = 0; index < client->scratch_ctx.count; index++) { + if (client->scratch_ctx.ctx[index].ctx_key == key) + break; + } + + if (index == client->scratch_ctx.count) { + ret = -1; + goto out; + } + + if (value) + *value = client->scratch_ctx.ctx[index].ctx_value; + + client->scratch_ctx.ctx[index].ctx_key = 0; + client->scratch_ctx.ctx[index].ctx_value = 0; + +out: + return ret; +} + + +int +client_ctx_del (client_t *client, void *key, void **value) +{ + int ret = 0; + + if (!client || !key) + return -1; + + LOCK (&client->scratch_ctx.lock); + { + ret = client_ctx_del_int (client, key, value); + } + UNLOCK (&client->scratch_ctx.lock); + + return ret; +} + + +void +client_dump (client_t *client, char *prefix) +{ + char key[GF_DUMP_MAX_BUF_LEN]; + + if (!client) + return; + + memset(key, 0, sizeof key); + gf_proc_dump_write("refcount", "%d", client->ref.count); +} + + +void +cliententry_dump (cliententry_t *cliententry, char *prefix) +{ + if (!cliententry) + return; + + if (GF_CLIENTENTRY_ALLOCATED != cliententry->next_free) + return; + + if (cliententry->client) + client_dump(cliententry->client, prefix); +} + + +void +clienttable_dump (clienttable_t *clienttable, char *prefix) +{ + int i = 0; + int ret = -1; + char key[GF_DUMP_MAX_BUF_LEN] = {0}; + + if (!clienttable) + return; + + ret = TRY_LOCK (&clienttable->lock); + { + if (ret) { + gf_log ("client_t", GF_LOG_WARNING, + "Unable to acquire lock"); + return; + } + memset(key, 0, sizeof key); + gf_proc_dump_build_key(key, prefix, "maxclients"); + gf_proc_dump_write(key, "%d", clienttable->max_clients); + gf_proc_dump_build_key(key, prefix, "first_free"); + gf_proc_dump_write(key, "%d", clienttable->first_free); + for ( i = 0 ; i < clienttable->max_clients; i++) { + if (GF_CLIENTENTRY_ALLOCATED == + clienttable->cliententries[i].next_free) { + gf_proc_dump_build_key(key, prefix, + "cliententry[%d]", i); + gf_proc_dump_add_section(key); + cliententry_dump(&clienttable->cliententries[i], + key); + } + } + } + UNLOCK(&clienttable->lock); +} + + +void +client_ctx_dump (client_t *client, char *prefix) +{ +#if 0 /* TBD, FIXME */ + struct client_ctx *client_ctx = NULL; + xlator_t *xl = NULL; + int i = 0; + + if ((client == NULL) || (client->ctx == NULL)) { + goto out; + } + + LOCK (&client->ctx_lock); + if (client->ctx != NULL) { + client_ctx = GF_CALLOC (client->inode->table->xl->graph->ctx_count, + sizeof (*client_ctx), + gf_common_mt_client_ctx); + if (client_ctx == NULL) { + goto unlock; + } + + for (i = 0; i < client->inode->table->xl->graph->ctx_count; i++) { + client_ctx[i] = client->ctx[i]; + } + } +unlock: + UNLOCK (&client->ctx_lock); + + if (client_ctx == NULL) { + goto out; + } + + for (i = 0; i < client->inode->table->xl->graph->ctx_count; i++) { + if (client_ctx[i].xl_key) { + xl = (xlator_t *)(long)client_ctx[i].xl_key; + if (xl->dumpops && xl->dumpops->clientctx) + xl->dumpops->clientctx (xl, client); + } + } +out: + GF_FREE (client_ctx); +#endif +} + + +/* + * the following functions are here to preserve legacy behavior of the + * protocol/server xlator dump, but perhaps they should just be folded + * into the client dump instead? + */ +int +gf_client_dump_fdtables_to_dict (xlator_t *this, dict_t *dict) +{ + clienttable_t *clienttable = NULL; + int count = 0; + int ret = -1; +#ifdef NOTYET + client_t *client = NULL; + char key[GF_DUMP_MAX_BUF_LEN] = {0,}; +#endif + + GF_VALIDATE_OR_GOTO (THIS->name, this, out); + GF_VALIDATE_OR_GOTO (this->name, dict, out); + + clienttable = this->ctx->clienttable; + + if (!clienttable) + return -1; + +#ifdef NOTYET + ret = TRY_LOCK (&clienttable->lock); + { + if (ret) { + gf_log ("client_t", GF_LOG_WARNING, + "Unable to acquire lock"); + return -1; + } + for ( ; count < clienttable->max_clients; count++) { + if (GF_CLIENTENTRY_ALLOCATED != + clienttable->cliententries[count].next_free) + continue; + client = clienttable->cliententries[count].client; + memset(key, 0, sizeof key); + snprintf (key, sizeof key, "conn%d", count++); + fdtable_dump_to_dict (client->server_ctx.fdtable, + key, dict); + } + } + UNLOCK(&clienttable->lock); +#endif + + ret = dict_set_int32 (dict, "conncount", count); +out: + return ret; +} + +int +gf_client_dump_fdtables (xlator_t *this) +{ + client_t *client = NULL; + clienttable_t *clienttable = NULL; + int count = 1; + int ret = -1; + char key[GF_DUMP_MAX_BUF_LEN] = {0,}; + + GF_VALIDATE_OR_GOTO (THIS->name, this, out); + + clienttable = this->ctx->clienttable; + + if (!clienttable) + return -1; + + ret = TRY_LOCK (&clienttable->lock); + { + if (ret) { + gf_log ("client_t", GF_LOG_WARNING, + "Unable to acquire lock"); + return -1; + } + + + for ( ; count < clienttable->max_clients; count++) { + if (GF_CLIENTENTRY_ALLOCATED != + clienttable->cliententries[count].next_free) + continue; + client = clienttable->cliententries[count].client; + memset(key, 0, sizeof key); + if (client->client_uid) { + gf_proc_dump_build_key (key, "conn", + "%d.id", count); + gf_proc_dump_write (key, "%s", + client->client_uid); + } + + gf_proc_dump_build_key (key, "conn", "%d.ref", + count); + gf_proc_dump_write (key, "%d", client->ref.count); + if (client->bound_xl) { + gf_proc_dump_build_key (key, "conn", + "%d.bound_xl", count); + gf_proc_dump_write (key, "%s", + client->bound_xl->name); + } + +#ifdef NOTYET + gf_proc_dump_build_key (key, "conn","%d.id", count); + fdtable_dump (client->server_ctx.fdtable, key); +#endif + } + } + + UNLOCK(&clienttable->lock); + + ret = 0; +out: + return ret; +} + + +int +gf_client_dump_inodes_to_dict (xlator_t *this, dict_t *dict) +{ + client_t *client = NULL; + clienttable_t *clienttable = NULL; + xlator_t *prev_bound_xl = NULL; + char key[32] = {0,}; + int count = 0; + int ret = -1; + + GF_VALIDATE_OR_GOTO (THIS->name, this, out); + GF_VALIDATE_OR_GOTO (this->name, dict, out); + + clienttable = this->ctx->clienttable; + + if (!clienttable) + return -1; + + ret = TRY_LOCK (&clienttable->lock); + { + if (ret) { + gf_log ("client_t", GF_LOG_WARNING, + "Unable to acquire lock"); + return -1; + } + for ( ; count < clienttable->max_clients; count++) { + if (GF_CLIENTENTRY_ALLOCATED != + clienttable->cliententries[count].next_free) + continue; + client = clienttable->cliententries[count].client; + memset(key, 0, sizeof key); + if (client->bound_xl && client->bound_xl->itable) { + /* Presently every brick contains only + * one bound_xl for all connections. + * This will lead to duplicating of + * the inode lists, if listing is + * done for every connection. This + * simple check prevents duplication + * in the present case. If need arises + * the check can be improved. + */ + if (client->bound_xl == prev_bound_xl) + continue; + prev_bound_xl = client->bound_xl; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "conn%d", count); + inode_table_dump_to_dict (client->bound_xl->itable, + key, dict); + } + } + } + UNLOCK(&clienttable->lock); + + ret = dict_set_int32 (dict, "conncount", count); + +out: + if (prev_bound_xl) + prev_bound_xl = NULL; + return ret; +} + +int +gf_client_dump_inodes (xlator_t *this) +{ + client_t *client = NULL; + clienttable_t *clienttable = NULL; + xlator_t *prev_bound_xl = NULL; + int count = 1; + int ret = -1; + char key[GF_DUMP_MAX_BUF_LEN] = {0,}; + + GF_VALIDATE_OR_GOTO (THIS->name, this, out); + + clienttable = this->ctx->clienttable; + + if (!clienttable) + goto out; + + ret = TRY_LOCK (&clienttable->lock); + { + if (ret) { + gf_log ("client_t", GF_LOG_WARNING, + "Unable to acquire lock"); + goto out; + } + + for ( ; count < clienttable->max_clients; count++) { + if (GF_CLIENTENTRY_ALLOCATED != + clienttable->cliententries[count].next_free) + continue; + client = clienttable->cliententries[count].client; + memset(key, 0, sizeof key); + if (client->bound_xl && client->bound_xl->itable) { + /* Presently every brick contains only + * one bound_xl for all connections. + * This will lead to duplicating of + * the inode lists, if listing is + * done for every connection. This + * simple check prevents duplication + * in the present case. If need arises + * the check can be improved. + */ + if (client->bound_xl == prev_bound_xl) + continue; + prev_bound_xl = client->bound_xl; + + gf_proc_dump_build_key(key, "conn", + "%d.bound_xl.%s", count, + client->bound_xl->name); + inode_table_dump(client->bound_xl->itable,key); + } + } + } + UNLOCK(&clienttable->lock); + + ret = 0; +out: + return ret; +} + diff --git a/libglusterfs/src/client_t.h b/libglusterfs/src/client_t.h new file mode 100644 index 000000000..f7812f8f0 --- /dev/null +++ b/libglusterfs/src/client_t.h @@ -0,0 +1,135 @@ +/* + 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 _CLIENT_T_H +#define _CLIENT_T_H + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "glusterfs.h" +#include "locking.h" /* for gf_lock_t, not included by glusterfs.h */ + +struct client_ctx { + void *ctx_key; + void *ctx_value; +}; + +typedef struct _client_t { + struct { + /* e.g. protocol/server stashes its ctx here */ + gf_lock_t lock; + unsigned short count; + struct client_ctx *ctx; + } scratch_ctx; + struct { + gf_lock_t lock; + volatile int bind; + volatile int count; + } ref; + xlator_t *bound_xl; + xlator_t *this; + int tbl_index; + char *client_uid; + struct { + int flavour; + size_t len; + char *data; + } auth; +} client_t; + +#define GF_CLIENTCTX_INITIAL_SIZE 8 + +struct client_table_entry { + client_t *client; + int next_free; +}; +typedef struct client_table_entry cliententry_t; + +struct clienttable { + unsigned int max_clients; + gf_lock_t lock; + cliententry_t *cliententries; + int first_free; +}; +typedef struct clienttable clienttable_t; + +#define GF_CLIENTTABLE_INITIAL_SIZE 32 + +/* Signifies no more entries in the client table. */ +#define GF_CLIENTTABLE_END -1 + +/* This is used to invalidate + * the next_free value in an cliententry that has been allocated + */ +#define GF_CLIENTENTRY_ALLOCATED -2 + +struct rpcsvc_auth_data; + +client_t * +gf_client_get (xlator_t *this, struct rpcsvc_auth_data *cred, char *client_uid); + +void +gf_client_put (client_t *client, gf_boolean_t *detached); + +clienttable_t * +gf_clienttable_alloc (void); + +void +gf_client_clienttable_destroy (clienttable_t *clienttable); + +client_t * +gf_client_ref (client_t *client); + +void +gf_client_unref (client_t *client); + +int +gf_client_dump_fdtable_to_dict (xlator_t *this, dict_t *dict); + +int +gf_client_dump_fdtable (xlator_t *this); + +int +gf_client_dump_inodes_to_dict (xlator_t *this, dict_t *dict); + +int +gf_client_dump_inodes (xlator_t *this); + +int +client_ctx_set (client_t *client, void *key, void *value); + +int +client_ctx_get (client_t *client, void *key, void **value); + +int +client_ctx_del (client_t *client, void *key, void **value); + +void +client_ctx_dump (client_t *client, char *prefix); + +int +gf_client_dump_fdtables_to_dict (xlator_t *this, dict_t *dict); + +int +gf_client_dump_fdtables (xlator_t *this); + +int +gf_client_dump_inodes_to_dict (xlator_t *this, dict_t *dict); + +int +gf_client_dump_inodes (xlator_t *this); + +int +gf_client_disconnect (client_t *client); + +#endif /* _CLIENT_T_H */ diff --git a/libglusterfs/src/common-utils.c b/libglusterfs/src/common-utils.c index 9375c5d40..827475282 100644 --- a/libglusterfs/src/common-utils.c +++ b/libglusterfs/src/common-utils.c @@ -45,6 +45,7 @@ #include "globals.h" #include "lkowner.h" #include "syscall.h" +#include <ifaddrs.h> #ifndef AI_ADDRCONFIG #define AI_ADDRCONFIG 0 @@ -58,6 +59,16 @@ struct dnscache6 { struct addrinfo *next; }; +void +md5_wrapper(const unsigned char *data, size_t len, char *md5) +{ + unsigned short i = 0; + unsigned short lim = MD5_DIGEST_LENGTH*2+1; + unsigned char scratch[MD5_DIGEST_LENGTH] = {0,}; + MD5(data, len, scratch); + for (; i < MD5_DIGEST_LENGTH; i++) + snprintf(md5 + i * 2, lim-i*2, "%02x", scratch[i]); +} /* works similar to mkdir(1) -p. */ @@ -1114,7 +1125,7 @@ gf_string2int8 (const char *str, int8_t *n) if (rv != 0) return rv; - if (l >= INT8_MIN && l <= INT8_MAX) { + if ((l >= INT8_MIN) && (l <= INT8_MAX)) { *n = (int8_t) l; return 0; } @@ -1133,7 +1144,7 @@ gf_string2int16 (const char *str, int16_t *n) if (rv != 0) return rv; - if (l >= INT16_MIN && l <= INT16_MAX) { + if ((l >= INT16_MIN) && (l <= INT16_MAX)) { *n = (int16_t) l; return 0; } @@ -1152,7 +1163,7 @@ gf_string2int32 (const char *str, int32_t *n) if (rv != 0) return rv; - if (l >= INT32_MIN && l <= INT32_MAX) { + if ((l >= INT32_MIN) && (l <= INT32_MAX)) { *n = (int32_t) l; return 0; } @@ -1171,7 +1182,7 @@ gf_string2int64 (const char *str, int64_t *n) if (rv != 0) return rv; - if (l >= INT64_MIN && l <= INT64_MAX) { + if ((l >= INT64_MIN) && (l <= INT64_MAX)) { *n = (int64_t) l; return 0; } @@ -1430,6 +1441,11 @@ gf_string2bytesize (const char *str, uint64_t *n) return -1; } + if ((UINT64_MAX - value) < 0) { + errno = ERANGE; + return -1; + } + *n = (uint64_t) value; return 0; @@ -1489,6 +1505,12 @@ gf_string2percent_or_bytesize (const char *str, return -1; } + /* Error out if we cannot store the value in uint64 */ + if ((UINT64_MAX - value) < 0) { + errno = ERANGE; + return -1; + } + *n = (uint64_t) value; return 0; @@ -1784,6 +1806,14 @@ valid_host_name (char *address, int length) goto out; } + /* Check for consecutive dots, which is invalid in a hostname and is + * ignored by strtok() + */ + if (strstr (dup_addr, "..")) { + ret = 0; + goto out; + } + /* gen-name */ temp_str = strtok_r (dup_addr, ".", &save_ptr); do { @@ -1939,6 +1969,50 @@ out: return ret; } +/** + * gf_sock_union_equal_addr - check if two given gf_sock_unions have same addr + * + * @param a - first sock union + * @param b - second sock union + * @return _gf_true if a and b have same ipv{4,6} addr, _gf_false otherwise + */ +gf_boolean_t +gf_sock_union_equal_addr (union gf_sock_union *a, + union gf_sock_union *b) +{ + if (!a || !b) { + gf_log ("common-utils", GF_LOG_ERROR, "Invalid arguments" + " to gf_sock_union_equal_addr"); + return _gf_false; + } + + if (a->storage.ss_family != b->storage.ss_family) + return _gf_false; + + switch (a->storage.ss_family) { + case AF_INET: + if (a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr) + return _gf_true; + else + return _gf_false; + + case AF_INET6: + if (memcmp ((void *)(&a->sin6.sin6_addr), + (void *)(&b->sin6.sin6_addr), + sizeof (a->sin6.sin6_addr))) + return _gf_false; + else + return _gf_true; + + default: + gf_log ("common-utils", GF_LOG_DEBUG, + "Unsupported/invalid address family"); + break; + } + + return _gf_false; +} + /*Thread safe conversion function*/ char * uuid_utoa (uuid_t uuid) @@ -2513,3 +2587,322 @@ gf_get_hostname_from_ip (char *client_ip, char **hostname) return ret; } + +gf_boolean_t +gf_interface_search (char *ip) +{ + int32_t ret = -1; + gf_boolean_t found = _gf_false; + struct ifaddrs *ifaddr, *ifa; + int family; + char host[NI_MAXHOST]; + xlator_t *this = NULL; + char *pct = NULL; + + this = THIS; + + ret = getifaddrs (&ifaddr); + + if (ret != 0) { + gf_log (this->name, GF_LOG_ERROR, "getifaddrs() failed: %s\n", + gai_strerror(ret)); + goto out; + } + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (!ifa->ifa_addr) { + /* + * This seemingly happens if an interface hasn't + * been bound to a particular protocol (seen with + * TUN devices). + */ + continue; + } + family = ifa->ifa_addr->sa_family; + + if (family != AF_INET && family != AF_INET6) + continue; + + ret = getnameinfo (ifa->ifa_addr, + (family == AF_INET) ? sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6), + host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); + + if (ret != 0) { + gf_log (this->name, GF_LOG_ERROR, + "getnameinfo() failed: %s\n", + gai_strerror(ret)); + goto out; + } + + /* + * Sometimes the address comes back as addr%eth0 or + * similar. Since % is an invalid character, we can + * strip it out with confidence that doing so won't + * harm anything. + */ + pct = index(host,'%'); + if (pct) { + *pct = '\0'; + } + + if (strncmp (ip, host, NI_MAXHOST) == 0) { + gf_log (this->name, GF_LOG_DEBUG, + "%s is local address at interface %s", + ip, ifa->ifa_name); + found = _gf_true; + goto out; + } + } +out: + if(ifaddr) + freeifaddrs (ifaddr); + return found; +} + +char * +get_ip_from_addrinfo (struct addrinfo *addr, char **ip) +{ + char buf[64]; + void *in_addr = NULL; + struct sockaddr_in *s4 = NULL; + struct sockaddr_in6 *s6 = NULL; + + switch (addr->ai_family) + { + case AF_INET: + s4 = (struct sockaddr_in *)addr->ai_addr; + in_addr = &s4->sin_addr; + break; + + case AF_INET6: + s6 = (struct sockaddr_in6 *)addr->ai_addr; + in_addr = &s6->sin6_addr; + break; + + default: + gf_log ("glusterd", GF_LOG_ERROR, "Invalid family"); + return NULL; + } + + if (!inet_ntop(addr->ai_family, in_addr, buf, sizeof(buf))) { + gf_log ("glusterd", GF_LOG_ERROR, "String conversion failed"); + return NULL; + } + + *ip = strdup (buf); + return *ip; +} + +gf_boolean_t +gf_is_loopback_localhost (const struct sockaddr *sa, char *hostname) +{ + GF_ASSERT (sa); + + gf_boolean_t is_local = _gf_false; + const struct in_addr *addr4 = NULL; + const struct in6_addr *addr6 = NULL; + uint8_t *ap = NULL; + struct in6_addr loopbackaddr6 = IN6ADDR_LOOPBACK_INIT; + + switch (sa->sa_family) { + case AF_INET: + addr4 = &(((struct sockaddr_in *)sa)->sin_addr); + ap = (uint8_t*)&addr4->s_addr; + if (ap[0] == 127) + is_local = _gf_true; + break; + + case AF_INET6: + addr6 = &(((struct sockaddr_in6 *)sa)->sin6_addr); + if (memcmp (addr6, &loopbackaddr6, + sizeof (loopbackaddr6)) == 0) + is_local = _gf_true; + break; + + default: + if (hostname) + gf_log ("glusterd", GF_LOG_ERROR, + "unknown address family %d for %s", + sa->sa_family, hostname); + break; + } + + return is_local; +} + +gf_boolean_t +gf_is_local_addr (char *hostname) +{ + int32_t ret = -1; + struct addrinfo *result = NULL; + struct addrinfo *res = NULL; + gf_boolean_t found = _gf_false; + char *ip = NULL; + xlator_t *this = NULL; + + this = THIS; + ret = getaddrinfo (hostname, NULL, NULL, &result); + + if (ret != 0) { + gf_log (this->name, GF_LOG_ERROR, "error in getaddrinfo: %s\n", + gai_strerror(ret)); + goto out; + } + + for (res = result; res != NULL; res = res->ai_next) { + gf_log (this->name, GF_LOG_DEBUG, "%s ", + get_ip_from_addrinfo (res, &ip)); + + found = gf_is_loopback_localhost (res->ai_addr, hostname) + || gf_interface_search (ip); + if (found) + goto out; + } + +out: + if (result) + freeaddrinfo (result); + + if (!found) + gf_log (this->name, GF_LOG_DEBUG, "%s is not local", hostname); + + return found; +} + +gf_boolean_t +gf_is_same_address (char *name1, char *name2) +{ + struct addrinfo *addr1 = NULL; + struct addrinfo *addr2 = NULL; + struct addrinfo *p = NULL; + struct addrinfo *q = NULL; + gf_boolean_t ret = _gf_false; + int gai_err = 0; + + gai_err = getaddrinfo(name1,NULL,NULL,&addr1); + if (gai_err != 0) { + gf_log (name1, GF_LOG_WARNING, + "error in getaddrinfo: %s\n", gai_strerror(gai_err)); + goto out; + } + + gai_err = getaddrinfo(name2,NULL,NULL,&addr2); + if (gai_err != 0) { + gf_log (name2, GF_LOG_WARNING, + "error in getaddrinfo: %s\n", gai_strerror(gai_err)); + goto out; + } + + for (p = addr1; p; p = p->ai_next) { + for (q = addr2; q; q = q->ai_next) { + if (p->ai_addrlen != q->ai_addrlen) { + continue; + } + if (memcmp(p->ai_addr,q->ai_addr,p->ai_addrlen)) { + continue; + } + ret = _gf_true; + goto out; + } + } + +out: + if (addr1) { + freeaddrinfo(addr1); + } + if (addr2) { + freeaddrinfo(addr2); + } + return ret; + +} + + +/* Sets log file path from user provided arguments */ +int +gf_set_log_file_path (cmd_args_t *cmd_args) +{ + int i = 0; + int j = 0; + int ret = 0; + char tmp_str[1024] = {0,}; + + if (!cmd_args) + goto done; + + if (cmd_args->mount_point) { + j = 0; + i = 0; + if (cmd_args->mount_point[0] == '/') + i = 1; + for (; i < strlen (cmd_args->mount_point); i++,j++) { + tmp_str[j] = cmd_args->mount_point[i]; + if (cmd_args->mount_point[i] == '/') + tmp_str[j] = '-'; + } + + ret = gf_asprintf (&cmd_args->log_file, + DEFAULT_LOG_FILE_DIRECTORY "/%s.log", + tmp_str); + if (ret > 0) + ret = 0; + goto done; + } + + if (cmd_args->volfile) { + j = 0; + i = 0; + if (cmd_args->volfile[0] == '/') + i = 1; + for (; i < strlen (cmd_args->volfile); i++,j++) { + tmp_str[j] = cmd_args->volfile[i]; + if (cmd_args->volfile[i] == '/') + tmp_str[j] = '-'; + } + ret = gf_asprintf (&cmd_args->log_file, + DEFAULT_LOG_FILE_DIRECTORY "/%s.log", + tmp_str); + if (ret > 0) + ret = 0; + goto done; + } + + if (cmd_args->volfile_server) { + + ret = gf_asprintf (&cmd_args->log_file, + DEFAULT_LOG_FILE_DIRECTORY "/%s-%s-%d.log", + cmd_args->volfile_server, + cmd_args->volfile_id, getpid()); + if (ret > 0) + ret = 0; + } +done: + return ret; +} + +int +gf_thread_create (pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *arg) +{ + sigset_t set, old; + int ret; + + sigemptyset (&set); + + sigfillset (&set); + sigdelset (&set, SIGSEGV); + sigdelset (&set, SIGBUS); + sigdelset (&set, SIGILL); + sigdelset (&set, SIGSYS); + sigdelset (&set, SIGFPE); + sigdelset (&set, SIGABRT); + + pthread_sigmask (SIG_BLOCK, &set, &old); + + ret = pthread_create (thread, attr, start_routine, arg); + + pthread_sigmask (SIG_SETMASK, &old, NULL); + + return ret; +} diff --git a/libglusterfs/src/common-utils.h b/libglusterfs/src/common-utils.h index e1193031c..3c99a4212 100644 --- a/libglusterfs/src/common-utils.h +++ b/libglusterfs/src/common-utils.h @@ -23,6 +23,7 @@ #include <string.h> #include <assert.h> #include <pthread.h> +#include <openssl/md5.h> #ifndef GF_BSD_HOST_OS #include <alloca.h> #endif @@ -111,6 +112,7 @@ in_addr_t gf_resolve_ip (const char *hostname, void **dnscache); void gf_log_dump_graph (FILE *specfp, glusterfs_graph_t *graph); void gf_print_trace (int32_t signal, glusterfs_ctx_t *ctx); +int gf_set_log_file_path (cmd_args_t *cmd_args); #define VECTORSIZE(count) (count * (sizeof (struct iovec))) @@ -557,6 +559,8 @@ char valid_internet_address (char *address, gf_boolean_t wildcard_acc); char valid_ipv4_wildcard_check (char *address); char valid_ipv6_wildcard_check (char *address); char valid_wildcard_internet_address (char *address); +gf_boolean_t gf_sock_union_equal_addr (union gf_sock_union *a, + union gf_sock_union *b); char *uuid_utoa (uuid_t uuid); char *uuid_utoa_r (uuid_t uuid, char *dst); @@ -580,5 +584,11 @@ char *gf_get_reserved_ports(); int gf_process_reserved_ports (gf_boolean_t ports[]); gf_boolean_t gf_ports_reserved (char *blocked_port, gf_boolean_t *ports); int gf_get_hostname_from_ip (char *client_ip, char **hostname); +gf_boolean_t gf_is_local_addr (char *hostname); +gf_boolean_t gf_is_same_address (char *host1, char *host2); +void md5_wrapper(const unsigned char *data, size_t len, char *md5); + +int gf_thread_create (pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *arg); #endif /* _COMMON_UTILS_H */ diff --git a/libglusterfs/src/compat.h b/libglusterfs/src/compat.h index 3d0cee1a9..2bd982541 100644 --- a/libglusterfs/src/compat.h +++ b/libglusterfs/src/compat.h @@ -32,6 +32,12 @@ #include <linux/limits.h> #include <sys/xattr.h> #include <endian.h> +#ifdef HAVE_FALLOC_H +#include <linux/falloc.h> +#else +#define FALLOC_FL_KEEP_SIZE 0x01 /* default is extend size */ +#define FALLOC_FL_PUNCH_HOLE 0x02 /* de-allocates range */ +#endif #ifndef HAVE_LLISTXATTR diff --git a/libglusterfs/src/defaults.c b/libglusterfs/src/defaults.c index 5bac845c1..2ebb25150 100644 --- a/libglusterfs/src/defaults.c +++ b/libglusterfs/src/defaults.c @@ -455,6 +455,35 @@ default_fsetattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, } int32_t +default_fallocate_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *pre, + struct iatt *post, dict_t *xdata) +{ + STACK_UNWIND_STRICT(fallocate, frame, op_ret, op_errno, pre, post, xdata); + return 0; +} + +int32_t +default_discard_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *pre, + struct iatt *post, dict_t *xdata) +{ + STACK_UNWIND_STRICT(discard, frame, op_ret, op_errno, pre, post, xdata); + return 0; +} + +int32_t +default_zerofill_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *pre, + struct iatt *post, dict_t *xdata) +{ + STACK_UNWIND_STRICT(zerofill, frame, op_ret, op_errno, pre, + post, xdata); + return 0; +} + + +int32_t default_getspec_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, char *spec_data) { @@ -862,6 +891,37 @@ default_fsetattr_resume (call_frame_t *frame, xlator_t *this, fd_t *fd, return 0; } +int32_t +default_fallocate_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, + int32_t keep_size, off_t offset, size_t len, dict_t *xdata) +{ + STACK_WIND(frame, default_fallocate_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fallocate, fd, keep_size, offset, len, + xdata); + return 0; +} + +int32_t +default_discard_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, + off_t offset, size_t len, dict_t *xdata) +{ + STACK_WIND(frame, default_discard_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->discard, fd, offset, len, + xdata); + return 0; +} + +int32_t +default_zerofill_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, + off_t offset, size_t len, dict_t *xdata) +{ + STACK_WIND(frame, default_zerofill_cbk, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->zerofill, fd, offset, len, + xdata); + return 0; +} + + /* FOPS */ int32_t @@ -1266,6 +1326,36 @@ default_fsetattr (call_frame_t *frame, xlator_t *this, fd_t *fd, return 0; } +int32_t +default_fallocate(call_frame_t *frame, xlator_t *this, fd_t *fd, + int32_t keep_size, off_t offset, size_t len, dict_t *xdata) +{ + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->fallocate, fd, keep_size, offset, + len, xdata); + return 0; +} + +int32_t +default_discard(call_frame_t *frame, xlator_t *this, fd_t *fd, + off_t offset, size_t len, dict_t *xdata) +{ + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->discard, fd, offset, len, + xdata); + return 0; +} + +int32_t +default_zerofill(call_frame_t *frame, xlator_t *this, fd_t *fd, + off_t offset, size_t len, dict_t *xdata) +{ + STACK_WIND_TAIL(frame, FIRST_CHILD(this), + FIRST_CHILD(this)->fops->zerofill, fd, offset, len, + xdata); + return 0; +} + int32_t default_forget (xlator_t *this, inode_t *inode) diff --git a/libglusterfs/src/defaults.h b/libglusterfs/src/defaults.h index 8a9de7899..0747027bc 100644 --- a/libglusterfs/src/defaults.h +++ b/libglusterfs/src/defaults.h @@ -243,6 +243,25 @@ int32_t default_fsetattr (call_frame_t *frame, struct iatt *stbuf, int32_t valid, dict_t *xdata); +int32_t default_fallocate(call_frame_t *frame, + xlator_t *this, + fd_t *fd, + int32_t keep_size, off_t offset, + size_t len, dict_t *xdata); + +int32_t default_discard(call_frame_t *frame, + xlator_t *this, + fd_t *fd, + off_t offset, + size_t len, dict_t *xdata); + +int32_t default_zerofill(call_frame_t *frame, + xlator_t *this, + fd_t *fd, + off_t offset, + size_t len, dict_t *xdata); + + /* Resume */ int32_t default_getspec_resume (call_frame_t *frame, xlator_t *this, @@ -453,6 +472,25 @@ int32_t default_fsetattr_resume (call_frame_t *frame, struct iatt *stbuf, int32_t valid, dict_t *xdata); +int32_t default_fallocate_resume(call_frame_t *frame, + xlator_t *this, + fd_t *fd, + int32_t keep_size, off_t offset, + size_t len, dict_t *xdata); + +int32_t default_discard_resume(call_frame_t *frame, + xlator_t *this, + fd_t *fd, + off_t offset, + size_t len, dict_t *xdata); + +int32_t default_zerofill_resume(call_frame_t *frame, + xlator_t *this, + fd_t *fd, + off_t offset, + size_t len, dict_t *xdata); + + /* _cbk */ int32_t @@ -663,6 +701,18 @@ default_fsetattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, struct iatt *statpre, struct iatt *statpost, dict_t *xdata); +int32_t default_fallocate_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *pre, + struct iatt *post, dict_t *xdata); + +int32_t default_discard_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *pre, + struct iatt *post, dict_t *xdata); + +int32_t default_zerofill_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *pre, + struct iatt *post, dict_t *xdata); + int32_t default_getspec_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, int32_t op_errno, char *spec_data); diff --git a/libglusterfs/src/dict.c b/libglusterfs/src/dict.c index b017f87e5..3b7ddce5e 100644 --- a/libglusterfs/src/dict.c +++ b/libglusterfs/src/dict.c @@ -896,7 +896,7 @@ data_to_int32 (data_t *data) int16_t data_to_int16 (data_t *data) { - int16_t value = 0; + int16_t value = 0; if (!data) { gf_log_callingfn ("dict", GF_LOG_WARNING, "data is NULL"); @@ -910,16 +910,16 @@ data_to_int16 (data_t *data) memcpy (str, data->data, data->len); str[data->len] = '\0'; - errno = 0; - value = strtol (str, NULL, 0); + errno = 0; + value = strtol (str, NULL, 0); - if ((SHRT_MAX > value) || (SHRT_MIN < value)) { - errno = ERANGE; + if ((value > SHRT_MAX) || (value < SHRT_MIN)) { + errno = ERANGE; gf_log_callingfn ("dict", GF_LOG_WARNING, - "Error in data conversion: " - "detected overflow"); + "Error in data conversion: " + "detected overflow"); return -1; - } + } return (int16_t)value; } @@ -928,7 +928,7 @@ data_to_int16 (data_t *data) int8_t data_to_int8 (data_t *data) { - int32_t value = 0; + int8_t value = 0; if (!data) { gf_log_callingfn ("dict", GF_LOG_WARNING, "data is NULL"); @@ -942,16 +942,16 @@ data_to_int8 (data_t *data) memcpy (str, data->data, data->len); str[data->len] = '\0'; - errno = 0; - value = strtol (str, NULL, 0); + errno = 0; + value = strtol (str, NULL, 0); - if ((SCHAR_MAX > value) || (SCHAR_MIN < value)) { - errno = ERANGE; + if ((value > SCHAR_MAX) || (value < SCHAR_MIN)) { + errno = ERANGE; gf_log_callingfn ("dict", GF_LOG_WARNING, - "Error in data conversion: " - "detected overflow"); + "Error in data conversion: " + "detected overflow"); return -1; - } + } return (int8_t)value; } diff --git a/libglusterfs/src/event-history.c b/libglusterfs/src/event-history.c index fe511caeb..82baa521a 100644 --- a/libglusterfs/src/event-history.c +++ b/libglusterfs/src/event-history.c @@ -11,7 +11,8 @@ #include "event-history.h" eh_t * -eh_new (size_t buffer_size, gf_boolean_t use_buffer_once) +eh_new (size_t buffer_size, gf_boolean_t use_buffer_once, + void (*destroy_buffer_data) (void *data)) { eh_t *history = NULL; buffer_t *buffer = NULL; @@ -22,7 +23,8 @@ eh_new (size_t buffer_size, gf_boolean_t use_buffer_once) goto out; } - buffer = cb_buffer_new (buffer_size, use_buffer_once); + buffer = cb_buffer_new (buffer_size, use_buffer_once, + destroy_buffer_data); if (!buffer) { gf_log ("", GF_LOG_ERROR, "allocating circular buffer failed"); GF_FREE (history); diff --git a/libglusterfs/src/event-history.h b/libglusterfs/src/event-history.h index b1750bbae..b64f63b5e 100644 --- a/libglusterfs/src/event-history.h +++ b/libglusterfs/src/event-history.h @@ -32,7 +32,8 @@ eh_dump (eh_t *event , void *data, int (fn) (circular_buffer_t *buffer, void *data)); eh_t * -eh_new (size_t buffer_size, gf_boolean_t use_buffer_once); +eh_new (size_t buffer_size, gf_boolean_t use_buffer_once, + void (*destroy_data) (void *data)); int eh_save_history (eh_t *history, void *string); diff --git a/libglusterfs/src/fd.c b/libglusterfs/src/fd.c index 2f4afc5e8..36cc4d056 100644 --- a/libglusterfs/src/fd.c +++ b/libglusterfs/src/fd.c @@ -780,6 +780,23 @@ fd_anonymous (inode_t *inode) return fd; } +fd_t* +fd_lookup_anonymous (inode_t *inode) +{ + fd_t *fd = NULL; + + if (!inode) { + gf_log_callingfn ("fd", GF_LOG_WARNING, "!inode"); + return NULL; + } + + LOCK (&inode->lock); + { + fd = __fd_lookup_anonymous (inode); + } + UNLOCK (&inode->lock); + return fd; +} gf_boolean_t fd_is_anonymous (fd_t *fd) diff --git a/libglusterfs/src/fd.h b/libglusterfs/src/fd.h index 54290b198..c1b9157d8 100644 --- a/libglusterfs/src/fd.h +++ b/libglusterfs/src/fd.h @@ -134,6 +134,9 @@ fd_lookup (struct _inode *inode, pid_t pid); fd_t * fd_lookup_uint64 (struct _inode *inode, uint64_t pid); +fd_t* +fd_lookup_anonymous (inode_t *inode); + fd_t * fd_anonymous (inode_t *inode); diff --git a/libglusterfs/src/gidcache.c b/libglusterfs/src/gidcache.c index c55ed2581..c5bdda925 100644 --- a/libglusterfs/src/gidcache.c +++ b/libglusterfs/src/gidcache.c @@ -35,6 +35,21 @@ int gid_cache_init(gid_cache_t *cache, uint32_t timeout) } /* + * Reconfigure the cache timeout. + */ +int gid_cache_reconf(gid_cache_t *cache, uint32_t timeout) +{ + if (!cache) + return -1; + + LOCK(&cache->gc_lock); + cache->gc_max_age = timeout; + UNLOCK(&cache->gc_lock); + + return 0; +} + +/* * Look up an ID in the cache. If found, return the actual cache entry to avoid * an additional allocation and memory copy. The caller should copy the data and * release (unlock) the cache as soon as possible. diff --git a/libglusterfs/src/gidcache.h b/libglusterfs/src/gidcache.h index f904f26eb..9379f8e8b 100644 --- a/libglusterfs/src/gidcache.h +++ b/libglusterfs/src/gidcache.h @@ -45,6 +45,7 @@ typedef struct { } gid_cache_t; int gid_cache_init(gid_cache_t *, uint32_t); +int gid_cache_reconf(gid_cache_t *, uint32_t); const gid_list_t *gid_cache_lookup(gid_cache_t *, uint64_t); void gid_cache_release(gid_cache_t *, const gid_list_t *); int gid_cache_add(gid_cache_t *, gid_list_t *); diff --git a/libglusterfs/src/globals.c b/libglusterfs/src/globals.c index 05ff52c2c..259c5c885 100644 --- a/libglusterfs/src/globals.c +++ b/libglusterfs/src/globals.c @@ -19,6 +19,7 @@ #include "globals.h" #include "xlator.h" #include "mem-pool.h" +#include "syncop.h" const char *gf_fop_list[GF_FOP_MAXVALUE] = { [GF_FOP_NULL] = "NULL", @@ -67,6 +68,9 @@ const char *gf_fop_list[GF_FOP_MAXVALUE] = { [GF_FOP_RELEASE] = "RELEASE", [GF_FOP_RELEASEDIR] = "RELEASEDIR", [GF_FOP_FREMOVEXATTR]= "FREMOVEXATTR", + [GF_FOP_FALLOCATE] = "FALLOCATE", + [GF_FOP_DISCARD] = "DISCARD", + [GF_FOP_ZEROFILL] = "ZEROFILL", }; /* THIS */ @@ -121,8 +125,6 @@ __glusterfs_this_location () ret = pthread_setspecific (this_xlator_key, this_location); if (ret != 0) { - gf_log ("", GF_LOG_WARNING, "pthread setspecific failed"); - FREE (this_location); this_location = NULL; goto out; @@ -164,6 +166,54 @@ glusterfs_this_set (xlator_t *this) return 0; } +/* SYNCOPCTX */ +static pthread_key_t syncopctx_key; + +static void +syncopctx_key_destroy (void *ptr) +{ + struct syncopctx *opctx = ptr; + + if (opctx) { + if (opctx->groups) + GF_FREE (opctx->groups); + + GF_FREE (opctx); + } + + return; +} + +void * +syncopctx_getctx () +{ + void *opctx = NULL; + + opctx = pthread_getspecific (syncopctx_key); + + return opctx; +} + +int +syncopctx_setctx (void *ctx) +{ + int ret = 0; + + ret = pthread_setspecific (syncopctx_key, ctx); + + return ret; +} + +static int +syncopctx_init (void) +{ + int ret; + + ret = pthread_key_create (&syncopctx_key, syncopctx_key_destroy); + + return ret; +} + /* SYNCTASK */ int @@ -176,7 +226,6 @@ synctask_init () return ret; } - void * synctask_get () { @@ -300,6 +349,13 @@ glusterfs_globals_init (glusterfs_ctx_t *ctx) "ERROR: glusterfs synctask init failed"); goto out; } + + ret = syncopctx_init (); + if (ret) { + gf_log ("", GF_LOG_CRITICAL, + "ERROR: glusterfs syncopctx init failed"); + goto out; + } out: return ret; } diff --git a/libglusterfs/src/globals.h b/libglusterfs/src/globals.h index 64a1594f5..3085db21c 100644 --- a/libglusterfs/src/globals.h +++ b/libglusterfs/src/globals.h @@ -20,14 +20,15 @@ /* Gluster versions - OP-VERSION mapping * * 3.3.0 - 1 - * 3.3.Next/3.Next - 2 + * 3.4.0 - 2 + * 3.next (3.5?) - 3 * * TODO: Change above comment once gluster version is finalised * TODO: Finalize the op-version ranges */ #define GD_OP_VERSION_MIN 1 /* MIN is the fresh start op-version, mostly should not change */ -#define GD_OP_VERSION_MAX 2 /* MAX VERSION is the maximum count in VME table, +#define GD_OP_VERSION_MAX 3 /* MAX VERSION is the maximum count in VME table, should keep changing with introduction of newer versions */ @@ -40,6 +41,10 @@ xlator_t **__glusterfs_this_location (); xlator_t *glusterfs_this_get (); int glusterfs_this_set (xlator_t *); +/* syncopctx */ +void *syncopctx_getctx (); +int syncopctx_setctx (void *ctx); + /* task */ void *synctask_get (); int synctask_set (void *); diff --git a/libglusterfs/src/glusterfs-acl.h b/libglusterfs/src/glusterfs-acl.h new file mode 100644 index 000000000..b7de1cdb4 --- /dev/null +++ b/libglusterfs/src/glusterfs-acl.h @@ -0,0 +1,81 @@ +/* + 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 _GLUSTERFS_ACL_H +#define _GLUSTERFS_ACL_H + +#include <stdint.h> +#include <sys/types.h> /* For uid_t */ + +#include "locking.h" /* For gf_lock_t in struct posix_acl_conf */ + +#define ACL_PROGRAM 100227 +#define ACLV3_VERSION 3 + +#define POSIX_ACL_MINIMAL_ACE_COUNT 3 + +#define POSIX_ACL_READ (0x04) +#define POSIX_ACL_WRITE (0x02) +#define POSIX_ACL_EXECUTE (0x01) + +#define POSIX_ACL_UNDEFINED_TAG (0x00) +#define POSIX_ACL_USER_OBJ (0x01) +#define POSIX_ACL_USER (0x02) +#define POSIX_ACL_GROUP_OBJ (0x04) +#define POSIX_ACL_GROUP (0x08) +#define POSIX_ACL_MASK (0x10) +#define POSIX_ACL_OTHER (0x20) + +#define POSIX_ACL_UNDEFINED_ID (-1) + +#define POSIX_ACL_VERSION (0x02) + +#define POSIX_ACL_ACCESS_XATTR "system.posix_acl_access" +#define POSIX_ACL_DEFAULT_XATTR "system.posix_acl_default" + +struct posix_acl_xattr_entry { + uint16_t tag; + uint16_t perm; + uint32_t id; +}; + +struct posix_acl_xattr_header { + uint32_t version; + struct posix_acl_xattr_entry entries[]; +}; + +struct posix_ace { + uint16_t tag; + uint16_t perm; + uint32_t id; +}; + + +struct posix_acl { + int refcnt; + int count; + struct posix_ace entries[]; +}; + +struct posix_acl_ctx { + uid_t uid; + gid_t gid; + mode_t perm; + struct posix_acl *acl_access; + struct posix_acl *acl_default; +}; + +struct posix_acl_conf { + gf_lock_t acl_lock; + uid_t super_uid; + struct posix_acl *minimal_acl; +}; + +#endif /* _GLUSTERFS_ACL_H */ diff --git a/libglusterfs/src/glusterfs.h b/libglusterfs/src/glusterfs.h index 8ee55c706..2f1e12ee7 100644 --- a/libglusterfs/src/glusterfs.h +++ b/libglusterfs/src/glusterfs.h @@ -32,6 +32,7 @@ #include <arpa/inet.h> #include <sys/poll.h> #include <pthread.h> +#include <limits.h> /* For PATH_MAX */ #include "list.h" #include "logging.h" @@ -69,6 +70,7 @@ #define FNM_EXTMATCH 0 #endif +#define GLUSTERD_MAX_SNAP_NAME 256 #define ZR_MOUNTPOINT_OPT "mountpoint" #define ZR_ATTR_TIMEOUT_OPT "attribute-timeout" #define ZR_ENTRY_TIMEOUT_OPT "entry-timeout" @@ -87,6 +89,8 @@ #define GF_READDIR_SKIP_DIRS "readdir-filter-directories" +#define BD_XATTR_KEY "user.glusterfs" + #define XATTR_IS_PATHINFO(x) (strncmp (x, GF_XATTR_PATHINFO_KEY, \ strlen (GF_XATTR_PATHINFO_KEY)) == 0) #define XATTR_IS_NODE_UUID(x) (strncmp (x, GF_XATTR_NODE_UUID_KEY, \ @@ -94,24 +98,33 @@ #define XATTR_IS_LOCKINFO(x) (strncmp (x, GF_XATTR_LOCKINFO_KEY, \ strlen (GF_XATTR_LOCKINFO_KEY)) == 0) +#define XATTR_IS_BD(x) (strncmp (x, BD_XATTR_KEY, strlen (BD_XATTR_KEY)) == 0) + #define GF_XATTR_LINKINFO_KEY "trusted.distribute.linkinfo" -#define GFID_XATTR_KEY "trusted.gfid" +#define GFID_XATTR_KEY "trusted.gfid" +#define VIRTUAL_GFID_XATTR_KEY_STR "glusterfs.gfid.string" +#define VIRTUAL_GFID_XATTR_KEY "glusterfs.gfid" +#define UUID_CANONICAL_FORM_LEN 36 #define GLUSTERFS_INTERNAL_FOP_KEY "glusterfs-internal-fop" #define ZR_FILE_CONTENT_STR "glusterfs.file." #define ZR_FILE_CONTENT_STRLEN 15 +#define GLUSTERFS_WRITE_IS_APPEND "glusterfs.write-is-append" #define GLUSTERFS_OPEN_FD_COUNT "glusterfs.open-fd-count" #define GLUSTERFS_INODELK_COUNT "glusterfs.inodelk-count" #define GLUSTERFS_ENTRYLK_COUNT "glusterfs.entrylk-count" #define GLUSTERFS_POSIXLK_COUNT "glusterfs.posixlk-count" #define GLUSTERFS_PARENT_ENTRYLK "glusterfs.parent-entrylk" +#define GLUSTERFS_INODELK_DOM_COUNT "glusterfs.inodelk-dom-count" #define QUOTA_SIZE_KEY "trusted.glusterfs.quota.size" #define GFID_TO_PATH_KEY "glusterfs.gfid2path" +#define GF_XATTR_STIME_PATTERN "trusted.glusterfs.*.stime" /* Index xlator related */ #define GF_XATTROP_INDEX_GFID "glusterfs.xattrop_index_gfid" +#define GF_BASE_INDICES_HOLDER_GFID "glusterfs.base_indicies_holder_gfid" #define GF_GFIDLESS_LOOKUP "gfidless-lookup" /* replace-brick and pump related internal xattrs */ @@ -121,9 +134,6 @@ #define RB_PUMP_CMD_ABORT "glusterfs.pump.abort" #define RB_PUMP_CMD_STATUS "glusterfs.pump.status" -#define POSIX_ACL_DEFAULT_XATTR "system.posix_acl_default" -#define POSIX_ACL_ACCESS_XATTR "system.posix_acl_access" - #define GLUSTERFS_RDMA_INLINE_THRESHOLD (2048) #define GLUSTERFS_RDMA_MAX_HEADER_SIZE (228) /* (sizeof (rdma_header_t) \ + RDMA_MAX_SEGMENTS \ @@ -133,15 +143,16 @@ #define GLUSTERFS_RPC_REPLY_SIZE 24 #define ZR_FILE_CONTENT_REQUEST(key) (!strncmp(key, ZR_FILE_CONTENT_STR, \ - ZR_FILE_CONTENT_STRLEN)) + ZR_FILE_CONTENT_STRLEN)) #define DEFAULT_VAR_RUN_DIRECTORY DATADIR "/run/gluster" +#define GF_REPLICATE_TRASH_DIR ".landfill" /* GlusterFS's maximum supported Auxilary GIDs */ /* TODO: Keeping it to 200, so that we can fit in 2KB buffer for auth data * in RPC server code, if there is ever need for having more aux-gids, then * we have to add aux-gid in payload of actors */ -#define GF_MAX_AUX_GROUPS 200 +#define GF_MAX_AUX_GROUPS 65536 #define GF_UUID_BUF_SIZE 50 @@ -149,6 +160,13 @@ #define GF_REMOVE_BRICK_TID_KEY "remove-brick-id" #define GF_REPLACE_BRICK_TID_KEY "replace-brick-id" +#define UUID_CANONICAL_FORM_LEN 36 + +/* Adding this here instead of any glusterd*.h files as it is also required by + * cli + */ +#define DEFAULT_GLUSTERD_SOCKFILE DATADIR "/run/glusterd.socket" + /* NOTE: add members ONLY at the end (just before _MAXVALUE) */ typedef enum { GF_FOP_NULL = 0, @@ -182,8 +200,8 @@ typedef enum { GF_FOP_READDIR, GF_FOP_INODELK, GF_FOP_FINODELK, - GF_FOP_ENTRYLK, - GF_FOP_FENTRYLK, + GF_FOP_ENTRYLK, + GF_FOP_FENTRYLK, GF_FOP_XATTROP, GF_FOP_FXATTROP, GF_FOP_FGETXATTR, @@ -197,6 +215,9 @@ typedef enum { GF_FOP_RELEASEDIR, GF_FOP_GETSPEC, GF_FOP_FREMOVEXATTR, + GF_FOP_FALLOCATE, + GF_FOP_DISCARD, + GF_FOP_ZEROFILL, GF_FOP_MAXVALUE, } glusterfs_fop_t; @@ -246,20 +267,20 @@ typedef enum { typedef enum { - ENTRYLK_LOCK, - ENTRYLK_UNLOCK, - ENTRYLK_LOCK_NB + ENTRYLK_LOCK, + ENTRYLK_UNLOCK, + ENTRYLK_LOCK_NB } entrylk_cmd; typedef enum { - ENTRYLK_RDLCK, - ENTRYLK_WRLCK + ENTRYLK_RDLCK, + ENTRYLK_WRLCK } entrylk_type; typedef enum { - GF_XATTROP_ADD_ARRAY, + GF_XATTROP_ADD_ARRAY, GF_XATTROP_ADD_ARRAY64, GF_XATTROP_OR_ARRAY, GF_XATTROP_AND_ARRAY @@ -275,65 +296,75 @@ typedef enum { #define GF_CONTENT_KEY "glusterfs.content" struct _xlator_cmdline_option { - struct list_head cmd_args; - char *volume; - char *key; - char *value; + struct list_head cmd_args; + char *volume; + char *key; + char *value; }; typedef struct _xlator_cmdline_option xlator_cmdline_option_t; +struct _server_cmdline { + struct list_head list; + char *volfile_server; +}; +typedef struct _server_cmdline server_cmdline_t; #define GF_OPTION_ENABLE _gf_true #define GF_OPTION_DISABLE _gf_false #define GF_OPTION_DEFERRED 2 struct _cmd_args { - /* basic options */ - char *volfile_server; - char *volfile; - char *log_server; - gf_loglevel_t log_level; - char *log_file; + /* basic options */ + char *volfile_server; + server_cmdline_t *curr_server; + /* List of backup volfile servers, including original */ + struct list_head volfile_servers; + char *volfile; + char *log_server; + gf_loglevel_t log_level; + char *log_file; int32_t max_connect_attempts; - /* advanced options */ - uint32_t volfile_server_port; - char *volfile_server_transport; + /* advanced options */ + uint32_t volfile_server_port; + char *volfile_server_transport; uint32_t log_server_port; - char *pid_file; + char *pid_file; char *sock_file; - int no_daemon_mode; - char *run_id; - int debug_mode; + int no_daemon_mode; + char *run_id; + int debug_mode; int read_only; int acl; int selinux; int enable_ino32; int worm; int mac_compat; - int fopen_keep_cache; - int gid_timeout; - struct list_head xlator_options; /* list of xlator_option_t */ - - /* fuse options */ - int fuse_direct_io_mode; + int fopen_keep_cache; + int gid_timeout; + int aux_gfid_mount; + struct list_head xlator_options; /* list of xlator_option_t */ + + /* fuse options */ + int fuse_direct_io_mode; + char *use_readdirp; int volfile_check; - double fuse_entry_timeout; - double fuse_negative_timeout; - double fuse_attribute_timeout; - char *volume_name; - int fuse_nodev; - int fuse_nosuid; - char *dump_fuse; + double fuse_entry_timeout; + double fuse_negative_timeout; + double fuse_attribute_timeout; + char *volume_name; + int fuse_nodev; + int fuse_nosuid; + char *dump_fuse; pid_t client_pid; int client_pid_set; unsigned uid_map_root; int background_qlen; int congestion_threshold; - char *fuse_mountopts; + char *fuse_mountopts; - /* key args */ - char *mount_point; - char *volfile_id; + /* key args */ + char *mount_point; + char *volfile_id; /* required for portmap */ int brick_port; @@ -361,16 +392,16 @@ typedef struct _glusterfs_graph glusterfs_graph_t; typedef int32_t (*glusterfsd_mgmt_event_notify_fn_t) (int32_t event, void *data, ...); struct _glusterfs_ctx { - cmd_args_t cmd_args; - char *process_uuid; - FILE *pidfp; - char fin; - void *timer; - void *ib; - void *pool; - void *event_pool; + cmd_args_t cmd_args; + char *process_uuid; + FILE *pidfp; + char fin; + void *timer; + void *ib; + struct call_pool *pool; + void *event_pool; void *iobuf_pool; - pthread_mutex_t lock; + pthread_mutex_t lock; size_t page_size; struct list_head graphs; /* double linked list of graphs - one per volfile parse */ glusterfs_graph_t *active; /* the latest graph in use */ @@ -386,12 +417,12 @@ struct _glusterfs_ctx { got changed */ pid_t mnt_pid; /* pid of the mount agent */ int process_mode; /*mode in which process is runninng*/ - struct syncenv *env; /* The env pointer to the synctasks */ + struct syncenv *env; /* The env pointer to the synctasks */ struct list_head mempool_list; /* used to keep a global list of mempools, used to log details of mempool in statedump */ - char *statedump_path; + char *statedump_path; struct mem_pool *dict_pool; struct mem_pool *dict_pair_pool; @@ -401,9 +432,12 @@ struct _glusterfs_ctx { call to fsd-mgmt */ gf_log_handle_t log; /* all logging related variables */ - int mem_acct_enable; + int mem_acct_enable; int daemon_pipe[2]; + + struct client_disconnect *client_disconnect; + struct clienttable *clienttable; }; typedef struct _glusterfs_ctx glusterfs_ctx_t; @@ -427,6 +461,7 @@ typedef enum { GF_EVENT_AUTH_FAILED, GF_EVENT_VOLUME_DEFRAG, GF_EVENT_PARENT_DOWN, + GF_EVENT_VOLUME_BARRIER_OP, GF_EVENT_MAXVAL, } glusterfs_event_t; diff --git a/libglusterfs/src/graph.c b/libglusterfs/src/graph.c index 8a84d4cbc..e76df1ca5 100644 --- a/libglusterfs/src/graph.c +++ b/libglusterfs/src/graph.c @@ -213,6 +213,21 @@ glusterfs_graph_mac_compat (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx) return ret; } +int +glusterfs_graph_gfid_access (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx) +{ + int ret = 0; + cmd_args_t *cmd_args = NULL; + + cmd_args = &ctx->cmd_args; + + if (!cmd_args->aux_gfid_mount) + return 0; + + ret = glusterfs_graph_insert (graph, ctx, "features/gfid-access", + "gfid-access-autoload", 1); + return ret; +} static void gf_add_cmdline_options (glusterfs_graph_t *graph, cmd_args_t *cmd_args) @@ -441,6 +456,14 @@ glusterfs_graph_prepare (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx) return -1; } + /* XXX: gfid-access */ + ret = glusterfs_graph_gfid_access (graph, ctx); + if (ret) { + gf_log ("graph", GF_LOG_ERROR, + "glusterfs graph 'gfid-access' failed"); + return -1; + } + /* XXX: this->ctx setting */ for (trav = graph->first; trav; trav = trav->next) { trav->ctx = ctx; @@ -514,6 +537,184 @@ glusterfs_graph_activate (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx) int +xlator_equal_rec (xlator_t *xl1, xlator_t *xl2) +{ + xlator_list_t *trav1 = NULL; + xlator_list_t *trav2 = NULL; + int ret = 0; + + if (xl1 == NULL || xl2 == NULL) { + gf_log ("xlator", GF_LOG_DEBUG, "invalid argument"); + return -1; + } + + trav1 = xl1->children; + trav2 = xl2->children; + + while (trav1 && trav2) { + ret = xlator_equal_rec (trav1->xlator, trav2->xlator); + if (ret) { + gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG, + "xlators children not equal"); + goto out; + } + + trav1 = trav1->next; + trav2 = trav2->next; + } + + if (trav1 || trav2) { + ret = -1; + goto out; + } + + if (strcmp (xl1->name, xl2->name)) { + ret = -1; + goto out; + } + + /* type could have changed even if xlator names match, + e.g cluster/distrubte and cluster/nufa share the same + xlator name + */ + if (strcmp (xl1->type, xl2->type)) { + ret = -1; + goto out; + } +out : + return ret; +} + + +gf_boolean_t +is_graph_topology_equal (glusterfs_graph_t *graph1, glusterfs_graph_t *graph2) +{ + xlator_t *trav1 = NULL; + xlator_t *trav2 = NULL; + gf_boolean_t ret = _gf_true; + + trav1 = graph1->first; + trav2 = graph2->first; + + ret = xlator_equal_rec (trav1, trav2); + + if (ret) { + gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG, + "graphs are not equal"); + ret = _gf_false; + goto out; + } + + ret = _gf_true; + gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG, + "graphs are equal"); + +out: + return ret; +} + + +/* Function has 3types of return value 0, -ve , 1 + * return 0 =======> reconfiguration of options has succeeded + * return 1 =======> the graph has to be reconstructed and all the xlators should be inited + * return -1(or -ve) =======> Some Internal Error occurred during the operation + */ +int +glusterfs_volfile_reconfigure (int oldvollen, FILE *newvolfile_fp, + glusterfs_ctx_t *ctx, const char *oldvolfile) +{ + glusterfs_graph_t *oldvolfile_graph = NULL; + glusterfs_graph_t *newvolfile_graph = NULL; + FILE *oldvolfile_fp = NULL; + gf_boolean_t active_graph_found = _gf_true; + + int ret = -1; + + if (!oldvollen) { + ret = 1; // Has to call INIT for the whole graph + goto out; + } + + if (!ctx) { + gf_log ("glusterfsd-mgmt", GF_LOG_ERROR, + "ctx is NULL"); + goto out; + } + + oldvolfile_graph = ctx->active; + if (!oldvolfile_graph) { + active_graph_found = _gf_false; + gf_log ("glusterfsd-mgmt", GF_LOG_ERROR, + "glusterfs_ctx->active is NULL"); + + oldvolfile_fp = tmpfile (); + if (!oldvolfile_fp) { + gf_log ("glusterfsd-mgmt", GF_LOG_ERROR, "Unable to " + "create temporary volfile: (%s)", + strerror (errno)); + goto out; + } + + fwrite (oldvolfile, oldvollen, 1, oldvolfile_fp); + fflush (oldvolfile_fp); + if (ferror (oldvolfile_fp)) { + goto out; + } + + oldvolfile_graph = glusterfs_graph_construct (oldvolfile_fp); + if (!oldvolfile_graph) + goto out; + } + + newvolfile_graph = glusterfs_graph_construct (newvolfile_fp); + if (!newvolfile_graph) { + goto out; + } + + if (!is_graph_topology_equal (oldvolfile_graph, + newvolfile_graph)) { + + ret = 1; + gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG, + "Graph topology not equal(should call INIT)"); + goto out; + } + + gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG, + "Only options have changed in the new " + "graph"); + + /* */ + ret = glusterfs_graph_reconfigure (oldvolfile_graph, + newvolfile_graph); + if (ret) { + gf_log ("glusterfsd-mgmt", GF_LOG_DEBUG, + "Could not reconfigure new options in old graph"); + goto out; + } + + ret = 0; +out: + if (oldvolfile_fp) + fclose (oldvolfile_fp); + + /* Do not simply destroy the old graph here. If the oldgraph + is constructed here in this function itself instead of getting + it from ctx->active (which happens only of ctx->active is NULL), + then destroy the old graph. If some i/o is still happening in + the old graph and the old graph is obtained from ctx->active, + then destroying the graph will cause problems. + */ + if (!active_graph_found && oldvolfile_graph) + glusterfs_graph_destroy (oldvolfile_graph); + if (newvolfile_graph) + glusterfs_graph_destroy (newvolfile_graph); + + return ret; +} + + +int glusterfs_graph_reconfigure (glusterfs_graph_t *oldgraph, glusterfs_graph_t *newgraph) { @@ -539,5 +740,12 @@ glusterfs_graph_reconfigure (glusterfs_graph_t *oldgraph, int glusterfs_graph_destroy (glusterfs_graph_t *graph) { + xlator_tree_free (graph->first); + + if (graph) { + list_del_init (&graph->list); + GF_FREE (graph); + } + return 0; } diff --git a/libglusterfs/src/graph.l b/libglusterfs/src/graph.l index ff34f6ef1..e4eba9cbe 100644 --- a/libglusterfs/src/graph.l +++ b/libglusterfs/src/graph.l @@ -70,10 +70,10 @@ TYPE [t][y][p][e] yyunput (0, NULL); } BEGIN (INITIAL); - yylval = text; + graphyylval = text; return STRING_TOK; } } -[^ \t\r\n\"\\]+ { yylval = gf_strdup (yytext) ; return ID; } +[^ \t\r\n\"\\]+ { graphyylval = gf_strdup (yytext) ; return ID; } [ \t\r\n]+ ; %% diff --git a/libglusterfs/src/graph.y b/libglusterfs/src/graph.y index e2f16ff71..a220abeb9 100644 --- a/libglusterfs/src/graph.y +++ b/libglusterfs/src/graph.y @@ -18,6 +18,7 @@ #include <sys/mman.h> #include <sys/types.h> #include <sys/wait.h> +#include <pthread.h> #define RELAX_POISONING @@ -37,8 +38,8 @@ static void option_error (void); #define YYSTYPE char * #define GF_CMD_BUFFER_LEN (8 * GF_UNIT_KB) -int yyerror (const char *); -int yylex (); +int graphyyerror (const char *); +int graphyylex (); %} @@ -78,11 +79,11 @@ glusterfs_graph_t *construct; static void type_error (void) { - extern int yylineno; + extern int graphyylineno; gf_log ("parser", GF_LOG_ERROR, "Volume %s, before line %d: Please specify volume type", - curr->name, yylineno); + curr->name, graphyylineno); return; } @@ -90,11 +91,11 @@ type_error (void) static void sub_error (void) { - extern int yylineno; + extern int graphyylineno; gf_log ("parser", GF_LOG_ERROR, "Volume %s, before line %d: Please specify subvolumes", - curr->name, yylineno); + curr->name, graphyylineno); return; } @@ -102,12 +103,12 @@ sub_error (void) static void option_error (void) { - extern int yylineno; + extern int graphyylineno; gf_log ("parser", GF_LOG_ERROR, "Volume %s, before line %d: Please specify " "option <key> <value>", - curr->name, yylineno); + curr->name, graphyylineno); return; } @@ -115,7 +116,7 @@ option_error (void) static int new_volume (char *name) { - extern int yylineno; + extern int graphyylineno; xlator_t *trav = NULL; int ret = 0; @@ -129,7 +130,7 @@ new_volume (char *name) if (curr) { gf_log ("parser", GF_LOG_ERROR, "new volume (%s) defintion in line %d unexpected", - name, yylineno); + name, graphyylineno); ret = -1; goto out; } @@ -149,7 +150,7 @@ new_volume (char *name) if (!strcmp (name, trav->name)) { gf_log ("parser", GF_LOG_ERROR, "Line %d: volume '%s' defined again", - yylineno, name); + graphyylineno, name); ret = -1; goto out; } @@ -194,7 +195,7 @@ out: static int volume_type (char *type) { - extern int yylineno; + extern int graphyylineno; int32_t ret = 0; if (!type) { @@ -208,7 +209,7 @@ volume_type (char *type) gf_log ("parser", GF_LOG_ERROR, "Volume '%s', line %d: type '%s' is not valid or " "not found on this machine", - curr->name, yylineno, type); + curr->name, graphyylineno, type); ret = -1; goto out; } @@ -225,7 +226,7 @@ out: static int volume_option (char *key, char *value) { - extern int yylineno; + extern int graphyylineno; int ret = 0; char *set_value = NULL; @@ -242,7 +243,7 @@ volume_option (char *key, char *value) gf_log ("parser", GF_LOG_ERROR, "Volume '%s', line %d: duplicate entry " "('option %s') present", - curr->name, yylineno, key); + curr->name, graphyylineno, key); ret = -1; goto out; } @@ -261,7 +262,7 @@ out: static int volume_sub (char *sub) { - extern int yylineno; + extern int graphyylineno; xlator_t *trav = NULL; int ret = 0; @@ -283,7 +284,7 @@ volume_sub (char *sub) gf_log ("parser", GF_LOG_ERROR, "Volume '%s', line %d: subvolume '%s' is not defined " "prior to usage", - curr->name, yylineno, sub); + curr->name, graphyylineno, sub); ret = -1; goto out; } @@ -291,7 +292,7 @@ volume_sub (char *sub) if (trav == curr) { gf_log ("parser", GF_LOG_ERROR, "Volume '%s', line %d: has '%s' itself as subvolume", - curr->name, yylineno, sub); + curr->name, graphyylineno, sub); ret = -1; goto out; } @@ -328,46 +329,46 @@ volume_end (void) int -yywrap () +graphyywrap () { return 1; } int -yyerror (const char *str) +graphyyerror (const char *str) { - extern char *yytext; - extern int yylineno; + extern char *graphyytext; + extern int graphyylineno; - if (curr && curr->name && yytext) { - if (!strcmp (yytext, "volume")) { + if (curr && curr->name && graphyytext) { + if (!strcmp (graphyytext, "volume")) { gf_log ("parser", GF_LOG_ERROR, "'end-volume' not defined for volume '%s'", curr->name); - } else if (!strcmp (yytext, "type")) { + } else if (!strcmp (graphyytext, "type")) { gf_log ("parser", GF_LOG_ERROR, "line %d: duplicate 'type' defined for " "volume '%s'", - yylineno, curr->name); - } else if (!strcmp (yytext, "subvolumes")) { + graphyylineno, curr->name); + } else if (!strcmp (graphyytext, "subvolumes")) { gf_log ("parser", GF_LOG_ERROR, "line %d: duplicate 'subvolumes' defined for " "volume '%s'", - yylineno, curr->name); + graphyylineno, curr->name); } else if (curr) { gf_log ("parser", GF_LOG_ERROR, "syntax error: line %d (volume '%s'): \"%s\"" "\nallowed tokens are 'volume', 'type', " "'subvolumes', 'option', 'end-volume'()", - yylineno, curr->name, - yytext); + graphyylineno, curr->name, + graphyytext); } else { gf_log ("parser", GF_LOG_ERROR, "syntax error: line %d (just after volume " "'%s'): \"%s\"\n(%s)", - yylineno, curr->name, - yytext, + graphyylineno, curr->name, + graphyytext, "allowed tokens are 'volume', 'type', " "'subvolumes', 'option', 'end-volume'"); } @@ -376,7 +377,7 @@ yyerror (const char *str) "syntax error in line %d: \"%s\" \n" "(allowed tokens are 'volume', 'type', " "'subvolumes', 'option', 'end-volume')\n", - yylineno, yytext); + graphyylineno, graphyytext); } return -1; @@ -481,6 +482,7 @@ preprocess (FILE *srcfp, FILE *dstfp) cmd_buf_size *= 2; cmd = GF_REALLOC (cmd, cmd_buf_size); if (cmd == NULL) { + GF_FREE (result); return -1; } @@ -522,6 +524,7 @@ preprocess (FILE *srcfp, FILE *dstfp) out: fseek (srcfp, 0L, SEEK_SET); fseek (dstfp, 0L, SEEK_SET); + GF_FREE (cmd); GF_FREE (result); @@ -529,7 +532,7 @@ out: } -extern FILE *yyin; +extern FILE *graphyyin; glusterfs_graph_t * glusterfs_graph_new () @@ -557,6 +560,7 @@ glusterfs_graph_construct (FILE *fp) glusterfs_graph_t *graph = NULL; FILE *tmp_file = NULL; char template[PATH_MAX] = {0}; + static pthread_mutex_t graph_mutex = PTHREAD_MUTEX_INITIALIZER; graph = glusterfs_graph_new (); if (!graph) @@ -583,10 +587,14 @@ glusterfs_graph_construct (FILE *fp) goto err; } - yyin = tmp_file; - construct = graph; - ret = yyparse (); - construct = NULL; + pthread_mutex_lock (&graph_mutex); + { + graphyyin = tmp_file; + construct = graph; + ret = yyparse (); + construct = NULL; + } + pthread_mutex_unlock (&graph_mutex); if (ret == 1) { gf_log ("parser", GF_LOG_DEBUG, diff --git a/libglusterfs/src/inode.c b/libglusterfs/src/inode.c index 6f1c8ec3f..15e0ccf78 100644 --- a/libglusterfs/src/inode.c +++ b/libglusterfs/src/inode.c @@ -310,7 +310,7 @@ __inode_destroy (inode_t *inode) goto noctx; } - for (index = 0; index < inode->table->xl->graph->xl_count; index++) { + for (index = 0; index < inode->table->ctxcount; index++) { if (inode->_ctx[index].xl_key) { xl = (xlator_t *)(long)inode->_ctx[index].xl_key; old_THIS = THIS; @@ -528,10 +528,9 @@ __inode_create (inode_table_t *table) INIT_LIST_HEAD (&newi->hash); INIT_LIST_HEAD (&newi->dentry_list); - newi->_ctx = GF_CALLOC (1, (sizeof (struct _inode_ctx) * - table->xl->graph->xl_count), + newi->_ctx = GF_CALLOC (1, + (sizeof (struct _inode_ctx) * table->ctxcount), gf_common_mt_inode_ctx); - if (newi->_ctx == NULL) { LOCK_DESTROY (&newi->lock); mem_put (newi); @@ -1316,6 +1315,7 @@ inode_table_new (size_t lru_limit, xlator_t *xl) return NULL; new->xl = xl; + new->ctxcount = xl->graph->xl_count + 1; new->lru_limit = lru_limit; @@ -1466,7 +1466,7 @@ __inode_ctx_set2 (inode_t *inode, xlator_t *xlator, uint64_t *value1_p, if (!inode || !xlator) return -1; - for (index = 0; index < xlator->graph->xl_count; index++) { + for (index = 0; index < inode->table->ctxcount; index++) { if (!inode->_ctx[index].xl_key) { if (set_idx == -1) set_idx = index; @@ -1493,6 +1493,18 @@ out: return ret; } +int +__inode_ctx_set0 (inode_t *inode, xlator_t *xlator, uint64_t *value1_p) +{ + return __inode_ctx_set2 (inode, xlator, value1_p, NULL); +} + +int +__inode_ctx_set1 (inode_t *inode, xlator_t *xlator, uint64_t *value2_p) +{ + return __inode_ctx_set2 (inode, xlator, NULL, value2_p); +} + int inode_ctx_set2 (inode_t *inode, xlator_t *xlator, uint64_t *value1_p, @@ -1512,34 +1524,97 @@ inode_ctx_set2 (inode_t *inode, xlator_t *xlator, uint64_t *value1_p, return ret; } +int +inode_ctx_set1 (inode_t *inode, xlator_t *xlator, uint64_t *value2_p) +{ + int ret = 0; + + if (!inode || !xlator) + return -1; + + LOCK (&inode->lock); + { + ret = __inode_ctx_set1 (inode, xlator, value2_p); + } + UNLOCK (&inode->lock); + + return ret; +} +int +inode_ctx_set0 (inode_t *inode, xlator_t *xlator, uint64_t *value1_p) +{ + int ret = 0; + + if (!inode || !xlator) + return -1; + + LOCK (&inode->lock); + { + ret = __inode_ctx_set0 (inode, xlator, value1_p); + } + UNLOCK (&inode->lock); + + return ret; +} + int __inode_ctx_get2 (inode_t *inode, xlator_t *xlator, uint64_t *value1, uint64_t *value2) { int index = 0; - int ret = 0; + int ret = -1; if (!inode || !xlator) - return -1; + goto out; - for (index = 0; index < xlator->graph->xl_count; index++) { + for (index = 0; index < inode->table->ctxcount; index++) { if (inode->_ctx[index].xl_key == xlator) break; } - if (index == xlator->graph->xl_count) { - ret = -1; + if (index == inode->table->ctxcount) goto out; + + if (inode->_ctx[index].value1) { + if (value1) + *value1 = inode->_ctx[index].value1; + ret = 0; } + if (inode->_ctx[index].value2) { + if (value2) + *value2 = inode->_ctx[index].value2; + ret = 0; + } +out: + return ret; +} - if (value1) - *value1 = inode->_ctx[index].value1; - if (value2) - *value2 = inode->_ctx[index].value2; -out: +int +__inode_ctx_get0 (inode_t *inode, xlator_t *xlator, uint64_t *value1) +{ + uint64_t tmp_value = 0; + int ret = 0; + + ret = __inode_ctx_get2 (inode, xlator, &tmp_value, NULL); + if (!ret) + *value1 = tmp_value; + + return ret; +} + +int +__inode_ctx_get1 (inode_t *inode, xlator_t *xlator, uint64_t *value2) +{ + uint64_t tmp_value = 0; + int ret = 0; + + ret = __inode_ctx_get2 (inode, xlator, NULL, &tmp_value); + if (!ret) + *value2 = tmp_value; + return ret; } @@ -1562,6 +1637,40 @@ inode_ctx_get2 (inode_t *inode, xlator_t *xlator, uint64_t *value1, return ret; } +int +inode_ctx_get1 (inode_t *inode, xlator_t *xlator, uint64_t *value2) +{ + int ret = 0; + + if (!inode || !xlator) + return -1; + + LOCK (&inode->lock); + { + ret = __inode_ctx_get1 (inode, xlator, value2); + } + UNLOCK (&inode->lock); + + return ret; +} + +int +inode_ctx_get0 (inode_t *inode, xlator_t *xlator, uint64_t *value1) +{ + int ret = 0; + + if (!inode || !xlator) + return -1; + + LOCK (&inode->lock); + { + ret = __inode_ctx_get0 (inode, xlator, value1); + } + UNLOCK (&inode->lock); + + return ret; +} + int inode_ctx_del2 (inode_t *inode, xlator_t *xlator, uint64_t *value1, @@ -1575,19 +1684,20 @@ inode_ctx_del2 (inode_t *inode, xlator_t *xlator, uint64_t *value1, LOCK (&inode->lock); { - for (index = 0; index < xlator->graph->xl_count; index++) { + for (index = 0; index < inode->table->ctxcount; + index++) { if (inode->_ctx[index].xl_key == xlator) break; } - if (index == xlator->graph->xl_count) { + if (index == inode->table->ctxcount) { ret = -1; goto unlock; } - if (value1) + if (inode->_ctx[index].value1 && value1) *value1 = inode->_ctx[index].value1; - if (value2) + if (inode->_ctx[index].value2 && value2) *value2 = inode->_ctx[index].value2; inode->_ctx[index].key = 0; @@ -1600,6 +1710,97 @@ unlock: return ret; } +/* function behavior: + - if value1 is set, value1 in ctx is reset to 0 with current value passed + back in value1 address. + - if value2 is set, value2 in ctx is reset to 0 with current value passed + back in value2 address. + - if both are set, both fields are reset. +*/ +static int +__inode_ctx_reset2 (inode_t *inode, xlator_t *xlator, uint64_t *value1, + uint64_t *value2) +{ + int index = 0; + int ret = 0; + + if (!inode || !xlator) + return -1; + + LOCK (&inode->lock); + { + for (index = 0; index < inode->table->ctxcount; + index++) { + if (inode->_ctx[index].xl_key == xlator) + break; + } + + if (index == inode->table->ctxcount) { + ret = -1; + goto unlock; + } + + if (inode->_ctx[index].value1 && value1) { + *value1 = inode->_ctx[index].value1; + inode->_ctx[index].value1 = 0; + } + if (inode->_ctx[index].value2 && value2) { + *value2 = inode->_ctx[index].value2; + inode->_ctx[index].value2 = 0; + } + } +unlock: + UNLOCK (&inode->lock); + + return ret; +} + +int +inode_ctx_reset2 (inode_t *inode, xlator_t *xlator, uint64_t *value1_p, + uint64_t *value2_p) +{ + uint64_t tmp_value1 = 0; + uint64_t tmp_value2 = 0; + int ret = 0; + + ret = __inode_ctx_reset2 (inode, xlator, &tmp_value1, &tmp_value2); + if (!ret) { + if (value1_p) + *value1_p = tmp_value1; + if (value2_p) + *value2_p = tmp_value2; + } + return ret; +} + +int +inode_ctx_reset1 (inode_t *inode, xlator_t *xlator, uint64_t *value2_p) +{ + uint64_t tmp_value2 = 0; + int ret = 0; + + ret = __inode_ctx_reset2 (inode, xlator, NULL, &tmp_value2); + + if (!ret && value2_p) + *value2_p = tmp_value2; + + return ret; + +} +int +inode_ctx_reset0 (inode_t *inode, xlator_t *xlator, uint64_t *value1_p) +{ + uint64_t tmp_value1 = 0; + int ret = 0; + + ret = __inode_ctx_reset2 (inode, xlator, &tmp_value1, NULL); + + if (!ret && value1_p) + *value1_p = tmp_value1; + + return ret; +} + void inode_dump (inode_t *inode, char *prefix) @@ -1628,14 +1829,15 @@ inode_dump (inode_t *inode, char *prefix) gf_proc_dump_write("ref", "%u", inode->ref); gf_proc_dump_write("ia_type", "%d", inode->ia_type); if (inode->_ctx) { - inode_ctx = GF_CALLOC (inode->table->xl->graph->xl_count, + inode_ctx = GF_CALLOC (inode->table->ctxcount, sizeof (*inode_ctx), gf_common_mt_inode_ctx); if (inode_ctx == NULL) { goto unlock; } - for (i = 0; i < inode->table->xl->graph->xl_count; i++) { + for (i = 0; i < inode->table->ctxcount; + i++) { inode_ctx[i] = inode->_ctx[i]; } } @@ -1652,7 +1854,7 @@ unlock: UNLOCK(&inode->lock); if (inode_ctx && (dump_options.xl_options.dump_inodectx == _gf_true)) { - for (i = 0; i < inode->table->xl->graph->xl_count; i++) { + for (i = 0; i < inode->table->ctxcount; i++) { if (inode_ctx[i].xl_key) { xl = (xlator_t *)(long)inode_ctx[i].xl_key; if (xl->dumpops && xl->dumpops->inodectx) diff --git a/libglusterfs/src/inode.h b/libglusterfs/src/inode.h index 199ce4484..a88976265 100644 --- a/libglusterfs/src/inode.h +++ b/libglusterfs/src/inode.h @@ -56,6 +56,7 @@ struct _inode_table { struct mem_pool *inode_pool; /* memory pool for inodes */ struct mem_pool *dentry_pool; /* memory pool for dentrys */ struct mem_pool *fd_mem_pool; /* memory pool for fd_t */ + int ctxcount; /* number of slots in inode->ctx */ }; @@ -72,10 +73,12 @@ struct _inode_ctx { uint64_t key; xlator_t *xl_key; }; + /* if value1 is 0, then field is not set.. */ union { uint64_t value1; void *ptr1; }; + /* if value2 is 0, then field is not set.. */ union { uint64_t value2; void *ptr2; @@ -158,6 +161,11 @@ __inode_path (inode_t *inode, const char *name, char **bufp); inode_t * inode_from_path (inode_table_t *table, const char *path); +inode_t * +inode_resolve (inode_table_t *table, char *path); + +/* deal with inode ctx's both values */ + int inode_ctx_set2 (inode_t *inode, xlator_t *xlator, uint64_t *value1, uint64_t *value2); @@ -176,29 +184,66 @@ int inode_ctx_del2 (inode_t *inode, xlator_t *xlator, uint64_t *value1, uint64_t *value2); -inode_t * -inode_resolve (inode_table_t *table, char *path); +int +inode_ctx_reset2 (inode_t *inode, xlator_t *xlator, uint64_t *value1, + uint64_t *value2); + +/* deal with inode ctx's 1st value */ + +int +inode_ctx_set0 (inode_t *inode, xlator_t *xlator, uint64_t *value1); + +int +__inode_ctx_set0 (inode_t *inode, xlator_t *xlator, uint64_t *value1); + +int +inode_ctx_get0 (inode_t *inode, xlator_t *xlator, uint64_t *value1); +int +__inode_ctx_get0 (inode_t *inode, xlator_t *xlator, uint64_t *value1); + +int +inode_ctx_reset0 (inode_t *inode, xlator_t *xlator, uint64_t *value1); + +/* deal with inode ctx's 2st value */ + +int +inode_ctx_set1 (inode_t *inode, xlator_t *xlator, uint64_t *value2); + +int +__inode_ctx_set1 (inode_t *inode, xlator_t *xlator, uint64_t *value2); + +int +inode_ctx_get1 (inode_t *inode, xlator_t *xlator, uint64_t *value2); +int +__inode_ctx_get1 (inode_t *inode, xlator_t *xlator, uint64_t *value2); + +int +inode_ctx_reset1 (inode_t *inode, xlator_t *xlator, uint64_t *value2); -#define __inode_ctx_set(i,x,v_p) __inode_ctx_set2(i,x,v_p,0) -#define inode_ctx_set(i,x,v_p) inode_ctx_set2(i,x,v_p,0) static inline int __inode_ctx_put(inode_t *inode, xlator_t *this, uint64_t v) { - return __inode_ctx_set2 (inode, this, &v, 0); + return __inode_ctx_set0 (inode, this, &v); } static inline int inode_ctx_put(inode_t *inode, xlator_t *this, uint64_t v) { - return inode_ctx_set2(inode, this, &v, 0); + return inode_ctx_set0 (inode, this, &v); } -#define __inode_ctx_get(i,x,v) __inode_ctx_get2(i,x,v,0) -#define inode_ctx_get(i,x,v) inode_ctx_get2(i,x,v,0) +#define __inode_ctx_set(i,x,v_p) __inode_ctx_set0(i,x,v_p) -#define inode_ctx_del(i,x,v) inode_ctx_del2(i,x,v,0) +#define inode_ctx_set(i,x,v_p) inode_ctx_set0(i,x,v_p) +#define inode_ctx_reset(i,x,v) inode_ctx_reset0(i,x,v) + +#define __inode_ctx_get(i,x,v) __inode_ctx_get0(i,x,v) + +#define inode_ctx_get(i,x,v) inode_ctx_get0(i,x,v) + +#define inode_ctx_del(i,x,v) inode_ctx_del2(i,x,v,0) gf_boolean_t __is_root_gfid (uuid_t gfid); diff --git a/libglusterfs/src/list.h b/libglusterfs/src/list.h index 35fccdf25..392c22ceb 100644 --- a/libglusterfs/src/list.h +++ b/libglusterfs/src/list.h @@ -1,5 +1,5 @@ /* - Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + Copyright (c) 2008-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 @@ -11,7 +11,6 @@ #ifndef _LLIST_H #define _LLIST_H - struct list_head { struct list_head *next; struct list_head *prev; @@ -45,6 +44,31 @@ list_add_tail (struct list_head *new, struct list_head *head) } +/* This function will insert the element to the list in a order. + Order will be based on the compare function provided as a input. + If element to be inserted in ascending order compare should return: + 0: if both the arguments are equal + >0: if first argument is greater than second argument + <0: if first argument is less than second argument */ +static inline void +list_add_order (struct list_head *new, struct list_head *head, + int (*compare)(struct list_head *, struct list_head *)) +{ + struct list_head *pos = head->prev; + + while ( pos != head ) { + if (compare(new, pos) >= 0) + break; + + /* Iterate the list in the reverse order. This will have + better efficiency if the elements are inserted in the + ascending order */ + pos = pos->prev; + } + + list_add (new, pos); +} + static inline void list_del (struct list_head *old) { @@ -175,4 +199,16 @@ list_append_init (struct list_head *list, struct list_head *head) &pos->member != (head); \ pos = n, n = list_entry(n->member.next, typeof(*n), member)) +#define list_for_each_entry_reverse(pos, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.prev, typeof(*pos), member)) + + +#define list_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos = list_entry((head)->prev, typeof(*pos), member), \ + n = list_entry(pos->member.prev, typeof(*pos), member); \ + &pos->member != (head); \ + pos = n, n = list_entry(n->member.prev, typeof(*n), member)) + #endif /* _LLIST_H */ diff --git a/libglusterfs/src/logging.c b/libglusterfs/src/logging.c index 65613f985..5deb90cda 100644 --- a/libglusterfs/src/logging.c +++ b/libglusterfs/src/logging.c @@ -22,6 +22,18 @@ #include <string.h> #include <stdlib.h> +#ifdef GF_USE_SYSLOG +#include <libintl.h> +#include <syslog.h> +#include <sys/stat.h> +#include "gf-error-codes.h" + +#define GF_JSON_MSG_LENGTH 8192 +#define GF_SYSLOG_CEE_FORMAT \ + "@cee: {\"msg\": \"%s\", \"gf_code\": \"%u\", \"gf_message\": \"%s\"}" +#define GF_LOG_CONTROL_FILE "/etc/glusterfs/logger.conf" +#endif /* GF_USE_SYSLOG */ + #include "xlator.h" #include "logging.h" #include "defaults.h" @@ -102,6 +114,207 @@ gf_log_fini (void) } +#ifdef GF_USE_SYSLOG +/** + * gf_get_error_message -function to get error message for given error code + * @error_code: error code defined by log book + * + * @return: success: string + * failure: NULL + */ +const char * +gf_get_error_message (int error_code) { + return _gf_get_message (error_code); +} + + +/** + * gf_openlog -function to open syslog specific to gluster based on + * existence of file /etc/glusterfs/logger.conf + * @ident: optional identification string similar to openlog() + * @option: optional value to option to openlog(). Passing -1 uses + * 'LOG_PID | LOG_NDELAY' as default + * @facility: optional facility code similar to openlog(). Passing -1 + * uses LOG_DAEMON as default + * + * @return: void + */ +void +gf_openlog (const char *ident, int option, int facility) +{ + int _option = option; + int _facility = facility; + + if (-1 == _option) { + _option = LOG_PID | LOG_NDELAY; + } + if (-1 == _facility) { + _facility = LOG_LOCAL1; + } + + setlocale(LC_ALL, ""); + bindtextdomain("gluster", "/usr/share/locale"); + textdomain("gluster"); + + openlog(ident, _option, _facility); +} + + +/** + * _json_escape -function to convert string to json encoded string + * @str: input string + * @buf: buffer to store encoded string + * @len: length of @buf + * + * @return: success: last unprocessed character position by pointer in @str + * failure: NULL + * + * Internal function. Heavily inspired by _ul_str_escape() function in + * libumberlog + * + * Sample output: + * [1] str = "devel error" + * buf = "devel error" + * [2] str = "devel error" + * buf = "devel\terror" + * [3] str = "I/O error on "/tmp/foo" file" + * buf = "I/O error on \"/tmp/foo\" file" + * [4] str = "I/O erroron /tmp/bar file" + * buf = "I/O error\u001bon /tmp/bar file" + * + */ +char * +_json_escape(const char *str, char *buf, size_t len) +{ + static const unsigned char json_exceptions[UCHAR_MAX + 1] = + { + [0x01] = 1, [0x02] = 1, [0x03] = 1, [0x04] = 1, + [0x05] = 1, [0x06] = 1, [0x07] = 1, [0x08] = 1, + [0x09] = 1, [0x0a] = 1, [0x0b] = 1, [0x0c] = 1, + [0x0d] = 1, [0x0e] = 1, [0x0f] = 1, [0x10] = 1, + [0x11] = 1, [0x12] = 1, [0x13] = 1, [0x14] = 1, + [0x15] = 1, [0x16] = 1, [0x17] = 1, [0x18] = 1, + [0x19] = 1, [0x1a] = 1, [0x1b] = 1, [0x1c] = 1, + [0x1d] = 1, [0x1e] = 1, [0x1f] = 1, + ['\\'] = 1, ['"'] = 1 + }; + static const char json_hex_chars[16] = "0123456789abcdef"; + unsigned char *p = NULL; + size_t pos = 0; + + if (!str || !buf || len <= 0) { + return NULL; + } + + for (p = (unsigned char *)str; + *p && (pos + 1) < len; + p++) + { + if (json_exceptions[*p] == 0) { + buf[pos++] = *p; + continue; + } + + if ((pos + 2) >= len) { + break; + } + + switch (*p) + { + case '\b': + buf[pos++] = '\\'; + buf[pos++] = 'b'; + break; + case '\n': + buf[pos++] = '\\'; + buf[pos++] = 'n'; + break; + case '\r': + buf[pos++] = '\\'; + buf[pos++] = 'r'; + break; + case '\t': + buf[pos++] = '\\'; + buf[pos++] = 't'; + break; + case '\\': + buf[pos++] = '\\'; + buf[pos++] = '\\'; + break; + case '"': + buf[pos++] = '\\'; + buf[pos++] = '"'; + break; + default: + if ((pos + 6) >= len) { + buf[pos] = '\0'; + return (char *)p; + } + buf[pos++] = '\\'; + buf[pos++] = 'u'; + buf[pos++] = '0'; + buf[pos++] = '0'; + buf[pos++] = json_hex_chars[(*p) >> 4]; + buf[pos++] = json_hex_chars[(*p) & 0xf]; + break; + } + } + + buf[pos] = '\0'; + return (char *)p; +} + + +/** + * gf_syslog -function to submit message to syslog specific to gluster + * @error_code: error code defined by log book + * @facility_priority: facility_priority of syslog() + * @format: optional format string to syslog() + * + * @return: void + */ +void +gf_syslog (int error_code, int facility_priority, char *format, ...) +{ + char *msg = NULL; + char json_msg[GF_JSON_MSG_LENGTH]; + GF_UNUSED char *p = NULL; + const char *error_message = NULL; + char json_error_message[GF_JSON_MSG_LENGTH]; + va_list ap; + + error_message = gf_get_error_message (error_code); + + va_start (ap, format); + if (format) { + vasprintf (&msg, format, ap); + p = _json_escape (msg, json_msg, GF_JSON_MSG_LENGTH); + if (error_message) { + p = _json_escape (error_message, json_error_message, + GF_JSON_MSG_LENGTH); + syslog (facility_priority, GF_SYSLOG_CEE_FORMAT, + json_msg, error_code, json_error_message); + } else { + /* ignore the error code because no error message for it + and use normal syslog */ + syslog (facility_priority, "%s", msg); + } + free (msg); + } else { + if (error_message) { + /* no user message: treat error_message as msg */ + syslog (facility_priority, GF_SYSLOG_CEE_FORMAT, + json_error_message, error_code, + json_error_message); + } else { + /* cannot produce log as neither error_message nor + msg available */ + } + } + va_end (ap); +} +#endif /* GF_USE_SYSLOG */ + void gf_log_globals_init (void *data) { @@ -113,21 +326,47 @@ gf_log_globals_init (void *data) ctx->log.gf_log_syslog = 1; ctx->log.sys_log_level = GF_LOG_CRITICAL; +#ifndef GF_USE_SYSLOG #ifdef GF_LINUX_HOST_OS /* For the 'syslog' output. one can grep 'GlusterFS' in syslog for serious logs */ openlog ("GlusterFS", LOG_PID, LOG_DAEMON); #endif +#endif } int -gf_log_init (void *data, const char *file) +gf_log_init (void *data, const char *file, const char *ident) { glusterfs_ctx_t *ctx = NULL; int fd = -1; ctx = data; +#if defined(GF_USE_SYSLOG) + { + /* use default ident and option */ + /* TODO: make FACILITY configurable than LOG_DAEMON */ + struct stat buf; + + if (stat (GF_LOG_CONTROL_FILE, &buf) == 0) { + /* use syslog logging */ + ctx->log.log_control_file_found = 1; + if (ident) { + /* we need to keep this value as */ + /* syslog uses it on every logging */ + ctx->log.ident = gf_strdup (ident); + gf_openlog (ctx->log.ident, -1, LOG_DAEMON); + } else { + gf_openlog (NULL, -1, LOG_DAEMON); + } + } else { + /* use old style logging */ + ctx->log.log_control_file_found = 0; + } + } +#endif + if (!file){ fprintf (stderr, "ERROR: no filename specified\n"); return -1; @@ -135,7 +374,7 @@ gf_log_init (void *data, const char *file) if (strcmp (file, "-") == 0) { ctx->log.gf_log_logfile = stderr; - + ctx->log.logfile = stderr; return 0; } @@ -215,6 +454,12 @@ _gf_log_nomem (const char *domain, const char *file, return -1; } + basename = strrchr (file, '/'); + if (basename) + basename++; + else + basename = file; + #if HAVE_BACKTRACE /* Print 'calling function' */ do { @@ -241,6 +486,25 @@ _gf_log_nomem (const char *domain, const char *file, } while (0); #endif /* HAVE_BACKTRACE */ +#if defined(GF_USE_SYSLOG) + if (ctx->log.log_control_file_found) + { + int priority; + /* treat GF_LOG_TRACE and GF_LOG_NONE as LOG_DEBUG and + other level as is */ + if (GF_LOG_TRACE == level || GF_LOG_NONE == level) { + priority = LOG_DEBUG; + } else { + priority = level - 1; + } + gf_syslog (GF_ERR_DEV, priority, + "[%s:%d:%s] %s %s: no memory " + "available for size (%"GF_PRI_SIZET")", + basename, line, function, callstr, domain, + size); + goto out; + } +#endif /* GF_USE_SYSLOG */ ret = gettimeofday (&tv, NULL); if (-1 == ret) goto out; @@ -248,12 +512,6 @@ _gf_log_nomem (const char *domain, const char *file, snprintf (timestr + strlen (timestr), sizeof timestr - strlen (timestr), ".%"GF_PRI_SUSECONDS, tv.tv_usec); - basename = strrchr (file, '/'); - if (basename) - basename++; - else - basename = file; - ret = sprintf (msg, "[%s] %s [%s:%d:%s] %s %s: no memory " "available for size (%"GF_PRI_SIZET")", timestr, level_strings[level], @@ -331,6 +589,12 @@ _gf_log_callingfn (const char *domain, const char *file, const char *function, return -1; } + basename = strrchr (file, '/'); + if (basename) + basename++; + else + basename = file; + #if HAVE_BACKTRACE /* Print 'calling function' */ do { @@ -357,6 +621,32 @@ _gf_log_callingfn (const char *domain, const char *file, const char *function, } while (0); #endif /* HAVE_BACKTRACE */ +#if defined(GF_USE_SYSLOG) + if (ctx->log.log_control_file_found) + { + int priority; + /* treat GF_LOG_TRACE and GF_LOG_NONE as LOG_DEBUG and + other level as is */ + if (GF_LOG_TRACE == level || GF_LOG_NONE == level) { + priority = LOG_DEBUG; + } else { + priority = level - 1; + } + + va_start (ap, fmt); + vasprintf (&str2, fmt, ap); + va_end (ap); + + gf_syslog (GF_ERR_DEV, priority, + "[%s:%d:%s] %s %d-%s: %s", + basename, line, function, + callstr, + ((this->graph) ? this->graph->id:0), domain, + str2); + + goto out; + } +#endif /* GF_USE_SYSLOG */ ret = gettimeofday (&tv, NULL); if (-1 == ret) goto out; @@ -365,12 +655,6 @@ _gf_log_callingfn (const char *domain, const char *file, const char *function, snprintf (timestr + strlen (timestr), sizeof timestr - strlen (timestr), ".%"GF_PRI_SUSECONDS, tv.tv_usec); - basename = strrchr (file, '/'); - if (basename) - basename++; - else - basename = file; - ret = gf_asprintf (&str1, "[%s] %s [%s:%d:%s] %s %d-%s: ", timestr, level_strings[level], basename, line, function, callstr, @@ -468,6 +752,35 @@ _gf_log (const char *domain, const char *file, const char *function, int line, return -1; } + basename = strrchr (file, '/'); + if (basename) + basename++; + else + basename = file; + +#if defined(GF_USE_SYSLOG) + if (ctx->log.log_control_file_found) + { + int priority; + /* treat GF_LOG_TRACE and GF_LOG_NONE as LOG_DEBUG and + other level as is */ + if (GF_LOG_TRACE == level || GF_LOG_NONE == level) { + priority = LOG_DEBUG; + } else { + priority = level - 1; + } + + va_start (ap, fmt); + vasprintf (&str2, fmt, ap); + va_end (ap); + + gf_syslog (GF_ERR_DEV, priority, + "[%s:%d:%s] %d-%s: %s", + basename, line, function, + ((this->graph) ? this->graph->id:0), domain, str2); + goto err; + } +#endif /* GF_USE_SYSLOG */ if (ctx->log.logrotate) { ctx->log.logrotate = 0; @@ -509,12 +822,6 @@ log: snprintf (timestr + strlen (timestr), sizeof timestr - strlen (timestr), ".%"GF_PRI_SUSECONDS, tv.tv_usec); - basename = strrchr (file, '/'); - if (basename) - basename++; - else - basename = file; - ret = gf_asprintf (&str1, "[%s] %s [%s:%d:%s] %d-%s: ", timestr, level_strings[level], basename, line, function, diff --git a/libglusterfs/src/logging.h b/libglusterfs/src/logging.h index d08f944cc..cc806a767 100644 --- a/libglusterfs/src/logging.h +++ b/libglusterfs/src/logging.h @@ -35,6 +35,7 @@ #define GF_PRI_BLKSIZE PRId32 #define GF_PRI_SIZET "zu" + #if 0 /* Syslog definitions :-) */ #define LOG_EMERG 0 /* system is unusable */ @@ -60,6 +61,9 @@ typedef enum { GF_LOG_TRACE, /* full trace of operation */ } gf_loglevel_t; +#define DEFAULT_LOG_FILE_DIRECTORY DATADIR "/log/glusterfs" +#define DEFAULT_LOG_LEVEL GF_LOG_INFO + typedef struct gf_log_handle_ { pthread_mutex_t logfile_mutex; uint8_t logrotate; @@ -72,11 +76,15 @@ typedef struct gf_log_handle_ { FILE *gf_log_logfile; char *cmd_log_filename; FILE *cmdlogfile; +#ifdef GF_USE_SYSLOG + int log_control_file_found; + char *ident; +#endif /* GF_USE_SYSLOG */ } gf_log_handle_t; void gf_log_globals_init (void *ctx); -int gf_log_init (void *data, const char *filename); +int gf_log_init (void *data, const char *filename, const char *ident); void gf_log_logrotate (int signum); diff --git a/libglusterfs/src/mem-pool.h b/libglusterfs/src/mem-pool.h index 939b4f2a7..31f49f75c 100644 --- a/libglusterfs/src/mem-pool.h +++ b/libglusterfs/src/mem-pool.h @@ -148,7 +148,7 @@ char * gf_strdup (const char *src) } static inline void * -gf_memdup (const void *src, void *dst, size_t size) +gf_memdup (const void *src, size_t size) { void *dup_mem = NULL; diff --git a/libglusterfs/src/mem-types.h b/libglusterfs/src/mem-types.h index 12379bf31..666bd120a 100644 --- a/libglusterfs/src/mem-types.h +++ b/libglusterfs/src/mem-types.h @@ -102,6 +102,24 @@ enum gf_common_mem_types_ { gf_common_mt_buffer_t = 86, gf_common_mt_circular_buffer_t = 87, gf_common_mt_eh_t = 88, - gf_common_mt_end = 89 + gf_common_mt_store_handle_t = 89, + gf_common_mt_store_iter_t = 90, + gf_common_mt_drc_client_t = 91, + gf_common_mt_drc_globals_t = 92, + gf_common_mt_drc_rbtree_node_t = 93, + gf_common_mt_iov_base_t = 94, + gf_common_mt_groups_t = 95, + gf_common_mt_cliententry_t = 96, + gf_common_mt_clienttable_t = 97, + gf_common_mt_client_t = 98, + gf_common_mt_client_ctx = 99, + gf_common_mt_lock_table = 100, + gf_common_mt_locker = 101, + gf_common_mt_auxgids = 102, + gf_common_mt_syncopctx = 103, + gf_common_mt_uuid_t = 104, + gf_common_mt_mgmt_v3_lock_obj_t = 105, + gf_common_mt_txn_opinfo_obj_t = 106, + gf_common_mt_end = 107 }; #endif diff --git a/libglusterfs/src/options.c b/libglusterfs/src/options.c index 5d436bab3..842b6413a 100644 --- a/libglusterfs/src/options.c +++ b/libglusterfs/src/options.c @@ -761,7 +761,7 @@ out: } -static volume_option_t * +volume_option_t * xlator_volume_option_get_list (volume_opt_list_t *vol_list, const char *key) { volume_option_t *opt = NULL; @@ -1098,7 +1098,6 @@ pc_or_size (char *in, double *out) return ret; } - DEFINE_INIT_OPT(char *, str, pass); DEFINE_INIT_OPT(uint64_t, uint64, gf_string2uint64); DEFINE_INIT_OPT(int64_t, int64, gf_string2int64); diff --git a/libglusterfs/src/options.h b/libglusterfs/src/options.h index 64c2c64ef..e2a25baa9 100644 --- a/libglusterfs/src/options.h +++ b/libglusterfs/src/options.h @@ -93,6 +93,9 @@ int xlator_options_validate (xlator_t *xl, dict_t *options, char **errstr); volume_option_t * xlator_volume_option_get (xlator_t *xl, const char *key); +volume_option_t * +xlator_volume_option_get_list (volume_opt_list_t *vol_list, const char *key); + #define DECLARE_INIT_OPT(type_t, type) \ int \ diff --git a/libglusterfs/src/run.c b/libglusterfs/src/run.c index ebe7f3962..4fd2a3a0d 100644 --- a/libglusterfs/src/run.c +++ b/libglusterfs/src/run.c @@ -187,7 +187,7 @@ runner_log (runner_t *runner, const char *dom, gf_loglevel_t lvl, if (len > 0) buf[len - 1] = '\0'; - gf_log (dom, lvl, "%s: %s", msg, buf); + gf_log_callingfn (dom, lvl, "%s: %s", msg, buf); GF_FREE (buf); } diff --git a/libglusterfs/src/stack.h b/libglusterfs/src/stack.h index a91b635e4..f2d2ef950 100644 --- a/libglusterfs/src/stack.h +++ b/libglusterfs/src/stack.h @@ -25,8 +25,8 @@ struct _call_stack_t; typedef struct _call_stack_t call_stack_t; struct _call_frame_t; typedef struct _call_frame_t call_frame_t; -struct _call_pool_t; -typedef struct _call_pool_t call_pool_t; +struct call_pool; +typedef struct call_pool call_pool_t; #include <sys/time.h> @@ -36,6 +36,7 @@ typedef struct _call_pool_t call_pool_t; #include "common-utils.h" #include "globals.h" #include "lkowner.h" +#include "client_t.h" #define NFS_PID 1 #define LOW_PRIO_PROC_PID -1 @@ -46,7 +47,7 @@ typedef int32_t (*ret_fn_t) (call_frame_t *frame, int32_t op_errno, ...); -struct _call_pool_t { +struct call_pool { union { struct list_head all_frames; struct { @@ -82,6 +83,8 @@ struct _call_frame_t { const char *unwind_to; }; +#define SMALL_GROUP_COUNT 128 + struct _call_stack_t { union { struct list_head all_frames; @@ -92,14 +95,16 @@ struct _call_stack_t { }; call_pool_t *pool; gf_lock_t stack_lock; - void *trans; + client_t *client; uint64_t unique; void *state; /* pointer to request state */ uid_t uid; gid_t gid; pid_t pid; uint16_t ngrps; - uint32_t groups[GF_MAX_AUX_GROUPS]; + uint32_t groups_small[SMALL_GROUP_COUNT]; + uint32_t *groups_large; + uint32_t *groups; gf_lkowner_t lk_owner; glusterfs_ctx_t *ctx; @@ -174,6 +179,9 @@ STACK_DESTROY (call_stack_t *stack) while (stack->frames.next) { FRAME_DESTROY (stack->frames.next); } + + GF_FREE (stack->groups_large); + mem_put (stack); if (local) @@ -370,6 +378,24 @@ STACK_RESET (call_stack_t *stack) } while (0) +static inline int +call_stack_alloc_groups (call_stack_t *stack, int ngrps) +{ + if (ngrps <= SMALL_GROUP_COUNT) { + stack->groups = stack->groups_small; + } else { + stack->groups_large = GF_CALLOC (sizeof (gid_t), ngrps, + gf_common_mt_groups_t); + if (!stack->groups_large) + return -1; + stack->groups = stack->groups_large; + } + + stack->ngrps = ngrps; + + return 0; +} + static inline call_frame_t * copy_frame (call_frame_t *frame) { @@ -393,8 +419,12 @@ copy_frame (call_frame_t *frame) newstack->ngrps = oldstack->ngrps; newstack->op = oldstack->op; newstack->type = oldstack->type; + if (call_stack_alloc_groups (newstack, oldstack->ngrps) != 0) { + mem_put (newstack); + return NULL; + } memcpy (newstack->groups, oldstack->groups, - sizeof (gid_t) * GF_MAX_AUX_GROUPS); + sizeof (gid_t) * oldstack->ngrps); newstack->unique = oldstack->unique; newstack->frames.this = frame->this; diff --git a/libglusterfs/src/store.c b/libglusterfs/src/store.c new file mode 100644 index 000000000..1e6601837 --- /dev/null +++ b/libglusterfs/src/store.c @@ -0,0 +1,709 @@ +/* + 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 _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include <inttypes.h> +#include <libgen.h> + +#include "glusterfs.h" +#include "store.h" +#include "dict.h" +#include "xlator.h" + +int32_t +gf_store_mkdir (char *path) +{ + int32_t ret = -1; + + ret = mkdir (path, 0777); + + if ((-1 == ret) && (EEXIST != errno)) { + gf_log ("", GF_LOG_ERROR, "mkdir() failed on path %s," + "errno: %s", path, strerror (errno)); + } else { + ret = 0; + } + + return ret; +} + +int32_t +gf_store_handle_create_on_absence (gf_store_handle_t **shandle, + char *path) +{ + GF_ASSERT (shandle); + int32_t ret = 0; + + if (*shandle == NULL) { + ret = gf_store_handle_new (path, shandle); + + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to create store" + " handle for path: %s", path); + } + } + return ret; +} + +int32_t +gf_store_mkstemp (gf_store_handle_t *shandle) +{ + int fd = -1; + char tmppath[PATH_MAX] = {0,}; + + GF_ASSERT (shandle); + GF_ASSERT (shandle->path); + + snprintf (tmppath, sizeof (tmppath), "%s.tmp", shandle->path); + fd = open (tmppath, O_RDWR | O_CREAT | O_TRUNC | O_SYNC, 0600); + if (fd <= 0) { + gf_log ("", GF_LOG_ERROR, "Failed to open %s, error: %s", + tmppath, strerror (errno)); + } + + return fd; +} + +int +gf_store_sync_direntry (char *path) +{ + int ret = -1; + int dirfd = -1; + char *dir = NULL; + char *pdir = NULL; + xlator_t *this = NULL; + + this = THIS; + + dir = gf_strdup (path); + if (!dir) + goto out; + + pdir = dirname (dir); + dirfd = open (pdir, O_RDONLY); + if (dirfd == -1) { + gf_log (this->name, GF_LOG_ERROR, "Failed to open directory " + "%s, due to %s", pdir, strerror (errno)); + goto out; + } + + ret = fsync (dirfd); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to fsync %s, due to " + "%s", pdir, strerror (errno)); + goto out; + } + + ret = 0; +out: + if (dirfd >= 0) { + ret = close (dirfd); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to close " + "%s, due to %s", pdir, strerror (errno)); + } + } + + if (dir) + GF_FREE (dir); + + return ret; +} + +int32_t +gf_store_rename_tmppath (gf_store_handle_t *shandle) +{ + int32_t ret = -1; + char tmppath[PATH_MAX] = {0,}; + + GF_ASSERT (shandle); + GF_ASSERT (shandle->path); + + snprintf (tmppath, sizeof (tmppath), "%s.tmp", shandle->path); + ret = rename (tmppath, shandle->path); + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, "Failed to rename %s to %s, " + "error: %s", tmppath, shandle->path, strerror (errno)); + goto out; + } + + ret = gf_store_sync_direntry (tmppath); +out: + return ret; +} + +int32_t +gf_store_unlink_tmppath (gf_store_handle_t *shandle) +{ + int32_t ret = -1; + char tmppath[PATH_MAX] = {0,}; + + GF_ASSERT (shandle); + GF_ASSERT (shandle->path); + + snprintf (tmppath, sizeof (tmppath), "%s.tmp", shandle->path); + ret = unlink (tmppath); + if (ret && (errno != ENOENT)) { + gf_log ("", GF_LOG_ERROR, "Failed to mv %s to %s, error: %s", + tmppath, shandle->path, strerror (errno)); + } else { + ret = 0; + } + + return ret; +} + +int +gf_store_read_and_tokenize (FILE *file, char *str, char **iter_key, + char **iter_val, gf_store_op_errno_t *store_errno) +{ + int32_t ret = -1; + char *savetok = NULL; + char *key = NULL; + char *value = NULL; + char *temp = NULL; + size_t str_len = 0; + + GF_ASSERT (file); + GF_ASSERT (str); + GF_ASSERT (iter_key); + GF_ASSERT (iter_val); + GF_ASSERT (store_errno); + + temp = fgets (str, PATH_MAX, file); + if (temp == NULL || feof (file)) { + ret = -1; + *store_errno = GD_STORE_EOF; + goto out; + } + + str_len = strlen(str); + str[str_len - 1] = '\0'; + /* Truncate the "\n", as fgets stores "\n" in str */ + + key = strtok_r (str, "=", &savetok); + if (!key) { + ret = -1; + *store_errno = GD_STORE_KEY_NULL; + goto out; + } + + value = strtok_r (NULL, "=", &savetok); + if (!value) { + ret = -1; + *store_errno = GD_STORE_VALUE_NULL; + goto out; + } + + *iter_key = key; + *iter_val = value; + *store_errno = GD_STORE_SUCCESS; + ret = 0; +out: + return ret; +} + +int32_t +gf_store_retrieve_value (gf_store_handle_t *handle, char *key, char **value) +{ + int32_t ret = -1; + char *scan_str = NULL; + char *iter_key = NULL; + char *iter_val = NULL; + char *free_str = NULL; + struct stat st = {0,}; + gf_store_op_errno_t store_errno = GD_STORE_SUCCESS; + + GF_ASSERT (handle); + + if (handle->locked == F_ULOCK) + /* no locking is used handle->fd gets closed() after usage */ + handle->fd = open (handle->path, O_RDWR); + else + /* handle->fd is valid already, kept open for lockf() */ + lseek (handle->fd, 0, SEEK_SET); + + if (handle->fd == -1) { + gf_log ("", GF_LOG_ERROR, "Unable to open file %s errno: %s", + handle->path, strerror (errno)); + goto out; + } + if (!handle->read) + handle->read = fdopen (dup(handle->fd), "r"); + else + fseek (handle->read, 0, SEEK_SET); + + if (!handle->read) { + gf_log ("", GF_LOG_ERROR, "Unable to open file %s errno: %s", + handle->path, strerror (errno)); + goto out; + } + + ret = fstat (handle->fd, &st); + if (ret < 0) { + gf_log ("", GF_LOG_WARNING, "stat on file %s failed", + handle->path); + ret = -1; + store_errno = GD_STORE_STAT_FAILED; + goto out; + } + + /* "st.st_size + 1" is used as we are fetching each + * line of a file using fgets, fgets will append "\0" + * to the end of the string + */ + scan_str = GF_CALLOC (1, st.st_size + 1, + gf_common_mt_char); + + if (scan_str == NULL) { + ret = -1; + store_errno = GD_STORE_ENOMEM; + goto out; + } + + free_str = scan_str; + + do { + ret = gf_store_read_and_tokenize (handle->read, scan_str, + &iter_key, &iter_val, + &store_errno); + if (ret < 0) { + gf_log ("", GF_LOG_TRACE, "error while reading key " + "'%s': %s", key, + gf_store_strerror (store_errno)); + goto out; + } + + gf_log ("", GF_LOG_TRACE, "key %s read", iter_key); + + if (!strcmp (key, iter_key)) { + gf_log ("", GF_LOG_DEBUG, "key %s found", key); + ret = 0; + if (iter_val) + *value = gf_strdup (iter_val); + goto out; + } + } while (1); +out: + if (handle->read) { + fclose (handle->read); + handle->read = NULL; + } + + if (handle->fd > 0 && handle->locked == F_ULOCK) { + /* only invalidate handle->fd if not locked */ + close (handle->fd); + } + + GF_FREE (free_str); + + return ret; +} + +int32_t +gf_store_save_value (int fd, char *key, char *value) +{ + int32_t ret = -1; + int dup_fd = -1; + FILE *fp = NULL; + + GF_ASSERT (fd > 0); + GF_ASSERT (key); + GF_ASSERT (value); + + dup_fd = dup (fd); + if (dup_fd == -1) + goto out; + + fp = fdopen (dup_fd, "a+"); + if (fp == NULL) { + gf_log ("", GF_LOG_WARNING, "fdopen failed."); + ret = -1; + goto out; + } + + ret = fprintf (fp, "%s=%s\n", key, value); + if (ret < 0) { + gf_log ("", GF_LOG_WARNING, "Unable to store key: %s," + "value: %s, error: %s", key, value, + strerror (errno)); + ret = -1; + goto out; + } + + ret = fflush (fp); + if (feof (fp)) { + gf_log ("", GF_LOG_WARNING, + "fflush failed, error: %s", + strerror (errno)); + ret = -1; + goto out; + } + + ret = 0; +out: + if (fp) + fclose (fp); + + gf_log ("", GF_LOG_DEBUG, "returning: %d", ret); + return ret; +} + +int32_t +gf_store_handle_new (char *path, gf_store_handle_t **handle) +{ + int32_t ret = -1; + gf_store_handle_t *shandle = NULL; + int fd = -1; + char *spath = NULL; + + shandle = GF_CALLOC (1, sizeof (*shandle), gf_common_mt_store_handle_t); + if (!shandle) + goto out; + + spath = gf_strdup (path); + + if (!spath) + goto out; + + fd = open (path, O_RDWR | O_CREAT | O_APPEND, 0600); + if (fd <= 0) { + gf_log ("", GF_LOG_ERROR, "Failed to open file: %s, error: %s", + path, strerror (errno)); + goto out; + } + + ret = gf_store_sync_direntry (spath); + if (ret) + goto out; + + shandle->path = spath; + shandle->locked = F_ULOCK; + *handle = shandle; + + ret = 0; +out: + if (fd > 0) + close (fd); + + if (ret == -1) { + GF_FREE (spath); + GF_FREE (shandle); + } + + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +gf_store_handle_retrieve (char *path, gf_store_handle_t **handle) +{ + int32_t ret = -1; + struct stat statbuf = {0}; + + ret = stat (path, &statbuf); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Path corresponding to " + "%s, returned error: (%s)", + path, strerror (errno)); + goto out; + } + ret = gf_store_handle_new (path, handle); +out: + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int32_t +gf_store_handle_destroy (gf_store_handle_t *handle) +{ + int32_t ret = -1; + + if (!handle) { + ret = 0; + goto out; + } + + GF_FREE (handle->path); + + GF_FREE (handle); + + ret = 0; + +out: + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +int32_t +gf_store_iter_new (gf_store_handle_t *shandle, gf_store_iter_t **iter) +{ + int32_t ret = -1; + FILE *fp = NULL; + gf_store_iter_t *tmp_iter = NULL; + + GF_ASSERT (shandle); + GF_ASSERT (iter); + + fp = fopen (shandle->path, "r"); + if (!fp) { + gf_log ("", GF_LOG_ERROR, "Unable to open file %s errno: %d", + shandle->path, errno); + goto out; + } + + tmp_iter = GF_CALLOC (1, sizeof (*tmp_iter), + gf_common_mt_store_iter_t); + if (!tmp_iter) + goto out; + + strncpy (tmp_iter->filepath, shandle->path, sizeof (tmp_iter->filepath)); + tmp_iter->filepath[sizeof (tmp_iter->filepath) - 1] = 0; + tmp_iter->file = fp; + + *iter = tmp_iter; + tmp_iter = NULL; + ret = 0; + +out: + if (ret && fp) + fclose (fp); + + GF_FREE (tmp_iter); + + gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + return ret; +} + +int32_t +gf_store_validate_key_value (char *storepath, char *key, char *val, + gf_store_op_errno_t *op_errno) +{ + int ret = 0; + + GF_ASSERT (op_errno); + GF_ASSERT (storepath); + + if ((key == NULL) && (val == NULL)) { + ret = -1; + gf_log ("", GF_LOG_ERROR, "Glusterd store may be corrupted, " + "Invalid key and value (null) in %s", storepath); + *op_errno = GD_STORE_KEY_VALUE_NULL; + } else if (key == NULL) { + ret = -1; + gf_log ("", GF_LOG_ERROR, "Glusterd store may be corrupted, " + "Invalid key (null) in %s", storepath); + *op_errno = GD_STORE_KEY_NULL; + } else if (val == NULL) { + ret = -1; + gf_log ("", GF_LOG_ERROR, "Glusterd store may be corrupted, " + "Invalid value (null) for key %s in %s", key, + storepath); + *op_errno = GD_STORE_VALUE_NULL; + } else { + ret = 0; + *op_errno = GD_STORE_SUCCESS; + } + + return ret; +} + +int32_t +gf_store_iter_get_next (gf_store_iter_t *iter, char **key, char **value, + gf_store_op_errno_t *op_errno) +{ + int32_t ret = -1; + char *scan_str = NULL; + char *iter_key = NULL; + char *iter_val = NULL; + struct stat st = {0,}; + gf_store_op_errno_t store_errno = GD_STORE_SUCCESS; + + GF_ASSERT (iter); + GF_ASSERT (key); + GF_ASSERT (value); + + ret = stat (iter->filepath, &st); + if (ret < 0) { + gf_log ("", GF_LOG_WARNING, "stat on file failed"); + ret = -1; + store_errno = GD_STORE_STAT_FAILED; + goto out; + } + + /* "st.st_size + 1" is used as we are fetching each + * line of a file using fgets, fgets will append "\0" + * to the end of the string + */ + scan_str = GF_CALLOC (1, st.st_size + 1, + gf_common_mt_char); + if (!scan_str) { + ret = -1; + store_errno = GD_STORE_ENOMEM; + goto out; + } + + ret = gf_store_read_and_tokenize (iter->file, scan_str, + &iter_key, &iter_val, + &store_errno); + if (ret < 0) { + goto out; + } + + ret = gf_store_validate_key_value (iter->filepath, iter_key, + iter_val, &store_errno); + if (ret) + goto out; + + *key = gf_strdup (iter_key); + if (!*key) { + ret = -1; + store_errno = GD_STORE_ENOMEM; + goto out; + } + *value = gf_strdup (iter_val); + if (!*value) { + ret = -1; + store_errno = GD_STORE_ENOMEM; + goto out; + } + ret = 0; + +out: + GF_FREE (scan_str); + if (ret) { + GF_FREE (*key); + GF_FREE (*value); + *key = NULL; + *value = NULL; + } + if (op_errno) + *op_errno = store_errno; + + gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + return ret; +} + +int32_t +gf_store_iter_get_matching (gf_store_iter_t *iter, char *key, char **value) +{ + int32_t ret = -1; + char *tmp_key = NULL; + char *tmp_value = NULL; + + ret = gf_store_iter_get_next (iter, &tmp_key, &tmp_value, NULL); + while (!ret) { + if (!strncmp (key, tmp_key, strlen (key))){ + *value = tmp_value; + GF_FREE (tmp_key); + goto out; + } + GF_FREE (tmp_key); + tmp_key = NULL; + GF_FREE (tmp_value); + tmp_value = NULL; + ret = gf_store_iter_get_next (iter, &tmp_key, &tmp_value, + NULL); + } +out: + return ret; +} + +int32_t +gf_store_iter_destroy (gf_store_iter_t *iter) +{ + int32_t ret = -1; + + if (!iter) + return 0; + + /* gf_store_iter_new will not return a valid iter object with iter->file + * being NULL*/ + ret = fclose (iter->file); + if (ret) + gf_log ("", GF_LOG_ERROR, "Unable to close file: %s, ret: %d, " + "errno: %d" ,iter->filepath, ret, errno); + + GF_FREE (iter); + return ret; +} + +char* +gf_store_strerror (gf_store_op_errno_t op_errno) +{ + switch (op_errno) { + case GD_STORE_SUCCESS: + return "Success"; + case GD_STORE_KEY_NULL: + return "Invalid Key"; + case GD_STORE_VALUE_NULL: + return "Invalid Value"; + case GD_STORE_KEY_VALUE_NULL: + return "Invalid Key and Value"; + case GD_STORE_EOF: + return "No data"; + case GD_STORE_ENOMEM: + return "No memory"; + default: + return "Invalid errno"; + } + return "Invalid errno"; +} + +int +gf_store_lock (gf_store_handle_t *sh) +{ + int ret; + + GF_ASSERT (sh); + GF_ASSERT (sh->path); + GF_ASSERT (sh->locked == F_ULOCK); + + sh->fd = open (sh->path, O_RDWR); + if (sh->fd == -1) { + gf_log ("", GF_LOG_ERROR, "Failed to open '%s': %s", sh->path, + strerror (errno)); + return -1; + } + + ret = lockf (sh->fd, F_LOCK, 0); + if (ret) + gf_log ("", GF_LOG_ERROR, "Failed to gain lock on '%s': %s", + sh->path, strerror (errno)); + else + /* sh->locked is protected by the lockf(sh->fd) above */ + sh->locked = F_LOCK; + + return ret; +} + +void +gf_store_unlock (gf_store_handle_t *sh) +{ + GF_ASSERT (sh); + GF_ASSERT (sh->locked == F_LOCK); + + sh->locked = F_ULOCK; + lockf (sh->fd, F_ULOCK, 0); + close (sh->fd); +} + +int +gf_store_locked_local (gf_store_handle_t *sh) +{ + GF_ASSERT (sh); + + return (sh->locked == F_LOCK); +} diff --git a/libglusterfs/src/store.h b/libglusterfs/src/store.h new file mode 100644 index 000000000..337103ff7 --- /dev/null +++ b/libglusterfs/src/store.h @@ -0,0 +1,112 @@ +/* + 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 _GLUSTERD_STORE_H_ +#define _GLUSTERD_STORE_H_ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "glusterfs.h" + +struct gf_store_handle_ { + char *path; + int fd; + FILE *read; + int locked; /* state of lockf() */ +}; + +typedef struct gf_store_handle_ gf_store_handle_t; + +struct gf_store_iter_ { + FILE *file; + char filepath[PATH_MAX]; +}; + +typedef struct gf_store_iter_ gf_store_iter_t; + +typedef enum { + GD_STORE_SUCCESS, + GD_STORE_KEY_NULL, + GD_STORE_VALUE_NULL, + GD_STORE_KEY_VALUE_NULL, + GD_STORE_EOF, + GD_STORE_ENOMEM, + GD_STORE_STAT_FAILED +} gf_store_op_errno_t; + +int32_t +gf_store_mkdir (char *path); + +int32_t +gf_store_handle_create_on_absence (gf_store_handle_t **shandle, char *path); + +int32_t +gf_store_mkstemp (gf_store_handle_t *shandle); + +int +gf_store_sync_direntry (char *path); + +int32_t +gf_store_rename_tmppath (gf_store_handle_t *shandle); + +int32_t +gf_store_unlink_tmppath (gf_store_handle_t *shandle); + +int +gf_store_read_and_tokenize (FILE *file, char *str, char **iter_key, + char **iter_val, gf_store_op_errno_t *store_errno); + +int32_t +gf_store_retrieve_value (gf_store_handle_t *handle, char *key, char **value); + +int32_t +gf_store_save_value (int fd, char *key, char *value); + +int32_t +gf_store_handle_new (char *path, gf_store_handle_t **handle); + +int +gf_store_handle_retrieve (char *path, gf_store_handle_t **handle); + +int32_t +gf_store_handle_destroy (gf_store_handle_t *handle); + +int32_t +gf_store_iter_new (gf_store_handle_t *shandle, gf_store_iter_t **iter); + +int32_t +gf_store_validate_key_value (char *storepath, char *key, char *val, + gf_store_op_errno_t *op_errno); + +int32_t +gf_store_iter_get_next (gf_store_iter_t *iter, char **key, char **value, + gf_store_op_errno_t *op_errno); + +int32_t +gf_store_iter_get_matching (gf_store_iter_t *iter, char *key, char **value); + +int32_t +gf_store_iter_destroy (gf_store_iter_t *iter); + +char* +gf_store_strerror (gf_store_op_errno_t op_errno); + +int +gf_store_lock (gf_store_handle_t *sh); + +void +gf_store_unlock (gf_store_handle_t *sh); + +int +gf_store_locked_local (gf_store_handle_t *sh); + +#endif diff --git a/libglusterfs/src/syncop.c b/libglusterfs/src/syncop.c index 8e5db41fd..c1620bb70 100644 --- a/libglusterfs/src/syncop.c +++ b/libglusterfs/src/syncop.c @@ -15,6 +15,160 @@ #include "syncop.h" +int +syncopctx_setfsuid (void *uid) +{ + struct syncopctx *opctx = NULL; + int ret = 0; + + /* In args check */ + if (!uid) { + ret = -1; + errno = EINVAL; + goto out; + } + + opctx = syncopctx_getctx (); + + /* alloc for this thread the first time */ + if (!opctx) { + opctx = GF_CALLOC (1, sizeof (*opctx), gf_common_mt_syncopctx); + if (!opctx) { + ret = -1; + goto out; + } + + ret = syncopctx_setctx (opctx); + if (ret != 0) { + GF_FREE (opctx); + opctx = NULL; + goto out; + } + } + +out: + if (opctx && uid) { + opctx->uid = *(uid_t *)uid; + opctx->valid |= SYNCOPCTX_UID; + } + + return ret; +} + +int +syncopctx_setfsgid (void *gid) +{ + struct syncopctx *opctx = NULL; + int ret = 0; + + /* In args check */ + if (!gid) { + ret = -1; + errno = EINVAL; + goto out; + } + + opctx = syncopctx_getctx (); + + /* alloc for this thread the first time */ + if (!opctx) { + opctx = GF_CALLOC (1, sizeof (*opctx), gf_common_mt_syncopctx); + if (!opctx) { + ret = -1; + goto out; + } + + ret = syncopctx_setctx (opctx); + if (ret != 0) { + GF_FREE (opctx); + opctx = NULL; + goto out; + } + } + +out: + if (opctx && gid) { + opctx->gid = *(gid_t *)gid; + opctx->valid |= SYNCOPCTX_GID; + } + + return ret; +} + +int +syncopctx_setfsgroups (int count, const void *groups) +{ + struct syncopctx *opctx = NULL; + gid_t *tmpgroups = NULL; + int ret = 0; + + /* In args check */ + if (count != 0 && !groups) { + ret = -1; + errno = EINVAL; + goto out; + } + + opctx = syncopctx_getctx (); + + /* alloc for this thread the first time */ + if (!opctx) { + opctx = GF_CALLOC (1, sizeof (*opctx), gf_common_mt_syncopctx); + if (!opctx) { + ret = -1; + goto out; + } + + ret = syncopctx_setctx (opctx); + if (ret != 0) { + GF_FREE (opctx); + opctx = NULL; + goto out; + } + } + + /* resize internal groups as required */ + if (count && opctx->grpsize < count) { + if (opctx->groups) { + tmpgroups = GF_REALLOC (opctx->groups, + (sizeof (gid_t) * count)); + /* NOTE: Not really required to zero the reallocation, + * as ngrps controls the validity of data, + * making a note irrespective */ + if (tmpgroups == NULL) { + opctx->grpsize = 0; + GF_FREE (opctx->groups); + opctx->groups = NULL; + ret = -1; + goto out; + } + } + else { + tmpgroups = GF_CALLOC (count, sizeof (gid_t), + gf_common_mt_syncopctx); + if (tmpgroups == NULL) { + opctx->grpsize = 0; + ret = -1; + goto out; + } + } + + opctx->groups = tmpgroups; + opctx->grpsize = count; + } + + /* copy out the groups passed */ + if (count) + memcpy (opctx->groups, groups, (sizeof (gid_t) * count)); + + /* set/reset the ngrps, this is where reset of groups is handled */ + opctx->ngrps = count; + opctx->valid |= SYNCOPCTX_GROUPS; + +out: + return ret; +} + static void __run (struct synctask *task) { @@ -28,7 +182,7 @@ __run (struct synctask *task) case SYNCTASK_SUSPEND: break; case SYNCTASK_RUN: - gf_log (task->xl->name, GF_LOG_WARNING, + gf_log (task->xl->name, GF_LOG_DEBUG, "re-running already running task"); env->runcount--; break; @@ -38,7 +192,11 @@ __run (struct synctask *task) case SYNCTASK_DONE: gf_log (task->xl->name, GF_LOG_WARNING, "running completed task"); - break; + return; + case SYNCTASK_ZOMBIE: + gf_log (task->xl->name, GF_LOG_WARNING, + "attempted to wake up zombie!!"); + return; } list_add_tail (&task->all_tasks, &env->runq); @@ -70,7 +228,11 @@ __wait (struct synctask *task) case SYNCTASK_DONE: gf_log (task->xl->name, GF_LOG_WARNING, "running completed task"); - break; + return; + case SYNCTASK_ZOMBIE: + gf_log (task->xl->name, GF_LOG_WARNING, + "attempted to sleep a zombie!!"); + return; } list_add_tail (&task->all_tasks, &env->waitq); @@ -168,6 +330,7 @@ synctask_done (struct synctask *task) pthread_mutex_lock (&task->mutex); { + task->state = SYNCTASK_ZOMBIE; task->done = 1; pthread_cond_broadcast (&task->cond); } @@ -191,20 +354,19 @@ synctask_setid (struct synctask *task, uid_t uid, gid_t gid) } -int -synctask_new (struct syncenv *env, synctask_fn_t fn, synctask_cbk_t cbk, - call_frame_t *frame, void *opaque) +struct synctask * +synctask_create (struct syncenv *env, synctask_fn_t fn, synctask_cbk_t cbk, + call_frame_t *frame, void *opaque) { struct synctask *newtask = NULL; xlator_t *this = THIS; - int ret = 0; VALIDATE_OR_GOTO (env, err); VALIDATE_OR_GOTO (fn, err); newtask = CALLOC (1, sizeof (*newtask)); if (!newtask) - return -ENOMEM; + return NULL; newtask->frame = frame; if (!frame) { @@ -263,21 +425,7 @@ synctask_new (struct syncenv *env, synctask_fn_t fn, synctask_cbk_t cbk, */ syncenv_scale(env); - if (!cbk) { - pthread_mutex_lock (&newtask->mutex); - { - while (!newtask->done) { - pthread_cond_wait (&newtask->cond, &newtask->mutex); - } - } - pthread_mutex_unlock (&newtask->mutex); - - ret = newtask->ret; - - synctask_destroy (newtask); - } - - return ret; + return newtask; err: if (newtask) { FREE (newtask->stack); @@ -285,7 +433,46 @@ err: STACK_DESTROY (newtask->opframe->root); FREE (newtask); } - return -1; + + return NULL; +} + + +int +synctask_join (struct synctask *task) +{ + int ret = 0; + + pthread_mutex_lock (&task->mutex); + { + while (!task->done) + pthread_cond_wait (&task->cond, &task->mutex); + } + pthread_mutex_unlock (&task->mutex); + + ret = task->ret; + + synctask_destroy (task); + + return ret; +} + + +int +synctask_new (struct syncenv *env, synctask_fn_t fn, synctask_cbk_t cbk, + call_frame_t *frame, void *opaque) +{ + struct synctask *newtask = NULL; + int ret = 0; + + newtask = synctask_create (env, fn, cbk, frame, opaque); + if (!newtask) + return -1; + + if (!cbk) + ret = synctask_join (newtask); + + return ret; } @@ -308,7 +495,7 @@ syncenv_task (struct syncproc *proc) if (!list_empty (&env->runq)) break; if ((ret == ETIMEDOUT) && - (env->procs > SYNCENV_PROC_MIN)) { + (env->procs > env->procmin)) { task = NULL; env->procs--; memset (proc, 0, sizeof (*proc)); @@ -408,20 +595,20 @@ syncenv_scale (struct syncenv *env) goto unlock; scale = env->runcount; - if (scale > SYNCENV_PROC_MAX) - scale = SYNCENV_PROC_MAX; + if (scale > env->procmax) + scale = env->procmax; if (scale > env->procs) diff = scale - env->procs; while (diff) { diff--; - for (; (i < SYNCENV_PROC_MAX); i++) { + for (; (i < env->procmax); i++) { if (env->proc[i].processor == 0) break; } env->proc[i].env = env; - ret = pthread_create (&env->proc[i].processor, NULL, - syncenv_processor, &env->proc[i]); + ret = gf_thread_create (&env->proc[i].processor, NULL, + syncenv_processor, &env->proc[i]); if (ret) break; env->procs++; @@ -441,12 +628,20 @@ syncenv_destroy (struct syncenv *env) struct syncenv * -syncenv_new (size_t stacksize) +syncenv_new (size_t stacksize, int procmin, int procmax) { struct syncenv *newenv = NULL; int ret = 0; int i = 0; + if (!procmin || procmin < 0) + procmin = SYNCENV_PROC_MIN; + if (!procmax || procmax > SYNCENV_PROC_MAX) + procmax = SYNCENV_PROC_MAX; + + if (procmin > procmax) + return NULL; + newenv = CALLOC (1, sizeof (*newenv)); if (!newenv) @@ -461,11 +656,13 @@ syncenv_new (size_t stacksize) newenv->stacksize = SYNCENV_DEFAULT_STACKSIZE; if (stacksize) newenv->stacksize = stacksize; + newenv->procmin = procmin; + newenv->procmax = procmax; - for (i = 0; i < SYNCENV_PROC_MIN; i++) { + for (i = 0; i < newenv->procmin; i++) { newenv->proc[i].env = newenv; - ret = pthread_create (&newenv->proc[i].processor, NULL, - syncenv_processor, &newenv->proc[i]); + ret = gf_thread_create (&newenv->proc[i].processor, NULL, + syncenv_processor, &newenv->proc[i]); if (ret) break; newenv->procs++; @@ -1917,6 +2114,96 @@ syncop_access (xlator_t *subvol, loc_t *loc, int32_t mask) int +syncop_fallocate_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + + __wake (args); + + return 0; +} + +int +syncop_fallocate(xlator_t *subvol, fd_t *fd, int32_t keep_size, off_t offset, + size_t len) +{ + struct syncargs args = {0, }; + + SYNCOP (subvol, (&args), syncop_fallocate_cbk, subvol->fops->fallocate, + fd, keep_size, offset, len, NULL); + + errno = args.op_errno; + return args.op_ret; +} + + +int +syncop_discard_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + + __wake (args); + + return 0; +} + +int +syncop_discard(xlator_t *subvol, fd_t *fd, off_t offset, size_t len) +{ + struct syncargs args = {0, }; + + SYNCOP (subvol, (&args), syncop_discard_cbk, subvol->fops->discard, + fd, offset, len, NULL); + + errno = args.op_errno; + return args.op_ret; +} + +int +syncop_zerofill_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + + __wake (args); + + return 0; +} + +int +syncop_zerofill(xlator_t *subvol, fd_t *fd, off_t offset, size_t len) +{ + struct syncargs args = {0, }; + + SYNCOP (subvol, (&args), syncop_zerofill_cbk, subvol->fops->zerofill, + fd, offset, len, NULL); + + errno = args.op_errno; + return args.op_ret; +} + + +int syncop_lk_cbk (call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, int op_errno, struct gf_flock *flock, dict_t *xdata) diff --git a/libglusterfs/src/syncop.h b/libglusterfs/src/syncop.h index 98e88ff37..f790981f0 100644 --- a/libglusterfs/src/syncop.h +++ b/libglusterfs/src/syncop.h @@ -25,6 +25,13 @@ #define SYNCENV_PROC_MIN 2 #define SYNCPROC_IDLE_TIME 600 +/* + * Flags for syncopctx valid elements + */ +#define SYNCOPCTX_UID 0x00000001 +#define SYNCOPCTX_GID 0x00000002 +#define SYNCOPCTX_GROUPS 0x00000004 + struct synctask; struct syncproc; struct syncenv; @@ -41,6 +48,7 @@ typedef enum { SYNCTASK_SUSPEND, SYNCTASK_WAIT, SYNCTASK_DONE, + SYNCTASK_ZOMBIE, } synctask_state_t; /* for one sequential execution of @syncfn */ @@ -90,6 +98,9 @@ struct syncenv { struct list_head waitq; int waitcount; + int procmin; + int procmax; + pthread_mutex_t mutex; pthread_cond_t cond; @@ -146,6 +157,14 @@ struct syncargs { int done; }; +struct syncopctx { + unsigned int valid; /* valid flags for elements that are set */ + uid_t uid; + gid_t gid; + int grpsize; + int ngrps; + gid_t *groups; +}; #define __yawn(args) do { \ args->task = synctask_get (); \ @@ -219,11 +238,14 @@ struct syncargs { #define SYNCENV_DEFAULT_STACKSIZE (2 * 1024 * 1024) -struct syncenv * syncenv_new (); +struct syncenv * syncenv_new (size_t stacksize, int procmin, int procmax); void syncenv_destroy (struct syncenv *); void syncenv_scale (struct syncenv *env); int synctask_new (struct syncenv *, synctask_fn_t, synctask_cbk_t, call_frame_t* frame, void *); +struct synctask *synctask_create (struct syncenv *, synctask_fn_t, + synctask_cbk_t, call_frame_t *, void *); +int synctask_join (struct synctask *task); void synctask_wake (struct synctask *task); void synctask_yield (struct synctask *task); void synctask_waitfor (struct synctask *task, int count); @@ -235,20 +257,64 @@ void synctask_waitfor (struct synctask *task, int count); int synctask_setid (struct synctask *task, uid_t uid, gid_t gid); #define SYNCTASK_SETID(uid, gid) synctask_setid (synctask_get(), uid, gid); +int syncopctx_setfsuid (void *uid); +int syncopctx_setfsgid (void *gid); +int syncopctx_setfsgroups (int count, const void *groups); static inline call_frame_t * syncop_create_frame (xlator_t *this) { - call_frame_t *frame = NULL; + call_frame_t *frame = NULL; + int ngrps = -1; + struct syncopctx *opctx = NULL; frame = create_frame (this, this->ctx->pool); if (!frame) return NULL; - frame->root->pid = getpid(); - frame->root->uid = geteuid (); - frame->root->gid = getegid (); - frame->root->ngrps = getgroups (GF_MAX_AUX_GROUPS, frame->root->groups); + frame->root->pid = getpid (); + + opctx = syncopctx_getctx (); + if (opctx && (opctx->valid & SYNCOPCTX_UID)) + frame->root->uid = opctx->uid; + else + frame->root->uid = geteuid (); + + if (opctx && (opctx->valid & SYNCOPCTX_GID)) + frame->root->gid = opctx->gid; + else + frame->root->gid = getegid (); + + if (opctx && (opctx->valid & SYNCOPCTX_GROUPS)) { + ngrps = opctx->ngrps; + + if (ngrps != 0 && opctx->groups != NULL) { + if (call_stack_alloc_groups (frame->root, ngrps) != 0) { + STACK_DESTROY (frame->root); + return NULL; + } + + memcpy (frame->root->groups, opctx->groups, + (sizeof (gid_t) * ngrps)); + } + } + else { + ngrps = getgroups (0, 0); + if (ngrps < 0) { + STACK_DESTROY (frame->root); + return NULL; + } + + if (call_stack_alloc_groups (frame->root, ngrps) != 0) { + STACK_DESTROY (frame->root); + return NULL; + } + + if (getgroups (ngrps, frame->root->groups) < 0) { + STACK_DESTROY (frame->root); + return NULL; + } + } return frame; } @@ -333,6 +399,11 @@ int syncop_mkdir (xlator_t *subvol, loc_t *loc, mode_t mode, dict_t *dict, int syncop_link (xlator_t *subvol, loc_t *oldloc, loc_t *newloc); int syncop_fsyncdir (xlator_t *subvol, fd_t *fd, int datasync); int syncop_access (xlator_t *subvol, loc_t *loc, int32_t mask); +int syncop_fallocate(xlator_t *subvol, fd_t *fd, int32_t keep_size, off_t offset, + size_t len); +int syncop_discard(xlator_t *subvol, fd_t *fd, off_t offset, size_t len); + +int syncop_zerofill(xlator_t *subvol, fd_t *fd, off_t offset, size_t len); int syncop_rename (xlator_t *subvol, loc_t *oldloc, loc_t *newloc); diff --git a/libglusterfs/src/syscall.c b/libglusterfs/src/syscall.c index bb834dbfd..e8954cc23 100644 --- a/libglusterfs/src/syscall.c +++ b/libglusterfs/src/syscall.c @@ -458,3 +458,26 @@ sys_access (const char *pathname, int mode) { return access (pathname, mode); } + + +int +sys_fallocate(int fd, int mode, off_t offset, off_t len) +{ +#ifdef HAVE_FALLOCATE + return fallocate(fd, mode, offset, len); +#endif + +#ifdef HAVE_POSIX_FALLOCATE + if (mode) { + /* keep size not supported */ + errno = EOPNOTSUPP; + return -1; + } + + return posix_fallocate(fd, offset, len); +#endif + + errno = ENOSYS; + return -1; +} + diff --git a/libglusterfs/src/syscall.h b/libglusterfs/src/syscall.h index d5c6ce5f6..f1c9f58c3 100644 --- a/libglusterfs/src/syscall.h +++ b/libglusterfs/src/syscall.h @@ -139,4 +139,6 @@ sys_access (const char *pathname, int mode); int sys_ftruncate (int fd, off_t length); +int sys_fallocate(int fd, int mode, off_t offset, off_t len); + #endif /* __SYSCALL_H__ */ diff --git a/libglusterfs/src/timer.c b/libglusterfs/src/timer.c index ae40142ad..a059cc212 100644 --- a/libglusterfs/src/timer.c +++ b/libglusterfs/src/timer.c @@ -17,19 +17,18 @@ #include "logging.h" #include "common-utils.h" #include "globals.h" - -#define TS(tv) ((((unsigned long long) tv.tv_sec) * 1000000) + (tv.tv_usec)) +#include "timespec.h" gf_timer_t * gf_timer_call_after (glusterfs_ctx_t *ctx, - struct timeval delta, + struct timespec delta, gf_timer_cbk_t callbk, void *data) { gf_timer_registry_t *reg = NULL; gf_timer_t *event = NULL; gf_timer_t *trav = NULL; - unsigned long long at = 0L; + uint64_t at = 0; if (ctx == NULL) { @@ -48,10 +47,8 @@ gf_timer_call_after (glusterfs_ctx_t *ctx, if (!event) { return NULL; } - gettimeofday (&event->at, NULL); - event->at.tv_usec = ((event->at.tv_usec + delta.tv_usec) % 1000000); - event->at.tv_sec += ((event->at.tv_usec + delta.tv_usec) / 1000000); - event->at.tv_sec += delta.tv_sec; + timespec_now (&event->at); + timespec_adjust_delta (&event->at, delta); at = TS (event->at); event->callbk = callbk; event->data = data; @@ -127,7 +124,7 @@ void * gf_timer_proc (void *ctx) { gf_timer_registry_t *reg = NULL; - const struct timespec sleepts = {.tv_sec = 1, .tv_nsec = 0, }; + const struct timespec sleepts = {.tv_sec = 1, .tv_nsec = 0, }; if (ctx == NULL) { @@ -142,14 +139,14 @@ gf_timer_proc (void *ctx) } while (!reg->fin) { - unsigned long long now; - struct timeval now_tv; + uint64_t now; + struct timespec now_ts; gf_timer_t *event = NULL; - gettimeofday (&now_tv, NULL); - now = TS (now_tv); + timespec_now (&now_ts); + now = TS (now_ts); while (1) { - unsigned long long at; + uint64_t at; char need_cbk = 0; pthread_mutex_lock (®->lock); @@ -213,7 +210,7 @@ gf_timer_registry_init (glusterfs_ctx_t *ctx) reg->stale.prev = ®->stale; ctx->timer = reg; - pthread_create (®->th, NULL, gf_timer_proc, ctx); + gf_thread_create (®->th, NULL, gf_timer_proc, ctx); } out: return ctx->timer; diff --git a/libglusterfs/src/timer.h b/libglusterfs/src/timer.h index 2954f6aff..2f963adbf 100644 --- a/libglusterfs/src/timer.h +++ b/libglusterfs/src/timer.h @@ -25,7 +25,7 @@ typedef void (*gf_timer_cbk_t) (void *); struct _gf_timer { struct _gf_timer *next, *prev; - struct timeval at; + struct timespec at; gf_timer_cbk_t callbk; void *data; xlator_t *xl; @@ -44,7 +44,7 @@ typedef struct _gf_timer_registry gf_timer_registry_t; gf_timer_t * gf_timer_call_after (glusterfs_ctx_t *ctx, - struct timeval delta, + struct timespec delta, gf_timer_cbk_t cbk, void *data); diff --git a/libglusterfs/src/timespec.c b/libglusterfs/src/timespec.c new file mode 100644 index 000000000..a0c281a1e --- /dev/null +++ b/libglusterfs/src/timespec.c @@ -0,0 +1,68 @@ +/* + 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 <stdio.h> +#include <inttypes.h> +#if defined GF_LINUX_HOST_OS || defined GF_SOLARIS_HOST_OS || defined GF_BSD_HOST_OS +#include <time.h> +#include <sys/time.h> +#endif + +#if defined GF_DARWIN_HOST_OS +#include <mach/mach_time.h> +#endif + +#include "logging.h" +#include "time.h" + + +void tv2ts (struct timeval tv, struct timespec *ts) +{ + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; +} + +void timespec_now (struct timespec *ts) +{ +#if defined GF_LINUX_HOST_OS || defined GF_SOLARIS_HOST_OS || defined GF_BSD_HOST_OS + + if (0 == clock_gettime(CLOCK_MONOTONIC, ts)) + return; + else { + struct timeval tv; + if (0 == gettimeofday(&tv, NULL)) + tv2ts(tv, ts); + } +#elif defined GF_DARWIN_HOST_OS + mach_timebase_info_data_t tb = { 0 }; + static double timebase = 0.0; + uint64_t time = 0; + mach_timebase_info (&tb); + + timebase *= info.numer; + timebase /= info.denom; + + time = mach_absolute_time(); + time *= timebase; + + ts->tv_sec = (time * NANO); + ts->tv_nsec = (time - (ts.tv_sec * GIGA)); + +#endif /* Platform verification */ + gf_log_callingfn ("timer", GF_LOG_DEBUG, "%"PRIu64".%09"PRIu64, + ts->tv_sec, ts->tv_nsec); +} + +void timespec_adjust_delta (struct timespec *ts, struct timespec delta) +{ + ts->tv_nsec = ((ts->tv_nsec + delta.tv_nsec) % 1000000000); + ts->tv_sec += ((ts->tv_nsec + delta.tv_nsec) / 1000000000); + ts->tv_sec += delta.tv_sec; +} diff --git a/libglusterfs/src/timespec.h b/libglusterfs/src/timespec.h new file mode 100644 index 000000000..490255df9 --- /dev/null +++ b/libglusterfs/src/timespec.h @@ -0,0 +1,24 @@ +/* + 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 __INCLUDE_TIMESPEC_H__ +#define __INCLUDE_TIMESPEC_H__ + +#include <stdint.h> + +#define TS(ts) ((ts.tv_sec * 1000000000LL) + ts.tv_nsec) +#define NANO (+1.0E-9) +#define GIGA UINT64_C(1000000000) + +void tv2ts (struct timeval tv, struct timespec *ts); +void timespec_now (struct timespec *ts); +void timespec_adjust_delta (struct timespec *ts, struct timespec delta); + +#endif /* __INCLUDE_TIMESPEC_H__ */ diff --git a/libglusterfs/src/xlator.c b/libglusterfs/src/xlator.c index 348f48c48..a277c58a8 100644 --- a/libglusterfs/src/xlator.c +++ b/libglusterfs/src/xlator.c @@ -79,6 +79,9 @@ fill_defaults (xlator_t *xl) SET_DEFAULT_FOP (fxattrop); SET_DEFAULT_FOP (setattr); SET_DEFAULT_FOP (fsetattr); + SET_DEFAULT_FOP (fallocate); + SET_DEFAULT_FOP (discard); + SET_DEFAULT_FOP (zerofill); SET_DEFAULT_FOP (getspec); @@ -119,18 +122,9 @@ xlator_volopt_dynload (char *xlator_type, void **dl_handle, int ret = -1; char *name = NULL; void *handle = NULL; - volume_opt_list_t *vol_opt = NULL; GF_VALIDATE_OR_GOTO ("xlator", xlator_type, out); - GF_ASSERT (dl_handle); - - if (*dl_handle) - if (dlclose (*dl_handle)) - gf_log ("xlator", GF_LOG_WARNING, "Unable to close " - "previously opened handle( may be stale)." - "Ignoring the invalid handle"); - ret = gf_asprintf (&name, "%s/%s.so", XLATORDIR, xlator_type); if (-1 == ret) { gf_log ("xlator", GF_LOG_ERROR, "asprintf failed"); @@ -146,25 +140,15 @@ xlator_volopt_dynload (char *xlator_type, void **dl_handle, gf_log ("xlator", GF_LOG_WARNING, "%s", dlerror ()); goto out; } - *dl_handle = handle; - - - vol_opt = GF_CALLOC (1, sizeof (volume_opt_list_t), - gf_common_mt_volume_opt_list_t); - if (!vol_opt) { - goto out; - } - - if (!(vol_opt->given_opt = dlsym (handle, "options"))) { + if (!(opt_list->given_opt = dlsym (handle, "options"))) { dlerror (); - gf_log ("xlator", GF_LOG_DEBUG, - "Strict option validation not enforced -- neglecting"); + gf_log ("xlator", GF_LOG_ERROR, + "Failed to load xlator opt table"); + goto out; } - opt_list->given_opt = vol_opt->given_opt; - INIT_LIST_HEAD (&vol_opt->list); - list_add_tail (&vol_opt->list, &opt_list->list); + *dl_handle = handle; ret = 0; out: @@ -378,29 +362,6 @@ out: return search; } -xlator_t * -xlator_search_by_xl_type (xlator_t *any, const char *type) -{ - xlator_t *search = NULL; - - GF_VALIDATE_OR_GOTO ("xlator", any, out); - GF_VALIDATE_OR_GOTO ("xlator", type, out); - - search = any; - - while (search->prev) - search = search->prev; - - while (search) { - if (!strcmp (search->type, type)) - break; - search = search->next; - } - -out: - return search; -} - static int __xlator_init(xlator_t *xl) { @@ -555,10 +516,26 @@ out: return; } +int +xlator_list_destroy (xlator_list_t *list) +{ + xlator_list_t *next = NULL; + + while (list) { + next = list->next; + GF_FREE (list); + list = next; + } + + return 0; +} + int xlator_tree_free (xlator_t *tree) { + volume_opt_list_t *vol_opt = NULL; + volume_opt_list_t *tmp = NULL; xlator_t *trav = tree; xlator_t *prev = tree; @@ -569,9 +546,19 @@ xlator_tree_free (xlator_t *tree) while (prev) { trav = prev->next; - dict_destroy (prev->options); + if (prev->dlhandle) + dlclose (prev->dlhandle); + dict_unref (prev->options); GF_FREE (prev->name); GF_FREE (prev->type); + xlator_list_destroy (prev->children); + xlator_list_destroy (prev->parents); + + list_for_each_entry_safe (vol_opt, tmp, &prev->volume_options, + list) { + list_del_init (&vol_opt->list); + GF_FREE (vol_opt); + } GF_FREE (prev); prev = trav; } @@ -637,10 +624,12 @@ out: return ret; } -char* -loc_gfid_utoa (loc_t *loc) +void +loc_gfid (loc_t *loc, uuid_t gfid) { - uuid_t gfid={0}; + if (!gfid) + goto out; + uuid_clear (gfid); if (!loc) goto out; @@ -649,6 +638,14 @@ loc_gfid_utoa (loc_t *loc) else if (loc->inode && (!uuid_is_null (loc->inode->gfid))) uuid_copy (gfid, loc->inode->gfid); out: + return; +} + +char* +loc_gfid_utoa (loc_t *loc) +{ + uuid_t gfid; + loc_gfid (loc, gfid); return uuid_utoa (gfid); } @@ -691,21 +688,17 @@ err: return ret; } -int -xlator_list_destroy (xlator_list_t *list) +gf_boolean_t +loc_is_root (loc_t *loc) { - xlator_list_t *next = NULL; - - while (list) { - next = list->next; - GF_FREE (list); - list = next; + if (loc && __is_root_gfid (loc->gfid)) { + return _gf_true; + } else if (loc && loc->inode && __is_root_gfid (loc->inode->gfid)) { + return _gf_true; } - - return 0; + return _gf_false; } - int xlator_destroy (xlator_t *xl) { diff --git a/libglusterfs/src/xlator.h b/libglusterfs/src/xlator.h index 071a4bdb7..b57e5873e 100644 --- a/libglusterfs/src/xlator.h +++ b/libglusterfs/src/xlator.h @@ -66,6 +66,7 @@ typedef int32_t (*event_notify_fn_t) (xlator_t *this, int32_t event, void *data, #include "globals.h" #include "iatt.h" #include "options.h" +#include "client_t.h" struct _loc { @@ -417,6 +418,30 @@ typedef int32_t (*fop_fsetattr_cbk_t) (call_frame_t *frame, struct iatt *preop_stbuf, struct iatt *postop_stbuf, dict_t *xdata); +typedef int32_t (*fop_fallocate_cbk_t) (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct iatt *preop_stbuf, + struct iatt *postop_stbuf, dict_t *xdata); + +typedef int32_t (*fop_discard_cbk_t) (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct iatt *preop_stbuf, + struct iatt *postop_stbuf, dict_t *xdata); + +typedef int32_t (*fop_zerofill_cbk_t) (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct iatt *preop_stbuf, + struct iatt *postop_stbuf, dict_t *xdata); + typedef int32_t (*fop_lookup_t) (call_frame_t *frame, xlator_t *this, loc_t *loc, @@ -634,6 +659,26 @@ typedef int32_t (*fop_fsetattr_t) (call_frame_t *frame, struct iatt *stbuf, int32_t valid, dict_t *xdata); +typedef int32_t (*fop_fallocate_t) (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + int32_t keep_size, + off_t offset, + size_t len, + dict_t *xdata); + +typedef int32_t (*fop_discard_t) (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + off_t offset, + size_t len, + dict_t *xdata); +typedef int32_t (*fop_zerofill_t) (call_frame_t *frame, + xlator_t *this, + fd_t *fd, + off_t offset, + size_t len, + dict_t *xdata); struct xlator_fops { fop_lookup_t lookup; @@ -678,6 +723,9 @@ struct xlator_fops { fop_setattr_t setattr; fop_fsetattr_t fsetattr; fop_getspec_t getspec; + fop_fallocate_t fallocate; + fop_discard_t discard; + fop_zerofill_t zerofill; /* these entries are used for a typechecking hack in STACK_WIND _only_ */ fop_lookup_cbk_t lookup_cbk; @@ -722,6 +770,9 @@ struct xlator_fops { fop_setattr_cbk_t setattr_cbk; fop_fsetattr_cbk_t fsetattr_cbk; fop_getspec_cbk_t getspec_cbk; + fop_fallocate_cbk_t fallocate_cbk; + fop_discard_cbk_t discard_cbk; + fop_zerofill_cbk_t zerofill_cbk; }; typedef int32_t (*cbk_forget_t) (xlator_t *this, @@ -732,11 +783,15 @@ typedef int32_t (*cbk_release_t) (xlator_t *this, typedef int32_t (*cbk_invalidate_t)(xlator_t *this, inode_t *inode); +typedef int32_t (*cbk_client_t)(xlator_t *this, client_t *client); + struct xlator_cbks { - cbk_forget_t forget; - cbk_release_t release; - cbk_release_t releasedir; - cbk_invalidate_t invalidate; + cbk_forget_t forget; + cbk_release_t release; + cbk_release_t releasedir; + cbk_invalidate_t invalidate; + cbk_client_t client_destroy; + cbk_client_t client_disconnect; }; typedef int32_t (*dumpop_priv_t) (xlator_t *this); @@ -878,7 +933,6 @@ void xlator_foreach_depth_first (xlator_t *this, void *data); xlator_t *xlator_search_by_name (xlator_t *any, const char *name); -xlator_t *xlator_search_by_xl_type (xlator_t *any, const char *type); void inode_destroy_notify (inode_t *inode, const char *xlname); @@ -886,7 +940,9 @@ int loc_copy (loc_t *dst, loc_t *src); #define loc_dup(src, dst) loc_copy(dst, src) void loc_wipe (loc_t *loc); int loc_path (loc_t *loc, const char *bname); +void loc_gfid (loc_t *loc, uuid_t gfid); char* loc_gfid_utoa (loc_t *loc); +gf_boolean_t loc_is_root (loc_t *loc); int xlator_mem_acct_init (xlator_t *xl, int num_types); int is_gf_log_command (xlator_t *trans, const char *name, char *value); int glusterd_check_log_level (const char *value); @@ -896,5 +952,9 @@ enum gf_hdsk_event_notify_op { GF_EN_DEFRAG_STATUS, GF_EN_MAX, }; - +gf_boolean_t +is_graph_topology_equal (glusterfs_graph_t *graph1, glusterfs_graph_t *graph2); +int +glusterfs_volfile_reconfigure (int oldvollen, FILE *newvolfile_fp, + glusterfs_ctx_t *ctx, const char *oldvolfile); #endif /* _XLATOR_H */ |
