diff options
Diffstat (limited to 'libglusterfs')
163 files changed, 59623 insertions, 22804 deletions
diff --git a/libglusterfs/src/Makefile.am b/libglusterfs/src/Makefile.am index 3513419ebc9..385e8ef4600 100644 --- a/libglusterfs/src/Makefile.am +++ b/libglusterfs/src/Makefile.am @@ -1,21 +1,116 @@ -libglusterfs_la_CFLAGS = -fPIC -Wall -g -shared -nostartfiles $(GF_CFLAGS) $(GF_DARWIN_LIBGLUSTERFS_CFLAGS) +noinst_PYTHON = generator.py gen-defaults.py $(top_srcdir)/events/eventskeygen.py -libglusterfs_la_CPPFLAGS = -D_FILE_OFFSET_BITS=64 -D__USE_FILE_OFFSET64 -D_GNU_SOURCE -DXLATORDIR=\"$(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator\" -D$(GF_HOST_OS) -I$(CONTRIBDIR)/rbtree -DSCHEDULERDIR=\"$(libdir)/glusterfs/$(PACKAGE_VERSION)/scheduler\" -I$(CONTRIBDIR)/md5 +libglusterfs_la_CFLAGS = $(GF_CFLAGS) $(GF_DARWIN_LIBGLUSTERFS_CFLAGS) \ + -DDATADIR=\"$(localstatedir)\" -libglusterfs_la_LIBADD = @LEXLIB@ +libglusterfs_la_CPPFLAGS = $(GF_CPPFLAGS) -D__USE_FILE_OFFSET64 \ + -DXLATORDIR=\"$(libdir)/glusterfs/$(PACKAGE_VERSION)/xlator\" \ + -DXLATORPARENTDIR=\"$(libdir)/glusterfs/$(PACKAGE_VERSION)\" \ + -DXXH_NAMESPACE=GF_ -D__USE_LARGEFILE64 \ + -I$(CONTRIBDIR)/rbtree \ + -I$(CONTRIBDIR)/libexecinfo ${ARGP_STANDALONE_CPPFLAGS} \ + -DSBIN_DIR=\"$(sbindir)\" -I$(CONTRIBDIR)/timer-wheel \ + -I$(CONTRIBDIR)/xxhash + +libglusterfs_la_LIBADD = $(ZLIB_LIBS) $(MATH_LIB) $(UUID_LIBS) $(LIB_DL) \ + $(URCU_LIBS) $(URCU_CDS_LIBS) +libglusterfs_la_LDFLAGS = -version-info $(LIBGLUSTERFS_LT_VERSION) $(GF_LDFLAGS) \ + -export-symbols $(top_srcdir)/libglusterfs/src/libglusterfs.sym lib_LTLIBRARIES = libglusterfs.la +libgfchangelogdir = $(includedir)/glusterfs/gfchangelog + +CONTRIB_BUILDDIR = $(top_builddir)/contrib + +libglusterfs_la_SOURCES = dict.c xlator.c logging.c \ + hashfn.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 timespec.c \ + $(CONTRIBDIR)/rbtree/rb.c rbthash.c store.c latency.c \ + graph.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 client_t.c event-poll.c \ + event-epoll.c syncop-utils.c cluster-syncop.c refcount.c \ + $(CONTRIBDIR)/libgen/basename_r.c \ + $(CONTRIBDIR)/libgen/dirname_r.c \ + strfd.c parse-utils.c $(CONTRIBDIR)/mount/mntent.c \ + $(CONTRIBDIR)/libexecinfo/execinfo.c quota-common-utils.c rot-buffs.c \ + $(CONTRIBDIR)/timer-wheel/timer-wheel.c \ + $(CONTRIBDIR)/timer-wheel/find_last_bit.c default-args.c locking.c \ + $(CONTRIBDIR)/xxhash/xxhash.c \ + throttle-tbf.c monitoring.c async.c + +nodist_libglusterfs_la_SOURCES = y.tab.c graph.lex.c defaults.c +nodist_libglusterfs_la_HEADERS = y.tab.h + +BUILT_SOURCES = graph.lex.c defaults.c eventtypes.h + +libglusterfs_la_HEADERS = glusterfs/common-utils.h glusterfs/defaults.h \ + glusterfs/default-args.h glusterfs/dict.h glusterfs/glusterfs.h \ + glusterfs/hashfn.h glusterfs/timespec.h glusterfs/logging.h \ + glusterfs/xlator.h glusterfs/stack.h glusterfs/timer.h glusterfs/list.h \ + glusterfs/inode.h glusterfs/call-stub.h glusterfs/compat.h glusterfs/fd.h \ + glusterfs/revision.h glusterfs/compat-errno.h glusterfs/gf-event.h \ + glusterfs/mem-pool.h glusterfs/byte-order.h glusterfs/gf-dirent.h \ + glusterfs/locking.h glusterfs/syscall.h glusterfs/iobuf.h \ + glusterfs/globals.h glusterfs/statedump.h glusterfs/checksum.h \ + glusterfs/daemon.h glusterfs/store.h glusterfs/rbthash.h glusterfs/iatt.h \ + glusterfs/latency.h glusterfs/mem-types.h glusterfs/syncop.h \ + glusterfs/cluster-syncop.h glusterfs/graph-utils.h glusterfs/trie.h \ + glusterfs/refcount.h glusterfs/run.h glusterfs/options.h \ + glusterfs/lkowner.h glusterfs/fd-lk.h glusterfs/circ-buff.h \ + glusterfs/event-history.h glusterfs/gidcache.h glusterfs/client_t.h \ + glusterfs/glusterfs-acl.h glusterfs/glfs-message-id.h \ + glusterfs/template-component-messages.h glusterfs/strfd.h \ + glusterfs/syncop-utils.h glusterfs/parse-utils.h \ + glusterfs/libglusterfs-messages.h glusterfs/lvm-defaults.h \ + glusterfs/quota-common-utils.h glusterfs/rot-buffs.h \ + glusterfs/compat-uuid.h glusterfs/upcall-utils.h glusterfs/throttle-tbf.h \ + glusterfs/events.h glusterfs/atomic.h glusterfs/monitoring.h \ + glusterfs/async.h glusterfs/glusterfs-fops.h -libglusterfs_la_SOURCES = dict.c graph.lex.c y.tab.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 $(CONTRIBDIR)/md5/md5.c $(CONTRIBDIR)/rbtree/rb.c rbthash.c latency.c graph.c $(CONTRIBDIR)/uuid/clear.c $(CONTRIBDIR)/uuid/copy.c $(CONTRIBDIR)/uuid/gen_uuid.c $(CONTRIBDIR)/uuid/pack.c $(CONTRIBDIR)/uuid/tst_uuid.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 +libglusterfs_ladir = $(includedir)/glusterfs -noinst_HEADERS = common-utils.h defaults.h dict.h glusterfs.h hashfn.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 $(CONTRIBDIR)/md5/md5.h $(CONTRIBDIR)/rbtree/rb.h rbthash.h iatt.h latency.h mem-types.h $(CONTRIBDIR)/uuid/uuidd.h $(CONTRIBDIR)/uuid/uuid.h $(CONTRIBDIR)/uuid/uuidP.h $(CONTRIBDIR)/uuid/uuid_types.h syncop.h +noinst_HEADERS = unittest/unittest.h \ + $(CONTRIBDIR)/rbtree/rb.h \ + $(CONTRIBDIR)/mount/mntent_compat.h \ + $(CONTRIBDIR)/libexecinfo/execinfo_compat.h \ + $(CONTRIBDIR)/timer-wheel/timer-wheel.h \ + $(CONTRIBDIR)/xxhash/xxhash.h \ + $(CONTRIBDIR)/userspace-rcu/wfcqueue.h \ + $(CONTRIBDIR)/userspace-rcu/wfstack.h \ + $(CONTRIBDIR)/userspace-rcu/static-wfcqueue.h \ + $(CONTRIBDIR)/userspace-rcu/static-wfstack.h -EXTRA_DIST = graph.l graph.y +eventtypes.h: $(top_srcdir)/events/eventskeygen.py + $(PYTHON) $(top_srcdir)/events/eventskeygen.py C_HEADER + +if BUILD_EVENTS +libglusterfs_la_SOURCES += events.c +endif + +libgfchangelog_HEADERS = changelog.h + +EXTRA_DIST = graph.l graph.y defaults-tmpl.c libglusterfs.sym 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) -p graphyy -d $(srcdir)/graph.y + +defaults.c: defaults-tmpl.c generator.py gen-defaults.py + $(PYTHON) $(srcdir)/gen-defaults.py $(srcdir)/defaults-tmpl.c > $@ + +CLEANFILES = $(nodist_libglusterfs_la_SOURCES) \ + $(nodist_libglusterfs_la_HEADERS) *.pyc -y.tab.c y.tab.h: graph.y - $(YACC) -d $(srcdir)/graph.y +if UNITTEST +CLEANFILES += *.gcda *.gcno *_xunit.xml +noinst_PROGRAMS = +TESTS = +endif -CLEANFILES = graph.lex.c y.tab.c y.tab.h +if BUILD_EVENTS +CLEANFILES += eventtypes.h +endif diff --git a/libglusterfs/src/async.c b/libglusterfs/src/async.c new file mode 100644 index 00000000000..1d6cfa374b6 --- /dev/null +++ b/libglusterfs/src/async.c @@ -0,0 +1,720 @@ +/* + Copyright (c) 2019 Red Hat, Inc <https://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. +*/ + +/* To implement an efficient thread pool with minimum contention we have used + * the following ideas: + * + * - The queue of jobs has been implemented using a Wait-Free queue provided + * by the userspace-rcu library. This queue requires a mutex when multiple + * consumers can be extracting items from it concurrently, but the locked + * region is very small, which minimizes the chances of contention. To + * further minimize contention, the number of active worker threads that + * are accessing the queue is dynamically adjusted so that we always have + * the minimum required amount of workers contending for the queue. Adding + * new items can be done with a single atomic operation, without locks. + * + * - All queue management operations, like creating more threads, enabling + * sleeping ones, etc. are done by a single thread. This makes it possible + * to manage all scaling related information and workers lists without + * locks. This functionality is implemented as a role that can be assigned + * to any of the worker threads, which avoids that some lengthy operations + * could interfere with this task. + * + * - Management is based on signals. We used signals for management tasks to + * avoid multiple system calls for each request (with signals we can wait + * for multiple events and get some additional data for each request in a + * single call, instead of first polling and then reading). + * + * TODO: There are some other changes that can take advantage of this new + * thread pool. + * + * - Use this thread pool as the core threading model for synctasks. I + * think this would improve synctask performance because I think we + * currently have some contention there for some workloads. + * + * - Implement a per thread timer that will allow adding and removing + * timers without using mutexes. + * + * - Integrate with userspace-rcu library in QSBR mode, allowing + * other portions of code to be implemented using RCU-based + * structures with a extremely fast read side without contention. + * + * - Integrate I/O into the thread pool so that the thread pool is + * able to efficiently manage all loads and scale dynamically. This + * could make it possible to minimize context switching when serving + * requests from fuse or network. + * + * - Dynamically scale the number of workers based on system load. + * This will make it possible to reduce contention when system is + * heavily loaded, improving performance under these circumstances + * (or minimizing performance loss). This will also make it possible + * that gluster can coexist with other processes that also consume + * CPU, with minimal interference from each other. + */ + +#include <unistd.h> +#include <pthread.h> +#include <errno.h> + +#include "glusterfs/list.h" +#include "glusterfs/mem-types.h" +#include "glusterfs/async.h" + +/* These macros wrap a simple system/library call to check the returned error + * and log a message in case of failure. */ +#define GF_ASYNC_CHECK(_func, _args...) \ + ({ \ + int32_t __async_error = -_func(_args); \ + if (caa_unlikely(__async_error != 0)) { \ + gf_async_error(__async_error, #_func "() failed."); \ + } \ + __async_error; \ + }) + +#define GF_ASYNC_CHECK_ERRNO(_func, _args...) \ + ({ \ + int32_t __async_error = _func(_args); \ + if (caa_unlikely(__async_error < 0)) { \ + __async_error = -errno; \ + gf_async_error(__async_error, #_func "() failed."); \ + } \ + __async_error; \ + }) + +/* These macros are used when, based on POSIX documentation, the function + * should never fail under the conditions we are using it. So any unexpected + * error will be handled as a fatal event. It probably means a critical bug + * or memory corruption. In both cases we consider that stopping the process + * is safer (otherwise it could cause more corruption with unknown effects + * that could be worse). */ +#define GF_ASYNC_CANTFAIL(_func, _args...) \ + do { \ + int32_t __async_error = -_func(_args); \ + if (caa_unlikely(__async_error != 0)) { \ + gf_async_fatal(__async_error, #_func "() failed"); \ + } \ + } while (0) + +#define GF_ASYNC_CANTFAIL_ERRNO(_func, _args...) \ + ({ \ + int32_t __async_error = _func(_args); \ + if (caa_unlikely(__async_error < 0)) { \ + __async_error = -errno; \ + gf_async_fatal(__async_error, #_func "() failed"); \ + } \ + __async_error; \ + }) + +/* TODO: for now we allocate a static array of workers. There's an issue if we + * try to use dynamic memory since these workers are initialized very + * early in the process startup and it seems that sometimes not all is + * ready to use dynamic memory. */ +static gf_async_worker_t gf_async_workers[GF_ASYNC_MAX_THREADS]; + +/* This is the only global variable needed to manage the entire framework. */ +gf_async_control_t gf_async_ctrl = {}; + +static __thread gf_async_worker_t *gf_async_current_worker = NULL; + +/* The main function of the worker threads. */ +static void * +gf_async_worker(void *arg); + +static void +gf_async_sync_init(void) +{ + GF_ASYNC_CANTFAIL(pthread_barrier_init, &gf_async_ctrl.sync, NULL, 2); +} + +static void +gf_async_sync_now(void) +{ + int32_t ret; + + ret = pthread_barrier_wait(&gf_async_ctrl.sync); + if (ret == PTHREAD_BARRIER_SERIAL_THREAD) { + GF_ASYNC_CANTFAIL(pthread_barrier_destroy, &gf_async_ctrl.sync); + ret = 0; + } + if (caa_unlikely(ret != 0)) { + gf_async_fatal(-ret, "pthread_barrier_wait() failed"); + } +} + +static void +gf_async_sigmask_empty(sigset_t *mask) +{ + GF_ASYNC_CANTFAIL_ERRNO(sigemptyset, mask); +} + +static void +gf_async_sigmask_add(sigset_t *mask, int32_t signal) +{ + GF_ASYNC_CANTFAIL_ERRNO(sigaddset, mask, signal); +} + +static void +gf_async_sigmask_set(int32_t mode, sigset_t *mask, sigset_t *old) +{ + GF_ASYNC_CANTFAIL(pthread_sigmask, mode, mask, old); +} + +static void +gf_async_sigaction(int32_t signum, const struct sigaction *action, + struct sigaction *old) +{ + GF_ASYNC_CANTFAIL_ERRNO(sigaction, signum, action, old); +} + +static int32_t +gf_async_sigwait(sigset_t *set) +{ + int32_t ret, signum; + + do { + ret = sigwait(set, &signum); + } while (caa_unlikely((ret < 0) && (errno == EINTR))); + + if (caa_unlikely(ret < 0)) { + ret = -errno; + gf_async_fatal(ret, "sigwait() failed"); + } + + return signum; +} + +static int32_t +gf_async_sigtimedwait(sigset_t *set, struct timespec *timeout) +{ + int32_t ret; + + do { + ret = sigtimedwait(set, NULL, timeout); + } while (caa_unlikely((ret < 0) && (errno == EINTR))); + if (caa_unlikely(ret < 0)) { + ret = -errno; + /* EAGAIN means that the timeout has expired, so we allow this error. + * Any other error shouldn't happen. */ + if (caa_unlikely(ret != -EAGAIN)) { + gf_async_fatal(ret, "sigtimedwait() failed"); + } + ret = 0; + } + + return ret; +} + +static void +gf_async_sigbroadcast(int32_t signum) +{ + GF_ASYNC_CANTFAIL_ERRNO(kill, gf_async_ctrl.pid, signum); +} + +static void +gf_async_signal_handler(int32_t signum) +{ + /* We should never handle a signal in this function. */ + gf_async_fatal(-EBUSY, + "Unexpected processing of signal %d through a handler.", + signum); +} + +static void +gf_async_signal_setup(void) +{ + struct sigaction action; + + /* We configure all related signals so that we can detect threads using an + * invalid signal mask that doesn't block our critical signal. */ + memset(&action, 0, sizeof(action)); + action.sa_handler = gf_async_signal_handler; + + gf_async_sigaction(GF_ASYNC_SIGCTRL, &action, &gf_async_ctrl.handler_ctrl); + + gf_async_sigaction(GF_ASYNC_SIGQUEUE, &action, + &gf_async_ctrl.handler_queue); +} + +static void +gf_async_signal_restore(void) +{ + /* Handlers we have previously changed are restored back to their original + * value. */ + + if (gf_async_ctrl.handler_ctrl.sa_handler != gf_async_signal_handler) { + gf_async_sigaction(GF_ASYNC_SIGCTRL, &gf_async_ctrl.handler_ctrl, NULL); + } + + if (gf_async_ctrl.handler_queue.sa_handler != gf_async_signal_handler) { + gf_async_sigaction(GF_ASYNC_SIGQUEUE, &gf_async_ctrl.handler_queue, + NULL); + } +} + +static void +gf_async_signal_flush(void) +{ + struct timespec delay; + + delay.tv_sec = 0; + delay.tv_nsec = 0; + + /* We read all pending signals so that they don't trigger once the signal + * mask of some thread is changed. */ + while (gf_async_sigtimedwait(&gf_async_ctrl.sigmask_ctrl, &delay) > 0) { + } + while (gf_async_sigtimedwait(&gf_async_ctrl.sigmask_queue, &delay) > 0) { + } +} + +static int32_t +gf_async_thread_create(pthread_t *thread, int32_t id, void *data) +{ + int32_t ret; + + ret = gf_thread_create(thread, NULL, gf_async_worker, data, + GF_ASYNC_THREAD_NAME "%u", id); + if (caa_unlikely(ret < 0)) { + /* TODO: gf_thread_create() should return a more specific error + * code. */ + return -ENOMEM; + } + + return 0; +} + +static void +gf_async_thread_wait(pthread_t thread) +{ + /* TODO: this is a blocking call executed inside one of the workers of the + * thread pool. This is bad, but this is only executed once we have + * received a notification from the thread that it's terminating, so + * this should return almost immediately. However, to be more robust + * it would be better to use pthread_timedjoin_np() (or even a call + * to pthread_tryjoin_np() followed by a delayed recheck if it + * fails), but they are not portable. We should see how to do this + * in other platforms. */ + GF_ASYNC_CANTFAIL(pthread_join, thread, NULL); +} + +static int32_t +gf_async_worker_create(void) +{ + struct cds_wfs_node *node; + gf_async_worker_t *worker; + uint32_t counts, running, max; + int32_t ret; + + node = __cds_wfs_pop_blocking(&gf_async_ctrl.available); + if (caa_unlikely(node == NULL)) { + /* There are no more available workers. We have all threads running. */ + return 1; + } + cds_wfs_node_init(node); + + ret = 1; + + counts = uatomic_read(&gf_async_ctrl.counts); + max = uatomic_read(&gf_async_ctrl.max_threads); + running = GF_ASYNC_COUNT_RUNNING(counts); + if (running < max) { + uatomic_add(&gf_async_ctrl.counts, GF_ASYNC_COUNTS(1, 0)); + + worker = caa_container_of(node, gf_async_worker_t, stack); + + ret = gf_async_thread_create(&worker->thread, worker->id, worker); + if (caa_likely(ret >= 0)) { + return 0; + } + + uatomic_add(&gf_async_ctrl.counts, GF_ASYNC_COUNTS(-1, 0)); + } + + cds_wfs_push(&gf_async_ctrl.available, node); + + return ret; +} + +static void +gf_async_worker_enable(void) +{ + /* This will wake one of the spare workers. If all workers are busy now, + * the signal will be queued so that the first one that completes its + * work will become the leader. */ + gf_async_sigbroadcast(GF_ASYNC_SIGCTRL); + + /* We have consumed a spare worker. We create another one for future + * needs. */ + gf_async_worker_create(); +} + +static void +gf_async_worker_wait(void) +{ + int32_t signum; + + signum = gf_async_sigwait(&gf_async_ctrl.sigmask_ctrl); + if (caa_unlikely(signum != GF_ASYNC_SIGCTRL)) { + gf_async_fatal(-EINVAL, "Worker received an unexpected signal (%d)", + signum); + } +} + +static void +gf_async_leader_wait(void) +{ + int32_t signum; + + signum = gf_async_sigwait(&gf_async_ctrl.sigmask_queue); + if (caa_unlikely(signum != GF_ASYNC_SIGQUEUE)) { + gf_async_fatal(-EINVAL, "Leader received an unexpected signal (%d)", + signum); + } +} + +static void +gf_async_run(struct cds_wfcq_node *node) +{ + gf_async_t *async; + + /* We've just got work from the queue. Process it. */ + async = caa_container_of(node, gf_async_t, queue); + /* TODO: remove dependency from THIS and xl. */ + THIS = async->xl; + async->cbk(async->xl, async); +} + +static void +gf_async_worker_run(void) +{ + struct cds_wfcq_node *node; + + do { + /* We keep executing jobs from the queue while it's not empty. Note + * that while we do this, we are ignoring any stop request. That's + * fine, since we need to process our own 'join' messages to fully + * terminate all threads. Note that normal jobs should have already + * completed once a stop request is received. */ + node = cds_wfcq_dequeue_blocking(&gf_async_ctrl.queue.head, + &gf_async_ctrl.queue.tail); + if (node != NULL) { + gf_async_run(node); + } + } while (node != NULL); + + /* TODO: I've tried to keep the worker looking at the queue for some small + * amount of time in a busy loop to see if more jobs come soon. With + * this I attempted to avoid the overhead of signal management if + * jobs come fast enough. However experimental results seem to + * indicate that doing this, CPU utilization grows and performance + * is actually reduced. We need to see if that's because I used bad + * parameters or it's really better to do it as it's done now. */ +} + +static void +gf_async_leader_run(void) +{ + struct cds_wfcq_node *node; + + node = cds_wfcq_dequeue_blocking(&gf_async_ctrl.queue.head, + &gf_async_ctrl.queue.tail); + while (caa_unlikely(node == NULL)) { + gf_async_leader_wait(); + + node = cds_wfcq_dequeue_blocking(&gf_async_ctrl.queue.head, + &gf_async_ctrl.queue.tail); + } + + /* Activate the next available worker thread. It will become the new + * leader. */ + gf_async_worker_enable(); + + gf_async_run(node); +} + +static uint32_t +gf_async_stop_check(gf_async_worker_t *worker) +{ + uint32_t counts, old, running, max; + + /* First we check if we should stop without doing any costly atomic + * operation. */ + old = uatomic_read(&gf_async_ctrl.counts); + max = uatomic_read(&gf_async_ctrl.max_threads); + running = GF_ASYNC_COUNT_RUNNING(old); + while (running > max) { + /* There are too many threads. We try to stop the current worker. */ + counts = uatomic_cmpxchg(&gf_async_ctrl.counts, old, + old + GF_ASYNC_COUNTS(-1, 1)); + if (old != counts) { + /* Another thread has just updated the counts. We need to retry. */ + old = counts; + running = GF_ASYNC_COUNT_RUNNING(old); + + continue; + } + + running--; + worker->running = false; + } + + return running; +} + +static void +gf_async_stop_all(xlator_t *xl, gf_async_t *async) +{ + if (gf_async_stop_check(gf_async_current_worker) > 0) { + /* There are more workers running. We propagate the stop request to + * them. */ + gf_async(async, xl, gf_async_stop_all); + } +} + +static void +gf_async_join(xlator_t *xl, gf_async_t *async) +{ + gf_async_worker_t *worker; + + worker = caa_container_of(async, gf_async_worker_t, async); + + gf_async_thread_wait(worker->thread); + + cds_wfs_push(&gf_async_ctrl.available, &worker->stack); +} + +static void +gf_async_terminate(gf_async_worker_t *worker) +{ + uint32_t counts; + + counts = uatomic_add_return(&gf_async_ctrl.counts, GF_ASYNC_COUNTS(0, -1)); + if (counts == 0) { + /* This is the termination of the last worker thread. We need to + * synchronize the main thread that is waiting for all workers to + * finish. */ + gf_async_ctrl.sync_thread = worker->thread; + + gf_async_sync_now(); + } else { + /* Force someone else to join this thread to release resources. */ + gf_async(&worker->async, THIS, gf_async_join); + } +} + +static void * +gf_async_worker(void *arg) +{ + gf_async_worker_t *worker; + + worker = (gf_async_worker_t *)arg; + gf_async_current_worker = worker; + + worker->running = true; + do { + /* This thread does nothing until someone enables it to become a + * leader. */ + gf_async_worker_wait(); + + /* This thread is now a leader. It will process jobs from the queue + * and, if necessary, enable another worker and transfer leadership + * to it. */ + gf_async_leader_run(); + + /* This thread is not a leader anymore. It will continue processing + * queued jobs until it becomes empty. */ + gf_async_worker_run(); + + /* Stop the current thread if there are too many threads running. */ + gf_async_stop_check(worker); + } while (worker->running); + + gf_async_terminate(worker); + + return NULL; +} + +static void +gf_async_cleanup(void) +{ + /* We do some basic initialization of the global variable 'gf_async_ctrl' + * so that it's put into a relatively consistent state. */ + + gf_async_ctrl.enabled = false; + + gf_async_ctrl.pid = 0; + gf_async_sigmask_empty(&gf_async_ctrl.sigmask_ctrl); + gf_async_sigmask_empty(&gf_async_ctrl.sigmask_queue); + + /* This is used to later detect if the handler of these signals have been + * changed or not. */ + gf_async_ctrl.handler_ctrl.sa_handler = gf_async_signal_handler; + gf_async_ctrl.handler_queue.sa_handler = gf_async_signal_handler; + + gf_async_ctrl.table = NULL; + gf_async_ctrl.max_threads = 0; + gf_async_ctrl.counts = 0; +} + +void +gf_async_fini(void) +{ + gf_async_t async; + + if (uatomic_read(&gf_async_ctrl.counts) != 0) { + /* We ensure that all threads will quit on the next check. */ + gf_async_ctrl.max_threads = 0; + + /* Send the stop request to the thread pool. This will cause the + * execution of gf_async_stop_all() by one of the worker threads which, + * eventually, will terminate all worker threads. */ + gf_async(&async, THIS, gf_async_stop_all); + + /* We synchronize here with the last thread. */ + gf_async_sync_now(); + + /* We have just synchronized with the latest thread. Now just wait for + * it to terminate. */ + gf_async_thread_wait(gf_async_ctrl.sync_thread); + + gf_async_signal_flush(); + } + + gf_async_signal_restore(); + + gf_async_cleanup(); +} + +void +gf_async_adjust_threads(int32_t threads) +{ + if (threads == 0) { + /* By default we allow a maximum of 2 * #cores worker threads. This + * value is to try to accommodate threads that will do some I/O. Having + * more threads than cores we can keep CPU busy even if some threads + * are blocked for I/O. In the most efficient case, we can have #cores + * computing threads and #cores blocked threads on I/O. However this is + * hard to achieve because we can end with more than #cores computing + * threads, which won't provide a real benefit and will increase + * contention. + * + * TODO: implement a more intelligent dynamic maximum based on CPU + * usage and/or system load. */ + threads = sysconf(_SC_NPROCESSORS_ONLN) * 2; + if (threads < 0) { + /* If we can't get the current number of processors, we pick a + * random number. */ + threads = 16; + } + } + if (threads > GF_ASYNC_MAX_THREADS) { + threads = GF_ASYNC_MAX_THREADS; + } + uatomic_set(&gf_async_ctrl.max_threads, threads); +} + +int32_t +gf_async_init(glusterfs_ctx_t *ctx) +{ + sigset_t set; + gf_async_worker_t *worker; + uint32_t i; + int32_t ret; + bool running; + + gf_async_cleanup(); + + if (!ctx->cmd_args.global_threading || + (ctx->process_mode == GF_GLUSTERD_PROCESS)) { + return 0; + } + + /* At the init time, the maximum number of threads has not yet been + * configured. We use a small starting value that will be layer dynamically + * adjusted when ctx->config.max_threads is updated. */ + gf_async_adjust_threads(GF_ASYNC_SPARE_THREADS + 1); + + gf_async_ctrl.pid = getpid(); + + __cds_wfs_init(&gf_async_ctrl.available); + cds_wfcq_init(&gf_async_ctrl.queue.head, &gf_async_ctrl.queue.tail); + + gf_async_sync_init(); + + /* TODO: it would be cleaner to use dynamic memory, but at this point some + * memory management resources are not yet initialized. */ + gf_async_ctrl.table = gf_async_workers; + + /* We keep all workers in a stack. It will be used when a new thread needs + * to be created. */ + for (i = GF_ASYNC_MAX_THREADS; i > 0; i--) { + worker = &gf_async_ctrl.table[i - 1]; + + worker->id = i - 1; + cds_wfs_node_init(&worker->stack); + cds_wfs_push(&gf_async_ctrl.available, &worker->stack); + } + + /* Prepare the signal mask for regular workers and the leader. */ + gf_async_sigmask_add(&gf_async_ctrl.sigmask_ctrl, GF_ASYNC_SIGCTRL); + gf_async_sigmask_add(&gf_async_ctrl.sigmask_queue, GF_ASYNC_SIGQUEUE); + + /* TODO: this is needed to block our special signals in the current thread + * and all children that it starts. It would be cleaner to do it when + * signals are initialized, but there doesn't seem to be a unique + * place to do that, so for now we do it here. */ + gf_async_sigmask_empty(&set); + gf_async_sigmask_add(&set, GF_ASYNC_SIGCTRL); + gf_async_sigmask_add(&set, GF_ASYNC_SIGQUEUE); + gf_async_sigmask_set(SIG_BLOCK, &set, NULL); + + /* Configure the signal handlers. This is mostly for safety, not really + * needed, but it doesn't hurt. Note that the caller must ensure that the + * signals we need to run are already blocked in any thread already + * started. Otherwise this won't work. */ + gf_async_signal_setup(); + + running = false; + + /* We start the spare workers + 1 for the leader. */ + for (i = 0; i < GF_ASYNC_SPARE_THREADS; i++) { + ret = gf_async_worker_create(); + if (caa_unlikely(ret < 0)) { + /* This is the initial start up so we enforce that the spare + * threads are created. If this fails at the beginning, it's very + * unlikely that the async workers could do its job, so we abort + * the initialization. */ + goto out; + } + + /* Once the first thread is started, we can enable it to become the + * initial leader. */ + if ((ret == 0) && !running) { + running = true; + gf_async_worker_enable(); + } + } + + if (caa_unlikely(!running)) { + gf_async_fatal(-ENOMEM, "No worker thread has started"); + } + + gf_async_ctrl.enabled = true; + + ret = 0; + +out: + if (ret < 0) { + gf_async_error(ret, "Unable to initialize the thread pool."); + gf_async_fini(); + } + + return ret; +} diff --git a/libglusterfs/src/byte-order.h b/libglusterfs/src/byte-order.h deleted file mode 100644 index 817ae47904e..00000000000 --- a/libglusterfs/src/byte-order.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - Copyright (c) 2008-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _BYTE_ORDER_H -#define _BYTE_ORDER_H - -#include <inttypes.h> - -#define LS1 0x00ffU -#define MS1 0xff00U -#define LS2 0x0000ffffU -#define MS2 0xffff0000U -#define LS4 0x00000000ffffffffULL -#define MS4 0xffffffff00000000ULL - - -static uint16_t (*hton16) (uint16_t); -static uint32_t (*hton32) (uint32_t); -static uint64_t (*hton64) (uint64_t); - -#define ntoh16 hton16 -#define ntoh32 hton32 -#define ntoh64 hton64 - -#define do_swap2(x) (((x&LS1) << 8)|(((x&MS1) >> 8))) -#define do_swap4(x) ((do_swap2(x&LS2) << 16)|(do_swap2((x&MS2) >> 16))) -#define do_swap8(x) ((do_swap4(x&LS4) << 32)|(do_swap4((x&MS4) >> 32))) - - -static inline uint16_t -__swap16 (uint16_t x) -{ - return do_swap2(x); -} - - -static inline uint32_t -__swap32 (uint32_t x) -{ - return do_swap4(x); -} - - -static inline uint64_t -__swap64 (uint64_t x) -{ - return do_swap8(x); -} - - -static inline uint16_t -__noswap16 (uint16_t x) -{ - return x; -} - - -static inline uint32_t -__noswap32 (uint32_t x) -{ - return x; -} - - -static inline uint64_t -__noswap64 (uint64_t x) -{ - return x; -} - - -static inline uint16_t -__byte_order_init16 (uint16_t i) -{ - uint32_t num = 1; - - if (((char *)(&num))[0] == 1) { - hton16 = __swap16; - hton32 = __swap32; - hton64 = __swap64; - } else { - hton16 = __noswap16; - hton32 = __noswap32; - hton64 = __noswap64; - } - - return hton16 (i); -} - - -static inline uint32_t -__byte_order_init32 (uint32_t i) -{ - uint32_t num = 1; - - if (((char *)(&num))[0] == 1) { - hton16 = __swap16; - hton32 = __swap32; - hton64 = __swap64; - } else { - hton16 = __noswap16; - hton32 = __noswap32; - hton64 = __noswap64; - } - - return hton32 (i); -} - - -static inline uint64_t -__byte_order_init64 (uint64_t i) -{ - uint32_t num = 1; - - if (((char *)(&num))[0] == 1) { - hton16 = __swap16; - hton32 = __swap32; - hton64 = __swap64; - } else { - hton16 = __noswap16; - hton32 = __noswap32; - hton64 = __noswap64; - } - - return hton64 (i); -} - - -static uint16_t (*hton16) (uint16_t) = __byte_order_init16; -static uint32_t (*hton32) (uint32_t) = __byte_order_init32; -static uint64_t (*hton64) (uint64_t) = __byte_order_init64; - - -#endif /* _BYTE_ORDER_H */ diff --git a/libglusterfs/src/call-stub.c b/libglusterfs/src/call-stub.c index 7008cfd6f38..ee84f08acd4 100644 --- a/libglusterfs/src/call-stub.c +++ b/libglusterfs/src/call-stub.c @@ -1,3881 +1,2467 @@ /* - Copyright (c) 2007-2009 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 <openssl/md5.h> #include <inttypes.h> -#include "md5.h" -#include "call-stub.h" -#include "mem-types.h" - +#include "glusterfs/call-stub.h" +#include "glusterfs/mem-types.h" +#include "glusterfs/libglusterfs-messages.h" static call_stub_t * -stub_new (call_frame_t *frame, - char wind, - glusterfs_fop_t fop) +stub_new(call_frame_t *frame, const char wind, const glusterfs_fop_t fop) { - call_stub_t *new = NULL; + call_stub_t *new = NULL; + + GF_VALIDATE_OR_GOTO("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + new = mem_get0(frame->this->ctx->stub_mem_pool); + GF_VALIDATE_OR_GOTO("call-stub", new, out); - new = mem_get0 (frame->this->ctx->stub_mem_pool); - GF_VALIDATE_OR_GOTO ("call-stub", new, out); + new->frame = frame; + new->wind = wind; + new->fop = fop; + new->stub_mem_pool = frame->this->ctx->stub_mem_pool; + INIT_LIST_HEAD(&new->list); - new->frame = frame; - new->wind = wind; - new->fop = fop; - new->stub_mem_pool = frame->this->ctx->stub_mem_pool; - INIT_LIST_HEAD (&new->list); + INIT_LIST_HEAD(&new->args_cbk.entries); out: - return new; + return new; } - call_stub_t * -fop_lookup_stub (call_frame_t *frame, - fop_lookup_t fn, - loc_t *loc, - dict_t *xattr_req) +fop_lookup_stub(call_frame_t *frame, fop_lookup_t fn, loc_t *loc, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", loc, out); + GF_VALIDATE_OR_GOTO("call-stub", loc, out); - stub = stub_new (frame, 1, GF_FOP_LOOKUP); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_LOOKUP); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.lookup.fn = fn; + stub->fn.lookup = fn; + args_lookup_store(&stub->args, loc, xdata); +out: + return stub; +} + +call_stub_t * +fop_lookup_cbk_stub(call_frame_t *frame, fop_lookup_cbk_t fn, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + dict_t *xdata, struct iatt *postparent) +{ + call_stub_t *stub = NULL; - if (xattr_req) - stub->args.lookup.xattr_req = dict_ref (xattr_req); + stub = stub_new(frame, 0, GF_FOP_LOOKUP); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - loc_copy (&stub->args.lookup.loc, loc); + stub->fn_cbk.lookup = fn; + args_lookup_cbk_store(&stub->args_cbk, op_ret, op_errno, inode, buf, xdata, + postparent); out: - return stub; + return stub; } - call_stub_t * -fop_lookup_cbk_stub (call_frame_t *frame, - fop_lookup_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - dict_t *dict, - struct iatt *postparent) +fop_stat_stub(call_frame_t *frame, fop_stat_t fn, loc_t *loc, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + GF_VALIDATE_OR_GOTO("call-stub", loc, out); - stub = stub_new (frame, 0, GF_FOP_LOOKUP); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_STAT); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.lookup_cbk.fn = fn; - stub->args.lookup_cbk.op_ret = op_ret; - stub->args.lookup_cbk.op_errno = op_errno; - if (inode) - stub->args.lookup_cbk.inode = inode_ref (inode); - if (buf) - stub->args.lookup_cbk.buf = *buf; - if (dict) - stub->args.lookup_cbk.dict = dict_ref (dict); - if (postparent) - stub->args.lookup_cbk.postparent = *postparent; + stub->fn.stat = fn; + args_stat_store(&stub->args, loc, xdata); out: - return stub; + return stub; } - - call_stub_t * -fop_stat_stub (call_frame_t *frame, - fop_stat_t fn, - loc_t *loc) +fop_stat_cbk_stub(call_frame_t *frame, fop_stat_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct iatt *buf, dict_t *xdata) { - call_stub_t *stub = NULL; - - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", loc, out); + call_stub_t *stub = NULL; - stub = stub_new (frame, 1, GF_FOP_STAT); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 0, GF_FOP_STAT); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.stat.fn = fn; - loc_copy (&stub->args.stat.loc, loc); + stub->fn_cbk.stat = fn; + args_stat_cbk_store(&stub->args_cbk, op_ret, op_errno, buf, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_stat_cbk_stub (call_frame_t *frame, - fop_stat_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *buf) +fop_fstat_stub(call_frame_t *frame, fop_fstat_t fn, fd_t *fd, dict_t *xdata) { - call_stub_t *stub = NULL; - - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + call_stub_t *stub = NULL; - stub = stub_new (frame, 0, GF_FOP_STAT); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_FSTAT); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.stat_cbk.fn = fn; - stub->args.stat_cbk.op_ret = op_ret; - stub->args.stat_cbk.op_errno = op_errno; - if (op_ret == 0) - stub->args.stat_cbk.buf = *buf; + stub->fn.fstat = fn; + args_fstat_store(&stub->args, fd, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_fstat_stub (call_frame_t *frame, - fop_fstat_t fn, - fd_t *fd) +fop_fstat_cbk_stub(call_frame_t *frame, fop_fstat_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct iatt *buf, dict_t *xdata) { - call_stub_t *stub = NULL; - - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - - stub = stub_new (frame, 1, GF_FOP_FSTAT); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + call_stub_t *stub = NULL; - stub->args.fstat.fn = fn; + stub = stub_new(frame, 0, GF_FOP_FSTAT); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - if (fd) - stub->args.fstat.fd = fd_ref (fd); + stub->fn_cbk.fstat = fn; + args_fstat_cbk_store(&stub->args_cbk, op_ret, op_errno, buf, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_fstat_cbk_stub (call_frame_t *frame, - fop_fstat_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *buf) +fop_truncate_stub(call_frame_t *frame, fop_truncate_t fn, loc_t *loc, off_t off, + dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + GF_VALIDATE_OR_GOTO("call-stub", loc, out); - stub = stub_new (frame, 0, GF_FOP_FSTAT); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_TRUNCATE); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.fstat_cbk.fn = fn; - stub->args.fstat_cbk.op_ret = op_ret; - stub->args.fstat_cbk.op_errno = op_errno; - if (buf) - stub->args.fstat_cbk.buf = *buf; + stub->fn.truncate = fn; + args_truncate_store(&stub->args, loc, off, xdata); out: - return stub; + return stub; } +call_stub_t * +fop_truncate_cbk_stub(call_frame_t *frame, fop_truncate_cbk_t fn, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +{ + call_stub_t *stub = NULL; -/* truncate */ + stub = stub_new(frame, 0, GF_FOP_TRUNCATE); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + + stub->fn_cbk.truncate = fn; + args_truncate_cbk_store(&stub->args_cbk, op_ret, op_errno, prebuf, postbuf, + xdata); +out: + return stub; +} call_stub_t * -fop_truncate_stub (call_frame_t *frame, - fop_truncate_t fn, - loc_t *loc, - off_t off) +fop_ftruncate_stub(call_frame_t *frame, fop_ftruncate_t fn, fd_t *fd, off_t off, + dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", loc, out); + stub = stub_new(frame, 1, GF_FOP_FTRUNCATE); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 1, GF_FOP_TRUNCATE); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub->fn.ftruncate = fn; + args_ftruncate_store(&stub->args, fd, off, xdata); - stub->args.truncate.fn = fn; - loc_copy (&stub->args.truncate.loc, loc); - stub->args.truncate.off = off; out: - return stub; + return stub; } - call_stub_t * -fop_truncate_cbk_stub (call_frame_t *frame, - fop_truncate_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *prebuf, - struct iatt *postbuf) +fop_ftruncate_cbk_stub(call_frame_t *frame, fop_ftruncate_cbk_t fn, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + stub = stub_new(frame, 0, GF_FOP_FTRUNCATE); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 0, GF_FOP_TRUNCATE); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub->fn_cbk.ftruncate = fn; + args_ftruncate_cbk_store(&stub->args_cbk, op_ret, op_errno, prebuf, postbuf, + xdata); - stub->args.truncate_cbk.fn = fn; - stub->args.truncate_cbk.op_ret = op_ret; - stub->args.truncate_cbk.op_errno = op_errno; - if (prebuf) - stub->args.truncate_cbk.prebuf = *prebuf; - if (postbuf) - stub->args.truncate_cbk.postbuf = *postbuf; out: - return stub; + return stub; } - call_stub_t * -fop_ftruncate_stub (call_frame_t *frame, - fop_ftruncate_t fn, - fd_t *fd, - off_t off) +fop_access_stub(call_frame_t *frame, fop_access_t fn, loc_t *loc, int32_t mask, + dict_t *xdata) { - call_stub_t *stub = NULL; - - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + call_stub_t *stub = NULL; - stub = stub_new (frame, 1, GF_FOP_FTRUNCATE); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + GF_VALIDATE_OR_GOTO("call-stub", loc, out); - stub->args.ftruncate.fn = fn; - if (fd) - stub->args.ftruncate.fd = fd_ref (fd); + stub = stub_new(frame, 1, GF_FOP_ACCESS); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.ftruncate.off = off; + stub->fn.access = fn; + args_access_store(&stub->args, loc, mask, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_ftruncate_cbk_stub (call_frame_t *frame, - fop_ftruncate_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *prebuf, - struct iatt *postbuf) +fop_access_cbk_stub(call_frame_t *frame, fop_access_cbk_t fn, int32_t op_ret, + int32_t op_errno, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + stub = stub_new(frame, 0, GF_FOP_ACCESS); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 0, GF_FOP_FTRUNCATE); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); - - stub->args.ftruncate_cbk.fn = fn; - stub->args.ftruncate_cbk.op_ret = op_ret; - stub->args.ftruncate_cbk.op_errno = op_errno; - if (prebuf) - stub->args.ftruncate_cbk.prebuf = *prebuf; - if (postbuf) - stub->args.ftruncate_cbk.postbuf = *postbuf; + stub->fn_cbk.access = fn; + args_access_cbk_store(&stub->args_cbk, op_ret, op_errno, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_access_stub (call_frame_t *frame, - fop_access_t fn, - loc_t *loc, - int32_t mask) +fop_readlink_stub(call_frame_t *frame, fop_readlink_t fn, loc_t *loc, + size_t size, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", loc, out); + GF_VALIDATE_OR_GOTO("call-stub", loc, out); - stub = stub_new (frame, 1, GF_FOP_ACCESS); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_READLINK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.access.fn = fn; - loc_copy (&stub->args.access.loc, loc); - stub->args.access.mask = mask; + stub->fn.readlink = fn; + args_readlink_store(&stub->args, loc, size, xdata); out: - return stub; + return stub; } +call_stub_t * +fop_readlink_cbk_stub(call_frame_t *frame, fop_readlink_cbk_t fn, + int32_t op_ret, int32_t op_errno, const char *path, + struct iatt *stbuf, dict_t *xdata) +{ + call_stub_t *stub = NULL; + + stub = stub_new(frame, 0, GF_FOP_READLINK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + + stub->fn_cbk.readlink = fn; + args_readlink_cbk_store(&stub->args_cbk, op_ret, op_errno, path, stbuf, + xdata); +out: + return stub; +} call_stub_t * -fop_access_cbk_stub (call_frame_t *frame, - fop_access_cbk_t fn, - int32_t op_ret, - int32_t op_errno) +fop_mknod_stub(call_frame_t *frame, fop_mknod_t fn, loc_t *loc, mode_t mode, + dev_t rdev, mode_t umask, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + GF_VALIDATE_OR_GOTO("call-stub", loc, out); - stub = stub_new (frame, 0, GF_FOP_ACCESS); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_MKNOD); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.access_cbk.fn = fn; - stub->args.access_cbk.op_ret = op_ret; - stub->args.access_cbk.op_errno = op_errno; + stub->fn.mknod = fn; + args_mknod_store(&stub->args, loc, mode, rdev, umask, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_readlink_stub (call_frame_t *frame, - fop_readlink_t fn, - loc_t *loc, - size_t size) +fop_mknod_cbk_stub(call_frame_t *frame, fop_mknod_cbk_t fn, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + struct iatt *preparent, struct iatt *postparent, + dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", loc, out); - - stub = stub_new (frame, 1, GF_FOP_READLINK); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 0, GF_FOP_MKNOD); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.readlink.fn = fn; - loc_copy (&stub->args.readlink.loc, loc); - stub->args.readlink.size = size; + stub->fn_cbk.mknod = fn; + args_mknod_cbk_store(&stub->args_cbk, op_ret, op_errno, inode, buf, + preparent, postparent, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_readlink_cbk_stub (call_frame_t *frame, - fop_readlink_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - const char *path, - struct iatt *sbuf) +fop_mkdir_stub(call_frame_t *frame, fop_mkdir_t fn, loc_t *loc, mode_t mode, + mode_t umask, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + GF_VALIDATE_OR_GOTO("call-stub", loc, out); - stub = stub_new (frame, 0, GF_FOP_READLINK); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_MKDIR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.readlink_cbk.fn = fn; - stub->args.readlink_cbk.op_ret = op_ret; - stub->args.readlink_cbk.op_errno = op_errno; - if (path) - stub->args.readlink_cbk.buf = gf_strdup (path); - if (sbuf) - stub->args.readlink_cbk.sbuf = *sbuf; + stub->fn.mkdir = fn; + args_mkdir_store(&stub->args, loc, mode, umask, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_mknod_stub (call_frame_t *frame, fop_mknod_t fn, - loc_t *loc, mode_t mode, dev_t rdev, dict_t *params) +fop_mkdir_cbk_stub(call_frame_t *frame, fop_mkdir_cbk_t fn, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + struct iatt *preparent, struct iatt *postparent, + dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", loc, out); + stub = stub_new(frame, 0, GF_FOP_MKDIR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 1, GF_FOP_MKNOD); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); - - stub->args.mknod.fn = fn; - loc_copy (&stub->args.mknod.loc, loc); - stub->args.mknod.mode = mode; - stub->args.mknod.rdev = rdev; - if (params) - stub->args.mknod.params = dict_ref (params); + stub->fn_cbk.mkdir = fn; + args_mkdir_cbk_store(&stub->args_cbk, op_ret, op_errno, inode, buf, + preparent, postparent, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_mknod_cbk_stub (call_frame_t *frame, - fop_mknod_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent) +fop_unlink_stub(call_frame_t *frame, fop_unlink_t fn, loc_t *loc, int xflag, + dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; + + GF_VALIDATE_OR_GOTO("call-stub", loc, out); - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + stub = stub_new(frame, 1, GF_FOP_UNLINK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 0, GF_FOP_MKNOD); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub->fn.unlink = fn; + args_unlink_store(&stub->args, loc, xflag, xdata); - stub->args.mknod_cbk.fn = fn; - stub->args.mknod_cbk.op_ret = op_ret; - stub->args.mknod_cbk.op_errno = op_errno; - if (inode) - stub->args.mknod_cbk.inode = inode_ref (inode); - if (buf) - stub->args.mknod_cbk.buf = *buf; - if (preparent) - stub->args.mknod_cbk.preparent = *preparent; - if (postparent) - stub->args.mknod_cbk.postparent = *postparent; out: - return stub; + return stub; } - call_stub_t * -fop_mkdir_stub (call_frame_t *frame, fop_mkdir_t fn, - loc_t *loc, mode_t mode, dict_t *params) +fop_unlink_cbk_stub(call_frame_t *frame, fop_unlink_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) { - call_stub_t *stub = NULL; - - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", loc, out); + call_stub_t *stub = NULL; - stub = stub_new (frame, 1, GF_FOP_MKDIR); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 0, GF_FOP_UNLINK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.mkdir.fn = fn; - loc_copy (&stub->args.mkdir.loc, loc); - stub->args.mkdir.mode = mode; - if (params) - stub->args.mkdir.params = dict_ref (params); + stub->fn_cbk.unlink = fn; + args_unlink_cbk_store(&stub->args_cbk, op_ret, op_errno, preparent, + postparent, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_mkdir_cbk_stub (call_frame_t *frame, - fop_mkdir_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent) +fop_rmdir_stub(call_frame_t *frame, fop_rmdir_t fn, loc_t *loc, int flags, + dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; + + GF_VALIDATE_OR_GOTO("call-stub", loc, out); - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + stub = stub_new(frame, 1, GF_FOP_RMDIR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 0, GF_FOP_MKDIR); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub->fn.rmdir = fn; + args_rmdir_store(&stub->args, loc, flags, xdata); - stub->args.mkdir_cbk.fn = fn; - stub->args.mkdir_cbk.op_ret = op_ret; - stub->args.mkdir_cbk.op_errno = op_errno; - if (inode) - stub->args.mkdir_cbk.inode = inode_ref (inode); - if (buf) - stub->args.mkdir_cbk.buf = *buf; - if (preparent) - stub->args.mkdir_cbk.preparent = *preparent; - if (postparent) - stub->args.mkdir_cbk.postparent = *postparent; out: - return stub; + return stub; } - call_stub_t * -fop_unlink_stub (call_frame_t *frame, - fop_unlink_t fn, - loc_t *loc) +fop_rmdir_cbk_stub(call_frame_t *frame, fop_rmdir_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", loc, out); + stub = stub_new(frame, 0, GF_FOP_RMDIR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 1, GF_FOP_UNLINK); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); - - stub->args.unlink.fn = fn; - loc_copy (&stub->args.unlink.loc, loc); + stub->fn_cbk.rmdir = fn; + args_rmdir_cbk_store(&stub->args_cbk, op_ret, op_errno, preparent, + postparent, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_unlink_cbk_stub (call_frame_t *frame, - fop_unlink_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *preparent, - struct iatt *postparent) +fop_symlink_stub(call_frame_t *frame, fop_symlink_t fn, const char *linkname, + loc_t *loc, mode_t umask, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + GF_VALIDATE_OR_GOTO("call-stub", loc, out); + GF_VALIDATE_OR_GOTO("call-stub", linkname, out); - stub = stub_new (frame, 0, GF_FOP_UNLINK); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_SYMLINK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.unlink_cbk.fn = fn; - stub->args.unlink_cbk.op_ret = op_ret; - stub->args.unlink_cbk.op_errno = op_errno; - if (preparent) - stub->args.unlink_cbk.preparent = *preparent; - if (postparent) - stub->args.unlink_cbk.postparent = *postparent; + stub->fn.symlink = fn; + args_symlink_store(&stub->args, linkname, loc, umask, xdata); out: - return stub; + return stub; } +call_stub_t * +fop_symlink_cbk_stub(call_frame_t *frame, fop_symlink_cbk_t fn, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + struct iatt *preparent, struct iatt *postparent, + dict_t *xdata) +{ + call_stub_t *stub = NULL; + + stub = stub_new(frame, 0, GF_FOP_SYMLINK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + stub->fn_cbk.symlink = fn; + args_symlink_cbk_store(&stub->args_cbk, op_ret, op_errno, inode, buf, + preparent, postparent, xdata); +out: + return stub; +} call_stub_t * -fop_rmdir_stub (call_frame_t *frame, - fop_rmdir_t fn, - loc_t *loc) +fop_rename_stub(call_frame_t *frame, fop_rename_t fn, loc_t *oldloc, + loc_t *newloc, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", loc, out); + GF_VALIDATE_OR_GOTO("call-stub", oldloc, out); + GF_VALIDATE_OR_GOTO("call-stub", newloc, out); - stub = stub_new (frame, 1, GF_FOP_RMDIR); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_RENAME); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.rmdir.fn = fn; - loc_copy (&stub->args.rmdir.loc, loc); + stub->fn.rename = fn; + args_rename_store(&stub->args, oldloc, newloc, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_rmdir_cbk_stub (call_frame_t *frame, - fop_rmdir_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *preparent, - struct iatt *postparent) +fop_rename_cbk_stub(call_frame_t *frame, fop_rename_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct iatt *buf, + struct iatt *preoldparent, struct iatt *postoldparent, + struct iatt *prenewparent, struct iatt *postnewparent, + dict_t *xdata) { - call_stub_t *stub = NULL; - - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + call_stub_t *stub = NULL; - stub = stub_new (frame, 0, GF_FOP_RMDIR); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 0, GF_FOP_RENAME); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.rmdir_cbk.fn = fn; - stub->args.rmdir_cbk.op_ret = op_ret; - stub->args.rmdir_cbk.op_errno = op_errno; - if (preparent) - stub->args.rmdir_cbk.preparent = *preparent; - if (postparent) - stub->args.rmdir_cbk.postparent = *postparent; + stub->fn_cbk.rename = fn; + args_rename_cbk_store(&stub->args_cbk, op_ret, op_errno, buf, preoldparent, + postoldparent, prenewparent, postnewparent, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_symlink_stub (call_frame_t *frame, fop_symlink_t fn, - const char *linkname, loc_t *loc, dict_t *params) +fop_link_stub(call_frame_t *frame, fop_link_t fn, loc_t *oldloc, loc_t *newloc, + dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", loc, out); - GF_VALIDATE_OR_GOTO ("call-stub", linkname, out); + GF_VALIDATE_OR_GOTO("call-stub", oldloc, out); + GF_VALIDATE_OR_GOTO("call-stub", newloc, out); - stub = stub_new (frame, 1, GF_FOP_SYMLINK); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_LINK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.symlink.fn = fn; - stub->args.symlink.linkname = gf_strdup (linkname); - loc_copy (&stub->args.symlink.loc, loc); - if (params) - stub->args.symlink.params = dict_ref (params); + stub->fn.link = fn; + args_link_store(&stub->args, oldloc, newloc, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_symlink_cbk_stub (call_frame_t *frame, - fop_symlink_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent) +fop_link_cbk_stub(call_frame_t *frame, fop_link_cbk_t fn, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + struct iatt *preparent, struct iatt *postparent, + dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + stub = stub_new(frame, 0, GF_FOP_LINK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 0, GF_FOP_SYMLINK); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); - - stub->args.symlink_cbk.fn = fn; - stub->args.symlink_cbk.op_ret = op_ret; - stub->args.symlink_cbk.op_errno = op_errno; - if (inode) - stub->args.symlink_cbk.inode = inode_ref (inode); - if (buf) - stub->args.symlink_cbk.buf = *buf; - if (preparent) - stub->args.symlink_cbk.preparent = *preparent; - if (postparent) - stub->args.symlink_cbk.postparent = *postparent; + stub->fn_cbk.link = fn; + args_link_cbk_store(&stub->args_cbk, op_ret, op_errno, inode, buf, + preparent, postparent, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_rename_stub (call_frame_t *frame, - fop_rename_t fn, - loc_t *oldloc, - loc_t *newloc) +fop_create_stub(call_frame_t *frame, fop_create_t fn, loc_t *loc, int32_t flags, + mode_t mode, mode_t umask, fd_t *fd, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", oldloc, out); - GF_VALIDATE_OR_GOTO ("call-stub", newloc, out); + GF_VALIDATE_OR_GOTO("call-stub", loc, out); - stub = stub_new (frame, 1, GF_FOP_RENAME); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_CREATE); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.rename.fn = fn; - loc_copy (&stub->args.rename.old, oldloc); - loc_copy (&stub->args.rename.new, newloc); + stub->fn.create = fn; + args_create_store(&stub->args, loc, flags, mode, umask, fd, xdata); out: - return stub; + return stub; } +call_stub_t * +fop_create_cbk_stub(call_frame_t *frame, fop_create_cbk_t fn, int32_t op_ret, + int32_t op_errno, fd_t *fd, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + call_stub_t *stub = NULL; + + stub = stub_new(frame, 0, GF_FOP_CREATE); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + + stub->fn_cbk.create = fn; + args_create_cbk_store(&stub->args_cbk, op_ret, op_errno, fd, inode, buf, + preparent, postparent, xdata); +out: + return stub; +} call_stub_t * -fop_rename_cbk_stub (call_frame_t *frame, - fop_rename_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *buf, - struct iatt *preoldparent, - struct iatt *postoldparent, - struct iatt *prenewparent, - struct iatt *postnewparent) +fop_open_stub(call_frame_t *frame, fop_open_t fn, loc_t *loc, int32_t flags, + fd_t *fd, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + GF_VALIDATE_OR_GOTO("call-stub", loc, out); - stub = stub_new (frame, 0, GF_FOP_RENAME); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_OPEN); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.rename_cbk.fn = fn; - stub->args.rename_cbk.op_ret = op_ret; - stub->args.rename_cbk.op_errno = op_errno; - if (buf) - stub->args.rename_cbk.buf = *buf; - if (preoldparent) - stub->args.rename_cbk.preoldparent = *preoldparent; - if (postoldparent) - stub->args.rename_cbk.postoldparent = *postoldparent; - if (prenewparent) - stub->args.rename_cbk.prenewparent = *prenewparent; - if (postnewparent) - stub->args.rename_cbk.postnewparent = *postnewparent; + stub->fn.open = fn; + args_open_store(&stub->args, loc, flags, fd, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_link_stub (call_frame_t *frame, - fop_link_t fn, - loc_t *oldloc, - loc_t *newloc) +fop_open_cbk_stub(call_frame_t *frame, fop_open_cbk_t fn, int32_t op_ret, + int32_t op_errno, fd_t *fd, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", oldloc, out); - GF_VALIDATE_OR_GOTO ("call-stub", newloc, out); + stub = stub_new(frame, 0, GF_FOP_OPEN); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 1, GF_FOP_LINK); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub->fn_cbk.open = fn; + args_open_cbk_store(&stub->args_cbk, op_ret, op_errno, fd, xdata); +out: + return stub; +} - stub->args.link.fn = fn; - loc_copy (&stub->args.link.oldloc, oldloc); - loc_copy (&stub->args.link.newloc, newloc); +call_stub_t * +fop_readv_stub(call_frame_t *frame, fop_readv_t fn, fd_t *fd, size_t size, + off_t off, uint32_t flags, dict_t *xdata) +{ + call_stub_t *stub = NULL; + stub = stub_new(frame, 1, GF_FOP_READ); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + + stub->fn.readv = fn; + args_readv_store(&stub->args, fd, size, off, flags, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_link_cbk_stub (call_frame_t *frame, - fop_link_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent) +fop_readv_cbk_stub(call_frame_t *frame, fop_readv_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct iovec *vector, int32_t count, + struct iatt *stbuf, struct iobref *iobref, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + stub = stub_new(frame, 0, GF_FOP_READ); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 0, GF_FOP_LINK); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); - - stub->args.link_cbk.fn = fn; - stub->args.link_cbk.op_ret = op_ret; - stub->args.link_cbk.op_errno = op_errno; - if (inode) - stub->args.link_cbk.inode = inode_ref (inode); - if (buf) - stub->args.link_cbk.buf = *buf; - if (preparent) - stub->args.link_cbk.preparent = *preparent; - if (postparent) - stub->args.link_cbk.postparent = *postparent; + stub->fn_cbk.readv = fn; + args_readv_cbk_store(&stub->args_cbk, op_ret, op_errno, vector, count, + stbuf, iobref, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_create_stub (call_frame_t *frame, fop_create_t fn, - loc_t *loc, int32_t flags, mode_t mode, - fd_t *fd, dict_t *params) +fop_writev_stub(call_frame_t *frame, fop_writev_t fn, fd_t *fd, + struct iovec *vector, int32_t count, off_t off, uint32_t flags, + struct iobref *iobref, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", loc, out); + GF_VALIDATE_OR_GOTO("call-stub", vector, out); - stub = stub_new (frame, 1, GF_FOP_CREATE); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_WRITE); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.create.fn = fn; - loc_copy (&stub->args.create.loc, loc); - stub->args.create.flags = flags; - stub->args.create.mode = mode; - if (fd) - stub->args.create.fd = fd_ref (fd); - if (params) - stub->args.create.params = dict_ref (params); + stub->fn.writev = fn; + args_writev_store(&stub->args, fd, vector, count, off, flags, iobref, + xdata); out: - return stub; + return stub; } - call_stub_t * -fop_create_cbk_stub (call_frame_t *frame, - fop_create_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - fd_t *fd, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent) +fop_writev_cbk_stub(call_frame_t *frame, fop_writev_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct iatt *prebuf, struct iatt *postbuf, + dict_t *xdata) { - call_stub_t *stub = NULL; - - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + call_stub_t *stub = NULL; - stub = stub_new (frame, 0, GF_FOP_CREATE); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 0, GF_FOP_WRITE); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.create_cbk.fn = fn; - stub->args.create_cbk.op_ret = op_ret; - stub->args.create_cbk.op_errno = op_errno; - if (fd) - stub->args.create_cbk.fd = fd_ref (fd); - if (inode) - stub->args.create_cbk.inode = inode_ref (inode); - if (buf) - stub->args.create_cbk.buf = *buf; - if (preparent) - stub->args.create_cbk.preparent = *preparent; - if (postparent) - stub->args.create_cbk.postparent = *postparent; + stub->fn_cbk.writev = fn; + args_writev_cbk_store(&stub->args_cbk, op_ret, op_errno, prebuf, postbuf, + xdata); out: - return stub; + return stub; } - call_stub_t * -fop_open_stub (call_frame_t *frame, - fop_open_t fn, - loc_t *loc, - int32_t flags, fd_t *fd, - int32_t wbflags) +fop_flush_stub(call_frame_t *frame, fop_flush_t fn, fd_t *fd, dict_t *xdata) { - call_stub_t *stub = NULL; - - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", loc, out); + call_stub_t *stub = NULL; - stub = stub_new (frame, 1, GF_FOP_OPEN); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_FLUSH); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.open.fn = fn; - loc_copy (&stub->args.open.loc, loc); - stub->args.open.flags = flags; - stub->args.open.wbflags = wbflags; - if (fd) - stub->args.open.fd = fd_ref (fd); + stub->fn.flush = fn; + args_flush_store(&stub->args, fd, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_open_cbk_stub (call_frame_t *frame, - fop_open_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - fd_t *fd) - +fop_flush_cbk_stub(call_frame_t *frame, fop_flush_cbk_t fn, int32_t op_ret, + int32_t op_errno, dict_t *xdata) { - call_stub_t *stub = NULL; - - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + call_stub_t *stub = NULL; - stub = stub_new (frame, 0, GF_FOP_OPEN); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 0, GF_FOP_FLUSH); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.open_cbk.fn = fn; - stub->args.open_cbk.op_ret = op_ret; - stub->args.open_cbk.op_errno = op_errno; - if (fd) - stub->args.open_cbk.fd = fd_ref (fd); + stub->fn_cbk.flush = fn; + args_flush_cbk_store(&stub->args_cbk, op_ret, op_errno, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_readv_stub (call_frame_t *frame, - fop_readv_t fn, - fd_t *fd, - size_t size, - off_t off) +fop_fsync_stub(call_frame_t *frame, fop_fsync_t fn, fd_t *fd, int32_t datasync, + dict_t *xdata) { - call_stub_t *stub = NULL; - - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + call_stub_t *stub = NULL; - stub = stub_new (frame, 1, GF_FOP_READ); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_FSYNC); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.readv.fn = fn; - if (fd) - stub->args.readv.fd = fd_ref (fd); - stub->args.readv.size = size; - stub->args.readv.off = off; + stub->fn.fsync = fn; + args_fsync_store(&stub->args, fd, datasync, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_readv_cbk_stub (call_frame_t *frame, - fop_readv_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iovec *vector, - int32_t count, - struct iatt *stbuf, - struct iobref *iobref) - +fop_fsync_cbk_stub(call_frame_t *frame, fop_fsync_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct iatt *prebuf, struct iatt *postbuf, + dict_t *xdata) { - call_stub_t *stub = NULL; - - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + call_stub_t *stub = NULL; - stub = stub_new (frame, 0, GF_FOP_READ); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 0, GF_FOP_FSYNC); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.readv_cbk.fn = fn; - stub->args.readv_cbk.op_ret = op_ret; - stub->args.readv_cbk.op_errno = op_errno; - if (op_ret >= 0) { - stub->args.readv_cbk.vector = iov_dup (vector, count); - stub->args.readv_cbk.count = count; - stub->args.readv_cbk.stbuf = *stbuf; - stub->args.readv_cbk.iobref = iobref_ref (iobref); - } + stub->fn_cbk.fsync = fn; + args_fsync_cbk_store(&stub->args_cbk, op_ret, op_errno, prebuf, postbuf, + xdata); out: - return stub; + return stub; } - call_stub_t * -fop_writev_stub (call_frame_t *frame, - fop_writev_t fn, - fd_t *fd, - struct iovec *vector, - int32_t count, - off_t off, - struct iobref *iobref) +fop_opendir_stub(call_frame_t *frame, fop_opendir_t fn, loc_t *loc, fd_t *fd, + dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", vector, out); + GF_VALIDATE_OR_GOTO("call-stub", loc, out); - stub = stub_new (frame, 1, GF_FOP_WRITE); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_OPENDIR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.writev.fn = fn; - if (fd) - stub->args.writev.fd = fd_ref (fd); - stub->args.writev.vector = iov_dup (vector, count); - stub->args.writev.count = count; - stub->args.writev.off = off; - stub->args.writev.iobref = iobref_ref (iobref); + stub->fn.opendir = fn; + args_opendir_store(&stub->args, loc, fd, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_writev_cbk_stub (call_frame_t *frame, - fop_writev_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *prebuf, - struct iatt *postbuf) - +fop_opendir_cbk_stub(call_frame_t *frame, fop_opendir_cbk_t fn, int32_t op_ret, + int32_t op_errno, fd_t *fd, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + stub = stub_new(frame, 0, GF_FOP_OPENDIR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 0, GF_FOP_WRITE); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); - - stub->args.writev_cbk.fn = fn; - stub->args.writev_cbk.op_ret = op_ret; - stub->args.writev_cbk.op_errno = op_errno; - if (op_ret >= 0) - stub->args.writev_cbk.postbuf = *postbuf; - if (prebuf) - stub->args.writev_cbk.prebuf = *prebuf; + stub->fn_cbk.opendir = fn; + args_opendir_cbk_store(&stub->args_cbk, op_ret, op_errno, fd, xdata); out: - return stub; + return stub; } +call_stub_t * +fop_fsyncdir_stub(call_frame_t *frame, fop_fsyncdir_t fn, fd_t *fd, + int32_t datasync, dict_t *xdata) +{ + call_stub_t *stub = NULL; + + stub = stub_new(frame, 1, GF_FOP_FSYNCDIR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + stub->fn.fsyncdir = fn; + args_fsyncdir_store(&stub->args, fd, datasync, xdata); +out: + return stub; +} call_stub_t * -fop_flush_stub (call_frame_t *frame, - fop_flush_t fn, - fd_t *fd) +fop_fsyncdir_cbk_stub(call_frame_t *frame, fop_fsyncdir_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + stub = stub_new(frame, 0, GF_FOP_FSYNCDIR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 1, GF_FOP_FLUSH); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); - - stub->args.flush.fn = fn; - if (fd) - stub->args.flush.fd = fd_ref (fd); + stub->fn_cbk.fsyncdir = fn; + args_fsyncdir_cbk_store(&stub->args_cbk, op_ret, op_errno, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_flush_cbk_stub (call_frame_t *frame, - fop_flush_cbk_t fn, - int32_t op_ret, - int32_t op_errno) - +fop_statfs_stub(call_frame_t *frame, fop_statfs_t fn, loc_t *loc, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + GF_VALIDATE_OR_GOTO("call-stub", loc, out); - stub = stub_new (frame, 0, GF_FOP_FLUSH); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_STATFS); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.flush_cbk.fn = fn; - stub->args.flush_cbk.op_ret = op_ret; - stub->args.flush_cbk.op_errno = op_errno; + stub->fn.statfs = fn; + args_statfs_store(&stub->args, loc, xdata); out: - return stub; + return stub; } +call_stub_t * +fop_statfs_cbk_stub(call_frame_t *frame, fop_statfs_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct statvfs *buf, dict_t *xdata) +{ + call_stub_t *stub = NULL; + stub = stub_new(frame, 0, GF_FOP_STATFS); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + stub->fn_cbk.statfs = fn; + args_statfs_cbk_store(&stub->args_cbk, op_ret, op_errno, buf, xdata); +out: + return stub; +} call_stub_t * -fop_fsync_stub (call_frame_t *frame, - fop_fsync_t fn, - fd_t *fd, - int32_t datasync) +fop_setxattr_stub(call_frame_t *frame, fop_setxattr_t fn, loc_t *loc, + dict_t *dict, int32_t flags, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + GF_VALIDATE_OR_GOTO("call-stub", loc, out); - stub = stub_new (frame, 1, GF_FOP_FSYNC); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_SETXATTR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.fsync.fn = fn; - if (fd) - stub->args.fsync.fd = fd_ref (fd); - stub->args.fsync.datasync = datasync; + stub->fn.setxattr = fn; + args_setxattr_store(&stub->args, loc, dict, flags, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_fsync_cbk_stub (call_frame_t *frame, - fop_fsync_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *prebuf, - struct iatt *postbuf) +fop_setxattr_cbk_stub(call_frame_t *frame, fop_setxattr_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + stub = stub_new(frame, 0, GF_FOP_SETXATTR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 0, GF_FOP_FSYNC); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); - - stub->args.fsync_cbk.fn = fn; - stub->args.fsync_cbk.op_ret = op_ret; - stub->args.fsync_cbk.op_errno = op_errno; - if (prebuf) - stub->args.fsync_cbk.prebuf = *prebuf; - if (postbuf) - stub->args.fsync_cbk.postbuf = *postbuf; + stub->fn_cbk.setxattr = fn; + args_setxattr_cbk_store(&stub->args_cbk, op_ret, op_errno, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_opendir_stub (call_frame_t *frame, - fop_opendir_t fn, - loc_t *loc, fd_t *fd) +fop_getxattr_stub(call_frame_t *frame, fop_getxattr_t fn, loc_t *loc, + const char *name, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", loc, out); + GF_VALIDATE_OR_GOTO("call-stub", loc, out); - stub = stub_new (frame, 1, GF_FOP_OPENDIR); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_GETXATTR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.opendir.fn = fn; - loc_copy (&stub->args.opendir.loc, loc); - if (fd) - stub->args.opendir.fd = fd_ref (fd); + stub->fn.getxattr = fn; + args_getxattr_store(&stub->args, loc, name, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_opendir_cbk_stub (call_frame_t *frame, - fop_opendir_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - fd_t *fd) - +fop_getxattr_cbk_stub(call_frame_t *frame, fop_getxattr_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata) { - call_stub_t *stub = NULL; - - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + call_stub_t *stub = NULL; - stub = stub_new (frame, 0, GF_FOP_OPENDIR); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 0, GF_FOP_GETXATTR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.opendir_cbk.fn = fn; - stub->args.opendir_cbk.op_ret = op_ret; - stub->args.opendir_cbk.op_errno = op_errno; - - if (fd) - stub->args.opendir_cbk.fd = fd_ref (fd); + stub->fn_cbk.getxattr = fn; + args_getxattr_cbk_store(&stub->args_cbk, op_ret, op_errno, dict, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_fsyncdir_stub (call_frame_t *frame, - fop_fsyncdir_t fn, - fd_t *fd, - int32_t datasync) +fop_fsetxattr_stub(call_frame_t *frame, fop_fsetxattr_t fn, fd_t *fd, + dict_t *dict, int32_t flags, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + GF_VALIDATE_OR_GOTO("call-stub", fd, out); - stub = stub_new (frame, 1, GF_FOP_FSYNCDIR); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_FSETXATTR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.fsyncdir.fn = fn; - if (fd) - stub->args.fsyncdir.fd = fd_ref (fd); - stub->args.fsyncdir.datasync = datasync; + stub->fn.fsetxattr = fn; + args_fsetxattr_store(&stub->args, fd, dict, flags, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_fsyncdir_cbk_stub (call_frame_t *frame, - fop_fsyncdir_cbk_t fn, - int32_t op_ret, - int32_t op_errno) - +fop_fsetxattr_cbk_stub(call_frame_t *frame, fop_fsetxattr_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + stub = stub_new(frame, 0, GF_FOP_FSETXATTR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 0, GF_FOP_FSYNCDIR); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); - - stub->args.fsyncdir_cbk.fn = fn; - stub->args.fsyncdir_cbk.op_ret = op_ret; - stub->args.fsyncdir_cbk.op_errno = op_errno; + stub->fn_cbk.fsetxattr = fn; + args_fsetxattr_cbk_store(&stub->args_cbk, op_ret, op_errno, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_statfs_stub (call_frame_t *frame, - fop_statfs_t fn, - loc_t *loc) +fop_fgetxattr_stub(call_frame_t *frame, fop_fgetxattr_t fn, fd_t *fd, + const char *name, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", loc, out); + GF_VALIDATE_OR_GOTO("call-stub", fd, out); - stub = stub_new (frame, 1, GF_FOP_STATFS); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_FGETXATTR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.statfs.fn = fn; - loc_copy (&stub->args.statfs.loc, loc); + stub->fn.fgetxattr = fn; + args_fgetxattr_store(&stub->args, fd, name, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_statfs_cbk_stub (call_frame_t *frame, - fop_statfs_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct statvfs *buf) - +fop_fgetxattr_cbk_stub(call_frame_t *frame, fop_fgetxattr_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata) { - call_stub_t *stub = NULL; - - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + call_stub_t *stub = NULL; - stub = stub_new (frame, 0, GF_FOP_STATFS); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 0, GF_FOP_GETXATTR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.statfs_cbk.fn = fn; - stub->args.statfs_cbk.op_ret = op_ret; - stub->args.statfs_cbk.op_errno = op_errno; - if (op_ret == 0) - stub->args.statfs_cbk.buf = *buf; + stub->fn_cbk.fgetxattr = fn; + args_fgetxattr_cbk_store(&stub->args_cbk, op_ret, op_errno, dict, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_setxattr_stub (call_frame_t *frame, - fop_setxattr_t fn, - loc_t *loc, - dict_t *dict, - int32_t flags) +fop_removexattr_stub(call_frame_t *frame, fop_removexattr_t fn, loc_t *loc, + const char *name, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", loc, out); + GF_VALIDATE_OR_GOTO("call-stub", loc, out); + GF_VALIDATE_OR_GOTO("call-stub", name, out); - stub = stub_new (frame, 1, GF_FOP_SETXATTR); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_REMOVEXATTR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.setxattr.fn = fn; - loc_copy (&stub->args.setxattr.loc, loc); - /* TODO */ - if (dict) - stub->args.setxattr.dict = dict_ref (dict); - stub->args.setxattr.flags = flags; + stub->fn.removexattr = fn; + args_removexattr_store(&stub->args, loc, name, xdata); out: - return stub; + return stub; } +call_stub_t * +fop_removexattr_cbk_stub(call_frame_t *frame, fop_removexattr_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + call_stub_t *stub = NULL; + + stub = stub_new(frame, 0, GF_FOP_REMOVEXATTR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + + stub->fn_cbk.removexattr = fn; + args_removexattr_cbk_store(&stub->args_cbk, op_ret, op_errno, xdata); +out: + return stub; +} call_stub_t * -fop_setxattr_cbk_stub (call_frame_t *frame, - fop_setxattr_cbk_t fn, - int32_t op_ret, - int32_t op_errno) +fop_fremovexattr_stub(call_frame_t *frame, fop_fremovexattr_t fn, fd_t *fd, + const char *name, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + GF_VALIDATE_OR_GOTO("call-stub", fd, out); + GF_VALIDATE_OR_GOTO("call-stub", name, out); - stub = stub_new (frame, 0, GF_FOP_SETXATTR); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_FREMOVEXATTR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.setxattr_cbk.fn = fn; - stub->args.setxattr_cbk.op_ret = op_ret; - stub->args.setxattr_cbk.op_errno = op_errno; + stub->fn.fremovexattr = fn; + args_fremovexattr_store(&stub->args, fd, name, xdata); out: - return stub; + return stub; } call_stub_t * -fop_getxattr_stub (call_frame_t *frame, - fop_getxattr_t fn, - loc_t *loc, - const char *name) +fop_fremovexattr_cbk_stub(call_frame_t *frame, fop_fremovexattr_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", loc, out); + stub = stub_new(frame, 0, GF_FOP_FREMOVEXATTR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 1, GF_FOP_GETXATTR); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub->fn_cbk.fremovexattr = fn; + args_fremovexattr_cbk_store(&stub->args_cbk, op_ret, op_errno, xdata); +out: + return stub; +} + +call_stub_t * +fop_lk_stub(call_frame_t *frame, fop_lk_t fn, fd_t *fd, int32_t cmd, + struct gf_flock *lock, dict_t *xdata) +{ + call_stub_t *stub = NULL; - stub->args.getxattr.fn = fn; - loc_copy (&stub->args.getxattr.loc, loc); + GF_VALIDATE_OR_GOTO("call-stub", lock, out); - if (name) - stub->args.getxattr.name = gf_strdup (name); + stub = stub_new(frame, 1, GF_FOP_LK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + + stub->fn.lk = fn; + args_lk_store(&stub->args, fd, cmd, lock, xdata); out: - return stub; + return stub; } +call_stub_t * +fop_lk_cbk_stub(call_frame_t *frame, fop_lk_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct gf_flock *lock, dict_t *xdata) +{ + call_stub_t *stub = NULL; + + stub = stub_new(frame, 0, GF_FOP_LK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + + stub->fn_cbk.lk = fn; + args_lk_cbk_store(&stub->args_cbk, op_ret, op_errno, lock, xdata); +out: + return stub; +} call_stub_t * -fop_getxattr_cbk_stub (call_frame_t *frame, - fop_getxattr_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - dict_t *dict) +fop_inodelk_stub(call_frame_t *frame, fop_inodelk_t fn, const char *volume, + loc_t *loc, int32_t cmd, struct gf_flock *lock, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + GF_VALIDATE_OR_GOTO("call-stub", lock, out); - stub = stub_new (frame, 0, GF_FOP_GETXATTR); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_INODELK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.getxattr_cbk.fn = fn; - stub->args.getxattr_cbk.op_ret = op_ret; - stub->args.getxattr_cbk.op_errno = op_errno; - /* TODO */ - if (dict) - stub->args.getxattr_cbk.dict = dict_ref (dict); + stub->fn.inodelk = fn; + args_inodelk_store(&stub->args, volume, loc, cmd, lock, xdata); out: - return stub; + return stub; } +call_stub_t * +fop_inodelk_cbk_stub(call_frame_t *frame, fop_inodelk_cbk_t fn, int32_t op_ret, + int32_t op_errno, dict_t *xdata) +{ + call_stub_t *stub = NULL; + + stub = stub_new(frame, 0, GF_FOP_INODELK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + + stub->fn_cbk.inodelk = fn; + args_inodelk_cbk_store(&stub->args_cbk, op_ret, op_errno, xdata); +out: + return stub; +} call_stub_t * -fop_fsetxattr_stub (call_frame_t *frame, - fop_fsetxattr_t fn, - fd_t *fd, - dict_t *dict, - int32_t flags) +fop_finodelk_stub(call_frame_t *frame, fop_finodelk_t fn, const char *volume, + fd_t *fd, int32_t cmd, struct gf_flock *lock, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", fd, out); + GF_VALIDATE_OR_GOTO("call-stub", lock, out); - stub = stub_new (frame, 1, GF_FOP_FSETXATTR); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_FINODELK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.fsetxattr.fn = fn; - stub->args.fsetxattr.fd = fd_ref (fd); + stub->fn.finodelk = fn; + args_finodelk_store(&stub->args, volume, fd, cmd, lock, xdata); - /* TODO */ - if (dict) - stub->args.fsetxattr.dict = dict_ref (dict); - stub->args.fsetxattr.flags = flags; out: - return stub; + return stub; } - call_stub_t * -fop_fsetxattr_cbk_stub (call_frame_t *frame, - fop_fsetxattr_cbk_t fn, - int32_t op_ret, - int32_t op_errno) +fop_finodelk_cbk_stub(call_frame_t *frame, fop_inodelk_cbk_t fn, int32_t op_ret, + int32_t op_errno, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + stub = stub_new(frame, 0, GF_FOP_FINODELK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 0, GF_FOP_FSETXATTR); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); - - stub->args.fsetxattr_cbk.fn = fn; - stub->args.fsetxattr_cbk.op_ret = op_ret; - stub->args.fsetxattr_cbk.op_errno = op_errno; + stub->fn_cbk.finodelk = fn; + args_finodelk_cbk_store(&stub->args_cbk, op_ret, op_errno, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_fgetxattr_stub (call_frame_t *frame, - fop_fgetxattr_t fn, - fd_t *fd, - const char *name) +fop_entrylk_stub(call_frame_t *frame, fop_entrylk_t fn, const char *volume, + loc_t *loc, const char *name, entrylk_cmd cmd, + entrylk_type type, dict_t *xdata) { - call_stub_t *stub = NULL; - - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", fd, out); + call_stub_t *stub = NULL; - stub = stub_new (frame, 1, GF_FOP_FGETXATTR); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_ENTRYLK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.fgetxattr.fn = fn; - stub->args.fgetxattr.fd = fd_ref (fd); + stub->fn.entrylk = fn; + args_entrylk_store(&stub->args, volume, loc, name, cmd, type, xdata); - if (name) - stub->args.fgetxattr.name = gf_strdup (name); out: - return stub; + return stub; } - call_stub_t * -fop_fgetxattr_cbk_stub (call_frame_t *frame, - fop_fgetxattr_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - dict_t *dict) +fop_entrylk_cbk_stub(call_frame_t *frame, fop_entrylk_cbk_t fn, int32_t op_ret, + int32_t op_errno, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + stub = stub_new(frame, 0, GF_FOP_ENTRYLK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 0, GF_FOP_GETXATTR); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub->fn_cbk.entrylk = fn; + args_entrylk_cbk_store(&stub->args_cbk, op_ret, op_errno, xdata); +out: + return stub; +} + +call_stub_t * +fop_fentrylk_stub(call_frame_t *frame, fop_fentrylk_t fn, const char *volume, + fd_t *fd, const char *name, entrylk_cmd cmd, + entrylk_type type, dict_t *xdata) +{ + call_stub_t *stub = NULL; - stub->args.fgetxattr_cbk.fn = fn; - stub->args.fgetxattr_cbk.op_ret = op_ret; - stub->args.fgetxattr_cbk.op_errno = op_errno; + stub = stub_new(frame, 1, GF_FOP_FENTRYLK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - /* TODO */ - if (dict) - stub->args.fgetxattr_cbk.dict = dict_ref (dict); + stub->fn.fentrylk = fn; + args_fentrylk_store(&stub->args, volume, fd, name, cmd, type, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_removexattr_stub (call_frame_t *frame, - fop_removexattr_t fn, - loc_t *loc, - const char *name) +fop_fentrylk_cbk_stub(call_frame_t *frame, fop_fentrylk_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *xdata) { - call_stub_t *stub = NULL; - - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", loc, out); - GF_VALIDATE_OR_GOTO ("call-stub", name, out); + call_stub_t *stub = NULL; - stub = stub_new (frame, 1, GF_FOP_REMOVEXATTR); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 0, GF_FOP_FENTRYLK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.removexattr.fn = fn; - loc_copy (&stub->args.removexattr.loc, loc); - stub->args.removexattr.name = gf_strdup (name); + stub->fn_cbk.fentrylk = fn; + args_fentrylk_cbk_store(&stub->args_cbk, op_ret, op_errno, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_removexattr_cbk_stub (call_frame_t *frame, - fop_removexattr_cbk_t fn, - int32_t op_ret, - int32_t op_errno) +fop_readdirp_cbk_stub(call_frame_t *frame, fop_readdirp_cbk_t fn, + int32_t op_ret, int32_t op_errno, gf_dirent_t *entries, + dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + stub = stub_new(frame, 0, GF_FOP_READDIRP); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 0, GF_FOP_REMOVEXATTR); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); - - stub->args.removexattr_cbk.fn = fn; - stub->args.removexattr_cbk.op_ret = op_ret; - stub->args.removexattr_cbk.op_errno = op_errno; + stub->fn_cbk.readdirp = fn; + args_readdirp_cbk_store(&stub->args_cbk, op_ret, op_errno, entries, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_lk_stub (call_frame_t *frame, - fop_lk_t fn, - fd_t *fd, - int32_t cmd, - struct flock *lock) +fop_readdir_cbk_stub(call_frame_t *frame, fop_readdir_cbk_t fn, int32_t op_ret, + int32_t op_errno, gf_dirent_t *entries, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", lock, out); - - stub = stub_new (frame, 1, GF_FOP_LK); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 0, GF_FOP_READDIR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.lk.fn = fn; - if (fd) - stub->args.lk.fd = fd_ref (fd); - stub->args.lk.cmd = cmd; - stub->args.lk.lock = *lock; + stub->fn_cbk.readdir = fn; + args_readdir_cbk_store(&stub->args_cbk, op_ret, op_errno, entries, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_lk_cbk_stub (call_frame_t *frame, - fop_lk_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct flock *lock) - +fop_readdir_stub(call_frame_t *frame, fop_readdir_t fn, fd_t *fd, size_t size, + off_t off, dict_t *xdata) { - call_stub_t *stub = NULL; - - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + call_stub_t *stub = NULL; - stub = stub_new (frame, 0, GF_FOP_LK); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_READDIR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.lk_cbk.fn = fn; - stub->args.lk_cbk.op_ret = op_ret; - stub->args.lk_cbk.op_errno = op_errno; - if (op_ret == 0) - stub->args.lk_cbk.lock = *lock; + stub->fn.readdir = fn; + args_readdir_store(&stub->args, fd, size, off, xdata); out: - return stub; + return stub; } call_stub_t * -fop_inodelk_stub (call_frame_t *frame, fop_inodelk_t fn, - const char *volume, loc_t *loc, int32_t cmd, struct flock *lock) +fop_readdirp_stub(call_frame_t *frame, fop_readdirp_t fn, fd_t *fd, size_t size, + off_t off, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - if (!frame || !lock) - return NULL; + stub = stub_new(frame, 1, GF_FOP_READDIRP); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 1, GF_FOP_INODELK); - if (!stub) - return NULL; + stub->fn.readdirp = fn; + args_readdirp_store(&stub->args, fd, size, off, xdata); +out: + return stub; +} - stub->args.inodelk.fn = fn; +call_stub_t * +fop_rchecksum_stub(call_frame_t *frame, fop_rchecksum_t fn, fd_t *fd, + off_t offset, int32_t len, dict_t *xdata) +{ + call_stub_t *stub = NULL; - if (volume) - stub->args.inodelk.volume = gf_strdup (volume); + GF_VALIDATE_OR_GOTO("call-stub", fd, out); - loc_copy (&stub->args.inodelk.loc, loc); - stub->args.inodelk.cmd = cmd; - stub->args.inodelk.lock = *lock; + stub = stub_new(frame, 1, GF_FOP_RCHECKSUM); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - return stub; + stub->fn.rchecksum = fn; + args_rchecksum_store(&stub->args, fd, offset, len, xdata); +out: + return stub; } call_stub_t * -fop_inodelk_cbk_stub (call_frame_t *frame, fop_inodelk_cbk_t fn, - int32_t op_ret, int32_t op_errno) +fop_rchecksum_cbk_stub(call_frame_t *frame, fop_rchecksum_cbk_t fn, + int32_t op_ret, int32_t op_errno, uint32_t weak_checksum, + uint8_t *strong_checksum, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - if (!frame) - return NULL; + stub = stub_new(frame, 0, GF_FOP_RCHECKSUM); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + + stub->fn_cbk.rchecksum = fn; + args_rchecksum_cbk_store(&stub->args_cbk, op_ret, op_errno, weak_checksum, + strong_checksum, xdata); +out: + return stub; +} - stub = stub_new (frame, 0, GF_FOP_INODELK); - if (!stub) - return NULL; +call_stub_t * +fop_xattrop_cbk_stub(call_frame_t *frame, fop_xattrop_cbk_t fn, int32_t op_ret, + int32_t op_errno, dict_t *xattr, dict_t *xdata) +{ + call_stub_t *stub = NULL; - stub->args.inodelk_cbk.fn = fn; - stub->args.inodelk_cbk.op_ret = op_ret; - stub->args.inodelk_cbk.op_errno = op_errno; + stub = stub_new(frame, 0, GF_FOP_XATTROP); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - return stub; + stub->fn_cbk.xattrop = fn; + args_xattrop_cbk_store(&stub->args_cbk, op_ret, op_errno, xattr, xdata); +out: + return stub; } +call_stub_t * +fop_fxattrop_cbk_stub(call_frame_t *frame, fop_fxattrop_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *xattr, + dict_t *xdata) +{ + call_stub_t *stub = NULL; + + stub = stub_new(frame, 0, GF_FOP_FXATTROP); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + + stub->fn_cbk.fxattrop = fn; + args_xattrop_cbk_store(&stub->args_cbk, op_ret, op_errno, xattr, xdata); +out: + return stub; +} call_stub_t * -fop_finodelk_stub (call_frame_t *frame, fop_finodelk_t fn, - const char *volume, fd_t *fd, int32_t cmd, struct flock *lock) +fop_xattrop_stub(call_frame_t *frame, fop_xattrop_t fn, loc_t *loc, + gf_xattrop_flags_t optype, dict_t *xattr, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - if (!frame || !lock) - return NULL; + GF_VALIDATE_OR_GOTO("call-stub", xattr, out); - stub = stub_new (frame, 1, GF_FOP_FINODELK); - if (!stub) - return NULL; + stub = stub_new(frame, 1, GF_FOP_XATTROP); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.finodelk.fn = fn; + stub->fn.xattrop = fn; + args_xattrop_store(&stub->args, loc, optype, xattr, xdata); +out: + return stub; +} - if (fd) - stub->args.finodelk.fd = fd_ref (fd); +call_stub_t * +fop_fxattrop_stub(call_frame_t *frame, fop_fxattrop_t fn, fd_t *fd, + gf_xattrop_flags_t optype, dict_t *xattr, dict_t *xdata) +{ + call_stub_t *stub = NULL; - if (volume) - stub->args.finodelk.volume = gf_strdup (volume); + GF_VALIDATE_OR_GOTO("call-stub", xattr, out); - stub->args.finodelk.cmd = cmd; - stub->args.finodelk.lock = *lock; + stub = stub_new(frame, 1, GF_FOP_FXATTROP); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - return stub; + stub->fn.fxattrop = fn; + args_fxattrop_store(&stub->args, fd, optype, xattr, xdata); +out: + return stub; } - call_stub_t * -fop_finodelk_cbk_stub (call_frame_t *frame, fop_inodelk_cbk_t fn, - int32_t op_ret, int32_t op_errno) +fop_setattr_cbk_stub(call_frame_t *frame, fop_setattr_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; + call_stub_t *stub = NULL; - if (!frame) - return NULL; + stub = stub_new(frame, 0, GF_FOP_SETATTR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 0, GF_FOP_FINODELK); - if (!stub) - return NULL; + stub->fn_cbk.setattr = fn; + args_setattr_cbk_store(&stub->args_cbk, op_ret, op_errno, statpre, statpost, + xdata); +out: + return stub; +} - stub->args.finodelk_cbk.fn = fn; - stub->args.finodelk_cbk.op_ret = op_ret; - stub->args.finodelk_cbk.op_errno = op_errno; +call_stub_t * +fop_fsetattr_cbk_stub(call_frame_t *frame, fop_setattr_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; - return stub; -} + stub = stub_new(frame, 0, GF_FOP_FSETATTR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + stub->fn_cbk.fsetattr = fn; + args_fsetattr_cbk_store(&stub->args_cbk, op_ret, op_errno, statpre, + statpost, xdata); +out: + return stub; +} call_stub_t * -fop_entrylk_stub (call_frame_t *frame, fop_entrylk_t fn, - const char *volume, loc_t *loc, const char *name, - entrylk_cmd cmd, entrylk_type type) +fop_setattr_stub(call_frame_t *frame, fop_setattr_t fn, loc_t *loc, + struct iatt *stbuf, int32_t valid, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - if (!frame) - return NULL; + GF_VALIDATE_OR_GOTO("call-stub", fn, out); - stub = stub_new (frame, 1, GF_FOP_ENTRYLK); - if (!stub) - return NULL; + stub = stub_new(frame, 1, GF_FOP_SETATTR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.entrylk.fn = fn; + stub->fn.setattr = fn; + args_setattr_store(&stub->args, loc, stbuf, valid, xdata); +out: + return stub; +} - if (volume) - stub->args.entrylk.volume = gf_strdup (volume); +call_stub_t * +fop_fsetattr_stub(call_frame_t *frame, fop_fsetattr_t fn, fd_t *fd, + struct iatt *stbuf, int32_t valid, dict_t *xdata) +{ + call_stub_t *stub = NULL; - loc_copy (&stub->args.entrylk.loc, loc); + GF_VALIDATE_OR_GOTO("call-stub", fn, out); - stub->args.entrylk.cmd = cmd; - stub->args.entrylk.type = type; - if (name) - stub->args.entrylk.name = gf_strdup (name); + stub = stub_new(frame, 1, GF_FOP_FSETATTR); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - return stub; + stub->fn.fsetattr = fn; + args_fsetattr_store(&stub->args, fd, stbuf, valid, xdata); +out: + return stub; } call_stub_t * -fop_entrylk_cbk_stub (call_frame_t *frame, fop_entrylk_cbk_t fn, - int32_t op_ret, int32_t op_errno) +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; - - if (!frame) - return NULL; + call_stub_t *stub = NULL; - stub = stub_new (frame, 0, GF_FOP_ENTRYLK); - if (!stub) - return NULL; + stub = stub_new(frame, 0, GF_FOP_FALLOCATE); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.entrylk_cbk.fn = fn; - stub->args.entrylk_cbk.op_ret = op_ret; - stub->args.entrylk_cbk.op_errno = op_errno; + stub->fn_cbk.fallocate = fn; - return stub; + args_fallocate_cbk_store(&stub->args_cbk, op_ret, op_errno, statpre, + statpost, xdata); +out: + return stub; } - call_stub_t * -fop_fentrylk_stub (call_frame_t *frame, fop_fentrylk_t fn, - const char *volume, fd_t *fd, const char *name, - entrylk_cmd cmd, entrylk_type type) +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; + call_stub_t *stub = NULL; - if (!frame) - return NULL; + GF_VALIDATE_OR_GOTO("call-stub", fn, out); - stub = stub_new (frame, 1, GF_FOP_FENTRYLK); - if (!stub) - return NULL; + stub = stub_new(frame, 1, GF_FOP_FALLOCATE); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.fentrylk.fn = fn; + stub->fn.fallocate = fn; + args_fallocate_store(&stub->args, fd, mode, offset, len, xdata); +out: + return stub; +} - if (volume) - stub->args.fentrylk.volume = gf_strdup (volume); +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; + + stub = stub_new(frame, 0, GF_FOP_DISCARD); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - if (fd) - stub->args.fentrylk.fd = fd_ref (fd); - stub->args.fentrylk.cmd = cmd; - stub->args.fentrylk.type = type; - if (name) - stub->args.fentrylk.name = gf_strdup (name); + stub->fn_cbk.discard = fn; - return stub; + args_discard_cbk_store(&stub->args_cbk, op_ret, op_errno, statpre, statpost, + xdata); +out: + return stub; } call_stub_t * -fop_fentrylk_cbk_stub (call_frame_t *frame, fop_fentrylk_cbk_t fn, - int32_t op_ret, int32_t op_errno) +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; + call_stub_t *stub = NULL; - if (!frame) - return NULL; + GF_VALIDATE_OR_GOTO("call-stub", fn, out); - stub = stub_new (frame, 0, GF_FOP_FENTRYLK); - if (!stub) - return NULL; + stub = stub_new(frame, 1, GF_FOP_DISCARD); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.fentrylk_cbk.fn = fn; - stub->args.fentrylk_cbk.op_ret = op_ret; - stub->args.fentrylk_cbk.op_errno = op_errno; - - return stub; + stub->fn.discard = fn; + args_discard_store(&stub->args, fd, offset, len, xdata); +out: + return stub; } - call_stub_t * -fop_readdirp_cbk_stub (call_frame_t *frame, - fop_readdirp_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - gf_dirent_t *entries) +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_dirent_t *stub_entry = NULL, *entry = NULL; - - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + call_stub_t *stub = NULL; - stub = stub_new (frame, 0, GF_FOP_READDIRP); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 0, GF_FOP_ZEROFILL); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.readdirp_cbk.fn = fn; - stub->args.readdirp_cbk.op_ret = op_ret; - stub->args.readdirp_cbk.op_errno = op_errno; - INIT_LIST_HEAD (&stub->args.readdirp_cbk.entries.list); + stub->fn_cbk.zerofill = fn; - /* This check must come after the init of head above - * so we're sure the list is empty for list_empty. - */ - if (!entries) - goto out; - - if (op_ret > 0) { - list_for_each_entry (entry, &entries->list, list) { - stub_entry = gf_dirent_for_name (entry->d_name); - if (!stub_entry) - goto out; - stub_entry->d_off = entry->d_off; - stub_entry->d_ino = entry->d_ino; - stub_entry->d_stat = entry->d_stat; - list_add_tail (&stub_entry->list, - &stub->args.readdirp_cbk.entries.list); - } - } + args_zerofill_cbk_store(&stub->args_cbk, op_ret, op_errno, statpre, + statpost, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_readdir_cbk_stub (call_frame_t *frame, - fop_readdir_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - gf_dirent_t *entries) +fop_zerofill_stub(call_frame_t *frame, fop_zerofill_t fn, fd_t *fd, + off_t offset, off_t len, dict_t *xdata) { - call_stub_t *stub = NULL; - gf_dirent_t *stub_entry = NULL, *entry = NULL; + 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, 0, GF_FOP_READDIR); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); - - stub->args.readdir_cbk.fn = fn; - stub->args.readdir_cbk.op_ret = op_ret; - stub->args.readdir_cbk.op_errno = op_errno; - INIT_LIST_HEAD (&stub->args.readdir_cbk.entries.list); + stub = stub_new(frame, 1, GF_FOP_ZEROFILL); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - /* This check must come after the init of head above - * so we're sure the list is empty for list_empty. - */ - if (!entries) - goto out; + stub->fn.zerofill = fn; + args_zerofill_store(&stub->args, fd, offset, len, xdata); +out: + return stub; +} + +call_stub_t * +fop_ipc_cbk_stub(call_frame_t *frame, fop_ipc_cbk_t fn, int32_t op_ret, + int32_t op_errno, dict_t *xdata) +{ + call_stub_t *stub = NULL; - if (op_ret > 0) { - list_for_each_entry (entry, &entries->list, list) { - stub_entry = gf_dirent_for_name (entry->d_name); - if (!stub_entry) - goto out; - stub_entry->d_off = entry->d_off; - stub_entry->d_ino = entry->d_ino; + stub = stub_new(frame, 0, GF_FOP_IPC); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - list_add_tail (&stub_entry->list, - &stub->args.readdir_cbk.entries.list); - } - } + stub->fn_cbk.ipc = fn; + + args_ipc_cbk_store(&stub->args_cbk, op_ret, op_errno, xdata); out: - return stub; + return stub; } call_stub_t * -fop_readdir_stub (call_frame_t *frame, - fop_readdir_t fn, - fd_t *fd, - size_t size, - off_t off) +fop_ipc_stub(call_frame_t *frame, fop_ipc_t fn, int32_t op, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; + + GF_VALIDATE_OR_GOTO("call-stub", fn, out); - stub = stub_new (frame, 1, GF_FOP_READDIR); - stub->args.readdir.fn = fn; - stub->args.readdir.fd = fd_ref (fd); - stub->args.readdir.size = size; - stub->args.readdir.off = off; + stub = stub_new(frame, 1, GF_FOP_IPC); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - return stub; + stub->fn.ipc = fn; + args_ipc_store(&stub->args, op, xdata); +out: + return stub; } call_stub_t * -fop_readdirp_stub (call_frame_t *frame, - fop_readdirp_t fn, - fd_t *fd, - size_t size, - off_t off) +fop_lease_cbk_stub(call_frame_t *frame, fop_lease_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct gf_lease *lease, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - stub = stub_new (frame, 1, GF_FOP_READDIRP); - stub->args.readdirp.fn = fn; - stub->args.readdirp.fd = fd_ref (fd); - stub->args.readdirp.size = size; - stub->args.readdirp.off = off; + stub = stub_new(frame, 0, GF_FOP_LEASE); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - return stub; + stub->fn_cbk.lease = fn; + args_lease_cbk_store(&stub->args_cbk, op_ret, op_errno, lease, xdata); +out: + return stub; } call_stub_t * -fop_rchecksum_stub (call_frame_t *frame, - fop_rchecksum_t fn, - fd_t *fd, off_t offset, - int32_t len) +fop_lease_stub(call_frame_t *frame, fop_lease_t fn, loc_t *loc, + struct gf_lease *lease, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - GF_VALIDATE_OR_GOTO ("call-stub", fd, out); + GF_VALIDATE_OR_GOTO("call-stub", fn, out); + GF_VALIDATE_OR_GOTO("call-stub", lease, out); - stub = stub_new (frame, 1, GF_FOP_RCHECKSUM); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub = stub_new(frame, 1, GF_FOP_LEASE); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.rchecksum.fn = fn; - stub->args.rchecksum.fd = fd_ref (fd); - stub->args.rchecksum.offset = offset; - stub->args.rchecksum.len = len; + stub->fn.lease = fn; + args_lease_store(&stub->args, loc, lease, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_rchecksum_cbk_stub (call_frame_t *frame, - fop_rchecksum_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - uint32_t weak_checksum, - uint8_t *strong_checksum) +fop_seek_cbk_stub(call_frame_t *frame, fop_seek_cbk_t fn, int32_t op_ret, + int32_t op_errno, off_t offset, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + stub = stub_new(frame, 0, GF_FOP_SEEK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 0, GF_FOP_RCHECKSUM); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + stub->fn_cbk.seek = fn; - stub->args.rchecksum_cbk.fn = fn; - stub->args.rchecksum_cbk.op_ret = op_ret; - stub->args.rchecksum_cbk.op_errno = op_errno; - - if (op_ret >= 0) - { - stub->args.rchecksum_cbk.weak_checksum = - weak_checksum; - - stub->args.rchecksum_cbk.strong_checksum = - memdup (strong_checksum, MD5_DIGEST_LEN); - } + args_seek_cbk_store(&stub->args_cbk, op_ret, op_errno, offset, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_xattrop_cbk_stub (call_frame_t *frame, - fop_xattrop_cbk_t fn, - int32_t op_ret, - int32_t op_errno) +fop_seek_stub(call_frame_t *frame, fop_seek_t fn, fd_t *fd, off_t offset, + gf_seek_what_t what, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); - - stub = stub_new (frame, 0, GF_FOP_XATTROP); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + GF_VALIDATE_OR_GOTO("call-stub", fn, out); - stub->args.xattrop_cbk.fn = fn; - stub->args.xattrop_cbk.op_ret = op_ret; - stub->args.xattrop_cbk.op_errno = op_errno; + stub = stub_new(frame, 1, GF_FOP_SEEK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + stub->fn.seek = fn; + args_seek_store(&stub->args, fd, offset, what, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_fxattrop_cbk_stub (call_frame_t *frame, - fop_fxattrop_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - dict_t *xattr) +fop_getactivelk_cbk_stub(call_frame_t *frame, fop_getactivelk_cbk_t fn, + int32_t op_ret, int32_t op_errno, + lock_migration_info_t *lmi, dict_t *xdata) { - call_stub_t *stub = NULL; - GF_VALIDATE_OR_GOTO ("call-stub", frame, out); + call_stub_t *stub = NULL; + + stub = stub_new(frame, 0, GF_FOP_GETACTIVELK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 0, GF_FOP_FXATTROP); - stub->args.fxattrop_cbk.fn = fn; - stub->args.fxattrop_cbk.op_ret = op_ret; - stub->args.fxattrop_cbk.op_errno = op_errno; - if (xattr) - stub->args.fxattrop_cbk.xattr = dict_ref (xattr); + stub->fn_cbk.getactivelk = fn; + args_getactivelk_cbk_store(&stub->args_cbk, op_ret, op_errno, lmi, xdata); out: - return stub; + return stub; } - call_stub_t * -fop_xattrop_stub (call_frame_t *frame, - fop_xattrop_t fn, - loc_t *loc, - gf_xattrop_flags_t optype, - dict_t *xattr) +fop_getactivelk_stub(call_frame_t *frame, fop_getactivelk_t fn, loc_t *loc, + dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - if (!frame || !xattr) - return NULL; + GF_VALIDATE_OR_GOTO("call-stub", fn, out); - stub = stub_new (frame, 1, GF_FOP_XATTROP); - if (!stub) - return NULL; + stub = stub_new(frame, 1, GF_FOP_GETACTIVELK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.xattrop.fn = fn; - - loc_copy (&stub->args.xattrop.loc, loc); + stub->fn.getactivelk = fn; - stub->args.xattrop.optype = optype; - stub->args.xattrop.xattr = dict_ref (xattr); + loc_copy(&stub->args.loc, loc); - return stub; + if (xdata) + stub->args.xdata = dict_ref(xdata); +out: + return stub; } call_stub_t * -fop_fxattrop_stub (call_frame_t *frame, - fop_fxattrop_t fn, - fd_t *fd, - gf_xattrop_flags_t optype, - dict_t *xattr) +fop_setactivelk_cbk_stub(call_frame_t *frame, fop_setactivelk_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - if (!frame || !xattr) - return NULL; + stub = stub_new(frame, 0, GF_FOP_SETACTIVELK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 1, GF_FOP_FXATTROP); - if (!stub) - return NULL; + stub->fn_cbk.setactivelk = fn; + stub->args_cbk.op_ret = op_ret; + stub->args_cbk.op_errno = op_errno; - stub->args.fxattrop.fn = fn; - - stub->args.fxattrop.fd = fd_ref (fd); + if (xdata) + stub->args.xdata = dict_ref(xdata); - stub->args.fxattrop.optype = optype; - stub->args.fxattrop.xattr = dict_ref (xattr); - - return stub; +out: + return stub; } - call_stub_t * -fop_setattr_cbk_stub (call_frame_t *frame, - fop_setattr_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *statpre, - struct iatt *statpost) +fop_setactivelk_stub(call_frame_t *frame, fop_setactivelk_t fn, loc_t *loc, + lock_migration_info_t *locklist, dict_t *xdata) { - call_stub_t *stub = NULL; - - if (frame == NULL) - goto out; + call_stub_t *stub = NULL; - stub = stub_new (frame, 0, GF_FOP_SETATTR); - if (stub == NULL) - goto out; + GF_VALIDATE_OR_GOTO("call-stub", fn, out); - stub->args.setattr_cbk.fn = fn; + stub = stub_new(frame, 1, GF_FOP_SETACTIVELK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.setattr_cbk.op_ret = op_ret; - stub->args.setattr_cbk.op_errno = op_errno; + stub->fn.setactivelk = fn; - if (statpre) - stub->args.setattr_cbk.statpre = *statpre; - if (statpost) - stub->args.setattr_cbk.statpost = *statpost; + args_setactivelk_store(&stub->args, loc, locklist, xdata); out: - return stub; + return stub; } call_stub_t * -fop_fsetattr_cbk_stub (call_frame_t *frame, - fop_setattr_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *statpre, - struct iatt *statpost) +fop_copy_file_range_stub(call_frame_t *frame, fop_copy_file_range_t fn, + fd_t *fd_in, off64_t off_in, fd_t *fd_out, + off64_t off_out, size_t len, uint32_t flags, + dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - if (frame == NULL) - goto out; + GF_VALIDATE_OR_GOTO("call-stub", fn, out); - stub = stub_new (frame, 0, GF_FOP_FSETATTR); - if (stub == NULL) - goto out; + stub = stub_new(frame, 1, GF_FOP_COPY_FILE_RANGE); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub->args.fsetattr_cbk.fn = fn; + stub->fn.copy_file_range = fn; - stub->args.fsetattr_cbk.op_ret = op_ret; - stub->args.fsetattr_cbk.op_errno = op_errno; + args_copy_file_range_store(&stub->args, fd_in, off_in, fd_out, off_out, len, + flags, xdata); - if (statpre) - stub->args.setattr_cbk.statpre = *statpre; - if (statpost) - stub->args.fsetattr_cbk.statpost = *statpost; out: - return stub; + return stub; } call_stub_t * -fop_setattr_stub (call_frame_t *frame, - fop_setattr_t fn, - loc_t *loc, - struct iatt *stbuf, - int32_t valid) +fop_copy_file_range_cbk_stub(call_frame_t *frame, fop_copy_file_range_cbk_t fn, + int32_t op_ret, int32_t op_errno, + struct iatt *stbuf, struct iatt *prebuf_dst, + struct iatt *postbuf_dst, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - if (frame == NULL) - goto out; + GF_VALIDATE_OR_GOTO("call-stub", fn, out); - if (fn == NULL) - goto out; + stub = stub_new(frame, 0, GF_FOP_COPY_FILE_RANGE); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - stub = stub_new (frame, 1, GF_FOP_SETATTR); - if (stub == NULL) - goto out; + stub->fn_cbk.copy_file_range = fn; + args_copy_file_range_cbk_store(&stub->args_cbk, op_ret, op_errno, stbuf, + prebuf_dst, postbuf_dst, xdata); - stub->args.setattr.fn = fn; +out: + return stub; +} - loc_copy (&stub->args.setattr.loc, loc); +call_stub_t * +fop_put_stub(call_frame_t *frame, fop_put_t fn, loc_t *loc, mode_t mode, + mode_t umask, uint32_t flags, struct iovec *vector, int32_t count, + off_t offset, struct iobref *iobref, dict_t *xattr, dict_t *xdata) +{ + call_stub_t *stub = NULL; - if (stbuf) - stub->args.setattr.stbuf = *stbuf; + GF_VALIDATE_OR_GOTO("call-stub", vector, out); - stub->args.setattr.valid = valid; + stub = stub_new(frame, 1, GF_FOP_PUT); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + stub->fn.put = fn; + args_put_store(&stub->args, loc, mode, umask, flags, vector, count, offset, + iobref, xattr, xdata); out: - return stub; + return stub; } call_stub_t * -fop_fsetattr_stub (call_frame_t *frame, - fop_fsetattr_t fn, - fd_t *fd, - struct iatt *stbuf, - int32_t valid) +fop_put_cbk_stub(call_frame_t *frame, fop_put_cbk_t fn, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + struct iatt *preparent, struct iatt *postparent, dict_t *xdata) { - call_stub_t *stub = NULL; + call_stub_t *stub = NULL; - if (frame == NULL) - goto out; + stub = stub_new(frame, 0, GF_FOP_PUT); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - if (fn == NULL) - goto out; + stub->fn_cbk.put = fn; + args_put_cbk_store(&stub->args_cbk, op_ret, op_errno, inode, buf, preparent, + postparent, xdata); +out: + return stub; +} - stub = stub_new (frame, 1, GF_FOP_FSETATTR); - if (stub == NULL) - goto out; +call_stub_t * +fop_icreate_stub(call_frame_t *frame, fop_icreate_t fn, loc_t *loc, mode_t mode, + dict_t *xdata) +{ + call_stub_t *stub = NULL; - stub->args.fsetattr.fn = fn; + GF_VALIDATE_OR_GOTO("call-stub", fn, out); - if (fd) - stub->args.fsetattr.fd = fd_ref (fd); + stub = stub_new(frame, 1, GF_FOP_ICREATE); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - if (stbuf) - stub->args.fsetattr.stbuf = *stbuf; + stub->fn.icreate = fn; - stub->args.fsetattr.valid = valid; + stub->args.mode = mode; + if (loc) + loc_copy(&stub->args.loc, loc); + if (xdata) + stub->args.xdata = dict_ref(xdata); out: - return stub; + return stub; } static void -call_resume_wind (call_stub_t *stub) -{ - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); - - switch (stub->fop) { - case GF_FOP_OPEN: - { - stub->args.open.fn (stub->frame, - stub->frame->this, - &stub->args.open.loc, - stub->args.open.flags, stub->args.open.fd, - stub->args.open.wbflags); - break; - } - case GF_FOP_CREATE: - { - stub->args.create.fn (stub->frame, - stub->frame->this, - &stub->args.create.loc, - stub->args.create.flags, - stub->args.create.mode, - stub->args.create.fd, - stub->args.create.params); - break; - } - case GF_FOP_STAT: - { - stub->args.stat.fn (stub->frame, - stub->frame->this, - &stub->args.stat.loc); - break; - } - case GF_FOP_READLINK: - { - stub->args.readlink.fn (stub->frame, - stub->frame->this, - &stub->args.readlink.loc, - stub->args.readlink.size); - break; - } - - case GF_FOP_MKNOD: - { - stub->args.mknod.fn (stub->frame, stub->frame->this, - &stub->args.mknod.loc, - stub->args.mknod.mode, - stub->args.mknod.rdev, - stub->args.mknod.params); - } - break; - - case GF_FOP_MKDIR: - { - stub->args.mkdir.fn (stub->frame, stub->frame->this, - &stub->args.mkdir.loc, - stub->args.mkdir.mode, - stub->args.mkdir.params); - } - break; - - case GF_FOP_UNLINK: - { - stub->args.unlink.fn (stub->frame, - stub->frame->this, - &stub->args.unlink.loc); - } - break; - - case GF_FOP_RMDIR: - { - stub->args.rmdir.fn (stub->frame, - stub->frame->this, - &stub->args.rmdir.loc); - } - break; - - case GF_FOP_SYMLINK: - { - stub->args.symlink.fn (stub->frame, - stub->frame->this, - stub->args.symlink.linkname, - &stub->args.symlink.loc, - stub->args.symlink.params); - } - break; - - case GF_FOP_RENAME: - { - stub->args.rename.fn (stub->frame, - stub->frame->this, - &stub->args.rename.old, - &stub->args.rename.new); - } - break; - - case GF_FOP_LINK: - { - stub->args.link.fn (stub->frame, - stub->frame->this, - &stub->args.link.oldloc, - &stub->args.link.newloc); - } - break; - - case GF_FOP_TRUNCATE: - { - stub->args.truncate.fn (stub->frame, - stub->frame->this, - &stub->args.truncate.loc, - stub->args.truncate.off); - break; - } - - case GF_FOP_READ: - { - stub->args.readv.fn (stub->frame, - stub->frame->this, - stub->args.readv.fd, - stub->args.readv.size, - stub->args.readv.off); - break; - } - - case GF_FOP_WRITE: - { - stub->args.writev.fn (stub->frame, - stub->frame->this, - stub->args.writev.fd, - stub->args.writev.vector, - stub->args.writev.count, - stub->args.writev.off, - stub->args.writev.iobref); - break; - } - - case GF_FOP_STATFS: - { - stub->args.statfs.fn (stub->frame, - stub->frame->this, - &stub->args.statfs.loc); - break; - } - case GF_FOP_FLUSH: - { - stub->args.flush.fn (stub->frame, - stub->frame->this, - stub->args.flush.fd); - break; - } - - case GF_FOP_FSYNC: - { - stub->args.fsync.fn (stub->frame, - stub->frame->this, - stub->args.fsync.fd, - stub->args.fsync.datasync); - break; - } - - case GF_FOP_SETXATTR: - { - stub->args.setxattr.fn (stub->frame, - stub->frame->this, - &stub->args.setxattr.loc, - stub->args.setxattr.dict, - stub->args.setxattr.flags); - break; - } - - case GF_FOP_GETXATTR: - { - stub->args.getxattr.fn (stub->frame, - stub->frame->this, - &stub->args.getxattr.loc, - stub->args.getxattr.name); - break; - } - - case GF_FOP_FSETXATTR: - { - stub->args.fsetxattr.fn (stub->frame, - stub->frame->this, - stub->args.fsetxattr.fd, - stub->args.fsetxattr.dict, - stub->args.fsetxattr.flags); - break; - } - - case GF_FOP_FGETXATTR: - { - stub->args.fgetxattr.fn (stub->frame, - stub->frame->this, - stub->args.fgetxattr.fd, - stub->args.fgetxattr.name); - break; - } - - case GF_FOP_REMOVEXATTR: - { - stub->args.removexattr.fn (stub->frame, - stub->frame->this, - &stub->args.removexattr.loc, - stub->args.removexattr.name); - break; - } - - case GF_FOP_OPENDIR: - { - stub->args.opendir.fn (stub->frame, - stub->frame->this, - &stub->args.opendir.loc, - stub->args.opendir.fd); - break; - } - - case GF_FOP_FSYNCDIR: - { - stub->args.fsyncdir.fn (stub->frame, - stub->frame->this, - stub->args.fsyncdir.fd, - stub->args.fsyncdir.datasync); - break; - } - - case GF_FOP_ACCESS: - { - stub->args.access.fn (stub->frame, - stub->frame->this, - &stub->args.access.loc, - stub->args.access.mask); - break; - } - - case GF_FOP_FTRUNCATE: - { - stub->args.ftruncate.fn (stub->frame, - stub->frame->this, - stub->args.ftruncate.fd, - stub->args.ftruncate.off); - break; - } - - case GF_FOP_FSTAT: - { - stub->args.fstat.fn (stub->frame, - stub->frame->this, - stub->args.fstat.fd); - break; - } - - case GF_FOP_LK: - { - stub->args.lk.fn (stub->frame, - stub->frame->this, - stub->args.lk.fd, - stub->args.lk.cmd, - &stub->args.lk.lock); - break; - } - - case GF_FOP_INODELK: - { - stub->args.inodelk.fn (stub->frame, - stub->frame->this, - stub->args.inodelk.volume, - &stub->args.inodelk.loc, - stub->args.inodelk.cmd, - &stub->args.inodelk.lock); - break; - } - - case GF_FOP_FINODELK: - { - stub->args.finodelk.fn (stub->frame, - stub->frame->this, - stub->args.finodelk.volume, - stub->args.finodelk.fd, - stub->args.finodelk.cmd, - &stub->args.finodelk.lock); - break; - } - - case GF_FOP_ENTRYLK: - { - stub->args.entrylk.fn (stub->frame, - stub->frame->this, - stub->args.entrylk.volume, - &stub->args.entrylk.loc, - stub->args.entrylk.name, - stub->args.entrylk.cmd, - stub->args.entrylk.type); - break; - } - - case GF_FOP_FENTRYLK: - { - stub->args.fentrylk.fn (stub->frame, - stub->frame->this, - stub->args.fentrylk.volume, - stub->args.fentrylk.fd, - stub->args.fentrylk.name, - stub->args.fentrylk.cmd, - stub->args.fentrylk.type); - break; - } - - break; - - case GF_FOP_LOOKUP: - { - stub->args.lookup.fn (stub->frame, - stub->frame->this, - &stub->args.lookup.loc, - stub->args.lookup.xattr_req); - break; - } - - case GF_FOP_RCHECKSUM: - { - stub->args.rchecksum.fn (stub->frame, - stub->frame->this, - stub->args.rchecksum.fd, - stub->args.rchecksum.offset, - stub->args.rchecksum.len); - break; - } - - case GF_FOP_READDIR: - { - stub->args.readdir.fn (stub->frame, - stub->frame->this, - stub->args.readdir.fd, - stub->args.readdir.size, - stub->args.readdir.off); - break; - } +args_icreate_store_cbk(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (inode) + args->inode = inode_ref(inode); + if (buf) + args->stat = *buf; + if (xdata) + args->xdata = dict_ref(xdata); +} - case GF_FOP_READDIRP: - { - stub->args.readdirp.fn (stub->frame, - stub->frame->this, - stub->args.readdirp.fd, - stub->args.readdirp.size, - stub->args.readdirp.off); - break; - } - - case GF_FOP_XATTROP: - { - stub->args.xattrop.fn (stub->frame, - stub->frame->this, - &stub->args.xattrop.loc, - stub->args.xattrop.optype, - stub->args.xattrop.xattr); - - break; - } - case GF_FOP_FXATTROP: - { - stub->args.fxattrop.fn (stub->frame, - stub->frame->this, - stub->args.fxattrop.fd, - stub->args.fxattrop.optype, - stub->args.fxattrop.xattr); - - break; - } - case GF_FOP_SETATTR: - { - stub->args.setattr.fn (stub->frame, - stub->frame->this, - &stub->args.setattr.loc, - &stub->args.setattr.stbuf, - stub->args.setattr.valid); - break; - } - case GF_FOP_FSETATTR: - { - stub->args.fsetattr.fn (stub->frame, - stub->frame->this, - stub->args.fsetattr.fd, - &stub->args.fsetattr.stbuf, - stub->args.fsetattr.valid); - break; - } - default: - { - gf_log ("call-stub", GF_LOG_ERROR, "Invalid value of FOP (%d)", - stub->fop); - break; - } +call_stub_t * +fop_icreate_cbk_stub(call_frame_t *frame, fop_icreate_cbk_t fn, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + dict_t *xdata) +{ + call_stub_t *stub = NULL; + + stub = stub_new(frame, 0, GF_FOP_ICREATE); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + + stub->fn_cbk.icreate = fn; + args_icreate_store_cbk(&stub->args_cbk, op_ret, op_errno, inode, buf, + xdata); - } out: - return; + return stub; } +call_stub_t * +fop_namelink_stub(call_frame_t *frame, fop_namelink_t fn, loc_t *loc, + dict_t *xdata) +{ + call_stub_t *stub = NULL; + + GF_VALIDATE_OR_GOTO("call-stub", fn, out); + + stub = stub_new(frame, 1, GF_FOP_NAMELINK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + + stub->fn.namelink = fn; + if (loc) + loc_copy(&stub->args.loc, loc); + if (xdata) + stub->args.xdata = dict_ref(xdata); + +out: + return stub; +} static void -call_resume_unwind (call_stub_t *stub) -{ - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); - - switch (stub->fop) { - case GF_FOP_OPEN: - { - if (!stub->args.open_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.open_cbk.op_ret, - stub->args.open_cbk.op_errno, - stub->args.open_cbk.fd); - else - stub->args.open_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.open_cbk.op_ret, - stub->args.open_cbk.op_errno, - stub->args.open_cbk.fd); - break; - } - - case GF_FOP_CREATE: - { - if (!stub->args.create_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.create_cbk.op_ret, - stub->args.create_cbk.op_errno, - stub->args.create_cbk.fd, - stub->args.create_cbk.inode, - &stub->args.create_cbk.buf, - &stub->args.create_cbk.preparent, - &stub->args.create_cbk.postparent); - else - stub->args.create_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.create_cbk.op_ret, - stub->args.create_cbk.op_errno, - stub->args.create_cbk.fd, - stub->args.create_cbk.inode, - &stub->args.create_cbk.buf, - &stub->args.create_cbk.preparent, - &stub->args.create_cbk.postparent); - - break; - } - - case GF_FOP_STAT: - { - if (!stub->args.stat_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.stat_cbk.op_ret, - stub->args.stat_cbk.op_errno, - &stub->args.stat_cbk.buf); - else - stub->args.stat_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.stat_cbk.op_ret, - stub->args.stat_cbk.op_errno, - &stub->args.stat_cbk.buf); - - break; - } - - case GF_FOP_READLINK: - { - if (!stub->args.readlink_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.readlink_cbk.op_ret, - stub->args.readlink_cbk.op_errno, - stub->args.readlink_cbk.buf, - &stub->args.readlink_cbk.sbuf); - else - stub->args.readlink_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.readlink_cbk.op_ret, - stub->args.readlink_cbk.op_errno, - stub->args.readlink_cbk.buf, - &stub->args.readlink_cbk.sbuf); - - break; - } - - case GF_FOP_MKNOD: - { - if (!stub->args.mknod_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.mknod_cbk.op_ret, - stub->args.mknod_cbk.op_errno, - stub->args.mknod_cbk.inode, - &stub->args.mknod_cbk.buf, - &stub->args.mknod_cbk.preparent, - &stub->args.mknod_cbk.postparent); - else - stub->args.mknod_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.mknod_cbk.op_ret, - stub->args.mknod_cbk.op_errno, - stub->args.mknod_cbk.inode, - &stub->args.mknod_cbk.buf, - &stub->args.mknod_cbk.preparent, - &stub->args.mknod_cbk.postparent); - break; - } - - case GF_FOP_MKDIR: - { - if (!stub->args.mkdir_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.mkdir_cbk.op_ret, - stub->args.mkdir_cbk.op_errno, - stub->args.mkdir_cbk.inode, - &stub->args.mkdir_cbk.buf, - &stub->args.mkdir_cbk.preparent, - &stub->args.mkdir_cbk.postparent); - else - stub->args.mkdir_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.mkdir_cbk.op_ret, - stub->args.mkdir_cbk.op_errno, - stub->args.mkdir_cbk.inode, - &stub->args.mkdir_cbk.buf, - &stub->args.mkdir_cbk.preparent, - &stub->args.mkdir_cbk.postparent); - - if (stub->args.mkdir_cbk.inode) - inode_unref (stub->args.mkdir_cbk.inode); - - break; - } - - case GF_FOP_UNLINK: - { - if (!stub->args.unlink_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.unlink_cbk.op_ret, - stub->args.unlink_cbk.op_errno, - &stub->args.unlink_cbk.preparent, - &stub->args.unlink_cbk.postparent); - else - stub->args.unlink_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.unlink_cbk.op_ret, - stub->args.unlink_cbk.op_errno, - &stub->args.unlink_cbk.preparent, - &stub->args.unlink_cbk.postparent); - break; - } - - case GF_FOP_RMDIR: - { - if (!stub->args.rmdir_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.rmdir_cbk.op_ret, - stub->args.rmdir_cbk.op_errno, - &stub->args.rmdir_cbk.preparent, - &stub->args.rmdir_cbk.postparent); - else - stub->args.unlink_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.rmdir_cbk.op_ret, - stub->args.rmdir_cbk.op_errno, - &stub->args.rmdir_cbk.preparent, - &stub->args.rmdir_cbk.postparent); - break; - } - - case GF_FOP_SYMLINK: - { - if (!stub->args.symlink_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.symlink_cbk.op_ret, - stub->args.symlink_cbk.op_errno, - stub->args.symlink_cbk.inode, - &stub->args.symlink_cbk.buf, - &stub->args.symlink_cbk.preparent, - &stub->args.symlink_cbk.postparent); - else - stub->args.symlink_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.symlink_cbk.op_ret, - stub->args.symlink_cbk.op_errno, - stub->args.symlink_cbk.inode, - &stub->args.symlink_cbk.buf, - &stub->args.symlink_cbk.preparent, - &stub->args.symlink_cbk.postparent); - } - break; - - case GF_FOP_RENAME: - { -#if 0 - if (!stub->args.rename_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.rename_cbk.op_ret, - stub->args.rename_cbk.op_errno, - &stub->args.rename_cbk.buf, - &stub->args.rename_cbk.preoldparent, - &stub->args.rename_cbk.postoldparent, - &stub->args.rename_cbk.prenewparent, - &stub->args.rename_cbk.postnewparent); - else - stub->args.rename_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.rename_cbk.op_ret, - stub->args.rename_cbk.op_errno, - &stub->args.rename_cbk.buf, - &stub->args.rename_cbk.preoldparent, - &stub->args.rename_cbk.postoldparent, - &stub->args.rename_cbk.prenewparent, - &stub->args.rename_cbk.postnewparent); -#endif - break; - } - - case GF_FOP_LINK: - { - if (!stub->args.link_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.link_cbk.op_ret, - stub->args.link_cbk.op_errno, - stub->args.link_cbk.inode, - &stub->args.link_cbk.buf); - else - stub->args.link_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.link_cbk.op_ret, - stub->args.link_cbk.op_errno, - stub->args.link_cbk.inode, - &stub->args.link_cbk.buf, - &stub->args.link_cbk.preparent, - &stub->args.link_cbk.postparent); - break; - } - - case GF_FOP_TRUNCATE: - { - if (!stub->args.truncate_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.truncate_cbk.op_ret, - stub->args.truncate_cbk.op_errno, - &stub->args.truncate_cbk.prebuf, - &stub->args.truncate_cbk.postbuf); - else - stub->args.truncate_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.truncate_cbk.op_ret, - stub->args.truncate_cbk.op_errno, - &stub->args.truncate_cbk.prebuf, - &stub->args.truncate_cbk.postbuf); - break; - } - - case GF_FOP_READ: - { - if (!stub->args.readv_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.readv_cbk.op_ret, - stub->args.readv_cbk.op_errno, - stub->args.readv_cbk.vector, - stub->args.readv_cbk.count, - &stub->args.readv_cbk.stbuf, - stub->args.readv_cbk.iobref); - else - stub->args.readv_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.readv_cbk.op_ret, - stub->args.readv_cbk.op_errno, - stub->args.readv_cbk.vector, - stub->args.readv_cbk.count, - &stub->args.readv_cbk.stbuf, - stub->args.readv_cbk.iobref); - } - break; - - case GF_FOP_WRITE: - { - if (!stub->args.writev_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.writev_cbk.op_ret, - stub->args.writev_cbk.op_errno, - &stub->args.writev_cbk.prebuf, - &stub->args.writev_cbk.postbuf); - else - stub->args.writev_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.writev_cbk.op_ret, - stub->args.writev_cbk.op_errno, - &stub->args.writev_cbk.prebuf, - &stub->args.writev_cbk.postbuf); - break; - } - - case GF_FOP_STATFS: - { - if (!stub->args.statfs_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.statfs_cbk.op_ret, - stub->args.statfs_cbk.op_errno, - &(stub->args.statfs_cbk.buf)); - else - stub->args.statfs_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.statfs_cbk.op_ret, - stub->args.statfs_cbk.op_errno, - &(stub->args.statfs_cbk.buf)); - } - break; - - case GF_FOP_FLUSH: - { - if (!stub->args.flush_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.flush_cbk.op_ret, - stub->args.flush_cbk.op_errno); - else - stub->args.flush_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.flush_cbk.op_ret, - stub->args.flush_cbk.op_errno); - - break; - } - - case GF_FOP_FSYNC: - { - if (!stub->args.fsync_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.fsync_cbk.op_ret, - stub->args.fsync_cbk.op_errno, - &stub->args.fsync_cbk.prebuf, - &stub->args.fsync_cbk.postbuf); - else - stub->args.fsync_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.fsync_cbk.op_ret, - stub->args.fsync_cbk.op_errno, - &stub->args.fsync_cbk.prebuf, - &stub->args.fsync_cbk.postbuf); - break; - } - - case GF_FOP_SETXATTR: - { - if (!stub->args.setxattr_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.setxattr_cbk.op_ret, - stub->args.setxattr_cbk.op_errno); - - else - stub->args.setxattr_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.setxattr_cbk.op_ret, - stub->args.setxattr_cbk.op_errno); - - break; - } - - case GF_FOP_GETXATTR: - { - if (!stub->args.getxattr_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.getxattr_cbk.op_ret, - stub->args.getxattr_cbk.op_errno, - stub->args.getxattr_cbk.dict); - else - stub->args.getxattr_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.getxattr_cbk.op_ret, - stub->args.getxattr_cbk.op_errno, - stub->args.getxattr_cbk.dict); - break; - } - - case GF_FOP_FSETXATTR: - { - if (!stub->args.fsetxattr_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.fsetxattr_cbk.op_ret, - stub->args.fsetxattr_cbk.op_errno); - - else - stub->args.fsetxattr_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.fsetxattr_cbk.op_ret, - stub->args.fsetxattr_cbk.op_errno); - - break; - } - - case GF_FOP_FGETXATTR: - { - if (!stub->args.fgetxattr_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.fgetxattr_cbk.op_ret, - stub->args.fgetxattr_cbk.op_errno, - stub->args.fgetxattr_cbk.dict); - else - stub->args.fgetxattr_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.fgetxattr_cbk.op_ret, - stub->args.fgetxattr_cbk.op_errno, - stub->args.fgetxattr_cbk.dict); - break; - } - - case GF_FOP_REMOVEXATTR: - { - if (!stub->args.removexattr_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.removexattr_cbk.op_ret, - stub->args.removexattr_cbk.op_errno); - else - stub->args.removexattr_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.removexattr_cbk.op_ret, - stub->args.removexattr_cbk.op_errno); - - break; - } - - case GF_FOP_OPENDIR: - { - if (!stub->args.opendir_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.opendir_cbk.op_ret, - stub->args.opendir_cbk.op_errno, - stub->args.opendir_cbk.fd); - else - stub->args.opendir_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.opendir_cbk.op_ret, - stub->args.opendir_cbk.op_errno, - stub->args.opendir_cbk.fd); - break; - } - - case GF_FOP_FSYNCDIR: - { - if (!stub->args.fsyncdir_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.fsyncdir_cbk.op_ret, - stub->args.fsyncdir_cbk.op_errno); - else - stub->args.fsyncdir_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.fsyncdir_cbk.op_ret, - stub->args.fsyncdir_cbk.op_errno); - break; - } - - case GF_FOP_ACCESS: - { - if (!stub->args.access_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.access_cbk.op_ret, - stub->args.access_cbk.op_errno); - else - stub->args.access_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.access_cbk.op_ret, - stub->args.access_cbk.op_errno); - - break; - } - - case GF_FOP_FTRUNCATE: - { - if (!stub->args.ftruncate_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.ftruncate_cbk.op_ret, - stub->args.ftruncate_cbk.op_errno, - &stub->args.ftruncate_cbk.prebuf, - &stub->args.ftruncate_cbk.postbuf); - else - stub->args.ftruncate_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.ftruncate_cbk.op_ret, - stub->args.ftruncate_cbk.op_errno, - &stub->args.ftruncate_cbk.prebuf, - &stub->args.ftruncate_cbk.postbuf); - break; - } - - case GF_FOP_FSTAT: - { - if (!stub->args.fstat_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.fstat_cbk.op_ret, - stub->args.fstat_cbk.op_errno, - &stub->args.fstat_cbk.buf); - else - stub->args.fstat_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.fstat_cbk.op_ret, - stub->args.fstat_cbk.op_errno, - &stub->args.fstat_cbk.buf); - - break; - } - - case GF_FOP_LK: - { - if (!stub->args.lk_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.lk_cbk.op_ret, - stub->args.lk_cbk.op_errno, - &stub->args.lk_cbk.lock); - else - stub->args.lk_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.lk_cbk.op_ret, - stub->args.lk_cbk.op_errno, - &stub->args.lk_cbk.lock); - break; - } - - case GF_FOP_INODELK: - { - if (!stub->args.inodelk_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.inodelk_cbk.op_ret, - stub->args.inodelk_cbk.op_errno); - - else - stub->args.inodelk_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.inodelk_cbk.op_ret, - stub->args.inodelk_cbk.op_errno); - break; - } - - case GF_FOP_FINODELK: - { - if (!stub->args.finodelk_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.finodelk_cbk.op_ret, - stub->args.finodelk_cbk.op_errno); - - else - stub->args.finodelk_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.finodelk_cbk.op_ret, - stub->args.finodelk_cbk.op_errno); - break; - } - - case GF_FOP_ENTRYLK: - { - if (!stub->args.entrylk_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.entrylk_cbk.op_ret, - stub->args.entrylk_cbk.op_errno); - - else - stub->args.entrylk_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.entrylk_cbk.op_ret, - stub->args.entrylk_cbk.op_errno); - break; - } - - case GF_FOP_FENTRYLK: - { - if (!stub->args.fentrylk_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.fentrylk_cbk.op_ret, - stub->args.fentrylk_cbk.op_errno); - - else - stub->args.fentrylk_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.fentrylk_cbk.op_ret, - stub->args.fentrylk_cbk.op_errno); - break; - } - - case GF_FOP_LOOKUP: - { - if (!stub->args.lookup_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.lookup_cbk.op_ret, - stub->args.lookup_cbk.op_errno, - stub->args.lookup_cbk.inode, - &stub->args.lookup_cbk.buf, - stub->args.lookup_cbk.dict, - &stub->args.lookup_cbk.postparent); - else - stub->args.lookup_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.lookup_cbk.op_ret, - stub->args.lookup_cbk.op_errno, - stub->args.lookup_cbk.inode, - &stub->args.lookup_cbk.buf, - stub->args.lookup_cbk.dict, - &stub->args.lookup_cbk.postparent); - /* FIXME NULL should not be passed */ - - if (stub->args.lookup_cbk.dict) - dict_unref (stub->args.lookup_cbk.dict); - if (stub->args.lookup_cbk.inode) - inode_unref (stub->args.lookup_cbk.inode); - - break; - } - - case GF_FOP_RCHECKSUM: - { - if (!stub->args.rchecksum_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.rchecksum_cbk.op_ret, - stub->args.rchecksum_cbk.op_errno, - stub->args.rchecksum_cbk.weak_checksum, - stub->args.rchecksum_cbk.strong_checksum); - else - stub->args.rchecksum_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.rchecksum_cbk.op_ret, - stub->args.rchecksum_cbk.op_errno, - stub->args.rchecksum_cbk.weak_checksum, - stub->args.rchecksum_cbk.strong_checksum); - if (stub->args.rchecksum_cbk.op_ret >= 0) - { - GF_FREE (stub->args.rchecksum_cbk.strong_checksum); - } - - break; - } - - case GF_FOP_READDIR: - { - if (!stub->args.readdir_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.readdir_cbk.op_ret, - stub->args.readdir_cbk.op_errno, - &stub->args.readdir_cbk.entries); - else - stub->args.readdir_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.readdir_cbk.op_ret, - stub->args.readdir_cbk.op_errno, - &stub->args.readdir_cbk.entries); - - if (stub->args.readdir_cbk.op_ret > 0) - gf_dirent_free (&stub->args.readdir_cbk.entries); - - break; - } +args_namelink_store_cbk(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + + if (prebuf) + args->prestat = *prebuf; + if (postbuf) + args->poststat = *postbuf; + if (xdata) + args->xdata = dict_ref(xdata); +} + +call_stub_t * +fop_namelink_cbk_stub(call_frame_t *frame, fop_namelink_cbk_t fn, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +{ + call_stub_t *stub = NULL; + + stub = stub_new(frame, 0, GF_FOP_NAMELINK); + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + + stub->fn_cbk.namelink = fn; + args_namelink_store_cbk(&stub->args_cbk, op_ret, op_errno, prebuf, postbuf, + xdata); + +out: + return stub; +} +void +call_resume_wind(call_stub_t *stub) +{ + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + + switch (stub->fop) { + case GF_FOP_OPEN: + stub->fn.open(stub->frame, stub->frame->this, &stub->args.loc, + stub->args.flags, stub->args.fd, stub->args.xdata); + break; + case GF_FOP_CREATE: + stub->fn.create(stub->frame, stub->frame->this, &stub->args.loc, + stub->args.flags, stub->args.mode, stub->args.umask, + stub->args.fd, stub->args.xdata); + break; + case GF_FOP_STAT: + stub->fn.stat(stub->frame, stub->frame->this, &stub->args.loc, + stub->args.xdata); + break; + case GF_FOP_READLINK: + stub->fn.readlink(stub->frame, stub->frame->this, &stub->args.loc, + stub->args.size, stub->args.xdata); + break; + case GF_FOP_MKNOD: + stub->fn.mknod(stub->frame, stub->frame->this, &stub->args.loc, + stub->args.mode, stub->args.rdev, stub->args.umask, + stub->args.xdata); + break; + case GF_FOP_MKDIR: + stub->fn.mkdir(stub->frame, stub->frame->this, &stub->args.loc, + stub->args.mode, stub->args.umask, stub->args.xdata); + break; + case GF_FOP_UNLINK: + stub->fn.unlink(stub->frame, stub->frame->this, &stub->args.loc, + stub->args.xflag, stub->args.xdata); + break; + case GF_FOP_RMDIR: + stub->fn.rmdir(stub->frame, stub->frame->this, &stub->args.loc, + stub->args.flags, stub->args.xdata); + break; + case GF_FOP_SYMLINK: + stub->fn.symlink(stub->frame, stub->frame->this, + stub->args.linkname, &stub->args.loc, + stub->args.umask, stub->args.xdata); + break; + case GF_FOP_RENAME: + stub->fn.rename(stub->frame, stub->frame->this, &stub->args.loc, + &stub->args.loc2, stub->args.xdata); + break; + case GF_FOP_LINK: + stub->fn.link(stub->frame, stub->frame->this, &stub->args.loc, + &stub->args.loc2, stub->args.xdata); + break; + case GF_FOP_TRUNCATE: + stub->fn.truncate(stub->frame, stub->frame->this, &stub->args.loc, + stub->args.offset, stub->args.xdata); + break; + case GF_FOP_READ: + stub->fn.readv(stub->frame, stub->frame->this, stub->args.fd, + stub->args.size, stub->args.offset, stub->args.flags, + stub->args.xdata); + break; + case GF_FOP_WRITE: + stub->fn.writev(stub->frame, stub->frame->this, stub->args.fd, + stub->args.vector, stub->args.count, + stub->args.offset, stub->args.flags, + stub->args.iobref, stub->args.xdata); + break; + case GF_FOP_STATFS: + stub->fn.statfs(stub->frame, stub->frame->this, &stub->args.loc, + stub->args.xdata); + break; + case GF_FOP_FLUSH: + stub->fn.flush(stub->frame, stub->frame->this, stub->args.fd, + stub->args.xdata); + break; + case GF_FOP_FSYNC: + stub->fn.fsync(stub->frame, stub->frame->this, stub->args.fd, + stub->args.datasync, stub->args.xdata); + break; + case GF_FOP_SETXATTR: + stub->fn.setxattr(stub->frame, stub->frame->this, &stub->args.loc, + stub->args.xattr, stub->args.flags, + stub->args.xdata); + break; + case GF_FOP_GETXATTR: + stub->fn.getxattr(stub->frame, stub->frame->this, &stub->args.loc, + stub->args.name, stub->args.xdata); + break; + case GF_FOP_FSETXATTR: + stub->fn.fsetxattr(stub->frame, stub->frame->this, stub->args.fd, + stub->args.xattr, stub->args.flags, + stub->args.xdata); + break; + case GF_FOP_FGETXATTR: + stub->fn.fgetxattr(stub->frame, stub->frame->this, stub->args.fd, + stub->args.name, stub->args.xdata); + break; + case GF_FOP_REMOVEXATTR: + stub->fn.removexattr(stub->frame, stub->frame->this, + &stub->args.loc, stub->args.name, + stub->args.xdata); + break; + case GF_FOP_FREMOVEXATTR: + stub->fn.fremovexattr(stub->frame, stub->frame->this, stub->args.fd, + stub->args.name, stub->args.xdata); + break; + case GF_FOP_OPENDIR: + stub->fn.opendir(stub->frame, stub->frame->this, &stub->args.loc, + stub->args.fd, stub->args.xdata); + break; + case GF_FOP_FSYNCDIR: + stub->fn.fsyncdir(stub->frame, stub->frame->this, stub->args.fd, + stub->args.datasync, stub->args.xdata); + break; + case GF_FOP_ACCESS: + stub->fn.access(stub->frame, stub->frame->this, &stub->args.loc, + stub->args.mask, stub->args.xdata); + break; + + case GF_FOP_FTRUNCATE: + stub->fn.ftruncate(stub->frame, stub->frame->this, stub->args.fd, + stub->args.offset, stub->args.xdata); + break; + case GF_FOP_FSTAT: + stub->fn.fstat(stub->frame, stub->frame->this, stub->args.fd, + stub->args.xdata); + break; + case GF_FOP_LK: + stub->fn.lk(stub->frame, stub->frame->this, stub->args.fd, + stub->args.cmd, &stub->args.lock, stub->args.xdata); + break; + case GF_FOP_INODELK: + stub->fn.inodelk(stub->frame, stub->frame->this, stub->args.volume, + &stub->args.loc, stub->args.cmd, &stub->args.lock, + stub->args.xdata); + break; + case GF_FOP_FINODELK: + stub->fn.finodelk(stub->frame, stub->frame->this, stub->args.volume, + stub->args.fd, stub->args.cmd, &stub->args.lock, + stub->args.xdata); + break; + case GF_FOP_ENTRYLK: + stub->fn.entrylk(stub->frame, stub->frame->this, stub->args.volume, + &stub->args.loc, stub->args.name, + stub->args.entrylkcmd, stub->args.entrylktype, + stub->args.xdata); + break; + case GF_FOP_FENTRYLK: + stub->fn.fentrylk(stub->frame, stub->frame->this, stub->args.volume, + stub->args.fd, stub->args.name, + stub->args.entrylkcmd, stub->args.entrylktype, + stub->args.xdata); + break; + case GF_FOP_LOOKUP: + stub->fn.lookup(stub->frame, stub->frame->this, &stub->args.loc, + stub->args.xdata); + break; + case GF_FOP_RCHECKSUM: + stub->fn.rchecksum(stub->frame, stub->frame->this, stub->args.fd, + stub->args.offset, stub->args.size, + stub->args.xdata); + break; + case GF_FOP_READDIR: + stub->fn.readdir(stub->frame, stub->frame->this, stub->args.fd, + stub->args.size, stub->args.offset, + stub->args.xdata); + break; case GF_FOP_READDIRP: - { - if (!stub->args.readdirp_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.readdirp_cbk.op_ret, - stub->args.readdirp_cbk.op_errno, - &stub->args.readdirp_cbk.entries); - else - stub->args.readdirp_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.readdirp_cbk.op_ret, - stub->args.readdirp_cbk.op_errno, - &stub->args.readdirp_cbk.entries); - - if (stub->args.readdirp_cbk.op_ret > 0) - gf_dirent_free (&stub->args.readdirp_cbk.entries); - - break; - } - - case GF_FOP_XATTROP: - { - if (!stub->args.xattrop_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.xattrop_cbk.op_ret, - stub->args.xattrop_cbk.op_errno); - else - stub->args.xattrop_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.xattrop_cbk.op_ret, - stub->args.xattrop_cbk.op_errno, - stub->args.xattrop_cbk.xattr); - - if (stub->args.xattrop_cbk.xattr) - dict_unref (stub->args.xattrop_cbk.xattr); - - break; - } - case GF_FOP_FXATTROP: - { - if (!stub->args.fxattrop_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.fxattrop_cbk.op_ret, - stub->args.fxattrop_cbk.op_errno); - else - stub->args.fxattrop_cbk.fn (stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.fxattrop_cbk.op_ret, - stub->args.fxattrop_cbk.op_errno, - stub->args.fxattrop_cbk.xattr); - - if (stub->args.fxattrop_cbk.xattr) - dict_unref (stub->args.fxattrop_cbk.xattr); - - break; - } + stub->fn.readdirp(stub->frame, stub->frame->this, stub->args.fd, + stub->args.size, stub->args.offset, + stub->args.xdata); + break; + case GF_FOP_XATTROP: + stub->fn.xattrop(stub->frame, stub->frame->this, &stub->args.loc, + stub->args.optype, stub->args.xattr, + stub->args.xdata); + break; + case GF_FOP_FXATTROP: + stub->fn.fxattrop(stub->frame, stub->frame->this, stub->args.fd, + stub->args.optype, stub->args.xattr, + stub->args.xdata); + break; case GF_FOP_SETATTR: - { - if (!stub->args.setattr_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.setattr_cbk.op_ret, - stub->args.setattr_cbk.op_errno, - &stub->args.setattr_cbk.statpre, - &stub->args.setattr_cbk.statpost); - else - stub->args.setattr_cbk.fn ( - stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.setattr_cbk.op_ret, - stub->args.setattr_cbk.op_errno, - &stub->args.setattr_cbk.statpre, - &stub->args.setattr_cbk.statpost); - break; - } + stub->fn.setattr(stub->frame, stub->frame->this, &stub->args.loc, + &stub->args.stat, stub->args.valid, + stub->args.xdata); + break; case GF_FOP_FSETATTR: - { - if (!stub->args.fsetattr_cbk.fn) - STACK_UNWIND (stub->frame, - stub->args.fsetattr_cbk.op_ret, - stub->args.fsetattr_cbk.op_errno, - &stub->args.fsetattr_cbk.statpre, - &stub->args.fsetattr_cbk.statpost); - else - stub->args.fsetattr_cbk.fn ( - stub->frame, - stub->frame->cookie, - stub->frame->this, - stub->args.fsetattr_cbk.op_ret, - stub->args.fsetattr_cbk.op_errno, - &stub->args.fsetattr_cbk.statpre, - &stub->args.fsetattr_cbk.statpost); - break; - } - default: - { - gf_log ("call-stub", GF_LOG_ERROR, "Invalid value of FOP (%d)", - stub->fop); - break; - } - } -out: - return; -} + stub->fn.fsetattr(stub->frame, stub->frame->this, 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; + case GF_FOP_IPC: + stub->fn.ipc(stub->frame, stub->frame->this, stub->args.cmd, + stub->args.xdata); + break; + case GF_FOP_SEEK: + stub->fn.seek(stub->frame, stub->frame->this, stub->args.fd, + stub->args.offset, stub->args.what, stub->args.xdata); + break; + case GF_FOP_LEASE: + stub->fn.lease(stub->frame, stub->frame->this, &stub->args.loc, + &stub->args.lease, stub->args.xdata); + break; + + case GF_FOP_GETACTIVELK: + stub->fn.getactivelk(stub->frame, stub->frame->this, + &stub->args.loc, stub->args.xdata); + break; + + case GF_FOP_SETACTIVELK: + stub->fn.setactivelk(stub->frame, stub->frame->this, + &stub->args.loc, &stub->args.locklist, + stub->args.xdata); + break; + + case GF_FOP_PUT: + stub->fn.put(stub->frame, stub->frame->this, &stub->args.loc, + stub->args.mode, stub->args.umask, stub->args.flags, + stub->args.vector, stub->args.count, stub->args.offset, + stub->args.iobref, stub->args.xattr, stub->args.xdata); + break; + + case GF_FOP_COPY_FILE_RANGE: + stub->fn.copy_file_range( + stub->frame, stub->frame->this, stub->args.fd, + stub->args.off_in, stub->args.fd_dst, stub->args.off_out, + stub->args.size, stub->args.flags, stub->args.xdata); + break; + default: + gf_msg_callingfn("call-stub", GF_LOG_ERROR, EINVAL, + LG_MSG_INVALID_ENTRY, + "Invalid value of FOP" + " (%d)", + stub->fop); + break; + } +out: + return; +} + +#define STUB_UNWIND(stb, fop, args...) \ + do { \ + if (stb->fn_cbk.fop) \ + stb->fn_cbk.fop(stb->frame, stb->frame->cookie, stb->frame->this, \ + stb->args_cbk.op_ret, stb->args_cbk.op_errno, \ + args); \ + else \ + STACK_UNWIND_STRICT(fop, stb->frame, stb->args_cbk.op_ret, \ + stb->args_cbk.op_errno, args); \ + } while (0) static void -call_stub_destroy_wind (call_stub_t *stub) -{ - switch (stub->fop) { - case GF_FOP_OPEN: - { - loc_wipe (&stub->args.open.loc); - if (stub->args.open.fd) - fd_unref (stub->args.open.fd); - break; - } - case GF_FOP_CREATE: - { - loc_wipe (&stub->args.create.loc); - if (stub->args.create.fd) - fd_unref (stub->args.create.fd); - if (stub->args.create.params) - dict_unref (stub->args.create.params); - break; - } - case GF_FOP_STAT: - { - loc_wipe (&stub->args.stat.loc); - break; - } - case GF_FOP_READLINK: - { - loc_wipe (&stub->args.readlink.loc); - break; - } - - case GF_FOP_MKNOD: - { - loc_wipe (&stub->args.mknod.loc); - if (stub->args.mknod.params) - dict_unref (stub->args.mknod.params); - } - break; - - case GF_FOP_MKDIR: - { - loc_wipe (&stub->args.mkdir.loc); - if (stub->args.mkdir.params) - dict_unref (stub->args.mkdir.params); - } - break; - - case GF_FOP_UNLINK: - { - loc_wipe (&stub->args.unlink.loc); - } - break; - - case GF_FOP_RMDIR: - { - loc_wipe (&stub->args.rmdir.loc); - } - break; - - case GF_FOP_SYMLINK: - { - GF_FREE ((char *)stub->args.symlink.linkname); - loc_wipe (&stub->args.symlink.loc); - if (stub->args.symlink.params) - dict_unref (stub->args.symlink.params); - } - break; - - case GF_FOP_RENAME: - { - loc_wipe (&stub->args.rename.old); - loc_wipe (&stub->args.rename.new); - } - break; - - case GF_FOP_LINK: - { - loc_wipe (&stub->args.link.oldloc); - loc_wipe (&stub->args.link.newloc); - } - break; - - case GF_FOP_TRUNCATE: - { - loc_wipe (&stub->args.truncate.loc); - break; - } - - case GF_FOP_READ: - { - if (stub->args.readv.fd) - fd_unref (stub->args.readv.fd); - break; - } - - case GF_FOP_WRITE: - { - struct iobref *iobref = stub->args.writev.iobref; - if (stub->args.writev.fd) - fd_unref (stub->args.writev.fd); - GF_FREE (stub->args.writev.vector); - if (iobref) - iobref_unref (iobref); - break; - } - - case GF_FOP_STATFS: - { - loc_wipe (&stub->args.statfs.loc); - break; - } - case GF_FOP_FLUSH: - { - if (stub->args.flush.fd) - fd_unref (stub->args.flush.fd); - break; - } - - case GF_FOP_FSYNC: - { - if (stub->args.fsync.fd) - fd_unref (stub->args.fsync.fd); - break; - } - - case GF_FOP_SETXATTR: - { - loc_wipe (&stub->args.setxattr.loc); - if (stub->args.setxattr.dict) - dict_unref (stub->args.setxattr.dict); - break; - } - - case GF_FOP_GETXATTR: - { - if (stub->args.getxattr.name) - GF_FREE ((char *)stub->args.getxattr.name); - loc_wipe (&stub->args.getxattr.loc); - break; - } - - case GF_FOP_FSETXATTR: - { - fd_unref (stub->args.fsetxattr.fd); - if (stub->args.fsetxattr.dict) - dict_unref (stub->args.fsetxattr.dict); - break; - } - - case GF_FOP_FGETXATTR: - { - if (stub->args.fgetxattr.name) - GF_FREE ((char *)stub->args.fgetxattr.name); - fd_unref (stub->args.fgetxattr.fd); - break; - } - - case GF_FOP_REMOVEXATTR: - { - loc_wipe (&stub->args.removexattr.loc); - GF_FREE ((char *)stub->args.removexattr.name); - break; - } - - case GF_FOP_OPENDIR: - { - loc_wipe (&stub->args.opendir.loc); - if (stub->args.opendir.fd) - fd_unref (stub->args.opendir.fd); - break; - } - - case GF_FOP_FSYNCDIR: - { - if (stub->args.fsyncdir.fd) - fd_unref (stub->args.fsyncdir.fd); - break; - } - - case GF_FOP_ACCESS: - { - loc_wipe (&stub->args.access.loc); - break; - } - - case GF_FOP_FTRUNCATE: - { - if (stub->args.ftruncate.fd) - fd_unref (stub->args.ftruncate.fd); - break; - } - - case GF_FOP_FSTAT: - { - if (stub->args.fstat.fd) - fd_unref (stub->args.fstat.fd); - break; - } - - case GF_FOP_LK: - { - if (stub->args.lk.fd) - fd_unref (stub->args.lk.fd); - break; - } - - case GF_FOP_INODELK: - { - if (stub->args.inodelk.volume) - GF_FREE ((char *)stub->args.inodelk.volume); - - loc_wipe (&stub->args.inodelk.loc); - break; - } - case GF_FOP_FINODELK: - { - if (stub->args.finodelk.volume) - GF_FREE ((char *)stub->args.finodelk.volume); - - if (stub->args.finodelk.fd) - fd_unref (stub->args.finodelk.fd); - break; - } - case GF_FOP_ENTRYLK: - { - if (stub->args.entrylk.volume) - GF_FREE ((char *)stub->args.entrylk.volume); - - if (stub->args.entrylk.name) - GF_FREE ((char *)stub->args.entrylk.name); - loc_wipe (&stub->args.entrylk.loc); - break; - } - case GF_FOP_FENTRYLK: - { - if (stub->args.fentrylk.volume) - GF_FREE ((char *)stub->args.fentrylk.volume); - - if (stub->args.fentrylk.name) - GF_FREE ((char *)stub->args.fentrylk.name); - - if (stub->args.fentrylk.fd) - fd_unref (stub->args.fentrylk.fd); - break; - } - - case GF_FOP_LOOKUP: - { - loc_wipe (&stub->args.lookup.loc); - if (stub->args.lookup.xattr_req) - dict_unref (stub->args.lookup.xattr_req); - break; - } - - case GF_FOP_RCHECKSUM: - { - if (stub->args.rchecksum.fd) - fd_unref (stub->args.rchecksum.fd); - break; - } - - case GF_FOP_READDIR: - { - if (stub->args.readdir.fd) - fd_unref (stub->args.readdir.fd); - break; - } - +call_resume_unwind(call_stub_t *stub) +{ + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + + switch (stub->fop) { + case GF_FOP_OPEN: + STUB_UNWIND(stub, open, stub->args_cbk.fd, stub->args_cbk.xdata); + break; + case GF_FOP_CREATE: + STUB_UNWIND(stub, create, stub->args_cbk.fd, stub->args_cbk.inode, + &stub->args_cbk.stat, &stub->args_cbk.preparent, + &stub->args_cbk.postparent, stub->args_cbk.xdata); + break; + case GF_FOP_STAT: + STUB_UNWIND(stub, stat, &stub->args_cbk.stat, stub->args_cbk.xdata); + break; + case GF_FOP_READLINK: + STUB_UNWIND(stub, readlink, stub->args_cbk.buf, + &stub->args_cbk.stat, stub->args.xdata); + break; + case GF_FOP_MKNOD: + STUB_UNWIND(stub, mknod, stub->args_cbk.inode, &stub->args_cbk.stat, + &stub->args_cbk.preparent, &stub->args_cbk.postparent, + stub->args_cbk.xdata); + break; + case GF_FOP_MKDIR: + STUB_UNWIND(stub, mkdir, stub->args_cbk.inode, &stub->args_cbk.stat, + &stub->args_cbk.preparent, &stub->args_cbk.postparent, + stub->args_cbk.xdata); + break; + case GF_FOP_UNLINK: + STUB_UNWIND(stub, unlink, &stub->args_cbk.preparent, + &stub->args_cbk.postparent, stub->args_cbk.xdata); + break; + case GF_FOP_RMDIR: + STUB_UNWIND(stub, rmdir, &stub->args_cbk.preparent, + &stub->args_cbk.postparent, stub->args_cbk.xdata); + break; + case GF_FOP_SYMLINK: + STUB_UNWIND(stub, symlink, stub->args_cbk.inode, + &stub->args_cbk.stat, &stub->args_cbk.preparent, + &stub->args_cbk.postparent, stub->args_cbk.xdata); + break; + case GF_FOP_RENAME: + STUB_UNWIND(stub, rename, &stub->args_cbk.stat, + &stub->args_cbk.preparent, &stub->args_cbk.postparent, + &stub->args_cbk.preparent2, &stub->args_cbk.postparent2, + stub->args_cbk.xdata); + break; + case GF_FOP_LINK: + STUB_UNWIND(stub, link, stub->args_cbk.inode, &stub->args_cbk.stat, + &stub->args_cbk.preparent, &stub->args_cbk.postparent, + stub->args_cbk.xdata); + break; + case GF_FOP_TRUNCATE: + STUB_UNWIND(stub, truncate, &stub->args_cbk.prestat, + &stub->args_cbk.poststat, stub->args_cbk.xdata); + break; + case GF_FOP_READ: + STUB_UNWIND(stub, readv, stub->args_cbk.vector, + stub->args_cbk.count, &stub->args_cbk.stat, + stub->args_cbk.iobref, stub->args_cbk.xdata); + break; + case GF_FOP_WRITE: + STUB_UNWIND(stub, writev, &stub->args_cbk.prestat, + &stub->args_cbk.poststat, stub->args_cbk.xdata); + break; + case GF_FOP_STATFS: + STUB_UNWIND(stub, statfs, &stub->args_cbk.statvfs, + stub->args_cbk.xdata); + break; + case GF_FOP_FLUSH: + STUB_UNWIND(stub, flush, stub->args_cbk.xdata); + break; + case GF_FOP_FSYNC: + STUB_UNWIND(stub, fsync, &stub->args_cbk.prestat, + &stub->args_cbk.poststat, stub->args_cbk.xdata); + break; + case GF_FOP_SETXATTR: + STUB_UNWIND(stub, setxattr, stub->args_cbk.xdata); + break; + case GF_FOP_GETXATTR: + STUB_UNWIND(stub, getxattr, stub->args_cbk.xattr, + stub->args_cbk.xdata); + break; + case GF_FOP_FSETXATTR: + STUB_UNWIND(stub, fsetxattr, stub->args_cbk.xdata); + break; + case GF_FOP_FGETXATTR: + STUB_UNWIND(stub, fgetxattr, stub->args_cbk.xattr, + stub->args_cbk.xdata); + break; + case GF_FOP_REMOVEXATTR: + STUB_UNWIND(stub, removexattr, stub->args_cbk.xdata); + break; + case GF_FOP_FREMOVEXATTR: + STUB_UNWIND(stub, fremovexattr, stub->args_cbk.xdata); + break; + case GF_FOP_OPENDIR: + STUB_UNWIND(stub, opendir, stub->args_cbk.fd, stub->args_cbk.xdata); + break; + case GF_FOP_FSYNCDIR: + STUB_UNWIND(stub, fsyncdir, stub->args_cbk.xdata); + break; + case GF_FOP_ACCESS: + STUB_UNWIND(stub, access, stub->args_cbk.xdata); + break; + case GF_FOP_FTRUNCATE: + STUB_UNWIND(stub, ftruncate, &stub->args_cbk.prestat, + &stub->args_cbk.poststat, stub->args_cbk.xdata); + break; + case GF_FOP_FSTAT: + STUB_UNWIND(stub, fstat, &stub->args_cbk.stat, + stub->args_cbk.xdata); + break; + case GF_FOP_LK: + STUB_UNWIND(stub, lk, &stub->args_cbk.lock, stub->args_cbk.xdata); + break; + case GF_FOP_INODELK: + STUB_UNWIND(stub, inodelk, stub->args_cbk.xdata); + break; + case GF_FOP_FINODELK: + STUB_UNWIND(stub, finodelk, stub->args_cbk.xdata); + break; + case GF_FOP_ENTRYLK: + STUB_UNWIND(stub, entrylk, stub->args_cbk.xdata); + break; + case GF_FOP_FENTRYLK: + STUB_UNWIND(stub, fentrylk, stub->args_cbk.xdata); + break; + case GF_FOP_LOOKUP: + STUB_UNWIND(stub, lookup, stub->args_cbk.inode, + &stub->args_cbk.stat, stub->args_cbk.xdata, + &stub->args_cbk.postparent); + break; + case GF_FOP_RCHECKSUM: + STUB_UNWIND(stub, rchecksum, stub->args_cbk.weak_checksum, + stub->args_cbk.strong_checksum, stub->args_cbk.xdata); + break; + case GF_FOP_READDIR: + STUB_UNWIND(stub, readdir, &stub->args_cbk.entries, + stub->args_cbk.xdata); + break; case GF_FOP_READDIRP: - { - if (stub->args.readdirp.fd) - fd_unref (stub->args.readdirp.fd); - break; - } - - case GF_FOP_XATTROP: - { - loc_wipe (&stub->args.xattrop.loc); - dict_unref (stub->args.xattrop.xattr); - break; - } - case GF_FOP_FXATTROP: - { - if (stub->args.fxattrop.fd) - fd_unref (stub->args.fxattrop.fd); - dict_unref (stub->args.fxattrop.xattr); - break; - } + STUB_UNWIND(stub, readdir, &stub->args_cbk.entries, + stub->args_cbk.xdata); + break; + case GF_FOP_XATTROP: + STUB_UNWIND(stub, xattrop, stub->args_cbk.xattr, + stub->args_cbk.xdata); + break; + case GF_FOP_FXATTROP: + STUB_UNWIND(stub, fxattrop, stub->args_cbk.xattr, + stub->args_cbk.xdata); + break; case GF_FOP_SETATTR: - { - loc_wipe (&stub->args.setattr.loc); - break; - } + STUB_UNWIND(stub, setattr, &stub->args_cbk.prestat, + &stub->args_cbk.poststat, stub->args_cbk.xdata); + break; case GF_FOP_FSETATTR: - { - if (stub->args.fsetattr.fd) - fd_unref (stub->args.fsetattr.fd); - break; - } + 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; + case GF_FOP_IPC: + STUB_UNWIND(stub, ipc, stub->args_cbk.xdata); + break; + case GF_FOP_SEEK: + STUB_UNWIND(stub, seek, stub->args_cbk.offset, + stub->args_cbk.xdata); + break; + case GF_FOP_LEASE: + STUB_UNWIND(stub, lease, &stub->args_cbk.lease, + stub->args_cbk.xdata); + break; + + case GF_FOP_GETACTIVELK: + STUB_UNWIND(stub, getactivelk, &stub->args_cbk.locklist, + stub->args_cbk.xdata); + break; + + case GF_FOP_SETACTIVELK: + STUB_UNWIND(stub, setactivelk, stub->args_cbk.xdata); + break; + + case GF_FOP_PUT: + STUB_UNWIND(stub, put, stub->args_cbk.inode, &stub->args_cbk.stat, + &stub->args_cbk.preparent, &stub->args_cbk.postparent, + stub->args_cbk.xdata); + break; + + case GF_FOP_COPY_FILE_RANGE: + STUB_UNWIND(stub, copy_file_range, &stub->args_cbk.stat, + &stub->args_cbk.prestat, &stub->args_cbk.poststat, + stub->args_cbk.xdata); + break; + default: - { - gf_log ("call-stub", GF_LOG_ERROR, "Invalid value of FOP (%d)", - stub->fop); - break; - } - } + gf_msg_callingfn("call-stub", GF_LOG_ERROR, EINVAL, + LG_MSG_INVALID_ENTRY, + "Invalid value of FOP" + " (%d)", + stub->fop); + break; + } +out: + return; } +static void +call_stub_wipe_args(call_stub_t *stub) +{ + args_wipe(&stub->args); +} static void -call_stub_destroy_unwind (call_stub_t *stub) -{ - switch (stub->fop) { - case GF_FOP_OPEN: - { - if (stub->args.open_cbk.fd) - fd_unref (stub->args.open_cbk.fd); - } - break; - - case GF_FOP_CREATE: - { - if (stub->args.create_cbk.fd) - fd_unref (stub->args.create_cbk.fd); - - if (stub->args.create_cbk.inode) - inode_unref (stub->args.create_cbk.inode); - } - break; - - case GF_FOP_STAT: - break; - - case GF_FOP_READLINK: - { - if (stub->args.readlink_cbk.buf) - GF_FREE ((char *)stub->args.readlink_cbk.buf); - } - break; - - case GF_FOP_MKNOD: - { - if (stub->args.mknod_cbk.inode) - inode_unref (stub->args.mknod_cbk.inode); - } - break; - - case GF_FOP_MKDIR: - { - if (stub->args.mkdir_cbk.inode) - inode_unref (stub->args.mkdir_cbk.inode); - } - break; - - case GF_FOP_UNLINK: - break; - - case GF_FOP_RMDIR: - break; - - case GF_FOP_SYMLINK: - { - if (stub->args.symlink_cbk.inode) - inode_unref (stub->args.symlink_cbk.inode); - } - break; - - case GF_FOP_RENAME: - break; - - case GF_FOP_LINK: - { - if (stub->args.link_cbk.inode) - inode_unref (stub->args.link_cbk.inode); - } - break; - - case GF_FOP_TRUNCATE: - break; - - case GF_FOP_READ: - { - if (stub->args.readv_cbk.op_ret >= 0) { - struct iobref *iobref = stub->args.readv_cbk.iobref; - GF_FREE (stub->args.readv_cbk.vector); - - if (iobref) { - iobref_unref (iobref); - } - } - } - break; - - case GF_FOP_WRITE: - break; - - case GF_FOP_STATFS: - break; - - case GF_FOP_FLUSH: - break; - - case GF_FOP_FSYNC: - break; - - case GF_FOP_SETXATTR: - break; - - case GF_FOP_GETXATTR: - { - if (stub->args.getxattr_cbk.dict) - dict_unref (stub->args.getxattr_cbk.dict); - } - break; - - case GF_FOP_FSETXATTR: - break; - - case GF_FOP_FGETXATTR: - { - if (stub->args.fgetxattr_cbk.dict) - dict_unref (stub->args.fgetxattr_cbk.dict); - } - break; - - case GF_FOP_REMOVEXATTR: - break; - - case GF_FOP_OPENDIR: - { - if (stub->args.opendir_cbk.fd) - fd_unref (stub->args.opendir_cbk.fd); - } - break; - - case GF_FOP_FSYNCDIR: - break; - - case GF_FOP_ACCESS: - break; - - case GF_FOP_FTRUNCATE: - break; - - case GF_FOP_FSTAT: - break; - - case GF_FOP_LK: - break; - - case GF_FOP_INODELK: - break; - - case GF_FOP_FINODELK: - break; - - case GF_FOP_ENTRYLK: - break; - - case GF_FOP_FENTRYLK: - break; - - case GF_FOP_LOOKUP: - { - if (stub->args.lookup_cbk.inode) - inode_unref (stub->args.lookup_cbk.inode); - - if (stub->args.lookup_cbk.dict) - dict_unref (stub->args.lookup_cbk.dict); - } - break; - - case GF_FOP_RCHECKSUM: - { - if (stub->args.rchecksum_cbk.op_ret >= 0) { - GF_FREE (stub->args.rchecksum_cbk.strong_checksum); - } - } - break; - - case GF_FOP_READDIR: - { - if (stub->args.readdir_cbk.op_ret > 0) { - gf_dirent_free (&stub->args.readdir_cbk.entries); - } - } - break; +call_stub_wipe_args_cbk(call_stub_t *stub) +{ + args_cbk_wipe(&stub->args_cbk); +} - case GF_FOP_READDIRP: - { - if (stub->args.readdirp_cbk.op_ret > 0) { - gf_dirent_free (&stub->args.readdirp_cbk.entries); - } - } - break; - - case GF_FOP_XATTROP: - { - if (stub->args.xattrop_cbk.xattr) - dict_unref (stub->args.xattrop_cbk.xattr); - } - break; - - case GF_FOP_FXATTROP: - { - if (stub->args.fxattrop_cbk.xattr) - dict_unref (stub->args.fxattrop_cbk.xattr); - } - break; - - case GF_FOP_SETATTR: - { - break; - } +void +call_stub_destroy(call_stub_t *stub) +{ + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - case GF_FOP_FSETATTR: - { - break; - } + if (stub->wind) + call_stub_wipe_args(stub); + else + call_stub_wipe_args_cbk(stub); - default: - { - gf_log ("call-stub", GF_LOG_ERROR, "Invalid value of FOP (%d)", - stub->fop); - break; - } - } + stub->stub_mem_pool = NULL; + + mem_put(stub); +out: + return; } - void -call_stub_destroy (call_stub_t *stub) +call_resume(call_stub_t *stub) { - struct mem_pool *tmp_pool = NULL; + xlator_t *old_THIS = NULL; + + errno = EINVAL; + GF_VALIDATE_OR_GOTO("call-stub", stub, out); - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + list_del_init(&stub->list); - tmp_pool = stub->stub_mem_pool; - - if (stub->wind) { - call_stub_destroy_wind (stub); - } else { - call_stub_destroy_unwind (stub); - } + old_THIS = THIS; + THIS = stub->frame->this; + { + if (stub->wind) + call_resume_wind(stub); + else + call_resume_unwind(stub); + } + THIS = old_THIS; - stub->stub_mem_pool = NULL; - mem_put (tmp_pool, stub); + call_stub_destroy(stub); out: - tmp_pool = NULL; + return; +} + +void +call_unwind_error(call_stub_t *stub, int op_ret, int op_errno) +{ + xlator_t *old_THIS = NULL; + + list_del_init(&stub->list); + + old_THIS = THIS; + THIS = stub->frame->this; + { + stub->args_cbk.op_ret = op_ret; + stub->args_cbk.op_errno = op_errno; + call_resume_unwind(stub); + } + THIS = old_THIS; + + call_stub_destroy(stub); - return; + return; } void -call_resume (call_stub_t *stub) +call_unwind_error_keep_stub(call_stub_t *stub, int op_ret, int op_errno) { - xlator_t *old_THIS = NULL; + xlator_t *old_THIS = NULL; - errno = EINVAL; - GF_VALIDATE_OR_GOTO ("call-stub", stub, out); + list_del_init(&stub->list); - list_del_init (&stub->list); + old_THIS = THIS; + THIS = stub->frame->this; + { + stub->args_cbk.op_ret = op_ret; + stub->args_cbk.op_errno = op_errno; + call_resume_unwind(stub); + } - old_THIS = THIS; - THIS = stub->frame->this; - { - if (stub->wind) - call_resume_wind (stub); - else - call_resume_unwind (stub); - } - THIS = old_THIS; + THIS = old_THIS; - call_stub_destroy (stub); -out: - return; + return; } +void +call_resume_keep_stub(call_stub_t *stub) +{ + xlator_t *old_THIS = NULL; + + errno = EINVAL; + GF_VALIDATE_OR_GOTO("call-stub", stub, out); + + list_del_init(&stub->list); + old_THIS = THIS; + THIS = stub->frame->this; + { + if (stub->wind) + call_resume_wind(stub); + else + call_resume_unwind(stub); + } + + THIS = old_THIS; + +out: + return; +} diff --git a/libglusterfs/src/call-stub.h b/libglusterfs/src/call-stub.h deleted file mode 100644 index 83efa9a4857..00000000000 --- a/libglusterfs/src/call-stub.h +++ /dev/null @@ -1,1116 +0,0 @@ -/* - Copyright (c) 2007-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _CALL_STUB_H_ -#define _CALL_STUB_H_ - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include "xlator.h" -#include "stack.h" -#include "list.h" - -typedef struct { - struct list_head list; - char wind; - call_frame_t *frame; - glusterfs_fop_t fop; - struct mem_pool *stub_mem_pool; /* pointer to stub mempool in glusterfs ctx */ - - union { - /* lookup */ - struct { - fop_lookup_t fn; - loc_t loc; - dict_t *xattr_req; - } lookup; - struct { - fop_lookup_cbk_t fn; - int32_t op_ret, op_errno; - inode_t *inode; - struct iatt buf; - dict_t *dict; - struct iatt postparent; - } lookup_cbk; - - /* stat */ - struct { - fop_stat_t fn; - loc_t loc; - } stat; - struct { - fop_stat_cbk_t fn; - int32_t op_ret, op_errno; - struct iatt buf; - } stat_cbk; - - /* fstat */ - struct { - fop_fstat_t fn; - fd_t *fd; - } fstat; - struct { - fop_fstat_cbk_t fn; - int32_t op_ret, op_errno; - struct iatt buf; - } fstat_cbk; - - /* truncate */ - struct { - fop_truncate_t fn; - loc_t loc; - off_t off; - } truncate; - struct { - fop_truncate_cbk_t fn; - int32_t op_ret, op_errno; - struct iatt prebuf; - struct iatt postbuf; - } truncate_cbk; - - /* ftruncate */ - struct { - fop_ftruncate_t fn; - fd_t *fd; - off_t off; - } ftruncate; - struct { - fop_ftruncate_cbk_t fn; - int32_t op_ret, op_errno; - struct iatt prebuf; - struct iatt postbuf; - } ftruncate_cbk; - - /* access */ - struct { - fop_access_t fn; - loc_t loc; - int32_t mask; - } access; - struct { - fop_access_cbk_t fn; - int32_t op_ret, op_errno; - } access_cbk; - - /* readlink */ - struct { - fop_readlink_t fn; - loc_t loc; - size_t size; - } readlink; - struct { - fop_readlink_cbk_t fn; - int32_t op_ret, op_errno; - const char *buf; - struct iatt sbuf; - } readlink_cbk; - - /* mknod */ - struct { - fop_mknod_t fn; - loc_t loc; - mode_t mode; - dev_t rdev; - dict_t *params; - } mknod; - struct { - fop_mknod_cbk_t fn; - int32_t op_ret, op_errno; - inode_t *inode; - struct iatt buf; - struct iatt preparent; - struct iatt postparent; - } mknod_cbk; - - /* mkdir */ - struct { - fop_mkdir_t fn; - loc_t loc; - mode_t mode; - dict_t *params; - } mkdir; - struct { - fop_mkdir_cbk_t fn; - int32_t op_ret, op_errno; - inode_t *inode; - struct iatt buf; - struct iatt preparent; - struct iatt postparent; - } mkdir_cbk; - - /* unlink */ - struct { - fop_unlink_t fn; - loc_t loc; - } unlink; - struct { - fop_unlink_cbk_t fn; - int32_t op_ret, op_errno; - struct iatt preparent; - struct iatt postparent; - } unlink_cbk; - - /* rmdir */ - struct { - fop_rmdir_t fn; - loc_t loc; - } rmdir; - struct { - fop_rmdir_cbk_t fn; - int32_t op_ret, op_errno; - struct iatt preparent; - struct iatt postparent; - } rmdir_cbk; - - /* symlink */ - struct { - fop_symlink_t fn; - const char *linkname; - loc_t loc; - dict_t *params; - } symlink; - struct { - fop_symlink_cbk_t fn; - int32_t op_ret, op_errno; - inode_t *inode; - struct iatt buf; - struct iatt preparent; - struct iatt postparent; - } symlink_cbk; - - /* rename */ - struct { - fop_rename_t fn; - loc_t old; - loc_t new; - } rename; - struct { - fop_rename_cbk_t fn; - int32_t op_ret, op_errno; - struct iatt buf; - struct iatt preoldparent; - struct iatt postoldparent; - struct iatt prenewparent; - struct iatt postnewparent; - } rename_cbk; - - /* link */ - struct { - fop_link_t fn; - loc_t oldloc; - loc_t newloc; - } link; - struct { - fop_link_cbk_t fn; - int32_t op_ret, op_errno; - inode_t *inode; - struct iatt buf; - struct iatt preparent; - struct iatt postparent; - } link_cbk; - - /* create */ - struct { - fop_create_t fn; - loc_t loc; - int32_t flags; - mode_t mode; - fd_t *fd; - dict_t *params; - } create; - struct { - fop_create_cbk_t fn; - int32_t op_ret, op_errno; - fd_t *fd; - inode_t *inode; - struct iatt buf; - struct iatt preparent; - struct iatt postparent; - } create_cbk; - - /* open */ - struct { - fop_open_t fn; - loc_t loc; - int32_t flags; - fd_t *fd; - int32_t wbflags; - } open; - struct { - fop_open_cbk_t fn; - int32_t op_ret, op_errno; - fd_t *fd; - } open_cbk; - - /* readv */ - struct { - fop_readv_t fn; - fd_t *fd; - size_t size; - off_t off; - } readv; - struct { - fop_readv_cbk_t fn; - int32_t op_ret; - int32_t op_errno; - struct iovec *vector; - int32_t count; - struct iatt stbuf; - struct iobref *iobref; - } readv_cbk; - - /* writev */ - struct { - fop_writev_t fn; - fd_t *fd; - struct iovec *vector; - int32_t count; - off_t off; - struct iobref *iobref; - } writev; - struct { - fop_writev_cbk_t fn; - int32_t op_ret, op_errno; - struct iatt prebuf; - struct iatt postbuf; - } writev_cbk; - - /* flush */ - struct { - fop_flush_t fn; - fd_t *fd; - } flush; - struct { - fop_flush_cbk_t fn; - int32_t op_ret, op_errno; - } flush_cbk; - - /* fsync */ - struct { - fop_fsync_t fn; - fd_t *fd; - int32_t datasync; - } fsync; - struct { - fop_fsync_cbk_t fn; - int32_t op_ret, op_errno; - struct iatt prebuf; - struct iatt postbuf; - } fsync_cbk; - - /* opendir */ - struct { - fop_opendir_t fn; - loc_t loc; - fd_t *fd; - } opendir; - struct { - fop_opendir_cbk_t fn; - int32_t op_ret, op_errno; - fd_t *fd; - } opendir_cbk; - - - /* fsyncdir */ - struct { - fop_fsyncdir_t fn; - fd_t *fd; - int32_t datasync; - } fsyncdir; - struct { - fop_fsyncdir_cbk_t fn; - int32_t op_ret, op_errno; - } fsyncdir_cbk; - - /* statfs */ - struct { - fop_statfs_t fn; - loc_t loc; - } statfs; - struct { - fop_statfs_cbk_t fn; - int32_t op_ret, op_errno; - struct statvfs buf; - } statfs_cbk; - - /* setxattr */ - struct { - fop_setxattr_t fn; - loc_t loc; - dict_t *dict; - int32_t flags; - } setxattr; - struct { - fop_setxattr_cbk_t fn; - int32_t op_ret, op_errno; - } setxattr_cbk; - - /* getxattr */ - struct { - fop_getxattr_t fn; - loc_t loc; - const char *name; - } getxattr; - struct { - fop_getxattr_cbk_t fn; - int32_t op_ret, op_errno; - dict_t *dict; - } getxattr_cbk; - - /* fsetxattr */ - struct { - fop_fsetxattr_t fn; - fd_t *fd; - dict_t *dict; - int32_t flags; - } fsetxattr; - struct { - fop_fsetxattr_cbk_t fn; - int32_t op_ret, op_errno; - } fsetxattr_cbk; - - /* fgetxattr */ - struct { - fop_fgetxattr_t fn; - fd_t *fd; - const char *name; - } fgetxattr; - struct { - fop_fgetxattr_cbk_t fn; - int32_t op_ret, op_errno; - dict_t *dict; - } fgetxattr_cbk; - - /* removexattr */ - struct { - fop_removexattr_t fn; - loc_t loc; - const char *name; - } removexattr; - struct { - fop_removexattr_cbk_t fn; - int32_t op_ret, op_errno; - } removexattr_cbk; - - /* lk */ - struct { - fop_lk_t fn; - fd_t *fd; - int32_t cmd; - struct flock lock; - } lk; - struct { - fop_lk_cbk_t fn; - int32_t op_ret, op_errno; - struct flock lock; - } lk_cbk; - - /* inodelk */ - struct { - fop_inodelk_t fn; - const char *volume; - loc_t loc; - int32_t cmd; - struct flock lock; - } inodelk; - - struct { - fop_inodelk_cbk_t fn; - int32_t op_ret, op_errno; - } inodelk_cbk; - - /* finodelk */ - struct { - fop_finodelk_t fn; - const char *volume; - fd_t *fd; - int32_t cmd; - struct flock lock; - } finodelk; - - struct { - fop_finodelk_cbk_t fn; - int32_t op_ret, op_errno; - } finodelk_cbk; - - /* entrylk */ - struct { - fop_entrylk_t fn; - loc_t loc; - const char *volume; - const char *name; - entrylk_cmd cmd; - entrylk_type type; - } entrylk; - - struct { - fop_entrylk_cbk_t fn; - int32_t op_ret, op_errno; - } entrylk_cbk; - - /* fentrylk */ - struct { - fop_fentrylk_t fn; - fd_t *fd; - const char *volume; - const char *name; - entrylk_cmd cmd; - entrylk_type type; - } fentrylk; - - struct { - fop_fentrylk_cbk_t fn; - int32_t op_ret, op_errno; - } fentrylk_cbk; - - /* readdir */ - struct { - fop_readdir_t fn; - fd_t *fd; - size_t size; - off_t off; - } readdir; - struct { - fop_readdir_cbk_t fn; - int32_t op_ret, op_errno; - gf_dirent_t entries; - } readdir_cbk; - - /* readdirp */ - struct { - fop_readdirp_t fn; - fd_t *fd; - size_t size; - off_t off; - } readdirp; - struct { - fop_readdirp_cbk_t fn; - int32_t op_ret, op_errno; - gf_dirent_t entries; - } readdirp_cbk; - - /* rchecksum */ - struct { - fop_rchecksum_t fn; - fd_t *fd; - off_t offset; - int32_t len; - } rchecksum; - struct { - fop_rchecksum_cbk_t fn; - int32_t op_ret, op_errno; - uint32_t weak_checksum; - uint8_t *strong_checksum; - } rchecksum_cbk; - - /* xattrop */ - struct { - fop_xattrop_t fn; - loc_t loc; - gf_xattrop_flags_t optype; - dict_t *xattr; - } xattrop; - struct { - fop_xattrop_cbk_t fn; - int32_t op_ret; - int32_t op_errno; - dict_t *xattr; - } xattrop_cbk; - - /* fxattrop */ - struct { - fop_fxattrop_t fn; - fd_t *fd; - gf_xattrop_flags_t optype; - dict_t *xattr; - } fxattrop; - struct { - fop_fxattrop_cbk_t fn; - int32_t op_ret; - int32_t op_errno; - dict_t *xattr; - } fxattrop_cbk; - - /* setattr */ - struct { - fop_setattr_t fn; - loc_t loc; - struct iatt stbuf; - int32_t valid; - } setattr; - struct { - fop_setattr_cbk_t fn; - int32_t op_ret; - int32_t op_errno; - struct iatt statpre; - struct iatt statpost; - } setattr_cbk; - - /* fsetattr */ - struct { - fop_fsetattr_t fn; - fd_t *fd; - struct iatt stbuf; - int32_t valid; - } fsetattr; - struct { - fop_fsetattr_cbk_t fn; - int32_t op_ret; - int32_t op_errno; - struct iatt statpre; - struct iatt statpost; - } fsetattr_cbk; - - } args; -} call_stub_t; - -call_stub_t * -fop_lookup_stub (call_frame_t *frame, - fop_lookup_t fn, - loc_t *loc, - dict_t *xattr_req); - -call_stub_t * -fop_lookup_cbk_stub (call_frame_t *frame, - fop_lookup_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - dict_t *dict, - struct iatt *postparent); -call_stub_t * -fop_stat_stub (call_frame_t *frame, - fop_stat_t fn, - loc_t *loc); -call_stub_t * -fop_stat_cbk_stub (call_frame_t *frame, - fop_stat_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *buf); -call_stub_t * -fop_fstat_stub (call_frame_t *frame, - fop_fstat_t fn, - fd_t *fd); -call_stub_t * -fop_fstat_cbk_stub (call_frame_t *frame, - fop_fstat_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *buf); - -call_stub_t * -fop_truncate_stub (call_frame_t *frame, - fop_truncate_t fn, - loc_t *loc, - off_t off); - -call_stub_t * -fop_truncate_cbk_stub (call_frame_t *frame, - fop_truncate_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *prebuf, - struct iatt *postbuf); - -call_stub_t * -fop_ftruncate_stub (call_frame_t *frame, - fop_ftruncate_t fn, - fd_t *fd, - off_t off); - -call_stub_t * -fop_ftruncate_cbk_stub (call_frame_t *frame, - fop_ftruncate_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *prebuf, - struct iatt *postbuf); - -call_stub_t * -fop_access_stub (call_frame_t *frame, - fop_access_t fn, - loc_t *loc, - int32_t mask); - -call_stub_t * -fop_access_cbk_stub (call_frame_t *frame, - fop_access_cbk_t fn, - int32_t op_ret, - int32_t op_errno); - -call_stub_t * -fop_readlink_stub (call_frame_t *frame, - fop_readlink_t fn, - loc_t *loc, - size_t size); - -call_stub_t * -fop_readlink_cbk_stub (call_frame_t *frame, - fop_readlink_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - const char *path, - struct iatt *buf); - -call_stub_t * -fop_mknod_stub (call_frame_t *frame, fop_mknod_t fn, - loc_t *loc, mode_t mode, dev_t rdev, dict_t *params); - -call_stub_t * -fop_mknod_cbk_stub (call_frame_t *frame, - fop_mknod_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent); - -call_stub_t * -fop_mkdir_stub (call_frame_t *frame, fop_mkdir_t fn, - loc_t *loc, mode_t mode, dict_t *params); - -call_stub_t * -fop_mkdir_cbk_stub (call_frame_t *frame, - fop_mkdir_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent); - -call_stub_t * -fop_unlink_stub (call_frame_t *frame, - fop_unlink_t fn, - loc_t *loc); - -call_stub_t * -fop_unlink_cbk_stub (call_frame_t *frame, - fop_unlink_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *preparent, - struct iatt *postparent); - -call_stub_t * -fop_rmdir_stub (call_frame_t *frame, - fop_rmdir_t fn, - loc_t *loc); - -call_stub_t * -fop_rmdir_cbk_stub (call_frame_t *frame, - fop_rmdir_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *preparent, - struct iatt *postparent); - -call_stub_t * -fop_symlink_stub (call_frame_t *frame, fop_symlink_t fn, - const char *linkname, loc_t *loc, dict_t *params); - -call_stub_t * -fop_symlink_cbk_stub (call_frame_t *frame, - fop_symlink_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent); - -call_stub_t * -fop_rename_stub (call_frame_t *frame, - fop_rename_t fn, - loc_t *oldloc, - loc_t *newloc); - -call_stub_t * -fop_rename_cbk_stub (call_frame_t *frame, - fop_rename_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *buf, - struct iatt *preoldparent, - struct iatt *postoldparent, - struct iatt *prenewparent, - struct iatt *postnewparent); - -call_stub_t * -fop_link_stub (call_frame_t *frame, - fop_link_t fn, - loc_t *oldloc, - loc_t *newloc); - -call_stub_t * -fop_link_cbk_stub (call_frame_t *frame, - fop_link_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent); - -call_stub_t * -fop_create_stub (call_frame_t *frame, fop_create_t fn, - loc_t *loc, int32_t flags, mode_t mode, - fd_t *fd, dict_t *params); - -call_stub_t * -fop_create_cbk_stub (call_frame_t *frame, - fop_create_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - fd_t *fd, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent); - -call_stub_t * -fop_open_stub (call_frame_t *frame, - fop_open_t fn, - loc_t *loc, - int32_t flags, - fd_t *fd, - int32_t wbflags); - -call_stub_t * -fop_open_cbk_stub (call_frame_t *frame, - fop_open_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - fd_t *fd); - -call_stub_t * -fop_readv_stub (call_frame_t *frame, - fop_readv_t fn, - fd_t *fd, - size_t size, - off_t off); - -call_stub_t * -fop_readv_cbk_stub (call_frame_t *frame, - fop_readv_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iovec *vector, - int32_t count, - struct iatt *stbuf, - struct iobref *iobref); - -call_stub_t * -fop_writev_stub (call_frame_t *frame, - fop_writev_t fn, - fd_t *fd, - struct iovec *vector, - int32_t count, - off_t off, - struct iobref *iobref); - -call_stub_t * -fop_writev_cbk_stub (call_frame_t *frame, - fop_writev_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *prebuf, - struct iatt *postbuf); - -call_stub_t * -fop_flush_stub (call_frame_t *frame, - fop_flush_t fn, - fd_t *fd); - -call_stub_t * -fop_flush_cbk_stub (call_frame_t *frame, - fop_flush_cbk_t fn, - int32_t op_ret, - int32_t op_errno); - -call_stub_t * -fop_fsync_stub (call_frame_t *frame, - fop_fsync_t fn, - fd_t *fd, - int32_t datasync); - -call_stub_t * -fop_fsync_cbk_stub (call_frame_t *frame, - fop_fsync_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *prebuf, - struct iatt *postbuf); - -call_stub_t * -fop_opendir_stub (call_frame_t *frame, - fop_opendir_t fn, - loc_t *loc, fd_t *fd); - -call_stub_t * -fop_opendir_cbk_stub (call_frame_t *frame, - fop_opendir_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - fd_t *fd); - -call_stub_t * -fop_fsyncdir_stub (call_frame_t *frame, - fop_fsyncdir_t fn, - fd_t *fd, - int32_t datasync); - -call_stub_t * -fop_fsyncdir_cbk_stub (call_frame_t *frame, - fop_fsyncdir_cbk_t fn, - int32_t op_ret, - int32_t op_errno); - -call_stub_t * -fop_statfs_stub (call_frame_t *frame, - fop_statfs_t fn, - loc_t *loc); - -call_stub_t * -fop_statfs_cbk_stub (call_frame_t *frame, - fop_statfs_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct statvfs *buf); - -call_stub_t * -fop_setxattr_stub (call_frame_t *frame, - fop_setxattr_t fn, - loc_t *loc, - dict_t *dict, - int32_t flags); - -call_stub_t * -fop_setxattr_cbk_stub (call_frame_t *frame, - fop_setxattr_cbk_t fn, - int32_t op_ret, - int32_t op_errno); - -call_stub_t * -fop_getxattr_stub (call_frame_t *frame, - fop_getxattr_t fn, - loc_t *loc, - const char *name); - -call_stub_t * -fop_getxattr_cbk_stub (call_frame_t *frame, - fop_getxattr_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - dict_t *value); - -call_stub_t * -fop_fsetxattr_stub (call_frame_t *frame, - fop_fsetxattr_t fn, - fd_t *fd, - dict_t *dict, - int32_t flags); - -call_stub_t * -fop_fsetxattr_cbk_stub (call_frame_t *frame, - fop_fsetxattr_cbk_t fn, - int32_t op_ret, - int32_t op_errno); - -call_stub_t * -fop_fgetxattr_stub (call_frame_t *frame, - fop_fgetxattr_t fn, - fd_t *fd, - const char *name); - -call_stub_t * -fop_fgetxattr_cbk_stub (call_frame_t *frame, - fop_fgetxattr_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - dict_t *value); - -call_stub_t * -fop_removexattr_stub (call_frame_t *frame, - fop_removexattr_t fn, - loc_t *loc, - const char *name); - -call_stub_t * -fop_removexattr_cbk_stub (call_frame_t *frame, - fop_removexattr_cbk_t fn, - int32_t op_ret, - int32_t op_errno); -call_stub_t * -fop_lk_stub (call_frame_t *frame, - fop_lk_t fn, - fd_t *fd, - int32_t cmd, - struct flock *lock); - -call_stub_t * -fop_lk_cbk_stub (call_frame_t *frame, - fop_lk_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct flock *lock); - -call_stub_t * -fop_inodelk_stub (call_frame_t *frame, fop_inodelk_t fn, - const char *volume, loc_t *loc, int32_t cmd, - struct flock *lock); - -call_stub_t * -fop_finodelk_stub (call_frame_t *frame, fop_finodelk_t fn, - const char *volume, fd_t *fd, int32_t cmd, - struct flock *lock); - -call_stub_t * -fop_entrylk_stub (call_frame_t *frame, fop_entrylk_t fn, - const char *volume, loc_t *loc, const char *basename, - entrylk_cmd cmd, entrylk_type type); - -call_stub_t * -fop_fentrylk_stub (call_frame_t *frame, fop_fentrylk_t fn, - const char *volume, fd_t *fd, const char *basename, - entrylk_cmd cmd, entrylk_type type); - -call_stub_t * -fop_inodelk_cbk_stub (call_frame_t *frame, fop_inodelk_cbk_t fn, - int32_t op_ret, int32_t op_errno); - -call_stub_t * -fop_finodelk_cbk_stub (call_frame_t *frame, fop_inodelk_cbk_t fn, - int32_t op_ret, int32_t op_errno); - -call_stub_t * -fop_entrylk_cbk_stub (call_frame_t *frame, fop_entrylk_cbk_t fn, - int32_t op_ret, int32_t op_errno); - -call_stub_t * -fop_fentrylk_cbk_stub (call_frame_t *frame, fop_entrylk_cbk_t fn, - int32_t op_ret, int32_t op_errno); - -call_stub_t * -fop_readdir_stub (call_frame_t *frame, - fop_readdir_t fn, - fd_t *fd, - size_t size, - off_t off); - -call_stub_t * -fop_readdirp_stub (call_frame_t *frame, - fop_readdir_t fn, - fd_t *fd, - size_t size, - off_t off); - -call_stub_t * -fop_readdirp_cbk_stub (call_frame_t *frame, - fop_readdir_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - gf_dirent_t *entries); - -call_stub_t * -fop_readdir_cbk_stub (call_frame_t *frame, - fop_readdir_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - gf_dirent_t *entries); - -call_stub_t * -fop_rchecksum_stub (call_frame_t *frame, - fop_rchecksum_t fn, - fd_t *fd, off_t offset, - int32_t len); - -call_stub_t * -fop_rchecksum_cbk_stub (call_frame_t *frame, - fop_rchecksum_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - uint32_t weak_checksum, - uint8_t *strong_checksum); - -call_stub_t * -fop_xattrop_stub (call_frame_t *frame, - fop_xattrop_t fn, - loc_t *loc, - gf_xattrop_flags_t optype, - dict_t *xattr); - -call_stub_t * -fop_xattrop_stub_cbk_stub (call_frame_t *frame, - fop_xattrop_cbk_t fn, - int32_t op_ret, - int32_t op_errno); - -call_stub_t * -fop_fxattrop_stub (call_frame_t *frame, - fop_fxattrop_t fn, - fd_t *fd, - gf_xattrop_flags_t optype, - dict_t *xattr); - -call_stub_t * -fop_fxattrop_stub_cbk_stub (call_frame_t *frame, - fop_xattrop_cbk_t fn, - int32_t op_ret, - int32_t op_errno); - -call_stub_t * -fop_setattr_stub (call_frame_t *frame, - fop_setattr_t fn, - loc_t *loc, - struct iatt *stbuf, - int32_t valid); - -call_stub_t * -fop_setattr_cbk_stub (call_frame_t *frame, - fop_setattr_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *statpre, - struct iatt *statpost); - -call_stub_t * -fop_fsetattr_stub (call_frame_t *frame, - fop_fsetattr_t fn, - fd_t *fd, - struct iatt *stbuf, - int32_t valid); - -call_stub_t * -fop_fsetattr_cbk_stub (call_frame_t *frame, - fop_setattr_cbk_t fn, - int32_t op_ret, - int32_t op_errno, - struct iatt *statpre, - struct iatt *statpost); - -void call_resume (call_stub_t *stub); -void call_stub_destroy (call_stub_t *stub); -#endif diff --git a/libglusterfs/src/changelog.h b/libglusterfs/src/changelog.h new file mode 100644 index 00000000000..a09d9f25287 --- /dev/null +++ b/libglusterfs/src/changelog.h @@ -0,0 +1,115 @@ +/* + 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 _GF_CHANGELOG_H +#define _GF_CHANGELOG_H + +struct gf_brick_spec; + +/** + * Max bit shiter for event selection + */ +#define CHANGELOG_EV_SELECTION_RANGE 5 + +#define CHANGELOG_OP_TYPE_JOURNAL (1 << 0) +#define CHANGELOG_OP_TYPE_OPEN (1 << 1) +#define CHANGELOG_OP_TYPE_CREATE (1 << 2) +#define CHANGELOG_OP_TYPE_RELEASE (1 << 3) +#define CHANGELOG_OP_TYPE_BR_RELEASE \ + (1 << 4) /* logical release (last close()), \ + sent by bitrot stub */ +#define CHANGELOG_OP_TYPE_MAX (1 << CHANGELOG_EV_SELECTION_RANGE) + +struct ev_open { + unsigned char gfid[16]; + int32_t flags; +}; + +struct ev_creat { + unsigned char gfid[16]; + int32_t flags; +}; + +struct ev_release { + unsigned char gfid[16]; +}; + +struct ev_release_br { + unsigned long version; + unsigned char gfid[16]; + int32_t sign_info; +}; + +struct ev_changelog { + char path[PATH_MAX]; +}; + +typedef struct changelog_event { + unsigned int ev_type; + + union { + struct ev_open open; + struct ev_creat create; + struct ev_release release; + struct ev_changelog journal; + struct ev_release_br releasebr; + } u; +} changelog_event_t; + +#define CHANGELOG_EV_SIZE (sizeof(changelog_event_t)) + +/** + * event callback, connected & disconnection defs + */ +typedef void(CALLBACK)(void *, char *, void *, changelog_event_t *); +typedef void *(INIT)(void *, struct gf_brick_spec *); +typedef void(FINI)(void *, char *, void *); +typedef void(CONNECT)(void *, char *, void *); +typedef void(DISCONNECT)(void *, char *, void *); + +struct gf_brick_spec { + char *brick_path; + unsigned int filter; + + INIT *init; + FINI *fini; + CALLBACK *callback; + CONNECT *connected; + DISCONNECT *disconnected; + + void *ptr; +}; + +/* API set */ + +int +gf_changelog_register(char *brick_path, char *scratch_dir, char *log_file, + int log_levl, int max_reconnects); +ssize_t +gf_changelog_scan(); + +int +gf_changelog_start_fresh(); + +ssize_t +gf_changelog_next_change(char *bufptr, size_t maxlen); + +int +gf_changelog_done(char *file); + +/* newer flexible API */ +int +gf_changelog_init(void *xl); + +int +gf_changelog_register_generic(struct gf_brick_spec *bricks, int count, + int ordered, char *logfile, int lvl, void *xl); + +#endif diff --git a/libglusterfs/src/checksum.c b/libglusterfs/src/checksum.c index 000ab8d93a2..acdaed04ae2 100644 --- a/libglusterfs/src/checksum.c +++ b/libglusterfs/src/checksum.c @@ -1,78 +1,44 @@ /* - Copyright (c) 2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 <inttypes.h> - -#include "glusterfs.h" -#include "md5.h" -#include "checksum.h" - +#include <openssl/md5.h> +#include <openssl/sha.h> +#include <zlib.h> +#include <stdint.h> +#include <string.h> /* - * The "weak" checksum required for the rsync algorithm, - * adapted from the rsync source code. The following comment - * appears there: + * The "weak" checksum required for the rsync algorithm. * - * "a simple 32 bit checksum that can be upadted from either end - * (inspired by Mark Adler's Adler-32 checksum)" + * Note: these functions are only called to compute checksums on + * pathnames; they don't need to handle arbitrarily long strings of + * data. Thus int32_t and uint32_t are sufficient */ - uint32_t -gf_rsync_weak_checksum (char *buf1, int32_t len) +gf_rsync_weak_checksum(unsigned char *buf, size_t len) { - int32_t i; - uint32_t s1, s2; - - signed char *buf = (signed char *) buf1; - uint32_t csum; - - s1 = s2 = 0; - for (i = 0; i < (len-4); i+=4) { - s2 += 4*(s1 + buf[i]) + 3*buf[i+1] + 2*buf[i+2] + buf[i+3]; - - s1 += buf[i+0] + buf[i+1] + buf[i+2] + buf[i+3]; - } - - for (; i < len; i++) { - s1 += buf[i]; - s2 += s1; - } - - csum = (s1 & 0xffff) + (s2 << 16); - - return csum; + return adler32(0, buf, len); } - /* - * The "strong" checksum required for the rsync algorithm, - * adapted from the rsync source code. + * The "strong" checksum required for the rsync algorithm. */ - void -gf_rsync_strong_checksum (char *buf, int32_t len, uint8_t *sum) +gf_rsync_strong_checksum(unsigned char *data, size_t len, + unsigned char *sha256_md) { - md_context m; - - md5_begin (&m); - md5_update (&m, (unsigned char *) buf, len); - md5_result (&m, (unsigned char *) sum); + SHA256((const unsigned char *)data, len, sha256_md); +} - return; +void +gf_rsync_md5_checksum(unsigned char *data, size_t len, unsigned char *md5) +{ + MD5(data, len, md5); } diff --git a/libglusterfs/src/checksum.h b/libglusterfs/src/checksum.h deleted file mode 100644 index 36a114cc217..00000000000 --- a/libglusterfs/src/checksum.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - Copyright (c) 2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef __CHECKSUM_H__ -#define __CHECKSUM_H__ - -uint32_t -gf_rsync_weak_checksum (char *buf, int32_t len); - -void -gf_rsync_strong_checksum (char *buf, int32_t len, uint8_t *sum); - -#endif /* __CHECKSUM_H__ */ diff --git a/libglusterfs/src/circ-buff.c b/libglusterfs/src/circ-buff.c new file mode 100644 index 00000000000..913115c7be1 --- /dev/null +++ b/libglusterfs/src/circ-buff.c @@ -0,0 +1,193 @@ +/* + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include "glusterfs/circ-buff.h" +#include "glusterfs/libglusterfs-messages.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) +{ + circular_buffer_t *ptr = NULL; + int ret = -1; + // DO we really need the assert here? + GF_ASSERT(buffer->used_len <= buffer->size_buffer); + + if (buffer->use_once == _gf_true && + buffer->used_len == buffer->size_buffer) { + gf_msg("circ-buff", GF_LOG_WARNING, 0, LG_MSG_BUFFER_ERROR, + "buffer %p is use once buffer", buffer); + return -1; + } else { + if (buffer->used_len == buffer->size_buffer) { + if (buffer->cb[buffer->w_index]) { + ptr = buffer->cb[buffer->w_index]; + if (ptr->data) { + cb_destroy_data(ptr, buffer->destroy_buffer_data); + ptr->data = NULL; + GF_FREE(ptr); + } + buffer->cb[buffer->w_index] = NULL; + ptr = NULL; + } + } + + buffer->cb[buffer->w_index] = GF_CALLOC(1, sizeof(circular_buffer_t), + gf_common_mt_circular_buffer_t); + if (!buffer->cb[buffer->w_index]) + return -1; + + buffer->cb[buffer->w_index]->data = item; + ret = gettimeofday(&buffer->cb[buffer->w_index]->tv, NULL); + if (ret == -1) + gf_msg_callingfn("circ-buff", GF_LOG_WARNING, 0, + LG_MSG_GETTIMEOFDAY_FAILED, + "getting time of the day failed"); + buffer->w_index++; + buffer->w_index %= buffer->size_buffer; + // used_buffer size cannot be greater than the total buffer size + + if (buffer->used_len < buffer->size_buffer) + buffer->used_len++; + return buffer->w_index; + } +} + +int +cb_add_entry_buffer(buffer_t *buffer, void *item) +{ + int write_index = -1; + + pthread_mutex_lock(&buffer->lock); + { + write_index = __cb_add_entry_buffer(buffer, item); + } + pthread_mutex_unlock(&buffer->lock); + + return write_index; +} + +void +cb_buffer_show(buffer_t *buffer) +{ + pthread_mutex_lock(&buffer->lock); + { + gf_msg_debug("circ-buff", 0, + "w_index: %d, size: %" GF_PRI_SIZET " used_buffer: %d", + buffer->w_index, buffer->size_buffer, buffer->used_len); + } + pthread_mutex_unlock(&buffer->lock); +} + +void +cb_buffer_dump(buffer_t *buffer, void *data, + int(fn)(circular_buffer_t *buffer, void *data)) +{ + 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) { + 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); + else + gf_msg_callingfn("circ-buff", GF_LOG_WARNING, 0, + LG_MSG_NULL_PTR, + "Null entry in " + "circular buffer at " + "index %d.", + index); + + index++; + index %= buffer->size_buffer; + } + } else { + for (i = 0; i < buffer->used_len; i++) { + entry = buffer->cb[i]; + fn(entry, data); + } + } + } + pthread_mutex_unlock(&buffer->lock); +} + +buffer_t * +cb_buffer_new(size_t buffer_size, gf_boolean_t use_once, + void (*destroy_buffer_data)(void *data)) +{ + buffer_t *buffer = NULL; + + buffer = GF_CALLOC(1, sizeof(*buffer), gf_common_mt_buffer_t); + if (!buffer) { + goto out; + } + + buffer->cb = GF_CALLOC(buffer_size, sizeof(circular_buffer_t *), + gf_common_mt_circular_buffer_t); + if (!buffer->cb) { + GF_FREE(buffer); + buffer = NULL; + goto out; + } + + buffer->w_index = 0; + 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: + return buffer; +} + +void +cb_buffer_destroy(buffer_t *buffer) +{ + int i = 0; + circular_buffer_t *ptr = NULL; + if (buffer) { + if (buffer->cb) { + for (i = 0; i < buffer->used_len; 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); + } + pthread_mutex_destroy(&buffer->lock); + GF_FREE(buffer); + } +} diff --git a/libglusterfs/src/client_t.c b/libglusterfs/src/client_t.c new file mode 100644 index 00000000000..9d377c3c2e1 --- /dev/null +++ b/libglusterfs/src/client_t.c @@ -0,0 +1,825 @@ +/* + 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/glusterfs.h" +#include "glusterfs/dict.h" +#include "glusterfs/statedump.h" +#include "glusterfs/client_t.h" +#include "glusterfs/list.h" +#include "glusterfs/libglusterfs-messages.h" + +static int +gf_client_chain_client_entries(cliententry_t *entries, uint32_t startidx, + uint32_t endcount) +{ + uint32_t i = 0; + + if (!entries) { + gf_msg_callingfn("client_t", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "!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 up to 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 <= clienttable->max_clients) { + gf_msg_callingfn("client_t", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + ret = EINVAL; + goto out; + } + + oldclients = clienttable->cliententries; + oldmax_clients = clienttable->max_clients; + + clienttable->cliententries = GF_CALLOC(nr, sizeof(cliententry_t), + gf_common_mt_cliententry_t); + if (!clienttable->cliententries) { + clienttable->cliententries = oldclients; + ret = 0; + 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; + int result = 0; + + clienttable = GF_CALLOC(1, sizeof(clienttable_t), + gf_common_mt_clienttable_t); + if (!clienttable) + return NULL; + + LOCK_INIT(&clienttable->lock); + + result = gf_client_clienttable_expand(clienttable, + GF_CLIENTTABLE_INITIAL_SIZE); + if (result != 0) { + gf_msg("client_t", GF_LOG_ERROR, 0, LG_MSG_EXPAND_CLIENT_TABLE_FAILED, + "gf_client_clienttable_expand failed"); + GF_FREE(clienttable); + return NULL; + } + + return clienttable; +} + +/* + * Increments ref.bind if the client is already present or creates a new + * client with ref.bind = 1,ref.count = 1 it signifies that + * as long as ref.bind is > 0 client should be alive. + */ +client_t * +gf_client_get(xlator_t *this, client_auth_data_t *cred, char *client_uid, + char *subdir_mount) +{ + client_t *client = NULL; + cliententry_t *cliententry = NULL; + clienttable_t *clienttable = NULL; + unsigned int i = 0; + + if (this == NULL || client_uid == NULL) { + gf_msg_callingfn("client_t", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + errno = EINVAL; + return NULL; + } + + 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 && (cred->flavour == client->auth.flavour && + (size_t)cred->datalen == client->auth.len && + memcmp(cred->authdata, client->auth.data, + client->auth.len) == 0))) { + GF_ATOMIC_INC(client->bind); + goto unlock; + } + } + + client = GF_CALLOC(1, sizeof(client_t), gf_common_mt_client_t); + if (client == NULL) { + errno = ENOMEM; + goto unlock; + } + + client->this = this; + if (subdir_mount != NULL) + client->subdir_mount = gf_strdup(subdir_mount); + + LOCK_INIT(&client->scratch_ctx.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; + } + + GF_ATOMIC_INIT(client->bind, 1); + GF_ATOMIC_INIT(client->count, 1); + GF_ATOMIC_INIT(client->fd_cnt, 0); + + client->auth.flavour = cred->flavour; + if (cred->flavour) { + client->auth.data = GF_MALLOC(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[clienttable->first_free]; + if (cliententry->next_free == GF_CLIENTTABLE_END) { + int result = gf_client_clienttable_expand( + clienttable, + clienttable->max_clients + GF_CLIENTTABLE_INITIAL_SIZE); + if (result != 0) { + GF_FREE(client->scratch_ctx.ctx); + GF_FREE(client->client_uid); + GF_FREE(client); + client = NULL; + errno = result; + goto unlock; + } + cliententry = &clienttable->cliententries[client->tbl_index]; + cliententry->next_free = clienttable->first_free; + } + cliententry->client = client; + clienttable->first_free = cliententry->next_free; + cliententry->next_free = GF_CLIENTENTRY_ALLOCATED; + } +unlock: + UNLOCK(&clienttable->lock); + + if (client) + gf_msg_callingfn("client_t", GF_LOG_DEBUG, 0, LG_MSG_BIND_REF, + "%s: bind_ref: %" GF_PRI_ATOMIC + ", ref: " + "%" GF_PRI_ATOMIC, + client->client_uid, GF_ATOMIC_GET(client->bind), + GF_ATOMIC_GET(client->count)); + return client; +} + +void +gf_client_put(client_t *client, gf_boolean_t *detached) +{ + gf_boolean_t unref = _gf_false; + int bind_ref; + + if (client == NULL) + goto out; + + if (detached) + *detached = _gf_false; + + bind_ref = GF_ATOMIC_DEC(client->bind); + if (bind_ref == 0) + unref = _gf_true; + + gf_msg_callingfn("client_t", GF_LOG_DEBUG, 0, LG_MSG_BIND_REF, + "%s: " + "bind_ref: %" GF_PRI_ATOMIC ", ref: %" GF_PRI_ATOMIC + ", " + "unref: %d", + client->client_uid, GF_ATOMIC_GET(client->bind), + GF_ATOMIC_GET(client->count), unref); + if (unref) { + if (detached) + *detached = _gf_true; + gf_client_unref(client); + } + +out: + return; +} + +client_t * +gf_client_ref(client_t *client) +{ + if (!client) { + gf_msg_callingfn("client_t", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "null client"); + return NULL; + } + + GF_ATOMIC_INC(client->count); + gf_msg_callingfn("client_t", GF_LOG_DEBUG, 0, LG_MSG_REF_COUNT, + "%s: " + "ref-count %" GF_PRI_ATOMIC, + client->client_uid, GF_ATOMIC_GET(client->count)); + return client; +} + +static void +gf_client_destroy_recursive(xlator_t *xl, client_t *client) +{ + xlator_list_t *trav; + + if (!xl->call_cleanup && xl->cbks->client_destroy) { + xl->cbks->client_destroy(xl, client); + } + + for (trav = xl->children; trav; trav = trav->next) { + gf_client_destroy_recursive(trav->xlator, client); + } +} + +static void +client_destroy(client_t *client) +{ + clienttable_t *clienttable = NULL; + glusterfs_graph_t *gtrav = NULL; + + if (client == NULL) { + gf_msg_callingfn("xlator", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + goto out; + } + + clienttable = client->this->ctx->clienttable; + + 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) + { + gf_client_destroy_recursive(gtrav->top, client); + } + + if (client->subdir_inode) + inode_unref(client->subdir_inode); + + LOCK_DESTROY(&client->scratch_ctx.lock); + + GF_FREE(client->auth.data); + GF_FREE(client->auth.username); + GF_FREE(client->auth.passwd); + GF_FREE(client->scratch_ctx.ctx); + GF_FREE(client->client_uid); + GF_FREE(client->subdir_mount); + GF_FREE(client->client_name); + GF_FREE(client); +out: + return; +} + +static int +gf_client_disconnect_recursive(xlator_t *xl, client_t *client) +{ + int ret = 0; + xlator_list_t *trav; + + if (!xl->call_cleanup && xl->cbks->client_disconnect) { + ret = xl->cbks->client_disconnect(xl, client); + } + + for (trav = xl->children; trav; trav = trav->next) { + ret |= gf_client_disconnect_recursive(trav->xlator, client); + } + + return ret; +} + +int +gf_client_disconnect(client_t *client) +{ + int ret = 0; + glusterfs_graph_t *gtrav = NULL; + + list_for_each_entry(gtrav, &client->this->ctx->graphs, list) + { + ret |= gf_client_disconnect_recursive(gtrav->top, client); + } + + return ret; +} + +void +gf_client_unref(client_t *client) +{ + uint64_t refcount; + + if (!client) { + gf_msg_callingfn("client_t", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "client is NULL"); + return; + } + + refcount = GF_ATOMIC_DEC(client->count); + gf_msg_callingfn("client_t", GF_LOG_DEBUG, 0, LG_MSG_REF_COUNT, + "%s: " + "ref-count %" GF_PRI_ATOMIC, + client->client_uid, refcount); + if (refcount == 0) { + gf_msg(THIS->name, GF_LOG_INFO, 0, LG_MSG_DISCONNECT_CLIENT, + "Shutting down connection %s", client->client_uid); + client_destroy(client); + } +} + +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; +} + +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; + /* don't 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; +} + +/*will return success with old value if exist*/ +void * +client_ctx_set(client_t *client, void *key, void *value) +{ + int ret = 0; + void *ret_value = NULL; + + if (!client || !key || !value) + return NULL; + + LOCK(&client->scratch_ctx.lock); + { + ret = __client_ctx_get_int(client, key, &ret_value); + if (!ret && ret_value) { + UNLOCK(&client->scratch_ctx.lock); + return ret_value; + } + + ret = __client_ctx_set_int(client, key, value); + } + UNLOCK(&client->scratch_ctx.lock); + + if (ret) + return NULL; + return value; +} + +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_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_msg("client_t", GF_LOG_WARNING, 0, LG_MSG_LOCK_FAILED, + "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; + if (client->bound_xl && + !strcmp(client->bound_xl->name, this->name)) { + 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_msg("client_t", GF_LOG_WARNING, 0, LG_MSG_LOCK_FAILED, + "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; + if (client->client_uid) { + gf_proc_dump_build_key(key, "conn", "%d.id", count); + gf_proc_dump_write(key, "%s", client->client_uid); + } + + if (client->subdir_mount) { + gf_proc_dump_build_key(key, "conn", "%d.subdir", count); + gf_proc_dump_write(key, "%s", client->subdir_mount); + } + gf_proc_dump_build_key(key, "conn", "%d.ref", count); + gf_proc_dump_write(key, "%" GF_PRI_ATOMIC, + GF_ATOMIC_GET(client->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 = LOCK(&clienttable->lock); + { + if (ret) { + gf_msg("client_t", GF_LOG_WARNING, 0, LG_MSG_LOCK_FAILED, + "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; + if (!strcmp(client->bound_xl->name, this->name)) { + 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; + + 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 = 0; + 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_msg("client_t", GF_LOG_WARNING, 0, LG_MSG_LOCK_FAILED, + "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; + 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/cluster-syncop.c b/libglusterfs/src/cluster-syncop.c new file mode 100644 index 00000000000..6ee89ddfdcf --- /dev/null +++ b/libglusterfs/src/cluster-syncop.c @@ -0,0 +1,1261 @@ +/* + Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +/* Perform fop on all subvolumes represented by list[] array and wait + for all callbacks to return */ + +/* NOTE: Cluster-syncop, like syncop blocks the executing thread until the + * responses are gathered if it is not executed as part of synctask. So it + * shouldn't be invoked in epoll worker thread */ +#include "glusterfs/cluster-syncop.h" +#include "glusterfs/defaults.h" + +#define FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, fop, \ + args...) \ + do { \ + int __i = 0; \ + int __count = 0; \ + cluster_local_t __local = { \ + 0, \ + }; \ + void *__old_local = frame->local; \ + \ + __local.replies = replies; \ + memset(output, 0, numsubvols); \ + cluster_replies_wipe(replies, numsubvols); \ + for (__i = 0; __i < numsubvols; __i++) \ + INIT_LIST_HEAD(&replies[__i].entries.list); \ + if (syncbarrier_init(&__local.barrier)) \ + break; \ + frame->local = &__local; \ + for (__i = 0; __i < numsubvols; __i++) { \ + if (on[__i]) { \ + __count++; \ + } \ + } \ + __local.barrier.waitfor = __count; \ + for (__i = 0; __i < numsubvols; __i++) { \ + if (!on[__i]) \ + continue; \ + STACK_WIND_COOKIE(frame, cluster_##fop##_cbk, (void *)(long)__i, \ + subvols[__i], subvols[__i]->fops->fop, args); \ + } \ + syncbarrier_wait(&__local.barrier, __count); \ + syncbarrier_destroy(&__local.barrier); \ + frame->local = __old_local; \ + STACK_RESET(frame->root); \ + } while (0) + +#define FOP_SEQ(subvols, on, numsubvols, replies, output, frame, fop, args...) \ + do { \ + int __i = 0; \ + \ + cluster_local_t __local = { \ + 0, \ + }; \ + void *__old_local = frame->local; \ + __local.replies = replies; \ + memset(output, 0, numsubvols); \ + cluster_replies_wipe(replies, numsubvols); \ + for (__i = 0; __i < numsubvols; __i++) \ + INIT_LIST_HEAD(&replies[__i].entries.list); \ + if (syncbarrier_init(&__local.barrier)) \ + break; \ + frame->local = &__local; \ + for (__i = 0; __i < numsubvols; __i++) { \ + if (!on[__i]) \ + continue; \ + STACK_WIND_COOKIE(frame, cluster_##fop##_cbk, (void *)(long)__i, \ + subvols[__i], subvols[__i]->fops->fop, args); \ + syncbarrier_wait(&__local.barrier, 1); \ + } \ + syncbarrier_destroy(&__local.barrier); \ + frame->local = __old_local; \ + STACK_RESET(frame->root); \ + } while (0) + +#define FOP_CBK(fop, frame, cookie, args...) \ + do { \ + cluster_local_t *__local = frame->local; \ + int __i = (long)cookie; \ + args_##fop##_cbk_store(&__local->replies[__i], args); \ + __local->replies[__i].valid = 1; \ + syncbarrier_wake(&__local->barrier); \ + } while (0) + +int32_t +cluster_fop_success_fill(default_args_cbk_t *replies, int numsubvols, + unsigned char *success) +{ + int i = 0; + int count = 0; + + for (i = 0; i < numsubvols; i++) { + if (replies[i].valid && replies[i].op_ret >= 0) { + success[i] = 1; + count++; + } else { + success[i] = 0; + } + } + + return count; +} + +void +cluster_replies_wipe(default_args_cbk_t *replies, int numsubvols) +{ + int i = 0; + + if (!replies) + return; + + for (i = 0; i < numsubvols; i++) + args_cbk_wipe(&replies[i]); + memset(replies, 0, numsubvols * sizeof(*replies)); +} + +int32_t +cluster_lookup_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, dict_t *xdata, struct iatt *postparent) +{ + FOP_CBK(lookup, frame, cookie, op_ret, op_errno, inode, buf, xdata, + postparent); + return 0; +} + +int32_t +cluster_stat_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *buf, + dict_t *xdata) +{ + FOP_CBK(stat, frame, cookie, op_ret, op_errno, buf, xdata); + return 0; +} + +int32_t +cluster_truncate_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +{ + FOP_CBK(truncate, frame, cookie, op_ret, op_errno, prebuf, postbuf, xdata); + return 0; +} + +int32_t +cluster_ftruncate_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +{ + FOP_CBK(ftruncate, frame, cookie, op_ret, op_errno, prebuf, postbuf, xdata); + return 0; +} + +int32_t +cluster_access_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + FOP_CBK(access, frame, cookie, op_ret, op_errno, xdata); + return 0; +} + +int32_t +cluster_readlink_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, const char *path, + struct iatt *buf, dict_t *xdata) +{ + FOP_CBK(readlink, frame, cookie, op_ret, op_errno, path, buf, xdata); + return 0; +} + +int32_t +cluster_mknod_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + FOP_CBK(mknod, frame, cookie, op_ret, op_errno, inode, buf, preparent, + postparent, xdata); + return 0; +} + +int32_t +cluster_mkdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + FOP_CBK(mkdir, frame, cookie, op_ret, op_errno, inode, buf, preparent, + postparent, xdata); + return 0; +} + +int32_t +cluster_unlink_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + FOP_CBK(unlink, frame, cookie, op_ret, op_errno, preparent, postparent, + xdata); + return 0; +} + +int32_t +cluster_rmdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + FOP_CBK(rmdir, frame, cookie, op_ret, op_errno, preparent, postparent, + xdata); + return 0; +} + +int32_t +cluster_symlink_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + FOP_CBK(symlink, frame, cookie, op_ret, op_errno, inode, buf, preparent, + postparent, xdata); + return 0; +} + +int32_t +cluster_rename_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *buf, + struct iatt *preoldparent, struct iatt *postoldparent, + struct iatt *prenewparent, struct iatt *postnewparent, + dict_t *xdata) +{ + FOP_CBK(rename, frame, cookie, op_ret, op_errno, buf, preoldparent, + postoldparent, prenewparent, postnewparent, xdata); + return 0; +} + +int32_t +cluster_link_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + FOP_CBK(link, frame, cookie, op_ret, op_errno, inode, buf, preparent, + postparent, xdata); + return 0; +} + +int32_t +cluster_create_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + FOP_CBK(create, frame, cookie, op_ret, op_errno, fd, inode, buf, preparent, + postparent, xdata); + return 0; +} + +int32_t +cluster_open_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd, dict_t *xdata) +{ + FOP_CBK(open, frame, cookie, op_ret, op_errno, fd, xdata); + return 0; +} + +int32_t +cluster_readv_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iovec *vector, + int32_t count, struct iatt *stbuf, struct iobref *iobref, + dict_t *xdata) +{ + FOP_CBK(readv, frame, cookie, op_ret, op_errno, vector, count, stbuf, + iobref, xdata); + return 0; +} + +int32_t +cluster_writev_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +{ + FOP_CBK(writev, frame, cookie, op_ret, op_errno, prebuf, postbuf, xdata); + return 0; +} + +int32_t +cluster_put_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + FOP_CBK(put, frame, cookie, op_ret, op_errno, inode, buf, preparent, + postparent, xdata); + return 0; +} + +int32_t +cluster_flush_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + FOP_CBK(flush, frame, cookie, op_ret, op_errno, xdata); + return 0; +} + +int32_t +cluster_fsync_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +{ + FOP_CBK(fsync, frame, cookie, op_ret, op_errno, prebuf, postbuf, xdata); + return 0; +} + +int32_t +cluster_fstat_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *buf, + dict_t *xdata) +{ + FOP_CBK(fstat, frame, cookie, op_ret, op_errno, buf, xdata); + return 0; +} + +int32_t +cluster_opendir_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd, dict_t *xdata) +{ + FOP_CBK(opendir, frame, cookie, op_ret, op_errno, fd, xdata); + return 0; +} + +int32_t +cluster_fsyncdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + FOP_CBK(fsyncdir, frame, cookie, op_ret, op_errno, xdata); + return 0; +} + +int32_t +cluster_statfs_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct statvfs *buf, + dict_t *xdata) +{ + FOP_CBK(statfs, frame, cookie, op_ret, op_errno, buf, xdata); + return 0; +} + +int32_t +cluster_setxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + FOP_CBK(setxattr, frame, cookie, op_ret, op_errno, xdata); + return 0; +} + +int32_t +cluster_fsetxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + FOP_CBK(fsetxattr, frame, cookie, op_ret, op_errno, xdata); + return 0; +} + +int32_t +cluster_fgetxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata) +{ + FOP_CBK(fgetxattr, frame, cookie, op_ret, op_errno, dict, xdata); + return 0; +} + +int32_t +cluster_getxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata) +{ + FOP_CBK(getxattr, frame, cookie, op_ret, op_errno, dict, xdata); + return 0; +} + +int32_t +cluster_xattrop_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata) +{ + FOP_CBK(xattrop, frame, cookie, op_ret, op_errno, dict, xdata); + return 0; +} + +int32_t +cluster_fxattrop_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata) +{ + FOP_CBK(fxattrop, frame, cookie, op_ret, op_errno, dict, xdata); + return 0; +} + +int32_t +cluster_removexattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + FOP_CBK(removexattr, frame, cookie, op_ret, op_errno, xdata); + return 0; +} + +int32_t +cluster_fremovexattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + FOP_CBK(fremovexattr, frame, cookie, op_ret, op_errno, xdata); + return 0; +} + +int32_t +cluster_lk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct gf_flock *lock, + dict_t *xdata) +{ + FOP_CBK(lk, frame, cookie, op_ret, op_errno, lock, xdata); + return 0; +} + +int32_t +cluster_inodelk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + FOP_CBK(inodelk, frame, cookie, op_ret, op_errno, xdata); + return 0; +} + +int32_t +cluster_finodelk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + FOP_CBK(finodelk, frame, cookie, op_ret, op_errno, xdata); + return 0; +} + +int32_t +cluster_entrylk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + FOP_CBK(entrylk, frame, cookie, op_ret, op_errno, xdata); + return 0; +} + +int32_t +cluster_fentrylk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + FOP_CBK(fentrylk, frame, cookie, op_ret, op_errno, xdata); + return 0; +} + +int32_t +cluster_rchecksum_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, uint32_t weak_checksum, + uint8_t *strong_checksum, dict_t *xdata) +{ + FOP_CBK(rchecksum, frame, cookie, op_ret, op_errno, weak_checksum, + strong_checksum, xdata); + return 0; +} + +int32_t +cluster_readdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, gf_dirent_t *entries, + dict_t *xdata) +{ + FOP_CBK(readdir, frame, cookie, op_ret, op_errno, entries, xdata); + return 0; +} + +int32_t +cluster_readdirp_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, gf_dirent_t *entries, + dict_t *xdata) +{ + FOP_CBK(readdirp, frame, cookie, op_ret, op_errno, entries, xdata); + return 0; +} + +int32_t +cluster_setattr_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) +{ + FOP_CBK(setattr, frame, cookie, op_ret, op_errno, statpre, statpost, xdata); + return 0; +} + +int32_t +cluster_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) +{ + FOP_CBK(fsetattr, frame, cookie, op_ret, op_errno, statpre, statpost, + xdata); + return 0; +} + +int32_t +cluster_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) +{ + FOP_CBK(fallocate, frame, cookie, op_ret, op_errno, pre, post, xdata); + return 0; +} + +int32_t +cluster_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) +{ + FOP_CBK(discard, frame, cookie, op_ret, op_errno, pre, post, xdata); + return 0; +} + +int32_t +cluster_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) +{ + FOP_CBK(zerofill, frame, cookie, op_ret, op_errno, pre, post, xdata); + return 0; +} + +int32_t +cluster_ipc_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + FOP_CBK(ipc, frame, cookie, op_ret, op_errno, xdata); + return 0; +} + +int32_t +cluster_fgetxattr(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, + const char *name, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, fgetxattr, fd, + name, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_fsetxattr(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *dict, + int32_t flags, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, fsetxattr, fd, + dict, flags, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_setxattr(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, + int32_t flags, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, setxattr, loc, + dict, flags, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_statfs(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, statfs, loc, + xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_fsyncdir(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags, + dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, fsyncdir, fd, + flags, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_opendir(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, fd_t *fd, + dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, opendir, loc, + fd, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_fstat(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, fstat, fd, + xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_fsync(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t flags, + dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, fsync, fd, + flags, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_flush(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, flush, fd, + xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_writev(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, + struct iovec *vector, int32_t count, off_t off, uint32_t flags, + struct iobref *iobref, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, writev, fd, + vector, count, off, flags, iobref, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_put(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, + mode_t umask, uint32_t flags, struct iovec *vector, int32_t count, + off_t offset, struct iobref *iobref, dict_t *xattr, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, put, loc, mode, + umask, flags, vector, count, offset, iobref, xattr, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_readv(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, + off_t offset, uint32_t flags, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, readv, fd, size, + offset, flags, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_open(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + fd_t *fd, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, open, loc, + flags, fd, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_create(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + mode_t mode, mode_t umask, fd_t *fd, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, create, loc, + flags, mode, umask, fd, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_link(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, + dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, link, oldloc, + newloc, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_rename(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *oldloc, + loc_t *newloc, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, rename, oldloc, + newloc, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int +cluster_symlink(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, const char *linkpath, + loc_t *loc, mode_t umask, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, symlink, + linkpath, loc, umask, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_rmdir(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, int flags, + dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, rmdir, loc, + flags, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_unlink(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag, + dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, unlink, loc, + xflag, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int +cluster_mkdir(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, + mode_t umask, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, mkdir, loc, + mode, umask, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int +cluster_mknod(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, + dev_t rdev, mode_t umask, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, mknod, loc, + mode, rdev, umask, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_readlink(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, size_t size, + dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, readlink, loc, + size, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_access(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t mask, + dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, access, loc, + mask, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_ftruncate(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, + dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, ftruncate, fd, + offset, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_getxattr(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, + const char *name, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, getxattr, loc, + name, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_xattrop(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, + gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, xattrop, loc, + flags, dict, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_fxattrop(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, + gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, fxattrop, fd, + flags, dict, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_removexattr(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, + const char *name, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, removexattr, + loc, name, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_fremovexattr(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, + const char *name, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, fremovexattr, + fd, name, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_lk(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t cmd, + struct gf_flock *lock, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, lk, fd, cmd, + lock, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_rchecksum(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, + int32_t len, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, rchecksum, fd, + offset, len, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_readdir(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, + off_t off, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, readdir, fd, + size, off, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_readdirp(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, + off_t off, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, readdirp, fd, + size, off, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_setattr(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, + struct iatt *stbuf, int32_t valid, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, setattr, loc, + stbuf, valid, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_truncate(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, off_t offset, + dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, truncate, loc, + offset, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_stat(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, stat, loc, + xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_lookup(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, lookup, loc, + xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_fsetattr(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, + struct iatt *stbuf, int32_t valid, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, fsetattr, fd, + stbuf, valid, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_fallocate(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, + int32_t keep_size, off_t offset, size_t len, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, fallocate, fd, + keep_size, offset, len, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_discard(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, + size_t len, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, discard, fd, + offset, len, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_zerofill(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, + off_t len, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, zerofill, fd, + offset, len, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int32_t +cluster_ipc(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, int32_t op, dict_t *xdata) +{ + FOP_ONLIST(subvols, on, numsubvols, replies, output, frame, ipc, op, xdata); + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int +cluster_uninodelk(xlator_t **subvols, unsigned char *locked_on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, char *dom, + inode_t *inode, off_t off, size_t size) +{ + loc_t loc = { + 0, + }; + struct gf_flock flock = { + 0, + }; + + loc.inode = inode_ref(inode); + gf_uuid_copy(loc.gfid, inode->gfid); + + flock.l_type = F_UNLCK; + flock.l_start = off; + flock.l_len = size; + + FOP_ONLIST(subvols, locked_on, numsubvols, replies, output, frame, inodelk, + dom, &loc, F_SETLK, &flock, NULL); + + loc_wipe(&loc); + + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int +cluster_tryinodelk(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *locked_on, + call_frame_t *frame, xlator_t *this, char *dom, + inode_t *inode, off_t off, size_t size) +{ + struct gf_flock flock = { + 0, + }; + loc_t loc = {0}; + + flock.l_type = F_WRLCK; + flock.l_start = off; + flock.l_len = size; + + loc.inode = inode_ref(inode); + gf_uuid_copy(loc.gfid, inode->gfid); + FOP_ONLIST(subvols, on, numsubvols, replies, locked_on, frame, inodelk, dom, + &loc, F_SETLK, &flock, NULL); + + loc_wipe(&loc); + return cluster_fop_success_fill(replies, numsubvols, locked_on); +} + +int +cluster_inodelk(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *locked_on, + call_frame_t *frame, xlator_t *this, char *dom, inode_t *inode, + off_t off, size_t size) +{ + struct gf_flock flock = { + 0, + }; + int i = 0; + loc_t loc = {0}; + unsigned char *output = NULL; + + flock.l_type = F_WRLCK; + flock.l_start = off; + flock.l_len = size; + + output = alloca(numsubvols); + loc.inode = inode_ref(inode); + gf_uuid_copy(loc.gfid, inode->gfid); + FOP_ONLIST(subvols, on, numsubvols, replies, locked_on, frame, inodelk, dom, + &loc, F_SETLK, &flock, NULL); + + for (i = 0; i < numsubvols; i++) { + if (replies[i].op_ret == -1 && replies[i].op_errno == EAGAIN) { + cluster_fop_success_fill(replies, numsubvols, locked_on); + cluster_uninodelk(subvols, locked_on, numsubvols, replies, output, + frame, this, dom, inode, off, size); + + FOP_SEQ(subvols, on, numsubvols, replies, locked_on, frame, inodelk, + dom, &loc, F_SETLKW, &flock, NULL); + break; + } + } + + loc_wipe(&loc); + return cluster_fop_success_fill(replies, numsubvols, locked_on); +} + +int +cluster_unentrylk(xlator_t **subvols, unsigned char *locked_on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, char *dom, + inode_t *inode, const char *name) +{ + loc_t loc = { + 0, + }; + + loc.inode = inode_ref(inode); + gf_uuid_copy(loc.gfid, inode->gfid); + + FOP_ONLIST(subvols, locked_on, numsubvols, replies, output, frame, entrylk, + dom, &loc, name, ENTRYLK_UNLOCK, ENTRYLK_WRLCK, NULL); + + loc_wipe(&loc); + + return cluster_fop_success_fill(replies, numsubvols, output); +} + +int +cluster_tryentrylk(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *locked_on, + call_frame_t *frame, xlator_t *this, char *dom, + inode_t *inode, const char *name) +{ + loc_t loc = {0}; + + loc.inode = inode_ref(inode); + gf_uuid_copy(loc.gfid, inode->gfid); + FOP_ONLIST(subvols, on, numsubvols, replies, locked_on, frame, entrylk, dom, + &loc, name, ENTRYLK_LOCK_NB, ENTRYLK_WRLCK, NULL); + + loc_wipe(&loc); + return cluster_fop_success_fill(replies, numsubvols, locked_on); +} + +int +cluster_entrylk(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *locked_on, + call_frame_t *frame, xlator_t *this, char *dom, inode_t *inode, + const char *name) +{ + int i = 0; + loc_t loc = {0}; + unsigned char *output = NULL; + + output = alloca(numsubvols); + loc.inode = inode_ref(inode); + gf_uuid_copy(loc.gfid, inode->gfid); + FOP_ONLIST(subvols, on, numsubvols, replies, locked_on, frame, entrylk, dom, + &loc, name, ENTRYLK_LOCK_NB, ENTRYLK_WRLCK, NULL); + + for (i = 0; i < numsubvols; i++) { + if (replies[i].op_ret == -1 && replies[i].op_errno == EAGAIN) { + cluster_fop_success_fill(replies, numsubvols, locked_on); + cluster_unentrylk(subvols, locked_on, numsubvols, replies, output, + frame, this, dom, inode, name); + FOP_SEQ(subvols, on, numsubvols, replies, locked_on, frame, entrylk, + dom, &loc, name, ENTRYLK_LOCK, ENTRYLK_WRLCK, NULL); + break; + } + } + + loc_wipe(&loc); + return cluster_fop_success_fill(replies, numsubvols, locked_on); +} + +int +cluster_tiebreaker_inodelk(xlator_t **subvols, unsigned char *on, + int numsubvols, default_args_cbk_t *replies, + unsigned char *locked_on, call_frame_t *frame, + xlator_t *this, char *dom, inode_t *inode, off_t off, + size_t size) +{ + struct gf_flock flock = { + 0, + }; + int i = 0; + int num_success = 0; + loc_t loc = {0}; + unsigned char *output = NULL; + + flock.l_type = F_WRLCK; + flock.l_start = off; + flock.l_len = size; + + output = alloca(numsubvols); + loc.inode = inode_ref(inode); + gf_uuid_copy(loc.gfid, inode->gfid); + FOP_ONLIST(subvols, on, numsubvols, replies, locked_on, frame, inodelk, dom, + &loc, F_SETLK, &flock, NULL); + + for (i = 0; i < numsubvols; i++) { + if (replies[i].valid && replies[i].op_ret == 0) { + num_success++; + continue; + } + + /* TODO: If earlier subvols fail with an error other + * than EAGAIN, we could still have 2 clients competing + * for the lock*/ + if (replies[i].op_ret == -1 && replies[i].op_errno == EAGAIN) { + cluster_fop_success_fill(replies, numsubvols, locked_on); + cluster_uninodelk(subvols, locked_on, numsubvols, replies, output, + frame, this, dom, inode, off, size); + + if (num_success) { + FOP_SEQ(subvols, on, numsubvols, replies, locked_on, frame, + inodelk, dom, &loc, F_SETLKW, &flock, NULL); + } else { + loc_wipe(&loc); + memset(locked_on, 0, numsubvols); + return 0; + } + break; + } + } + + loc_wipe(&loc); + return cluster_fop_success_fill(replies, numsubvols, locked_on); +} + +int +cluster_tiebreaker_entrylk(xlator_t **subvols, unsigned char *on, + int numsubvols, default_args_cbk_t *replies, + unsigned char *locked_on, call_frame_t *frame, + xlator_t *this, char *dom, inode_t *inode, + const char *name) +{ + int i = 0; + loc_t loc = {0}; + unsigned char *output = NULL; + int num_success = 0; + + output = alloca(numsubvols); + loc.inode = inode_ref(inode); + gf_uuid_copy(loc.gfid, inode->gfid); + FOP_ONLIST(subvols, on, numsubvols, replies, locked_on, frame, entrylk, dom, + &loc, name, ENTRYLK_LOCK_NB, ENTRYLK_WRLCK, NULL); + + for (i = 0; i < numsubvols; i++) { + if (replies[i].valid && replies[i].op_ret == 0) { + num_success++; + continue; + } + if (replies[i].op_ret == -1 && replies[i].op_errno == EAGAIN) { + cluster_fop_success_fill(replies, numsubvols, locked_on); + cluster_unentrylk(subvols, locked_on, numsubvols, replies, output, + frame, this, dom, inode, name); + if (num_success) { + FOP_SEQ(subvols, on, numsubvols, replies, locked_on, frame, + entrylk, dom, &loc, name, ENTRYLK_LOCK, ENTRYLK_WRLCK, + NULL); + } else { + loc_wipe(&loc); + memset(locked_on, 0, numsubvols); + return 0; + } + break; + } + } + + loc_wipe(&loc); + return cluster_fop_success_fill(replies, numsubvols, locked_on); +} diff --git a/libglusterfs/src/common-utils.c b/libglusterfs/src/common-utils.c index f3386fe2b62..682cbf28055 100644 --- a/libglusterfs/src/common-utils.c +++ b/libglusterfs/src/common-utils.c @@ -1,29 +1,17 @@ /* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 - #ifdef HAVE_BACKTRACE #include <execinfo.h> +#else +#include "execinfo_compat.h" #endif #include <stdio.h> @@ -36,1515 +24,5442 @@ #include <time.h> #include <locale.h> #include <sys/socket.h> -#include <sys/wait.h> #include <netinet/in.h> #include <arpa/inet.h> #include <signal.h> +#include <assert.h> +#include <libgen.h> /* for dirname() */ +#include <grp.h> + +#if defined(GF_BSD_HOST_OS) || defined(GF_DARWIN_HOST_OS) +#include <sys/sysctl.h> +#endif +#ifndef GF_LINUX_HOST_OS +#include <sys/resource.h> +#endif +#ifdef HAVE_SYNCFS_SYS +#include <sys/syscall.h> +#endif + +#include "glusterfs/compat-errno.h" +#include "glusterfs/common-utils.h" +#include "glusterfs/revision.h" +#include "glusterfs/glusterfs.h" +#include "glusterfs/stack.h" +#include "glusterfs/lkowner.h" +#include "glusterfs/syscall.h" +#include "glusterfs/globals.h" +#define XXH_INLINE_ALL +#include "xxhash.h" +#include <ifaddrs.h> +#include "glusterfs/libglusterfs-messages.h" +#include "glusterfs/glusterfs-acl.h" +#ifdef __FreeBSD__ +#include <pthread_np.h> +#undef BIT_SET +#endif -#include "logging.h" -#include "common-utils.h" -#include "revision.h" -#include "glusterfs.h" -#include "stack.h" +#ifndef AI_ADDRCONFIG +#define AI_ADDRCONFIG 0 +#endif /* AI_ADDRCONFIG */ + +char *vol_type_str[] = { + "Distribute", + "Stripe [NOT SUPPORTED from v6.0]", + "Replicate", + "Striped-Replicate [NOT SUPPORTED from v6.0]", + "Disperse", + "Tier [NOT SUPPORTED from v6.0]", + "Distributed-Stripe [NOT SUPPORTED from v6.0]", + "Distributed-Replicate", + "Distributed-Striped-Replicate [NOT SUPPORTED from v6.0]", + "Distributed-Disperse", +}; typedef int32_t (*rw_op_t)(int32_t fd, char *buf, int32_t size); typedef int32_t (*rwv_op_t)(int32_t fd, const struct iovec *buf, int32_t size); +char *xattrs_to_heal[] = {"user.", + POSIX_ACL_ACCESS_XATTR, + POSIX_ACL_DEFAULT_XATTR, + QUOTA_LIMIT_KEY, + QUOTA_LIMIT_OBJECTS_KEY, + GF_SELINUX_XATTR_KEY, + GF_XATTR_MDATA_KEY, + NULL}; -struct dnscache6 { - struct addrinfo *first; - struct addrinfo *next; -}; +void +gf_xxh64_wrapper(const unsigned char *data, size_t const len, + unsigned long long const seed, char *xxh64) +{ + unsigned short i = 0; + const unsigned short lim = GF_XXH64_DIGEST_LENGTH * 2 + 1; + XXH64_hash_t hash = 0; + XXH64_canonical_t c_hash = { + { + 0, + }, + }; + const uint8_t *p = (const uint8_t *)&c_hash; + + hash = XXH64(data, len, seed); + XXH64_canonicalFromHash(&c_hash, hash); + + for (i = 0; i < GF_XXH64_DIGEST_LENGTH; i++) + snprintf(xxh64 + i * 2, lim - i * 2, "%02x", p[i]); +} + +/** + * This function takes following arguments + * @this: xlator + * @gfid: The gfid which has to be filled + * @hash: the 8 byte hash which has to be filled inside the gfid + * @index: the array element of the uuid_t structure (which is + * a array of unsigned char) from where the 8 bytes of + * the hash has to be filled. Since uuid_t contains 16 + * char elements in the array, each byte of the hash has + * to be filled in one array element. + * + * This function is called twice for 2 hashes (of 8 byte each) to + * be filled in the gfid. + * + * The for loop in this function actually is doing these 2 things + * for each hash + * + * 1) One of the hashes + * tmp[0] = (hash_2 >> 56) & 0xff; + * tmp[1] = (hash_2 >> 48) & 0xff; + * tmp[2] = (hash_2 >> 40) & 0xff; + * tmp[3] = (hash_2 >> 32) & 0xff; + * tmp[4] = (hash_2 >> 24) & 0xff; + * tmp[5] = (hash_2 >> 16) & 0xff; + * tmp[6] = (hash_2 >> 8) & 0xff; + * tmp[7] = (hash_2) & 0xff; + * + * 2) The other hash: + * tmp[8] = (hash_1 >> 56) & 0xff; + * tmp[9] = (hash_1 >> 48) & 0xff; + * tmp[10] = (hash_1 >> 40) & 0xff; + * tmp[11] = (hash_1 >> 32) & 0xff; + * tmp[12] = (hash_1 >> 24) & 0xff; + * tmp[13] = (hash_1 >> 16) & 0xff; + * tmp[14] = (hash_1 >> 8) & 0xff; + * tmp[15] = (hash_1) & 0xff; + **/ +static int +gf_gfid_from_xxh64(xlator_t *this, uuid_t gfid, XXH64_hash_t hash, + unsigned short index) +{ + int ret = -1; + int i = -1; + + if ((index != 0) && (index != 8)) { + gf_msg_callingfn("gfid-from-xxh64", GF_LOG_WARNING, 0, + LG_MSG_INDEX_NOT_FOUND, + "index can only be either 0 or 8, as this" + "function's purpose is to encode a 8 byte " + "hash inside the gfid (index: %d)", + index); + goto out; + } + + for (i = 0; i < sizeof(hash); i++) { + /* + * As of now the below statement is equivalent of this. + * gfid[index+i] = (hash >> (64 - (8 * (i+1)))) & 0xff; + */ + gfid[index + i] = (hash >> ((sizeof(hash) * 8) - (8 * (i + 1)))) & + (0xff); + } + + ret = 0; + +out: + return ret; +} + +/** + * This function does the same thing as gf_xxh64_wrapper. But gf_xxh64_wrapper + * does not return anything and in this xlator there is a need for both the + * actual hash and the canonicalized form of the hash. + * + * To summarize: + * - XXH64_hash_t is needed as return because, those bytes which contain the + * hash can be used for different purposes as needed. One example is + * to have those bytes copied into the uuid_t structure to be used as gfid + * - xxh64 string is needed because, it can be used as the key for generating + * the next hash (and any other purpose which might require canonical form + * of the hash). + **/ +XXH64_hash_t +gf_xxh64_hash_wrapper(const unsigned char *data, size_t const len, + unsigned long long const seed, char *xxh64) +{ + unsigned short i = 0; + const unsigned short lim = GF_XXH64_DIGEST_LENGTH * 2 + 1; + XXH64_hash_t hash = 0; + XXH64_canonical_t c_hash = { + { + 0, + }, + }; + const uint8_t *p = (const uint8_t *)&c_hash; + + hash = XXH64(data, len, seed); + XXH64_canonicalFromHash(&c_hash, hash); + for (i = 0; i < GF_XXH64_DIGEST_LENGTH; i++) + snprintf(xxh64 + i * 2, lim - i * 2, "%02x", p[i]); + return hash; +} + +/** + * This is the algorithm followed for generating new gfid + * 1) generate xxh64 hash using snapname and original gfid of the object + * 2) Using the canonicalized form of above hash as the key, generate + * another hash + * 3) Combine both of the 8 byte hashes to generate a 16 byte uuid_t type + * 4) Use the above uuid as the gfid + * + * Each byte of the hash is stored separately in different elements of the + * character array represented by uuid_t + * Ex: tmp[0] = (hash_2 >> 56) & 0xFF + * This saves the most significant byte of hash_2 in tmp[0] + * tmp[1] = (hash_2 >> 48) & 0xFF + * This saves next most significant byte of hash_2 in tmp[1] + * . + * . + * So on. + * tmp[0] - tmp[7] holds the contents of hash_2 + * tmp[8] - tmp[15] hold the conents of hash_1 + * + * The hash generated (i.e. of type XXH64_hash_t) is 8 bytes long. And for + * gfid 16 byte uuid is needed. Hecne the 2 hashes are combined to form + * one 16 byte entity. + **/ +int +gf_gfid_generate_from_xxh64(uuid_t gfid, char *key) +{ + char xxh64_1[GF_XXH64_DIGEST_LENGTH * 2 + 1] = { + 0, + }; + char xxh64_2[GF_XXH64_DIGEST_LENGTH * 2 + 1] = { + 0, + }; + XXH64_hash_t hash_1 = 0; + XXH64_hash_t hash_2 = 0; + int ret = -1; + xlator_t *this = THIS; + + hash_1 = gf_xxh64_hash_wrapper((unsigned char *)key, strlen(key), + GF_XXHSUM64_DEFAULT_SEED, xxh64_1); + + hash_2 = gf_xxh64_hash_wrapper((unsigned char *)xxh64_1, strlen(xxh64_1), + GF_XXHSUM64_DEFAULT_SEED, xxh64_2); + + /* hash_2 is saved in 1st 8 elements of uuid_t char array */ + if (gf_gfid_from_xxh64(this, gfid, hash_2, 0)) { + gf_msg_callingfn(this->name, GF_LOG_WARNING, 0, + LG_MSG_XXH64_TO_GFID_FAILED, + "failed to encode the hash %llx into the 1st" + "half of gfid", + hash_2); + goto out; + } + + /* hash_1 is saved in the remaining 8 elements of uuid_t */ + if (gf_gfid_from_xxh64(this, gfid, hash_1, 8)) { + gf_msg_callingfn(this->name, GF_LOG_WARNING, 0, + LG_MSG_XXH64_TO_GFID_FAILED, + "failed to encode the hash %llx into the 2nd" + "half of gfid", + hash_1); + goto out; + } + + gf_msg_debug(this->name, 0, + "gfid generated is %s (hash1: %llx) " + "hash2: %llx, xxh64_1: %s xxh64_2: %s", + uuid_utoa(gfid), hash_1, hash_2, xxh64_1, xxh64_2); + + ret = 0; + +out: + return ret; +} + +/* works similar to mkdir(1) -p. + */ int -log_base2 (unsigned long x) +mkdir_p(char *path, mode_t mode, gf_boolean_t allow_symlinks) { - int val = 0; + int i = 0; + int ret = -1; + char dir[PATH_MAX] = { + 0, + }; + struct stat stbuf = { + 0, + }; + + const int path_len = min(strlen(path), PATH_MAX - 1); + + snprintf(dir, path_len + 1, "%s", path); + + i = (dir[0] == '/') ? 1 : 0; + do { + if (path[i] != '/' && path[i] != '\0') + continue; + + dir[i] = '\0'; + ret = sys_mkdir(dir, mode); + if (ret && errno != EEXIST) { + gf_smsg("", GF_LOG_ERROR, errno, LG_MSG_DIR_OP_FAILED, NULL); + goto out; + } + + if (ret && errno == EEXIST && !allow_symlinks) { + ret = sys_lstat(dir, &stbuf); + if (ret) + goto out; - while (x > 1) { - x /= 2; - val++; + if (S_ISLNK(stbuf.st_mode)) { + ret = -1; + gf_smsg("", GF_LOG_ERROR, 0, LG_MSG_DIR_IS_SYMLINK, "dir=%s", + dir, NULL); + goto out; + } } + dir[i] = '/'; + + } while (path[i++] != '\0'); + + ret = sys_stat(dir, &stbuf); + if (ret || !S_ISDIR(stbuf.st_mode)) { + if (ret == 0) + errno = 0; + ret = -1; + gf_smsg("", GF_LOG_ERROR, errno, LG_MSG_DIR_OP_FAILED, + "possibly some of the components" + " were not directories", + NULL); + goto out; + } + + ret = 0; +out: - return val; + return ret; } +int +gf_lstat_dir(const char *path, struct stat *stbuf_in) +{ + int ret = -1; + struct stat stbuf = { + 0, + }; + + if (path == NULL) { + errno = EINVAL; + goto out; + } + + ret = sys_lstat(path, &stbuf); + if (ret) + goto out; + + if (!S_ISDIR(stbuf.st_mode)) { + errno = ENOTDIR; + ret = -1; + goto out; + } + ret = 0; + +out: + if (!ret && stbuf_in) + *stbuf_in = stbuf; + + return ret; +} + +int +log_base2(unsigned long x) +{ + int val = 0; + + while (x > 1) { + x /= 2; + val++; + } + + return val; +} + +/** + * gf_rev_dns_lookup -- Perform a reverse DNS lookup on the IP address. + * + * @ip: The IP address to perform a reverse lookup on + * + * @return: success: Allocated string containing the hostname + * failure: NULL + */ +char * +gf_rev_dns_lookup(const char *ip) +{ + char *fqdn = NULL; + int ret = 0; + + GF_VALIDATE_OR_GOTO("resolver", ip, out); + + /* Get the FQDN */ + ret = gf_get_hostname_from_ip((char *)ip, &fqdn); + if (ret != 0) { + gf_smsg("resolver", GF_LOG_INFO, errno, LG_MSG_RESOLVE_HOSTNAME_FAILED, + "hostname=%s", ip, NULL); + } +out: + return fqdn; +} + +/** + * gf_resolve_path_parent -- Given a path, returns an allocated string + * containing the parent's path. + * @path: Path to parse + * @return: The parent path if found, NULL otherwise + */ +char * +gf_resolve_path_parent(const char *path) +{ + char *parent = NULL; + char *tmp = NULL; + char *pathc = NULL; + + GF_VALIDATE_OR_GOTO(THIS->name, path, out); + + if (0 == strlen(path)) { + gf_msg_callingfn(THIS->name, GF_LOG_DEBUG, 0, LG_MSG_INVALID_STRING, + "invalid string for 'path'"); + goto out; + } + + /* dup the parameter, we don't want to modify it */ + pathc = strdupa(path); + if (!pathc) { + goto out; + } + + /* Get the parent directory */ + tmp = dirname(pathc); + if (strcmp(tmp, "/") == 0) + goto out; + + parent = gf_strdup(tmp); +out: + return parent; +} int32_t -gf_resolve_ip6 (const char *hostname, - uint16_t port, - int family, - void **dnscache, - struct addrinfo **addr_info) -{ - int32_t ret = 0; - struct addrinfo hints; - struct dnscache6 *cache = NULL; - char service[NI_MAXSERV], host[NI_MAXHOST]; - - if (!hostname) { - gf_log ("resolver", GF_LOG_WARNING, "hostname is NULL"); - return -1; - } - - if (!*dnscache) { - *dnscache = GF_CALLOC (1, sizeof (struct dnscache6), - gf_common_mt_dnscache6); - if (!*dnscache) - return -1; - } - - cache = *dnscache; - if (cache->first && !cache->next) { - freeaddrinfo(cache->first); - cache->first = cache->next = NULL; - gf_log ("resolver", GF_LOG_TRACE, - "flushing DNS cache"); - } - - if (!cache->first) { - char *port_str = NULL; - gf_log ("resolver", GF_LOG_TRACE, - "DNS cache not present, freshly probing hostname: %s", - hostname); - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = family; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_ADDRCONFIG; - - ret = gf_asprintf (&port_str, "%d", port); - if (-1 == ret) { - gf_log ("resolver", GF_LOG_ERROR, "asprintf failed"); - return -1; - } - if ((ret = getaddrinfo(hostname, port_str, &hints, &cache->first)) != 0) { - gf_log ("resolver", GF_LOG_ERROR, - "getaddrinfo failed (%s)", gai_strerror (ret)); - - GF_FREE (*dnscache); - *dnscache = NULL; - GF_FREE (port_str); - return -1; - } - GF_FREE (port_str); - - cache->next = cache->first; - } - - if (cache->next) { - ret = getnameinfo((struct sockaddr *)cache->next->ai_addr, - cache->next->ai_addrlen, - host, sizeof (host), - service, sizeof (service), - NI_NUMERICHOST); - if (ret != 0) { - gf_log ("resolver", - GF_LOG_ERROR, - "getnameinfo failed (%s)", gai_strerror (ret)); - goto err; - } - - gf_log ("resolver", GF_LOG_TRACE, - "returning ip-%s (port-%s) for hostname: %s and port: %d", - host, service, hostname, port); - - *addr_info = cache->next; - } - - if (cache->next) - cache->next = cache->next->ai_next; - if (cache->next) { - ret = getnameinfo((struct sockaddr *)cache->next->ai_addr, - cache->next->ai_addrlen, - host, sizeof (host), - service, sizeof (service), - NI_NUMERICHOST); - if (ret != 0) { - gf_log ("resolver", - GF_LOG_ERROR, - "getnameinfo failed (%s)", gai_strerror (ret)); - goto err; - } - - gf_log ("resolver", GF_LOG_TRACE, - "next DNS query will return: ip-%s port-%s", host, service); - } - - return 0; +gf_resolve_ip6(const char *hostname, uint16_t port, int family, void **dnscache, + struct addrinfo **addr_info) +{ + int32_t ret = 0; + struct addrinfo hints; + struct dnscache6 *cache = NULL; + char service[NI_MAXSERV], host[NI_MAXHOST]; + + if (!hostname) { + gf_msg_callingfn("resolver", GF_LOG_WARNING, 0, LG_MSG_HOSTNAME_NULL, + "hostname is NULL"); + return -1; + } + + if (!*dnscache) { + *dnscache = GF_CALLOC(1, sizeof(struct dnscache6), + gf_common_mt_dnscache6); + if (!*dnscache) + return -1; + } + + cache = *dnscache; + if (cache->first && !cache->next) { + freeaddrinfo(cache->first); + cache->first = cache->next = NULL; + gf_msg_trace("resolver", 0, "flushing DNS cache"); + } + + if (!cache->first) { + char *port_str = NULL; + gf_msg_trace("resolver", 0, + "DNS cache not present, freshly " + "probing hostname: %s", + hostname); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_socktype = SOCK_STREAM; + + ret = gf_asprintf(&port_str, "%d", port); + if (-1 == ret) { + return -1; + } + if ((ret = getaddrinfo(hostname, port_str, &hints, &cache->first)) != + 0) { + gf_smsg("resolver", GF_LOG_ERROR, 0, LG_MSG_GETADDRINFO_FAILED, + "family=%d", family, "ret=%s", gai_strerror(ret), NULL); + + GF_FREE(*dnscache); + *dnscache = NULL; + GF_FREE(port_str); + return -1; + } + GF_FREE(port_str); + + cache->next = cache->first; + } + + if (cache->next) { + ret = getnameinfo((struct sockaddr *)cache->next->ai_addr, + cache->next->ai_addrlen, host, sizeof(host), service, + sizeof(service), NI_NUMERICHOST); + if (ret != 0) { + gf_smsg("resolver", GF_LOG_ERROR, 0, LG_MSG_GETNAMEINFO_FAILED, + "ret=%s", gai_strerror(ret), NULL); + goto err; + } + + gf_msg_debug("resolver", 0, + "returning ip-%s (port-%s) for " + "hostname: %s and port: %d", + host, service, hostname, port); + + *addr_info = cache->next; + } + + if (cache->next) + cache->next = cache->next->ai_next; + if (cache->next) { + ret = getnameinfo((struct sockaddr *)cache->next->ai_addr, + cache->next->ai_addrlen, host, sizeof(host), service, + sizeof(service), NI_NUMERICHOST); + if (ret != 0) { + gf_smsg("resolver", GF_LOG_ERROR, 0, LG_MSG_GETNAMEINFO_FAILED, + "ret=%s", gai_strerror(ret), NULL); + goto err; + } + + gf_msg_debug("resolver", 0, + "next DNS query will return: " + "ip-%s port-%s", + host, service); + } + + return 0; err: - freeaddrinfo (cache->first); - cache->first = cache->next = NULL; - GF_FREE (cache); - *dnscache = NULL; - return -1; + freeaddrinfo(cache->first); + cache->first = cache->next = NULL; + GF_FREE(cache); + *dnscache = NULL; + return -1; +} + +/** + * gf_dnscache_init -- Initializes a dnscache struct and sets the ttl + * to the specified value in the parameter. + * + * @ttl: the TTL in seconds + * @return: SUCCESS: Pointer to an allocated dnscache struct + * FAILURE: NULL + */ +struct dnscache * +gf_dnscache_init(time_t ttl) +{ + struct dnscache *cache = GF_MALLOC(sizeof(*cache), gf_common_mt_dnscache); + if (!cache) + return NULL; + + cache->cache_dict = dict_new(); + if (!cache->cache_dict) { + GF_FREE(cache); + cache = NULL; + } else { + cache->ttl = ttl; + } + + return cache; +} + +/** + * gf_dnscache_deinit -- cleanup resources used by struct dnscache + */ +void +gf_dnscache_deinit(struct dnscache *cache) +{ + if (!cache) { + gf_msg_plain(GF_LOG_WARNING, "dnscache is NULL"); + return; + } + dict_unref(cache->cache_dict); + GF_FREE(cache); } +/** + * gf_dnscache_entry_init -- Initialize a dnscache entry + * + * @return: SUCCESS: Pointer to an allocated dnscache entry struct + * FAILURE: NULL + */ +struct dnscache_entry * +gf_dnscache_entry_init() +{ + struct dnscache_entry *entry = GF_CALLOC(1, sizeof(*entry), + gf_common_mt_dnscache_entry); + return entry; +} +/** + * gf_dnscache_entry_deinit -- Free memory used by a dnscache entry + * + * @entry: Pointer to deallocate + */ void -gf_log_volume_file (FILE *specfp) +gf_dnscache_entry_deinit(struct dnscache_entry *entry) { - extern FILE *gf_log_logfile; - int lcount = 0; - char data[GF_UNIT_KB]; + GF_FREE(entry->ip); + GF_FREE(entry->fqdn); + GF_FREE(entry); +} + +/** + * gf_rev_dns_lookup -- Perform a reverse DNS lookup on the IP address. + * + * @ip: The IP address to perform a reverse lookup on + * + * @return: success: Allocated string containing the hostname + * failure: NULL + */ +char * +gf_rev_dns_lookup_cached(const char *ip, struct dnscache *dnscache) +{ + char *fqdn = NULL; + int ret = 0; + dict_t *cache = NULL; + data_t *entrydata = NULL; + struct dnscache_entry *dnsentry = NULL; + gf_boolean_t from_cache = _gf_false; + + if (!dnscache) + goto out; + + cache = dnscache->cache_dict; + + /* Quick cache lookup to see if we already hold it */ + entrydata = dict_get(cache, (char *)ip); + if (entrydata) { + dnsentry = (struct dnscache_entry *)entrydata->data; + /* First check the TTL & timestamp */ + if (gf_time() - dnsentry->timestamp > dnscache->ttl) { + gf_dnscache_entry_deinit(dnsentry); + entrydata->data = NULL; /* Mark this as 'null' so + * dict_del () doesn't try free + * this after we've already + * freed it. + */ + + dict_del(cache, (char *)ip); /* Remove this entry */ + } else { + /* Cache entry is valid, get the FQDN and return */ + fqdn = dnsentry->fqdn; + from_cache = _gf_true; /* Mark this as from cache */ + goto out; + } + } - fseek (specfp, 0L, SEEK_SET); + /* Get the FQDN */ + ret = gf_get_hostname_from_ip((char *)ip, &fqdn); + if (ret != 0) + goto out; - fprintf (gf_log_logfile, "Given volfile:\n"); - fprintf (gf_log_logfile, - "+---------------------------------------" - "---------------------------------------+\n"); - while (fgets (data, GF_UNIT_KB, specfp) != NULL){ - lcount++; - fprintf (gf_log_logfile, "%3d: %s", lcount, data); - } - fprintf (gf_log_logfile, - "\n+---------------------------------------" - "---------------------------------------+\n"); - fflush (gf_log_logfile); - fseek (specfp, 0L, SEEK_SET); + if (!fqdn) { + gf_log_callingfn("resolver", GF_LOG_CRITICAL, + "Allocation failed for the host address"); + goto out; + } + + from_cache = _gf_false; +out: + /* Insert into the cache */ + if (fqdn && !from_cache && ip) { + struct dnscache_entry *entry = gf_dnscache_entry_init(); + + if (entry) { + entry->fqdn = fqdn; + entry->ip = gf_strdup(ip); + entry->timestamp = gf_time(); + entrydata = bin_to_data(entry, sizeof(*entry)); + dict_set(cache, (char *)ip, entrydata); + } + } + return fqdn; +} + +struct xldump { + int lineno; +}; + +/* to catch any format discrepencies that may arise in code */ +static int +nprintf(struct xldump *dump, const char *fmt, ...) + __attribute__((__format__(__printf__, 2, 3))); +static int +nprintf(struct xldump *dump, const char *fmt, ...) +{ + va_list ap; + char *msg = NULL; + char header[32]; + int ret = 0; + + ret = snprintf(header, 32, "%3d:", ++dump->lineno); + if (ret < 0) + goto out; + + va_start(ap, fmt); + ret = vasprintf(&msg, fmt, ap); + va_end(ap); + if (-1 == ret) + goto out; + + /* NOTE: No ret value from gf_msg_plain, so unable to compute printed + * characters. The return value from nprintf is not used, so for now + * living with it */ + gf_msg_plain(GF_LOG_WARNING, "%s %s", header, msg); + +out: + FREE(msg); + return 0; +} + +static int +xldump_options(dict_t *this, char *key, data_t *value, void *d) +{ + nprintf(d, " option %s %s", key, value->data); + return 0; } static void -gf_dump_config_flags (int fd) +xldump_subvolumes(xlator_t *this, void *d) { - int ret = 0; + xlator_list_t *subv = NULL; + int len = 0; + char *subvstr = NULL; - ret = write (fd, "configuration details:\n", 23); - if (ret == -1) - goto out; + if (!this->children) + return; + + for (subv = this->children; subv; subv = subv->next) + len += (strlen(subv->xlator->name) + 1); + + subvstr = GF_MALLOC(len, gf_common_mt_strdup); + + len = 0; + for (subv = this->children; subv; subv = subv->next) + len += sprintf(subvstr + len, "%s%s", subv->xlator->name, + subv->next ? " " : ""); + + nprintf(d, " subvolumes %s", subvstr); + + GF_FREE(subvstr); +} + +static void +xldump(xlator_t *each, void *d) +{ + nprintf(d, "volume %s", each->name); + nprintf(d, " type %s", each->type); + dict_foreach(each->options, xldump_options, d); + + xldump_subvolumes(each, d); + + nprintf(d, "end-volume"); + nprintf(d, " "); +} + +void +gf_log_dump_graph(FILE *specfp, glusterfs_graph_t *graph) +{ + struct xldump xld = { + 0, + }; + + gf_msg_plain(GF_LOG_WARNING, "Final graph:"); + gf_msg_plain(GF_LOG_WARNING, + "+---------------------------------------" + "---------------------------------------+"); + + xlator_foreach_depth_first(graph->top, xldump, &xld); + + gf_msg_plain(GF_LOG_WARNING, + "+---------------------------------------" + "---------------------------------------+"); +} + +static void +gf_dump_config_flags() +{ + gf_msg_plain_nomem(GF_LOG_ALERT, "configuration details:"); /* have argp */ #ifdef HAVE_ARGP - ret = write (fd, "argp 1\n", 7); - if (ret == -1) - goto out; + gf_msg_plain_nomem(GF_LOG_ALERT, "argp 1"); #endif /* ifdef if found backtrace */ #ifdef HAVE_BACKTRACE - ret = write (fd, "backtrace 1\n", 12); - if (ret == -1) - goto out; + gf_msg_plain_nomem(GF_LOG_ALERT, "backtrace 1"); #endif /* Berkeley-DB version has cursor->get() */ #ifdef HAVE_BDB_CURSOR_GET - ret = write (fd, "bdb->cursor->get 1\n", 19); - if (ret == -1) - goto out; + gf_msg_plain_nomem(GF_LOG_ALERT, "bdb->cursor->get 1"); #endif /* Define to 1 if you have the <db.h> header file. */ #ifdef HAVE_DB_H - ret = write (fd, "db.h 1\n", 7); - if (ret == -1) - goto out; + gf_msg_plain_nomem(GF_LOG_ALERT, "db.h 1"); #endif /* Define to 1 if you have the <dlfcn.h> header file. */ #ifdef HAVE_DLFCN_H - ret = write (fd, "dlfcn 1\n", 8); - if (ret == -1) - goto out; + gf_msg_plain_nomem(GF_LOG_ALERT, "dlfcn 1"); #endif /* define if fdatasync exists */ #ifdef HAVE_FDATASYNC - ret = write (fd, "fdatasync 1\n", 12); - if (ret == -1) - goto out; + gf_msg_plain_nomem(GF_LOG_ALERT, "fdatasync 1"); #endif /* Define to 1 if you have the `pthread' library (-lpthread). */ #ifdef HAVE_LIBPTHREAD - ret = write (fd, "libpthread 1\n", 13); - if (ret == -1) - goto out; + gf_msg_plain_nomem(GF_LOG_ALERT, "libpthread 1"); #endif /* define if llistxattr exists */ #ifdef HAVE_LLISTXATTR - ret = write (fd, "llistxattr 1\n", 13); - if (ret == -1) - goto out; + gf_msg_plain_nomem(GF_LOG_ALERT, "llistxattr 1"); #endif /* define if found setfsuid setfsgid */ #ifdef HAVE_SET_FSID - ret = write (fd, "setfsid 1\n", 10); - if (ret == -1) - goto out; + gf_msg_plain_nomem(GF_LOG_ALERT, "setfsid 1"); #endif /* define if found spinlock */ #ifdef HAVE_SPINLOCK - ret = write (fd, "spinlock 1\n", 11); - if (ret == -1) - goto out; + gf_msg_plain_nomem(GF_LOG_ALERT, "spinlock 1"); #endif /* Define to 1 if you have the <sys/epoll.h> header file. */ #ifdef HAVE_SYS_EPOLL_H - ret = write (fd, "epoll.h 1\n", 10); - if (ret == -1) - goto out; + gf_msg_plain_nomem(GF_LOG_ALERT, "epoll.h 1"); #endif /* Define to 1 if you have the <sys/extattr.h> header file. */ #ifdef HAVE_SYS_EXTATTR_H - ret = write (fd, "extattr.h 1\n", 12); - if (ret == -1) - goto out; + gf_msg_plain_nomem(GF_LOG_ALERT, "extattr.h 1"); #endif /* Define to 1 if you have the <sys/xattr.h> header file. */ #ifdef HAVE_SYS_XATTR_H - ret = write (fd, "xattr.h 1\n", 10); - if (ret == -1) - goto out; + gf_msg_plain_nomem(GF_LOG_ALERT, "xattr.h 1"); #endif /* define if found st_atim.tv_nsec */ #ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC - ret = write (fd, "st_atim.tv_nsec 1\n", 18); - if (ret == -1) - goto out; + gf_msg_plain_nomem(GF_LOG_ALERT, "st_atim.tv_nsec 1"); #endif /* define if found st_atimespec.tv_nsec */ #ifdef HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC - ret = write (fd, "st_atimespec.tv_nsec 1\n",23); - if (ret == -1) - goto out; + gf_msg_plain_nomem(GF_LOG_ALERT, "st_atimespec.tv_nsec 1"); #endif /* Define to the full name and version of this package. */ #ifdef PACKAGE_STRING - { - char msg[128]; - sprintf (msg, "package-string: %s\n", PACKAGE_STRING); - ret = write (fd, msg, strlen (msg)); - if (ret == -1) - goto out; - } + { + char *msg = NULL; + int ret = -1; + + ret = gf_asprintf(&msg, "package-string: %s", PACKAGE_STRING); + if (ret >= 0) { + gf_msg_plain_nomem(GF_LOG_ALERT, msg); + GF_FREE(msg); + } + } #endif -out: - return; + return; } -/* Obtain a backtrace and print it to stdout. */ -/* TODO: It looks like backtrace_symbols allocates memory, - it may be problem because mostly memory allocation/free causes 'sigsegv' */ +/* Obtain a backtrace and print it to the log */ void -gf_print_trace (int32_t signum) -{ - extern FILE *gf_log_logfile; - struct tm *tm = NULL; - char msg[1024] = {0,}; - char timestr[256] = {0,}; - time_t utime = 0; - int ret = 0; - int fd = 0; - - fd = fileno (gf_log_logfile); - - /* Pending frames, (if any), list them in order */ - ret = write (fd, "pending frames:\n", 16); - { - glusterfs_ctx_t *ctx = glusterfs_ctx_get (); - struct list_head *trav = ((call_pool_t *)ctx->pool)->all_frames.next; - while (trav != (&((call_pool_t *)ctx->pool)->all_frames)) { - call_frame_t *tmp = (call_frame_t *)(&((call_stack_t *)trav)->frames); - if (tmp->root->type == GF_OP_TYPE_FOP) - sprintf (msg,"frame : type(%d) op(%s)\n", - tmp->root->type, - gf_fop_list[tmp->root->op]); - if (tmp->root->type == GF_OP_TYPE_MGMT) - sprintf (msg,"frame : type(%d) op(%s)\n", - tmp->root->type, - gf_mgmt_list[tmp->root->op]); - - ret = write (fd, msg, strlen (msg)); - trav = trav->next; - } - ret = write (fd, "\n", 1); - } - - sprintf (msg, "patchset: %s\n", GLUSTERFS_REPOSITORY_REVISION); - ret = write (fd, msg, strlen (msg)); - - sprintf (msg, "signal received: %d\n", signum); - ret = write (fd, msg, strlen (msg)); - +gf_print_trace(int32_t signum, glusterfs_ctx_t *ctx) +{ + char msg[1024] = { + 0, + }; + char timestr[GF_TIMESTR_SIZE] = { + 0, + }; + call_stack_t *stack = NULL; + + /* Now every gf_log call will just write to a buffer and when the + * buffer becomes full, its written to the log-file. Suppose the process + * crashes and prints the backtrace in the log-file, then the previous + * log information will still be in the buffer itself. So flush the + * contents of the buffer to the log file before printing the backtrace + * which helps in debugging. + */ + gf_log_flush(); + + gf_log_disable_suppression_before_exit(ctx); + + /* Pending frames, (if any), list them in order */ + gf_msg_plain_nomem(GF_LOG_ALERT, "pending frames:"); + { + /* FIXME: traversing stacks outside pool->lock */ + list_for_each_entry(stack, &ctx->pool->all_frames, all_frames) { - /* Dump the timestamp of the crash too, so the previous logs - can be related */ - utime = time (NULL); - tm = localtime (&utime); - strftime (timestr, 256, "%Y-%m-%d %H:%M:%S\n", tm); - ret = write (fd, "time of crash: ", 15); - ret = write (fd, timestr, strlen (timestr)); - } - - gf_dump_config_flags (fd); -#if HAVE_BACKTRACE - /* Print 'backtrace' */ - { - void *array[200]; - size_t size; + if (stack->type == GF_OP_TYPE_FOP) + sprintf(msg, "frame : type(%d) op(%s)", stack->type, + gf_fop_list[stack->op]); + else + sprintf(msg, "frame : type(%d) op(%d)", stack->type, stack->op); - size = backtrace (array, 200); - backtrace_symbols_fd (&array[1], size-1, fd); - sprintf (msg, "---------\n"); - ret = write (fd, msg, strlen (msg)); - } -#endif /* HAVE_BACKTRACE */ - - /* Send a signal to terminate the process */ - signal (signum, SIG_DFL); - raise (signum); + gf_msg_plain_nomem(GF_LOG_ALERT, msg); + } + } + + sprintf(msg, "patchset: %s", GLUSTERFS_REPOSITORY_REVISION); + gf_msg_plain_nomem(GF_LOG_ALERT, msg); + + sprintf(msg, "signal received: %d", signum); + gf_msg_plain_nomem(GF_LOG_ALERT, msg); + { + /* Dump the timestamp of the crash too, so the previous logs + can be related */ + gf_time_fmt(timestr, sizeof timestr, gf_time(), gf_timefmt_FT); + gf_msg_plain_nomem(GF_LOG_ALERT, "time of crash: "); + gf_msg_plain_nomem(GF_LOG_ALERT, timestr); + } + + gf_dump_config_flags(); + gf_msg_backtrace_nomem(GF_LOG_ALERT, 200); + sprintf(msg, "---------"); + gf_msg_plain_nomem(GF_LOG_ALERT, msg); + + /* Send a signal to terminate the process */ + signal(signum, SIG_DFL); + raise(signum); } void -trap (void) +trap(void) { - } char * -gf_trim (char *string) +gf_trim(char *string) { - register char *s, *t; + register char *s, *t; - if (string == NULL) - { - return NULL; - } + if (string == NULL) { + return NULL; + } - for (s = string; isspace (*s); s++) - ; + for (s = string; isspace(*s); s++) + ; - if (*s == 0) - return s; + if (*s == 0) + return s; - t = s + strlen (s) - 1; - while (t > s && isspace (*t)) - t--; - *++t = '\0'; + t = s + strlen(s) - 1; + while (t > s && isspace(*t)) + t--; + *++t = '\0'; - return s; + return s; } int -gf_strsplit (const char *str, const char *delim, - char ***tokens, int *token_count) +gf_strstr(const char *str, const char *delim, const char *match) { - char *_running = NULL; - char *running = NULL; - char *token = NULL; - char **token_list = NULL; - int count = 0; - int i = 0; - int j = 0; + char *tmp = NULL; + char *save_ptr = NULL; + char *tmp_str = NULL; + + int ret = 0; + + tmp_str = strdup(str); - if (str == NULL || delim == NULL || tokens == NULL || token_count == NULL) - { - return -1; - } + if (str == NULL || delim == NULL || match == NULL || tmp_str == NULL) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "argument invalid"); + ret = -1; + goto out; + } + + tmp = strtok_r(tmp_str, delim, &save_ptr); + + while (tmp) { + ret = strcmp(tmp, match); + + if (ret == 0) + break; + + tmp = strtok_r(NULL, delim, &save_ptr); + } + +out: + free(tmp_str); - _running = gf_strdup (str); - if (_running == NULL) - { - return -1; - } - running = _running; + return ret; +} - while ((token = strsep (&running, delim)) != NULL) - { - if (token[0] != '\0') - count++; - } - GF_FREE (_running); +int +gf_volume_name_validate(const char *volume_name) +{ + const char *vname = NULL; - _running = gf_strdup (str); - if (_running == NULL) - { - return -1; - } - running = _running; + if (volume_name == NULL) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "argument invalid"); + return -1; + } - if ((token_list = GF_CALLOC (count, sizeof (char *), - gf_common_mt_char)) == NULL) - { - GF_FREE (_running); - return -1; - } + if (!isalpha(volume_name[0])) + return 1; - while ((token = strsep (&running, delim)) != NULL) - { - if (token[0] == '\0') - continue; + for (vname = &volume_name[1]; *vname != '\0'; vname++) { + if (!(isalnum(*vname) || *vname == '_')) + return 1; + } - token_list[i] = gf_strdup (token); - if (token_list[i] == NULL) - goto free_exit; - i++; - } + return 0; +} - GF_FREE (_running); +int +gf_string2time(const char *str, uint32_t *n) +{ + unsigned long value = 0; + char *tail = NULL; + int old_errno = 0; + const char *s = NULL; + + if (str == NULL || n == NULL) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "argument invalid"); + errno = EINVAL; + return -1; + } + + for (s = str; *s != '\0'; s++) { + if (isspace(*s)) + continue; + if (*s == '-') + return -1; + break; + } + + old_errno = errno; + errno = 0; + value = strtol(str, &tail, 0); + if (str == tail) + errno = EINVAL; + + if (errno == ERANGE || errno == EINVAL) + return -1; + + if (errno == 0) + errno = old_errno; + + if (((tail[0] == '\0') || ((tail[0] == 's') && (tail[1] == '\0')) || + ((tail[0] == 's') && (tail[1] == 'e') && (tail[2] == 'c') && + (tail[3] == '\0')))) + goto out; + + else if (((tail[0] == 'm') && (tail[1] == '\0')) || + ((tail[0] == 'm') && (tail[1] == 'i') && (tail[2] == 'n') && + (tail[3] == '\0'))) { + value = value * GF_MINUTE_IN_SECONDS; + goto out; + } + + else if (((tail[0] == 'h') && (tail[1] == '\0')) || + ((tail[0] == 'h') && (tail[1] == 'r') && (tail[2] == '\0'))) { + value = value * GF_HOUR_IN_SECONDS; + goto out; + } + + else if (((tail[0] == 'd') && (tail[1] == '\0')) || + ((tail[0] == 'd') && (tail[1] == 'a') && (tail[2] == 'y') && + (tail[3] == 's') && (tail[4] == '\0'))) { + value = value * GF_DAY_IN_SECONDS; + goto out; + } + + else if (((tail[0] == 'w') && (tail[1] == '\0')) || + ((tail[0] == 'w') && (tail[1] == 'k') && (tail[2] == '\0'))) { + value = value * GF_WEEK_IN_SECONDS; + goto out; + } else { + return -1; + } - *tokens = token_list; - *token_count = count; - return 0; +out: + *n = value; -free_exit: - GF_FREE (_running); - for (j = 0; j < i; j++) - { - GF_FREE (token_list[j]); - } - GF_FREE (token_list); - return -1; + return 0; } int -gf_strstr (const char *str, const char *delim, const char *match) +gf_string2percent(const char *str, double *n) { - char *tmp = NULL; - char *save_ptr = NULL; - char *tmp_str = NULL; + double value = 0; + char *tail = NULL; + int old_errno = 0; + const char *s = NULL; + + if (str == NULL || n == NULL) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "argument invalid"); + errno = EINVAL; + return -1; + } + + for (s = str; *s != '\0'; s++) { + if (isspace(*s)) + continue; + if (*s == '-') + return -1; + break; + } + + old_errno = errno; + errno = 0; + value = strtod(str, &tail); + if (str == tail) + errno = EINVAL; + + if (errno == ERANGE || errno == EINVAL) + return -1; + + if (errno == 0) + errno = old_errno; + + if (!((tail[0] == '\0') || ((tail[0] == '%') && (tail[1] == '\0')))) + return -1; + + *n = value; + + return 0; +} - int ret = 0; +static int +_gf_string2long(const char *str, long *n, int base) +{ + long value = 0; + char *tail = NULL; + int old_errno = 0; - tmp_str = strdup (str); + if (str == NULL || n == NULL) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "argument invalid"); + errno = EINVAL; + return -1; + } - if (str == NULL || delim == NULL || match == NULL || tmp_str == NULL) { - ret = -1; - goto out; - } + old_errno = errno; + errno = 0; + value = strtol(str, &tail, base); + if (str == tail) + errno = EINVAL; + if (errno == ERANGE || errno == EINVAL) + return -1; - tmp = strtok_r (tmp_str, delim, &save_ptr); + if (errno == 0) + errno = old_errno; - while (tmp) { - ret = strcmp (tmp, match); + if (tail[0] != '\0') + return -1; - if (ret == 0) - break; + *n = value; - tmp = strtok_r (NULL, delim, &save_ptr); - } + return 0; +} -out: - if (tmp_str) - free (tmp_str); +static int +_gf_string2ulong(const char *str, unsigned long *n, int base) +{ + unsigned long value = 0; + char *tail = NULL; + int old_errno = 0; + const char *s = NULL; + + if (str == NULL || n == NULL) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "argument invalid"); + errno = EINVAL; + return -1; + } + + for (s = str; *s != '\0'; s++) { + if (isspace(*s)) + continue; + if (*s == '-') + return -1; + break; + } + + old_errno = errno; + errno = 0; + value = strtoul(str, &tail, base); + if (str == tail) + errno = EINVAL; + + if (errno == ERANGE || errno == EINVAL) + return -1; + + if (errno == 0) + errno = old_errno; + + if (tail[0] != '\0') + return -1; + + *n = value; + + return 0; +} - return ret; +static int +_gf_string2uint(const char *str, unsigned int *n, int base) +{ + unsigned long value = 0; + char *tail = NULL; + int old_errno = 0; + const char *s = NULL; + + if (str == NULL || n == NULL) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "argument invalid"); + errno = EINVAL; + return -1; + } + + for (s = str; *s != '\0'; s++) { + if (isspace(*s)) + continue; + if (*s == '-') + return -1; + break; + } + + old_errno = errno; + errno = 0; + value = strtoul(str, &tail, base); + if (str == tail) + errno = EINVAL; + + if (errno == ERANGE || errno == EINVAL) + return -1; + + if (errno == 0) + errno = old_errno; + + if (tail[0] != '\0') + return -1; + + *n = (unsigned int)value; + + return 0; +} + +static int +_gf_string2double(const char *str, double *n) +{ + double value = 0.0; + char *tail = NULL; + int old_errno = 0; + + if (str == NULL || n == NULL) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "argument invalid"); + errno = EINVAL; + return -1; + } + + old_errno = errno; + errno = 0; + value = strtod(str, &tail); + if (str == tail) + errno = EINVAL; + + if (errno == ERANGE || errno == EINVAL) + return -1; + if (errno == 0) + errno = old_errno; + + if (tail[0] != '\0') + return -1; + + *n = value; + + return 0; } -int -gf_volume_name_validate (const char *volume_name) +static int +_gf_string2longlong(const char *str, long long *n, int base) { - const char *vname = NULL; + long long value = 0; + char *tail = NULL; + int old_errno = 0; + + if (str == NULL || n == NULL) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "argument invalid"); + errno = EINVAL; + return -1; + } + + old_errno = errno; + errno = 0; + value = strtoll(str, &tail, base); + if (str == tail) + errno = EINVAL; - if (volume_name == NULL) - { - return -1; - } + if (errno == ERANGE || errno == EINVAL) + return -1; - if (!isalpha (volume_name[0])) - { - return 1; - } + if (errno == 0) + errno = old_errno; - for (vname = &volume_name[1]; *vname != '\0'; vname++) - { - if (!(isalnum (*vname) || *vname == '_')) - return 1; - } + if (tail[0] != '\0') + return -1; - return 0; + *n = value; + + return 0; } +static int +_gf_string2ulonglong(const char *str, unsigned long long *n, int base) +{ + unsigned long long value = 0; + char *tail = NULL; + int old_errno = 0; + const char *s = NULL; + + if (str == NULL || n == NULL) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "argument invalid"); + errno = EINVAL; + return -1; + } + + for (s = str; *s != '\0'; s++) { + if (isspace(*s)) + continue; + if (*s == '-') + return -1; + break; + } + + old_errno = errno; + errno = 0; + value = strtoull(str, &tail, base); + if (str == tail) + errno = EINVAL; + + if (errno == ERANGE || errno == EINVAL) + return -1; + + if (errno == 0) + errno = old_errno; + + if (tail[0] != '\0') + return -1; + + *n = value; + + return 0; +} int -gf_string2time (const char *str, uint32_t *n) +gf_string2long(const char *str, long *n) { - unsigned long value = 0; - char *tail = NULL; - int old_errno = 0; - const char *s = NULL; + return _gf_string2long(str, n, 0); +} - if (str == NULL || n == NULL) - { - errno = EINVAL; - return -1; - } +int +gf_string2ulong(const char *str, unsigned long *n) +{ + return _gf_string2ulong(str, n, 0); +} - for (s = str; *s != '\0'; s++) - { - if (isspace (*s)) - { - continue; - } - if (*s == '-') - { - return -1; - } - break; - } +int +gf_string2int(const char *str, int *n) +{ + long l = 0; + int ret = 0; - old_errno = errno; - errno = 0; - value = strtol (str, &tail, 0); + ret = _gf_string2long(str, &l, 0); - if (errno == ERANGE || errno == EINVAL) - { - return -1; - } + *n = l; + return ret; +} - if (errno == 0) - { - errno = old_errno; - } +int +gf_string2uint(const char *str, unsigned int *n) +{ + return _gf_string2uint(str, n, 0); +} - if (!((tail[0] == '\0') || - ((tail[0] == 's') && (tail[1] == '\0')) || - ((tail[0] == 's') && (tail[1] == 'e') && (tail[2] == 'c') && (tail[3] == '\0')))) - { - return -1; - } +int +gf_string2double(const char *str, double *n) +{ + return _gf_string2double(str, n); +} - *n = value; +int +gf_string2longlong(const char *str, long long *n) +{ + return _gf_string2longlong(str, n, 0); +} - return 0; +int +gf_string2ulonglong(const char *str, unsigned long long *n) +{ + return _gf_string2ulonglong(str, n, 0); } +int +gf_string2int8(const char *str, int8_t *n) +{ + long l = 0L; + int rv = 0; + + rv = _gf_string2long(str, &l, 0); + if (rv != 0) + return rv; + + if ((l >= INT8_MIN) && (l <= INT8_MAX)) { + *n = (int8_t)l; + return 0; + } + + errno = ERANGE; + return -1; +} int -gf_string2percent (const char *str, uint32_t *n) +gf_string2int16(const char *str, int16_t *n) { - unsigned long value = 0; - char *tail = NULL; - int old_errno = 0; - const char *s = NULL; + long l = 0L; + int rv = 0; - if (str == NULL || n == NULL) - { - errno = EINVAL; - return -1; - } + rv = _gf_string2long(str, &l, 0); + if (rv != 0) + return rv; - for (s = str; *s != '\0'; s++) - { - if (isspace (*s)) - { - continue; - } - if (*s == '-') - { - return -1; - } - break; - } + if ((l >= INT16_MIN) && (l <= INT16_MAX)) { + *n = (int16_t)l; + return 0; + } - old_errno = errno; - errno = 0; - value = strtol (str, &tail, 0); + errno = ERANGE; + return -1; +} - if (errno == ERANGE || errno == EINVAL) - { - return -1; - } +int +gf_string2int32(const char *str, int32_t *n) +{ + long l = 0L; + int rv = 0; - if (errno == 0) - { - errno = old_errno; - } + rv = _gf_string2long(str, &l, 0); + if (rv != 0) + return rv; - if (!((tail[0] == '\0') || - ((tail[0] == '%') && (tail[1] == '\0')))) - { - return -1; - } + if ((l >= INT32_MIN) && (l <= INT32_MAX)) { + *n = (int32_t)l; + return 0; + } - *n = value; - - return 0; + errno = ERANGE; + return -1; } +int +gf_string2int64(const char *str, int64_t *n) +{ + long long l = 0LL; + int rv = 0; -static int -_gf_string2long (const char *str, long *n, int base) + rv = _gf_string2longlong(str, &l, 0); + if (rv != 0) + return rv; + + *n = (int64_t)l; + return 0; +} + +int +gf_string2uint8(const char *str, uint8_t *n) { - long value = 0; - char *tail = NULL; - int old_errno = 0; + unsigned long l = 0L; + int rv = 0; - if (str == NULL || n == NULL) - { - errno = EINVAL; - return -1; - } + rv = _gf_string2ulong(str, &l, 0); + if (rv != 0) + return rv; - old_errno = errno; - errno = 0; - value = strtol (str, &tail, base); + if (l <= UINT8_MAX) { + *n = (uint8_t)l; + return 0; + } - if (errno == ERANGE || errno == EINVAL) - { - return -1; - } + errno = ERANGE; + return -1; +} - if (errno == 0) - { - errno = old_errno; - } +int +gf_string2uint16(const char *str, uint16_t *n) +{ + unsigned long l = 0L; + int rv = 0; - if (tail[0] != '\0') - { - /* bala: invalid integer format */ - return -1; - } + rv = _gf_string2ulong(str, &l, 0); + if (rv != 0) + return rv; - *n = value; + if (l <= UINT16_MAX) { + *n = (uint16_t)l; + return 0; + } - return 0; + errno = ERANGE; + return -1; } -static int -_gf_string2ulong (const char *str, unsigned long *n, int base) -{ - unsigned long value = 0; - char *tail = NULL; - int old_errno = 0; - const char *s = NULL; - - if (str == NULL || n == NULL) - { - errno = EINVAL; - return -1; - } - - for (s = str; *s != '\0'; s++) - { - if (isspace (*s)) - { - continue; - } - if (*s == '-') - { - /* bala: we do not support suffixed (-) sign and - invalid integer format */ - return -1; - } - break; - } - - old_errno = errno; - errno = 0; - value = strtoul (str, &tail, base); - - if (errno == ERANGE || errno == EINVAL) - { - return -1; - } - - if (errno == 0) - { - errno = old_errno; - } - - if (tail[0] != '\0') - { - /* bala: invalid integer format */ - return -1; - } - - *n = value; - - return 0; -} +int +gf_string2uint32(const char *str, uint32_t *n) +{ + unsigned long l = 0L; + int rv = 0; -static int -_gf_string2uint (const char *str, unsigned int *n, int base) -{ - unsigned long value = 0; - char *tail = NULL; - int old_errno = 0; - const char *s = NULL; - - if (str == NULL || n == NULL) - { - errno = EINVAL; - return -1; - } - - for (s = str; *s != '\0'; s++) - { - if (isspace (*s)) - { - continue; - } - if (*s == '-') - { - /* bala: we do not support suffixed (-) sign and - invalid integer format */ - return -1; - } - break; - } - - old_errno = errno; - errno = 0; - value = strtoul (str, &tail, base); - - if (errno == ERANGE || errno == EINVAL) - { - return -1; - } - - if (errno == 0) - { - errno = old_errno; - } - - if (tail[0] != '\0') - { - /* bala: invalid integer format */ - return -1; - } - - *n = (unsigned int)value; - - return 0; + rv = _gf_string2ulong(str, &l, 0); + if (rv != 0) + return rv; + + if (l <= UINT32_MAX) { + *n = (uint32_t)l; + return 0; + } + + errno = ERANGE; + return -1; } -static int -_gf_string2double (const char *str, double *n) +int +gf_string2uint64(const char *str, uint64_t *n) { - double value = 0.0; - char *tail = NULL; - int old_errno = 0; + unsigned long long l = 0ULL; + int rv = 0; - if (str == NULL || n == NULL) { - errno = EINVAL; - return -1; - } + rv = _gf_string2ulonglong(str, &l, 0); + if (rv != 0) + return rv; - old_errno = errno; - errno = 0; - value = strtod (str, &tail); + if (l <= UINT64_MAX) { + *n = (uint64_t)l; + return 0; + } + + errno = ERANGE; + return -1; +} + +int +gf_string2ulong_base10(const char *str, unsigned long *n) +{ + return _gf_string2ulong(str, n, 10); +} - if (errno == ERANGE || errno == EINVAL) { - return -1; - } +int +gf_string2uint_base10(const char *str, unsigned int *n) +{ + return _gf_string2uint(str, n, 10); +} - if (errno == 0) { - errno = old_errno; - } +int +gf_string2uint8_base10(const char *str, uint8_t *n) +{ + unsigned long l = 0L; + int rv = 0; - if (tail[0] != '\0') { - return -1; - } + rv = _gf_string2ulong(str, &l, 10); + if (rv != 0) + return rv; - *n = value; + if (l <= UINT8_MAX) { + *n = (uint8_t)l; + return 0; + } - return 0; + errno = ERANGE; + return -1; } -static int -_gf_string2longlong (const char *str, long long *n, int base) +int +gf_string2uint16_base10(const char *str, uint16_t *n) { - long long value = 0; - char *tail = NULL; - int old_errno = 0; + unsigned long l = 0L; + int rv = 0; - if (str == NULL || n == NULL) - { - errno = EINVAL; - return -1; - } + rv = _gf_string2ulong(str, &l, 10); + if (rv != 0) + return rv; - old_errno = errno; - errno = 0; - value = strtoll (str, &tail, base); + if (l <= UINT16_MAX) { + *n = (uint16_t)l; + return 0; + } - if (errno == ERANGE || errno == EINVAL) - { - return -1; - } + errno = ERANGE; + return -1; +} - if (errno == 0) - { - errno = old_errno; - } +int +gf_string2uint32_base10(const char *str, uint32_t *n) +{ + unsigned long l = 0L; + int rv = 0; - if (tail[0] != '\0') - { - /* bala: invalid integer format */ - return -1; - } + rv = _gf_string2ulong(str, &l, 10); + if (rv != 0) + return rv; - *n = value; + if (l <= UINT32_MAX) { + *n = (uint32_t)l; + return 0; + } - return 0; + errno = ERANGE; + return -1; } -static int -_gf_string2ulonglong (const char *str, unsigned long long *n, int base) +int +gf_string2uint64_base10(const char *str, uint64_t *n) { - unsigned long long value = 0; - char *tail = NULL; - int old_errno = 0; - const char *s = NULL; + unsigned long long l = 0ULL; + int rv = 0; - if (str == NULL || n == NULL) - { - errno = EINVAL; - return -1; - } + rv = _gf_string2ulonglong(str, &l, 10); + if (rv != 0) + return rv; - for (s = str; *s != '\0'; s++) - { - if (isspace (*s)) - { - continue; - } - if (*s == '-') - { - /* bala: we do not support suffixed (-) sign and - invalid integer format */ - return -1; - } - break; - } + if (l <= UINT64_MAX) { + *n = (uint64_t)l; + return 0; + } - old_errno = errno; - errno = 0; - value = strtoull (str, &tail, base); + errno = ERANGE; + return -1; +} - if (errno == ERANGE || errno == EINVAL) - { - return -1; - } +char * +gf_uint64_2human_readable(uint64_t n) +{ + int ret = 0; + char *str = NULL; + + if (n >= GF_UNIT_PB) { + ret = gf_asprintf(&str, "%.1lfPB", ((double)n) / GF_UNIT_PB); + if (ret < 0) + goto err; + } else if (n >= GF_UNIT_TB) { + ret = gf_asprintf(&str, "%.1lfTB", ((double)n) / GF_UNIT_TB); + if (ret < 0) + goto err; + } else if (n >= GF_UNIT_GB) { + ret = gf_asprintf(&str, "%.1lfGB", ((double)n) / GF_UNIT_GB); + if (ret < 0) + goto err; + } else if (n >= GF_UNIT_MB) { + ret = gf_asprintf(&str, "%.1lfMB", ((double)n) / GF_UNIT_MB); + if (ret < 0) + goto err; + } else if (n >= GF_UNIT_KB) { + ret = gf_asprintf(&str, "%.1lfKB", ((double)n) / GF_UNIT_KB); + if (ret < 0) + goto err; + } else { + ret = gf_asprintf(&str, "%" PRIu64 "Bytes", n); + if (ret < 0) + goto err; + } + return str; +err: + return NULL; +} - if (errno == 0) - { - errno = old_errno; - } +int +gf_string2bytesize_range(const char *str, uint64_t *n, uint64_t umax) +{ + double value = 0.0; + int64_t int_value = 0; + uint64_t unit = 0; + int64_t max = 0; + char *tail = NULL; + int old_errno = 0; + const char *s = NULL; + gf_boolean_t fraction = _gf_false; + + if (str == NULL || n == NULL) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "argument invalid"); + errno = EINVAL; + return -1; + } + + max = umax & 0x7fffffffffffffffLL; + + for (s = str; *s != '\0'; s++) { + if (isspace(*s)) + continue; + if (*s == '-') + return -1; + break; + } + + if (strrchr(str, '.')) + fraction = _gf_true; + + old_errno = errno; + errno = 0; + if (fraction) + value = strtod(str, &tail); + else + int_value = strtoll(str, &tail, 10); + + if (str == tail) + errno = EINVAL; + + if (errno == ERANGE || errno == EINVAL) + return -1; + + if (errno == 0) + errno = old_errno; + + if (tail[0] != '\0') { + if (strcasecmp(tail, GF_UNIT_KB_STRING) == 0) + unit = GF_UNIT_KB; + else if (strcasecmp(tail, GF_UNIT_MB_STRING) == 0) + unit = GF_UNIT_MB; + else if (strcasecmp(tail, GF_UNIT_GB_STRING) == 0) + unit = GF_UNIT_GB; + else if (strcasecmp(tail, GF_UNIT_TB_STRING) == 0) + unit = GF_UNIT_TB; + else if (strcasecmp(tail, GF_UNIT_PB_STRING) == 0) + unit = GF_UNIT_PB; + else if (strcasecmp(tail, GF_UNIT_B_STRING) != 0) + return -1; + + if (unit > 0) { + if (fraction) + value *= unit; + else + int_value *= unit; + } + } - if (tail[0] != '\0') - { - /* bala: invalid integer format */ - return -1; - } + if (fraction) { + if ((max - value) < 0) { + errno = ERANGE; + return -1; + } + *n = (uint64_t)value; + } else { + if ((max - int_value) < 0) { + errno = ERANGE; + return -1; + } + *n = int_value; + } - *n = value; + return 0; +} - return 0; +int +gf_string2bytesize_uint64(const char *str, uint64_t *n) +{ + return gf_string2bytesize_range(str, n, UINT64_MAX); } int -gf_string2long (const char *str, long *n) +gf_string2bytesize_int64(const char *str, int64_t *n) { - return _gf_string2long (str, n, 0); + uint64_t u64 = 0; + int ret = 0; + + ret = gf_string2bytesize_range(str, &u64, INT64_MAX); + *n = (int64_t)u64; + return ret; } int -gf_string2ulong (const char *str, unsigned long *n) +gf_string2percent_or_bytesize(const char *str, double *n, + gf_boolean_t *is_percent) { - return _gf_string2ulong (str, n, 0); + double value = 0ULL; + char *tail = NULL; + int old_errno = 0; + const char *s = NULL; + + if (str == NULL || n == NULL) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "argument invalid"); + errno = EINVAL; + return -1; + } + + for (s = str; *s != '\0'; s++) { + if (isspace(*s)) + continue; + if (*s == '-') + return -1; + break; + } + + old_errno = errno; + errno = 0; + value = strtod(str, &tail); + if (str == tail) + errno = EINVAL; + + if (errno == ERANGE || errno == EINVAL) + return -1; + + if (errno == 0) + errno = old_errno; + + /*Maximum accepted value for 64 bit OS will be (2^14 -1)PB*/ + if (tail[0] != '\0') { + if (strcasecmp(tail, GF_UNIT_KB_STRING) == 0) + value *= GF_UNIT_KB; + else if (strcasecmp(tail, GF_UNIT_MB_STRING) == 0) + value *= GF_UNIT_MB; + else if (strcasecmp(tail, GF_UNIT_GB_STRING) == 0) + value *= GF_UNIT_GB; + else if (strcasecmp(tail, GF_UNIT_TB_STRING) == 0) + value *= GF_UNIT_TB; + else if (strcasecmp(tail, GF_UNIT_PB_STRING) == 0) + value *= GF_UNIT_PB; + else if (strcasecmp(tail, GF_UNIT_PERCENT_STRING) == 0) + *is_percent = _gf_true; + else + return -1; + } + + /* Error out if we cannot store the value in uint64 */ + if ((UINT64_MAX - value) < 0) { + errno = ERANGE; + return -1; + } + + *n = value; + + return 0; +} + +int64_t +gf_str_to_long_long(const char *number) +{ + int64_t unit = 1; + int64_t ret = 0; + char *endptr = NULL; + if (!number) + return 0; + + ret = strtoll(number, &endptr, 0); + + if (endptr) { + switch (*endptr) { + case 'G': + case 'g': + if ((*(endptr + 1) == 'B') || (*(endptr + 1) == 'b')) + unit = 1024 * 1024 * 1024; + break; + case 'M': + case 'm': + if ((*(endptr + 1) == 'B') || (*(endptr + 1) == 'b')) + unit = 1024 * 1024; + break; + case 'K': + case 'k': + if ((*(endptr + 1) == 'B') || (*(endptr + 1) == 'b')) + unit = 1024; + break; + case '%': + unit = 1; + break; + default: + unit = 1; + break; + } + } + return ret * unit; } int -gf_string2int (const char *str, int *n) +gf_string2boolean(const char *str, gf_boolean_t *b) { - return _gf_string2long (str, (long *) n, 0); + if (str == NULL) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "argument invalid"); + return -1; + } + + if ((strcasecmp(str, "1") == 0) || (strcasecmp(str, "on") == 0) || + (strcasecmp(str, "yes") == 0) || (strcasecmp(str, "true") == 0) || + (strcasecmp(str, "enable") == 0)) { + *b = _gf_true; + return 0; + } + + if ((strcasecmp(str, "0") == 0) || (strcasecmp(str, "off") == 0) || + (strcasecmp(str, "no") == 0) || (strcasecmp(str, "false") == 0) || + (strcasecmp(str, "disable") == 0)) { + *b = _gf_false; + return 0; + } + + return -1; } int -gf_string2uint (const char *str, unsigned int *n) +gf_strn2boolean(const char *str, const int len, gf_boolean_t *b) { - return _gf_string2uint (str, n, 0); + if (str == NULL) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "argument invalid"); + return -1; + } + + switch (len) { + case 1: + if (strcasecmp(str, "1") == 0) { + *b = _gf_true; + return 0; + } else if (strcasecmp(str, "0") == 0) { + *b = _gf_false; + return 0; + } + break; + case 2: + if (strcasecmp(str, "on") == 0) { + *b = _gf_true; + return 0; + } else if (strcasecmp(str, "no") == 0) { + *b = _gf_false; + return 0; + } + break; + case 3: + if (strcasecmp(str, "yes") == 0) { + *b = _gf_true; + return 0; + } else if (strcasecmp(str, "off") == 0) { + *b = _gf_false; + return 0; + } + break; + case 4: + if (strcasecmp(str, "true") == 0) { + *b = _gf_true; + return 0; + } + break; + case 5: + if (strcasecmp(str, "false") == 0) { + *b = _gf_false; + return 0; + } + break; + case 6: + if (strcasecmp(str, "enable") == 0) { + *b = _gf_true; + return 0; + } + break; + case 7: + if (strcasecmp(str, "disable") == 0) { + *b = _gf_false; + return 0; + } + break; + default: + return -1; + break; + } + return -1; } int -gf_string2double (const char *str, double *n) +gf_lockfd(int fd) { - return _gf_string2double (str, n); + struct gf_flock fl; + + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + + return fcntl(fd, F_SETLK, &fl); } int -gf_string2longlong (const char *str, long long *n) +gf_unlockfd(int fd) { - return _gf_string2longlong (str, n, 0); + struct gf_flock fl; + + fl.l_type = F_UNLCK; + fl.l_whence = SEEK_SET; + fl.l_start = 0; + fl.l_len = 0; + + return fcntl(fd, F_SETLK, &fl); } +static void +compute_checksum(char *buf, const ssize_t size, uint32_t *checksum) +{ + int ret = -1; + char *checksum_buf = NULL; + + checksum_buf = (char *)(checksum); + + if (!(*checksum)) { + checksum_buf[0] = 0xba; + checksum_buf[1] = 0xbe; + checksum_buf[2] = 0xb0; + checksum_buf[3] = 0x0b; + } + + for (ret = 0; ret < (size - 4); ret += 4) { + checksum_buf[0] ^= (buf[ret]); + checksum_buf[1] ^= (buf[ret + 1] << 1); + checksum_buf[2] ^= (buf[ret + 2] << 2); + checksum_buf[3] ^= (buf[ret + 3] << 3); + } + + for (ret = 0; ret <= (size % 4); ret++) { + checksum_buf[ret] ^= (buf[(size - 4) + ret] << ret); + } + + return; +} + +#define GF_CHECKSUM_BUF_SIZE 1024 + int -gf_string2ulonglong (const char *str, unsigned long long *n) +get_checksum_for_file(int fd, uint32_t *checksum, int op_version) { - return _gf_string2ulonglong (str, n, 0); + int ret = -1; + char buf[GF_CHECKSUM_BUF_SIZE] = { + 0, + }; + + /* goto first place */ + sys_lseek(fd, 0L, SEEK_SET); + do { + ret = sys_read(fd, &buf, GF_CHECKSUM_BUF_SIZE); + if (ret > 0) { + if (op_version < GD_OP_VERSION_5_4) + compute_checksum(buf, GF_CHECKSUM_BUF_SIZE, checksum); + else + compute_checksum(buf, ret, checksum); + } + } while (ret > 0); + + /* set it back */ + sys_lseek(fd, 0L, SEEK_SET); + + return ret; } int -gf_string2int8 (const char *str, int8_t *n) +get_checksum_for_path(char *path, uint32_t *checksum, int op_version) { - long l = 0L; - int rv = 0; + int ret = -1; + int fd = -1; + + GF_ASSERT(path); + GF_ASSERT(checksum); + + fd = open(path, O_RDWR); - rv = _gf_string2long (str, &l, 0); - if (rv != 0) - return rv; + if (fd == -1) { + gf_smsg(THIS->name, GF_LOG_ERROR, errno, LG_MSG_PATH_OPEN_FAILED, + "path=%s", path, NULL); + goto out; + } - if (l >= INT8_MIN && l <= INT8_MAX) - { - *n = (int8_t) l; - return 0; - } + ret = get_checksum_for_file(fd, checksum, op_version); - errno = ERANGE; - return -1; +out: + if (fd != -1) + sys_close(fd); + + return ret; } +/** + * get_file_mtime -- Given a path, get the mtime for the file + * + * @path: The filepath to check the mtime on + * @stamp: The parameter to set after we get the mtime + * + * @returns: success: 0 + * errors : Errors returned by the stat () call + */ int -gf_string2int16 (const char *str, int16_t *n) +get_file_mtime(const char *path, time_t *stamp) +{ + struct stat f_stat = {0}; + int ret = -EINVAL; + + GF_VALIDATE_OR_GOTO(THIS->name, path, out); + GF_VALIDATE_OR_GOTO(THIS->name, stamp, out); + + ret = sys_stat(path, &f_stat); + if (ret < 0) { + gf_smsg(THIS->name, GF_LOG_ERROR, errno, LG_MSG_FILE_STAT_FAILED, + "path=%s", path, NULL); + goto out; + } + + /* Set the mtime */ + *stamp = f_stat.st_mtime; +out: + return ret; +} + +/** + * gf_is_ip_in_net -- Checks if an IP Address is in a network. + * A network should be specified by something like + * '10.5.153.0/24' (in CIDR notation). + * + * @result : Sets to true if the IP is in the network + * @ip_str : The IP to check + * @network: The network to check the IP against. + * + * @return: success: _gf_true + * failure: -EINVAL for bad args, retval of inet_pton otherwise + */ +gf_boolean_t +gf_is_ip_in_net(const char *network, const char *ip_str) +{ + unsigned long ip_buf = 0; + unsigned long net_ip_buf = 0; + unsigned long subnet_mask = 0; + int ret = -EINVAL; + char *slash = NULL; + char *net_ip = NULL; + char *subnet = NULL; + char *net_str = NULL; + int family = AF_INET; + gf_boolean_t result = _gf_false; + + GF_ASSERT(network); + GF_ASSERT(ip_str); + + if (strchr(network, ':')) + family = AF_INET6; + else if (strchr(network, '.')) + family = AF_INET; + else { + goto out; + } + + net_str = strdupa(network); + slash = strchr(net_str, '/'); + if (!slash) + goto out; + *slash = '\0'; + + subnet = slash + 1; + net_ip = net_str; + + /* Convert IP address to a long */ + ret = inet_pton(family, ip_str, &ip_buf); + if (ret < 0) + gf_smsg("common-utils", GF_LOG_ERROR, errno, LG_MSG_INET_PTON_FAILED, + NULL); + + /* Convert network IP address to a long */ + ret = inet_pton(family, net_ip, &net_ip_buf); + if (ret < 0) { + gf_smsg("common-utils", GF_LOG_ERROR, errno, LG_MSG_INET_PTON_FAILED, + NULL); + goto out; + } + + /* Converts /x into a mask */ + subnet_mask = (1 << atoi(subnet)) - 1; + + result = ((ip_buf & subnet_mask) == (net_ip_buf & subnet_mask)); +out: + return result; +} + +char * +strtail(char *str, const char *pattern) { - long l = 0L; - int rv = 0; + int i = 0; - rv = _gf_string2long (str, &l, 0); - if (rv != 0) - return rv; + for (i = 0; str[i] == pattern[i] && str[i]; i++) + ; - if (l >= INT16_MIN && l <= INT16_MAX) - { - *n = (int16_t) l; - return 0; - } + if (pattern[i] == '\0') + return str + i; - errno = ERANGE; - return -1; + return NULL; +} + +void +skipwhite(char **s) +{ + while (isspace(**s)) + (*s)++; +} + +void +gf_strTrim(char **s) +{ + char *end = NULL; + + end = *s + strlen(*s) - 1; + while (end > *s && isspace((unsigned char)*end)) + end--; + + *(end + 1) = '\0'; + + while (isspace(**s)) + (*s)++; + + return; +} + +char * +nwstrtail(char *str, char *pattern) +{ + for (;;) { + skipwhite(&str); + skipwhite(&pattern); + + if (*str != *pattern || !*str) + break; + + str++; + pattern++; + } + + return *pattern ? NULL : str; +} + +/** + * token_iter_init -- initialize tokenization + * + * @str: string to be tokenized + * @sep: token separator character + * @tit: pointer to iteration state + * + * @return: token string + * + * The returned token string and tit are + * not to be used directly, but through + * next_token(). + */ +char * +token_iter_init(char *str, char sep, token_iter_t *tit) +{ + tit->end = str + strlen(str); + tit->sep = sep; + + return str; +} + +/** + * next_token -- fetch next token in tokenization + * inited by token_iter_init(). + * + * @tokenp: pointer to token + * @tit: pointer to iteration state + * + * @return: true if iteration ends, else false + * + * The token pointed by @tokenp can be used + * after a call to next_token(). When next_token() + * returns true the iteration is to be stopped + * and the string with which the tokenization + * was inited (see token_iter_init() is restored, + * apart from dropped tokens (see drop_token()). + */ +gf_boolean_t +next_token(char **tokenp, token_iter_t *tit) +{ + char *cursor = NULL; + gf_boolean_t is_last = _gf_false; + + for (cursor = *tokenp; *cursor; cursor++) + ; + if (cursor < tit->end) { + /* + * We detect that in between current token and end a zero + * marker has already been inserted. This means that the + * token has already been returned. We restore the + * separator and move ahead. + */ + *cursor = tit->sep; + *tokenp = cursor + 1; + } + + for (cursor = *tokenp; *cursor && *cursor != tit->sep; cursor++) + ; + /* If the cursor ended up on a zero byte, then it's the last token. */ + is_last = !*cursor; + /* Zero-terminate the token. */ + *cursor = 0; + + return is_last; +} + +/* + * drop_token -- drop a token during iterated calls of next_token(). + * + * Sample program that uses these functions to tokenize + * a comma-separated first argument while dropping the + * rest of the arguments if they occur as token: + * + * #include <stdio.h> + * #include <stdlib.h> + * #include <string.h> + * #include "glusterfs/common-utils.h" + * + * int + * main (int argc, char **argv) + * { + * char *buf; + * char *token; + * token_iter_t tit; + * int i; + * gf_boolean_t iter_end; + * + * if (argc <= 1) + * abort(); + * + * buf = strdup (argv[1]); + * if (!buf) + * abort(); + * + * for (token = token_iter_init (buf, ',', &tit) ;;) { + * iter_end = next_token (&token, &tit); + * printf("found token: '%s'\n", token); + * for (i = 2; i < argc; i++) { + * if (strcmp (argv[i], token) == 0) { + * printf ("%s\n", "dropping token!"); + * drop_token (token, &tit); + * break; + * } + * } + * if (iter_end) + * break; + * } + * + * printf ("finally: '%s'\n", buf); + * + * return 0; + * } + */ +void +drop_token(char *token, token_iter_t *tit) +{ + char *cursor = NULL; + + for (cursor = token; *cursor; cursor++) + ; + if (cursor < tit->end) { + /* + * We detect a zero inserted by next_token(). + * Step the cursor and copy what comes after + * to token. + */ + for (cursor++; cursor < tit->end; *token++ = *cursor++) + ; + } + + /* + * Zero out the remainder of the buffer. + * It would be enough to insert just a single zero, + * but we continue 'till the end to have cleaner + * memory content. + */ + for (cursor = token; cursor < tit->end; *cursor++ = 0) + ; + + /* Adjust the end to point to the new terminating zero. */ + tit->end = token; +} + +/* Syntax formed according to RFC 1912 (RFC 1123 & 952 are more restrictive) * + <hname> ::= <gen-name>*["."<gen-name>] * + <gen-name> ::= <let-or-digit> <[*[<let-or-digit-or-hyphen>]<let-or-digit>] */ +char +valid_host_name(char *address, int length) +{ + int i = 0; + int str_len = 0; + char ret = 1; + char *dup_addr = NULL; + char *temp_str = NULL; + char *save_ptr = NULL; + + if ((length > _POSIX_HOST_NAME_MAX) || (length < 1)) { + ret = 0; + goto out; + } + + dup_addr = gf_strdup(address); + if (!dup_addr) { + ret = 0; + goto out; + } + + if (!isalnum(dup_addr[length - 1]) && (dup_addr[length - 1] != '*')) { + ret = 0; + 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 { + str_len = strlen(temp_str); + + if (!isalnum(temp_str[0]) || !isalnum(temp_str[str_len - 1])) { + ret = 0; + goto out; + } + for (i = 1; i < str_len; i++) { + if (!isalnum(temp_str[i]) && (temp_str[i] != '-')) { + ret = 0; + goto out; + } + } + } while ((temp_str = strtok_r(NULL, ".", &save_ptr))); + +out: + GF_FREE(dup_addr); + return ret; +} + +/* Matches all ipv4 address, if wildcard_acc is true '*' wildcard pattern for* + subnets is considered as valid strings as well */ +char +valid_ipv4_address(char *address, int length, gf_boolean_t wildcard_acc) +{ + int octets = 0; + int value = 0; + char *tmp = NULL, *ptr = NULL, *prev = NULL, *endptr = NULL; + char ret = 1; + int is_wildcard = 0; + + tmp = gf_strdup(address); + + /* + * To prevent cases where last character is '.' and which have + * consecutive dots like ".." as strtok ignore consecutive + * delimiters. + */ + if (length <= 0 || (strstr(address, "..")) || + (!isdigit(tmp[length - 1]) && (tmp[length - 1] != '*'))) { + ret = 0; + goto out; + } + + prev = strtok_r(tmp, ".", &ptr); + + while (prev != NULL) { + octets++; + if (wildcard_acc && !strcmp(prev, "*")) { + is_wildcard = 1; + } else { + value = strtol(prev, &endptr, 10); + if ((value > 255) || (value < 0) || + (endptr != NULL && *endptr != '\0')) { + ret = 0; + goto out; + } + } + prev = strtok_r(NULL, ".", &ptr); + } + + if ((octets > 4) || (octets < 4 && !is_wildcard)) { + ret = 0; + } + +out: + GF_FREE(tmp); + return ret; +} + +char +valid_cidr_address(char *cidr_address, gf_boolean_t wildcard_acc) +{ + unsigned int net_mask = 0, len = 0; + char *temp = NULL, *cidr_str = NULL, ret = 1; + + cidr_str = strdupa(cidr_address); + temp = strstr(cidr_str, "/"); + if (temp == NULL) + return 0; /* Since Invalid cidr ip address we return 0 */ + + *temp = '\0'; + temp++; + net_mask = (unsigned int)atoi(temp); + + if (net_mask > 32 || net_mask < 1) + return 0; /* Since Invalid cidr ip address we return 0*/ + + len = strlen(cidr_str); + + ret = valid_ipv4_address(cidr_str, len, wildcard_acc); + + return ret; +} + +/** + * valid_ipv4_subnetwork() takes the pattern and checks if it contains + * a valid ipv4 subnetwork pattern i.e. xx.xx.xx.xx/n. IPv4 address + * part (xx.xx.xx.xx) and mask bits length part (n). The mask bits length + * must be in 0-32 range (ipv4 addr is 32 bit). The pattern must be + * in this format. + * + * Returns _gf_true if both IP addr and mask bits len are valid + * _gf_false otherwise. + */ +gf_boolean_t +valid_ipv4_subnetwork(const char *address) +{ + char *slash = NULL; + char *paddr = NULL; + char *endptr = NULL; + long prefixlen = -1; + gf_boolean_t retv = _gf_true; + + if (address == NULL) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "argument invalid"); + return _gf_false; + } + + paddr = gf_strdup(address); + if (paddr == NULL) /* ENOMEM */ + return _gf_false; + + /* + * INVALID: If '/' is not present OR + * Nothing specified after '/' + */ + slash = strchr(paddr, '/'); + if ((slash == NULL) || (slash[1] == '\0')) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, 0, + LG_MSG_INVALID_IPV4_FORMAT, + "Invalid IPv4 " + "subnetwork format"); + retv = _gf_false; + goto out; + } + + *slash = '\0'; + retv = valid_ipv4_address(paddr, strlen(paddr), _gf_false); + if (retv == _gf_false) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, 0, + LG_MSG_INVALID_IPV4_FORMAT, + "Invalid IPv4 subnetwork address"); + goto out; + } + /* + * Reset errno before checking it + */ + errno = 0; + prefixlen = strtol(slash + 1, &endptr, 10); + if ((errno != 0) || (*endptr != '\0') || (prefixlen < 0) || + (prefixlen > IPv4_ADDR_SIZE)) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, 0, + LG_MSG_INVALID_IPV4_FORMAT, + "Invalid IPv4 subnetwork mask"); + retv = _gf_false; + goto out; + } + + retv = _gf_true; +out: + GF_FREE(paddr); + return retv; +} + +char +valid_ipv6_address(char *address, int length, gf_boolean_t wildcard_acc) +{ + int hex_numbers = 0; + int value = 0; + int i = 0; + char *tmp = NULL, *ptr = NULL, *prev = NULL, *endptr = NULL; + char ret = 1; + int is_wildcard = 0; + int is_compressed = 0; + + tmp = gf_strdup(address); + + /* Check for '%' for link local addresses */ + endptr = strchr(tmp, '%'); + if (endptr) { + *endptr = '\0'; + length = strlen(tmp); + endptr = NULL; + } + + /* Check for compressed form */ + if (length <= 0 || tmp[length - 1] == ':') { + ret = 0; + goto out; + } + for (i = 0; i < (length - 1); i++) { + if (tmp[i] == ':' && tmp[i + 1] == ':') { + if (is_compressed == 0) + is_compressed = 1; + else { + ret = 0; + goto out; + } + } + } + + prev = strtok_r(tmp, ":", &ptr); + + while (prev != NULL) { + hex_numbers++; + if (wildcard_acc && !strcmp(prev, "*")) { + is_wildcard = 1; + } else { + value = strtol(prev, &endptr, 16); + if ((value > 0xffff) || (value < 0) || + (endptr != NULL && *endptr != '\0')) { + ret = 0; + goto out; + } + } + prev = strtok_r(NULL, ":", &ptr); + } + + if ((hex_numbers > 8) || + (hex_numbers < 8 && !is_wildcard && !is_compressed)) { + ret = 0; + } + +out: + GF_FREE(tmp); + return ret; +} + +char +valid_internet_address(char *address, gf_boolean_t wildcard_acc, + gf_boolean_t cidr) +{ + char ret = 0; + int length = 0; + + if (address == NULL) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "argument invalid"); + goto out; + } + + length = strlen(address); + if (length == 0) + goto out; + + if (cidr && valid_cidr_address(address, wildcard_acc)) { + ret = 1; + } + + if (valid_ipv4_address(address, length, wildcard_acc) || + valid_ipv6_address(address, length, wildcard_acc) || + valid_host_name(address, length)) + ret = 1; + +out: + return ret; +} + +/** + * valid_mount_auth_address - Validate the rpc-auth.addr.allow/reject pattern + * + * @param address - Pattern to be validated + * + * @return _gf_true if "address" is "*" (anonymous) 'OR' + * if "address" is valid FQDN or valid IPv4/6 address 'OR' + * if "address" contains wildcard chars e.g. "'*' or '?' or + * '['" if "address" is valid ipv4 subnet pattern (xx.xx.xx.xx/n) _gf_false + * otherwise + * + * + * NB: If the user/admin set for wildcard pattern, then it does not have + * to be validated. Make it similar to the way exportfs (kNFS) works. + */ +gf_boolean_t +valid_mount_auth_address(char *address) +{ + int length = 0; + char *cp = NULL; + + /* 1. Check for "NULL and empty string */ + if ((address == NULL) || (address[0] == '\0')) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "argument invalid"); + return _gf_false; + } + + /* 2. Check for Anonymous */ + if (strcmp(address, "*") == 0) + return _gf_true; + + for (cp = address; *cp; cp++) { + /* 3. Check for wildcard pattern */ + if (*cp == '*' || *cp == '?' || *cp == '[') { + return _gf_true; + } + + /* + * 4. check for IPv4 subnetwork i.e. xx.xx.xx.xx/n + * TODO: check for IPv6 subnetwork + * NB: Wildcard must not be mixed with subnetwork. + */ + if (*cp == '/') { + return valid_ipv4_subnetwork(address); + } + } + + /* 5. Check for v4/v6 IP addr and FQDN/hostname */ + length = strlen(address); + if ((valid_ipv4_address(address, length, _gf_false)) || + (valid_ipv6_address(address, length, _gf_false)) || + (valid_host_name(address, length))) { + return _gf_true; + } + + return _gf_false; +} + +/** + * 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_smsg("common-utils", GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, + "gf_sock_union_equal_addr", NULL); + 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_msg_debug("common-utils", 0, + "Unsupported/invalid address " + "family"); + break; + } + + return _gf_false; +} + +/* + * Check if both have same network address. + * Extract the network address from the sockaddr(s) addr by applying the + * network mask. If they match, return boolean _gf_true, _gf_false otherwise. + * + * (x == y) <=> (x ^ y == 0) + * (x & y) ^ (x & z) <=> x & (y ^ z) + * + * ((ip1 & mask) == (ip2 & mask)) <=> ((mask & (ip1 ^ ip2)) == 0) + */ +gf_boolean_t +mask_match(const uint32_t a, const uint32_t b, const uint32_t m) +{ + return (((a ^ b) & m) == 0); +} + +/*Thread safe conversion function*/ +char * +uuid_utoa(uuid_t uuid) +{ + char *uuid_buffer = glusterfs_uuid_buf_get(); + gf_uuid_unparse(uuid, uuid_buffer); + return uuid_buffer; +} + +/*Re-entrant conversion function*/ +char * +uuid_utoa_r(uuid_t uuid, char *dst) +{ + if (!dst) + return NULL; + gf_uuid_unparse(uuid, dst); + return dst; +} + +/*Thread safe conversion function*/ +char * +lkowner_utoa(gf_lkowner_t *lkowner) +{ + char *lkowner_buffer = glusterfs_lkowner_buf_get(); + lkowner_unparse(lkowner, lkowner_buffer, GF_LKOWNER_BUF_SIZE); + return lkowner_buffer; +} + +/*Re-entrant conversion function*/ +char * +lkowner_utoa_r(gf_lkowner_t *lkowner, char *dst, int len) +{ + if (!dst) + return NULL; + lkowner_unparse(lkowner, dst, len); + return dst; +} + +gf_boolean_t +is_valid_lease_id(const char *lease_id) +{ + int i = 0; + gf_boolean_t valid = _gf_false; + + for (i = 0; i < LEASE_ID_SIZE; i++) { + if (lease_id[i] != 0) { + valid = _gf_true; + goto out; + } + } +out: + return valid; +} + +/* Lease_id can be a either in printable or non printable binary + * format. This function can be used to print any lease_id. + * + * This function returns a pointer to a buf, containing the ascii + * representation of the value in lease_id, in the following format: + * 4hexnum-4hexnum-4hexnum-4hexnum-4hexnum-4hexnum-4hexnum-4hexnum + * + * Eg: If lease_id = "lid1-clnt1" the printable string would be: + * 6c69-6431-2d63-6c6e-7431-0000-0000-0000 + * + * Note: The pointer returned should not be stored for further use, as any + * subsequent call to this function will override the same buffer. + */ +char * +leaseid_utoa(const char *lease_id) +{ + char *buf = NULL; + int i = 0; + int j = 0; + + buf = glusterfs_leaseid_buf_get(); + if (!buf) + goto out; + + for (i = 0; i < LEASE_ID_SIZE; i++) { + if (i && !(i % 2)) { + buf[j] = '-'; + j++; + } + sprintf(&buf[j], "%02hhx", lease_id[i]); + j += 2; + if (j == GF_LEASE_ID_BUF_SIZE) + break; + } + buf[GF_LEASE_ID_BUF_SIZE - 1] = '\0'; +out: + return buf; +} + +char * +gf_leaseid_get() +{ + return glusterfs_leaseid_buf_get(); +} + +char * +gf_existing_leaseid() +{ + return glusterfs_leaseid_exist(); +} + +void * +gf_array_elem(void *a, int index, size_t elem_size) +{ + uint8_t *ptr = a; + return (void *)(ptr + index * elem_size); +} + +void +gf_elem_swap(void *x, void *y, size_t l) +{ + uint8_t *a = x, *b = y, c; + while (l--) { + c = *a; + *a++ = *b; + *b++ = c; + } +} + +void +gf_array_insertionsort(void *A, int l, int r, size_t elem_size, gf_cmp cmp) +{ + int i = l; + int N = r + 1; + void *Temp = NULL; + int j = 0; + + for (i = l; i < N; i++) { + Temp = gf_array_elem(A, i, elem_size); + j = i - 1; + while (j >= 0 && (cmp(Temp, gf_array_elem(A, j, elem_size)) < 0)) { + gf_elem_swap(Temp, gf_array_elem(A, j, elem_size), elem_size); + Temp = gf_array_elem(A, j, elem_size); + j = j - 1; + } + } } int -gf_string2int32 (const char *str, int32_t *n) +gf_is_str_int(const char *value) { - long l = 0L; - int rv = 0; + int flag = 0; + char *str = NULL; + char *fptr = NULL; + + GF_VALIDATE_OR_GOTO(THIS->name, value, out); - rv = _gf_string2long (str, &l, 0); - if (rv != 0) - return rv; + str = gf_strdup(value); + if (!str) + goto out; - if (l >= INT32_MIN && l <= INT32_MAX) - { - *n = (int32_t) l; - return 0; - } + fptr = str; + + while (*str) { + if (!isdigit(*str)) { + flag = 1; + goto out; + } + str++; + } - errno = ERANGE; - return -1; +out: + GF_FREE(fptr); + + return flag; +} +/* + * rounds up nr to power of two. If nr is already a power of two, just returns + * nr + */ + +int32_t +gf_roundup_power_of_two(int32_t nr) +{ + int32_t result = 1; + + if (nr < 0) { + gf_smsg("common-utils", GF_LOG_WARNING, 0, LG_MSG_NEGATIVE_NUM_PASSED, + NULL); + result = -1; + goto out; + } + + while (result < nr) + result *= 2; + +out: + return result; +} + +/* + * rounds up nr to next power of two. If nr is already a power of two, next + * power of two is returned. + */ + +int32_t +gf_roundup_next_power_of_two(int32_t nr) +{ + int32_t result = 1; + + if (nr < 0) { + gf_smsg("common-utils", GF_LOG_WARNING, 0, LG_MSG_NEGATIVE_NUM_PASSED, + NULL); + result = -1; + goto out; + } + + while (result <= nr) + result *= 2; + +out: + return result; } int -gf_string2int64 (const char *str, int64_t *n) +validate_brick_name(char *brick) { - long long l = 0LL; - int rv = 0; + char *delimiter = NULL; + int ret = 0; + delimiter = strrchr(brick, ':'); + if (!delimiter || delimiter == brick || *(delimiter + 1) != '/') + ret = -1; - rv = _gf_string2longlong (str, &l, 0); - if (rv != 0) - return rv; + return ret; +} - if (l >= INT64_MIN && l <= INT64_MAX) - { - *n = (int64_t) l; - return 0; - } +char * +get_host_name(char *word, char **host) +{ + char *delimiter = NULL; + delimiter = strrchr(word, ':'); + if (delimiter) + *delimiter = '\0'; + else + return NULL; + *host = word; + return *host; +} - errno = ERANGE; - return -1; +char * +get_path_name(char *word, char **path) +{ + char *delimiter = NULL; + delimiter = strchr(word, '/'); + if (!delimiter) + return NULL; + *path = delimiter; + return *path; } +void +gf_path_strip_trailing_slashes(char *path) +{ + int i = 0; + int len = 0; + + if (!path) + return; + + len = strlen(path); + for (i = len - 1; i > 0; i--) { + if (path[i] != '/') + break; + } + + if (i < (len - 1)) + path[i + 1] = '\0'; + + return; +} + +uint64_t +get_mem_size() +{ + uint64_t memsize = -1; + +#if defined GF_LINUX_HOST_OS || defined GF_SOLARIS_HOST_OS + + uint64_t page_size = 0; + uint64_t num_pages = 0; + + page_size = sysconf(_SC_PAGESIZE); + num_pages = sysconf(_SC_PHYS_PAGES); + + memsize = page_size * num_pages; +#endif + +#if defined GF_DARWIN_HOST_OS || defined __FreeBSD__ + + size_t len = sizeof(memsize); + int name[] = {CTL_HW, HW_PHYSMEM}; + + sysctl(name, 2, &memsize, &len, NULL, 0); +#endif + +#if defined __NetBSD__ + + size_t len = sizeof(memsize); + int name64[] = {CTL_HW, HW_PHYSMEM64}; + + sysctl(name64, 2, &memsize, &len, NULL, 0); + if (memsize == -1) + sysctl(name64, 2, &memsize, &len, NULL, 0); +#endif + return memsize; +} + +/* Strips all whitespace characters in a string and returns length of new string + * on success + */ int -gf_string2uint8 (const char *str, uint8_t *n) +gf_strip_whitespace(char *str, int len) { - unsigned long l = 0L; - int rv = 0; + int i = 0; + int new_len = 0; + char *new_str = NULL; + + GF_ASSERT(str); + + new_str = GF_MALLOC(len + 1, gf_common_mt_char); + if (new_str == NULL) + return -1; - rv = _gf_string2ulong (str, &l, 0); - if (rv != 0) - return rv; + for (i = 0; i < len; i++) { + if (!isspace(str[i])) + new_str[new_len++] = str[i]; + } + new_str[new_len] = '\0'; - if (l >= 0 && l <= UINT8_MAX) - { - *n = (uint8_t) l; - return 0; - } + if (new_len != len) { + snprintf(str, new_len + 1, "%s", new_str); + } - errno = ERANGE; - return -1; + GF_FREE(new_str); + return new_len; } int -gf_string2uint16 (const char *str, uint16_t *n) +gf_canonicalize_path(char *path) +{ + int ret = -1; + int path_len = 0; + int dir_path_len = 0; + char *tmppath = NULL; + char *dir = NULL; + char *tmpstr = NULL; + + if (!path || *path != '/') + goto out; + + if (!strcmp(path, "/")) + return 0; + + tmppath = gf_strdup(path); + if (!tmppath) + goto out; + + /* Strip the extra slashes and return */ + bzero(path, strlen(path)); + path[0] = '/'; + dir = strtok_r(tmppath, "/", &tmpstr); + + while (dir) { + dir_path_len = strlen(dir); + memcpy((path + path_len + 1), dir, dir_path_len); + path_len += dir_path_len + 1; + dir = strtok_r(NULL, "/", &tmpstr); + if (dir) { + path[path_len] = '/'; + } + } + path[path_len] = '\0'; + ret = 0; + +out: + if (ret) + gf_smsg("common-utils", GF_LOG_ERROR, 0, LG_MSG_PATH_ERROR, NULL); + + GF_FREE(tmppath); + + return ret; +} + +static const char *__gf_timefmts[] = { + "%F %T", "%Y/%m/%d-%T", "%b %d %T", "%F %H%M%S", "%Y-%m-%d-%T", "%s", +}; + +static const char *__gf_zerotimes[] = { + "0000-00-00 00:00:00", "0000/00/00-00:00:00", "xxx 00 00:00:00", + "0000-00-00 000000", "0000-00-00-00:00:00", "0", +}; + +void +_gf_timestuff(const char ***fmts, const char ***zeros) { - unsigned long l = 0L; - int rv = 0; + *fmts = __gf_timefmts; + *zeros = __gf_zerotimes; +} - rv = _gf_string2ulong (str, &l, 0); - if (rv != 0) - return rv; +char * +generate_glusterfs_ctx_id(void) +{ + uuid_t ctxid; + char *tmp = NULL; - if (l >= 0 && l <= UINT16_MAX) - { - *n = (uint16_t) l; - return 0; - } + gf_uuid_generate(ctxid); + tmp = uuid_utoa(ctxid); - errno = ERANGE; - return -1; + return gf_strdup(tmp); +} + +char * +gf_get_reserved_ports() +{ + char *ports_info = NULL; +#if defined GF_LINUX_HOST_OS + int proc_fd = -1; + char *proc_file = "/proc/sys/net/ipv4/ip_local_reserved_ports"; + char buffer[4096] = { + 0, + }; + int32_t ret = -1; + + proc_fd = open(proc_file, O_RDONLY); + if (proc_fd == -1) { + /* What should be done in this case? error out from here + * and thus stop the glusterfs process from starting or + * continue with older method of using any of the available + * port? For now 2nd option is considered. + */ + gf_smsg("glusterfs", GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED, + " /proc/sys/net/ipv4/ip_local_reserved_ports", NULL); + goto out; + } + + ret = sys_read(proc_fd, buffer, sizeof(buffer) - 1); + if (ret < 0) { + gf_smsg("glusterfs", GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED, + "file=%s", proc_file, NULL); + goto out; + } + + buffer[ret] = '\0'; + ports_info = gf_strdup(buffer); + +out: + if (proc_fd != -1) + sys_close(proc_fd); +#endif /* GF_LINUX_HOST_OS */ + return ports_info; } int -gf_string2uint32 (const char *str, uint32_t *n) +gf_process_reserved_ports(unsigned char *ports, uint32_t ceiling) { - unsigned long l = 0L; - int rv = 0; + int ret = -1; + + memset(ports, 0, GF_PORT_ARRAY_SIZE); + +#if defined GF_LINUX_HOST_OS + char *ports_info = NULL; + char *tmp = NULL; + char *blocked_port = NULL; - rv = _gf_string2ulong (str, &l, 0); - if (rv != 0) - return rv; + ports_info = gf_get_reserved_ports(); + if (!ports_info) { + gf_smsg("glusterfs", GF_LOG_WARNING, 0, LG_MSG_RESERVED_PORTS_ERROR, + NULL); + goto out; + } - if (l >= 0 && l <= UINT32_MAX) - { - *n = (uint32_t) l; - return 0; - } + blocked_port = strtok_r(ports_info, ",\n", &tmp); - errno = ERANGE; - return -1; + while (blocked_port) { + gf_ports_reserved(blocked_port, ports, ceiling); + blocked_port = strtok_r(NULL, ",\n", &tmp); + } + + ret = 0; + +out: + GF_FREE(ports_info); + +#else /* FIXME: Non Linux Host */ + ret = 0; +#endif /* GF_LINUX_HOST_OS */ + + return ret; } +gf_boolean_t +gf_ports_reserved(char *blocked_port, unsigned char *ports, uint32_t ceiling) +{ + gf_boolean_t result = _gf_false; + char *range_port = NULL; + int32_t tmp_port1 = -1; + int32_t tmp_port2 = -1; + + if (strstr(blocked_port, "-") == NULL) { + /* get rid of the new line character*/ + if (blocked_port[strlen(blocked_port) - 1] == '\n') + blocked_port[strlen(blocked_port) - 1] = '\0'; + if (gf_string2int32(blocked_port, &tmp_port1) == 0) { + if (tmp_port1 > GF_PORT_MAX || tmp_port1 < 0) { + gf_smsg("glusterfs-socket", GF_LOG_WARNING, 0, + LG_MSG_INVALID_PORT, "port=%d", tmp_port1, NULL); + result = _gf_true; + goto out; + } else { + gf_msg_debug("glusterfs", 0, + "blocking port " + "%d", + tmp_port1); + BIT_SET(ports, tmp_port1); + } + } else { + gf_smsg("glusterfs-socket", GF_LOG_WARNING, 0, LG_MSG_INVALID_PORT, + "port=%s", blocked_port, NULL); + result = _gf_true; + goto out; + } + } else { + range_port = strtok(blocked_port, "-"); + if (!range_port) { + result = _gf_true; + goto out; + } + if (gf_string2int32(range_port, &tmp_port1) == 0) { + if (tmp_port1 > ceiling) + tmp_port1 = ceiling; + if (tmp_port1 < 0) + tmp_port1 = 0; + } + range_port = strtok(NULL, "-"); + if (!range_port) { + result = _gf_true; + goto out; + } + /* get rid of the new line character*/ + if (range_port[strlen(range_port) - 1] == '\n') + range_port[strlen(range_port) - 1] = '\0'; + if (gf_string2int32(range_port, &tmp_port2) == 0) { + if (tmp_port2 > ceiling) + tmp_port2 = ceiling; + if (tmp_port2 < 0) + tmp_port2 = 0; + } + gf_msg_debug("glusterfs", 0, "lower: %d, higher: %d", tmp_port1, + tmp_port2); + for (; tmp_port1 <= tmp_port2; tmp_port1++) + BIT_SET(ports, tmp_port1); + } + +out: + return result; +} + +/* Takes in client ip{v4,v6} and returns associated hostname, if any + * Also, allocates memory for the hostname. + * Returns: 0 for success, -1 for failure + */ int -gf_string2uint64 (const char *str, uint64_t *n) +gf_get_hostname_from_ip(char *client_ip, char **hostname) +{ + int ret = -1; + struct sockaddr *client_sockaddr = NULL; + struct sockaddr_in client_sock_in = {0}; + struct sockaddr_in6 client_sock_in6 = {0}; + char client_hostname[NI_MAXHOST] = {0}; + char *client_ip_copy = NULL; + char *tmp = NULL; + char *ip = NULL; + size_t addr_sz = 0; + + /* if ipv4, reverse lookup the hostname to + * allow FQDN based rpc authentication + */ + if (!valid_ipv6_address(client_ip, strlen(client_ip), 0) && + !valid_ipv4_address(client_ip, strlen(client_ip), 0)) { + /* most times, we get a.b.c.d:port form, so check that */ + client_ip_copy = gf_strdup(client_ip); + if (!client_ip_copy) + goto out; + + ip = strtok_r(client_ip_copy, ":", &tmp); + } else { + ip = client_ip; + } + + if (valid_ipv4_address(ip, strlen(ip), 0) == _gf_true) { + client_sockaddr = (struct sockaddr *)&client_sock_in; + addr_sz = sizeof(client_sock_in); + client_sock_in.sin_family = AF_INET; + ret = inet_pton(AF_INET, ip, (void *)&client_sock_in.sin_addr.s_addr); + + } else if (valid_ipv6_address(ip, strlen(ip), 0) == _gf_true) { + client_sockaddr = (struct sockaddr *)&client_sock_in6; + addr_sz = sizeof(client_sock_in6); + + client_sock_in6.sin6_family = AF_INET6; + ret = inet_pton(AF_INET6, ip, (void *)&client_sock_in6.sin6_addr); + } else { + goto out; + } + + if (ret != 1) { + ret = -1; + goto out; + } + + /* You cannot just use sizeof (*client_sockaddr), as per the man page + * the (getnameinfo) size must be the size of the underlying sockaddr + * struct e.g. sockaddr_in6 or sockaddr_in. Failure to do so will + * break IPv6 hostname resolution (IPv4 will work only because + * the sockaddr_in struct happens to be of the correct size). + */ + ret = getnameinfo(client_sockaddr, addr_sz, client_hostname, + sizeof(client_hostname), NULL, 0, 0); + if (ret) { + gf_smsg("common-utils", GF_LOG_ERROR, 0, LG_MSG_GETNAMEINFO_FAILED, + "ip=%s", client_ip, "ret=%s", gai_strerror(ret), NULL); + ret = -1; + goto out; + } + + *hostname = gf_strdup((char *)client_hostname); +out: + if (client_ip_copy) + GF_FREE(client_ip_copy); + + 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_smsg(this->name, GF_LOG_ERROR, 0, LG_MSG_GETIFADDRS_FAILED, "ret=%s", + gai_strerror(ret), NULL); + 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_smsg(this->name, GF_LOG_ERROR, 0, LG_MSG_GETNAMEINFO_FAILED, + "ret=%s", gai_strerror(ret), NULL); + 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_msg_debug(this->name, 0, + "%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_smsg("glusterd", GF_LOG_ERROR, 0, LG_MSG_INVALID_FAMILY, NULL); + return NULL; + } + + if (!inet_ntop(addr->ai_family, in_addr, buf, sizeof(buf))) { + gf_smsg("glusterd", GF_LOG_ERROR, 0, LG_MSG_CONVERSION_FAILED, NULL); + return NULL; + } + + *ip = gf_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_smsg("glusterd", GF_LOG_ERROR, 0, LG_MSG_INVALID_FAMILY, + "family=%d", sa->sa_family, "hostname=%s", hostname, + NULL); + break; + } + + return is_local; +} + +gf_boolean_t +gf_is_local_addr(char *hostname) { - unsigned long long l = 0ULL; - int rv = 0; + 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; + struct addrinfo hints; + + this = THIS; + + memset(&hints, 0, sizeof(hints)); + /* + * Removing AI_ADDRCONFIG from default_hints + * for being able to use link local ipv6 addresses + */ + hints.ai_family = AF_UNSPEC; + + ret = getaddrinfo(hostname, NULL, &hints, &result); + + if (ret != 0) { + gf_smsg(this->name, GF_LOG_ERROR, 0, LG_MSG_GETADDRINFO_FAILED, + "ret=%s", gai_strerror(ret), NULL); + goto out; + } + + for (res = result; res != NULL; res = res->ai_next) { + get_ip_from_addrinfo(res, &ip); + gf_msg_debug(this->name, 0, "%s ", ip); + + if (ip) { + found = (gf_is_loopback_localhost(res->ai_addr, hostname) || + gf_interface_search(ip)); + } + if (found) { + GF_FREE(ip); + goto out; + } + GF_FREE(ip); + /* the above free will not set ip to NULL, and hence, there is + double free possible as the loop continues. set ip to NULL. */ + ip = NULL; + } - rv = _gf_string2ulonglong (str, &l, 0); - if (rv != 0) - return rv; +out: + if (result) + freeaddrinfo(result); - if (l >= 0 && l <= UINT64_MAX) - { - *n = (uint64_t) l; - return 0; - } + if (!found) + gf_msg_debug(this->name, 0, "%s is not local", hostname); - errno = ERANGE; - return -1; + 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; + struct addrinfo hints; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + + gai_err = getaddrinfo(name1, NULL, &hints, &addr1); + if (gai_err != 0) { + gf_smsg(name1, GF_LOG_WARNING, 0, LG_MSG_GETADDRINFO_FAILED, "error=%s", + gai_strerror(gai_err), NULL); + goto out; + } + + gai_err = getaddrinfo(name2, NULL, &hints, &addr2); + if (gai_err != 0) { + gf_smsg(name2, GF_LOG_WARNING, 0, LG_MSG_GETADDRINFO_FAILED, "error=%s", + gai_strerror(gai_err), NULL); + 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; +} + +/* + * Processes list of volfile servers. + * Format: <host1>:<port1> <host2>:<port2>... + */ int -gf_string2ulong_base10 (const char *str, unsigned long *n) +gf_process_getspec_servers_list(cmd_args_t *cmd_args, const char *servers_list) { - return _gf_string2ulong (str, n, 10); + char *tmp = NULL; + char *address = NULL; + char *host = NULL; + char *last_colon = NULL; + char *save_ptr = NULL; + int port = 0; + int ret = -1; + + tmp = gf_strdup(servers_list); + if (!tmp) { + errno = ENOMEM; + goto out; + } + + address = strtok_r(tmp, " ", &save_ptr); + if (!address) { + errno = EINVAL; + goto out; + } + + while (1) { + last_colon = strrchr(address, ':'); + if (!last_colon) { + errno = EINVAL; + ret = -1; + break; + } + *last_colon = '\0'; + host = address; + port = atoi(last_colon + 1); + if (port <= 0) { + errno = EINVAL; + ret = -1; + break; + } + ret = gf_set_volfile_server_common(cmd_args, host, + GF_DEFAULT_VOLFILE_TRANSPORT, port); + if (ret && errno != EEXIST) { + break; + } + address = strtok_r(NULL, " ", &save_ptr); + if (!address) { + errno = 0; + ret = 0; + break; + } + } + +out: + if (tmp) { + GF_FREE(tmp); + } + + return ret; } int -gf_string2uint_base10 (const char *str, unsigned int *n) +gf_set_volfile_server_common(cmd_args_t *cmd_args, const char *host, + const char *transport, int port) { - return _gf_string2uint (str, n, 10); + server_cmdline_t *server = NULL; + server_cmdline_t *tmp = NULL; + int ret = -1; + + GF_VALIDATE_OR_GOTO(THIS->name, cmd_args, out); + GF_VALIDATE_OR_GOTO(THIS->name, host, out); + GF_VALIDATE_OR_GOTO(THIS->name, transport, out); + + server = GF_CALLOC(1, sizeof(server_cmdline_t), + gf_common_mt_server_cmdline_t); + if (!server) { + errno = ENOMEM; + goto out; + } + + INIT_LIST_HEAD(&server->list); + + server->volfile_server = gf_strdup(host); + if (!server->volfile_server) { + errno = ENOMEM; + goto out; + } + + server->transport = gf_strdup(transport); + if (!server->transport) { + errno = ENOMEM; + goto out; + } + + server->port = port; + + if (!cmd_args->volfile_server) { + cmd_args->volfile_server = server->volfile_server; + cmd_args->volfile_server_transport = server->transport; + cmd_args->volfile_server_port = server->port; + cmd_args->curr_server = server; + } + + list_for_each_entry(tmp, &cmd_args->volfile_servers, list) + { + if ((!strcmp(tmp->volfile_server, server->volfile_server) && + !strcmp(tmp->transport, server->transport) && + (tmp->port == server->port))) { + /* Duplicate option given, log and ignore */ + gf_smsg("gluster", GF_LOG_INFO, EEXIST, LG_MSG_DUPLICATE_ENTRY, + NULL); + ret = 0; + goto out; + } + } + + list_add_tail(&server->list, &cmd_args->volfile_servers); + + ret = 0; +out: + if (-1 == ret) { + if (server) { + GF_FREE(server->volfile_server); + GF_FREE(server->transport); + GF_FREE(server); + } + } + + return ret; } +/* Sets log file path from user provided arguments */ int -gf_string2uint8_base10 (const char *str, uint8_t *n) +gf_set_log_file_path(cmd_args_t *cmd_args, glusterfs_ctx_t *ctx) { - unsigned long l = 0L; - int rv = 0; + int i = 0; + int j = 0; + int ret = 0; + int tmp_len = 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 (ctx && GF_GLUSTERD_PROCESS == ctx->process_mode) { + ret = gf_asprintf(&cmd_args->log_file, + DEFAULT_LOG_FILE_DIRECTORY "/%s.log", GLUSTERD_NAME); + 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) { + if (strncmp(cmd_args->volfile_server_transport, "unix", 4) == 0) { + if (cmd_args->volfile_server[0] == '/') + i = 1; + tmp_len = strlen(cmd_args->volfile_server); + for (j = 0; i < tmp_len; i++, j++) { + tmp_str[j] = cmd_args->volfile_server[i]; + if (cmd_args->volfile_server[i] == '/') + tmp_str[j] = '-'; + } + ret = gf_asprintf(&cmd_args->log_file, "%s/%s-%s-%d.log", + DEFAULT_LOG_FILE_DIRECTORY, tmp_str, + cmd_args->volfile_id, getpid()); + } else { + ret = gf_asprintf(&cmd_args->log_file, "%s/%s-%s-%d.log", + DEFAULT_LOG_FILE_DIRECTORY, + cmd_args->volfile_server, cmd_args->volfile_id, + getpid()); + } + if (ret > 0) + ret = 0; + } +done: + return ret; +} - rv = _gf_string2ulong (str, &l, 10); - if (rv != 0) - return rv; +int +gf_set_log_ident(cmd_args_t *cmd_args) +{ + int ret = 0; + char *ptr = NULL; + + if (cmd_args->log_file == NULL) { + /* no ident source */ + return 0; + } + + /* TODO: Some idents would look like, etc-glusterfs-glusterd.vol, which + * seems ugly and can be bettered? */ + /* just get the filename as the ident */ + if (NULL != (ptr = strrchr(cmd_args->log_file, '/'))) { + ret = gf_asprintf(&cmd_args->log_ident, "%s", ptr + 1); + } else { + ret = gf_asprintf(&cmd_args->log_ident, "%s", cmd_args->log_file); + } + + if (ret > 0) + ret = 0; + else + return ret; - if (l >= 0 && l <= UINT8_MAX) - { - *n = (uint8_t) l; - return 0; - } + /* remove .log suffix */ + if (NULL != (ptr = strrchr(cmd_args->log_ident, '.'))) { + if (strcmp(ptr, ".log") == 0) { + ptr[0] = '\0'; + } + } - errno = ERANGE; - return -1; + return ret; } int -gf_string2uint16_base10 (const char *str, uint16_t *n) +gf_thread_cleanup_xint(pthread_t thread) { - unsigned long l = 0L; - int rv = 0; + int ret = 0; + void *res = NULL; + + ret = pthread_cancel(thread); + if (ret != 0) + goto error_return; - rv = _gf_string2ulong (str, &l, 10); - if (rv != 0) - return rv; + ret = pthread_join(thread, &res); + if (ret != 0) + goto error_return; - if (l >= 0 && l <= UINT16_MAX) - { - *n = (uint16_t) l; - return 0; - } + if (res != PTHREAD_CANCELED) + goto error_return; - errno = ERANGE; - return -1; + ret = 0; + +error_return: + return ret; +} + +void +gf_thread_set_vname(pthread_t thread, const char *name, va_list args) +{ + char thread_name[GF_THREAD_NAME_LIMIT]; + int ret; + + /* Initialize the thread name with the prefix (not NULL terminated). */ + memcpy(thread_name, GF_THREAD_NAME_PREFIX, + sizeof(GF_THREAD_NAME_PREFIX) - 1); + + ret = vsnprintf(thread_name + sizeof(GF_THREAD_NAME_PREFIX) - 1, + sizeof(thread_name) - sizeof(GF_THREAD_NAME_PREFIX) + 1, + name, args); + if (ret < 0) { + gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_PTHREAD_NAMING_FAILED, + "name=%s", name, NULL); + return; + } + + if (ret >= sizeof(thread_name)) { + gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_THREAD_NAME_TOO_LONG, + "name=%s", thread_name, NULL); + } + +#ifdef GF_LINUX_HOST_OS + ret = pthread_setname_np(thread, thread_name); +#elif defined(__NetBSD__) + ret = pthread_setname_np(thread, thread_name, NULL); +#elif defined(__FreeBSD__) + pthread_set_name_np(thread, thread_name); + ret = 0; +#else + ret = ENOSYS; +#endif + if (ret != 0) { + gf_smsg(THIS->name, GF_LOG_WARNING, ret, LG_MSG_SET_THREAD_FAILED, + "name=%s", thread_name, NULL); + } +} + +void +gf_thread_set_name(pthread_t thread, const char *name, ...) +{ + va_list args; + + va_start(args, name); + gf_thread_set_vname(thread, name, args); + va_end(args); } int -gf_string2uint32_base10 (const char *str, uint32_t *n) +gf_thread_vcreate(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *arg, const char *name, + va_list args) { - unsigned long l = 0L; - int rv = 0; + sigset_t set, old; + int ret; + + sigemptyset(&old); + 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); + if (ret != 0) { + gf_smsg(THIS->name, GF_LOG_ERROR, ret, LG_MSG_THREAD_CREATE_FAILED, + NULL); + ret = -1; + } else if (name != NULL) { + gf_thread_set_vname(*thread, name, args); + } + + pthread_sigmask(SIG_SETMASK, &old, NULL); + + return ret; +} - rv = _gf_string2ulong (str, &l, 10); - if (rv != 0) - return rv; +int +gf_thread_create(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *arg, const char *name, + ...) +{ + va_list args; + int ret; - if (l >= 0 && l <= UINT32_MAX) - { - *n = (uint32_t) l; - return 0; - } + va_start(args, name); + ret = gf_thread_vcreate(thread, attr, start_routine, arg, name, args); + va_end(args); - errno = ERANGE; - return -1; + return ret; } int -gf_string2uint64_base10 (const char *str, uint64_t *n) +gf_thread_create_detached(pthread_t *thread, void *(*start_routine)(void *), + void *arg, const char *name, ...) { - unsigned long long l = 0ULL; - int rv = 0; + pthread_attr_t attr; + va_list args; + int ret = -1; + + ret = pthread_attr_init(&attr); + if (ret) { + gf_smsg(THIS->name, GF_LOG_ERROR, ret, LG_MSG_PTHREAD_ATTR_INIT_FAILED, + NULL); + return -1; + } + + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - rv = _gf_string2ulonglong (str, &l, 10); - if (rv != 0) - return rv; + va_start(args, name); + ret = gf_thread_vcreate(thread, &attr, start_routine, arg, name, args); + va_end(args); - if (l >= 0 && l <= UINT64_MAX) - { - *n = (uint64_t) l; - return 0; - } + pthread_attr_destroy(&attr); - errno = ERANGE; - return -1; + return ret; } int -gf_string2bytesize (const char *str, uint64_t *n) +gf_skip_header_section(int fd, int header_len) { - uint64_t value = 0ULL; - char *tail = NULL; - int old_errno = 0; - const char *s = NULL; + int ret = -1; - if (str == NULL || n == NULL) - { - errno = EINVAL; - return -1; - } + ret = sys_lseek(fd, header_len, SEEK_SET); + if (ret == (off_t)-1) { + gf_smsg("", GF_LOG_ERROR, 0, LG_MSG_SKIP_HEADER_FAILED, NULL); + } else { + ret = 0; + } - for (s = str; *s != '\0'; s++) - { - if (isspace (*s)) - { - continue; - } - if (*s == '-') - { - /* bala: we do not support suffixed (-) sign and - invalid integer format */ - return -1; - } - break; - } + return ret; +} - old_errno = errno; - errno = 0; - value = strtoull (str, &tail, 10); +/* Below function is use to check at runtime if pid is running */ - if (errno == ERANGE || errno == EINVAL) - { - return -1; - } +gf_boolean_t +gf_is_pid_running(int pid) +{ +#ifdef __FreeBSD__ + int ret = -1; + + ret = sys_kill(pid, 0); + if (ret < 0) { + return _gf_false; + } +#else + char fname[32] = { + 0, + }; + int fd = -1; + + snprintf(fname, sizeof(fname), "/proc/%d/cmdline", pid); + + fd = sys_open(fname, O_RDONLY, 0); + if (fd < 0) { + return _gf_false; + } + + sys_close(fd); +#endif + return _gf_true; +} - if (errno == 0) - { - errno = old_errno; - } - - if (tail[0] != '\0') - { - if (strcasecmp (tail, GF_UNIT_KB_STRING) == 0) - { - value *= GF_UNIT_KB; - } - else if (strcasecmp (tail, GF_UNIT_MB_STRING) == 0) - { - value *= GF_UNIT_MB; - } - else if (strcasecmp (tail, GF_UNIT_GB_STRING) == 0) - { - value *= GF_UNIT_GB; - } - else if (strcasecmp (tail, GF_UNIT_TB_STRING) == 0) - { - value *= GF_UNIT_TB; - } - else if (strcasecmp (tail, GF_UNIT_PB_STRING) == 0) - { - value *= GF_UNIT_PB; - } - else - { - /* bala: invalid integer format */ - return -1; - } - } - - *n = value; - - return 0; +gf_boolean_t +gf_is_service_running(char *pidfile, int *pid) +{ + FILE *file = NULL; + gf_boolean_t running = _gf_false; + int ret = 0; + int fno = 0; + + file = fopen(pidfile, "r+"); + if (!file) { + goto out; + } + + fno = fileno(file); + ret = lockf(fno, F_TEST, 0); + if (ret == -1) { + running = _gf_true; + } + + ret = fscanf(file, "%d", pid); + if (ret <= 0) { + gf_smsg("", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED, "pidfile=%s", + pidfile, NULL); + *pid = -1; + running = _gf_false; + goto out; + } + + running = gf_is_pid_running(*pid); +out: + if (file) + fclose(file); + return running; } -int64_t -gf_str_to_long_long (const char *number) +/* Check if the pid is > 0 */ +gf_boolean_t +gf_valid_pid(const char *pid, int length) { - int64_t unit = 1; - int64_t ret = 0; - char *endptr = NULL ; - if (!number) - return 0; + gf_boolean_t ret = _gf_true; + pid_t value = 0; + char *end_ptr = NULL; + + if (length <= 0) { + ret = _gf_false; + goto out; + } + + value = strtol(pid, &end_ptr, 10); + if (value <= 0) { + ret = _gf_false; + } +out: + return ret; +} - ret = strtoll (number, &endptr, 0); +static int +dht_is_linkfile_key(dict_t *this, char *key, data_t *value, void *data) +{ + gf_boolean_t *linkfile_key_found = NULL; + + if (!data) + goto out; - if (endptr) { - switch (*endptr) { - case 'G': - case 'g': - if ((* (endptr + 1) == 'B') ||(* (endptr + 1) == 'b')) - unit = 1024 * 1024 * 1024; - break; - case 'M': - case 'm': - if ((* (endptr + 1) == 'B') ||(* (endptr + 1) == 'b')) - unit = 1024 * 1024; - break; - case 'K': - case 'k': - if ((* (endptr + 1) == 'B') ||(* (endptr + 1) == 'b')) - unit = 1024; - break; - case '%': - unit = 1; - break; - default: - unit = 1; - break; - } - } - return ret * unit; + linkfile_key_found = data; + + *linkfile_key_found = _gf_true; +out: + return 0; } -int -gf_string2boolean (const char *str, gf_boolean_t *b) +gf_boolean_t +dht_is_linkfile(struct iatt *buf, dict_t *dict) { - if (str == NULL) { - return -1; - } + gf_boolean_t linkfile_key_found = _gf_false; - if ((strcasecmp (str, "1") == 0) || - (strcasecmp (str, "on") == 0) || - (strcasecmp (str, "yes") == 0) || - (strcasecmp (str, "true") == 0) || - (strcasecmp (str, "enable") == 0)) { - *b = _gf_true; - return 0; - } + if (!IS_DHT_LINKFILE_MODE(buf)) + return _gf_false; - if ((strcasecmp (str, "0") == 0) || - (strcasecmp (str, "off") == 0) || - (strcasecmp (str, "no") == 0) || - (strcasecmp (str, "false") == 0) || - (strcasecmp (str, "disable") == 0)) { - *b = _gf_false; - return 0; - } + dict_foreach_fnmatch(dict, "*." DHT_LINKFILE_STR, dht_is_linkfile_key, + &linkfile_key_found); - return -1; + return linkfile_key_found; } +int +gf_check_log_format(const char *value) +{ + int log_format = -1; + + if (!strcasecmp(value, GF_LOG_FORMAT_NO_MSG_ID)) + log_format = gf_logformat_traditional; + else if (!strcasecmp(value, GF_LOG_FORMAT_WITH_MSG_ID)) + log_format = gf_logformat_withmsgid; + + if (log_format == -1) + gf_smsg(THIS->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_LOG, + "possible_values=" GF_LOG_FORMAT_NO_MSG_ID + "|" GF_LOG_FORMAT_WITH_MSG_ID, + NULL); + + return log_format; +} int -gf_lockfd (int fd) +gf_check_logger(const char *value) { - struct flock fl; + int logger = -1; + + if (!strcasecmp(value, GF_LOGGER_GLUSTER_LOG)) + logger = gf_logger_glusterlog; + else if (!strcasecmp(value, GF_LOGGER_SYSLOG)) + logger = gf_logger_syslog; - fl.l_type = F_WRLCK; - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 0; + if (logger == -1) + gf_smsg(THIS->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_LOG, + "possible_values=" GF_LOGGER_GLUSTER_LOG "|" GF_LOGGER_SYSLOG, + NULL); - return fcntl (fd, F_SETLK, &fl); + return logger; } +/* gf_compare_sockaddr compares the given addresses @addr1 and @addr2 for + * equality, ie. if they both refer to the same address. + * + * This was inspired by sock_addr_cmp_addr() from + * https://www.opensource.apple.com/source/postfix/postfix-197/postfix/src/util/sock_addr.c + */ +gf_boolean_t +gf_compare_sockaddr(const struct sockaddr *addr1, const struct sockaddr *addr2) +{ + GF_ASSERT(addr1 != NULL); + GF_ASSERT(addr2 != NULL); + + /* Obviously, the addresses don't match if their families are different + */ + if (addr1->sa_family != addr2->sa_family) + return _gf_false; + + if (AF_INET == addr1->sa_family) { + if (((struct sockaddr_in *)addr1)->sin_addr.s_addr == + ((struct sockaddr_in *)addr2)->sin_addr.s_addr) + return _gf_true; + + } else if (AF_INET6 == addr1->sa_family) { + if (memcmp((char *)&((struct sockaddr_in6 *)addr1)->sin6_addr, + (char *)&((struct sockaddr_in6 *)addr2)->sin6_addr, + sizeof(struct in6_addr)) == 0) + return _gf_true; + } + return _gf_false; +} + +/* + * gf_set_timestamp: + * It sets the mtime and atime of 'dest' file as of 'src'. + */ int -gf_unlockfd (int fd) +gf_set_timestamp(const char *src, const char *dest) +{ + struct stat sb = { + 0, + }; +#if defined(HAVE_UTIMENSAT) + struct timespec new_time[2] = {{ + 0, + }, + { + 0, + }}; +#else + struct timeval new_time[2] = {{ + 0, + }, + { + 0, + }}; +#endif + int ret = 0; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT(this); + GF_ASSERT(src); + GF_ASSERT(dest); + + ret = sys_stat(src, &sb); + if (ret) { + gf_smsg(this->name, GF_LOG_ERROR, errno, LG_MSG_FILE_STAT_FAILED, + "stat=%s", src, NULL); + goto out; + } + /* The granularity is nano seconds if `utimensat()` is available, + * and micro seconds otherwise. + */ +#if defined(HAVE_UTIMENSAT) + new_time[0].tv_sec = sb.st_atime; + new_time[0].tv_nsec = ST_ATIM_NSEC(&sb); + + new_time[1].tv_sec = sb.st_mtime; + new_time[1].tv_nsec = ST_MTIM_NSEC(&sb); + + /* dirfd = 0 is ignored because `dest` is an absolute path. */ + ret = sys_utimensat(AT_FDCWD, dest, new_time, AT_SYMLINK_NOFOLLOW); + if (ret) { + gf_smsg(this->name, GF_LOG_ERROR, errno, LG_MSG_UTIMENSAT_FAILED, + "dest=%s", dest, NULL); + } +#else + new_time[0].tv_sec = sb.st_atime; + new_time[0].tv_usec = ST_ATIM_NSEC(&sb) / 1000; + + new_time[1].tv_sec = sb.st_mtime; + new_time[1].tv_usec = ST_MTIM_NSEC(&sb) / 1000; + + ret = sys_utimes(dest, new_time); + if (ret) { + gf_smsg(this->name, GF_LOG_ERROR, errno, LG_MSG_UTIMES_FAILED, + "dest=%s", dest, NULL); + } +#endif +out: + return ret; +} + +static void +gf_backtrace_end(char *buf, size_t frames) { - struct flock fl; + size_t pos = 0; - fl.l_type = F_UNLCK; - fl.l_whence = SEEK_SET; - fl.l_start = 0; - fl.l_len = 0; + if (!buf) + return; - return fcntl (fd, F_SETLK, &fl); + pos = strlen(buf); + + frames = min(frames, GF_BACKTRACE_LEN - pos - 1); + + if (0 == frames) + return; + + memset(buf + pos, ')', frames); + buf[pos + frames] = '\0'; } -static void -compute_checksum (char *buf, size_t size, uint32_t *checksum) +/*Returns bytes written*/ +static int +gf_backtrace_append(char *buf, size_t pos, char *framestr) { - int ret = -1; - char *checksum_buf = NULL; + if (pos >= GF_BACKTRACE_LEN) + return -1; + return snprintf(buf + pos, GF_BACKTRACE_LEN - pos, "(--> %s ", framestr); +} - checksum_buf = (char *)(checksum); +static int +gf_backtrace_fillframes(char *buf) +{ + void *array[GF_BACKTRACE_FRAME_COUNT]; + size_t frames = 0; + FILE *fp = NULL; + char callingfn[GF_BACKTRACE_FRAME_COUNT - 2][1024] = { + {0}, + }; + int ret = -1; + int fd = -1; + size_t idx = 0; + size_t pos = 0; + size_t inc = 0; + char tmpl[] = "/tmp/glfs-bt-XXXXXX"; + + frames = backtrace(array, GF_BACKTRACE_FRAME_COUNT); + if (!frames) + return -1; + + /* coverity[secure_temp] mkstemp uses 0600 as the mode and is safe */ + fd = mkstemp(tmpl); + if (fd == -1) + return -1; + + /* Calling unlink so that when the file is closed or program + * terminates the temporary file is deleted. + */ + ret = sys_unlink(tmpl); + if (ret < 0) { + gf_smsg(THIS->name, GF_LOG_INFO, 0, LG_MSG_FILE_DELETE_FAILED, + "temporary_file=%s", tmpl, NULL); + } + + /*The most recent two frames are the calling function and + * gf_backtrace_save, which we can infer.*/ + + backtrace_symbols_fd(&array[2], frames - 2, fd); + + fp = fdopen(fd, "r"); + if (!fp) { + sys_close(fd); + goto out; + } + + ret = fseek(fp, 0L, SEEK_SET); + if (ret) + goto out; + + pos = 0; + for (idx = 0; idx < frames - 2; idx++) { + ret = fscanf(fp, "%1023s", callingfn[idx]); + if (ret == EOF) + break; + inc = gf_backtrace_append(buf, pos, callingfn[idx]); + if (inc == -1) + break; + pos += inc; + } + gf_backtrace_end(buf, idx); - if (!(*checksum)) { - checksum_buf [0] = 0xba; - checksum_buf [1] = 0xbe; - checksum_buf [2] = 0xb0; - checksum_buf [3] = 0x0b; - } +out: + if (fp) + fclose(fp); - for (ret = 0; ret < (size - 4); ret += 4) { - checksum_buf[0] ^= (buf[ret]); - checksum_buf[1] ^= (buf[ret + 1] << 1) ; - checksum_buf[2] ^= (buf[ret + 2] << 2); - checksum_buf[3] ^= (buf[ret + 3] << 3); - } + return (idx > 0) ? 0 : -1; +} + +/* Optionally takes @buf to save backtrace. If @buf is NULL, uses the + * pre-allocated ctx->btbuf to avoid allocating memory while printing + * backtrace. + * TODO: This API doesn't provide flexibility in terms of no. of frames + * of the backtrace is being saved in the buffer. Deferring fixing it + * when there is a real-use for that.*/ + +char * +gf_backtrace_save(char *buf) +{ + char *bt = NULL; + + if (!buf) { + bt = THIS->ctx->btbuf; + GF_ASSERT(bt); + + } else { + bt = buf; + } + + if ((0 == gf_backtrace_fillframes(bt))) + return bt; - for (ret = 0; ret <= (size % 4); ret++) { - checksum_buf[ret] ^= (buf[(size - 4) + ret] << ret); + gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_BACKTRACE_SAVE_FAILED, NULL); + return NULL; +} + +gf_loglevel_t +fop_log_level(glusterfs_fop_t fop, int op_errno) +{ + /* if gfid doesn't exist ESTALE comes */ + if (op_errno == ENOENT || op_errno == ESTALE) + return GF_LOG_DEBUG; + + if ((fop == GF_FOP_ENTRYLK) || (fop == GF_FOP_FENTRYLK) || + (fop == GF_FOP_FINODELK) || (fop == GF_FOP_INODELK) || + (fop == GF_FOP_LK)) { + /* + * if non-blocking lock fails EAGAIN comes + * if locks xlator is not loaded ENOSYS comes + */ + if (op_errno == EAGAIN || op_errno == ENOSYS) + return GF_LOG_DEBUG; + } + + if ((fop == GF_FOP_GETXATTR) || (fop == GF_FOP_FGETXATTR)) { + if (op_errno == ENOTSUP || op_errno == ENODATA) + return GF_LOG_DEBUG; + } + + if ((fop == GF_FOP_SETXATTR) || (fop == GF_FOP_FSETXATTR) || + (fop == GF_FOP_REMOVEXATTR) || (fop == GF_FOP_FREMOVEXATTR)) { + if (op_errno == ENOTSUP) + return GF_LOG_DEBUG; + } + + if (fop == GF_FOP_MKNOD || fop == GF_FOP_MKDIR) + if (op_errno == EEXIST) + return GF_LOG_DEBUG; + + if (fop == GF_FOP_SEEK) { +#ifdef HAVE_SEEK_HOLE + if (op_errno == ENXIO) { + return GF_LOG_DEBUG; } +#else + return GF_LOG_DEBUG; +#endif + } - return; + return GF_LOG_ERROR; } -#define GF_CHECKSUM_BUF_SIZE 1024 +/* This function will build absolute path of file/directory from the + * current location and relative path given from the current location + * For example consider our current path is /a/b/c/ and relative path + * from current location is ./../x/y/z .After parsing through this + * function the absolute path becomes /a/b/x/y/z/. + * + * The function gives a pointer to absolute path if it is successful + * and also returns zero. + * Otherwise function gives NULL pointer with returning an err value. + * + * So the user need to free memory allocated for path. + * + */ + +int32_t +gf_build_absolute_path(char *current_path, char *relative_path, char **path) +{ + char *absolute_path = NULL; + char *token = NULL; + char *component = NULL; + char *saveptr = NULL; + char *end = NULL; + int ret = 0; + size_t relativepath_len = 0; + size_t currentpath_len = 0; + size_t max_absolutepath_len = 0; + + GF_ASSERT(current_path); + GF_ASSERT(relative_path); + GF_ASSERT(path); + + if (!path || !current_path || !relative_path) { + ret = -EFAULT; + goto err; + } + /* Check for current and relative path + * current path should be absolute one and start from '/' + * relative path should not start from '/' + */ + currentpath_len = strlen(current_path); + if (current_path[0] != '/' || (currentpath_len > PATH_MAX)) { + gf_smsg(THIS->name, GF_LOG_ERROR, 0, LG_MSG_WRONG_VALUE, + "current-path=%s", current_path, NULL); + ret = -EINVAL; + goto err; + } + + relativepath_len = strlen(relative_path); + if (relative_path[0] == '/' || (relativepath_len > PATH_MAX)) { + gf_smsg(THIS->name, GF_LOG_ERROR, 0, LG_MSG_WRONG_VALUE, + "relative-path=%s", relative_path, NULL); + ret = -EINVAL; + goto err; + } + + /* It is maximum possible value for absolute path */ + max_absolutepath_len = currentpath_len + relativepath_len + 2; + + absolute_path = GF_CALLOC(1, max_absolutepath_len, gf_common_mt_char); + if (!absolute_path) { + ret = -ENOMEM; + goto err; + } + absolute_path[0] = '\0'; + + /* If current path is root i.e contains only "/", we do not + * need to copy it + */ + if (strcmp(current_path, "/") != 0) { + strcpy(absolute_path, current_path); + + /* We trim '/' at the end for easier string manipulation */ + gf_path_strip_trailing_slashes(absolute_path); + } + + /* Used to spilt relative path based on '/' */ + component = gf_strdup(relative_path); + if (!component) { + ret = -ENOMEM; + goto err; + } + + /* In the relative path, we want to consider ".." and "." + * if token is ".." , we just need to reduce one level hierarchy + * if token is "." , we just ignore it + * if token is NULL , end of relative path + * if absolute path becomes '\0' and still "..", then it is a bad + * relative path, it points to out of boundary area and stop + * building the absolute path + * All other cases we just concatenate token to the absolute path + */ + for (token = strtok_r(component, "/", &saveptr), + end = strchr(absolute_path, '\0'); + token; token = strtok_r(NULL, "/", &saveptr)) { + if (strcmp(token, ".") == 0) + continue; + + else if (strcmp(token, "..") == 0) { + if (absolute_path[0] == '\0') { + ret = -EACCES; + goto err; + } + + end = strrchr(absolute_path, '/'); + *end = '\0'; + } else { + ret = snprintf(end, max_absolutepath_len - strlen(absolute_path), + "/%s", token); + end = strchr(absolute_path, '\0'); + } + } + if (strlen(absolute_path) > PATH_MAX) { + ret = -EINVAL; + goto err; + } + *path = gf_strdup(absolute_path); + +err: + if (component) + GF_FREE(component); + if (absolute_path) + GF_FREE(absolute_path); + return ret; +} + +/* This is an utility function which will recursively delete + * a folder and its contents. + * + * @param delete_path folder to be deleted. + * + * @return 0 on success and -1 on failure. + */ int -get_checksum_for_file (int fd, uint32_t *checksum) +recursive_rmdir(const char *delete_path) { - int ret = -1; - char buf[GF_CHECKSUM_BUF_SIZE] = {0,}; + int ret = -1; + char path[PATH_MAX] = { + 0, + }; + struct stat st = { + 0, + }; + DIR *dir = NULL; + struct dirent *entry = NULL; + struct dirent scratch[2] = { + { + 0, + }, + }; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT(this); + GF_VALIDATE_OR_GOTO(this->name, delete_path, out); + + dir = sys_opendir(delete_path); + if (!dir) { + gf_msg_debug(this->name, 0, + "Failed to open directory %s. " + "Reason : %s", + delete_path, strerror(errno)); + ret = 0; + goto out; + } + + while ((entry = sys_readdir(dir, scratch))) { + if (gf_irrelevant_entry(entry)) + continue; + snprintf(path, PATH_MAX, "%s/%s", delete_path, entry->d_name); + ret = sys_lstat(path, &st); + if (ret == -1) { + gf_msg_debug(this->name, 0, + "Failed to stat entry %s :" + " %s", + path, strerror(errno)); + (void)sys_closedir(dir); + goto out; + } - /* goto first place */ - lseek (fd, 0L, SEEK_SET); - do { - ret = read (fd, &buf, GF_CHECKSUM_BUF_SIZE); - if (ret > 0) - compute_checksum (buf, GF_CHECKSUM_BUF_SIZE, - checksum); - } while (ret > 0); + if (S_ISDIR(st.st_mode)) + ret = recursive_rmdir(path); + else + ret = sys_unlink(path); - /* set it back */ - lseek (fd, 0L, SEEK_SET); + if (ret) { + gf_msg_debug(this->name, 0, + " Failed to remove %s. " + "Reason : %s", + path, strerror(errno)); + } - return ret; + gf_msg_debug(this->name, 0, "%s %s", + ret ? "Failed to remove" : "Removed", entry->d_name); + } + + ret = sys_closedir(dir); + if (ret) { + gf_msg_debug(this->name, 0, + "Failed to close dir %s. Reason :" + " %s", + delete_path, strerror(errno)); + } + + ret = sys_rmdir(delete_path); + if (ret) { + gf_msg_debug(this->name, 0, "Failed to rmdir: %s,err: %s", delete_path, + strerror(errno)); + } + +out: + return ret; } +/* + * Input: Array of strings 'array' terminating in NULL + * string 'elem' to be searched in the array + * + * Output: Index of the element in the array if found, '-1' otherwise + */ +int +gf_get_index_by_elem(char **array, char *elem) +{ + int i = 0; + + for (i = 0; array[i]; i++) { + if (strcmp(elem, array[i]) == 0) + return i; + } + return -1; +} + +static int +get_pathinfo_host(char *pathinfo, char *hostname, size_t size) +{ + char *start = NULL; + char *end = NULL; + int ret = -1; + int i = 0; + + if (!pathinfo) + goto out; + + start = strchr(pathinfo, ':'); + if (!start) + goto out; + + end = strrchr(pathinfo, ':'); + if (start == end) + goto out; + + memset(hostname, 0, size); + i = 0; + while (++start != end) + hostname[i++] = *start; + ret = 0; +out: + return ret; +} -/* One should pass the command here with command with full path, - otherwise, execv will fail */ +/*Note: 'pathinfo' should be gathered only from one brick*/ int -gf_system (const char *command) +glusterfs_is_local_pathinfo(char *pathinfo, gf_boolean_t *is_local) { - int ret = -1; - pid_t pid = 0; - int status = 0; - int idx = 0; - char *dupcmd = NULL; - char *arg = NULL; - char *tmp = NULL; - char *argv[100] = { NULL, }; + int ret = 0; + char pathinfohost[1024] = {0}; + char localhost[1024] = {0}; - dupcmd = gf_strdup (command); - if (!dupcmd) - goto out; + *is_local = _gf_false; + ret = get_pathinfo_host(pathinfo, pathinfohost, sizeof(pathinfohost)); + if (ret) + goto out; - pid = fork (); - if (pid < 0) { - /* failure */ + ret = gethostname(localhost, sizeof(localhost)); + if (ret) + goto out; + + if (!strcmp(localhost, pathinfohost)) + *is_local = _gf_true; +out: + return ret; +} + +ssize_t +gf_nread(int fd, void *buf, size_t count) +{ + ssize_t ret = 0; + ssize_t read_bytes = 0; + + for (read_bytes = 0; read_bytes < count; read_bytes += ret) { + ret = sys_read(fd, buf + read_bytes, count - read_bytes); + if (ret == 0) { + break; + } else if (ret < 0) { + if (errno == EINTR) + ret = 0; + else goto out; } - if (pid == 0) { - /* Child process */ - /* Step 0: Prepare the argv */ - arg = strtok_r (dupcmd, " ", &tmp); - while (arg) { - argv[idx] = arg; - arg = strtok_r (NULL, " ", &tmp); - idx++; - } - /* Step 1: Close all 'fd' */ - for (idx = 3; idx < 65536; idx++) { - close (idx); - } - /* Step 2: execv (); */ - ret = execvp (argv[0], argv); - - /* Code will not come here at all */ - gf_log ("", GF_LOG_ERROR, "execv of (%s) failed", command); - } - if (pid > 0) { - /* Current, ie, parent process */ - pid = waitpid (pid, &status, 0); - ret = status; + } + + ret = read_bytes; +out: + return ret; +} + +ssize_t +gf_nwrite(int fd, const void *buf, size_t count) +{ + ssize_t ret = 0; + ssize_t written = 0; + + for (written = 0; written != count; written += ret) { + ret = sys_write(fd, buf + written, count - written); + if (ret < 0) { + if (errno == EINTR) + ret = 0; + else + goto out; } + } + + ret = written; out: - if (dupcmd) - GF_FREE (dupcmd); + return ret; +} - return ret; +void +gf_free_mig_locks(lock_migration_info_t *locks) +{ + lock_migration_info_t *current = NULL; + lock_migration_info_t *temp = NULL; + + if (!locks) + return; + + if (list_empty(&locks->list)) + return; + + list_for_each_entry_safe(current, temp, &locks->list, list) + { + list_del_init(¤t->list); + GF_FREE(current->client_uid); + GF_FREE(current); + } } -int -get_checksum_for_path (char *path, uint32_t *checksum) +void +_mask_cancellation(void) { - int ret = -1; - int fd = -1; + (void)pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); +} - GF_ASSERT (path); - GF_ASSERT (checksum); +void +_unmask_cancellation(void) +{ + (void)pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); +} - fd = open (path, O_RDWR); +/* This is a wrapper function to add a pointer to a list, + * which doesn't contain list member + */ +struct list_node * +_list_node_add(void *ptr, struct list_head *list, + int (*compare)(struct list_head *, struct list_head *)) +{ + struct list_node *node = NULL; - if (fd == -1) { - gf_log ("", GF_LOG_ERROR, "Unable to open %s, errno: %d", - path, errno); - goto out; - } + if (ptr == NULL || list == NULL) + goto out; + + node = GF_CALLOC(1, sizeof(struct list_node), gf_common_list_node); - ret = get_checksum_for_file (fd, checksum); + if (node == NULL) + goto out; + node->ptr = ptr; + if (compare) + list_add_order(&node->list, list, compare); + else + list_add_tail(&node->list, list); out: - if (fd != -1) - close (fd); + return node; +} + +struct list_node * +list_node_add(void *ptr, struct list_head *list) +{ + return _list_node_add(ptr, list, NULL); +} + +struct list_node * +list_node_add_order(void *ptr, struct list_head *list, + int (*compare)(struct list_head *, struct list_head *)) +{ + return _list_node_add(ptr, list, compare); +} + +void +list_node_del(struct list_node *node) +{ + if (node == NULL) + return; + list_del_init(&node->list); + GF_FREE(node); +} + +const char * +fop_enum_to_pri_string(glusterfs_fop_t fop) +{ + switch (fop) { + case GF_FOP_OPEN: + case GF_FOP_STAT: + case GF_FOP_FSTAT: + case GF_FOP_LOOKUP: + case GF_FOP_ACCESS: + case GF_FOP_READLINK: + case GF_FOP_OPENDIR: + case GF_FOP_STATFS: + case GF_FOP_READDIR: + case GF_FOP_READDIRP: + case GF_FOP_GETACTIVELK: + case GF_FOP_SETACTIVELK: + case GF_FOP_ICREATE: + case GF_FOP_NAMELINK: + return "HIGH"; + + case GF_FOP_CREATE: + case GF_FOP_FLUSH: + case GF_FOP_LK: + case GF_FOP_INODELK: + case GF_FOP_FINODELK: + case GF_FOP_ENTRYLK: + case GF_FOP_FENTRYLK: + case GF_FOP_UNLINK: + case GF_FOP_SETATTR: + case GF_FOP_FSETATTR: + case GF_FOP_MKNOD: + case GF_FOP_MKDIR: + case GF_FOP_RMDIR: + case GF_FOP_SYMLINK: + case GF_FOP_RENAME: + case GF_FOP_LINK: + case GF_FOP_SETXATTR: + case GF_FOP_GETXATTR: + case GF_FOP_FGETXATTR: + case GF_FOP_FSETXATTR: + case GF_FOP_REMOVEXATTR: + case GF_FOP_FREMOVEXATTR: + case GF_FOP_IPC: + case GF_FOP_LEASE: + return "NORMAL"; + + case GF_FOP_READ: + case GF_FOP_WRITE: + case GF_FOP_FSYNC: + case GF_FOP_TRUNCATE: + case GF_FOP_FTRUNCATE: + case GF_FOP_FSYNCDIR: + case GF_FOP_XATTROP: + case GF_FOP_FXATTROP: + case GF_FOP_RCHECKSUM: + case GF_FOP_ZEROFILL: + case GF_FOP_FALLOCATE: + case GF_FOP_SEEK: + return "LOW"; + + case GF_FOP_NULL: + case GF_FOP_FORGET: + case GF_FOP_RELEASE: + case GF_FOP_RELEASEDIR: + case GF_FOP_GETSPEC: + case GF_FOP_MAXVALUE: + case GF_FOP_DISCARD: + return "LEAST"; + default: + return "UNKNOWN"; + } +} + +const char * +gf_inode_type_to_str(ia_type_t type) +{ + static const char *const str_ia_type[] = { + "UNKNOWN", "REGULAR FILE", "DIRECTORY", "LINK", + "BLOCK DEVICE", "CHARACTER DEVICE", "PIPE", "SOCKET"}; + return str_ia_type[type]; +} + +gf_boolean_t +gf_is_zero_filled_stat(struct iatt *buf) +{ + if (!buf) + return 1; + + /* Do not use st_dev because it is transformed to store the xlator id + * in place of the device number. Do not use st_ino because by this time + * we've already mapped the root ino to 1 so it is not guaranteed to be + * 0. + */ + if ((buf->ia_nlink == 0) && (buf->ia_ctime == 0)) + return 1; + + return 0; +} + +void +gf_zero_fill_stat(struct iatt *buf) +{ + buf->ia_nlink = 0; + buf->ia_ctime = 0; +} + +gf_boolean_t +gf_is_valid_xattr_namespace(char *key) +{ + static char *xattr_namespaces[] = {"trusted.", "system.", "user.", + "security.", NULL}; + int i = 0; + + for (i = 0; xattr_namespaces[i]; i++) { + if (strncmp(key, xattr_namespaces[i], strlen(xattr_namespaces[i])) == 0) + return _gf_true; + } + + return _gf_false; +} + +ino_t +gfid_to_ino(uuid_t gfid) +{ + ino_t ino = 0; + int32_t i; + + for (i = 8; i < 16; i++) { + ino <<= 8; + ino += (uint8_t)gfid[i]; + } + + return ino; +} + +int +gf_bits_count(uint64_t n) +{ + int val = 0; +#if defined(__GNUC__) || defined(__clang__) + val = __builtin_popcountll(n); +#else + n -= (n >> 1) & 0x5555555555555555ULL; + n = ((n >> 2) & 0x3333333333333333ULL) + (n & 0x3333333333333333ULL); + n = (n + (n >> 4)) & 0x0F0F0F0F0F0F0F0FULL; + n += n >> 8; + n += n >> 16; + n += n >> 32; + val = n & 0xFF; +#endif + return val; +} + +int +gf_bits_index(uint64_t n) +{ +#if defined(__GNUC__) || defined(__clang__) + return __builtin_ffsll(n) - 1; +#else + return ffsll(n) - 1; +#endif +} + +const char * +gf_fop_string(glusterfs_fop_t fop) +{ + if ((fop > GF_FOP_NULL) && (fop < GF_FOP_MAXVALUE)) + return gf_fop_list[fop]; + return "INVALID"; +} + +int +gf_fop_int(char *fop) +{ + int i = 0; + + for (i = GF_FOP_NULL + 1; i < GF_FOP_MAXVALUE; i++) { + if (strcasecmp(fop, gf_fop_list[i]) == 0) + return i; + } + return -1; +} + +int +close_fds_except(int *fdv, size_t count) +{ + int i = 0; + size_t j = 0; + gf_boolean_t should_close = _gf_true; +#ifdef GF_LINUX_HOST_OS + DIR *d = NULL; + struct dirent *de = NULL; + struct dirent scratch[2] = { + { + 0, + }, + }; + char *e = NULL; + + d = sys_opendir("/proc/self/fd"); + if (!d) + return -1; + + for (;;) { + should_close = _gf_true; + + errno = 0; + de = sys_readdir(d, scratch); + if (!de || errno != 0) + break; + i = strtoul(de->d_name, &e, 10); + if (*e != '\0' || i == dirfd(d)) + continue; + + for (j = 0; j < count; j++) { + if (i == fdv[j]) { + should_close = _gf_false; + break; + } + } + if (should_close) + sys_close(i); + } + sys_closedir(d); +#else /* !GF_LINUX_HOST_OS */ + struct rlimit rl; + int ret = -1; + + ret = getrlimit(RLIMIT_NOFILE, &rl); + if (ret) return ret; + + for (i = 0; i < rl.rlim_cur; i++) { + should_close = _gf_true; + for (j = 0; j < count; j++) { + if (i == fdv[j]) { + should_close = _gf_false; + break; + } + } + if (should_close) + sys_close(i); + } +#endif /* !GF_LINUX_HOST_OS */ + return 0; +} + +/** + * gf_getgrouplist - get list of groups to which a user belongs + * + * A convenience wrapper for getgrouplist(3). + * + * @param user - same as in getgrouplist(3) + * @param group - same as in getgrouplist(3) + * @param groups - pointer to a gid_t pointer + * + * gf_getgrouplist allocates a gid_t buffer which is big enough to + * hold the list of auxiliary group ids for user, up to the GF_MAX_AUX_GROUPS + * threshold. Upon successful invocation groups will be pointed to that buffer. + * + * @return success: the number of auxiliary group ids retrieved + * failure: -1 + */ +int +gf_getgrouplist(const char *user, gid_t group, gid_t **groups) +{ + int ret = -1; + int ngroups = SMALL_GROUP_COUNT; + + *groups = GF_CALLOC(sizeof(gid_t), ngroups, gf_common_mt_groups_t); + if (!*groups) + return -1; + + /* + * We are running getgrouplist() in a loop until we succeed (or hit + * certain exit conditions, see the comments below). This is because + * the indicated number of auxiliary groups that we obtain in case of + * the failure of the first invocation is not guaranteed to keep its + * validity upon the next invocation with a gid buffer of that size. + */ + for (;;) { + int ngroups_old = ngroups; + ret = getgrouplist(user, group, *groups, &ngroups); + if (ret != -1) + break; + + if (ngroups >= GF_MAX_AUX_GROUPS) { + /* + * This should not happen as GF_MAX_AUX_GROUPS is set + * to the max value of number of supported auxiliary + * groups across all platforms supported by GlusterFS. + * However, if it still happened some way, we wouldn't + * care about the incompleteness of the result, we'd + * just go on with what we got. + */ + return GF_MAX_AUX_GROUPS; + } else if (ngroups <= ngroups_old) { + /* + * There is an edge case that getgrouplist() fails but + * ngroups remains the same. This is actually not + * specified in getgrouplist(3), but implementations + * can do this upon internal failure[1]. To avoid + * falling into an infinite loop when this happens, we + * break the loop if the getgrouplist call failed + * without an increase in the indicated group number. + * + * [1] + * https://sourceware.org/git/?p=glibc.git;a=blob;f=grp/initgroups.c;hb=refs/heads/release/2.25/master#l168 + */ + GF_FREE(*groups); + return -1; + } + + *groups = GF_REALLOC(*groups, ngroups * sizeof(gid_t)); + if (!*groups) + return -1; + } + return ret; +} + +int +glusterfs_compute_sha256(const unsigned char *content, size_t size, + char *sha256_hash) +{ + SHA256_CTX sha256; + + SHA256_Init(&sha256); + SHA256_Update(&sha256, (const unsigned char *)(content), size); + SHA256_Final((unsigned char *)sha256_hash, &sha256); + + return 0; +} + +/* * Safe wrapper function for strncpy. + * This wrapper makes sure that when there is no null byte among the first n in + * source srting for strncpy function call, the string placed in dest will be + * null-terminated. + */ + +char * +gf_strncpy(char *dest, const char *src, const size_t dest_size) +{ + strncpy(dest, src, dest_size - 1); + dest[dest_size - 1] = '\0'; + return dest; +} + +int +gf_replace_old_iatt_in_dict(dict_t *xdata) +{ + int ret; + struct old_iatt *o_iatt; /* old iatt structure */ + struct iatt *c_iatt; /* current iatt */ + + if (!xdata) { + return 0; + } + + ret = dict_get_bin(xdata, DHT_IATT_IN_XDATA_KEY, (void **)&c_iatt); + if (ret < 0) { + return 0; + } + + o_iatt = GF_CALLOC(1, sizeof(struct old_iatt), gf_common_mt_char); + if (!o_iatt) { + return -1; + } + + oldiatt_from_iatt(o_iatt, c_iatt); + + ret = dict_set_bin(xdata, DHT_IATT_IN_XDATA_KEY, o_iatt, + sizeof(struct old_iatt)); + if (ret) { + GF_FREE(o_iatt); + } + + return ret; +} + +int +gf_replace_new_iatt_in_dict(dict_t *xdata) +{ + int ret; + struct old_iatt *o_iatt; /* old iatt structure */ + struct iatt *c_iatt; /* new iatt */ + + if (!xdata) { + return 0; + } + + ret = dict_get_bin(xdata, DHT_IATT_IN_XDATA_KEY, (void **)&o_iatt); + if (ret < 0) { + return 0; + } + + c_iatt = GF_CALLOC(1, sizeof(struct iatt), gf_common_mt_char); + if (!c_iatt) { + return -1; + } + + iatt_from_oldiatt(c_iatt, o_iatt); + + ret = dict_set_bin(xdata, DHT_IATT_IN_XDATA_KEY, c_iatt, + sizeof(struct iatt)); + if (ret) { + GF_FREE(c_iatt); + } + + return ret; +} + +xlator_cmdline_option_t * +find_xlator_option_in_cmd_args_t(const char *option_name, cmd_args_t *args) +{ + xlator_cmdline_option_t *pos = NULL; + xlator_cmdline_option_t *tmp = NULL; + + list_for_each_entry_safe(pos, tmp, &args->xlator_options, cmd_args) + { + if (strcmp(pos->key, option_name) == 0) + return pos; + } + return NULL; +} + +int +gf_d_type_from_ia_type(ia_type_t type) +{ + switch (type) { + case IA_IFDIR: + return DT_DIR; + case IA_IFCHR: + return DT_CHR; + case IA_IFBLK: + return DT_BLK; + case IA_IFIFO: + return DT_FIFO; + case IA_IFLNK: + return DT_LNK; + case IA_IFREG: + return DT_REG; + case IA_IFSOCK: + return DT_SOCK; + default: + return DT_UNKNOWN; + } +} + +int +gf_nanosleep(uint64_t nsec) +{ + struct timespec req; + struct timespec rem; + int ret = -1; + + req.tv_sec = nsec / GF_SEC_IN_NS; + req.tv_nsec = nsec % GF_SEC_IN_NS; + + do { + ret = nanosleep(&req, &rem); + req = rem; + } while (ret == -1 && errno == EINTR); + + return ret; +} + +int +gf_syncfs(int fd) +{ + int ret = 0; +#if defined(HAVE_SYNCFS) + /* Linux with glibc recent enough. */ + ret = syncfs(fd); +#elif defined(HAVE_SYNCFS_SYS) + /* Linux with no library function. */ + ret = syscall(SYS_syncfs, fd); +#else + /* Fallback to generic UNIX stuff. */ + sync(); +#endif + return ret; +} + +char ** +get_xattrs_to_heal() +{ + return xattrs_to_heal; } diff --git a/libglusterfs/src/common-utils.h b/libglusterfs/src/common-utils.h deleted file mode 100644 index 54f52a5a0b1..00000000000 --- a/libglusterfs/src/common-utils.h +++ /dev/null @@ -1,335 +0,0 @@ -/* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _COMMON_UTILS_H -#define _COMMON_UTILS_H - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include <stdint.h> -#include <sys/uio.h> -#include <netdb.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include <pthread.h> -#ifndef GF_BSD_HOST_OS -#include <alloca.h> -#endif - -void trap (void); - -#define GF_UNIVERSAL_ANSWER 42 /* :O */ - -/* To solve type punned error */ -#define VOID(ptr) ((void **) ((void *) ptr)) - -#include "logging.h" -#include "glusterfs.h" -#include "locking.h" -#include "mem-pool.h" - - -#define min(a,b) ((a)<(b)?(a):(b)) -#define max(a,b) ((a)>(b)?(a):(b)) -#define roof(a,b) ((((a)+(b)-1)/((b)?(b):1))*(b)) -#define floor(a,b) (((a)/((b)?(b):1))*(b)) - - -#define GF_UNIT_KB 1024ULL -#define GF_UNIT_MB 1048576ULL -#define GF_UNIT_GB 1073741824ULL -#define GF_UNIT_TB 1099511627776ULL -#define GF_UNIT_PB 1125899906842624ULL - -#define GF_UNIT_KB_STRING "KB" -#define GF_UNIT_MB_STRING "MB" -#define GF_UNIT_GB_STRING "GB" -#define GF_UNIT_TB_STRING "TB" -#define GF_UNIT_PB_STRING "PB" - - -enum _gf_boolean -{ - _gf_false = 0, - _gf_true = 1 -}; - -typedef enum _gf_boolean gf_boolean_t; - -void gf_global_variable_init(void); - -in_addr_t gf_resolve_ip (const char *hostname, void **dnscache); - -void gf_log_volume_file (FILE *specfp); -void gf_print_trace (int32_t signal); - -extern char *gf_fop_list[GF_FOP_MAXVALUE]; -extern char *gf_mgmt_list[GF_MGMT_MAXVALUE]; - -#define VECTORSIZE(count) (count * (sizeof (struct iovec))) - -#define STRLEN_0(str) (strlen(str) + 1) -#define VALIDATE_OR_GOTO(arg,label) do { \ - if (!arg) { \ - errno = EINVAL; \ - gf_log ((this ? this->name : "(Govinda! Govinda!)"), \ - GF_LOG_ERROR, \ - "invalid argument: " #arg); \ - goto label; \ - } \ - } while (0); - -#define GF_VALIDATE_OR_GOTO(name,arg,label) do { \ - if (!arg) { \ - errno = EINVAL; \ - gf_log (name, GF_LOG_ERROR, \ - "invalid argument: " #arg); \ - goto label; \ - } \ - } while (0); - -#define GF_VALIDATE_OR_GOTO_WITH_ERROR(name, arg, label, errno, error) do { \ - if (!arg) { \ - errno = error; \ - gf_log (name, GF_LOG_ERROR, \ - "invalid argument: " #arg); \ - goto label; \ - } \ - }while (0); - -#define GF_VALIDATE_ABSOLUTE_PATH_OR_GOTO(name,arg,label) \ - do { \ - GF_VALIDATE_OR_GOTO (name, arg, label); \ - if ((arg[0]) != '/') { \ - errno = EINVAL; \ - gf_log (name, GF_LOG_ERROR, \ - "invalid argument: " #arg); \ - goto label; \ - } \ - } while (0); - -#define GF_FILE_CONTENT_REQUESTED(_xattr_req,_content_limit) \ - (dict_get_uint64 (_xattr_req, "glusterfs.content", _content_limit) == 0) - -#define GF_ASSERT(x) assert (x); - -static inline void -iov_free (struct iovec *vector, int count) -{ - int i; - - for (i = 0; i < count; i++) - FREE (vector[i].iov_base); - - GF_FREE (vector); -} - - -static inline int -iov_length (const struct iovec *vector, int count) -{ - int i = 0; - size_t size = 0; - - for (i = 0; i < count; i++) - size += vector[i].iov_len; - - return size; -} - - -static inline struct iovec * -iov_dup (struct iovec *vector, int count) -{ - int bytecount = 0; - int i; - struct iovec *newvec = NULL; - - bytecount = (count * sizeof (struct iovec)); - newvec = GF_MALLOC (bytecount, gf_common_mt_iovec); - if (!newvec) - return NULL; - - for (i = 0; i < count; i++) { - newvec[i].iov_len = vector[i].iov_len; - newvec[i].iov_base = vector[i].iov_base; - } - - return newvec; -} - - -static inline int -iov_subset (struct iovec *orig, int orig_count, - off_t src_offset, off_t dst_offset, - struct iovec *new) -{ - int new_count = 0; - int i; - off_t offset = 0; - size_t start_offset = 0; - size_t end_offset = 0; - - - for (i = 0; i < orig_count; i++) { - if ((offset + orig[i].iov_len < src_offset) - || (offset > dst_offset)) { - goto not_subset; - } - - if (!new) { - goto count_only; - } - - start_offset = 0; - end_offset = orig[i].iov_len; - - if (src_offset >= offset) { - start_offset = (src_offset - offset); - } - - if (dst_offset <= (offset + orig[i].iov_len)) { - end_offset = (dst_offset - offset); - } - - new[new_count].iov_base = orig[i].iov_base + start_offset; - new[new_count].iov_len = end_offset - start_offset; - - count_only: - new_count++; - - not_subset: - offset += orig[i].iov_len; - } - - return new_count; -} - - -static inline void -iov_unload (char *buf, const struct iovec *vector, int count) -{ - int i; - int copied = 0; - - for (i = 0; i < count; i++) { - memcpy (buf + copied, vector[i].iov_base, vector[i].iov_len); - copied += vector[i].iov_len; - } -} - - -static inline int -mem_0filled (const char *buf, size_t size) -{ - int i = 0; - int ret = 0; - - for (i = 0; i < size; i++) { - ret = buf[i]; - if (ret) - break; - } - - return ret; -} - - -static inline int -iov_0filled (struct iovec *vector, int count) -{ - int i = 0; - int ret = 0; - - for (i = 0; i < count; i++) { - ret = mem_0filled (vector[i].iov_base, vector[i].iov_len); - if (ret) - break; - } - - return ret; -} - - -static inline void * -memdup (const void *ptr, size_t size) -{ - void *newptr = NULL; - - newptr = GF_MALLOC (size, gf_common_mt_memdup); - if (!newptr) - return NULL; - - memcpy (newptr, ptr, size); - return newptr; -} - - -char *gf_trim (char *string); -int gf_strsplit (const char *str, const char *delim, - char ***tokens, int *token_count); -int gf_volume_name_validate (const char *volume_name); - -int gf_string2long (const char *str, long *n); -int gf_string2ulong (const char *str, unsigned long *n); -int gf_string2int (const char *str, int *n); -int gf_string2uint (const char *str, unsigned int *n); -int gf_string2double (const char *str, double *n); -int gf_string2longlong (const char *str, long long *n); -int gf_string2ulonglong (const char *str, unsigned long long *n); - -int gf_string2int8 (const char *str, int8_t *n); -int gf_string2int16 (const char *str, int16_t *n); -int gf_string2int32 (const char *str, int32_t *n); -int gf_string2int64 (const char *str, int64_t *n); -int gf_string2uint8 (const char *str, uint8_t *n); -int gf_string2uint16 (const char *str, uint16_t *n); -int gf_string2uint32 (const char *str, uint32_t *n); -int gf_string2uint64 (const char *str, uint64_t *n); - -int gf_strstr (const char *str, const char *delim, const char *match); - -int gf_string2ulong_base10 (const char *str, unsigned long *n); -int gf_string2uint_base10 (const char *str, unsigned int *n); -int gf_string2uint8_base10 (const char *str, uint8_t *n); -int gf_string2uint16_base10 (const char *str, uint16_t *n); -int gf_string2uint32_base10 (const char *str, uint32_t *n); -int gf_string2uint64_base10 (const char *str, uint64_t *n); - -int gf_string2bytesize (const char *str, uint64_t *n); - -int gf_string2boolean (const char *str, gf_boolean_t *b); -int gf_string2percent (const char *str, uint32_t *n); -int gf_string2time (const char *str, uint32_t *n); - -int gf_lockfd (int fd); -int gf_unlockfd (int fd); - -int get_checksum_for_file (int fd, uint32_t *checksum); -int log_base2 (unsigned long x); - -int gf_system (const char *command); -int get_checksum_for_path (char *path, uint32_t *checksum); - -#endif /* _COMMON_UTILS_H */ - diff --git a/libglusterfs/src/compat-errno.c b/libglusterfs/src/compat-errno.c index 1dccec2fa3d..df57e243239 100644 --- a/libglusterfs/src/compat-errno.c +++ b/libglusterfs/src/compat-errno.c @@ -1,938 +1,955 @@ /* - Copyright (c) 2008-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif + 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 <stdint.h> -#include "compat-errno.h" - +#include "glusterfs/compat-errno.h" -static int32_t gf_error_to_errno_array[1024]; +static int32_t gf_error_to_errno_array[1024]; static int32_t gf_errno_to_error_array[1024]; static int32_t gf_compat_errno_init_done; #ifdef GF_SOLARIS_HOST_OS -static void -init_compat_errno_arrays () +static void +init_compat_errno_arrays() { -/* ENOMSG 35 / * No message of desired type */ - gf_error_to_errno_array[GF_ERROR_CODE_NOMSG] = ENOMSG; - gf_errno_to_error_array[ENOMSG] = GF_ERROR_CODE_NOMSG; - -/* EIDRM 36 / * Identifier removed */ - gf_error_to_errno_array[GF_ERROR_CODE_IDRM] = EIDRM; - gf_errno_to_error_array[EIDRM] = GF_ERROR_CODE_IDRM; - -/* ECHRNG 37 / * Channel number out of range */ - gf_error_to_errno_array[GF_ERROR_CODE_CHRNG] = ECHRNG; - gf_errno_to_error_array[ECHRNG] = GF_ERROR_CODE_CHRNG; - -/* EL2NSYNC 38 / * Level 2 not synchronized */ - gf_error_to_errno_array[GF_ERROR_CODE_L2NSYNC] = EL2NSYNC; - gf_errno_to_error_array[EL2NSYNC] = GF_ERROR_CODE_L2NSYNC; - -/* EL3HLT 39 / * Level 3 halted */ - gf_error_to_errno_array[GF_ERROR_CODE_L3HLT] = EL3HLT; - gf_errno_to_error_array[EL3HLT] = GF_ERROR_CODE_L3HLT; - -/* EL3RST 40 / * Level 3 reset */ - gf_error_to_errno_array[GF_ERROR_CODE_L3RST] = EL3RST; - gf_errno_to_error_array[EL3RST] = GF_ERROR_CODE_L3RST; - -/* ELNRNG 41 / * Link number out of range */ - gf_error_to_errno_array[GF_ERROR_CODE_LNRNG] = ELNRNG; - gf_errno_to_error_array[ELNRNG] = GF_ERROR_CODE_LNRNG; - -/* EUNATCH 42 / * Protocol driver not attached */ - gf_error_to_errno_array[GF_ERROR_CODE_UNATCH] = EUNATCH; - gf_errno_to_error_array[EUNATCH] = GF_ERROR_CODE_UNATCH; - -/* ENOCSI 43 / * No CSI structure available */ - gf_error_to_errno_array[GF_ERROR_CODE_NOCSI] = ENOCSI; - gf_errno_to_error_array[ENOCSI] = GF_ERROR_CODE_NOCSI; - -/* EL2HLT 44 / * Level 2 halted */ - gf_error_to_errno_array[GF_ERROR_CODE_L2HLT] = EL2HLT; - gf_errno_to_error_array[EL2HLT] = GF_ERROR_CODE_L2HLT; - -/* EDEADLK 45 / * Deadlock condition. */ - gf_error_to_errno_array[GF_ERROR_CODE_DEADLK] = EDEADLK; - gf_errno_to_error_array[EDEADLK] = GF_ERROR_CODE_DEADLK; - -/* ENOLCK 46 / * No record locks available. */ - gf_error_to_errno_array[GF_ERROR_CODE_NOLCK] = ENOLCK; - gf_errno_to_error_array[ENOLCK] = GF_ERROR_CODE_NOLCK; - -/* ECANCELED 47 / * Operation canceled */ - gf_error_to_errno_array[GF_ERROR_CODE_CANCELED] = ECANCELED; - gf_errno_to_error_array[ECANCELED] = GF_ERROR_CODE_CANCELED; - -/* ENOTSUP 48 / * Operation not supported */ - gf_error_to_errno_array[GF_ERROR_CODE_NOTSUPP] = ENOTSUP; - gf_errno_to_error_array[ENOTSUP] = GF_ERROR_CODE_NOTSUPP; - -/* Filesystem Quotas */ -/* EDQUOT 49 / * Disc quota exceeded */ - gf_error_to_errno_array[GF_ERROR_CODE_DQUOT] = EDQUOT; - gf_errno_to_error_array[EDQUOT] = GF_ERROR_CODE_DQUOT; - -/* Convergent Error Returns */ -/* EBADE 50 / * invalid exchange */ - gf_error_to_errno_array[GF_ERROR_CODE_BADE] = EBADE; - gf_errno_to_error_array[EBADE] = GF_ERROR_CODE_BADE; -/* EBADR 51 / * invalid request descriptor */ - gf_error_to_errno_array[GF_ERROR_CODE_BADR] = EBADR; - gf_errno_to_error_array[EBADR] = GF_ERROR_CODE_BADR; -/* EXFULL 52 / * exchange full */ - gf_error_to_errno_array[GF_ERROR_CODE_XFULL] = EXFULL; - gf_errno_to_error_array[EXFULL] = GF_ERROR_CODE_XFULL; -/* ENOANO 53 / * no anode */ - gf_error_to_errno_array[GF_ERROR_CODE_NOANO] = ENOANO; - gf_errno_to_error_array[ENOANO] = GF_ERROR_CODE_NOANO; -/* EBADRQC 54 / * invalid request code */ - gf_error_to_errno_array[GF_ERROR_CODE_BADRQC] = EBADRQC; - gf_errno_to_error_array[EBADRQC] = GF_ERROR_CODE_BADRQC; -/* EBADSLT 55 / * invalid slot */ - gf_error_to_errno_array[GF_ERROR_CODE_BADSLT] = EBADSLT; - gf_errno_to_error_array[EBADSLT] = GF_ERROR_CODE_BADSLT; -/* EDEADLOCK 56 / * file locking deadlock error */ -/* This is same as EDEADLK on linux */ - gf_error_to_errno_array[GF_ERROR_CODE_DEADLK] = EDEADLOCK; - gf_errno_to_error_array[EDEADLOCK] = GF_ERROR_CODE_DEADLK; - -/* EBFONT 57 / * bad font file fmt */ - gf_error_to_errno_array[GF_ERROR_CODE_BFONT] = EBFONT; - gf_errno_to_error_array[EBFONT] = GF_ERROR_CODE_BFONT; - -/* Interprocess Robust Locks */ -/* EOWNERDEAD 58 / * process died with the lock */ - gf_error_to_errno_array[GF_ERROR_CODE_OWNERDEAD] = EOWNERDEAD; - gf_errno_to_error_array[EOWNERDEAD] = GF_ERROR_CODE_OWNERDEAD; -/* ENOTRECOVERABLE 59 / * lock is not recoverable */ - gf_error_to_errno_array[GF_ERROR_CODE_NOTRECOVERABLE] = ENOTRECOVERABLE; - gf_errno_to_error_array[ENOTRECOVERABLE] = GF_ERROR_CODE_NOTRECOVERABLE; - -/* stream problems */ -/* ENOSTR 60 / * Device not a stream */ - gf_error_to_errno_array[GF_ERROR_CODE_NOSTR] = ENOSTR; - gf_errno_to_error_array[ENOSTR] = GF_ERROR_CODE_NOSTR; -/* ENODATA 61 / * no data (for no delay io) */ - gf_error_to_errno_array[GF_ERROR_CODE_NODATA] = ENODATA; - gf_errno_to_error_array[ENODATA] = GF_ERROR_CODE_NODATA; -/* ETIME 62 / * timer expired */ - gf_error_to_errno_array[GF_ERROR_CODE_TIME] = ETIME; - gf_errno_to_error_array[ETIME] = GF_ERROR_CODE_TIME; -/* ENOSR 63 / * out of streams resources */ - gf_error_to_errno_array[GF_ERROR_CODE_NOSR] = ENOSR; - gf_errno_to_error_array[ENOSR] = GF_ERROR_CODE_NOSR; - -/* ENONET 64 / * Machine is not on the network */ - gf_error_to_errno_array[GF_ERROR_CODE_NONET] = ENONET; - gf_errno_to_error_array[ENONET] = GF_ERROR_CODE_NONET; -/* ENOPKG 65 / * Package not installed */ - gf_error_to_errno_array[GF_ERROR_CODE_NOPKG] = ENOPKG; - gf_errno_to_error_array[ENOPKG] = GF_ERROR_CODE_NOPKG; -/* EREMOTE 66 / * The object is remote */ - gf_error_to_errno_array[GF_ERROR_CODE_REMOTE] = EREMOTE; - gf_errno_to_error_array[EREMOTE] = GF_ERROR_CODE_REMOTE; -/* ENOLINK 67 / * the link has been severed */ - gf_error_to_errno_array[GF_ERROR_CODE_NOLINK] = ENOLINK; - gf_errno_to_error_array[ENOLINK] = GF_ERROR_CODE_NOLINK; -/* EADV 68 / * advertise error */ - gf_error_to_errno_array[GF_ERROR_CODE_ADV] = EADV; - gf_errno_to_error_array[EADV] = GF_ERROR_CODE_ADV; -/* ESRMNT 69 / * srmount error */ - gf_error_to_errno_array[GF_ERROR_CODE_SRMNT] = ESRMNT; - gf_errno_to_error_array[ESRMNT] = GF_ERROR_CODE_SRMNT; - -/* ECOMM 70 / * Communication error on send */ - gf_error_to_errno_array[GF_ERROR_CODE_COMM] = ECOMM; - gf_errno_to_error_array[ECOMM] = GF_ERROR_CODE_COMM; -/* EPROTO 71 / * Protocol error */ - gf_error_to_errno_array[GF_ERROR_CODE_PROTO] = EPROTO; - gf_errno_to_error_array[EPROTO] = GF_ERROR_CODE_PROTO; - -/* Interprocess Robust Locks */ -/* ELOCKUNMAPPED 72 / * locked lock was unmapped */ - gf_error_to_errno_array[GF_ERROR_CODE_LOCKUNMAPPED] = ELOCKUNMAPPED; - gf_errno_to_error_array[ELOCKUNMAPPED] = GF_ERROR_CODE_LOCKUNMAPPED; - -/* ENOTACTIVE 73 / * Facility is not active */ - gf_error_to_errno_array[GF_ERROR_CODE_NOTACTIVE] = ENOTACTIVE; - gf_errno_to_error_array[ENOTACTIVE] = GF_ERROR_CODE_NOTACTIVE; -/* EMULTIHOP 74 / * multihop attempted */ - gf_error_to_errno_array[GF_ERROR_CODE_MULTIHOP] = EMULTIHOP; - gf_errno_to_error_array[EMULTIHOP] = GF_ERROR_CODE_MULTIHOP; -/* EBADMSG 77 / * trying to read unreadable message */ - gf_error_to_errno_array[GF_ERROR_CODE_BADMSG] = EBADMSG; - gf_errno_to_error_array[EBADMSG] = GF_ERROR_CODE_BADMSG; -/* ENAMETOOLONG 78 / * path name is too long */ - gf_error_to_errno_array[GF_ERROR_CODE_NAMETOOLONG] = ENAMETOOLONG; - gf_errno_to_error_array[ENAMETOOLONG] = GF_ERROR_CODE_NAMETOOLONG; -/* EOVERFLOW 79 / * value too large to be stored in data type */ - gf_error_to_errno_array[GF_ERROR_CODE_OVERFLOW] = EOVERFLOW; - gf_errno_to_error_array[EOVERFLOW] = GF_ERROR_CODE_OVERFLOW; -/* ENOTUNIQ 80 / * given log. name not unique */ - gf_error_to_errno_array[GF_ERROR_CODE_NOTUNIQ] = ENOTUNIQ; - gf_errno_to_error_array[ENOTUNIQ] = GF_ERROR_CODE_NOTUNIQ; -/* EBADFD 81 / * f.d. invalid for this operation */ - gf_error_to_errno_array[GF_ERROR_CODE_BADFD] = EBADFD; - gf_errno_to_error_array[EBADFD] = GF_ERROR_CODE_BADFD; -/* EREMCHG 82 / * Remote address changed */ - gf_error_to_errno_array[GF_ERROR_CODE_REMCHG] = EREMCHG; - gf_errno_to_error_array[EREMCHG] = GF_ERROR_CODE_REMCHG; - -/* shared library problems */ -/* ELIBACC 83 / * Can't access a needed shared lib. */ - gf_error_to_errno_array[GF_ERROR_CODE_LIBACC] = ELIBACC; - gf_errno_to_error_array[ELIBACC] = GF_ERROR_CODE_LIBACC; -/* ELIBBAD 84 / * Accessing a corrupted shared lib. */ - gf_error_to_errno_array[GF_ERROR_CODE_LIBBAD] = ELIBBAD; - gf_errno_to_error_array[ELIBBAD] = GF_ERROR_CODE_LIBBAD; -/* ELIBSCN 85 / * .lib section in a.out corrupted. */ - gf_error_to_errno_array[GF_ERROR_CODE_LIBSCN] = ELIBSCN; - gf_errno_to_error_array[ELIBSCN] = GF_ERROR_CODE_LIBSCN; -/* ELIBMAX 86 / * Attempting to link in too many libs. */ - gf_error_to_errno_array[GF_ERROR_CODE_LIBMAX] = ELIBMAX; - gf_errno_to_error_array[ELIBMAX] = GF_ERROR_CODE_LIBMAX; -/* ELIBEXEC 87 / * Attempting to exec a shared library. */ - gf_error_to_errno_array[GF_ERROR_CODE_LIBEXEC] = ELIBEXEC; - gf_errno_to_error_array[ELIBEXEC] = GF_ERROR_CODE_LIBEXEC; -/* EILSEQ 88 / * Illegal byte sequence. */ - gf_error_to_errno_array[GF_ERROR_CODE_ILSEQ] = EILSEQ; - gf_errno_to_error_array[EILSEQ] = GF_ERROR_CODE_ILSEQ; -/* ENOSYS 89 / * Unsupported file system operation */ - gf_error_to_errno_array[GF_ERROR_CODE_NOSYS] = ENOSYS; - gf_errno_to_error_array[ENOSYS] = GF_ERROR_CODE_NOSYS; -/* ELOOP 90 / * Symbolic link loop */ - gf_error_to_errno_array[GF_ERROR_CODE_LOOP] = ELOOP; - gf_errno_to_error_array[ELOOP] = GF_ERROR_CODE_LOOP; -/* ERESTART 91 / * Restartable system call */ - gf_error_to_errno_array[GF_ERROR_CODE_RESTART] = ERESTART; - gf_errno_to_error_array[ERESTART] = GF_ERROR_CODE_RESTART; -/* ESTRPIPE 92 / * if pipe/FIFO, don't sleep in stream head */ - gf_error_to_errno_array[GF_ERROR_CODE_STRPIPE] = ESTRPIPE; - gf_errno_to_error_array[ESTRPIPE] = GF_ERROR_CODE_STRPIPE; -/* ENOTEMPTY 93 / * directory not empty */ - gf_error_to_errno_array[GF_ERROR_CODE_NOTEMPTY] = ENOTEMPTY; - gf_errno_to_error_array[ENOTEMPTY] = GF_ERROR_CODE_NOTEMPTY; -/* EUSERS 94 / * Too many users (for UFS) */ - gf_error_to_errno_array[GF_ERROR_CODE_USERS] = EUSERS; - gf_errno_to_error_array[EUSERS] = GF_ERROR_CODE_USERS; - -/* BSD Networking Software */ - /* argument errors */ -/* ENOTSOCK 95 / * Socket operation on non-socket */ - gf_error_to_errno_array[GF_ERROR_CODE_NOTSOCK] = ENOTSOCK; - gf_errno_to_error_array[ENOTSOCK] = GF_ERROR_CODE_NOTSOCK; -/* EDESTADDRREQ 96 / * Destination address required */ - gf_error_to_errno_array[GF_ERROR_CODE_DESTADDRREQ] = EDESTADDRREQ; - gf_errno_to_error_array[EDESTADDRREQ] = GF_ERROR_CODE_DESTADDRREQ; -/* EMSGSIZE 97 / * Message too long */ - gf_error_to_errno_array[GF_ERROR_CODE_MSGSIZE] = EMSGSIZE; - gf_errno_to_error_array[EMSGSIZE] = GF_ERROR_CODE_MSGSIZE; -/* EPROTOTYPE 98 / * Protocol wrong type for socket */ - gf_error_to_errno_array[GF_ERROR_CODE_PROTOTYPE] = EPROTOTYPE; - gf_errno_to_error_array[EPROTOTYPE] = GF_ERROR_CODE_PROTOTYPE; -/* ENOPROTOOPT 99 / * Protocol not available */ - gf_error_to_errno_array[GF_ERROR_CODE_NOPROTOOPT] = ENOPROTOOPT; - gf_errno_to_error_array[ENOPROTOOPT] = GF_ERROR_CODE_NOPROTOOPT; -/* EPROTONOSUPPORT 120 / * Protocol not supported */ - gf_error_to_errno_array[GF_ERROR_CODE_PROTONOSUPPORT] = EPROTONOSUPPORT; - gf_errno_to_error_array[EPROTONOSUPPORT] = GF_ERROR_CODE_PROTONOSUPPORT; -/* ESOCKTNOSUPPORT 121 / * Socket type not supported */ - gf_error_to_errno_array[GF_ERROR_CODE_SOCKTNOSUPPORT] = ESOCKTNOSUPPORT; - gf_errno_to_error_array[ESOCKTNOSUPPORT] = GF_ERROR_CODE_SOCKTNOSUPPORT; - -/* EOPNOTSUPP 122 / * Operation not supported on socket */ - gf_error_to_errno_array[GF_ERROR_CODE_OPNOTSUPP] = EOPNOTSUPP; - gf_errno_to_error_array[EOPNOTSUPP] = GF_ERROR_CODE_OPNOTSUPP; -/* EPFNOSUPPORT 123 / * Protocol family not supported */ - gf_error_to_errno_array[GF_ERROR_CODE_PFNOSUPPORT] = EPFNOSUPPORT; - gf_errno_to_error_array[EPFNOSUPPORT] = GF_ERROR_CODE_PFNOSUPPORT; -/* EAFNOSUPPORT 124 / * Address family not supported by */ - /* protocol family */ - gf_error_to_errno_array[GF_ERROR_CODE_AFNOSUPPORT] = EAFNOSUPPORT; - gf_errno_to_error_array[EAFNOSUPPORT] = GF_ERROR_CODE_AFNOSUPPORT; -/* EADDRINUSE 125 / * Address already in use */ - gf_error_to_errno_array[GF_ERROR_CODE_ADDRINUSE] = EADDRINUSE; - gf_errno_to_error_array[EADDRINUSE] = GF_ERROR_CODE_ADDRINUSE; -/* EADDRNOTAVAIL 126 / * Can't assign requested address */ - /* operational errors */ - gf_error_to_errno_array[GF_ERROR_CODE_ADDRNOTAVAIL] = EADDRNOTAVAIL; - gf_errno_to_error_array[EADDRNOTAVAIL] = GF_ERROR_CODE_ADDRNOTAVAIL; -/* ENETDOWN 127 / * Network is down */ - gf_error_to_errno_array[GF_ERROR_CODE_NETDOWN] = ENETDOWN; - gf_errno_to_error_array[ENETDOWN] = GF_ERROR_CODE_NETDOWN; -/* ENETUNREACH 128 / * Network is unreachable */ - gf_error_to_errno_array[GF_ERROR_CODE_NETUNREACH] = ENETUNREACH; - gf_errno_to_error_array[ENETUNREACH] = GF_ERROR_CODE_NETUNREACH; -/* ENETRESET 129 / * Network dropped connection because */ - /* of reset */ - gf_error_to_errno_array[GF_ERROR_CODE_NETRESET] = ENETRESET; - gf_errno_to_error_array[ENETRESET] = GF_ERROR_CODE_NETRESET; -/* ECONNABORTED 130 / * Software caused connection abort */ - gf_error_to_errno_array[GF_ERROR_CODE_CONNABORTED] = ECONNABORTED; - gf_errno_to_error_array[ECONNABORTED] = GF_ERROR_CODE_CONNABORTED; -/* ECONNRESET 131 / * Connection reset by peer */ - gf_error_to_errno_array[GF_ERROR_CODE_CONNRESET] = ECONNRESET; - gf_errno_to_error_array[ECONNRESET] = GF_ERROR_CODE_CONNRESET; -/* ENOBUFS 132 / * No buffer space available */ - gf_error_to_errno_array[GF_ERROR_CODE_NOBUFS] = ENOBUFS; - gf_errno_to_error_array[ENOBUFS] = GF_ERROR_CODE_NOBUFS; -/* EISCONN 133 / * Socket is already connected */ - gf_error_to_errno_array[GF_ERROR_CODE_ISCONN] = EISCONN; - gf_errno_to_error_array[EISCONN] = GF_ERROR_CODE_ISCONN; -/* ENOTCONN 134 / * Socket is not connected */ - gf_error_to_errno_array[GF_ERROR_CODE_NOTCONN] = ENOTCONN; - gf_errno_to_error_array[ENOTCONN] = GF_ERROR_CODE_NOTCONN; -/* XENIX has 135 - 142 */ -/* ESHUTDOWN 143 / * Can't send after socket shutdown */ - gf_error_to_errno_array[GF_ERROR_CODE_SHUTDOWN] = ESHUTDOWN; - gf_errno_to_error_array[ESHUTDOWN] = GF_ERROR_CODE_SHUTDOWN; -/* ETOOMANYREFS 144 / * Too many references: can't splice */ - gf_error_to_errno_array[GF_ERROR_CODE_TOOMANYREFS] = ETOOMANYREFS; - gf_errno_to_error_array[ETOOMANYREFS] = GF_ERROR_CODE_TOOMANYREFS; -/* ETIMEDOUT 145 / * Connection timed out */ - gf_error_to_errno_array[GF_ERROR_CODE_TIMEDOUT] = ETIMEDOUT; - gf_errno_to_error_array[ETIMEDOUT] = GF_ERROR_CODE_TIMEDOUT; - -/* ECONNREFUSED 146 / * Connection refused */ - gf_error_to_errno_array[GF_ERROR_CODE_CONNREFUSED] = ECONNREFUSED; - gf_errno_to_error_array[ECONNREFUSED] = GF_ERROR_CODE_CONNREFUSED; -/* EHOSTDOWN 147 / * Host is down */ - gf_error_to_errno_array[GF_ERROR_CODE_HOSTDOWN] = EHOSTDOWN; - gf_errno_to_error_array[EHOSTDOWN] = GF_ERROR_CODE_HOSTDOWN; -/* EHOSTUNREACH 148 / * No route to host */ - gf_error_to_errno_array[GF_ERROR_CODE_HOSTUNREACH] = EHOSTUNREACH; - gf_errno_to_error_array[EHOSTUNREACH] = GF_ERROR_CODE_HOSTUNREACH; -/* EALREADY 149 / * operation already in progress */ - gf_error_to_errno_array[GF_ERROR_CODE_ALREADY] = EALREADY; - gf_errno_to_error_array[EALREADY] = GF_ERROR_CODE_ALREADY; -/* EINPROGRESS 150 / * operation now in progress */ - gf_error_to_errno_array[GF_ERROR_CODE_INPROGRESS] = EINPROGRESS; - gf_errno_to_error_array[EINPROGRESS] = GF_ERROR_CODE_INPROGRESS; - -/* SUN Network File System */ -/* ESTALE 151 / * Stale NFS file handle */ - gf_error_to_errno_array[GF_ERROR_CODE_STALE] = ESTALE; - gf_errno_to_error_array[ESTALE] = GF_ERROR_CODE_STALE; - - return ; + /* ENOMSG 35 / * No message of desired type */ + gf_error_to_errno_array[GF_ERROR_CODE_NOMSG] = ENOMSG; + gf_errno_to_error_array[ENOMSG] = GF_ERROR_CODE_NOMSG; + + /* EIDRM 36 / * Identifier removed */ + gf_error_to_errno_array[GF_ERROR_CODE_IDRM] = EIDRM; + gf_errno_to_error_array[EIDRM] = GF_ERROR_CODE_IDRM; + + /* ECHRNG 37 / * Channel number out of range */ + gf_error_to_errno_array[GF_ERROR_CODE_CHRNG] = ECHRNG; + gf_errno_to_error_array[ECHRNG] = GF_ERROR_CODE_CHRNG; + + /* EL2NSYNC 38 / * Level 2 not synchronized */ + gf_error_to_errno_array[GF_ERROR_CODE_L2NSYNC] = EL2NSYNC; + gf_errno_to_error_array[EL2NSYNC] = GF_ERROR_CODE_L2NSYNC; + + /* EL3HLT 39 / * Level 3 halted */ + gf_error_to_errno_array[GF_ERROR_CODE_L3HLT] = EL3HLT; + gf_errno_to_error_array[EL3HLT] = GF_ERROR_CODE_L3HLT; + + /* EL3RST 40 / * Level 3 reset */ + gf_error_to_errno_array[GF_ERROR_CODE_L3RST] = EL3RST; + gf_errno_to_error_array[EL3RST] = GF_ERROR_CODE_L3RST; + + /* ELNRNG 41 / * Link number out of range */ + gf_error_to_errno_array[GF_ERROR_CODE_LNRNG] = ELNRNG; + gf_errno_to_error_array[ELNRNG] = GF_ERROR_CODE_LNRNG; + + /* EUNATCH 42 / * Protocol driver not attached */ + gf_error_to_errno_array[GF_ERROR_CODE_UNATCH] = EUNATCH; + gf_errno_to_error_array[EUNATCH] = GF_ERROR_CODE_UNATCH; + + /* ENOCSI 43 / * No CSI structure available */ + gf_error_to_errno_array[GF_ERROR_CODE_NOCSI] = ENOCSI; + gf_errno_to_error_array[ENOCSI] = GF_ERROR_CODE_NOCSI; + + /* EL2HLT 44 / * Level 2 halted */ + gf_error_to_errno_array[GF_ERROR_CODE_L2HLT] = EL2HLT; + gf_errno_to_error_array[EL2HLT] = GF_ERROR_CODE_L2HLT; + + /* EDEADLK 45 / * Deadlock condition. */ + gf_error_to_errno_array[GF_ERROR_CODE_DEADLK] = EDEADLK; + gf_errno_to_error_array[EDEADLK] = GF_ERROR_CODE_DEADLK; + + /* ENOLCK 46 / * No record locks available. */ + gf_error_to_errno_array[GF_ERROR_CODE_NOLCK] = ENOLCK; + gf_errno_to_error_array[ENOLCK] = GF_ERROR_CODE_NOLCK; + + /* ECANCELED 47 / * Operation canceled */ + gf_error_to_errno_array[GF_ERROR_CODE_CANCELED] = ECANCELED; + gf_errno_to_error_array[ECANCELED] = GF_ERROR_CODE_CANCELED; + + /* ENOTSUP 48 / * Operation not supported */ + gf_error_to_errno_array[GF_ERROR_CODE_NOTSUPP] = ENOTSUP; + gf_errno_to_error_array[ENOTSUP] = GF_ERROR_CODE_NOTSUPP; + + /* Filesystem Quotas */ + /* EDQUOT 49 / * Disc quota exceeded */ + gf_error_to_errno_array[GF_ERROR_CODE_DQUOT] = EDQUOT; + gf_errno_to_error_array[EDQUOT] = GF_ERROR_CODE_DQUOT; + + /* Convergent Error Returns */ + /* EBADE 50 / * invalid exchange */ + gf_error_to_errno_array[GF_ERROR_CODE_BADE] = EBADE; + gf_errno_to_error_array[EBADE] = GF_ERROR_CODE_BADE; + /* EBADR 51 / * invalid request descriptor */ + gf_error_to_errno_array[GF_ERROR_CODE_BADR] = EBADR; + gf_errno_to_error_array[EBADR] = GF_ERROR_CODE_BADR; + /* EXFULL 52 / * exchange full */ + gf_error_to_errno_array[GF_ERROR_CODE_XFULL] = EXFULL; + gf_errno_to_error_array[EXFULL] = GF_ERROR_CODE_XFULL; + /* ENOANO 53 / * no anode */ + gf_error_to_errno_array[GF_ERROR_CODE_NOANO] = ENOANO; + gf_errno_to_error_array[ENOANO] = GF_ERROR_CODE_NOANO; + /* EBADRQC 54 / * invalid request code */ + gf_error_to_errno_array[GF_ERROR_CODE_BADRQC] = EBADRQC; + gf_errno_to_error_array[EBADRQC] = GF_ERROR_CODE_BADRQC; + /* EBADSLT 55 / * invalid slot */ + gf_error_to_errno_array[GF_ERROR_CODE_BADSLT] = EBADSLT; + gf_errno_to_error_array[EBADSLT] = GF_ERROR_CODE_BADSLT; + /* EDEADLOCK 56 / * file locking deadlock error */ + /* This is same as EDEADLK on linux */ + gf_error_to_errno_array[GF_ERROR_CODE_DEADLK] = EDEADLOCK; + gf_errno_to_error_array[EDEADLOCK] = GF_ERROR_CODE_DEADLK; + + /* EBFONT 57 / * bad font file fmt */ + gf_error_to_errno_array[GF_ERROR_CODE_BFONT] = EBFONT; + gf_errno_to_error_array[EBFONT] = GF_ERROR_CODE_BFONT; + + /* Interprocess Robust Locks */ + /* EOWNERDEAD 58 / * process died with the lock */ + gf_error_to_errno_array[GF_ERROR_CODE_OWNERDEAD] = EOWNERDEAD; + gf_errno_to_error_array[EOWNERDEAD] = GF_ERROR_CODE_OWNERDEAD; + /* ENOTRECOVERABLE 59 / * lock is not recoverable */ + gf_error_to_errno_array[GF_ERROR_CODE_NOTRECOVERABLE] = ENOTRECOVERABLE; + gf_errno_to_error_array[ENOTRECOVERABLE] = GF_ERROR_CODE_NOTRECOVERABLE; + + /* stream problems */ + /* ENOSTR 60 / * Device not a stream */ + gf_error_to_errno_array[GF_ERROR_CODE_NOSTR] = ENOSTR; + gf_errno_to_error_array[ENOSTR] = GF_ERROR_CODE_NOSTR; + /* ENODATA 61 / * no data (for no delay io) */ + gf_error_to_errno_array[GF_ERROR_CODE_NODATA] = ENODATA; + gf_errno_to_error_array[ENODATA] = GF_ERROR_CODE_NODATA; + /* ETIME 62 / * timer expired */ + gf_error_to_errno_array[GF_ERROR_CODE_TIME] = ETIME; + gf_errno_to_error_array[ETIME] = GF_ERROR_CODE_TIME; + /* ENOSR 63 / * out of streams resources */ + gf_error_to_errno_array[GF_ERROR_CODE_NOSR] = ENOSR; + gf_errno_to_error_array[ENOSR] = GF_ERROR_CODE_NOSR; + + /* ENONET 64 / * Machine is not on the network */ + gf_error_to_errno_array[GF_ERROR_CODE_NONET] = ENONET; + gf_errno_to_error_array[ENONET] = GF_ERROR_CODE_NONET; + /* ENOPKG 65 / * Package not installed */ + gf_error_to_errno_array[GF_ERROR_CODE_NOPKG] = ENOPKG; + gf_errno_to_error_array[ENOPKG] = GF_ERROR_CODE_NOPKG; + /* EREMOTE 66 / * The object is remote */ + gf_error_to_errno_array[GF_ERROR_CODE_REMOTE] = EREMOTE; + gf_errno_to_error_array[EREMOTE] = GF_ERROR_CODE_REMOTE; + /* ENOLINK 67 / * the link has been severed */ + gf_error_to_errno_array[GF_ERROR_CODE_NOLINK] = ENOLINK; + gf_errno_to_error_array[ENOLINK] = GF_ERROR_CODE_NOLINK; + /* EADV 68 / * advertise error */ + gf_error_to_errno_array[GF_ERROR_CODE_ADV] = EADV; + gf_errno_to_error_array[EADV] = GF_ERROR_CODE_ADV; + /* ESRMNT 69 / * srmount error */ + gf_error_to_errno_array[GF_ERROR_CODE_SRMNT] = ESRMNT; + gf_errno_to_error_array[ESRMNT] = GF_ERROR_CODE_SRMNT; + + /* ECOMM 70 / * Communication error on send */ + gf_error_to_errno_array[GF_ERROR_CODE_COMM] = ECOMM; + gf_errno_to_error_array[ECOMM] = GF_ERROR_CODE_COMM; + /* EPROTO 71 / * Protocol error */ + gf_error_to_errno_array[GF_ERROR_CODE_PROTO] = EPROTO; + gf_errno_to_error_array[EPROTO] = GF_ERROR_CODE_PROTO; + + /* Interprocess Robust Locks */ + /* ELOCKUNMAPPED 72 / * locked lock was unmapped */ + gf_error_to_errno_array[GF_ERROR_CODE_LOCKUNMAPPED] = ELOCKUNMAPPED; + gf_errno_to_error_array[ELOCKUNMAPPED] = GF_ERROR_CODE_LOCKUNMAPPED; + + /* ENOTACTIVE 73 / * Facility is not active */ + gf_error_to_errno_array[GF_ERROR_CODE_NOTACTIVE] = ENOTACTIVE; + gf_errno_to_error_array[ENOTACTIVE] = GF_ERROR_CODE_NOTACTIVE; + /* EMULTIHOP 74 / * multihop attempted */ + gf_error_to_errno_array[GF_ERROR_CODE_MULTIHOP] = EMULTIHOP; + gf_errno_to_error_array[EMULTIHOP] = GF_ERROR_CODE_MULTIHOP; + /* EBADMSG 77 / * trying to read unreadable message */ + gf_error_to_errno_array[GF_ERROR_CODE_BADMSG] = EBADMSG; + gf_errno_to_error_array[EBADMSG] = GF_ERROR_CODE_BADMSG; + /* ENAMETOOLONG 78 / * path name is too long */ + gf_error_to_errno_array[GF_ERROR_CODE_NAMETOOLONG] = ENAMETOOLONG; + gf_errno_to_error_array[ENAMETOOLONG] = GF_ERROR_CODE_NAMETOOLONG; + /* EOVERFLOW 79 / * value too large to be stored in data type */ + gf_error_to_errno_array[GF_ERROR_CODE_OVERFLOW] = EOVERFLOW; + gf_errno_to_error_array[EOVERFLOW] = GF_ERROR_CODE_OVERFLOW; + /* ENOTUNIQ 80 / * given log. name not unique */ + gf_error_to_errno_array[GF_ERROR_CODE_NOTUNIQ] = ENOTUNIQ; + gf_errno_to_error_array[ENOTUNIQ] = GF_ERROR_CODE_NOTUNIQ; + /* EBADFD 81 / * f.d. invalid for this operation */ + gf_error_to_errno_array[GF_ERROR_CODE_BADFD] = EBADFD; + gf_errno_to_error_array[EBADFD] = GF_ERROR_CODE_BADFD; + /* EREMCHG 82 / * Remote address changed */ + gf_error_to_errno_array[GF_ERROR_CODE_REMCHG] = EREMCHG; + gf_errno_to_error_array[EREMCHG] = GF_ERROR_CODE_REMCHG; + + /* shared library problems */ + /* ELIBACC 83 / * Can't access a needed shared lib. */ + gf_error_to_errno_array[GF_ERROR_CODE_LIBACC] = ELIBACC; + gf_errno_to_error_array[ELIBACC] = GF_ERROR_CODE_LIBACC; + /* ELIBBAD 84 / * Accessing a corrupted shared lib. */ + gf_error_to_errno_array[GF_ERROR_CODE_LIBBAD] = ELIBBAD; + gf_errno_to_error_array[ELIBBAD] = GF_ERROR_CODE_LIBBAD; + /* ELIBSCN 85 / * .lib section in a.out corrupted. */ + gf_error_to_errno_array[GF_ERROR_CODE_LIBSCN] = ELIBSCN; + gf_errno_to_error_array[ELIBSCN] = GF_ERROR_CODE_LIBSCN; + /* ELIBMAX 86 / * Attempting to link in too many libs. */ + gf_error_to_errno_array[GF_ERROR_CODE_LIBMAX] = ELIBMAX; + gf_errno_to_error_array[ELIBMAX] = GF_ERROR_CODE_LIBMAX; + /* ELIBEXEC 87 / * Attempting to exec a shared library. */ + gf_error_to_errno_array[GF_ERROR_CODE_LIBEXEC] = ELIBEXEC; + gf_errno_to_error_array[ELIBEXEC] = GF_ERROR_CODE_LIBEXEC; + /* EILSEQ 88 / * Illegal byte sequence. */ + gf_error_to_errno_array[GF_ERROR_CODE_ILSEQ] = EILSEQ; + gf_errno_to_error_array[EILSEQ] = GF_ERROR_CODE_ILSEQ; + /* ENOSYS 89 / * Unsupported file system operation */ + gf_error_to_errno_array[GF_ERROR_CODE_NOSYS] = ENOSYS; + gf_errno_to_error_array[ENOSYS] = GF_ERROR_CODE_NOSYS; + /* ELOOP 90 / * Symbolic link loop */ + gf_error_to_errno_array[GF_ERROR_CODE_LOOP] = ELOOP; + gf_errno_to_error_array[ELOOP] = GF_ERROR_CODE_LOOP; + /* ERESTART 91 / * Restartable system call */ + gf_error_to_errno_array[GF_ERROR_CODE_RESTART] = ERESTART; + gf_errno_to_error_array[ERESTART] = GF_ERROR_CODE_RESTART; + /* ESTRPIPE 92 / * if pipe/FIFO, don't sleep in stream head */ + gf_error_to_errno_array[GF_ERROR_CODE_STRPIPE] = ESTRPIPE; + gf_errno_to_error_array[ESTRPIPE] = GF_ERROR_CODE_STRPIPE; + /* ENOTEMPTY 93 / * directory not empty */ + gf_error_to_errno_array[GF_ERROR_CODE_NOTEMPTY] = ENOTEMPTY; + gf_errno_to_error_array[ENOTEMPTY] = GF_ERROR_CODE_NOTEMPTY; + /* EUSERS 94 / * Too many users (for UFS) */ + gf_error_to_errno_array[GF_ERROR_CODE_USERS] = EUSERS; + gf_errno_to_error_array[EUSERS] = GF_ERROR_CODE_USERS; + + /* BSD Networking Software */ + /* argument errors */ + /* ENOTSOCK 95 / * Socket operation on non-socket */ + gf_error_to_errno_array[GF_ERROR_CODE_NOTSOCK] = ENOTSOCK; + gf_errno_to_error_array[ENOTSOCK] = GF_ERROR_CODE_NOTSOCK; + /* EDESTADDRREQ 96 / * Destination address required */ + gf_error_to_errno_array[GF_ERROR_CODE_DESTADDRREQ] = EDESTADDRREQ; + gf_errno_to_error_array[EDESTADDRREQ] = GF_ERROR_CODE_DESTADDRREQ; + /* EMSGSIZE 97 / * Message too long */ + gf_error_to_errno_array[GF_ERROR_CODE_MSGSIZE] = EMSGSIZE; + gf_errno_to_error_array[EMSGSIZE] = GF_ERROR_CODE_MSGSIZE; + /* EPROTOTYPE 98 / * Protocol wrong type for socket */ + gf_error_to_errno_array[GF_ERROR_CODE_PROTOTYPE] = EPROTOTYPE; + gf_errno_to_error_array[EPROTOTYPE] = GF_ERROR_CODE_PROTOTYPE; + /* ENOPROTOOPT 99 / * Protocol not available */ + gf_error_to_errno_array[GF_ERROR_CODE_NOPROTOOPT] = ENOPROTOOPT; + gf_errno_to_error_array[ENOPROTOOPT] = GF_ERROR_CODE_NOPROTOOPT; + /* EPROTONOSUPPORT 120 / * Protocol not supported */ + gf_error_to_errno_array[GF_ERROR_CODE_PROTONOSUPPORT] = EPROTONOSUPPORT; + gf_errno_to_error_array[EPROTONOSUPPORT] = GF_ERROR_CODE_PROTONOSUPPORT; + /* ESOCKTNOSUPPORT 121 / * Socket type not supported */ + gf_error_to_errno_array[GF_ERROR_CODE_SOCKTNOSUPPORT] = ESOCKTNOSUPPORT; + gf_errno_to_error_array[ESOCKTNOSUPPORT] = GF_ERROR_CODE_SOCKTNOSUPPORT; + + /* EOPNOTSUPP 122 / * Operation not supported on socket */ + gf_error_to_errno_array[GF_ERROR_CODE_OPNOTSUPP] = EOPNOTSUPP; + gf_errno_to_error_array[EOPNOTSUPP] = GF_ERROR_CODE_OPNOTSUPP; + /* EPFNOSUPPORT 123 / * Protocol family not supported */ + gf_error_to_errno_array[GF_ERROR_CODE_PFNOSUPPORT] = EPFNOSUPPORT; + gf_errno_to_error_array[EPFNOSUPPORT] = GF_ERROR_CODE_PFNOSUPPORT; + /* EAFNOSUPPORT 124 / * Address family not supported by */ + /* protocol family */ + gf_error_to_errno_array[GF_ERROR_CODE_AFNOSUPPORT] = EAFNOSUPPORT; + gf_errno_to_error_array[EAFNOSUPPORT] = GF_ERROR_CODE_AFNOSUPPORT; + /* EADDRINUSE 125 / * Address already in use */ + gf_error_to_errno_array[GF_ERROR_CODE_ADDRINUSE] = EADDRINUSE; + gf_errno_to_error_array[EADDRINUSE] = GF_ERROR_CODE_ADDRINUSE; + /* EADDRNOTAVAIL 126 / * Can't assign requested address */ + /* operational errors */ + gf_error_to_errno_array[GF_ERROR_CODE_ADDRNOTAVAIL] = EADDRNOTAVAIL; + gf_errno_to_error_array[EADDRNOTAVAIL] = GF_ERROR_CODE_ADDRNOTAVAIL; + /* ENETDOWN 127 / * Network is down */ + gf_error_to_errno_array[GF_ERROR_CODE_NETDOWN] = ENETDOWN; + gf_errno_to_error_array[ENETDOWN] = GF_ERROR_CODE_NETDOWN; + /* ENETUNREACH 128 / * Network is unreachable */ + gf_error_to_errno_array[GF_ERROR_CODE_NETUNREACH] = ENETUNREACH; + gf_errno_to_error_array[ENETUNREACH] = GF_ERROR_CODE_NETUNREACH; + /* ENETRESET 129 / * Network dropped connection because */ + /* of reset */ + gf_error_to_errno_array[GF_ERROR_CODE_NETRESET] = ENETRESET; + gf_errno_to_error_array[ENETRESET] = GF_ERROR_CODE_NETRESET; + /* ECONNABORTED 130 / * Software caused connection abort */ + gf_error_to_errno_array[GF_ERROR_CODE_CONNABORTED] = ECONNABORTED; + gf_errno_to_error_array[ECONNABORTED] = GF_ERROR_CODE_CONNABORTED; + /* ECONNRESET 131 / * Connection reset by peer */ + gf_error_to_errno_array[GF_ERROR_CODE_CONNRESET] = ECONNRESET; + gf_errno_to_error_array[ECONNRESET] = GF_ERROR_CODE_CONNRESET; + /* ENOBUFS 132 / * No buffer space available */ + gf_error_to_errno_array[GF_ERROR_CODE_NOBUFS] = ENOBUFS; + gf_errno_to_error_array[ENOBUFS] = GF_ERROR_CODE_NOBUFS; + /* EISCONN 133 / * Socket is already connected */ + gf_error_to_errno_array[GF_ERROR_CODE_ISCONN] = EISCONN; + gf_errno_to_error_array[EISCONN] = GF_ERROR_CODE_ISCONN; + /* ENOTCONN 134 / * Socket is not connected */ + gf_error_to_errno_array[GF_ERROR_CODE_NOTCONN] = ENOTCONN; + gf_errno_to_error_array[ENOTCONN] = GF_ERROR_CODE_NOTCONN; + /* XENIX has 135 - 142 */ + /* ESHUTDOWN 143 / * Can't send after socket shutdown */ + gf_error_to_errno_array[GF_ERROR_CODE_SHUTDOWN] = ESHUTDOWN; + gf_errno_to_error_array[ESHUTDOWN] = GF_ERROR_CODE_SHUTDOWN; + /* ETOOMANYREFS 144 / * Too many references: can't splice */ + gf_error_to_errno_array[GF_ERROR_CODE_TOOMANYREFS] = ETOOMANYREFS; + gf_errno_to_error_array[ETOOMANYREFS] = GF_ERROR_CODE_TOOMANYREFS; + /* ETIMEDOUT 145 / * Connection timed out */ + gf_error_to_errno_array[GF_ERROR_CODE_TIMEDOUT] = ETIMEDOUT; + gf_errno_to_error_array[ETIMEDOUT] = GF_ERROR_CODE_TIMEDOUT; + + /* ECONNREFUSED 146 / * Connection refused */ + gf_error_to_errno_array[GF_ERROR_CODE_CONNREFUSED] = ECONNREFUSED; + gf_errno_to_error_array[ECONNREFUSED] = GF_ERROR_CODE_CONNREFUSED; + /* EHOSTDOWN 147 / * Host is down */ + gf_error_to_errno_array[GF_ERROR_CODE_HOSTDOWN] = EHOSTDOWN; + gf_errno_to_error_array[EHOSTDOWN] = GF_ERROR_CODE_HOSTDOWN; + /* EHOSTUNREACH 148 / * No route to host */ + gf_error_to_errno_array[GF_ERROR_CODE_HOSTUNREACH] = EHOSTUNREACH; + gf_errno_to_error_array[EHOSTUNREACH] = GF_ERROR_CODE_HOSTUNREACH; + /* EALREADY 149 / * operation already in progress */ + gf_error_to_errno_array[GF_ERROR_CODE_ALREADY] = EALREADY; + gf_errno_to_error_array[EALREADY] = GF_ERROR_CODE_ALREADY; + /* EINPROGRESS 150 / * operation now in progress */ + gf_error_to_errno_array[GF_ERROR_CODE_INPROGRESS] = EINPROGRESS; + gf_errno_to_error_array[EINPROGRESS] = GF_ERROR_CODE_INPROGRESS; + + /* SUN Network File System */ + /* ESTALE 151 / * Stale NFS file handle */ + gf_error_to_errno_array[GF_ERROR_CODE_STALE] = ESTALE; + gf_errno_to_error_array[ESTALE] = GF_ERROR_CODE_STALE; + + return; } #endif /* GF_SOLARIS_HOST_OS */ #ifdef GF_DARWIN_HOST_OS -static void -init_compat_errno_arrays () +static void +init_compat_errno_arrays() { - /* EDEADLK 11 / * Resource deadlock would occur */ - gf_error_to_errno_array[GF_ERROR_CODE_DEADLK] = EDEADLK; - gf_errno_to_error_array[EDEADLK] = GF_ERROR_CODE_DEADLK; - - /* EAGAIN 35 / * Try Again */ - gf_error_to_errno_array[GF_ERROR_CODE_AGAIN] = EAGAIN; - gf_errno_to_error_array[EAGAIN] = GF_ERROR_CODE_AGAIN; - - /* EINPROGRESS 36 / * Operation now in progress */ - gf_error_to_errno_array[GF_ERROR_CODE_INPROGRESS] = EINPROGRESS; - gf_errno_to_error_array[EINPROGRESS] = GF_ERROR_CODE_INPROGRESS; - - /* EALREADY 37 / * Operation already in progress */ - gf_error_to_errno_array[GF_ERROR_CODE_ALREADY] = EALREADY; - gf_errno_to_error_array[EALREADY] = GF_ERROR_CODE_ALREADY; - - /* ENOTSOCK 38 / * Socket operation on non-socket */ - gf_error_to_errno_array[GF_ERROR_CODE_NOTSOCK] = ENOTSOCK; - gf_errno_to_error_array[ENOTSOCK] = GF_ERROR_CODE_NOTSOCK; - - /* EDESTADDRREQ 39 / * Destination address required */ - gf_error_to_errno_array[GF_ERROR_CODE_DESTADDRREQ] = EDESTADDRREQ; - gf_errno_to_error_array[EDESTADDRREQ] = GF_ERROR_CODE_DESTADDRREQ; - - /* EMSGSIZE 40 / * Message too long */ - gf_error_to_errno_array[GF_ERROR_CODE_MSGSIZE] = EMSGSIZE; - gf_errno_to_error_array[EMSGSIZE] = GF_ERROR_CODE_MSGSIZE; - - /* EPROTOTYPE 41 / * Protocol wrong type for socket */ - gf_error_to_errno_array[GF_ERROR_CODE_PROTOTYPE] = EPROTOTYPE; - gf_errno_to_error_array[EPROTOTYPE] = GF_ERROR_CODE_PROTOTYPE; - - /* ENOPROTOOPT 42 / * Protocol not available */ - gf_error_to_errno_array[GF_ERROR_CODE_NOPROTOOPT] = ENOPROTOOPT; - gf_errno_to_error_array[ENOPROTOOPT] = GF_ERROR_CODE_NOPROTOOPT; - - /* EPROTONOSUPPORT 43 / * Protocol not supported */ - gf_error_to_errno_array[GF_ERROR_CODE_PROTONOSUPPORT] = EPROTONOSUPPORT; - gf_errno_to_error_array[EPROTONOSUPPORT] = GF_ERROR_CODE_PROTONOSUPPORT; - - /* ESOCKTNOSUPPORT 44 / * Socket type not supported */ - gf_error_to_errno_array[GF_ERROR_CODE_SOCKTNOSUPPORT] = ESOCKTNOSUPPORT; - gf_errno_to_error_array[ESOCKTNOSUPPORT] = GF_ERROR_CODE_SOCKTNOSUPPORT; - - /* EOPNOTSUPP 45 / * Operation not supported */ - gf_error_to_errno_array[GF_ERROR_CODE_OPNOTSUPP] = EOPNOTSUPP; - gf_errno_to_error_array[EOPNOTSUPP] = GF_ERROR_CODE_OPNOTSUPP; - - /* EPFNOSUPPORT 46 / * Protocol family not supported */ - gf_error_to_errno_array[GF_ERROR_CODE_PFNOSUPPORT] = EPFNOSUPPORT; - gf_errno_to_error_array[EPFNOSUPPORT] = GF_ERROR_CODE_PFNOSUPPORT; - - /* EAFNOSUPPORT 47 / * Address family not supported by protocol family */ - gf_error_to_errno_array[GF_ERROR_CODE_AFNOSUPPORT] = EAFNOSUPPORT; - gf_errno_to_error_array[EAFNOSUPPORT] = GF_ERROR_CODE_AFNOSUPPORT; - - /* EADDRINUSE 48 / * Address already in use */ - gf_error_to_errno_array[GF_ERROR_CODE_ADDRINUSE] = EADDRINUSE; - gf_errno_to_error_array[EADDRINUSE] = GF_ERROR_CODE_ADDRINUSE; - - /* EADDRNOTAVAIL 49 / * Can't assign requested address */ - gf_error_to_errno_array[GF_ERROR_CODE_ADDRNOTAVAIL] = EADDRNOTAVAIL; - gf_errno_to_error_array[EADDRNOTAVAIL] = GF_ERROR_CODE_ADDRNOTAVAIL; - - /* ENETDOWN 50 / * Network is down */ - gf_error_to_errno_array[GF_ERROR_CODE_NETDOWN] = ENETDOWN; - gf_errno_to_error_array[ENETDOWN] = GF_ERROR_CODE_NETDOWN; - - /* ENETUNREACH 51 / * Network is unreachable */ - gf_error_to_errno_array[GF_ERROR_CODE_NETUNREACH] = ENETUNREACH; - gf_errno_to_error_array[ENETUNREACH] = GF_ERROR_CODE_NETUNREACH; - - /* ENETRESET 52 / * Network dropped connection on reset */ - gf_error_to_errno_array[GF_ERROR_CODE_NETRESET] = ENETRESET; - gf_errno_to_error_array[ENETRESET] = GF_ERROR_CODE_NETRESET; - - /* ECONNABORTED 53 / * Software caused connection abort */ - gf_error_to_errno_array[GF_ERROR_CODE_CONNABORTED] = ECONNABORTED; - gf_errno_to_error_array[ECONNABORTED] = GF_ERROR_CODE_CONNABORTED; - - /* ECONNRESET 54 / * Connection reset by peer */ - gf_error_to_errno_array[GF_ERROR_CODE_CONNRESET] = ECONNRESET; - gf_errno_to_error_array[ECONNRESET] = GF_ERROR_CODE_CONNRESET; - - /* ENOBUFS 55 / * No buffer space available */ - gf_error_to_errno_array[GF_ERROR_CODE_NOBUFS] = ENOBUFS; - gf_errno_to_error_array[ENOBUFS] = GF_ERROR_CODE_NOBUFS; - - /* EISCONN 56 / * Socket is already connected */ - gf_error_to_errno_array[GF_ERROR_CODE_ISCONN] = EISCONN; - gf_errno_to_error_array[EISCONN] = GF_ERROR_CODE_ISCONN; - - /* ENOTCONN 57 / * Socket is not connected */ - gf_error_to_errno_array[GF_ERROR_CODE_NOTCONN] = ENOTCONN; - gf_errno_to_error_array[ENOTCONN] = GF_ERROR_CODE_NOTCONN; - - /* ESHUTDOWN 58 / * Can't send after socket shutdown */ - gf_error_to_errno_array[GF_ERROR_CODE_SHUTDOWN] = ESHUTDOWN; - gf_errno_to_error_array[ESHUTDOWN] = GF_ERROR_CODE_SHUTDOWN; - - /* ETOOMANYREFS 59 / * Too many references: can't splice */ - gf_error_to_errno_array[GF_ERROR_CODE_TOOMANYREFS] = ETOOMANYREFS; - gf_errno_to_error_array[ETOOMANYREFS] = GF_ERROR_CODE_TOOMANYREFS; - - /* ETIMEDOUT 60 / * Operation timed out */ - gf_error_to_errno_array[GF_ERROR_CODE_TIMEDOUT] = ETIMEDOUT; - gf_errno_to_error_array[ETIMEDOUT] = GF_ERROR_CODE_TIMEDOUT; - - /* ECONNREFUSED 61 / * Connection refused */ - gf_error_to_errno_array[GF_ERROR_CODE_CONNREFUSED] = ECONNREFUSED; - gf_errno_to_error_array[ECONNREFUSED] = GF_ERROR_CODE_CONNREFUSED; - - /* ELOOP 62 / * Too many levels of symbolic links */ - gf_error_to_errno_array[GF_ERROR_CODE_LOOP] = ELOOP; - gf_errno_to_error_array[ELOOP] = GF_ERROR_CODE_LOOP; - - /* ENAMETOOLONG 63 / * File name too long */ - gf_error_to_errno_array[GF_ERROR_CODE_NAMETOOLONG] = ENAMETOOLONG; - gf_errno_to_error_array[ENAMETOOLONG] = GF_ERROR_CODE_NAMETOOLONG; - - /* EHOSTDOWN 64 / * Host is down */ - gf_error_to_errno_array[GF_ERROR_CODE_HOSTDOWN] = EHOSTDOWN; - gf_errno_to_error_array[EHOSTDOWN] = GF_ERROR_CODE_HOSTDOWN; - - /* EHOSTUNREACH 65 / * No route to host */ - gf_error_to_errno_array[GF_ERROR_CODE_HOSTUNREACH] = EHOSTUNREACH; - gf_errno_to_error_array[EHOSTUNREACH] = GF_ERROR_CODE_HOSTUNREACH; - - /* ENOTEMPTY 66 / * Directory not empty */ - gf_error_to_errno_array[GF_ERROR_CODE_NOTEMPTY] = ENOTEMPTY; - gf_errno_to_error_array[ENOTEMPTY] = GF_ERROR_CODE_NOTEMPTY; - - /* EPROCLIM 67 / * Too many processes */ - gf_error_to_errno_array[GF_ERROR_CODE_PROCLIM] = EPROCLIM; - gf_errno_to_error_array[EPROCLIM] = GF_ERROR_CODE_PROCLIM; - - /* EUSERS 68 / * Too many users */ - gf_error_to_errno_array[GF_ERROR_CODE_USERS] = EUSERS; - gf_errno_to_error_array[EUSERS] = GF_ERROR_CODE_USERS; - - /* EDQUOT 69 / * Disc quota exceeded */ - gf_error_to_errno_array[GF_ERROR_CODE_DQUOT] = EDQUOT; - gf_errno_to_error_array[EDQUOT] = GF_ERROR_CODE_DQUOT; - - /* ESTALE 70 / * Stale NFS file handle */ - gf_error_to_errno_array[GF_ERROR_CODE_STALE] = ESTALE; - gf_errno_to_error_array[ESTALE] = GF_ERROR_CODE_STALE; - - /* EREMOTE 71 / * Too many levels of remote in path */ - gf_error_to_errno_array[GF_ERROR_CODE_REMOTE] = EREMOTE; - gf_errno_to_error_array[EREMOTE] = GF_ERROR_CODE_REMOTE; - - /* EBADRPC 72 / * RPC struct is bad */ - gf_error_to_errno_array[GF_ERROR_CODE_BADRPC] = EBADRPC; - gf_errno_to_error_array[EBADRPC] = GF_ERROR_CODE_BADRPC; - - /* ERPCMISMATCH 73 / * RPC version wrong */ - gf_error_to_errno_array[GF_ERROR_CODE_RPCMISMATCH] = ERPCMISMATCH; - gf_errno_to_error_array[ERPCMISMATCH] = GF_ERROR_CODE_RPCMISMATCH; - - /* EPROGUNAVAIL 74 / * RPC prog. not avail */ - gf_error_to_errno_array[GF_ERROR_CODE_PROGUNAVAIL] = EPROGUNAVAIL; - gf_errno_to_error_array[EPROGUNAVAIL] = GF_ERROR_CODE_PROGUNAVAIL; - - /* EPROGMISMATCH 75 / * Program version wrong */ - gf_error_to_errno_array[GF_ERROR_CODE_PROGMISMATCH] = EPROGMISMATCH; - gf_errno_to_error_array[EPROGMISMATCH] = GF_ERROR_CODE_PROGMISMATCH; - - /* EPROCUNAVAIL 76 / * Bad procedure for program */ - gf_error_to_errno_array[GF_ERROR_CODE_PROCUNAVAIL] = EPROCUNAVAIL; - gf_errno_to_error_array[EPROCUNAVAIL] = GF_ERROR_CODE_PROCUNAVAIL; - - /* ENOLCK 77 / * No locks available */ - gf_error_to_errno_array[GF_ERROR_CODE_NOLCK] = ENOLCK; - gf_errno_to_error_array[ENOLCK] = GF_ERROR_CODE_NOLCK; - - /* ENOSYS 78 / * Function not implemented */ - gf_error_to_errno_array[GF_ERROR_CODE_NOSYS] = ENOSYS; - gf_errno_to_error_array[ENOSYS] = GF_ERROR_CODE_NOSYS; - - /* EFTYPE 79 / * Inappropriate file type or format */ - gf_error_to_errno_array[GF_ERROR_CODE_FTYPE] = EFTYPE; - gf_errno_to_error_array[EFTYPE] = GF_ERROR_CODE_FTYPE; - - /* EAUTH 80 / * Authentication error */ - gf_error_to_errno_array[GF_ERROR_CODE_AUTH] = EAUTH; - gf_errno_to_error_array[EAUTH] = GF_ERROR_CODE_AUTH; - - /* ENEEDAUTH 81 / * Need authenticator */ - gf_error_to_errno_array[GF_ERROR_CODE_NEEDAUTH] = ENEEDAUTH; - gf_errno_to_error_array[ENEEDAUTH] = GF_ERROR_CODE_NEEDAUTH; -/* Intelligent device errors */ -/* EPWROFF 82 / * Device power is off */ - gf_error_to_errno_array[GF_ERROR_CODE_PWROFF] = EPWROFF; - gf_errno_to_error_array[EPWROFF] = GF_ERROR_CODE_PWROFF; -/* EDEVERR 83 / * Device error, e.g. paper out */ - gf_error_to_errno_array[GF_ERROR_CODE_DEVERR] = EDEVERR; - gf_errno_to_error_array[EDEVERR] = GF_ERROR_CODE_DEVERR; - - /* EOVERFLOW 84 / * Value too large to be stored in data type */ - gf_error_to_errno_array[GF_ERROR_CODE_OVERFLOW] = EOVERFLOW; - gf_errno_to_error_array[EOVERFLOW] = GF_ERROR_CODE_OVERFLOW; - -/* Program loading errors */ -/* EBADEXEC 85 / * Bad executable */ - gf_error_to_errno_array[GF_ERROR_CODE_BADEXEC] = EBADEXEC; - gf_errno_to_error_array[EBADEXEC] = GF_ERROR_CODE_BADEXEC; - -/* EBADARCH 86 / * Bad CPU type in executable */ - gf_error_to_errno_array[GF_ERROR_CODE_BADARCH] = EBADARCH; - gf_errno_to_error_array[EBADARCH] = GF_ERROR_CODE_BADARCH; - -/* ESHLIBVERS 87 / * Shared library version mismatch */ - gf_error_to_errno_array[GF_ERROR_CODE_SHLIBVERS] = ESHLIBVERS; - gf_errno_to_error_array[ESHLIBVERS] = GF_ERROR_CODE_SHLIBVERS; - -/* EBADMACHO 88 / * Malformed Macho file */ - gf_error_to_errno_array[GF_ERROR_CODE_BADMACHO] = EBADMACHO; - gf_errno_to_error_array[EBADMACHO] = GF_ERROR_CODE_BADMACHO; - -#if 0 - /* EDOOFUS 88 / * Programming error */ - gf_error_to_errno_array[GF_ERROR_CODE_DOOFUS] = EDOOFUS; - gf_errno_to_error_array[EDOOFUS] = GF_ERROR_CODE_DOOFUS; + /* EDEADLK 11 / * Resource deadlock would occur */ + gf_error_to_errno_array[GF_ERROR_CODE_DEADLK] = EDEADLK; + gf_errno_to_error_array[EDEADLK] = GF_ERROR_CODE_DEADLK; + + /* EAGAIN 35 / * Try Again */ + gf_error_to_errno_array[GF_ERROR_CODE_AGAIN] = EAGAIN; + gf_errno_to_error_array[EAGAIN] = GF_ERROR_CODE_AGAIN; + + /* EINPROGRESS 36 / * Operation now in progress */ + gf_error_to_errno_array[GF_ERROR_CODE_INPROGRESS] = EINPROGRESS; + gf_errno_to_error_array[EINPROGRESS] = GF_ERROR_CODE_INPROGRESS; + + /* EALREADY 37 / * Operation already in progress */ + gf_error_to_errno_array[GF_ERROR_CODE_ALREADY] = EALREADY; + gf_errno_to_error_array[EALREADY] = GF_ERROR_CODE_ALREADY; + + /* ENOTSOCK 38 / * Socket operation on non-socket + */ + gf_error_to_errno_array[GF_ERROR_CODE_NOTSOCK] = ENOTSOCK; + gf_errno_to_error_array[ENOTSOCK] = GF_ERROR_CODE_NOTSOCK; + + /* EDESTADDRREQ 39 / * Destination address required */ + gf_error_to_errno_array[GF_ERROR_CODE_DESTADDRREQ] = EDESTADDRREQ; + gf_errno_to_error_array[EDESTADDRREQ] = GF_ERROR_CODE_DESTADDRREQ; + + /* EMSGSIZE 40 / * Message too long */ + gf_error_to_errno_array[GF_ERROR_CODE_MSGSIZE] = EMSGSIZE; + gf_errno_to_error_array[EMSGSIZE] = GF_ERROR_CODE_MSGSIZE; + + /* EPROTOTYPE 41 / * Protocol wrong type for socket + */ + gf_error_to_errno_array[GF_ERROR_CODE_PROTOTYPE] = EPROTOTYPE; + gf_errno_to_error_array[EPROTOTYPE] = GF_ERROR_CODE_PROTOTYPE; + + /* ENOPROTOOPT 42 / * Protocol not available */ + gf_error_to_errno_array[GF_ERROR_CODE_NOPROTOOPT] = ENOPROTOOPT; + gf_errno_to_error_array[ENOPROTOOPT] = GF_ERROR_CODE_NOPROTOOPT; + + /* EPROTONOSUPPORT 43 / * Protocol not supported */ + gf_error_to_errno_array[GF_ERROR_CODE_PROTONOSUPPORT] = EPROTONOSUPPORT; + gf_errno_to_error_array[EPROTONOSUPPORT] = GF_ERROR_CODE_PROTONOSUPPORT; + + /* ESOCKTNOSUPPORT 44 / * Socket type not supported */ + gf_error_to_errno_array[GF_ERROR_CODE_SOCKTNOSUPPORT] = ESOCKTNOSUPPORT; + gf_errno_to_error_array[ESOCKTNOSUPPORT] = GF_ERROR_CODE_SOCKTNOSUPPORT; + + /* EOPNOTSUPP 45 / * Operation not supported */ + gf_error_to_errno_array[GF_ERROR_CODE_OPNOTSUPP] = EOPNOTSUPP; + gf_errno_to_error_array[EOPNOTSUPP] = GF_ERROR_CODE_OPNOTSUPP; + + /* EPFNOSUPPORT 46 / * Protocol family not supported */ + gf_error_to_errno_array[GF_ERROR_CODE_PFNOSUPPORT] = EPFNOSUPPORT; + gf_errno_to_error_array[EPFNOSUPPORT] = GF_ERROR_CODE_PFNOSUPPORT; + + /* EAFNOSUPPORT 47 / * Address family not supported by + * protocol family */ + gf_error_to_errno_array[GF_ERROR_CODE_AFNOSUPPORT] = EAFNOSUPPORT; + gf_errno_to_error_array[EAFNOSUPPORT] = GF_ERROR_CODE_AFNOSUPPORT; + + /* EADDRINUSE 48 / * Address already in use */ + gf_error_to_errno_array[GF_ERROR_CODE_ADDRINUSE] = EADDRINUSE; + gf_errno_to_error_array[EADDRINUSE] = GF_ERROR_CODE_ADDRINUSE; + + /* EADDRNOTAVAIL 49 / * Can't assign requested address + */ + gf_error_to_errno_array[GF_ERROR_CODE_ADDRNOTAVAIL] = EADDRNOTAVAIL; + gf_errno_to_error_array[EADDRNOTAVAIL] = GF_ERROR_CODE_ADDRNOTAVAIL; + + /* ENETDOWN 50 / * Network is down */ + gf_error_to_errno_array[GF_ERROR_CODE_NETDOWN] = ENETDOWN; + gf_errno_to_error_array[ENETDOWN] = GF_ERROR_CODE_NETDOWN; + + /* ENETUNREACH 51 / * Network is unreachable */ + gf_error_to_errno_array[GF_ERROR_CODE_NETUNREACH] = ENETUNREACH; + gf_errno_to_error_array[ENETUNREACH] = GF_ERROR_CODE_NETUNREACH; + + /* ENETRESET 52 / * Network dropped connection on + * reset */ + gf_error_to_errno_array[GF_ERROR_CODE_NETRESET] = ENETRESET; + gf_errno_to_error_array[ENETRESET] = GF_ERROR_CODE_NETRESET; + + /* ECONNABORTED 53 / * Software caused connection abort + */ + gf_error_to_errno_array[GF_ERROR_CODE_CONNABORTED] = ECONNABORTED; + gf_errno_to_error_array[ECONNABORTED] = GF_ERROR_CODE_CONNABORTED; + + /* ECONNRESET 54 / * Connection reset by peer */ + gf_error_to_errno_array[GF_ERROR_CODE_CONNRESET] = ECONNRESET; + gf_errno_to_error_array[ECONNRESET] = GF_ERROR_CODE_CONNRESET; + + /* ENOBUFS 55 / * No buffer space available */ + gf_error_to_errno_array[GF_ERROR_CODE_NOBUFS] = ENOBUFS; + gf_errno_to_error_array[ENOBUFS] = GF_ERROR_CODE_NOBUFS; + + /* EISCONN 56 / * Socket is already connected */ + gf_error_to_errno_array[GF_ERROR_CODE_ISCONN] = EISCONN; + gf_errno_to_error_array[EISCONN] = GF_ERROR_CODE_ISCONN; + + /* ENOTCONN 57 / * Socket is not connected */ + gf_error_to_errno_array[GF_ERROR_CODE_NOTCONN] = ENOTCONN; + gf_errno_to_error_array[ENOTCONN] = GF_ERROR_CODE_NOTCONN; + + /* ESHUTDOWN 58 / * Can't send after socket shutdown + */ + gf_error_to_errno_array[GF_ERROR_CODE_SHUTDOWN] = ESHUTDOWN; + gf_errno_to_error_array[ESHUTDOWN] = GF_ERROR_CODE_SHUTDOWN; + + /* ETOOMANYREFS 59 / * Too many references: can't + * splice */ + gf_error_to_errno_array[GF_ERROR_CODE_TOOMANYREFS] = ETOOMANYREFS; + gf_errno_to_error_array[ETOOMANYREFS] = GF_ERROR_CODE_TOOMANYREFS; + + /* ETIMEDOUT 60 / * Operation timed out */ + gf_error_to_errno_array[GF_ERROR_CODE_TIMEDOUT] = ETIMEDOUT; + gf_errno_to_error_array[ETIMEDOUT] = GF_ERROR_CODE_TIMEDOUT; + + /* ECONNREFUSED 61 / * Connection refused */ + gf_error_to_errno_array[GF_ERROR_CODE_CONNREFUSED] = ECONNREFUSED; + gf_errno_to_error_array[ECONNREFUSED] = GF_ERROR_CODE_CONNREFUSED; + + /* ELOOP 62 / * Too many levels of symbolic + * links */ + gf_error_to_errno_array[GF_ERROR_CODE_LOOP] = ELOOP; + gf_errno_to_error_array[ELOOP] = GF_ERROR_CODE_LOOP; + + /* ENAMETOOLONG 63 / * File name too long */ + gf_error_to_errno_array[GF_ERROR_CODE_NAMETOOLONG] = ENAMETOOLONG; + gf_errno_to_error_array[ENAMETOOLONG] = GF_ERROR_CODE_NAMETOOLONG; + + /* EHOSTDOWN 64 / * Host is down */ + gf_error_to_errno_array[GF_ERROR_CODE_HOSTDOWN] = EHOSTDOWN; + gf_errno_to_error_array[EHOSTDOWN] = GF_ERROR_CODE_HOSTDOWN; + + /* EHOSTUNREACH 65 / * No route to host */ + gf_error_to_errno_array[GF_ERROR_CODE_HOSTUNREACH] = EHOSTUNREACH; + gf_errno_to_error_array[EHOSTUNREACH] = GF_ERROR_CODE_HOSTUNREACH; + + /* ENOTEMPTY 66 / * Directory not empty */ + gf_error_to_errno_array[GF_ERROR_CODE_NOTEMPTY] = ENOTEMPTY; + gf_errno_to_error_array[ENOTEMPTY] = GF_ERROR_CODE_NOTEMPTY; + + /* EPROCLIM 67 / * Too many processes */ + gf_error_to_errno_array[GF_ERROR_CODE_PROCLIM] = EPROCLIM; + gf_errno_to_error_array[EPROCLIM] = GF_ERROR_CODE_PROCLIM; + + /* EUSERS 68 / * Too many users */ + gf_error_to_errno_array[GF_ERROR_CODE_USERS] = EUSERS; + gf_errno_to_error_array[EUSERS] = GF_ERROR_CODE_USERS; + + /* EDQUOT 69 / * Disc quota exceeded */ + gf_error_to_errno_array[GF_ERROR_CODE_DQUOT] = EDQUOT; + gf_errno_to_error_array[EDQUOT] = GF_ERROR_CODE_DQUOT; + + /* ESTALE 70 / * Stale NFS file handle */ + gf_error_to_errno_array[GF_ERROR_CODE_STALE] = ESTALE; + gf_errno_to_error_array[ESTALE] = GF_ERROR_CODE_STALE; + + /* EREMOTE 71 / * Too many levels of remote in + * path */ + gf_error_to_errno_array[GF_ERROR_CODE_REMOTE] = EREMOTE; + gf_errno_to_error_array[EREMOTE] = GF_ERROR_CODE_REMOTE; + + /* EBADRPC 72 / * RPC struct is bad */ + gf_error_to_errno_array[GF_ERROR_CODE_BADRPC] = EBADRPC; + gf_errno_to_error_array[EBADRPC] = GF_ERROR_CODE_BADRPC; + + /* ERPCMISMATCH 73 / * RPC version wrong */ + gf_error_to_errno_array[GF_ERROR_CODE_RPCMISMATCH] = ERPCMISMATCH; + gf_errno_to_error_array[ERPCMISMATCH] = GF_ERROR_CODE_RPCMISMATCH; + + /* EPROGUNAVAIL 74 / * RPC prog. not avail */ + gf_error_to_errno_array[GF_ERROR_CODE_PROGUNAVAIL] = EPROGUNAVAIL; + gf_errno_to_error_array[EPROGUNAVAIL] = GF_ERROR_CODE_PROGUNAVAIL; + + /* EPROGMISMATCH 75 / * Program version wrong */ + gf_error_to_errno_array[GF_ERROR_CODE_PROGMISMATCH] = EPROGMISMATCH; + gf_errno_to_error_array[EPROGMISMATCH] = GF_ERROR_CODE_PROGMISMATCH; + + /* EPROCUNAVAIL 76 / * Bad procedure for program */ + gf_error_to_errno_array[GF_ERROR_CODE_PROCUNAVAIL] = EPROCUNAVAIL; + gf_errno_to_error_array[EPROCUNAVAIL] = GF_ERROR_CODE_PROCUNAVAIL; + + /* ENOLCK 77 / * No locks available */ + gf_error_to_errno_array[GF_ERROR_CODE_NOLCK] = ENOLCK; + gf_errno_to_error_array[ENOLCK] = GF_ERROR_CODE_NOLCK; + + /* ENOSYS 78 / * Function not implemented */ + gf_error_to_errno_array[GF_ERROR_CODE_NOSYS] = ENOSYS; + gf_errno_to_error_array[ENOSYS] = GF_ERROR_CODE_NOSYS; + + /* EFTYPE 79 / * Inappropriate file type or + * format */ + gf_error_to_errno_array[GF_ERROR_CODE_FTYPE] = EFTYPE; + gf_errno_to_error_array[EFTYPE] = GF_ERROR_CODE_FTYPE; + + /* EAUTH 80 / * Authentication error */ + gf_error_to_errno_array[GF_ERROR_CODE_AUTH] = EAUTH; + gf_errno_to_error_array[EAUTH] = GF_ERROR_CODE_AUTH; + + /* ENEEDAUTH 81 / * Need authenticator */ + gf_error_to_errno_array[GF_ERROR_CODE_NEEDAUTH] = ENEEDAUTH; + gf_errno_to_error_array[ENEEDAUTH] = GF_ERROR_CODE_NEEDAUTH; + /* Intelligent device errors */ + /* EPWROFF 82 / * Device power is off */ + gf_error_to_errno_array[GF_ERROR_CODE_PWROFF] = EPWROFF; + gf_errno_to_error_array[EPWROFF] = GF_ERROR_CODE_PWROFF; + /* EDEVERR 83 / * Device error, e.g. paper out */ + gf_error_to_errno_array[GF_ERROR_CODE_DEVERR] = EDEVERR; + gf_errno_to_error_array[EDEVERR] = GF_ERROR_CODE_DEVERR; + + /* EOVERFLOW 84 / * Value too large to be stored in + * data type */ + gf_error_to_errno_array[GF_ERROR_CODE_OVERFLOW] = EOVERFLOW; + gf_errno_to_error_array[EOVERFLOW] = GF_ERROR_CODE_OVERFLOW; + + /* Program loading errors */ + /* EBADEXEC 85 / * Bad executable */ + gf_error_to_errno_array[GF_ERROR_CODE_BADEXEC] = EBADEXEC; + gf_errno_to_error_array[EBADEXEC] = GF_ERROR_CODE_BADEXEC; + + /* EBADARCH 86 / * Bad CPU type in executable */ + gf_error_to_errno_array[GF_ERROR_CODE_BADARCH] = EBADARCH; + gf_errno_to_error_array[EBADARCH] = GF_ERROR_CODE_BADARCH; + + /* ESHLIBVERS 87 / * Shared library version mismatch */ + gf_error_to_errno_array[GF_ERROR_CODE_SHLIBVERS] = ESHLIBVERS; + gf_errno_to_error_array[ESHLIBVERS] = GF_ERROR_CODE_SHLIBVERS; + + /* EBADMACHO 88 / * Malformed Macho file */ + gf_error_to_errno_array[GF_ERROR_CODE_BADMACHO] = EBADMACHO; + gf_errno_to_error_array[EBADMACHO] = GF_ERROR_CODE_BADMACHO; + +#ifdef EDOOFUS + /* EDOOFUS 88 / * Programming error */ + gf_error_to_errno_array[GF_ERROR_CODE_DOOFUS] = EDOOFUS; + gf_errno_to_error_array[EDOOFUS] = GF_ERROR_CODE_DOOFUS; #endif - /* ECANCELED 89 / * Operation canceled */ - gf_error_to_errno_array[GF_ERROR_CODE_CANCELED] = ECANCELED; - gf_errno_to_error_array[ECANCELED] = GF_ERROR_CODE_CANCELED; - - /* EIDRM 90 / * Identifier removed */ - gf_error_to_errno_array[GF_ERROR_CODE_IDRM] = EIDRM; - gf_errno_to_error_array[EIDRM] = GF_ERROR_CODE_IDRM; - /* ENOMSG 91 / * No message of desired type */ - gf_error_to_errno_array[GF_ERROR_CODE_NOMSG] = ENOMSG; - gf_errno_to_error_array[ENOMSG] = GF_ERROR_CODE_NOMSG; - - /* EILSEQ 92 / * Illegal byte sequence */ - gf_error_to_errno_array[GF_ERROR_CODE_ILSEQ] = EILSEQ; - gf_errno_to_error_array[EILSEQ] = GF_ERROR_CODE_ILSEQ; - - /* ENOATTR 93 / * Attribute not found */ - gf_error_to_errno_array[GF_ERROR_CODE_NOATTR] = ENOATTR; - gf_errno_to_error_array[ENOATTR] = GF_ERROR_CODE_NOATTR; - - /* EBADMSG 94 / * Bad message */ - gf_error_to_errno_array[GF_ERROR_CODE_BADMSG] = EBADMSG; - gf_errno_to_error_array[EBADMSG] = GF_ERROR_CODE_BADMSG; - - /* EMULTIHOP 95 / * Reserved */ - gf_error_to_errno_array[GF_ERROR_CODE_MULTIHOP] = EMULTIHOP; - gf_errno_to_error_array[EMULTIHOP] = GF_ERROR_CODE_MULTIHOP; - - /* ENODATA 96 / * No message available on STREAM */ - gf_error_to_errno_array[GF_ERROR_CODE_NEEDAUTH] = ENEEDAUTH; - gf_errno_to_error_array[ENEEDAUTH] = GF_ERROR_CODE_NEEDAUTH; - - /* ENOLINK 97 / * Reserved */ - gf_error_to_errno_array[GF_ERROR_CODE_NOLINK] = ENOLINK; - gf_errno_to_error_array[ENOLINK] = GF_ERROR_CODE_NOLINK; - - /* ENOSR 98 / * No STREAM resources */ - gf_error_to_errno_array[GF_ERROR_CODE_NOSR] = ENOSR; - gf_errno_to_error_array[ENOSR] = GF_ERROR_CODE_NOSR; - - /* ENOSTR 99 / * Not a STREAM */ - gf_error_to_errno_array[GF_ERROR_CODE_NOSTR] = ENOSTR; - gf_errno_to_error_array[ENOSTR] = GF_ERROR_CODE_NOSTR; - -/* EPROTO 100 / * Protocol error */ - gf_error_to_errno_array[GF_ERROR_CODE_PROTO] = EPROTO; - gf_errno_to_error_array[EPROTO] = GF_ERROR_CODE_PROTO; -/* ETIME 101 / * STREAM ioctl timeout */ - gf_error_to_errno_array[GF_ERROR_CODE_TIME] = ETIME; - gf_errno_to_error_array[ETIME] = GF_ERROR_CODE_TIME; - -/* This value is only discrete when compiling __DARWIN_UNIX03, or KERNEL */ -/* EOPNOTSUPP 102 / * Operation not supported on socket */ - gf_error_to_errno_array[GF_ERROR_CODE_OPNOTSUPP] = EOPNOTSUPP; - gf_errno_to_error_array[EOPNOTSUPP] = GF_ERROR_CODE_OPNOTSUPP; - -/* ENOPOLICY 103 / * No such policy registered */ - gf_error_to_errno_array[GF_ERROR_CODE_NOPOLICY] = ENOPOLICY; - gf_errno_to_error_array[ENOPOLICY] = GF_ERROR_CODE_NOPOLICY; - - return ; + /* ECANCELED 89 / * Operation canceled */ + gf_error_to_errno_array[GF_ERROR_CODE_CANCELED] = ECANCELED; + gf_errno_to_error_array[ECANCELED] = GF_ERROR_CODE_CANCELED; + + /* EIDRM 90 / * Identifier removed */ + gf_error_to_errno_array[GF_ERROR_CODE_IDRM] = EIDRM; + gf_errno_to_error_array[EIDRM] = GF_ERROR_CODE_IDRM; + /* ENOMSG 91 / * No message of desired type */ + gf_error_to_errno_array[GF_ERROR_CODE_NOMSG] = ENOMSG; + gf_errno_to_error_array[ENOMSG] = GF_ERROR_CODE_NOMSG; + + /* EILSEQ 92 / * Illegal byte sequence */ + gf_error_to_errno_array[GF_ERROR_CODE_ILSEQ] = EILSEQ; + gf_errno_to_error_array[EILSEQ] = GF_ERROR_CODE_ILSEQ; + + /* ENOATTR 93 / * Attribute not found */ + gf_error_to_errno_array[GF_ERROR_CODE_NOATTR] = ENOATTR; + gf_errno_to_error_array[ENOATTR] = GF_ERROR_CODE_NOATTR; + + /* EBADMSG 94 / * Bad message */ + gf_error_to_errno_array[GF_ERROR_CODE_BADMSG] = EBADMSG; + gf_errno_to_error_array[EBADMSG] = GF_ERROR_CODE_BADMSG; + + /* EMULTIHOP 95 / * Reserved */ + gf_error_to_errno_array[GF_ERROR_CODE_MULTIHOP] = EMULTIHOP; + gf_errno_to_error_array[EMULTIHOP] = GF_ERROR_CODE_MULTIHOP; + + /* ENODATA 96 / * No message available on STREAM + */ + gf_error_to_errno_array[GF_ERROR_CODE_NEEDAUTH] = ENEEDAUTH; + gf_errno_to_error_array[ENEEDAUTH] = GF_ERROR_CODE_NEEDAUTH; + + /* ENOLINK 97 / * Reserved */ + gf_error_to_errno_array[GF_ERROR_CODE_NOLINK] = ENOLINK; + gf_errno_to_error_array[ENOLINK] = GF_ERROR_CODE_NOLINK; + + /* ENOSR 98 / * No STREAM resources */ + gf_error_to_errno_array[GF_ERROR_CODE_NOSR] = ENOSR; + gf_errno_to_error_array[ENOSR] = GF_ERROR_CODE_NOSR; + + /* ENOSTR 99 / * Not a STREAM */ + gf_error_to_errno_array[GF_ERROR_CODE_NOSTR] = ENOSTR; + gf_errno_to_error_array[ENOSTR] = GF_ERROR_CODE_NOSTR; + + /* EPROTO 100 / * Protocol error */ + gf_error_to_errno_array[GF_ERROR_CODE_PROTO] = EPROTO; + gf_errno_to_error_array[EPROTO] = GF_ERROR_CODE_PROTO; + /* ETIME 101 / * STREAM ioctl timeout */ + gf_error_to_errno_array[GF_ERROR_CODE_TIME] = ETIME; + gf_errno_to_error_array[ETIME] = GF_ERROR_CODE_TIME; + + /* This value is only discrete when compiling __DARWIN_UNIX03, or KERNEL */ + /* EOPNOTSUPP 102 / * Operation not supported on + * socket */ + gf_error_to_errno_array[GF_ERROR_CODE_OPNOTSUPP] = EOPNOTSUPP; + gf_errno_to_error_array[EOPNOTSUPP] = GF_ERROR_CODE_OPNOTSUPP; + + /* ENOPOLICY 103 / * No such policy registered */ + gf_error_to_errno_array[GF_ERROR_CODE_NOPOLICY] = ENOPOLICY; + gf_errno_to_error_array[ENOPOLICY] = GF_ERROR_CODE_NOPOLICY; + + return; } #endif /* GF_DARWIN_HOST_OS */ #ifdef GF_BSD_HOST_OS -static void -init_compat_errno_arrays () +static void +init_compat_errno_arrays() { - /* Quite a bit of things changed in FreeBSD - current */ - - /* EAGAIN 35 / * Try Again */ - gf_error_to_errno_array[GF_ERROR_CODE_AGAIN] = EAGAIN; - gf_errno_to_error_array[EAGAIN] = GF_ERROR_CODE_AGAIN; - - /* EDEADLK 11 / * Resource deadlock would occur */ - gf_error_to_errno_array[GF_ERROR_CODE_DEADLK] = EDEADLK; - gf_errno_to_error_array[EDEADLK] = GF_ERROR_CODE_DEADLK; - - /* EINPROGRESS 36 / * Operation now in progress */ - gf_error_to_errno_array[GF_ERROR_CODE_INPROGRESS] = EINPROGRESS; - gf_errno_to_error_array[EINPROGRESS] = GF_ERROR_CODE_INPROGRESS; - - /* EALREADY 37 / * Operation already in progress */ - gf_error_to_errno_array[GF_ERROR_CODE_ALREADY] = EALREADY; - gf_errno_to_error_array[EALREADY] = GF_ERROR_CODE_ALREADY; - - /* ENOTSOCK 38 / * Socket operation on non-socket */ - gf_error_to_errno_array[GF_ERROR_CODE_NOTSOCK] = ENOTSOCK; - gf_errno_to_error_array[ENOTSOCK] = GF_ERROR_CODE_NOTSOCK; - - /* EDESTADDRREQ 39 / * Destination address required */ - gf_error_to_errno_array[GF_ERROR_CODE_DESTADDRREQ] = EDESTADDRREQ; - gf_errno_to_error_array[EDESTADDRREQ] = GF_ERROR_CODE_DESTADDRREQ; - - /* EMSGSIZE 40 / * Message too long */ - gf_error_to_errno_array[GF_ERROR_CODE_MSGSIZE] = EMSGSIZE; - gf_errno_to_error_array[EMSGSIZE] = GF_ERROR_CODE_MSGSIZE; - - /* EPROTOTYPE 41 / * Protocol wrong type for socket */ - gf_error_to_errno_array[GF_ERROR_CODE_PROTOTYPE] = EPROTOTYPE; - gf_errno_to_error_array[EPROTOTYPE] = GF_ERROR_CODE_PROTOTYPE; - - /* ENOPROTOOPT 42 / * Protocol not available */ - gf_error_to_errno_array[GF_ERROR_CODE_NOPROTOOPT] = ENOPROTOOPT; - gf_errno_to_error_array[ENOPROTOOPT] = GF_ERROR_CODE_NOPROTOOPT; - - /* EPROTONOSUPPORT 43 / * Protocol not supported */ - gf_error_to_errno_array[GF_ERROR_CODE_PROTONOSUPPORT] = EPROTONOSUPPORT; - gf_errno_to_error_array[EPROTONOSUPPORT] = GF_ERROR_CODE_PROTONOSUPPORT; - - /* ESOCKTNOSUPPORT 44 / * Socket type not supported */ - gf_error_to_errno_array[GF_ERROR_CODE_SOCKTNOSUPPORT] = ESOCKTNOSUPPORT; - gf_errno_to_error_array[ESOCKTNOSUPPORT] = GF_ERROR_CODE_SOCKTNOSUPPORT; - - /* EOPNOTSUPP 45 / * Operation not supported */ - gf_error_to_errno_array[GF_ERROR_CODE_OPNOTSUPP] = EOPNOTSUPP; - gf_errno_to_error_array[EOPNOTSUPP] = GF_ERROR_CODE_OPNOTSUPP; - - /* EPFNOSUPPORT 46 / * Protocol family not supported */ - gf_error_to_errno_array[GF_ERROR_CODE_PFNOSUPPORT] = EPFNOSUPPORT; - gf_errno_to_error_array[EPFNOSUPPORT] = GF_ERROR_CODE_PFNOSUPPORT; - - /* EAFNOSUPPORT 47 / * Address family not supported by protocol family */ - gf_error_to_errno_array[GF_ERROR_CODE_AFNOSUPPORT] = EAFNOSUPPORT; - gf_errno_to_error_array[EAFNOSUPPORT] = GF_ERROR_CODE_AFNOSUPPORT; - - /* EADDRINUSE 48 / * Address already in use */ - gf_error_to_errno_array[GF_ERROR_CODE_ADDRINUSE] = EADDRINUSE; - gf_errno_to_error_array[EADDRINUSE] = GF_ERROR_CODE_ADDRINUSE; - - /* EADDRNOTAVAIL 49 / * Can't assign requested address */ - gf_error_to_errno_array[GF_ERROR_CODE_ADDRNOTAVAIL] = EADDRNOTAVAIL; - gf_errno_to_error_array[EADDRNOTAVAIL] = GF_ERROR_CODE_ADDRNOTAVAIL; - - /* ENETDOWN 50 / * Network is down */ - gf_error_to_errno_array[GF_ERROR_CODE_NETDOWN] = ENETDOWN; - gf_errno_to_error_array[ENETDOWN] = GF_ERROR_CODE_NETDOWN; - - /* ENETUNREACH 51 / * Network is unreachable */ - gf_error_to_errno_array[GF_ERROR_CODE_NETUNREACH] = ENETUNREACH; - gf_errno_to_error_array[ENETUNREACH] = GF_ERROR_CODE_NETUNREACH; - - /* ENETRESET 52 / * Network dropped connection on reset */ - gf_error_to_errno_array[GF_ERROR_CODE_NETRESET] = ENETRESET; - gf_errno_to_error_array[ENETRESET] = GF_ERROR_CODE_NETRESET; - - /* ECONNABORTED 53 / * Software caused connection abort */ - gf_error_to_errno_array[GF_ERROR_CODE_CONNABORTED] = ECONNABORTED; - gf_errno_to_error_array[ECONNABORTED] = GF_ERROR_CODE_CONNABORTED; - - /* ECONNRESET 54 / * Connection reset by peer */ - gf_error_to_errno_array[GF_ERROR_CODE_CONNRESET] = ECONNRESET; - gf_errno_to_error_array[ECONNRESET] = GF_ERROR_CODE_CONNRESET; - - /* ENOBUFS 55 / * No buffer space available */ - gf_error_to_errno_array[GF_ERROR_CODE_NOBUFS] = ENOBUFS; - gf_errno_to_error_array[ENOBUFS] = GF_ERROR_CODE_NOBUFS; - - /* EISCONN 56 / * Socket is already connected */ - gf_error_to_errno_array[GF_ERROR_CODE_ISCONN] = EISCONN; - gf_errno_to_error_array[EISCONN] = GF_ERROR_CODE_ISCONN; - - /* ENOTCONN 57 / * Socket is not connected */ - gf_error_to_errno_array[GF_ERROR_CODE_NOTCONN] = ENOTCONN; - gf_errno_to_error_array[ENOTCONN] = GF_ERROR_CODE_NOTCONN; - - /* ESHUTDOWN 58 / * Can't send after socket shutdown */ - gf_error_to_errno_array[GF_ERROR_CODE_SHUTDOWN] = ESHUTDOWN; - gf_errno_to_error_array[ESHUTDOWN] = GF_ERROR_CODE_SHUTDOWN; - - /* ETOOMANYREFS 59 / * Too many references: can't splice */ - gf_error_to_errno_array[GF_ERROR_CODE_TOOMANYREFS] = ETOOMANYREFS; - gf_errno_to_error_array[ETOOMANYREFS] = GF_ERROR_CODE_TOOMANYREFS; - - /* ETIMEDOUT 60 / * Operation timed out */ - gf_error_to_errno_array[GF_ERROR_CODE_TIMEDOUT] = ETIMEDOUT; - gf_errno_to_error_array[ETIMEDOUT] = GF_ERROR_CODE_TIMEDOUT; - - /* ECONNREFUSED 61 / * Connection refused */ - gf_error_to_errno_array[GF_ERROR_CODE_CONNREFUSED] = ECONNREFUSED; - gf_errno_to_error_array[ECONNREFUSED] = GF_ERROR_CODE_CONNREFUSED; - - /* ELOOP 62 / * Too many levels of symbolic links */ - gf_error_to_errno_array[GF_ERROR_CODE_LOOP] = ELOOP; - gf_errno_to_error_array[ELOOP] = GF_ERROR_CODE_LOOP; - - /* ENAMETOOLONG 63 / * File name too long */ - gf_error_to_errno_array[GF_ERROR_CODE_NAMETOOLONG] = ENAMETOOLONG; - gf_errno_to_error_array[ENAMETOOLONG] = GF_ERROR_CODE_NAMETOOLONG; - - /* EHOSTDOWN 64 / * Host is down */ - gf_error_to_errno_array[GF_ERROR_CODE_HOSTDOWN] = EHOSTDOWN; - gf_errno_to_error_array[EHOSTDOWN] = GF_ERROR_CODE_HOSTDOWN; - - /* EHOSTUNREACH 65 / * No route to host */ - gf_error_to_errno_array[GF_ERROR_CODE_HOSTUNREACH] = EHOSTUNREACH; - gf_errno_to_error_array[EHOSTUNREACH] = GF_ERROR_CODE_HOSTUNREACH; - - /* ENOTEMPTY 66 / * Directory not empty */ - gf_error_to_errno_array[GF_ERROR_CODE_NOTEMPTY] = ENOTEMPTY; - gf_errno_to_error_array[ENOTEMPTY] = GF_ERROR_CODE_NOTEMPTY; - - /* EPROCLIM 67 / * Too many processes */ - gf_error_to_errno_array[GF_ERROR_CODE_PROCLIM] = EPROCLIM; - gf_errno_to_error_array[EPROCLIM] = GF_ERROR_CODE_PROCLIM; - - /* EUSERS 68 / * Too many users */ - gf_error_to_errno_array[GF_ERROR_CODE_USERS] = EUSERS; - gf_errno_to_error_array[EUSERS] = GF_ERROR_CODE_USERS; - - /* EDQUOT 69 / * Disc quota exceeded */ - gf_error_to_errno_array[GF_ERROR_CODE_DQUOT] = EDQUOT; - gf_errno_to_error_array[EDQUOT] = GF_ERROR_CODE_DQUOT; - - /* ESTALE 70 / * Stale NFS file handle */ - gf_error_to_errno_array[GF_ERROR_CODE_STALE] = ESTALE; - gf_errno_to_error_array[ESTALE] = GF_ERROR_CODE_STALE; - - /* EREMOTE 71 / * Too many levels of remote in path */ - gf_error_to_errno_array[GF_ERROR_CODE_REMOTE] = EREMOTE; - gf_errno_to_error_array[EREMOTE] = GF_ERROR_CODE_REMOTE; - - /* EBADRPC 72 / * RPC struct is bad */ - gf_error_to_errno_array[GF_ERROR_CODE_BADRPC] = EBADRPC; - gf_errno_to_error_array[EBADRPC] = GF_ERROR_CODE_BADRPC; - - /* ERPCMISMATCH 73 / * RPC version wrong */ - gf_error_to_errno_array[GF_ERROR_CODE_RPCMISMATCH] = ERPCMISMATCH; - gf_errno_to_error_array[ERPCMISMATCH] = GF_ERROR_CODE_RPCMISMATCH; - - /* EPROGUNAVAIL 74 / * RPC prog. not avail */ - gf_error_to_errno_array[GF_ERROR_CODE_PROGUNAVAIL] = EPROGUNAVAIL; - gf_errno_to_error_array[EPROGUNAVAIL] = GF_ERROR_CODE_PROGUNAVAIL; - - /* EPROGMISMATCH 75 / * Program version wrong */ - gf_error_to_errno_array[GF_ERROR_CODE_PROGMISMATCH] = EPROGMISMATCH; - gf_errno_to_error_array[EPROGMISMATCH] = GF_ERROR_CODE_PROGMISMATCH; - - /* EPROCUNAVAIL 76 / * Bad procedure for program */ - gf_error_to_errno_array[GF_ERROR_CODE_PROCUNAVAIL] = EPROCUNAVAIL; - gf_errno_to_error_array[EPROCUNAVAIL] = GF_ERROR_CODE_PROCUNAVAIL; - - /* ENOLCK 77 / * No locks available */ - gf_error_to_errno_array[GF_ERROR_CODE_NOLCK] = ENOLCK; - gf_errno_to_error_array[ENOLCK] = GF_ERROR_CODE_NOLCK; - - /* ENOSYS 78 / * Function not implemented */ - gf_error_to_errno_array[GF_ERROR_CODE_NOSYS] = ENOSYS; - gf_errno_to_error_array[ENOSYS] = GF_ERROR_CODE_NOSYS; - - /* EFTYPE 79 / * Inappropriate file type or format */ - gf_error_to_errno_array[GF_ERROR_CODE_FTYPE] = EFTYPE; - gf_errno_to_error_array[EFTYPE] = GF_ERROR_CODE_FTYPE; - - /* EAUTH 80 / * Authentication error */ - gf_error_to_errno_array[GF_ERROR_CODE_AUTH] = EAUTH; - gf_errno_to_error_array[EAUTH] = GF_ERROR_CODE_AUTH; - - /* ENEEDAUTH 81 / * Need authenticator */ - gf_error_to_errno_array[GF_ERROR_CODE_NEEDAUTH] = ENEEDAUTH; - gf_errno_to_error_array[ENEEDAUTH] = GF_ERROR_CODE_NEEDAUTH; - - /* EIDRM 82 / * Identifier removed */ - gf_error_to_errno_array[GF_ERROR_CODE_IDRM] = EIDRM; - gf_errno_to_error_array[EIDRM] = GF_ERROR_CODE_IDRM; - - /* ENOMSG 83 / * No message of desired type */ - gf_error_to_errno_array[GF_ERROR_CODE_NOMSG] = ENOMSG; - gf_errno_to_error_array[ENOMSG] = GF_ERROR_CODE_NOMSG; - - /* EOVERFLOW 84 / * Value too large to be stored in data type */ - gf_error_to_errno_array[GF_ERROR_CODE_OVERFLOW] = EOVERFLOW; - gf_errno_to_error_array[EOVERFLOW] = GF_ERROR_CODE_OVERFLOW; - - /* ECANCELED 85 / * Operation canceled */ - gf_error_to_errno_array[GF_ERROR_CODE_CANCELED] = ECANCELED; - gf_errno_to_error_array[ECANCELED] = GF_ERROR_CODE_CANCELED; - - /* EILSEQ 86 / * Illegal byte sequence */ - gf_error_to_errno_array[GF_ERROR_CODE_ILSEQ] = EILSEQ; - gf_errno_to_error_array[EILSEQ] = GF_ERROR_CODE_ILSEQ; - - /* ENOATTR 87 / * Attribute not found */ - gf_error_to_errno_array[GF_ERROR_CODE_NOATTR] = ENOATTR; - gf_errno_to_error_array[ENOATTR] = GF_ERROR_CODE_NOATTR; - - /* EDOOFUS 88 / * Programming error */ - gf_error_to_errno_array[GF_ERROR_CODE_DOOFUS] = EDOOFUS; - gf_errno_to_error_array[EDOOFUS] = GF_ERROR_CODE_DOOFUS; + /* Quite a bit of things changed in FreeBSD - current */ + + /* EAGAIN 35 / * Try Again */ + gf_error_to_errno_array[GF_ERROR_CODE_AGAIN] = EAGAIN; + gf_errno_to_error_array[EAGAIN] = GF_ERROR_CODE_AGAIN; + + /* EDEADLK 11 / * Resource deadlock would occur */ + gf_error_to_errno_array[GF_ERROR_CODE_DEADLK] = EDEADLK; + gf_errno_to_error_array[EDEADLK] = GF_ERROR_CODE_DEADLK; + + /* EINPROGRESS 36 / * Operation now in progress */ + gf_error_to_errno_array[GF_ERROR_CODE_INPROGRESS] = EINPROGRESS; + gf_errno_to_error_array[EINPROGRESS] = GF_ERROR_CODE_INPROGRESS; + + /* EALREADY 37 / * Operation already in progress */ + gf_error_to_errno_array[GF_ERROR_CODE_ALREADY] = EALREADY; + gf_errno_to_error_array[EALREADY] = GF_ERROR_CODE_ALREADY; + + /* ENOTSOCK 38 / * Socket operation on non-socket + */ + gf_error_to_errno_array[GF_ERROR_CODE_NOTSOCK] = ENOTSOCK; + gf_errno_to_error_array[ENOTSOCK] = GF_ERROR_CODE_NOTSOCK; + + /* EDESTADDRREQ 39 / * Destination address required */ + gf_error_to_errno_array[GF_ERROR_CODE_DESTADDRREQ] = EDESTADDRREQ; + gf_errno_to_error_array[EDESTADDRREQ] = GF_ERROR_CODE_DESTADDRREQ; + + /* EMSGSIZE 40 / * Message too long */ + gf_error_to_errno_array[GF_ERROR_CODE_MSGSIZE] = EMSGSIZE; + gf_errno_to_error_array[EMSGSIZE] = GF_ERROR_CODE_MSGSIZE; + + /* EPROTOTYPE 41 / * Protocol wrong type for socket + */ + gf_error_to_errno_array[GF_ERROR_CODE_PROTOTYPE] = EPROTOTYPE; + gf_errno_to_error_array[EPROTOTYPE] = GF_ERROR_CODE_PROTOTYPE; + + /* ENOPROTOOPT 42 / * Protocol not available */ + gf_error_to_errno_array[GF_ERROR_CODE_NOPROTOOPT] = ENOPROTOOPT; + gf_errno_to_error_array[ENOPROTOOPT] = GF_ERROR_CODE_NOPROTOOPT; + + /* EPROTONOSUPPORT 43 / * Protocol not supported */ + gf_error_to_errno_array[GF_ERROR_CODE_PROTONOSUPPORT] = EPROTONOSUPPORT; + gf_errno_to_error_array[EPROTONOSUPPORT] = GF_ERROR_CODE_PROTONOSUPPORT; + + /* ESOCKTNOSUPPORT 44 / * Socket type not supported */ + gf_error_to_errno_array[GF_ERROR_CODE_SOCKTNOSUPPORT] = ESOCKTNOSUPPORT; + gf_errno_to_error_array[ESOCKTNOSUPPORT] = GF_ERROR_CODE_SOCKTNOSUPPORT; + + /* EOPNOTSUPP 45 / * Operation not supported */ + gf_error_to_errno_array[GF_ERROR_CODE_OPNOTSUPP] = EOPNOTSUPP; + gf_errno_to_error_array[EOPNOTSUPP] = GF_ERROR_CODE_OPNOTSUPP; + + /* EPFNOSUPPORT 46 / * Protocol family not supported */ + gf_error_to_errno_array[GF_ERROR_CODE_PFNOSUPPORT] = EPFNOSUPPORT; + gf_errno_to_error_array[EPFNOSUPPORT] = GF_ERROR_CODE_PFNOSUPPORT; + + /* EAFNOSUPPORT 47 / * Address family not supported by + * protocol family */ + gf_error_to_errno_array[GF_ERROR_CODE_AFNOSUPPORT] = EAFNOSUPPORT; + gf_errno_to_error_array[EAFNOSUPPORT] = GF_ERROR_CODE_AFNOSUPPORT; + + /* EADDRINUSE 48 / * Address already in use */ + gf_error_to_errno_array[GF_ERROR_CODE_ADDRINUSE] = EADDRINUSE; + gf_errno_to_error_array[EADDRINUSE] = GF_ERROR_CODE_ADDRINUSE; + + /* EADDRNOTAVAIL 49 / * Can't assign requested address + */ + gf_error_to_errno_array[GF_ERROR_CODE_ADDRNOTAVAIL] = EADDRNOTAVAIL; + gf_errno_to_error_array[EADDRNOTAVAIL] = GF_ERROR_CODE_ADDRNOTAVAIL; + + /* ENETDOWN 50 / * Network is down */ + gf_error_to_errno_array[GF_ERROR_CODE_NETDOWN] = ENETDOWN; + gf_errno_to_error_array[ENETDOWN] = GF_ERROR_CODE_NETDOWN; + + /* ENETUNREACH 51 / * Network is unreachable */ + gf_error_to_errno_array[GF_ERROR_CODE_NETUNREACH] = ENETUNREACH; + gf_errno_to_error_array[ENETUNREACH] = GF_ERROR_CODE_NETUNREACH; + + /* ENETRESET 52 / * Network dropped connection on + * reset */ + gf_error_to_errno_array[GF_ERROR_CODE_NETRESET] = ENETRESET; + gf_errno_to_error_array[ENETRESET] = GF_ERROR_CODE_NETRESET; + + /* ECONNABORTED 53 / * Software caused connection abort + */ + gf_error_to_errno_array[GF_ERROR_CODE_CONNABORTED] = ECONNABORTED; + gf_errno_to_error_array[ECONNABORTED] = GF_ERROR_CODE_CONNABORTED; + + /* ECONNRESET 54 / * Connection reset by peer */ + gf_error_to_errno_array[GF_ERROR_CODE_CONNRESET] = ECONNRESET; + gf_errno_to_error_array[ECONNRESET] = GF_ERROR_CODE_CONNRESET; + + /* ENOBUFS 55 / * No buffer space available */ + gf_error_to_errno_array[GF_ERROR_CODE_NOBUFS] = ENOBUFS; + gf_errno_to_error_array[ENOBUFS] = GF_ERROR_CODE_NOBUFS; + + /* EISCONN 56 / * Socket is already connected */ + gf_error_to_errno_array[GF_ERROR_CODE_ISCONN] = EISCONN; + gf_errno_to_error_array[EISCONN] = GF_ERROR_CODE_ISCONN; + + /* ENOTCONN 57 / * Socket is not connected */ + gf_error_to_errno_array[GF_ERROR_CODE_NOTCONN] = ENOTCONN; + gf_errno_to_error_array[ENOTCONN] = GF_ERROR_CODE_NOTCONN; + + /* ESHUTDOWN 58 / * Can't send after socket shutdown + */ + gf_error_to_errno_array[GF_ERROR_CODE_SHUTDOWN] = ESHUTDOWN; + gf_errno_to_error_array[ESHUTDOWN] = GF_ERROR_CODE_SHUTDOWN; + + /* ETOOMANYREFS 59 / * Too many references: can't + * splice */ + gf_error_to_errno_array[GF_ERROR_CODE_TOOMANYREFS] = ETOOMANYREFS; + gf_errno_to_error_array[ETOOMANYREFS] = GF_ERROR_CODE_TOOMANYREFS; + + /* ETIMEDOUT 60 / * Operation timed out */ + gf_error_to_errno_array[GF_ERROR_CODE_TIMEDOUT] = ETIMEDOUT; + gf_errno_to_error_array[ETIMEDOUT] = GF_ERROR_CODE_TIMEDOUT; + + /* ECONNREFUSED 61 / * Connection refused */ + gf_error_to_errno_array[GF_ERROR_CODE_CONNREFUSED] = ECONNREFUSED; + gf_errno_to_error_array[ECONNREFUSED] = GF_ERROR_CODE_CONNREFUSED; + + /* ELOOP 62 / * Too many levels of symbolic + * links */ + gf_error_to_errno_array[GF_ERROR_CODE_LOOP] = ELOOP; + gf_errno_to_error_array[ELOOP] = GF_ERROR_CODE_LOOP; + + /* ENAMETOOLONG 63 / * File name too long */ + gf_error_to_errno_array[GF_ERROR_CODE_NAMETOOLONG] = ENAMETOOLONG; + gf_errno_to_error_array[ENAMETOOLONG] = GF_ERROR_CODE_NAMETOOLONG; + + /* EHOSTDOWN 64 / * Host is down */ + gf_error_to_errno_array[GF_ERROR_CODE_HOSTDOWN] = EHOSTDOWN; + gf_errno_to_error_array[EHOSTDOWN] = GF_ERROR_CODE_HOSTDOWN; + + /* EHOSTUNREACH 65 / * No route to host */ + gf_error_to_errno_array[GF_ERROR_CODE_HOSTUNREACH] = EHOSTUNREACH; + gf_errno_to_error_array[EHOSTUNREACH] = GF_ERROR_CODE_HOSTUNREACH; + + /* ENOTEMPTY 66 / * Directory not empty */ + gf_error_to_errno_array[GF_ERROR_CODE_NOTEMPTY] = ENOTEMPTY; + gf_errno_to_error_array[ENOTEMPTY] = GF_ERROR_CODE_NOTEMPTY; + + /* EPROCLIM 67 / * Too many processes */ + gf_error_to_errno_array[GF_ERROR_CODE_PROCLIM] = EPROCLIM; + gf_errno_to_error_array[EPROCLIM] = GF_ERROR_CODE_PROCLIM; + + /* EUSERS 68 / * Too many users */ + gf_error_to_errno_array[GF_ERROR_CODE_USERS] = EUSERS; + gf_errno_to_error_array[EUSERS] = GF_ERROR_CODE_USERS; + + /* EDQUOT 69 / * Disc quota exceeded */ + gf_error_to_errno_array[GF_ERROR_CODE_DQUOT] = EDQUOT; + gf_errno_to_error_array[EDQUOT] = GF_ERROR_CODE_DQUOT; + + /* ESTALE 70 / * Stale NFS file handle */ + gf_error_to_errno_array[GF_ERROR_CODE_STALE] = ESTALE; + gf_errno_to_error_array[ESTALE] = GF_ERROR_CODE_STALE; + + /* EREMOTE 71 / * Too many levels of remote in + * path */ + gf_error_to_errno_array[GF_ERROR_CODE_REMOTE] = EREMOTE; + gf_errno_to_error_array[EREMOTE] = GF_ERROR_CODE_REMOTE; + + /* EBADRPC 72 / * RPC struct is bad */ + gf_error_to_errno_array[GF_ERROR_CODE_BADRPC] = EBADRPC; + gf_errno_to_error_array[EBADRPC] = GF_ERROR_CODE_BADRPC; + + /* ERPCMISMATCH 73 / * RPC version wrong */ + gf_error_to_errno_array[GF_ERROR_CODE_RPCMISMATCH] = ERPCMISMATCH; + gf_errno_to_error_array[ERPCMISMATCH] = GF_ERROR_CODE_RPCMISMATCH; + + /* EPROGUNAVAIL 74 / * RPC prog. not avail */ + gf_error_to_errno_array[GF_ERROR_CODE_PROGUNAVAIL] = EPROGUNAVAIL; + gf_errno_to_error_array[EPROGUNAVAIL] = GF_ERROR_CODE_PROGUNAVAIL; + + /* EPROGMISMATCH 75 / * Program version wrong */ + gf_error_to_errno_array[GF_ERROR_CODE_PROGMISMATCH] = EPROGMISMATCH; + gf_errno_to_error_array[EPROGMISMATCH] = GF_ERROR_CODE_PROGMISMATCH; + + /* EPROCUNAVAIL 76 / * Bad procedure for program */ + gf_error_to_errno_array[GF_ERROR_CODE_PROCUNAVAIL] = EPROCUNAVAIL; + gf_errno_to_error_array[EPROCUNAVAIL] = GF_ERROR_CODE_PROCUNAVAIL; + + /* ENOLCK 77 / * No locks available */ + gf_error_to_errno_array[GF_ERROR_CODE_NOLCK] = ENOLCK; + gf_errno_to_error_array[ENOLCK] = GF_ERROR_CODE_NOLCK; + + /* ENOSYS 78 / * Function not implemented */ + gf_error_to_errno_array[GF_ERROR_CODE_NOSYS] = ENOSYS; + gf_errno_to_error_array[ENOSYS] = GF_ERROR_CODE_NOSYS; + + /* EFTYPE 79 / * Inappropriate file type or + * format */ + gf_error_to_errno_array[GF_ERROR_CODE_FTYPE] = EFTYPE; + gf_errno_to_error_array[EFTYPE] = GF_ERROR_CODE_FTYPE; + + /* EAUTH 80 / * Authentication error */ + gf_error_to_errno_array[GF_ERROR_CODE_AUTH] = EAUTH; + gf_errno_to_error_array[EAUTH] = GF_ERROR_CODE_AUTH; + + /* ENEEDAUTH 81 / * Need authenticator */ + gf_error_to_errno_array[GF_ERROR_CODE_NEEDAUTH] = ENEEDAUTH; + gf_errno_to_error_array[ENEEDAUTH] = GF_ERROR_CODE_NEEDAUTH; + + /* EIDRM 82 / * Identifier removed */ + gf_error_to_errno_array[GF_ERROR_CODE_IDRM] = EIDRM; + gf_errno_to_error_array[EIDRM] = GF_ERROR_CODE_IDRM; + + /* ENOMSG 83 / * No message of desired type */ + gf_error_to_errno_array[GF_ERROR_CODE_NOMSG] = ENOMSG; + gf_errno_to_error_array[ENOMSG] = GF_ERROR_CODE_NOMSG; + + /* EOVERFLOW 84 / * Value too large to be stored in + * data type */ + gf_error_to_errno_array[GF_ERROR_CODE_OVERFLOW] = EOVERFLOW; + gf_errno_to_error_array[EOVERFLOW] = GF_ERROR_CODE_OVERFLOW; + + /* ECANCELED 85 / * Operation canceled */ + gf_error_to_errno_array[GF_ERROR_CODE_CANCELED] = ECANCELED; + gf_errno_to_error_array[ECANCELED] = GF_ERROR_CODE_CANCELED; + + /* EILSEQ 86 / * Illegal byte sequence */ + gf_error_to_errno_array[GF_ERROR_CODE_ILSEQ] = EILSEQ; + gf_errno_to_error_array[EILSEQ] = GF_ERROR_CODE_ILSEQ; + + /* ENOATTR 87 / * Attribute not found */ + gf_error_to_errno_array[GF_ERROR_CODE_NOATTR] = ENOATTR; + gf_errno_to_error_array[ENOATTR] = GF_ERROR_CODE_NOATTR; + +#ifdef EDOOFUS + /* EDOOFUS 88 / * Programming error */ + gf_error_to_errno_array[GF_ERROR_CODE_DOOFUS] = EDOOFUS; + gf_errno_to_error_array[EDOOFUS] = GF_ERROR_CODE_DOOFUS; +#endif - /* EBADMSG 89 / * Bad message */ - gf_error_to_errno_array[GF_ERROR_CODE_BADMSG] = EBADMSG; - gf_errno_to_error_array[EBADMSG] = GF_ERROR_CODE_BADMSG; + /* EBADMSG 89 / * Bad message */ + gf_error_to_errno_array[GF_ERROR_CODE_BADMSG] = EBADMSG; + gf_errno_to_error_array[EBADMSG] = GF_ERROR_CODE_BADMSG; - /* EMULTIHOP 90 / * Multihop attempted */ - gf_error_to_errno_array[GF_ERROR_CODE_MULTIHOP] = EMULTIHOP; - gf_errno_to_error_array[EMULTIHOP] = GF_ERROR_CODE_MULTIHOP; +#ifdef __NetBSD__ + /* ENODATA 89 / * No message available */ + gf_error_to_errno_array[GF_ERROR_CODE_NODATA] = ENODATA; + gf_errno_to_error_array[ENODATA] = GF_ERROR_CODE_NODATA; +#endif - /* ENOLINK 91 / * Link has been severed */ - gf_error_to_errno_array[GF_ERROR_CODE_NOLINK] = ENOLINK; - gf_errno_to_error_array[ENOLINK] = GF_ERROR_CODE_NOLINK; + /* EMULTIHOP 90 / * Multihop attempted */ + gf_error_to_errno_array[GF_ERROR_CODE_MULTIHOP] = EMULTIHOP; + gf_errno_to_error_array[EMULTIHOP] = GF_ERROR_CODE_MULTIHOP; - /* EPROTO 92 / * Protocol error */ - gf_error_to_errno_array[GF_ERROR_CODE_PROTO] = EPROTO; - gf_errno_to_error_array[EPROTO] = GF_ERROR_CODE_PROTO; + /* ENOLINK 91 / * Link has been severed */ + gf_error_to_errno_array[GF_ERROR_CODE_NOLINK] = ENOLINK; + gf_errno_to_error_array[ENOLINK] = GF_ERROR_CODE_NOLINK; + /* EPROTO 92 / * Protocol error */ + gf_error_to_errno_array[GF_ERROR_CODE_PROTO] = EPROTO; + gf_errno_to_error_array[EPROTO] = GF_ERROR_CODE_PROTO; - return ; + return; } #endif /* GF_BSD_HOST_OS */ #ifdef GF_LINUX_HOST_OS -static void -init_compat_errno_arrays () +static void +init_compat_errno_arrays() { - /* Things are fine. Everything should work seemlessly on GNU/Linux machines */ - return ; + /* Things are fine. Everything should work seemlessly on GNU/Linux machines + */ + return; } #endif /* GF_LINUX_HOST_OS */ - static void -init_errno_arrays () +init_errno_arrays() { - int i; - for (i=0; i < GF_ERROR_CODE_UNKNOWN; i++) { - gf_errno_to_error_array[i] = i; - gf_error_to_errno_array[i] = i; - } - /* Now change the order if it needs to be. */ - init_compat_errno_arrays(); - - return; + int i; + for (i = 0; i < GF_ERROR_CODE_UNKNOWN; i++) { + gf_errno_to_error_array[i] = i; + gf_error_to_errno_array[i] = i; + } + /* Now change the order if it needs to be. */ + init_compat_errno_arrays(); + + return; } -int32_t -gf_errno_to_error (int32_t op_errno) +int32_t +gf_errno_to_error(int32_t op_errno) { - if (!gf_compat_errno_init_done) { - init_errno_arrays (); - gf_compat_errno_init_done = 1; - } + if (!gf_compat_errno_init_done) { + init_errno_arrays(); + gf_compat_errno_init_done = 1; + } - if ((op_errno > GF_ERROR_CODE_SUCCESS) && (op_errno < GF_ERROR_CODE_UNKNOWN)) - return gf_errno_to_error_array[op_errno]; + if ((op_errno > GF_ERROR_CODE_SUCCESS) && + (op_errno < GF_ERROR_CODE_UNKNOWN)) + return gf_errno_to_error_array[op_errno]; - return op_errno; + return op_errno; } - -int32_t -gf_error_to_errno (int32_t error) +int32_t +gf_error_to_errno(int32_t error) { - if (!gf_compat_errno_init_done) { - init_errno_arrays (); - gf_compat_errno_init_done = 1; - } + if (!gf_compat_errno_init_done) { + init_errno_arrays(); + gf_compat_errno_init_done = 1; + } - if ((error > GF_ERROR_CODE_SUCCESS) && (error < GF_ERROR_CODE_UNKNOWN)) - return gf_error_to_errno_array[error]; + if ((error > GF_ERROR_CODE_SUCCESS) && (error < GF_ERROR_CODE_UNKNOWN)) + return gf_error_to_errno_array[error]; - return error; + return error; } - diff --git a/libglusterfs/src/compat-errno.h b/libglusterfs/src/compat-errno.h deleted file mode 100644 index c1812e97b62..00000000000 --- a/libglusterfs/src/compat-errno.h +++ /dev/null @@ -1,240 +0,0 @@ -/* - Copyright (c) 2008-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef __COMPAT_ERRNO_H__ -#define __COMPAT_ERRNO_H__ - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include <errno.h> - -#define GF_ERROR_CODE_SUCCESS 0 -#define GF_ERROR_CODE_UNKNOWN 1024 -#define GF_ERRNO_UNKNOWN 1024 - -#define GF_ERROR_CODE_PERM 1 /* Operation not permitted */ -#define GF_ERROR_CODE_NOENT 2 /* No such file or directory */ -#define GF_ERROR_CODE_SRCH 3 /* No such process */ -#define GF_ERROR_CODE_INTR 4 /* Interrupted system call */ -#define GF_ERROR_CODE_IO 5 /* I/O error */ -#define GF_ERROR_CODE_NXIO 6 /* No such device or address */ -#define GF_ERROR_CODE_2BIG 7 /* Argument list too long */ -#define GF_ERROR_CODE_NOEXEC 8 /* Exec format error */ -#define GF_ERROR_CODE_BADF 9 /* Bad file number */ -#define GF_ERROR_CODE_CHILD 10 /* No child processes */ -#define GF_ERROR_CODE_AGAIN 11 /* Try again */ -#define GF_ERROR_CODE_NOMEM 12 /* Out of memory */ -#define GF_ERROR_CODE_ACCES 13 /* Permission denied */ -#define GF_ERROR_CODE_FAULT 14 /* Bad address */ -#define GF_ERROR_CODE_NOTBLK 15 /* Block device required */ -#define GF_ERROR_CODE_BUSY 16 /* Device or resource busy */ -#define GF_ERROR_CODE_EXIST 17 /* File exists */ -#define GF_ERROR_CODE_XDEV 18 /* Cross-device link */ -#define GF_ERROR_CODE_NODEV 19 /* No such device */ -#define GF_ERROR_CODE_NOTDIR 20 /* Not a directory */ -#define GF_ERROR_CODE_ISDIR 21 /* Is a directory */ -#define GF_ERROR_CODE_INVAL 22 /* Invalid argument */ -#define GF_ERROR_CODE_NFILE 23 /* File table overflow */ -#define GF_ERROR_CODE_MFILE 24 /* Too many open files */ -#define GF_ERROR_CODE_NOTTY 25 /* Not a typewriter */ -#define GF_ERROR_CODE_TXTBSY 26 /* Text file busy */ -#define GF_ERROR_CODE_FBIG 27 /* File too large */ -#define GF_ERROR_CODE_NOSPC 28 /* No space left on device */ -#define GF_ERROR_CODE_SPIPE 29 /* Illegal seek */ -#define GF_ERROR_CODE_ROFS 30 /* Read-only file system */ -#define GF_ERROR_CODE_MLINK 31 /* Too many links */ -#define GF_ERROR_CODE_PIPE 32 /* Broken pipe */ -#define GF_ERROR_CODE_DOM 33 /* Math argument out of domain of func */ -#define GF_ERROR_CODE_RANGE 34 /* Math result not representable */ -#define GF_ERROR_CODE_DEADLK 35 /* Resource deadlock would occur */ -#define GF_ERROR_CODE_NAMETOOLONG 36 /* File name too long */ -#define GF_ERROR_CODE_NOLCK 37 /* No record locks available */ -#define GF_ERROR_CODE_NOSYS 38 /* Function not implemented */ -#define GF_ERROR_CODE_NOTEMPTY 39 /* Directory not empty */ -#define GF_ERROR_CODE_LOOP 40 /* Too many symbolic links encountered */ - -#define GF_ERROR_CODE_NOMSG 42 /* No message of desired type */ -#define GF_ERROR_CODE_IDRM 43 /* Identifier removed */ -#define GF_ERROR_CODE_CHRNG 44 /* Channel number out of range */ -#define GF_ERROR_CODE_L2NSYNC 45 /* Level 2 not synchronized */ -#define GF_ERROR_CODE_L3HLT 46 /* Level 3 halted */ -#define GF_ERROR_CODE_L3RST 47 /* Level 3 reset */ -#define GF_ERROR_CODE_LNRNG 48 /* Link number out of range */ -#define GF_ERROR_CODE_UNATCH 49 /* Protocol driver not attached */ -#define GF_ERROR_CODE_NOCSI 50 /* No CSI structure available */ -#define GF_ERROR_CODE_L2HLT 51 /* Level 2 halted */ -#define GF_ERROR_CODE_BADE 52 /* Invalid exchange */ -#define GF_ERROR_CODE_BADR 53 /* Invalid request descriptor */ -#define GF_ERROR_CODE_XFULL 54 /* Exchange full */ -#define GF_ERROR_CODE_NOANO 55 /* No anode */ -#define GF_ERROR_CODE_BADRQC 56 /* Invalid request code */ -#define GF_ERROR_CODE_BADSLT 57 /* Invalid slot */ -#define GF_ERROR_CODE_BFONT 59 /* Bad font file format */ -#define GF_ERROR_CODE_NOSTR 60 /* Device not a stream */ -#define GF_ERROR_CODE_NODATA 61 /* No data available */ -#define GF_ERROR_CODE_TIME 62 /* Timer expired */ -#define GF_ERROR_CODE_NOSR 63 /* Out of streams resources */ -#define GF_ERROR_CODE_NONET 64 /* Machine is not on the network */ -#define GF_ERROR_CODE_NOPKG 65 /* Package not installed */ -#define GF_ERROR_CODE_REMOTE 66 /* Object is remote */ -#define GF_ERROR_CODE_NOLINK 67 /* Link has been severed */ -#define GF_ERROR_CODE_ADV 68 /* Advertise error */ -#define GF_ERROR_CODE_SRMNT 69 /* Srmount error */ -#define GF_ERROR_CODE_COMM 70 /* Communication error on send */ -#define GF_ERROR_CODE_PROTO 71 /* Protocol error */ -#define GF_ERROR_CODE_MULTIHOP 72 /* Multihop attempted */ -#define GF_ERROR_CODE_DOTDOT 73 /* RFS specific error */ -#define GF_ERROR_CODE_BADMSG 74 /* Not a data message */ -#define GF_ERROR_CODE_OVERFLOW 75 /* Value too large for defined data type */ -#define GF_ERROR_CODE_NOTUNIQ 76 /* Name not unique on network */ -#define GF_ERROR_CODE_BADFD 77 /* File descriptor in bad state */ -#define GF_ERROR_CODE_REMCHG 78 /* Remote address changed */ -#define GF_ERROR_CODE_LIBACC 79 /* Can not access a needed shared library */ -#define GF_ERROR_CODE_LIBBAD 80 /* Accessing a corrupted shared library */ -#define GF_ERROR_CODE_LIBSCN 81 /* .lib section in a.out corrupted */ -#define GF_ERROR_CODE_LIBMAX 82 /* Attempting to link in too many shared libraries */ -#define GF_ERROR_CODE_LIBEXEC 83 /* Cannot exec a shared library directly */ -#define GF_ERROR_CODE_ILSEQ 84 /* Illegal byte sequence */ -#define GF_ERROR_CODE_RESTART 85 /* Interrupted system call should be restarted */ -#define GF_ERROR_CODE_STRPIPE 86 /* Streams pipe error */ -#define GF_ERROR_CODE_USERS 87 /* Too many users */ -#define GF_ERROR_CODE_NOTSOCK 88 /* Socket operation on non-socket */ -#define GF_ERROR_CODE_DESTADDRREQ 89 /* Destination address required */ -#define GF_ERROR_CODE_MSGSIZE 90 /* Message too long */ -#define GF_ERROR_CODE_PROTOTYPE 91 /* Protocol wrong type for socket */ -#define GF_ERROR_CODE_NOPROTOOPT 92 /* Protocol not available */ -#define GF_ERROR_CODE_PROTONOSUPPORT 93 /* Protocol not supported */ -#define GF_ERROR_CODE_SOCKTNOSUPPORT 94 /* Socket type not supported */ -#define GF_ERROR_CODE_OPNOTSUPP 95 /* Operation not supported on transport endpoint */ -#define GF_ERROR_CODE_PFNOSUPPORT 96 /* Protocol family not supported */ -#define GF_ERROR_CODE_AFNOSUPPORT 97 /* Address family not supported by protocol */ -#define GF_ERROR_CODE_ADDRINUSE 98 /* Address already in use */ -#define GF_ERROR_CODE_ADDRNOTAVAIL 99 /* Cannot assign requested address */ -#define GF_ERROR_CODE_NETDOWN 100 /* Network is down */ -#define GF_ERROR_CODE_NETUNREACH 101 /* Network is unreachable */ -#define GF_ERROR_CODE_NETRESET 102 /* Network dropped connection because of reset */ -#define GF_ERROR_CODE_CONNABORTED 103 /* Software caused connection abort */ -#define GF_ERROR_CODE_CONNRESET 104 /* Connection reset by peer */ -#define GF_ERROR_CODE_NOBUFS 105 /* No buffer space available */ -#define GF_ERROR_CODE_ISCONN 106 /* Transport endpoint is already connected */ -#define GF_ERROR_CODE_NOTCONN 107 /* Transport endpoint is not connected */ -#define GF_ERROR_CODE_SHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ -#define GF_ERROR_CODE_TOOMANYREFS 109 /* Too many references: cannot splice */ -#define GF_ERROR_CODE_TIMEDOUT 110 /* Connection timed out */ -#define GF_ERROR_CODE_CONNREFUSED 111 /* Connection refused */ -#define GF_ERROR_CODE_HOSTDOWN 112 /* Host is down */ -#define GF_ERROR_CODE_HOSTUNREACH 113 /* No route to host */ -#define GF_ERROR_CODE_ALREADY 114 /* Operation already in progress */ -#define GF_ERROR_CODE_INPROGRESS 115 /* Operation now in progress */ -#define GF_ERROR_CODE_ALREADY 114 /* Operation already in progress */ -#define GF_ERROR_CODE_INPROGRESS 115 /* Operation now in progress */ -#define GF_ERROR_CODE_STALE 116 /* Stale NFS file handle */ -#define GF_ERROR_CODE_UCLEAN 117 /* Structure needs cleaning */ -#define GF_ERROR_CODE_NOTNAM 118 /* Not a XENIX named type file */ -#define GF_ERROR_CODE_NAVAIL 119 /* No XENIX semaphores available */ -#define GF_ERROR_CODE_ISNAM 120 /* Is a named type file */ -#define GF_ERROR_CODE_REMOTEIO 121 /* Remote I/O error */ -#define GF_ERROR_CODE_DQUOT 122 /* Quota exceeded */ -#define GF_ERROR_CODE_NOMEDIUM 123 /* No medium found */ -#define GF_ERROR_CODE_MEDIUMTYPE 124 /* Wrong medium type */ -#define GF_ERROR_CODE_CANCELED 125 /* Operation Canceled */ -#define GF_ERROR_CODE_NOKEY 126 /* Required key not available */ -#define GF_ERROR_CODE_KEYEXPIRED 127 /* Key has expired */ -#define GF_ERROR_CODE_KEYREVOKED 128 /* Key has been revoked */ -#define GF_ERROR_CODE_KEYREJECTED 129 /* Key was rejected by service */ - -/* for robust mutexes */ -#define GF_ERROR_CODE_OWNERDEAD 130 /* Owner died */ -#define GF_ERROR_CODE_NOTRECOVERABLE 131 /* State not recoverable */ - - - -/* Should never be seen by user programs */ -#define GF_ERROR_CODE_RESTARTSYS 512 -#define GF_ERROR_CODE_RESTARTNOINTR 513 -#define GF_ERROR_CODE_RESTARTNOHAND 514 /* restart if no handler.. */ -#define GF_ERROR_CODE_NOIOCTLCMD 515 /* No ioctl command */ -#define GF_ERROR_CODE_RESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */ - -/* Defined for the NFSv3 protocol */ -#define GF_ERROR_CODE_BADHANDLE 521 /* Illegal NFS file handle */ -#define GF_ERROR_CODE_NOTSYNC 522 /* Update synchronization mismatch */ -#define GF_ERROR_CODE_BADCOOKIE 523 /* Cookie is stale */ -#define GF_ERROR_CODE_NOTSUPP 524 /* Operation is not supported */ -#define GF_ERROR_CODE_TOOSMALL 525 /* Buffer or request is too small */ -#define GF_ERROR_CODE_SERVERFAULT 526 /* An untranslatable error occurred */ -#define GF_ERROR_CODE_BADTYPE 527 /* Type not supported by server */ -#define GF_ERROR_CODE_JUKEBOX 528 /* Request initiated, but will not complete before timeout */ -#define GF_ERROR_CODE_IOCBQUEUED 529 /* iocb queued, will get completion event */ -#define GF_ERROR_CODE_IOCBRETRY 530 /* iocb queued, will trigger a retry */ - -/* Darwin OS X */ -#define GF_ERROR_CODE_NOPOLICY 701 -#define GF_ERROR_CODE_BADMACHO 702 -#define GF_ERROR_CODE_PWROFF 703 -#define GF_ERROR_CODE_DEVERR 704 -#define GF_ERROR_CODE_BADARCH 705 -#define GF_ERROR_CODE_BADEXEC 706 -#define GF_ERROR_CODE_SHLIBVERS 707 - - - -/* Solaris */ -/* ENOTACTIVE 73 / * Facility is not active */ -#define GF_ERROR_CODE_NOTACTIVE 801 -/* ELOCKUNMAPPED 72 / * locked lock was unmapped */ -#define GF_ERROR_CODE_LOCKUNMAPPED 802 - -/* BSD system */ -#define GF_ERROR_CODE_PROCLIM 901 /* Too many processes */ -#define GF_ERROR_CODE_BADRPC 902 /* RPC struct is bad */ -#define GF_ERROR_CODE_RPCMISMATCH 903 /* RPC version wrong */ -#define GF_ERROR_CODE_PROGUNAVAIL 904 /* RPC prog. not avail */ -#define GF_ERROR_CODE_PROGMISMATCH 905 /* Program version wrong */ -#define GF_ERROR_CODE_PROCUNAVAIL 905 /* Bad procedure for program */ -#define GF_ERROR_CODE_FTYPE 906 /* Inappropriate file type or format */ -#define GF_ERROR_CODE_AUTH 907 /* Authentication error */ -#define GF_ERROR_CODE_NEEDAUTH 908 /* Need authenticator */ -#define GF_ERROR_CODE_DOOFUS 909 /* Programming error */ - -#define GF_ERROR_CODE_NOATTR GF_ERROR_CODE_NODATA /* Attribute not found */ - -/* Either one of enodata or enoattr will be there in system */ -#ifndef ENOATTR -#define ENOATTR ENODATA -#endif /* ENOATTR */ - -#ifndef ENODATA -#define ENODATA ENOATTR -#endif /* ENODATA */ - -#ifndef EBADFD -#define EBADFD EBADRPC -#endif /* EBADFD */ - -/* These functions are defined for all the OS flags, but content will - * be different for each OS flag. - */ -int32_t gf_errno_to_error (int32_t op_errno); -int32_t gf_error_to_errno (int32_t error); - -#endif /* __COMPAT_ERRNO_H__ */ diff --git a/libglusterfs/src/compat.c b/libglusterfs/src/compat.c index 891b156d3f5..8a05a30a8fe 100644 --- a/libglusterfs/src/compat.c +++ b/libglusterfs/src/compat.c @@ -1,426 +1,618 @@ /* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif + 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 <string.h> #include <stdlib.h> +#include <unistd.h> #include <stdarg.h> #include <getopt.h> #include <sys/types.h> #include <dirent.h> -#ifdef GF_SOLARIS_HOST_OS -#include "logging.h" -#endif /* GF_SOLARIS_HOST_OS */ - -#include "compat.h" -#include "common-utils.h" +#include "glusterfs/logging.h" +#include "glusterfs/compat.h" +#include "glusterfs/iatt.h" +#include "glusterfs/syscall.h" +#include "glusterfs/run.h" +#include "glusterfs/libglusterfs-messages.h" #ifdef GF_SOLARIS_HOST_OS - -int -solaris_fsetxattr(int fd, - const char* key, - const char *value, - size_t size, - int flags) +int +solaris_fsetxattr(int fd, const char *key, const char *value, size_t size, + int flags) { - int attrfd = -1; - int ret = 0; - - attrfd = openat (fd, key, flags|O_CREAT|O_WRONLY|O_XATTR, 0777); - if (attrfd >= 0) { - ftruncate (attrfd, 0); - ret = write (attrfd, value, size); - close (attrfd); - } else { - if (errno != ENOENT) - gf_log ("libglusterfs", GF_LOG_ERROR, - "Couldn't set extended attribute for %d (%d)", - fd, errno); - return -1; - } - - return 0; -} + int attrfd = -1; + int ret = 0; + + attrfd = openat(fd, key, flags | O_CREAT | O_WRONLY | O_XATTR, 0777); + if (attrfd >= 0) { + ftruncate(attrfd, 0); + ret = write(attrfd, value, size); + close(attrfd); + } else { + if (errno != ENOENT) + gf_msg("libglusterfs", GF_LOG_ERROR, errno, + LG_MSG_SET_ATTRIBUTE_FAILED, + "Couldn't set " + "extended attribute for %d", + fd); + return -1; + } + return 0; +} -int -solaris_fgetxattr(int fd, - const char* key, - char *value, - size_t size) +int +solaris_fgetxattr(int fd, const char *key, char *value, size_t size) { - int attrfd = -1; - int ret = 0; - - attrfd = openat (fd, key, O_RDONLY|O_XATTR); - if (attrfd >= 0) { - if (size == 0) { - struct stat buf; - fstat (attrfd, &buf); - ret = buf.st_size; - } else { - ret = read (attrfd, value, size); - } - close (attrfd); - } else { - if (errno == ENOENT) - errno = ENODATA; - if (errno != ENOENT) - gf_log ("libglusterfs", GF_LOG_DEBUG, - "Couldn't read extended attribute for the file %d (%d)", - fd, errno); - return -1; - } - - return ret; + int attrfd = -1; + int ret = 0; + + attrfd = openat(fd, key, O_RDONLY | O_XATTR); + if (attrfd >= 0) { + if (size == 0) { + struct stat buf; + fstat(attrfd, &buf); + ret = buf.st_size; + } else { + ret = read(attrfd, value, size); + } + close(attrfd); + } else { + if (errno != ENOENT) + gf_msg("libglusterfs", GF_LOG_INFO, errno, + LG_MSG_READ_ATTRIBUTE_FAILED, + "Couldn't read " + "extended attribute for the file %d", + fd); + if (errno == ENOENT) + errno = ENODATA; + return -1; + } + + return ret; } +/* Solaris does not support xattr for symlinks and dev files. Since gfid and + other trusted attributes are stored as xattrs, we need to provide support for + them. A mapped regular file is stored in the /.glusterfs_xattr_inode of the + export dir. All xattr ops related to the special files are redirected to this + map file. +*/ -int -solaris_setxattr(const char *path, - const char* key, - const char *value, - size_t size, - int flags) +int +make_export_path(const char *real_path, char **path) { - int attrfd = -1; - int ret = 0; - - attrfd = attropen (path, key, flags|O_CREAT|O_WRONLY, 0777); - if (attrfd >= 0) { - ftruncate (attrfd, 0); - ret = write (attrfd, value, size); - close (attrfd); - } else { - if (errno != ENOENT) - gf_log ("libglusterfs", GF_LOG_ERROR, - "Couldn't set extended attribute for %s (%d)", - path, errno); - return -1; - } - - return 0; + int ret = -1; + char *tmp = NULL; + char *export_path = NULL; + char *dup = NULL; + char *ptr = NULL; + char *freeptr = NULL; + uuid_t gfid = { + 0, + }; + + export_path = GF_CALLOC(1, sizeof(char) * PATH_MAX, 0); + if (!export_path) + goto out; + + dup = gf_strdup(real_path); + if (!dup) + goto out; + + freeptr = dup; + ret = solaris_getxattr("/", GFID_XATTR_KEY, gfid, 16); + /* Return value of getxattr */ + if (ret == 16) { + if (__is_root_gfid(gfid)) { + strcat(export_path, "/"); + ret = 0; + goto done; + } + } + + do { + ptr = strtok_r(dup, "/", &tmp); + if (!ptr) + break; + strcat(export_path, dup); + ret = solaris_getxattr(export_path, GFID_XATTR_KEY, gfid, 16); + if (ret == 16) { + if (__is_root_gfid(gfid)) { + ret = 0; + goto done; + } + } + strcat(export_path, "/"); + dup = tmp; + } while (ptr); + + goto out; + +done: + if (!ret) { + *path = export_path; + } +out: + GF_FREE(freeptr); + if (ret && export_path) + GF_FREE(export_path); + + return ret; } +int +solaris_xattr_resolve_path(const char *real_path, char **path) +{ + int ret = -1; + char *export_path = NULL; + char xattr_path[PATH_MAX] = { + 0, + }; + struct stat lstatbuf = { + 0, + }; + struct iatt stbuf = { + 0, + }; + struct stat statbuf = { + 0, + }; + + ret = lstat(real_path, &lstatbuf); + if (ret != 0) + return ret; + iatt_from_stat(&stbuf, &lstatbuf); + if (IA_ISREG(stbuf.ia_type) || IA_ISDIR(stbuf.ia_type)) + return -1; + + ret = make_export_path(real_path, &export_path); + if (!ret && export_path) { + strcat(export_path, "/" GF_SOLARIS_XATTR_DIR); + if (lstat(export_path, &statbuf)) { + ret = mkdir(export_path, 0755); + if (ret && (errno != EEXIST)) { + gf_msg_debug(THIS->name, 0, + "mkdir failed," + " errno: %d", + errno); + goto out; + } + } + snprintf(xattr_path, PATH_MAX, "%s%s%lu", export_path, "/", + stbuf.ia_ino); + + ret = lstat(xattr_path, &statbuf); + + if (ret) { + ret = mknod(xattr_path, S_IFREG | O_WRONLY, 0); + if (ret && (errno != EEXIST)) { + gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED, + "Failed to " + "create mapped file %s", + xattr_path); + goto out; + } + } + *path = gf_strdup(xattr_path); + } +out: + GF_FREE(export_path); + if (*path) + return 0; + else + return -1; +} int -solaris_listxattr(const char *path, - char *list, - size_t size) +solaris_setxattr(const char *path, const char *key, const char *value, + size_t size, int flags) { - int attrdirfd = -1; - ssize_t len = 0; - DIR *dirptr = NULL; - struct dirent *dent = NULL; - int newfd = -1; - - attrdirfd = attropen (path, ".", O_RDONLY, 0); - if (attrdirfd >= 0) { - newfd = dup(attrdirfd); - dirptr = fdopendir(newfd); - if (dirptr) { - while ((dent = readdir(dirptr))) { - size_t listlen = strlen(dent->d_name); - if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) { - /* we don't want "." and ".." here */ - continue; - } - if (size == 0) { - /* return the current size of the list of extended attribute names*/ - len += listlen + 1; - } else { - /* check size and copy entrie + nul into list. */ - if ((len + listlen + 1) > size) { - errno = ERANGE; - len = -1; - break; - } else { - strncpy(list + len, dent->d_name, listlen); - len += listlen; - list[len] = '\0'; - ++len; - } - } - } - - if (closedir(dirptr) == -1) { - close (attrdirfd); - return -1; - } - } else { - close (attrdirfd); - return -1; - } - close (attrdirfd); - } - return len; + int attrfd = -1; + int ret = 0; + char *mapped_path = NULL; + + ret = solaris_xattr_resolve_path(path, &mapped_path); + if (!ret) { + attrfd = attropen(mapped_path, key, flags | O_CREAT | O_WRONLY, 0777); + } else { + attrfd = attropen(path, key, flags | O_CREAT | O_WRONLY, 0777); + } + if (attrfd >= 0) { + ftruncate(attrfd, 0); + ret = write(attrfd, value, size); + close(attrfd); + ret = 0; + } else { + if (errno != ENOENT) + gf_msg("libglusterfs", GF_LOG_ERROR, errno, + LG_MSG_SET_ATTRIBUTE_FAILED, + "Couldn't set " + "extended attribute for %s", + path); + ret = -1; + } + GF_FREE(mapped_path); + return ret; } +int +solaris_listxattr(const char *path, char *list, size_t size) +{ + int attrdirfd = -1; + ssize_t len = 0; + DIR *dirptr = NULL; + struct dirent *dent = NULL; + int newfd = -1; + char *mapped_path = NULL; + int ret = -1; + + ret = solaris_xattr_resolve_path(path, &mapped_path); + if (!ret) { + attrdirfd = attropen(mapped_path, ".", O_RDONLY, 0); + } else { + attrdirfd = attropen(path, ".", O_RDONLY, 0); + } + if (attrdirfd >= 0) { + newfd = dup(attrdirfd); + dirptr = fdopendir(newfd); + if (dirptr) { + while ((dent = readdir(dirptr))) { + size_t listlen = strlen(dent->d_name); + if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) { + /* we don't want "." and ".." here */ + continue; + } + if (size == 0) { + /* return the current size of the list + of extended attribute names*/ + len += listlen + 1; + } else { + /* check size and copy entry + null + into list. */ + if ((len + listlen + 1) > size) { + errno = ERANGE; + len = -1; + break; + } else { + strncpy(list + len, dent->d_name, listlen); + len += listlen; + list[len] = '\0'; + ++len; + } + } + } + + if (closedir(dirptr) == -1) { + close(attrdirfd); + len = -1; + goto out; + } + } else { + close(attrdirfd); + len = -1; + goto out; + } + close(attrdirfd); + } +out: + GF_FREE(mapped_path); + return len; +} int -solaris_flistxattr(int fd, - char *list, - size_t size) +solaris_flistxattr(int fd, char *list, size_t size) { - int attrdirfd = -1; - ssize_t len = 0; - DIR *dirptr = NULL; - struct dirent *dent = NULL; - int newfd = -1; - - attrdirfd = openat (fd, ".", O_RDONLY, 0); - if (attrdirfd >= 0) { - newfd = dup(attrdirfd); - dirptr = fdopendir(newfd); - if (dirptr) { - while ((dent = readdir(dirptr))) { - size_t listlen = strlen(dent->d_name); - if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) { - /* we don't want "." and ".." here */ - continue; - } - if (size == 0) { - /* return the current size of the list of extended attribute names*/ - len += listlen + 1; - } else { - /* check size and copy entrie + nul into list. */ - if ((len + listlen + 1) > size) { - errno = ERANGE; - len = -1; - break; - } else { - strncpy(list + len, dent->d_name, listlen); - len += listlen; - list[len] = '\0'; - ++len; - } - } - } - - if (closedir(dirptr) == -1) { - close (attrdirfd); - return -1; - } - } else { - close (attrdirfd); - return -1; - } - close (attrdirfd); - } - return len; + int attrdirfd = -1; + ssize_t len = 0; + DIR *dirptr = NULL; + struct dirent *dent = NULL; + int newfd = -1; + + attrdirfd = openat(fd, ".", O_RDONLY, 0); + if (attrdirfd >= 0) { + newfd = dup(attrdirfd); + dirptr = fdopendir(newfd); + if (dirptr) { + while ((dent = readdir(dirptr))) { + size_t listlen = strlen(dent->d_name); + if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) { + /* we don't want "." and ".." here */ + continue; + } + if (size == 0) { + /* return the current size of the list + of extended attribute names*/ + len += listlen + 1; + } else { + /* check size and copy entry + null + into list. */ + if ((len + listlen + 1) > size) { + errno = ERANGE; + len = -1; + break; + } else { + strncpy(list + len, dent->d_name, listlen); + len += listlen; + list[len] = '\0'; + ++len; + } + } + } + + if (closedir(dirptr) == -1) { + close(attrdirfd); + return -1; + } + } else { + close(attrdirfd); + return -1; + } + close(attrdirfd); + } + return len; } +int +solaris_removexattr(const char *path, const char *key) +{ + int ret = -1; + int attrfd = -1; + char *mapped_path = NULL; + + ret = solaris_xattr_resolve_path(path, &mapped_path); + if (!ret) { + attrfd = attropen(mapped_path, ".", O_RDONLY, 0); + } else { + attrfd = attropen(path, ".", O_RDONLY, 0); + } + if (attrfd >= 0) { + ret = unlinkat(attrfd, key, 0); + close(attrfd); + } else { + if (errno == ENOENT) + errno = ENODATA; + ret = -1; + } + + GF_FREE(mapped_path); + + return ret; +} -int -solaris_removexattr(const char *path, - const char* key) +int +solaris_getxattr(const char *path, const char *key, char *value, size_t size) { - int ret = -1; - int attrfd = attropen (path, ".", O_RDONLY, 0); - if (attrfd >= 0) { - ret = unlinkat (attrfd, key, 0); - close (attrfd); - } else { - if (errno == ENOENT) - errno = ENODATA; - return -1; - } - - return ret; + int attrfd = -1; + int ret = 0; + char *mapped_path = NULL; + + ret = solaris_xattr_resolve_path(path, &mapped_path); + if (!ret) { + attrfd = attropen(mapped_path, key, O_RDONLY, 0); + } else { + attrfd = attropen(path, key, O_RDONLY, 0); + } + + if (attrfd >= 0) { + if (size == 0) { + struct stat buf; + fstat(attrfd, &buf); + ret = buf.st_size; + } else { + ret = read(attrfd, value, size); + } + close(attrfd); + } else { + if (errno != ENOENT) + gf_msg("libglusterfs", GF_LOG_INFO, errno, + LG_MSG_READ_ATTRIBUTE_FAILED, + "Couldn't read " + "extended attribute for the file %s", + path); + if (errno == ENOENT) + errno = ENODATA; + ret = -1; + } + GF_FREE(mapped_path); + return ret; } -int -solaris_getxattr(const char *path, - const char* key, - char *value, - size_t size) +char * +strsep(char **str, const char *delims) { - int attrfd = -1; - int ret = 0; - - attrfd = attropen (path, key, O_RDONLY, 0); - if (attrfd >= 0) { - if (size == 0) { - struct stat buf; - fstat (attrfd, &buf); - ret = buf.st_size; - } else { - ret = read (attrfd, value, size); - } - close (attrfd); - } else { - if (errno == ENOENT) - errno = ENODATA; - if (errno != ENOENT) - gf_log ("libglusterfs", GF_LOG_DEBUG, - "Couldn't read extended attribute for the file %s (%d)", - path, errno); - return -1; - } - return ret; + char *token; + + if (*str == NULL) { + /* No more tokens */ + return NULL; + } + + token = *str; + while (**str != '\0') { + if (strchr(delims, **str) != NULL) { + **str = '\0'; + (*str)++; + return token; + } + (*str)++; + } + /* There is no other token */ + *str = NULL; + return token; } +/* Code comes from libiberty */ -char* strsep(char** str, const char* delims) +int +vasprintf(char **result, const char *format, va_list args) { - char* token; - - if (*str==NULL) { - /* No more tokens */ - return NULL; - } - - token=*str; - while (**str!='\0') { - if (strchr(delims,**str)!=NULL) { - **str='\0'; - (*str)++; - return token; - } - (*str)++; - } - /* There is no other token */ - *str=NULL; - return token; + return gf_vasprintf(result, format, args); } -/* Code comes from libiberty */ +int +asprintf(char **buf, const char *fmt, ...) +{ + int status; + va_list ap; + + va_start(ap, fmt); + status = vasprintf(buf, fmt, ap); + va_end(ap); + return status; +} int -vasprintf (char **result, const char *format, va_list args) +solaris_unlink(const char *path) { - const char *p = format; - /* Add one to make sure that it is never zero, which might cause malloc - to return NULL. */ - int total_width = strlen (format) + 1; - va_list ap; - - /* vasprintf does not work on Solaris when memcpy is called on va_list pointers. - * Replacing it with va_copy which works on Solaris - */ - va_copy (ap, args); - - while (*p != '\0') - { - if (*p++ == '%') - { - while (strchr ("-+ #0", *p)) - ++p; - if (*p == '*') - { - ++p; - total_width += abs (va_arg (ap, int)); - } - else - { - char *endp; - total_width += strtoul (p, &endp, 10); - p = endp; - } - if (*p == '.') - { - ++p; - if (*p == '*') - { - ++p; - total_width += abs (va_arg (ap, int)); - } - else - { - char *endp; - total_width += strtoul (p, &endp, 10); - p = endp; - } - } - while (strchr ("hlL", *p)) - ++p; - /* Should be big enough for any format specifier except %s - and floats. */ - total_width += 30; - switch (*p) - { - case 'd': - case 'i': - case 'o': - case 'u': - case 'x': - case 'X': - case 'c': - (void) va_arg (ap, int); - break; - case 'f': - case 'e': - case 'E': - case 'g': - case 'G': - (void) va_arg (ap, double); - /* Since an ieee double can have an exponent of 307, we'll - make the buffer wide enough to cover the gross case. */ - total_width += 307; - - case 's': - total_width += strlen (va_arg (ap, char *)); - break; - case 'p': - case 'n': - (void) va_arg (ap, char *); - break; - } - } + char *mapped_path = NULL; + struct stat stbuf = { + 0, + }; + int ret = -1; + + ret = solaris_xattr_resolve_path(path, &mapped_path); + + if (!ret && mapped_path) { + if (lstat(path, &stbuf)) { + gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED, + "Stat failed on " + "mapped file %s", + mapped_path); + goto out; + } + if (stbuf.st_nlink == 1) { + if (remove(mapped_path)) + gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED, + "Failed to " + "remove mapped file %s", + mapped_path); + } } - va_end (ap); +out: + GF_FREE(mapped_path); - *result = malloc (total_width); - if (*result != NULL) - return vsprintf (*result, format, args); - else - return 0; + return unlink(path); } int -asprintf (char **buf, const char *fmt, ...) +solaris_rename(const char *old_path, const char *new_path) +{ + char *mapped_path = NULL; + int ret = -1; + + ret = solaris_xattr_resolve_path(new_path, &mapped_path); + + if (!ret && mapped_path) { + if (!remove(mapped_path)) + gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED, + "Failed to remove " + "mapped file %s.", + mapped_path); + GF_FREE(mapped_path); + } + + return rename(old_path, new_path); +} + +char * +mkdtemp(char *tempstring) { - int status; - va_list ap; + char *new_string = NULL; + int ret = 0; + + new_string = mkstemp(tempstring); + if (!new_string) + goto out; - va_start (ap, fmt); - status = vasprintf (buf, fmt, ap); - va_end (ap); - return status; + ret = mkdir(new_string, 0700); + if (ret < 0) + new_string = NULL; + +out: + return new_string; } #endif /* GF_SOLARIS_HOST_OS */ +#ifdef GF_BSD_HOST_OS +void +gf_extattr_list_reshape(char *bsd_list, ssize_t size) +{ + /* + * the format of bsd_list is + * <attr_len>attr<attr_len>attr... + * we try to reformat it as Linux's + * attr<\0>attr<\0>... + * */ + if (NULL == bsd_list || size <= 0) + return; + + size_t i = 0, j; + + while (i < size) { + size_t attr_len = bsd_list[i]; + + for (j = i; j < i + attr_len; ++j) + bsd_list[j] = bsd_list[j + 1]; + bsd_list[j] = '\0'; + + i += attr_len + 1; + gf_msg_debug("syscall", 0, "syscall debug: %lu", attr_len); + } +} +#endif /* GF_BSD_HOST_OS */ + #ifndef HAVE_STRNLEN -size_t -strnlen(const char *string, size_t maxlen) +size_t +strnlen(const char *string, size_t maxlen) { - int len = 0; - while ((len < maxlen) && string[len]) - len++; - return len; + int len = 0; + while ((len < maxlen) && string[len]) + len++; + return len; } #endif /* STRNLEN */ + +int +gf_umount_lazy(char *xlname, char *path, int rmdir_flag) +{ + int ret = -1; + runner_t runner = { + 0, + }; + + runinit(&runner); +#ifdef GF_LINUX_HOST_OS + runner_add_args(&runner, _PATH_UMOUNT, "-l", path, NULL); +#else + if (rmdir_flag) + runner_add_args(&runner, SBIN_DIR "/umountd", "-r", path, NULL); + else + runner_add_args(&runner, SBIN_DIR "/umountd", path, NULL); +#endif + ret = runner_run(&runner); + if (ret) { + gf_msg(xlname, GF_LOG_ERROR, errno, LG_MSG_UNMOUNT_FAILED, + "Lazy unmount of %s", path); + } + +#ifdef GF_LINUX_HOST_OS + if (!ret && rmdir_flag) { + ret = sys_rmdir(path); + if (ret) + gf_msg(xlname, GF_LOG_WARNING, errno, LG_MSG_DIR_OP_FAILED, + "rmdir %s", path); + } +#endif + + return ret; +} diff --git a/libglusterfs/src/compat.h b/libglusterfs/src/compat.h deleted file mode 100644 index 51539648b22..00000000000 --- a/libglusterfs/src/compat.h +++ /dev/null @@ -1,354 +0,0 @@ -/* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef __COMPAT_H__ -#define __COMPAT_H__ - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include <stdint.h> -#include "dict.h" - -#ifndef LLONG_MAX -#define LLONG_MAX __LONG_LONG_MAX__ /* compat with old gcc */ -#endif /* LLONG_MAX */ - - -#ifdef GF_LINUX_HOST_OS - -#define UNIX_PATH_MAX 108 - -#include <sys/un.h> -#include <linux/limits.h> -#include <sys/xattr.h> -#include <endian.h> - - -#ifndef HAVE_LLISTXATTR - -/* This part is valid only incase of old glibc which doesn't support - * 'llistxattr()' system calls. - */ - -#define lremovexattr(path,key) removexattr(path,key) -#define llistxattr(path,key,size) listxattr(path,key,size) -#define lgetxattr(path, key, value, size) getxattr(path,key,value,size) -#define lsetxattr(path,key,value,size,flags) setxattr(path,key,value,size,flags) - -#endif /* HAVE_LLISTXATTR */ -#endif /* GF_LINUX_HOST_OS */ - -#ifdef GF_BSD_HOST_OS -/* In case of FreeBSD */ - -#define UNIX_PATH_MAX 104 -#include <sys/types.h> - -#include <sys/un.h> -#include <sys/endian.h> -#include <sys/extattr.h> -#include <limits.h> - -#include <libgen.h> - -enum { - ATTR_CREATE = 1, -#define XATTR_CREATE ATTR_CREATE - ATTR_REPLACE = 2 -#define XATTR_REPLACE ATTR_REPLACE -}; - - -#ifndef sighandler_t -#define sighandler_t sig_t -#endif - -#ifndef ino64_t -#define ino64_t ino_t -#endif - -#ifndef EUCLEAN -#define EUCLEAN 0 -#endif - -#include <netinet/in.h> -#ifndef s6_addr16 -#define s6_addr16 __u6_addr.__u6_addr16 -#endif -#ifndef s6_addr32 -#define s6_addr32 __u6_addr.__u6_addr32 -#endif - -/* Posix dictates NAME_MAX to be used */ -# ifndef NAME_MAX -# ifdef MAXNAMLEN -# define NAME_MAX MAXNAMLEN -# else -# define NAME_MAX 255 -# endif -# endif - -#define F_GETLK64 F_GETLK -#define F_SETLK64 F_SETLK -#define F_SETLKW64 F_SETLKW - -#endif /* GF_BSD_HOST_OS */ - -#ifdef GF_DARWIN_HOST_OS - -#define UNIX_PATH_MAX 104 -#include <sys/types.h> - -#include <sys/un.h> -#include <machine/endian.h> -#include <sys/xattr.h> -#include <limits.h> - -#include <libgen.h> - - -#if __DARWIN_64_BIT_INO_T == 0 -# error '64 bit ino_t is must for GlusterFS to work, Compile with "CFLAGS=-D__DARWIN_64_BIT_INO_T"' -#endif /* __DARWIN_64_BIT_INO_T */ - - -#if __DARWIN_64_BIT_INO_T == 0 -# error '64 bit ino_t is must for GlusterFS to work, Compile with "CFLAGS=-D__DARWIN_64_BIT_INO_T"' -#endif /* __DARWIN_64_BIT_INO_T */ - -#ifndef sighandler_t -#define sighandler_t sig_t -#endif - -#ifndef EUCLEAN -#define EUCLEAN 0 -#endif - -#include <netinet/in.h> -#ifndef s6_addr16 -#define s6_addr16 __u6_addr.__u6_addr16 -#endif -#ifndef s6_addr32 -#define s6_addr32 __u6_addr.__u6_addr32 -#endif - -/* Posix dictates NAME_MAX to be used */ -# ifndef NAME_MAX -# ifdef MAXNAMLEN -# define NAME_MAX MAXNAMLEN -# else -# define NAME_MAX 255 -# endif -# endif - -#define F_GETLK64 F_GETLK -#define F_SETLK64 F_SETLK -#define F_SETLKW64 F_SETLKW - -#ifndef FTW_CONTINUE - #define FTW_CONTINUE 0 -#endif - -int32_t gf_darwin_compat_listxattr (int len, dict_t *dict, int size); -int32_t gf_darwin_compat_getxattr (const char *key, dict_t *dict); -int32_t gf_darwin_compat_setxattr (dict_t *dict); - -#endif /* GF_DARWIN_HOST_OS */ - -#ifdef GF_SOLARIS_HOST_OS - -#define UNIX_PATH_MAX 108 -#define EUCLEAN 117 - -#include <sys/un.h> -#include <limits.h> -#include <sys/stat.h> -#include <unistd.h> -#include <sys/fcntl.h> -#include <libgen.h> -#include <sys/mkdev.h> - -#ifndef lchmod -#define lchmod chmod -#endif - -#define lgetxattr(path, key, value, size) solaris_getxattr(path,key,value,size) -enum { - ATTR_CREATE = 1, -#define XATTR_CREATE ATTR_CREATE - ATTR_REPLACE = 2 -#define XATTR_REPLACE ATTR_REPLACE -}; - -/* This patch is not present in Solaris 10 and before */ -#ifndef dirfd -#define dirfd(dirp) ((dirp)->dd_fd) -#endif - -/* Posix dictates NAME_MAX to be used */ -# ifndef NAME_MAX -# ifdef MAXNAMLEN -# define NAME_MAX MAXNAMLEN -# else -# define NAME_MAX 255 -# endif -# endif - -#include <netinet/in.h> -#ifndef s6_addr16 -#define S6_ADDR16(x) ((uint16_t*) ((char*)&(x).s6_addr)) -#endif -#ifndef s6_addr32 -#define s6_addr32 _S6_un._S6_u32 -#endif - -#define lutimes(filename,times) utimes(filename,times) - -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif - -enum { - DT_UNKNOWN = 0, -# define DT_UNKNOWN DT_UNKNOWN - DT_FIFO = 1, -# define DT_FIFO DT_FIFO - DT_CHR = 2, -# define DT_CHR DT_CHR - DT_DIR = 4, -# define DT_DIR DT_DIR - DT_BLK = 6, -# define DT_BLK DT_BLK - DT_REG = 8, -# define DT_REG DT_REG - DT_LNK = 10, -# define DT_LNK DT_LNK - DT_SOCK = 12, -# define DT_SOCK DT_SOCK - DT_WHT = 14 -# define DT_WHT DT_WHT -}; - -#ifndef _PATH_MOUNTED - #define _PATH_MOUNTED "/etc/mtab" -#endif - -#ifndef O_ASYNC - #ifdef FASYNC - #define O_ASYNC FASYNC - #else - #define O_ASYNC 0 - #endif -#endif - -#ifndef FTW_CONTINUE - #define FTW_CONTINUE 0 -#endif - -int asprintf(char **string_ptr, const char *format, ...); - -int vasprintf (char **result, const char *format, va_list args); -char* strsep(char** str, const char* delims); -int solaris_listxattr(const char *path, char *list, size_t size); -int solaris_removexattr(const char *path, const char* key); -int solaris_getxattr(const char *path, const char* key, - char *value, size_t size); -int solaris_setxattr(const char *path, const char* key, const char *value, - size_t size, int flags); -int solaris_fgetxattr(int fd, const char* key, - char *value, size_t size); -int solaris_fsetxattr(int fd, const char* key, const char *value, - size_t size, int flags); -int solaris_flistxattr(int fd, char *list, size_t size); - -#endif /* GF_SOLARIS_HOST_OS */ - -#ifndef HAVE_ARGP -#include "argp.h" -#else -#include <argp.h> -#endif /* HAVE_ARGP */ - -#ifndef HAVE_STRNLEN -size_t strnlen(const char *string, size_t maxlen); -#endif /* STRNLEN */ - -#ifndef strdupa -#define strdupa(s) \ - (__extension__ \ - ({ \ - __const char *__old = (s); \ - size_t __len = strlen (__old) + 1; \ - char *__new = (char *) __builtin_alloca (__len); \ - (char *) memcpy (__new, __old, __len); \ - })) -#endif - -#define GF_DIR_ALIGN(x) (((x) + sizeof (uint64_t) - 1) & ~(sizeof (uint64_t) - 1)) - -#include <sys/types.h> -#include <dirent.h> - -static inline int32_t -dirent_size (struct dirent *entry) -{ -#ifdef GF_BSD_HOST_OS - return GF_DIR_ALIGN (24 /* FIX MEEEE!!! */ + entry->d_namlen); -#endif -#ifdef GF_DARWIN_HOST_OS - return GF_DIR_ALIGN (24 /* FIX MEEEE!!! */ + entry->d_namlen); -#endif -#ifdef GF_LINUX_HOST_OS - return GF_DIR_ALIGN (24 /* FIX MEEEE!!! */ + entry->d_reclen); -#endif -#ifdef GF_SOLARIS_HOST_OS - return GF_DIR_ALIGN (24 /* FIX MEEEE!!! */ + entry->d_reclen); -#endif -} - - -#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC -/* Linux, Solaris, Cygwin */ -#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atim.tv_nsec) -#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctim.tv_nsec) -#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtim.tv_nsec) -#define ST_ATIM_NSEC_SET(stbuf, val) ((stbuf)->st_atim.tv_nsec = (val)) -#define ST_MTIM_NSEC_SET(stbuf, val) ((stbuf)->st_mtim.tv_nsec = (val)) -#define ST_CTIM_NSEC_SET(stbuf, val) ((stbuf)->st_ctim.tv_nsec = (val)) -#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC) -/* FreeBSD, NetBSD */ -#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atimespec.tv_nsec) -#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctimespec.tv_nsec) -#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtimespec.tv_nsec) -#define ST_ATIM_NSEC_SET(stbuf, val) ((stbuf)->st_atimespec.tv_nsec = (val)) -#define ST_MTIM_NSEC_SET(stbuf, val) ((stbuf)->st_mtimespec.tv_nsec = (val)) -#define ST_CTIM_NSEC_SET(stbuf, val) ((stbuf)->st_ctimespec.tv_nsec = (val)) -#else -#define ST_ATIM_NSEC(stbuf) (0) -#define ST_CTIM_NSEC(stbuf) (0) -#define ST_MTIM_NSEC(stbuf) (0) -#define ST_ATIM_NSEC_SET(stbuf, val) do { } while (0); -#define ST_MTIM_NSEC_SET(stbuf, val) do { } while (0); -#define ST_CTIM_NSEC_SET(stbuf, val) do { } while (0); -#endif - -#endif /* __COMPAT_H__ */ diff --git a/libglusterfs/src/ctx.c b/libglusterfs/src/ctx.c new file mode 100644 index 00000000000..3d890b04ec9 --- /dev/null +++ b/libglusterfs/src/ctx.c @@ -0,0 +1,97 @@ +/* + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include <pthread.h> + +#include "glusterfs/globals.h" +#include "glusterfs/glusterfs.h" +#include "timer-wheel.h" + +glusterfs_ctx_t * +glusterfs_ctx_new() +{ + glusterfs_ctx_t *ctx = NULL; + + /* no GF_CALLOC here, gf_acct_mem_set_enable is not + yet decided at this point */ + ctx = CALLOC(1, sizeof(*ctx)); + if (!ctx) { + goto out; + } + + ctx->mem_acct_enable = gf_global_mem_acct_enable_get(); + + INIT_LIST_HEAD(&ctx->graphs); + INIT_LIST_HEAD(&ctx->mempool_list); + INIT_LIST_HEAD(&ctx->volfile_list); + + ctx->daemon_pipe[0] = -1; + ctx->daemon_pipe[1] = -1; + + ctx->log.loglevel = DEFAULT_LOG_LEVEL; + +#if defined(RUN_WITH_MEMCHECK) + ctx->cmd_args.vgtool = _gf_memcheck; +#elif defined(RUN_WITH_DRD) + ctx->cmd_args.vgtool = _gf_drd; +#else + ctx->cmd_args.vgtool = _gf_none; +#endif + + /* lock is never destroyed! */ + if (LOCK_INIT(&ctx->lock)) { + free(ctx); + ctx = NULL; + goto out; + } + + GF_ATOMIC_INIT(ctx->stats.max_dict_pairs, 0); + GF_ATOMIC_INIT(ctx->stats.total_pairs_used, 0); + GF_ATOMIC_INIT(ctx->stats.total_dicts_used, 0); +out: + return ctx; +} + +static void +glusterfs_ctx_tw_destroy(struct gf_ctx_tw *ctx_tw) +{ + if (ctx_tw->timer_wheel) + gf_tw_cleanup_timers(ctx_tw->timer_wheel); + + GF_FREE(ctx_tw); +} + +struct tvec_base * +glusterfs_ctx_tw_get(glusterfs_ctx_t *ctx) +{ + struct gf_ctx_tw *ctx_tw = NULL; + + LOCK(&ctx->lock); + { + if (ctx->tw) { + ctx_tw = GF_REF_GET(ctx->tw); + } else { + ctx_tw = GF_CALLOC(1, sizeof(struct gf_ctx_tw), + gf_common_mt_tw_ctx); + ctx_tw->timer_wheel = gf_tw_init_timers(); + GF_REF_INIT(ctx_tw, glusterfs_ctx_tw_destroy); + ctx->tw = ctx_tw; + } + } + UNLOCK(&ctx->lock); + + return ctx_tw->timer_wheel; +} + +void +glusterfs_ctx_tw_put(glusterfs_ctx_t *ctx) +{ + GF_REF_PUT(ctx->tw); +} diff --git a/libglusterfs/src/daemon.c b/libglusterfs/src/daemon.c new file mode 100644 index 00000000000..0a3e5438325 --- /dev/null +++ b/libglusterfs/src/daemon.c @@ -0,0 +1,65 @@ +/* + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include <unistd.h> +#include <stdio.h> +#include "glusterfs/daemon.h" + +int +os_daemon_return(int nochdir, int noclose) +{ + pid_t pid = -1; + int ret = -1; + FILE *ptr = NULL; + + ret = fork(); + if (ret) + return ret; + + pid = setsid(); + + if (pid == -1) { + ret = -1; + goto out; + } + + if (!nochdir) + ret = chdir("/"); + + if (!noclose) { + ptr = freopen(DEVNULLPATH, "r", stdin); + if (!ptr) + goto out; + + ptr = freopen(DEVNULLPATH, "w", stdout); + if (!ptr) + goto out; + + ptr = freopen(DEVNULLPATH, "w", stderr); + if (!ptr) + goto out; + } + + ret = 0; +out: + return ret; +} + +int +os_daemon(int nochdir, int noclose) +{ + int ret = -1; + + ret = os_daemon_return(nochdir, noclose); + if (ret <= 0) + return ret; + + _exit(0); +} diff --git a/libglusterfs/src/default-args.c b/libglusterfs/src/default-args.c new file mode 100644 index 00000000000..a0ba1cfb299 --- /dev/null +++ b/libglusterfs/src/default-args.c @@ -0,0 +1,1651 @@ +/* + Copyright (c) 2008-2015 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "glusterfs/defaults.h" + +int +args_lookup_store(default_args_t *args, loc_t *loc, dict_t *xdata) +{ + loc_copy(&args->loc, loc); + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_lookup_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + dict_t *xdata, struct iatt *postparent) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (inode) + args->inode = inode_ref(inode); + if (buf) + args->stat = *buf; + if (postparent) + args->postparent = *postparent; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_stat_store(default_args_t *args, loc_t *loc, dict_t *xdata) +{ + loc_copy(&args->loc, loc); + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_stat_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + struct iatt *buf, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (op_ret == 0) + args->stat = *buf; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_fstat_store(default_args_t *args, fd_t *fd, dict_t *xdata) +{ + if (fd) + args->fd = fd_ref(fd); + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_fstat_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + struct iatt *buf, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (buf) + args->stat = *buf; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_truncate_store(default_args_t *args, loc_t *loc, off_t off, dict_t *xdata) +{ + loc_copy(&args->loc, loc); + args->offset = off; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_truncate_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (prebuf) + args->prestat = *prebuf; + if (postbuf) + args->poststat = *postbuf; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_ftruncate_store(default_args_t *args, fd_t *fd, off_t off, dict_t *xdata) +{ + if (fd) + args->fd = fd_ref(fd); + + args->offset = off; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_ftruncate_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (prebuf) + args->prestat = *prebuf; + if (postbuf) + args->poststat = *postbuf; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_access_store(default_args_t *args, loc_t *loc, int32_t mask, dict_t *xdata) +{ + loc_copy(&args->loc, loc); + args->mask = mask; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_access_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_readlink_store(default_args_t *args, loc_t *loc, size_t size, + dict_t *xdata) +{ + loc_copy(&args->loc, loc); + args->size = size; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_readlink_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, const char *path, struct iatt *stbuf, + dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (path) + args->buf = gf_strdup(path); + if (stbuf) + args->stat = *stbuf; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_mknod_store(default_args_t *args, loc_t *loc, mode_t mode, dev_t rdev, + mode_t umask, dict_t *xdata) +{ + loc_copy(&args->loc, loc); + args->mode = mode; + args->rdev = rdev; + args->umask = umask; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_mknod_cbk_store(default_args_cbk_t *args, int op_ret, int32_t op_errno, + inode_t *inode, struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (inode) + args->inode = inode_ref(inode); + if (buf) + args->stat = *buf; + if (preparent) + args->preparent = *preparent; + if (postparent) + args->postparent = *postparent; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_mkdir_store(default_args_t *args, loc_t *loc, mode_t mode, mode_t umask, + dict_t *xdata) +{ + loc_copy(&args->loc, loc); + args->mode = mode; + args->umask = umask; + + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_mkdir_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + inode_t *inode, struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (inode) + args->inode = inode_ref(inode); + if (buf) + args->stat = *buf; + if (preparent) + args->preparent = *preparent; + if (postparent) + args->postparent = *postparent; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_unlink_store(default_args_t *args, loc_t *loc, int xflag, dict_t *xdata) +{ + loc_copy(&args->loc, loc); + args->xflag = xflag; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_unlink_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (preparent) + args->preparent = *preparent; + if (postparent) + args->postparent = *postparent; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_rmdir_store(default_args_t *args, loc_t *loc, int flags, dict_t *xdata) +{ + loc_copy(&args->loc, loc); + args->flags = flags; + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_rmdir_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + struct iatt *preparent, struct iatt *postparent, + dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (preparent) + args->preparent = *preparent; + if (postparent) + args->postparent = *postparent; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_symlink_store(default_args_t *args, const char *linkname, loc_t *loc, + mode_t umask, dict_t *xdata) +{ + args->linkname = gf_strdup(linkname); + args->umask = umask; + loc_copy(&args->loc, loc); + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_symlink_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + struct iatt *preparent, struct iatt *postparent, + dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (inode) + args->inode = inode_ref(inode); + if (buf) + args->stat = *buf; + if (preparent) + args->preparent = *preparent; + if (postparent) + args->postparent = *postparent; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_rename_store(default_args_t *args, loc_t *oldloc, loc_t *newloc, + dict_t *xdata) +{ + loc_copy(&args->loc, oldloc); + loc_copy(&args->loc2, newloc); + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_rename_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *buf, + struct iatt *preoldparent, struct iatt *postoldparent, + struct iatt *prenewparent, struct iatt *postnewparent, + dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (buf) + args->stat = *buf; + if (preoldparent) + args->preparent = *preoldparent; + if (postoldparent) + args->postparent = *postoldparent; + if (prenewparent) + args->preparent2 = *prenewparent; + if (postnewparent) + args->postparent2 = *postnewparent; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_link_store(default_args_t *args, loc_t *oldloc, loc_t *newloc, + dict_t *xdata) +{ + loc_copy(&args->loc, oldloc); + loc_copy(&args->loc2, newloc); + + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_link_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + inode_t *inode, struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (inode) + args->inode = inode_ref(inode); + if (buf) + args->stat = *buf; + if (preparent) + args->preparent = *preparent; + if (postparent) + args->postparent = *postparent; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_create_store(default_args_t *args, loc_t *loc, int32_t flags, mode_t mode, + mode_t umask, fd_t *fd, dict_t *xdata) +{ + loc_copy(&args->loc, loc); + args->flags = flags; + args->mode = mode; + args->umask = umask; + if (fd) + args->fd = fd_ref(fd); + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_create_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, fd_t *fd, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (fd) + args->fd = fd_ref(fd); + if (inode) + args->inode = inode_ref(inode); + if (buf) + args->stat = *buf; + if (preparent) + args->preparent = *preparent; + if (postparent) + args->postparent = *postparent; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_open_store(default_args_t *args, loc_t *loc, int32_t flags, fd_t *fd, + dict_t *xdata) +{ + loc_copy(&args->loc, loc); + args->flags = flags; + if (fd) + args->fd = fd_ref(fd); + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_open_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + fd_t *fd, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (fd) + args->fd = fd_ref(fd); + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_readv_store(default_args_t *args, fd_t *fd, size_t size, off_t off, + uint32_t flags, dict_t *xdata) +{ + if (fd) + args->fd = fd_ref(fd); + args->size = size; + args->offset = off; + args->flags = flags; + + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_readv_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + struct iovec *vector, int32_t count, struct iatt *stbuf, + struct iobref *iobref, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (op_ret >= 0) { + args->vector = iov_dup(vector, count); + args->count = count; + args->stat = *stbuf; + args->iobref = iobref_ref(iobref); + } + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_writev_store(default_args_t *args, fd_t *fd, struct iovec *vector, + int32_t count, off_t off, uint32_t flags, + struct iobref *iobref, dict_t *xdata) +{ + if (fd) + args->fd = fd_ref(fd); + args->vector = iov_dup(vector, count); + args->count = count; + args->offset = off; + args->flags = flags; + args->iobref = iobref_ref(iobref); + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_writev_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (op_ret >= 0) + args->poststat = *postbuf; + if (prebuf) + args->prestat = *prebuf; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_put_store(default_args_t *args, loc_t *loc, mode_t mode, mode_t umask, + uint32_t flags, struct iovec *vector, int32_t count, off_t off, + struct iobref *iobref, dict_t *xattr, dict_t *xdata) +{ + loc_copy(&args->loc, loc); + args->mode = mode; + args->umask = umask; + args->flags = flags; + args->vector = iov_dup(vector, count); + args->count = count; + args->offset = off; + args->iobref = iobref_ref(iobref); + if (xattr) + args->xattr = dict_ref(xattr); + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_put_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + inode_t *inode, struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (op_ret >= 0) + args->stat = *buf; + if (inode) + args->inode = inode_ref(inode); + if (preparent) + args->preparent = *preparent; + if (postparent) + args->postparent = *postparent; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} +int +args_flush_store(default_args_t *args, fd_t *fd, dict_t *xdata) +{ + if (fd) + args->fd = fd_ref(fd); + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_flush_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_fsync_store(default_args_t *args, fd_t *fd, int32_t datasync, + dict_t *xdata) +{ + if (fd) + args->fd = fd_ref(fd); + args->datasync = datasync; + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_fsync_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + struct iatt *prebuf, struct iatt *postbuf, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (prebuf) + args->prestat = *prebuf; + if (postbuf) + args->poststat = *postbuf; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_opendir_store(default_args_t *args, loc_t *loc, fd_t *fd, dict_t *xdata) +{ + loc_copy(&args->loc, loc); + if (fd) + args->fd = fd_ref(fd); + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_opendir_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, fd_t *fd, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (fd) + args->fd = fd_ref(fd); + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_fsyncdir_store(default_args_t *args, fd_t *fd, int32_t datasync, + dict_t *xdata) +{ + if (fd) + args->fd = fd_ref(fd); + args->datasync = datasync; + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} +int +args_fsyncdir_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_statfs_store(default_args_t *args, loc_t *loc, dict_t *xdata) +{ + loc_copy(&args->loc, loc); + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_statfs_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct statvfs *buf, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (op_ret == 0) + args->statvfs = *buf; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_setxattr_store(default_args_t *args, loc_t *loc, dict_t *dict, + int32_t flags, dict_t *xdata) +{ + loc_copy(&args->loc, loc); + /* TODO */ + if (dict) + args->xattr = dict_ref(dict); + args->flags = flags; + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_setxattr_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_getxattr_store(default_args_t *args, loc_t *loc, const char *name, + dict_t *xdata) +{ + loc_copy(&args->loc, loc); + + if (name) + args->name = gf_strdup(name); + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_getxattr_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *dict, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (dict) + args->xattr = dict_ref(dict); + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_fsetxattr_store(default_args_t *args, fd_t *fd, dict_t *dict, + int32_t flags, dict_t *xdata) +{ + args->fd = fd_ref(fd); + + if (dict) + args->xattr = dict_ref(dict); + args->flags = flags; + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_fsetxattr_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_fgetxattr_store(default_args_t *args, fd_t *fd, const char *name, + dict_t *xdata) +{ + args->fd = fd_ref(fd); + + if (name) + args->name = gf_strdup(name); + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_fgetxattr_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *dict, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (dict) + args->xattr = dict_ref(dict); + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_removexattr_store(default_args_t *args, loc_t *loc, const char *name, + dict_t *xdata) +{ + loc_copy(&args->loc, loc); + args->name = gf_strdup(name); + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_removexattr_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_fremovexattr_store(default_args_t *args, fd_t *fd, const char *name, + dict_t *xdata) +{ + args->fd = fd_ref(fd); + args->name = gf_strdup(name); + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_fremovexattr_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_lk_store(default_args_t *args, fd_t *fd, int32_t cmd, + struct gf_flock *lock, dict_t *xdata) +{ + if (fd) + args->fd = fd_ref(fd); + args->cmd = cmd; + args->lock = *lock; + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_lk_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + struct gf_flock *lock, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (op_ret == 0) + args->lock = *lock; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_inodelk_store(default_args_t *args, const char *volume, loc_t *loc, + int32_t cmd, struct gf_flock *lock, dict_t *xdata) +{ + if (volume) + args->volume = gf_strdup(volume); + + loc_copy(&args->loc, loc); + args->cmd = cmd; + args->lock = *lock; + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_inodelk_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_finodelk_store(default_args_t *args, const char *volume, fd_t *fd, + int32_t cmd, struct gf_flock *lock, dict_t *xdata) +{ + if (fd) + args->fd = fd_ref(fd); + + if (volume) + args->volume = gf_strdup(volume); + + args->cmd = cmd; + args->lock = *lock; + + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_finodelk_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_entrylk_store(default_args_t *args, const char *volume, loc_t *loc, + const char *name, entrylk_cmd cmd, entrylk_type type, + dict_t *xdata) +{ + if (volume) + args->volume = gf_strdup(volume); + + loc_copy(&args->loc, loc); + + args->entrylkcmd = cmd; + args->entrylktype = type; + + if (name) + args->name = gf_strdup(name); + + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_entrylk_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_fentrylk_store(default_args_t *args, const char *volume, fd_t *fd, + const char *name, entrylk_cmd cmd, entrylk_type type, + dict_t *xdata) +{ + if (volume) + args->volume = gf_strdup(volume); + + if (fd) + args->fd = fd_ref(fd); + args->entrylkcmd = cmd; + args->entrylktype = type; + if (name) + args->name = gf_strdup(name); + + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_fentrylk_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_readdirp_store(default_args_t *args, fd_t *fd, size_t size, off_t off, + dict_t *xdata) +{ + args->fd = fd_ref(fd); + args->size = size; + args->offset = off; + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_readdirp_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, gf_dirent_t *entries, dict_t *xdata) +{ + gf_dirent_t *stub_entry = NULL, *entry = NULL; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (op_ret > 0) { + list_for_each_entry(entry, &entries->list, list) + { + stub_entry = gf_dirent_for_name(entry->d_name); + if (!stub_entry) + goto out; + stub_entry->d_off = entry->d_off; + stub_entry->d_ino = entry->d_ino; + stub_entry->d_stat = entry->d_stat; + stub_entry->d_type = entry->d_type; + if (entry->inode) + stub_entry->inode = inode_ref(entry->inode); + if (entry->dict) + stub_entry->dict = dict_ref(entry->dict); + list_add_tail(&stub_entry->list, &args->entries.list); + } + } + if (xdata) + args->xdata = dict_ref(xdata); +out: + return 0; +} + +int +args_readdir_store(default_args_t *args, fd_t *fd, size_t size, off_t off, + dict_t *xdata) +{ + args->fd = fd_ref(fd); + args->size = size; + args->offset = off; + + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_readdir_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, gf_dirent_t *entries, dict_t *xdata) +{ + gf_dirent_t *stub_entry = NULL, *entry = NULL; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (op_ret > 0) { + list_for_each_entry(entry, &entries->list, list) + { + stub_entry = gf_dirent_for_name(entry->d_name); + if (!stub_entry) + goto out; + stub_entry->d_off = entry->d_off; + stub_entry->d_ino = entry->d_ino; + stub_entry->d_type = entry->d_type; + list_add_tail(&stub_entry->list, &args->entries.list); + } + } + if (xdata) + args->xdata = dict_ref(xdata); +out: + return 0; +} + +int +args_rchecksum_store(default_args_t *args, fd_t *fd, off_t offset, int32_t len, + dict_t *xdata) +{ + args->fd = fd_ref(fd); + args->offset = offset; + args->size = len; + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_rchecksum_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, uint32_t weak_checksum, + uint8_t *strong_checksum, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (op_ret >= 0) { + args->weak_checksum = weak_checksum; + args->strong_checksum = gf_memdup(strong_checksum, + SHA256_DIGEST_LENGTH); + } + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_xattrop_store(default_args_t *args, loc_t *loc, gf_xattrop_flags_t optype, + dict_t *xattr, dict_t *xdata) +{ + loc_copy(&args->loc, loc); + + args->optype = optype; + args->xattr = dict_ref(xattr); + + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_xattrop_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xattr, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xattr) + args->xattr = dict_ref(xattr); + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_fxattrop_store(default_args_t *args, fd_t *fd, gf_xattrop_flags_t optype, + dict_t *xattr, dict_t *xdata) +{ + args->fd = fd_ref(fd); + + args->optype = optype; + args->xattr = dict_ref(xattr); + + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_fxattrop_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xattr, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xattr) + args->xattr = dict_ref(xattr); + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_setattr_store(default_args_t *args, loc_t *loc, struct iatt *stbuf, + int32_t valid, dict_t *xdata) +{ + loc_copy(&args->loc, loc); + + if (stbuf) + args->stat = *stbuf; + + args->valid = valid; + + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_setattr_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *statpre, + struct iatt *statpost, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (statpre) + args->prestat = *statpre; + if (statpost) + args->poststat = *statpost; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_fsetattr_store(default_args_t *args, fd_t *fd, struct iatt *stbuf, + int32_t valid, dict_t *xdata) +{ + if (fd) + args->fd = fd_ref(fd); + + if (stbuf) + args->stat = *stbuf; + + args->valid = valid; + + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} +int +args_fsetattr_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *statpre, + struct iatt *statpost, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (statpre) + args->prestat = *statpre; + if (statpost) + args->poststat = *statpost; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_fallocate_store(default_args_t *args, fd_t *fd, int32_t mode, off_t offset, + size_t len, dict_t *xdata) +{ + if (fd) + args->fd = fd_ref(fd); + + args->flags = mode; + args->offset = offset; + args->size = len; + + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_fallocate_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *statpre, + struct iatt *statpost, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (statpre) + args->prestat = *statpre; + if (statpost) + args->poststat = *statpost; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_discard_store(default_args_t *args, fd_t *fd, off_t offset, size_t len, + dict_t *xdata) +{ + if (fd) + args->fd = fd_ref(fd); + + args->offset = offset; + args->size = len; + + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_discard_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *statpre, + struct iatt *statpost, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (statpre) + args->prestat = *statpre; + if (statpost) + args->poststat = *statpost; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_zerofill_store(default_args_t *args, fd_t *fd, off_t offset, off_t len, + dict_t *xdata) +{ + if (fd) + args->fd = fd_ref(fd); + + args->offset = offset; + args->size = len; + + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_zerofill_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *statpre, + struct iatt *statpost, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (statpre) + args->prestat = *statpre; + if (statpost) + args->poststat = *statpost; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_ipc_store(default_args_t *args, int32_t op, dict_t *xdata) +{ + args->cmd = op; + + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_ipc_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_seek_store(default_args_t *args, fd_t *fd, off_t offset, + gf_seek_what_t what, dict_t *xdata) +{ + if (fd) + args->fd = fd_ref(fd); + + args->offset = offset; + args->what = what; + + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_seek_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + off_t offset, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + args->offset = offset; + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_getactivelk_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, lock_migration_info_t *locklist, + dict_t *xdata) +{ + lock_migration_info_t *stub_entry = NULL, *entry = NULL; + int ret = 0; + + args->op_ret = op_ret; + args->op_errno = op_errno; + /*op_ret needs to carry the number of locks present in the list*/ + if (op_ret > 0) { + list_for_each_entry(entry, &locklist->list, list) + { + stub_entry = GF_CALLOC(1, sizeof(*stub_entry), gf_common_mt_char); + if (!stub_entry) { + ret = -1; + goto out; + } + + INIT_LIST_HEAD(&stub_entry->list); + stub_entry->flock = entry->flock; + + stub_entry->lk_flags = entry->lk_flags; + + stub_entry->client_uid = gf_strdup(entry->client_uid); + if (!stub_entry->client_uid) { + GF_FREE(stub_entry); + ret = -1; + goto out; + } + + list_add_tail(&stub_entry->list, &args->locklist.list); + } + } + + if (xdata) + args->xdata = dict_ref(xdata); +out: + return ret; +} + +int +args_setactivelk_store(default_args_t *args, loc_t *loc, + lock_migration_info_t *locklist, dict_t *xdata) +{ + lock_migration_info_t *stub_entry = NULL, *entry = NULL; + int ret = 0; + + list_for_each_entry(entry, &locklist->list, list) + { + stub_entry = GF_CALLOC(1, sizeof(*stub_entry), gf_common_mt_lock_mig); + if (!stub_entry) { + ret = -1; + goto out; + } + + INIT_LIST_HEAD(&stub_entry->list); + stub_entry->flock = entry->flock; + + stub_entry->lk_flags = entry->lk_flags; + + stub_entry->client_uid = gf_strdup(entry->client_uid); + if (!stub_entry->client_uid) { + GF_FREE(stub_entry); + ret = -1; + goto out; + } + + list_add_tail(&stub_entry->list, &args->locklist.list); + } + + loc_copy(&args->loc, loc); + + if (xdata) + args->xdata = dict_ref(xdata); + +out: + return ret; +} + +void +args_lease_store(default_args_t *args, loc_t *loc, struct gf_lease *lease, + dict_t *xdata) +{ + loc_copy(&args->loc, loc); + args->lease = *lease; + + if (xdata) + args->xdata = dict_ref(xdata); + + return; +} + +void +args_lease_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + struct gf_lease *lease, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (op_ret == 0) + args->lease = *lease; + if (xdata) + args->xdata = dict_ref(xdata); +} + +int +args_icreate_store(default_args_t *args, loc_t *loc, mode_t mode, dict_t *xdata) +{ + loc_copy(&args->loc, loc); + args->mode = mode; + + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_namelink_store(default_args_t *args, loc_t *loc, dict_t *xdata) +{ + loc_copy(&args->loc, loc); + + if (xdata) + args->xdata = dict_ref(xdata); + return 0; +} + +int +args_copy_file_range_store(default_args_t *args, fd_t *fd_in, off64_t off_in, + fd_t *fd_out, off64_t off_out, size_t len, + uint32_t flags, dict_t *xdata) +{ + if (fd_in) + args->fd = fd_ref(fd_in); + if (fd_out) + args->fd_dst = fd_ref(fd_out); + args->size = len; + args->off_in = off_in; + args->off_out = off_out; + args->flags = flags; + + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +int +args_copy_file_range_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *stbuf, + struct iatt *prebuf_dst, + struct iatt *postbuf_dst, dict_t *xdata) +{ + args->op_ret = op_ret; + args->op_errno = op_errno; + if (op_ret >= 0) { + if (postbuf_dst) + args->poststat = *postbuf_dst; + if (prebuf_dst) + args->prestat = *prebuf_dst; + if (stbuf) + args->stat = *stbuf; + } + if (xdata) + args->xdata = dict_ref(xdata); + + return 0; +} + +void +args_cbk_wipe(default_args_cbk_t *args_cbk) +{ + if (!args_cbk) + return; + if (args_cbk->inode) + inode_unref(args_cbk->inode); + + GF_FREE((char *)args_cbk->buf); + + GF_FREE(args_cbk->vector); + + if (args_cbk->iobref) + iobref_unref(args_cbk->iobref); + + if (args_cbk->fd) + fd_unref(args_cbk->fd); + + if (args_cbk->xattr) + dict_unref(args_cbk->xattr); + + GF_FREE(args_cbk->strong_checksum); + + if (args_cbk->xdata) + dict_unref(args_cbk->xdata); + + if (!list_empty(&args_cbk->entries.list)) + gf_dirent_free(&args_cbk->entries); +} + +void +args_wipe(default_args_t *args) +{ + if (!args) + return; + + loc_wipe(&args->loc); + + loc_wipe(&args->loc2); + + if (args->fd) + fd_unref(args->fd); + + GF_FREE((char *)args->linkname); + + GF_FREE(args->vector); + + if (args->iobref) + iobref_unref(args->iobref); + + if (args->xattr) + dict_unref(args->xattr); + + if (args->xdata) + dict_unref(args->xdata); + + GF_FREE((char *)args->name); + + GF_FREE((char *)args->volume); +} + +void +args_cbk_init(default_args_cbk_t *args_cbk) +{ + INIT_LIST_HEAD(&args_cbk->entries); +} diff --git a/libglusterfs/src/defaults-tmpl.c b/libglusterfs/src/defaults-tmpl.c new file mode 100644 index 00000000000..3cf707f42aa --- /dev/null +++ b/libglusterfs/src/defaults-tmpl.c @@ -0,0 +1,247 @@ +/* + Copyright (c) 2008-2015 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +/* libglusterfs/src/defaults.c: + This file contains functions, which are used to fill the 'fops', 'cbk' + structures in the xlator structures, if they are not written. Here, all the + function calls are plainly forwarded to the first child of the xlator, and + all the *_cbk function does plain STACK_UNWIND of the frame, and returns. + + This function also implements *_resume () functions, which does same + operation as a fop(). + + All the functions are plain enough to understand. +*/ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "glusterfs/xlator.h" +#include "glusterfs/defaults.h" + +#pragma generate + +struct xlator_fops _default_fops = { + .create = default_create, + .open = default_open, + .stat = default_stat, + .readlink = default_readlink, + .mknod = default_mknod, + .mkdir = default_mkdir, + .unlink = default_unlink, + .rmdir = default_rmdir, + .symlink = default_symlink, + .rename = default_rename, + .link = default_link, + .truncate = default_truncate, + .readv = default_readv, + .writev = default_writev, + .statfs = default_statfs, + .flush = default_flush, + .fsync = default_fsync, + .setxattr = default_setxattr, + .getxattr = default_getxattr, + .fsetxattr = default_fsetxattr, + .fgetxattr = default_fgetxattr, + .removexattr = default_removexattr, + .fremovexattr = default_fremovexattr, + .opendir = default_opendir, + .readdir = default_readdir, + .readdirp = default_readdirp, + .fsyncdir = default_fsyncdir, + .access = default_access, + .ftruncate = default_ftruncate, + .fstat = default_fstat, + .lk = default_lk, + .inodelk = default_inodelk, + .finodelk = default_finodelk, + .entrylk = default_entrylk, + .fentrylk = default_fentrylk, + .lookup = default_lookup, + .rchecksum = default_rchecksum, + .xattrop = default_xattrop, + .fxattrop = default_fxattrop, + .setattr = default_setattr, + .fsetattr = default_fsetattr, + .fallocate = default_fallocate, + .discard = default_discard, + .zerofill = default_zerofill, + .ipc = default_ipc, + .seek = default_seek, + + .getspec = default_getspec, + .getactivelk = default_getactivelk, + .setactivelk = default_setactivelk, + .put = default_put, + .icreate = default_icreate, + .namelink = default_namelink, + .copy_file_range = default_copy_file_range, +}; +struct xlator_fops *default_fops = &_default_fops; + +/* + * Remaining functions don't follow the fop calling conventions, so they're + * not generated. + */ + +int32_t +default_forget(xlator_t *this, inode_t *inode) +{ + gf_log_callingfn(this->name, GF_LOG_DEBUG, + "xlator does not " + "implement forget_cbk"); + return 0; +} + +int32_t +default_releasedir(xlator_t *this, fd_t *fd) +{ + gf_log_callingfn(this->name, GF_LOG_DEBUG, + "xlator does not " + "implement releasedir_cbk"); + return 0; +} + +int32_t +default_release(xlator_t *this, fd_t *fd) +{ + gf_log_callingfn(this->name, GF_LOG_DEBUG, + "xlator does not " + "implement release_cbk"); + return 0; +} + +/* notify */ +int +default_notify(xlator_t *this, int32_t event, void *data, ...) +{ + GF_UNUSED int ret = 0; + xlator_t *victim = data; + + glusterfs_graph_t *graph = NULL; + + GF_VALIDATE_OR_GOTO("notify", this, out); + graph = this->graph; + GF_VALIDATE_OR_GOTO(this->name, graph, out); + + switch (event) { + case GF_EVENT_PARENT_UP: + case GF_EVENT_PARENT_DOWN: { + xlator_list_t *list = this->children; + + while (list) { + if (victim && victim->cleanup_starting) + xlator_notify(list->xlator, event, victim); + else + xlator_notify(list->xlator, event, this); + list = list->next; + } + } break; + case GF_EVENT_CHILD_CONNECTING: + case GF_EVENT_CHILD_DOWN: + case GF_EVENT_CHILD_UP: + case GF_EVENT_AUTH_FAILED: { + xlator_list_t *parent = this->parents; + + /* + * Handle case of CHILD_* & AUTH_FAILED event specially, send + * it to fuse. + */ + if (!parent && this->ctx && this->ctx->master) { + xlator_notify(this->ctx->master, event, this->graph, NULL); + } + + while (parent) { + if (parent->xlator->init_succeeded) + xlator_notify(parent->xlator, event, this, NULL); + parent = parent->next; + } + + if (event == GF_EVENT_CHILD_DOWN && + !(this->ctx && this->ctx->master) && (graph->top == this)) { + /* Make sure this is not a daemon with master xlator */ + pthread_mutex_lock(&graph->mutex); + { + if (graph->parent_down == + graph_total_client_xlator(graph)) { + graph->used = 0; + pthread_cond_broadcast(&graph->child_down_cond); + } + } + pthread_mutex_unlock(&graph->mutex); + } + } break; + case GF_EVENT_UPCALL: { + xlator_list_t *parent = this->parents; + + if (!parent && this->ctx && this->ctx->master) + xlator_notify(this->ctx->master, event, data, NULL); + + while (parent) { + if (parent->xlator->init_succeeded) + xlator_notify(parent->xlator, event, data, NULL); + parent = parent->next; + } + } break; + case GF_EVENT_CHILD_PING: { + xlator_list_t *parent = this->parents; + + while (parent) { + if (parent->xlator->init_succeeded) + XLATOR_NOTIFY(ret, parent->xlator, event, this, data); + parent = parent->next; + } + } break; + case GF_EVENT_CLEANUP: { + xlator_list_t *list = this->children; + + while (list) { + xlator_notify(list->xlator, event, this); + list = list->next; + } + } break; + + default: { + xlator_list_t *parent = this->parents; + + while (parent) { + if (parent->xlator->init_succeeded) + xlator_notify(parent->xlator, event, this, NULL); + parent = parent->next; + } + } + /* + * Apparently our picky-about-everything else coding standard allows + * adjacent same-indendation-level close braces. Clearly it has + * nothing to do with readability. + */ + } +out: + return 0; +} + +int32_t +default_mem_acct_init(xlator_t *this) +{ + int ret = -1; + + ret = xlator_mem_acct_init(this, gf_common_mt_end); + + return ret; +} + +void +default_fini(xlator_t *this) +{ + if (this && this->private) + GF_FREE(this->private); +} diff --git a/libglusterfs/src/defaults.c b/libglusterfs/src/defaults.c deleted file mode 100644 index 5aa0fad8937..00000000000 --- a/libglusterfs/src/defaults.c +++ /dev/null @@ -1,1339 +0,0 @@ -/* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -/* libglusterfs/src/defaults.c: - This file contains functions, which are used to fill the 'fops' and 'mops' - structures in the xlator structures, if they are not written. Here, all the - function calls are plainly forwared to the first child of the xlator, and - all the *_cbk function does plain STACK_UNWIND of the frame, and returns. - - All the functions are plain enough to understand. -*/ - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include "xlator.h" - -static int32_t -default_lookup_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - dict_t *dict, - struct iatt *postparent) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - inode, - buf, - dict, - postparent); - return 0; -} - -int32_t -default_lookup (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - dict_t *xattr_req) -{ - STACK_WIND (frame, - default_lookup_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->lookup, - loc, - xattr_req); - return 0; -} - - -int32_t -default_forget (xlator_t *this, - inode_t *inode) -{ - return 0; -} - -static int32_t -default_stat_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *buf) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - buf); - return 0; -} - -int32_t -default_stat (call_frame_t *frame, - xlator_t *this, - loc_t *loc) -{ - STACK_WIND (frame, - default_stat_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->stat, - loc); - return 0; -} - -int32_t -default_truncate_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *prebuf, - struct iatt *postbuf) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - prebuf, - postbuf); - return 0; -} - -int32_t -default_truncate (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - off_t offset) -{ - STACK_WIND (frame, - default_truncate_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->truncate, - loc, - offset); - return 0; -} - -static int32_t -default_ftruncate_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *prebuf, - struct iatt *postbuf) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - prebuf, - postbuf); - return 0; -} - -int32_t -default_ftruncate (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - off_t offset) -{ - STACK_WIND (frame, - default_ftruncate_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->ftruncate, - fd, - offset); - return 0; -} - -int32_t -default_access_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno) -{ - STACK_UNWIND (frame, - op_ret, - op_errno); - return 0; -} - -int32_t -default_access (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - int32_t mask) -{ - STACK_WIND (frame, - default_access_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->access, - loc, - mask); - return 0; -} - - -int32_t -default_readlink_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - const char *path, - struct iatt *buf) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - path, - buf); - return 0; -} - -int32_t -default_readlink (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - size_t size) -{ - STACK_WIND (frame, - default_readlink_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->readlink, - loc, - size); - return 0; -} - - -int32_t -default_mknod_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - inode, - buf, - preparent, - postparent); - return 0; -} - - -int -default_mknod (call_frame_t *frame, xlator_t *this, - loc_t *loc, mode_t mode, dev_t rdev, dict_t *parms) -{ - STACK_WIND (frame, default_mknod_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->mknod, - loc, mode, rdev, parms); - return 0; -} - -int32_t -default_mkdir_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - inode, - buf, - preparent, - postparent); - return 0; -} - - -int -default_mkdir (call_frame_t *frame, xlator_t *this, - loc_t *loc, mode_t mode, dict_t *params) -{ - STACK_WIND (frame, default_mkdir_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->mkdir, - loc, mode, params); - return 0; -} - -int32_t -default_unlink_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *preparent, - struct iatt *postparent) -{ - STACK_UNWIND (frame, op_ret, op_errno, preparent, postparent); - return 0; -} - -int32_t -default_unlink (call_frame_t *frame, - xlator_t *this, - loc_t *loc) -{ - STACK_WIND (frame, - default_unlink_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->unlink, - loc); - return 0; -} - -int32_t -default_rmdir_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *preparent, - struct iatt *postparent) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - preparent, - postparent); - return 0; -} - -int32_t -default_rmdir (call_frame_t *frame, - xlator_t *this, - loc_t *loc) -{ - STACK_WIND (frame, - default_rmdir_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->rmdir, - loc); - return 0; -} - - -int32_t -default_symlink_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent) -{ - STACK_UNWIND (frame, op_ret, op_errno, inode, buf, preparent, - postparent); - return 0; -} - - -int -default_symlink (call_frame_t *frame, xlator_t *this, - const char *linkpath, loc_t *loc, dict_t *params) -{ - STACK_WIND (frame, default_symlink_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->symlink, - linkpath, loc, params); - return 0; -} - - -int32_t -default_rename_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *buf, - struct iatt *preoldparent, - struct iatt *postoldparent, - struct iatt *prenewparent, - struct iatt *postnewparent) -{ - STACK_UNWIND (frame, op_ret, op_errno, buf, preoldparent, postoldparent, - prenewparent, postnewparent); - return 0; -} - -int32_t -default_rename (call_frame_t *frame, - xlator_t *this, - loc_t *oldloc, - loc_t *newloc) -{ - STACK_WIND (frame, - default_rename_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->rename, - oldloc, newloc); - return 0; -} - - -int32_t -default_link_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent) -{ - STACK_UNWIND (frame, op_ret, op_errno, inode, buf, preparent, - postparent); - return 0; -} - -int32_t -default_link (call_frame_t *frame, - xlator_t *this, - loc_t *oldloc, - loc_t *newloc) -{ - STACK_WIND (frame, - default_link_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->link, - oldloc, newloc); - return 0; -} - - -int32_t -default_create_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - fd_t *fd, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent) -{ - STACK_UNWIND (frame, op_ret, op_errno, fd, inode, buf, preparent, - postparent); - return 0; -} - -int32_t -default_create (call_frame_t *frame, xlator_t *this, - loc_t *loc, int32_t flags, mode_t mode, - fd_t *fd, dict_t *params) -{ - STACK_WIND (frame, default_create_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->create, - loc, flags, mode, fd, params); - return 0; -} - -int32_t -default_open_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - fd_t *fd) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - fd); - return 0; -} - -int32_t -default_open (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - int32_t flags, fd_t *fd, - int32_t wbflags) -{ - STACK_WIND (frame, - default_open_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->open, - loc, flags, fd, wbflags); - return 0; -} - -int32_t -default_readv_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iovec *vector, - int32_t count, - struct iatt *stbuf, - struct iobref *iobref) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - vector, - count, - stbuf, - iobref); - return 0; -} - -int32_t -default_readv (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - size_t size, - off_t offset) -{ - STACK_WIND (frame, - default_readv_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->readv, - fd, - size, - offset); - return 0; -} - - -int32_t -default_writev_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *prebuf, - struct iatt *postbuf) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - prebuf, - postbuf); - return 0; -} - -int32_t -default_writev (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - struct iovec *vector, - int32_t count, - off_t off, - struct iobref *iobref) -{ - STACK_WIND (frame, - default_writev_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->writev, - fd, - vector, - count, - off, - iobref); - return 0; -} - -static int32_t -default_flush_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno) -{ - STACK_UNWIND (frame, - op_ret, - op_errno); - return 0; -} - -int32_t -default_flush (call_frame_t *frame, - xlator_t *this, - fd_t *fd) -{ - STACK_WIND (frame, - default_flush_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->flush, - fd); - return 0; -} - - -static int32_t -default_fsync_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *prebuf, - struct iatt *postbuf) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - prebuf, - postbuf); - return 0; -} - -int32_t -default_fsync (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - int32_t flags) -{ - STACK_WIND (frame, - default_fsync_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->fsync, - fd, - flags); - return 0; -} - -static int32_t -default_fstat_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *buf) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - buf); - return 0; -} - -int32_t -default_fstat (call_frame_t *frame, - xlator_t *this, - fd_t *fd) -{ - STACK_WIND (frame, - default_fstat_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->fstat, - fd); - return 0; -} - -int32_t -default_opendir_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - fd_t *fd) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - fd); - return 0; -} - -int32_t -default_opendir (call_frame_t *frame, - xlator_t *this, - loc_t *loc, fd_t *fd) -{ - STACK_WIND (frame, - default_opendir_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->opendir, - loc, fd); - return 0; -} - -static int32_t -default_fsyncdir_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno) -{ - STACK_UNWIND (frame, - op_ret, - op_errno); - return 0; -} - -int32_t -default_fsyncdir (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - int32_t flags) -{ - STACK_WIND (frame, - default_fsyncdir_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->fsyncdir, - fd, - flags); - return 0; -} - - -static int32_t -default_statfs_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct statvfs *buf) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - buf); - return 0; -} - -int32_t -default_statfs (call_frame_t *frame, - xlator_t *this, - loc_t *loc) -{ - STACK_WIND (frame, - default_statfs_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->statfs, - loc); - return 0; -} - - -static int32_t -default_setxattr_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno) -{ - STACK_UNWIND (frame, - op_ret, - op_errno); - return 0; -} - -int32_t -default_setxattr (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - dict_t *dict, - int32_t flags) -{ - STACK_WIND (frame, - default_setxattr_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->setxattr, - loc, - dict, - flags); - return 0; -} - - -static int32_t -default_fsetxattr_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno) -{ - STACK_UNWIND (frame, - op_ret, - op_errno); - return 0; -} - -int32_t -default_fsetxattr (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - dict_t *dict, - int32_t flags) -{ - STACK_WIND (frame, - default_fsetxattr_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->fsetxattr, - fd, - dict, - flags); - return 0; -} - - -static int32_t -default_fgetxattr_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - dict_t *dict) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - dict); - return 0; -} - - -int32_t -default_fgetxattr (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - const char *name) -{ - STACK_WIND (frame, - default_fgetxattr_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->fgetxattr, - fd, - name); - return 0; -} - -static int32_t -default_getxattr_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - dict_t *dict) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - dict); - return 0; -} - -int32_t -default_getxattr (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - const char *name) -{ - STACK_WIND (frame, - default_getxattr_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->getxattr, - loc, - name); - return 0; -} - -int32_t -default_xattrop_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - dict_t *dict) -{ - STACK_UNWIND (frame, op_ret, op_errno, dict); - return 0; -} - -int32_t -default_xattrop (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - gf_xattrop_flags_t flags, - dict_t *dict) -{ - STACK_WIND (frame, - default_xattrop_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->xattrop, - loc, - flags, - dict); - return 0; -} - -int32_t -default_fxattrop_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - dict_t *dict) -{ - STACK_UNWIND (frame, op_ret, op_errno, dict); - return 0; -} - -int32_t -default_fxattrop (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - gf_xattrop_flags_t flags, - dict_t *dict) -{ - STACK_WIND (frame, - default_fxattrop_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->fxattrop, - fd, - flags, - dict); - return 0; -} - - -static int32_t -default_removexattr_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno) -{ - STACK_UNWIND (frame, - op_ret, - op_errno); - return 0; -} - -int32_t -default_removexattr (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - const char *name) -{ - STACK_WIND (frame, - default_removexattr_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->removexattr, - loc, - name); - return 0; -} - -static int32_t -default_lk_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct flock *lock) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - lock); - return 0; -} - -int32_t -default_lk (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - int32_t cmd, - struct flock *lock) -{ - STACK_WIND (frame, - default_lk_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->lk, - fd, - cmd, - lock); - return 0; -} - - -static int32_t -default_inodelk_cbk (call_frame_t *frame, void *cookie, - xlator_t *this, int32_t op_ret, int32_t op_errno) - -{ - STACK_UNWIND (frame, op_ret, op_errno); - return 0; -} - - -int32_t -default_inodelk (call_frame_t *frame, xlator_t *this, - const char *volume, loc_t *loc, int32_t cmd, - struct flock *lock) -{ - STACK_WIND (frame, - default_inodelk_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->inodelk, - volume, loc, cmd, lock); - return 0; -} - - -static int32_t -default_finodelk_cbk (call_frame_t *frame, void *cookie, - xlator_t *this, int32_t op_ret, int32_t op_errno) - -{ - STACK_UNWIND (frame, op_ret, op_errno); - return 0; -} - - -int32_t -default_finodelk (call_frame_t *frame, xlator_t *this, - const char *volume, fd_t *fd, int32_t cmd, struct flock *lock) -{ - STACK_WIND (frame, - default_finodelk_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->finodelk, - volume, fd, cmd, lock); - return 0; -} - - -static int32_t -default_entrylk_cbk (call_frame_t *frame, void *cookie, - xlator_t *this, int32_t op_ret, int32_t op_errno) - -{ - STACK_UNWIND (frame, op_ret, op_errno); - return 0; -} - -int32_t -default_entrylk (call_frame_t *frame, xlator_t *this, - const char *volume, loc_t *loc, const char *basename, - entrylk_cmd cmd, entrylk_type type) -{ - STACK_WIND (frame, default_entrylk_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->entrylk, - volume, loc, basename, cmd, type); - return 0; -} - -static int32_t -default_fentrylk_cbk (call_frame_t *frame, void *cookie, - xlator_t *this, int32_t op_ret, int32_t op_errno) - -{ - STACK_UNWIND (frame, op_ret, op_errno); - return 0; -} - -int32_t -default_fentrylk (call_frame_t *frame, xlator_t *this, - const char *volume, fd_t *fd, const char *basename, - entrylk_cmd cmd, entrylk_type type) -{ - STACK_WIND (frame, default_fentrylk_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->fentrylk, - volume, fd, basename, cmd, type); - return 0; -} - - -/* Management operations */ - -static 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) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - spec_data); - return 0; -} - - -int32_t -default_getspec (call_frame_t *frame, - xlator_t *this, - const char *key, - int32_t flags) -{ - STACK_WIND (frame, - default_getspec_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->getspec, - key, flags); - return 0; -} - -static int32_t -default_rchecksum_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - uint32_t weak_checksum, - uint8_t *strong_checksum) -{ - STACK_UNWIND (frame, - op_ret, - op_errno, - weak_checksum, - strong_checksum); - return 0; -} - - -int32_t -default_rchecksum (call_frame_t *frame, - xlator_t *this, - fd_t *fd, off_t offset, - int32_t len) -{ - STACK_WIND (frame, - default_rchecksum_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->rchecksum, - fd, offset, len); - return 0; -} - - -int32_t -default_readdir_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - gf_dirent_t *entries) -{ - STACK_UNWIND (frame, op_ret, op_errno, entries); - return 0; -} - - -int32_t -default_readdirp_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - gf_dirent_t *entries) -{ - STACK_UNWIND (frame, op_ret, op_errno, entries); - return 0; -} - -int32_t -default_readdir (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - size_t size, - off_t off) -{ - STACK_WIND (frame, - default_readdir_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->readdir, - fd, size, off); - return 0; -} - - -int32_t -default_readdirp (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - size_t size, - off_t off) -{ - STACK_WIND (frame, - default_readdirp_cbk, - FIRST_CHILD(this), - FIRST_CHILD(this)->fops->readdirp, - fd, size, off); - return 0; -} - - -/* notify */ -int -default_notify (xlator_t *this, int32_t event, void *data, ...) -{ - switch (event) - { - case GF_EVENT_PARENT_UP: - { - xlator_list_t *list = this->children; - - while (list) { - xlator_notify (list->xlator, event, this); - list = list->next; - } - } - break; - case GF_EVENT_CHILD_CONNECTING: - case GF_EVENT_CHILD_UP: - { - xlator_list_t *parent = this->parents; - /* Handle the case of CHILD_UP specially, send it to fuse */ - if (!parent && this->ctx && this->ctx->master) - xlator_notify (this->ctx->master, event, this->graph, NULL); - - while (parent) { - if (parent->xlator->init_succeeded) - xlator_notify (parent->xlator, event, - this, NULL); - parent = parent->next; - } - } - break; - case GF_EVENT_CHILD_DOWN: - default: - { - xlator_list_t *parent = this->parents; - while (parent) { - if (parent->xlator->init_succeeded) - xlator_notify (parent->xlator, event, - this, NULL); - parent = parent->next; - } - } - } - - return 0; -} - -int32_t -default_releasedir (xlator_t *this, - fd_t *fd) -{ - return 0; -} - -int32_t -default_release (xlator_t *this, - fd_t *fd) -{ - return 0; -} - -int32_t -default_setattr_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *statpre, - struct iatt *statpost) -{ - STACK_UNWIND (frame, op_ret, op_errno, statpre, statpost); - return 0; -} - -int32_t -default_setattr (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - struct iatt *stbuf, - int32_t valid) -{ - STACK_WIND (frame, - default_setattr_cbk, - FIRST_CHILD (this), - FIRST_CHILD (this)->fops->setattr, - loc, stbuf, valid); - return 0; -} - -int32_t -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) -{ - STACK_UNWIND (frame, op_ret, op_errno, statpre, statpost); - return 0; -} - -int32_t -default_fsetattr (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - struct iatt *stbuf, - int32_t valid) -{ - STACK_WIND (frame, - default_fsetattr_cbk, - FIRST_CHILD (this), - FIRST_CHILD (this)->fops->fsetattr, - fd, stbuf, valid); - return 0; -} - -int32_t -default_mem_acct_init (xlator_t *this) -{ - int ret = -1; - - ret = xlator_mem_acct_init (this, gf_common_mt_end); - - return ret; -} diff --git a/libglusterfs/src/defaults.h b/libglusterfs/src/defaults.h deleted file mode 100644 index a1177cb6c52..00000000000 --- a/libglusterfs/src/defaults.h +++ /dev/null @@ -1,423 +0,0 @@ -/* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -/* libglusterfs/src/defaults.h: - This file contains definition of default fops and mops functions. -*/ - -#ifndef _DEFAULTS_H -#define _DEFAULTS_H - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include "xlator.h" - -/* Management Operations */ - -int32_t default_getspec (call_frame_t *frame, - xlator_t *this, - const char *key, - int32_t flag); - -int32_t default_checksum (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - int32_t flag); - -int32_t default_rchecksum (call_frame_t *frame, - xlator_t *this, - fd_t *fd, off_t offset, - int32_t len); - -/* FileSystem operations */ -int32_t default_lookup (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - dict_t *xattr_req); - -int32_t default_stat (call_frame_t *frame, - xlator_t *this, - loc_t *loc); - -int32_t default_fstat (call_frame_t *frame, - xlator_t *this, - fd_t *fd); - -int32_t default_truncate (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - off_t offset); - -int32_t default_ftruncate (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - off_t offset); - -int32_t default_access (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - int32_t mask); - -int32_t default_readlink (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - size_t size); - -int32_t default_mknod (call_frame_t *frame, xlator_t *this, - loc_t *loc, mode_t mode, dev_t rdev, dict_t *params); - -int32_t default_mkdir (call_frame_t *frame, xlator_t *this, - loc_t *loc, mode_t mode, dict_t *params); - -int32_t default_unlink (call_frame_t *frame, - xlator_t *this, - loc_t *loc); - -int32_t default_rmdir (call_frame_t *frame, - xlator_t *this, - loc_t *loc); - -int32_t default_symlink (call_frame_t *frame, xlator_t *this, - const char *linkpath, loc_t *loc, dict_t *params); - -int32_t default_rename (call_frame_t *frame, - xlator_t *this, - loc_t *oldloc, - loc_t *newloc); - -int32_t default_link (call_frame_t *frame, - xlator_t *this, - loc_t *oldloc, - loc_t *newloc); - -int32_t default_create (call_frame_t *frame, xlator_t *this, - loc_t *loc, int32_t flags, mode_t mode, - fd_t *fd, dict_t *params); - -int32_t default_open (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - int32_t flags, fd_t *fd, - int32_t wbflags); - -int32_t default_readv (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - size_t size, - off_t offset); - -int32_t default_writev (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - struct iovec *vector, - int32_t count, - off_t offset, - struct iobref *iobref); - -int32_t default_flush (call_frame_t *frame, - xlator_t *this, - fd_t *fd); - -int32_t default_fsync (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - int32_t datasync); - -int32_t default_opendir (call_frame_t *frame, - xlator_t *this, - loc_t *loc, fd_t *fd); - -int32_t default_fsyncdir (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - int32_t datasync); - -int32_t default_statfs (call_frame_t *frame, - xlator_t *this, - loc_t *loc); - -int32_t default_setxattr (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - dict_t *dict, - int32_t flags); - -int32_t default_getxattr (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - const char *name); - -int32_t default_fsetxattr (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - dict_t *dict, - int32_t flags); - -int32_t default_fgetxattr (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - const char *name); - -int32_t default_removexattr (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - const char *name); - -int32_t default_lk (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - int32_t cmd, - struct flock *flock); - -int32_t default_inodelk (call_frame_t *frame, xlator_t *this, - const char *volume, loc_t *loc, int32_t cmd, - struct flock *flock); - -int32_t default_finodelk (call_frame_t *frame, xlator_t *this, - const char *volume, fd_t *fd, int32_t cmd, - struct flock *flock); - -int32_t default_entrylk (call_frame_t *frame, xlator_t *this, - const char *volume, loc_t *loc, const char *basename, - entrylk_cmd cmd, entrylk_type type); - -int32_t default_fentrylk (call_frame_t *frame, xlator_t *this, - const char *volume, fd_t *fd, const char *basename, - entrylk_cmd cmd, entrylk_type type); - -int32_t default_readdir (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - size_t size, off_t off); - -int32_t default_readdirp (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - size_t size, off_t off); - -int32_t default_xattrop (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - gf_xattrop_flags_t flags, - dict_t *dict); - -int32_t default_fxattrop (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - gf_xattrop_flags_t flags, - dict_t *dict); - -int32_t default_notify (xlator_t *this, - int32_t event, - void *data, - ...); - -int32_t default_forget (xlator_t *this, - inode_t *inode); - -int32_t default_release (xlator_t *this, - fd_t *fd); - -int32_t default_releasedir (xlator_t *this, - fd_t *fd); - -int32_t default_setattr (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - struct iatt *stbuf, - int32_t valid); - -int32_t default_fsetattr (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - struct iatt *stbuf, - int32_t valid); - -int32_t -default_truncate_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *prebuf, - struct iatt *postbuf); - -int32_t -default_access_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno); - -int32_t -default_readlink_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - const char *path, - struct iatt *buf); - -int32_t -default_mknod_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent); - -int32_t -default_mkdir_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent); - -int32_t -default_unlink_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *preparent, - struct iatt *postparent); - -int32_t -default_rmdir_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *preparent, - struct iatt *postparent); - -int32_t -default_symlink_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent); - -int32_t -default_rename_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *buf, - struct iatt *preoldparent, - struct iatt *postoldparent, - struct iatt *prenewparent, - struct iatt *postnewparent); - -int32_t -default_link_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent); - - -int32_t -default_create_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - fd_t *fd, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent); - -int32_t -default_open_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - fd_t *fd); - -int32_t -default_readv_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iovec *vector, - int32_t count, - struct iatt *stbuf, - struct iobref *iobref); - -int32_t -default_opendir_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - fd_t *fd); - -int32_t -default_setattr_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *statpre, - struct iatt *statpost); - -int32_t -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); - -int32_t -default_writev_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *prebuf, - struct iatt *postbuf); - -int32_t -default_mem_acct_init (xlator_t *this); -#endif /* _DEFAULTS_H */ diff --git a/libglusterfs/src/dict.c b/libglusterfs/src/dict.c index f2528aeebda..1d9be9217a6 100644 --- a/libglusterfs/src/dict.c +++ b/libglusterfs/src/dict.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 <unistd.h> @@ -22,1255 +13,1475 @@ #include <stdlib.h> #include <stdio.h> #include <inttypes.h> +#include <limits.h> +#include <fnmatch.h> + +#include "glusterfs/dict.h" +#define XXH_INLINE_ALL +#include "xxhash.h" +#include "glusterfs/compat.h" +#include "glusterfs/compat-errno.h" +#include "glusterfs/byte-order.h" +#include "glusterfs/statedump.h" +#include "glusterfs/libglusterfs-messages.h" + +struct dict_cmp { + dict_t *dict; + gf_boolean_t (*value_ignore)(char *k); +}; + +#define VALIDATE_DATA_AND_LOG(data, type, key, ret_val) \ + do { \ + if (!data || !data->data) { \ + gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG, \ + "data is NULL"); \ + return ret_val; \ + } \ + /* Not of the asked type, or old version */ \ + if ((data->data_type != type) && \ + (data->data_type != GF_DATA_TYPE_STR_OLD)) { \ + gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG, \ + "key %s, %s type asked, has %s type", key, \ + data_type_name[type], \ + data_type_name[data->data_type]); \ + } \ + } while (0) -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include "glusterfs.h" -#include "common-utils.h" -#include "dict.h" -#include "hashfn.h" -#include "logging.h" -#include "compat.h" -#include "byte-order.h" - -data_pair_t * -get_new_data_pair () -{ - data_pair_t *data_pair_ptr = NULL; +static data_t * +get_new_data() +{ + data_t *data = mem_get(THIS->ctx->dict_data_pool); + + if (!data) + return NULL; + + GF_ATOMIC_INIT(data->refcount, 0); + data->is_static = _gf_false; + + return data; +} + +static dict_t * +get_new_dict_full(int size_hint) +{ + dict_t *dict = mem_get0(THIS->ctx->dict_pool); + + if (!dict) { + return NULL; + } + + dict->hash_size = size_hint; + if (size_hint == 1) { + /* + * This is the only case we ever see currently. If we ever + * need to support resizing the hash table, the resize function + * will have to take into account the possibility that + * "members" is not separately allocated (i.e. don't just call + * realloc() blindly. + */ + dict->members = &dict->members_internal; + } else { + /* + * We actually need to allocate space for size_hint *pointers* + * but we actually allocate space for one *structure*. Since + * a data_pair_t consists of five pointers, we're wasting four + * pointers' worth for N=1, and will overrun what we allocated + * for N>5. If anybody ever starts using size_hint, we'll need + * to fix this. + */ + GF_ASSERT(size_hint <= (sizeof(data_pair_t) / sizeof(data_pair_t *))); + dict->members = mem_get0(THIS->ctx->dict_pair_pool); + if (!dict->members) { + mem_put(dict); + return NULL; + } + } - data_pair_ptr = (data_pair_t *) GF_CALLOC (1, sizeof (data_pair_t), - gf_common_mt_data_pair_t); - if (!data_pair_ptr) - gf_log ("dict", GF_LOG_ERROR, "memory alloc failed"); + dict->free_pair.key = NULL; + dict->totkvlen = 0; + LOCK_INIT(&dict->lock); - return data_pair_ptr; + return dict; } -data_t * -get_new_data () +dict_t * +dict_new(void) { - data_t *data = NULL; + dict_t *dict = get_new_dict_full(1); - data = (data_t *) GF_CALLOC (1, sizeof (data_t), gf_common_mt_data_t); - if (!data) { - gf_log ("dict", GF_LOG_CRITICAL, - "calloc () returned NULL"); - return NULL; - } + if (dict) + dict_ref(dict); - LOCK_INIT (&data->lock); - return data; + return dict; } -dict_t * -get_new_dict_full (int size_hint) +int32_t +is_data_equal(data_t *one, data_t *two) { - dict_t *dict = GF_CALLOC (1, sizeof (dict_t), gf_common_mt_dict_t); - - if (!dict) { - gf_log ("dict", GF_LOG_CRITICAL, - "calloc () returned NULL"); - return NULL; - } + struct iatt *iatt1, *iatt2; + struct mdata_iatt *mdata_iatt1, *mdata_iatt2; - dict->hash_size = size_hint; - dict->members = GF_CALLOC (size_hint, sizeof (data_pair_t *), - gf_common_mt_data_pair_t); + if (!one || !two || !one->data || !two->data) { + gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "input arguments are provided " + "with value data_t as NULL"); + return -1; + } - if (!dict->members) { - gf_log ("dict", GF_LOG_CRITICAL, - "calloc () returned NULL"); - return NULL; - } + if (one == two) + return 1; - LOCK_INIT (&dict->lock); + if (one->data == two->data) + return 1; - return dict; -} - -dict_t * -get_new_dict (void) -{ - return get_new_dict_full (1); -} + if (one->data_type != two->data_type) { + return 0; + } -dict_t * -dict_new (void) -{ - dict_t *dict = NULL; - - dict = get_new_dict_full(1); - - if (dict) - dict_ref (dict); - - return dict; -} + if (one->data_type == GF_DATA_TYPE_IATT) { + if ((one->len < sizeof(struct iatt)) || + (two->len < sizeof(struct iatt))) { + return 0; + } + iatt1 = (struct iatt *)one->data; + iatt2 = (struct iatt *)two->data; -int32_t -is_data_equal (data_t *one, - data_t *two) -{ - if (!one || !two || !one->data || !two->data) - return 1; + /* Two iatt structs are considered equal if main fields are + * equal, even if times differ. + * TODO: maybe when ctime if fully operational we could + * enforce time matching. */ + if (iatt1->ia_ino != iatt2->ia_ino) { + return 0; + } + if (iatt1->ia_type != iatt2->ia_type) { + return 0; + } + if ((iatt1->ia_type == IA_IFBLK) || (iatt1->ia_type == IA_IFCHR)) { + if (iatt1->ia_rdev != iatt2->ia_rdev) { + return 0; + } + } + if (gf_uuid_compare(iatt1->ia_gfid, iatt2->ia_gfid) != 0) { + return 0; + } - if (one == two) - return 1; + /* TODO: ia_uid, ia_gid, ia_prot and ia_size can be changed + * with some commands. Here we don't have enough + * information to decide if they should match or not. */ + /* + if ((iatt1->ia_uid != iatt2->ia_uid) || + (iatt1->ia_gid != iatt2->ia_gid) || + (st_mode_from_ia(iatt1->ia_prot, iatt1->ia_type) != + st_mode_from_ia(iatt2->ia_prot, + iatt2->ia_type))) { return 0; + } + if (iatt1->ia_type == IA_IFREG) { + if (iatt1->ia_size != iatt2->ia_size) { + return 0; + } + } + */ + return 1; + } + if (one->data_type == GF_DATA_TYPE_MDATA) { + if ((one->len < sizeof(struct mdata_iatt)) || + (two->len < sizeof(struct mdata_iatt))) { + return 0; + } + mdata_iatt1 = (struct mdata_iatt *)one->data; + mdata_iatt2 = (struct mdata_iatt *)two->data; + + if (mdata_iatt1->ia_atime != mdata_iatt2->ia_atime || + mdata_iatt1->ia_mtime != mdata_iatt2->ia_mtime || + mdata_iatt1->ia_ctime != mdata_iatt2->ia_ctime || + mdata_iatt1->ia_atime_nsec != mdata_iatt2->ia_atime_nsec || + mdata_iatt1->ia_mtime_nsec != mdata_iatt2->ia_mtime_nsec || + mdata_iatt1->ia_ctime_nsec != mdata_iatt2->ia_ctime_nsec) { + return 0; + } + return 1; + } - if (one->len != two->len) - return 0; + if (one->len != two->len) + return 0; - if (one->data == two->data) - return 1; + if (memcmp(one->data, two->data, one->len) == 0) + return 1; - if (memcmp (one->data, two->data, one->len) == 0) - return 1; + return 0; +} - return 0; +static int +key_value_cmp(dict_t *one, char *key1, data_t *value1, void *data) +{ + struct dict_cmp *cmp = data; + dict_t *two = cmp->dict; + data_t *value2 = dict_get(two, key1); + + if (value2) { + if (cmp->value_ignore && cmp->value_ignore(key1)) + return 0; + + if (is_data_equal(value1, value2) == 1) + return 0; + } + + if (value2 == NULL) { + gf_msg_debug(THIS->name, 0, "'%s' found only on one dict", key1); + } else { + gf_msg_debug(THIS->name, 0, + "'%s' is different in two dicts " + "(%u, %u)", + key1, value1->len, value2->len); + } + + return -1; +} + +/* If both dicts are NULL then equal. If one of the dicts is NULL but the + * other has only ignorable keys then also they are equal. If both dicts are + * non-null then check if for each non-ignorable key, values are same or + * not. value_ignore function is used to skip comparing values for the keys + * which must be present in both the dictionaries but the value could be + * different. + */ +gf_boolean_t +are_dicts_equal(dict_t *one, dict_t *two, + gf_boolean_t (*match)(dict_t *d, char *k, data_t *v, + void *data), + gf_boolean_t (*value_ignore)(char *k)) +{ + int num_matches1 = 0; + int num_matches2 = 0; + struct dict_cmp cmp = {0}; + + if (one == two) + return _gf_true; + + if (!match) + match = dict_match_everything; + + if ((one == NULL) || (two == NULL)) { + num_matches1 = dict_foreach_match(one ? one : two, match, NULL, + dict_null_foreach_fn, NULL); + goto done; + } + + cmp.dict = two; + cmp.value_ignore = value_ignore; + num_matches1 = dict_foreach_match(one, match, NULL, key_value_cmp, &cmp); + + if (num_matches1 == -1) + return _gf_false; + + if ((num_matches1 == one->count) && (one->count == two->count)) + return _gf_true; + + num_matches2 = dict_foreach_match(two, match, NULL, dict_null_foreach_fn, + NULL); +done: + /* If the number of matches is same in 'two' then for all the + * valid-keys that exist in 'one' the value matched and no extra valid + * keys exist in 'two' alone. Otherwise there exists at least one extra + * valid-key in 'two' which doesn't exist in 'one' */ + if (num_matches1 == num_matches2) + return _gf_true; + return _gf_false; } void -data_destroy (data_t *data) +data_destroy(data_t *data) { - if (data) { - LOCK_DESTROY (&data->lock); - - if (!data->is_static) { - if (data->data) - GF_FREE (data->data); - if (data->vec) - GF_FREE (data->vec); - } + if (data) { + if (!data->is_static) + GF_FREE(data->data); - data->len = 0xbabababa; - if (!data->is_const) - GF_FREE (data); - } + data->len = 0xbabababa; + mem_put(data); + } } data_t * -data_copy (data_t *old) -{ - if (!old) { - gf_log ("dict", GF_LOG_CRITICAL, - "@old is NULL"); - return NULL; - } - - data_t *newdata = (data_t *) GF_CALLOC (1, sizeof (*newdata), - gf_common_mt_data_t); - - if (!newdata) { - gf_log ("dict", GF_LOG_CRITICAL, - "@newdata - NULL returned by CALLOC"); - return NULL; - } - - if (old) { - newdata->len = old->len; - if (old->data) { - newdata->data = memdup (old->data, old->len); - if (!newdata->data) - goto err_out; - } - if (old->vec) { - newdata->vec = memdup (old->vec, old->len * (sizeof (void *) + - sizeof (size_t))); - if (!newdata->vec) - goto err_out; - } - } - - return newdata; - - err_out: - - if (newdata->data) - FREE (newdata->data); - if (newdata->vec) - FREE (newdata->vec); - FREE (newdata); - - gf_log ("dict", GF_LOG_CRITICAL, - "@newdata->data || @newdata->vec got NULL from CALLOC()"); - return NULL; +data_copy(data_t *old) +{ + if (!old) { + gf_msg_callingfn("dict", GF_LOG_WARNING, 0, LG_MSG_NULL_PTR, + "old is NULL"); + return NULL; + } + + data_t *newdata = mem_get0(THIS->ctx->dict_data_pool); + if (!newdata) { + return NULL; + } + + newdata->len = old->len; + if (old->data) { + newdata->data = gf_memdup(old->data, old->len); + if (!newdata->data) + goto err_out; + } + newdata->data_type = old->data_type; + + return newdata; + +err_out: + mem_put(newdata); + + return NULL; } +/* Always need to be called under lock + * Always this and key variables are not null - + * checked by callers. + */ static data_pair_t * -_dict_lookup (dict_t *this, char *key) +dict_lookup_common(const dict_t *this, const char *key, const uint32_t hash) { - if (!this || !key) { - gf_log ("dict", GF_LOG_CRITICAL, - "@this=%p @key=%p", this, key); - return NULL; - } + int hashval = 0; + data_pair_t *pair; - int hashval = SuperFastHash (key, strlen (key)) % this->hash_size; - data_pair_t *pair; - - for (pair = this->members[hashval]; pair != NULL; pair = pair->hash_next) { - if (pair->key && !strcmp (pair->key, key)) - return pair; - } - - return NULL; -} + /* If the divisor is 1, the modulo is always 0, + * in such case avoid hash calculation. + */ + if (this->hash_size != 1) + hashval = hash % this->hash_size; + for (pair = this->members[hashval]; pair != NULL; pair = pair->hash_next) { + if (pair->key && (hash == pair->key_hash) && !strcmp(pair->key, key)) + return pair; + } -static int32_t -_dict_set (dict_t *this, - char *key, - data_t *value) -{ - int hashval; - data_pair_t *pair; - char key_free = 0; - int tmp = 0; - int ret = 0; - - if (!key) { - ret = gf_asprintf (&key, "ref:%p", value); - if (-1 == ret) { - gf_log ("dict", GF_LOG_ERROR, "asprintf failed"); - return -1; - } - key_free = 1; - } - - tmp = SuperFastHash (key, strlen (key)); - hashval = (tmp % this->hash_size); - pair = _dict_lookup (this, key); - - if (pair) { - data_t *unref_data = pair->value; - pair->value = data_ref (value); - data_unref (unref_data); - if (key_free) - GF_FREE (key); - /* Indicates duplicate key */ - return 0; - } - pair = (data_pair_t *) GF_CALLOC (1, sizeof (*pair), - gf_common_mt_data_pair_t); - if (!pair) { - gf_log ("dict", GF_LOG_CRITICAL, - "@pair - NULL returned by CALLOC"); - return -1; - } - - pair->key = (char *) GF_CALLOC (1, strlen (key) + 1, - gf_common_mt_char); - if (!pair->key) { - gf_log ("dict", GF_LOG_CRITICAL, - "@pair->key - NULL returned by CALLOC"); - FREE (pair); - - if (key_free) - GF_FREE (key); - return -1; - } - - strcpy (pair->key, key); - pair->value = data_ref (value); - - pair->hash_next = this->members[hashval]; - this->members[hashval] = pair; - - pair->next = this->members_list; - pair->prev = NULL; - if (this->members_list) - this->members_list->prev = pair; - this->members_list = pair; - this->count++; - - if (key_free) - GF_FREE (key); - return 0; + return NULL; } int32_t -dict_set (dict_t *this, - char *key, - data_t *value) +dict_lookup(dict_t *this, char *key, data_t **data) { - int32_t ret; + if (!this || !key || !data) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "!this || !key || " + "!data"); + return -1; + } - if (!this || !value) { - gf_log ("dict", GF_LOG_CRITICAL, - "@this=%p @value=%p", this, value); - return -1; - } + data_pair_t *tmp = NULL; - LOCK (&this->lock); + uint32_t hash = (uint32_t)XXH64(key, strlen(key), 0); - ret = _dict_set (this, key, value); + LOCK(&this->lock); + { + tmp = dict_lookup_common(this, key, hash); + } + UNLOCK(&this->lock); - UNLOCK (&this->lock); + if (!tmp) + return -1; + + *data = tmp->value; + return 0; +} - return ret; +static int32_t +dict_set_lk(dict_t *this, char *key, const int key_len, data_t *value, + const uint32_t hash, gf_boolean_t replace) +{ + int hashval = 0; + data_pair_t *pair; + int key_free = 0; + uint32_t key_hash; + int keylen; + + if (!key) { + keylen = gf_asprintf(&key, "ref:%p", value); + if (-1 == keylen) { + return -1; + } + key_free = 1; + key_hash = (uint32_t)XXH64(key, keylen, 0); + } else { + keylen = key_len; + key_hash = hash; + } + + /* Search for a existing key if 'replace' is asked for */ + if (replace) { + pair = dict_lookup_common(this, key, key_hash); + if (pair) { + data_t *unref_data = pair->value; + pair->value = data_ref(value); + this->totkvlen += (value->len - unref_data->len); + data_unref(unref_data); + if (key_free) + GF_FREE(key); + /* Indicates duplicate key */ + return 0; + } + } + + if (this->free_pair.key) { /* the free_pair is used */ + pair = mem_get(THIS->ctx->dict_pair_pool); + if (!pair) { + if (key_free) + GF_FREE(key); + return -1; + } + } else { /* assign the pair to the free pair */ + pair = &this->free_pair; + } + + if (key_free) { + /* It's ours. Use it. */ + pair->key = key; + key_free = 0; + } else { + pair->key = (char *)GF_MALLOC(keylen + 1, gf_common_mt_char); + if (!pair->key) { + if (pair != &this->free_pair) { + mem_put(pair); + } + return -1; + } + strcpy(pair->key, key); + } + pair->key_hash = key_hash; + pair->value = data_ref(value); + this->totkvlen += (keylen + 1 + value->len); + + /* If the divisor is 1, the modulo is always 0, + * in such case avoid hash calculation. + */ + if (this->hash_size != 1) { + hashval = (key_hash % this->hash_size); + } + pair->hash_next = this->members[hashval]; + this->members[hashval] = pair; + + pair->next = this->members_list; + pair->prev = NULL; + if (this->members_list) + this->members_list->prev = pair; + this->members_list = pair; + this->count++; + + if (key_free) + GF_FREE(key); + + if (this->max_count < this->count) + this->max_count = this->count; + return 0; } +int32_t +dict_set(dict_t *this, char *key, data_t *value) +{ + if (key) + return dict_setn(this, key, strlen(key), value); + else + return dict_setn(this, NULL, 0, value); +} -data_t * -dict_get (dict_t *this, - char *key) +int32_t +dict_setn(dict_t *this, char *key, const int keylen, data_t *value) { - data_pair_t *pair; + int32_t ret; + uint32_t key_hash = 0; - if (!this || !key) { - gf_log ("dict", GF_LOG_DEBUG, - "@this=%p @key=%p", this, key); - return NULL; - } + if (!this || !value) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "!this || !value for " + "key=%s", + key); + return -1; + } - LOCK (&this->lock); + if (key) { + key_hash = (uint32_t)XXH64(key, keylen, 0); + } - pair = _dict_lookup (this, key); + LOCK(&this->lock); - UNLOCK (&this->lock); + ret = dict_set_lk(this, key, keylen, value, key_hash, 1); - if (pair) - return pair->value; - - return NULL; + UNLOCK(&this->lock); + + return ret; } -void -dict_del (dict_t *this, - char *key) -{ - if (!this || !key) { - gf_log ("dict", GF_LOG_DEBUG, - "@this=%p @key=%p", this, key); - return; - } - - LOCK (&this->lock); - - int hashval = SuperFastHash (key, strlen (key)) % this->hash_size; - data_pair_t *pair = this->members[hashval]; - data_pair_t *prev = NULL; - - while (pair) { - if (strcmp (pair->key, key) == 0) { - if (prev) - prev->hash_next = pair->hash_next; - else - this->members[hashval] = pair->hash_next; - - data_unref (pair->value); - - if (pair->prev) - pair->prev->next = pair->next; - else - this->members_list = pair->next; - - if (pair->next) - pair->next->prev = pair->prev; - - GF_FREE (pair->key); - GF_FREE (pair); - this->count--; - break; - } - - prev = pair; - pair = pair->hash_next; - } - - UNLOCK (&this->lock); - - return; +int32_t +dict_add(dict_t *this, char *key, data_t *value) +{ + if (key) + return dict_addn(this, key, strlen(key), value); + else + return dict_addn(this, NULL, 0, value); } -void -dict_destroy (dict_t *this) +int32_t +dict_addn(dict_t *this, char *key, const int keylen, data_t *value) { - if (!this) { - gf_log ("dict", GF_LOG_DEBUG, - "@this=%p", this); - return; - } + int32_t ret; + uint32_t key_hash = 0; - data_pair_t *pair = this->members_list; - data_pair_t *prev = this->members_list; + if (!this || !value) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "!this || !value for key=%s", key); + return -1; + } - LOCK_DESTROY (&this->lock); + if (key) { + key_hash = (uint32_t)XXH64(key, keylen, 0); + } - while (prev) { - pair = pair->next; - data_unref (prev->value); - GF_FREE (prev->key); - GF_FREE (prev); - prev = pair; - } + LOCK(&this->lock); - GF_FREE (this->members); + ret = dict_set_lk(this, key, keylen, value, key_hash, 0); - if (this->extra_free) - GF_FREE (this->extra_free); + UNLOCK(&this->lock); - if (!this->is_static) - GF_FREE (this); + return ret; +} + +data_t * +dict_get(dict_t *this, char *key) +{ + if (!this || !key) { + gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG, + "!this || key=%s", (key) ? key : "()"); + return NULL; + } - return; + return dict_getn(this, key, strlen(key)); } -void -dict_unref (dict_t *this) +data_t * +dict_getn(dict_t *this, char *key, const int keylen) { - int32_t ref; + data_pair_t *pair; + uint32_t hash; - if (!this) { - gf_log ("dict", GF_LOG_DEBUG, - "@this=%p", this); - return; - } + if (!this || !key) { + gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG, + "!this || key=%s", (key) ? key : "()"); + return NULL; + } - LOCK (&this->lock); + hash = (uint32_t)XXH64(key, keylen, 0); - this->refcount--; - ref = this->refcount; + LOCK(&this->lock); + { + pair = dict_lookup_common(this, key, hash); + } + UNLOCK(&this->lock); - UNLOCK (&this->lock); + if (pair) + return pair->value; - if (!ref) - dict_destroy (this); + return NULL; } -dict_t * -dict_ref (dict_t *this) +int +dict_key_count(dict_t *this) { - if (!this) { - gf_log ("dict", GF_LOG_DEBUG, - "@this=%p", this); - return NULL; - } + int ret = -1; - LOCK (&this->lock); + if (!this) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict passed is NULL"); + return ret; + } - this->refcount++; + LOCK(&this->lock); + { + ret = this->count; + } + UNLOCK(&this->lock); - UNLOCK (&this->lock); - - return this; + return ret; } void -data_unref (data_t *this) +dict_del(dict_t *this, char *key) { - int32_t ref; + if (!this || !key) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "!this || key=%s", key); + return; + } - if (!this) { - gf_log ("dict", GF_LOG_DEBUG, - "@this=%p", this); - return; - } + return dict_deln(this, key, strlen(key)); +} - LOCK (&this->lock); +void +dict_deln(dict_t *this, char *key, const int keylen) +{ + int hashval = 0; + uint32_t hash; + + if (!this || !key) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "!this || key=%s", key); + return; + } + + hash = (uint32_t)XXH64(key, keylen, 0); + + LOCK(&this->lock); + + /* If the divisor is 1, the modulo is always 0, + * in such case avoid hash calculation. + */ + if (this->hash_size != 1) + hashval = hash % this->hash_size; + + data_pair_t *pair = this->members[hashval]; + data_pair_t *prev = NULL; + + while (pair) { + if ((hash == pair->key_hash) && strcmp(pair->key, key) == 0) { + if (prev) + prev->hash_next = pair->hash_next; + else + this->members[hashval] = pair->hash_next; + + this->totkvlen -= pair->value->len; + data_unref(pair->value); + + if (pair->prev) + pair->prev->next = pair->next; + else + this->members_list = pair->next; + + if (pair->next) + pair->next->prev = pair->prev; + + this->totkvlen -= (strlen(pair->key) + 1); + GF_FREE(pair->key); + if (pair == &this->free_pair) { + this->free_pair.key = NULL; + } else { + mem_put(pair); + } + this->count--; + break; + } - this->refcount--; - ref = this->refcount; + prev = pair; + pair = pair->hash_next; + } - UNLOCK (&this->lock); + UNLOCK(&this->lock); - if (!ref) - data_destroy (this); + return; } -data_t * -data_ref (data_t *this) -{ - if (!this) { - gf_log ("dict", GF_LOG_DEBUG, - "@this=%p", this); - return NULL; - } - - LOCK (&this->lock); - - this->refcount++; - - UNLOCK (&this->lock); +void +dict_destroy(dict_t *this) +{ + if (!this) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict is NULL"); + return; + } + + data_pair_t *pair = this->members_list; + data_pair_t *prev = this->members_list; + glusterfs_ctx_t *ctx = NULL; + uint64_t current_max = 0; + uint32_t total_pairs = 0; + + LOCK_DESTROY(&this->lock); + + while (prev) { + pair = pair->next; + data_unref(prev->value); + GF_FREE(prev->key); + if (prev != &this->free_pair) { + mem_put(prev); + } else { + this->free_pair.key = NULL; + } + total_pairs++; + prev = pair; + } - return this; -} + this->totkvlen = 0; + if (this->members != &this->members_internal) { + mem_put(this->members); + } -/* - Serialization format: - ---- - Count:8 - Key_len:8:Value_len:8 - Key - Value - . - . - . -*/ + free(this->extra_stdfree); -int32_t -dict_serialized_length_old (dict_t *this) -{ + /* update 'ctx->stats.dict.details' using max_count */ + ctx = THIS->ctx; - if (!this) { - gf_log ("dict", GF_LOG_DEBUG, - "@this=%p", this); - return -1; - } + /* NOTE: below logic is not totaly race proof */ + /* thread0 and thread1 gets current_max as 10 */ + /* thread0 has 'this->max_count as 11 */ + /* thread1 has 'this->max_count as 20 */ + /* thread1 goes ahead and sets the max_dict_pairs to 20 */ + /* thread0 then goes and sets it to 11 */ + /* As it is for information purpose only, no functionality will be + broken by this, but a point to consider about ATOMIC macros. */ + current_max = GF_ATOMIC_GET(ctx->stats.max_dict_pairs); + if (current_max < this->max_count) + GF_ATOMIC_INIT(ctx->stats.max_dict_pairs, this->max_count); - int32_t len = 9; /* count + \n */ - int32_t count = this->count; - data_pair_t *pair = this->members_list; + GF_ATOMIC_ADD(ctx->stats.total_pairs_used, total_pairs); + GF_ATOMIC_INC(ctx->stats.total_dicts_used); - while (count) { - len += 18; - len += strlen (pair->key) + 1; - if (pair->value->vec) { - int i; - for (i=0; i<pair->value->len; i++) { - len += pair->value->vec[i].iov_len; - } - } else { - len += pair->value->len; - } - pair = pair->next; - count--; - } + mem_put(this); - return len; + return; } -int32_t -dict_serialize_old (dict_t *this, char *buf) +void +dict_unref(dict_t *this) { - if (!this || !buf) { - gf_log ("dict", GF_LOG_DEBUG, - "@this=%p @buf=%p", this, buf); - return -1; - } + uint64_t ref = 0; - data_pair_t *pair = this->members_list; - int32_t count = this->count; - uint64_t dcount = this->count; + if (!this) { + gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG, + "dict is NULL"); + return; + } - // FIXME: magic numbers + ref = GF_ATOMIC_DEC(this->refcount); - sprintf (buf, "%08"PRIx64"\n", dcount); - buf += 9; - while (count) { - uint64_t keylen = strlen (pair->key) + 1; - uint64_t vallen = pair->value->len; - - sprintf (buf, "%08"PRIx64":%08"PRIx64"\n", keylen, vallen); - buf += 18; - memcpy (buf, pair->key, keylen); - buf += keylen; - memcpy (buf, pair->value->data, pair->value->len); - buf += pair->value->len; - pair = pair->next; - count--; - } - return (0); + if (!ref) + dict_destroy(this); } - dict_t * -dict_unserialize_old (char *buf, int32_t size, dict_t **fill) -{ - int32_t ret = 0; - int32_t cnt = 0; - - if (!buf || !fill || !(*fill)) { - gf_log ("dict", GF_LOG_ERROR, - "@buf=%p @fill=%p @*fill=%p", - buf, fill, (fill) ? (*fill) : NULL); - return NULL; - } - - uint64_t count; - ret = sscanf (buf, "%"SCNx64"\n", &count); - (*fill)->count = 0; - - if (!ret){ - gf_log ("dict", - GF_LOG_ERROR, - "sscanf on buf failed"); - goto err; - } - buf += 9; - - if (count == 0) { - gf_log ("dict", - GF_LOG_ERROR, - "count == 0"); - goto err; - } - - for (cnt = 0; cnt < count; cnt++) { - data_t *value = NULL; - char *key = NULL; - uint64_t key_len, value_len; - - ret = sscanf (buf, "%"SCNx64":%"SCNx64"\n", &key_len, &value_len); - if (ret != 2) { - gf_log ("dict", - GF_LOG_ERROR, - "sscanf for key_len and value_len failed"); - goto err; - } - buf += 18; - - key = buf; - buf += key_len; - - value = get_new_data (); - value->len = value_len; - value->data = buf; - value->is_static = 1; - buf += value_len; - - dict_set (*fill, key, value); - } - - goto ret; - -err: - GF_FREE (*fill); - *fill = NULL; +dict_ref(dict_t *this) +{ + if (!this) { + gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG, + "dict is NULL"); + return NULL; + } -ret: - return *fill; + GF_ATOMIC_INC(this->refcount); + return this; } - -int32_t -dict_iovec_len (dict_t *this) +void +data_unref(data_t *this) { - if (!this) { - gf_log ("dict", GF_LOG_CRITICAL, - "@this=%p", this); - return -1; - } + uint64_t ref; - int32_t len = 0; - data_pair_t *pair = this->members_list; + if (!this) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "data is NULL"); + return; + } - len++; /* initial header */ - while (pair) { - len++; /* pair header */ - len++; /* key */ + ref = GF_ATOMIC_DEC(this->refcount); - if (pair->value->vec) - len += pair->value->len; - else - len++; - pair = pair->next; - } - - return len; -} - -int32_t -dict_to_iovec (dict_t *this, - struct iovec *vec, - int32_t count) -{ - if (!this || !vec) { - gf_log ("dict", GF_LOG_CRITICAL, - "@this=%p @vec=%p", this, vec); - return -1; - } - - int32_t i = 0; - data_pair_t *pair = this->members_list; - - vec[0].iov_len = 9; - if (vec[0].iov_base) - sprintf (vec[0].iov_base, - "%08"PRIx64"\n", - (int64_t)this->count); - i++; - - while (pair) { - int64_t keylen = strlen (pair->key) + 1; - int64_t vallen = 0; - - if (pair->value->vec) { - int i; - - for (i=0; i<pair->value->len; i++) { - vallen += pair->value->vec[i].iov_len; - } - } else { - vallen = pair->value->len; - } - - vec[i].iov_len = 18; - if (vec[i].iov_base) - sprintf (vec[i].iov_base, - "%08"PRIx64":%08"PRIx64"\n", - keylen, - vallen); - i++; - - vec[i].iov_len = keylen; - vec[i].iov_base = pair->key; - i++; - - if (pair->value->vec) { - int k; - - for (k=0; k<pair->value->len; k++) { - vec[i].iov_len = pair->value->vec[k].iov_len; - vec[i].iov_base = pair->value->vec[k].iov_base; - i++; - } - } else { - vec[i].iov_len = pair->value->len; - vec[i].iov_base = pair->value->data; - i++; - } - - pair = pair->next; - } - - return 0; + if (!ref) + data_destroy(this); } data_t * -int_to_data (int64_t value) +data_ref(data_t *this) { - int ret = 0; - data_t *data = get_new_data (); + if (!this) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "data is NULL"); + return NULL; + } - if (!data) { - gf_log ("dict", GF_LOG_CRITICAL, - "@data - NULL returned by CALLOC"); - return NULL; - } + GF_ATOMIC_INC(this->refcount); - ret = gf_asprintf (&data->data, "%"PRId64, value); - if (-1 == ret) { - gf_log ("dict", GF_LOG_ERROR, "asprintf failed"); - return NULL; - } - data->len = strlen (data->data) + 1; - - return data; + return this; } data_t * -data_from_int64 (int64_t value) -{ - int ret = 0; - data_t *data = get_new_data (); - - if (!data) { - gf_log ("dict", GF_LOG_CRITICAL, - "@data - NULL returned by CALLOC"); - return NULL; - } - ret = gf_asprintf (&data->data, "%"PRId64, value); - if (-1 == ret) { - gf_log ("dict", GF_LOG_ERROR, "asprintf failed"); - return NULL; - } - data->len = strlen (data->data) + 1; +int_to_data(int64_t value) +{ + data_t *data = get_new_data(); - return data; + if (!data) { + return NULL; + } + + data->len = gf_asprintf(&data->data, "%" PRId64, value); + if (-1 == data->len) { + gf_msg_debug("dict", 0, "asprintf failed"); + data_destroy(data); + return NULL; + } + data->len++; /* account for terminating NULL */ + data->data_type = GF_DATA_TYPE_INT; + + return data; } data_t * -data_from_int32 (int32_t value) -{ - int ret = 0; - data_t *data = get_new_data (); - - if (!data) { - gf_log ("dict", GF_LOG_CRITICAL, - "@data - NULL returned by CALLOC"); - return NULL; - } - ret = gf_asprintf (&data->data, "%"PRId32, value); - if (-1 == ret) { - gf_log ("dict", GF_LOG_ERROR, "asprintf failed"); - return NULL; - } +data_from_int64(int64_t value) +{ + data_t *data = get_new_data(); - data->len = strlen (data->data) + 1; + if (!data) { + return NULL; + } + data->len = gf_asprintf(&data->data, "%" PRId64, value); + if (-1 == data->len) { + gf_msg_debug("dict", 0, "asprintf failed"); + data_destroy(data); + return NULL; + } + data->len++; /* account for terminating NULL */ + data->data_type = GF_DATA_TYPE_INT; - return data; + return data; } data_t * -data_from_int16 (int16_t value) -{ - int ret = 0; - data_t *data = get_new_data (); - - if (!data) { - gf_log ("dict", GF_LOG_CRITICAL, - "@data - NULL returned by CALLOC"); - return NULL; - } - ret = gf_asprintf (&data->data, "%"PRId16, value); - if (-1 == ret) { - gf_log ("dict", GF_LOG_ERROR, "asprintf failed"); - return NULL; - } +data_from_int32(int32_t value) +{ + data_t *data = get_new_data(); - data->len = strlen (data->data) + 1; + if (!data) { + return NULL; + } + data->len = gf_asprintf(&data->data, "%" PRId32, value); + if (-1 == data->len) { + gf_msg_debug("dict", 0, "asprintf failed"); + data_destroy(data); + return NULL; + } - return data; + data->len++; /* account for terminating NULL */ + data->data_type = GF_DATA_TYPE_INT; + + return data; } data_t * -data_from_int8 (int8_t value) -{ - int ret = 0; - data_t *data = get_new_data (); - - if (!data) { - gf_log ("dict", GF_LOG_CRITICAL, - "@data - NULL returned by CALLOC"); - return NULL; - } - ret = gf_asprintf (&data->data, "%d", value); - if (-1 == ret) { - gf_log ("dict", GF_LOG_ERROR, "asprintf failed"); - return NULL; - } +data_from_int16(int16_t value) +{ + data_t *data = get_new_data(); + + if (!data) { + return NULL; + } + data->len = gf_asprintf(&data->data, "%" PRId16, value); + if (-1 == data->len) { + gf_msg_debug("dict", 0, "asprintf failed"); + data_destroy(data); + return NULL; + } - data->len = strlen (data->data) + 1; + data->len++; /* account for terminating NULL */ + data->data_type = GF_DATA_TYPE_INT; - return data; + return data; } data_t * -data_from_uint64 (uint64_t value) -{ - int ret = 0; - data_t *data = get_new_data (); - - if (!data) { - gf_log ("dict", GF_LOG_CRITICAL, - "@data - NULL returned by CALLOC"); - return NULL; - } - ret = gf_asprintf (&data->data, "%"PRIu64, value); - if (-1 == ret) { - gf_log ("dict", GF_LOG_ERROR, "asprintf failed"); - return NULL; - } +data_from_int8(int8_t value) +{ + data_t *data = get_new_data(); - data->len = strlen (data->data) + 1; + if (!data) { + return NULL; + } + data->len = gf_asprintf(&data->data, "%d", value); + if (-1 == data->len) { + gf_msg_debug("dict", 0, "asprintf failed"); + data_destroy(data); + return NULL; + } - return data; + data->len++; /* account for terminating NULL */ + data->data_type = GF_DATA_TYPE_INT; + + return data; } -static data_t * -data_from_double (double value) +data_t * +data_from_uint64(uint64_t value) { - data_t *data = NULL; - int ret = 0; - - data = get_new_data (); + data_t *data = get_new_data(); - if (!data) { - gf_log ("dict", GF_LOG_CRITICAL, - "@data - NULL returned by CALLOC"); - return NULL; - } + if (!data) { + return NULL; + } + data->len = gf_asprintf(&data->data, "%" PRIu64, value); + if (-1 == data->len) { + gf_msg_debug("dict", 0, "asprintf failed"); + data_destroy(data); + return NULL; + } - ret = gf_asprintf (&data->data, "%f", value); - if (ret == -1) { - gf_log ("dict", GF_LOG_CRITICAL, - "@data - allocation failed by ASPRINTF"); - return NULL; - } - data->len = strlen (data->data) + 1; + data->len++; /* account for terminating NULL */ + data->data_type = GF_DATA_TYPE_UINT; - return data; + return data; } - data_t * -data_from_uint32 (uint32_t value) -{ - int ret = 0; - data_t *data = get_new_data (); - - if (!data) { - gf_log ("dict", GF_LOG_CRITICAL, - "@data - NULL returned by CALLOC"); - return NULL; - } - ret = gf_asprintf (&data->data, "%"PRIu32, value); - if (-1 == ret) { - gf_log ("dict", GF_LOG_ERROR, "asprintf failed"); - return NULL; - } +data_from_double(double value) +{ + data_t *data = get_new_data(); - data->len = strlen (data->data) + 1; + if (!data) { + return NULL; + } - return data; -} + data->len = gf_asprintf(&data->data, "%f", value); + if (data->len == -1) { + gf_msg_debug("dict", 0, "asprintf failed"); + data_destroy(data); + return NULL; + } + data->len++; /* account for terminating NULL */ + data->data_type = GF_DATA_TYPE_DOUBLE; + return data; +} data_t * -data_from_uint16 (uint16_t value) -{ - int ret = 0; - data_t *data = get_new_data (); - - if (!data) { - gf_log ("dict", GF_LOG_CRITICAL, - "@data - NULL returned by CALLOC"); - return NULL; - } - ret = gf_asprintf (&data->data, "%"PRIu16, value); - if (-1 == ret) { - gf_log ("dict", GF_LOG_ERROR, "asprintf failed"); - return NULL; - } +data_from_uint32(uint32_t value) +{ + data_t *data = get_new_data(); - data->len = strlen (data->data) + 1; + if (!data) { + return NULL; + } + data->len = gf_asprintf(&data->data, "%" PRIu32, value); + if (-1 == data->len) { + gf_msg_debug("dict", 0, "asprintf failed"); + data_destroy(data); + return NULL; + } - return data; -} + data->len++; /* account for terminating NULL */ + data->data_type = GF_DATA_TYPE_UINT; + return data; +} data_t * -data_from_ptr (void *value) +data_from_uint16(uint16_t value) { - if (!value) { - gf_log ("dict", GF_LOG_CRITICAL, - "@value=%p", value); - return NULL; - } + data_t *data = get_new_data(); - data_t *data = get_new_data (); + if (!data) { + return NULL; + } + data->len = gf_asprintf(&data->data, "%" PRIu16, value); + if (-1 == data->len) { + gf_msg_debug("dict", 0, "asprintf failed"); + data_destroy(data); + return NULL; + } - if (!data) { - gf_log ("dict", GF_LOG_CRITICAL, - "@data - NULL returned by CALLOC"); - return NULL; - } + data->len++; /* account for terminating NULL */ + data->data_type = GF_DATA_TYPE_UINT; - data->data = value; - return data; + return data; } -data_t * -data_from_static_ptr (void *value) +static data_t * +data_from_ptr_common(void *value, gf_boolean_t is_static) { -/* - this is valid to set 0 as value.. + /* it is valid to set 0/NULL as a value, no need to check *value */ - if (!value) { - gf_log ("dict", GF_LOG_CRITICAL, - "@value=%p", value); - return NULL; - } -*/ - data_t *data = get_new_data (); + data_t *data = get_new_data(); + if (!data) { + return NULL; + } + + data->data = value; + data->len = 0; + data->is_static = is_static; - if (!data) { - gf_log ("dict", GF_LOG_CRITICAL, - "@data - NULL returned by CALLOC"); - return NULL; - } + data->data_type = GF_DATA_TYPE_PTR; + return data; +} - data->is_static = 1; - data->data = value; +data_t * +str_to_data(char *value) +{ + if (!value) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "value is NULL"); + return NULL; + } - return data; + return strn_to_data(value, strlen(value)); } data_t * -str_to_data (char *value) +strn_to_data(char *value, const int vallen) { - if (!value) { - gf_log ("dict", GF_LOG_CRITICAL, - "@value=%p", value); - return NULL; - } - data_t *data = get_new_data (); + if (!value) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "value is NULL"); + return NULL; + } + data_t *data = get_new_data(); - if (!data) { - gf_log ("dict", GF_LOG_CRITICAL, - "@data - NULL returned by CALLOC"); - return NULL; - } - data->len = strlen (value) + 1; + if (!data) { + return NULL; + } + data->len = vallen + 1; + data->data_type = GF_DATA_TYPE_STR; - data->data = value; - data->is_static = 1; + data->data = value; + data->is_static = _gf_true; - return data; + return data; } -data_t * -data_from_dynstr (char *value) +static data_t * +data_from_dynstr(char *value) { - if (!value) { - gf_log ("dict", GF_LOG_CRITICAL, - "@value=%p", value); - return NULL; - } + if (!value) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "value is NULL"); + return NULL; + } - data_t *data = get_new_data (); + data_t *data = get_new_data(); - data->len = strlen (value) + 1; - data->data = value; + if (!data) + return NULL; + data->len = strlen(value) + 1; + data->data = value; + data->data_type = GF_DATA_TYPE_STR; - return data; + return data; } data_t * -data_from_dynptr (void *value, int32_t len) +data_from_dynptr(void *value, int32_t len) { - data_t *data = get_new_data (); + data_t *data = get_new_data(); + + if (!data) + return NULL; - data->len = len; - data->data = value; + data->len = len; + data->data = value; + data->data_type = GF_DATA_TYPE_PTR; - return data; + return data; } data_t * -bin_to_data (void *value, int32_t len) +bin_to_data(void *value, int32_t len) { - if (!value) { - gf_log ("dict", GF_LOG_CRITICAL, - "@value=%p", value); - return NULL; - } + if (!value) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "value is NULL"); + return NULL; + } - data_t *data = get_new_data (); + data_t *data = get_new_data(); - data->is_static = 1; - data->len = len; - data->data = value; + if (!data) + return NULL; - return data; + data->is_static = _gf_true; + data->len = len; + data->data = value; + + return data; } +static char *data_type_name[GF_DATA_TYPE_MAX] = { + [GF_DATA_TYPE_UNKNOWN] = "unknown", + [GF_DATA_TYPE_STR_OLD] = "string-old-version", + [GF_DATA_TYPE_INT] = "integer", + [GF_DATA_TYPE_UINT] = "unsigned integer", + [GF_DATA_TYPE_DOUBLE] = "float", + [GF_DATA_TYPE_STR] = "string", + [GF_DATA_TYPE_PTR] = "pointer", + [GF_DATA_TYPE_GFUUID] = "gf-uuid", + [GF_DATA_TYPE_IATT] = "iatt", + [GF_DATA_TYPE_MDATA] = "mdata", +}; + int64_t -data_to_int64 (data_t *data) -{ - if (!data) - return -1; +data_to_int64(data_t *data) +{ + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, "null", -1); + + char *endptr = NULL; + int64_t value = 0; + + errno = 0; + value = strtoll(data->data, &endptr, 0); + + if (endptr && *endptr != '\0') + /* Unrecognized characters at the end of string. */ + errno = EINVAL; + if (errno) { + gf_msg_callingfn("dict", GF_LOG_WARNING, errno, + LG_MSG_DATA_CONVERSION_ERROR, + "Error in data conversion: '%s' can't " + "be represented as int64_t", + data->data); + return -1; + } + return value; +} + +/* Like above but implies signed range check. */ + +#define DATA_TO_RANGED_SIGNED(endptr, value, data, type, min, max) \ + do { \ + errno = 0; \ + value = strtoll(data->data, &endptr, 0); \ + if (endptr && *endptr != '\0') \ + errno = EINVAL; \ + if (errno || value > max || value < min) { \ + gf_msg_callingfn("dict", GF_LOG_WARNING, errno, \ + LG_MSG_DATA_CONVERSION_ERROR, \ + "Error in data conversion: '%s' can't " \ + "be represented as " #type, \ + data->data); \ + return -1; \ + } \ + return (type)value; \ + } while (0) - char *str = alloca (data->len + 1); - if (!str) - return -1; +int32_t +data_to_int32(data_t *data) +{ + char *endptr = NULL; + int64_t value = 0; - memcpy (str, data->data, data->len); - str[data->len] = '\0'; - return (int64_t) strtoull (str, NULL, 0); + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, "null", -1); + DATA_TO_RANGED_SIGNED(endptr, value, data, int32_t, INT_MIN, INT_MAX); } -int32_t -data_to_int32 (data_t *data) +int16_t +data_to_int16(data_t *data) { - if (!data) - return -1; + char *endptr = NULL; + int64_t value = 0; - char *str = alloca (data->len + 1); - if (!str) - return -1; + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, "null", -1); + DATA_TO_RANGED_SIGNED(endptr, value, data, int16_t, SHRT_MIN, SHRT_MAX); +} - memcpy (str, data->data, data->len); - str[data->len] = '\0'; +int8_t +data_to_int8(data_t *data) +{ + char *endptr = NULL; + int64_t value = 0; - return strtoul (str, NULL, 0); + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, "null", -1); + DATA_TO_RANGED_SIGNED(endptr, value, data, int8_t, CHAR_MIN, CHAR_MAX); } -int16_t -data_to_int16 (data_t *data) +uint64_t +data_to_uint64(data_t *data) +{ + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, "null", -1); + + char *endptr = NULL; + uint64_t value = 0; + + errno = 0; + value = strtoull(data->data, &endptr, 0); + + if (endptr && *endptr != '\0') + errno = EINVAL; + if (errno) { + gf_msg_callingfn("dict", GF_LOG_WARNING, errno, + LG_MSG_DATA_CONVERSION_ERROR, + "Error in data conversion: '%s' can't " + "be represented as uint64_t", + data->data); + return -1; + } + return value; +} + +/* Like above but implies unsigned range check. */ + +#define DATA_TO_RANGED_UNSIGNED(endptr, value, data, type, max) \ + do { \ + errno = 0; \ + value = strtoull(data->data, &endptr, 0); \ + if (endptr && *endptr != '\0') \ + errno = EINVAL; \ + if (errno || value > max) { \ + gf_msg_callingfn("dict", GF_LOG_WARNING, errno, \ + LG_MSG_DATA_CONVERSION_ERROR, \ + "Error in data conversion: '%s' can't " \ + "be represented as " #type, \ + data->data); \ + return -1; \ + } \ + return (type)value; \ + } while (0) + +uint32_t +data_to_uint32(data_t *data) { - if (!data) - return -1; + char *endptr = NULL; + uint64_t value = 0; - char *str = alloca (data->len + 1); - if (!str) - return -1; + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, "null", -1); + DATA_TO_RANGED_UNSIGNED(endptr, value, data, uint32_t, UINT_MAX); +} - memcpy (str, data->data, data->len); - str[data->len] = '\0'; +uint16_t +data_to_uint16(data_t *data) +{ + char *endptr = NULL; + uint64_t value = 0; - return strtol (str, NULL, 0); + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, "null", -1); + DATA_TO_RANGED_UNSIGNED(endptr, value, data, uint16_t, USHRT_MAX); } - -int8_t -data_to_int8 (data_t *data) +uint8_t +data_to_uint8(data_t *data) { - if (!data) - return -1; + char *endptr = NULL; + uint64_t value = 0; - char *str = alloca (data->len + 1); - if (!str) - return -1; + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, "null", -1); + DATA_TO_RANGED_UNSIGNED(endptr, value, data, uint8_t, UCHAR_MAX); +} - memcpy (str, data->data, data->len); - str[data->len] = '\0'; +char * +data_to_str(data_t *data) +{ + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_STR, "null", NULL); + return data->data; +} - return (int8_t)strtol (str, NULL, 0); +void * +data_to_ptr(data_t *data) +{ + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, "null", NULL); + return data->data; } +void * +data_to_bin(data_t *data) +{ + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, "null", NULL); + return data->data; +} -uint64_t -data_to_uint64 (data_t *data) +struct iatt * +data_to_iatt(data_t *data, char *key) { - if (!data) - return -1; - char *str = alloca (data->len + 1); - if (!str) - return -1; + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_IATT, key, NULL); - memcpy (str, data->data, data->len); - str[data->len] = '\0'; + /* We only check for smaller size. If it's bigger we simply ignore + * the extra data. This way it's easy to do changes in the future that + * pass more data but are backward compatible (if the initial contents + * of the struct are maintained, of course). */ + if (data->len < sizeof(struct iatt)) { + gf_smsg("glusterfs", GF_LOG_ERROR, ENOBUFS, LG_MSG_UNDERSIZED_BUF, + "key=%s", key, NULL); + return NULL; + } - return strtoll (str, NULL, 0); + return (struct iatt *)data->data; } -uint32_t -data_to_uint32 (data_t *data) +int +dict_null_foreach_fn(dict_t *d, char *k, data_t *v, void *tmp) { - if (!data) - return -1; - - char *str = alloca (data->len + 1); - if (!str) - return -1; + return 0; +} - memcpy (str, data->data, data->len); - str[data->len] = '\0'; +int +dict_remove_foreach_fn(dict_t *d, char *k, data_t *v, void *_tmp) +{ + if (!d || !k) { + gf_smsg("glusterfs", GF_LOG_WARNING, EINVAL, LG_MSG_KEY_OR_VALUE_NULL, + "d=%s", d ? "key" : "dictionary", NULL); + return -1; + } - return strtol (str, NULL, 0); + dict_del(d, k); + return 0; } -uint16_t -data_to_uint16 (data_t *data) +gf_boolean_t +dict_match_everything(dict_t *d, char *k, data_t *v, void *data) { - if (!data) - return -1; + return _gf_true; +} - char *str = alloca (data->len + 1); - if (!str) - return -1; +int +dict_foreach(dict_t *dict, + int (*fn)(dict_t *this, char *key, data_t *value, void *data), + void *data) +{ + int ret = dict_foreach_match(dict, dict_match_everything, NULL, fn, data); - memcpy (str, data->data, data->len); - str[data->len] = '\0'; + if (ret > 0) + ret = 0; - return strtol (str, NULL, 0); + return ret; } -char * -data_to_str (data_t *data) -{ - if (!data) { - gf_log ("dict", GF_LOG_CRITICAL, - "@data=%p", data); - return NULL; - } - return data->data; +/* return values: + -1 = failure, + 0 = no matches found, + +n = n number of matches +*/ +int +dict_foreach_match(dict_t *dict, + gf_boolean_t (*match)(dict_t *this, char *key, data_t *value, + void *mdata), + void *match_data, + int (*action)(dict_t *this, char *key, data_t *value, + void *adata), + void *action_data) +{ + if (!dict || !match || !action) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict|match|action is " + "NULL"); + return -1; + } + + int ret = -1; + int count = 0; + data_pair_t *pairs = dict->members_list; + data_pair_t *next = NULL; + + while (pairs) { + next = pairs->next; + if (match(dict, pairs->key, pairs->value, match_data)) { + ret = action(dict, pairs->key, pairs->value, action_data); + if (ret < 0) + return ret; + count++; + } + pairs = next; + } + + return count; } -void * -data_to_ptr (data_t *data) +static gf_boolean_t +dict_fnmatch(dict_t *d, char *k, data_t *val, void *match_data) { - if (!data) { - return NULL; - } - return data->data; + return (fnmatch(match_data, k, 0) == 0); } - -void * -data_to_bin (data_t *data) +/* return values: + -1 = failure, + 0 = no matches found, + +n = n number of matches +*/ +int +dict_foreach_fnmatch(dict_t *dict, char *pattern, + int (*fn)(dict_t *this, char *key, data_t *value, + void *data), + void *data) { - if (!data) { - gf_log ("dict", GF_LOG_CRITICAL, - "@data=%p", data); - return NULL; - } - return data->data; + return dict_foreach_match(dict, dict_fnmatch, pattern, fn, data); } -void -dict_foreach (dict_t *dict, - void (*fn)(dict_t *this, - char *key, - data_t *value, - void *data), - void *data) +/** + * dict_keys_join - pack the keys of the dictionary in a buffer. + * + * @value : buffer in which the keys will be packed (can be NULL) + * @size : size of the buffer which is sent (can be 0, in which case buffer + * is not packed but only length is returned) + * @dict : dictionary of which all the keys will be packed + * @filter_fn : keys matched in filter_fn() is counted. + * + * @return : @length of string after joining keys. + * + */ + +int +dict_keys_join(void *value, int size, dict_t *dict, int (*filter_fn)(char *k)) { - if (!data) { - gf_log ("dict", GF_LOG_CRITICAL, - "@data=%p", data); - return; - } + int len = 0; + data_pair_t *pairs = dict->members_list; + data_pair_t *next = NULL; - data_pair_t *pairs = dict->members_list; + while (pairs) { + next = pairs->next; - while (pairs) { - fn (dict, pairs->key, pairs->value, data); - pairs = pairs->next; - } -} + if (filter_fn && filter_fn(pairs->key)) { + pairs = next; + continue; + } + if (value && (size > len)) + strncpy(value + len, pairs->key, size - len); -static void -_copy (dict_t *unused, - char *key, - data_t *value, - void *newdict) -{ - dict_set ((dict_t *)newdict, key, (value)); + len += (strlen(pairs->key) + 1); + + pairs = next; + } + + return len; } +static int +dict_copy_one(dict_t *unused, char *key, data_t *value, void *newdict) +{ + return dict_set((dict_t *)newdict, key, (value)); +} dict_t * -dict_copy (dict_t *dict, - dict_t *new) +dict_copy(dict_t *dict, dict_t *new) { - if (!dict) { - gf_log ("dict", GF_LOG_CRITICAL, - "@data=%p", dict); - return NULL; - } + if (!dict) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict is NULL"); + return NULL; + } - if (!new) - new = get_new_dict_full (dict->hash_size); + if (!new) + new = get_new_dict_full(dict->hash_size); - dict_foreach (dict, _copy, new); + dict_foreach(dict, dict_copy_one, new); + + return new; +} - return new; +int +dict_reset(dict_t *dict) +{ + int32_t ret = -1; + if (!dict) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict is NULL"); + goto out; + } + dict_foreach(dict, dict_remove_foreach_fn, NULL); + ret = 0; +out: + return ret; } dict_t * -dict_copy_with_ref (dict_t *dict, - dict_t *new) +dict_copy_with_ref(dict_t *dict, dict_t *new) { - dict_t *local_new = NULL; + dict_t *local_new = NULL; - GF_VALIDATE_OR_GOTO("dict", dict, fail); + GF_VALIDATE_OR_GOTO("dict", dict, fail); - if (new == NULL) { - local_new = dict_new (); - GF_VALIDATE_OR_GOTO("dict", local_new, fail); - new = local_new; - } + if (new == NULL) { + local_new = dict_new(); + GF_VALIDATE_OR_GOTO("dict", local_new, fail); + new = local_new; + } - dict_foreach (dict, _copy, new); + dict_foreach(dict, dict_copy_one, new); fail: - return new; + return new; } /* @@ -1279,850 +1490,1392 @@ fail: /** * Common cleaned up interface: - * + * * Return value: 0 success * -val error, val = errno */ - static int -dict_get_with_ref (dict_t *this, char *key, data_t **data) +dict_get_with_refn(dict_t *this, char *key, const int keylen, data_t **data) { - data_pair_t * pair = NULL; - int ret = -ENOENT; + data_pair_t *pair = NULL; + int ret = -ENOENT; + uint32_t hash; - if (!this || !key || !data) { - ret = -EINVAL; - goto err; - } + hash = (uint32_t)XXH64(key, keylen, 0); - LOCK (&this->lock); - { - pair = _dict_lookup (this, key); - } - UNLOCK (&this->lock); + LOCK(&this->lock); + { + pair = dict_lookup_common(this, key, hash); - if (pair) { - ret = 0; - *data = data_ref (pair->value); - } + if (pair) { + ret = 0; + *data = data_ref(pair->value); + } + } + UNLOCK(&this->lock); + + return ret; +} + +int +dict_get_with_ref(dict_t *this, char *key, data_t **data) +{ + if (!this || !key || !data) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict OR key (%s) is NULL", key); + return -EINVAL; + } -err: - return ret; + return dict_get_with_refn(this, key, strlen(key), data); } static int -_data_to_ptr (data_t *data, void **val) +data_to_ptr_common(data_t *data, void **val) { - int ret = 0; + int ret = 0; - if (!data) { - ret = -EINVAL; - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - *val = data->data; + *val = data->data; err: - return ret; + return ret; } - static int -_data_to_int8 (data_t *data, int8_t *val) +data_to_int8_ptr(data_t *data, int8_t *val) { - int ret = 0; - char * str = NULL; - - if (!data || !val) { - ret = -EINVAL; - goto err; - } + int ret = 0; - str = alloca (data->len + 1); - if (!str) { - ret = -ENOMEM; - goto err; - } - memcpy (str, data->data, data->len); - str[data->len] = '\0'; + if (!data || !val) { + ret = -EINVAL; + goto err; + } - errno = 0; - *val = strtol (str, NULL, 0); - if (errno != 0) - ret = -errno; + errno = 0; + *val = strtol(data->data, NULL, 0); + if (errno != 0) + ret = -errno; err: - return ret; + return ret; } static int -_data_to_int16 (data_t *data, int16_t *val) +data_to_int16_ptr(data_t *data, int16_t *val) { - int ret = 0; - char * str = NULL; + int ret = 0; - if (!data || !val) { - ret = -EINVAL; - goto err; - } + if (!data || !val) { + ret = -EINVAL; + goto err; + } - str = alloca (data->len + 1); - if (!str) { - ret = -ENOMEM; - goto err; - } - memcpy (str, data->data, data->len); - str[data->len] = '\0'; - - errno = 0; - *val = strtol (str, NULL, 0); - if (errno != 0) - ret = -errno; + errno = 0; + *val = strtol(data->data, NULL, 0); + if (errno != 0) + ret = -errno; err: - return ret; + return ret; } static int -_data_to_int32 (data_t *data, int32_t *val) +data_to_int32_ptr(data_t *data, int32_t *val) { - int ret = 0; - char * str = NULL; - - if (!data || !val) { - ret = -EINVAL; - goto err; - } + int ret = 0; - str = alloca (data->len + 1); - if (!str) { - ret = -ENOMEM; - goto err; - } - memcpy (str, data->data, data->len); - str[data->len] = '\0'; + if (!data || !val) { + ret = -EINVAL; + goto err; + } - errno = 0; - *val = strtol (str, NULL, 0); - if (errno != 0) - ret = -errno; + errno = 0; + *val = strtol(data->data, NULL, 0); + if (errno != 0) + ret = -errno; err: - return ret; + return ret; } static int -_data_to_int64 (data_t *data, int64_t *val) +data_to_int64_ptr(data_t *data, int64_t *val) { - int ret = 0; - char * str = NULL; + int ret = 0; - if (!data || !val) { - ret = -EINVAL; - goto err; - } + if (!data || !val) { + ret = -EINVAL; + goto err; + } - str = alloca (data->len + 1); - if (!str) { - ret = -ENOMEM; - goto err; - } - memcpy (str, data->data, data->len); - str[data->len] = '\0'; - - errno = 0; - *val = strtoll (str, NULL, 0); - if (errno != 0) - ret = -errno; + errno = 0; + *val = strtoll(data->data, NULL, 0); + if (errno != 0) + ret = -errno; err: - return ret; + return ret; } static int -_data_to_uint16 (data_t *data, uint16_t *val) +data_to_uint16_ptr(data_t *data, uint16_t *val) { - int ret = 0; - char * str = NULL; - - if (!data || !val) { - ret = -EINVAL; - goto err; - } + int ret = 0; - str = alloca (data->len + 1); - if (!str) { - ret = -ENOMEM; - goto err; - } - memcpy (str, data->data, data->len); - str[data->len] = '\0'; + if (!data || !val) { + ret = -EINVAL; + goto err; + } - errno = 0; - *val = strtoul (str, NULL, 0); - if (errno != 0) - ret = -errno; + errno = 0; + *val = strtoul(data->data, NULL, 0); + if (errno != 0) + ret = -errno; err: - return ret; + return ret; } static int -_data_to_uint32 (data_t *data, uint32_t *val) +data_to_uint32_ptr(data_t *data, uint32_t *val) { - int ret = 0; - char * str = NULL; + int ret = 0; - if (!data || !val) { - ret = -EINVAL; - goto err; - } + if (!data || !val) { + ret = -EINVAL; + goto err; + } - str = alloca (data->len + 1); - if (!str) { - ret = -ENOMEM; - goto err; - } - memcpy (str, data->data, data->len); - str[data->len] = '\0'; - - errno = 0; - *val = strtoul (str, NULL, 0); - if (errno != 0) - ret = -errno; + errno = 0; + *val = strtoul(data->data, NULL, 0); + if (errno != 0) + ret = -errno; err: - return ret; + return ret; } static int -_data_to_uint64 (data_t *data, uint64_t *val) +data_to_uint64_ptr(data_t *data, uint64_t *val) { - int ret = 0; - char * str = NULL; - - if (!data || !val) { - ret = -EINVAL; - goto err; - } + int ret = 0; - str = alloca (data->len + 1); - if (!str) { - ret = -ENOMEM; - goto err; - } - memcpy (str, data->data, data->len); - str[data->len] = '\0'; + if (!data || !val) { + ret = -EINVAL; + goto err; + } - errno = 0; - *val = strtoull (str, NULL, 0); - if (errno != 0) - ret = -errno; + errno = 0; + *val = strtoull(data->data, NULL, 0); + if (errno != 0) + ret = -errno; err: - return ret; + return ret; } static int -_data_to_double (data_t *data, double *val) +data_to_double_ptr(data_t *data, double *val) { - int ret = 0; - char * str = NULL; + int ret = 0; - if (!data || !val) { - ret = -EINVAL; - goto err; - } + if (!data || !val) { + ret = -EINVAL; + goto err; + } - str = alloca (data->len + 1); - if (!str) { - ret = -ENOMEM; - goto err; - } - memcpy (str, data->data, data->len); - str[data->len] = '\0'; + errno = 0; + *val = strtod(data->data, NULL); + if (errno != 0) + ret = -errno; - errno = 0; - *val = strtod (str, NULL); - if (errno != 0) - ret = -errno; +err: + return ret; +} + +int +dict_get_int8(dict_t *this, char *key, int8_t *val) +{ + data_t *data = NULL; + int ret = 0; + + if (!val) { + ret = -EINVAL; + goto err; + } + + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } + + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL); + + ret = data_to_int8_ptr(data, val); err: - return ret; + if (data) + data_unref(data); + return ret; } int -dict_get_int8 (dict_t *this, char *key, int8_t *val) +dict_set_int8(dict_t *this, char *key, int8_t val) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; - if (!this || !key || !val) { - ret = -EINVAL; - goto err; - } + data = data_from_int8(val); + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_get_with_ref (this, key, &data); - if (ret != 0) { - goto err; - } + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); - ret = _data_to_int8 (data, val); - err: - if (data) - data_unref (data); - return ret; + return ret; } +int +dict_get_int16(dict_t *this, char *key, int16_t *val) +{ + data_t *data = NULL; + int ret = 0; + + if (!val) { + ret = -EINVAL; + goto err; + } + + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } + + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL); + + ret = data_to_int16_ptr(data, val); + +err: + if (data) + data_unref(data); + return ret; +} int -dict_set_int8 (dict_t *this, char *key, int8_t val) +dict_set_int16(dict_t *this, char *key, int16_t val) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; - data = data_from_int8 (val); - if (!data) { - ret = -EINVAL; - goto err; - } + data = data_from_int16(val); + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_set (this, key, data); + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); err: - return ret; + return ret; } int -dict_get_int16 (dict_t *this, char *key, int16_t *val) +dict_get_int32n(dict_t *this, char *key, const int keylen, int32_t *val) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; - if (!this || !key || !val) { - ret = -EINVAL; - goto err; - } + if (!this || !key || !val) { + ret = -EINVAL; + goto err; + } - ret = dict_get_with_ref (this, key, &data); - if (ret != 0) { - goto err; - } + ret = dict_get_with_refn(this, key, keylen, &data); + if (ret != 0) { + goto err; + } + + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL); + + ret = data_to_int32_ptr(data, val); - ret = _data_to_int16 (data, val); - err: - if (data) - data_unref (data); - return ret; + if (data) + data_unref(data); + return ret; } +int +dict_get_int32(dict_t *this, char *key, int32_t *val) +{ + data_t *data = NULL; + int ret = 0; + + if (!val) { + ret = -EINVAL; + goto err; + } + + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } + + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL); + + ret = data_to_int32_ptr(data, val); + +err: + if (data) + data_unref(data); + return ret; +} int -dict_set_int16 (dict_t *this, char *key, int16_t val) +dict_set_int32n(dict_t *this, char *key, const int keylen, int32_t val) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; - data = data_from_int16 (val); - if (!data) { - ret = -EINVAL; - goto err; - } + data = data_from_int32(val); + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_set (this, key, data); + ret = dict_setn(this, key, keylen, data); + if (ret < 0) + data_destroy(data); err: - return ret; + return ret; } int -dict_get_int32 (dict_t *this, char *key, int32_t *val) +dict_set_int32(dict_t *this, char *key, int32_t val) { - data_t * data = NULL; - int ret = 0; + data_t *data = data_from_int32(val); + int ret = 0; - if (!this || !key || !val) { - ret = -EINVAL; - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_get_with_ref (this, key, &data); - if (ret != 0) { - goto err; - } + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); - ret = _data_to_int32 (data, val); - err: - if (data) - data_unref (data); - return ret; + return ret; } +int +dict_get_int64(dict_t *this, char *key, int64_t *val) +{ + data_t *data = NULL; + int ret = 0; + + if (!val) { + ret = -EINVAL; + goto err; + } + + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } + + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL); + + ret = data_to_int64_ptr(data, val); + +err: + if (data) + data_unref(data); + return ret; +} int -dict_set_int32 (dict_t *this, char *key, int32_t val) +dict_set_int64(dict_t *this, char *key, int64_t val) { - data_t * data = NULL; - int ret = 0; + data_t *data = data_from_int64(val); + int ret = 0; - data = data_from_int32 (val); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_set (this, key, data); + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); err: - return ret; + return ret; } int -dict_get_int64 (dict_t *this, char *key, int64_t *val) +dict_get_uint16(dict_t *this, char *key, uint16_t *val) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; + + if (!val) { + ret = -EINVAL; + goto err; + } - if (!this || !key || !val) { - ret = -EINVAL; - goto err; - } + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } - ret = dict_get_with_ref (this, key, &data); - if (ret != 0) { - goto err; - } + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, key, -EINVAL); + + ret = data_to_uint16_ptr(data, val); - ret = _data_to_int64 (data, val); - err: - if (data) - data_unref (data); - return ret; + if (data) + data_unref(data); + return ret; } +int +dict_set_uint16(dict_t *this, char *key, uint16_t val) +{ + data_t *data = data_from_uint16(val); + int ret = 0; + + if (!data) { + ret = -EINVAL; + goto err; + } + + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); + +err: + return ret; +} int -dict_set_int64 (dict_t *this, char *key, int64_t val) +dict_get_uint32(dict_t *this, char *key, uint32_t *val) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; + + if (!val) { + ret = -EINVAL; + goto err; + } + + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } - data = data_from_int64 (val); - if (!data) { - ret = -EINVAL; - goto err; - } + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, key, -EINVAL); - ret = dict_set (this, key, data); + ret = data_to_uint32_ptr(data, val); err: - return ret; + if (data) + data_unref(data); + return ret; } int -dict_get_uint16 (dict_t *this, char *key, uint16_t *val) +dict_set_uint32(dict_t *this, char *key, uint32_t val) { - data_t * data = NULL; - int ret = 0; + data_t *data = data_from_uint32(val); + int ret = 0; - if (!this || !key || !val) { - ret = -EINVAL; - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_get_with_ref (this, key, &data); - if (ret != 0) { - goto err; - } + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); - ret = _data_to_uint16 (data, val); - err: - if (data) - data_unref (data); - return ret; + return ret; } +int +dict_get_uint64(dict_t *this, char *key, uint64_t *val) +{ + data_t *data = NULL; + int ret = 0; + + if (!val) { + ret = -EINVAL; + goto err; + } + + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } + + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, key, -EINVAL); + + ret = data_to_uint64_ptr(data, val); + +err: + if (data) + data_unref(data); + return ret; +} int -dict_set_uint16 (dict_t *this, char *key, uint16_t val) +dict_set_uint64(dict_t *this, char *key, uint64_t val) { - data_t * data = NULL; - int ret = 0; + data_t *data = data_from_uint64(val); + int ret = 0; - data = data_from_uint16 (val); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_set (this, key, data); + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); err: - return ret; + return ret; } +/* + * dict_check_flag can be used to check a one bit flag in an array of flags + * The flag argument indicates the bit position (within the array of bits). + * Currently limited to max of 256 flags for a key. + * return value, + * 1 : flag is set + * 0 : flag is not set + * <0: Error + */ int -dict_get_uint32 (dict_t *this, char *key, uint32_t *val) +dict_check_flag(dict_t *this, char *key, int flag) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = -ENOENT; + + ret = dict_get_with_ref(this, key, &data); + if (ret < 0) { + return ret; + } - if (!this || !key || !val) { - ret = -EINVAL; - goto err; - } + if (BIT_VALUE((unsigned char *)(data->data), flag)) + ret = 1; + else + ret = 0; + + data_unref(data); + return ret; +} + +/* + * _dict_modify_flag can be used to set/clear a bit flag in an array of flags + * flag: indicates the bit position. limited to max of DICT_MAX_FLAGS. + * op: Indicates operation DICT_FLAG_SET / DICT_FLAG_CLEAR + */ +static int +_dict_modify_flag(dict_t *this, char *key, int flag, int op) +{ + data_t *data = NULL; + int ret = 0; + data_pair_t *pair = NULL; + char *ptr = NULL; + int hashval = 0; + uint32_t hash; + + if (!this || !key) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict OR key (%s) is NULL", key); + ret = -EINVAL; + goto err; + } + + /* + * Using a size of 32 bytes to support max of 256 + * flags in a single key. This should be suffcient. + */ + GF_ASSERT(flag >= 0 && flag < DICT_MAX_FLAGS); + + hash = (uint32_t)XXH64(key, strlen(key), 0); + LOCK(&this->lock); + { + pair = dict_lookup_common(this, key, hash); + + if (pair) { + data = pair->value; + if (op == DICT_FLAG_SET) + BIT_SET((unsigned char *)(data->data), flag); + else + BIT_CLEAR((unsigned char *)(data->data), flag); + } else { + ptr = GF_CALLOC(1, DICT_MAX_FLAGS / 8, gf_common_mt_char); + if (!ptr) { + gf_smsg("dict", GF_LOG_ERROR, ENOMEM, LG_MSG_NO_MEMORY, + "flag bit array", NULL); + ret = -ENOMEM; + goto err; + } + + data = data_from_dynptr(ptr, DICT_MAX_FLAGS / 8); + + if (!data) { + gf_smsg("dict", GF_LOG_ERROR, ENOMEM, LG_MSG_NO_MEMORY, "data", + NULL); + GF_FREE(ptr); + ret = -ENOMEM; + goto err; + } + + if (op == DICT_FLAG_SET) + BIT_SET((unsigned char *)(data->data), flag); + else + BIT_CLEAR((unsigned char *)(data->data), flag); + + if (this->free_pair.key) { /* the free pair is in use */ + pair = mem_get0(THIS->ctx->dict_pair_pool); + if (!pair) { + gf_smsg("dict", GF_LOG_ERROR, ENOMEM, LG_MSG_NO_MEMORY, + "dict pair", NULL); + ret = -ENOMEM; + goto err; + } + } else { /* use the free pair */ + pair = &this->free_pair; + } + + pair->key = (char *)GF_MALLOC(strlen(key) + 1, gf_common_mt_char); + if (!pair->key) { + gf_smsg("dict", GF_LOG_ERROR, ENOMEM, LG_MSG_NO_MEMORY, + "dict pair", NULL); + ret = -ENOMEM; + goto err; + } + strcpy(pair->key, key); + pair->key_hash = hash; + pair->value = data_ref(data); + this->totkvlen += (strlen(key) + 1 + data->len); + hashval = hash % this->hash_size; + pair->hash_next = this->members[hashval]; + this->members[hashval] = pair; + + pair->next = this->members_list; + pair->prev = NULL; + if (this->members_list) + this->members_list->prev = pair; + this->members_list = pair; + this->count++; + + if (this->max_count < this->count) + this->max_count = this->count; + } + } - ret = dict_get_with_ref (this, key, &data); - if (ret != 0) { - goto err; - } + UNLOCK(&this->lock); + return 0; - ret = _data_to_uint32 (data, val); - err: - if (data) - data_unref (data); - return ret; + if (key && this) + UNLOCK(&this->lock); + + if (pair) { + if (pair->key) { + GF_FREE(pair->key); + pair->key = NULL; + } + if (pair != &this->free_pair) { + mem_put(pair); + } + } + + if (data) + data_destroy(data); + + gf_smsg("dict", GF_LOG_ERROR, EINVAL, LG_MSG_DICT_SET_FAILED, "key=%s", key, + NULL); + + return ret; } +/* + * Todo: + * Add below primitives as needed: + * dict_check_flags(this, key, flag...): variadic function to check + * multiple flags at a time. + * dict_set_flags(this, key, flag...): set multiple flags + * dict_clear_flags(this, key, flag...): reset multiple flags + */ + +int +dict_set_flag(dict_t *this, char *key, int flag) +{ + return _dict_modify_flag(this, key, flag, DICT_FLAG_SET); +} +int +dict_clear_flag(dict_t *this, char *key, int flag) +{ + return _dict_modify_flag(this, key, flag, DICT_FLAG_CLEAR); +} int -dict_set_uint32 (dict_t *this, char *key, uint32_t val) +dict_get_double(dict_t *this, char *key, double *val) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; + + if (!val) { + ret = -EINVAL; + goto err; + } - data = data_from_uint32 (val); - if (!data) { - ret = -EINVAL; - goto err; - } + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } - ret = dict_set (this, key, data); + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_DOUBLE, key, -EINVAL); + + ret = data_to_double_ptr(data, val); err: - return ret; + if (data) + data_unref(data); + return ret; } int -dict_get_uint64 (dict_t *this, char *key, uint64_t *val) +dict_set_double(dict_t *this, char *key, double val) { - data_t * data = NULL; - int ret = 0; + data_t *data = data_from_double(val); + int ret = 0; - if (!this || !key || !val) { - ret = -EINVAL; - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_get_with_ref (this, key, &data); - if (ret != 0) { - goto err; - } + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); - ret = _data_to_uint64 (data, val); - err: - if (data) - data_unref (data); - return ret; + return ret; } +int +dict_set_static_ptr(dict_t *this, char *key, void *ptr) +{ + data_t *data = data_from_ptr_common(ptr, _gf_true); + int ret = 0; + + if (!data) { + ret = -EINVAL; + goto err; + } + + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); + +err: + return ret; +} int -dict_set_uint64 (dict_t *this, char *key, uint64_t val) +dict_set_dynptr(dict_t *this, char *key, void *ptr, size_t len) { - data_t * data = NULL; - int ret = 0; + data_t *data = data_from_dynptr(ptr, len); + int ret = 0; - data = data_from_uint64 (val); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_set (this, key, data); + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); err: - return ret; + return ret; } int -dict_get_double (dict_t *this, char *key, double *val) +dict_get_ptr(dict_t *this, char *key, void **ptr) { - data_t *data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; - if (!this || !key || !val) { - ret = -EINVAL; - goto err; - } + if (!ptr) { + ret = -EINVAL; + goto err; + } - ret = dict_get_with_ref (this, key, &data); - if (ret != 0) { - goto err; - } + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } - ret = _data_to_double (data, val); + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, key, -EINVAL); + + ret = data_to_ptr_common(data, ptr); + if (ret != 0) { + goto err; + } err: - if (data) - data_unref (data); - return ret; + if (data) + data_unref(data); + + return ret; } int -dict_set_double (dict_t *this, char *key, double val) +dict_get_ptr_and_len(dict_t *this, char *key, void **ptr, int *len) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; + + if (!ptr) { + ret = -EINVAL; + goto err; + } + + ret = dict_get_with_ref(this, key, &data); + if (ret != 0) { + goto err; + } - data = data_from_double (val); - if (!data) { - ret = -EINVAL; - goto err; - } + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, key, -EINVAL); - ret = dict_set (this, key, data); + *len = data->len; + + ret = data_to_ptr_common(data, ptr); + if (ret != 0) { + goto err; + } err: - return ret; + if (data) + data_unref(data); + + return ret; } +/* Get string - with known key length */ int -dict_set_static_ptr (dict_t *this, char *key, void *ptr) +dict_get_strn(dict_t *this, char *key, const int keylen, char **str) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = -EINVAL; - data = data_from_static_ptr (ptr); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!this || !key || !str) { + goto err; + } + ret = dict_get_with_refn(this, key, keylen, &data); + if (ret < 0) { + goto err; + } - ret = dict_set (this, key, data); + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_STR, key, -EINVAL); + + *str = data->data; err: - return ret; + if (data) + data_unref(data); + + return ret; } int -dict_set_dynptr (dict_t *this, char *key, void *ptr, size_t len) +dict_get_str(dict_t *this, char *key, char **str) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = -EINVAL; - data = data_from_dynptr (ptr, len); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!str) { + goto err; + } + ret = dict_get_with_ref(this, key, &data); + if (ret < 0) { + goto err; + } - ret = dict_set (this, key, data); + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_STR, key, -EINVAL); + + *str = data->data; err: - return ret; + if (data) + data_unref(data); + + return ret; } int -dict_get_ptr (dict_t *this, char *key, void **ptr) +dict_set_str(dict_t *this, char *key, char *str) { - data_t * data = NULL; - int ret = 0; + data_t *data = str_to_data(str); + int ret = 0; + + if (!data) { + ret = -EINVAL; + goto err; + } + + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); - if (!this || !key || !ptr) { - ret = -EINVAL; - goto err; - } +err: + return ret; +} - ret = dict_get_with_ref (this, key, &data); - if (ret != 0) { - goto err; - } +/* Set string - with known key length */ +int +dict_set_strn(dict_t *this, char *key, const int keylen, char *str) +{ + data_t *data = NULL; + int ret = 0; - ret = _data_to_ptr (data, ptr); - if (ret != 0) { - goto err; - } + data = str_to_data(str); + if (!data) { + ret = -EINVAL; + goto err; + } -err: - if (data) - data_unref (data); + ret = dict_setn(this, key, keylen, data); + if (ret < 0) + data_destroy(data); - return ret; +err: + return ret; } +/* Set string - with known key length and known value length */ int -dict_set_ptr (dict_t *this, char *key, void *ptr) +dict_set_nstrn(dict_t *this, char *key, const int keylen, char *str, + const int vallen) { - data_t * data = NULL; - int ret = 0; + data_t *data = strn_to_data(str, vallen); + int ret = 0; - data = data_from_ptr (ptr); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!data) { + ret = -EINVAL; + goto err; + } - ret = dict_set (this, key, data); + ret = dict_setn(this, key, keylen, data); + if (ret < 0) + data_destroy(data); err: - return ret; + return ret; +} + +int +dict_set_dynstr_with_alloc(dict_t *this, char *key, const char *str) +{ + char *alloc_str = gf_strdup(str); + int ret = -1; + + if (!alloc_str) + return ret; + + ret = dict_set_dynstr(this, key, alloc_str); + if (ret == -EINVAL) + GF_FREE(alloc_str); + + return ret; } +int +dict_set_dynstr(dict_t *this, char *key, char *str) +{ + const int keylen = strlen(key); + return dict_set_dynstrn(this, key, keylen, str); +} int -dict_get_str (dict_t *this, char *key, char **str) +dict_set_dynstrn(dict_t *this, char *key, const int keylen, char *str) { - data_t * data = NULL; - int ret = -EINVAL; + data_t *data = data_from_dynstr(str); + int ret = 0; + + if (!data) { + ret = -EINVAL; + goto err; + } - if (!this || !key || !str) { - goto err; - } + ret = dict_setn(this, key, keylen, data); + if (ret < 0) + data_destroy(data); - ret = dict_get_with_ref (this, key, &data); - if (ret < 0) { - goto err; - } +err: + return ret; +} - if (!data || !data->data) { - goto err; - } - *str = data->data; +/* This function is called only by the volgen for now. + Check how else you can handle it */ +int +dict_set_option(dict_t *this, char *key, char *str) +{ + data_t *data = data_from_dynstr(str); + int ret = 0; -err: - if (data) - data_unref (data); + if (!data) { + ret = -EINVAL; + goto err; + } - return ret; + data->data_type = GF_DATA_TYPE_STR_OLD; + ret = dict_set(this, key, data); + if (ret < 0) + data_destroy(data); +err: + return ret; } int -dict_set_str (dict_t *this, char *key, char *str) +dict_add_dynstr_with_alloc(dict_t *this, char *key, char *str) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = 0; + char *alloc_str = gf_strdup(str); - data = str_to_data (str); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!alloc_str) + goto out; - ret = dict_set (this, key, data); + data = data_from_dynstr(alloc_str); + if (!data) { + GF_FREE(alloc_str); + ret = -EINVAL; + goto out; + } -err: - return ret; + ret = dict_add(this, key, data); + if (ret < 0) + data_destroy(data); + +out: + return ret; } int -dict_set_dynstr (dict_t *this, char *key, char *str) +dict_get_bin(dict_t *this, char *key, void **bin) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + int ret = -EINVAL; - data = data_from_dynstr (str); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!bin) { + goto err; + } - ret = dict_set (this, key, data); + ret = dict_get_with_ref(this, key, &data); + if (ret < 0) { + goto err; + } + + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, key, ret); + + *bin = data->data; err: - return ret; + if (data) + data_unref(data); + + return ret; } +/******************************************************************** + * + * dict_set_bin_common: + * This is the common function to set key and its value in + * dictionary. Flag(is_static) should be set appropriately based + * on the type of memory type used for value(*ptr). If flag is set + * to false value(*ptr) will be freed using GF_FREE() on destroy. + * + *******************************************************************/ +static int +dict_set_bin_common(dict_t *this, char *key, void *ptr, size_t size, + gf_boolean_t is_static, gf_dict_data_type_t type) +{ + data_t *data = NULL; + int ret = 0; + + if (!ptr || (size > DICT_KEY_VALUE_MAX_SIZE)) { + ret = -EINVAL; + goto err; + } + data = bin_to_data(ptr, size); + if (!data) { + ret = -EINVAL; + goto err; + } + + data->is_static = is_static; + data->data_type = type; + + ret = dict_set(this, key, data); + if (ret < 0) { + /* don't free data->data, let callers handle it */ + data->data = NULL; + data_destroy(data); + } + +err: + return ret; +} + +/******************************************************************** + * + * dict_set_bin: + * Set key and its value in the dictionary. This function should + * be called if the value is stored in dynamic memory. + * + *******************************************************************/ int -dict_get_bin (dict_t *this, char *key, void **bin) +dict_set_bin(dict_t *this, char *key, void *ptr, size_t size) { - data_t * data = NULL; - int ret = -EINVAL; + return dict_set_bin_common(this, key, ptr, size, _gf_false, + GF_DATA_TYPE_PTR); +} + +/******************************************************************** + * + * dict_set_static_bin: + * Set key and its value in the dictionary. This function should + * be called if the value is stored in static memory. + * + *******************************************************************/ +int +dict_set_static_bin(dict_t *this, char *key, void *ptr, size_t size) +{ + return dict_set_bin_common(this, key, ptr, size, _gf_true, + GF_DATA_TYPE_PTR); +} + +/* */ +int +dict_set_gfuuid(dict_t *this, char *key, uuid_t gfid, bool is_static) +{ + return dict_set_bin_common(this, key, gfid, sizeof(uuid_t), is_static, + GF_DATA_TYPE_GFUUID); +} + +int +dict_get_gfuuid(dict_t *this, char *key, uuid_t *gfid) +{ + data_t *data = NULL; + int ret = -EINVAL; + + if (!gfid) { + goto err; + } + ret = dict_get_with_ref(this, key, &data); + if (ret < 0) { + goto err; + } - if (!this || !key || !bin) { - goto err; - } + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_GFUUID, key, -EINVAL); - ret = dict_get_with_ref (this, key, &data); - if (ret < 0) { - goto err; - } + memcpy(*gfid, data->data, min(data->len, sizeof(uuid_t))); - if (!data || !data->data) { - goto err; - } - *bin = data->data; +err: + if (data) + data_unref(data); -err: - if (data) - data_unref (data); + return ret; +} - return ret; +int +dict_set_mdata(dict_t *this, char *key, struct mdata_iatt *mdata, + bool is_static) +{ + return dict_set_bin_common(this, key, mdata, sizeof(struct mdata_iatt), + is_static, GF_DATA_TYPE_MDATA); } +int +dict_get_mdata(dict_t *this, char *key, struct mdata_iatt *mdata) +{ + data_t *data = NULL; + int ret = -EINVAL; + + if (!mdata) { + goto err; + } + ret = dict_get_with_ref(this, key, &data); + if (ret < 0) { + goto err; + } + + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_MDATA, key, -EINVAL); + if (data->len < sizeof(struct mdata_iatt)) { + gf_smsg("glusterfs", GF_LOG_ERROR, ENOBUFS, LG_MSG_UNDERSIZED_BUF, + "key=%s", key, NULL); + ret = -ENOBUFS; + goto err; + } + + memcpy(mdata, data->data, min(data->len, sizeof(struct mdata_iatt))); + +err: + if (data) + data_unref(data); + + return ret; +} int -dict_set_bin (dict_t *this, char *key, void *ptr, size_t size) +dict_set_iatt(dict_t *this, char *key, struct iatt *iatt, bool is_static) { - data_t * data = NULL; - int ret = 0; + return dict_set_bin_common(this, key, iatt, sizeof(struct iatt), is_static, + GF_DATA_TYPE_IATT); +} - if (!ptr || (size < 0)) { - ret = -EINVAL; - goto err; - } +int +dict_get_iatt(dict_t *this, char *key, struct iatt *iatt) +{ + data_t *data = NULL; + int ret = -EINVAL; - data = bin_to_data (ptr, size); - if (!data) { - ret = -EINVAL; - goto err; - } + if (!iatt) { + goto err; + } + ret = dict_get_with_ref(this, key, &data); + if (ret < 0) { + goto err; + } - data->data = ptr; - data->len = size; - data->is_static = 0; + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_IATT, key, -EINVAL); - ret = dict_set (this, key, data); + memcpy(iatt, data->data, min(data->len, sizeof(struct iatt))); err: - return ret; + if (data) + data_unref(data); + + return ret; } +/** + * dict_get_str_boolean - get a boolean value based on string representation. + * + * @this : dictionary + * @key : dictionary key queried + * @default_val : default value if key not found + * + * @return : @default_val if key not found + * : boolean interpretation of @this[@key] if it makes sense + * (ie., "on", "true", "enable" ...) + * : -1 if error occurs or @this[@key] doesn't make sens as + * boolean + * + * So if you query a boolean option, then via @default_val you can choose + * between following patterns: + * + * - fall back to _gf_false if @key is not set [@default_val = 0] + * - fall back to _gf_true if @key is not set [@default_val = 1] + * - regard as failure if @key is not set [@default_val = -1] + * - handle specially (not as error) if @key is not set + * [@default_val = anything else] + */ int -dict_set_static_bin (dict_t *this, char *key, void *ptr, size_t size) +dict_get_str_boolean(dict_t *this, char *key, int default_val) { - data_t * data = NULL; - int ret = 0; + data_t *data = NULL; + gf_boolean_t boo = _gf_false; + int ret = 0; - if (!ptr || (size < 0)) { - ret = -EINVAL; - goto err; - } + ret = dict_get_with_ref(this, key, &data); + if (ret < 0) { + if (ret == -ENOENT) + ret = default_val; + else + ret = -1; + goto err; + } - data = bin_to_data (ptr, size); - if (!data) { - ret = -EINVAL; - goto err; - } + VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL); - data->data = ptr; - data->len = size; - data->is_static = 1; + ret = gf_strn2boolean(data->data, data->len - 1, &boo); + if (ret == -1) + goto err; - ret = dict_set (this, key, data); + ret = boo; err: - return ret; + if (data) + data_unref(data); + + return ret; +} + +int +dict_rename_key(dict_t *this, char *key, char *replace_key) +{ + data_pair_t *pair = NULL; + int ret = -EINVAL; + uint32_t hash; + uint32_t replacekey_hash; + int replacekey_len; + + /* replacing a key by itself is a NO-OP */ + if (strcmp(key, replace_key) == 0) + return 0; + + if (!this) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict is NULL"); + return ret; + } + + hash = (uint32_t)XXH64(key, strlen(key), 0); + replacekey_len = strlen(replace_key); + replacekey_hash = (uint32_t)XXH64(replace_key, replacekey_len, 0); + + LOCK(&this->lock); + { + /* no need to data_ref(pair->value), dict_set_lk() does it */ + pair = dict_lookup_common(this, key, hash); + if (!pair) + ret = -ENODATA; + else + ret = dict_set_lk(this, replace_key, replacekey_len, pair->value, + replacekey_hash, 1); + } + UNLOCK(&this->lock); + + if (!ret) + /* only delete the key on success */ + dict_del(this, key); + + return ret; } /** @@ -2133,13 +2886,9 @@ err: * 4 4 4 <key len> <value len> */ -#define DICT_HDR_LEN 4 -#define DICT_DATA_HDR_KEY_LEN 4 -#define DICT_DATA_HDR_VAL_LEN 4 - /** - * _dict_serialized_length - return the length of serialized dict. This - * procedure has to be called with this->lock held. + * dict_serialized_length_lk - return the length of serialized dict. This + * procedure has to be called with this->lock held. * * @this : dict to be serialized * @return: success: len @@ -2147,167 +2896,103 @@ err: */ int -_dict_serialized_length (dict_t *this) -{ - int ret = -EINVAL; - int count = 0; - int len = 0; - int i = 0; - data_pair_t * pair = NULL; - - len = DICT_HDR_LEN; - count = this->count; - - if (count < 0) { - gf_log ("dict", GF_LOG_ERROR, "count (%d) < 0!", count); - goto out; - } - - pair = this->members_list; - - while (count) { - if (!pair) { - gf_log ("dict", GF_LOG_ERROR, - "less than count data pairs found!"); - goto out; - } - - len += DICT_DATA_HDR_KEY_LEN + DICT_DATA_HDR_VAL_LEN; - - if (!pair->key) { - gf_log ("dict", GF_LOG_ERROR, "pair->key is null!"); - goto out; - } - - len += strlen (pair->key) + 1 /* for '\0' */; - - if (!pair->value) { - gf_log ("dict", GF_LOG_ERROR, - "pair->value is null!"); - goto out; - } - - if (pair->value->vec) { - for (i = 0; i < pair->value->len; i++) { - if (pair->value->vec[i].iov_len < 0) { - gf_log ("dict", GF_LOG_ERROR, - "iov_len (%"GF_PRI_SIZET") < 0!", - pair->value->vec[i].iov_len); - goto out; - } - - len += pair->value->vec[i].iov_len; - } - } else { - if (pair->value->len < 0) { - gf_log ("dict", GF_LOG_ERROR, - "value->len (%d) < 0", - pair->value->len); - goto out; - } - - len += pair->value->len; - } - - pair = pair->next; - count--; - } - - ret = len; +dict_serialized_length_lk(dict_t *this) +{ + int ret = -EINVAL; + int count = this->count; + const int keyhdrlen = DICT_DATA_HDR_KEY_LEN + DICT_DATA_HDR_VAL_LEN; + + if (count < 0) { + gf_smsg("dict", GF_LOG_ERROR, EINVAL, LG_MSG_COUNT_LESS_THAN_ZERO, + "count=%d", count, NULL); + goto out; + } + + ret = DICT_HDR_LEN + this->totkvlen + (count * keyhdrlen); out: - return ret; + return ret; } /** - * _dict_serialize - serialize a dictionary into a buffer. This procedure has - * to be called with this->lock held. + * dict_serialize_lk - serialize a dictionary into a buffer. This procedure has + * to be called with this->lock held. * * @this: dict to serialize - * @buf: buffer to serialize into. This must be - * atleast dict_serialized_length (this) large + * @buf: buffer to serialize into. This must be + * at least dict_serialized_length (this) large * * @return: success: 0 * failure: -errno */ -int -_dict_serialize (dict_t *this, char *buf) -{ - int ret = -1; - data_pair_t * pair = NULL; - int32_t count = 0; - int32_t keylen = 0; - int32_t vallen = 0; - int32_t netword = 0; - - if (!buf) { - gf_log ("dict", GF_LOG_ERROR, - "buf is null!"); - goto out; - } - - count = this->count; - if (count < 0) { - gf_log ("dict", GF_LOG_ERROR, "count (%d) < 0!", count); - goto out; - } - - netword = hton32 (count); - memcpy (buf, &netword, sizeof(netword)); - buf += DICT_HDR_LEN; - pair = this->members_list; - - while (count) { - if (!pair) { - gf_log ("dict", GF_LOG_ERROR, - "less than count data pairs found!"); - goto out; - } - - if (!pair->key) { - gf_log ("dict", GF_LOG_ERROR, - "pair->key is null!"); - goto out; - } - - keylen = strlen (pair->key); - netword = hton32 (keylen); - memcpy (buf, &netword, sizeof(netword)); - buf += DICT_DATA_HDR_KEY_LEN; - - if (!pair->value) { - gf_log ("dict", GF_LOG_ERROR, - "pair->value is null!"); - goto out; - } - - vallen = pair->value->len; - netword = hton32 (vallen); - memcpy (buf, &netword, sizeof(netword)); - buf += DICT_DATA_HDR_VAL_LEN; - - memcpy (buf, pair->key, keylen); - buf += keylen; - *buf++ = '\0'; - - if (!pair->value->data) { - gf_log ("dict", GF_LOG_ERROR, - "pair->value->data is null!"); - goto out; - } - memcpy (buf, pair->value->data, vallen); - buf += vallen; - - pair = pair->next; - count--; - } - - ret = 0; +static int +dict_serialize_lk(dict_t *this, char *buf) +{ + int ret = -1; + data_pair_t *pair = this->members_list; + int32_t count = this->count; + int32_t keylen = 0; + int32_t netword = 0; + + if (!buf) { + gf_smsg("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, NULL); + goto out; + } + + if (count < 0) { + gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_COUNT_LESS_THAN_ZERO, + "count=%d", count, NULL); + goto out; + } + + netword = hton32(count); + memcpy(buf, &netword, sizeof(netword)); + buf += DICT_HDR_LEN; + + while (count) { + if (!pair) { + gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_PAIRS_LESS_THAN_COUNT, + NULL); + goto out; + } + + if (!pair->key) { + gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_NULL_PTR, NULL); + goto out; + } + + keylen = strlen(pair->key); + netword = hton32(keylen); + memcpy(buf, &netword, sizeof(netword)); + buf += DICT_DATA_HDR_KEY_LEN; + + if (!pair->value) { + gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_NULL_PTR, NULL); + goto out; + } + + netword = hton32(pair->value->len); + memcpy(buf, &netword, sizeof(netword)); + buf += DICT_DATA_HDR_VAL_LEN; + + memcpy(buf, pair->key, keylen); + buf += keylen; + *buf++ = '\0'; + + if (pair->value->data) { + memcpy(buf, pair->value->data, pair->value->len); + buf += pair->value->len; + } + + pair = pair->next; + count--; + } + + ret = 0; out: - return ret; + return ret; } - /** * dict_serialized_length - return the length of serialized dict * @@ -2317,245 +3002,488 @@ out: */ int -dict_serialized_length (dict_t *this) -{ - int ret = -EINVAL; - - if (!this) { - gf_log ("dict", GF_LOG_ERROR, "this is null!"); - goto out; - } - - LOCK (&this->lock); - { - ret = _dict_serialized_length (this); - } - UNLOCK (&this->lock); +dict_serialized_length(dict_t *this) +{ + int ret = -EINVAL; + + if (!this) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict is null!"); + goto out; + } + + LOCK(&this->lock); + { + ret = dict_serialized_length_lk(this); + } + UNLOCK(&this->lock); out: - return ret; + return ret; } /** * dict_serialize - serialize a dictionary into a buffer * * @this: dict to serialize - * @buf: buffer to serialize into. This must be - * atleast dict_serialized_length (this) large + * @buf: buffer to serialize into. This must be + * at least dict_serialized_length (this) large * * @return: success: 0 * failure: -errno */ int -dict_serialize (dict_t *this, char *buf) -{ - int ret = -1; - - if (!this) { - gf_log ("dict", GF_LOG_ERROR, - "this is null!"); - goto out; - } - if (!buf) { - gf_log ("dict", GF_LOG_ERROR, - "buf is null!"); - goto out; - } - - LOCK (&this->lock); - { - ret = _dict_serialize (this, buf); - } - UNLOCK (&this->lock); +dict_serialize(dict_t *this, char *buf) +{ + int ret = -1; + + if (!this || !buf) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict is null!"); + goto out; + } + + LOCK(&this->lock); + { + ret = dict_serialize_lk(this, buf); + } + UNLOCK(&this->lock); out: - return ret; + return ret; } - /** * dict_unserialize - unserialize a buffer into a dict * * @buf: buf containing serialized dict * @size: size of the @buf * @fill: dict to fill in - * + * * @return: success: 0 * failure: -errno */ int32_t -dict_unserialize (char *orig_buf, int32_t size, dict_t **fill) -{ - char *buf = NULL; - int ret = -1; - int32_t count = 0; - int i = 0; - - data_t * value = NULL; - char * key = NULL; - int32_t keylen = 0; - int32_t vallen = 0; - int32_t hostord = 0; - - buf = orig_buf; - - if (!buf) { - gf_log ("dict", GF_LOG_ERROR, - "buf is null!"); - goto out; - } - - if (size == 0) { - gf_log ("dict", GF_LOG_ERROR, - "size is 0!"); - goto out; - } - - if (!fill) { - gf_log ("dict", GF_LOG_ERROR, - "fill is null!"); - goto out; - } - - if (!*fill) { - gf_log ("dict", GF_LOG_ERROR, - "*fill is null!"); - goto out; - } - - if ((buf + DICT_HDR_LEN) > (orig_buf + size)) { - gf_log ("dict", GF_LOG_ERROR, - "undersized buffer passed"); - goto out; - } - - memcpy (&hostord, buf, sizeof(hostord)); - count = ntoh32 (hostord); - buf += DICT_HDR_LEN; - - if (count < 0) { - gf_log ("dict", GF_LOG_ERROR, - "count (%d) <= 0", count); - goto out; - } - - /* count will be set by the dict_set's below */ - (*fill)->count = 0; - - for (i = 0; i < count; i++) { - if ((buf + DICT_DATA_HDR_KEY_LEN) > (orig_buf + size)) { - gf_log ("dict", GF_LOG_DEBUG, - "No room for keylen (size %d).", - DICT_DATA_HDR_KEY_LEN); - gf_log ("dict", GF_LOG_ERROR, - "undersized buffer passed"); - goto out; - } - memcpy (&hostord, buf, sizeof(hostord)); - keylen = ntoh32 (hostord); - buf += DICT_DATA_HDR_KEY_LEN; - - if ((buf + DICT_DATA_HDR_VAL_LEN) > (orig_buf + size)) { - gf_log ("dict", GF_LOG_DEBUG, - "No room for vallen (size %d).", - DICT_DATA_HDR_VAL_LEN); - gf_log ("dict", GF_LOG_ERROR, - "undersized buffer passed"); - goto out; - } - memcpy (&hostord, buf, sizeof(hostord)); - vallen = ntoh32 (hostord); - buf += DICT_DATA_HDR_VAL_LEN; - - if ((buf + keylen) > (orig_buf + size)) { - gf_log ("dict", GF_LOG_DEBUG, - "No room for key (size %d).", keylen); - gf_log ("dict", GF_LOG_ERROR, - "undersized buffer passed"); - goto out; - } - key = buf; - buf += keylen + 1; /* for '\0' */ - - if ((buf + vallen) > (orig_buf + size)) { - gf_log ("dict", GF_LOG_DEBUG, - "No room for value (size %d).", vallen); - gf_log ("dict", GF_LOG_ERROR, - "undersized buffer passed"); - goto out; - } - value = get_new_data (); - value->len = vallen; - value->data = buf; - value->is_static = 1; - buf += vallen; - - dict_set (*fill, key, value); - } - - ret = 0; +dict_unserialize(char *orig_buf, int32_t size, dict_t **fill) +{ + char *buf = orig_buf; + int ret = -1; + int32_t count = 0; + int i = 0; + + data_t *value = NULL; + char *key = NULL; + int32_t keylen = 0; + int32_t vallen = 0; + int32_t hostord = 0; + + if (!buf) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "buf is null!"); + goto out; + } + + if (size == 0) { + gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "size is 0!"); + goto out; + } + + if (!fill) { + gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "fill is null!"); + goto out; + } + + if (!*fill) { + gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "*fill is null!"); + goto out; + } + + if ((buf + DICT_HDR_LEN) > (orig_buf + size)) { + gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF, + "undersized buffer " + "passed. available (%lu) < required (%lu)", + (long)(orig_buf + size), (long)(buf + DICT_HDR_LEN)); + goto out; + } + + memcpy(&hostord, buf, sizeof(hostord)); + count = ntoh32(hostord); + buf += DICT_HDR_LEN; + + if (count < 0) { + gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_COUNT_LESS_THAN_ZERO, + "count=%d", count, NULL); + goto out; + } + + /* count will be set by the dict_set's below */ + (*fill)->count = 0; + + for (i = 0; i < count; i++) { + if ((buf + DICT_DATA_HDR_KEY_LEN) > (orig_buf + size)) { + gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF, + "undersized " + "buffer passed. available (%lu) < " + "required (%lu)", + (long)(orig_buf + size), + (long)(buf + DICT_DATA_HDR_KEY_LEN)); + goto out; + } + memcpy(&hostord, buf, sizeof(hostord)); + keylen = ntoh32(hostord); + buf += DICT_DATA_HDR_KEY_LEN; + + if ((buf + DICT_DATA_HDR_VAL_LEN) > (orig_buf + size)) { + gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF, + "undersized " + "buffer passed. available (%lu) < " + "required (%lu)", + (long)(orig_buf + size), + (long)(buf + DICT_DATA_HDR_VAL_LEN)); + goto out; + } + memcpy(&hostord, buf, sizeof(hostord)); + vallen = ntoh32(hostord); + buf += DICT_DATA_HDR_VAL_LEN; + + if ((keylen < 0) || (vallen < 0)) { + gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF, + "undersized length passed " + "key:%d val:%d", + keylen, vallen); + goto out; + } + if ((buf + keylen) > (orig_buf + size)) { + gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF, + "undersized buffer passed. " + "available (%lu) < required (%lu)", + (long)(orig_buf + size), (long)(buf + keylen)); + goto out; + } + key = buf; + buf += keylen + 1; /* for '\0' */ + + if ((buf + vallen) > (orig_buf + size)) { + gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF, + "undersized buffer passed. " + "available (%lu) < required (%lu)", + (long)(orig_buf + size), (long)(buf + vallen)); + goto out; + } + value = get_new_data(); + + if (!value) { + ret = -1; + goto out; + } + value->len = vallen; + value->data = gf_memdup(buf, vallen); + value->data_type = GF_DATA_TYPE_STR_OLD; + value->is_static = _gf_false; + buf += vallen; + + ret = dict_addn(*fill, key, keylen, value); + if (ret < 0) + goto out; + } + + ret = 0; out: - return ret; + return ret; } - /** * dict_allocate_and_serialize - serialize a dictionary into an allocated buffer * * @this: dict to serialize * @buf: pointer to pointer to character. The allocated buffer is stored in - * this pointer. The buffer has to be freed by the caller. + * this pointer. The buffer has to be freed by the caller. * * @return: success: 0 * failure: -errno */ int32_t -dict_allocate_and_serialize (dict_t *this, char **buf, size_t *length) -{ - int ret = -EINVAL; - ssize_t len = 0; - - if (!this) { - gf_log ("dict", GF_LOG_DEBUG, - "NULL passed as this pointer"); - goto out; - } - if (!buf) { - gf_log ("dict", GF_LOG_DEBUG, - "NULL passed as buf"); - goto out; - } - - LOCK (&this->lock); - { - len = _dict_serialized_length (this); - if (len < 0) { - ret = len; - goto unlock; - } +dict_allocate_and_serialize(dict_t *this, char **buf, u_int *length) +{ + int ret = -EINVAL; + ssize_t len = 0; + + if (!this || !buf) { + gf_msg_debug("dict", 0, "dict OR buf is NULL"); + goto out; + } + + LOCK(&this->lock); + { + len = dict_serialized_length_lk(this); + if (len < 0) { + ret = len; + goto unlock; + } - *buf = GF_CALLOC (1, len, gf_common_mt_char); - if (*buf == NULL) { - ret = -ENOMEM; - gf_log ("dict", GF_LOG_ERROR, "out of memory"); - goto unlock; - } + *buf = GF_MALLOC(len, gf_common_mt_char); + if (*buf == NULL) { + ret = -ENOMEM; + goto unlock; + } - ret = _dict_serialize (this, *buf); - if (ret < 0) { - GF_FREE (*buf); - *buf = NULL; - goto unlock; - } + ret = dict_serialize_lk(this, *buf); + if (ret < 0) { + GF_FREE(*buf); + *buf = NULL; + goto unlock; + } - if (length != NULL) { - *length = len; - } + if (length != NULL) { + *length = len; } + } unlock: - UNLOCK (&this->lock); + UNLOCK(&this->lock); +out: + return ret; +} + +/** + * dict_serialize_value_with_delim_lk: serialize the values in the dictionary + * into a buffer separated by delimiter (except the last) + * + * @this : dictionary to serialize + * @buf : the buffer to store the serialized data + * @serz_len : the length of the serialized data (excluding the last delimiter) + * @delimiter : the delimiter to separate the values + * + * @return : 0 -> success + * : -errno -> failure + */ +int +dict_serialize_value_with_delim_lk(dict_t *this, char *buf, int32_t *serz_len, + char delimiter) +{ + int ret = -1; + int32_t count = this->count; + int32_t vallen = 0; + int32_t total_len = 0; + data_pair_t *pair = this->members_list; + + if (!buf) { + gf_smsg("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, NULL); + goto out; + } + + if (count < 0) { + gf_smsg("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, "count=%d", + count, NULL); + goto out; + } + + while (count) { + if (!pair) { + gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_PAIRS_LESS_THAN_COUNT, + NULL); + goto out; + } + + if (!pair->key || !pair->value) { + gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_KEY_OR_VALUE_NULL, NULL); + goto out; + } + + if (!pair->value->data) { + gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_NULL_VALUE_IN_DICT, NULL); + goto out; + } + + vallen = pair->value->len - 1; // length includes \0 + memcpy(buf, pair->value->data, vallen); + buf += vallen; + *buf++ = delimiter; + + total_len += (vallen + 1); + + pair = pair->next; + count--; + } + + *--buf = '\0'; // remove the last delimiter + total_len--; // adjust the length + ret = 0; + + if (serz_len) + *serz_len = total_len; + +out: + return ret; +} + +int +dict_serialize_value_with_delim(dict_t *this, char *buf, int32_t *serz_len, + char delimiter) +{ + int ret = -1; + + if (!this || !buf) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict is null!"); + goto out; + } + + LOCK(&this->lock); + { + ret = dict_serialize_value_with_delim_lk(this, buf, serz_len, + delimiter); + } + UNLOCK(&this->lock); out: - return ret; + return ret; +} + +int +dict_dump_to_str(dict_t *dict, char *dump, int dumpsize, char *format) +{ + int ret = 0; + int dumplen = 0; + data_pair_t *trav = NULL; + + if (!dict) + return 0; + + for (trav = dict->members_list; trav; trav = trav->next) { + ret = snprintf(&dump[dumplen], dumpsize - dumplen, format, trav->key, + trav->value->data); + if ((ret == -1) || !ret) + return ret; + + dumplen += ret; + } + return 0; +} + +void +dict_dump_to_log(dict_t *dict) +{ + int ret = -1; + char *dump = NULL; + const int dump_size = 64 * 1024; + char *format = "(%s:%s)"; + + if (!dict) { + gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict is NULL"); + goto out; + } + + dump = GF_MALLOC(dump_size, gf_common_mt_char); + if (!dump) { + gf_msg_callingfn("dict", GF_LOG_WARNING, ENOMEM, LG_MSG_NO_MEMORY, + "dump buffer is NULL"); + goto out; + } + + ret = dict_dump_to_str(dict, dump, dump_size, format); + if (ret) { + gf_smsg("dict", GF_LOG_WARNING, 0, LG_MSG_FAILED_TO_LOG_DICT, NULL); + goto out; + } + gf_smsg("dict", GF_LOG_INFO, 0, LG_MSG_DICT_ERROR, "dict=%p", dict, + "dump=%s", dump, NULL); +out: + GF_FREE(dump); + + return; +} + +void +dict_dump_to_statedump(dict_t *dict, char *dict_name, char *domain) +{ + int ret = -1; + char *dump = NULL; + const int dump_size = 64 * 1024; + char key[4096] = { + 0, + }; + char *format = "\n\t%s:%s"; + + if (!dict) { + gf_msg_callingfn(domain, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "dict is NULL"); + goto out; + } + + dump = GF_MALLOC(dump_size, gf_common_mt_char); + if (!dump) { + gf_msg_callingfn(domain, GF_LOG_WARNING, ENOMEM, LG_MSG_NO_MEMORY, + "dump buffer is NULL"); + goto out; + } + + ret = dict_dump_to_str(dict, dump, dump_size, format); + if (ret) { + gf_smsg(domain, GF_LOG_WARNING, 0, LG_MSG_FAILED_TO_LOG_DICT, "name=%s", + dict_name, NULL); + goto out; + } + gf_proc_dump_build_key(key, domain, "%s", dict_name); + gf_proc_dump_write(key, "%s", dump); + +out: + GF_FREE(dump); + + return; +} + +dict_t * +dict_for_key_value(const char *name, const char *value, size_t size, + gf_boolean_t is_static) +{ + dict_t *xattr = dict_new(); + int ret = 0; + + if (!xattr) + return NULL; + + if (is_static) + ret = dict_set_static_bin(xattr, (char *)name, (void *)value, size); + else + ret = dict_set_bin(xattr, (char *)name, (void *)value, size); + + if (ret) { + dict_destroy(xattr); + xattr = NULL; + } + + return xattr; +} + +/* + * "strings" should be NULL terminated strings array. + */ +int +dict_has_key_from_array(dict_t *dict, char **strings, gf_boolean_t *result) +{ + int i = 0; + uint32_t hash = 0; + + if (!dict || !strings || !result) + return -EINVAL; + + LOCK(&dict->lock); + { + for (i = 0; strings[i]; i++) { + hash = (uint32_t)XXH64(strings[i], strlen(strings[i]), 0); + if (dict_lookup_common(dict, strings[i], hash)) { + *result = _gf_true; + goto unlock; + } + } + *result = _gf_false; + } +unlock: + UNLOCK(&dict->lock); + return 0; } diff --git a/libglusterfs/src/dict.h b/libglusterfs/src/dict.h deleted file mode 100644 index 508b139a288..00000000000 --- a/libglusterfs/src/dict.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _DICT_H -#define _DICT_H - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include <inttypes.h> -#include <sys/uio.h> -#include <pthread.h> - -#include "common-utils.h" - -typedef struct _data data_t; -typedef struct _dict dict_t; -typedef struct _data_pair data_pair_t; - -struct _data { - unsigned char is_static:1; - unsigned char is_const:1; - int32_t len; - struct iovec *vec; - char *data; - int32_t refcount; - gf_lock_t lock; -}; - -struct _data_pair { - struct _data_pair *hash_next; - struct _data_pair *prev; - struct _data_pair *next; - data_t *value; - char *key; -}; - -struct _dict { - unsigned char is_static:1; - int32_t hash_size; - int32_t count; - int32_t refcount; - data_pair_t **members; - data_pair_t *members_list; - char *extra_free; - gf_lock_t lock; -}; - - -int32_t is_data_equal (data_t *one, data_t *two); -void data_destroy (data_t *data); - -int32_t dict_set (dict_t *this, char *key, data_t *value); -data_t *dict_get (dict_t *this, char *key); -void dict_del (dict_t *this, char *key); - -int32_t dict_serialized_length (dict_t *dict); -int32_t dict_serialize (dict_t *dict, char *buf); -int32_t dict_unserialize (char *buf, int32_t size, dict_t **fill); - -int32_t -dict_allocate_and_serialize (dict_t *this, char **buf, size_t *length); - -int32_t dict_iovec_len (dict_t *dict); -int32_t dict_to_iovec (dict_t *dict, struct iovec *vec, int32_t count); - -void dict_destroy (dict_t *dict); -void dict_unref (dict_t *dict); -dict_t *dict_ref (dict_t *dict); -data_t *data_ref (data_t *data); -void data_unref (data_t *data); - -/* - TODO: provide converts for differnt byte sizes, signedness, and void * - */ -data_t *int_to_data (int64_t value); -data_t *str_to_data (char *value); -data_t *data_from_dynstr (char *value); -data_t *data_from_dynptr (void *value, int32_t len); -data_t *bin_to_data (void *value, int32_t len); -data_t *static_str_to_data (char *value); -data_t *static_bin_to_data (void *value); - -int64_t data_to_int64 (data_t *data); -int32_t data_to_int32 (data_t *data); -int16_t data_to_int16 (data_t *data); -int8_t data_to_int8 (data_t *data); - -uint64_t data_to_uint64 (data_t *data); -uint32_t data_to_uint32 (data_t *data); -uint16_t data_to_uint16 (data_t *data); - -data_t *data_from_ptr (void *value); -data_t *data_from_static_ptr (void *value); - -data_t *data_from_int64 (int64_t value); -data_t *data_from_int32 (int32_t value); -data_t *data_from_int16 (int16_t value); -data_t *data_from_int8 (int8_t value); - -data_t *data_from_uint64 (uint64_t value); -data_t *data_from_uint32 (uint32_t value); -data_t *data_from_uint16 (uint16_t value); - -char *data_to_str (data_t *data); -void *data_to_bin (data_t *data); -void *data_to_ptr (data_t *data); - -data_t *get_new_data (); -dict_t *get_new_dict_full (int size_hint); -dict_t *get_new_dict (); - -data_pair_t *get_new_data_pair (); - -void dict_foreach (dict_t *this, - void (*fn)(dict_t *this, - char *key, - data_t *value, - void *data), - void *data); - -dict_t *dict_copy (dict_t *this, - dict_t *new); - -/* CLEANED UP FUNCTIONS DECLARATIONS */ -GF_MUST_CHECK dict_t *dict_new (void); -dict_t *dict_copy_with_ref (dict_t *this, - dict_t *new); - -GF_MUST_CHECK int dict_get_int8 (dict_t *this, char *key, int8_t *val); -GF_MUST_CHECK int dict_set_int8 (dict_t *this, char *key, int8_t val); - -GF_MUST_CHECK int dict_get_int16 (dict_t *this, char *key, int16_t *val); -GF_MUST_CHECK int dict_set_int16 (dict_t *this, char *key, int16_t val); - -GF_MUST_CHECK int dict_get_int32 (dict_t *this, char *key, int32_t *val); -GF_MUST_CHECK int dict_set_int32 (dict_t *this, char *key, int32_t val); - -GF_MUST_CHECK int dict_get_int64 (dict_t *this, char *key, int64_t *val); -GF_MUST_CHECK int dict_set_int64 (dict_t *this, char *key, int64_t val); - -GF_MUST_CHECK int dict_get_uint16 (dict_t *this, char *key, uint16_t *val); -GF_MUST_CHECK int dict_set_uint16 (dict_t *this, char *key, uint16_t val); - -GF_MUST_CHECK int dict_get_uint32 (dict_t *this, char *key, uint32_t *val); -GF_MUST_CHECK int dict_set_uint32 (dict_t *this, char *key, uint32_t val); - -GF_MUST_CHECK int dict_get_uint64 (dict_t *this, char *key, uint64_t *val); -GF_MUST_CHECK int dict_set_uint64 (dict_t *this, char *key, uint64_t val); - -GF_MUST_CHECK int dict_get_double (dict_t *this, char *key, double *val); -GF_MUST_CHECK int dict_set_double (dict_t *this, char *key, double val); - -GF_MUST_CHECK int dict_set_static_ptr (dict_t *this, char *key, void *ptr); -GF_MUST_CHECK int dict_get_ptr (dict_t *this, char *key, void **ptr); -GF_MUST_CHECK int dict_set_ptr (dict_t *this, char *key, void *ptr); -GF_MUST_CHECK int dict_set_dynptr (dict_t *this, char *key, void *ptr, size_t size); - -GF_MUST_CHECK int dict_get_bin (dict_t *this, char *key, void **ptr); -GF_MUST_CHECK int dict_set_bin (dict_t *this, char *key, void *ptr, size_t size); -GF_MUST_CHECK int dict_set_static_bin (dict_t *this, char *key, void *ptr, size_t size); - -GF_MUST_CHECK int dict_set_str (dict_t *this, char *key, char *str); -GF_MUST_CHECK int dict_set_dynstr (dict_t *this, char *key, char *str); -GF_MUST_CHECK int dict_get_str (dict_t *this, char *key, char **str); - -#endif diff --git a/libglusterfs/src/event-epoll.c b/libglusterfs/src/event-epoll.c new file mode 100644 index 00000000000..fb4fb845b40 --- /dev/null +++ b/libglusterfs/src/event-epoll.c @@ -0,0 +1,1032 @@ +/* + Copyright (c) 2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include <pthread.h> +#include <stdlib.h> +#include <errno.h> + +#include "glusterfs/gf-event.h" +#include "glusterfs/common-utils.h" +#include "glusterfs/syscall.h" +#include "glusterfs/libglusterfs-messages.h" + +#ifdef HAVE_SYS_EPOLL_H +#include <sys/epoll.h> + +struct event_slot_epoll { + int fd; + int events; + int gen; + int idx; + gf_atomic_t ref; + int do_close; + int in_handler; + int handled_error; + void *data; + event_handler_t handler; + gf_lock_t lock; + struct list_head poller_death; +}; + +struct event_thread_data { + struct event_pool *event_pool; + int event_index; +}; + +static struct event_slot_epoll * +__event_newtable(struct event_pool *event_pool, int table_idx) +{ + struct event_slot_epoll *table = NULL; + int i = -1; + + table = GF_CALLOC(sizeof(*table), EVENT_EPOLL_SLOTS, gf_common_mt_ereg); + if (!table) + return NULL; + + for (i = 0; i < EVENT_EPOLL_SLOTS; i++) { + table[i].fd = -1; + LOCK_INIT(&table[i].lock); + INIT_LIST_HEAD(&table[i].poller_death); + } + + event_pool->ereg[table_idx] = table; + event_pool->slots_used[table_idx] = 0; + + return table; +} + +static int +event_slot_ref(struct event_slot_epoll *slot) +{ + if (!slot) + return -1; + + return GF_ATOMIC_INC(slot->ref); +} + +static int +__event_slot_alloc(struct event_pool *event_pool, int fd, + char notify_poller_death, struct event_slot_epoll **slot) +{ + int i = 0; + int j = 0; + int table_idx = -1; + int gen = -1; + struct event_slot_epoll *table = NULL; + +retry: + + while (i < EVENT_EPOLL_TABLES) { + switch (event_pool->slots_used[i]) { + case EVENT_EPOLL_SLOTS: + break; + case 0: + if (!event_pool->ereg[i]) { + table = __event_newtable(event_pool, i); + if (!table) + return -1; + } else { + table = event_pool->ereg[i]; + } + break; + default: + table = event_pool->ereg[i]; + break; + } + + if (table) + /* break out of the loop */ + break; + i++; + } + + if (!table) + return -1; + + table_idx = i; + + for (j = 0; j < EVENT_EPOLL_SLOTS; j++) { + if (table[j].fd == -1) { + /* wipe everything except bump the generation */ + gen = table[j].gen; + memset(&table[j], 0, sizeof(table[j])); + table[j].gen = gen + 1; + + LOCK_INIT(&table[j].lock); + INIT_LIST_HEAD(&table[j].poller_death); + + table[j].fd = fd; + if (notify_poller_death) { + table[j].idx = table_idx * EVENT_EPOLL_SLOTS + j; + list_add_tail(&table[j].poller_death, + &event_pool->poller_death); + } + + event_pool->slots_used[table_idx]++; + + break; + } + } + + if (j == EVENT_EPOLL_SLOTS) { + table = NULL; + i++; + goto retry; + } else { + (*slot) = &table[j]; + event_slot_ref(*slot); + return table_idx * EVENT_EPOLL_SLOTS + j; + } +} + +static int +event_slot_alloc(struct event_pool *event_pool, int fd, + char notify_poller_death, struct event_slot_epoll **slot) +{ + int idx = -1; + + pthread_mutex_lock(&event_pool->mutex); + { + idx = __event_slot_alloc(event_pool, fd, notify_poller_death, slot); + } + pthread_mutex_unlock(&event_pool->mutex); + + return idx; +} + +static void +__event_slot_dealloc(struct event_pool *event_pool, int idx) +{ + int table_idx = 0; + int offset = 0; + struct event_slot_epoll *table = NULL; + struct event_slot_epoll *slot = NULL; + int fd = -1; + + table_idx = idx / EVENT_EPOLL_SLOTS; + offset = idx % EVENT_EPOLL_SLOTS; + + table = event_pool->ereg[table_idx]; + if (!table) + return; + + slot = &table[offset]; + slot->gen++; + + fd = slot->fd; + slot->fd = -1; + slot->handled_error = 0; + slot->in_handler = 0; + list_del_init(&slot->poller_death); + if (fd != -1) + event_pool->slots_used[table_idx]--; + + return; +} + +static void +event_slot_dealloc(struct event_pool *event_pool, int idx) +{ + pthread_mutex_lock(&event_pool->mutex); + { + __event_slot_dealloc(event_pool, idx); + } + pthread_mutex_unlock(&event_pool->mutex); + + return; +} + +static struct event_slot_epoll * +event_slot_get(struct event_pool *event_pool, int idx) +{ + struct event_slot_epoll *slot = NULL; + struct event_slot_epoll *table = NULL; + int table_idx = 0; + int offset = 0; + + table_idx = idx / EVENT_EPOLL_SLOTS; + offset = idx % EVENT_EPOLL_SLOTS; + + table = event_pool->ereg[table_idx]; + if (!table) + return NULL; + + slot = &table[offset]; + + event_slot_ref(slot); + return slot; +} + +static void +__event_slot_unref(struct event_pool *event_pool, struct event_slot_epoll *slot, + int idx) +{ + int ref = -1; + int fd = -1; + int do_close = 0; + + ref = GF_ATOMIC_DEC(slot->ref); + if (ref) + /* slot still alive */ + goto done; + + LOCK(&slot->lock); + { + fd = slot->fd; + do_close = slot->do_close; + slot->do_close = 0; + } + UNLOCK(&slot->lock); + + __event_slot_dealloc(event_pool, idx); + + if (do_close) + sys_close(fd); +done: + return; +} + +static void +event_slot_unref(struct event_pool *event_pool, struct event_slot_epoll *slot, + int idx) +{ + int ref = -1; + int fd = -1; + int do_close = 0; + + ref = GF_ATOMIC_DEC(slot->ref); + if (ref) + /* slot still alive */ + goto done; + + LOCK(&slot->lock); + { + fd = slot->fd; + do_close = slot->do_close; + slot->do_close = 0; + } + UNLOCK(&slot->lock); + + event_slot_dealloc(event_pool, idx); + + if (do_close) + sys_close(fd); +done: + return; +} + +static struct event_pool * +event_pool_new_epoll(int count, int eventthreadcount) +{ + struct event_pool *event_pool = NULL; + int epfd = -1; + + event_pool = GF_CALLOC(1, sizeof(*event_pool), gf_common_mt_event_pool); + + if (!event_pool) + goto out; + + epfd = epoll_create(count); + + if (epfd == -1) { + gf_smsg("epoll", GF_LOG_ERROR, errno, LG_MSG_EPOLL_FD_CREATE_FAILED, + NULL); + GF_FREE(event_pool->reg); + GF_FREE(event_pool); + event_pool = NULL; + goto out; + } + + event_pool->fd = epfd; + + event_pool->count = count; + INIT_LIST_HEAD(&event_pool->poller_death); + event_pool->eventthreadcount = eventthreadcount; + event_pool->auto_thread_count = 0; + + pthread_mutex_init(&event_pool->mutex, NULL); + +out: + return event_pool; +} + +static void +__slot_update_events(struct event_slot_epoll *slot, int poll_in, int poll_out) +{ + switch (poll_in) { + case 1: + slot->events |= EPOLLIN; + break; + case 0: + slot->events &= ~EPOLLIN; + break; + case -1: + /* do nothing */ + break; + default: + gf_smsg("epoll", GF_LOG_ERROR, 0, LG_MSG_INVALID_POLL_IN, + "value=%d", poll_in, NULL); + break; + } + + switch (poll_out) { + case 1: + slot->events |= EPOLLOUT; + break; + case 0: + slot->events &= ~EPOLLOUT; + break; + case -1: + /* do nothing */ + break; + default: + gf_smsg("epoll", GF_LOG_ERROR, 0, LG_MSG_INVALID_POLL_OUT, + "value=%d", poll_out, NULL); + break; + } +} + +int +event_register_epoll(struct event_pool *event_pool, int fd, + event_handler_t handler, void *data, int poll_in, + int poll_out, char notify_poller_death) +{ + int idx = -1; + int ret = -1; + int destroy = 0; + struct epoll_event epoll_event = { + 0, + }; + struct event_data *ev_data = (void *)&epoll_event.data; + struct event_slot_epoll *slot = NULL; + + GF_VALIDATE_OR_GOTO("event", event_pool, out); + + /* TODO: Even with the below check, there is a possibility of race, + * What if the destroy mode is set after the check is done. + * Not sure of the best way to prevent this race, ref counting + * is one possibility. + * There is no harm in registering and unregistering the fd + * even after destroy mode is set, just that such fds will remain + * open until unregister is called, also the events on that fd will be + * notified, until one of the poller thread is alive. + */ + pthread_mutex_lock(&event_pool->mutex); + { + destroy = event_pool->destroy; + } + pthread_mutex_unlock(&event_pool->mutex); + + if (destroy == 1) + goto out; + + idx = event_slot_alloc(event_pool, fd, notify_poller_death, &slot); + if (idx == -1) { + gf_smsg("epoll", GF_LOG_ERROR, 0, LG_MSG_SLOT_NOT_FOUND, "fd=%d", fd, + NULL); + return -1; + } + + assert(slot->fd == fd); + + LOCK(&slot->lock); + { + /* make epoll 'singleshot', which + means we need to re-add the fd with + epoll_ctl(EPOLL_CTL_MOD) after delivery of every + single event. This assures us that while a poller + thread has picked up and is processing an event, + another poller will not try to pick this at the same + time as well. + */ + + slot->events = EPOLLPRI | EPOLLHUP | EPOLLERR | EPOLLONESHOT; + slot->handler = handler; + slot->data = data; + + __slot_update_events(slot, poll_in, poll_out); + + epoll_event.events = slot->events; + ev_data->idx = idx; + ev_data->gen = slot->gen; + + ret = epoll_ctl(event_pool->fd, EPOLL_CTL_ADD, fd, &epoll_event); + /* check ret after UNLOCK() to avoid deadlock in + event_slot_unref() + */ + } + UNLOCK(&slot->lock); + + if (ret == -1) { + gf_smsg("epoll", GF_LOG_ERROR, errno, LG_MSG_EPOLL_FD_ADD_FAILED, + "fd=%d", fd, "epoll_fd=%d", event_pool->fd, NULL); + event_slot_unref(event_pool, slot, idx); + idx = -1; + } + + /* keep slot->ref (do not event_slot_unref) if successful */ +out: + return idx; +} + +static int +event_unregister_epoll_common(struct event_pool *event_pool, int fd, int idx, + int do_close) +{ + int ret = -1; + struct event_slot_epoll *slot = NULL; + + GF_VALIDATE_OR_GOTO("event", event_pool, out); + + /* During shutdown, it may happen that a socket registration with + * the event sub-system may fail and an rpc_transport_unref() may + * be called for such an unregistered socket with idx == -1. This + * may cause the following assert(slot->fd == fd) to fail. + */ + if (idx < 0) + goto out; + + slot = event_slot_get(event_pool, idx); + if (!slot) { + gf_smsg("epoll", GF_LOG_ERROR, 0, LG_MSG_SLOT_NOT_FOUND, "fd=%d", fd, + "idx=%d", idx, NULL); + return -1; + } + + assert(slot->fd == fd); + + LOCK(&slot->lock); + { + ret = epoll_ctl(event_pool->fd, EPOLL_CTL_DEL, fd, NULL); + + if (ret == -1) { + gf_smsg("epoll", GF_LOG_ERROR, errno, LG_MSG_EPOLL_FD_DEL_FAILED, + "fd=%d", fd, "epoll_fd=%d", event_pool->fd, NULL); + goto unlock; + } + + slot->do_close = do_close; + slot->gen++; /* detect unregister in dispatch_handler() */ + } +unlock: + UNLOCK(&slot->lock); + + event_slot_unref(event_pool, slot, idx); /* one for event_register() */ + event_slot_unref(event_pool, slot, idx); /* one for event_slot_get() */ +out: + return ret; +} + +static int +event_unregister_epoll(struct event_pool *event_pool, int fd, int idx_hint) +{ + int ret = -1; + + ret = event_unregister_epoll_common(event_pool, fd, idx_hint, 0); + + return ret; +} + +static int +event_unregister_close_epoll(struct event_pool *event_pool, int fd, + int idx_hint) +{ + int ret = -1; + + ret = event_unregister_epoll_common(event_pool, fd, idx_hint, 1); + + return ret; +} + +static int +event_select_on_epoll(struct event_pool *event_pool, int fd, int idx, + int poll_in, int poll_out) +{ + int ret = -1; + struct event_slot_epoll *slot = NULL; + struct epoll_event epoll_event = { + 0, + }; + struct event_data *ev_data = (void *)&epoll_event.data; + + GF_VALIDATE_OR_GOTO("event", event_pool, out); + + slot = event_slot_get(event_pool, idx); + if (!slot) { + gf_smsg("epoll", GF_LOG_ERROR, 0, LG_MSG_SLOT_NOT_FOUND, "fd=%d", fd, + "idx=%d", idx, NULL); + return -1; + } + + assert(slot->fd == fd); + + LOCK(&slot->lock); + { + __slot_update_events(slot, poll_in, poll_out); + + epoll_event.events = slot->events; + ev_data->idx = idx; + ev_data->gen = slot->gen; + + if (slot->in_handler) + /* + * in_handler indicates at least one thread + * executing event_dispatch_epoll_handler() + * which will perform epoll_ctl(EPOLL_CTL_MOD) + * anyways (because of EPOLLET) + * + * This not only saves a system call, but also + * avoids possibility of another epoll thread + * picking up the next event while the ongoing + * handler is still in progress (and resulting + * in unnecessary contention on rpc_transport_t->mutex). + */ + goto unlock; + + ret = epoll_ctl(event_pool->fd, EPOLL_CTL_MOD, fd, &epoll_event); + if (ret == -1) { + gf_smsg("epoll", GF_LOG_ERROR, errno, LG_MSG_EPOLL_FD_MODIFY_FAILED, + "fd=%d", fd, "events=%d", epoll_event.events, NULL); + } + } +unlock: + UNLOCK(&slot->lock); + + event_slot_unref(event_pool, slot, idx); + +out: + return idx; +} + +static int +event_dispatch_epoll_handler(struct event_pool *event_pool, + struct epoll_event *event) +{ + struct event_data *ev_data = NULL; + struct event_slot_epoll *slot = NULL; + event_handler_t handler = NULL; + void *data = NULL; + int idx = -1; + int gen = -1; + int ret = -1; + int fd = -1; + gf_boolean_t handled_error_previously = _gf_false; + + ev_data = (void *)&event->data; + handler = NULL; + data = NULL; + + idx = ev_data->idx; + gen = ev_data->gen; + + slot = event_slot_get(event_pool, idx); + if (!slot) { + gf_smsg("epoll", GF_LOG_ERROR, 0, LG_MSG_SLOT_NOT_FOUND, "idx=%d", idx, + NULL); + return -1; + } + + LOCK(&slot->lock); + { + fd = slot->fd; + if (fd == -1) { + gf_smsg("epoll", GF_LOG_ERROR, 0, LG_MSG_STALE_FD_FOUND, "idx=%d", + idx, "gen=%d", gen, "events=%d", event->events, + "slot->gen=%d", slot->gen, NULL); + /* fd got unregistered in another thread */ + goto pre_unlock; + } + + if (gen != slot->gen) { + gf_smsg("epoll", GF_LOG_ERROR, 0, LG_MSG_GENERATION_MISMATCH, + "idx=%d", idx, "gen=%d", gen, "slot->gen=%d", slot->gen, + "slot->fd=%d", slot->fd, NULL); + /* slot was re-used and therefore is another fd! */ + goto pre_unlock; + } + + handler = slot->handler; + data = slot->data; + + if (slot->in_handler > 0) { + /* Another handler is inprogress, skip this one. */ + handler = NULL; + goto pre_unlock; + } + + if (slot->handled_error) { + handled_error_previously = _gf_true; + } else { + slot->handled_error = (event->events & (EPOLLERR | EPOLLHUP)); + slot->in_handler++; + } + } +pre_unlock: + UNLOCK(&slot->lock); + + ret = 0; + + if (!handler) + goto out; + + if (!handled_error_previously) { + handler(fd, idx, gen, data, (event->events & (EPOLLIN | EPOLLPRI)), + (event->events & (EPOLLOUT)), + (event->events & (EPOLLERR | EPOLLHUP)), 0); + } +out: + event_slot_unref(event_pool, slot, idx); + + return ret; +} + +static void * +event_dispatch_epoll_worker(void *data) +{ + struct epoll_event event; + int ret = -1; + struct event_thread_data *ev_data = data; + struct event_pool *event_pool; + int myindex = -1; + int timetodie = 0, gen = 0; + struct list_head poller_death_notify; + struct event_slot_epoll *slot = NULL, *tmp = NULL; + + GF_VALIDATE_OR_GOTO("event", ev_data, out); + + event_pool = ev_data->event_pool; + myindex = ev_data->event_index; + + GF_VALIDATE_OR_GOTO("event", event_pool, out); + + gf_smsg("epoll", GF_LOG_INFO, 0, LG_MSG_STARTED_EPOLL_THREAD, "index=%d", + myindex - 1, NULL); + + pthread_mutex_lock(&event_pool->mutex); + { + event_pool->activethreadcount++; + } + pthread_mutex_unlock(&event_pool->mutex); + + for (;;) { + if (event_pool->eventthreadcount < myindex) { + /* ...time to die, thread count was decreased below + * this threads index */ + /* Start with extra safety at this point, reducing + * lock conention in normal case when threads are not + * reconfigured always */ + pthread_mutex_lock(&event_pool->mutex); + { + if (event_pool->eventthreadcount < myindex) { + while (event_pool->poller_death_sliced) { + pthread_cond_wait(&event_pool->cond, + &event_pool->mutex); + } + + INIT_LIST_HEAD(&poller_death_notify); + /* if found true in critical section, + * die */ + event_pool->pollers[myindex - 1] = 0; + event_pool->activethreadcount--; + timetodie = 1; + gen = ++event_pool->poller_gen; + list_for_each_entry(slot, &event_pool->poller_death, + poller_death) + { + event_slot_ref(slot); + } + + list_splice_init(&event_pool->poller_death, + &poller_death_notify); + event_pool->poller_death_sliced = 1; + pthread_cond_broadcast(&event_pool->cond); + } + } + pthread_mutex_unlock(&event_pool->mutex); + if (timetodie) { + list_for_each_entry(slot, &poller_death_notify, poller_death) + { + slot->handler(slot->fd, 0, gen, slot->data, 0, 0, 0, 1); + } + + pthread_mutex_lock(&event_pool->mutex); + { + list_for_each_entry_safe(slot, tmp, &poller_death_notify, + poller_death) + { + __event_slot_unref(event_pool, slot, slot->idx); + } + + list_splice(&poller_death_notify, + &event_pool->poller_death); + event_pool->poller_death_sliced = 0; + pthread_cond_broadcast(&event_pool->cond); + } + pthread_mutex_unlock(&event_pool->mutex); + + gf_smsg("epoll", GF_LOG_INFO, 0, LG_MSG_EXITED_EPOLL_THREAD, + "index=%d", myindex, NULL); + + goto out; + } + } + + ret = epoll_wait(event_pool->fd, &event, 1, -1); + + if (ret == 0) + /* timeout */ + continue; + + if (ret == -1 && errno == EINTR) + /* sys call */ + continue; + + ret = event_dispatch_epoll_handler(event_pool, &event); + if (ret) { + gf_smsg("epoll", GF_LOG_ERROR, 0, LG_MSG_DISPATCH_HANDLER_FAILED, + NULL); + } + } +out: + if (ev_data) + GF_FREE(ev_data); + return NULL; +} + +/* Attempts to start the # of configured pollers, ensuring at least the first + * is started in a joinable state */ +static int +event_dispatch_epoll(struct event_pool *event_pool) +{ + int i = 0; + pthread_t t_id; + int pollercount = 0; + int ret = -1; + struct event_thread_data *ev_data = NULL; + + /* Start the configured number of pollers */ + pthread_mutex_lock(&event_pool->mutex); + { + pollercount = event_pool->eventthreadcount; + + /* Set to MAX if greater */ + if (pollercount > EVENT_MAX_THREADS) + pollercount = EVENT_MAX_THREADS; + + /* Default pollers to 1 in case this is incorrectly set */ + if (pollercount <= 0) + pollercount = 1; + + event_pool->activethreadcount++; + + for (i = 0; i < pollercount; i++) { + ev_data = GF_CALLOC(1, sizeof(*ev_data), gf_common_mt_event_pool); + if (!ev_data) { + if (i == 0) { + /* Need to succeed creating 0'th + * thread, to joinable and wait */ + break; + } else { + /* Inability to create other threads + * are a lesser evil, and ignored */ + continue; + } + } + + ev_data->event_pool = event_pool; + ev_data->event_index = i + 1; + + ret = gf_thread_create(&t_id, NULL, event_dispatch_epoll_worker, + ev_data, "epoll%03hx", i & 0x3ff); + if (!ret) { + event_pool->pollers[i] = t_id; + + /* mark all threads other than one in index 0 + * as detachable. Errors can be ignored, they + * spend their time as zombies if not detched + * and the thread counts are decreased */ + if (i != 0) + pthread_detach(event_pool->pollers[i]); + } else { + gf_smsg("epoll", GF_LOG_WARNING, 0, + LG_MSG_START_EPOLL_THREAD_FAILED, "index=%d", i, NULL); + if (i == 0) { + GF_FREE(ev_data); + break; + } else { + GF_FREE(ev_data); + continue; + } + } + } + } + pthread_mutex_unlock(&event_pool->mutex); + + /* Just wait for the first thread, that is created in a joinable state + * and will never die, ensuring this function never returns */ + if (event_pool->pollers[0] != 0) + pthread_join(event_pool->pollers[0], NULL); + + pthread_mutex_lock(&event_pool->mutex); + { + event_pool->activethreadcount--; + } + pthread_mutex_unlock(&event_pool->mutex); + + return ret; +} + +/** + * @param event_pool event_pool on which fds of interest are registered for + * events. + * + * @return 1 if at least one epoll worker thread is spawned, 0 otherwise + * + * NB This function SHOULD be called under event_pool->mutex. + */ + +static int +event_pool_dispatched_unlocked(struct event_pool *event_pool) +{ + return (event_pool->pollers[0] != 0); +} + +int +event_reconfigure_threads_epoll(struct event_pool *event_pool, int value) +{ + int i; + int ret = 0; + pthread_t t_id; + int oldthreadcount; + struct event_thread_data *ev_data = NULL; + + pthread_mutex_lock(&event_pool->mutex); + { + /* Reconfigure to 0 threads is allowed only in destroy mode */ + if (event_pool->destroy == 1) { + value = 0; + } else { + /* Set to MAX if greater */ + if (value > EVENT_MAX_THREADS) + value = EVENT_MAX_THREADS; + + /* Default pollers to 1 in case this is set incorrectly */ + if (value <= 0) + value = 1; + } + + oldthreadcount = event_pool->eventthreadcount; + + /* Start 'worker' threads as necessary only if event_dispatch() + * was called before. If event_dispatch() was not called, there + * will be no epoll 'worker' threads running yet. */ + + if (event_pool_dispatched_unlocked(event_pool) && + (oldthreadcount < value)) { + /* create more poll threads */ + for (i = oldthreadcount; i < value; i++) { + /* Start a thread if the index at this location + * is a 0, so that the older thread is confirmed + * as dead */ + if (event_pool->pollers[i] == 0) { + ev_data = GF_CALLOC(1, sizeof(*ev_data), + gf_common_mt_event_pool); + if (!ev_data) { + continue; + } + + ev_data->event_pool = event_pool; + ev_data->event_index = i + 1; + + ret = gf_thread_create(&t_id, NULL, + event_dispatch_epoll_worker, ev_data, + "epoll%03hx", i & 0x3ff); + if (ret) { + gf_smsg("epoll", GF_LOG_WARNING, 0, + LG_MSG_START_EPOLL_THREAD_FAILED, "index=%d", i, + NULL); + GF_FREE(ev_data); + } else { + pthread_detach(t_id); + event_pool->pollers[i] = t_id; + } + } + } + } + + /* if value decreases, threads will terminate, themselves */ + event_pool->eventthreadcount = value; + } + pthread_mutex_unlock(&event_pool->mutex); + + return 0; +} + +/* This function is the destructor for the event_pool data structure + * Should be called only after poller_threads_destroy() is called, + * else will lead to crashes. + */ +static int +event_pool_destroy_epoll(struct event_pool *event_pool) +{ + int ret = 0, i = 0, j = 0; + struct event_slot_epoll *table = NULL; + + ret = sys_close(event_pool->fd); + + for (i = 0; i < EVENT_EPOLL_TABLES; i++) { + if (event_pool->ereg[i]) { + table = event_pool->ereg[i]; + event_pool->ereg[i] = NULL; + for (j = 0; j < EVENT_EPOLL_SLOTS; j++) { + LOCK_DESTROY(&table[j].lock); + } + GF_FREE(table); + } + } + + pthread_mutex_destroy(&event_pool->mutex); + pthread_cond_destroy(&event_pool->cond); + + GF_FREE(event_pool->evcache); + GF_FREE(event_pool->reg); + GF_FREE(event_pool); + + return ret; +} + +static int +event_handled_epoll(struct event_pool *event_pool, int fd, int idx, int gen) +{ + struct event_slot_epoll *slot = NULL; + struct epoll_event epoll_event = { + 0, + }; + struct event_data *ev_data = (void *)&epoll_event.data; + int ret = 0; + + slot = event_slot_get(event_pool, idx); + if (!slot) { + gf_smsg("epoll", GF_LOG_ERROR, 0, LG_MSG_SLOT_NOT_FOUND, "fd=%d", fd, + "idx=%d", idx, NULL); + return -1; + } + + assert(slot->fd == fd); + + LOCK(&slot->lock); + { + slot->in_handler--; + + if (gen != slot->gen) { + /* event_unregister() happened while we were + in handler() + */ + gf_msg_debug("epoll", 0, + "generation bumped on idx=%d" + " from gen=%d to slot->gen=%d, fd=%d, " + "slot->fd=%d", + idx, gen, slot->gen, fd, slot->fd); + goto unlock; + } + + /* This call also picks up the changes made by another + thread calling event_select_on_epoll() while this + thread was busy in handler() + */ + if (slot->in_handler == 0) { + epoll_event.events = slot->events; + ev_data->idx = idx; + ev_data->gen = gen; + + ret = epoll_ctl(event_pool->fd, EPOLL_CTL_MOD, fd, &epoll_event); + } + } +unlock: + UNLOCK(&slot->lock); + + event_slot_unref(event_pool, slot, idx); + + return ret; +} + +struct event_ops event_ops_epoll = { + .new = event_pool_new_epoll, + .event_register = event_register_epoll, + .event_select_on = event_select_on_epoll, + .event_unregister = event_unregister_epoll, + .event_unregister_close = event_unregister_close_epoll, + .event_dispatch = event_dispatch_epoll, + .event_reconfigure_threads = event_reconfigure_threads_epoll, + .event_pool_destroy = event_pool_destroy_epoll, + .event_handled = event_handled_epoll, +}; + +#endif diff --git a/libglusterfs/src/event-history.c b/libglusterfs/src/event-history.c new file mode 100644 index 00000000000..379fed866be --- /dev/null +++ b/libglusterfs/src/event-history.c @@ -0,0 +1,82 @@ +/* + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include "glusterfs/event-history.h" +#include "glusterfs/libglusterfs-messages.h" + +eh_t * +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; + + history = GF_CALLOC(1, sizeof(eh_t), gf_common_mt_eh_t); + if (!history) { + goto out; + } + + buffer = cb_buffer_new(buffer_size, use_buffer_once, destroy_buffer_data); + if (!buffer) { + GF_FREE(history); + history = NULL; + goto out; + } + + history->buffer = buffer; + + pthread_mutex_init(&history->lock, NULL); +out: + return history; +} + +void +eh_dump(eh_t *history, void *data, + int(dump_fn)(circular_buffer_t *buffer, void *data)) +{ + if (!history) { + gf_msg_debug("event-history", 0, "history is NULL"); + goto out; + } + + cb_buffer_dump(history->buffer, data, dump_fn); + +out: + return; +} + +int +eh_save_history(eh_t *history, void *data) +{ + int ret = -1; + + ret = cb_add_entry_buffer(history->buffer, data); + + return ret; +} + +int +eh_destroy(eh_t *history) +{ + if (!history) { + gf_msg("event-history", GF_LOG_INFO, 0, LG_MSG_INVALID_ARG, + "history for the xlator is NULL"); + return -1; + } + + cb_buffer_destroy(history->buffer); + history->buffer = NULL; + + pthread_mutex_destroy(&history->lock); + + GF_FREE(history); + + return 0; +} diff --git a/libglusterfs/src/event-poll.c b/libglusterfs/src/event-poll.c new file mode 100644 index 00000000000..2cba963f096 --- /dev/null +++ b/libglusterfs/src/event-poll.c @@ -0,0 +1,513 @@ +/* + Copyright (c) 2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include <sys/poll.h> +#include <pthread.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> + +#include "glusterfs/logging.h" +#include "glusterfs/gf-event.h" +#include "glusterfs/mem-pool.h" +#include "glusterfs/common-utils.h" +#include "glusterfs/syscall.h" +#include "glusterfs/libglusterfs-messages.h" + +struct event_slot_poll { + int fd; + int events; + void *data; + event_handler_t handler; +}; + +static int +event_register_poll(struct event_pool *event_pool, int fd, + event_handler_t handler, void *data, int poll_in, + int poll_out, char notify_poller_death); + +static void +__flush_fd(int fd, int idx, int gen, void *data, int poll_in, int poll_out, + int poll_err, char event_thread_died) +{ + char buf[64]; + int ret = -1; + + if (!poll_in) + return; + + do { + ret = sys_read(fd, buf, 64); + if (ret == -1 && errno != EAGAIN) { + gf_smsg("poll", GF_LOG_ERROR, errno, LG_MSG_READ_FILE_FAILED, + "fd=%d", fd, NULL); + } + } while (ret == 64); + + return; +} + +static int +__event_getindex(struct event_pool *event_pool, int fd, int idx) +{ + int ret = -1; + int i = 0; + + GF_VALIDATE_OR_GOTO("event", event_pool, out); + + /* lookup in used space based on index provided */ + if (idx > -1 && idx < event_pool->used) { + if (event_pool->reg[idx].fd == fd) { + ret = idx; + goto out; + } + } + + /* search in used space, if lookup fails */ + for (i = 0; i < event_pool->used; i++) { + if (event_pool->reg[i].fd == fd) { + ret = i; + break; + } + } + +out: + return ret; +} + +static struct event_pool * +event_pool_new_poll(int count, int eventthreadcount) +{ + struct event_pool *event_pool = NULL; + int ret = -1; + + event_pool = GF_CALLOC(1, sizeof(*event_pool), gf_common_mt_event_pool); + + if (!event_pool) + return NULL; + + event_pool->count = count; + event_pool->reg = GF_CALLOC(event_pool->count, sizeof(*event_pool->reg), + gf_common_mt_reg); + + if (!event_pool->reg) { + GF_FREE(event_pool); + return NULL; + } + + pthread_mutex_init(&event_pool->mutex, NULL); + + ret = pipe(event_pool->breaker); + + if (ret == -1) { + gf_smsg("poll", GF_LOG_ERROR, errno, LG_MSG_PIPE_CREATE_FAILED, NULL); + GF_FREE(event_pool->reg); + GF_FREE(event_pool); + return NULL; + } + + ret = fcntl(event_pool->breaker[0], F_SETFL, O_NONBLOCK); + if (ret == -1) { + gf_smsg("poll", GF_LOG_ERROR, errno, LG_MSG_SET_PIPE_FAILED, NULL); + sys_close(event_pool->breaker[0]); + sys_close(event_pool->breaker[1]); + event_pool->breaker[0] = event_pool->breaker[1] = -1; + + GF_FREE(event_pool->reg); + GF_FREE(event_pool); + return NULL; + } + + ret = fcntl(event_pool->breaker[1], F_SETFL, O_NONBLOCK); + if (ret == -1) { + gf_smsg("poll", GF_LOG_ERROR, errno, LG_MSG_SET_PIPE_FAILED, NULL); + + sys_close(event_pool->breaker[0]); + sys_close(event_pool->breaker[1]); + event_pool->breaker[0] = event_pool->breaker[1] = -1; + + GF_FREE(event_pool->reg); + GF_FREE(event_pool); + return NULL; + } + + ret = event_register_poll(event_pool, event_pool->breaker[0], __flush_fd, + NULL, 1, 0, 0); + if (ret == -1) { + gf_smsg("poll", GF_LOG_ERROR, 0, LG_MSG_REGISTER_PIPE_FAILED, NULL); + sys_close(event_pool->breaker[0]); + sys_close(event_pool->breaker[1]); + event_pool->breaker[0] = event_pool->breaker[1] = -1; + + GF_FREE(event_pool->reg); + GF_FREE(event_pool); + return NULL; + } + + if (eventthreadcount > 1) { + gf_smsg("poll", GF_LOG_INFO, 0, LG_MSG_POLL_IGNORE_MULTIPLE_THREADS, + "count=%d", eventthreadcount, NULL); + } + + /* although, eventhreadcount for poll implementation is always + * going to be 1, eventthreadcount needs to be set to 1 so that + * rpcsvc_request_handler() thread scaling works flawlessly in + * both epoll and poll models + */ + event_pool->eventthreadcount = 1; + + return event_pool; +} + +static int +event_register_poll(struct event_pool *event_pool, int fd, + event_handler_t handler, void *data, int poll_in, + int poll_out, char notify_poller_death) +{ + int idx = -1; + + GF_VALIDATE_OR_GOTO("event", event_pool, out); + + pthread_mutex_lock(&event_pool->mutex); + { + if (event_pool->count == event_pool->used) { + event_pool->count += 256; + + event_pool->reg = GF_REALLOC( + event_pool->reg, event_pool->count * sizeof(*event_pool->reg)); + if (!event_pool->reg) + goto unlock; + } + + idx = event_pool->used++; + + event_pool->reg[idx].fd = fd; + event_pool->reg[idx].events = POLLPRI; + event_pool->reg[idx].handler = handler; + event_pool->reg[idx].data = data; + + switch (poll_in) { + case 1: + event_pool->reg[idx].events |= POLLIN; + break; + case 0: + event_pool->reg[idx].events &= ~POLLIN; + break; + case -1: + /* do nothing */ + break; + default: + gf_smsg("poll", GF_LOG_ERROR, 0, LG_MSG_INVALID_POLL_IN, + "value=%d", poll_in, NULL); + break; + } + + switch (poll_out) { + case 1: + event_pool->reg[idx].events |= POLLOUT; + break; + case 0: + event_pool->reg[idx].events &= ~POLLOUT; + break; + case -1: + /* do nothing */ + break; + default: + gf_smsg("poll", GF_LOG_ERROR, 0, LG_MSG_INVALID_POLL_OUT, + "value=%d", poll_out, NULL); + break; + } + + event_pool->changed = 1; + } +unlock: + pthread_mutex_unlock(&event_pool->mutex); + +out: + return idx; +} + +static int +event_unregister_poll(struct event_pool *event_pool, int fd, int idx_hint) +{ + int idx = -1; + + GF_VALIDATE_OR_GOTO("event", event_pool, out); + + pthread_mutex_lock(&event_pool->mutex); + { + idx = __event_getindex(event_pool, fd, idx_hint); + + if (idx == -1) { + gf_smsg("poll", GF_LOG_ERROR, 0, LG_MSG_INDEX_NOT_FOUND, "fd=%d", + fd, "idx_hint=%d", idx_hint, NULL); + errno = ENOENT; + goto unlock; + } + + event_pool->reg[idx] = event_pool->reg[--event_pool->used]; + event_pool->changed = 1; + } +unlock: + pthread_mutex_unlock(&event_pool->mutex); + +out: + return idx; +} + +static int +event_unregister_close_poll(struct event_pool *event_pool, int fd, int idx_hint) +{ + int ret = -1; + + ret = event_unregister_poll(event_pool, fd, idx_hint); + + sys_close(fd); + + return ret; +} + +static int +event_select_on_poll(struct event_pool *event_pool, int fd, int idx_hint, + int poll_in, int poll_out) +{ + int idx = -1; + + GF_VALIDATE_OR_GOTO("event", event_pool, out); + + pthread_mutex_lock(&event_pool->mutex); + { + idx = __event_getindex(event_pool, fd, idx_hint); + + if (idx == -1) { + gf_smsg("poll", GF_LOG_ERROR, 0, LG_MSG_INDEX_NOT_FOUND, "fd=%d", + fd, "idx_hint=%d", idx_hint, NULL); + errno = ENOENT; + goto unlock; + } + + switch (poll_in) { + case 1: + event_pool->reg[idx].events |= POLLIN; + break; + case 0: + event_pool->reg[idx].events &= ~POLLIN; + break; + case -1: + /* do nothing */ + break; + default: + /* TODO: log error */ + break; + } + + switch (poll_out) { + case 1: + event_pool->reg[idx].events |= POLLOUT; + break; + case 0: + event_pool->reg[idx].events &= ~POLLOUT; + break; + case -1: + /* do nothing */ + break; + default: + /* TODO: log error */ + break; + } + + if (poll_in + poll_out > -2) + event_pool->changed = 1; + } +unlock: + pthread_mutex_unlock(&event_pool->mutex); + +out: + return idx; +} + +static int +event_dispatch_poll_handler(struct event_pool *event_pool, struct pollfd *ufds, + int i) +{ + event_handler_t handler = NULL; + void *data = NULL; + int idx = -1; + int ret = 0; + + handler = NULL; + data = NULL; + + pthread_mutex_lock(&event_pool->mutex); + { + idx = __event_getindex(event_pool, ufds[i].fd, i); + + if (idx == -1) { + gf_smsg("poll", GF_LOG_ERROR, 0, LG_MSG_INDEX_NOT_FOUND, "fd=%d", + ufds[i].fd, "idx_hint=%d", i, NULL); + goto unlock; + } + + handler = event_pool->reg[idx].handler; + data = event_pool->reg[idx].data; + } +unlock: + pthread_mutex_unlock(&event_pool->mutex); + + if (handler) + handler(ufds[i].fd, idx, 0, data, + (ufds[i].revents & (POLLIN | POLLPRI)), + (ufds[i].revents & (POLLOUT)), + (ufds[i].revents & (POLLERR | POLLHUP | POLLNVAL)), 0); + + return ret; +} + +static int +event_dispatch_poll_resize(struct event_pool *event_pool, struct pollfd *ufds, + int size) +{ + int i = 0; + + pthread_mutex_lock(&event_pool->mutex); + { + if (event_pool->changed == 0) { + goto unlock; + } + + if (event_pool->used > event_pool->evcache_size) { + GF_FREE(event_pool->evcache); + + event_pool->evcache = ufds = NULL; + + event_pool->evcache_size = event_pool->used; + + ufds = GF_CALLOC(sizeof(struct pollfd), event_pool->evcache_size, + gf_common_mt_pollfd); + if (!ufds) + goto unlock; + event_pool->evcache = ufds; + } + + if (ufds == NULL) { + goto unlock; + } + + for (i = 0; i < event_pool->used; i++) { + ufds[i].fd = event_pool->reg[i].fd; + ufds[i].events = event_pool->reg[i].events; + ufds[i].revents = 0; + } + + size = i; + } +unlock: + pthread_mutex_unlock(&event_pool->mutex); + + return size; +} + +static int +event_dispatch_poll(struct event_pool *event_pool) +{ + struct pollfd *ufds = NULL; + int size = 0; + int i = 0; + int ret = -1; + + GF_VALIDATE_OR_GOTO("event", event_pool, out); + + pthread_mutex_lock(&event_pool->mutex); + { + event_pool->activethreadcount = 1; + } + pthread_mutex_unlock(&event_pool->mutex); + + while (1) { + pthread_mutex_lock(&event_pool->mutex); + { + if (event_pool->destroy == 1) { + event_pool->activethreadcount = 0; + pthread_cond_broadcast(&event_pool->cond); + pthread_mutex_unlock(&event_pool->mutex); + return 0; + } + } + pthread_mutex_unlock(&event_pool->mutex); + + size = event_dispatch_poll_resize(event_pool, ufds, size); + ufds = event_pool->evcache; + + ret = poll(ufds, size, 1); + + if (ret == 0) + /* timeout */ + continue; + + if (ret == -1 && errno == EINTR) + /* sys call */ + continue; + + for (i = 0; i < size; i++) { + if (!ufds[i].revents) + continue; + + event_dispatch_poll_handler(event_pool, ufds, i); + } + } + +out: + return -1; +} + +int +event_reconfigure_threads_poll(struct event_pool *event_pool, int value) +{ + /* No-op for poll */ + + return 0; +} + +/* This function is the destructor for the event_pool data structure + * Should be called only after poller_threads_destroy() is called, + * else will lead to crashes. + */ +static int +event_pool_destroy_poll(struct event_pool *event_pool) +{ + int ret = 0; + + ret = sys_close(event_pool->breaker[0]); + if (ret) + return ret; + + ret = sys_close(event_pool->breaker[1]); + if (ret) + return ret; + + event_pool->breaker[0] = event_pool->breaker[1] = -1; + + GF_FREE(event_pool->reg); + GF_FREE(event_pool); + + return ret; +} + +struct event_ops event_ops_poll = { + .new = event_pool_new_poll, + .event_register = event_register_poll, + .event_select_on = event_select_on_poll, + .event_unregister = event_unregister_poll, + .event_unregister_close = event_unregister_close_poll, + .event_dispatch = event_dispatch_poll, + .event_reconfigure_threads = event_reconfigure_threads_poll, + .event_pool_destroy = event_pool_destroy_poll}; diff --git a/libglusterfs/src/event.c b/libglusterfs/src/event.c index 59b1bd79eac..402c253ca25 100644 --- a/libglusterfs/src/event.c +++ b/libglusterfs/src/event.c @@ -1,20 +1,11 @@ /* - Copyright (c) 2008-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #include <sys/poll.h> @@ -25,963 +16,290 @@ #include <errno.h> #include <string.h> -#include "logging.h" -#include "event.h" -#include "mem-pool.h" - - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -static int -event_register_poll (struct event_pool *event_pool, int fd, - event_handler_t handler, - void *data, int poll_in, int poll_out); - +#include "glusterfs/gf-event.h" +#include "glusterfs/timespec.h" +#include "glusterfs/common-utils.h" +#include "glusterfs/libglusterfs-messages.h" +#include "glusterfs/syscall.h" -static int -__flush_fd (int fd, int idx, void *data, - int poll_in, int poll_out, int poll_err) -{ - char buf[64]; - int ret = -1; - - if (!poll_in) - return ret; - - do { - ret = read (fd, buf, 64); - if (ret == -1 && errno != EAGAIN) { - gf_log ("poll", GF_LOG_ERROR, - "read on %d returned error (%s)", - fd, strerror (errno)); - } - } while (ret == 64); - - return ret; -} - - -static int -__event_getindex (struct event_pool *event_pool, int fd, int idx) +struct event_pool * +gf_event_pool_new(int count, int eventthreadcount) { - int ret = -1; - int i = 0; - - if (event_pool == NULL) { - gf_log ("event", GF_LOG_ERROR, "invalid argument"); - return -1; - } - - if (idx > -1 && idx < event_pool->used) { - if (event_pool->reg[idx].fd == fd) - ret = idx; - } - - for (i=0; ret == -1 && i<event_pool->used; i++) { - if (event_pool->reg[i].fd == fd) { - ret = i; - break; - } - } - - return ret; -} + struct event_pool *event_pool = NULL; + extern struct event_ops event_ops_poll; +#ifdef HAVE_SYS_EPOLL_H + extern struct event_ops event_ops_epoll; -static struct event_pool * -event_pool_new_poll (int count) -{ - struct event_pool *event_pool = NULL; - int ret = -1; - - event_pool = GF_CALLOC (1, sizeof (*event_pool), - gf_common_mt_event_pool); - - if (!event_pool) - return NULL; - - event_pool->count = count; - event_pool->reg = GF_CALLOC (event_pool->count, - sizeof (*event_pool->reg), - gf_common_mt_reg); - - if (!event_pool->reg) { - gf_log ("poll", GF_LOG_CRITICAL, - "failed to allocate event registry"); - GF_FREE (event_pool); - return NULL; - } - - pthread_mutex_init (&event_pool->mutex, NULL); - - ret = pipe (event_pool->breaker); - - if (ret == -1) { - gf_log ("poll", GF_LOG_ERROR, - "pipe creation failed (%s)", strerror (errno)); - GF_FREE (event_pool->reg); - GF_FREE (event_pool); - return NULL; - } - - ret = fcntl (event_pool->breaker[0], F_SETFL, O_NONBLOCK); - if (ret == -1) { - gf_log ("poll", GF_LOG_ERROR, - "could not set pipe to non blocking mode (%s)", - strerror (errno)); - close (event_pool->breaker[0]); - close (event_pool->breaker[1]); - event_pool->breaker[0] = event_pool->breaker[1] = -1; - - GF_FREE (event_pool->reg); - GF_FREE (event_pool); - return NULL; - } - - ret = fcntl (event_pool->breaker[1], F_SETFL, O_NONBLOCK); - if (ret == -1) { - gf_log ("poll", GF_LOG_ERROR, - "could not set pipe to non blocking mode (%s)", - strerror (errno)); - - close (event_pool->breaker[0]); - close (event_pool->breaker[1]); - event_pool->breaker[0] = event_pool->breaker[1] = -1; - - GF_FREE (event_pool->reg); - GF_FREE (event_pool); - return NULL; - } - - ret = event_register_poll (event_pool, event_pool->breaker[0], - __flush_fd, NULL, 1, 0); - if (ret == -1) { - gf_log ("poll", GF_LOG_ERROR, - "could not register pipe fd with poll event loop"); - close (event_pool->breaker[0]); - close (event_pool->breaker[1]); - event_pool->breaker[0] = event_pool->breaker[1] = -1; - - GF_FREE (event_pool->reg); - GF_FREE (event_pool); - return NULL; - } - - return event_pool; -} + event_pool = event_ops_epoll.new(count, eventthreadcount); + if (event_pool) { + event_pool->ops = &event_ops_epoll; + } else { + gf_msg("event", GF_LOG_WARNING, 0, LG_MSG_FALLBACK_TO_POLL, + "falling back to poll based event handling"); + } +#endif -static int -event_register_poll (struct event_pool *event_pool, int fd, - event_handler_t handler, - void *data, int poll_in, int poll_out) -{ - int idx = -1; - - if (event_pool == NULL) { - gf_log ("event", GF_LOG_ERROR, "invalid argument"); - return -1; - } - - pthread_mutex_lock (&event_pool->mutex); - { - if (event_pool->count == event_pool->used) - { - event_pool->count += 256; - - event_pool->reg = GF_REALLOC (event_pool->reg, - event_pool->count * - sizeof (*event_pool->reg)); - if (!event_pool->reg) - goto unlock; - } - - idx = event_pool->used++; - - event_pool->reg[idx].fd = fd; - event_pool->reg[idx].events = POLLPRI; - event_pool->reg[idx].handler = handler; - event_pool->reg[idx].data = data; - - switch (poll_in) { - case 1: - event_pool->reg[idx].events |= POLLIN; - break; - case 0: - event_pool->reg[idx].events &= ~POLLIN; - break; - case -1: - /* do nothing */ - break; - default: - gf_log ("poll", GF_LOG_ERROR, - "invalid poll_in value %d", poll_in); - break; - } - - switch (poll_out) { - case 1: - event_pool->reg[idx].events |= POLLOUT; - break; - case 0: - event_pool->reg[idx].events &= ~POLLOUT; - break; - case -1: - /* do nothing */ - break; - default: - gf_log ("poll", GF_LOG_ERROR, - "invalid poll_out value %d", poll_out); - break; - } - - event_pool->changed = 1; - - } -unlock: - pthread_mutex_unlock (&event_pool->mutex); - - return idx; -} + if (!event_pool) { + event_pool = event_ops_poll.new(count, eventthreadcount); + if (event_pool) + event_pool->ops = &event_ops_poll; + } -static int -event_unregister_poll (struct event_pool *event_pool, int fd, int idx_hint) -{ - int idx = -1; - - if (event_pool == NULL) { - gf_log ("event", GF_LOG_ERROR, "invalid argument"); - return -1; - } - - pthread_mutex_lock (&event_pool->mutex); - { - idx = __event_getindex (event_pool, fd, idx_hint); - - if (idx == -1) { - gf_log ("poll", GF_LOG_ERROR, - "index not found for fd=%d (idx_hint=%d)", - fd, idx_hint); - errno = ENOENT; - goto unlock; - } - - event_pool->reg[idx] = event_pool->reg[--event_pool->used]; - event_pool->changed = 1; - } -unlock: - pthread_mutex_unlock (&event_pool->mutex); - - return idx; + return event_pool; } - -static int -event_select_on_poll (struct event_pool *event_pool, int fd, int idx_hint, - int poll_in, int poll_out) -{ - int idx = -1; - - if (event_pool == NULL) { - gf_log ("event", GF_LOG_ERROR, "invalid argument"); - return -1; - } - - pthread_mutex_lock (&event_pool->mutex); - { - idx = __event_getindex (event_pool, fd, idx_hint); - - if (idx == -1) { - gf_log ("poll", GF_LOG_ERROR, - "index not found for fd=%d (idx_hint=%d)", - fd, idx_hint); - errno = ENOENT; - goto unlock; - } - - switch (poll_in) { - case 1: - event_pool->reg[idx].events |= POLLIN; - break; - case 0: - event_pool->reg[idx].events &= ~POLLIN; - break; - case -1: - /* do nothing */ - break; - default: - /* TODO: log error */ - break; - } - - switch (poll_out) { - case 1: - event_pool->reg[idx].events |= POLLOUT; - break; - case 0: - event_pool->reg[idx].events &= ~POLLOUT; - break; - case -1: - /* do nothing */ - break; - default: - /* TODO: log error */ - break; - } - - if (poll_in + poll_out > -2) - event_pool->changed = 1; - } -unlock: - pthread_mutex_unlock (&event_pool->mutex); - - return idx; -} - - -static int -event_dispatch_poll_handler (struct event_pool *event_pool, - struct pollfd *ufds, int i) +int +gf_event_register(struct event_pool *event_pool, int fd, + event_handler_t handler, void *data, int poll_in, + int poll_out, char notify_poller_death) { - event_handler_t handler = NULL; - void *data = NULL; - int idx = -1; - int ret = 0; - - handler = NULL; - data = NULL; - - pthread_mutex_lock (&event_pool->mutex); - { - idx = __event_getindex (event_pool, ufds[i].fd, i); - - if (idx == -1) { - gf_log ("poll", GF_LOG_ERROR, - "index not found for fd=%d (idx_hint=%d)", - ufds[i].fd, i); - goto unlock; - } - - handler = event_pool->reg[idx].handler; - data = event_pool->reg[idx].data; - } -unlock: - pthread_mutex_unlock (&event_pool->mutex); - - if (handler) - ret = handler (ufds[i].fd, idx, data, - (ufds[i].revents & (POLLIN|POLLPRI)), - (ufds[i].revents & (POLLOUT)), - (ufds[i].revents & (POLLERR|POLLHUP|POLLNVAL))); - - return ret; -} + int ret = -1; + GF_VALIDATE_OR_GOTO("event", event_pool, out); -static int -event_dispatch_poll_resize (struct event_pool *event_pool, - struct pollfd *ufds, int size) -{ - int i = 0; - - pthread_mutex_lock (&event_pool->mutex); - { - if (event_pool->changed == 0) { - goto unlock; - } - - if (event_pool->used > event_pool->evcache_size) { - if (event_pool->evcache) - GF_FREE (event_pool->evcache); - - event_pool->evcache = ufds = NULL; - - event_pool->evcache_size = event_pool->used; - - ufds = GF_CALLOC (sizeof (struct pollfd), - event_pool->evcache_size, - gf_common_mt_pollfd); - if (!ufds) - goto unlock; - event_pool->evcache = ufds; - } - - for (i = 0; i < event_pool->used; i++) { - ufds[i].fd = event_pool->reg[i].fd; - ufds[i].events = event_pool->reg[i].events; - ufds[i].revents = 0; - } - - size = i; - } -unlock: - pthread_mutex_unlock (&event_pool->mutex); - - return size; + ret = event_pool->ops->event_register( + event_pool, fd, handler, data, poll_in, poll_out, notify_poller_death); +out: + return ret; } - -static int -event_dispatch_poll (struct event_pool *event_pool) +int +gf_event_unregister(struct event_pool *event_pool, int fd, int idx) { - struct pollfd *ufds = NULL; - int size = 0; - int i = 0; - int ret = -1; - - - if (event_pool == NULL) { - gf_log ("event", GF_LOG_ERROR, "invalid argument"); - return -1; - } - - while (1) { - size = event_dispatch_poll_resize (event_pool, ufds, size); - ufds = event_pool->evcache; - - ret = poll (ufds, size, 1); - - if (ret == 0) - /* timeout */ - continue; + int ret = -1; - if (ret == -1 && errno == EINTR) - /* sys call */ - continue; + GF_VALIDATE_OR_GOTO("event", event_pool, out); - for (i = 0; i < size; i++) { - if (!ufds[i].revents) - continue; + ret = event_pool->ops->event_unregister(event_pool, fd, idx); - event_dispatch_poll_handler (event_pool, ufds, i); - } - } - - return -1; +out: + return ret; } - -static struct event_ops event_ops_poll = { - .new = event_pool_new_poll, - .event_register = event_register_poll, - .event_select_on = event_select_on_poll, - .event_unregister = event_unregister_poll, - .event_dispatch = event_dispatch_poll -}; - - - -#ifdef HAVE_SYS_EPOLL_H -#include <sys/epoll.h> - - -static struct event_pool * -event_pool_new_epoll (int count) +int +gf_event_unregister_close(struct event_pool *event_pool, int fd, int idx) { - struct event_pool *event_pool = NULL; - int epfd = -1; - - event_pool = GF_CALLOC (1, sizeof (*event_pool), - gf_common_mt_event_pool); + int ret = -1; - if (!event_pool) - return NULL; + GF_VALIDATE_OR_GOTO("event", event_pool, out); - event_pool->count = count; - event_pool->reg = GF_CALLOC (event_pool->count, - sizeof (*event_pool->reg), - gf_common_mt_reg); + ret = event_pool->ops->event_unregister_close(event_pool, fd, idx); - if (!event_pool->reg) { - gf_log ("epoll", GF_LOG_CRITICAL, - "event registry allocation failed"); - GF_FREE (event_pool); - return NULL; - } - - epfd = epoll_create (count); - - if (epfd == -1) { - gf_log ("epoll", GF_LOG_ERROR, "epoll fd creation failed (%s)", - strerror (errno)); - GF_FREE (event_pool->reg); - GF_FREE (event_pool); - return NULL; - } - - event_pool->fd = epfd; - - event_pool->count = count; - - pthread_mutex_init (&event_pool->mutex, NULL); - pthread_cond_init (&event_pool->cond, NULL); - - return event_pool; +out: + return ret; } - int -event_register_epoll (struct event_pool *event_pool, int fd, - event_handler_t handler, - void *data, int poll_in, int poll_out) +gf_event_select_on(struct event_pool *event_pool, int fd, int idx_hint, + int poll_in, int poll_out) { - int idx = -1; - int ret = -1; - struct epoll_event epoll_event = {0, }; - struct event_data *ev_data = (void *)&epoll_event.data; - - - if (event_pool == NULL) { - gf_log ("event", GF_LOG_ERROR, "invalid argument"); - return -1; - } - - pthread_mutex_lock (&event_pool->mutex); - { - if (event_pool->count == event_pool->used) { - event_pool->count *= 2; - - event_pool->reg = GF_REALLOC (event_pool->reg, - event_pool->count * - sizeof (*event_pool->reg)); - - if (!event_pool->reg) { - gf_log ("epoll", GF_LOG_ERROR, - "event registry re-allocation failed"); - goto unlock; - } - } - - idx = event_pool->used; - event_pool->used++; - - event_pool->reg[idx].fd = fd; - event_pool->reg[idx].events = EPOLLPRI; - event_pool->reg[idx].handler = handler; - event_pool->reg[idx].data = data; - - switch (poll_in) { - case 1: - event_pool->reg[idx].events |= EPOLLIN; - break; - case 0: - event_pool->reg[idx].events &= ~EPOLLIN; - break; - case -1: - /* do nothing */ - break; - default: - gf_log ("epoll", GF_LOG_ERROR, - "invalid poll_in value %d", poll_in); - break; - } - - switch (poll_out) { - case 1: - event_pool->reg[idx].events |= EPOLLOUT; - break; - case 0: - event_pool->reg[idx].events &= ~EPOLLOUT; - break; - case -1: - /* do nothing */ - break; - default: - gf_log ("epoll", GF_LOG_ERROR, - "invalid poll_out value %d", poll_out); - break; - } - - event_pool->changed = 1; - - epoll_event.events = event_pool->reg[idx].events; - ev_data->fd = fd; - ev_data->idx = idx; - - ret = epoll_ctl (event_pool->fd, EPOLL_CTL_ADD, fd, - &epoll_event); - - if (ret == -1) { - gf_log ("epoll", GF_LOG_ERROR, - "failed to add fd(=%d) to epoll fd(=%d) (%s)", - fd, event_pool->fd, strerror (errno)); - goto unlock; - } - - pthread_cond_broadcast (&event_pool->cond); - } -unlock: - pthread_mutex_unlock (&event_pool->mutex); - - return ret; -} + int ret = -1; + GF_VALIDATE_OR_GOTO("event", event_pool, out); -static int -event_unregister_epoll (struct event_pool *event_pool, int fd, int idx_hint) -{ - int idx = -1; - int ret = -1; - - struct epoll_event epoll_event = {0, }; - struct event_data *ev_data = (void *)&epoll_event.data; - int lastidx = -1; - - if (event_pool == NULL) { - gf_log ("event", GF_LOG_ERROR, "invalid argument"); - return -1; - } - - pthread_mutex_lock (&event_pool->mutex); - { - idx = __event_getindex (event_pool, fd, idx_hint); - - if (idx == -1) { - gf_log ("epoll", GF_LOG_ERROR, - "index not found for fd=%d (idx_hint=%d)", - fd, idx_hint); - errno = ENOENT; - goto unlock; - } - - ret = epoll_ctl (event_pool->fd, EPOLL_CTL_DEL, fd, NULL); - - /* if ret is -1, this array member should never be accessed */ - /* if it is 0, the array member might be used by idx_cache - * in which case the member should not be accessed till - * it is reallocated - */ - - event_pool->reg[idx].fd = -1; - - if (ret == -1) { - gf_log ("epoll", GF_LOG_ERROR, - "fail to del fd(=%d) from epoll fd(=%d) (%s)", - fd, event_pool->fd, strerror (errno)); - goto unlock; - } - - lastidx = event_pool->used - 1; - if (lastidx == idx) { - event_pool->used--; - goto unlock; - } - - epoll_event.events = event_pool->reg[lastidx].events; - ev_data->fd = event_pool->reg[lastidx].fd; - ev_data->idx = idx; - - ret = epoll_ctl (event_pool->fd, EPOLL_CTL_MOD, ev_data->fd, - &epoll_event); - if (ret == -1) { - gf_log ("epoll", GF_LOG_ERROR, - "fail to modify fd(=%d) index %d to %d (%s)", - ev_data->fd, event_pool->used, idx, - strerror (errno)); - goto unlock; - } - - /* just replace the unregistered idx by last one */ - event_pool->reg[idx] = event_pool->reg[lastidx]; - event_pool->used--; - } -unlock: - pthread_mutex_unlock (&event_pool->mutex); - - return ret; + ret = event_pool->ops->event_select_on(event_pool, fd, idx_hint, poll_in, + poll_out); +out: + return ret; } - -static int -event_select_on_epoll (struct event_pool *event_pool, int fd, int idx_hint, - int poll_in, int poll_out) +int +gf_event_dispatch(struct event_pool *event_pool) { - int idx = -1; - int ret = -1; - - struct epoll_event epoll_event = {0, }; - struct event_data *ev_data = (void *)&epoll_event.data; - - - if (event_pool == NULL) { - gf_log ("event", GF_LOG_ERROR, "invalid argument"); - return -1; - } - - pthread_mutex_lock (&event_pool->mutex); - { - idx = __event_getindex (event_pool, fd, idx_hint); - - if (idx == -1) { - gf_log ("epoll", GF_LOG_ERROR, - "index not found for fd=%d (idx_hint=%d)", - fd, idx_hint); - errno = ENOENT; - goto unlock; - } - - switch (poll_in) { - case 1: - event_pool->reg[idx].events |= EPOLLIN; - break; - case 0: - event_pool->reg[idx].events &= ~EPOLLIN; - break; - case -1: - /* do nothing */ - break; - default: - gf_log ("epoll", GF_LOG_ERROR, - "invalid poll_in value %d", poll_in); - break; - } - - switch (poll_out) { - case 1: - event_pool->reg[idx].events |= EPOLLOUT; - break; - case 0: - event_pool->reg[idx].events &= ~EPOLLOUT; - break; - case -1: - /* do nothing */ - break; - default: - gf_log ("epoll", GF_LOG_ERROR, - "invalid poll_out value %d", poll_out); - break; - } - - epoll_event.events = event_pool->reg[idx].events; - ev_data->fd = fd; - ev_data->idx = idx; - - ret = epoll_ctl (event_pool->fd, EPOLL_CTL_MOD, fd, - &epoll_event); - if (ret == -1) { - gf_log ("epoll", GF_LOG_ERROR, - "failed to modify fd(=%d) events to %d", - fd, epoll_event.events); - } - } -unlock: - pthread_mutex_unlock (&event_pool->mutex); - - return ret; -} + int ret = -1; + GF_VALIDATE_OR_GOTO("event", event_pool, out); -static int -event_dispatch_epoll_handler (struct event_pool *event_pool, - struct epoll_event *events, int i) -{ - struct event_data *event_data = NULL; - event_handler_t handler = NULL; - void *data = NULL; - int idx = -1; - int ret = -1; - - - event_data = (void *)&events[i].data; - handler = NULL; - data = NULL; - - pthread_mutex_lock (&event_pool->mutex); - { - idx = __event_getindex (event_pool, event_data->fd, - event_data->idx); - - if (idx == -1) { - gf_log ("epoll", GF_LOG_ERROR, - "index not found for fd(=%d) (idx_hint=%d)", - event_data->fd, event_data->idx); - goto unlock; - } - - handler = event_pool->reg[idx].handler; - data = event_pool->reg[idx].data; - } -unlock: - pthread_mutex_unlock (&event_pool->mutex); - - if (handler) - ret = handler (event_data->fd, event_data->idx, data, - (events[i].events & (EPOLLIN|EPOLLPRI)), - (events[i].events & (EPOLLOUT)), - (events[i].events & (EPOLLERR|EPOLLHUP))); - return ret; -} + ret = event_pool->ops->event_dispatch(event_pool); + if (ret) + goto out; +out: + return ret; +} -static int -event_dispatch_epoll (struct event_pool *event_pool) +int +gf_event_reconfigure_threads(struct event_pool *event_pool, int value) { - struct epoll_event *events = NULL; - int size = 0; - int i = 0; - int ret = -1; - - - if (event_pool == NULL) { - gf_log ("event", GF_LOG_ERROR, "invalid argument"); - return -1; - } - - while (1) { - pthread_mutex_lock (&event_pool->mutex); - { - while (event_pool->used == 0) - pthread_cond_wait (&event_pool->cond, - &event_pool->mutex); - - if (event_pool->used > event_pool->evcache_size) { - if (event_pool->evcache) - GF_FREE (event_pool->evcache); - - event_pool->evcache = events = NULL; - - event_pool->evcache_size = - event_pool->used + 256; - - events = GF_CALLOC (event_pool->evcache_size, - sizeof (struct epoll_event), - gf_common_mt_epoll_event); + int ret = -1; - event_pool->evcache = events; - } - } - pthread_mutex_unlock (&event_pool->mutex); + GF_VALIDATE_OR_GOTO("event", event_pool, out); - ret = epoll_wait (event_pool->fd, event_pool->evcache, - event_pool->evcache_size, -1); + /* call event refresh function */ + ret = event_pool->ops->event_reconfigure_threads(event_pool, value); - if (ret == 0) - /* timeout */ - continue; - - if (ret == -1 && errno == EINTR) - /* sys call */ - continue; - - size = ret; - - for (i = 0; i < size; i++) { - if (!events || !events[i].events) - continue; - - ret = event_dispatch_epoll_handler (event_pool, - events, i); - } - } - - return -1; +out: + return ret; } - -static struct event_ops event_ops_epoll = { - .new = event_pool_new_epoll, - .event_register = event_register_epoll, - .event_select_on = event_select_on_epoll, - .event_unregister = event_unregister_epoll, - .event_dispatch = event_dispatch_epoll -}; - -#endif - - -struct event_pool * -event_pool_new (int count) +int +gf_event_pool_destroy(struct event_pool *event_pool) { - struct event_pool *event_pool = NULL; + int ret = -1; + int destroy = 0, activethreadcount = 0; -#ifdef HAVE_SYS_EPOLL_H - event_pool = event_ops_epoll.new (count); - - if (event_pool) { - event_pool->ops = &event_ops_epoll; - } else { - gf_log ("event", GF_LOG_WARNING, - "failing back to poll based event handling"); - } -#endif + GF_VALIDATE_OR_GOTO("event", event_pool, out); - if (!event_pool) { - event_pool = event_ops_poll.new (count); + pthread_mutex_lock(&event_pool->mutex); + { + destroy = event_pool->destroy; + activethreadcount = event_pool->activethreadcount; + } + pthread_mutex_unlock(&event_pool->mutex); - if (event_pool) - event_pool->ops = &event_ops_poll; - } + if (!destroy || (activethreadcount > 0)) { + goto out; + } - return event_pool; + ret = event_pool->ops->event_pool_destroy(event_pool); +out: + return ret; } - -int -event_register (struct event_pool *event_pool, int fd, - event_handler_t handler, - void *data, int poll_in, int poll_out) +void +poller_destroy_handler(int fd, int idx, int gen, void *data, int poll_out, + int poll_in, int poll_err, char event_thread_exit) { - int ret = -1; - - if (event_pool == NULL) { - gf_log ("event", GF_LOG_ERROR, "invalid argument"); - return -1; - } - - ret = event_pool->ops->event_register (event_pool, fd, handler, data, - poll_in, poll_out); - return ret; -} + struct event_destroy_data *destroy = NULL; + int readfd = -1; + char buf = '\0'; + destroy = data; + readfd = destroy->readfd; + if (readfd < 0) { + goto out; + } -int -event_unregister (struct event_pool *event_pool, int fd, int idx) -{ - int ret = -1; + while (sys_read(readfd, &buf, 1) > 0) { + } - if (event_pool == NULL) { - gf_log ("event", GF_LOG_ERROR, "invalid argument"); - return -1; - } - - ret = event_pool->ops->event_unregister (event_pool, fd, idx); +out: + gf_event_handled(destroy->pool, fd, idx, gen); - return ret; + return; } - +/* This function destroys all the poller threads. + * Note: to be called before gf_event_pool_destroy is called. + * The order in which cleaning is performed: + * - Register a pipe fd(this is for waking threads in poll()/epoll_wait()) + * - Set the destroy mode, which this no new event registration will succeed + * - Reconfigure the thread count to 0(this will succeed only in destroy mode) + * - Wake up all the threads in poll() or epoll_wait(), so that they can + * destroy themselves. + * - Wait for the thread to join(which will happen only after all the other + * threads are destroyed) + */ int -event_select_on (struct event_pool *event_pool, int fd, int idx_hint, - int poll_in, int poll_out) +gf_event_dispatch_destroy(struct event_pool *event_pool) { - int ret = -1; - - if (event_pool == NULL) { - gf_log ("event", GF_LOG_ERROR, "invalid argument"); - return -1; - } - - ret = event_pool->ops->event_select_on (event_pool, fd, idx_hint, - poll_in, poll_out); - return ret; + int ret = -1, threadcount = 0; + int fd[2] = {-1}; + int idx = -1; + int flags = 0; + struct timespec sleep_till = { + 0, + }; + struct event_destroy_data data = { + 0, + }; + + GF_VALIDATE_OR_GOTO("event", event_pool, out); + + ret = pipe(fd); + if (ret < 0) + goto out; + + /* Make the read end of the pipe nonblocking */ + flags = fcntl(fd[0], F_GETFL); + flags |= O_NONBLOCK; + ret = fcntl(fd[0], F_SETFL, flags); + if (ret < 0) + goto out; + + /* Make the write end of the pipe nonblocking */ + flags = fcntl(fd[1], F_GETFL); + flags |= O_NONBLOCK; + ret = fcntl(fd[1], F_SETFL, flags); + if (ret < 0) + goto out; + + data.pool = event_pool; + data.readfd = fd[1]; + + /* From the main thread register an event on the pipe fd[0], + */ + idx = gf_event_register(event_pool, fd[0], poller_destroy_handler, &data, 1, + 0, 0); + if (idx < 0) + goto out; + + /* Enter the destroy mode first, set this before reconfiguring to 0 + * threads, to prevent further reconfigure to thread count > 0. + */ + pthread_mutex_lock(&event_pool->mutex); + { + threadcount = event_pool->eventthreadcount; + event_pool->destroy = 1; + } + pthread_mutex_unlock(&event_pool->mutex); + + ret = gf_event_reconfigure_threads(event_pool, 0); + if (ret < 0) + goto out; + + /* Write something onto the write end of the pipe(fd[1]) so that + * poll wakes up and calls the handler, poller_destroy_handler() + */ + pthread_mutex_lock(&event_pool->mutex); + { + /* Write to pipe(fd[1]) and then wait for 1 second or until + * a poller thread that is dying, broadcasts. Make sure we + * do not loop forever by limiting to 10 retries + */ + int retry = 0; + + while (event_pool->activethreadcount > 0 && + (retry++ < (threadcount + 10))) { + if (sys_write(fd[1], "dummy", 6) == -1) { + break; + } + timespec_now_realtime(&sleep_till); + sleep_till.tv_sec += 1; + ret = pthread_cond_timedwait(&event_pool->cond, &event_pool->mutex, + &sleep_till); + if (ret) { + gf_msg_debug("event", 0, + "thread cond-timedwait failed " + "active-thread-count: %d, " + "retry: %d", + event_pool->activethreadcount, retry); + } + } + } + pthread_mutex_unlock(&event_pool->mutex); + + ret = gf_event_unregister(event_pool, fd[0], idx); + +out: + if (fd[0] != -1) + sys_close(fd[0]); + if (fd[1] != -1) + sys_close(fd[1]); + + return ret; } - int -event_dispatch (struct event_pool *event_pool) +gf_event_handled(struct event_pool *event_pool, int fd, int idx, int gen) { - int ret = -1; + int ret = 0; - if (event_pool == NULL) { - gf_log ("event", GF_LOG_ERROR, "invalid argument"); - return -1; - } - - ret = event_pool->ops->event_dispatch (event_pool); + if (event_pool->ops->event_handled) + ret = event_pool->ops->event_handled(event_pool, fd, idx, gen); - return ret; + return ret; } diff --git a/libglusterfs/src/event.h b/libglusterfs/src/event.h deleted file mode 100644 index 6baad115075..00000000000 --- a/libglusterfs/src/event.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - Copyright (c) 2008-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _EVENT_H_ -#define _EVENT_H_ - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include <pthread.h> - -struct event_pool; -struct event_ops; -struct event_data { - int fd; - int idx; -} __attribute__ ((__packed__)); - - -typedef int (*event_handler_t) (int fd, int idx, void *data, - int poll_in, int poll_out, int poll_err); - -struct event_pool { - struct event_ops *ops; - - int fd; - int breaker[2]; - - int count; - struct { - int fd; - int events; - void *data; - event_handler_t handler; - } *reg; - - int used; - int idx_cache; - int changed; - - pthread_mutex_t mutex; - pthread_cond_t cond; - - void *evcache; - int evcache_size; -}; - -struct event_ops { - struct event_pool * (*new) (int count); - - int (*event_register) (struct event_pool *event_pool, int fd, - event_handler_t handler, - void *data, int poll_in, int poll_out); - - int (*event_select_on) (struct event_pool *event_pool, int fd, int idx, - int poll_in, int poll_out); - - int (*event_unregister) (struct event_pool *event_pool, int fd, int idx); - - int (*event_dispatch) (struct event_pool *event_pool); -}; - -struct event_pool * event_pool_new (int count); -int event_select_on (struct event_pool *event_pool, int fd, int idx, - int poll_in, int poll_out); -int event_register (struct event_pool *event_pool, int fd, - event_handler_t handler, - void *data, int poll_in, int poll_out); -int event_unregister (struct event_pool *event_pool, int fd, int idx); -int event_dispatch (struct event_pool *event_pool); - -#endif /* _EVENT_H_ */ diff --git a/libglusterfs/src/events.c b/libglusterfs/src/events.c new file mode 100644 index 00000000000..33157549897 --- /dev/null +++ b/libglusterfs/src/events.c @@ -0,0 +1,136 @@ +/* + Copyright (c) 2016 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <stdio.h> +#include <unistd.h> +#include <time.h> +#include <stdarg.h> +#include <string.h> +#include <netinet/in.h> +#include <netdb.h> + +#include "glusterfs/syscall.h" +#include "glusterfs/mem-pool.h" +#include "glusterfs/glusterfs.h" +#include "glusterfs/globals.h" +#include "glusterfs/events.h" + +#define EVENT_HOST "127.0.0.1" +#define EVENT_PORT 24009 + +int +_gf_event(eventtypes_t event, const char *fmt, ...) +{ + int ret = 0; + int sock = -1; + char *eventstr = NULL; + va_list arguments; + char *msg = NULL; + glusterfs_ctx_t *ctx = NULL; + char *host = NULL; + struct addrinfo hints; + struct addrinfo *result = NULL; + struct addrinfo *iter_result_ptr = NULL; + xlator_t *this = THIS; + char *volfile_server_transport = NULL; + + /* Global context */ + ctx = this->ctx; + + if (event < 0 || event >= EVENT_LAST) { + ret = EVENT_ERROR_INVALID_INPUTS; + goto out; + } + + if (ctx) { + volfile_server_transport = ctx->cmd_args.volfile_server_transport; + } + if (!volfile_server_transport) { + volfile_server_transport = "tcp"; + } + + /* host = NULL returns localhost */ + if (ctx && ctx->cmd_args.volfile_server && + (strcmp(volfile_server_transport, "unix"))) { + /* If it is client code then volfile_server is set + use that information to push the events. */ + host = ctx->cmd_args.volfile_server; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_ADDRCONFIG; + + if ((getaddrinfo(host, TOSTRING(EVENT_PORT), &hints, &result)) != 0) { + ret = EVENT_ERROR_RESOLVE; + goto out; + } + + // iterate over the result and break when socket creation is success. + for (iter_result_ptr = result; iter_result_ptr != NULL; + iter_result_ptr = iter_result_ptr->ai_next) { + sock = socket(iter_result_ptr->ai_family, iter_result_ptr->ai_socktype, + iter_result_ptr->ai_protocol); + if (sock != -1) { + break; + } + } + /* + * If none of the addrinfo structures lead to a successful socket + * creation, socket creation has failed. + */ + if (sock < 0) { + ret = EVENT_ERROR_SOCKET; + goto out; + } + + va_start(arguments, fmt); + ret = gf_vasprintf(&msg, fmt, arguments); + va_end(arguments); + + if (ret < 0) { + ret = EVENT_ERROR_INVALID_INPUTS; + goto out; + } + + ret = gf_asprintf(&eventstr, "%u %d %s", (unsigned)gf_time(), event, msg); + GF_FREE(msg); + if (ret <= 0) { + ret = EVENT_ERROR_MSG_FORMAT; + goto out; + } + + /* Send Message */ + if (sendto(sock, eventstr, strlen(eventstr), 0, result->ai_addr, + result->ai_addrlen) <= 0) { + ret = EVENT_ERROR_SEND; + goto out; + } + + ret = EVENT_SEND_OK; + +out: + if (sock >= 0) { + sys_close(sock); + } + + /* Allocated by gf_asprintf */ + if (eventstr) + GF_FREE(eventstr); + + if (result) + freeaddrinfo(result); + + return ret; +} diff --git a/libglusterfs/src/fd-lk.c b/libglusterfs/src/fd-lk.c new file mode 100644 index 00000000000..c2d34f81c9c --- /dev/null +++ b/libglusterfs/src/fd-lk.c @@ -0,0 +1,433 @@ +/* + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include "glusterfs/fd-lk.h" +#include "glusterfs/common-utils.h" +#include "glusterfs/libglusterfs-messages.h" + +int32_t +_fd_lk_delete_lock(fd_lk_ctx_node_t *lock) +{ + int32_t ret = -1; + + GF_VALIDATE_OR_GOTO("fd-lk", lock, out); + + list_del_init(&lock->next); + + ret = 0; +out: + return ret; +} + +int32_t +_fd_lk_destroy_lock(fd_lk_ctx_node_t *lock) +{ + int32_t ret = -1; + + GF_VALIDATE_OR_GOTO("fd-lk", lock, out); + + GF_FREE(lock); + + ret = 0; +out: + return ret; +} + +int +_fd_lk_destroy_lock_list(fd_lk_ctx_t *lk_ctx) +{ + int ret = -1; + fd_lk_ctx_node_t *lk = NULL; + fd_lk_ctx_node_t *tmp = NULL; + + GF_VALIDATE_OR_GOTO("fd-lk", lk_ctx, out); + + list_for_each_entry_safe(lk, tmp, &lk_ctx->lk_list, next) + { + _fd_lk_delete_lock(lk); + _fd_lk_destroy_lock(lk); + } + ret = 0; +out: + return ret; +} + +int +fd_lk_ctx_unref(fd_lk_ctx_t *lk_ctx) +{ + int ref = -1; + + GF_VALIDATE_OR_GOTO("fd-lk", lk_ctx, err); + + ref = GF_ATOMIC_DEC(lk_ctx->ref); + if (ref < 0) + GF_ASSERT(!ref); + if (ref == 0) + _fd_lk_destroy_lock_list(lk_ctx); + + if (ref == 0) { + LOCK_DESTROY(&lk_ctx->lock); + GF_FREE(lk_ctx); + } + + return 0; +err: + return -1; +} + +fd_lk_ctx_t * +fd_lk_ctx_ref(fd_lk_ctx_t *lk_ctx) +{ + if (!lk_ctx) { + gf_msg_callingfn("fd-lk", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + return NULL; + } + + GF_ATOMIC_INC(lk_ctx->ref); + + return lk_ctx; +} + +fd_lk_ctx_t * +fd_lk_ctx_create() +{ + fd_lk_ctx_t *fd_lk_ctx = NULL; + + fd_lk_ctx = GF_CALLOC(1, sizeof(fd_lk_ctx_t), gf_common_mt_fd_lk_ctx_t); + if (!fd_lk_ctx) + goto out; + + INIT_LIST_HEAD(&fd_lk_ctx->lk_list); + + LOCK_INIT(&fd_lk_ctx->lock); + + fd_lk_ctx = fd_lk_ctx_ref(fd_lk_ctx); +out: + return fd_lk_ctx; +} + +int +_fd_lk_insert_lock(fd_lk_ctx_t *lk_ctx, fd_lk_ctx_node_t *lock) +{ + list_add_tail(&lock->next, &lk_ctx->lk_list); + return 0; +} + +static off_t +_fd_lk_get_lock_len(off_t start, off_t end) +{ + if (end == LLONG_MAX) + return 0; + else + return (end - start + 1); +} + +fd_lk_ctx_node_t * +fd_lk_ctx_node_new(int32_t cmd, struct gf_flock *flock) +{ + fd_lk_ctx_node_t *new_lock = NULL; + + /* TODO: get from mem-pool */ + new_lock = GF_CALLOC(1, sizeof(fd_lk_ctx_node_t), + gf_common_mt_fd_lk_ctx_node_t); + if (!new_lock) + goto out; + + new_lock->cmd = cmd; + + if (flock) { + new_lock->fl_type = flock->l_type; + new_lock->fl_start = flock->l_start; + + if (flock->l_len == 0) + new_lock->fl_end = LLONG_MAX; + else + new_lock->fl_end = flock->l_start + flock->l_len - 1; + + memcpy(&new_lock->user_flock, flock, sizeof(struct gf_flock)); + } + + INIT_LIST_HEAD(&new_lock->next); +out: + return new_lock; +} + +int32_t +_fd_lk_delete_unlck_locks(fd_lk_ctx_t *lk_ctx) +{ + int32_t ret = -1; + fd_lk_ctx_node_t *tmp = NULL; + fd_lk_ctx_node_t *lk = NULL; + + GF_VALIDATE_OR_GOTO("fd-lk", lk_ctx, out); + + list_for_each_entry_safe(lk, tmp, &lk_ctx->lk_list, next) + { + if (lk->fl_type == F_UNLCK) { + _fd_lk_delete_lock(lk); + _fd_lk_destroy_lock(lk); + } + } +out: + return ret; +} + +int +fd_lk_overlap(fd_lk_ctx_node_t *l1, fd_lk_ctx_node_t *l2) +{ + if (l1->fl_end >= l2->fl_start && l2->fl_end >= l1->fl_start) + return 1; + + return 0; +} + +fd_lk_ctx_node_t * +_fd_lk_add_locks(fd_lk_ctx_node_t *l1, fd_lk_ctx_node_t *l2) +{ + fd_lk_ctx_node_t *sum = NULL; + + sum = fd_lk_ctx_node_new(0, NULL); + if (!sum) + goto out; + + sum->fl_start = min(l1->fl_start, l2->fl_start); + sum->fl_end = max(l1->fl_end, l2->fl_end); + + sum->user_flock.l_start = sum->fl_start; + sum->user_flock.l_len = _fd_lk_get_lock_len(sum->fl_start, sum->fl_end); +out: + return sum; +} + +/* Subtract two locks */ +struct _values { + fd_lk_ctx_node_t *locks[3]; +}; + +int32_t +_fd_lk_sub_locks(struct _values *v, fd_lk_ctx_node_t *big, + fd_lk_ctx_node_t *small) +{ + int32_t ret = -1; + + if ((big->fl_start == small->fl_start) && (big->fl_end == small->fl_end)) { + /* both edges coincide with big */ + v->locks[0] = fd_lk_ctx_node_new(small->cmd, NULL); + if (!v->locks[0]) + goto out; + + memcpy(v->locks[0], big, sizeof(fd_lk_ctx_node_t)); + + v->locks[0]->fl_type = small->fl_type; + v->locks[0]->user_flock.l_type = small->fl_type; + } else if ((small->fl_start > big->fl_start) && + (small->fl_end < big->fl_end)) { + /* small lock is completely inside big lock, + break it down into 3 different locks. */ + v->locks[0] = fd_lk_ctx_node_new(big->cmd, NULL); + if (!v->locks[0]) + goto out; + + v->locks[1] = fd_lk_ctx_node_new(small->cmd, NULL); + if (!v->locks[1]) + goto out; + + v->locks[2] = fd_lk_ctx_node_new(big->cmd, NULL); + if (!v->locks[2]) + goto out; + + memcpy(v->locks[0], big, sizeof(fd_lk_ctx_node_t)); + v->locks[0]->fl_end = small->fl_start - 1; + v->locks[0]->user_flock.l_len = _fd_lk_get_lock_len( + v->locks[0]->fl_start, v->locks[0]->fl_end); + + memcpy(v->locks[1], small, sizeof(fd_lk_ctx_node_t)); + + memcpy(v->locks[2], big, sizeof(fd_lk_ctx_node_t)); + v->locks[2]->fl_start = small->fl_end + 1; + v->locks[2]->user_flock.l_len = _fd_lk_get_lock_len( + v->locks[2]->fl_start, v->locks[2]->fl_end); + } else if (small->fl_start == big->fl_start) { + /* One of the ends co-incide, break the + locks into two separate parts */ + v->locks[0] = fd_lk_ctx_node_new(small->cmd, NULL); + if (!v->locks[0]) + goto out; + + v->locks[1] = fd_lk_ctx_node_new(big->cmd, NULL); + if (!v->locks[1]) + goto out; + + memcpy(v->locks[0], small, sizeof(fd_lk_ctx_node_t)); + + memcpy(v->locks[1], big, sizeof(fd_lk_ctx_node_t)); + v->locks[1]->fl_start = small->fl_end + 1; + v->locks[1]->user_flock.l_start = small->fl_end + 1; + } else if (small->fl_end == big->fl_end) { + /* One of the ends co-incide, break the + locks into two separate parts */ + v->locks[0] = fd_lk_ctx_node_new(small->cmd, NULL); + if (!v->locks[0]) + goto out; + + v->locks[1] = fd_lk_ctx_node_new(big->cmd, NULL); + if (!v->locks[1]) + goto out; + + memcpy(v->locks[0], big, sizeof(fd_lk_ctx_node_t)); + v->locks[0]->fl_end = small->fl_start - 1; + v->locks[0]->user_flock.l_len = _fd_lk_get_lock_len( + v->locks[0]->fl_start, v->locks[0]->fl_end); + + memcpy(v->locks[1], small, sizeof(fd_lk_ctx_node_t)); + } else { + /* We should never come to this case */ + GF_ASSERT(!"Invalid case"); + } + ret = 0; +out: + return ret; +} + +static void +_fd_lk_insert_and_merge(fd_lk_ctx_t *lk_ctx, fd_lk_ctx_node_t *lock) +{ + int32_t ret = -1; + int32_t i = 0; + fd_lk_ctx_node_t *entry = NULL; + fd_lk_ctx_node_t *t = NULL; + fd_lk_ctx_node_t *sum = NULL; + struct _values v = {.locks = {0, 0, 0}}; + + list_for_each_entry_safe(entry, t, &lk_ctx->lk_list, next) + { + if (!fd_lk_overlap(entry, lock)) + continue; + + if (entry->fl_type == lock->fl_type) { + sum = _fd_lk_add_locks(entry, lock); + if (!sum) + return; + sum->fl_type = entry->fl_type; + sum->user_flock.l_type = entry->fl_type; + _fd_lk_delete_lock(entry); + _fd_lk_destroy_lock(entry); + _fd_lk_destroy_lock(lock); + _fd_lk_insert_and_merge(lk_ctx, sum); + return; + } else { + sum = _fd_lk_add_locks(entry, lock); + sum->fl_type = lock->fl_type; + sum->user_flock.l_type = lock->fl_type; + ret = _fd_lk_sub_locks(&v, sum, lock); + if (ret) + return; + _fd_lk_delete_lock(entry); + _fd_lk_destroy_lock(entry); + + _fd_lk_delete_lock(lock); + _fd_lk_destroy_lock(lock); + + _fd_lk_destroy_lock(sum); + + for (i = 0; i < 3; i++) { + if (!v.locks[i]) + continue; + + INIT_LIST_HEAD(&v.locks[i]->next); + _fd_lk_insert_and_merge(lk_ctx, v.locks[i]); + } + _fd_lk_delete_unlck_locks(lk_ctx); + return; + } + } + + /* no conflicts, so just insert */ + if (lock->fl_type != F_UNLCK) { + _fd_lk_insert_lock(lk_ctx, lock); + } else { + _fd_lk_destroy_lock(lock); + } +} + +static void +print_lock_list(fd_lk_ctx_t *lk_ctx) +{ + fd_lk_ctx_node_t *lk = NULL; + + gf_msg_debug("fd-lk", 0, "lock list:"); + + list_for_each_entry(lk, &lk_ctx->lk_list, next) + gf_msg_debug("fd-lk", 0, + "owner = %s, cmd = %s fl_type = %s," + " fs_start = %" PRId64 ", fs_end = %" PRId64 + ", " + "user_flock: l_type = %s, l_start = %" PRId64 + ", " + "l_len = %" PRId64 ", ", + lkowner_utoa(&lk->user_flock.l_owner), get_lk_cmd(lk->cmd), + get_lk_type(lk->fl_type), lk->fl_start, lk->fl_end, + get_lk_type(lk->user_flock.l_type), lk->user_flock.l_start, + lk->user_flock.l_len); +} + +int +fd_lk_insert_and_merge(fd_t *fd, int32_t cmd, struct gf_flock *flock) +{ + int32_t ret = -1; + fd_lk_ctx_t *lk_ctx = NULL; + fd_lk_ctx_node_t *lk = NULL; + + GF_VALIDATE_OR_GOTO("fd-lk", fd, out); + GF_VALIDATE_OR_GOTO("fd-lk", flock, out); + + lk_ctx = fd_lk_ctx_ref(fd->lk_ctx); + lk = fd_lk_ctx_node_new(cmd, flock); + + gf_msg_debug("fd-lk", 0, + "new lock request: owner = %s, fl_type = %s" + ", fs_start = %" PRId64 ", fs_end = %" PRId64 + ", user_flock:" + " l_type = %s, l_start = %" PRId64 ", l_len = %" PRId64, + lkowner_utoa(&flock->l_owner), get_lk_type(lk->fl_type), + lk->fl_start, lk->fl_end, get_lk_type(lk->user_flock.l_type), + lk->user_flock.l_start, lk->user_flock.l_len); + + LOCK(&lk_ctx->lock); + { + _fd_lk_insert_and_merge(lk_ctx, lk); + print_lock_list(lk_ctx); + } + UNLOCK(&lk_ctx->lock); + + fd_lk_ctx_unref(lk_ctx); + + ret = 0; +out: + return ret; +} + +gf_boolean_t +fd_lk_ctx_empty(fd_lk_ctx_t *lk_ctx) +{ + gf_boolean_t verdict = _gf_true; + + if (!lk_ctx) + return _gf_true; + + LOCK(&lk_ctx->lock); + { + verdict = list_empty(&lk_ctx->lk_list); + } + UNLOCK(&lk_ctx->lock); + + return verdict; +} diff --git a/libglusterfs/src/fd.c b/libglusterfs/src/fd.c index 870c85e3f32..62606e91164 100644 --- a/libglusterfs/src/fd.c +++ b/libglusterfs/src/fd.c @@ -1,808 +1,1203 @@ /* - Copyright (c) 2007-2009 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 "fd.h" -#include "glusterfs.h" -#include "inode.h" -#include "dict.h" -#include "statedump.h" - - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - +#include "glusterfs/fd.h" +#include <errno.h> // for EINVAL, errno, ENOMEM +#include <inttypes.h> // for PRIu64 +#include <stdint.h> // for UINT32_MAX +#include <string.h> // for NULL, memcpy, memset, size_t +#include "glusterfs/statedump.h" static int -gf_fd_fdtable_expand (fdtable_t *fdtable, uint32_t nr); - +gf_fd_fdtable_expand(fdtable_t *fdtable, uint32_t nr); fd_t * -_fd_ref (fd_t *fd); - -/* - Allocate in memory chunks of power of 2 starting from 1024B - Assumes fdtable->lock is held -*/ -static inline int -gf_roundup_power_of_two (uint32_t nr) -{ - uint32_t result = 1; - - if (nr < 0) { - gf_log ("server-protocol/fd", - GF_LOG_ERROR, - "Negative number passed"); - return -1; - } - - while (result <= nr) - result *= 2; - - return result; -} - +__fd_ref(fd_t *fd); static int -gf_fd_chain_fd_entries (fdentry_t *entries, uint32_t startidx, - uint32_t endcount) +gf_fd_chain_fd_entries(fdentry_t *entries, uint32_t startidx, uint32_t endcount) { - uint32_t i = 0; + uint32_t i = 0; - if (!entries) - return -1; + if (!entries) { + gf_msg_callingfn("fd", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "!entries"); + return -1; + } - /* Chain only till the second to last entry because we want to - * ensure that the last entry has GF_FDTABLE_END. - */ - for (i = startidx; i < (endcount - 1); i++) - entries[i].next_free = i + 1; + /* Chain only till the second to last entry because we want to + * ensure that the last entry has GF_FDTABLE_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_FDTABLE_END; + /* i has already been incremented up to the last entry. */ + entries[i].next_free = GF_FDTABLE_END; - return 0; + return 0; } - static int -gf_fd_fdtable_expand (fdtable_t *fdtable, uint32_t nr) +gf_fd_fdtable_expand(fdtable_t *fdtable, uint32_t nr) { - fdentry_t *oldfds = NULL; - uint32_t oldmax_fds = -1; - int ret = -1; - - if (fdtable == NULL || nr < 0) { - gf_log ("fd", GF_LOG_ERROR, "invalid argument"); - ret = EINVAL; - goto out; - } - - nr /= (1024 / sizeof (fdentry_t)); - nr = gf_roundup_power_of_two (nr + 1); - nr *= (1024 / sizeof (fdentry_t)); + fdentry_t *oldfds = NULL; + uint32_t oldmax_fds = -1; + int ret = -1; + + if (fdtable == NULL || nr > UINT32_MAX) { + gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + ret = EINVAL; + goto out; + } + + nr /= (1024 / sizeof(fdentry_t)); + nr = gf_roundup_next_power_of_two(nr + 1); + nr *= (1024 / sizeof(fdentry_t)); + + oldfds = fdtable->fdentries; + oldmax_fds = fdtable->max_fds; + + fdtable->fdentries = GF_CALLOC(nr, sizeof(fdentry_t), + gf_common_mt_fdentry_t); + if (!fdtable->fdentries) { + ret = ENOMEM; + goto out; + } + fdtable->max_fds = nr; + + if (oldfds) { + uint32_t cpy = oldmax_fds * sizeof(fdentry_t); + memcpy(fdtable->fdentries, oldfds, cpy); + } + + gf_fd_chain_fd_entries(fdtable->fdentries, oldmax_fds, fdtable->max_fds); + + /* Now that expansion is done, we must update the fd list + * head pointer so that the fd allocation functions can continue + * using the expanded table. + */ + fdtable->first_free = oldmax_fds; + GF_FREE(oldfds); + ret = 0; +out: + return ret; +} - oldfds = fdtable->fdentries; - oldmax_fds = fdtable->max_fds; +fdtable_t * +gf_fd_fdtable_alloc(void) +{ + fdtable_t *fdtable = NULL; - fdtable->fdentries = GF_CALLOC (nr, sizeof (fdentry_t), - gf_common_mt_fdentry_t); - if (!fdtable->fdentries) { - ret = ENOMEM; - goto out; - } - fdtable->max_fds = nr; + fdtable = GF_CALLOC(1, sizeof(*fdtable), gf_common_mt_fdtable_t); + if (!fdtable) + return NULL; - if (oldfds) { - uint32_t cpy = oldmax_fds * sizeof (fdentry_t); - memcpy (fdtable->fdentries, oldfds, cpy); - } + pthread_rwlock_init(&fdtable->lock, NULL); - gf_fd_chain_fd_entries (fdtable->fdentries, oldmax_fds, - fdtable->max_fds); + pthread_rwlock_wrlock(&fdtable->lock); + { + gf_fd_fdtable_expand(fdtable, 0); + } + pthread_rwlock_unlock(&fdtable->lock); - /* Now that expansion is done, we must update the fd list - * head pointer so that the fd allocation functions can continue - * using the expanded table. - */ - fdtable->first_free = oldmax_fds; - GF_FREE (oldfds); - ret = 0; -out: - return ret; + return fdtable; } - -fdtable_t * -gf_fd_fdtable_alloc (void) +static fdentry_t * +__gf_fd_fdtable_get_all_fds(fdtable_t *fdtable, uint32_t *count) { - fdtable_t *fdtable = NULL; - - fdtable = GF_CALLOC (1, sizeof (*fdtable), gf_common_mt_fdtable_t); - if (!fdtable) - return NULL; + fdentry_t *fdentries = NULL; - pthread_mutex_init (&fdtable->lock, NULL); + if (count == NULL) { + gf_msg_callingfn("fd", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "!count"); + goto out; + } - pthread_mutex_lock (&fdtable->lock); - { - gf_fd_fdtable_expand (fdtable, 0); - } - pthread_mutex_unlock (&fdtable->lock); + fdentries = fdtable->fdentries; + fdtable->fdentries = GF_CALLOC(fdtable->max_fds, sizeof(fdentry_t), + gf_common_mt_fdentry_t); + gf_fd_chain_fd_entries(fdtable->fdentries, 0, fdtable->max_fds); + *count = fdtable->max_fds; - return fdtable; +out: + return fdentries; } - fdentry_t * -__gf_fd_fdtable_get_all_fds (fdtable_t *fdtable, uint32_t *count) +gf_fd_fdtable_get_all_fds(fdtable_t *fdtable, uint32_t *count) { - fdentry_t *fdentries = NULL; + fdentry_t *entries = NULL; - if (count == NULL) { - goto out; + if (fdtable) { + pthread_rwlock_wrlock(&fdtable->lock); + { + entries = __gf_fd_fdtable_get_all_fds(fdtable, count); } + pthread_rwlock_unlock(&fdtable->lock); + } - fdentries = fdtable->fdentries; - fdtable->fdentries = GF_CALLOC (fdtable->max_fds, sizeof (fdentry_t), - gf_common_mt_fdentry_t); - gf_fd_chain_fd_entries (fdtable->fdentries, 0, fdtable->max_fds); - *count = fdtable->max_fds; + return entries; +} + +static fdentry_t * +__gf_fd_fdtable_copy_all_fds(fdtable_t *fdtable, uint32_t *count) +{ + fdentry_t *fdentries = NULL; + int i = 0; + + if (count == NULL) { + gf_msg_callingfn("fd", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "!count"); + goto out; + } + + fdentries = GF_CALLOC(fdtable->max_fds, sizeof(fdentry_t), + gf_common_mt_fdentry_t); + if (fdentries == NULL) { + goto out; + } + + *count = fdtable->max_fds; + + for (i = 0; i < fdtable->max_fds; i++) { + if (fdtable->fdentries[i].fd != NULL) { + fdentries[i].fd = fd_ref(fdtable->fdentries[i].fd); + } + } out: - return fdentries; + return fdentries; } - fdentry_t * -gf_fd_fdtable_get_all_fds (fdtable_t *fdtable, uint32_t *count) +gf_fd_fdtable_copy_all_fds(fdtable_t *fdtable, uint32_t *count) { - fdentry_t *entries = NULL; + fdentry_t *entries = NULL; - if (fdtable) { - pthread_mutex_lock (&fdtable->lock); - { - entries = __gf_fd_fdtable_get_all_fds (fdtable, count); - } - pthread_mutex_unlock (&fdtable->lock); + if (fdtable) { + pthread_rwlock_rdlock(&fdtable->lock); + { + entries = __gf_fd_fdtable_copy_all_fds(fdtable, count); } + pthread_rwlock_unlock(&fdtable->lock); + } - return entries; + return entries; } - void -gf_fd_fdtable_destroy (fdtable_t *fdtable) -{ - struct list_head list = {0, }; - fd_t *fd = NULL; - fdentry_t *fdentries = NULL; - uint32_t fd_count = 0; - int32_t i = 0; - - INIT_LIST_HEAD (&list); - - if (!fdtable) - return; - - pthread_mutex_lock (&fdtable->lock); - { - fdentries = __gf_fd_fdtable_get_all_fds (fdtable, &fd_count); - GF_FREE (fdtable->fdentries); - } - pthread_mutex_unlock (&fdtable->lock); - - if (fdentries != NULL) { - for (i = 0; i < fd_count; i++) { - fd = fdentries[i].fd; - if (fd != NULL) { - fd_unref (fd); - } - } +gf_fd_fdtable_destroy(fdtable_t *fdtable) +{ + struct list_head list = { + 0, + }; + fd_t *fd = NULL; + fdentry_t *fdentries = NULL; + uint32_t fd_count = 0; + int32_t i = 0; + + INIT_LIST_HEAD(&list); + + if (!fdtable) { + gf_msg_callingfn("fd", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "!fdtable"); + return; + } + + pthread_rwlock_wrlock(&fdtable->lock); + { + fdentries = __gf_fd_fdtable_get_all_fds(fdtable, &fd_count); + GF_FREE(fdtable->fdentries); + } + pthread_rwlock_unlock(&fdtable->lock); + + if (fdentries != NULL) { + for (i = 0; i < fd_count; i++) { + fd = fdentries[i].fd; + if (fd != NULL) { + fd_unref(fd); + } + } - GF_FREE (fdentries); - pthread_mutex_destroy (&fdtable->lock); - GF_FREE (fdtable); - } + GF_FREE(fdentries); + pthread_rwlock_destroy(&fdtable->lock); + GF_FREE(fdtable); + } } - int -gf_fd_unused_get (fdtable_t *fdtable, fd_t *fdptr) -{ - int32_t fd = -1; - fdentry_t *fde = NULL; - int error; - int alloc_attempts = 0; - - if (fdtable == NULL || fdptr == NULL) - { - gf_log ("fd", GF_LOG_ERROR, "invalid argument"); - return EINVAL; - } - - pthread_mutex_lock (&fdtable->lock); - { -fd_alloc_try_again: - if (fdtable->first_free != GF_FDTABLE_END) { - fde = &fdtable->fdentries[fdtable->first_free]; - fd = fdtable->first_free; - fdtable->first_free = fde->next_free; - fde->next_free = GF_FDENTRY_ALLOCATED; - fde->fd = fdptr; - } else { - /* If this is true, there is something - * seriously wrong with our data structures. - */ - if (alloc_attempts >= 2) { - gf_log ("server-protocol.c", GF_LOG_ERROR, - "Multiple attempts to expand fd table" - " have failed."); - goto out; - } - error = gf_fd_fdtable_expand (fdtable, - fdtable->max_fds + 1); - if (error) { - gf_log ("server-protocol.c", - GF_LOG_ERROR, - "Cannot expand fdtable:%s", strerror (error)); - goto out; - } - ++alloc_attempts; - /* At this point, the table stands expanded - * with the first_free referring to the first - * free entry in the new set of fdentries that - * have just been allocated. That means, the - * above logic should just work. - */ - goto fd_alloc_try_again; - } - } +gf_fd_unused_get(fdtable_t *fdtable, fd_t *fdptr) +{ + int32_t fd = -1; + fdentry_t *fde = NULL; + int error; + int alloc_attempts = 0; + + if (fdtable == NULL || fdptr == NULL) { + gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + return EINVAL; + } + + pthread_rwlock_wrlock(&fdtable->lock); + { + fd_alloc_try_again: + if (fdtable->first_free != GF_FDTABLE_END) { + fde = &fdtable->fdentries[fdtable->first_free]; + fd = fdtable->first_free; + fdtable->first_free = fde->next_free; + fde->next_free = GF_FDENTRY_ALLOCATED; + fde->fd = fdptr; + } else { + /* If this is true, there is something + * seriously wrong with our data structures. + */ + if (alloc_attempts >= 2) { + gf_msg("fd", GF_LOG_ERROR, 0, LG_MSG_EXPAND_FD_TABLE_FAILED, + "multiple attempts to expand fd table" + " have failed."); + goto out; + } + error = gf_fd_fdtable_expand(fdtable, fdtable->max_fds + 1); + if (error) { + gf_msg("fd", GF_LOG_ERROR, error, LG_MSG_EXPAND_FD_TABLE_FAILED, + "Cannot expand fdtable"); + goto out; + } + ++alloc_attempts; + /* At this point, the table stands expanded + * with the first_free referring to the first + * free entry in the new set of fdentries that + * have just been allocated. That means, the + * above logic should just work. + */ + goto fd_alloc_try_again; + } + } out: - pthread_mutex_unlock (&fdtable->lock); - - return fd; -} - - -inline void -gf_fd_put (fdtable_t *fdtable, int32_t fd) -{ - fd_t *fdptr = NULL; - fdentry_t *fde = NULL; - - if (fdtable == NULL || fd < 0) { - gf_log ("fd", GF_LOG_ERROR, "invalid argument"); - return; - } - - if (!(fd < fdtable->max_fds)) { - gf_log ("fd", GF_LOG_ERROR, "invalid argument"); - return; - } - - pthread_mutex_lock (&fdtable->lock); - { - fde = &fdtable->fdentries[fd]; - /* If the entry is not allocated, put operation must return - * without doing anything. - * This has the potential of masking out any bugs in a user of - * fd that ends up calling gf_fd_put twice for the same fd or - * for an unallocated fd, but thats a price we have to pay for - * ensuring sanity of our fd-table. - */ - if (fde->next_free != GF_FDENTRY_ALLOCATED) - goto unlock_out; - fdptr = fde->fd; - fde->fd = NULL; - fde->next_free = fdtable->first_free; - fdtable->first_free = fd; - } -unlock_out: - pthread_mutex_unlock (&fdtable->lock); + pthread_rwlock_unlock(&fdtable->lock); - if (fdptr) { - fd_unref (fdptr); - } + return fd; } - -fd_t * -gf_fd_fdptr_get (fdtable_t *fdtable, int64_t fd) +void +gf_fd_put(fdtable_t *fdtable, int32_t fd) { - fd_t *fdptr = NULL; + fd_t *fdptr = NULL; + fdentry_t *fde = NULL; - if (fdtable == NULL || fd < 0) { - gf_log ("fd", GF_LOG_ERROR, "invalid argument"); - errno = EINVAL; - return NULL; - } + if (fd == GF_ANON_FD_NO) + return; - if (!(fd < fdtable->max_fds)) { - gf_log ("fd", GF_LOG_ERROR, "invalid argument"); - errno = EINVAL; - return NULL; - } + if (fdtable == NULL || fd < 0) { + gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + return; + } - pthread_mutex_lock (&fdtable->lock); - { - fdptr = fdtable->fdentries[fd].fd; - if (fdptr) { - fd_ref (fdptr); - } - } - pthread_mutex_unlock (&fdtable->lock); + if (!(fd < fdtable->max_fds)) { + gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + return; + } + + pthread_rwlock_wrlock(&fdtable->lock); + { + fde = &fdtable->fdentries[fd]; + /* If the entry is not allocated, put operation must return + * without doing anything. + * This has the potential of masking out any bugs in a user of + * fd that ends up calling gf_fd_put twice for the same fd or + * for an unallocated fd, but it is a price we have to pay for + * ensuring sanity of our fd-table. + */ + if (fde->next_free != GF_FDENTRY_ALLOCATED) + goto unlock_out; + fdptr = fde->fd; + fde->fd = NULL; + fde->next_free = fdtable->first_free; + fdtable->first_free = fd; + } +unlock_out: + pthread_rwlock_unlock(&fdtable->lock); - return fdptr; + if (fdptr) { + fd_unref(fdptr); + } } - -fd_t * -_fd_ref (fd_t *fd) +void +gf_fdptr_put(fdtable_t *fdtable, fd_t *fd) { - ++fd->refcount; + fdentry_t *fde = NULL; + int32_t i = 0; - return fd; -} + if ((fdtable == NULL) || (fd == NULL)) { + gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + return; + } + + pthread_rwlock_wrlock(&fdtable->lock); + { + for (i = 0; i < fdtable->max_fds; i++) { + if (fdtable->fdentries[i].fd == fd) { + fde = &fdtable->fdentries[i]; + break; + } + } + + if (fde == NULL) { + gf_msg_callingfn("fd", GF_LOG_WARNING, 0, + LG_MSG_FD_NOT_FOUND_IN_FDTABLE, + "fd (%p) is not present in fdtable", fd); + goto unlock_out; + } + /* If the entry is not allocated, put operation must return + * without doing anything. + * This has the potential of masking out any bugs in a user of + * fd that ends up calling gf_fd_put twice for the same fd or + * for an unallocated fd, but it is a price we have to pay for + * ensuring sanity of our fd-table. + */ + if (fde->next_free != GF_FDENTRY_ALLOCATED) + goto unlock_out; + fde->fd = NULL; + fde->next_free = fdtable->first_free; + fdtable->first_free = i; + } +unlock_out: + pthread_rwlock_unlock(&fdtable->lock); + + if ((fd != NULL) && (fde != NULL)) { + fd_unref(fd); + } +} fd_t * -fd_ref (fd_t *fd) +gf_fd_fdptr_get(fdtable_t *fdtable, int64_t fd) { - fd_t *refed_fd = NULL; + fd_t *fdptr = NULL; + + if (fdtable == NULL || fd < 0) { + gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + errno = EINVAL; + return NULL; + } + + if (!(fd < fdtable->max_fds)) { + gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + errno = EINVAL; + return NULL; + } + + pthread_rwlock_rdlock(&fdtable->lock); + { + fdptr = fdtable->fdentries[fd].fd; + if (fdptr) { + fd_ref(fdptr); + } + } + pthread_rwlock_unlock(&fdtable->lock); - if (!fd) { - gf_log ("fd", GF_LOG_ERROR, "@fd=%p", fd); - return NULL; - } + return fdptr; +} - LOCK (&fd->inode->lock); - refed_fd = _fd_ref (fd); - UNLOCK (&fd->inode->lock); +fd_t * +__fd_ref(fd_t *fd) +{ + GF_ATOMIC_INC(fd->refcount); - return refed_fd; + return fd; } - fd_t * -_fd_unref (fd_t *fd) +fd_ref(fd_t *fd) { - assert (fd->refcount); - - --fd->refcount; + if (!fd) { + gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "null fd"); + return NULL; + } - if (fd->refcount == 0) { - list_del_init (&fd->inode_list); - } + GF_ATOMIC_INC(fd->refcount); - return fd; + return fd; } - static void -fd_destroy (fd_t *fd) +fd_destroy(fd_t *fd, gf_boolean_t bound) { - xlator_t *xl = NULL; - int i = 0; - xlator_t *old_THIS = NULL; - struct mem_pool *tmp_pool = NULL; - - if (fd == NULL){ - gf_log ("xlator", GF_LOG_ERROR, "invalid arugument"); - goto out; + xlator_t *xl = NULL; + int i = 0; + xlator_t *old_THIS = NULL; + + if (fd == NULL) { + gf_msg_callingfn("xlator", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + goto out; + } + + if (fd->inode == NULL) { + gf_msg_callingfn("xlator", GF_LOG_ERROR, 0, LG_MSG_FD_INODE_NULL, + "fd->inode is NULL"); + goto out; + } + if (!fd->_ctx) + goto out; + + if (IA_ISDIR(fd->inode->ia_type)) { + for (i = 0; i < fd->xl_count; i++) { + if (fd->_ctx[i].key) { + xl = fd->_ctx[i].xl_key; + old_THIS = THIS; + THIS = xl; + if (!xl->call_cleanup && xl->cbks->releasedir) + xl->cbks->releasedir(xl, fd); + THIS = old_THIS; + } } - - if (fd->inode == NULL){ - gf_log ("xlator", GF_LOG_ERROR, "fd->inode is NULL"); - goto out; - } - if (!fd->_ctx) - goto out; - - tmp_pool = fd->inode->table->fd_mem_pool; - - if (IA_ISDIR (fd->inode->ia_type)) { - for (i = 0; i < fd->xl_count; i++) { - if (fd->_ctx[i].key) { - xl = fd->_ctx[i].xl_key; - old_THIS = THIS; - THIS = xl; - if (xl->cbks->releasedir) - xl->cbks->releasedir (xl, fd); - THIS = old_THIS; - } - } - } else { - for (i = 0; i < fd->xl_count; i++) { - if (fd->_ctx[i].key) { - xl = fd->_ctx[i].xl_key; - old_THIS = THIS; - THIS = xl; - if (xl->cbks->release) - xl->cbks->release (xl, fd); - THIS = old_THIS; - } - } + } else { + for (i = 0; i < fd->xl_count; i++) { + if (fd->_ctx[i].key) { + xl = fd->_ctx[i].xl_key; + old_THIS = THIS; + THIS = xl; + if (!xl->call_cleanup && xl->cbks->release) + xl->cbks->release(xl, fd); + THIS = old_THIS; + } } + } - LOCK_DESTROY (&fd->lock); + LOCK_DESTROY(&fd->lock); - GF_FREE (fd->_ctx); - inode_unref (fd->inode); - fd->inode = (inode_t *)0xaaaaaaaa; - mem_put (tmp_pool,fd); - tmp_pool = NULL; + GF_FREE(fd->_ctx); + if (bound) { + /*Decrease the count only after close happens on file*/ + LOCK(&fd->inode->lock); + { + fd->inode->fd_count--; + } + UNLOCK(&fd->inode->lock); + } + inode_unref(fd->inode); + fd->inode = NULL; + fd_lk_ctx_unref(fd->lk_ctx); + mem_put(fd); out: - return; + return; } - void -fd_unref (fd_t *fd) +fd_close(fd_t *fd) { - int32_t refcount = 0; + xlator_t *xl, *old_THIS; - if (!fd) { - gf_log ("fd.c", GF_LOG_ERROR, "fd is NULL"); - return; - } + old_THIS = THIS; - LOCK (&fd->inode->lock); - { - _fd_unref (fd); - refcount = fd->refcount; + for (xl = fd->inode->table->xl->graph->first; xl != NULL; xl = xl->next) { + if (!xl->call_cleanup) { + THIS = xl; + + if (IA_ISDIR(fd->inode->ia_type)) { + if (xl->cbks->fdclosedir != NULL) { + xl->cbks->fdclosedir(xl, fd); + } + } else { + if (xl->cbks->fdclose != NULL) { + xl->cbks->fdclose(xl, fd); + } + } } - UNLOCK (&fd->inode->lock); + } + THIS = old_THIS; +} + +void +fd_unref(fd_t *fd) +{ + int32_t refcount = 0; + gf_boolean_t bound = _gf_false; + + if (!fd) { + gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "fd is NULL"); + return; + } + + LOCK(&fd->inode->lock); + { + refcount = GF_ATOMIC_DEC(fd->refcount); if (refcount == 0) { - fd_destroy (fd); + if (!list_empty(&fd->inode_list)) { + list_del_init(&fd->inode_list); + fd->inode->active_fd_count--; + bound = _gf_true; + } } + } + UNLOCK(&fd->inode->lock); + + if (refcount == 0) { + fd_destroy(fd, bound); + } - return ; + return; } +static fd_t * +__fd_bind(fd_t *fd) +{ + list_del_init(&fd->inode_list); + list_add(&fd->inode_list, &fd->inode->fd_list); + fd->inode->fd_count++; + fd->inode->active_fd_count++; + + return fd; +} fd_t * -fd_bind (fd_t *fd) +fd_bind(fd_t *fd) { - inode_t *inode = NULL; + if (!fd || !fd->inode) { + gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "!fd || !fd->inode"); + return NULL; + } + + LOCK(&fd->inode->lock); + { + fd = __fd_bind(fd); + } + UNLOCK(&fd->inode->lock); + + return fd; +} - if (!fd) { - gf_log ("fd.c", GF_LOG_ERROR, "fd is NULL"); - return NULL; - } - inode = fd->inode; +static fd_t * +fd_allocate(inode_t *inode, uint64_t pid) +{ + fd_t *fd; + + if (inode == NULL) { + gf_msg_callingfn("fd", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + return NULL; + } + + fd = mem_get0(inode->table->fd_mem_pool); + if (fd == NULL) { + return NULL; + } + + fd->xl_count = inode->table->xl->graph->xl_count + 1; + + fd->_ctx = GF_CALLOC(1, (sizeof(struct _fd_ctx) * fd->xl_count), + gf_common_mt_fd_ctx); + if (fd->_ctx == NULL) { + goto failed; + } + + fd->lk_ctx = fd_lk_ctx_create(); + if (fd->lk_ctx != NULL) { + /* We need to take a reference from the inode, but we cannot do it + * here because this function can be called with the inode lock taken + * and inode_ref() takes the inode's table lock. This is the reverse + * of the logical lock acquisition order and can cause a deadlock. So + * we simply assign the inode here and we delefate the inode reference + * responsibility to the caller (when this function succeeds and the + * inode lock is released). This is safe because the caller must hold + * a reference of the inode to use it, so it's guaranteed that the + * number of references won't reach 0 before the caller finishes. + * + * TODO: minimize use of locks in favor of atomic operations to avoid + * these dependencies. */ + fd->inode = inode; + fd->pid = pid; + INIT_LIST_HEAD(&fd->inode_list); + LOCK_INIT(&fd->lock); + GF_ATOMIC_INIT(fd->refcount, 1); + return fd; + } - LOCK (&inode->lock); - { - list_add (&fd->inode_list, &inode->fd_list); - } - UNLOCK (&inode->lock); + GF_FREE(fd->_ctx); - return fd; +failed: + mem_put(fd); + + return NULL; } fd_t * -fd_create (inode_t *inode, pid_t pid) +fd_create_uint64(inode_t *inode, uint64_t pid) { - fd_t *fd = NULL; + fd_t *fd; - if (inode == NULL) { - gf_log ("fd", GF_LOG_ERROR, "invalid argument"); - return NULL; - } + fd = fd_allocate(inode, pid); + if (fd != NULL) { + /* fd_allocate() doesn't get a reference from the inode. We need to + * take it here in case of success. */ + inode_ref(inode); + } - fd = mem_get0 (inode->table->fd_mem_pool); - if (!fd) - goto out; + return fd; +} - fd->xl_count = inode->table->xl->graph->xl_count + 1; +fd_t * +fd_create(inode_t *inode, pid_t pid) +{ + return fd_create_uint64(inode, (uint64_t)pid); +} - fd->_ctx = GF_CALLOC (1, (sizeof (struct _fd_ctx) * fd->xl_count), - gf_common_mt_fd_ctx); - if (!fd->_ctx) { - GF_FREE (fd); - fd = NULL; - goto out; +static fd_t * +__fd_lookup(inode_t *inode, uint64_t pid) +{ + fd_t *iter_fd = NULL; + fd_t *fd = NULL; + + if (list_empty(&inode->fd_list)) + return NULL; + + list_for_each_entry(iter_fd, &inode->fd_list, inode_list) + { + if (iter_fd->anonymous) + /* If someone was interested in getting an + anonymous fd (or was OK getting an anonymous fd), + they can as well call fd_anonymous() directly */ + continue; + + if (!pid || iter_fd->pid == pid) { + fd = __fd_ref(iter_fd); + break; } + } - fd->inode = inode_ref (inode); - fd->pid = pid; - INIT_LIST_HEAD (&fd->inode_list); + return fd; +} - LOCK_INIT (&fd->lock); +fd_t * +fd_lookup(inode_t *inode, pid_t pid) +{ + fd_t *fd = NULL; - LOCK (&inode->lock); - { - fd = _fd_ref (fd); - } - UNLOCK (&inode->lock); -out: - return fd; + if (!inode) { + gf_msg_callingfn("fd", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "!inode"); + return NULL; + } + + LOCK(&inode->lock); + { + fd = __fd_lookup(inode, (uint64_t)pid); + } + UNLOCK(&inode->lock); + + return fd; } +fd_t * +fd_lookup_uint64(inode_t *inode, uint64_t pid) +{ + fd_t *fd = NULL; + + if (!inode) { + gf_msg_callingfn("fd", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "!inode"); + return NULL; + } + + LOCK(&inode->lock); + { + fd = __fd_lookup(inode, pid); + } + UNLOCK(&inode->lock); + + return fd; +} + +static fd_t * +__fd_lookup_anonymous(inode_t *inode, int32_t flags) +{ + fd_t *iter_fd = NULL; + fd_t *fd = NULL; + + if (list_empty(&inode->fd_list)) + return NULL; + + list_for_each_entry(iter_fd, &inode->fd_list, inode_list) + { + if ((iter_fd->anonymous) && (flags == iter_fd->flags)) { + fd = __fd_ref(iter_fd); + break; + } + } + + return fd; +} fd_t * -fd_lookup (inode_t *inode, pid_t pid) +fd_anonymous_with_flags(inode_t *inode, int32_t flags) { - fd_t *fd = NULL; - fd_t *iter_fd = NULL; + fd_t *fd = NULL; + bool ref = false; - if (!inode) - return NULL; + LOCK(&inode->lock); - LOCK (&inode->lock); - { - if (list_empty (&inode->fd_list)) { - fd = NULL; - } else { - list_for_each_entry (iter_fd, &inode->fd_list, inode_list) { - if (pid) { - if (iter_fd->pid == pid) { - fd = _fd_ref (iter_fd); - break; - } - } else { - fd = _fd_ref (iter_fd); - break; - } - } - } + fd = __fd_lookup_anonymous(inode, flags); + + /* if (fd); then we already have increased the refcount in + __fd_lookup_anonymous(), so no need of one more fd_ref(). + if (!fd); then both create and bind won't bump up the ref + count, so we have to call fd_ref() after bind. */ + if (fd == NULL) { + fd = fd_allocate(inode, 0); + if (fd != NULL) { + fd->anonymous = _gf_true; + fd->flags = GF_ANON_FD_FLAGS | (flags & O_DIRECT); + + __fd_bind(fd); + + ref = true; } - UNLOCK (&inode->lock); + } - return fd; + UNLOCK(&inode->lock); + + if (ref) { + /* fd_allocate() doesn't get a reference from the inode. We need to + * take it here in case of success. */ + inode_ref(inode); + } + + return fd; } +fd_t * +fd_anonymous(inode_t *inode) +{ + return fd_anonymous_with_flags(inode, 0); +} + +fd_t * +fd_lookup_anonymous(inode_t *inode, int32_t flags) +{ + fd_t *fd = NULL; + + if (!inode) { + gf_msg_callingfn("fd", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "!inode"); + return NULL; + } + + LOCK(&inode->lock); + { + fd = __fd_lookup_anonymous(inode, flags); + } + UNLOCK(&inode->lock); + return fd; +} + +gf_boolean_t +fd_is_anonymous(fd_t *fd) +{ + return (fd && fd->anonymous); +} uint8_t -fd_list_empty (inode_t *inode) +fd_list_empty(inode_t *inode) { - uint8_t empty = 0; + uint8_t empty = 0; - LOCK (&inode->lock); - { - empty = list_empty (&inode->fd_list); - } - UNLOCK (&inode->lock); + LOCK(&inode->lock); + { + empty = list_empty(&inode->fd_list); + } + UNLOCK(&inode->lock); - return empty; + return empty; } - int -__fd_ctx_set (fd_t *fd, xlator_t *xlator, uint64_t value) +__fd_ctx_set(fd_t *fd, xlator_t *xlator, uint64_t value) { - int index = 0; - int ret = 0; - int set_idx = -1; + int index = 0, new_xl_count = 0; + int ret = 0; + int set_idx = -1; + void *begin = NULL; + size_t diff = 0; + struct _fd_ctx *tmp = NULL; + + if (!fd || !xlator) + return -1; + + for (index = 0; index < fd->xl_count; index++) { + if (!fd->_ctx[index].key) { + if (set_idx == -1) + set_idx = index; + /* don't break, to check if key already exists + further on */ + } + if (fd->_ctx[index].xl_key == xlator) { + set_idx = index; + break; + } + } - if (!fd || !xlator) - return -1; + if (set_idx == -1) { + set_idx = fd->xl_count; - for (index = 0; index < fd->xl_count; index++) { - if (!fd->_ctx[index].key) { - if (set_idx == -1) - set_idx = index; - /* dont break, to check if key already exists - further on */ - } - if (fd->_ctx[index].xl_key == xlator) { - set_idx = index; - break; - } - } + new_xl_count = fd->xl_count + xlator->graph->xl_count; - if (set_idx == -1) { - ret = -1; - goto out; + tmp = GF_REALLOC(fd->_ctx, (sizeof(struct _fd_ctx) * new_xl_count)); + if (tmp == NULL) { + ret = -1; + goto out; } - fd->_ctx[set_idx].xl_key = xlator; - fd->_ctx[set_idx].value1 = value; + fd->_ctx = tmp; + + begin = fd->_ctx; + begin += (fd->xl_count * sizeof(struct _fd_ctx)); + + diff = (new_xl_count - fd->xl_count) * sizeof(struct _fd_ctx); + + memset(begin, 0, diff); + + fd->xl_count = new_xl_count; + } + + fd->_ctx[set_idx].xl_key = xlator; + fd->_ctx[set_idx].value1 = value; out: - return ret; + return ret; } - int -fd_ctx_set (fd_t *fd, xlator_t *xlator, uint64_t value) +fd_ctx_set(fd_t *fd, xlator_t *xlator, uint64_t value) { - int ret = 0; + int ret = 0; - if (!fd || !xlator) - return -1; + if (!fd || !xlator) { + gf_msg_callingfn("fd", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "%p %p", fd, xlator); + return -1; + } - LOCK (&fd->lock); - { - ret = __fd_ctx_set (fd, xlator, value); - } - UNLOCK (&fd->lock); + LOCK(&fd->lock); + { + ret = __fd_ctx_set(fd, xlator, value); + } + UNLOCK(&fd->lock); - return ret; + return ret; } - int -__fd_ctx_get (fd_t *fd, xlator_t *xlator, uint64_t *value) +__fd_ctx_get(fd_t *fd, xlator_t *xlator, uint64_t *value) { - int index = 0; - int ret = 0; + int index = 0; + int ret = 0; - if (!fd || !xlator) - return -1; + if (!fd || !xlator) + return -1; - for (index = 0; index < fd->xl_count; index++) { - if (fd->_ctx[index].xl_key == xlator) - break; - } + for (index = 0; index < fd->xl_count; index++) { + if (fd->_ctx[index].xl_key == xlator) + break; + } - if (index == fd->xl_count) { - ret = -1; - goto out; - } + if (index == fd->xl_count) { + ret = -1; + goto out; + } - if (value) - *value = fd->_ctx[index].value1; + if (value) + *value = fd->_ctx[index].value1; out: - return ret; + return ret; } - int -fd_ctx_get (fd_t *fd, xlator_t *xlator, uint64_t *value) +fd_ctx_get(fd_t *fd, xlator_t *xlator, uint64_t *value) { - int ret = 0; + int ret = 0; - if (!fd || !xlator) - return -1; + if (!fd || !xlator) + return -1; - LOCK (&fd->lock); - { - ret = __fd_ctx_get (fd, xlator, value); - } - UNLOCK (&fd->lock); + LOCK(&fd->lock); + { + ret = __fd_ctx_get(fd, xlator, value); + } + UNLOCK(&fd->lock); - return ret; + return ret; } - int -__fd_ctx_del (fd_t *fd, xlator_t *xlator, uint64_t *value) +__fd_ctx_del(fd_t *fd, xlator_t *xlator, uint64_t *value) { - int index = 0; - int ret = 0; + int index = 0; + int ret = 0; - if (!fd || !xlator) - return -1; + if (!fd || !xlator) + return -1; - for (index = 0; index < fd->xl_count; index++) { - if (fd->_ctx[index].xl_key == xlator) - break; - } + for (index = 0; index < fd->xl_count; index++) { + if (fd->_ctx[index].xl_key == xlator) + break; + } - if (index == fd->xl_count) { - ret = -1; - goto out; - } + if (index == fd->xl_count) { + ret = -1; + goto out; + } - if (value) - *value = fd->_ctx[index].value1; + if (value) + *value = fd->_ctx[index].value1; - fd->_ctx[index].key = 0; - fd->_ctx[index].value1 = 0; + fd->_ctx[index].key = 0; + fd->_ctx[index].value1 = 0; out: - return ret; + return ret; } - int -fd_ctx_del (fd_t *fd, xlator_t *xlator, uint64_t *value) +fd_ctx_del(fd_t *fd, xlator_t *xlator, uint64_t *value) { - int ret = 0; + int ret = 0; - if (!fd || !xlator) - return -1; + if (!fd || !xlator) + return -1; - LOCK (&fd->lock); - { - ret = __fd_ctx_del (fd, xlator, value); - } - UNLOCK (&fd->lock); + LOCK(&fd->lock); + { + ret = __fd_ctx_del(fd, xlator, value); + } + UNLOCK(&fd->lock); - return ret; + return ret; } - void -fd_dump (fd_t *fd, char *prefix) -{ - char key[GF_DUMP_MAX_BUF_LEN]; - - if (!fd) - return; - - memset(key, 0, sizeof(key)); - gf_proc_dump_build_key(key, prefix, "pid"); - gf_proc_dump_write(key, "%d", fd->pid); - gf_proc_dump_build_key(key, prefix, "refcount"); - gf_proc_dump_write(key, "%d", fd->refcount); - gf_proc_dump_build_key(key, prefix, "flags"); - gf_proc_dump_write(key, "%d", fd->flags); - if (fd->inode) { - gf_proc_dump_build_key(key, prefix, "inode"); - gf_proc_dump_write(key, "%ld", fd->inode->ino); - } +fd_dump(fd_t *fd, char *prefix) +{ + char key[GF_DUMP_MAX_BUF_LEN]; + + if (!fd) + return; + + gf_proc_dump_write("pid", "%" PRIu64, fd->pid); + gf_proc_dump_write("refcount", "%" GF_PRI_ATOMIC, + GF_ATOMIC_GET(fd->refcount)); + gf_proc_dump_write("flags", "%d", fd->flags); + + if (fd->inode) { + gf_proc_dump_build_key(key, "inode", NULL); + gf_proc_dump_add_section("%s", key); + inode_dump(fd->inode, key); + } } +void +fdentry_dump(fdentry_t *fdentry, char *prefix) +{ + if (!fdentry) + return; + + if (GF_FDENTRY_ALLOCATED != fdentry->next_free) + return; + + if (fdentry->fd) + fd_dump(fdentry->fd, prefix); +} void -fdentry_dump (fdentry_t *fdentry, char *prefix) +fdtable_dump(fdtable_t *fdtable, char *prefix) { - if (!fdentry) - return; + char key[GF_DUMP_MAX_BUF_LEN]; + int i = 0; + int ret = -1; + + if (!fdtable) + return; + + ret = pthread_rwlock_tryrdlock(&fdtable->lock); + if (ret) + goto out; + + gf_proc_dump_build_key(key, prefix, "refcount"); + gf_proc_dump_write(key, "%d", fdtable->refcount); + gf_proc_dump_build_key(key, prefix, "maxfds"); + gf_proc_dump_write(key, "%d", fdtable->max_fds); + gf_proc_dump_build_key(key, prefix, "first_free"); + gf_proc_dump_write(key, "%d", fdtable->first_free); + + for (i = 0; i < fdtable->max_fds; i++) { + if (GF_FDENTRY_ALLOCATED == fdtable->fdentries[i].next_free) { + gf_proc_dump_build_key(key, prefix, "fdentry[%d]", i); + gf_proc_dump_add_section("%s", key); + fdentry_dump(&fdtable->fdentries[i], key); + } + } - if (GF_FDENTRY_ALLOCATED != fdentry->next_free) - return; + pthread_rwlock_unlock(&fdtable->lock); - if (fdentry->fd) - fd_dump(fdentry->fd, prefix); +out: + if (ret != 0) + gf_proc_dump_write("Unable to dump the fdtable", + "(Lock acquistion failed) %p", fdtable); + return; } +void +fd_ctx_dump(fd_t *fd, char *prefix) +{ + struct _fd_ctx *fd_ctx = NULL; + xlator_t *xl = NULL; + int i = 0; + + if ((fd == NULL) || (fd->_ctx == NULL)) { + goto out; + } + + LOCK(&fd->lock); + { + if (fd->_ctx != NULL) { + fd_ctx = GF_CALLOC(fd->xl_count, sizeof(*fd_ctx), + gf_common_mt_fd_ctx); + if (fd_ctx == NULL) { + goto unlock; + } + + for (i = 0; i < fd->xl_count; i++) { + fd_ctx[i] = fd->_ctx[i]; + } + } + } +unlock: + UNLOCK(&fd->lock); + + if (fd_ctx == NULL) { + goto out; + } + + for (i = 0; i < fd->xl_count; i++) { + if (fd_ctx[i].xl_key) { + xl = (xlator_t *)(long)fd_ctx[i].xl_key; + if (xl->dumpops && xl->dumpops->fdctx) + xl->dumpops->fdctx(xl, fd); + } + } + +out: + GF_FREE(fd_ctx); + + return; +} void -fdtable_dump (fdtable_t *fdtable, char *prefix) +fdentry_dump_to_dict(fdentry_t *fdentry, char *prefix, dict_t *dict, + int *openfds) { - char key[GF_DUMP_MAX_BUF_LEN]; - int i = 0; - int ret = -1; + char key[GF_DUMP_MAX_BUF_LEN] = { + 0, + }; + int ret = -1; - if (!fdtable) - return; + if (!fdentry) + return; + if (!dict) + return; - ret = pthread_mutex_trylock (&fdtable->lock); + if (GF_FDENTRY_ALLOCATED != fdentry->next_free) + return; - if (ret) { - gf_log ("fd", GF_LOG_WARNING, "Unable to acquire lock"); - return; - } + if (fdentry->fd) { + snprintf(key, sizeof(key), "%s.pid", prefix); + ret = dict_set_uint64(dict, key, fdentry->fd->pid); + if (ret) + return; + + snprintf(key, sizeof(key), "%s.refcount", prefix); + ret = dict_set_int32(dict, key, GF_ATOMIC_GET(fdentry->fd->refcount)); + if (ret) + return; + + snprintf(key, sizeof(key), "%s.flags", prefix); + ret = dict_set_int32(dict, key, fdentry->fd->flags); + if (ret) + return; + + (*openfds)++; + } + return; +} - memset(key, 0, sizeof(key)); - gf_proc_dump_build_key(key, prefix, "refcount"); - gf_proc_dump_write(key, "%d", fdtable->refcount); - gf_proc_dump_build_key(key, prefix, "maxfds"); - gf_proc_dump_write(key, "%d", fdtable->max_fds); - gf_proc_dump_build_key(key, prefix, "first_free"); - gf_proc_dump_write(key, "%d", fdtable->first_free); - - for ( i = 0 ; i < fdtable->max_fds; i++) { - if (GF_FDENTRY_ALLOCATED == - fdtable->fdentries[i].next_free) { - gf_proc_dump_build_key(key, prefix, "fdentry[%d]", i); - gf_proc_dump_add_section(key); - fdentry_dump(&fdtable->fdentries[i], key); - } +void +fdtable_dump_to_dict(fdtable_t *fdtable, char *prefix, dict_t *dict) +{ + char key[GF_DUMP_MAX_BUF_LEN] = { + 0, + }; + int i = 0; + int openfds = 0; + int ret = -1; + + if (!fdtable) + return; + if (!dict) + return; + + ret = pthread_rwlock_tryrdlock(&fdtable->lock); + if (ret) + return; + + snprintf(key, sizeof(key), "%s.fdtable.refcount", prefix); + ret = dict_set_int32(dict, key, fdtable->refcount); + if (ret) + goto out; + + snprintf(key, sizeof(key), "%s.fdtable.maxfds", prefix); + ret = dict_set_uint32(dict, key, fdtable->max_fds); + if (ret) + goto out; + + snprintf(key, sizeof(key), "%s.fdtable.firstfree", prefix); + ret = dict_set_int32(dict, key, fdtable->first_free); + if (ret) + goto out; + + for (i = 0; i < fdtable->max_fds; i++) { + if (GF_FDENTRY_ALLOCATED == fdtable->fdentries[i].next_free) { + snprintf(key, sizeof(key), "%s.fdtable.fdentry%d", prefix, i); + fdentry_dump_to_dict(&fdtable->fdentries[i], key, dict, &openfds); } + } + + snprintf(key, sizeof(key), "%s.fdtable.openfds", prefix); + ret = dict_set_int32(dict, key, openfds); + if (ret) + goto out; - pthread_mutex_unlock(&fdtable->lock); +out: + pthread_rwlock_unlock(&fdtable->lock); + return; } diff --git a/libglusterfs/src/fd.h b/libglusterfs/src/fd.h deleted file mode 100644 index e01ef753e28..00000000000 --- a/libglusterfs/src/fd.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - Copyright (c) 2007-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _FD_H -#define _FD_H - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include "list.h" -#include <sys/types.h> -#include <unistd.h> -#include "glusterfs.h" -#include "locking.h" - -struct _inode; -struct _dict; - -struct _fd_ctx { - union { - uint64_t key; - void *xl_key; - }; - union { - uint64_t value1; - void *ptr1; - }; -}; - -/* If this structure changes, please have mercy on the booster maintainer - * and update the fd_t struct in booster/src/booster-fd.h. - * See the comment there to know why. - */ -struct _fd { - pid_t pid; - int32_t flags; - int32_t refcount; - uint64_t flush_unique; - struct list_head inode_list; - struct _inode *inode; - gf_lock_t lock; /* used ONLY for manipulating - 'struct _fd_ctx' array (_ctx).*/ - struct _fd_ctx *_ctx; - int xl_count; /* Number of xl referred in this fd */ -}; -typedef struct _fd fd_t; - - -struct fd_table_entry { - fd_t *fd; - int next_free; -}; -typedef struct fd_table_entry fdentry_t; - - -struct _fdtable { - int refcount; - uint32_t max_fds; - pthread_mutex_t lock; - fdentry_t *fdentries; - int first_free; -}; -typedef struct _fdtable fdtable_t; - - -/* Signifies no more entries in the fd table. */ -#define GF_FDTABLE_END -1 - -/* This is used to invalidated - * the next_free value in an fdentry that has been allocated - */ -#define GF_FDENTRY_ALLOCATED -2 - -#include "logging.h" -#include "xlator.h" - - -inline void -gf_fd_put (fdtable_t *fdtable, int32_t fd); - - -fd_t * -gf_fd_fdptr_get (fdtable_t *fdtable, int64_t fd); - - -fdtable_t * -gf_fd_fdtable_alloc (void); - - -int -gf_fd_unused_get (fdtable_t *fdtable, fd_t *fdptr); - - -fdentry_t * -gf_fd_fdtable_get_all_fds (fdtable_t *fdtable, uint32_t *count); - - -void -gf_fd_fdtable_destroy (fdtable_t *fdtable); - - -fd_t * -fd_ref (fd_t *fd); - - -void -fd_unref (fd_t *fd); - - -fd_t * -fd_create (struct _inode *inode, pid_t pid); - - -fd_t * -fd_lookup (struct _inode *inode, pid_t pid); - - -uint8_t -fd_list_empty (struct _inode *inode); - - -fd_t * -fd_bind (fd_t *fd); - - -int -fd_ctx_set (fd_t *fd, xlator_t *xlator, uint64_t value); - - -int -fd_ctx_get (fd_t *fd, xlator_t *xlator, uint64_t *value); - - -int -fd_ctx_del (fd_t *fd, xlator_t *xlator, uint64_t *value); - - -int -__fd_ctx_set (fd_t *fd, xlator_t *xlator, uint64_t value); - - -int -__fd_ctx_get (fd_t *fd, xlator_t *xlator, uint64_t *value); - - -int -__fd_ctx_del (fd_t *fd, xlator_t *xlator, uint64_t *value); - - -#endif /* _FD_H */ diff --git a/libglusterfs/src/gen-defaults.py b/libglusterfs/src/gen-defaults.py new file mode 100755 index 00000000000..e31d3a9fe8a --- /dev/null +++ b/libglusterfs/src/gen-defaults.py @@ -0,0 +1,81 @@ +#!/usr/bin/python3 + +from __future__ import print_function +import sys +from generator import ops, fop_subs, cbk_subs, generate + +FAILURE_CBK_TEMPLATE = """ +int32_t +default_@NAME@_failure_cbk (call_frame_t *frame, int32_t op_errno) +{ + STACK_UNWIND_STRICT (@NAME@, frame, -1, op_errno, @ERROR_ARGS@); + return 0; +} +""" + +CBK_RESUME_TEMPLATE = """ +int32_t +default_@NAME@_cbk_resume (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, @LONG_ARGS@) +{ + STACK_UNWIND_STRICT (@NAME@, frame, op_ret, op_errno, + @SHORT_ARGS@); + return 0; +} +""" + +CBK_TEMPLATE = """ +int32_t +default_@NAME@_cbk (call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, @LONG_ARGS@) +{ + STACK_UNWIND_STRICT (@NAME@, frame, op_ret, op_errno, + @SHORT_ARGS@); + return 0; +} +""" + +RESUME_TEMPLATE = """ +int32_t +default_@NAME@_resume (call_frame_t *frame, xlator_t *this, @LONG_ARGS@) +{ + STACK_WIND (frame, default_@NAME@_cbk, + FIRST_CHILD(this), FIRST_CHILD(this)->fops->@NAME@, + @SHORT_ARGS@); + return 0; +} +""" + +FOP_TEMPLATE = """ +int32_t +default_@NAME@ ( + call_frame_t *frame, + xlator_t *this, + @LONG_ARGS@) +{ + STACK_WIND_TAIL (frame, + FIRST_CHILD(this), FIRST_CHILD(this)->fops->@NAME@, + @SHORT_ARGS@); + return 0; +} +""" + +def gen_defaults (): + for name in list(ops.keys()): + print(generate(FAILURE_CBK_TEMPLATE, name, cbk_subs)) + for name in list(ops.keys()): + print(generate(CBK_RESUME_TEMPLATE, name, cbk_subs)) + for name in list(ops.keys()): + print(generate(CBK_TEMPLATE, name, cbk_subs)) + for name in list(ops.keys()): + print(generate(RESUME_TEMPLATE, name, fop_subs)) + for name in list(ops.keys()): + print(generate(FOP_TEMPLATE, name, fop_subs)) + +for l in open(sys.argv[1], 'r').readlines(): + if l.find('#pragma generate') != -1: + print("/* BEGIN GENERATED CODE - DO NOT MODIFY */") + gen_defaults() + print("/* END GENERATED CODE */") + else: + print(l[:-1]) diff --git a/libglusterfs/src/generator.py b/libglusterfs/src/generator.py new file mode 100755 index 00000000000..5b7aa4764a0 --- /dev/null +++ b/libglusterfs/src/generator.py @@ -0,0 +1,777 @@ +#!/usr/bin/python3 + +import string + +# ops format: 'fop-arg' name type stub-field [nosync] +# 'cbk-arg' name type +# 'extra' name type arg-str +# 'journal' fop-type +# 'link' inode iatt +# +# 'role' indicates the significance of this line to the code generator (sort of +# our own type). +# +# For fop-arg, we first need to know the name and the type of the arg so that +# we can generate SHORT_ARGS (for function calls) and LONG_ARGS (for +# declarations). For code that uses stubs, we also need to know the name of +# the stub field, which might be different than the argument itself. Lastly, +# for code that uses syncops, we need to know whether whoever wrote the syncop +# for this fop "forgot" to include this argument. (Editorial: this kind of +# creeping inconsistency is why we should have used code generation for stubs +# and syncops as well as defaults all along.) To address this need, we use the +# optional 'nosync' field for arguments (e.g. mkdir.umask) that we should skip +# in generated syncop code. +# +# 'cbk-arg' is like fop-arg but simpler and used for generating callbacks +# instead of fop functions. +# +# 'extra' is also like fop-arg, but it's another hack for syncops. This time +# the problem is that some of what would normally be *callback* arguments are +# instead created in the caller and passed to the syncop. We handle that by +# adding an entry at the appropriate place in the fop-arg list, with the name +# and type to generate a declaration and an argument string to generate the +# actual syncop call. +# +# The mere presence of a 'journal' item is sufficient for most of the journal +# code to recognize that it should do something. However, reconciliation also +# needs to decide how reconciliation builds the arguments it needs to call down +# to the syncop layer, based on what's in the journal. To do that, we divide +# ops into three types and store those types in the ops table. In general, +# these three types work as follows. +# +# For an fd-op, the GFID in the journal is used (in loc.gfid) field to +# look up an inode, then an anonymous fd is found/created for that inode. +# +# For an inode-op, the GFID in the journal is used the same way, but no fd +# is needed. +# +# For an entry-op, the *parent* GFID and name from the journal are used to +# look up an inode (via loc.pargfid and par.name respectively). +# +# The only places this seems to fall down is for link and create. In link, +# which is generally an entry-op, the source is looked up as though it's an +# inode-op. In create, we have an fd argument but it's really a return +# argument so we get a fresh inode instead of looking one up. Those two cases +# need to be handled as special cases in the reconciliation code. +# +# 'link' is (hopefully) the last of the journal/syncop hacks. Much like +# 'extra', some values that are returned as callback arguments in the normal +# case are handled differently for syncops. For syncops that create objects +# (e.g. mkdir) we need to link those objects into our inode table. The 'inode' +# and 'iatt' fields here give us the information we need to construct the +# proper inode_link call(s). + +ops = {} +xlator_cbks = {} +xlator_dumpops = {} + +ops['fgetxattr'] = ( + ('fop-arg', 'fd', 'fd_t *'), + ('fop-arg', 'name', 'const char *'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'dict', 'dict_t *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['fsetxattr'] = ( + ('fop-arg', 'fd', 'fd_t *', 'fd'), + ('fop-arg', 'dict', 'dict_t *', 'xattr'), + ('fop-arg', 'flags', 'int32_t', 'flags'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'fd-op'), +) + +ops['setxattr'] = ( + ('fop-arg', 'loc', 'loc_t *', 'loc'), + ('fop-arg', 'dict', 'dict_t *', 'xattr'), + ('fop-arg', 'flags', 'int32_t', 'flags'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'inode-op'), +) + +ops['statfs'] = ( + ('fop-arg', 'loc', 'loc_t *'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'buf', 'struct statvfs *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['fsyncdir'] = ( + ('fop-arg', 'fd', 'fd_t *'), + ('fop-arg', 'flags', 'int32_t'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['opendir'] = ( + ('fop-arg', 'loc', 'loc_t *'), + ('fop-arg', 'fd', 'fd_t *'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'fd', 'fd_t *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['fstat'] = ( + ('fop-arg', 'fd', 'fd_t *'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'buf', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['fsync'] = ( + ('fop-arg', 'fd', 'fd_t *'), + ('fop-arg', 'flags', 'int32_t'), + ('extra', 'preop', 'struct iatt', '&preop'), + ('extra', 'postop', 'struct iatt', '&postop'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'prebuf', 'struct iatt *'), + ('cbk-arg', 'postbuf', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['flush'] = ( + ('fop-arg', 'fd', 'fd_t *'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['writev'] = ( + ('fop-arg', 'fd', 'fd_t *', 'fd'), + ('fop-arg', 'vector', 'struct iovec *', 'vector'), + ('fop-arg', 'count', 'int32_t'), + ('fop-arg', 'off', 'off_t', 'offset'), + ('fop-arg', 'flags', 'uint32_t', 'flags'), + ('fop-arg', 'iobref', 'struct iobref *'), + ('extra', 'preop', 'struct iatt', '&preop'), + ('extra', 'postop', 'struct iatt', '&postop'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'prebuf', 'struct iatt *'), + ('cbk-arg', 'postbuf', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'fd-op'), +) + +ops['readv'] = ( + ('fop-arg', 'fd', 'fd_t *'), + ('fop-arg', 'size', 'size_t'), + ('fop-arg', 'offset', 'off_t'), + ('fop-arg', 'flags', 'uint32_t'), + ('extra', 'iatt', 'struct iatt', '&iatt'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'vector', 'struct iovec *'), + ('cbk-arg', 'count', 'int32_t'), + ('cbk-arg', 'stbuf', 'struct iatt *'), + ('cbk-arg', 'iobref', 'struct iobref *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['open'] = ( + ('fop-arg', 'loc', 'loc_t *'), + ('fop-arg', 'flags', 'int32_t'), + ('fop-arg', 'fd', 'fd_t *'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'fd', 'fd_t *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['create'] = ( + ('fop-arg', 'loc', 'loc_t *', 'loc'), + ('fop-arg', 'flags', 'int32_t', 'flags'), + ('fop-arg', 'mode', 'mode_t', 'mode'), + ('fop-arg', 'umask', 'mode_t', 'umask', 'nosync'), + ('fop-arg', 'fd', 'fd_t *', 'fd'), + ('extra', 'iatt', 'struct iatt', '&iatt'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'fd', 'fd_t *'), + ('cbk-arg', 'inode', 'inode_t *'), + ('cbk-arg', 'buf', 'struct iatt *'), + ('cbk-arg', 'preparent', 'struct iatt *'), + ('cbk-arg', 'postparent', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'entry-op'), + ('link', 'loc.inode', '&iatt'), +) + +ops['link'] = ( + ('fop-arg', 'oldloc', 'loc_t *', 'loc'), + ('fop-arg', 'newloc', 'loc_t *', 'loc2'), + ('extra', 'iatt', 'struct iatt', '&iatt'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'inode', 'inode_t *'), + ('cbk-arg', 'buf', 'struct iatt *'), + ('cbk-arg', 'preparent', 'struct iatt *'), + ('cbk-arg', 'postparent', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'entry-op'), +) + +ops['rename'] = ( + ('fop-arg', 'oldloc', 'loc_t *', 'loc'), + ('fop-arg', 'newloc', 'loc_t *', 'loc2'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'buf', 'struct iatt *'), + ('cbk-arg', 'preoldparent', 'struct iatt *'), + ('cbk-arg', 'postoldparent', 'struct iatt *'), + ('cbk-arg', 'prenewparent', 'struct iatt *'), + ('cbk-arg', 'postnewparent', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'entry-op'), +) + +ops['symlink'] = ( + ('fop-arg', 'linkpath', 'const char *', 'linkname'), + ('fop-arg', 'loc', 'loc_t *', 'loc'), + ('fop-arg', 'umask', 'mode_t', 'mode', 'nosync'), + ('extra', 'iatt', 'struct iatt', '&iatt'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'inode', 'inode_t *'), + ('cbk-arg', 'buf', 'struct iatt *'), + ('cbk-arg', 'preparent', 'struct iatt *'), + ('cbk-arg', 'postparent', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'entry-op'), +) + +ops['rmdir'] = ( + ('fop-arg', 'loc', 'loc_t *', 'loc'), + ('fop-arg', 'flags', 'int32_t', 'flags'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'preparent', 'struct iatt *'), + ('cbk-arg', 'postparent', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'entry-op'), +) + +ops['unlink'] = ( + ('fop-arg', 'loc', 'loc_t *', 'loc'), + ('fop-arg', 'flags', 'int32_t', 'flags', 'nosync'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'preparent', 'struct iatt *'), + ('cbk-arg', 'postparent', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'entry-op'), +) + +ops['mkdir'] = ( + ('fop-arg', 'loc', 'loc_t *', 'loc'), + ('fop-arg', 'mode', 'mode_t', 'mode'), + ('fop-arg', 'umask', 'mode_t', 'umask', 'nosync'), + ('extra', 'iatt', 'struct iatt', '&iatt'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'inode', 'inode_t *'), + ('cbk-arg', 'buf', 'struct iatt *'), + ('cbk-arg', 'preparent', 'struct iatt *'), + ('cbk-arg', 'postparent', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'entry-op'), + ('link', 'loc.inode', '&iatt'), +) + +ops['mknod'] = ( + ('fop-arg', 'loc', 'loc_t *', 'loc'), + ('fop-arg', 'mode', 'mode_t', 'mode'), + ('fop-arg', 'rdev', 'dev_t', 'rdev'), + ('fop-arg', 'umask', 'mode_t', 'umask', 'nosync'), + ('extra', 'iatt', 'struct iatt', '&iatt'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'inode', 'inode_t *'), + ('cbk-arg', 'buf', 'struct iatt *'), + ('cbk-arg', 'preparent', 'struct iatt *'), + ('cbk-arg', 'postparent', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'entry-op'), +) + +ops['readlink'] = ( + ('fop-arg', 'loc', 'loc_t *'), + ('fop-arg', 'size', 'size_t'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'path', 'const char *'), + ('cbk-arg', 'buf', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['access'] = ( + ('fop-arg', 'loc', 'loc_t *'), + ('fop-arg', 'mask', 'int32_t'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['ftruncate'] = ( + ('fop-arg', 'fd', 'fd_t *', 'fd'), + ('fop-arg', 'offset', 'off_t', 'offset'), + ('extra', 'preop', 'struct iatt', '&preop'), + ('extra', 'postop', 'struct iatt', '&postop'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'prebuf', 'struct iatt *'), + ('cbk-arg', 'postbuf', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'fd-op'), +) + +ops['getxattr'] = ( + ('fop-arg', 'loc', 'loc_t *'), + ('fop-arg', 'name', 'const char *'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'dict', 'dict_t *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['xattrop'] = ( + ('fop-arg', 'loc', 'loc_t *', 'loc'), + ('fop-arg', 'flags', 'gf_xattrop_flags_t', 'optype'), + ('fop-arg', 'dict', 'dict_t *', 'xattr'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'dict', 'dict_t *'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'inode-op'), +) + +ops['fxattrop'] = ( + ('fop-arg', 'fd', 'fd_t *', 'fd'), + ('fop-arg', 'flags', 'gf_xattrop_flags_t', 'optype'), + ('fop-arg', 'dict', 'dict_t *', 'xattr'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'dict', 'dict_t *'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'fd-op'), +) + +ops['removexattr'] = ( + ('fop-arg', 'loc', 'loc_t *', 'loc'), + ('fop-arg', 'name', 'const char *', 'name'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'inode-op'), +) + +ops['fremovexattr'] = ( + ('fop-arg', 'fd', 'fd_t *', 'fd'), + ('fop-arg', 'name', 'const char *', 'name'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'fd-op'), +) + +ops['lk'] = ( + ('fop-arg', 'fd', 'fd_t *'), + ('fop-arg', 'cmd', 'int32_t'), + ('fop-arg', 'lock', 'struct gf_flock *'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'lock', 'struct gf_flock *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['inodelk'] = ( + ('fop-arg', 'volume', 'const char *'), + ('fop-arg', 'loc', 'loc_t *'), + ('fop-arg', 'cmd', 'int32_t'), + ('fop-arg', 'lock', 'struct gf_flock *'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['finodelk'] = ( + ('fop-arg', 'volume', 'const char *'), + ('fop-arg', 'fd', 'fd_t *'), + ('fop-arg', 'cmd', 'int32_t'), + ('fop-arg', 'lock', 'struct gf_flock *'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['entrylk'] = ( + ('fop-arg', 'volume', 'const char *'), + ('fop-arg', 'loc', 'loc_t *'), + ('fop-arg', 'basename', 'const char *'), + ('fop-arg', 'cmd', 'entrylk_cmd'), + ('fop-arg', 'type', 'entrylk_type'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['fentrylk'] = ( + ('fop-arg', 'volume', 'const char *'), + ('fop-arg', 'fd', 'fd_t *'), + ('fop-arg', 'basename', 'const char *'), + ('fop-arg', 'cmd', 'entrylk_cmd'), + ('fop-arg', 'type', 'entrylk_type'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['rchecksum'] = ( + ('fop-arg', 'fd', 'fd_t *'), + ('fop-arg', 'offset', 'off_t'), + ('fop-arg', 'len', 'int32_t'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'weak_cksum', 'uint32_t'), + ('cbk-arg', 'strong_cksum', 'uint8_t *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['readdir'] = ( + ('fop-arg', 'fd', 'fd_t *'), + ('fop-arg', 'size', 'size_t'), + ('fop-arg', 'off', 'off_t'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'entries', 'gf_dirent_t *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['readdirp'] = ( + ('fop-arg', 'fd', 'fd_t *'), + ('fop-arg', 'size', 'size_t'), + ('fop-arg', 'off', 'off_t'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'entries', 'gf_dirent_t *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['setattr'] = ( + ('fop-arg', 'loc', 'loc_t *', 'loc'), + ('fop-arg', 'stbuf', 'struct iatt *', 'stat'), + ('fop-arg', 'valid', 'int32_t', 'valid'), + ('extra', 'preop', 'struct iatt', '&preop'), + ('extra', 'postop', 'struct iatt', '&postop'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'statpre', 'struct iatt *'), + ('cbk-arg', 'statpost', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'inode-op'), +) + +ops['truncate'] = ( + ('fop-arg', 'loc', 'loc_t *', 'loc'), + ('fop-arg', 'offset', 'off_t', 'offset'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'prebuf', 'struct iatt *'), + ('cbk-arg', 'postbuf', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'inode-op'), +) + +ops['stat'] = ( + ('fop-arg', 'loc', 'loc_t *'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'buf', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['lookup'] = ( + ('fop-arg', 'loc', 'loc_t *'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'inode', 'inode_t *'), + ('cbk-arg', 'buf', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), + # We could add xdata everywhere automatically if somebody hadn't put + # something after it here. + ('cbk-arg', 'postparent', 'struct iatt *'), +) + +ops['fsetattr'] = ( + ('fop-arg', 'fd', 'fd_t *', 'fd'), + ('fop-arg', 'stbuf', 'struct iatt *', 'stat'), + ('fop-arg', 'valid', 'int32_t', 'valid'), + ('extra', 'preop', 'struct iatt', '&preop'), + ('extra', 'postop', 'struct iatt', '&postop'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'statpre', 'struct iatt *'), + ('cbk-arg', 'statpost', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'fd-op'), +) + +ops['fallocate'] = ( + ('fop-arg', 'fd', 'fd_t *', 'fd'), + ('fop-arg', 'keep_size', 'int32_t', 'mode'), + ('fop-arg', 'offset', 'off_t', 'offset'), + ('fop-arg', 'len', 'size_t', 'size'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'pre', 'struct iatt *'), + ('cbk-arg', 'post', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'fd-op'), +) + +ops['discard'] = ( + ('fop-arg', 'fd', 'fd_t *', 'fd'), + ('fop-arg', 'offset', 'off_t', 'offset'), + ('fop-arg', 'len', 'size_t', 'size'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'pre', 'struct iatt *'), + ('cbk-arg', 'post', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'fd-op'), +) + +ops['zerofill'] = ( + ('fop-arg', 'fd', 'fd_t *', 'fd'), + ('fop-arg', 'offset', 'off_t', 'offset'), + # As e.g. fallocate/discard (above) "len" should really be a size_t. + ('fop-arg', 'len', 'off_t', 'size'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'pre', 'struct iatt *'), + ('cbk-arg', 'post', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'fd-op'), +) + +ops['ipc'] = ( + ('fop-arg', 'op', 'int32_t'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'xdata', 'dict_t *'), + ('journal', 'fd-op'), +) + +ops['seek'] = ( + ('fop-arg', 'fd', 'fd_t *'), + ('fop-arg', 'offset', 'off_t'), + ('fop-arg', 'what', 'gf_seek_what_t'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'offset', 'off_t'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['getspec'] = ( + ('fop-arg', 'key', 'const char *'), + ('fop-arg', 'flags', 'int32_t'), + ('cbk-arg', 'spec_data', 'char *'), +) + +ops['lease'] = ( + ('fop-arg', 'loc', 'loc_t *'), + ('fop-arg', 'lease', 'struct gf_lease *'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'lease', 'struct gf_lease *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['getactivelk'] = ( + ('fop-arg', 'loc', 'loc_t *'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'locklist', 'lock_migration_info_t *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['setactivelk'] = ( + ('fop-arg', 'loc', 'loc_t *'), + ('fop-arg', 'locklist', 'lock_migration_info_t *'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['put'] = ( + ('fop-arg', 'loc', 'loc_t *', 'loc'), + ('fop-arg', 'mode', 'mode_t', 'mode'), + ('fop-arg', 'umask', 'mode_t', 'umask'), + ('fop-arg', 'flags', 'uint32_t', 'flags'), + ('fop-arg', 'vector', 'struct iovec *', 'vector'), + ('fop-arg', 'count', 'int32_t'), + ('fop-arg', 'off', 'off_t', 'offset'), + ('fop-arg', 'iobref', 'struct iobref *'), + ('fop-arg', 'dict', 'dict_t *', 'xattr'), + ('fop-arg', 'xdata', 'dict_t *', 'xdata'), + ('cbk-arg', 'inode', 'inode_t *'), + ('cbk-arg', 'buf', 'struct iatt *'), + ('cbk-arg', 'preparent', 'struct iatt *'), + ('cbk-arg', 'postparent', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['icreate'] = ( + ('fop-arg', 'loc', 'loc_t *'), + ('fop-arg', 'mode', 'mode_t'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'inode', 'inode_t *'), + ('cbk-arg', 'buf', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['namelink'] = ( + ('fop-arg', 'loc', 'loc_t *'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'prebuf', 'struct iatt *'), + ('cbk-arg', 'postbuf', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) + +ops['copy_file_range'] = ( + ('fop-arg', 'fd_in', 'fd_t *'), + ('fop-arg', 'off_in', 'off64_t '), + ('fop-arg', 'fd_out', 'fd_t *'), + ('fop-arg', 'off_out', 'off64_t '), + ('fop-arg', 'len', 'size_t'), + ('fop-arg', 'flags', 'uint32_t'), + ('fop-arg', 'xdata', 'dict_t *'), + ('cbk-arg', 'stbuf', 'struct iatt *'), + ('cbk-arg', 'prebuf_dst', 'struct iatt *'), + ('cbk-arg', 'postbuf_dst', 'struct iatt *'), + ('cbk-arg', 'xdata', 'dict_t *'), +) +##################################################################### +xlator_cbks['forget'] = ( + ('fn-arg', 'this', 'xlator_t *'), + ('fn-arg', 'inode', 'inode_t *'), + ('ret-val', 'int32_t', '0'), +) + +xlator_cbks['release'] = ( + ('fn-arg', 'this', 'xlator_t *'), + ('fn-arg', 'fd', 'fd_t *'), + ('ret-val', 'int32_t', '0'), +) + +xlator_cbks['releasedir'] = ( + ('fn-arg', 'this', 'xlator_t *'), + ('fn-arg', 'fd', 'fd_t *'), + ('ret-val', 'int32_t', '0'), +) + +xlator_cbks['invalidate'] = ( + ('fn-arg', 'this', 'xlator_t *'), + ('fn-arg', 'inode', 'inode_t *'), + ('ret-val', 'int32_t', '0'), +) + +xlator_cbks['client_destroy'] = ( + ('fn-arg', 'this', 'xlator_t *'), + ('fn-arg', 'client', 'client_t *'), + ('ret-val', 'int32_t', '0'), +) + +xlator_cbks['client_disconnect'] = ( + ('fn-arg', 'this', 'xlator_t *'), + ('fn-arg', 'client', 'client_t *'), + ('ret-val', 'int32_t', '0'), +) + +xlator_cbks['ictxmerge'] = ( + ('fn-arg', 'this', 'xlator_t *'), + ('fn-arg', 'fd', 'fd_t *'), + ('fn-arg', 'inode', 'inode_t *'), + ('fn-arg', 'linked_inode', 'inode_t *'), + ('ret-val', 'void', ''), +) + +##################################################################### +xlator_dumpops['priv'] = ( + ('fn-arg', 'this', 'xlator_t *'), + ('ret-val', 'int32_t', '0'), +) + +xlator_dumpops['inode'] = ( + ('fn-arg', 'this', 'xlator_t *'), + ('ret-val', 'int32_t', '0'), +) + +xlator_dumpops['fd'] = ( + ('fn-arg', 'this', 'xlator_t *'), + ('ret-val', 'int32_t', '0'), +) + +xlator_dumpops['inodectx'] = ( + ('fn-arg', 'this', 'xlator_t *'), + ('fn-arg', 'ino', 'inode_t *'), + ('ret-val', 'int32_t', '0'), +) + +xlator_dumpops['fdctx'] = ( + ('fn-arg', 'this', 'xlator_t *'), + ('fn-arg', 'fd', 'fd_t *'), + ('ret-val', 'int32_t', '0'), +) + +xlator_dumpops['priv_to_dict'] = ( + ('fn-arg', 'this', 'xlator_t *'), + ('fn-arg', 'dict', 'dict_t *'), + ('ret-val', 'int32_t', '0'), +) + +xlator_dumpops['inode_to_dict'] = ( + ('fn-arg', 'this', 'xlator_t *'), + ('fn-arg', 'dict', 'dict_t *'), + ('ret-val', 'int32_t', '0'), +) + +xlator_dumpops['fd_to_dict'] = ( + ('fn-arg', 'this', 'xlator_t *'), + ('fn-arg', 'dict', 'dict_t *'), + ('ret-val', 'int32_t', '0'), +) + +xlator_dumpops['inodectx_to_dict'] = ( + ('fn-arg', 'this', 'xlator_t *'), + ('fn-arg', 'ino', 'inode_t *'), + ('fn-arg', 'dict', 'dict_t *'), + ('ret-val', 'int32_t', '0'), +) + +xlator_dumpops['fdctx_to_dict'] = ( + ('fn-arg', 'this', 'xlator_t *'), + ('fn-arg', 'fd', 'fd_t *'), + ('fn-arg', 'dict', 'dict_t *'), + ('ret-val', 'int32_t', '0'), +) + +xlator_dumpops['history'] = ( + ('fn-arg', 'this', 'xlator_t *'), + ('ret-val', 'int32_t', '0'), +) + +def get_error_arg (type_str): + if type_str.find(" *") != -1: + return "NULL" + return "-1" + +def get_subs (names, types, cbktypes=None): + sdict = {} + sdict["@SHORT_ARGS@"] = ', '.join(names) + # Convert two separate tuples to one of (name, type) sub-tuples. + as_tuples = list(zip(types, names)) + # Convert each sub-tuple into a "type name" string. + as_strings = [' '.join(item) for item in as_tuples] + # Join all of those into one big string. + sdict["@LONG_ARGS@"] = ',\n\t'.join(as_strings) + # So much more readable than string.join(map(string.join,zip(...)))) + sdict["@ERROR_ARGS@"] = ', '.join(list(map(get_error_arg, types))) + if cbktypes is not None: + sdict["@CBK_ERROR_ARGS@"] = ', '.join(list(map(get_error_arg, cbktypes))) + return sdict + +def generate (tmpl, name, subs): + text = tmpl.replace("@NAME@", name) + if name == "writev": + # More spurious inconsistency. + text = text.replace("@UPNAME@", "WRITE") + elif name == "readv": + text = text.replace("@UPNAME@", "READ") + else: + text = text.replace("@UPNAME@", name.upper()) + for old, new in subs[name].items(): + text = text.replace(old, new) + # TBD: reindent/reformat the result for maximum readability. + return text + +fop_subs = {} +cbk_subs = {} + +for name, args in ops.items(): + + # Create the necessary substitution strings for fops. + arg_names = [ a[1] for a in args if a[0] == 'fop-arg'] + arg_types = [ a[2] for a in args if a[0] == 'fop-arg'] + cbk_types = [ a[2] for a in args if a[0] == 'cbk-arg'] + fop_subs[name] = get_subs(arg_names, arg_types, cbk_types) + + # Same thing for callbacks. + arg_names = [ a[1] for a in args if a[0] == 'cbk-arg'] + arg_types = [ a[2] for a in args if a[0] == 'cbk-arg'] + cbk_subs[name] = get_subs(arg_names, arg_types) + + # Callers can add other subs to these tables, or even create their + # own tables, using these same techniques, and then pass the result + # to generate() which would Do The Right Thing with them. diff --git a/libglusterfs/src/gf-dirent.c b/libglusterfs/src/gf-dirent.c index 5ae74f9820a..a809efc97ef 100644 --- a/libglusterfs/src/gf-dirent.c +++ b/libglusterfs/src/gf-dirent.c @@ -1,94 +1,301 @@ /* - Copyright (c) 2008-2009 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. + 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. +*/ - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include "glusterfs/compat.h" +#include "glusterfs/syncop.h" - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ +#define ONE 1ULL +#define PRESENT_D_OFF_BITS 63 +#define BACKEND_D_OFF_BITS 63 +#define TOP_BIT (ONE << (PRESENT_D_OFF_BITS - 1)) +#define MASK (~0ULL) +#define SHIFT_BITS (max(0, (BACKEND_D_OFF_BITS - PRESENT_D_OFF_BITS + 1))) +#define PRESENT_MASK (MASK >> (64 - PRESENT_D_OFF_BITS)) +static uint64_t +bits_for(uint64_t num) +{ + uint64_t bits = 0, ctrl = 1; -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif + while (ctrl < num) { + ctrl *= 2; + bits++; + } + return bits; +} -#include <stdio.h> -#include <string.h> -#include <stdint.h> -#include "compat.h" -#include "xlator.h" +int +gf_deitransform(xlator_t *this, uint64_t offset) +{ + int cnt = 0; + int max = 0; + int max_bits = 0; + uint64_t off_mask = 0; + uint64_t host_mask = 0; + + max = glusterfs_get_leaf_count(this->graph); + + if (max == 1) { + cnt = 0; + goto out; + } + + if (offset & TOP_BIT) { + /* HUGE d_off */ + max_bits = bits_for(max); + off_mask = (MASK << max_bits); + host_mask = ~(off_mask); + + cnt = offset & host_mask; + } else { + /* small d_off */ + cnt = offset % max; + } +out: + return cnt; +} + +uint64_t +gf_dirent_orig_offset(xlator_t *this, uint64_t offset) +{ + int max = 0; + int max_bits = 0; + uint64_t off_mask = 0; + uint64_t orig_offset; + + max = glusterfs_get_leaf_count(this->graph); + + if (max == 1) { + orig_offset = offset; + goto out; + } + + if (offset & TOP_BIT) { + /* HUGE d_off */ + max_bits = bits_for(max); + off_mask = (MASK << max_bits); + orig_offset = ((offset & ~TOP_BIT) & off_mask) << SHIFT_BITS; + } else { + /* small d_off */ + orig_offset = offset / max; + } +out: + return orig_offset; +} + +int +gf_itransform(xlator_t *this, uint64_t x, uint64_t *y_p, int client_id) +{ + int max = 0; + uint64_t y = 0; + uint64_t hi_mask = 0; + uint64_t off_mask = 0; + int max_bits = 0; + + if (x == ((uint64_t)-1)) { + y = (uint64_t)-1; + goto out; + } + + if (!x) { + y = 0; + goto out; + } + + max = glusterfs_get_leaf_count(this->graph); + + if (max == 1) { + y = x; + goto out; + } + + max_bits = bits_for(max); + + hi_mask = ~(PRESENT_MASK >> (max_bits + 1)); + + if (x & hi_mask) { + /* HUGE d_off */ + off_mask = MASK << max_bits; + y = TOP_BIT | ((x >> SHIFT_BITS) & off_mask) | client_id; + } else { + /* small d_off */ + y = ((x * max) + client_id); + } + +out: + if (y_p) + *y_p = y; + + return 0; +} gf_dirent_t * -gf_dirent_for_namelen (int len) +gf_dirent_for_name(const char *name) { - gf_dirent_t *gf_dirent = NULL; + gf_dirent_t *gf_dirent = NULL; - /* TODO: use mem-pool */ - gf_dirent = CALLOC (len, sizeof(char)); - if (!gf_dirent) - return NULL; + /* TODO: use mem-pool */ + gf_dirent = GF_CALLOC(gf_dirent_size(name), 1, gf_common_mt_gf_dirent_t); + if (!gf_dirent) + return NULL; - INIT_LIST_HEAD (&gf_dirent->list); + INIT_LIST_HEAD(&gf_dirent->list); + strcpy(gf_dirent->d_name, name); - gf_dirent->d_off = 0; - gf_dirent->d_ino = -1; - gf_dirent->d_type = 0; + gf_dirent->d_off = 0; + gf_dirent->d_ino = -1; + gf_dirent->d_type = 0; + gf_dirent->d_len = strlen(name); - return gf_dirent; + return gf_dirent; } +void +gf_dirent_entry_free(gf_dirent_t *entry) +{ + if (!entry) + return; + + if (entry->dict) + dict_unref(entry->dict); + if (entry->inode) + inode_unref(entry->inode); + + list_del_init(&entry->list); + GF_FREE(entry); +} + +void +gf_dirent_free(gf_dirent_t *entries) +{ + gf_dirent_t *entry = NULL; + gf_dirent_t *tmp = NULL; + + if (!entries) + return; + + if (list_empty(&entries->list)) + return; + + list_for_each_entry_safe(entry, tmp, &entries->list, list) + { + gf_dirent_entry_free(entry); + } +} gf_dirent_t * -gf_dirent_for_name (const char *name) +entry_copy(gf_dirent_t *source) { - gf_dirent_t *gf_dirent = NULL; + gf_dirent_t *sink = NULL; - /* TODO: use mem-pool */ - gf_dirent = GF_CALLOC (gf_dirent_size (name), 1, - gf_common_mt_gf_dirent_t); - if (!gf_dirent) - return NULL; + sink = gf_dirent_for_name(source->d_name); + if (!sink) + return NULL; - INIT_LIST_HEAD (&gf_dirent->list); - strcpy (gf_dirent->d_name, name); + sink->d_off = source->d_off; + sink->d_ino = source->d_ino; + sink->d_type = source->d_type; + sink->d_stat = source->d_stat; + sink->d_len = source->d_len; - gf_dirent->d_off = 0; - gf_dirent->d_ino = -1; - gf_dirent->d_type = 0; - gf_dirent->d_len = strlen (name); + if (source->inode) + sink->inode = inode_ref(source->inode); - return gf_dirent; + if (source->dict) + sink->dict = dict_ref(source->dict); + return sink; } - void -gf_dirent_free (gf_dirent_t *entries) +gf_link_inode_from_dirent(xlator_t *this, inode_t *parent, gf_dirent_t *entry) { - gf_dirent_t *entry = NULL; - gf_dirent_t *tmp = NULL; + inode_t *link_inode = NULL; + inode_t *tmp = NULL; + + if (!entry->inode) + return; + link_inode = inode_link(entry->inode, parent, entry->d_name, + &entry->d_stat); + if (!link_inode) + return; - if (!entries) - return; + inode_lookup(link_inode); + tmp = entry->inode; + entry->inode = link_inode; + inode_unref(tmp); +} + +/* TODO: Currently, with this function, we will be breaking the + policy of 1-1 mapping of kernel nlookup refs with our inode_t's + nlookup count. + Need more thoughts before finalizing this function +*/ +int +gf_link_inodes_from_dirent(xlator_t *this, inode_t *parent, + gf_dirent_t *entries) +{ + gf_dirent_t *entry = NULL; - if (list_empty (&entries->list)) - return; + list_for_each_entry(entry, &entries->list, list) + { + gf_link_inode_from_dirent(this, parent, entry); + } - list_for_each_entry_safe (entry, tmp, &entries->list, list) { - list_del (&entry->list); - GF_FREE (entry); - } + return 0; } +int +gf_fill_iatt_for_dirent(gf_dirent_t *entry, inode_t *parent, xlator_t *subvol) +{ + loc_t loc = { + 0, + }; + int ret = -1; + char *path = NULL; + struct iatt iatt = { + 0, + }; + + loc.inode = inode_grep(parent->table, parent, entry->d_name); + if (!loc.inode) { + loc.inode = inode_new(parent->table); + gf_uuid_copy(loc.inode->gfid, entry->d_stat.ia_gfid); + } + + gf_uuid_copy(loc.pargfid, parent->gfid); + loc.name = entry->d_name; + loc.parent = inode_ref(parent); + ret = inode_path(loc.parent, entry->d_name, &path); + loc.path = path; + if (ret < 0) + goto out; + ret = syncop_lookup(subvol, &loc, &iatt, NULL, NULL, NULL); + if (ret) + goto out; + + entry->d_stat = iatt; + entry->inode = inode_ref(loc.inode); + /* We don't need to link inode here, because as part of readdirp_cbk + * we will link all dirents. + * + * Since we did a proper lookup, we don't need to set need_lookup + * flag. + */ + + ret = 0; +out: + loc_wipe(&loc); + return ret; +} diff --git a/libglusterfs/src/gf-dirent.h b/libglusterfs/src/gf-dirent.h deleted file mode 100644 index abac13cf3c6..00000000000 --- a/libglusterfs/src/gf-dirent.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - Copyright (c) 2008-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - - -#ifndef _GF_DIRENT_H -#define _GF_DIRENT_H - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include "iatt.h" - -#define gf_dirent_size(name) (sizeof (gf_dirent_t) + strlen (name) + 1) - -struct _dir_entry_t { - struct _dir_entry_t *next; - char *name; - char *link; - struct iatt buf; -}; - - -struct _gf_dirent_t { - union { - struct list_head list; - struct { - struct _gf_dirent_t *next; - struct _gf_dirent_t *prev; - }; - }; - uint64_t d_ino; - uint64_t d_off; - uint32_t d_len; - uint32_t d_type; - struct iatt d_stat; - char d_name[0]; -}; - - -gf_dirent_t *gf_dirent_for_name (const char *name); -void gf_dirent_free (gf_dirent_t *entries); -gf_dirent_t * gf_dirent_for_namelen (int len); - -#endif /* _GF_DIRENT_H */ diff --git a/libglusterfs/src/gidcache.c b/libglusterfs/src/gidcache.c new file mode 100644 index 00000000000..64a93802f76 --- /dev/null +++ b/libglusterfs/src/gidcache.c @@ -0,0 +1,211 @@ +/* + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include "glusterfs/gidcache.h" +#include "glusterfs/mem-pool.h" +#include "glusterfs/common-utils.h" + +/* + * We treat this as a very simple set-associative LRU cache, with entries aged + * out after a configurable interval. Hardly rocket science, but lots of + * details to worry about. + */ +#define BUCKET_START(p, n) ((p) + ((n)*AUX_GID_CACHE_ASSOC)) + +/* + * Initialize the cache. + */ +int +gid_cache_init(gid_cache_t *cache, uint32_t timeout) +{ + if (!cache) + return -1; + + LOCK_INIT(&cache->gc_lock); + cache->gc_max_age = timeout; + cache->gc_nbuckets = AUX_GID_CACHE_BUCKETS; + memset(cache->gc_cache, 0, sizeof(gid_list_t) * AUX_GID_CACHE_SIZE); + + return 0; +} + +/* + * 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. + */ +const gid_list_t * +gid_cache_lookup(gid_cache_t *cache, uint64_t id, uint64_t uid, uint64_t gid) +{ + int bucket; + int i; + time_t now; + const gid_list_t *agl; + + now = gf_time(); + LOCK(&cache->gc_lock); + bucket = id % cache->gc_nbuckets; + agl = BUCKET_START(cache->gc_cache, bucket); + for (i = 0; i < AUX_GID_CACHE_ASSOC; i++, agl++) { + if (!agl->gl_list) + continue; + if (agl->gl_id != id) + continue; + + /* + @uid and @gid reflect the latest UID/GID of the + process performing the syscall (taken from frame->root). + + If the UID and GID has changed for the PID since the + time we cached it, we should treat the cache as having + stale values and query them freshly. + */ + if (agl->gl_uid != uid || agl->gl_gid != gid) + break; + + /* + * We don't put new entries in the cache when expiration=0, but + * there might be entries still in there if expiration was + * changed very recently. Writing the check this way ensures + * that they're not used. + */ + if (now < agl->gl_deadline) { + return agl; + } + + /* + * We're not going to find any more UID matches, and reaping + * is handled further down to maintain LRU order. + */ + break; + } + UNLOCK(&cache->gc_lock); + return NULL; +} + +/* + * Release an entry found via lookup. + */ +void +gid_cache_release(gid_cache_t *cache, const gid_list_t *agl) +{ + UNLOCK(&cache->gc_lock); +} + +/* + * Add a new list entry to the cache. If an entry for this ID already exists, + * update it. + */ +int +gid_cache_add(gid_cache_t *cache, gid_list_t *gl) +{ + gid_list_t *agl; + int bucket; + int i; + time_t now; + + if (!gl || !gl->gl_list) + return -1; + + if (!cache->gc_max_age) + return 0; + + now = gf_time(); + LOCK(&cache->gc_lock); + + /* + * Scan for the first free entry or one that matches this id. The id + * check is added to address a bug where the cache might contain an + * expired entry for this id. Since lookup occurs in LRU order and + * does not reclaim entries, it will always return failure on discovery + * of an expired entry. This leads to duplicate entries being added, + * which still do not satisfy lookups until the expired entry (and + * everything before it) is reclaimed. + * + * We address this through reuse of an entry already allocated to this + * id, whether expired or not, since we have obviously already received + * more recent data. The entry is repopulated with the new data and a new + * deadline and is pushed forward to reside as the last populated entry in + * the bucket. + */ + bucket = gl->gl_id % cache->gc_nbuckets; + agl = BUCKET_START(cache->gc_cache, bucket); + for (i = 0; i < AUX_GID_CACHE_ASSOC; ++i, ++agl) { + if (agl->gl_id == gl->gl_id) + break; + if (!agl->gl_list) + break; + } + + /* + * The way we allocate free entries naturally places the newest + * ones at the highest indices, so evicting the lowest makes + * sense, but that also means we can't just replace it with the + * one that caused the eviction. That would cause us to thrash + * the first entry while others remain idle. Therefore, we + * need to slide the other entries down and add the new one at + * the end just as if the *last* slot had been free. + * + * Deadline expiration is also handled here, since the oldest + * expired entry will be in the first position. This does mean + * the bucket can stay full of expired entries if we're idle + * but, if the small amount of extra memory or scan time before + * we decide to evict someone ever become issues, we could + * easily add a reaper thread. + */ + + if (i >= AUX_GID_CACHE_ASSOC) { + /* cache full, evict the first (LRU) entry */ + i = 0; + agl = BUCKET_START(cache->gc_cache, bucket); + GF_FREE(agl->gl_list); + } else if (agl->gl_list) { + /* evict the old entry we plan to reuse */ + GF_FREE(agl->gl_list); + } + + /* + * If we have evicted an entry, slide the subsequent populated entries + * back and populate the last entry. + */ + for (; i < AUX_GID_CACHE_ASSOC - 1; i++) { + if (!agl[1].gl_list) + break; + agl[0] = agl[1]; + agl++; + } + + agl->gl_id = gl->gl_id; + agl->gl_uid = gl->gl_uid; + agl->gl_gid = gl->gl_gid; + agl->gl_count = gl->gl_count; + agl->gl_list = gl->gl_list; + agl->gl_deadline = now + cache->gc_max_age; + + UNLOCK(&cache->gc_lock); + + return 1; +} diff --git a/libglusterfs/src/globals.c b/libglusterfs/src/globals.c index e845b3dcb66..ae06f8be386 100644 --- a/libglusterfs/src/globals.c +++ b/libglusterfs/src/globals.c @@ -1,336 +1,366 @@ /* - Copyright (c) 2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif /* !_CONFIG_H */ + 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 <pthread.h> -#include "glusterfs.h" -#include "globals.h" -#include "xlator.h" -#include "mem-pool.h" +#include "glusterfs/syncop.h" +#include "glusterfs/libglusterfs-messages.h" + +const char *gf_fop_list[GF_FOP_MAXVALUE] = { + [GF_FOP_NULL] = "NULL", + [GF_FOP_STAT] = "STAT", + [GF_FOP_READLINK] = "READLINK", + [GF_FOP_MKNOD] = "MKNOD", + [GF_FOP_MKDIR] = "MKDIR", + [GF_FOP_UNLINK] = "UNLINK", + [GF_FOP_RMDIR] = "RMDIR", + [GF_FOP_SYMLINK] = "SYMLINK", + [GF_FOP_RENAME] = "RENAME", + [GF_FOP_LINK] = "LINK", + [GF_FOP_TRUNCATE] = "TRUNCATE", + [GF_FOP_OPEN] = "OPEN", + [GF_FOP_READ] = "READ", + [GF_FOP_WRITE] = "WRITE", + [GF_FOP_STATFS] = "STATFS", + [GF_FOP_FLUSH] = "FLUSH", + [GF_FOP_FSYNC] = "FSYNC", + [GF_FOP_SETXATTR] = "SETXATTR", + [GF_FOP_GETXATTR] = "GETXATTR", + [GF_FOP_REMOVEXATTR] = "REMOVEXATTR", + [GF_FOP_OPENDIR] = "OPENDIR", + [GF_FOP_FSYNCDIR] = "FSYNCDIR", + [GF_FOP_ACCESS] = "ACCESS", + [GF_FOP_CREATE] = "CREATE", + [GF_FOP_FTRUNCATE] = "FTRUNCATE", + [GF_FOP_FSTAT] = "FSTAT", + [GF_FOP_LK] = "LK", + [GF_FOP_LOOKUP] = "LOOKUP", + [GF_FOP_READDIR] = "READDIR", + [GF_FOP_INODELK] = "INODELK", + [GF_FOP_FINODELK] = "FINODELK", + [GF_FOP_ENTRYLK] = "ENTRYLK", + [GF_FOP_FENTRYLK] = "FENTRYLK", + [GF_FOP_XATTROP] = "XATTROP", + [GF_FOP_FXATTROP] = "FXATTROP", + [GF_FOP_FSETXATTR] = "FSETXATTR", + [GF_FOP_FGETXATTR] = "FGETXATTR", + [GF_FOP_RCHECKSUM] = "RCHECKSUM", + [GF_FOP_SETATTR] = "SETATTR", + [GF_FOP_FSETATTR] = "FSETATTR", + [GF_FOP_READDIRP] = "READDIRP", + [GF_FOP_GETSPEC] = "GETSPEC", + [GF_FOP_FORGET] = "FORGET", + [GF_FOP_RELEASE] = "RELEASE", + [GF_FOP_RELEASEDIR] = "RELEASEDIR", + [GF_FOP_FREMOVEXATTR] = "FREMOVEXATTR", + [GF_FOP_FALLOCATE] = "FALLOCATE", + [GF_FOP_DISCARD] = "DISCARD", + [GF_FOP_ZEROFILL] = "ZEROFILL", + [GF_FOP_IPC] = "IPC", + [GF_FOP_SEEK] = "SEEK", + [GF_FOP_LEASE] = "LEASE", + [GF_FOP_COMPOUND] = "COMPOUND", + [GF_FOP_GETACTIVELK] = "GETACTIVELK", + [GF_FOP_SETACTIVELK] = "SETACTIVELK", + [GF_FOP_PUT] = "PUT", + [GF_FOP_ICREATE] = "ICREATE", + [GF_FOP_NAMELINK] = "NAMELINK", + [GF_FOP_COPY_FILE_RANGE] = "COPY_FILE_RANGE", +}; + +const char *gf_upcall_list[GF_UPCALL_FLAGS_MAXVALUE] = { + [GF_UPCALL_NULL] = "NULL", + [GF_UPCALL] = "UPCALL", + [GF_UPCALL_CI_STAT] = "CI_IATT", + [GF_UPCALL_CI_XATTR] = "CI_XATTR", + [GF_UPCALL_CI_RENAME] = "CI_RENAME", + [GF_UPCALL_CI_NLINK] = "CI_UNLINK", + [GF_UPCALL_CI_FORGET] = "CI_FORGET", + [GF_UPCALL_LEASE_RECALL] = "LEASE_RECALL", +}; +/* THIS */ -/* gf_*_list[] */ +/* This global ctx is a bad hack to prevent some of the libgfapi crashes. + * This should be removed once the patch on resource pool is accepted + */ +glusterfs_ctx_t *global_ctx = NULL; +pthread_mutex_t global_ctx_mutex = PTHREAD_MUTEX_INITIALIZER; +xlator_t global_xlator; +static int gf_global_mem_acct_enable = 1; +static pthread_once_t globals_inited = PTHREAD_ONCE_INIT; -char *gf_fop_list[GF_FOP_MAXVALUE]; -char *gf_mgmt_list[GF_MGMT_MAXVALUE]; +static pthread_key_t free_key; +static __thread xlator_t *thread_xlator = NULL; +static __thread void *thread_synctask = NULL; +static __thread void *thread_leaseid = NULL; +static __thread struct syncopctx thread_syncopctx = {}; +static __thread char thread_uuid_buf[GF_UUID_BUF_SIZE] = {}; +static __thread char thread_lkowner_buf[GF_LKOWNER_BUF_SIZE] = {}; +static __thread char thread_leaseid_buf[GF_LEASE_ID_BUF_SIZE] = {}; -void -gf_op_list_init() +int +gf_global_mem_acct_enable_get(void) { - gf_fop_list[GF_FOP_NULL] = "NULL"; - gf_fop_list[GF_FOP_STAT] = "STAT"; - gf_fop_list[GF_FOP_READLINK] = "READLINK"; - gf_fop_list[GF_FOP_MKNOD] = "MKNOD"; - gf_fop_list[GF_FOP_MKDIR] = "MKDIR"; - gf_fop_list[GF_FOP_UNLINK] = "UNLINK"; - gf_fop_list[GF_FOP_RMDIR] = "RMDIR"; - gf_fop_list[GF_FOP_SYMLINK] = "SYMLINK"; - gf_fop_list[GF_FOP_RENAME] = "RENAME"; - gf_fop_list[GF_FOP_LINK] = "LINK"; - gf_fop_list[GF_FOP_TRUNCATE] = "TRUNCATE"; - gf_fop_list[GF_FOP_OPEN] = "OPEN"; - gf_fop_list[GF_FOP_READ] = "READ"; - gf_fop_list[GF_FOP_WRITE] = "WRITE"; - gf_fop_list[GF_FOP_STATFS] = "STATFS"; - gf_fop_list[GF_FOP_FLUSH] = "FLUSH"; - gf_fop_list[GF_FOP_FSYNC] = "FSYNC"; - gf_fop_list[GF_FOP_SETXATTR] = "SETXATTR"; - gf_fop_list[GF_FOP_GETXATTR] = "GETXATTR"; - gf_fop_list[GF_FOP_REMOVEXATTR] = "REMOVEXATTR"; - gf_fop_list[GF_FOP_OPENDIR] = "OPENDIR"; - gf_fop_list[GF_FOP_FSYNCDIR] = "FSYNCDIR"; - gf_fop_list[GF_FOP_ACCESS] = "ACCESS"; - gf_fop_list[GF_FOP_CREATE] = "CREATE"; - gf_fop_list[GF_FOP_FTRUNCATE] = "FTRUNCATE"; - gf_fop_list[GF_FOP_FSTAT] = "FSTAT"; - gf_fop_list[GF_FOP_LK] = "LK"; - gf_fop_list[GF_FOP_LOOKUP] = "LOOKUP"; - gf_fop_list[GF_FOP_READDIR] = "READDIR"; - gf_fop_list[GF_FOP_INODELK] = "INODELK"; - gf_fop_list[GF_FOP_FINODELK] = "FINODELK"; - gf_fop_list[GF_FOP_ENTRYLK] = "ENTRYLK"; - gf_fop_list[GF_FOP_FENTRYLK] = "FENTRYLK"; - gf_fop_list[GF_FOP_XATTROP] = "XATTROP"; - gf_fop_list[GF_FOP_FXATTROP] = "FXATTROP"; - gf_fop_list[GF_FOP_FSETXATTR] = "FSETXATTR"; - gf_fop_list[GF_FOP_FGETXATTR] = "FGETXATTR"; - gf_fop_list[GF_FOP_RCHECKSUM] = "RCHECKSUM"; - gf_fop_list[GF_FOP_SETATTR] = "SETATTR"; - gf_fop_list[GF_FOP_FSETATTR] = "FSETATTR"; - gf_fop_list[GF_FOP_READDIRP] = "READDIRP"; - gf_fop_list[GF_FOP_GETSPEC] = "GETSPEC"; - gf_fop_list[GF_FOP_FORGET] = "FORGET"; - gf_fop_list[GF_FOP_RELEASE] = "RELEASE"; - gf_fop_list[GF_FOP_RELEASEDIR] = "RELEASEDIR"; - - gf_fop_list[GF_MGMT_NULL] = "NULL"; - return; + return gf_global_mem_acct_enable; } - -/* CTX */ -static glusterfs_ctx_t *glusterfs_ctx; - - int -glusterfs_ctx_init () +gf_global_mem_acct_enable_set(int val) { - int ret = 0; + gf_global_mem_acct_enable = val; + return 0; +} - if (glusterfs_ctx) - goto out; +static struct xlator_cbks global_cbks = { + .forget = NULL, + .release = NULL, + .releasedir = NULL, + .invalidate = NULL, + .client_destroy = NULL, + .client_disconnect = NULL, + .ictxmerge = NULL, + .ictxsize = NULL, + .fdctxsize = NULL, +}; + +/* This is required to get through the check in graph.c */ +static struct xlator_fops global_fops = {}; + +static int +global_xl_reconfigure(xlator_t *this, dict_t *options) +{ + int ret = -1; + gf_boolean_t bool_opt = _gf_false; + + /* This is not added in volume dump, hence adding the options in log + would be helpful for debugging later */ + dict_dump_to_log(options); - glusterfs_ctx = CALLOC (1, sizeof (*glusterfs_ctx)); - if (!glusterfs_ctx) { - ret = -1; - goto out; - } + GF_OPTION_RECONF("measure-latency", bool_opt, options, bool, out); + this->ctx->measure_latency = bool_opt; - INIT_LIST_HEAD (&glusterfs_ctx->graphs); - ret = pthread_mutex_init (&glusterfs_ctx->lock, NULL); + GF_OPTION_RECONF("metrics-dump-path", this->ctx->config.metrics_dumppath, + options, str, out); + /* TODO: add more things here */ + ret = 0; out: - return ret; + return ret; } - -glusterfs_ctx_t * -glusterfs_ctx_get () +static int +global_xl_init(xlator_t *this) { - return glusterfs_ctx; + int ret = -1; + gf_boolean_t bool_opt = false; -} + GF_OPTION_INIT("measure-latency", bool_opt, bool, out); + this->ctx->measure_latency = bool_opt; + GF_OPTION_INIT("metrics-dump-path", this->ctx->config.metrics_dumppath, str, + out); -/* THIS */ + ret = 0; -xlator_t global_xlator; -static pthread_key_t this_xlator_key; - -void -glusterfs_this_destroy (void *ptr) -{ - if (ptr) - FREE (ptr); +out: + return ret; } - -int -glusterfs_this_init () +static void +global_xl_fini(xlator_t *this) { - int ret = 0; - - ret = pthread_key_create (&this_xlator_key, glusterfs_this_destroy); - if (ret != 0) { - return ret; - } - - global_xlator.name = "glusterfs"; - global_xlator.type = "global"; - global_xlator.ctx = glusterfs_ctx; - - return ret; + return; } +struct volume_options global_xl_options[] = { + {.key = {"measure-latency"}, + .type = GF_OPTION_TYPE_BOOL, + .default_value = "no", + .op_version = {GD_OP_VERSION_4_0_0}, + .flags = OPT_FLAG_SETTABLE, + .tags = {"global", "context"}, + .description = "Use this option to toggle measuring latency"}, + {.key = {"metrics-dump-path"}, + .type = GF_OPTION_TYPE_STR, + .default_value = "{{gluster_workdir}}/metrics", + .op_version = {GD_OP_VERSION_4_0_0}, + .flags = OPT_FLAG_SETTABLE, + .tags = {"global", "context"}, + .description = "Use this option to set the metrics dump path"}, + + { + .key = {NULL}, + }, +}; + +static volume_opt_list_t global_xl_opt_list; -xlator_t ** -__glusterfs_this_location () +void +glusterfs_this_init() { - xlator_t **this_location = NULL; - int ret = 0; - - this_location = pthread_getspecific (this_xlator_key); - - if (!this_location) { - this_location = CALLOC (1, sizeof (*this_location)); - if (!this_location) - goto out; - - ret = pthread_setspecific (this_xlator_key, this_location); - if (ret != 0) { - FREE (this_location); - this_location = NULL; - goto out; - } - } -out: - if (this_location) { - if (!*this_location) - *this_location = &global_xlator; - } - return this_location; + global_xlator.name = "glusterfs"; + global_xlator.type = GF_GLOBAL_XLATOR_NAME; + global_xlator.cbks = &global_cbks; + global_xlator.fops = &global_fops; + global_xlator.reconfigure = global_xl_reconfigure; + global_xlator.init = global_xl_init; + global_xlator.fini = global_xl_fini; + + INIT_LIST_HEAD(&global_xlator.volume_options); + INIT_LIST_HEAD(&global_xl_opt_list.list); + global_xl_opt_list.given_opt = global_xl_options; + + list_add_tail(&global_xl_opt_list.list, &global_xlator.volume_options); } - -xlator_t * -glusterfs_this_get () +xlator_t ** +__glusterfs_this_location() { - xlator_t **this_location = NULL; + xlator_t **this_location; - this_location = __glusterfs_this_location (); - if (!this_location) - return &global_xlator; + this_location = &thread_xlator; + if (*this_location == NULL) { + thread_xlator = &global_xlator; + } - return *this_location; + return this_location; } - -int -glusterfs_this_set (xlator_t *this) +xlator_t * +glusterfs_this_get() { - xlator_t **this_location = NULL; - - this_location = __glusterfs_this_location (); - if (!this_location) - return -ENOMEM; - - *this_location = this; - - return 0; + return *__glusterfs_this_location(); } - -/* IS_CENTRAL_LOG */ - -static pthread_key_t central_log_flag_key; - void -glusterfs_central_log_flag_destroy (void *ptr) +glusterfs_this_set(xlator_t *this) { - if (ptr) - FREE (ptr); + thread_xlator = this; } +/* SYNCOPCTX */ -int -glusterfs_central_log_flag_init () +void * +syncopctx_getctx() { - int ret = 0; - - ret = pthread_key_create (¢ral_log_flag_key, - glusterfs_central_log_flag_destroy); - - if (ret != 0) { - return ret; - } + return &thread_syncopctx; +} - pthread_setspecific (central_log_flag_key, (void *) 0); +/* SYNCTASK */ - return ret; +void * +synctask_get() +{ + return thread_synctask; } - void -glusterfs_central_log_flag_set () +synctask_set(void *synctask) { - pthread_setspecific (central_log_flag_key, (void *) 1); + thread_synctask = synctask; } +// UUID_BUFFER -long -glusterfs_central_log_flag_get () +char * +glusterfs_uuid_buf_get() { - long flag = 0; - - flag = (long) pthread_getspecific (central_log_flag_key); - - return flag; + return thread_uuid_buf; } +/* LKOWNER_BUFFER */ -void -glusterfs_central_log_flag_unset () +char * +glusterfs_lkowner_buf_get() { - pthread_setspecific (central_log_flag_key, (void *) 0); + return thread_lkowner_buf; } +/* Leaseid buffer */ - -/* SYNCTASK */ - -static pthread_key_t synctask_key; - - -int -synctask_init () +char * +glusterfs_leaseid_buf_get() { - int ret = 0; + char *buf = NULL; - ret = pthread_key_create (&synctask_key, NULL); + buf = thread_leaseid; + if (buf == NULL) { + buf = thread_leaseid_buf; + thread_leaseid = buf; + } - return ret; + return buf; } - -void * -synctask_get () +char * +glusterfs_leaseid_exist() { - void *synctask = NULL; + return thread_leaseid; +} - synctask = pthread_getspecific (synctask_key); +static void +glusterfs_cleanup(void *ptr) +{ + if (thread_syncopctx.groups != NULL) { + GF_FREE(thread_syncopctx.groups); + } - return synctask; + mem_pool_thread_destructor(NULL); } +void +gf_thread_needs_cleanup(void) +{ + /* The value stored in free_key TLS is not really used for anything, but + * pthread implementation doesn't call the TLS destruction function unless + * it's != NULL. This function must be called whenever something is + * allocated for this thread so that glusterfs_cleanup() will be called + * and resources can be released. */ + (void)pthread_setspecific(free_key, (void *)1); +} -int -synctask_set (void *synctask) +static void +gf_globals_init_once() { - int ret = 0; + int ret = 0; - pthread_setspecific (synctask_key, synctask); + glusterfs_this_init(); - return ret; -} + /* This is needed only to cleanup the potential allocation of + * thread_syncopctx.groups. */ + ret = pthread_key_create(&free_key, glusterfs_cleanup); + if (ret != 0) { + gf_msg("", GF_LOG_ERROR, ret, LG_MSG_PTHREAD_KEY_CREATE_FAILED, + "failed to create the pthread key"); + gf_msg("", GF_LOG_CRITICAL, 0, LG_MSG_GLOBAL_INIT_FAILED, + "Exiting as global initialization failed"); + + exit(ret); + } +} int -glusterfs_globals_init () +glusterfs_globals_init(glusterfs_ctx_t *ctx) { - int ret = 0; + int ret = 0; - gf_op_list_init (); + gf_log_globals_init(ctx, GF_LOG_INFO); - ret = glusterfs_ctx_init (); - if (ret) - goto out; + ret = pthread_once(&globals_inited, gf_globals_init_once); - ret = glusterfs_this_init (); - if (ret) - goto out; + if (ret) + gf_msg("", GF_LOG_CRITICAL, ret, LG_MSG_PTHREAD_FAILED, + "pthread_once failed"); - ret = glusterfs_central_log_flag_init (); - if (ret) - goto out; - - gf_mem_acct_enable_set (); - - ret = synctask_init (); - if (ret) - goto out; - -out: - return ret; + return ret; } diff --git a/libglusterfs/src/globals.h b/libglusterfs/src/globals.h deleted file mode 100644 index bdd9e891046..00000000000 --- a/libglusterfs/src/globals.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - Copyright (c) 2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _GLOBALS_H -#define _GLOBALS_H - -/* This corresponds to the max 16 number of group IDs that are sent through an - * RPC request. Since NFS is the only one going to set this, we can be safe - * in keeping this size hardcoded. - */ -#define GF_REQUEST_MAXGROUPS 16 - -#include "glusterfs.h" - -/* CTX */ -#define CTX (glusterfs_ctx_get()) - -glusterfs_ctx_t *glusterfs_ctx_get (); - -#include "xlator.h" - -/* THIS */ -#define THIS (*__glusterfs_this_location()) - -xlator_t **__glusterfs_this_location (); -xlator_t *glusterfs_this_get (); -int glusterfs_this_set (xlator_t *); - -/* central log */ - -void glusterfs_central_log_flag_set (); -long glusterfs_central_log_flag_get (); -void glusterfs_central_log_flag_unset (); - -/* task */ -void *synctask_get (); -int synctask_set (void *); - -/* init */ -int glusterfs_globals_init (void); - -#endif /* !_GLOBALS_H */ diff --git a/libglusterfs/src/glusterfs.h b/libglusterfs/src/glusterfs.h deleted file mode 100644 index 1d0369c4d61..00000000000 --- a/libglusterfs/src/glusterfs.h +++ /dev/null @@ -1,313 +0,0 @@ -/* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _GLUSTERFS_H -#define _GLUSTERFS_H - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <netinet/in.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/statvfs.h> -#include <netdb.h> -#include <errno.h> -#include <dirent.h> -#include <unistd.h> -#include <fcntl.h> -#include <arpa/inet.h> -#include <sys/poll.h> -#include <pthread.h> - -#include "list.h" -#include "logging.h" - - -#define GF_YES 1 -#define GF_NO 0 - -#ifndef O_LARGEFILE -/* savannah bug #20053, patch for compiling on darwin */ -#define O_LARGEFILE 0 -#endif - -#ifndef O_DIRECT -/* savannah bug #20050, #20052 */ -#define O_DIRECT 0 /* From asm/fcntl.h */ -#endif - -#ifndef O_DIRECTORY -/* FreeBSD does not need O_DIRECTORY */ -#define O_DIRECTORY 0 -#endif - -#define GF_XATTR_PATHINFO_KEY "trusted.glusterfs.pathinfo" -#define GF_XATTR_LINKINFO_KEY "trusted.distribute.linkinfo" - -#define ZR_FILE_CONTENT_STR "glusterfs.file." -#define ZR_FILE_CONTENT_STRLEN 15 - -#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 ZR_FILE_CONTENT_REQUEST(key) (!strncmp(key, ZR_FILE_CONTENT_STR, \ - ZR_FILE_CONTENT_STRLEN)) - -/* TODO: Should we use PATH-MAX? On some systems it may save space */ -#define ZR_PATH_MAX 4096 - -/* NOTE: add members ONLY at the end (just before _MAXVALUE) */ -typedef enum { - GF_FOP_NULL = 0, - GF_FOP_STAT, - GF_FOP_READLINK, - GF_FOP_MKNOD, - GF_FOP_MKDIR, - GF_FOP_UNLINK, - GF_FOP_RMDIR, - GF_FOP_SYMLINK, - GF_FOP_RENAME, - GF_FOP_LINK, - GF_FOP_TRUNCATE, - GF_FOP_OPEN, - GF_FOP_READ, - GF_FOP_WRITE, - GF_FOP_STATFS, - GF_FOP_FLUSH, - GF_FOP_FSYNC, /* 15 */ - GF_FOP_SETXATTR, - GF_FOP_GETXATTR, - GF_FOP_REMOVEXATTR, - GF_FOP_OPENDIR, - GF_FOP_FSYNCDIR, - GF_FOP_ACCESS, - GF_FOP_CREATE, - GF_FOP_FTRUNCATE, - GF_FOP_FSTAT, /* 25 */ - GF_FOP_LK, - GF_FOP_LOOKUP, - GF_FOP_READDIR, - GF_FOP_INODELK, - GF_FOP_FINODELK, - GF_FOP_ENTRYLK, - GF_FOP_FENTRYLK, - GF_FOP_XATTROP, - GF_FOP_FXATTROP, - GF_FOP_FGETXATTR, - GF_FOP_FSETXATTR, - GF_FOP_RCHECKSUM, - GF_FOP_SETATTR, - GF_FOP_FSETATTR, - GF_FOP_READDIRP, - GF_FOP_FORGET, - GF_FOP_RELEASE, - GF_FOP_RELEASEDIR, - GF_FOP_GETSPEC, - GF_FOP_MAXVALUE, -} glusterfs_fop_t; - - -typedef enum { - GF_MGMT_NULL = 0, - GF_MGMT_MAXVALUE, -} glusterfs_mgmt_t; - -typedef enum { - GF_OP_TYPE_NULL = 0, - GF_OP_TYPE_FOP, - GF_OP_TYPE_MGMT, - GF_OP_TYPE_MAX, -} gf_op_type_t; - - -/* NOTE: all the miscellaneous flags used by GlusterFS should be listed here */ -typedef enum { - GF_LK_GETLK = 0, - GF_LK_SETLK, - GF_LK_SETLKW, -} glusterfs_lk_cmds_t; - - -typedef enum { - GF_LK_F_RDLCK = 0, - GF_LK_F_WRLCK, - GF_LK_F_UNLCK -} glusterfs_lk_types_t; - - -typedef enum { - GF_LOCK_POSIX, - GF_LOCK_INTERNAL -} gf_lk_domain_t; - - -typedef enum { - ENTRYLK_LOCK, - ENTRYLK_UNLOCK, - ENTRYLK_LOCK_NB -} entrylk_cmd; - - -typedef enum { - ENTRYLK_RDLCK, - ENTRYLK_WRLCK -} entrylk_type; - - -typedef enum { - GF_XATTROP_ADD_ARRAY, -} gf_xattrop_flags_t; - - -#define GF_SET_IF_NOT_PRESENT 0x1 /* default behaviour */ -#define GF_SET_OVERWRITE 0x2 /* Overwrite with the buf given */ -#define GF_SET_DIR_ONLY 0x4 -#define GF_SET_EPOCH_TIME 0x8 /* used by afr dir lookup selfheal */ - -/* Directory into which replicate self-heal will move deleted files and - directories into. The storage/posix janitor thread will periodically - clean up this directory */ - -#define GF_REPLICATE_TRASH_DIR ".landfill" - -/* key value which quick read uses to get small files in lookup cbk */ -#define GF_CONTENT_KEY "glusterfs.content" - -struct _xlator_cmdline_option { - struct list_head cmd_args; - char *volume; - char *key; - char *value; -}; -typedef struct _xlator_cmdline_option xlator_cmdline_option_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; - int32_t max_connect_attempts; - /* advanced options */ - uint32_t volfile_server_port; - char *volfile_server_transport; - uint32_t log_server_port; - char *pid_file; - int no_daemon_mode; - char *run_id; - int debug_mode; - int read_only; - int mac_compat; - struct list_head xlator_options; /* list of xlator_option_t */ - - /* fuse options */ - int fuse_direct_io_mode; - int volfile_check; - double fuse_entry_timeout; - double fuse_attribute_timeout; - char *volume_name; - int fuse_nodev; - int fuse_nosuid; - char *dump_fuse; - - /* key args */ - char *mount_point; - char *volfile_id; - - /* required for portmap */ - int brick_port; - char *brick_name; -}; -typedef struct _cmd_args cmd_args_t; - - -struct _glusterfs_graph { - struct list_head list; - char graph_uuid[128]; - struct timeval dob; - void *first; - void *top; /* selected by -n */ - int xl_count; - uint32_t volfile_checksum; -}; -typedef struct _glusterfs_graph glusterfs_graph_t; - - -struct _glusterfs_ctx { - cmd_args_t cmd_args; - char *process_uuid; - FILE *pidfp; - char fin; - void *timer; - void *ib; - void *pool; - void *event_pool; - void *iobuf_pool; - 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 */ - void *master; /* fuse, or libglusterfsclient (however, not protocol/server) */ - void *mgmt; /* xlator implementing MOPs for centralized logging, volfile server */ - unsigned char measure_latency; /* toggle switch for latency measurement */ - pthread_t sigwaiter; - struct mem_pool *stub_mem_pool; - -}; -typedef struct _glusterfs_ctx glusterfs_ctx_t; - - -typedef enum { - GF_EVENT_PARENT_UP = 1, - GF_EVENT_POLLIN, - GF_EVENT_POLLOUT, - GF_EVENT_POLLERR, - GF_EVENT_CHILD_UP, - GF_EVENT_CHILD_DOWN, - GF_EVENT_CHILD_CONNECTING, - GF_EVENT_TRANSPORT_CLEANUP, - GF_EVENT_TRANSPORT_CONNECTED, - GF_EVENT_VOLFILE_MODIFIED, - GF_EVENT_GRAPH_NEW, -} glusterfs_event_t; - - -#define GF_MUST_CHECK __attribute__((warn_unused_result)) - -int glusterfs_graph_prepare (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx); -int glusterfs_graph_destroy (glusterfs_graph_t *graph); -int glusterfs_graph_activate (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx); -glusterfs_graph_t *glusterfs_graph_construct (FILE *fp); -glusterfs_graph_t *glusterfs_graph_new (); -#endif /* _GLUSTERFS_H */ diff --git a/libglusterfs/src/glusterfs/async.h b/libglusterfs/src/glusterfs/async.h new file mode 100644 index 00000000000..d1d70ae0bc7 --- /dev/null +++ b/libglusterfs/src/glusterfs/async.h @@ -0,0 +1,209 @@ +/* + Copyright (c) 2019 Red Hat, Inc <https://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_ASYNC_H__ +#define __GLUSTERFS_ASYNC_H__ + +#define _LGPL_SOURCE + +#include <sys/types.h> +#include <signal.h> +#include <errno.h> + +#ifdef URCU_OLD + +/* TODO: Fix the include paths. Since this is a .h included from many places + * it makes no sense to append a '-I$(CONTRIBDIR)/userspace-rcu/' to each + * Makefile.am. I've also seen some problems with CI builders (they + * failed to find the include files, but the same source on another setup + * is working fine). */ +#include "wfcqueue.h" +#include "wfstack.h" + +#else /* !URCU_OLD */ + +#include <urcu/wfcqueue.h> +#include <urcu/wfstack.h> + +#endif /* URCU_OLD */ + +#include "glusterfs/xlator.h" +#include "glusterfs/common-utils.h" +#include "glusterfs/list.h" +#include "glusterfs/libglusterfs-messages.h" + +/* This is the name prefix that all worker threads will have. A number will + * be added to differentiate them. */ +#define GF_ASYNC_THREAD_NAME "tpw" + +/* This value determines the maximum number of threads that are allowed. */ +#define GF_ASYNC_MAX_THREADS 128 + +/* This value determines how many additional threads will be started but will + * remain inactive until they are explicitly activated by the leader. This is + * useful to react faster to bursts of load, but at the same time we minimize + * contention if they are not really needed to handle current load. + * + * TODO: Instead of a fixed number, it would probably be better to use a + * prcentage of the available cores. */ +#define GF_ASYNC_SPARE_THREADS 2 + +/* This value determines the signal used to wake the leader when new work has + * been added to the queue. To do so we reuse SIGALRM, since the most logical + * candidates (SIGUSR1/SIGUSR2) are already used. This signal must not be used + * by anything else in the process. */ +#define GF_ASYNC_SIGQUEUE SIGALRM + +/* This value determines the signal that will be used to transfer leader role + * to other workers. */ +#define GF_ASYNC_SIGCTRL SIGVTALRM + +#define gf_async_warning(_err, _msg, _args...) \ + gf_msg("async", GF_LOG_WARNING, -(_err), LG_MSG_ASYNC_WARNING, _msg, \ + ##_args) + +#define gf_async_error(_err, _msg, _args...) \ + gf_msg("async", GF_LOG_ERROR, -(_err), LG_MSG_ASYNC_FAILURE, _msg, ##_args) + +#define gf_async_fatal(_err, _msg, _args...) \ + do { \ + GF_ABORT("Critical error in async module. Unable to continue. (" _msg \ + "). Error %d.", \ + ##_args, -(_err)); \ + } while (0) + +struct _gf_async; +typedef struct _gf_async gf_async_t; + +struct _gf_async_worker; +typedef struct _gf_async_worker gf_async_worker_t; + +struct _gf_async_queue; +typedef struct _gf_async_queue gf_async_queue_t; + +struct _gf_async_control; +typedef struct _gf_async_control gf_async_control_t; + +typedef void (*gf_async_callback_f)(xlator_t *xl, gf_async_t *async); + +struct _gf_async { + /* TODO: remove dependency on xl/THIS. */ + xlator_t *xl; + gf_async_callback_f cbk; + struct cds_wfcq_node queue; +}; + +struct _gf_async_worker { + /* Used to send asynchronous jobs related to the worker. */ + gf_async_t async; + + /* Member of the available workers stack. */ + struct cds_wfs_node stack; + + /* Thread object of the current worker. */ + pthread_t thread; + + /* Unique identifier of this worker. */ + int32_t id; + + /* Indicates if this worker is enabled. */ + bool running; +}; + +struct _gf_async_queue { + /* Structures needed to manage a wait-free queue. For better performance + * they are placed in two different cache lines, as recommended by URCU + * documentation, even though in our case some threads will be producers + * and consumers at the same time. */ + struct cds_wfcq_head head __attribute__((aligned(64))); + struct cds_wfcq_tail tail __attribute__((aligned(64))); +}; + +#define GF_ASYNC_COUNTS(_run, _stop) (((uint32_t)(_run) << 16) + (_stop)) +#define GF_ASYNC_COUNT_RUNNING(_count) ((_count) >> 16) +#define GF_ASYNC_COUNT_STOPPING(_count) ((_count)&65535) + +struct _gf_async_control { + gf_async_queue_t queue; + + /* Stack of unused workers. */ + struct __cds_wfs_stack available; + + /* Array of preallocated worker structures. */ + gf_async_worker_t *table; + + /* Used to synchronize main thread with workers on termination. */ + pthread_barrier_t sync; + + /* The id of the last thread that will be used for synchronization. */ + pthread_t sync_thread; + + /* Signal mask to wait for control signals from leader. */ + sigset_t sigmask_ctrl; + + /* Signal mask to wait for queued items. */ + sigset_t sigmask_queue; + + /* Saved signal handlers. */ + struct sigaction handler_ctrl; + struct sigaction handler_queue; + + /* PID of the current process. */ + pid_t pid; + + /* Maximum number of allowed threads. */ + uint32_t max_threads; + + /* Current number of running and stopping workers. This value is split + * into 2 16-bits fields to track both counters atomically at the same + * time. */ + uint32_t counts; + + /* It's used to control whether the asynchronous infrastructure is used + * or not. */ + bool enabled; +}; + +extern gf_async_control_t gf_async_ctrl; + +int32_t +gf_async_init(glusterfs_ctx_t *ctx); + +void +gf_async_fini(void); + +void +gf_async_adjust_threads(int32_t threads); + +static inline void +gf_async(gf_async_t *async, xlator_t *xl, gf_async_callback_f cbk) +{ + if (!gf_async_ctrl.enabled) { + cbk(xl, async); + return; + } + + async->xl = xl; + async->cbk = cbk; + cds_wfcq_node_init(&async->queue); + if (caa_unlikely(!cds_wfcq_enqueue(&gf_async_ctrl.queue.head, + &gf_async_ctrl.queue.tail, + &async->queue))) { + /* The queue was empty, so the leader could be sleeping. We need to + * wake it so that the new item can be processed. If the queue was not + * empty, we don't need to do anything special since the leader will + * take care of it. */ + if (caa_unlikely(kill(gf_async_ctrl.pid, GF_ASYNC_SIGQUEUE) < 0)) { + gf_async_fatal(errno, "Unable to wake leader worker."); + }; + } +} + +#endif /* !__GLUSTERFS_ASYNC_H__ */ diff --git a/libglusterfs/src/glusterfs/atomic.h b/libglusterfs/src/glusterfs/atomic.h new file mode 100644 index 00000000000..ced81748218 --- /dev/null +++ b/libglusterfs/src/glusterfs/atomic.h @@ -0,0 +1,459 @@ +/* + Copyright (c) 2017 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 _ATOMIC_H +#define _ATOMIC_H + +#include <inttypes.h> +#include <stdbool.h> + +#include "glusterfs/locking.h" + +/* Macros used to join two arguments and generate a new macro name. */ +#define GF_ATOMIC_MACRO_1(_macro) _macro +#define GF_ATOMIC_MACRO(_base, _name) GF_ATOMIC_MACRO_1(_base##_name) + +/* There's a problem on 32-bit architectures when we try to use atomic + * builtins with 64-bit types. Only way to solve the problem is to use + * a mutex to protect the access to the atomic, but we don't want to + * use mutexes for other smaller types that could work with the atomic + * builtins. + * + * So on each atomic type we add a field for the mutex if atomic operation + * is not supported and a dummy zero size field if it's supported. This way + * we can have different atomic types, some with a mutex and some without. + * + * To define these types, we use two macros: + * + * GF_ATOMIC_MUTEX_FIELD_0 = char lk[0] + * GF_ATOMIC_MUTEX_FILED_1 = gf_lock_t lk + * + * Both macros define the 'lk' field that will be used in the atomic + * structure. One when the atomic is supported by the architecture and + * another when not. We need to define the field even if it won't be + * used. Otherwise the compiler will return an error. + * + * Now we need to take the mutex or not depending on the existence of + * the mutex field in the structure. To do so we check the size of the + * structure, and if it's bigger than uint64_t (all structures with a + * mutex will be bigger), we use the mutex-based version. Otherwise we + * use the atomic builtin. This check is easily optimized out by the + * compiler, leaving a clean and efficient compiled code. */ + +#define GF_ATOMIC_MUTEX_FIELD_0 char lk[0] +#define GF_ATOMIC_MUTEX_FIELD_1 gf_lock_t lk + +/* We'll use SIZEOF_LONG to determine the architecture. 32-bit machines + * will have 4 here, while 64-bit machines will have 8. If additional + * needs or restrictions appear on other platforms, these tests can be + * extended to handle them. */ + +/* GF_ATOMIC_SIZE_X macros map each type size to one of the + * GF_ATOMIC_MUTEX_FIELD_X macros, depending on detected conditions. */ + +#if defined(HAVE_ATOMIC_BUILTINS) || defined(HAVE_SYNC_BUILTINS) + +#define GF_ATOMIC_SIZE_1 GF_ATOMIC_MUTEX_FIELD_0 +#define GF_ATOMIC_SIZE_2 GF_ATOMIC_MUTEX_FIELD_0 +#define GF_ATOMIC_SIZE_4 GF_ATOMIC_MUTEX_FIELD_0 + +#if SIZEOF_LONG >= 8 +#define GF_ATOMIC_SIZE_8 GF_ATOMIC_MUTEX_FIELD_0 +#endif + +#endif /* HAVE_(ATOMIC|SYNC)_BUILTINS */ + +/* Any GF_ATOMIC_SIZE_X macro not yet defined will use the mutex version */ +#ifndef GF_ATOMIC_SIZE_1 +#define GF_ATOMIC_SIZE_1 GF_ATOMIC_MUTEX_FIELD_1 +#endif + +#ifndef GF_ATOMIC_SIZE_2 +#define GF_ATOMIC_SIZE_2 GF_ATOMIC_MUTEX_FIELD_1 +#endif + +#ifndef GF_ATOMIC_SIZE_4 +#define GF_ATOMIC_SIZE_4 GF_ATOMIC_MUTEX_FIELD_1 +#endif + +#ifndef GF_ATOMIC_SIZE_8 +#define GF_ATOMIC_SIZE_8 GF_ATOMIC_MUTEX_FIELD_1 +#endif + +/* This macro is used to define all atomic types supported. First field + * represents the size of the type in bytes, and the second one the name. */ +#define GF_ATOMIC_TYPE(_size, _name) \ + typedef struct _gf_atomic_##_name##_t { \ + GF_ATOMIC_MACRO(GF_ATOMIC_SIZE_, _size); \ + _name##_t value; \ + } gf_atomic_##_name##_t + +/* The atomic types we support */ +GF_ATOMIC_TYPE(1, int8); /* gf_atomic_int8_t */ +GF_ATOMIC_TYPE(2, int16); /* gf_atomic_int16_t */ +GF_ATOMIC_TYPE(4, int32); /* gf_atomic_int32_t */ +GF_ATOMIC_TYPE(8, int64); /* gf_atomic_int64_t */ +GF_ATOMIC_TYPE(SIZEOF_LONG, intptr); /* gf_atomic_intptr_t */ +GF_ATOMIC_TYPE(1, uint8); /* gf_atomic_uint8_t */ +GF_ATOMIC_TYPE(2, uint16); /* gf_atomic_uint16_t */ +GF_ATOMIC_TYPE(4, uint32); /* gf_atomic_uint32_t */ +GF_ATOMIC_TYPE(8, uint64); /* gf_atomic_uint64_t */ +GF_ATOMIC_TYPE(SIZEOF_LONG, uintptr); /* gf_atomic_uintptr_t */ + +/* Define the default atomic type as int64_t */ +#define gf_atomic_t gf_atomic_int64_t + +/* This macro will choose between the mutex based version and the atomic + * builtin version depending on the size of the atomic structure. */ +#define GF_ATOMIC_CHOOSE(_atomic, _op, _args...) \ + ((sizeof(_atomic) > sizeof(uint64_t)) \ + ? ({ \ + GF_ATOMIC_MACRO(GF_ATOMIC_LOCK_, _op) \ + (_atomic, ##_args); \ + }) \ + : ({ \ + GF_ATOMIC_MACRO(GF_ATOMIC_BASE_, _op) \ + (_atomic, ##_args); \ + })) + +/* Macros to implement the mutex-based atomics. */ +#define GF_ATOMIC_OP_PREPARE(_atomic, _name) \ + typeof(_atomic) *__atomic = &(_atomic); \ + gf_lock_t *__lock = (gf_lock_t *)&__atomic->lk; \ + LOCK(__lock); \ + typeof(__atomic->value) _name = __atomic->value + +#define GF_ATOMIC_OP_STORE(_value) (__atomic->value = (_value)) + +#define GF_ATOMIC_OP_RETURN(_value) \ + ({ \ + UNLOCK(__lock); \ + _value; \ + }) + +#define GF_ATOMIC_LOCK_INIT(_atomic, _value) \ + do { \ + typeof(_atomic) *__atomic = &(_atomic); \ + LOCK_INIT((gf_lock_t *)&__atomic->lk); \ + __atomic->value = (_value); \ + } while (0) + +#define GF_ATOMIC_LOCK_GET(_atomic) \ + ({ \ + GF_ATOMIC_OP_PREPARE(_atomic, __value); \ + GF_ATOMIC_OP_RETURN(__value); \ + }) + +#define GF_ATOMIC_LOCK_ADD(_atomic, _value) \ + ({ \ + GF_ATOMIC_OP_PREPARE(_atomic, __value); \ + GF_ATOMIC_OP_STORE(__value += (_value)); \ + GF_ATOMIC_OP_RETURN(__value); \ + }) + +#define GF_ATOMIC_LOCK_SUB(_atomic, _value) \ + ({ \ + GF_ATOMIC_OP_PREPARE(_atomic, __value); \ + GF_ATOMIC_OP_STORE(__value -= (_value)); \ + GF_ATOMIC_OP_RETURN(__value); \ + }) + +#define GF_ATOMIC_LOCK_AND(_atomic, _value) \ + ({ \ + GF_ATOMIC_OP_PREPARE(_atomic, __value); \ + GF_ATOMIC_OP_STORE(__value &= (_value)); \ + GF_ATOMIC_OP_RETURN(__value); \ + }) + +#define GF_ATOMIC_LOCK_OR(_atomic, _value) \ + ({ \ + GF_ATOMIC_OP_PREPARE(_atomic, __value); \ + GF_ATOMIC_OP_STORE(__value |= (_value)); \ + GF_ATOMIC_OP_RETURN(__value); \ + }) + +#define GF_ATOMIC_LOCK_XOR(_atomic, _value) \ + ({ \ + GF_ATOMIC_OP_PREPARE(_atomic, __value); \ + GF_ATOMIC_OP_STORE(__value ^= (_value)); \ + GF_ATOMIC_OP_RETURN(__value); \ + }) + +#define GF_ATOMIC_LOCK_NAND(_atomic, _value) \ + ({ \ + GF_ATOMIC_OP_PREPARE(_atomic, __value); \ + GF_ATOMIC_OP_STORE(__value = ~(__value & (_value))); \ + GF_ATOMIC_OP_RETURN(__value); \ + }) + +#define GF_ATOMIC_LOCK_FETCH_ADD(_atomic, _value) \ + ({ \ + GF_ATOMIC_OP_PREPARE(_atomic, __value); \ + GF_ATOMIC_OP_STORE(__value + (_value)); \ + GF_ATOMIC_OP_RETURN(__value); \ + }) + +#define GF_ATOMIC_LOCK_FETCH_SUB(_atomic, _value) \ + ({ \ + GF_ATOMIC_OP_PREPARE(_atomic, __value); \ + GF_ATOMIC_OP_STORE(__value - (_value)); \ + GF_ATOMIC_OP_RETURN(__value); \ + }) + +#define GF_ATOMIC_LOCK_FETCH_AND(_atomic, _value) \ + ({ \ + GF_ATOMIC_OP_PREPARE(_atomic, __value); \ + GF_ATOMIC_OP_STORE(__value &(_value)); \ + GF_ATOMIC_OP_RETURN(__value); \ + }) + +#define GF_ATOMIC_LOCK_FETCH_OR(_atomic, _value) \ + ({ \ + GF_ATOMIC_OP_PREPARE(_atomic, __value); \ + GF_ATOMIC_OP_STORE(__value | (_value)); \ + GF_ATOMIC_OP_RETURN(__value); \ + }) + +#define GF_ATOMIC_LOCK_FETCH_XOR(_atomic, _value) \ + ({ \ + GF_ATOMIC_OP_PREPARE(_atomic, __value); \ + GF_ATOMIC_OP_STORE(__value ^ (_value)); \ + GF_ATOMIC_OP_RETURN(__value); \ + }) + +#define GF_ATOMIC_LOCK_FETCH_NAND(_atomic, _value) \ + ({ \ + GF_ATOMIC_OP_PREPARE(_atomic, __value); \ + GF_ATOMIC_OP_STORE(~(__value & (_value))); \ + GF_ATOMIC_OP_RETURN(__value); \ + }) + +#define GF_ATOMIC_LOCK_SWAP(_atomic, _value) \ + ({ \ + GF_ATOMIC_OP_PREPARE(_atomic, __value); \ + GF_ATOMIC_OP_STORE(_value); \ + GF_ATOMIC_OP_RETURN(__value); \ + }) + +#define GF_ATOMIC_LOCK_CMP_SWAP(_atomic, _expected, _value) \ + ({ \ + GF_ATOMIC_OP_PREPARE(_atomic, __value); \ + bool __ret = (__value == (_expected)); \ + if (__ret) { \ + GF_ATOMIC_OP_STORE(_value); \ + } \ + GF_ATOMIC_OP_RETURN(__ret); \ + }) + +#if defined(HAVE_ATOMIC_BUILTINS) + +/* If compiler supports __atomic builtins, we use them. */ + +#define GF_ATOMIC_BASE_INIT(_atomic, _value) \ + __atomic_store_n(&(_atomic).value, (_value), __ATOMIC_RELEASE) + +#define GF_ATOMIC_BASE_GET(_atomic) \ + __atomic_load_n(&(_atomic).value, __ATOMIC_ACQUIRE) + +#define GF_ATOMIC_BASE_ADD(_atomic, _value) \ + __atomic_add_fetch(&(_atomic).value, (_value), __ATOMIC_ACQ_REL) + +#define GF_ATOMIC_BASE_SUB(_atomic, _value) \ + __atomic_sub_fetch(&(_atomic).value, (_value), __ATOMIC_ACQ_REL) + +#define GF_ATOMIC_BASE_AND(_atomic, _value) \ + __atomic_and_fetch(&(_atomic).value, (_value), __ATOMIC_ACQ_REL) + +#define GF_ATOMIC_BASE_OR(_atomic, _value) \ + __atomic_or_fetch(&(_atomic).value, (_value), __ATOMIC_ACQ_REL) + +#define GF_ATOMIC_BASE_XOR(_atomic, _value) \ + __atomic_xor_fetch(&(_atomic).value, (_value), __ATOMIC_ACQ_REL) + +#define GF_ATOMIC_BASE_NAND(_atomic, _value) \ + __atomic_nand_fetch(&(_atomic).value, (_value), __ATOMIC_ACQ_REL) + +#define GF_ATOMIC_BASE_FETCH_ADD(_atomic, _value) \ + __atomic_fetch_add(&(_atomic).value, (_value), __ATOMIC_ACQ_REL) + +#define GF_ATOMIC_BASE_FETCH_SUB(_atomic, _value) \ + __atomic_fetch_sub(&(_atomic).value, (_value), __ATOMIC_ACQ_REL) + +#define GF_ATOMIC_BASE_FETCH_AND(_atomic, _value) \ + __atomic_fetch_and(&(_atomic).value, (_value), __ATOMIC_ACQ_REL) + +#define GF_ATOMIC_BASE_FETCH_OR(_atomic, _value) \ + __atomic_fetch_or(&(_atomic).value, (_value), __ATOMIC_ACQ_REL) + +#define GF_ATOMIC_BASE_FETCH_XOR(_atomic, _value) \ + __atomic_fetch_xor(&(_atomic).value, (_value), __ATOMIC_ACQ_REL) + +#define GF_ATOMIC_BASE_FETCH_NAND(_atomic, _value) \ + __atomic_fetch_nand(&(_atomic).value, (_value), __ATOMIC_ACQ_REL) + +#define GF_ATOMIC_BASE_SWAP(_atomic, _value) \ + __atomic_exchange_n(&(_atomic).value, (_value), __ATOMIC_ACQ_REL) + +#define GF_ATOMIC_BASE_CMP_SWAP(_atomic, _expected, _value) \ + ({ \ + typeof((_atomic).value) __expected = (_expected); \ + __atomic_compare_exchange_n(&(_atomic).value, &__expected, (_value), \ + 0, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE); \ + }) + +#elif defined(HAVE_SYNC_BUILTINS) + +/* If compiler doesn't support __atomic builtins but supports __sync builtins, + * we use them. */ + +#define GF_ATOMIC_BASE_INIT(_atomic, _value) \ + do { \ + (_atomic).value = (_value); \ + __sync_synchronize(); \ + } while (0) + +#define GF_ATOMIC_BASE_ADD(_atomic, _value) \ + __sync_add_and_fetch(&(_atomic).value, (_value)) + +#define GF_ATOMIC_BASE_SUB(_atomic, _value) \ + __sync_sub_and_fetch(&(_atomic).value, (_value)) + +#define GF_ATOMIC_BASE_AND(_atomic, _value) \ + __sync_and_and_fetch(&(_atomic).value, (_value)) + +#define GF_ATOMIC_BASE_OR(_atomic, _value) \ + __sync_or_and_fetch(&(_atomic).value, (_value)) + +#define GF_ATOMIC_BASE_XOR(_atomic, _value) \ + __sync_xor_and_fetch(&(_atomic).value, (_value)) + +#define GF_ATOMIC_BASE_NAND(_atomic, _value) \ + __sync_nand_and_fetch(&(_atomic).value, (_value)) + +#define GF_ATOMIC_BASE_FETCH_ADD(_atomic, _value) \ + __sync_fetch_and_add(&(_atomic).value, (_value)) + +#define GF_ATOMIC_BASE_FETCH_SUB(_atomic, _value) \ + __sync_fetch_and_sub(&(_atomic).value, (_value)) + +#define GF_ATOMIC_BASE_FETCH_AND(_atomic, _value) \ + __sync_fetch_and_and(&(_atomic).value, (_value)) + +#define GF_ATOMIC_BASE_FETCH_OR(_atomic, _value) \ + __sync_fetch_and_or(&(_atomic).value, (_value)) + +#define GF_ATOMIC_BASE_FETCH_XOR(_atomic, _value) \ + __sync_fetch_and_xor(&(_atomic).value, (_value)) + +#define GF_ATOMIC_BASE_FETCH_NAND(_atomic, _value) \ + __sync_fetch_and_nand(&(_atomic).value, (_value)) + +#define GF_ATOMIC_BASE_SWAP(_atomic, _value) \ + ({ \ + __sync_synchronize(); \ + __sync_lock_test_and_set(&(_atomic).value, (_value)); \ + }) + +#define GF_ATOMIC_BASE_CMP_SWAP(_atomic, _expected, _value) \ + __sync_bool_compare_and_swap(&(_atomic).value, (_expected), (_value)) + +#define GF_ATOMIC_BASE_GET(_atomic) GF_ATOMIC_BASE_ADD(_atomic, 0) + +#else /* !HAVE_ATOMIC_BUILTINS && !HAVE_SYNC_BUILTINS */ + +/* The compiler doesn't support any atomic builtin. We fallback to the + * mutex-based implementation. */ + +#define GF_ATOMIC_BASE_INIT(_atomic, _value) \ + GF_ATOMIC_LOCK_INIT(_atomic, _value) + +#define GF_ATOMIC_BASE_GET(_atomic) GF_ATOMIC_LOCK_GET(_atomic) + +#define GF_ATOMIC_BASE_ADD(_atomic, _value) GF_ATOMIC_LOCK_ADD(_atomic, _value) + +#define GF_ATOMIC_BASE_SUB(_atomic, _value) GF_ATOMIC_LOCK_SUB(_atomic, _value) + +#define GF_ATOMIC_BASE_AND(_atomic, _value) GF_ATOMIC_LOCK_AND(_atomic, _value) + +#define GF_ATOMIC_BASE_OR(_atomic, _value) GF_ATOMIC_LOCK_OR(_atomic, _value) + +#define GF_ATOMIC_BASE_XOR(_atomic, _value) GF_ATOMIC_LOCK_XOR(_atomic, _value) + +#define GF_ATOMIC_BASE_NAND(_atomic, _value) \ + GF_ATOMIC_LOCK_NAND(_atomic, _value) + +#define GF_ATOMIC_BASE_FETCH_ADD(_atomic, _value) \ + GF_ATOMIC_LOCK_FETCH_ADD(_atomic, _value) + +#define GF_ATOMIC_BASE_FETCH_SUB(_atomic, _value) \ + GF_ATOMIC_LOCK_FETCH_SUB(_atomic, _value) + +#define GF_ATOMIC_BASE_FETCH_AND(_atomic, _value) \ + GF_ATOMIC_LOCK_FETCH_AND(_atomic, _value) + +#define GF_ATOMIC_BASE_FETCH_OR(_atomic, _value) \ + GF_ATOMIC_LOCK_FETCH_OR(_atomic, _value) + +#define GF_ATOMIC_BASE_FETCH_XOR(_atomic, _value) \ + GF_ATOMIC_LOCK_FETCH_XOR(_atomic, _value) + +#define GF_ATOMIC_BASE_FETCH_NAND(_atomic, _value) \ + GF_ATOMIC_LOCK_FETCH_NAND(_atomic, _value) + +#define GF_ATOMIC_BASE_SWAP(_atomic, _value) \ + GF_ATOMIC_LOCK_SWAP(_atomic, _value) + +#define GF_ATOMIC_BASE_CMP_SWAP(_atomic, _expected, _value) \ + GF_ATOMIC_LOCK_CMP_SWAP(_atomic, _expected, _value) + +#endif /* HAVE_(ATOMIC|SYNC)_BUILTINS */ + +/* Here we declare the real atomic macros available to the user. */ + +/* All macros have a 'gf_atomic_xxx' as 1st argument */ + +#define GF_ATOMIC_INIT(_atomic, _value) GF_ATOMIC_CHOOSE(_atomic, INIT, _value) +#define GF_ATOMIC_GET(_atomic) GF_ATOMIC_CHOOSE(_atomic, GET) +#define GF_ATOMIC_ADD(_atomic, _value) GF_ATOMIC_CHOOSE(_atomic, ADD, _value) +#define GF_ATOMIC_SUB(_atomic, _value) GF_ATOMIC_CHOOSE(_atomic, SUB, _value) +#define GF_ATOMIC_AND(_atomic, _value) GF_ATOMIC_CHOOSE(_atomic, AND, _value) +#define GF_ATOMIC_OR(_atomic, _value) GF_ATOMIC_CHOOSE(_atomic, OR, _value) +#define GF_ATOMIC_XOR(_atomic, _value) GF_ATOMIC_CHOOSE(_atomic, XOR, _value) +#define GF_ATOMIC_NAND(_atomic, _value) GF_ATOMIC_CHOOSE(_atomic, NAND, _value) + +#define GF_ATOMIC_FETCH_ADD(_atomic, _value) \ + GF_ATOMIC_CHOOSE(_atomic, FETCH_ADD, _value) + +#define GF_ATOMIC_FETCH_SUB(_atomic, _value) \ + GF_ATOMIC_CHOOSE(_atomic, FETCH_SUB, _value) + +#define GF_ATOMIC_FETCH_AND(_atomic, _value) \ + GF_ATOMIC_CHOOSE(_atomic, FETCH_AND, _value) + +#define GF_ATOMIC_FETCH_OR(_atomic, _value) \ + GF_ATOMIC_CHOOSE(_atomic, FETCH_OR, _value) + +#define GF_ATOMIC_FETCH_XOR(_atomic, _value) \ + GF_ATOMIC_CHOOSE(_atomic, FETCH_XOR, _value) + +#define GF_ATOMIC_FETCH_NAND(_atomic, _value) \ + GF_ATOMIC_CHOOSE(_atomic, FETCH_NAND, _value) + +#define GF_ATOMIC_SWAP(_atomic, _value) GF_ATOMIC_CHOOSE(_atomic, SWAP, _value) + +#define GF_ATOMIC_CMP_SWAP(_atomic, _expected, _value) \ + GF_ATOMIC_CHOOSE(_atomic, CMP_SWAP, _expected, _value) + +#define GF_ATOMIC_INC(_atomic) GF_ATOMIC_ADD(_atomic, 1) +#define GF_ATOMIC_DEC(_atomic) GF_ATOMIC_SUB(_atomic, 1) +#define GF_ATOMIC_FETCH_INC(_atomic) GF_ATOMIC_FETCH_ADD(_atomic, 1) +#define GF_ATOMIC_FETCH_DEC(_atomic) GF_ATOMIC_FETCH_SUB(_atomic, 1) + +#endif /* _ATOMIC_H */ diff --git a/libglusterfs/src/glusterfs/byte-order.h b/libglusterfs/src/glusterfs/byte-order.h new file mode 100644 index 00000000000..fd8cef9e58d --- /dev/null +++ b/libglusterfs/src/glusterfs/byte-order.h @@ -0,0 +1,279 @@ +/* + 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 _BYTE_ORDER_H +#define _BYTE_ORDER_H + +#include <inttypes.h> + +#define LS1 0x00ffU +#define MS1 0xff00U +#define LS2 0x0000ffffU +#define MS2 0xffff0000U +#define LS4 0x00000000ffffffffULL +#define MS4 0xffffffff00000000ULL + +static uint16_t (*hton16)(uint16_t); +static uint32_t (*hton32)(uint32_t); +static uint64_t (*hton64)(uint64_t); + +#define ntoh16 hton16 +#define ntoh32 hton32 +#define ntoh64 hton64 + +static uint16_t (*htole16)(uint16_t); +static uint32_t (*htole32)(uint32_t); +static uint64_t (*htole64)(uint64_t); + +#define letoh16 htole16 +#define letoh32 htole32 +#define letoh64 htole64 + +static uint16_t (*htobe16)(uint16_t); +static uint32_t (*htobe32)(uint32_t); +static uint64_t (*htobe64)(uint64_t); + +#define betoh16 htobe16 +#define betoh32 htobe32 +#define betoh64 htobe64 + +#define do_swap2(x) (((x & LS1) << 8) | (((x & MS1) >> 8))) +#define do_swap4(x) ((do_swap2(x & LS2) << 16) | (do_swap2((x & MS2) >> 16))) +#define do_swap8(x) ((do_swap4(x & LS4) << 32) | (do_swap4((x & MS4) >> 32))) + +static inline uint16_t +__swap16(uint16_t x) +{ + return do_swap2(x); +} + +static inline uint32_t +__swap32(uint32_t x) +{ + return do_swap4(x); +} + +static inline uint64_t +__swap64(uint64_t x) +{ + return do_swap8(x); +} + +static inline uint16_t +__noswap16(uint16_t x) +{ + return x; +} + +static inline uint32_t +__noswap32(uint32_t x) +{ + return x; +} + +static inline uint64_t +__noswap64(uint64_t x) +{ + return x; +} + +static inline uint16_t +__byte_order_n16(uint16_t i) +{ + uint32_t num = 1; + + if (((char *)(&num))[0] == 1) { + /* cpu is le */ + hton16 = __swap16; + hton32 = __swap32; + hton64 = __swap64; + } else { + /* cpu is be */ + hton16 = __noswap16; + hton32 = __noswap32; + hton64 = __noswap64; + } + + return hton16(i); +} + +static inline uint32_t +__byte_order_n32(uint32_t i) +{ + uint32_t num = 1; + + if (((char *)(&num))[0] == 1) { + /* cpu is le */ + hton16 = __swap16; + hton32 = __swap32; + hton64 = __swap64; + } else { + /* cpu is be */ + hton16 = __noswap16; + hton32 = __noswap32; + hton64 = __noswap64; + } + + return hton32(i); +} + +static inline uint64_t +__byte_order_n64(uint64_t i) +{ + uint32_t num = 1; + + if (((char *)(&num))[0] == 1) { + /* cpu is le */ + hton16 = __swap16; + hton32 = __swap32; + hton64 = __swap64; + } else { + /* cpu is be */ + hton16 = __noswap16; + hton32 = __noswap32; + hton64 = __noswap64; + } + + return hton64(i); +} + +static uint16_t (*hton16)(uint16_t) = __byte_order_n16; +static uint32_t (*hton32)(uint32_t) = __byte_order_n32; +static uint64_t (*hton64)(uint64_t) = __byte_order_n64; + +static inline uint16_t +__byte_order_le16(uint16_t i) +{ + uint32_t num = 1; + + if (((char *)(&num))[0] == 1) { + /* cpu is le */ + htole16 = __noswap16; + htole32 = __noswap32; + htole64 = __noswap64; + } else { + /* cpu is be */ + htole16 = __swap16; + htole32 = __swap32; + htole64 = __swap64; + } + + return htole16(i); +} + +static inline uint32_t +__byte_order_le32(uint32_t i) +{ + uint32_t num = 1; + + if (((char *)(&num))[0] == 1) { + /* cpu is le */ + htole16 = __noswap16; + htole32 = __noswap32; + htole64 = __noswap64; + } else { + /* cpu is be */ + htole16 = __swap16; + htole32 = __swap32; + htole64 = __swap64; + } + + return htole32(i); +} + +static inline uint64_t +__byte_order_le64(uint64_t i) +{ + uint32_t num = 1; + + if (((char *)(&num))[0] == 1) { + /* cpu is le */ + htole16 = __noswap16; + htole32 = __noswap32; + htole64 = __noswap64; + } else { + /* cpu is be */ + htole16 = __swap16; + htole32 = __swap32; + htole64 = __swap64; + } + + return htole64(i); +} + +static uint16_t (*htole16)(uint16_t) = __byte_order_le16; +static uint32_t (*htole32)(uint32_t) = __byte_order_le32; +static uint64_t (*htole64)(uint64_t) = __byte_order_le64; + +static inline uint16_t +__byte_order_be16(uint16_t i) +{ + uint32_t num = 1; + + if (((char *)(&num))[0] == 1) { + /* cpu is le */ + htobe16 = __swap16; + htobe32 = __swap32; + htobe64 = __swap64; + } else { + /* cpu is be */ + htobe16 = __noswap16; + htobe32 = __noswap32; + htobe64 = __noswap64; + } + + return htobe16(i); +} + +static inline uint32_t +__byte_order_be32(uint32_t i) +{ + uint32_t num = 1; + + if (((char *)(&num))[0] == 1) { + /* cpu is le */ + htobe16 = __swap16; + htobe32 = __swap32; + htobe64 = __swap64; + } else { + /* cpu is be */ + htobe16 = __noswap16; + htobe32 = __noswap32; + htobe64 = __noswap64; + } + + return htobe32(i); +} + +static inline uint64_t +__byte_order_be64(uint64_t i) +{ + uint32_t num = 1; + + if (((char *)(&num))[0] == 1) { + /* cpu is le */ + htobe16 = __swap16; + htobe32 = __swap32; + htobe64 = __swap64; + } else { + /* cpu is be */ + htobe16 = __noswap16; + htobe32 = __noswap32; + htobe64 = __noswap64; + } + + return htobe64(i); +} + +static uint16_t (*htobe16)(uint16_t) = __byte_order_be16; +static uint32_t (*htobe32)(uint32_t) = __byte_order_be32; +static uint64_t (*htobe64)(uint64_t) = __byte_order_be64; + +#endif /* _BYTE_ORDER_H */ diff --git a/libglusterfs/src/glusterfs/call-stub.h b/libglusterfs/src/glusterfs/call-stub.h new file mode 100644 index 00000000000..8237ea459bf --- /dev/null +++ b/libglusterfs/src/glusterfs/call-stub.h @@ -0,0 +1,622 @@ +/* + 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 _CALL_STUB_H_ +#define _CALL_STUB_H_ + +#include "glusterfs/xlator.h" +#include "glusterfs/defaults.h" +#include "glusterfs/default-args.h" +#include "glusterfs/stack.h" +#include "glusterfs/list.h" + +typedef struct _call_stub { + struct list_head list; + call_frame_t *frame; + struct mem_pool *stub_mem_pool; /* pointer to stub mempool in ctx_t */ + uint32_t jnl_meta_len; + uint32_t jnl_data_len; + void (*serialize)(struct _call_stub *, char *, char *); + union { + fop_lookup_t lookup; + fop_stat_t stat; + fop_fstat_t fstat; + fop_truncate_t truncate; + fop_ftruncate_t ftruncate; + fop_access_t access; + fop_readlink_t readlink; + fop_mknod_t mknod; + fop_mkdir_t mkdir; + fop_unlink_t unlink; + fop_rmdir_t rmdir; + fop_symlink_t symlink; + fop_rename_t rename; + fop_link_t link; + fop_create_t create; + fop_open_t open; + fop_readv_t readv; + fop_writev_t writev; + fop_flush_t flush; + fop_fsync_t fsync; + fop_opendir_t opendir; + fop_fsyncdir_t fsyncdir; + fop_statfs_t statfs; + fop_setxattr_t setxattr; + fop_getxattr_t getxattr; + fop_fgetxattr_t fgetxattr; + fop_fsetxattr_t fsetxattr; + fop_removexattr_t removexattr; + fop_fremovexattr_t fremovexattr; + fop_lk_t lk; + fop_inodelk_t inodelk; + fop_finodelk_t finodelk; + fop_entrylk_t entrylk; + fop_fentrylk_t fentrylk; + fop_readdir_t readdir; + fop_readdirp_t readdirp; + fop_rchecksum_t rchecksum; + fop_xattrop_t xattrop; + fop_fxattrop_t fxattrop; + fop_setattr_t setattr; + fop_fsetattr_t fsetattr; + fop_fallocate_t fallocate; + fop_discard_t discard; + fop_zerofill_t zerofill; + fop_ipc_t ipc; + fop_seek_t seek; + fop_lease_t lease; + fop_getactivelk_t getactivelk; + fop_setactivelk_t setactivelk; + fop_put_t put; + fop_icreate_t icreate; + fop_namelink_t namelink; + fop_copy_file_range_t copy_file_range; + } fn; + + union { + fop_lookup_cbk_t lookup; + fop_stat_cbk_t stat; + fop_fstat_cbk_t fstat; + fop_truncate_cbk_t truncate; + fop_ftruncate_cbk_t ftruncate; + fop_access_cbk_t access; + fop_readlink_cbk_t readlink; + fop_mknod_cbk_t mknod; + fop_mkdir_cbk_t mkdir; + fop_unlink_cbk_t unlink; + fop_rmdir_cbk_t rmdir; + fop_symlink_cbk_t symlink; + fop_rename_cbk_t rename; + fop_link_cbk_t link; + fop_create_cbk_t create; + fop_open_cbk_t open; + fop_readv_cbk_t readv; + fop_writev_cbk_t writev; + fop_flush_cbk_t flush; + fop_fsync_cbk_t fsync; + fop_opendir_cbk_t opendir; + fop_fsyncdir_cbk_t fsyncdir; + fop_statfs_cbk_t statfs; + fop_setxattr_cbk_t setxattr; + fop_getxattr_cbk_t getxattr; + fop_fgetxattr_cbk_t fgetxattr; + fop_fsetxattr_cbk_t fsetxattr; + fop_removexattr_cbk_t removexattr; + fop_fremovexattr_cbk_t fremovexattr; + fop_lk_cbk_t lk; + fop_inodelk_cbk_t inodelk; + fop_finodelk_cbk_t finodelk; + fop_entrylk_cbk_t entrylk; + fop_fentrylk_cbk_t fentrylk; + fop_readdir_cbk_t readdir; + fop_readdirp_cbk_t readdirp; + fop_rchecksum_cbk_t rchecksum; + fop_xattrop_cbk_t xattrop; + 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; + fop_ipc_cbk_t ipc; + fop_seek_cbk_t seek; + fop_lease_cbk_t lease; + fop_getactivelk_cbk_t getactivelk; + fop_setactivelk_cbk_t setactivelk; + fop_put_cbk_t put; + fop_icreate_cbk_t icreate; + fop_namelink_cbk_t namelink; + fop_copy_file_range_cbk_t copy_file_range; + } fn_cbk; + glusterfs_fop_t fop; + gf_boolean_t poison; + char wind; + default_args_t args; + default_args_cbk_t args_cbk; +} call_stub_t; + +call_stub_t * +fop_lookup_stub(call_frame_t *frame, fop_lookup_t fn, loc_t *loc, + dict_t *xdata); + +call_stub_t * +fop_lookup_cbk_stub(call_frame_t *frame, fop_lookup_cbk_t fn, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + dict_t *xdata, struct iatt *postparent); +call_stub_t * +fop_stat_stub(call_frame_t *frame, fop_stat_t fn, loc_t *loc, dict_t *xdata); +call_stub_t * +fop_stat_cbk_stub(call_frame_t *frame, fop_stat_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct iatt *buf, dict_t *xdata); +call_stub_t * +fop_fstat_stub(call_frame_t *frame, fop_fstat_t fn, fd_t *fd, dict_t *xdata); +call_stub_t * +fop_fstat_cbk_stub(call_frame_t *frame, fop_fstat_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct iatt *buf, dict_t *xdata); + +call_stub_t * +fop_truncate_stub(call_frame_t *frame, fop_truncate_t fn, loc_t *loc, off_t off, + dict_t *xdata); + +call_stub_t * +fop_truncate_cbk_stub(call_frame_t *frame, fop_truncate_cbk_t fn, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata); + +call_stub_t * +fop_ftruncate_stub(call_frame_t *frame, fop_ftruncate_t fn, fd_t *fd, off_t off, + dict_t *xdata); + +call_stub_t * +fop_ftruncate_cbk_stub(call_frame_t *frame, fop_ftruncate_cbk_t fn, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata); + +call_stub_t * +fop_access_stub(call_frame_t *frame, fop_access_t fn, loc_t *loc, int32_t mask, + dict_t *xdata); + +call_stub_t * +fop_access_cbk_stub(call_frame_t *frame, fop_access_cbk_t fn, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +call_stub_t * +fop_readlink_stub(call_frame_t *frame, fop_readlink_t fn, loc_t *loc, + size_t size, dict_t *xdata); + +call_stub_t * +fop_readlink_cbk_stub(call_frame_t *frame, fop_readlink_cbk_t fn, + int32_t op_ret, int32_t op_errno, const char *path, + struct iatt *buf, dict_t *xdata); + +call_stub_t * +fop_mknod_stub(call_frame_t *frame, fop_mknod_t fn, loc_t *loc, mode_t mode, + dev_t rdev, mode_t umask, dict_t *xdata); + +call_stub_t * +fop_mknod_cbk_stub(call_frame_t *frame, fop_mknod_cbk_t fn, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + struct iatt *preparent, struct iatt *postparent, + dict_t *xdata); + +call_stub_t * +fop_mkdir_stub(call_frame_t *frame, fop_mkdir_t fn, loc_t *loc, mode_t mode, + mode_t umask, dict_t *xdata); + +call_stub_t * +fop_mkdir_cbk_stub(call_frame_t *frame, fop_mkdir_cbk_t fn, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + struct iatt *preparent, struct iatt *postparent, + dict_t *xdata); + +call_stub_t * +fop_unlink_stub(call_frame_t *frame, fop_unlink_t fn, loc_t *loc, int xflag, + dict_t *xdata); + +call_stub_t * +fop_unlink_cbk_stub(call_frame_t *frame, fop_unlink_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +call_stub_t * +fop_rmdir_stub(call_frame_t *frame, fop_rmdir_t fn, loc_t *loc, int flags, + dict_t *xdata); + +call_stub_t * +fop_rmdir_cbk_stub(call_frame_t *frame, fop_rmdir_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +call_stub_t * +fop_symlink_stub(call_frame_t *frame, fop_symlink_t fn, const char *linkname, + loc_t *loc, mode_t umask, dict_t *xdata); + +call_stub_t * +fop_symlink_cbk_stub(call_frame_t *frame, fop_symlink_cbk_t fn, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + struct iatt *preparent, struct iatt *postparent, + dict_t *xdata); + +call_stub_t * +fop_rename_stub(call_frame_t *frame, fop_rename_t fn, loc_t *oldloc, + loc_t *newloc, dict_t *xdata); + +call_stub_t * +fop_rename_cbk_stub(call_frame_t *frame, fop_rename_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct iatt *buf, + struct iatt *preoldparent, struct iatt *postoldparent, + struct iatt *prenewparent, struct iatt *postnewparent, + dict_t *xdata); + +call_stub_t * +fop_link_stub(call_frame_t *frame, fop_link_t fn, loc_t *oldloc, loc_t *newloc, + dict_t *xdata); + +call_stub_t * +fop_link_cbk_stub(call_frame_t *frame, fop_link_cbk_t fn, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + struct iatt *preparent, struct iatt *postparent, + dict_t *xdata); + +call_stub_t * +fop_create_stub(call_frame_t *frame, fop_create_t fn, loc_t *loc, int32_t flags, + mode_t mode, mode_t umask, fd_t *fd, dict_t *xdata); + +call_stub_t * +fop_create_cbk_stub(call_frame_t *frame, fop_create_cbk_t fn, int32_t op_ret, + int32_t op_errno, fd_t *fd, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +call_stub_t * +fop_open_stub(call_frame_t *frame, fop_open_t fn, loc_t *loc, int32_t flags, + fd_t *fd, dict_t *xdata); + +call_stub_t * +fop_open_cbk_stub(call_frame_t *frame, fop_open_cbk_t fn, int32_t op_ret, + int32_t op_errno, fd_t *fd, dict_t *xdata); + +call_stub_t * +fop_readv_stub(call_frame_t *frame, fop_readv_t fn, fd_t *fd, size_t size, + off_t off, uint32_t flags, dict_t *xdata); + +call_stub_t * +fop_readv_cbk_stub(call_frame_t *frame, fop_readv_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct iovec *vector, int32_t count, + struct iatt *stbuf, struct iobref *iobref, dict_t *xdata); + +call_stub_t * +fop_writev_stub(call_frame_t *frame, fop_writev_t fn, fd_t *fd, + struct iovec *vector, int32_t count, off_t off, uint32_t flags, + struct iobref *iobref, dict_t *xdata); + +call_stub_t * +fop_writev_cbk_stub(call_frame_t *frame, fop_writev_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct iatt *prebuf, struct iatt *postbuf, + dict_t *xdata); + +call_stub_t * +fop_flush_stub(call_frame_t *frame, fop_flush_t fn, fd_t *fd, dict_t *xdata); + +call_stub_t * +fop_flush_cbk_stub(call_frame_t *frame, fop_flush_cbk_t fn, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +call_stub_t * +fop_fsync_stub(call_frame_t *frame, fop_fsync_t fn, fd_t *fd, int32_t datasync, + dict_t *xdata); + +call_stub_t * +fop_fsync_cbk_stub(call_frame_t *frame, fop_fsync_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct iatt *prebuf, struct iatt *postbuf, + dict_t *xdata); + +call_stub_t * +fop_opendir_stub(call_frame_t *frame, fop_opendir_t fn, loc_t *loc, fd_t *fd, + dict_t *xdata); + +call_stub_t * +fop_opendir_cbk_stub(call_frame_t *frame, fop_opendir_cbk_t fn, int32_t op_ret, + int32_t op_errno, fd_t *fd, dict_t *xdata); + +call_stub_t * +fop_fsyncdir_stub(call_frame_t *frame, fop_fsyncdir_t fn, fd_t *fd, + int32_t datasync, dict_t *xdata); + +call_stub_t * +fop_fsyncdir_cbk_stub(call_frame_t *frame, fop_fsyncdir_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +call_stub_t * +fop_statfs_stub(call_frame_t *frame, fop_statfs_t fn, loc_t *loc, + dict_t *xdata); + +call_stub_t * +fop_statfs_cbk_stub(call_frame_t *frame, fop_statfs_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct statvfs *buf, dict_t *xdata); + +call_stub_t * +fop_setxattr_stub(call_frame_t *frame, fop_setxattr_t fn, loc_t *loc, + dict_t *dict, int32_t flags, dict_t *xdata); + +call_stub_t * +fop_setxattr_cbk_stub(call_frame_t *frame, fop_setxattr_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +call_stub_t * +fop_getxattr_stub(call_frame_t *frame, fop_getxattr_t fn, loc_t *loc, + const char *name, dict_t *xdata); + +call_stub_t * +fop_getxattr_cbk_stub(call_frame_t *frame, fop_getxattr_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *value, + dict_t *xdata); + +call_stub_t * +fop_fsetxattr_stub(call_frame_t *frame, fop_fsetxattr_t fn, fd_t *fd, + dict_t *dict, int32_t flags, dict_t *xdata); + +call_stub_t * +fop_fsetxattr_cbk_stub(call_frame_t *frame, fop_fsetxattr_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +call_stub_t * +fop_fgetxattr_stub(call_frame_t *frame, fop_fgetxattr_t fn, fd_t *fd, + const char *name, dict_t *xdata); + +call_stub_t * +fop_fgetxattr_cbk_stub(call_frame_t *frame, fop_fgetxattr_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *value, + dict_t *xdata); + +call_stub_t * +fop_removexattr_stub(call_frame_t *frame, fop_removexattr_t fn, loc_t *loc, + const char *name, dict_t *xdata); + +call_stub_t * +fop_removexattr_cbk_stub(call_frame_t *frame, fop_removexattr_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +call_stub_t * +fop_fremovexattr_stub(call_frame_t *frame, fop_fremovexattr_t fn, fd_t *fd, + const char *name, dict_t *xdata); + +call_stub_t * +fop_fremovexattr_cbk_stub(call_frame_t *frame, fop_fremovexattr_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +call_stub_t * +fop_lk_stub(call_frame_t *frame, fop_lk_t fn, fd_t *fd, int32_t cmd, + struct gf_flock *lock, dict_t *xdata); + +call_stub_t * +fop_lk_cbk_stub(call_frame_t *frame, fop_lk_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct gf_flock *lock, dict_t *xdata); + +call_stub_t * +fop_inodelk_stub(call_frame_t *frame, fop_inodelk_t fn, const char *volume, + loc_t *loc, int32_t cmd, struct gf_flock *lock, dict_t *xdata); + +call_stub_t * +fop_finodelk_stub(call_frame_t *frame, fop_finodelk_t fn, const char *volume, + fd_t *fd, int32_t cmd, struct gf_flock *lock, dict_t *xdata); + +call_stub_t * +fop_entrylk_stub(call_frame_t *frame, fop_entrylk_t fn, const char *volume, + loc_t *loc, const char *basename, entrylk_cmd cmd, + entrylk_type type, dict_t *xdata); + +call_stub_t * +fop_fentrylk_stub(call_frame_t *frame, fop_fentrylk_t fn, const char *volume, + fd_t *fd, const char *basename, entrylk_cmd cmd, + entrylk_type type, dict_t *xdata); + +call_stub_t * +fop_inodelk_cbk_stub(call_frame_t *frame, fop_inodelk_cbk_t fn, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +call_stub_t * +fop_finodelk_cbk_stub(call_frame_t *frame, fop_inodelk_cbk_t fn, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +call_stub_t * +fop_entrylk_cbk_stub(call_frame_t *frame, fop_entrylk_cbk_t fn, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +call_stub_t * +fop_fentrylk_cbk_stub(call_frame_t *frame, fop_entrylk_cbk_t fn, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +call_stub_t * +fop_readdir_stub(call_frame_t *frame, fop_readdir_t fn, fd_t *fd, size_t size, + off_t off, dict_t *xdata); + +call_stub_t * +fop_readdirp_stub(call_frame_t *frame, fop_readdirp_t fn, fd_t *fd, size_t size, + off_t off, dict_t *xdata); + +call_stub_t * +fop_readdirp_cbk_stub(call_frame_t *frame, fop_readdir_cbk_t fn, int32_t op_ret, + int32_t op_errno, gf_dirent_t *entries, dict_t *xdata); + +call_stub_t * +fop_readdir_cbk_stub(call_frame_t *frame, fop_readdir_cbk_t fn, int32_t op_ret, + int32_t op_errno, gf_dirent_t *entries, dict_t *xdata); + +call_stub_t * +fop_rchecksum_stub(call_frame_t *frame, fop_rchecksum_t fn, fd_t *fd, + off_t offset, int32_t len, dict_t *xdata); + +call_stub_t * +fop_rchecksum_cbk_stub(call_frame_t *frame, fop_rchecksum_cbk_t fn, + int32_t op_ret, int32_t op_errno, uint32_t weak_checksum, + uint8_t *strong_checksum, dict_t *xdata); + +call_stub_t * +fop_xattrop_stub(call_frame_t *frame, fop_xattrop_t fn, loc_t *loc, + gf_xattrop_flags_t optype, dict_t *xattr, dict_t *xdata); + +call_stub_t * +fop_xattrop_stub_cbk_stub(call_frame_t *frame, fop_xattrop_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +call_stub_t * +fop_fxattrop_stub(call_frame_t *frame, fop_fxattrop_t fn, fd_t *fd, + gf_xattrop_flags_t optype, dict_t *xattr, dict_t *xdata); + +call_stub_t * +fop_fxattrop_stub_cbk_stub(call_frame_t *frame, fop_xattrop_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +call_stub_t * +fop_setattr_stub(call_frame_t *frame, fop_setattr_t fn, loc_t *loc, + struct iatt *stbuf, int32_t valid, dict_t *xdata); + +call_stub_t * +fop_setattr_cbk_stub(call_frame_t *frame, fop_setattr_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct iatt *statpre, + struct iatt *statpost, dict_t *xdata); + +call_stub_t * +fop_fsetattr_stub(call_frame_t *frame, fop_fsetattr_t fn, fd_t *fd, + struct iatt *stbuf, int32_t valid, dict_t *xdata); + +call_stub_t * +fop_fsetattr_cbk_stub(call_frame_t *frame, fop_setattr_cbk_t fn, int32_t op_ret, + int32_t op_errno, 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, off_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); + +call_stub_t * +fop_ipc_stub(call_frame_t *frame, fop_ipc_t fn, int32_t op, dict_t *xdata); + +call_stub_t * +fop_ipc_cbk_stub(call_frame_t *frame, fop_ipc_cbk_t fn, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +call_stub_t * +fop_seek_stub(call_frame_t *frame, fop_seek_t fn, fd_t *fd, off_t offset, + gf_seek_what_t what, dict_t *xdata); + +call_stub_t * +fop_seek_cbk_stub(call_frame_t *frame, fop_seek_cbk_t fn, int32_t op_ret, + int32_t op_errno, off_t offset, dict_t *xdata); + +call_stub_t * +fop_lease_stub(call_frame_t *frame, fop_lease_t fn, loc_t *loc, + struct gf_lease *lease, dict_t *xdata); + +call_stub_t * +fop_lease_cbk_stub(call_frame_t *frame, fop_lease_cbk_t fn, int32_t op_ret, + int32_t op_errno, struct gf_lease *lease, dict_t *xdata); + +call_stub_t * +fop_getactivelk_stub(call_frame_t *frame, fop_getactivelk_t fn, loc_t *loc, + dict_t *xdata); + +call_stub_t * +fop_getactivelk_cbk_stub(call_frame_t *frame, fop_getactivelk_cbk_t fn, + int32_t op_ret, int32_t op_errno, + lock_migration_info_t *lmi, dict_t *xdata); + +call_stub_t * +fop_setactivelk_stub(call_frame_t *frame, fop_setactivelk_t fn, loc_t *loc, + lock_migration_info_t *locklist, dict_t *xdata); + +call_stub_t * +fop_setactivelk_cbk_stub(call_frame_t *frame, fop_setactivelk_cbk_t fn, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +call_stub_t * +fop_put_stub(call_frame_t *frame, fop_put_t fn, loc_t *loc, mode_t mode, + mode_t umask, uint32_t flags, struct iovec *vector, int32_t count, + off_t offset, struct iobref *iobref, dict_t *xattr, dict_t *xdata); + +call_stub_t * +fop_put_cbk_stub(call_frame_t *frame, fop_put_cbk_t fn, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + struct iatt *preparent, struct iatt *postparent, + dict_t *xdata); + +call_stub_t * +fop_icreate_stub(call_frame_t *frame, fop_icreate_t fn, loc_t *loc, mode_t mode, + dict_t *xdata); + +call_stub_t * +fop_namelink_stub(call_frame_t *frame, fop_namelink_t fn, loc_t *loc, + dict_t *xdata); + +call_stub_t * +fop_icreate_cbk_stub(call_frame_t *frame, fop_icreate_cbk_t fn, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + dict_t *xdata); + +call_stub_t * +fop_namelink_cbk_stub(call_frame_t *frame, fop_namelink_cbk_t fn, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata); + +call_stub_t * +fop_copy_file_range_stub(call_frame_t *frame, fop_copy_file_range_t fn, + fd_t *fd_in, off64_t off_in, fd_t *fd_out, + off64_t off_out, size_t len, uint32_t flags, + dict_t *xdata); + +call_stub_t * +fop_copy_file_range_cbk_stub(call_frame_t *frame, fop_copy_file_range_cbk_t fn, + int32_t op_ret, int32_t op_errno, + struct iatt *stbuf, struct iatt *prebuf_dst, + struct iatt *postbuf_dst, dict_t *xdata); + +void +call_resume(call_stub_t *stub); +void +call_resume_keep_stub(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); +void +call_unwind_error_keep_stub(call_stub_t *stub, int op_ret, int op_errno); + +/* + * Sometimes we might want to call just this, perhaps repeatedly, without + * having (or being able) to destroy and recreate it. + */ +void +call_resume_wind(call_stub_t *stub); + +#endif diff --git a/libglusterfs/src/glusterfs/checksum.h b/libglusterfs/src/glusterfs/checksum.h new file mode 100644 index 00000000000..019bb14df71 --- /dev/null +++ b/libglusterfs/src/glusterfs/checksum.h @@ -0,0 +1,22 @@ +/* + 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 __CHECKSUM_H__ +#define __CHECKSUM_H__ + +uint32_t +gf_rsync_weak_checksum(unsigned char *buf, size_t len); + +void +gf_rsync_strong_checksum(unsigned char *buf, size_t len, unsigned char *sum); + +void +gf_rsync_md5_checksum(unsigned char *data, size_t len, unsigned char *md5); +#endif /* __CHECKSUM_H__ */ diff --git a/libglusterfs/src/glusterfs/circ-buff.h b/libglusterfs/src/glusterfs/circ-buff.h new file mode 100644 index 00000000000..822345b641b --- /dev/null +++ b/libglusterfs/src/glusterfs/circ-buff.h @@ -0,0 +1,61 @@ +/* + 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 _CB_H +#define _CB_H + +#include "glusterfs/common-utils.h" + +#define BUFFER_SIZE 10 +#define TOTAL_SIZE BUFFER_SIZE + 1 + +struct _circular_buffer { + struct timeval tv; + void *data; +}; + +typedef struct _circular_buffer circular_buffer_t; + +struct _buffer { + unsigned int w_index; + size_t size_buffer; + gf_boolean_t use_once; + /* This variable is assigned the proper value at the time of initing */ + /* the buffer. It indicates, whether the buffer should be used once */ + /* it becomes full. */ + + int used_len; + /* indicates the amount of circular buffer used. */ + + circular_buffer_t **cb; + void (*destroy_buffer_data)(void *data); + pthread_mutex_t lock; +}; + +typedef struct _buffer buffer_t; + +int +cb_add_entry_buffer(buffer_t *buffer, void *item); + +void +cb_buffer_show(buffer_t *buffer); + +buffer_t * +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); + +void +cb_buffer_dump(buffer_t *buffer, void *data, + int(fn)(circular_buffer_t *buffer, void *data)); + +#endif /* _CB_H */ diff --git a/libglusterfs/src/glusterfs/client_t.h b/libglusterfs/src/glusterfs/client_t.h new file mode 100644 index 00000000000..a2c508e1d5c --- /dev/null +++ b/libglusterfs/src/glusterfs/client_t.h @@ -0,0 +1,147 @@ +/* + 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 + +#include "glusterfs/glusterfs.h" +#include "glusterfs/locking.h" /* for gf_lock_t, not included by glusterfs.h */ +#include "glusterfs/atomic.h" /* for gf_atomic_t */ + +/* auth_data structure is required by RPC layer. But as it is also used in + * client_t structure validation, comparision, it is critical that it is defined + * in the larger scope of libglusterfs, instead of libgfrpc. With this change, + * even RPC will use this structure */ +#define GF_CLIENTT_AUTH_BYTES 400 +typedef struct client_auth_data { + int flavour; + int datalen; + char authdata[GF_CLIENTT_AUTH_BYTES]; +} client_auth_data_t; + +struct client_ctx { + void *ctx_key; + void *ctx_value; +}; + +typedef struct _client { + struct { + /* e.g. protocol/server stashes its ctx here */ + gf_lock_t lock; + unsigned short count; + struct client_ctx *ctx; + } scratch_ctx; + gf_atomic_t bind; + gf_atomic_t count; + xlator_t *bound_xl; + xlator_t *this; + int tbl_index; + char *client_uid; + char *client_name; + struct { + int flavour; + size_t len; + char *data; + char *username; + char *passwd; + } auth; + + /* subdir_mount */ + char *subdir_mount; + inode_t *subdir_inode; + uuid_t subdir_gfid; + int32_t opversion; + /* Variable to save fd_count for detach brick */ + gf_atomic_t fd_cnt; +} 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; + client_t *local; +}; +typedef struct clienttable clienttable_t; + +#define GF_CLIENTTABLE_INITIAL_SIZE 128 + +/* 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 + +void +gf_client_put(client_t *client, gf_boolean_t *detached); + +clienttable_t * +gf_clienttable_alloc(void); + +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); + +void * +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); + +client_t * +gf_client_get(xlator_t *this, client_auth_data_t *cred, char *client_uid, + char *subdir_mount); + +#endif /* _CLIENT_T_H */ diff --git a/libglusterfs/src/glusterfs/cluster-syncop.h b/libglusterfs/src/glusterfs/cluster-syncop.h new file mode 100644 index 00000000000..d0ad5ed548c --- /dev/null +++ b/libglusterfs/src/glusterfs/cluster-syncop.h @@ -0,0 +1,227 @@ +/* + Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _CLUSTER_SYNCOP_H +#define _CLUSTER_SYNCOP_H + +#include <sys/time.h> +#include <pthread.h> +#include <ucontext.h> + +#include "glusterfs/defaults.h" +#include "glusterfs/default-args.h" +#include "glusterfs/syncop.h" + +/********************************************************************* + * + * PARALLEL_FOP_ONLIST: + * Performs file operations in parallel on bricks. + * This macro expects a helper function(func) to implement the + * functionality. + * + ********************************************************************/ +#define PARALLEL_FOP_ONLIST(subvols, on, numsubvols, replies, frame, func, \ + args...) \ + do { \ + int __i = 0; \ + int __count = 0; \ + cluster_local_t __local = { \ + 0, \ + }; \ + void *__old_local = frame->local; \ + \ + __local.replies = replies; \ + cluster_replies_wipe(replies, numsubvols); \ + for (__i = 0; __i < numsubvols; __i++) \ + INIT_LIST_HEAD(&replies[__i].entries.list); \ + if (syncbarrier_init(&__local.barrier)) \ + break; \ + frame->local = &__local; \ + for (__i = 0; __i < numsubvols; __i++) { \ + if (on[__i]) { \ + __count++; \ + } \ + } \ + __local.barrier.waitfor = __count; \ + for (__i = 0; __i < numsubvols; __i++) { \ + if (on[__i]) { \ + func(frame, subvols[__i], __i, ##args); \ + } \ + } \ + syncbarrier_wait(&__local.barrier, __count); \ + syncbarrier_destroy(&__local.barrier); \ + frame->local = __old_local; \ + STACK_RESET(frame->root); \ + } while (0) + +typedef struct cluster_local_ { + default_args_cbk_t *replies; + syncbarrier_t barrier; +} cluster_local_t; + +int32_t +cluster_lookup(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata); +int32_t +cluster_setattr(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, + struct iatt *stbuf, int32_t valid, dict_t *xdata); +int32_t +cluster_getxattr(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, + const char *name, dict_t *xdata); +int32_t +cluster_setxattr(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, + int32_t flags, dict_t *xdata); + +int +cluster_inodelk(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *locked_on, + call_frame_t *frame, xlator_t *this, char *dom, inode_t *inode, + off_t off, size_t size); + +int +cluster_uninodelk(xlator_t **subvols, unsigned char *locked_on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, char *dom, + inode_t *inode, off_t off, size_t size); + +int +cluster_entrylk(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *locked_on, + call_frame_t *frame, xlator_t *this, char *dom, inode_t *inode, + const char *name); + +int32_t +cluster_rmdir(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, int flags, + dict_t *xdata); + +int32_t +cluster_unlink(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag, + dict_t *xdata); + +int +cluster_mkdir(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, + mode_t umask, dict_t *xdata); + +int32_t +cluster_readlink(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, size_t size, + dict_t *xdata); + +int +cluster_symlink(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, const char *linkpath, + loc_t *loc, mode_t umask, dict_t *xdata); + +int32_t +cluster_link(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, + dict_t *xdata); + +int +cluster_mknod(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, + dev_t rdev, mode_t umask, dict_t *xdata); + +int +cluster_unentrylk(xlator_t **subvols, unsigned char *locked_on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, char *dom, + inode_t *inode, const char *name); + +int +cluster_tryentrylk(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *locked_on, + call_frame_t *frame, xlator_t *this, char *dom, + inode_t *inode, const char *name); + +int32_t +cluster_fxattrop(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, + gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata); + +int32_t +cluster_xattrop(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, + gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata); + +int32_t +cluster_fstat(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *xdata); + +int32_t +cluster_ftruncate(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, + dict_t *xdata); + +int32_t +cluster_open(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + fd_t *fd, dict_t *xdata); + +int +cluster_tryinodelk(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *locked_on, + call_frame_t *frame, xlator_t *this, char *dom, + inode_t *inode, off_t off, size_t size); + +int32_t +cluster_fsetattr(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, fd_t *fd, + struct iatt *stbuf, int32_t valid, dict_t *xdata); + +int32_t +cluster_put(xlator_t **subvols, unsigned char *on, int numsubvols, + default_args_cbk_t *replies, unsigned char *output, + call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, + mode_t umask, uint32_t flags, struct iovec *vector, int32_t count, + off_t offset, struct iobref *iobref, dict_t *xattr, dict_t *xdata); + +void +cluster_replies_wipe(default_args_cbk_t *replies, int num_subvols); + +int32_t +cluster_fop_success_fill(default_args_cbk_t *replies, int numsubvols, + unsigned char *success); + +int32_t +cluster_xattrop_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata); + +int +cluster_tiebreaker_inodelk(xlator_t **subvols, unsigned char *on, + int numsubvols, default_args_cbk_t *replies, + unsigned char *locked_on, call_frame_t *frame, + xlator_t *this, char *dom, inode_t *inode, off_t off, + size_t size); +#endif /* !_CLUSTER_SYNCOP_H */ diff --git a/libglusterfs/src/glusterfs/common-utils.h b/libglusterfs/src/glusterfs/common-utils.h new file mode 100644 index 00000000000..f297fdab5c9 --- /dev/null +++ b/libglusterfs/src/glusterfs/common-utils.h @@ -0,0 +1,1256 @@ +/* + 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 _COMMON_UTILS_H +#define _COMMON_UTILS_H + +#include <stdint.h> +#include <sys/uio.h> +#include <netdb.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <pthread.h> +#include <unistd.h> +#include <openssl/md5.h> +#ifndef GF_BSD_HOST_OS +#include <alloca.h> +#endif +#include <limits.h> +#include <fnmatch.h> +#include <uuid/uuid.h> + +/* FreeBSD, etc. */ +#ifndef __BITS_PER_LONG +#define __BITS_PER_LONG (CHAR_BIT * (sizeof(long))) +#endif + +#ifndef ffsll +#define ffsll(x) __builtin_ffsll(x) +#endif + +void +trap(void); + +#define GF_UNIVERSAL_ANSWER 42 /* :O */ + +/* To solve type punned error */ +#define VOID(ptr) ((void **)((void *)ptr)) + +#include "glusterfs/mem-pool.h" +#include "glusterfs/compat-uuid.h" +#include "glusterfs/iatt.h" +#include "glusterfs/libglusterfs-messages.h" + +#define STRINGIFY(val) #val +#define TOSTRING(val) STRINGIFY(val) + +#define alloca0(size) \ + ({ \ + void *__ptr; \ + __ptr = alloca(size); \ + memset(__ptr, 0, size); \ + __ptr; \ + }) + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define gf_roof(a, b) ((((a) + (b)-1) / ((b != 0) ? (b) : 1)) * (b)) +#define gf_floor(a, b) (((a) / ((b != 0) ? (b) : 1)) * (b)) + +#define IPv4_ADDR_SIZE 32 + +#define GF_UNIT_KB 1024ULL +#define GF_UNIT_MB 1048576ULL +#define GF_UNIT_GB 1073741824ULL +#define GF_UNIT_TB 1099511627776ULL +#define GF_UNIT_PB 1125899906842624ULL + +#define GF_UNIT_B_STRING "B" +#define GF_UNIT_KB_STRING "KB" +#define GF_UNIT_MB_STRING "MB" +#define GF_UNIT_GB_STRING "GB" +#define GF_UNIT_TB_STRING "TB" +#define GF_UNIT_PB_STRING "PB" + +#define GF_UNIT_PERCENT_STRING "%" + +#define GEOREP "geo-replication" +#define GLUSTERD_NAME "glusterd" + +#define GF_SELINUX_XATTR_KEY "security.selinux" + +#define WIPE(statp) \ + do { \ + typeof(*statp) z = { \ + 0, \ + }; \ + if (statp) \ + *statp = z; \ + } while (0) + +#define IS_EXT_FS(fs_name) \ + (!strcmp(fs_name, "ext2") || !strcmp(fs_name, "ext3") || \ + !strcmp(fs_name, "ext4")) + +/* process mode definitions */ +#define GF_SERVER_PROCESS 0 +#define GF_CLIENT_PROCESS 1 +#define GF_GLUSTERD_PROCESS 2 + +/* Defining this here as it is needed by glusterd for setting + * nfs port in volume status. + */ +#define GF_NFS3_PORT 2049 + +#define GF_CLIENT_PORT_CEILING 1024 +#define GF_IANA_PRIV_PORTS_START 49152 /* RFC 6335 */ +#define GF_CLNT_INSECURE_PORT_CEILING (GF_IANA_PRIV_PORTS_START - 1) +#define GF_PORT_MAX 65535 +#define GF_PORT_ARRAY_SIZE ((GF_PORT_MAX + 7) / 8) +#define GF_LOCK_TIMER 180 +#define GF_MINUTE_IN_SECONDS 60 +#define GF_HOUR_IN_SECONDS (60 * 60) +#define GF_DAY_IN_SECONDS (24 * 60 * 60) +#define GF_WEEK_IN_SECONDS (7 * 24 * 60 * 60) +#define GF_SEC_IN_NS 1000000000 +#define GF_MS_IN_NS 1000000 +#define GF_US_IN_NS 1000 + +/* Default timeout for both barrier and changelog translator */ +#define BARRIER_TIMEOUT "120" + +/* Default value of signing waiting time to sign a file for bitrot */ +#define SIGNING_TIMEOUT "120" +#define BR_WORKERS "4" + +/* xxhash */ +#define GF_XXH64_DIGEST_LENGTH 8 +#define GF_XXHSUM64_DEFAULT_SEED 0 + +/* Shard */ +#define GF_XATTR_SHARD_FILE_SIZE "trusted.glusterfs.shard.file-size" +#define SHARD_ROOT_GFID "be318638-e8a0-4c6d-977d-7a937aa84806" +#define DOT_SHARD_REMOVE_ME_GFID "77dd5a45-dbf5-4592-b31b-b440382302e9" + +/* Lease: buffer length for stringified lease id + * Format: 4hexnum-4hexnum-4hexnum-4hexnum-4hexnum-4hexnum-4hexnum-4hexnum + * Eg:6c69-6431-2d63-6c6e-7431-0000-0000-0000 + */ +#define GF_LEASE_ID_BUF_SIZE ((LEASE_ID_SIZE * 2) + (LEASE_ID_SIZE / 2)) + +#define GF_PERCENTAGE(val, total) (((val)*100) / (total)) + +/* pthread related */ +/* as per the man page, thread-name should be at max 16 bytes */ +/* with prefix of 'glfs_' (5), we are left with 11 more bytes */ +#define GF_THREAD_NAME_LIMIT 16 +#define GF_THREAD_NAME_PREFIX "glfs_" + +/* Advisory buffer size for formatted timestamps (see gf_time_fmt) */ +#define GF_TIMESTR_SIZE 256 + +/* + * we could have initialized these as +ve values and treated + * them as negative while comparing etc.. (which would have + * saved us with the pain of assigning values), but since we + * only have a few clients that use this feature, it's okay. + */ +enum _gf_special_pid { + GF_CLIENT_PID_MAX = 0, + GF_CLIENT_PID_GSYNCD = -1, + GF_CLIENT_PID_HADOOP = -2, + GF_CLIENT_PID_DEFRAG = -3, + GF_CLIENT_PID_NO_ROOT_SQUASH = -4, + GF_CLIENT_PID_QUOTA_MOUNT = -5, + GF_CLIENT_PID_SELF_HEALD = -6, + GF_CLIENT_PID_GLFS_HEAL = -7, + GF_CLIENT_PID_BITD = -8, + GF_CLIENT_PID_SCRUB = -9, + GF_CLIENT_PID_TIER_DEFRAG = -10, + GF_SERVER_PID_TRASH = -11, + GF_CLIENT_PID_ADD_REPLICA_MOUNT = -12, + GF_CLIENT_PID_SET_UTIME = -13, +}; + +enum _gf_xlator_ipc_targets { + GF_IPC_TARGET_CHANGELOG = 0, + GF_IPC_TARGET_CTR = 1, + GF_IPC_TARGET_UPCALL = 2 +}; + +typedef enum _gf_special_pid gf_special_pid_t; +typedef enum _gf_xlator_ipc_targets _gf_xlator_ipc_targets_t; + +/* Array to hold custom xattr keys */ +extern char *xattrs_to_heal[]; + +char ** +get_xattrs_to_heal(); + +/* The DHT file rename operation is not a straightforward rename. + * It involves creating linkto and linkfiles, and can unlink or rename the + * source file depending on the hashed and cached subvols for the source + * and target files. this makes it difficult for geo-rep to figure out that + * a rename operation has taken place. + * + * We now send a special key and the values of the source and target pargfids + * and basenames to indicate to changelog that the operation in question + * should be treated as a rename. We are explicitly filling and sending this + * as a binary value in the dictionary as the unlink op will not have the + * source file information. The lengths of the src and target basenames + * are used to calculate where to start reading the names in the structure. + * XFS allows a max of 255 chars for filenames but other file systems might + * not have such restrictions + */ +typedef struct dht_changelog_rename_info { + uuid_t old_pargfid; + uuid_t new_pargfid; + int32_t oldname_len; + int32_t newname_len; + char buffer[1]; +} dht_changelog_rename_info_t; + +typedef int (*gf_cmp)(void *, void *); + +struct _dict; + +struct dnscache { + struct _dict *cache_dict; + time_t ttl; +}; + +struct dnscache_entry { + char *ip; + char *fqdn; + time_t timestamp; +}; + +struct dnscache6 { + struct addrinfo *first; + struct addrinfo *next; +}; + +struct list_node { + void *ptr; + struct list_head list; +}; + +extern char *vol_type_str[]; + +struct list_node * +list_node_add(void *ptr, struct list_head *list); +struct list_node * +list_node_add_order(void *ptr, struct list_head *list, + int (*compare)(struct list_head *, struct list_head *)); +void +list_node_del(struct list_node *node); + +struct dnscache * +gf_dnscache_init(time_t ttl); +void +gf_dnscache_deinit(struct dnscache *cache); +struct dnscache_entry * +gf_dnscache_entry_init(void); +void +gf_dnscache_entry_deinit(struct dnscache_entry *entry); +char * +gf_rev_dns_lookup_cached(const char *ip, struct dnscache *dnscache); + +char * +gf_resolve_path_parent(const char *path); + +void +gf_global_variable_init(void); + +int32_t +gf_resolve_ip6(const char *hostname, uint16_t port, int family, void **dnscache, + struct addrinfo **addr_info); + +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, glusterfs_ctx_t *ctx); +int +gf_set_log_ident(cmd_args_t *cmd_args); + +int +gf_process_getspec_servers_list(cmd_args_t *cmd_args, const char *servers_list); +int +gf_set_volfile_server_common(cmd_args_t *cmd_args, const char *host, + const char *transport, int port); + +static inline void +BIT_SET(unsigned char *array, unsigned int index) +{ + unsigned int offset = index / 8; + unsigned int shift = index % 8; + + array[offset] |= (1 << shift); +} + +static inline void +BIT_CLEAR(unsigned char *array, unsigned int index) +{ + unsigned int offset = index / 8; + unsigned int shift = index % 8; + + array[offset] &= ~(1 << shift); +} + +static inline unsigned int +BIT_VALUE(unsigned char *array, unsigned int index) +{ + unsigned int offset = index / 8; + unsigned int shift = index % 8; + + return (array[offset] >> shift) & 0x1; +} + +#define VECTORSIZE(count) (count * (sizeof(struct iovec))) + +#define STRLEN_0(str) (strlen(str) + 1) + +#define VALIDATE_OR_GOTO(arg, label) \ + do { \ + if (!arg) { \ + errno = EINVAL; \ + gf_msg_callingfn((this ? (this->name) : "(Govinda! Govinda!)"), \ + GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, \ + "invalid argument: " #arg); \ + goto label; \ + } \ + } while (0) + +#define GF_VALIDATE_OR_GOTO(name, arg, label) \ + do { \ + if (!arg) { \ + errno = EINVAL; \ + gf_msg_callingfn(name, GF_LOG_ERROR, errno, LG_MSG_INVALID_ARG, \ + "invalid argument: " #arg); \ + goto label; \ + } \ + } while (0) + +#define GF_VALIDATE_OR_GOTO_WITH_ERROR(name, arg, label, errno, error) \ + do { \ + if (!arg) { \ + errno = error; \ + gf_msg_callingfn(name, GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, \ + "invalid argument: " #arg); \ + goto label; \ + } \ + } while (0) + +#define GF_CHECK_ALLOC(arg, retval, label) \ + do { \ + if (!(arg)) { \ + retval = -ENOMEM; \ + goto label; \ + } \ + } while (0) + +#define GF_CHECK_ALLOC_AND_LOG(name, item, retval, msg, errlabel) \ + do { \ + if (!(item)) { \ + (retval) = -ENOMEM; \ + gf_msg(name, GF_LOG_CRITICAL, ENOMEM, LG_MSG_NO_MEMORY, (msg)); \ + goto errlabel; \ + } \ + } while (0) + +#define GF_ASSERT_AND_GOTO_WITH_ERROR(name, arg, label, errno, error) \ + do { \ + if (!arg) { \ + GF_ASSERT(0); \ + errno = error; \ + goto label; \ + } \ + } while (0) + +#define GF_VALIDATE_ABSOLUTE_PATH_OR_GOTO(name, arg, label) \ + do { \ + GF_VALIDATE_OR_GOTO(name, arg, label); \ + if ((arg[0]) != '/') { \ + errno = EINVAL; \ + gf_msg_callingfn(name, GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, \ + "invalid argument: " #arg); \ + goto label; \ + } \ + } while (0) + +#define GF_REMOVE_SLASH_FROM_PATH(path, string) \ + do { \ + int i = 0; \ + for (i = 1; i < strlen(path); i++) { \ + string[i - 1] = path[i]; \ + if (string[i - 1] == '/') \ + string[i - 1] = '-'; \ + } \ + } while (0) + +#define GF_REMOVE_INTERNAL_XATTR(pattern, dict) \ + do { \ + if (!dict) { \ + gf_msg(this->name, GF_LOG_ERROR, 0, LG_MSG_DICT_NULL, \ + "dict is null"); \ + break; \ + } \ + dict_foreach_fnmatch(dict, pattern, dict_remove_foreach_fn, NULL); \ + } while (0) + +#define GF_IF_INTERNAL_XATTR_GOTO(pattern, dict, op_errno, label) \ + do { \ + if (!dict) { \ + gf_msg(this->name, GF_LOG_ERROR, 0, LG_MSG_DICT_NULL, \ + "setxattr dict is null"); \ + goto label; \ + } \ + if (dict_foreach_fnmatch(dict, pattern, dict_null_foreach_fn, NULL) > \ + 0) { \ + op_errno = EPERM; \ + gf_msg(this->name, GF_LOG_ERROR, op_errno, LG_MSG_NO_PERM, \ + "attempt to set internal" \ + " xattr: %s", \ + pattern); \ + goto label; \ + } \ + } while (0) + +#define GF_IF_NATIVE_XATTR_GOTO(pattern, key, op_errno, label) \ + do { \ + if (!key) { \ + gf_msg(this->name, GF_LOG_ERROR, 0, LG_MSG_NO_KEY, \ + "no key for removexattr"); \ + goto label; \ + } \ + if (!fnmatch(pattern, key, 0)) { \ + op_errno = EPERM; \ + gf_msg(this->name, GF_LOG_ERROR, op_errno, LG_MSG_NO_PERM, \ + "attempt to remove internal " \ + "xattr: %s", \ + key); \ + goto label; \ + } \ + } while (0) + +#ifdef DEBUG +#define GF_ASSERT(x) assert(x); +#else +#define GF_ASSERT(x) \ + do { \ + if (!(x)) { \ + gf_msg_callingfn("", GF_LOG_ERROR, 0, LG_MSG_ASSERTION_FAILED, \ + "Assertion failed: " #x); \ + } \ + } while (0) +#endif + +/* Compile-time assert, borrowed from Linux kernel. */ +#ifdef HAVE_STATIC_ASSERT +#define GF_STATIC_ASSERT(expr, ...) \ + __gf_static_assert(expr, ##__VA_ARGS__, #expr) +#define __gf_static_assert(expr, msg, ...) _Static_assert(expr, msg) +#else +#define GF_STATIC_ASSERT(expr, ...) +#endif + +#define GF_ABORT(msg...) \ + do { \ + gf_msg_callingfn("", GF_LOG_CRITICAL, 0, LG_MSG_ASSERTION_FAILED, \ + "Assertion failed: " msg); \ + abort(); \ + } while (0) + +#define GF_UUID_ASSERT(u) \ + if (gf_uuid_is_null(u)) \ + GF_ASSERT(!"uuid null"); + +#define GF_IGNORE_IF_GSYNCD_SAFE_ERROR(frame, op_errno) \ + (((frame->root->pid == GF_CLIENT_PID_GSYNCD) && \ + (op_errno == EEXIST || op_errno == ENOENT)) \ + ? 0 \ + : 1) + +union gf_sock_union { + struct sockaddr_storage storage; + struct sockaddr_in6 sin6; + struct sockaddr_in sin; + struct sockaddr sa; +}; + +#define GF_HIDDEN_PATH ".glusterfs" +#define GF_UNLINK_PATH GF_HIDDEN_PATH "/unlink" +#define GF_LANDFILL_PATH GF_HIDDEN_PATH "/landfill" + +#define IOV_MIN(n) min(IOV_MAX, n) + +static inline gf_boolean_t +gf_irrelevant_entry(struct dirent *entry) +{ + GF_ASSERT(entry); + + return (!strcmp(entry->d_name, ".") || + !fnmatch("*.tmp", entry->d_name, 0) || + !strcmp(entry->d_name, "..")); +} + +static inline void +iov_free(struct iovec *vector, int count) +{ + int i; + + for (i = 0; i < count; i++) + FREE(vector[i].iov_base); + + GF_FREE(vector); +} + +static inline int +iov_length(const struct iovec *vector, int count) +{ + int i = 0; + size_t size = 0; + + for (i = 0; i < count; i++) + size += vector[i].iov_len; + + return size; +} + +static inline struct iovec * +iov_dup(const struct iovec *vector, int count) +{ + int bytecount = 0; + struct iovec *newvec = NULL; + + bytecount = (count * sizeof(struct iovec)); + newvec = GF_MALLOC(bytecount, gf_common_mt_iovec); + if (newvec != NULL) { + memcpy(newvec, vector, bytecount); + } + + return newvec; +} + +typedef struct _iov_iter { + const struct iovec *iovec; + void *ptr; + uint32_t len; + uint32_t count; +} iov_iter_t; + +static inline bool +iov_iter_init(iov_iter_t *iter, const struct iovec *iovec, uint32_t count, + uint32_t offset) +{ + uint32_t len; + + while (count > 0) { + count--; + len = iovec->iov_len; + if (offset < len) { + iter->ptr = iovec->iov_base + offset; + iter->len = len - offset; + iter->iovec = iovec + 1; + iter->count = count; + + return true; + } + offset -= len; + } + + memset(iter, 0, sizeof(*iter)); + + return false; +} + +static inline bool +iov_iter_end(iov_iter_t *iter) +{ + return iter->count == 0; +} + +static inline bool +iov_iter_next(iov_iter_t *iter, uint32_t size) +{ + GF_ASSERT(size <= iter->len); + + if (iter->len > size) { + iter->len -= size; + iter->ptr += size; + + return true; + } + if (iter->count > 0) { + iter->count--; + iter->ptr = iter->iovec->iov_base; + iter->len = iter->iovec->iov_len; + iter->iovec++; + + return true; + } + + memset(iter, 0, sizeof(*iter)); + + return false; +} + +static inline uint32_t +iov_iter_copy(iov_iter_t *dst, iov_iter_t *src, uint32_t size) +{ + uint32_t len; + + len = src->len; + if (len > dst->len) { + len = dst->len; + } + if (len > size) { + len = size; + } + memcpy(dst->ptr, src->ptr, len); + + return len; +} + +static inline uint32_t +iov_iter_to_iovec(iov_iter_t *iter, struct iovec *iovec, int32_t idx, + uint32_t size) +{ + uint32_t len; + + len = iter->len; + if (len > size) { + len = size; + } + iovec[idx].iov_base = iter->ptr; + iovec[idx].iov_len = len; + + return len; +} + +static inline int +iov_subset(struct iovec *src, int src_count, uint32_t start, uint32_t size, + struct iovec **dst, int32_t dst_count) +{ + struct iovec iovec[src_count]; + iov_iter_t iter; + uint32_t len; + int32_t idx; + + if ((size == 0) || !iov_iter_init(&iter, src, src_count, start)) { + return 0; + } + + idx = 0; + do { + len = iov_iter_to_iovec(&iter, iovec, idx, size); + idx++; + size -= len; + } while ((size > 0) && iov_iter_next(&iter, len)); + + if (*dst == NULL) { + *dst = iov_dup(iovec, idx); + if (*dst == NULL) { + return -1; + } + } else if (idx > dst_count) { + return -1; + } else { + memcpy(*dst, iovec, idx * sizeof(struct iovec)); + } + + return idx; +} + +static inline int +iov_skip(struct iovec *iovec, uint32_t count, uint32_t size) +{ + uint32_t len, idx; + + idx = 0; + while ((size > 0) && (idx < count)) { + len = iovec[idx].iov_len; + if (len > size) { + iovec[idx].iov_len -= size; + iovec[idx].iov_base += size; + break; + } + idx++; + size -= len; + } + + if (idx > 0) { + memmove(iovec, iovec + idx, (count - idx) * sizeof(struct iovec)); + } + + return count - idx; +} + +static inline size_t +iov_range_copy(const struct iovec *dst, uint32_t dst_count, uint32_t dst_offset, + const struct iovec *src, uint32_t src_count, uint32_t src_offset, + uint32_t size) +{ + iov_iter_t src_iter, dst_iter; + uint32_t len, total; + + if ((size == 0) || !iov_iter_init(&src_iter, src, src_count, src_offset) || + !iov_iter_init(&dst_iter, dst, dst_count, dst_offset)) { + return 0; + } + + total = 0; + do { + len = iov_iter_copy(&dst_iter, &src_iter, size); + total += len; + size -= len; + } while ((size > 0) && iov_iter_next(&src_iter, len) && + iov_iter_next(&dst_iter, len)); + + return total; +} + +static inline void +iov_unload(char *buf, const struct iovec *vector, int count) +{ + int i; + int copied = 0; + + for (i = 0; i < count; i++) { + memcpy(buf + copied, vector[i].iov_base, vector[i].iov_len); + copied += vector[i].iov_len; + } +} + +static inline size_t +iov_load(const struct iovec *vector, int count, char *buf, int size) +{ + size_t left = size; + size_t cp = 0; + int ret = 0; + int i = 0; + + while (left && i < count) { + cp = min(vector[i].iov_len, left); + if (vector[i].iov_base != buf + (size - left)) + memcpy(vector[i].iov_base, buf + (size - left), cp); + ret += cp; + left -= cp; + if (left) + i++; + } + + return ret; +} + +static inline size_t +iov_copy(const struct iovec *dst, int dcnt, const struct iovec *src, int scnt) +{ + return iov_range_copy(dst, dcnt, 0, src, scnt, 0, UINT32_MAX); +} + +/* based on the amusing discussion @ https://rusty.ozlabs.org/?p=560 */ +static bool +memeqzero(const void *data, size_t length) +{ + const unsigned char *p = data; + size_t len; + + /* Check first 16 bytes manually */ + for (len = 0; len < 16; len++) { + if (!length) + return true; + if (*p) + return false; + p++; + length--; + } + + /* Now we know that's zero, memcmp with self. */ + return memcmp(data, p, length) == 0; +} + +static inline int +mem_0filled(const char *buf, size_t size) +{ + return !memeqzero(buf, size); +} + +static inline int +iov_0filled(const struct iovec *vector, int count) +{ + int i = 0; + int ret = 0; + + for (i = 0; i < count; i++) { + ret = mem_0filled(vector[i].iov_base, vector[i].iov_len); + if (ret) + break; + } + + return ret; +} + +typedef enum { + gf_timefmt_default = 0, + gf_timefmt_FT = 0, /* YYYY-MM-DD hh:mm:ss */ + gf_timefmt_Ymd_T, /* YYYY/MM-DD-hh:mm:ss */ + gf_timefmt_bdT, /* MMM DD hh:mm:ss */ + gf_timefmt_F_HMS, /* YYYY-MM-DD hhmmss */ + gf_timefmt_dirent, + gf_timefmt_s, + gf_timefmt_last +} gf_timefmts; + +static inline char * +gf_time_fmt_tv(char *dst, size_t sz_dst, struct timeval *tv, unsigned int fmt) +{ + extern void _gf_timestuff(const char ***, const char ***); + static gf_timefmts timefmt_last = (gf_timefmts)-1; + static const char **fmts; + static const char **zeros; + struct tm tm, *res; + int localtime = 0; + int len = 0; + int pos = 0; + + if (timefmt_last == ((gf_timefmts)-1)) { + _gf_timestuff(&fmts, &zeros); + timefmt_last = gf_timefmt_last; + } + if (timefmt_last <= fmt) { + fmt = gf_timefmt_default; + } + localtime = gf_log_get_localtime(); + res = localtime ? localtime_r(&tv->tv_sec, &tm) + : gmtime_r(&tv->tv_sec, &tm); + if (tv->tv_sec && (res != NULL)) { + len = strftime(dst, sz_dst, fmts[fmt], &tm); + if (len == 0) + return dst; + pos += len; + if (tv->tv_usec >= 0) { + len = snprintf(dst + pos, sz_dst - pos, ".%" GF_PRI_SUSECONDS, + tv->tv_usec); + if (len >= sz_dst - pos) + return dst; + pos += len; + } + strftime(dst + pos, sz_dst - pos, " %z", &tm); + } else { + strncpy(dst, "N/A", sz_dst); + } + return dst; +} + +static inline char * +gf_time_fmt(char *dst, size_t sz_dst, time_t utime, unsigned int fmt) +{ + struct timeval tv = {utime, -1}; + + return gf_time_fmt_tv(dst, sz_dst, &tv, fmt); +} + +/* This function helps us use gfid (unique identity) to generate inode's unique + * number in glusterfs. + */ +ino_t +gfid_to_ino(uuid_t gfid); + +int +mkdir_p(char *path, mode_t mode, gf_boolean_t allow_symlinks); +/* + * rounds up nr to power of two. If nr is already a power of two, just returns + * nr + */ + +int +gf_lstat_dir(const char *path, struct stat *stbuf_in); + +int32_t +gf_roundup_power_of_two(int32_t nr); + +/* + * rounds up nr to next power of two. If nr is already a power of two, next + * power of two is returned. + */ + +int32_t +gf_roundup_next_power_of_two(int32_t nr); + +char * +gf_trim(char *string); +int +gf_volume_name_validate(const char *volume_name); + +int +gf_string2long(const char *str, long *n); +int +gf_string2ulong(const char *str, unsigned long *n); +int +gf_string2int(const char *str, int *n); +int +gf_string2uint(const char *str, unsigned int *n); +int +gf_string2double(const char *str, double *n); +int +gf_string2longlong(const char *str, long long *n); +int +gf_string2ulonglong(const char *str, unsigned long long *n); + +int +gf_string2int8(const char *str, int8_t *n); +int +gf_string2int16(const char *str, int16_t *n); +int +gf_string2int32(const char *str, int32_t *n); +int +gf_string2int64(const char *str, int64_t *n); +int +gf_string2uint8(const char *str, uint8_t *n); +int +gf_string2uint16(const char *str, uint16_t *n); +int +gf_string2uint32(const char *str, uint32_t *n); +int +gf_string2uint64(const char *str, uint64_t *n); + +int +gf_strstr(const char *str, const char *delim, const char *match); + +int +gf_string2ulong_base10(const char *str, unsigned long *n); +int +gf_string2uint_base10(const char *str, unsigned int *n); +int +gf_string2uint8_base10(const char *str, uint8_t *n); +int +gf_string2uint16_base10(const char *str, uint16_t *n); +int +gf_string2uint32_base10(const char *str, uint32_t *n); +int +gf_string2uint64_base10(const char *str, uint64_t *n); +int +gf_string2bytesize_uint64(const char *str, uint64_t *n); +int +gf_string2bytesize_int64(const char *str, int64_t *n); +int +gf_string2percent_or_bytesize(const char *str, double *n, + gf_boolean_t *is_percent); + +int +gf_string2boolean(const char *str, gf_boolean_t *b); +int +gf_strn2boolean(const char *str, const int len, gf_boolean_t *b); +int +gf_string2percent(const char *str, double *n); +int +gf_string2time(const char *str, uint32_t *n); + +int +gf_lockfd(int fd); +int +gf_unlockfd(int fd); + +int +get_checksum_for_file(int fd, uint32_t *checksum, int op_version); +int +log_base2(unsigned long x); + +int +get_checksum_for_path(char *path, uint32_t *checksum, int op_version); +int +get_file_mtime(const char *path, time_t *stamp); +char * +gf_resolve_path_parent(const char *path); + +char * +strtail(char *str, const char *pattern); +void +skipwhite(char **s); +char * +nwstrtail(char *str, char *pattern); +/* returns a new string with nth word of given string. n>=1 */ + +typedef struct token_iter { + char *end; + char sep; +} token_iter_t; +char * +token_iter_init(char *str, char sep, token_iter_t *tit); +gf_boolean_t +next_token(char **tokenp, token_iter_t *tit); +void +drop_token(char *token, token_iter_t *tit); + +gf_boolean_t +mask_match(const uint32_t a, const uint32_t b, const uint32_t m); +gf_boolean_t +gf_is_ip_in_net(const char *network, const char *ip_str); +char +valid_host_name(char *address, int length); +char +valid_ipv4_address(char *address, int length, gf_boolean_t wildcard_acc); +char +valid_ipv6_address(char *address, int length, gf_boolean_t wildcard_acc); +char +valid_internet_address(char *address, gf_boolean_t wildcard_acc, + gf_boolean_t cidr); +gf_boolean_t +valid_mount_auth_address(char *address); +gf_boolean_t +valid_ipv4_subnetwork(const char *address); +gf_boolean_t +gf_sock_union_equal_addr(union gf_sock_union *a, union gf_sock_union *b); +char * +gf_rev_dns_lookup(const char *ip); + +char * +uuid_utoa(uuid_t uuid); +char * +uuid_utoa_r(uuid_t uuid, char *dst); +char * +lkowner_utoa(gf_lkowner_t *lkowner); +char * +lkowner_utoa_r(gf_lkowner_t *lkowner, char *dst, int len); +char * +leaseid_utoa(const char *lease_id); +gf_boolean_t +is_valid_lease_id(const char *lease_id); +char * +gf_leaseid_get(void); +char * +gf_existing_leaseid(void); + +void +gf_array_insertionsort(void *a, int l, int r, size_t elem_size, gf_cmp cmp); +int +gf_is_str_int(const char *value); + +char *gf_uint64_2human_readable(uint64_t); +int +validate_brick_name(char *brick); +char * +get_host_name(char *word, char **host); +char * +get_path_name(char *word, char **path); +void +gf_path_strip_trailing_slashes(char *path); +uint64_t +get_mem_size(void); +int +gf_strip_whitespace(char *str, int len); +int +gf_canonicalize_path(char *path); +char * +generate_glusterfs_ctx_id(void); +char * +gf_get_reserved_ports(void); +int +gf_process_reserved_ports(unsigned char *ports, uint32_t ceiling); +gf_boolean_t +gf_ports_reserved(char *blocked_port, unsigned char *ports, uint32_t ceiling); +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 +gf_xxh64_wrapper(const unsigned char *data, size_t const len, + unsigned long long const seed, char *xxh64); +int +gf_gfid_generate_from_xxh64(uuid_t gfid, char *key); + +int +gf_set_timestamp(const char *src, const char *dest); + +int +gf_thread_create(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *arg, const char *name, + ...) __attribute__((__format__(__printf__, 5, 6))); + +int +gf_thread_vcreate(pthread_t *thread, const pthread_attr_t *attr, + void *(*start_routine)(void *), void *arg, const char *name, + va_list args); +int +gf_thread_create_detached(pthread_t *thread, void *(*start_routine)(void *), + void *arg, const char *name, ...) + __attribute__((__format__(__printf__, 4, 5))); + +void +gf_thread_set_name(pthread_t thread, const char *name, ...) + __attribute__((__format__(__printf__, 2, 3))); + +void +gf_thread_set_vname(pthread_t thread, const char *name, va_list args); +gf_boolean_t +gf_is_pid_running(int pid); +gf_boolean_t +gf_is_service_running(char *pidfile, int *pid); +gf_boolean_t +gf_valid_pid(const char *pid, int length); +int +gf_skip_header_section(int fd, int header_len); + +struct iatt; +struct _dict; + +gf_boolean_t +dht_is_linkfile(struct iatt *buf, struct _dict *dict); + +int +gf_check_log_format(const char *value); + +int +gf_check_logger(const char *value); + +gf_boolean_t +gf_compare_sockaddr(const struct sockaddr *addr1, const struct sockaddr *addr2); + +char * +gf_backtrace_save(char *buf); + +void +gf_backtrace_done(char *buf); + +gf_loglevel_t +fop_log_level(glusterfs_fop_t fop, int op_errno); + +int32_t +gf_build_absolute_path(char *current_path, char *relative_path, char **path); + +int +recursive_rmdir(const char *delete_path); + +int +gf_get_index_by_elem(char **array, char *elem); + +int +glusterfs_is_local_pathinfo(char *pathinfo, gf_boolean_t *local); + +int +gf_thread_cleanup_xint(pthread_t thread); + +ssize_t +gf_nread(int fd, void *buf, size_t count); + +ssize_t +gf_nwrite(int fd, const void *buf, size_t count); + +void +_mask_cancellation(void); +void +_unmask_cancellation(void); + +gf_boolean_t +gf_is_zero_filled_stat(struct iatt *buf); + +void +gf_zero_fill_stat(struct iatt *buf); + +gf_boolean_t +gf_is_valid_xattr_namespace(char *k); + +const char * +gf_inode_type_to_str(ia_type_t type); + +int32_t +gf_bits_count(uint64_t n); + +int32_t +gf_bits_index(uint64_t n); + +const char * +gf_fop_string(glusterfs_fop_t fop); + +int +gf_fop_int(char *fop); + +char * +get_ip_from_addrinfo(struct addrinfo *addr, char **ip); + +int +close_fds_except(int *fdv, size_t count); + +int +gf_getgrouplist(const char *user, gid_t group, gid_t **groups); + +int +glusterfs_compute_sha256(const unsigned char *content, size_t size, + char *sha256_hash); + +char * +gf_strncpy(char *dest, const char *src, const size_t dest_size); + +void +gf_strTrim(char **s); + +int +gf_replace_old_iatt_in_dict(struct _dict *); + +int +gf_replace_new_iatt_in_dict(struct _dict *); + +xlator_cmdline_option_t * +find_xlator_option_in_cmd_args_t(const char *option_name, cmd_args_t *args); + +int +gf_d_type_from_ia_type(ia_type_t type); + +int +gf_syncfs(int fd); + +int +gf_nanosleep(uint64_t nsec); + +static inline time_t +gf_time(void) +{ + return time(NULL); +} + +/* Return delta value in microseconds. */ + +static inline double +gf_tvdiff(struct timeval *start, struct timeval *end) +{ + struct timeval t; + + if (start->tv_usec > end->tv_usec) + t.tv_sec = end->tv_sec - 1, t.tv_usec = end->tv_usec + 1000000; + else + t.tv_sec = end->tv_sec, t.tv_usec = end->tv_usec; + + return (double)(t.tv_sec - start->tv_sec) * 1e6 + + (double)(t.tv_usec - start->tv_usec); +} + +/* Return delta value in nanoseconds. */ + +static inline double +gf_tsdiff(struct timespec *start, struct timespec *end) +{ + struct timespec t; + + if (start->tv_nsec > end->tv_nsec) + t.tv_sec = end->tv_sec - 1, t.tv_nsec = end->tv_nsec + 1000000000; + else + t.tv_sec = end->tv_sec, t.tv_nsec = end->tv_nsec; + + return (double)(t.tv_sec - start->tv_sec) * 1e9 + + (double)(t.tv_nsec - start->tv_nsec); +} + +#endif /* _COMMON_UTILS_H */ diff --git a/libglusterfs/src/glusterfs/compat-errno.h b/libglusterfs/src/glusterfs/compat-errno.h new file mode 100644 index 00000000000..c4ab09ab0d5 --- /dev/null +++ b/libglusterfs/src/glusterfs/compat-errno.h @@ -0,0 +1,238 @@ +/* + 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 __COMPAT_ERRNO_H__ +#define __COMPAT_ERRNO_H__ + +#include <errno.h> + +#define GF_ERROR_CODE_SUCCESS 0 +#define GF_ERROR_CODE_UNKNOWN 1024 +#define GF_ERRNO_UNKNOWN 1024 + +#define GF_ERROR_CODE_PERM 1 /* Operation not permitted */ +#define GF_ERROR_CODE_NOENT 2 /* No such file or directory */ +#define GF_ERROR_CODE_SRCH 3 /* No such process */ +#define GF_ERROR_CODE_INTR 4 /* Interrupted system call */ +#define GF_ERROR_CODE_IO 5 /* I/O error */ +#define GF_ERROR_CODE_NXIO 6 /* No such device or address */ +#define GF_ERROR_CODE_2BIG 7 /* Argument list too long */ +#define GF_ERROR_CODE_NOEXEC 8 /* Exec format error */ +#define GF_ERROR_CODE_BADF 9 /* Bad file number */ +#define GF_ERROR_CODE_CHILD 10 /* No child processes */ +#define GF_ERROR_CODE_AGAIN 11 /* Try again */ +#define GF_ERROR_CODE_NOMEM 12 /* Out of memory */ +#define GF_ERROR_CODE_ACCES 13 /* Permission denied */ +#define GF_ERROR_CODE_FAULT 14 /* Bad address */ +#define GF_ERROR_CODE_NOTBLK 15 /* Block device required */ +#define GF_ERROR_CODE_BUSY 16 /* Device or resource busy */ +#define GF_ERROR_CODE_EXIST 17 /* File exists */ +#define GF_ERROR_CODE_XDEV 18 /* Cross-device link */ +#define GF_ERROR_CODE_NODEV 19 /* No such device */ +#define GF_ERROR_CODE_NOTDIR 20 /* Not a directory */ +#define GF_ERROR_CODE_ISDIR 21 /* Is a directory */ +#define GF_ERROR_CODE_INVAL 22 /* Invalid argument */ +#define GF_ERROR_CODE_NFILE 23 /* File table overflow */ +#define GF_ERROR_CODE_MFILE 24 /* Too many open files */ +#define GF_ERROR_CODE_NOTTY 25 /* Not a typewriter */ +#define GF_ERROR_CODE_TXTBSY 26 /* Text file busy */ +#define GF_ERROR_CODE_FBIG 27 /* File too large */ +#define GF_ERROR_CODE_NOSPC 28 /* No space left on device */ +#define GF_ERROR_CODE_SPIPE 29 /* Illegal seek */ +#define GF_ERROR_CODE_ROFS 30 /* Read-only file system */ +#define GF_ERROR_CODE_MLINK 31 /* Too many links */ +#define GF_ERROR_CODE_PIPE 32 /* Broken pipe */ +#define GF_ERROR_CODE_DOM 33 /* Math argument out of domain of func */ +#define GF_ERROR_CODE_RANGE 34 /* Math result not representable */ +#define GF_ERROR_CODE_DEADLK 35 /* Resource deadlock would occur */ +#define GF_ERROR_CODE_NAMETOOLONG 36 /* File name too long */ +#define GF_ERROR_CODE_NOLCK 37 /* No record locks available */ +#define GF_ERROR_CODE_NOSYS 38 /* Function not implemented */ +#define GF_ERROR_CODE_NOTEMPTY 39 /* Directory not empty */ +#define GF_ERROR_CODE_LOOP 40 /* Too many symbolic links encountered */ + +#define GF_ERROR_CODE_NOMSG 42 /* No message of desired type */ +#define GF_ERROR_CODE_IDRM 43 /* Identifier removed */ +#define GF_ERROR_CODE_CHRNG 44 /* Channel number out of range */ +#define GF_ERROR_CODE_L2NSYNC 45 /* Level 2 not synchronized */ +#define GF_ERROR_CODE_L3HLT 46 /* Level 3 halted */ +#define GF_ERROR_CODE_L3RST 47 /* Level 3 reset */ +#define GF_ERROR_CODE_LNRNG 48 /* Link number out of range */ +#define GF_ERROR_CODE_UNATCH 49 /* Protocol driver not attached */ +#define GF_ERROR_CODE_NOCSI 50 /* No CSI structure available */ +#define GF_ERROR_CODE_L2HLT 51 /* Level 2 halted */ +#define GF_ERROR_CODE_BADE 52 /* Invalid exchange */ +#define GF_ERROR_CODE_BADR 53 /* Invalid request descriptor */ +#define GF_ERROR_CODE_XFULL 54 /* Exchange full */ +#define GF_ERROR_CODE_NOANO 55 /* No anode */ +#define GF_ERROR_CODE_BADRQC 56 /* Invalid request code */ +#define GF_ERROR_CODE_BADSLT 57 /* Invalid slot */ +#define GF_ERROR_CODE_BFONT 59 /* Bad font file format */ +#define GF_ERROR_CODE_NOSTR 60 /* Device not a stream */ +#define GF_ERROR_CODE_NODATA 61 /* No data available */ +#define GF_ERROR_CODE_TIME 62 /* Timer expired */ +#define GF_ERROR_CODE_NOSR 63 /* Out of streams resources */ +#define GF_ERROR_CODE_NONET 64 /* Machine is not on the network */ +#define GF_ERROR_CODE_NOPKG 65 /* Package not installed */ +#define GF_ERROR_CODE_REMOTE 66 /* Object is remote */ +#define GF_ERROR_CODE_NOLINK 67 /* Link has been severed */ +#define GF_ERROR_CODE_ADV 68 /* Advertise error */ +#define GF_ERROR_CODE_SRMNT 69 /* Srmount error */ +#define GF_ERROR_CODE_COMM 70 /* Communication error on send */ +#define GF_ERROR_CODE_PROTO 71 /* Protocol error */ +#define GF_ERROR_CODE_MULTIHOP 72 /* Multihop attempted */ +#define GF_ERROR_CODE_DOTDOT 73 /* RFS specific error */ +#define GF_ERROR_CODE_BADMSG 74 /* Not a data message */ +#define GF_ERROR_CODE_OVERFLOW 75 /* Value too large for defined data type */ +#define GF_ERROR_CODE_NOTUNIQ 76 /* Name not unique on network */ +#define GF_ERROR_CODE_BADFD 77 /* File descriptor in bad state */ +#define GF_ERROR_CODE_REMCHG 78 /* Remote address changed */ +#define GF_ERROR_CODE_LIBACC 79 /* Can not access a needed shared library */ +#define GF_ERROR_CODE_LIBBAD 80 /* Accessing a corrupted shared library */ +#define GF_ERROR_CODE_LIBSCN 81 /* .lib section in a.out corrupted */ +#define GF_ERROR_CODE_LIBMAX \ + 82 /* Attempting to link in too many shared libraries */ +#define GF_ERROR_CODE_LIBEXEC 83 /* Cannot exec a shared library directly */ +#define GF_ERROR_CODE_ILSEQ 84 /* Illegal byte sequence */ +#define GF_ERROR_CODE_RESTART \ + 85 /* Interrupted system call should be restarted */ +#define GF_ERROR_CODE_STRPIPE 86 /* Streams pipe error */ +#define GF_ERROR_CODE_USERS 87 /* Too many users */ +#define GF_ERROR_CODE_NOTSOCK 88 /* Socket operation on non-socket */ +#define GF_ERROR_CODE_DESTADDRREQ 89 /* Destination address required */ +#define GF_ERROR_CODE_MSGSIZE 90 /* Message too long */ +#define GF_ERROR_CODE_PROTOTYPE 91 /* Protocol wrong type for socket */ +#define GF_ERROR_CODE_NOPROTOOPT 92 /* Protocol not available */ +#define GF_ERROR_CODE_PROTONOSUPPORT 93 /* Protocol not supported */ +#define GF_ERROR_CODE_SOCKTNOSUPPORT 94 /* Socket type not supported */ +#define GF_ERROR_CODE_OPNOTSUPP \ + 95 /* Operation not supported on transport endpoint */ +#define GF_ERROR_CODE_PFNOSUPPORT 96 /* Protocol family not supported */ +#define GF_ERROR_CODE_AFNOSUPPORT \ + 97 /* Address family not supported by protocol */ +#define GF_ERROR_CODE_ADDRINUSE 98 /* Address already in use */ +#define GF_ERROR_CODE_ADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define GF_ERROR_CODE_NETDOWN 100 /* Network is down */ +#define GF_ERROR_CODE_NETUNREACH 101 /* Network is unreachable */ +#define GF_ERROR_CODE_NETRESET \ + 102 /* Network dropped connection because of reset */ +#define GF_ERROR_CODE_CONNABORTED 103 /* Software caused connection abort */ +#define GF_ERROR_CODE_CONNRESET 104 /* Connection reset by peer */ +#define GF_ERROR_CODE_NOBUFS 105 /* No buffer space available */ +#define GF_ERROR_CODE_ISCONN 106 /* Transport endpoint is already connected */ +#define GF_ERROR_CODE_NOTCONN 107 /* Transport endpoint is not connected */ +#define GF_ERROR_CODE_SHUTDOWN \ + 108 /* Cannot send after transport endpoint shutdown */ +#define GF_ERROR_CODE_TOOMANYREFS 109 /* Too many references: cannot splice */ +#define GF_ERROR_CODE_TIMEDOUT 110 /* Connection timed out */ +#define GF_ERROR_CODE_CONNREFUSED 111 /* Connection refused */ +#define GF_ERROR_CODE_HOSTDOWN 112 /* Host is down */ +#define GF_ERROR_CODE_HOSTUNREACH 113 /* No route to host */ +#define GF_ERROR_CODE_ALREADY 114 /* Operation already in progress */ +#define GF_ERROR_CODE_INPROGRESS 115 /* Operation now in progress */ +#define GF_ERROR_CODE_ALREADY 114 /* Operation already in progress */ +#define GF_ERROR_CODE_INPROGRESS 115 /* Operation now in progress */ +#define GF_ERROR_CODE_STALE 116 /* Stale NFS file handle */ +#define GF_ERROR_CODE_UCLEAN 117 /* Structure needs cleaning */ +#define GF_ERROR_CODE_NOTNAM 118 /* Not a XENIX named type file */ +#define GF_ERROR_CODE_NAVAIL 119 /* No XENIX semaphores available */ +#define GF_ERROR_CODE_ISNAM 120 /* Is a named type file */ +#define GF_ERROR_CODE_REMOTEIO 121 /* Remote I/O error */ +#define GF_ERROR_CODE_DQUOT 122 /* Quota exceeded */ +#define GF_ERROR_CODE_NOMEDIUM 123 /* No medium found */ +#define GF_ERROR_CODE_MEDIUMTYPE 124 /* Wrong medium type */ +#define GF_ERROR_CODE_CANCELED 125 /* Operation Canceled */ +#define GF_ERROR_CODE_NOKEY 126 /* Required key not available */ +#define GF_ERROR_CODE_KEYEXPIRED 127 /* Key has expired */ +#define GF_ERROR_CODE_KEYREVOKED 128 /* Key has been revoked */ +#define GF_ERROR_CODE_KEYREJECTED 129 /* Key was rejected by service */ + +/* for robust mutexes */ +#define GF_ERROR_CODE_OWNERDEAD 130 /* Owner died */ +#define GF_ERROR_CODE_NOTRECOVERABLE 131 /* State not recoverable */ + +/* Should never be seen by user programs */ +#define GF_ERROR_CODE_RESTARTSYS 512 +#define GF_ERROR_CODE_RESTARTNOINTR 513 +#define GF_ERROR_CODE_RESTARTNOHAND 514 /* restart if no handler.. */ +#define GF_ERROR_CODE_NOIOCTLCMD 515 /* No ioctl command */ +#define GF_ERROR_CODE_RESTART_RESTARTBLOCK \ + 516 /* restart by calling sys_restart_syscall */ + +/* Defined for the NFSv3 protocol */ +#define GF_ERROR_CODE_BADHANDLE 521 /* Illegal NFS file handle */ +#define GF_ERROR_CODE_NOTSYNC 522 /* Update synchronization mismatch */ +#define GF_ERROR_CODE_BADCOOKIE 523 /* Cookie is stale */ +#define GF_ERROR_CODE_NOTSUPP 524 /* Operation is not supported */ +#define GF_ERROR_CODE_TOOSMALL 525 /* Buffer or request is too small */ +#define GF_ERROR_CODE_SERVERFAULT 526 /* An untranslatable error occurred */ +#define GF_ERROR_CODE_BADTYPE 527 /* Type not supported by server */ +#define GF_ERROR_CODE_JUKEBOX \ + 528 /* Request initiated, but will not complete before timeout */ +#define GF_ERROR_CODE_IOCBQUEUED \ + 529 /* iocb queued, will get completion event */ +#define GF_ERROR_CODE_IOCBRETRY 530 /* iocb queued, will trigger a retry */ + +/* Darwin OS X */ +#define GF_ERROR_CODE_NOPOLICY 701 +#define GF_ERROR_CODE_BADMACHO 702 +#define GF_ERROR_CODE_PWROFF 703 +#define GF_ERROR_CODE_DEVERR 704 +#define GF_ERROR_CODE_BADARCH 705 +#define GF_ERROR_CODE_BADEXEC 706 +#define GF_ERROR_CODE_SHLIBVERS 707 + +/* Solaris */ +/* ENOTACTIVE 73 / * Facility is not active */ +#define GF_ERROR_CODE_NOTACTIVE 801 +/* ELOCKUNMAPPED 72 / * locked lock was unmapped */ +#define GF_ERROR_CODE_LOCKUNMAPPED 802 + +/* BSD system */ +#define GF_ERROR_CODE_PROCLIM 901 /* Too many processes */ +#define GF_ERROR_CODE_BADRPC 902 /* RPC struct is bad */ +#define GF_ERROR_CODE_RPCMISMATCH 903 /* RPC version wrong */ +#define GF_ERROR_CODE_PROGUNAVAIL 904 /* RPC prog. not avail */ +#define GF_ERROR_CODE_PROGMISMATCH 905 /* Program version wrong */ +#define GF_ERROR_CODE_PROCUNAVAIL 905 /* Bad procedure for program */ +#define GF_ERROR_CODE_FTYPE 906 /* Inappropriate file type or format */ +#define GF_ERROR_CODE_AUTH 907 /* Authentication error */ +#define GF_ERROR_CODE_NEEDAUTH 908 /* Need authenticator */ +#define GF_ERROR_CODE_DOOFUS 909 /* Programming error */ + +#define GF_ERROR_CODE_NOATTR GF_ERROR_CODE_NODATA /* Attribute not found */ + +/* Either one of enodata or enoattr will be there in system */ +#ifndef ENOATTR +#define ENOATTR ENODATA +#endif /* ENOATTR */ + +#ifndef ENODATA +#define ENODATA ENOATTR +#endif /* ENODATA */ + +#ifndef EBADFD +#define EBADFD EBADRPC +#endif /* EBADFD */ + +#if !defined(ENODATA) +/* This happens on FreeBSD. Value borrowed from Linux. */ +#define ENODATA 61 +#endif + +/* These functions are defined for all the OS flags, but content will + * be different for each OS flag. + */ +int32_t +gf_errno_to_error(int32_t op_errno); +int32_t +gf_error_to_errno(int32_t error); + +#endif /* __COMPAT_ERRNO_H__ */ diff --git a/libglusterfs/src/glusterfs/compat-uuid.h b/libglusterfs/src/glusterfs/compat-uuid.h new file mode 100644 index 00000000000..6e7fdefbfab --- /dev/null +++ b/libglusterfs/src/glusterfs/compat-uuid.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com> + * This file is part of GlusterFS. + * + * This file is licensed to you under your choice of the GNU Lesser + * General Public License, version 3 or any later version (LGPLv3 or + * later), or the GNU General Public License, version 2 (GPLv2), in all + * cases as published by the Free Software Foundation. + */ + +#ifndef _GF_UUID_H +#define _GF_UUID_H + +#include <uuid/uuid.h> + +static inline void +gf_uuid_clear(uuid_t uuid) +{ + uuid_clear(uuid); +} + +static inline int +gf_uuid_compare(uuid_t u1, uuid_t u2) +{ + return uuid_compare(u1, u2); +} + +static inline void +gf_uuid_copy(uuid_t dst, const uuid_t src) +{ + uuid_copy(dst, src); +} + +static inline void +gf_uuid_generate(uuid_t uuid) +{ + uuid_generate(uuid); +} + +static inline int +gf_uuid_is_null(uuid_t uuid) +{ + return uuid_is_null(uuid); +} + +static inline int +gf_uuid_parse(const char *in, uuid_t uuid) +{ + return uuid_parse(in, uuid); +} + +static inline void +gf_uuid_unparse(const uuid_t uuid, char *out) +{ + uuid_unparse(uuid, out); +} + +/* TODO: add more uuid APIs, use constructs like this: +#if defined(__NetBSD__) * NetBSD libc * + +#include <string.h> + +static inline void +gf_uuid_clear (uuid_t uuid) +{ + memset (uuid, 0, sizeof (uuid_t)); +} +#endif +*/ + +#endif /* _GF_UUID_H */ diff --git a/libglusterfs/src/glusterfs/compat.h b/libglusterfs/src/glusterfs/compat.h new file mode 100644 index 00000000000..bf00d903152 --- /dev/null +++ b/libglusterfs/src/glusterfs/compat.h @@ -0,0 +1,544 @@ +/* + 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 __COMPAT_H__ +#define __COMPAT_H__ + +#include <stdint.h> + +#ifndef LLONG_MAX +#define LLONG_MAX __LONG_LONG_MAX__ /* compat with old gcc */ +#endif /* LLONG_MAX */ + +#ifdef GF_LINUX_HOST_OS + +#define UNIX_PATH_MAX 108 + +#include <sys/un.h> +#include <linux/limits.h> +#include <sys/xattr.h> +#include <linux/xattr.h> +#include <endian.h> +#ifdef HAVE_LINUX_FALLOC_H +#include <linux/falloc.h> +#endif + +#ifdef HAVE_ENDIAN_H +#include <endian.h> +#endif + +#ifndef _PATH_UMOUNT +#define _PATH_UMOUNT "/bin/umount" +#endif +#define GF_XATTR_NAME_MAX XATTR_NAME_MAX +#endif /* GF_LINUX_HOST_OS */ + +/* + * Define the fallocate flags in case we do not have the header. This also + * accounts for older systems that do not define FALLOC_FL_PUNCH_HOLE. + */ + +#ifndef FALLOC_FL_KEEP_SIZE +#define FALLOC_FL_KEEP_SIZE 0x01 /* default is extend size */ +#endif +#ifndef FALLOC_FL_PUNCH_HOLE +#define FALLOC_FL_PUNCH_HOLE 0x02 /* de-allocates range */ +#endif +#ifndef FALLOC_FL_ZERO_RANGE +#define FALLOC_FL_ZERO_RANGE 0x10 /* zeroes out range */ +#endif +#ifndef FALLOC_FL_COLLAPSE_RANGE +#define FALLOC_FL_COLLAPSE_RANGE 0x08 /* reduces the size */ +#endif +#ifndef FALLOC_FL_INSERT_RANGE +#define FALLOC_FL_INSERT_RANGE 0x20 /* expands the size */ +#endif + +#ifndef HAVE_LLISTXATTR + +/* This part is valid only in case of old glibc which doesn't support + * 'llistxattr()' system calls. + */ + +#define lremovexattr(path, key) removexattr(path, key) +#define llistxattr(path, key, size) listxattr(path, key, size) +#define lgetxattr(path, key, value, size) getxattr(path, key, value, size) +#define lsetxattr(path, key, value, size, flags) \ + setxattr(path, key, value, size, flags) + +#endif /* HAVE_LLISTXATTR */ + +#ifdef GF_DARWIN_HOST_OS +#include <machine/endian.h> +#include <libkern/OSByteOrder.h> +#include <sys/xattr.h> + +#define htobe16(x) OSSwapHostToBigInt16(x) +#define htole16(x) OSSwapHostToLittleInt16(x) +#define be16toh(x) OSSwapBigToHostInt16(x) +#define le16toh(x) OSSwapLittleToHostInt16(x) + +#define htobe32(x) OSSwapHostToBigInt32(x) +#define htole32(x) OSSwapHostToLittleInt32(x) +#define be32toh(x) OSSwapBigToHostInt32(x) +#define le32toh(x) OSSwapLittleToHostInt32(x) + +#define htobe64(x) OSSwapHostToBigInt64(x) +#define htole64(x) OSSwapHostToLittleInt64(x) +#define be64toh(x) OSSwapBigToHostInt64(x) +#define le64toh(x) OSSwapLittleToHostInt64(x) + +#endif + +#ifdef GF_BSD_HOST_OS +/* In case of FreeBSD and NetBSD */ + +#define UNIX_PATH_MAX 104 +#include <sys/types.h> + +#include <sys/un.h> +#include <sys/endian.h> +#include <sys/extattr.h> +#ifdef HAVE_SYS_XATTR_H +#include <sys/xattr.h> +#endif /* HAVE_SYS_XATTR_H */ +#include <limits.h> + +#include <libgen.h> +/* + * This is where things like off64_t are defined. + * So include it before declaring _OFF64_T_DECLARED. + * If the freebsd version has support for off64_t + * including stdio.h should be sufficient. + */ +#include <stdio.h> + +#ifndef _OFF64_T_DECLARED +/* + * Including <stdio.h> (done above) should actually define + * _OFF64_T_DECLARED with off64_t data type being available + * for consumption. But, off64_t data type is not recognizable + * for FreeBSD versions less than 11. Hence, int64_t is typedefed + * to off64_t. + */ +#define _OFF64_T_DECLARED +typedef int64_t off64_t; +#endif /* _OFF64_T_DECLARED */ + +#ifndef XATTR_CREATE +enum { + ATTR_CREATE = 1, +#define XATTR_CREATE ATTR_CREATE + ATTR_REPLACE = 2 +#define XATTR_REPLACE ATTR_REPLACE +}; +#endif /* XATTR_CREATE */ + +#ifndef sighandler_t +#define sighandler_t sig_t +#endif + +#ifdef __FreeBSD__ +#undef ino_t +#define ino_t uint64_t +#include <sys/types.h> +#include <sys/extattr.h> +/* Using NAME_MAX since EXTATTR_MAXNAMELEN is inside a preprocessor conditional + * for the kernel + */ +#define GF_XATTR_NAME_MAX NAME_MAX +#endif /* __FreeBSD__ */ + +#ifdef __NetBSD__ +#define GF_XATTR_NAME_MAX XATTR_NAME_MAX +#endif + +#ifndef ino64_t +#define ino64_t ino_t +#endif + +#ifndef EUCLEAN +#define EUCLEAN 0 +#endif + +#include <netinet/in.h> +#ifndef s6_addr16 +#define s6_addr16 __u6_addr.__u6_addr16 +#endif +#ifndef s6_addr32 +#define s6_addr32 __u6_addr.__u6_addr32 +#endif + +#ifndef LOGIN_NAME_MAX +#define LOGIN_NAME_MAX 256 +#endif + +/* Posix dictates NAME_MAX to be used */ +#ifndef NAME_MAX +#ifdef MAXNAMLEN +#define NAME_MAX MAXNAMLEN +#else +#define NAME_MAX 255 +#endif +#endif + +#define F_GETLK64 F_GETLK +#define F_SETLK64 F_SETLK +#define F_SETLKW64 F_SETLKW +#define FALLOC_FL_KEEP_SIZE 0x01 /* default is extend size */ +#define FALLOC_FL_PUNCH_HOLE 0x02 /* de-allocates range */ +#define FALLOC_FL_ZERO_RANGE 0x10 /* zeroes out range */ +#define FALLOC_FL_INSERT_RANGE 0x20 /* Expands the size */ +#define FALLOC_FL_COLLAPSE_RANGE 0x08 /* Reduces the size */ + +#ifndef _PATH_UMOUNT +#define _PATH_UMOUNT "/sbin/umount" +#endif + +void +gf_extattr_list_reshape(char *list, ssize_t size); + +#endif /* GF_BSD_HOST_OS */ + +#ifdef GF_DARWIN_HOST_OS +#include <machine/endian.h> +#include <libkern/OSByteOrder.h> + +#define htobe16(x) OSSwapHostToBigInt16(x) +#define htole16(x) OSSwapHostToLittleInt16(x) +#define be16toh(x) OSSwapBigToHostInt16(x) +#define le16toh(x) OSSwapLittleToHostInt16(x) + +#define htobe32(x) OSSwapHostToBigInt32(x) +#define htole32(x) OSSwapHostToLittleInt32(x) +#define be32toh(x) OSSwapBigToHostInt32(x) +#define le32toh(x) OSSwapLittleToHostInt32(x) + +#define htobe64(x) OSSwapHostToBigInt64(x) +#define htole64(x) OSSwapHostToLittleInt64(x) +#define be64toh(x) OSSwapBigToHostInt64(x) +#define le64toh(x) OSSwapLittleToHostInt64(x) + +#define UNIX_PATH_MAX 104 +/* OSX Yosemite now has this defined */ +#ifndef AT_SYMLINK_NOFOLLOW +#define AT_SYMLINK_NOFOLLOW 0x100 +#endif +#include <sys/types.h> + +#include <sys/un.h> +#include <sys/xattr.h> +#include <limits.h> + +#include <libgen.h> + +#if __DARWIN_64_BIT_INO_T == 0 +#error '64 bit ino_t is must for GlusterFS to work, Compile with "CFLAGS=-D__DARWIN_64_BIT_INO_T"' +#endif /* __DARWIN_64_BIT_INO_T */ + +#if __DARWIN_64_BIT_INO_T == 0 +#error '64 bit ino_t is must for GlusterFS to work, Compile with "CFLAGS=-D__DARWIN_64_BIT_INO_T"' +#endif /* __DARWIN_64_BIT_INO_T */ + +#ifndef sighandler_t +#define sighandler_t sig_t +#endif + +#ifndef EUCLEAN +#define EUCLEAN 0 +#endif + +#include <netinet/in.h> +#ifndef s6_addr16 +#define s6_addr16 __u6_addr.__u6_addr16 +#endif +#ifndef s6_addr32 +#define s6_addr32 __u6_addr.__u6_addr32 +#endif + +/* Posix dictates NAME_MAX to be used */ +#ifndef NAME_MAX +#ifdef MAXNAMLEN +#define NAME_MAX MAXNAMLEN +#else +#define NAME_MAX 255 +#endif +#endif + +#define F_GETLK64 F_GETLK +#define F_SETLK64 F_SETLK +#define F_SETLKW64 F_SETLKW + +#ifndef FTW_CONTINUE +#define FTW_CONTINUE 0 +#endif + +#ifndef _PATH_UMOUNT +#define _PATH_UMOUNT "/sbin/umount" +#endif +#endif /* GF_DARWIN_HOST_OS */ + +#ifdef GF_SOLARIS_HOST_OS + +#define UNIX_PATH_MAX 108 +#define EUCLEAN 117 + +#include <sys/un.h> +#include <limits.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/fcntl.h> +#include <libgen.h> +#include <sys/mkdev.h> + +#ifndef lchmod +#define lchmod chmod +#endif + +#define lgetxattr(path, key, value, size) \ + solaris_getxattr(path, key, value, size) +enum { + ATTR_CREATE = 1, +#define XATTR_CREATE ATTR_CREATE + ATTR_REPLACE = 2 +#define XATTR_REPLACE ATTR_REPLACE +}; + +/* This patch is not present in Solaris 10 and before */ +#ifndef dirfd +#define dirfd(dirp) ((dirp)->dd_fd) +#endif + +/* Posix dictates NAME_MAX to be used */ +#ifndef NAME_MAX +#ifdef MAXNAMLEN +#define NAME_MAX MAXNAMLEN +#else +#define NAME_MAX 255 +#endif +#endif + +#include <netinet/in.h> +#ifndef s6_addr16 +#define S6_ADDR16(x) ((uint16_t *)((char *)&(x).s6_addr)) +#endif +#ifndef s6_addr32 +#define s6_addr32 _S6_un._S6_u32 +#endif + +#define lutimes(filename, times) utimes(filename, times) + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +enum { + DT_UNKNOWN = 0, +#define DT_UNKNOWN DT_UNKNOWN + DT_FIFO = 1, +#define DT_FIFO DT_FIFO + DT_CHR = 2, +#define DT_CHR DT_CHR + DT_DIR = 4, +#define DT_DIR DT_DIR + DT_BLK = 6, +#define DT_BLK DT_BLK + DT_REG = 8, +#define DT_REG DT_REG + DT_LNK = 10, +#define DT_LNK DT_LNK + DT_SOCK = 12, +#define DT_SOCK DT_SOCK + DT_WHT = 14 +#define DT_WHT DT_WHT +}; + +#ifndef _PATH_MOUNTED +#define _PATH_MOUNTED "/etc/mtab" +#endif +#ifndef _PATH_UMOUNT +#define _PATH_UMOUNT "/sbin/umount" +#endif + +#ifndef O_ASYNC +#ifdef FASYNC +#define O_ASYNC FASYNC +#else +#define O_ASYNC 0 +#endif +#endif + +#ifndef FTW_CONTINUE +#define FTW_CONTINUE 0 +#endif + +int +asprintf(char **string_ptr, const char *format, ...); + +int +vasprintf(char **result, const char *format, va_list args); +char * +strsep(char **str, const char *delims); +int +solaris_listxattr(const char *path, char *list, size_t size); +int +solaris_removexattr(const char *path, const char *key); +int +solaris_getxattr(const char *path, const char *key, char *value, size_t size); +int +solaris_setxattr(const char *path, const char *key, const char *value, + size_t size, int flags); +int +solaris_fgetxattr(int fd, const char *key, char *value, size_t size); +int +solaris_fsetxattr(int fd, const char *key, const char *value, size_t size, + int flags); +int +solaris_flistxattr(int fd, char *list, size_t size); + +int +solaris_rename(const char *oldpath, const char *newpath); + +int +solaris_unlink(const char *pathname); + +char * +mkdtemp(char *temp); + +#define GF_SOLARIS_XATTR_DIR ".glusterfs_xattr_inode" + +int +solaris_xattr_resolve_path(const char *real_path, char **path); + +#endif /* GF_SOLARIS_HOST_OS */ + +#ifndef HAVE_ARGP +#include "argp.h" +#else +#include <argp.h> +#endif /* HAVE_ARGP */ + +#ifndef HAVE_STRNLEN +size_t +strnlen(const char *string, size_t maxlen); +#endif /* STRNLEN */ + +#ifndef strdupa +#define strdupa(s) \ + (__extension__({ \ + __const char *__old = (s); \ + size_t __len = strlen(__old) + 1; \ + char *__new = (char *)__builtin_alloca(__len); \ + (char *)memcpy(__new, __old, __len); \ + })) +#endif + +#define GF_DIR_ALIGN(x) (((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1)) + +#include <sys/types.h> +#include <dirent.h> + +static inline int32_t +dirent_size(struct dirent *entry) +{ + int32_t size = -1; + +#ifdef GF_BSD_HOST_OS + size = GF_DIR_ALIGN(24 /* FIX MEEEE!!! */ + entry->d_namlen); +#endif +#ifdef GF_DARWIN_HOST_OS + size = GF_DIR_ALIGN(24 /* FIX MEEEE!!! */ + entry->d_namlen); +#endif +#ifdef GF_LINUX_HOST_OS + size = GF_DIR_ALIGN(24 /* FIX MEEEE!!! */ + entry->d_reclen); +#endif +#ifdef GF_SOLARIS_HOST_OS + size = GF_DIR_ALIGN(24 /* FIX MEEEE!!! */ + entry->d_reclen); +#endif + return size; +} + +#ifdef THREAD_UNSAFE_BASENAME +char * +basename_r(const char *); +#define basename(path) basename_r(path) +#endif /* THREAD_UNSAFE_BASENAME */ + +#ifdef THREAD_UNSAFE_DIRNAME +char * +dirname_r(char *path); +#define dirname(path) dirname_r(path) +#endif /* THREAD_UNSAFE_DIRNAME */ + +#ifdef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC +/* Linux, Solaris, Cygwin */ +#define ST_ATIM_SEC(stbuf) ((stbuf)->st_atim.tv_sec) +#define ST_CTIM_SEC(stbuf) ((stbuf)->st_ctim.tv_sec) +#define ST_MTIM_SEC(stbuf) ((stbuf)->st_mtim.tv_sec) +#define ST_ATIM_SEC_SET(stbuf, val) ((stbuf)->st_atim.tv_sec = (val)) +#define ST_MTIM_SEC_SET(stbuf, val) ((stbuf)->st_mtim.tv_sec = (val)) +#define ST_CTIM_SEC_SET(stbuf, val) ((stbuf)->st_ctim.tv_sec = (val)) +#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atim.tv_nsec) +#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctim.tv_nsec) +#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtim.tv_nsec) +#define ST_ATIM_NSEC_SET(stbuf, val) ((stbuf)->st_atim.tv_nsec = (val)) +#define ST_MTIM_NSEC_SET(stbuf, val) ((stbuf)->st_mtim.tv_nsec = (val)) +#define ST_CTIM_NSEC_SET(stbuf, val) ((stbuf)->st_ctim.tv_nsec = (val)) +#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC) +/* FreeBSD, NetBSD */ +#define ST_ATIM_SEC(stbuf) ((stbuf)->st_atimespec.tv_sec) +#define ST_CTIM_SEC(stbuf) ((stbuf)->st_ctimespec.tv_sec) +#define ST_MTIM_SEC(stbuf) ((stbuf)->st_mtimespec.tv_sec) +#define ST_ATIM_SEC_SET(stbuf, val) ((stbuf)->st_atimespec.tv_sec = (val)) +#define ST_MTIM_SEC_SET(stbuf, val) ((stbuf)->st_mtimespec.tv_sec = (val)) +#define ST_CTIM_SEC_SET(stbuf, val) ((stbuf)->st_ctimespec.tv_sec = (val)) +#define ST_ATIM_NSEC(stbuf) ((stbuf)->st_atimespec.tv_nsec) +#define ST_CTIM_NSEC(stbuf) ((stbuf)->st_ctimespec.tv_nsec) +#define ST_MTIM_NSEC(stbuf) ((stbuf)->st_mtimespec.tv_nsec) +#define ST_ATIM_NSEC_SET(stbuf, val) ((stbuf)->st_atimespec.tv_nsec = (val)) +#define ST_MTIM_NSEC_SET(stbuf, val) ((stbuf)->st_mtimespec.tv_nsec = (val)) +#define ST_CTIM_NSEC_SET(stbuf, val) ((stbuf)->st_ctimespec.tv_nsec = (val)) +#else +#define ST_ATIM_NSEC(stbuf) (0) +#define ST_CTIM_NSEC(stbuf) (0) +#define ST_MTIM_NSEC(stbuf) (0) +#define ST_ATIM_NSEC_SET(stbuf, val) \ + do { \ + } while (0); +#define ST_MTIM_NSEC_SET(stbuf, val) \ + do { \ + } while (0); +#define ST_CTIM_NSEC_SET(stbuf, val) \ + do { \ + } while (0); +#endif + +#ifdef GF_BSD_HOST_OS +#define CLOCK_REALTIME_COARSE CLOCK_REALTIME +#endif + +#if defined(__GNUC__) && !defined(RELAX_POISONING) +/* Use run API, see run.h */ +#include <stdlib.h> /* system(), mkostemp() */ +#include <stdio.h> /* popen() */ +#ifdef GF_LINUX_HOST_OS +#include <sys/sysmacros.h> +#endif +#pragma GCC poison system mkostemp popen +#endif + +int +gf_umount_lazy(char *xlname, char *path, int rmdir); + +#ifndef GF_XATTR_NAME_MAX +#error 'Please define GF_XATTR_NAME_MAX for your OS distribution.' +#endif + +#endif /* __COMPAT_H__ */ diff --git a/libglusterfs/src/glusterfs/daemon.h b/libglusterfs/src/glusterfs/daemon.h new file mode 100644 index 00000000000..48850800b5e --- /dev/null +++ b/libglusterfs/src/glusterfs/daemon.h @@ -0,0 +1,20 @@ +/* + 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 _DAEMON_H +#define _DAEMON_H + +#define DEVNULLPATH "/dev/null" + +int +os_daemon_return(int nochdir, int noclose); +int +os_daemon(int nochdir, int noclose); +#endif /*_DAEMON_H */ diff --git a/libglusterfs/src/glusterfs/default-args.h b/libglusterfs/src/glusterfs/default-args.h new file mode 100644 index 00000000000..ca7526fcab6 --- /dev/null +++ b/libglusterfs/src/glusterfs/default-args.h @@ -0,0 +1,455 @@ +/* + Copyright (c) 2008-2015 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +/* libglusterfs/src/defaults.h: + This file contains definition of default fops and mops functions. +*/ + +#ifndef _DEFAULT_ARGS_H +#define _DEFAULT_ARGS_H + +#include "glusterfs/xlator.h" + +int +args_lookup_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + dict_t *xdata, struct iatt *postparent); + +int +args_stat_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + struct iatt *buf, dict_t *xdata); + +int +args_fstat_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + struct iatt *buf, dict_t *xdata); + +int +args_truncate_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata); + +int +args_ftruncate_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata); + +int +args_access_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +int +args_readlink_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, const char *path, struct iatt *stbuf, + dict_t *xdata); + +int +args_mknod_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + inode_t *inode, struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +int +args_mkdir_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + inode_t *inode, struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +int +args_unlink_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +int +args_rmdir_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + struct iatt *preparent, struct iatt *postparent, + dict_t *xdata); + +int +args_symlink_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, inode_t *inode, struct iatt *buf, + struct iatt *preparent, struct iatt *postparent, + dict_t *xdata); + +int +args_rename_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *buf, + struct iatt *preoldparent, struct iatt *postoldparent, + struct iatt *prenewparent, struct iatt *postnewparent, + dict_t *xdata); + +int +args_link_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + inode_t *inode, struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +int +args_create_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, fd_t *fd, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +int +args_open_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + fd_t *fd, dict_t *xdata); + +int +args_readv_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + struct iovec *vector, int32_t count, struct iatt *stbuf, + struct iobref *iobref, dict_t *xdata); + +int +args_writev_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata); + +int +args_put_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + inode_t *inode, struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +int +args_flush_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + dict_t *xdata); + +int +args_fsync_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + struct iatt *prebuf, struct iatt *postbuf, dict_t *xdata); + +int +args_opendir_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, fd_t *fd, dict_t *xdata); + +int +args_fsyncdir_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +int +args_statfs_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct statvfs *buf, dict_t *xdata); + +int +args_setxattr_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +int +args_getxattr_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *dict, dict_t *xdata); + +int +args_fsetxattr_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +int +args_fgetxattr_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *dict, dict_t *xdata); + +int +args_removexattr_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +int +args_fremovexattr_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +int +args_lk_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + struct gf_flock *lock, dict_t *xdata); + +int +args_inodelk_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +int +args_finodelk_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +int +args_entrylk_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +int +args_fentrylk_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +int +args_readdirp_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, gf_dirent_t *entries, dict_t *xdata); + +int +args_readdir_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, gf_dirent_t *entries, dict_t *xdata); + +int +args_rchecksum_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, uint32_t weak_checksum, + uint8_t *strong_checksum, dict_t *xdata); + +int +args_xattrop_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xattr, dict_t *xdata); + +int +args_fxattrop_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, dict_t *xattr, dict_t *xdata); + +int +args_setattr_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *statpre, + struct iatt *statpost, dict_t *xdata); + +int +args_fsetattr_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *statpre, + struct iatt *statpost, dict_t *xdata); + +int +args_fallocate_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *statpre, + struct iatt *statpost, dict_t *xdata); + +int +args_discard_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *statpre, + struct iatt *statpost, dict_t *xdata); + +int +args_zerofill_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *statpre, + struct iatt *statpost, dict_t *xdata); + +int +args_ipc_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + dict_t *xdata); + +int +args_seek_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + off_t offset, dict_t *xdata); + +void +args_lease_cbk_store(default_args_cbk_t *args, int32_t op_ret, int32_t op_errno, + struct gf_lease *lease, dict_t *xdata); + +int +args_copy_file_range_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, struct iatt *stbuf, + struct iatt *prebuf_dst, + struct iatt *postbuf_dst, dict_t *xdata); + +void +args_cbk_wipe(default_args_cbk_t *args_cbk); + +void +args_wipe(default_args_t *args); + +int +args_lookup_store(default_args_t *args, loc_t *loc, dict_t *xdata); + +int +args_stat_store(default_args_t *args, loc_t *loc, dict_t *xdata); + +int +args_fstat_store(default_args_t *args, fd_t *fd, dict_t *xdata); + +int +args_truncate_store(default_args_t *args, loc_t *loc, off_t off, dict_t *xdata); +int +args_ftruncate_store(default_args_t *args, fd_t *fd, off_t off, dict_t *xdata); + +int +args_access_store(default_args_t *args, loc_t *loc, int32_t mask, + dict_t *xdata); + +int +args_readlink_store(default_args_t *args, loc_t *loc, size_t size, + dict_t *xdata); + +int +args_mknod_store(default_args_t *args, loc_t *loc, mode_t mode, dev_t rdev, + mode_t umask, dict_t *xdata); + +int +args_mkdir_store(default_args_t *args, loc_t *loc, mode_t mode, mode_t umask, + dict_t *xdata); + +int +args_unlink_store(default_args_t *args, loc_t *loc, int xflag, dict_t *xdata); + +int +args_rmdir_store(default_args_t *args, loc_t *loc, int flags, dict_t *xdata); + +int +args_symlink_store(default_args_t *args, const char *linkname, loc_t *loc, + mode_t umask, dict_t *xdata); + +int +args_rename_store(default_args_t *args, loc_t *oldloc, loc_t *newloc, + dict_t *xdata); + +int +args_link_store(default_args_t *args, loc_t *oldloc, loc_t *newloc, + dict_t *xdata); + +int +args_create_store(default_args_t *args, loc_t *loc, int32_t flags, mode_t mode, + mode_t umask, fd_t *fd, dict_t *xdata); + +int +args_open_store(default_args_t *args, loc_t *loc, int32_t flags, fd_t *fd, + dict_t *xdata); + +int +args_readv_store(default_args_t *args, fd_t *fd, size_t size, off_t off, + uint32_t flags, dict_t *xdata); + +int +args_writev_store(default_args_t *args, fd_t *fd, struct iovec *vector, + int32_t count, off_t off, uint32_t flags, + struct iobref *iobref, dict_t *xdata); + +int +args_put_store(default_args_t *args, loc_t *loc, mode_t mode, mode_t umask, + uint32_t flags, struct iovec *vector, int32_t count, off_t off, + struct iobref *iobref, dict_t *xattr, dict_t *xdata); + +int +args_flush_store(default_args_t *args, fd_t *fd, dict_t *xdata); + +int +args_fsync_store(default_args_t *args, fd_t *fd, int32_t datasync, + dict_t *xdata); + +int +args_opendir_store(default_args_t *args, loc_t *loc, fd_t *fd, dict_t *xdata); + +int +args_fsyncdir_store(default_args_t *args, fd_t *fd, int32_t datasync, + dict_t *xdata); + +int +args_statfs_store(default_args_t *args, loc_t *loc, dict_t *xdata); + +int +args_setxattr_store(default_args_t *args, loc_t *loc, dict_t *dict, + int32_t flags, dict_t *xdata); + +int +args_getxattr_store(default_args_t *args, loc_t *loc, const char *name, + dict_t *xdata); + +int +args_fsetxattr_store(default_args_t *args, fd_t *fd, dict_t *dict, + int32_t flags, dict_t *xdata); + +int +args_fgetxattr_store(default_args_t *args, fd_t *fd, const char *name, + dict_t *xdata); + +int +args_removexattr_store(default_args_t *args, loc_t *loc, const char *name, + dict_t *xdata); + +int +args_fremovexattr_store(default_args_t *args, fd_t *fd, const char *name, + dict_t *xdata); + +int +args_lk_store(default_args_t *args, fd_t *fd, int32_t cmd, + struct gf_flock *lock, dict_t *xdata); + +int +args_inodelk_store(default_args_t *args, const char *volume, loc_t *loc, + int32_t cmd, struct gf_flock *lock, dict_t *xdata); + +int +args_finodelk_store(default_args_t *args, const char *volume, fd_t *fd, + int32_t cmd, struct gf_flock *lock, dict_t *xdata); + +int +args_entrylk_store(default_args_t *args, const char *volume, loc_t *loc, + const char *name, entrylk_cmd cmd, entrylk_type type, + dict_t *xdata); + +int +args_fentrylk_store(default_args_t *args, const char *volume, fd_t *fd, + const char *name, entrylk_cmd cmd, entrylk_type type, + dict_t *xdata); +int +args_readdirp_store(default_args_t *args, fd_t *fd, size_t size, off_t off, + dict_t *xdata); + +int +args_readdir_store(default_args_t *args, fd_t *fd, size_t size, off_t off, + dict_t *xdata); + +int +args_rchecksum_store(default_args_t *args, fd_t *fd, off_t offset, int32_t len, + dict_t *xdata); + +int +args_xattrop_store(default_args_t *args, loc_t *loc, gf_xattrop_flags_t optype, + dict_t *xattr, dict_t *xdata); + +int +args_fxattrop_store(default_args_t *args, fd_t *fd, gf_xattrop_flags_t optype, + dict_t *xattr, dict_t *xdata); + +int +args_setattr_store(default_args_t *args, loc_t *loc, struct iatt *stbuf, + int32_t valid, dict_t *xdata); + +int +args_fsetattr_store(default_args_t *args, fd_t *fd, struct iatt *stbuf, + int32_t valid, dict_t *xdata); + +int +args_fallocate_store(default_args_t *args, fd_t *fd, int32_t mode, off_t offset, + size_t len, dict_t *xdata); + +int +args_discard_store(default_args_t *args, fd_t *fd, off_t offset, size_t len, + dict_t *xdata); + +int +args_zerofill_store(default_args_t *args, fd_t *fd, off_t offset, off_t len, + dict_t *xdata); + +int +args_ipc_store(default_args_t *args, int32_t op, dict_t *xdata); + +int +args_seek_store(default_args_t *args, fd_t *fd, off_t offset, + gf_seek_what_t what, dict_t *xdata); + +void +args_lease_store(default_args_t *args, loc_t *loc, struct gf_lease *lease, + dict_t *xdata); + +int +args_getactivelk_cbk_store(default_args_cbk_t *args, int32_t op_ret, + int32_t op_errno, lock_migration_info_t *locklist, + dict_t *xdata); + +int +args_setactivelk_store(default_args_t *args, loc_t *loc, + lock_migration_info_t *locklist, dict_t *xdata); + +int +args_icreate_store(default_args_t *args, loc_t *loc, mode_t mode, + dict_t *xdata); + +int +args_namelink_store(default_args_t *args, loc_t *loc, dict_t *xdata); + +int +args_copy_file_range_store(default_args_t *args, fd_t *fd_in, off64_t off_in, + fd_t *fd_out, off_t off64_out, size_t len, + uint32_t flags, dict_t *xdata); + +void +args_cbk_init(default_args_cbk_t *args_cbk); +#endif /* _DEFAULT_ARGS_H */ diff --git a/libglusterfs/src/glusterfs/defaults.h b/libglusterfs/src/glusterfs/defaults.h new file mode 100644 index 00000000000..5a818eeb91a --- /dev/null +++ b/libglusterfs/src/glusterfs/defaults.h @@ -0,0 +1,1275 @@ +/* + Copyright (c) 2008-2015 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +/* libglusterfs/src/defaults.h: + This file contains definition of default fops and mops functions. +*/ + +#ifndef _DEFAULTS_H +#define _DEFAULTS_H + +#include "glusterfs/xlator.h" + +typedef struct { + int op_ret; + int op_errno; + inode_t *inode; + struct iatt stat; + struct iatt prestat; + struct iatt poststat; + struct iatt preparent; /* @preoldparent in rename_cbk */ + struct iatt postparent; /* @postoldparent in rename_cbk */ + struct iatt preparent2; /* @prenewparent in rename_cbk */ + struct iatt postparent2; /* @postnewparent in rename_cbk */ + const char *buf; + struct iovec *vector; + int count; + struct iobref *iobref; + fd_t *fd; + struct statvfs statvfs; + dict_t *xattr; + struct gf_flock lock; + uint32_t weak_checksum; + uint8_t *strong_checksum; + dict_t *xdata; + gf_dirent_t entries; + off_t offset; /* seek hole/data */ + int valid; /* If the response is valid or not. For call-stub it is + always valid irrespective of this */ + struct gf_lease lease; + lock_migration_info_t locklist; +} default_args_cbk_t; + +typedef struct { + loc_t loc; /* @old in rename(), link() */ + loc_t loc2; /* @new in rename(), link() */ + fd_t *fd; /* for all the fd based ops */ + fd_t *fd_dst; /* Only for copy_file_range destination */ + off_t offset; + /* + * According to the man page of copy_file_range, + * the offsets for source and destination file + * are of type loff_t. But the type loff_t is + * linux specific and is actual a typedef of + * off64_t. + */ + off64_t off_in; /* For copy_file_range source fd */ + off64_t off_out; /* For copy_file_range destination fd only */ + int mask; + size_t size; + mode_t mode; + dev_t rdev; + mode_t umask; + int xflag; + int flags; + const char *linkname; + struct iovec *vector; + int count; + struct iobref *iobref; + int datasync; + dict_t *xattr; + const char *name; + int cmd; + struct gf_flock lock; + const char *volume; + entrylk_cmd entrylkcmd; + entrylk_type entrylktype; + gf_xattrop_flags_t optype; + int valid; + struct iatt stat; + gf_seek_what_t what; + dict_t *xdata; + struct gf_lease lease; + lock_migration_info_t locklist; +} default_args_t; + +typedef struct { + int fop_enum; + unsigned int fop_length; + int *enum_list; + default_args_t *req_list; + dict_t *xdata; +} compound_args_t; + +typedef struct { + int fop_enum; + unsigned int fop_length; + int *enum_list; + default_args_cbk_t *rsp_list; + dict_t *xdata; +} compound_args_cbk_t; + +int32_t +default_notify(xlator_t *this, int32_t event, void *data, ...); + +int32_t +default_forget(xlator_t *this, inode_t *inode); + +int32_t +default_release(xlator_t *this, fd_t *fd); + +int32_t +default_releasedir(xlator_t *this, fd_t *fd); + +extern struct xlator_fops *default_fops; + +/* Management Operations */ + +int32_t +default_getspec(call_frame_t *frame, xlator_t *this, const char *key, + int32_t flag); + +int32_t +default_rchecksum(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, + int32_t len, dict_t *xdata); + +/* FileSystem operations */ +int32_t +default_lookup(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata); + +int32_t +default_stat(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata); + +int32_t +default_fstat(call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *xdata); + +int32_t +default_truncate(call_frame_t *frame, xlator_t *this, loc_t *loc, off_t offset, + dict_t *xdata); + +int32_t +default_ftruncate(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, + dict_t *xdata); + +int32_t +default_access(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t mask, + dict_t *xdata); + +int32_t +default_readlink(call_frame_t *frame, xlator_t *this, loc_t *loc, size_t size, + dict_t *xdata); + +int32_t +default_mknod(call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, + dev_t rdev, mode_t umask, dict_t *xdata); + +int32_t +default_mkdir(call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, + mode_t umask, dict_t *xdata); + +int32_t +default_unlink(call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag, + dict_t *xdata); + +int32_t +default_rmdir(call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag, + dict_t *xdata); + +int32_t +default_symlink(call_frame_t *frame, xlator_t *this, const char *linkpath, + loc_t *loc, mode_t umask, dict_t *xdata); + +int32_t +default_rename(call_frame_t *frame, xlator_t *this, loc_t *oldloc, + loc_t *newloc, dict_t *xdata); + +int32_t +default_link(call_frame_t *frame, xlator_t *this, loc_t *oldloc, loc_t *newloc, + dict_t *xdata); + +int32_t +default_create(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + mode_t mode, mode_t umask, fd_t *fd, dict_t *xdata); + +int32_t +default_open(call_frame_t *frame, xlator_t *this, loc_t *loc, int32_t flags, + fd_t *fd, dict_t *xdata); + +int32_t +default_readv(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, + off_t offset, uint32_t flags, dict_t *xdata); + +int32_t +default_writev(call_frame_t *frame, xlator_t *this, fd_t *fd, + struct iovec *vector, int32_t count, off_t offset, + uint32_t flags, struct iobref *iobref, dict_t *xdata); + +int32_t +default_flush(call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *xdata); + +int32_t +default_fsync(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t datasync, + dict_t *xdata); + +int32_t +default_opendir(call_frame_t *frame, xlator_t *this, loc_t *loc, fd_t *fd, + dict_t *xdata); + +int32_t +default_fsyncdir(call_frame_t *frame, xlator_t *this, fd_t *fd, + int32_t datasync, dict_t *xdata); + +int32_t +default_statfs(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *xdata); + +int32_t +default_setxattr(call_frame_t *frame, xlator_t *this, loc_t *loc, dict_t *dict, + int32_t flags, dict_t *xdata); + +int32_t +default_getxattr(call_frame_t *frame, xlator_t *this, loc_t *loc, + const char *name, dict_t *xdata); + +int32_t +default_fsetxattr(call_frame_t *frame, xlator_t *this, fd_t *fd, dict_t *dict, + int32_t flags, dict_t *xdata); + +int32_t +default_fgetxattr(call_frame_t *frame, xlator_t *this, fd_t *fd, + const char *name, dict_t *xdata); + +int32_t +default_removexattr(call_frame_t *frame, xlator_t *this, loc_t *loc, + const char *name, dict_t *xdata); + +int32_t +default_fremovexattr(call_frame_t *frame, xlator_t *this, fd_t *fd, + const char *name, dict_t *xdata); + +int32_t +default_lk(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t cmd, + struct gf_flock *flock, dict_t *xdata); + +int32_t +default_inodelk(call_frame_t *frame, xlator_t *this, const char *volume, + loc_t *loc, int32_t cmd, struct gf_flock *flock, dict_t *xdata); + +int32_t +default_finodelk(call_frame_t *frame, xlator_t *this, const char *volume, + fd_t *fd, int32_t cmd, struct gf_flock *flock, dict_t *xdata); + +int32_t +default_entrylk(call_frame_t *frame, xlator_t *this, const char *volume, + loc_t *loc, const char *basename, entrylk_cmd cmd, + entrylk_type type, dict_t *xdata); + +int32_t +default_fentrylk(call_frame_t *frame, xlator_t *this, const char *volume, + fd_t *fd, const char *basename, entrylk_cmd cmd, + entrylk_type type, dict_t *xdata); + +int32_t +default_readdir(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, + off_t off, dict_t *xdata); + +int32_t +default_readdirp(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, + off_t off, dict_t *xdata); + +int32_t +default_xattrop(call_frame_t *frame, xlator_t *this, loc_t *loc, + gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata); + +int32_t +default_fxattrop(call_frame_t *frame, xlator_t *this, fd_t *fd, + gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata); + +int32_t +default_setattr(call_frame_t *frame, xlator_t *this, loc_t *loc, + struct iatt *stbuf, int32_t valid, dict_t *xdata); + +int32_t +default_fsetattr(call_frame_t *frame, xlator_t *this, fd_t *fd, + 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, + off_t len, dict_t *xdata); + +int32_t +default_ipc(call_frame_t *frame, xlator_t *this, int32_t op, dict_t *xdata); + +int32_t +default_seek(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, + gf_seek_what_t what, dict_t *xdata); + +int32_t +default_lease(call_frame_t *frame, xlator_t *this, loc_t *loc, + struct gf_lease *lease, dict_t *xdata); + +int32_t +default_getactivelk(call_frame_t *frame, xlator_t *this, loc_t *loc, + dict_t *xdata); + +int32_t +default_setactivelk(call_frame_t *frame, xlator_t *this, loc_t *loc, + lock_migration_info_t *locklist, dict_t *xdata); + +int32_t +default_put(call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, + mode_t umask, uint32_t flags, struct iovec *vector, int32_t count, + off_t off, struct iobref *iobref, dict_t *xattr, dict_t *xdata); + +int32_t +default_icreate(call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, + dict_t *xdata); + +int32_t +default_namelink(call_frame_t *frame, xlator_t *this, loc_t *loc, + dict_t *xdata); + +int32_t +default_copy_file_range(call_frame_t *frame, xlator_t *this, fd_t *fd_in, + off64_t off_in, fd_t *fd_out, off64_t off_out, + size_t len, uint32_t flags, dict_t *xdata); + +/* Resume */ +int32_t +default_getspec_resume(call_frame_t *frame, xlator_t *this, const char *key, + int32_t flag); + +int32_t +default_rchecksum_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, + off_t offset, int32_t len, dict_t *xdata); + +/* FileSystem operations */ +int32_t +default_lookup_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + dict_t *xdata); + +int32_t +default_stat_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + dict_t *xdata); + +int32_t +default_fstat_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, + dict_t *xdata); + +int32_t +default_truncate_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + off_t offset, dict_t *xdata); + +int32_t +default_ftruncate_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, + off_t offset, dict_t *xdata); + +int32_t +default_access_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + int32_t mask, dict_t *xdata); + +int32_t +default_readlink_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + size_t size, dict_t *xdata); + +int32_t +default_mknod_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + mode_t mode, dev_t rdev, mode_t umask, dict_t *xdata); + +int32_t +default_mkdir_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + mode_t mode, mode_t umask, dict_t *xdata); + +int32_t +default_unlink_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + int xflag, dict_t *xdata); + +int32_t +default_rmdir_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, int xflag, + dict_t *xdata); + +int32_t +default_symlink_resume(call_frame_t *frame, xlator_t *this, + const char *linkpath, loc_t *loc, mode_t umask, + dict_t *xdata); + +int32_t +default_rename_resume(call_frame_t *frame, xlator_t *this, loc_t *oldloc, + loc_t *newloc, dict_t *xdata); + +int32_t +default_link_resume(call_frame_t *frame, xlator_t *this, loc_t *oldloc, + loc_t *newloc, dict_t *xdata); + +int32_t +default_create_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + int32_t flags, mode_t mode, mode_t umask, fd_t *fd, + dict_t *xdata); + +int32_t +default_open_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + int32_t flags, fd_t *fd, dict_t *xdata); + +int32_t +default_readv_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, size_t size, + off_t offset, uint32_t flags, dict_t *xdata); + +int32_t +default_writev_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, + struct iovec *vector, int32_t count, off_t offset, + uint32_t flags, struct iobref *iobref, dict_t *xdata); + +int32_t +default_flush_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, + dict_t *xdata); + +int32_t +default_fsync_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, + int32_t datasync, dict_t *xdata); + +int32_t +default_opendir_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + fd_t *fd, dict_t *xdata); + +int32_t +default_fsyncdir_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, + int32_t datasync, dict_t *xdata); + +int32_t +default_statfs_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + dict_t *xdata); + +int32_t +default_setxattr_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + dict_t *dict, int32_t flags, dict_t *xdata); + +int32_t +default_getxattr_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + const char *name, dict_t *xdata); + +int32_t +default_fsetxattr_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, + dict_t *dict, int32_t flags, dict_t *xdata); + +int32_t +default_fgetxattr_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, + const char *name, dict_t *xdata); + +int32_t +default_removexattr_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + const char *name, dict_t *xdata); + +int32_t +default_fremovexattr_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, + const char *name, dict_t *xdata); + +int32_t +default_lk_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, int32_t cmd, + struct gf_flock *flock, dict_t *xdata); + +int32_t +default_inodelk_resume(call_frame_t *frame, xlator_t *this, const char *volume, + loc_t *loc, int32_t cmd, struct gf_flock *flock, + dict_t *xdata); + +int32_t +default_finodelk_resume(call_frame_t *frame, xlator_t *this, const char *volume, + fd_t *fd, int32_t cmd, struct gf_flock *flock, + dict_t *xdata); + +int32_t +default_entrylk_resume(call_frame_t *frame, xlator_t *this, const char *volume, + loc_t *loc, const char *basename, entrylk_cmd cmd, + entrylk_type type, dict_t *xdata); + +int32_t +default_fentrylk_resume(call_frame_t *frame, xlator_t *this, const char *volume, + fd_t *fd, const char *basename, entrylk_cmd cmd, + entrylk_type type, dict_t *xdata); + +int32_t +default_readdir_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, + size_t size, off_t off, dict_t *xdata); + +int32_t +default_readdirp_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, + size_t size, off_t off, dict_t *xdata); + +int32_t +default_xattrop_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata); + +int32_t +default_fxattrop_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, + gf_xattrop_flags_t flags, dict_t *dict, dict_t *xdata); +int32_t +default_rchecksum_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, + off_t offset, int32_t len, dict_t *xdata); + +int32_t +default_setattr_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + struct iatt *stbuf, int32_t valid, dict_t *xdata); + +int32_t +default_fsetattr_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, + 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, off_t len, dict_t *xdata); + +int32_t +default_ipc_resume(call_frame_t *frame, xlator_t *this, int32_t op, + dict_t *xdata); + +int32_t +default_seek_resume(call_frame_t *frame, xlator_t *this, fd_t *fd, off_t offset, + gf_seek_what_t what, dict_t *xdata); + +int32_t +default_lease_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + struct gf_lease *lease, dict_t *xdata); + +int32_t +default_getactivelk_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + dict_t *xdata); + +int32_t +default_setactivelk_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + lock_migration_info_t *locklist, dict_t *xdata); + +int32_t +default_put_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, mode_t mode, + mode_t umask, uint32_t flags, struct iovec *vector, + int32_t count, off_t off, struct iobref *iobref, + dict_t *xattr, dict_t *xdata); + +int32_t +default_copy_file_range_resume(call_frame_t *frame, xlator_t *this, fd_t *fd_in, + off_t off64_in, fd_t *fd_out, off64_t off_out, + size_t len, uint32_t flags, dict_t *xdata); + +/* _cbk_resume */ + +int32_t +default_lookup_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, dict_t *xdata, + struct iatt *postparent); + +int32_t +default_stat_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *buf, + dict_t *xdata); + +int32_t +default_truncate_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + struct iatt *prebuf, struct iatt *postbuf, + dict_t *xdata); + +int32_t +default_ftruncate_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + struct iatt *prebuf, struct iatt *postbuf, + dict_t *xdata); + +int32_t +default_access_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_readlink_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, const char *path, + struct iatt *buf, dict_t *xdata); + +int32_t +default_mknod_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +int32_t +default_mkdir_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +int32_t +default_unlink_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + struct iatt *preparent, struct iatt *postparent, + dict_t *xdata); + +int32_t +default_rmdir_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + struct iatt *preparent, struct iatt *postparent, + dict_t *xdata); + +int32_t +default_symlink_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +int32_t +default_rename_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *buf, + struct iatt *preoldparent, struct iatt *postoldparent, + struct iatt *prenewparent, struct iatt *postnewparent, + dict_t *xdata); + +int32_t +default_link_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +int32_t +default_create_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd, + inode_t *inode, struct iatt *buf, + struct iatt *preparent, struct iatt *postparent, + dict_t *xdata); + +int32_t +default_open_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd, + dict_t *xdata); + +int32_t +default_readv_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iovec *vector, + int32_t count, struct iatt *stbuf, + struct iobref *iobref, dict_t *xdata); + +int32_t +default_writev_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata); + +int32_t +default_flush_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_fsync_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata); + +int32_t +default_fstat_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *buf, + dict_t *xdata); + +int32_t +default_opendir_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd, + dict_t *xdata); + +int32_t +default_fsyncdir_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_statfs_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct statvfs *buf, + dict_t *xdata); + +int32_t +default_setxattr_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_fsetxattr_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_fgetxattr_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata); + +int32_t +default_getxattr_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata); + +int32_t +default_xattrop_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata); + +int32_t +default_fxattrop_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata); + +int32_t +default_removexattr_cbk_resume(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, int32_t op_errno, + dict_t *xdata); + +int32_t +default_fremovexattr_cbk_resume(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +int32_t +default_lk_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct gf_flock *lock, + dict_t *xdata); + +int32_t +default_inodelk_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_finodelk_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_entrylk_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_fentrylk_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_rchecksum_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + uint32_t weak_checksum, uint8_t *strong_checksum, + dict_t *xdata); + +int32_t +default_readdir_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + gf_dirent_t *entries, dict_t *xdata); + +int32_t +default_readdirp_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + gf_dirent_t *entries, dict_t *xdata); + +int32_t +default_setattr_cbk_resume(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_fsetattr_cbk_resume(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_resume(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_resume(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_resume(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_ipc_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_seek_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, off_t offset, + dict_t *xdata); + +int32_t +default_getspec_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, char *spec_data); + +int32_t +default_lease_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + struct gf_lease *lease, dict_t *xdata); + +int32_t +default_getactivelk_cbk_resume(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, int32_t op_errno, + lock_migration_info_t *locklist, dict_t *xdata); + +int32_t +default_setactivelk_cbk_resume(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, int32_t op_errno, + dict_t *xdata); + +int32_t +default_put_cbk_resume(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +int32_t +default_icreate_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + mode_t mode, dict_t *xdata); + +int32_t +default_namelink_resume(call_frame_t *frame, xlator_t *this, loc_t *loc, + dict_t *xdata); + +int32_t +default_copy_file_range_cbk_resume(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, struct iatt *stbuf, + struct iatt *prebuf_dst, + struct iatt *postbuf_dst, dict_t *xdata); + +/* _CBK */ +int32_t +default_lookup_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, dict_t *xdata, struct iatt *postparent); + +int32_t +default_stat_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *buf, + dict_t *xdata); + +int32_t +default_truncate_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata); + +int32_t +default_ftruncate_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata); + +int32_t +default_access_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_readlink_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, const char *path, + struct iatt *buf, dict_t *xdata); + +int32_t +default_mknod_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +int32_t +default_mkdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +int32_t +default_unlink_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +int32_t +default_rmdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +int32_t +default_symlink_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +int32_t +default_rename_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *buf, + struct iatt *preoldparent, struct iatt *postoldparent, + struct iatt *prenewparent, struct iatt *postnewparent, + dict_t *xdata); + +int32_t +default_link_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +int32_t +default_create_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +int32_t +default_open_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd, dict_t *xdata); + +int32_t +default_readv_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iovec *vector, + int32_t count, struct iatt *stbuf, struct iobref *iobref, + dict_t *xdata); + +int32_t +default_writev_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata); + +int32_t +default_flush_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_fsync_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata); + +int32_t +default_fstat_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *buf, + dict_t *xdata); + +int32_t +default_opendir_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd, dict_t *xdata); + +int32_t +default_fsyncdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_statfs_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct statvfs *buf, + dict_t *xdata); + +int32_t +default_setxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_fsetxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_fgetxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata); + +int32_t +default_getxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata); + +int32_t +default_xattrop_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata); + +int32_t +default_fxattrop_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata); + +int32_t +default_removexattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_fremovexattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_lk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct gf_flock *lock, + dict_t *xdata); + +int32_t +default_inodelk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_finodelk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_entrylk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_fentrylk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_rchecksum_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, uint32_t weak_checksum, + uint8_t *strong_checksum, dict_t *xdata); + +int32_t +default_readdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, gf_dirent_t *entries, + dict_t *xdata); + +int32_t +default_readdirp_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, gf_dirent_t *entries, + dict_t *xdata); + +int32_t +default_setattr_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_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_ipc_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_seek_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, off_t offset, 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); + +int32_t +default_lease_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct gf_lease *lease, + dict_t *xdata); + +int32_t +default_getactivelk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + lock_migration_info_t *locklist, dict_t *xdata); + +int32_t +default_setactivelk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int32_t +default_put_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +int32_t +default_icreate_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, dict_t *xdata); + +int32_t +default_namelink_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata); + +int32_t +default_copy_file_range_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + struct iatt *stbuf, struct iatt *prebuf_dst, + struct iatt *postbuf_dst, dict_t *xdata); + +int32_t +default_lookup_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_stat_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_truncate_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_ftruncate_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_access_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_readlink_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_mknod_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_mkdir_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_unlink_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_rmdir_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_symlink_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_rename_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_link_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_create_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_open_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_readv_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_writev_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_flush_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_fsync_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_fstat_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_opendir_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_fsyncdir_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_statfs_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_setxattr_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_fsetxattr_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_fgetxattr_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_getxattr_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_xattrop_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_fxattrop_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_removexattr_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_fremovexattr_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_lk_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_inodelk_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_finodelk_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_entrylk_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_fentrylk_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_rchecksum_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_readdir_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_readdirp_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_setattr_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_fsetattr_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_fallocate_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_discard_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_zerofill_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_getspec_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_ipc_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_seek_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_lease_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_getactivelk_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_setactivelk_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_put_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_icreate_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_namelink_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_copy_file_range_failure_cbk(call_frame_t *frame, int32_t op_errno); + +int32_t +default_mem_acct_init(xlator_t *this); + +void +default_fini(xlator_t *this); + +#endif /* _DEFAULTS_H */ diff --git a/libglusterfs/src/glusterfs/dict.h b/libglusterfs/src/glusterfs/dict.h new file mode 100644 index 00000000000..d0467c6dfb6 --- /dev/null +++ b/libglusterfs/src/glusterfs/dict.h @@ -0,0 +1,420 @@ +/* + 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 _DICT_H +#define _DICT_H + +#include <inttypes.h> +#include <sys/uio.h> +#include <pthread.h> + +#include "glusterfs/common-utils.h" + +typedef struct _data data_t; +typedef struct _dict dict_t; +typedef struct _data_pair data_pair_t; + +#define dict_set_sizen(this, key, value) dict_setn(this, key, SLEN(key), value) + +#define dict_add_sizen(this, key, value) dict_addn(this, key, SLEN(key), value) + +#define dict_get_sizen(this, key) dict_getn(this, key, SLEN(key)) + +#define dict_del_sizen(this, key) dict_deln(this, key, SLEN(key)) + +#define dict_set_str_sizen(this, key, str) \ + dict_set_strn(this, key, SLEN(key), str) + +#define dict_set_sizen_str_sizen(this, key, str) \ + dict_set_nstrn(this, key, SLEN(key), str, SLEN(str)) + +#define dict_set_dynstr_sizen(this, key, str) \ + dict_set_dynstrn(this, key, SLEN(key), str) + +#define dict_get_str_sizen(this, key, str) \ + dict_get_strn(this, key, SLEN(key), str) + +#define dict_get_int32_sizen(this, key, val) \ + dict_get_int32n(this, key, SLEN(key), val) + +#define dict_set_int32_sizen(this, key, val) \ + dict_set_int32n(this, key, SLEN(key), val) + +#define GF_PROTOCOL_DICT_SERIALIZE(this, from_dict, to, len, ope, labl) \ + do { \ + int _ret = 0; \ + \ + if (!from_dict) \ + break; \ + \ + _ret = dict_allocate_and_serialize(from_dict, to, &len); \ + if (_ret < 0) { \ + gf_msg(this->name, GF_LOG_WARNING, 0, LG_MSG_DICT_SERIAL_FAILED, \ + "failed to get serialized dict (%s)", (#from_dict)); \ + ope = EINVAL; \ + goto labl; \ + } \ + } while (0) + +#define GF_PROTOCOL_DICT_UNSERIALIZE(xl, to, buff, len, ret, ope, labl) \ + do { \ + if (!len) \ + break; \ + to = dict_new(); \ + GF_VALIDATE_OR_GOTO(xl->name, to, labl); \ + \ + ret = dict_unserialize(buff, len, &to); \ + if (ret < 0) { \ + gf_msg(xl->name, GF_LOG_WARNING, 0, LG_MSG_DICT_UNSERIAL_FAILED, \ + "failed to unserialize dictionary (%s)", (#to)); \ + \ + ope = EINVAL; \ + goto labl; \ + } \ + \ + } while (0) + +#define dict_foreach_inline(d, c) for (c = d->members_list; c; c = c->next) + +#define DICT_KEY_VALUE_MAX_SIZE 1048576 +#define DICT_MAX_FLAGS 256 +#define DICT_FLAG_SET 1 +#define DICT_FLAG_CLEAR 0 +#define DICT_HDR_LEN 4 +#define DICT_DATA_HDR_KEY_LEN 4 +#define DICT_DATA_HDR_VAL_LEN 4 + +struct _data { + char *data; + gf_atomic_t refcount; + gf_dict_data_type_t data_type; + uint32_t len; + gf_boolean_t is_static; +}; + +struct _data_pair { + struct _data_pair *hash_next; + struct _data_pair *prev; + struct _data_pair *next; + data_t *value; + char *key; + uint32_t key_hash; +}; + +struct _dict { + uint64_t max_count; + int32_t hash_size; + int32_t count; + gf_atomic_t refcount; + data_pair_t **members; + data_pair_t *members_list; + char *extra_stdfree; + gf_lock_t lock; + data_pair_t *members_internal; + data_pair_t free_pair; + /* Variable to store total keylen + value->len */ + uint32_t totkvlen; +}; + +typedef gf_boolean_t (*dict_match_t)(dict_t *d, char *k, data_t *v, void *data); + +int32_t +is_data_equal(data_t *one, data_t *two); +void +data_destroy(data_t *data); + +/* function to set a key/value pair (overwrite existing if matches the key */ +int32_t +dict_set(dict_t *this, char *key, data_t *value); +int32_t +dict_setn(dict_t *this, char *key, const int keylen, data_t *value); + +/* function to set a new key/value pair (without checking for duplicate) */ +int32_t +dict_add(dict_t *this, char *key, data_t *value); +int32_t +dict_addn(dict_t *this, char *key, const int keylen, data_t *value); +int +dict_get_with_ref(dict_t *this, char *key, data_t **data); +data_t * +dict_get(dict_t *this, char *key); +data_t * +dict_getn(dict_t *this, char *key, const int keylen); +void +dict_del(dict_t *this, char *key); +void +dict_deln(dict_t *this, char *key, const int keylen); +int +dict_reset(dict_t *dict); + +int +dict_key_count(dict_t *this); + +int32_t +dict_serialized_length(dict_t *dict); +int32_t +dict_serialize(dict_t *dict, char *buf); +int32_t +dict_unserialize(char *buf, int32_t size, dict_t **fill); + +int32_t +dict_allocate_and_serialize(dict_t *this, char **buf, u_int *length); + +void +dict_unref(dict_t *dict); +dict_t * +dict_ref(dict_t *dict); +data_t * +data_ref(data_t *data); +void +data_unref(data_t *data); + +int32_t +dict_lookup(dict_t *this, char *key, data_t **data); +/* + TODO: provide converts for different byte sizes, signedness, and void * + */ +data_t * +int_to_data(int64_t value); +data_t * +str_to_data(char *value); +data_t * +strn_to_data(char *value, const int vallen); +data_t * +data_from_dynptr(void *value, int32_t len); +data_t * +bin_to_data(void *value, int32_t len); +data_t * +static_str_to_data(char *value); +data_t * +static_bin_to_data(void *value); + +int64_t +data_to_int64(data_t *data); +int32_t +data_to_int32(data_t *data); +int16_t +data_to_int16(data_t *data); +int8_t +data_to_int8(data_t *data); + +uint64_t +data_to_uint64(data_t *data); +uint32_t +data_to_uint32(data_t *data); +uint16_t +data_to_uint16(data_t *data); +uint8_t +data_to_uint8(data_t *data); + +data_t * +data_from_int64(int64_t value); +data_t * +data_from_int32(int32_t value); +data_t * +data_from_int16(int16_t value); +data_t * +data_from_int8(int8_t value); + +data_t * +data_from_uint64(uint64_t value); +data_t * +data_from_uint32(uint32_t value); +data_t * +data_from_uint16(uint16_t value); + +char * +data_to_str(data_t *data); +void * +data_to_bin(data_t *data); +void * +data_to_ptr(data_t *data); +data_t * +data_copy(data_t *old); +struct iatt * +data_to_iatt(data_t *data, char *key); + +int +dict_foreach(dict_t *this, + int (*fn)(dict_t *this, char *key, data_t *value, void *data), + void *data); + +int +dict_foreach_fnmatch(dict_t *dict, char *pattern, + int (*fn)(dict_t *this, char *key, data_t *value, + void *data), + void *data); + +int +dict_foreach_match(dict_t *dict, + gf_boolean_t (*match)(dict_t *this, char *key, data_t *value, + void *mdata), + void *match_data, + int (*action)(dict_t *this, char *key, data_t *value, + void *adata), + void *action_data); + +int +dict_null_foreach_fn(dict_t *d, char *k, data_t *v, void *tmp); +int +dict_remove_foreach_fn(dict_t *d, char *k, data_t *v, void *tmp); +dict_t * +dict_copy(dict_t *this, dict_t *new); +int +dict_keys_join(void *value, int size, dict_t *dict, + int (*filter_fn)(char *key)); + +/* CLEANED UP FUNCTIONS DECLARATIONS */ +GF_MUST_CHECK dict_t * +dict_new(void); +dict_t * +dict_copy_with_ref(dict_t *this, dict_t *new); + +GF_MUST_CHECK int +dict_reset(dict_t *dict); + +GF_MUST_CHECK int +dict_get_int8(dict_t *this, char *key, int8_t *val); +GF_MUST_CHECK int +dict_set_int8(dict_t *this, char *key, int8_t val); + +GF_MUST_CHECK int +dict_get_int16(dict_t *this, char *key, int16_t *val); +GF_MUST_CHECK int +dict_set_int16(dict_t *this, char *key, int16_t val); + +GF_MUST_CHECK int +dict_get_int32(dict_t *this, char *key, int32_t *val); +GF_MUST_CHECK int +dict_get_int32n(dict_t *this, char *key, const int keylen, int32_t *val); +GF_MUST_CHECK int +dict_set_int32(dict_t *this, char *key, int32_t val); +GF_MUST_CHECK int +dict_set_int32n(dict_t *this, char *key, const int keylen, int32_t val); + +GF_MUST_CHECK int +dict_get_int64(dict_t *this, char *key, int64_t *val); +GF_MUST_CHECK int +dict_set_int64(dict_t *this, char *key, int64_t val); + +GF_MUST_CHECK int +dict_get_uint16(dict_t *this, char *key, uint16_t *val); +GF_MUST_CHECK int +dict_set_uint16(dict_t *this, char *key, uint16_t val); + +GF_MUST_CHECK int +dict_get_uint32(dict_t *this, char *key, uint32_t *val); +GF_MUST_CHECK int +dict_set_uint32(dict_t *this, char *key, uint32_t val); + +GF_MUST_CHECK int +dict_get_uint64(dict_t *this, char *key, uint64_t *val); +GF_MUST_CHECK int +dict_set_uint64(dict_t *this, char *key, uint64_t val); + +GF_MUST_CHECK int +dict_check_flag(dict_t *this, char *key, int flag); +GF_MUST_CHECK int +dict_set_flag(dict_t *this, char *key, int flag); +GF_MUST_CHECK int +dict_clear_flag(dict_t *this, char *key, int flag); + +GF_MUST_CHECK int +dict_get_double(dict_t *this, char *key, double *val); +GF_MUST_CHECK int +dict_set_double(dict_t *this, char *key, double val); + +GF_MUST_CHECK int +dict_set_static_ptr(dict_t *this, char *key, void *ptr); +GF_MUST_CHECK int +dict_get_ptr(dict_t *this, char *key, void **ptr); +GF_MUST_CHECK int +dict_get_ptr_and_len(dict_t *this, char *key, void **ptr, int *len); +GF_MUST_CHECK int +dict_set_dynptr(dict_t *this, char *key, void *ptr, size_t size); + +GF_MUST_CHECK int +dict_get_bin(dict_t *this, char *key, void **ptr); +GF_MUST_CHECK int +dict_set_bin(dict_t *this, char *key, void *ptr, size_t size); +GF_MUST_CHECK int +dict_set_static_bin(dict_t *this, char *key, void *ptr, size_t size); + +GF_MUST_CHECK int +dict_set_option(dict_t *this, char *key, char *str); +GF_MUST_CHECK int +dict_set_str(dict_t *this, char *key, char *str); +GF_MUST_CHECK int +dict_set_strn(dict_t *this, char *key, const int keylen, char *str); +GF_MUST_CHECK int +dict_set_nstrn(dict_t *this, char *key, const int keylen, char *str, + const int vallen); +GF_MUST_CHECK int +dict_set_dynstr(dict_t *this, char *key, char *str); +GF_MUST_CHECK int +dict_set_dynstrn(dict_t *this, char *key, const int keylen, char *str); +GF_MUST_CHECK int +dict_set_dynstr_with_alloc(dict_t *this, char *key, const char *str); +GF_MUST_CHECK int +dict_add_dynstr_with_alloc(dict_t *this, char *key, char *str); +GF_MUST_CHECK int +dict_get_str(dict_t *this, char *key, char **str); +GF_MUST_CHECK int +dict_get_strn(dict_t *this, char *key, const int keylen, char **str); + +GF_MUST_CHECK int +dict_get_str_boolean(dict_t *this, char *key, int default_val); +GF_MUST_CHECK int +dict_rename_key(dict_t *this, char *key, char *replace_key); +GF_MUST_CHECK int +dict_serialize_value_with_delim(dict_t *this, char *buf, int32_t *serz_len, + char delimiter); + +GF_MUST_CHECK int +dict_set_gfuuid(dict_t *this, char *key, uuid_t uuid, bool is_static); +GF_MUST_CHECK int +dict_get_gfuuid(dict_t *this, char *key, uuid_t *uuid); + +GF_MUST_CHECK int +dict_set_iatt(dict_t *this, char *key, struct iatt *iatt, bool is_static); +GF_MUST_CHECK int +dict_get_iatt(dict_t *this, char *key, struct iatt *iatt); +GF_MUST_CHECK int +dict_set_mdata(dict_t *this, char *key, struct mdata_iatt *mdata, + bool is_static); +GF_MUST_CHECK int +dict_get_mdata(dict_t *this, char *key, struct mdata_iatt *mdata); + +void +dict_dump_to_statedump(dict_t *dict, char *dict_name, char *domain); + +void +dict_dump_to_log(dict_t *dict); + +int +dict_dump_to_str(dict_t *dict, char *dump, int dumpsize, char *format); +gf_boolean_t +dict_match_everything(dict_t *d, char *k, data_t *v, void *data); + +dict_t * +dict_for_key_value(const char *name, const char *value, size_t size, + gf_boolean_t is_static); + +gf_boolean_t +are_dicts_equal(dict_t *one, dict_t *two, + gf_boolean_t (*match)(dict_t *d, char *k, data_t *v, + void *data), + gf_boolean_t (*value_ignore)(char *k)); +int +dict_has_key_from_array(dict_t *dict, char **strings, gf_boolean_t *result); + +int +dict_serialized_length_lk(dict_t *this); +#endif diff --git a/libglusterfs/src/glusterfs/event-history.h b/libglusterfs/src/glusterfs/event-history.h new file mode 100644 index 00000000000..f0e0422418e --- /dev/null +++ b/libglusterfs/src/glusterfs/event-history.h @@ -0,0 +1,40 @@ +/* + 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 _EH_H +#define _EH_H + +#include <pthread.h> // for pthread_mutex_t +#include <stddef.h> // for size_t +#include "glusterfs/circ-buff.h" // for buffer_t, circular_buffer_t +#include "glusterfs/glusterfs.h" // for gf_boolean_t + +struct event_hist { + buffer_t *buffer; + pthread_mutex_t lock; +}; + +typedef struct event_hist eh_t; + +void +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, + void (*destroy_data)(void *data)); + +int +eh_save_history(eh_t *history, void *string); + +int +eh_destroy(eh_t *history); + +#endif /* _EH_H */ diff --git a/libglusterfs/src/glusterfs/events.h b/libglusterfs/src/glusterfs/events.h new file mode 100644 index 00000000000..74c5326427b --- /dev/null +++ b/libglusterfs/src/glusterfs/events.h @@ -0,0 +1,34 @@ +/* + Copyright (c) 2016 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef __EVENTS_H__ +#define __EVENTS_H__ + +#include "eventtypes.h" + +#ifdef USE_EVENTS +int +_gf_event(eventtypes_t event, const char *fmt, ...) + __attribute__((__format__(__printf__, 2, 3))); +#else +__attribute__((__format__(__printf__, 2, 3))) static inline int +_gf_event(eventtypes_t event, const char *fmt, ...) +{ + return 0; +} +#endif /* USE_EVENTS */ + +#define gf_event(event, fmt...) \ + do { \ + FMT_WARN(fmt); \ + _gf_event(event, ##fmt); \ + } while (0) + +#endif /* __EVENTS_H__ */ diff --git a/libglusterfs/src/glusterfs/fd-lk.h b/libglusterfs/src/glusterfs/fd-lk.h new file mode 100644 index 00000000000..76cc680306a --- /dev/null +++ b/libglusterfs/src/glusterfs/fd-lk.h @@ -0,0 +1,59 @@ +/* + 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 _FD_LK_H +#define _FD_LK_H + +#include "glusterfs/fd.h" +#include "glusterfs/locking.h" +#include "glusterfs/list.h" +#include "glusterfs/glusterfs.h" + +#define get_lk_type(type) \ + type == F_UNLCK ? "F_UNLCK" : (type == F_RDLCK ? "F_RDLCK" : "F_WRLCK") + +#define get_lk_cmd(cmd) \ + cmd == F_SETLKW ? "F_SETLKW" : (cmd == F_SETLK ? "F_SETLK" : "F_GETLK") + +struct _fd; + +struct fd_lk_ctx { + struct list_head lk_list; + gf_atomic_t ref; + gf_lock_t lock; +}; +typedef struct fd_lk_ctx fd_lk_ctx_t; + +struct fd_lk_ctx_node { + int32_t cmd; + struct gf_flock user_flock; + off_t fl_start; + off_t fl_end; + short fl_type; + struct list_head next; +}; +typedef struct fd_lk_ctx_node fd_lk_ctx_node_t; + +fd_lk_ctx_t * +fd_lk_ctx_ref(fd_lk_ctx_t *lk_ctx); + +fd_lk_ctx_t * +fd_lk_ctx_create(void); + +int +fd_lk_insert_and_merge(struct _fd *lk_ctx, int32_t cmd, struct gf_flock *flock); + +int +fd_lk_ctx_unref(fd_lk_ctx_t *lk_ctx); + +gf_boolean_t +fd_lk_ctx_empty(fd_lk_ctx_t *lk_ctx); + +#endif /* _FD_LK_H */ diff --git a/libglusterfs/src/glusterfs/fd.h b/libglusterfs/src/glusterfs/fd.h new file mode 100644 index 00000000000..3ffaaa60504 --- /dev/null +++ b/libglusterfs/src/glusterfs/fd.h @@ -0,0 +1,169 @@ +/* + 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 _FD_H +#define _FD_H + +#include "glusterfs/list.h" +#include <sys/types.h> +#include <unistd.h> +#include "glusterfs/glusterfs.h" +#include "glusterfs/locking.h" +#include "glusterfs/fd-lk.h" + +#define GF_ANON_FD_NO -2 +#define GF_ANON_FD_FLAGS (O_RDWR | O_LARGEFILE) + +struct _inode; +struct _dict; +struct fd_lk_ctx; + +struct _fd_ctx { + union { + uint64_t key; + void *xl_key; + }; + union { + uint64_t value1; + void *ptr1; + }; +}; + +struct _fd { + uint64_t pid; + int32_t flags; + gf_atomic_t refcount; + struct list_head inode_list; + struct _inode *inode; + gf_lock_t lock; /* used ONLY for manipulating + 'struct _fd_ctx' array (_ctx).*/ + struct _fd_ctx *_ctx; + int xl_count; /* Number of xl referred in this fd */ + struct fd_lk_ctx *lk_ctx; + gf_boolean_t anonymous; /* fd which does not have counterpart open + fd on backend (server for client, posix + for server). */ +}; +typedef struct _fd fd_t; + +struct fd_table_entry { + fd_t *fd; + int next_free; +}; +typedef struct fd_table_entry fdentry_t; + +struct _fdtable { + int refcount; + uint32_t max_fds; + pthread_rwlock_t lock; + fdentry_t *fdentries; + int first_free; +}; +typedef struct _fdtable fdtable_t; + +/* Signifies no more entries in the fd table. */ +#define GF_FDTABLE_END -1 + +/* This is used to invalidated + * the next_free value in an fdentry that has been allocated + */ +#define GF_FDENTRY_ALLOCATED -2 + +#include "glusterfs/logging.h" +#include "glusterfs/xlator.h" + +void +gf_fd_put(fdtable_t *fdtable, int32_t fd); + +fd_t * +gf_fd_fdptr_get(fdtable_t *fdtable, int64_t fd); + +fdtable_t * +gf_fd_fdtable_alloc(void); + +int +gf_fd_unused_get(fdtable_t *fdtable, fd_t *fdptr); + +fdentry_t * +gf_fd_fdtable_get_all_fds(fdtable_t *fdtable, uint32_t *count); + +void +gf_fd_fdtable_destroy(fdtable_t *fdtable); + +fd_t * +__fd_ref(fd_t *fd); + +fd_t * +fd_ref(fd_t *fd); + +void +fd_unref(fd_t *fd); + +void +fd_close(fd_t *fd); + +fd_t * +fd_create(struct _inode *inode, pid_t pid); + +fd_t * +fd_create_uint64(struct _inode *inode, uint64_t pid); + +fd_t * +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, int32_t flags); + +fd_t * +fd_anonymous(inode_t *inode); + +fd_t * +fd_anonymous_with_flags(inode_t *inode, int32_t flags); + +gf_boolean_t +fd_is_anonymous(fd_t *fd); + +uint8_t +fd_list_empty(struct _inode *inode); + +fd_t * +fd_bind(fd_t *fd); + +int +fd_ctx_set(fd_t *fd, xlator_t *xlator, uint64_t value); + +int +fd_ctx_get(fd_t *fd, xlator_t *xlator, uint64_t *value); + +int +fd_ctx_del(fd_t *fd, xlator_t *xlator, uint64_t *value); + +int +__fd_ctx_del(fd_t *fd, xlator_t *xlator, uint64_t *value); + +int +__fd_ctx_set(fd_t *fd, xlator_t *xlator, uint64_t value); + +int +__fd_ctx_get(fd_t *fd, xlator_t *xlator, uint64_t *value); + +void +fd_ctx_dump(fd_t *fd, char *prefix); + +fdentry_t * +gf_fd_fdtable_copy_all_fds(fdtable_t *fdtable, uint32_t *count); + +void +gf_fdptr_put(fdtable_t *fdtable, fd_t *fd); + +#endif /* _FD_H */ diff --git a/libglusterfs/src/glusterfs/gf-dirent.h b/libglusterfs/src/glusterfs/gf-dirent.h new file mode 100644 index 00000000000..e358da30f58 --- /dev/null +++ b/libglusterfs/src/glusterfs/gf-dirent.h @@ -0,0 +1,71 @@ +/* + 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 _GF_DIRENT_H +#define _GF_DIRENT_H + +#include "glusterfs/iatt.h" +#include "glusterfs/inode.h" + +#define gf_dirent_size(name) (sizeof(gf_dirent_t) + strlen(name) + 1) + +int +gf_deitransform(xlator_t *this, uint64_t y); + +int +gf_itransform(xlator_t *this, uint64_t x, uint64_t *y_p, int client_id); + +uint64_t +gf_dirent_orig_offset(xlator_t *this, uint64_t offset); + +struct _dir_entry { + struct _dir_entry *next; + char *name; + char *link; + struct iatt buf; +}; + +struct _gf_dirent { + union { + struct list_head list; + struct { + struct _gf_dirent *next; + struct _gf_dirent *prev; + }; + }; + uint64_t d_ino; + uint64_t d_off; + uint32_t d_len; + uint32_t d_type; + struct iatt d_stat; + dict_t *dict; + inode_t *inode; + char d_name[]; +}; + +#define DT_ISDIR(mode) (mode == DT_DIR) + +gf_dirent_t * +gf_dirent_for_name(const char *name); +gf_dirent_t * +entry_copy(gf_dirent_t *source); +void +gf_dirent_entry_free(gf_dirent_t *entry); +void +gf_dirent_free(gf_dirent_t *entries); +int +gf_link_inodes_from_dirent(xlator_t *this, inode_t *parent, + gf_dirent_t *entries); +int +gf_fill_iatt_for_dirent(gf_dirent_t *entry, inode_t *parent, xlator_t *subvol); + +void +gf_link_inode_from_dirent(xlator_t *this, inode_t *parent, gf_dirent_t *entry); +#endif /* _GF_DIRENT_H */ diff --git a/libglusterfs/src/glusterfs/gf-event.h b/libglusterfs/src/glusterfs/gf-event.h new file mode 100644 index 00000000000..40f8fbdf10a --- /dev/null +++ b/libglusterfs/src/glusterfs/gf-event.h @@ -0,0 +1,140 @@ +/* + 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 _GF_EVENT_H_ +#define _GF_EVENT_H_ + +#include <pthread.h> +#include "common-utils.h" +#include "list.h" + +struct event_pool; +struct event_ops; +struct event_slot_poll; +struct event_slot_epoll; +struct event_data { + int idx; + int gen; +} __attribute__((__packed__, __may_alias__)); + +typedef void (*event_handler_t)(int fd, int idx, int gen, void *data, + int poll_in, int poll_out, int poll_err, + char event_thread_exit); + +#define EVENT_EPOLL_TABLES 1024 +#define EVENT_EPOLL_SLOTS 1024 +#define EVENT_MAX_THREADS 1024 + +/* See rpcsvc.h to check why. */ +GF_STATIC_ASSERT(EVENT_MAX_THREADS % __BITS_PER_LONG == 0); + +struct event_pool { + struct event_ops *ops; + + int fd; + int breaker[2]; + + int count; + struct event_slot_poll *reg; + struct event_slot_epoll *ereg[EVENT_EPOLL_TABLES]; + int slots_used[EVENT_EPOLL_TABLES]; + + struct list_head poller_death; + int poller_death_sliced; /* track whether the list of fds interested + * poller_death is sliced. If yes, new thread death + * notification has to wait till the list is added + * back + */ + int poller_gen; + int used; + int changed; + + pthread_mutex_t mutex; + pthread_cond_t cond; + + void *evcache; + int evcache_size; + + /* NOTE: Currently used only when event processing is done using + * epoll. */ + int eventthreadcount; /* number of event threads to execute. */ + pthread_t pollers[EVENT_MAX_THREADS]; /* poller thread_id store, and live + status */ + int destroy; + int activethreadcount; + + /* + * Number of threads created by auto-scaling, *in addition to* the + * configured number of threads. This is only applicable on the + * server, where we try to keep the number of threads around the number + * of bricks. In that case, the configured number is just "extra" + * threads to handle requests in excess of one per brick (including + * requests on the GlusterD connection). For clients or GlusterD, this + * number will always be zero, so the "extra" is all we have. + * + * TBD: consider auto-scaling for clients as well + */ + int auto_thread_count; +}; + +struct event_destroy_data { + int readfd; + struct event_pool *pool; +}; + +struct event_ops { + struct event_pool *(*new)(int count, int eventthreadcount); + + int (*event_register)(struct event_pool *event_pool, int fd, + event_handler_t handler, void *data, int poll_in, + int poll_out, char notify_poller_death); + + int (*event_select_on)(struct event_pool *event_pool, int fd, int idx, + int poll_in, int poll_out); + + int (*event_unregister)(struct event_pool *event_pool, int fd, int idx); + + int (*event_unregister_close)(struct event_pool *event_pool, int fd, + int idx); + + int (*event_dispatch)(struct event_pool *event_pool); + + int (*event_reconfigure_threads)(struct event_pool *event_pool, + int newcount); + int (*event_pool_destroy)(struct event_pool *event_pool); + int (*event_handled)(struct event_pool *event_pool, int fd, int idx, + int gen); +}; + +struct event_pool * +gf_event_pool_new(int count, int eventthreadcount); +int +gf_event_select_on(struct event_pool *event_pool, int fd, int idx, int poll_in, + int poll_out); +int +gf_event_register(struct event_pool *event_pool, int fd, + event_handler_t handler, void *data, int poll_in, + int poll_out, char notify_poller_death); +int +gf_event_unregister(struct event_pool *event_pool, int fd, int idx); +int +gf_event_unregister_close(struct event_pool *event_pool, int fd, int idx); +int +gf_event_dispatch(struct event_pool *event_pool); +int +gf_event_reconfigure_threads(struct event_pool *event_pool, int value); +int +gf_event_pool_destroy(struct event_pool *event_pool); +int +gf_event_dispatch_destroy(struct event_pool *event_pool); +int +gf_event_handled(struct event_pool *event_pool, int fd, int idx, int gen); + +#endif /* _GF_EVENT_H_ */ diff --git a/libglusterfs/src/glusterfs/gidcache.h b/libglusterfs/src/glusterfs/gidcache.h new file mode 100644 index 00000000000..ddaabd765b5 --- /dev/null +++ b/libglusterfs/src/glusterfs/gidcache.h @@ -0,0 +1,60 @@ +/* + 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 __GIDCACHE_H__ +#define __GIDCACHE_H__ + +#include "glusterfs/glusterfs.h" +#include "glusterfs/locking.h" + +/* + * TBD: make the cache size tunable + * + * The current size represents a pretty trivial amount of memory, and should + * provide good hit rates even for quite busy systems. If we ever want to + * support really large cache sizes, we'll need to do dynamic allocation + * instead of just defining an array within a private structure. It doesn't make + * a whole lot of sense to change the associativity, because it won't improve + * hit rates all that much and will increase the maintenance cost as we have + * to scan more entries with every lookup/update. + */ + +#define AUX_GID_CACHE_ASSOC 4 +#define AUX_GID_CACHE_BUCKETS 256 +#define AUX_GID_CACHE_SIZE (AUX_GID_CACHE_ASSOC * AUX_GID_CACHE_BUCKETS) + +typedef struct { + uint64_t gl_id; + uint64_t gl_uid; + uint64_t gl_gid; + int gl_count; + gid_t *gl_list; + time_t gl_deadline; +} gid_list_t; + +typedef struct { + gf_lock_t gc_lock; + uint32_t gc_max_age; + unsigned int gc_nbuckets; + gid_list_t gc_cache[AUX_GID_CACHE_SIZE]; +} 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, uint64_t, uint64_t); +void +gid_cache_release(gid_cache_t *, const gid_list_t *); +int +gid_cache_add(gid_cache_t *, gid_list_t *); + +#endif /* __GIDCACHE_H__ */ diff --git a/libglusterfs/src/glusterfs/glfs-message-id.h b/libglusterfs/src/glusterfs/glfs-message-id.h new file mode 100644 index 00000000000..a1a16ca1efb --- /dev/null +++ b/libglusterfs/src/glusterfs/glfs-message-id.h @@ -0,0 +1,102 @@ +/* + Copyright (c) 2015-2016 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _GLFS_MESSAGE_ID_H_ +#define _GLFS_MESSAGE_ID_H_ + +/* Base of all message IDs, all message IDs would be + * greater than this */ +#define GLFS_MSGID_BASE 100000 + +/* Segment size of allocated range. Any component needing more than this + * segment size should take multiple segments (at times non contiguous, + * if extensions are being made post the next segment already allocated) */ +#define GLFS_MSGID_SEGMENT 1000 + +/* Macro to define a range of messages for a component. The first argument is + * the name of the component. The second argument is the number of segments + * to allocate. The defined values will be GLFS_MSGID_COMP_<name> and + * GLFS_MSGID_COMP_<name>_END. */ +#define GLFS_MSGID_COMP(_name, _blocks) \ + GLFS_MSGID_COMP_##_name, \ + GLFS_MSGID_COMP_##_name##_END = (GLFS_MSGID_COMP_##_name + \ + (GLFS_MSGID_SEGMENT * (_blocks)) - 1) + +#define GLFS_MSGID(_name, _msgs...) \ + enum _msgid_table_##_name \ + { \ + GLFS_##_name##_COMP_BASE = GLFS_MSGID_COMP_##_name, ##_msgs, \ + GLGS_##_name##_COMP_END \ + } + +/* Per module message segments allocated */ +/* NOTE: For any new module add to the end the modules */ +enum _msgid_comp { + GLFS_MSGID_RESERVED = GLFS_MSGID_BASE - 1, + + GLFS_MSGID_COMP(GLUSTERFSD, 1), + GLFS_MSGID_COMP(LIBGLUSTERFS, 1), + GLFS_MSGID_COMP(RPC_LIB, 1), + GLFS_MSGID_COMP(RPC_TRANS_RDMA, 1), + GLFS_MSGID_COMP(API, 1), + GLFS_MSGID_COMP(CLI, 1), + /* glusterd has a lot of messages, taking 2 segments for the same */ + GLFS_MSGID_COMP(GLUSTERD, 2), + GLFS_MSGID_COMP(AFR, 1), + GLFS_MSGID_COMP(DHT, 1), + /* there is no component called 'common', however reserving this segment + * for common actions/errors like dict_{get/set}, memory accounting*/ + GLFS_MSGID_COMP(COMMON, 1), + GLFS_MSGID_COMP(UPCALL, 1), + GLFS_MSGID_COMP(NFS, 1), + GLFS_MSGID_COMP(POSIX, 1), + GLFS_MSGID_COMP(PC, 1), + GLFS_MSGID_COMP(PS, 1), + GLFS_MSGID_COMP(BITROT_STUB, 1), + GLFS_MSGID_COMP(CHANGELOG, 1), + GLFS_MSGID_COMP(BITROT_BITD, 1), + GLFS_MSGID_COMP(RPC_TRANS_SOCKET, 1), + GLFS_MSGID_COMP(QUOTA, 1), + GLFS_MSGID_COMP(CTR, 1), + GLFS_MSGID_COMP(EC, 1), + GLFS_MSGID_COMP(IO_CACHE, 1), + GLFS_MSGID_COMP(IO_THREADS, 1), + GLFS_MSGID_COMP(MD_CACHE, 1), + GLFS_MSGID_COMP(OPEN_BEHIND, 1), + GLFS_MSGID_COMP(QUICK_READ, 1), + GLFS_MSGID_COMP(READ_AHEAD, 1), + GLFS_MSGID_COMP(READDIR_AHEAD, 1), + GLFS_MSGID_COMP(SYMLINK_CACHE, 1), + GLFS_MSGID_COMP(WRITE_BEHIND, 1), + GLFS_MSGID_COMP(CHANGELOG_LIB, 1), + GLFS_MSGID_COMP(SHARD, 1), + GLFS_MSGID_COMP(JBR, 1), + GLFS_MSGID_COMP(PL, 1), + GLFS_MSGID_COMP(DC, 1), + GLFS_MSGID_COMP(LEASES, 1), + GLFS_MSGID_COMP(INDEX, 1), + GLFS_MSGID_COMP(POSIX_ACL, 1), + GLFS_MSGID_COMP(NLC, 1), + GLFS_MSGID_COMP(SL, 1), + GLFS_MSGID_COMP(HAM, 1), + GLFS_MSGID_COMP(SDFS, 1), + GLFS_MSGID_COMP(QUIESCE, 1), + GLFS_MSGID_COMP(TA, 1), + GLFS_MSGID_COMP(SNAPVIEW_CLIENT, 1), + GLFS_MSGID_COMP(TEMPLATE, 1), + GLFS_MSGID_COMP(UTIME, 1), + GLFS_MSGID_COMP(SNAPVIEW_SERVER, 1), + GLFS_MSGID_COMP(CVLT, 1), + /* --- new segments for messages goes above this line --- */ + + GLFS_MSGID_END +}; + +#endif /* !_GLFS_MESSAGE_ID_H_ */ diff --git a/libglusterfs/src/glusterfs/globals.h b/libglusterfs/src/glusterfs/globals.h new file mode 100644 index 00000000000..b22eaae6c2f --- /dev/null +++ b/libglusterfs/src/glusterfs/globals.h @@ -0,0 +1,188 @@ +/* + 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 _GLOBALS_H +#define _GLOBALS_H + +#define GF_DEFAULT_BASE_PORT 24007 +#define GF_DEFAULT_VOLFILE_TRANSPORT "tcp" + +#define GF_GLOBAL_XLATOR_NAME "global" +#define GD_OP_VERSION_KEY "operating-version" +#define GD_MIN_OP_VERSION_KEY "minimum-operating-version" +#define GD_MAX_OP_VERSION_KEY "maximum-operating-version" + +#define GF_PROTECT_FROM_EXTERNAL_WRITES "trusted.glusterfs.protect.writes" +#define GF_AVOID_OVERWRITE "glusterfs.avoid.overwrite" +#define GF_CLEAN_WRITE_PROTECTION "glusterfs.clean.writexattr" + +/* Gluster versions - OP-VERSION mapping + * + * 3.3.x - 1 + * 3.4.x - 2 + * 3.5.0 - 3 + * 3.5.1 - 30501 + * 3.6.0 - 30600 + * 3.7.0 - 30700 + * 3.7.1 - 30701 + * 3.7.2 - 30702 + * + * Starting with Gluster v3.6, the op-version will be multi-digit integer values + * based on the Glusterfs version, instead of a simply incrementing integer + * value. The op-version for a given X.Y.Z release will be an integer XYZ, with + * Y and Z 2 digit always 2 digits wide and padded with 0 when needed. This + * should allow for some gaps between two Y releases for backports of features + * in Z releases. + */ +#define GD_OP_VERSION_MIN \ + 1 /* MIN is the fresh start op-version, mostly \ + should not change */ +#define GD_OP_VERSION_MAX \ + GD_OP_VERSION_9_0 /* MAX VERSION is the maximum \ + count in VME table, should \ + keep changing with \ + introduction of newer \ + versions */ + +#define GD_OP_VERSION_3_6_0 30600 /* Op-Version for GlusterFS 3.6.0 */ + +#define GD_OP_VERSION_3_7_0 30700 /* Op-version for GlusterFS 3.7.0 */ + +#define GD_OP_VERSION_3_7_1 30701 /* Op-version for GlusterFS 3.7.1 */ + +#define GD_OP_VERSION_3_7_2 30702 /* Op-version for GlusterFS 3.7.2 */ + +#define GD_OP_VERSION_3_7_3 30703 /* Op-version for GlusterFS 3.7.3 */ + +#define GD_OP_VERSION_3_7_4 30704 /* Op-version for GlusterFS 3.7.4 */ + +#define GD_OP_VERSION_3_7_5 30705 /* Op-version for GlusterFS 3.7.5 */ + +#define GD_OP_VERSION_3_7_6 30706 /* Op-version for GlusterFS 3.7.6 */ + +#define GD_OP_VERSION_3_7_7 30707 /* Op-version for GlusterFS 3.7.7 */ + +#define GD_OP_VERSION_3_7_10 30710 /* Op-version for GlusterFS 3.7.10 */ + +#define GD_OP_VERSION_3_7_12 30712 /* Op-version for GlusterFS 3.7.12 */ + +#define GD_OP_VERSION_3_8_0 30800 /* Op-version for GlusterFS 3.8.0 */ + +#define GD_OP_VERSION_3_8_3 30803 /* Op-version for GlusterFS 3.8.3 */ + +#define GD_OP_VERSION_3_8_4 30804 /* Op-version for GlusterFS 3.8.4 */ + +#define GD_OP_VERSION_3_9_0 30900 /* Op-version for GlusterFS 3.9.0 */ + +#define GD_OP_VERSION_3_9_1 30901 /* Op-version for GlusterFS 3.9.1 */ + +#define GD_OP_VERSION_3_10_0 31000 /* Op-version for GlusterFS 3.10.0 */ + +#define GD_OP_VERSION_3_10_1 31001 /* Op-version for GlusterFS 3.10.1 */ + +#define GD_OP_VERSION_3_10_2 31002 /* Op-version for GlusterFS 3.10.2 */ + +#define GD_OP_VERSION_3_11_0 31100 /* Op-version for GlusterFS 3.11.0 */ + +#define GD_OP_VERSION_3_11_1 31101 /* Op-version for GlusterFS 3.11.1 */ + +#define GD_OP_VERSION_3_12_0 31200 /* Op-version for GlusterFS 3.12.0 */ + +#define GD_OP_VERSION_3_12_2 31202 /* Op-version for GlusterFS 3.12.2 */ + +#define GD_OP_VERSION_3_12_3 31203 /* Op-version for GlusterFS 3.12.3 */ + +#define GD_OP_VERSION_3_13_0 31300 /* Op-version for GlusterFS 3.13.0 */ + +#define GD_OP_VERSION_3_13_1 31301 /* Op-version for GlusterFS 3.13.1 */ + +#define GD_OP_VERSION_3_13_2 31302 /* Op-version for GlusterFS 3.13.2 */ + +#define GD_OP_VERSION_4_0_0 40000 /* Op-version for GlusterFS 4.0.0 */ + +#define GD_OP_VERSION_4_1_0 40100 /* Op-version for GlusterFS 4.1.0 */ + +#define GD_OP_VERSION_5_0 50000 /* Op-version for GlusterFS 5.0 */ + +#define GD_OP_VERSION_5_4 50400 /* Op-version for GlusterFS 5.4 */ + +#define GD_OP_VERSION_6_0 60000 /* Op-version for GlusterFS 6.0 */ + +#define GD_OP_VERSION_7_0 70000 /* Op-version for GlusterFS 7.0 */ +#define GD_OP_VERSION_7_1 70100 /* Op-version for GlusterFS 7.1 */ +#define GD_OP_VERSION_7_2 70200 /* Op-version for GlusterFS 7.2 */ +#define GD_OP_VERSION_7_3 70300 /* Op-version for GlusterFS 7.3 */ + +#define GD_OP_VERSION_8_0 80000 /* Op-version for GlusterFS 8.0 */ + +#define GD_OP_VERSION_9_0 90000 /* Op-version for GlusterFS 9.0 */ + +#define GD_OP_VER_PERSISTENT_AFR_XATTRS GD_OP_VERSION_3_6_0 + +#include "glusterfs/xlator.h" +#include "glusterfs/options.h" + +/* THIS */ +#define THIS (*__glusterfs_this_location()) +#define DECLARE_OLD_THIS xlator_t *old_THIS = THIS + +xlator_t ** +__glusterfs_this_location(void); +xlator_t * +glusterfs_this_get(void); +void +glusterfs_this_set(xlator_t *); + +extern xlator_t global_xlator; +extern struct volume_options global_xl_options[]; + +/* syncopctx */ +void * +syncopctx_getctx(void); + +/* task */ +void * +synctask_get(void); +void +synctask_set(void *); + +/* uuid_buf */ +char * +glusterfs_uuid_buf_get(void); +/* lkowner_buf */ +char * +glusterfs_lkowner_buf_get(void); +/* leaseid buf */ +char * +glusterfs_leaseid_buf_get(void); +char * +glusterfs_leaseid_exist(void); + +/* init */ +int +glusterfs_globals_init(glusterfs_ctx_t *ctx); + +void +gf_thread_needs_cleanup(void); + +struct tvec_base * +glusterfs_ctx_tw_get(glusterfs_ctx_t *ctx); +void +glusterfs_ctx_tw_put(glusterfs_ctx_t *ctx); + +extern const char *gf_fop_list[]; +extern const char *gf_upcall_list[]; + +/* mem acct enable/disable */ +int +gf_global_mem_acct_enable_get(void); +int +gf_global_mem_acct_enable_set(int val); +#endif /* !_GLOBALS_H */ diff --git a/libglusterfs/src/glusterfs/glusterfs-acl.h b/libglusterfs/src/glusterfs/glusterfs-acl.h new file mode 100644 index 00000000000..987bf5fab0b --- /dev/null +++ b/libglusterfs/src/glusterfs/glusterfs-acl.h @@ -0,0 +1,162 @@ +/* + 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 _GLUSTERFS_ACL_H +#define _GLUSTERFS_ACL_H + +/* WARNING: Much if this code is restricted to Linux usage. + * + * It would be much cleaner to replace the code with something that is based on + * libacl (or its libc implementation on *BSD). + * + * Initial work for replacing this Linux specific implementation has been + * started as part of the "Improve POSIX ACLs" feature. Functionality for this + * feature has been added to the end of this file. + */ + +#include <stdint.h> +#include <sys/types.h> /* For uid_t */ + +#include "glusterfs/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_XATTR_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[]; +}; + +typedef struct posix_acl_xattr_entry posix_acl_xattr_entry; +typedef struct posix_acl_xattr_header posix_acl_xattr_header; + +static inline size_t +posix_acl_xattr_size(unsigned int count) +{ + return (sizeof(posix_acl_xattr_header) + + (count * sizeof(posix_acl_xattr_entry))); +} + +static inline ssize_t +posix_acl_xattr_count(size_t size) +{ + if (size < sizeof(posix_acl_xattr_header)) + return (-1); + size -= sizeof(posix_acl_xattr_header); + if (size % sizeof(posix_acl_xattr_entry)) + return (-1); + return (size / sizeof(posix_acl_xattr_entry)); +} + +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; + glusterfs_fop_t fop; + 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; +}; + +/* Above this comment, the legacy POSIX ACL support is kept until it is not + * used anymore. Below you will find the more portable version to support POSIX + * ACls based on the implementation of libacl (see sys/acl.h). */ + +/* virtual xattrs passed over RPC, not stored on disk */ +#define GF_POSIX_ACL_ACCESS "glusterfs.posix.acl" +#define GF_POSIX_ACL_DEFAULT "glusterfs.posix.default_acl" +#define GF_POSIX_ACL_REQUEST(key) \ + (!strncmp(key, GF_POSIX_ACL_ACCESS, SLEN(GF_POSIX_ACL_ACCESS)) || \ + !strncmp(key, GF_POSIX_ACL_DEFAULT, SLEN(GF_POSIX_ACL_DEFAULT))) + +#ifdef HAVE_SYS_ACL_H /* only NetBSD does not support POSIX ACLs */ + +#include <sys/acl.h> + +static inline const char * +gf_posix_acl_get_key(const acl_type_t type) +{ + char *acl_key = NULL; + + switch (type) { + case ACL_TYPE_ACCESS: + acl_key = GF_POSIX_ACL_ACCESS; + break; + case ACL_TYPE_DEFAULT: + acl_key = GF_POSIX_ACL_DEFAULT; + break; + default: + errno = EINVAL; + } + + return acl_key; +} + +static inline acl_type_t +gf_posix_acl_get_type(const char *key) +{ + acl_type_t type = 0; + + if (!strncmp(key, GF_POSIX_ACL_ACCESS, SLEN(GF_POSIX_ACL_ACCESS))) + type = ACL_TYPE_ACCESS; + else if (!strncmp(key, GF_POSIX_ACL_DEFAULT, SLEN(GF_POSIX_ACL_DEFAULT))) + type = ACL_TYPE_DEFAULT; + else + errno = EINVAL; + + return type; +} + +#endif /* HAVE_SYS_ACL_H */ +#endif /* _GLUSTERFS_ACL_H */ diff --git a/libglusterfs/src/glusterfs/glusterfs-fops.h b/libglusterfs/src/glusterfs/glusterfs-fops.h new file mode 100644 index 00000000000..030b2701608 --- /dev/null +++ b/libglusterfs/src/glusterfs/glusterfs-fops.h @@ -0,0 +1,241 @@ +/* + Copyright (c) 2008-2019 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_FOPS_H_ +#define _GLUSTERFS_FOPS_H_ + +#include <glusterfs/compat.h> + +enum glusterfs_fop_t { + GF_FOP_NULL = 0, + GF_FOP_STAT = 0 + 1, + GF_FOP_READLINK = 0 + 2, + GF_FOP_MKNOD = 0 + 3, + GF_FOP_MKDIR = 0 + 4, + GF_FOP_UNLINK = 0 + 5, + GF_FOP_RMDIR = 0 + 6, + GF_FOP_SYMLINK = 0 + 7, + GF_FOP_RENAME = 0 + 8, + GF_FOP_LINK = 0 + 9, + GF_FOP_TRUNCATE = 0 + 10, + GF_FOP_OPEN = 0 + 11, + GF_FOP_READ = 0 + 12, + GF_FOP_WRITE = 0 + 13, + GF_FOP_STATFS = 0 + 14, + GF_FOP_FLUSH = 0 + 15, + GF_FOP_FSYNC = 0 + 16, + GF_FOP_SETXATTR = 0 + 17, + GF_FOP_GETXATTR = 0 + 18, + GF_FOP_REMOVEXATTR = 0 + 19, + GF_FOP_OPENDIR = 0 + 20, + GF_FOP_FSYNCDIR = 0 + 21, + GF_FOP_ACCESS = 0 + 22, + GF_FOP_CREATE = 0 + 23, + GF_FOP_FTRUNCATE = 0 + 24, + GF_FOP_FSTAT = 0 + 25, + GF_FOP_LK = 0 + 26, + GF_FOP_LOOKUP = 0 + 27, + GF_FOP_READDIR = 0 + 28, + GF_FOP_INODELK = 0 + 29, + GF_FOP_FINODELK = 0 + 30, + GF_FOP_ENTRYLK = 0 + 31, + GF_FOP_FENTRYLK = 0 + 32, + GF_FOP_XATTROP = 0 + 33, + GF_FOP_FXATTROP = 0 + 34, + GF_FOP_FGETXATTR = 0 + 35, + GF_FOP_FSETXATTR = 0 + 36, + GF_FOP_RCHECKSUM = 0 + 37, + GF_FOP_SETATTR = 0 + 38, + GF_FOP_FSETATTR = 0 + 39, + GF_FOP_READDIRP = 0 + 40, + GF_FOP_FORGET = 0 + 41, + GF_FOP_RELEASE = 0 + 42, + GF_FOP_RELEASEDIR = 0 + 43, + GF_FOP_GETSPEC = 0 + 44, + GF_FOP_FREMOVEXATTR = 0 + 45, + GF_FOP_FALLOCATE = 0 + 46, + GF_FOP_DISCARD = 0 + 47, + GF_FOP_ZEROFILL = 0 + 48, + GF_FOP_IPC = 0 + 49, + GF_FOP_SEEK = 0 + 50, + GF_FOP_LEASE = 0 + 51, + GF_FOP_COMPOUND = 0 + 52, + GF_FOP_GETACTIVELK = 0 + 53, + GF_FOP_SETACTIVELK = 0 + 54, + GF_FOP_PUT = 0 + 55, + GF_FOP_ICREATE = 0 + 56, + GF_FOP_NAMELINK = 0 + 57, + GF_FOP_COPY_FILE_RANGE = 0 + 58, + GF_FOP_MAXVALUE = 0 + 59, +}; +typedef enum glusterfs_fop_t glusterfs_fop_t; + +enum glusterfs_event_t { + GF_EVENT_PARENT_UP = 1, + GF_EVENT_POLLIN = 1 + 1, + GF_EVENT_POLLOUT = 1 + 2, + GF_EVENT_POLLERR = 1 + 3, + GF_EVENT_CHILD_UP = 1 + 4, + GF_EVENT_CHILD_DOWN = 1 + 5, + GF_EVENT_CHILD_CONNECTING = 1 + 6, + GF_EVENT_CLEANUP = 9, + GF_EVENT_TRANSPORT_CONNECTED = 9 + 1, + GF_EVENT_VOLFILE_MODIFIED = 9 + 2, + GF_EVENT_GRAPH_NEW = 9 + 3, + GF_EVENT_TRANSLATOR_INFO = 9 + 4, + GF_EVENT_TRANSLATOR_OP = 9 + 5, + GF_EVENT_AUTH_FAILED = 9 + 6, + GF_EVENT_VOLUME_DEFRAG = 9 + 7, + GF_EVENT_PARENT_DOWN = 9 + 8, + GF_EVENT_VOLUME_BARRIER_OP = 9 + 9, + GF_EVENT_UPCALL = 9 + 10, + GF_EVENT_SCRUB_STATUS = 9 + 11, + GF_EVENT_SOME_DESCENDENT_DOWN = 9 + 12, + GF_EVENT_SCRUB_ONDEMAND = 9 + 13, + GF_EVENT_SOME_DESCENDENT_UP = 9 + 14, + GF_EVENT_CHILD_PING = 9 + 15, + GF_EVENT_MAXVAL = 9 + 16, +}; +typedef enum glusterfs_event_t glusterfs_event_t; + +enum gf_op_type_t { + GF_OP_TYPE_NULL = 0, + GF_OP_TYPE_FOP = 0 + 1, + GF_OP_TYPE_MGMT = 0 + 2, + GF_OP_TYPE_MAX = 0 + 3, +}; +typedef enum gf_op_type_t gf_op_type_t; + +enum glusterfs_lk_cmds_t { + GF_LK_GETLK = 0, + GF_LK_SETLK = 0 + 1, + GF_LK_SETLKW = 0 + 2, + GF_LK_RESLK_LCK = 0 + 3, + GF_LK_RESLK_LCKW = 0 + 4, + GF_LK_RESLK_UNLCK = 0 + 5, + GF_LK_GETLK_FD = 0 + 6, +}; +typedef enum glusterfs_lk_cmds_t glusterfs_lk_cmds_t; + +enum glusterfs_lk_types_t { + GF_LK_F_RDLCK = 0, + GF_LK_F_WRLCK = 0 + 1, + GF_LK_F_UNLCK = 0 + 2, + GF_LK_EOL = 0 + 3, +}; +typedef enum glusterfs_lk_types_t glusterfs_lk_types_t; + +enum gf_lease_types_t { + NONE = 0, + GF_RD_LEASE = 1, + GF_RW_LEASE = 2, + GF_LEASE_MAX_TYPE = 2 + 1, +}; +typedef enum gf_lease_types_t gf_lease_types_t; + +enum gf_lease_cmds_t { + GF_GET_LEASE = 1, + GF_SET_LEASE = 2, + GF_UNLK_LEASE = 3, +}; +typedef enum gf_lease_cmds_t gf_lease_cmds_t; + +#define LEASE_ID_SIZE 16 /* 128bits */ + +struct gf_lease { + gf_lease_cmds_t cmd; + gf_lease_types_t lease_type; + char lease_id[LEASE_ID_SIZE]; + u_int lease_flags; +}; +typedef struct gf_lease gf_lease; + +enum glusterfs_lk_recovery_cmds_t { + F_RESLK_LCK = 200, + F_RESLK_LCKW = 200 + 1, + F_RESLK_UNLCK = 200 + 2, + F_GETLK_FD = 200 + 3, +}; +typedef enum glusterfs_lk_recovery_cmds_t glusterfs_lk_recovery_cmds_t; + +enum gf_lk_domain_t { + GF_LOCK_POSIX = 0, + GF_LOCK_INTERNAL = 1, +}; +typedef enum gf_lk_domain_t gf_lk_domain_t; + +enum entrylk_cmd { + ENTRYLK_LOCK = 0, + ENTRYLK_UNLOCK = 1, + ENTRYLK_LOCK_NB = 2, +}; +typedef enum entrylk_cmd entrylk_cmd; + +enum entrylk_type { + ENTRYLK_RDLCK = 0, + ENTRYLK_WRLCK = 1, +}; +typedef enum entrylk_type entrylk_type; +#define GF_MAX_LOCK_OWNER_LEN 1024 /* 1kB as per NLM */ +#define GF_LKOWNER_BUF_SIZE \ + ((GF_MAX_LOCK_OWNER_LEN * 2) + (GF_MAX_LOCK_OWNER_LEN / 8)) + +struct gf_lkowner_t { + int len; + char data[GF_MAX_LOCK_OWNER_LEN]; +}; +typedef struct gf_lkowner_t gf_lkowner_t; + +enum gf_xattrop_flags_t { + GF_XATTROP_ADD_ARRAY = 0, + GF_XATTROP_ADD_ARRAY64 = 1, + GF_XATTROP_OR_ARRAY = 2, + GF_XATTROP_AND_ARRAY = 3, + GF_XATTROP_GET_AND_SET = 4, + GF_XATTROP_ADD_ARRAY_WITH_DEFAULT = 5, + GF_XATTROP_ADD_ARRAY64_WITH_DEFAULT = 6, +}; +typedef enum gf_xattrop_flags_t gf_xattrop_flags_t; + +enum gf_seek_what_t { + GF_SEEK_DATA = 0, + GF_SEEK_HOLE = 1, +}; +typedef enum gf_seek_what_t gf_seek_what_t; + +enum gf_upcall_flags_t { + GF_UPCALL_NULL = 0, + GF_UPCALL = 1, + GF_UPCALL_CI_STAT = 2, + GF_UPCALL_CI_XATTR = 3, + GF_UPCALL_CI_RENAME = 4, + GF_UPCALL_CI_NLINK = 5, + GF_UPCALL_CI_FORGET = 6, + GF_UPCALL_LEASE_RECALL = 7, + GF_UPCALL_FLAGS_MAXVALUE = 8, +}; +typedef enum gf_upcall_flags_t gf_upcall_flags_t; + +enum gf_dict_data_type_t { + GF_DATA_TYPE_UNKNOWN = 0, + GF_DATA_TYPE_STR_OLD = 1, + GF_DATA_TYPE_INT = 2, + GF_DATA_TYPE_UINT = 3, + GF_DATA_TYPE_DOUBLE = 4, + GF_DATA_TYPE_STR = 5, + GF_DATA_TYPE_PTR = 6, + GF_DATA_TYPE_GFUUID = 7, + GF_DATA_TYPE_IATT = 8, + GF_DATA_TYPE_MDATA = 9, + GF_DATA_TYPE_MAX = 10, +}; +typedef enum gf_dict_data_type_t gf_dict_data_type_t; + +#endif /* !_GLUSTERFS_FOPS_H */ diff --git a/libglusterfs/src/glusterfs/glusterfs.h b/libglusterfs/src/glusterfs/glusterfs.h new file mode 100644 index 00000000000..e6425618b7f --- /dev/null +++ b/libglusterfs/src/glusterfs/glusterfs.h @@ -0,0 +1,838 @@ +/* + Copyright (c) 2008-2016 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _GLUSTERFS_H +#define _GLUSTERFS_H + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/statvfs.h> +#include <netdb.h> +#include <errno.h> +#include <dirent.h> +#include <unistd.h> +#include <fcntl.h> +#include <arpa/inet.h> +#include <sys/poll.h> +#include <pthread.h> +#include <limits.h> /* For PATH_MAX */ +#include <openssl/sha.h> + +#include "glusterfs/glusterfs-fops.h" +#include "glusterfs/list.h" +#include "glusterfs/locking.h" +#include "glusterfs/logging.h" +#include "glusterfs/lkowner.h" +#include "glusterfs/compat-uuid.h" +#include "glusterfs/refcount.h" +#include "glusterfs/atomic.h" + +#define GF_YES 1 +#define GF_NO 0 + +#define IS_ERROR(ret) ((ret) < 0) +#define IS_SUCCESS(ret) ((ret) >= 0) + +#ifndef O_LARGEFILE +/* savannah bug #20053, patch for compiling on darwin */ +#define O_LARGEFILE 0100000 /* from bits/fcntl.h */ +#endif + +#ifndef O_FMODE_EXEC +/* redhat bug 843080, added from linux/fs.h */ +#define O_FMODE_EXEC 040 // 0x20 +#endif + +#ifndef O_DIRECT +/* savannah bug #20050, #20052 */ +#define O_DIRECT 0 /* From asm/fcntl.h */ +#endif + +#ifndef O_DIRECTORY +/* FreeBSD does not need O_DIRECTORY */ +#define O_DIRECTORY 0 +#endif + +#ifndef EBADFD +/* Mac OS X does not have EBADFD */ +#define EBADFD EBADF +#endif + +#ifndef FNM_EXTMATCH +#define FNM_EXTMATCH 0 +#endif + +/*gets max-offset on all architectures correctly*/ +#define GF_OFF_MAX ((1ULL << (sizeof(off_t) * 8 - 1)) - 1ULL) + +#define GLUSTERD_MAX_SNAP_NAME 255 +#define GLUSTERFS_SOCKET_LISTEN_BACKLOG 1024 +#define GLUSTERD_BRICK_SERVERS "cluster.brick-vol-servers" +#define SLEN(str) (sizeof(str) - 1) + +#define ZR_MOUNTPOINT_OPT "mountpoint" +#define ZR_ATTR_TIMEOUT_OPT "attribute-timeout" +#define ZR_ENTRY_TIMEOUT_OPT "entry-timeout" +#define ZR_NEGATIVE_TIMEOUT_OPT "negative-timeout" +#define ZR_DIRECT_IO_OPT "direct-io-mode" +#define ZR_STRICT_VOLFILE_CHECK "strict-volfile-check" +#define ZR_DUMP_FUSE "dump-fuse" +#define ZR_FUSE_MOUNTOPTS "fuse-mountopts" +#define IO_THREADS_QUEUE_SIZE_KEY "io-thread-queue-size" + +#define GF_XATTR_CLRLK_CMD "glusterfs.clrlk" +#define GF_XATTR_PATHINFO_KEY "trusted.glusterfs.pathinfo" +#define GF_XATTR_NODE_UUID_KEY "trusted.glusterfs.node-uuid" +#define GF_XATTR_LIST_NODE_UUIDS_KEY "trusted.glusterfs.list-node-uuids" +#define GF_REBAL_FIND_LOCAL_SUBVOL "glusterfs.find-local-subvol" +#define GF_REBAL_OLD_FIND_LOCAL_SUBVOL "glusterfs.old-find-local-subvol" +#define GF_XATTR_VOL_ID_KEY "trusted.glusterfs.volume-id" +#define GF_XATTR_LOCKINFO_KEY "trusted.glusterfs.lockinfo" +#define GF_META_LOCK_KEY "glusterfs.lock-migration-meta-lock" +#define GF_META_UNLOCK_KEY "glusterfs.lock-migration-meta-unlock" +#define GF_XATTR_GET_REAL_FILENAME_KEY "glusterfs.get_real_filename:" +#define GF_XATTR_USER_PATHINFO_KEY "glusterfs.pathinfo" +#define GF_INTERNAL_IGNORE_DEEM_STATFS "ignore-deem-statfs" +#define GF_XATTR_IOSTATS_DUMP_KEY "trusted.io-stats-dump" + +#define GF_READDIR_SKIP_DIRS "readdir-filter-directories" +#define GF_MDC_LOADED_KEY_NAMES "glusterfs.mdc.loaded.key.names" + +#define BD_XATTR_KEY "user.glusterfs" +#define GF_PREOP_PARENT_KEY "glusterfs.preop.parent.key" +#define GF_PREOP_CHECK_FAILED "glusterfs.preop.check.failed" + +#define XATTR_IS_PATHINFO(x) \ + ((strncmp(x, GF_XATTR_PATHINFO_KEY, strlen(x)) == 0) || \ + (strncmp(x, GF_XATTR_USER_PATHINFO_KEY, strlen(x)) == 0)) +#define XATTR_IS_NODE_UUID(x) \ + (strncmp(x, GF_XATTR_NODE_UUID_KEY, SLEN(GF_XATTR_NODE_UUID_KEY)) == 0) +#define XATTR_IS_NODE_UUID_LIST(x) \ + (strncmp(x, GF_XATTR_LIST_NODE_UUIDS_KEY, \ + SLEN(GF_XATTR_LIST_NODE_UUIDS_KEY)) == 0) +#define XATTR_IS_LOCKINFO(x) \ + (strncmp(x, GF_XATTR_LOCKINFO_KEY, SLEN(GF_XATTR_LOCKINFO_KEY)) == 0) + +#define XATTR_IS_BD(x) (strncmp(x, BD_XATTR_KEY, SLEN(BD_XATTR_KEY)) == 0) + +#define GF_XATTR_LINKINFO_KEY "trusted.distribute.linkinfo" +#define GFID_XATTR_KEY "trusted.gfid" +#define PGFID_XATTR_KEY_PREFIX "trusted.pgfid." +#define GFID2PATH_VIRT_XATTR_KEY "glusterfs.gfidtopath" +#define GFID2PATH_XATTR_KEY_PREFIX "trusted.gfid2path." +#define GFID2PATH_XATTR_KEY_PREFIX_LENGTH 18 +#define VIRTUAL_GFID_XATTR_KEY_STR "glusterfs.gfid.string" +#define VIRTUAL_GFID_XATTR_KEY "glusterfs.gfid" +#define GF_XATTR_MDATA_KEY "trusted.glusterfs.mdata" +#define UUID_CANONICAL_FORM_LEN 36 + +#define GET_ANCESTRY_PATH_KEY "glusterfs.ancestry.path" +#define GET_ANCESTRY_DENTRY_KEY "glusterfs.ancestry.dentry" + +#define BITROT_DEFAULT_CURRENT_VERSION (unsigned long)1 +#define BITROT_DEFAULT_SIGNING_VERSION (unsigned long)0 + +/* on-disk object signature keys */ +#define BITROT_OBJECT_BAD_KEY "trusted.bit-rot.bad-file" +#define BITROT_CURRENT_VERSION_KEY "trusted.bit-rot.version" +#define BITROT_SIGNING_VERSION_KEY "trusted.bit-rot.signature" + +/* globally usable bad file marker */ +#define GLUSTERFS_BAD_INODE "glusterfs.bad-inode" + +/* on-disk size of signing xattr (not the signature itself) */ +#define BITROT_SIGNING_XATTR_SIZE_KEY "trusted.glusterfs.bit-rot.size" + +/* GET/SET object signature */ +#define GLUSTERFS_GET_OBJECT_SIGNATURE "trusted.glusterfs.get-signature" +#define GLUSTERFS_SET_OBJECT_SIGNATURE "trusted.glusterfs.set-signature" + +/* operation needs to be durable on-disk */ +#define GLUSTERFS_DURABLE_OP "trusted.glusterfs.durable-op" + +/* key for version exchange b/w bitrot stub and changelog */ +#define GLUSTERFS_VERSION_XCHG_KEY "glusterfs.version.xchg" + +#define GLUSTERFS_INTERNAL_FOP_KEY "glusterfs-internal-fop" + +#define GF_ENFORCE_MANDATORY_LOCK "trusted.glusterfs.enforce-mandatory-lock" + +/* GlusterFS Internal FOP Indicator flags + * (To pass information on the context in which a paritcular + * fop is performed between translators) + * The presence of a particular flag must be treated as an + * indicator of the context, however the flag is added only in + * a scenario where there is a need for such context across translators. + * So it cannot be an absolute information on context. + */ +#define GF_INTERNAL_CTX_KEY "glusterfs.internal-ctx" + +/* + * Always append entries to end of the enum, do not delete entries. + * Currently dict_set_flag allows to set up to 256 flag, if the enum + * needs to grow beyond this dict_set_flag has to be changed accordingly + */ +enum gf_internal_fop_indicator { + GF_DHT_HEAL_DIR /* Index 0 in bit array*/ +}; + +/* Todo: + * Add GF_FOP_LINK_FILE 0x2ULL + * address GLUSTERFS_MARKER_DONT_ACCOUNT_KEY and + * GLUSTERFS_INTERNAL_FOP_KEY with this flag + */ + +#define DHT_CHANGELOG_RENAME_OP_KEY "changelog.rename-op" + +#define GLUSTERFS_WRITE_IS_APPEND "glusterfs.write-is-append" +#define GLUSTERFS_WRITE_UPDATE_ATOMIC "glusterfs.write-update-atomic" +#define GLUSTERFS_OPEN_FD_COUNT "glusterfs.open-fd-count" +#define GLUSTERFS_ACTIVE_FD_COUNT "glusterfs.open-active-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 GLUSTERFS_INODELK_DOM_PREFIX "glusterfs.inodelk-dom-prefix" +#define GLUSTERFS_MULTIPLE_DOM_LK_CNT_REQUESTS "glusterfs.multi-dom-lk-cnt-req" +#define GFID_TO_PATH_KEY "glusterfs.gfid2path" +#define GF_XATTR_STIME_PATTERN "trusted.glusterfs.*.stime" +#define GF_XATTR_XTIME_PATTERN "trusted.glusterfs.*.xtime" +#define GF_XATTR_TRIGGER_SYNC "glusterfs.geo-rep.trigger-sync" + +/* quota xattrs */ +#define QUOTA_SIZE_KEY "trusted.glusterfs.quota.size" +#define QUOTA_LIMIT_KEY "trusted.glusterfs.quota.limit-set" +#define QUOTA_LIMIT_OBJECTS_KEY "trusted.glusterfs.quota.limit-objects" +#define VIRTUAL_QUOTA_XATTR_CLEANUP_KEY "glusterfs.quota-xattr-cleanup" +#define QUOTA_READ_ONLY_KEY "trusted.glusterfs.quota.read-only" + +/* ctime related */ +#define CTIME_MDATA_XDATA_KEY "set-ctime-mdata" + +/* afr related */ +#define AFR_XATTR_PREFIX "trusted.afr" + +/* Index xlator related */ +#define GF_XATTROP_INDEX_GFID "glusterfs.xattrop_index_gfid" +#define GF_XATTROP_ENTRY_CHANGES_GFID "glusterfs.xattrop_entry_changes_gfid" +#define GF_XATTROP_INDEX_COUNT "glusterfs.xattrop_index_count" +#define GF_XATTROP_DIRTY_GFID "glusterfs.xattrop_dirty_gfid" +#define GF_XATTROP_DIRTY_COUNT "glusterfs.xattrop_dirty_count" +#define GF_XATTROP_ENTRY_IN_KEY "glusterfs.xattrop-entry-create" +#define GF_XATTROP_ENTRY_OUT_KEY "glusterfs.xattrop-entry-delete" +#define GF_INDEX_IA_TYPE_GET_REQ "glusterfs.index-ia-type-get-req" +#define GF_INDEX_IA_TYPE_GET_RSP "glusterfs.index-ia-type-get-rsp" + +#define GF_HEAL_INFO "glusterfs.heal-info" +#define GF_AFR_HEAL_SBRAIN "glusterfs.heal-sbrain" +#define GF_AFR_SBRAIN_STATUS "replica.split-brain-status" +#define GF_AFR_SBRAIN_CHOICE "replica.split-brain-choice" +#define GF_AFR_SPB_CHOICE_TIMEOUT "replica.split-brain-choice-timeout" +#define GF_AFR_SBRAIN_RESOLVE "replica.split-brain-heal-finalize" +#define GF_AFR_ADD_BRICK "trusted.add-brick" +#define GF_AFR_REPLACE_BRICK "trusted.replace-brick" +#define GF_AFR_DIRTY "trusted.afr.dirty" +#define GF_XATTROP_ENTRY_OUT "glusterfs.xattrop-entry-delete" +#define GF_XATTROP_PURGE_INDEX "glusterfs.xattrop-purge-index" + +#define GF_GFIDLESS_LOOKUP "gfidless-lookup" +/* replace-brick and pump related internal xattrs */ +#define RB_PUMP_CMD_START "glusterfs.pump.start" +#define RB_PUMP_CMD_PAUSE "glusterfs.pump.pause" +#define RB_PUMP_CMD_COMMIT "glusterfs.pump.commit" +#define RB_PUMP_CMD_ABORT "glusterfs.pump.abort" +#define RB_PUMP_CMD_STATUS "glusterfs.pump.status" + +#define GLUSTERFS_MARKER_DONT_ACCOUNT_KEY "glusters.marker.dont-account" +#define GLUSTERFS_RDMA_INLINE_THRESHOLD (2048) +#define GLUSTERFS_RDMA_MAX_HEADER_SIZE \ + (228) /* (sizeof (rdma_header_t) \ + + RDMA_MAX_SEGMENTS \ + * sizeof (rdma_read_chunk_t)) \ + */ + +#define GLUSTERFS_RPC_REPLY_SIZE 24 + +#define STARTING_EVENT_THREADS 2 + +#define DEFAULT_VAR_RUN_DIRECTORY DATADIR "/run/gluster" +#define DEFAULT_GLUSTERFSD_MISC_DIRETORY DATADIR "/lib/misc/glusterfsd" +#ifdef GF_LINUX_HOST_OS +#define GLUSTERD_DEFAULT_WORKDIR DATADIR "/lib/glusterd" +#else +#define GLUSTERD_DEFAULT_WORKDIR DATADIR "/db/glusterd" +#endif +#define GF_REPLICATE_TRASH_DIR ".landfill" + +/* GlusterFS's maximum supported Auxiliary GIDs */ +#define GF_MAX_AUX_GROUPS 65535 + +#define GF_UUID_BUF_SIZE 37 /* UUID_CANONICAL_FORM_LEN + NULL */ +#define GF_UUID_BNAME_BUF_SIZE (320) /* (64 + 256) */ + +#define GF_REBALANCE_TID_KEY "rebalance-id" +#define GF_REMOVE_BRICK_TID_KEY "remove-brick-id" +#define GF_TIER_TID_KEY "tier-id" +#define GF_TIER_ENABLED "tier-enabled" + +#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" + +/* features/marker-quota also needs to have knowledge of link-files so as to + * exclude them from accounting. + */ +#define DHT_LINKFILE_MODE (S_ISVTX) + +#define IS_DHT_LINKFILE_MODE(iabuf) \ + ((st_mode_from_ia((iabuf)->ia_prot, (iabuf)->ia_type) & ~S_IFMT) == \ + DHT_LINKFILE_MODE) +#define DHT_LINKFILE_STR "linkto" +#define DHT_COMMITHASH_STR "commithash" + +#define DHT_SKIP_NON_LINKTO_UNLINK "unlink-only-if-dht-linkto-file" +#define TIER_SKIP_NON_LINKTO_UNLINK "unlink-only-if-tier-linkto-file" +#define DHT_SKIP_OPEN_FD_UNLINK "dont-unlink-for-open-fd" +#define DHT_IATT_IN_XDATA_KEY "dht-get-iatt-in-xattr" +#define DHT_MODE_IN_XDATA_KEY "dht-get-mode-in-xattr" +#define GET_LINK_COUNT "get-link-count" +#define GF_GET_SIZE "get-size" +#define GF_PRESTAT "virt-gf-prestat" +#define GF_POSTSTAT "virt-gf-poststat" + +/*CTR and Marker requires inode dentry link count from posix*/ +#define GF_RESPONSE_LINK_COUNT_XDATA "gf_response_link_count" +#define GF_REQUEST_LINK_COUNT_XDATA "gf_request_link_count" + +#define GF_GET_FILE_BLOCK_COUNT "gf_get_file_block_count" + +#define CTR_ATTACH_TIER_LOOKUP "ctr_attach_tier_lookup" + +#define CLIENT_CMD_CONNECT "trusted.glusterfs.client-connect" +#define CLIENT_CMD_DISCONNECT "trusted.glusterfs.client-disconnect" + +#define GF_LOG_LRU_BUFSIZE_DEFAULT 5 +#define GF_LOG_LRU_BUFSIZE_MIN 0 +#define GF_LOG_LRU_BUFSIZE_MAX 20 +#define GF_LOG_LRU_BUFSIZE_MIN_STR "0" +#define GF_LOG_LRU_BUFSIZE_MAX_STR "20" + +#define GF_LOG_FLUSH_TIMEOUT_DEFAULT 120 +#define GF_LOG_FLUSH_TIMEOUT_MIN 30 +#define GF_LOG_FLUSH_TIMEOUT_MAX 300 +#define GF_LOG_FLUSH_TIMEOUT_MIN_STR "30" +#define GF_LOG_FLUSH_TIMEOUT_MAX_STR "300" +#define GF_LOG_LOCALTIME_DEFAULT 0 + +#define GF_NETWORK_TIMEOUT 42 + +#define GF_BACKTRACE_LEN 4096 +#define GF_BACKTRACE_FRAME_COUNT 7 + +#define GF_LK_ADVISORY 0 /* maps to GLFS_LK_ADVISORY from libgfapi*/ +#define GF_LK_MANDATORY 1 /* maps to GLFS_LK_MANDATORY from libgfapi*/ +#define GF_LOCK_MODE "glusterfs.lk.lkmode" + +#define GF_CHECK_XATTR_KEY_AND_GOTO(key, cmpkey, errval, lbl) \ + do { \ + if (key && strcmp(key, cmpkey) == 0) { \ + errval = -EINVAL; \ + goto lbl; \ + } \ + } while (0) + +#define GF_CS_OBJECT_SIZE "trusted.glusterfs.cs.object_size" +#define GF_CS_BLOCK_SIZE "trusted.glusterfs.cs.block_size" +#define GF_CS_NUM_BLOCKS "trusted.glusterfs.cs.num_blocks" + +#define GF_CS_XATTR_ARCHIVE_UUID "trusted.cloudsync.uuid" + +#define GF_CS_OBJECT_UPLOAD_COMPLETE "trusted.glusterfs.csou.complete" +#define GF_CS_OBJECT_REMOTE "trusted.glusterfs.cs.remote" +#define GF_CS_OBJECT_DOWNLOADING "trusted.glusterfs.cs.downloading" +#define GF_CS_OBJECT_DOWNLOADED "trusted.glusterfs.cs.downloaded" +#define GF_CS_OBJECT_STATUS "trusted.glusterfs.cs.status" +#define GF_CS_OBJECT_REPAIR "trusted.glusterfs.cs.repair" + +#define gf_boolean_t bool +#define _gf_false false +#define _gf_true true + +typedef enum { + GF_CS_LOCAL = 1, + GF_CS_REMOTE = 2, + GF_CS_REPAIR = 4, + GF_CS_DOWNLOADING = 8, + GF_CS_ERROR = 16, +} gf_cs_obj_state; + +typedef enum { + GF_FOP_PRI_UNSPEC = -1, /* Priority not specified */ + GF_FOP_PRI_HI = 0, /* low latency */ + GF_FOP_PRI_NORMAL, /* normal */ + GF_FOP_PRI_LO, /* bulk */ + GF_FOP_PRI_LEAST, /* least */ + GF_FOP_PRI_MAX, /* Highest */ +} gf_fop_pri_t; + +typedef enum { + /* The 'component' (xlator / option) is not yet setting the flag */ + GF_UNCLASSIFIED = 0, + /* The 'component' is experimental, should not be recommened + in production mode */ + GF_EXPERIMENTAL, + /* The 'component' is tech preview, ie, it is 'mostly' working as + expected, but can have some of the corner cases, which is not + handled. */ + GF_TECH_PREVIEW, + /* The 'component' is good to run. Has good enough test and + documentation coverage. */ + GF_MAINTAINED, + /* The component is: + - no more a focus + - no more solving a valid use case + - no more maintained, no volunteers to maintain + - there is 'maintained' or 'tech-preview' feature, + which does the same thing, better. + */ + GF_DEPRECATED, + /* The 'component' is no more 'built'. */ + GF_OBSOLETE, + /* The 'component' exist for Documentation purposes. + No real usecase */ + GF_DOCUMENT_PURPOSE, +} gf_category_t; + +static const char *const FOP_PRI_STRINGS[] = {"HIGH", "NORMAL", "LOW", "LEAST"}; + +static inline const char * +fop_pri_to_string(gf_fop_pri_t pri) +{ + if (IS_ERROR(pri)) + return "UNSPEC"; + + if (pri >= GF_FOP_PRI_MAX) + return "INVALID"; + + return FOP_PRI_STRINGS[pri]; +} + +const char * +fop_enum_to_pri_string(glusterfs_fop_t fop); + +#define GF_SET_IF_NOT_PRESENT 0x1 /* default behaviour */ +#define GF_SET_OVERWRITE 0x2 /* Overwrite with the buf given */ +#define GF_SET_DIR_ONLY 0x4 +#define GF_SET_EPOCH_TIME 0x8 /* used by afr dir lookup selfheal */ +#define GF_AUXILLARY_PARGFID 0xd /* RIO dummy parent gfid */ + +/* key value which quick read uses to get small files in lookup cbk */ +#define GF_CONTENT_KEY "glusterfs.content" + +struct _xlator_cmdline_option { + 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; + char *transport; + int port; +}; +typedef struct _server_cmdline server_cmdline_t; + +#define GF_OPTION_ENABLE _gf_true +#define GF_OPTION_DISABLE _gf_false +#define GF_OPTION_DEFERRED 2 + +typedef enum { _gf_none, _gf_memcheck, _gf_drd } gf_valgrind_tool; + +struct _cmd_args { + /* 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; + char *log_ident; + gf_log_logger_t logger; + gf_log_format_t log_format; + uint32_t log_buf_size; + uint32_t log_flush_timeout; + int32_t max_connect_attempts; + char *print_exports; + char *print_netgroups; + int print_xlatordir; + int print_statedumpdir; + int print_logdir; + int print_libexecdir; + /* advanced options */ + uint32_t volfile_server_port; + char *volfile_server_transport; + uint32_t log_server_port; + char *pid_file; + char *sock_file; + int no_daemon_mode; + char *run_id; + int debug_mode; + int read_only; + int acl; + int selinux; + int capability; + int enable_ino32; + int worm; + int mac_compat; + int fopen_keep_cache; + int gid_timeout; + char gid_timeout_set; + int aux_gfid_mount; + + /* need a process wide timer-wheel? */ + int global_timer_wheel; + + /* list of xlator_option_t */ + struct list_head xlator_options; + + /* fuse options */ + int fuse_direct_io_mode; + char *use_readdirp; + int no_root_squash; + 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; + pid_t client_pid; + int client_pid_set; + unsigned uid_map_root; + int32_t lru_limit; + int32_t invalidate_limit; + int background_qlen; + int congestion_threshold; + char *fuse_mountopts; + int mem_acct; + int resolve_gids; + + /* key args */ + char *mount_point; + char *volfile_id; + + /* required for portmap */ + int brick_port; + char *brick_name; + int brick_port2; + + /* Should management connections use SSL? */ + int secure_mgmt; + + /* Linux-only OOM killer adjustment */ +#ifdef GF_LINUX_HOST_OS + char *oom_score_adj; +#endif + + /* Run this process with valgrind? Might want to prevent calling + * functions that prevent valgrind from working correctly, like + * dlclose(). */ + gf_valgrind_tool vgtool; + + int localtime_logging; + + /* For the subdir mount */ + char *subdir_mount; + + char *process_name; + char *event_history; + int thin_client; + uint32_t reader_thread_count; + + /* FUSE writeback cache support */ + int kernel_writeback_cache; + uint32_t attr_times_granularity; + + int fuse_flush_handle_interrupt; + int fuse_auto_inval; + + bool global_threading; + bool brick_mux; + + uint32_t fuse_dev_eperm_ratelimit_ns; +}; +typedef struct _cmd_args cmd_args_t; + +struct _glusterfs_graph { + struct list_head list; + struct timeval dob; + void *first; + void *top; /* selected by -n */ + int xl_count; + int id; /* Used in logging */ + int used; /* Should be set when fuse gets + first CHILD_UP */ + uint32_t volfile_checksum; + uint32_t leaf_count; + void *last_xl; /* Stores the last xl of the graph, as of now only populated + in client multiplexed code path */ + pthread_mutex_t mutex; + pthread_cond_t child_down_cond; /* for broadcasting CHILD_DOWN */ + int parent_down; + char graph_uuid[128]; + char volume_id[GF_UUID_BUF_SIZE]; +}; +typedef struct _glusterfs_graph glusterfs_graph_t; + +typedef int32_t (*glusterfsd_mgmt_event_notify_fn_t)(int32_t event, void *data, + ...); + +typedef enum { + MGMT_SSL_NEVER = 0, + MGMT_SSL_COPY_IO, + MGMT_SSL_ALWAYS +} mgmt_ssl_t; + +struct tvec_base; + +/* reference counting for the global (per ctx) timer-wheel */ +struct gf_ctx_tw { + GF_REF_DECL; + struct tvec_base *timer_wheel; /* global timer-wheel instance */ +}; + +struct _glusterfs_ctx { + 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; + void *logbuf_pool; + gf_lock_t lock; + size_t page_size; + + /* one per volfile parse */ + struct list_head graphs; + + /* the latest graph in use */ + glusterfs_graph_t *active; + + /* fuse or nfs (but not protocol/server) */ + void *master; + + /* xlator implementing MOPs for centralized logging, volfile server */ + void *mgmt; + + /* listener of the commands from glusterd */ + void *listener; + + /* toggle switch for latency measurement */ + unsigned char measure_latency; + pthread_t sigwaiter; + char *cmdlinestr; + struct mem_pool *stub_mem_pool; + unsigned char cleanup_started; + int graph_id; /* Incremented per graph, value should + indicate how many times the graph has + 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 list_head mempool_list; /* used to keep a global list of + mempools, used to log details of + mempool in statedump */ + char *statedump_path; + + struct mem_pool *dict_pool; + struct mem_pool *dict_pair_pool; + struct mem_pool *dict_data_pool; + + glusterfsd_mgmt_event_notify_fn_t notify; /* Used for xlators to make + call to fsd-mgmt */ + gf_log_handle_t log; /* all logging related variables */ + + int mem_acct_enable; + + int daemon_pipe[2]; + + struct clienttable *clienttable; + + /* + * Should management connections use SSL? This is the only place we + * can put it where both daemon-startup and socket code will see it. + * + * Why is it an int? Because we're included before common-utils.h, + * which defines gf_boolean_t (what we really want). It doesn't make + * any sense, but it's not worth turning the codebase upside-down to + * fix it. Thus, an int. + */ + int secure_mgmt; + + /* The option is use to set cert_depth while management connection + use SSL + */ + int ssl_cert_depth; + + /* + * Should *our* server/inbound connections use SSL? This is only true + * if we're glusterd and secure_mgmt is set, or if we're glusterfsd + * and SSL is set on the I/O path. It should never be set e.g. for + * NFS. + */ + mgmt_ssl_t secure_srvr; + /* Buffer to 'save' backtrace even under OOM-kill like situations*/ + char btbuf[GF_BACKTRACE_LEN]; + + pthread_mutex_t notify_lock; + pthread_mutex_t cleanup_lock; + pthread_cond_t notify_cond; + int notifying; + + struct gf_ctx_tw *tw; /* refcounted timer_wheel */ + + gf_lock_t volfile_lock; + + /* configuration related elements, which gets changed + from global xlator */ + struct { + char *metrics_dumppath; + } config; + + struct { + gf_atomic_t max_dict_pairs; + gf_atomic_t total_pairs_used; + gf_atomic_t total_dicts_used; + } stats; + + struct list_head volfile_list; + /* Add members to manage janitor threads for cleanup fd */ + struct list_head janitor_fds; + pthread_cond_t fd_cond; + pthread_mutex_t fd_lock; + pthread_t janitor; + /* The variable is use to save total posix xlator count */ + uint32_t pxl_count; + + char volume_id[GF_UUID_BUF_SIZE]; /* Used only in protocol/client */ +}; +typedef struct _glusterfs_ctx glusterfs_ctx_t; + +typedef struct { + char volfile_checksum[SHA256_DIGEST_LENGTH]; + char vol_id[NAME_MAX + 1]; + struct list_head volfile_list; + glusterfs_graph_t *graph; + FILE *pidfp; +} gf_volfile_t; + +glusterfs_ctx_t * +glusterfs_ctx_new(void); + +struct gf_flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; + gf_lkowner_t l_owner; +}; + +typedef struct lock_migration_info { + struct list_head list; + struct gf_flock flock; + char *client_uid; + uint32_t lk_flags; +} lock_migration_info_t; + +#define GF_MUST_CHECK __attribute__((warn_unused_result)) +/* + * Some macros (e.g. ALLOC_OR_GOTO) set variables in function scope, but the + * calling function might not only declare the variable to keep the macro happy + * and not use it otherwise. In such cases, the following can be used to + * suppress the "set but not used" warning that would otherwise occur. + */ +#define GF_UNUSED __attribute__((unused)) + +/* + * If present, this has the following effects: + * + * glusterd enables privileged commands over TCP + * + * all code enables SSL for outbound connections to management port + * + * glusterd enables SSL for inbound connections + * + * Servers and clients enable/disable SSL among themselves by other means. + * Making secure management connections conditional on a file is a bit of a + * hack, but we don't have any other place for such global settings across + * all of the affected components. Making it a compile-time option would + * reduce functionality, both for users and for testing (which can now be + * done using secure connections for all tests without change elsewhere). + * + */ +#define SECURE_ACCESS_FILE GLUSTERD_DEFAULT_WORKDIR "/secure-access" + +int +glusterfs_graph_prepare(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx, + char *volume_name); +int +glusterfs_graph_destroy_residual(glusterfs_graph_t *graph); +int +glusterfs_graph_deactivate(glusterfs_graph_t *graph); +int +glusterfs_graph_destroy(glusterfs_graph_t *graph); +int +glusterfs_get_leaf_count(glusterfs_graph_t *graph); +int +glusterfs_graph_activate(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx); +glusterfs_graph_t * +glusterfs_graph_construct(FILE *fp); +int +glusterfs_graph_init(glusterfs_graph_t *graph); +glusterfs_graph_t * +glusterfs_graph_new(void); +int +glusterfs_graph_reconfigure(glusterfs_graph_t *oldgraph, + glusterfs_graph_t *newgraph); +int +glusterfs_graph_attach(glusterfs_graph_t *orig_graph, char *path, + glusterfs_graph_t **newgraph); +int +glusterfs_graph_parent_up(glusterfs_graph_t *graph); + +void +gf_free_mig_locks(lock_migration_info_t *locks); + +int +glusterfs_read_secure_access_file(void); +int +glusterfs_graph_fini(glusterfs_graph_t *graph); +#endif /* _GLUSTERFS_H */ diff --git a/libglusterfs/src/glusterfs/graph-utils.h b/libglusterfs/src/glusterfs/graph-utils.h new file mode 100644 index 00000000000..247f1a55d5a --- /dev/null +++ b/libglusterfs/src/glusterfs/graph-utils.h @@ -0,0 +1,20 @@ +/* + 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 _GRAPH_H_ +#define _GRAPH_H_ + +int +glusterfs_graph_print_file(FILE *file, glusterfs_graph_t *graph); +int +glusterfs_xlator_link(xlator_t *pxl, xlator_t *cxl); +void +glusterfs_graph_set_first(glusterfs_graph_t *graph, xlator_t *xl); +#endif diff --git a/libglusterfs/src/glusterfs/hashfn.h b/libglusterfs/src/glusterfs/hashfn.h new file mode 100644 index 00000000000..6e92e706d8c --- /dev/null +++ b/libglusterfs/src/glusterfs/hashfn.h @@ -0,0 +1,23 @@ +/* + 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 __HASHFN_H__ +#define __HASHFN_H__ + +#include <sys/types.h> +#include <stdint.h> + +uint32_t +SuperFastHash(const char *data, int32_t len); + +uint32_t +gf_dm_hashfn(const char *msg, int len); + +#endif /* __HASHFN_H__ */ diff --git a/libglusterfs/src/glusterfs/iatt.h b/libglusterfs/src/glusterfs/iatt.h new file mode 100644 index 00000000000..f03d68b02f0 --- /dev/null +++ b/libglusterfs/src/glusterfs/iatt.h @@ -0,0 +1,489 @@ +/* + 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 _IATT_H +#define _IATT_H + +#if defined(GF_LINUX_HOST_OS) +#include <sys/sysmacros.h> /* for makedev(3), major(3), minor(3) */ +#endif +#include <sys/types.h> +#include <sys/stat.h> /* for iatt <--> stat conversions */ +#include <unistd.h> + +#include "glusterfs/compat.h" +#include "glusterfs/compat-uuid.h" + +typedef enum { + IA_INVAL = 0, + IA_IFREG, + IA_IFDIR, + IA_IFLNK, + IA_IFBLK, + IA_IFCHR, + IA_IFIFO, + IA_IFSOCK +} ia_type_t; + +typedef struct { + uint8_t suid : 1; + uint8_t sgid : 1; + uint8_t sticky : 1; + struct { + uint8_t read : 1; + uint8_t write : 1; + uint8_t exec : 1; + } owner, group, other; +} ia_prot_t; + +struct iatt { + uint64_t ia_flags; + uint64_t ia_ino; /* inode number */ + uint64_t ia_dev; /* backing device ID */ + uint64_t ia_rdev; /* device ID (if special file) */ + uint64_t ia_size; /* file size in bytes */ + uint32_t ia_nlink; /* Link count */ + uint32_t ia_uid; /* user ID of owner */ + uint32_t ia_gid; /* group ID of owner */ + uint32_t ia_blksize; /* blocksize for filesystem I/O */ + uint64_t ia_blocks; /* number of 512B blocks allocated */ + int64_t ia_atime; /* last access time */ + int64_t ia_mtime; /* last modification time */ + int64_t ia_ctime; /* last status change time */ + int64_t ia_btime; /* creation time. Fill using statx */ + uint32_t ia_atime_nsec; + uint32_t ia_mtime_nsec; + uint32_t ia_ctime_nsec; + uint32_t ia_btime_nsec; + uint64_t ia_attributes; /* chattr related:compressed, immutable, + * append only, encrypted etc.*/ + uint64_t ia_attributes_mask; /* Mask for the attributes */ + + uuid_t ia_gfid; + ia_type_t ia_type; /* type of file */ + ia_prot_t ia_prot; /* protection */ +}; + +struct old_iatt { + uint64_t ia_ino; /* inode number */ + uuid_t ia_gfid; + uint64_t ia_dev; /* backing device ID */ + ia_type_t ia_type; /* type of file */ + ia_prot_t ia_prot; /* protection */ + uint32_t ia_nlink; /* Link count */ + uint32_t ia_uid; /* user ID of owner */ + uint32_t ia_gid; /* group ID of owner */ + uint64_t ia_rdev; /* device ID (if special file) */ + uint64_t ia_size; /* file size in bytes */ + uint32_t ia_blksize; /* blocksize for filesystem I/O */ + uint64_t ia_blocks; /* number of 512B blocks allocated */ + uint32_t ia_atime; /* last access time */ + uint32_t ia_atime_nsec; + uint32_t ia_mtime; /* last modification time */ + uint32_t ia_mtime_nsec; + uint32_t ia_ctime; /* last status change time */ + uint32_t ia_ctime_nsec; +}; + +struct mdata_iatt { + int64_t ia_atime; /* last access time */ + int64_t ia_mtime; /* last modification time */ + int64_t ia_ctime; /* last status change time */ + uint32_t ia_atime_nsec; + uint32_t ia_mtime_nsec; + uint32_t ia_ctime_nsec; +}; + +/* 64-bit mask for valid members in struct iatt. */ +#define IATT_TYPE 0x0000000000000001U +#define IATT_MODE 0x0000000000000002U +#define IATT_NLINK 0x0000000000000004U +#define IATT_UID 0x0000000000000008U +#define IATT_GID 0x0000000000000010U +#define IATT_ATIME 0x0000000000000020U +#define IATT_MTIME 0x0000000000000040U +#define IATT_CTIME 0x0000000000000080U +#define IATT_INO 0x0000000000000100U +#define IATT_SIZE 0x0000000000000200U +#define IATT_BLOCKS 0x0000000000000400U +#define IATT_BTIME 0x0000000000000800U +#define IATT_GFID 0x0000000000001000U + +/* Macros for checking validity of struct iatt members.*/ +#define IATT_TYPE_VALID(iaflags) (iaflags & IATT_TYPE) +#define IATT_MODE_VALID(iaflags) (iaflags & IATT_MODE) +#define IATT_NLINK_VALID(iaflags) (iaflags & IATT_NLINK) +#define IATT_UID_VALID(iaflags) (iaflags & IATT_UID) +#define IATT_GID_VALID(iaflags) (iaflags & IATT_GID) +#define IATT_ATIME_VALID(iaflags) (iaflags & IATT_ATIME) +#define IATT_MTIME_VALID(iaflags) (iaflags & IATT_MTIME) +#define IATT_CTIME_VALID(iaflags) (iaflags & IATT_CTIME) +#define IATT_INO_VALID(iaflags) (iaflags & IATT_INO) +#define IATT_SIZE_VALID(iaflags) (iaflags & IATT_SIZE) +#define IATT_BLOCKS_VALID(iaflags) (iaflags & IATT_BLOCKS) +#define IATT_BTIME_VALID(iaflags) (iaflags & IATT_BTIME) +#define IATT_GFID_VALID(iaflags) (iaflags & IATT_GFID) + +#define IA_ISREG(t) (t == IA_IFREG) +#define IA_ISDIR(t) (t == IA_IFDIR) +#define IA_ISLNK(t) (t == IA_IFLNK) +#define IA_ISBLK(t) (t == IA_IFBLK) +#define IA_ISCHR(t) (t == IA_IFCHR) +#define IA_ISFIFO(t) (t == IA_IFIFO) +#define IA_ISSOCK(t) (t == IA_IFSOCK) +#define IA_ISINVAL(t) (t == IA_INVAL) + +#define IA_PROT_RUSR(prot) ((prot).owner.read == 1) +#define IA_PROT_WUSR(prot) ((prot).owner.write == 1) +#define IA_PROT_XUSR(prot) ((prot).owner.exec == 1) + +#define IA_PROT_RGRP(prot) ((prot).group.read == 1) +#define IA_PROT_WGRP(prot) ((prot).group.write == 1) +#define IA_PROT_XGRP(prot) ((prot).group.exec == 1) + +#define IA_PROT_ROTH(prot) ((prot).other.read == 1) +#define IA_PROT_WOTH(prot) ((prot).other.write == 1) +#define IA_PROT_XOTH(prot) ((prot).other.exec == 1) + +#define IA_PROT_SUID(prot) ((prot).suid == 1) +#define IA_PROT_SGID(prot) ((prot).sgid == 1) +#define IA_PROT_STCKY(prot) ((prot).sticky == 1) + +#define IA_FILE_OR_DIR(t) (IA_ISREG(t) || IA_ISDIR(t)) + +static inline uint32_t +ia_major(uint64_t ia_dev) +{ + return (uint32_t)(ia_dev >> 32); +} + +static inline uint32_t +ia_minor(uint64_t ia_dev) +{ + return (uint32_t)(ia_dev & 0xffffffff); +} + +static inline uint64_t +ia_makedev(uint32_t ia_maj, uint32_t ia_min) +{ + return ((((uint64_t)ia_maj) << 32) | ia_min); +} + +static inline ia_prot_t +ia_prot_from_st_mode(mode_t mode) +{ + ia_prot_t ia_prot = { + 0, + }; + + if (mode & S_ISUID) + ia_prot.suid = 1; + if (mode & S_ISGID) + ia_prot.sgid = 1; + if (mode & S_ISVTX) + ia_prot.sticky = 1; + + if (mode & S_IRUSR) + ia_prot.owner.read = 1; + if (mode & S_IWUSR) + ia_prot.owner.write = 1; + if (mode & S_IXUSR) + ia_prot.owner.exec = 1; + + if (mode & S_IRGRP) + ia_prot.group.read = 1; + if (mode & S_IWGRP) + ia_prot.group.write = 1; + if (mode & S_IXGRP) + ia_prot.group.exec = 1; + + if (mode & S_IROTH) + ia_prot.other.read = 1; + if (mode & S_IWOTH) + ia_prot.other.write = 1; + if (mode & S_IXOTH) + ia_prot.other.exec = 1; + + return ia_prot; +} + +static inline ia_type_t +ia_type_from_st_mode(mode_t mode) +{ + ia_type_t type = IA_INVAL; + + if (S_ISREG(mode)) + type = IA_IFREG; + if (S_ISDIR(mode)) + type = IA_IFDIR; + if (S_ISLNK(mode)) + type = IA_IFLNK; + if (S_ISBLK(mode)) + type = IA_IFBLK; + if (S_ISCHR(mode)) + type = IA_IFCHR; + if (S_ISFIFO(mode)) + type = IA_IFIFO; + if (S_ISSOCK(mode)) + type = IA_IFSOCK; + + return type; +} + +static inline uint32_t +st_mode_prot_from_ia(ia_prot_t prot) +{ + uint32_t prot_bit = 0; + + if (prot.suid) + prot_bit |= S_ISUID; + if (prot.sgid) + prot_bit |= S_ISGID; + if (prot.sticky) + prot_bit |= S_ISVTX; + + if (prot.owner.read) + prot_bit |= S_IRUSR; + if (prot.owner.write) + prot_bit |= S_IWUSR; + if (prot.owner.exec) + prot_bit |= S_IXUSR; + + if (prot.group.read) + prot_bit |= S_IRGRP; + if (prot.group.write) + prot_bit |= S_IWGRP; + if (prot.group.exec) + prot_bit |= S_IXGRP; + + if (prot.other.read) + prot_bit |= S_IROTH; + if (prot.other.write) + prot_bit |= S_IWOTH; + if (prot.other.exec) + prot_bit |= S_IXOTH; + + return prot_bit; +} + +static inline uint32_t +st_mode_type_from_ia(ia_type_t type) +{ + uint32_t type_bit = 0; + + switch (type) { + case IA_IFREG: + type_bit = S_IFREG; + break; + case IA_IFDIR: + type_bit = S_IFDIR; + break; + case IA_IFLNK: + type_bit = S_IFLNK; + break; + case IA_IFBLK: + type_bit = S_IFBLK; + break; + case IA_IFCHR: + type_bit = S_IFCHR; + break; + case IA_IFIFO: + type_bit = S_IFIFO; + break; + case IA_IFSOCK: + type_bit = S_IFSOCK; + break; + case IA_INVAL: + break; + } + + return type_bit; +} + +static inline mode_t +st_mode_from_ia(ia_prot_t prot, ia_type_t type) +{ + mode_t st_mode = 0; + uint32_t type_bit = 0; + uint32_t prot_bit = 0; + + type_bit = st_mode_type_from_ia(type); + prot_bit = st_mode_prot_from_ia(prot); + + st_mode = (type_bit | prot_bit); + + return st_mode; +} + +static inline void +iatt_to_mdata(struct mdata_iatt *mdata, struct iatt *iatt) +{ + mdata->ia_atime = iatt->ia_atime; + mdata->ia_atime_nsec = iatt->ia_atime_nsec; + mdata->ia_mtime = iatt->ia_mtime; + mdata->ia_mtime_nsec = iatt->ia_mtime_nsec; + mdata->ia_ctime = iatt->ia_ctime; + mdata->ia_ctime_nsec = iatt->ia_ctime_nsec; +} + +static inline int +iatt_from_stat(struct iatt *iatt, struct stat *stat) +{ + iatt->ia_dev = stat->st_dev; + iatt->ia_ino = stat->st_ino; + + iatt->ia_type = ia_type_from_st_mode(stat->st_mode); + iatt->ia_prot = ia_prot_from_st_mode(stat->st_mode); + + iatt->ia_nlink = stat->st_nlink; + iatt->ia_uid = stat->st_uid; + iatt->ia_gid = stat->st_gid; + + iatt->ia_rdev = ia_makedev(major(stat->st_rdev), minor(stat->st_rdev)); + + iatt->ia_size = stat->st_size; + iatt->ia_blksize = stat->st_blksize; + iatt->ia_blocks = stat->st_blocks; + + /* There is a possibility that the backend FS (like XFS) can + allocate blocks beyond EOF for better performance reasons, which + results in 'st_blocks' with higher values than what is consumed by + the file descriptor. This would break few logic inside GlusterFS, + like quota behavior etc, thus we need the exact number of blocks + which are consumed by the file to the higher layers inside GlusterFS. + Currently, this logic won't work for sparse files (ie, file with + holes) + */ + { + uint64_t maxblocks; + + maxblocks = (iatt->ia_size + 511) / 512; + + if (iatt->ia_blocks > maxblocks) + iatt->ia_blocks = maxblocks; + } + + iatt->ia_atime = stat->st_atime; + iatt->ia_atime_nsec = ST_ATIM_NSEC(stat); + + iatt->ia_mtime = stat->st_mtime; + iatt->ia_mtime_nsec = ST_MTIM_NSEC(stat); + + iatt->ia_ctime = stat->st_ctime; + iatt->ia_ctime_nsec = ST_CTIM_NSEC(stat); + + /* Setting IATT_INO in ia_flags is done in posix_fill_ino_from_gfid. */ + iatt->ia_flags = iatt->ia_flags | IATT_TYPE | IATT_MODE | IATT_NLINK | + IATT_UID | IATT_GID | IATT_SIZE | IATT_BLOCKS | + IATT_ATIME | IATT_MTIME | IATT_CTIME; + + return 0; +} + +static inline int +iatt_to_stat(struct iatt *iatt, struct stat *stat) +{ + stat->st_dev = iatt->ia_dev; + stat->st_ino = iatt->ia_ino; + + stat->st_mode = st_mode_from_ia(iatt->ia_prot, iatt->ia_type); + + stat->st_nlink = iatt->ia_nlink; + stat->st_uid = iatt->ia_uid; + stat->st_gid = iatt->ia_gid; + + stat->st_rdev = makedev(ia_major(iatt->ia_rdev), ia_minor(iatt->ia_rdev)); + + stat->st_size = iatt->ia_size; + stat->st_blksize = iatt->ia_blksize; + stat->st_blocks = iatt->ia_blocks; + + stat->st_atime = iatt->ia_atime; + ST_ATIM_NSEC_SET(stat, iatt->ia_atime_nsec); + + stat->st_mtime = iatt->ia_mtime; + ST_MTIM_NSEC_SET(stat, iatt->ia_mtime_nsec); + + stat->st_ctime = iatt->ia_ctime; + ST_CTIM_NSEC_SET(stat, iatt->ia_ctime_nsec); + + return 0; +} + +static inline void +oldiatt_from_iatt(struct old_iatt *o_iatt, struct iatt *c_iatt) +{ + o_iatt->ia_dev = c_iatt->ia_dev; + o_iatt->ia_ino = c_iatt->ia_ino; + o_iatt->ia_type = c_iatt->ia_type; + o_iatt->ia_prot = c_iatt->ia_prot; + o_iatt->ia_nlink = c_iatt->ia_nlink; + o_iatt->ia_uid = c_iatt->ia_uid; + o_iatt->ia_gid = c_iatt->ia_gid; + o_iatt->ia_rdev = c_iatt->ia_rdev; + o_iatt->ia_size = c_iatt->ia_size; + o_iatt->ia_blksize = c_iatt->ia_blksize; + o_iatt->ia_blocks = c_iatt->ia_blocks; + o_iatt->ia_atime = c_iatt->ia_atime; + o_iatt->ia_atime_nsec = c_iatt->ia_atime_nsec; + o_iatt->ia_mtime = c_iatt->ia_mtime; + o_iatt->ia_mtime_nsec = c_iatt->ia_mtime_nsec; + o_iatt->ia_ctime = c_iatt->ia_ctime; + o_iatt->ia_ctime_nsec = c_iatt->ia_ctime_nsec; + + gf_uuid_copy(o_iatt->ia_gfid, c_iatt->ia_gfid); + + return; +} + +static inline void +iatt_from_oldiatt(struct iatt *c_iatt, struct old_iatt *o_iatt) +{ + c_iatt->ia_dev = o_iatt->ia_dev; + c_iatt->ia_ino = o_iatt->ia_ino; + c_iatt->ia_type = o_iatt->ia_type; + c_iatt->ia_prot = o_iatt->ia_prot; + c_iatt->ia_nlink = o_iatt->ia_nlink; + c_iatt->ia_uid = o_iatt->ia_uid; + c_iatt->ia_gid = o_iatt->ia_gid; + c_iatt->ia_rdev = o_iatt->ia_rdev; + c_iatt->ia_size = o_iatt->ia_size; + c_iatt->ia_blksize = o_iatt->ia_blksize; + c_iatt->ia_blocks = o_iatt->ia_blocks; + c_iatt->ia_atime = o_iatt->ia_atime; + c_iatt->ia_atime_nsec = o_iatt->ia_atime_nsec; + c_iatt->ia_mtime = o_iatt->ia_mtime; + c_iatt->ia_mtime_nsec = o_iatt->ia_mtime_nsec; + c_iatt->ia_ctime = o_iatt->ia_ctime; + c_iatt->ia_ctime_nsec = o_iatt->ia_ctime_nsec; + + gf_uuid_copy(c_iatt->ia_gfid, o_iatt->ia_gfid); + + c_iatt->ia_attributes = 0; + + c_iatt->ia_flags = IATT_TYPE | IATT_MODE | IATT_NLINK | IATT_INO | + IATT_UID | IATT_GID | IATT_SIZE | IATT_BLOCKS | + IATT_ATIME | IATT_MTIME | IATT_CTIME | IATT_GFID; + + return; +} + +static inline int +is_same_mode(ia_prot_t prot1, ia_prot_t prot2) +{ + int ret = 0; + + if (st_mode_prot_from_ia(prot1) != st_mode_prot_from_ia(prot2)) + ret = -1; + + return ret; +} + +#endif /* _IATT_H */ diff --git a/libglusterfs/src/glusterfs/inode.h b/libglusterfs/src/glusterfs/inode.h new file mode 100644 index 00000000000..4b28da510c7 --- /dev/null +++ b/libglusterfs/src/glusterfs/inode.h @@ -0,0 +1,306 @@ +/* + 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 _INODE_H +#define _INODE_H + +#include <stdint.h> +#include <sys/types.h> + +#define LOOKUP_NEEDED 1 +#define LOOKUP_NOT_NEEDED 2 + +#define DEFAULT_INODE_MEMPOOL_ENTRIES 32 * 1024 +#define INODE_PATH_FMT "<gfid:%s>" +struct _inode_table; +typedef struct _inode_table inode_table_t; + +struct _inode; +typedef struct _inode inode_t; + +struct _dentry; +typedef struct _dentry dentry_t; + +#include "glusterfs/list.h" +#include "glusterfs/iatt.h" +#include "glusterfs/compat-uuid.h" +#include "glusterfs/fd.h" + +struct _inode_table { + pthread_mutex_t lock; + size_t hashsize; /* bucket size of inode hash and dentry hash */ + char *name; /* name of the inode table, just for gf_log() */ + inode_t *root; /* root directory inode, with number 1 */ + xlator_t *xl; /* xlator to be called to do purge */ + uint32_t lru_limit; /* maximum LRU cache size */ + struct list_head *inode_hash; /* buckets for inode hash table */ + struct list_head *name_hash; /* buckets for dentry hash table */ + struct list_head active; /* list of inodes currently active (in an fop) */ + uint32_t active_size; /* count of inodes in active list */ + struct list_head lru; /* list of inodes recently used. + lru.next most recent */ + uint32_t lru_size; /* count of inodes in lru list */ + struct list_head purge; /* list of inodes to be purged soon */ + uint32_t purge_size; /* count of inodes in purge list */ + + 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 */ + + /* This is required for 'invalidation' when 'nlookup' would be used, + specially in case of fuse-bridge */ + int32_t (*invalidator_fn)(xlator_t *, inode_t *); + xlator_t *invalidator_xl; + struct list_head invalidate; /* inodes which are in invalidation queue */ + uint32_t invalidate_size; /* count of inodes in invalidation list */ + + /* flag to indicate whether the cleanup of the inode + table started or not */ + gf_boolean_t cleanup_started; +}; + +struct _dentry { + struct list_head inode_list; /* list of dentries of inode */ + struct list_head hash; /* hash table pointers */ + inode_t *inode; /* inode of this directory entry */ + char *name; /* name of the directory entry */ + inode_t *parent; /* directory of the entry */ +}; + +struct _inode_ctx { + union { + 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; + }; + int ref; /* This is for debugging inode ref leaks, + basically helps in identifying the xlator + causing th ref leak, it is printed in + statedump */ +}; + +struct _inode { + inode_table_t *table; /* the table this inode belongs to */ + uuid_t gfid; + gf_lock_t lock; + gf_atomic_t nlookup; + uint32_t fd_count; /* Open fd count */ + uint32_t active_fd_count; /* Active open fd count */ + uint32_t ref; /* reference count on this inode */ + ia_type_t ia_type; /* what kind of file */ + struct list_head fd_list; /* list of open files on this inode */ + struct list_head dentry_list; /* list of directory entries for this inode */ + struct list_head hash; /* hash table pointers */ + struct list_head list; /* active/lru/purge */ + + struct _inode_ctx *_ctx; /* replacement for dict_t *(inode->ctx) */ + bool in_invalidate_list; /* Set if inode is in table invalidate list */ + bool invalidate_sent; /* Set it if invalidator_fn is called for inode */ +}; + +#define UUID0_STR "00000000-0000-0000-0000-000000000000" +#define GFID_STR_PFX "<gfid:" UUID0_STR ">" +#define GFID_STR_PFX_LEN (sizeof(GFID_STR_PFX) - 1) + +inode_table_t * +inode_table_new(uint32_t lru_limit, xlator_t *xl); + +inode_table_t * +inode_table_with_invalidator(uint32_t lru_limit, xlator_t *xl, + int32_t (*invalidator_fn)(xlator_t *, inode_t *), + xlator_t *invalidator_xl); + +void +inode_table_destroy_all(glusterfs_ctx_t *ctx); + +void +inode_table_destroy(inode_table_t *inode_table); + +inode_t * +inode_new(inode_table_t *table); + +inode_t * +inode_link(inode_t *inode, inode_t *parent, const char *name, + struct iatt *stbuf); + +void +inode_unlink(inode_t *inode, inode_t *parent, const char *name); + +inode_t * +inode_parent(inode_t *inode, uuid_t pargfid, const char *name); + +inode_t * +inode_ref(inode_t *inode); + +inode_t * +inode_unref(inode_t *inode); + +int +inode_lookup(inode_t *inode); + +int +inode_forget(inode_t *inode, uint64_t nlookup); +int +inode_forget_with_unref(inode_t *inode, uint64_t nlookup); + +int +inode_ref_reduce_by_n(inode_t *inode, uint64_t nref); + +int +inode_invalidate(inode_t *inode); + +int +inode_rename(inode_table_t *table, inode_t *olddir, const char *oldname, + inode_t *newdir, const char *newname, inode_t *inode, + struct iatt *stbuf); + +inode_t * +inode_grep(inode_table_t *table, inode_t *parent, const char *name); + +int +inode_grep_for_gfid(inode_table_t *table, inode_t *parent, const char *name, + uuid_t gfid, ia_type_t *type); + +inode_t * +inode_find(inode_table_t *table, uuid_t gfid); + +int +inode_path(inode_t *inode, const char *name, char **bufp); + +int +__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); +int +__inode_ctx_set2(inode_t *inode, xlator_t *xlator, uint64_t *value1, + uint64_t *value2); + +int +inode_ctx_get2(inode_t *inode, xlator_t *xlator, uint64_t *value1, + uint64_t *value2); +int +__inode_ctx_get2(inode_t *inode, xlator_t *xlator, uint64_t *value1, + uint64_t *value2); + +int +inode_ctx_del2(inode_t *inode, xlator_t *xlator, uint64_t *value1, + uint64_t *value2); + +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); + +static inline int +__inode_ctx_put(inode_t *inode, xlator_t *this, uint64_t v) +{ + 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_set0(inode, this, &v); +} + +#define __inode_ctx_set(i, x, v_p) __inode_ctx_set0(i, x, v_p) + +#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) +#define inode_ctx_del1(i, x, v) inode_ctx_del2(i, x, 0, v) + +gf_boolean_t +__is_root_gfid(uuid_t gfid); + +void +__inode_table_set_lru_limit(inode_table_t *table, uint32_t lru_limit); + +void +inode_table_set_lru_limit(inode_table_t *table, uint32_t lru_limit); + +void +inode_ctx_merge(fd_t *fd, inode_t *inode, inode_t *linked_inode); + +int +inode_is_linked(inode_t *inode); + +void +inode_set_need_lookup(inode_t *inode, xlator_t *this); + +gf_boolean_t +inode_needs_lookup(inode_t *inode, xlator_t *this); + +int +inode_has_dentry(inode_t *inode); + +size_t +inode_ctx_size(inode_t *inode); + +void +inode_find_directory_name(inode_t *inode, const char **name); +#endif /* _INODE_H */ diff --git a/libglusterfs/src/glusterfs/iobuf.h b/libglusterfs/src/glusterfs/iobuf.h new file mode 100644 index 00000000000..4bd443efd5e --- /dev/null +++ b/libglusterfs/src/glusterfs/iobuf.h @@ -0,0 +1,194 @@ +/* + 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 _IOBUF_H_ +#define _IOBUF_H_ + +#include <stddef.h> // for size_t +#include <sys/mman.h> +#include "glusterfs/atomic.h" // for gf_atomic_t +#include <sys/uio.h> // for struct iovec +#include "glusterfs/locking.h" // for gf_lock_t +#include "glusterfs/list.h" + +#define GF_VARIABLE_IOBUF_COUNT 32 + +#define GF_RDMA_DEVICE_COUNT 8 + +/* Lets try to define the new anonymous mapping + * flag, in case the system is still using the + * now deprecated MAP_ANON flag. + * + * Also, this should ideally be in a centralized/common + * header which can be used by other source files also. + */ +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif + +#define GF_ALIGN_BUF(ptr, bound) \ + ((void *)((unsigned long)(ptr + bound - 1) & (unsigned long)(~(bound - 1)))) + +#define GF_IOBUF_ALIGN_SIZE 512 + +/* one allocatable unit for the consumers of the IOBUF API */ +/* each unit hosts @page_size bytes of memory */ +struct iobuf; + +/* one region of memory mapped from the operating system */ +/* each region MMAPs @arena_size bytes of memory */ +/* each arena hosts @arena_size / @page_size IOBUFs */ +struct iobuf_arena; + +/* expandable and contractable pool of memory, internally broken into arenas */ +struct iobuf_pool; + +struct iobuf_init_config { + size_t pagesize; + int32_t num_pages; +}; + +struct iobuf { + union { + struct list_head list; + struct { + struct iobuf *next; + struct iobuf *prev; + }; + }; + struct iobuf_arena *iobuf_arena; + + gf_lock_t lock; /* for ->ptr and ->ref */ + gf_atomic_t ref; /* 0 == passive, >0 == active */ + + void *ptr; /* usable memory region by the consumer */ + + void *free_ptr; /* in case of stdalloc, this is the + one to be freed */ +}; + +struct iobuf_arena { + union { + struct list_head list; + struct { + struct iobuf_arena *next; + struct iobuf_arena *prev; + }; + }; + + struct list_head all_list; + size_t page_size; /* size of all iobufs in this arena */ + size_t arena_size; + /* this is equal to rounded_size * num_iobufs. + (rounded_size comes with gf_iobuf_get_pagesize().) */ + size_t page_count; + + struct iobuf_pool *iobuf_pool; + + void *mem_base; + struct iobuf *iobufs; /* allocated iobufs list */ + + struct iobuf active; /* head node iobuf + (unused by itself) */ + struct iobuf passive; /* head node iobuf + (unused by itself) */ + uint64_t alloc_cnt; /* total allocs in this pool */ + int active_cnt; + int passive_cnt; + int max_active; /* max active buffers at a given time */ +}; + +struct iobuf_pool { + pthread_mutex_t mutex; + size_t arena_size; /* size of memory region in + arena */ + size_t default_page_size; /* default size of iobuf */ + + struct list_head all_arenas; + struct list_head arenas[GF_VARIABLE_IOBUF_COUNT]; + /* array of arenas. Each element of the array is a list of arenas + holding iobufs of particular page_size */ + + struct list_head filled[GF_VARIABLE_IOBUF_COUNT]; + /* array of arenas without free iobufs */ + + struct list_head purge[GF_VARIABLE_IOBUF_COUNT]; + /* array of of arenas which can be purged */ + + uint64_t request_misses; /* mostly the requests for higher + value of iobufs */ + int arena_cnt; + int rdma_device_count; + struct list_head *mr_list[GF_RDMA_DEVICE_COUNT]; + void *device[GF_RDMA_DEVICE_COUNT]; + int (*rdma_registration)(void **, void *); + int (*rdma_deregistration)(struct list_head **, struct iobuf_arena *); +}; + +struct iobuf_pool * +iobuf_pool_new(void); +void +iobuf_pool_destroy(struct iobuf_pool *iobuf_pool); +struct iobuf * +iobuf_get(struct iobuf_pool *iobuf_pool); +void +iobuf_unref(struct iobuf *iobuf); +struct iobuf * +iobuf_ref(struct iobuf *iobuf); +void +iobuf_pool_destroy(struct iobuf_pool *iobuf_pool); +void +iobuf_to_iovec(struct iobuf *iob, struct iovec *iov); + +#define iobuf_ptr(iob) ((iob)->ptr) +#define iobpool_default_pagesize(iobpool) ((iobpool)->default_page_size) +#define iobuf_pagesize(iob) (iob->iobuf_arena->page_size) + +struct iobref { + gf_lock_t lock; + gf_atomic_t ref; + struct iobuf **iobrefs; + int allocated; + int used; +}; + +struct iobref * +iobref_new(void); +struct iobref * +iobref_ref(struct iobref *iobref); +void +iobref_unref(struct iobref *iobref); +int +iobref_add(struct iobref *iobref, struct iobuf *iobuf); +int +iobref_merge(struct iobref *to, struct iobref *from); +void +iobref_clear(struct iobref *iobref); + +size_t +iobuf_size(struct iobuf *iobuf); +size_t +iobref_size(struct iobref *iobref); +void +iobuf_stats_dump(struct iobuf_pool *iobuf_pool); + +struct iobuf * +iobuf_get2(struct iobuf_pool *iobuf_pool, size_t page_size); + +struct iobuf * +iobuf_get_page_aligned(struct iobuf_pool *iobuf_pool, size_t page_size, + size_t align_size); + +int +iobuf_copy(struct iobuf_pool *iobuf_pool, const struct iovec *iovec_src, + int iovcnt, struct iobref **iobref, struct iobuf **iobuf, + struct iovec *iov_dst); + +#endif /* !_IOBUF_H_ */ diff --git a/libglusterfs/src/glusterfs/latency.h b/libglusterfs/src/glusterfs/latency.h new file mode 100644 index 00000000000..4d601bbcbd6 --- /dev/null +++ b/libglusterfs/src/glusterfs/latency.h @@ -0,0 +1,33 @@ +/* + 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 __LATENCY_H__ +#define __LATENCY_H__ + +#include <inttypes.h> +#include <time.h> + +typedef struct _gf_latency { + uint64_t min; /* min time for the call (nanoseconds) */ + uint64_t max; /* max time for the call (nanoseconds) */ + uint64_t total; /* total time (nanoseconds) */ + uint64_t count; +} gf_latency_t; + +gf_latency_t * +gf_latency_new(size_t n); + +void +gf_latency_reset(gf_latency_t *lat); + +void +gf_latency_update(gf_latency_t *lat, struct timespec *begin, + struct timespec *end); +#endif /* __LATENCY_H__ */ diff --git a/libglusterfs/src/glusterfs/libglusterfs-messages.h b/libglusterfs/src/glusterfs/libglusterfs-messages.h new file mode 100644 index 00000000000..cb31dd7614b --- /dev/null +++ b/libglusterfs/src/glusterfs/libglusterfs-messages.h @@ -0,0 +1,245 @@ +/* + Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. + */ + +#ifndef _LG_MESSAGES_H_ +#define _LG_MESSAGES_H_ + +#include "glusterfs/glfs-message-id.h" + +/* To add new message IDs, append new identifiers at the end of the list. + * + * Never remove a message ID. If it's not used anymore, you can rename it or + * leave it as it is, but not delete it. This is to prevent reutilization of + * IDs by other messages. + * + * The component name must match one of the entries defined in + * glfs-message-id.h. + */ + +GLFS_MSGID( + LIBGLUSTERFS, LG_MSG_ASPRINTF_FAILED, LG_MSG_INVALID_ENTRY, + LG_MSG_COUNT_LESS_THAN_ZERO, LG_MSG_COUNT_LESS_THAN_DATA_PAIRS, + LG_MSG_VALUE_LENGTH_LESS_THAN_ZERO, LG_MSG_PAIRS_LESS_THAN_COUNT, + LG_MSG_KEY_OR_VALUE_NULL, LG_MSG_FAILED_TO_LOG_DICT, + LG_MSG_NULL_VALUE_IN_DICT, LG_MSG_DIR_OP_FAILED, + LG_MSG_STORE_HANDLE_CREATE_FAILED, LG_MSG_FILE_OP_FAILED, + LG_MSG_FILE_STAT_FAILED, LG_MSG_LOCK_FAILED, LG_MSG_UNLOCK_FAILED, + LG_MSG_DICT_SERIAL_FAILED, LG_MSG_DICT_UNSERIAL_FAILED, LG_MSG_NO_MEMORY, + LG_MSG_VOLUME_ERROR, LG_MSG_SUB_VOLUME_ERROR, LG_MSG_SYNTAX_ERROR, + LG_MSG_BACKTICK_PARSE_FAILED, LG_MSG_BUFFER_ERROR, LG_MSG_STRDUP_ERROR, + LG_MSG_HASH_FUNC_ERROR, LG_MSG_GET_BUCKET_FAILED, LG_MSG_INSERT_FAILED, + LG_MSG_OUT_OF_RANGE, LG_MSG_VALIDATE_RETURNS, LG_MSG_VALIDATE_REC_FAILED, + LG_MSG_RB_TABLE_CREATE_FAILED, LG_MSG_PATH_NOT_FOUND, + LG_MSG_EXPAND_FD_TABLE_FAILED, LG_MSG_MAPPING_FAILED, + LG_MSG_INIT_IOBUF_FAILED, LG_MSG_PAGE_SIZE_EXCEEDED, LG_MSG_ARENA_NOT_FOUND, + LG_MSG_IOBUF_NOT_FOUND, LG_MSG_POOL_NOT_FOUND, LG_MSG_SET_ATTRIBUTE_FAILED, + LG_MSG_READ_ATTRIBUTE_FAILED, LG_MSG_UNMOUNT_FAILED, + LG_MSG_LATENCY_MEASUREMENT_STATE, LG_MSG_NO_PERM, LG_MSG_NO_KEY, + LG_MSG_DICT_NULL, LG_MSG_INIT_TIMER_FAILED, LG_MSG_FD_ANONYMOUS_FAILED, + LG_MSG_FD_CREATE_FAILED, LG_MSG_BUFFER_FULL, LG_MSG_FWRITE_FAILED, + LG_MSG_PRINT_FAILED, LG_MSG_MEM_POOL_DESTROY, + LG_MSG_EXPAND_CLIENT_TABLE_FAILED, LG_MSG_DISCONNECT_CLIENT, + LG_MSG_PIPE_CREATE_FAILED, LG_MSG_SET_PIPE_FAILED, + LG_MSG_REGISTER_PIPE_FAILED, LG_MSG_POLL_IGNORE_MULTIPLE_THREADS, + LG_MSG_INDEX_NOT_FOUND, LG_MSG_EPOLL_FD_CREATE_FAILED, + LG_MSG_SLOT_NOT_FOUND, LG_MSG_STALE_FD_FOUND, LG_MSG_GENERATION_MISMATCH, + LG_MSG_PTHREAD_KEY_CREATE_FAILED, LG_MSG_TRANSLATOR_INIT_FAILED, + LG_MSG_UUID_BUF_INIT_FAILED, LG_MSG_LKOWNER_BUF_INIT_FAILED, + LG_MSG_SYNCTASK_INIT_FAILED, LG_MSG_SYNCOPCTX_INIT_FAILED, + LG_MSG_GLOBAL_INIT_FAILED, LG_MSG_PTHREAD_FAILED, LG_MSG_DIR_IS_SYMLINK, + LG_MSG_RESOLVE_HOSTNAME_FAILED, LG_MSG_GETADDRINFO_FAILED, + LG_MSG_GETNAMEINFO_FAILED, LG_MSG_PATH_ERROR, LG_MSG_INET_PTON_FAILED, + LG_MSG_NEGATIVE_NUM_PASSED, LG_MSG_GETHOSTNAME_FAILED, + LG_MSG_RESERVED_PORTS_ERROR, LG_MSG_INVALID_PORT, LG_MSG_INVALID_FAMILY, + LG_MSG_CONVERSION_FAILED, LG_MSG_SKIP_HEADER_FAILED, LG_MSG_INVALID_LOG, + LG_MSG_UTIMES_FAILED, LG_MSG_BACKTRACE_SAVE_FAILED, LG_MSG_INIT_FAILED, + LG_MSG_VALIDATION_FAILED, LG_MSG_GRAPH_ERROR, LG_MSG_UNKNOWN_OPTIONS_FAILED, + LG_MSG_CTX_NULL, LG_MSG_TMPFILE_CREATE_FAILED, LG_MSG_DLOPEN_FAILED, + LG_MSG_LOAD_FAILED, LG_MSG_DLSYM_ERROR, LG_MSG_TREE_NOT_FOUND, + LG_MSG_PER_DENTRY, LG_MSG_DENTRY, LG_MSG_GETIFADDRS_FAILED, + LG_MSG_REGEX_OP_FAILED, LG_MSG_FRAME_ERROR, LG_MSG_SET_PARAM_FAILED, + LG_MSG_GET_PARAM_FAILED, LG_MSG_PREPARE_FAILED, LG_MSG_EXEC_FAILED, + LG_MSG_BINDING_FAILED, LG_MSG_DELETE_FAILED, LG_MSG_GET_ID_FAILED, + LG_MSG_CREATE_FAILED, LG_MSG_PARSE_FAILED, LG_MSG_GETCONTEXT_FAILED, + LG_MSG_UPDATE_FAILED, LG_MSG_QUERY_CALL_BACK_FAILED, + LG_MSG_GET_RECORD_FAILED, LG_MSG_DB_ERROR, LG_MSG_CONNECTION_ERROR, + LG_MSG_NOT_MULTITHREAD_MODE, LG_MSG_SKIP_PATH, LG_MSG_INVALID_FOP, + LG_MSG_QUERY_FAILED, LG_MSG_CLEAR_COUNTER_FAILED, LG_MSG_LOCK_LIST_FAILED, + LG_MSG_UNLOCK_LIST_FAILED, LG_MSG_ADD_TO_LIST_FAILED, LG_MSG_INIT_DB_FAILED, + LG_MSG_DELETE_FROM_LIST_FAILED, LG_MSG_CLOSE_CONNECTION_FAILED, + LG_MSG_INSERT_OR_UPDATE_FAILED, LG_MSG_FIND_OP_FAILED, + LG_MSG_CONNECTION_INIT_FAILED, LG_MSG_COMPLETED_TASK, LG_MSG_WAKE_UP_ZOMBIE, + LG_MSG_REWAITING_TASK, LG_MSG_SLEEP_ZOMBIE, LG_MSG_SWAPCONTEXT_FAILED, + LG_MSG_UNSUPPORTED_PLUGIN, LG_MSG_INVALID_DB_TYPE, LG_MSG_UNDERSIZED_BUF, + LG_MSG_DATA_CONVERSION_ERROR, LG_MSG_DICT_ERROR, LG_MSG_IOBUFS_NOT_FOUND, + LG_MSG_ENTRIES_NULL, LG_MSG_FD_NOT_FOUND_IN_FDTABLE, + LG_MSG_REALLOC_FOR_FD_PTR_FAILED, LG_MSG_DICT_SET_FAILED, LG_MSG_NULL_PTR, + LG_MSG_RBTHASH_INIT_BUCKET_FAILED, LG_MSG_ASSERTION_FAILED, + LG_MSG_HOSTNAME_NULL, LG_MSG_INVALID_IPV4_FORMAT, + LG_MSG_CTX_CLEANUP_STARTED, LG_MSG_TIMER_REGISTER_ERROR, + LG_MSG_PTR_HEADER_CORRUPTED, LG_MSG_INVALID_UPLINK, LG_MSG_CLIENT_NULL, + LG_MSG_XLATOR_DOES_NOT_IMPLEMENT, LG_MSG_DENTRY_NOT_FOUND, + LG_MSG_INODE_NOT_FOUND, LG_MSG_INODE_TABLE_NOT_FOUND, + LG_MSG_DENTRY_CREATE_FAILED, LG_MSG_INODE_CONTEXT_FREED, + LG_MSG_UNKNOWN_LOCK_TYPE, LG_MSG_UNLOCK_BEFORE_LOCK, + LG_MSG_LOCK_OWNER_ERROR, LG_MSG_MEMPOOL_PTR_NULL, + LG_MSG_QUOTA_XATTRS_MISSING, LG_MSG_INVALID_STRING, LG_MSG_BIND_REF, + LG_MSG_REF_COUNT, LG_MSG_INVALID_ARG, LG_MSG_VOL_OPTION_ADD, + LG_MSG_XLATOR_OPTION_INVALID, LG_MSG_GETTIMEOFDAY_FAILED, + LG_MSG_GRAPH_INIT_FAILED, LG_MSG_EVENT_NOTIFY_FAILED, + LG_MSG_ACTIVE_GRAPH_NULL, LG_MSG_VOLFILE_PARSE_ERROR, LG_MSG_FD_INODE_NULL, + LG_MSG_INVALID_VOLFILE_ENTRY, LG_MSG_PER_DENTRY_FAILED, + LG_MSG_PARENT_DENTRY_NOT_FOUND, LG_MSG_DENTRY_CYCLIC_LOOP, + LG_MSG_INVALID_POLL_IN, LG_MSG_INVALID_POLL_OUT, LG_MSG_EPOLL_FD_ADD_FAILED, + LG_MSG_EPOLL_FD_DEL_FAILED, LG_MSG_EPOLL_FD_MODIFY_FAILED, + LG_MSG_STARTED_EPOLL_THREAD, LG_MSG_EXITED_EPOLL_THREAD, + LG_MSG_START_EPOLL_THREAD_FAILED, LG_MSG_FALLBACK_TO_POLL, + LG_MSG_QUOTA_CONF_ERROR, LG_MSG_RBTHASH_GET_ENTRY_FAILED, + LG_MSG_RBTHASH_GET_BUCKET_FAILED, LG_MSG_RBTHASH_INSERT_FAILED, + LG_MSG_RBTHASH_INIT_ENTRY_FAILED, LG_MSG_TMPFILE_DELETE_FAILED, + LG_MSG_MEMPOOL_INVALID_FREE, LG_MSG_LOCK_FAILURE, LG_MSG_SET_LOG_LEVEL, + LG_MSG_VERIFY_PLATFORM, LG_MSG_RUNNER_LOG, LG_MSG_LEASEID_BUF_INIT_FAILED, + LG_MSG_PTHREAD_ATTR_INIT_FAILED, LG_MSG_INVALID_INODE_LIST, + LG_MSG_COMPACT_FAILED, LG_MSG_COMPACT_STATUS, LG_MSG_UTIMENSAT_FAILED, + LG_MSG_PTHREAD_NAMING_FAILED, LG_MSG_SYSCALL_RETURNS_WRONG, + LG_MSG_XXH64_TO_GFID_FAILED, LG_MSG_ASYNC_WARNING, LG_MSG_ASYNC_FAILURE, + LG_MSG_GRAPH_CLEANUP_FAILED, LG_MSG_GRAPH_SETUP_FAILED, + LG_MSG_GRAPH_DETACH_STARTED, LG_MSG_GRAPH_ATTACH_FAILED, + LG_MSG_GRAPH_ATTACH_PID_FILE_UPDATED, LG_MSG_DUPLICATE_ENTRY, + LG_MSG_THREAD_NAME_TOO_LONG, LG_MSG_SET_THREAD_FAILED, + LG_MSG_THREAD_CREATE_FAILED, LG_MSG_FILE_DELETE_FAILED, LG_MSG_WRONG_VALUE, + LG_MSG_PATH_OPEN_FAILED, LG_MSG_DISPATCH_HANDLER_FAILED, + LG_MSG_READ_FILE_FAILED, LG_MSG_ENTRIES_NOT_PROVIDED, + LG_MSG_ENTRIES_PROVIDED, LG_MSG_UNKNOWN_OPTION_TYPE, + LG_MSG_OPTION_DEPRECATED, LG_MSG_INVALID_INIT, LG_MSG_OBJECT_NULL, + LG_MSG_GRAPH_NOT_SET, LG_MSG_FILENAME_NOT_SPECIFIED, LG_MSG_STRUCT_MISS, + LG_MSG_METHOD_MISS, LG_MSG_INPUT_DATA_NULL, LG_MSG_OPEN_LOGFILE_FAILED); + +#define LG_MSG_EPOLL_FD_CREATE_FAILED_STR "epoll fd creation failed" +#define LG_MSG_INVALID_POLL_IN_STR "invalid poll_in value" +#define LG_MSG_INVALID_POLL_OUT_STR "invalid poll_out value" +#define LG_MSG_SLOT_NOT_FOUND_STR "could not find slot" +#define LG_MSG_EPOLL_FD_ADD_FAILED_STR "failed to add fd to epoll" +#define LG_MSG_EPOLL_FD_DEL_FAILED_STR "fail to delete fd to epoll" +#define LG_MSG_EPOLL_FD_MODIFY_FAILED_STR "failed to modify fd events" +#define LG_MSG_STALE_FD_FOUND_STR "stale fd found" +#define LG_MSG_GENERATION_MISMATCH_STR "generation mismatch" +#define LG_MSG_STARTED_EPOLL_THREAD_STR "Started thread with index" +#define LG_MSG_EXITED_EPOLL_THREAD_STR "Exited thread" +#define LG_MSG_DISPATCH_HANDLER_FAILED_STR "Failed to dispatch handler" +#define LG_MSG_START_EPOLL_THREAD_FAILED_STR "Failed to start thread" +#define LG_MSG_PIPE_CREATE_FAILED_STR "pipe creation failed" +#define LG_MSG_SET_PIPE_FAILED_STR "could not set pipe to non blocking mode" +#define LG_MSG_REGISTER_PIPE_FAILED_STR \ + "could not register pipe fd with poll event loop" +#define LG_MSG_POLL_IGNORE_MULTIPLE_THREADS_STR \ + "Currently poll does not use multiple event processing threads, count " \ + "ignored" +#define LG_MSG_INDEX_NOT_FOUND_STR "index not found" +#define LG_MSG_READ_FILE_FAILED_STR "read on file returned error" +#define LG_MSG_RB_TABLE_CREATE_FAILED_STR "Failed to create rb table bucket" +#define LG_MSG_HASH_FUNC_ERROR_STR "Hash function not given" +#define LG_MSG_ENTRIES_NOT_PROVIDED_STR \ + "Both mem-pool and expected entries not provided" +#define LG_MSG_ENTRIES_PROVIDED_STR \ + "Both mem-pool and expected entries are provided" +#define LG_MSG_RBTHASH_INIT_BUCKET_FAILED_STR "failed to init buckets" +#define LG_MSG_RBTHASH_GET_ENTRY_FAILED_STR "Failed to get entry from mem-pool" +#define LG_MSG_RBTHASH_GET_BUCKET_FAILED_STR "Failed to get bucket" +#define LG_MSG_RBTHASH_INSERT_FAILED_STR "Failed to insert entry" +#define LG_MSG_RBTHASH_INIT_ENTRY_FAILED_STR "Failed to init entry" +#define LG_MSG_FILE_STAT_FAILED_STR "failed to stat" +#define LG_MSG_INET_PTON_FAILED_STR "inet_pton() failed" +#define LG_MSG_INVALID_ENTRY_STR "Invalid arguments" +#define LG_MSG_NEGATIVE_NUM_PASSED_STR "negative number passed" +#define LG_MSG_PATH_ERROR_STR "Path manipulation failed" +#define LG_MSG_FILE_OP_FAILED_STR "could not open/read file, getting ports info" +#define LG_MSG_RESERVED_PORTS_ERROR_STR \ + "Not able to get reserved ports, hence there is a possibility that " \ + "glusterfs may consume reserved port" +#define LG_MSG_INVALID_PORT_STR "invalid port" +#define LG_MSG_GETNAMEINFO_FAILED_STR "Could not lookup hostname" +#define LG_MSG_GETIFADDRS_FAILED_STR "getifaddrs() failed" +#define LG_MSG_INVALID_FAMILY_STR "Invalid family" +#define LG_MSG_CONVERSION_FAILED_STR "String conversion failed" +#define LG_MSG_GETADDRINFO_FAILED_STR "error in getaddrinfo" +#define LG_MSG_DUPLICATE_ENTRY_STR "duplicate entry for volfile-server" +#define LG_MSG_PTHREAD_NAMING_FAILED_STR "Failed to compose thread name" +#define LG_MSG_THREAD_NAME_TOO_LONG_STR \ + "Thread name is too long. It has been truncated" +#define LG_MSG_SET_THREAD_FAILED_STR "Could not set thread name" +#define LG_MSG_THREAD_CREATE_FAILED_STR "Thread creation failed" +#define LG_MSG_PTHREAD_ATTR_INIT_FAILED_STR \ + "Thread attribute initialization failed" +#define LG_MSG_SKIP_HEADER_FAILED_STR "Failed to skip header section" +#define LG_MSG_INVALID_LOG_STR "Invalid log-format" +#define LG_MSG_UTIMENSAT_FAILED_STR "utimenstat failed" +#define LG_MSG_UTIMES_FAILED_STR "utimes failed" +#define LG_MSG_FILE_DELETE_FAILED_STR "Unable to delete file" +#define LG_MSG_BACKTRACE_SAVE_FAILED_STR "Failed to save the backtrace" +#define LG_MSG_WRONG_VALUE_STR "wrong value" +#define LG_MSG_DIR_OP_FAILED_STR "Failed to create directory" +#define LG_MSG_DIR_IS_SYMLINK_STR "dir is symlink" +#define LG_MSG_RESOLVE_HOSTNAME_FAILED_STR "couldnot resolve hostname" +#define LG_MSG_PATH_OPEN_FAILED_STR "Unable to open path" +#define LG_MSG_NO_MEMORY_STR "Error allocating memory" +#define LG_MSG_EVENT_NOTIFY_FAILED_STR "notification failed" +#define LG_MSG_PER_DENTRY_FAILED_STR "per dentry fn returned" +#define LG_MSG_PARENT_DENTRY_NOT_FOUND_STR "parent not found" +#define LG_MSG_DENTRY_CYCLIC_LOOP_STR \ + "detected cyclic loop formation during inode linkage" +#define LG_MSG_CTX_NULL_STR "_ctx not found" +#define LG_MSG_DENTRY_NOT_FOUND_STR "dentry not found" +#define LG_MSG_OUT_OF_RANGE_STR "out of range" +#define LG_MSG_UNKNOWN_OPTION_TYPE_STR "unknown option type" +#define LG_MSG_VALIDATE_RETURNS_STR "validate of returned" +#define LG_MSG_OPTION_DEPRECATED_STR \ + "option is deprecated, continuing with correction" +#define LG_MSG_VALIDATE_REC_FAILED_STR "validate_rec failed" +#define LG_MSG_MAPPING_FAILED_STR "mapping failed" +#define LG_MSG_INIT_IOBUF_FAILED_STR "init failed" +#define LG_MSG_ARENA_NOT_FOUND_STR "arena not found" +#define LG_MSG_PAGE_SIZE_EXCEEDED_STR \ + "page_size of iobufs in arena being added is greater than max available" +#define LG_MSG_POOL_NOT_FOUND_STR "pool not found" +#define LG_MSG_IOBUF_NOT_FOUND_STR "iobuf not found" +#define LG_MSG_DLOPEN_FAILED_STR "DL open failed" +#define LG_MSG_DLSYM_ERROR_STR "dlsym missing" +#define LG_MSG_LOAD_FAILED_STR "Failed to load xlator options table" +#define LG_MSG_INPUT_DATA_NULL_STR \ + "input data is null. cannot update the lru limit of the inode table. " \ + "continuing with older value." +#define LG_MSG_INIT_FAILED_STR "No init() found" +#define LG_MSG_VOLUME_ERROR_STR \ + "Initialization of volume failed. review your volfile again." +#define LG_MSG_TREE_NOT_FOUND_STR "Translator tree not found" +#define LG_MSG_SET_LOG_LEVEL_STR "setting log level" +#define LG_MSG_INVALID_INIT_STR \ + "Invalid log-level. possible values are DEBUG|WARNING|ERROR|NONE|TRACE" +#define LG_MSG_OBJECT_NULL_STR "object is null, returning false." +#define LG_MSG_GRAPH_NOT_SET_STR "Graph is not set for xlator" +#define LG_MSG_OPEN_LOGFILE_FAILED_STR "failed to open logfile" +#define LG_MSG_STRDUP_ERROR_STR "failed to create metrics dir" +#define LG_MSG_FILENAME_NOT_SPECIFIED_STR "no filename specified" +#define LG_MSG_UNDERSIZED_BUF_STR "data value is smaller than expected" +#define LG_MSG_DICT_SET_FAILED_STR "unable to set dict" +#define LG_MSG_COUNT_LESS_THAN_ZERO_STR "count < 0!" +#define LG_MSG_PAIRS_LESS_THAN_COUNT_STR "less than count data pairs found" +#define LG_MSG_NULL_PTR_STR "pair->key is null!" +#define LG_MSG_VALUE_LENGTH_LESS_THAN_ZERO_STR "value->len < 0" +#define LG_MSG_INVALID_ARG_STR "buf is null" +#define LG_MSG_KEY_OR_VALUE_NULL_STR "key or value is null" +#define LG_MSG_NULL_VALUE_IN_DICT_STR "null value found in dict" +#define LG_MSG_FAILED_TO_LOG_DICT_STR "Failed to log dictionary" +#define LG_MSG_DICT_ERROR_STR "dict error" +#define LG_MSG_STRUCT_MISS_STR "struct missing" +#define LG_MSG_METHOD_MISS_STR "method missing(init)" + +#endif /* !_LG_MESSAGES_H_ */ diff --git a/libglusterfs/src/glusterfs/list.h b/libglusterfs/src/glusterfs/list.h new file mode 100644 index 00000000000..221a710ca30 --- /dev/null +++ b/libglusterfs/src/glusterfs/list.h @@ -0,0 +1,273 @@ +/* + 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 _LLIST_H +#define _LLIST_H + +struct list_head { + struct list_head *next; + struct list_head *prev; +}; + +#define INIT_LIST_HEAD(head) \ + do { \ + (head)->next = (head)->prev = head; \ + } while (0) + +static inline void +list_add(struct list_head *new, struct list_head *head) +{ + new->prev = head; + new->next = head->next; + + new->prev->next = new; + new->next->prev = new; +} + +static inline void +list_add_tail(struct list_head *new, struct list_head *head) +{ + new->next = head; + new->prev = head->prev; + + new->prev->next = new; + new->next->prev = new; +} + +/* 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) +{ + old->prev->next = old->next; + old->next->prev = old->prev; + + old->next = (void *)0xbabebabe; + old->prev = (void *)0xcafecafe; +} + +static inline void +list_del_init(struct list_head *old) +{ + old->prev->next = old->next; + old->next->prev = old->prev; + + old->next = old; + old->prev = old; +} + +static inline void +list_move(struct list_head *list, struct list_head *head) +{ + list_del(list); + list_add(list, head); +} + +static inline void +list_move_tail(struct list_head *list, struct list_head *head) +{ + list_del(list); + list_add_tail(list, head); +} + +static inline int +list_empty(struct list_head *head) +{ + return (head->next == head); +} + +static inline void +__list_splice(struct list_head *list, struct list_head *head) +{ + (list->prev)->next = (head->next); + (head->next)->prev = (list->prev); + + (head)->next = (list->next); + (list->next)->prev = (head); +} + +static inline void +list_splice(struct list_head *list, struct list_head *head) +{ + if (list_empty(list)) + return; + + __list_splice(list, head); +} + +/* Splice moves @list to the head of the list at @head. */ +static inline void +list_splice_init(struct list_head *list, struct list_head *head) +{ + if (list_empty(list)) + return; + + __list_splice(list, head); + INIT_LIST_HEAD(list); +} + +static inline void +__list_append(struct list_head *list, struct list_head *head) +{ + (head->prev)->next = (list->next); + (list->next)->prev = (head->prev); + (head->prev) = (list->prev); + (list->prev)->next = head; +} + +static inline void +list_append(struct list_head *list, struct list_head *head) +{ + if (list_empty(list)) + return; + + __list_append(list, head); +} + +/* Append moves @list to the end of @head */ +static inline void +list_append_init(struct list_head *list, struct list_head *head) +{ + if (list_empty(list)) + return; + + __list_append(list, head); + INIT_LIST_HEAD(list); +} + +static inline int +list_is_last(struct list_head *list, struct list_head *head) +{ + return (list->next == head); +} + +static inline int +list_is_singular(struct list_head *head) +{ + return !list_empty(head) && (head->next == head->prev); +} + +/** + * list_replace - replace old entry by new one + * @old : the element to be replaced + * @new : the new element to insert + * + * If @old was empty, it will be overwritten. + */ +static inline void +list_replace(struct list_head *old, struct list_head *new) +{ + new->next = old->next; + new->next->prev = new; + new->prev = old->prev; + new->prev->next = new; +} + +static inline void +list_replace_init(struct list_head *old, struct list_head *new) +{ + list_replace(old, new); + INIT_LIST_HEAD(old); +} + +/** + * list_rotate_left - rotate the list to the left + * @head: the head of the list + */ +static inline void +list_rotate_left(struct list_head *head) +{ + struct list_head *first; + + if (!list_empty(head)) { + first = head->next; + list_move_tail(first, head); + } +} + +#define list_entry(ptr, type, member) \ + ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member))) + +#define list_first_entry(ptr, type, member) \ + list_entry((ptr)->next, type, member) + +#define list_last_entry(ptr, type, member) list_entry((ptr)->prev, type, member) + +#define list_next_entry(pos, member) \ + list_entry((pos)->member.next, typeof(*(pos)), member) + +#define list_prev_entry(pos, member) \ + list_entry((pos)->member.prev, typeof(*(pos)), member) + +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + +#define list_for_each_entry(pos, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member); \ + &pos->member != (head); \ + pos = list_entry(pos->member.next, typeof(*pos), member)) + +#define list_for_each_entry_safe(pos, n, head, member) \ + for (pos = list_entry((head)->next, typeof(*pos), member), \ + n = list_entry(pos->member.next, typeof(*pos), member); \ + &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)) + +/* + * This list implementation has some advantages, but one disadvantage: you + * can't use NULL to check whether you're at the head or tail. Thus, the + * address of the head has to be an argument for these macros. + */ + +#define list_next(ptr, head, type, member) \ + (((ptr)->member.next == head) \ + ? NULL \ + : list_entry((ptr)->member.next, type, member)) + +#define list_prev(ptr, head, type, member) \ + (((ptr)->member.prev == head) \ + ? NULL \ + : list_entry((ptr)->member.prev, type, member)) + +#endif /* _LLIST_H */ diff --git a/libglusterfs/src/glusterfs/lkowner.h b/libglusterfs/src/glusterfs/lkowner.h new file mode 100644 index 00000000000..692de34bc7a --- /dev/null +++ b/libglusterfs/src/glusterfs/lkowner.h @@ -0,0 +1,93 @@ +/* + 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 _LK_OWNER_H +#define _LK_OWNER_H + +#include "glusterfs/glusterfs-fops.h" + +/* LKOWNER to string functions */ +static inline void +lkowner_unparse(gf_lkowner_t *lkowner, char *buf, int buf_len) +{ + int i = 0; + int j = 0; + + for (i = 0; i < lkowner->len; i++) { + if (i && !(i % 8)) { + buf[j] = '-'; + j++; + } + sprintf(&buf[j], "%02hhx", lkowner->data[i]); + j += 2; + if (j == buf_len) + break; + } + if (j < buf_len) + buf[j] = '\0'; +} + +static inline void +set_lk_owner_from_ptr(gf_lkowner_t *lkowner, void *data) +{ + int i = 0; + int j = 0; + + lkowner->len = sizeof(unsigned long); + for (i = 0, j = 0; i < lkowner->len; i++, j += 8) { + lkowner->data[i] = (char)((((unsigned long)data) >> j) & 0xff); + } +} + +static inline void +set_lk_owner_from_uint64(gf_lkowner_t *lkowner, uint64_t data) +{ + int i = 0; + int j = 0; + + lkowner->len = 8; + for (i = 0, j = 0; i < lkowner->len; i++, j += 8) { + lkowner->data[i] = (char)((data >> j) & 0xff); + } +} + +/* Return true if the locks have the same owner */ +static inline int +is_same_lkowner(gf_lkowner_t *l1, gf_lkowner_t *l2) +{ + return ((l1->len == l2->len) && !memcmp(l1->data, l2->data, l1->len)); +} + +static inline int +is_lk_owner_null(gf_lkowner_t *lkowner) +{ + int is_null = 1; + int i = 0; + + if (lkowner == NULL || lkowner->len == 0) + goto out; + + for (i = 0; i < lkowner->len; i++) { + if (lkowner->data[i] != 0) { + is_null = 0; + break; + } + } +out: + return is_null; +} + +static inline void +lk_owner_copy(gf_lkowner_t *dst, gf_lkowner_t *src) +{ + dst->len = src->len; + memcpy(dst->data, src->data, src->len); +} +#endif /* _LK_OWNER_H */ diff --git a/libglusterfs/src/glusterfs/locking.h b/libglusterfs/src/glusterfs/locking.h new file mode 100644 index 00000000000..43cc87735d1 --- /dev/null +++ b/libglusterfs/src/glusterfs/locking.h @@ -0,0 +1,84 @@ +/* + 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 _LOCKING_H +#define _LOCKING_H + +#include <pthread.h> + +#if defined(GF_DARWIN_HOST_OS) +#include <libkern/OSAtomic.h> +#define pthread_spinlock_t OSSpinLock +#define pthread_spin_lock(l) OSSpinLockLock(l) +#define pthread_spin_unlock(l) OSSpinLockUnlock(l) +#define pthread_spin_destroy(l) 0 +#define pthread_spin_init(l, v) (*l = v) +#endif + +#if defined(HAVE_SPINLOCK) + +typedef union { + pthread_spinlock_t spinlock; + pthread_mutex_t mutex; +} gf_lock_t; + +#if !defined(LOCKING_IMPL) +extern int use_spinlocks; + +/* + * Using a dispatch table would be unpleasant because we're dealing with two + * different types. If the dispatch contains direct pointers to pthread_xx + * or mutex_xxx then we have to hope that every possible union alternative + * starts at the same address as the union itself. I'm old enough to remember + * compilers where this was not the case (for alignment reasons) so I'm a bit + * paranoid about that. Also, I don't like casting arguments through "void *" + * which we'd also have to do to avoid type errors. The other alternative would + * be to define actual functions which pick out the right union member, and put + * those in the dispatch tables. Now we have a pointer dereference through the + * dispatch table plus a function call, which is likely to be worse than the + * branching here from the ?: construct. If it were a clear win it might be + * worth the extra complexity, but for now this way seems preferable. + */ + +#define LOCK_INIT(x) \ + (use_spinlocks ? pthread_spin_init(&((x)->spinlock), 0) \ + : pthread_mutex_init(&((x)->mutex), 0)) + +#define LOCK(x) \ + (use_spinlocks ? pthread_spin_lock(&((x)->spinlock)) \ + : pthread_mutex_lock(&((x)->mutex))) + +#define TRY_LOCK(x) \ + (use_spinlocks ? pthread_spin_trylock(&((x)->spinlock)) \ + : pthread_mutex_trylock(&((x)->mutex))) + +#define UNLOCK(x) \ + (use_spinlocks ? pthread_spin_unlock(&((x)->spinlock)) \ + : pthread_mutex_unlock(&((x)->mutex))) + +#define LOCK_DESTROY(x) \ + (use_spinlocks ? pthread_spin_destroy(&((x)->spinlock)) \ + : pthread_mutex_destroy(&((x)->mutex))) + +#endif + +#else + +typedef pthread_mutex_t gf_lock_t; + +#define LOCK_INIT(x) pthread_mutex_init(x, 0) +#define LOCK(x) pthread_mutex_lock(x) +#define TRY_LOCK(x) pthread_mutex_trylock(x) +#define UNLOCK(x) pthread_mutex_unlock(x) +#define LOCK_DESTROY(x) pthread_mutex_destroy(x) + +#endif /* HAVE_SPINLOCK */ + +#endif /* _LOCKING_H */ diff --git a/libglusterfs/src/glusterfs/logging.h b/libglusterfs/src/glusterfs/logging.h new file mode 100644 index 00000000000..b3a6ac191f0 --- /dev/null +++ b/libglusterfs/src/glusterfs/logging.h @@ -0,0 +1,383 @@ +/* + 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 __LOGGING_H__ +#define __LOGGING_H__ + +#include <sys/time.h> +#include <stdint.h> +#include <stdio.h> +#include <stdarg.h> +#include <pthread.h> +#include "glusterfs/list.h" + +#ifdef GF_DARWIN_HOST_OS +#define GF_PRI_FSBLK "u" +#define GF_PRI_DEV PRId32 +#define GF_PRI_INODE PRIu64 +#define GF_PRI_NLINK PRIu32 +#define GF_PRI_SECOND "ld" +#define GF_PRI_SUSECONDS "06d" +#define GF_PRI_SNSECONDS "09ld" +#define GF_PRI_USEC "d" +#else +#define GF_PRI_FSBLK PRIu64 +#define GF_PRI_DEV PRIu64 +#define GF_PRI_INODE PRIu64 +#define GF_PRI_NLINK PRIu32 +#define GF_PRI_SECOND "lu" +#define GF_PRI_SUSECONDS "06ld" +#define GF_PRI_SNSECONDS "09ld" +#define GF_PRI_USEC "ld" +#endif +#define GF_PRI_BLKSIZE PRId32 +#define GF_PRI_SIZET "zu" +#define GF_PRI_ATOMIC PRIu64 + +#ifdef GF_DARWIN_HOST_OS +#define GF_PRI_TIME "ld" +#else +#define GF_PRI_TIME PRIu64 +#endif + +#if 0 +/* Syslog definitions :-) */ +#define LOG_EMERG 0 /* system is unusable */ +#define LOG_ALERT 1 /* action must be taken immediately */ +#define LOG_CRIT 2 /* critical conditions */ +#define LOG_ERR 3 /* error conditions */ +#define LOG_WARNING 4 /* warning conditions */ +#define LOG_NOTICE 5 /* normal but significant condition */ +#define LOG_INFO 6 /* informational */ +#define LOG_DEBUG 7 /* debug-level messages */ +#endif + +#define GF_LOG_FORMAT_NO_MSG_ID "no-msg-id" +#define GF_LOG_FORMAT_WITH_MSG_ID "with-msg-id" + +#define GF_LOGGER_GLUSTER_LOG "gluster-log" +#define GF_LOGGER_SYSLOG "syslog" + +typedef enum { + GF_LOG_NONE, + GF_LOG_EMERG, + GF_LOG_ALERT, + GF_LOG_CRITICAL, /* fatal errors */ + GF_LOG_ERROR, /* major failures (not necessarily fatal) */ + GF_LOG_WARNING, /* info about normal operation */ + GF_LOG_NOTICE, + GF_LOG_INFO, /* Normal information */ + GF_LOG_DEBUG, /* internal errors */ + GF_LOG_TRACE, /* full trace of operation */ +} gf_loglevel_t; + +/* format for the logs */ +typedef enum { + gf_logformat_traditional = 0, /* Format as in gluster 3.5 */ + gf_logformat_withmsgid, /* Format enhanced with MsgID, ident, errstr */ + gf_logformat_cee /* log enhanced format in cee */ +} gf_log_format_t; + +/* log infrastructure to log to */ +typedef enum { + gf_logger_glusterlog = 0, /* locations and files as in gluster 3.5 */ + gf_logger_syslog /* log to (r)syslog, based on (r)syslog conf */ + /* NOTE: In the future journald, lumberjack, next new thing here */ +} gf_log_logger_t; + +#define DEFAULT_LOG_FILE_DIRECTORY DATADIR "/log/glusterfs" +#define DEFAULT_QUOTA_CRAWL_LOG_DIRECTORY DATADIR "/log/glusterfs/quota_crawl" +#define DEFAULT_LOG_LEVEL GF_LOG_INFO + +typedef struct gf_log_handle_ { + pthread_mutex_t logfile_mutex; + gf_loglevel_t loglevel; + gf_loglevel_t sys_log_level; + int gf_log_syslog; + char *filename; + FILE *logfile; + FILE *gf_log_logfile; + char *cmd_log_filename; + FILE *cmdlogfile; + gf_log_logger_t logger; + gf_log_format_t logformat; + char *ident; + int log_control_file_found; + struct list_head lru_queue; + pthread_mutex_t log_buf_lock; + struct _gf_timer *log_flush_timer; + int localtime; + uint32_t lru_size; + uint32_t lru_cur_size; + uint32_t timeout; + uint8_t logrotate; + uint8_t cmd_history_logrotate; +} gf_log_handle_t; + +typedef struct log_buf_ { + char *msg; + uint64_t msg_id; + int errnum; + struct timeval oldest; + struct timeval latest; + char *domain; + char *file; + char *function; + int32_t line; + gf_loglevel_t level; + int refcount; + int graph_id; + struct list_head msg_list; +} log_buf_t; + +void +gf_log_globals_init(void *ctx, gf_loglevel_t level); +int +gf_log_init(void *data, const char *filename, const char *ident); + +void +gf_log_logrotate(int signum); + +void +gf_log_cleanup(void); + +/* Internal interfaces to log messages with message IDs */ +int +_gf_msg(const char *domain, const char *file, const char *function, + int32_t line, gf_loglevel_t level, int errnum, int trace, + uint64_t msgid, const char *fmt, ...) + __attribute__((__format__(__printf__, 9, 10))); + +void +_gf_msg_backtrace_nomem(gf_loglevel_t level, int stacksize); + +int +_gf_msg_plain(gf_loglevel_t level, const char *fmt, ...) + __attribute__((__format__(__printf__, 2, 3))); + +int +_gf_msg_plain_nomem(gf_loglevel_t level, const char *msg); + +int +_gf_msg_vplain(gf_loglevel_t level, const char *fmt, va_list ap); + +int +_gf_msg_nomem(const char *domain, const char *file, const char *function, + int line, gf_loglevel_t level, size_t size); + +int +_gf_log(const char *domain, const char *file, const char *function, + int32_t line, gf_loglevel_t level, const char *fmt, ...) + __attribute__((__format__(__printf__, 6, 7))); + +int +_gf_log_callingfn(const char *domain, const char *file, const char *function, + int32_t line, gf_loglevel_t level, const char *fmt, ...) + __attribute__((__format__(__printf__, 6, 7))); + +int +_gf_log_eh(const char *function, const char *fmt, ...) + __attribute__((__format__(__printf__, 2, 3))); + +/* treat GF_LOG_TRACE and GF_LOG_NONE as LOG_DEBUG and + * other level as is */ +#define SET_LOG_PRIO(level, priority) \ + do { \ + if (GF_LOG_TRACE == (level) || GF_LOG_NONE == (level)) { \ + priority = LOG_DEBUG; \ + } else { \ + priority = (level)-1; \ + } \ + } while (0) + +/* extract just the file name from the path */ +#define GET_FILE_NAME_TO_LOG(file, basename) \ + do { \ + basename = strrchr((file), '/'); \ + if (basename) \ + basename++; \ + else \ + basename = (file); \ + } while (0) + +#define PRINT_SIZE_CHECK(ret, label, strsize) \ + do { \ + if (ret < 0) \ + goto label; \ + if ((strsize - ret) > 0) { \ + strsize -= ret; \ + } else { \ + ret = 0; \ + goto label; \ + } \ + } while (0) + +#define FMT_WARN(fmt...) \ + do { \ + if (0) \ + printf(fmt); \ + } while (0) + +/* Interface to log messages with message IDs */ +#define gf_msg(dom, level, errnum, msgid, fmt...) \ + do { \ + _gf_msg(dom, __FILE__, __FUNCTION__, __LINE__, level, errnum, 0, \ + msgid, ##fmt); \ + } while (0) + +/* no frills, no thrills, just a vanilla message, used to print the graph */ +#define gf_msg_plain(level, fmt...) \ + do { \ + _gf_msg_plain(level, ##fmt); \ + } while (0) + +#define gf_msg_plain_nomem(level, msg) \ + do { \ + _gf_msg_plain_nomem(level, msg); \ + } while (0) + +#define gf_msg_vplain(level, fmt, va) \ + do { \ + _gf_msg_vplain(level, fmt, va); \ + } while (0) + +#define gf_msg_backtrace_nomem(level, stacksize) \ + do { \ + _gf_msg_backtrace_nomem(level, stacksize); \ + } while (0) + +#define gf_msg_callingfn(dom, level, errnum, msgid, fmt...) \ + do { \ + _gf_msg(dom, __FILE__, __FUNCTION__, __LINE__, level, errnum, 1, \ + msgid, ##fmt); \ + } while (0) + +/* No malloc or calloc should be called in this function */ +#define gf_msg_nomem(dom, level, size) \ + do { \ + _gf_msg_nomem(dom, __FILE__, __FUNCTION__, __LINE__, level, size); \ + } while (0) + +/* Debug or trace messages do not need message IDs as these are more developer + * related. Hence, the following abstractions are provided for the same */ +#define gf_msg_debug(dom, errnum, fmt...) \ + do { \ + _gf_msg(dom, __FILE__, __FUNCTION__, __LINE__, GF_LOG_DEBUG, errnum, \ + 0, 0, ##fmt); \ + } while (0) + +#define gf_msg_trace(dom, errnum, fmt...) \ + do { \ + _gf_msg(dom, __FILE__, __FUNCTION__, __LINE__, GF_LOG_TRACE, errnum, \ + 0, 0, ##fmt); \ + } while (0) + +#define gf_log(dom, level, fmt...) \ + do { \ + FMT_WARN(fmt); \ + _gf_log(dom, __FILE__, __FUNCTION__, __LINE__, level, ##fmt); \ + } while (0) + +#define gf_log_eh(fmt...) \ + do { \ + FMT_WARN(fmt); \ + _gf_log_eh(__FUNCTION__, ##fmt); \ + } while (0) + +#define gf_log_callingfn(dom, level, fmt...) \ + do { \ + FMT_WARN(fmt); \ + _gf_log_callingfn(dom, __FILE__, __FUNCTION__, __LINE__, level, \ + ##fmt); \ + } while (0) + +/* Log once in GF_UNIVERSAL_ANSWER times */ +#define GF_LOG_OCCASIONALLY(var, args...) \ + if (var++ == 0 || !((var - 1) % GF_UNIVERSAL_ANSWER)) { \ + gf_log(args); \ + } + +struct _glusterfs_ctx; + +void +gf_log_disable_syslog(void); +void +gf_log_enable_syslog(void); +gf_loglevel_t +gf_log_get_loglevel(void); +void +gf_log_set_loglevel(struct _glusterfs_ctx *ctx, gf_loglevel_t level); +int +gf_log_get_localtime(void); +void +gf_log_set_localtime(int); +void +gf_log_flush(void); +gf_loglevel_t +gf_log_get_xl_loglevel(void *xl); +void +gf_log_set_xl_loglevel(void *xl, gf_loglevel_t level); + +int +gf_cmd_log(const char *domain, const char *fmt, ...) + __attribute__((__format__(__printf__, 2, 3))); + +int +gf_cmd_log_init(const char *filename); + +void +set_sys_log_level(gf_loglevel_t level); + +int +gf_log_fini(void *data); + +void +gf_log_set_logger(gf_log_logger_t logger); + +void +gf_log_set_logformat(gf_log_format_t format); + +void +gf_log_set_log_buf_size(uint32_t buf_size); + +void +gf_log_set_log_flush_timeout(uint32_t timeout); + +void +gf_log_flush_msgs(struct _glusterfs_ctx *ctx); + +int +gf_log_inject_timer_event(struct _glusterfs_ctx *ctx); + +void +gf_log_disable_suppression_before_exit(struct _glusterfs_ctx *ctx); + +#define GF_DEBUG(xl, format, args...) \ + gf_log((xl)->name, GF_LOG_DEBUG, format, ##args) +#define GF_INFO(xl, format, args...) \ + gf_log((xl)->name, GF_LOG_INFO, format, ##args) +#define GF_WARNING(xl, format, args...) \ + gf_log((xl)->name, GF_LOG_WARNING, format, ##args) +#define GF_ERROR(xl, format, args...) \ + gf_log((xl)->name, GF_LOG_ERROR, format, ##args) + +int +_gf_smsg(const char *domain, const char *file, const char *function, + int32_t line, gf_loglevel_t level, int errnum, int trace, + uint64_t msgid, const char *event, ...); + +/* Interface to log messages with message IDs */ +#define gf_smsg(dom, level, errnum, msgid, event...) \ + do { \ + _gf_smsg(dom, __FILE__, __FUNCTION__, __LINE__, level, errnum, 0, \ + msgid, msgid##_STR, ##event); \ + } while (0) + +#endif /* __LOGGING_H__ */ diff --git a/libglusterfs/src/glusterfs/lvm-defaults.h b/libglusterfs/src/glusterfs/lvm-defaults.h new file mode 100644 index 00000000000..32feebf3f6e --- /dev/null +++ b/libglusterfs/src/glusterfs/lvm-defaults.h @@ -0,0 +1,20 @@ +/* + Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _LVM_DEFAULTS_H +#define _LVM_DEFAULTS_H + +#define LVM_RESIZE "/sbin/lvresize" +#define LVM_CREATE "/sbin/lvcreate" +#define LVM_CONVERT "/sbin/lvconvert" +#define LVM_REMOVE "/sbin/lvremove" +#define LVS "/sbin/lvs" + +#endif /* _LVM_DEFAULTS_H */ diff --git a/libglusterfs/src/glusterfs/mem-pool.h b/libglusterfs/src/glusterfs/mem-pool.h new file mode 100644 index 00000000000..e5b3276d047 --- /dev/null +++ b/libglusterfs/src/glusterfs/mem-pool.h @@ -0,0 +1,336 @@ +/* + 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 _MEM_POOL_H_ +#define _MEM_POOL_H_ + +#include "glusterfs/list.h" +#include "glusterfs/atomic.h" +#include "glusterfs/logging.h" +#include "glusterfs/mem-types.h" +#include "glusterfs/glusterfs.h" /* for glusterfs_ctx_t */ +#include <stdlib.h> +#include <inttypes.h> +#include <string.h> +#include <stdarg.h> + +/* + * Need this for unit tests since inline functions + * access memory allocation and need to use the + * unit test versions + */ +#ifdef UNIT_TESTING +#include <stddef.h> +#include <setjmp.h> +#include <cmocka.h> +#endif + +#define GF_MEM_TRAILER_SIZE 8 +#define GF_MEM_HEADER_MAGIC 0xCAFEBABE +#define GF_MEM_TRAILER_MAGIC 0xBAADF00D +#define GF_MEM_INVALID_MAGIC 0xDEADC0DE + +#define POOL_SMALLEST 7 /* i.e. 128 */ +#define POOL_LARGEST 20 /* i.e. 1048576 */ +#define NPOOLS (POOL_LARGEST - POOL_SMALLEST + 1) + +struct mem_acct_rec { + const char *typestr; + uint64_t size; + uint64_t max_size; + uint64_t total_allocs; + uint32_t num_allocs; + uint32_t max_num_allocs; + gf_lock_t lock; +#ifdef DEBUG + struct list_head obj_list; +#endif +}; + +struct mem_acct { + uint32_t num_types; + gf_atomic_t refcnt; + struct mem_acct_rec rec[0]; +}; + +struct mem_header { + uint32_t type; + size_t size; + struct mem_acct *mem_acct; + uint32_t magic; +#ifdef DEBUG + struct list_head acct_list; +#endif + int padding[8]; +}; + +#define GF_MEM_HEADER_SIZE (sizeof(struct mem_header)) + +#ifdef DEBUG +struct mem_invalid { + uint32_t magic; + void *mem_acct; + uint32_t type; + size_t size; + void *baseaddr; +}; +#endif + +void * +__gf_calloc(size_t cnt, size_t size, uint32_t type, const char *typestr); + +void * +__gf_malloc(size_t size, uint32_t type, const char *typestr); + +void * +__gf_realloc(void *ptr, size_t size); + +int +gf_vasprintf(char **string_ptr, const char *format, va_list arg); + +int +gf_asprintf(char **string_ptr, const char *format, ...) + __attribute__((__format__(__printf__, 2, 3))); + +void +__gf_free(void *ptr); + +static inline void * +__gf_default_malloc(size_t size) +{ + void *ptr = NULL; + + ptr = malloc(size); + if (!ptr) + gf_msg_nomem("", GF_LOG_ALERT, size); + + return ptr; +} + +static inline void * +__gf_default_calloc(int cnt, size_t size) +{ + void *ptr = NULL; + + ptr = calloc(cnt, size); + if (!ptr) + gf_msg_nomem("", GF_LOG_ALERT, (cnt * size)); + + return ptr; +} + +static inline void * +__gf_default_realloc(void *oldptr, size_t size) +{ + void *ptr = NULL; + + ptr = realloc(oldptr, size); + if (!ptr) + gf_msg_nomem("", GF_LOG_ALERT, size); + + return ptr; +} + +#define MALLOC(size) __gf_default_malloc(size) +#define CALLOC(cnt, size) __gf_default_calloc(cnt, size) +#define REALLOC(ptr, size) __gf_default_realloc(ptr, size) + +#define FREE(ptr) \ + do { \ + if (ptr != NULL) { \ + free((void *)ptr); \ + ptr = (void *)0xeeeeeeee; \ + } \ + } while (0) + +#define GF_CALLOC(nmemb, size, type) __gf_calloc(nmemb, size, type, #type) + +#define GF_MALLOC(size, type) __gf_malloc(size, type, #type) + +#define GF_REALLOC(ptr, size) __gf_realloc(ptr, size) + +#define GF_FREE(free_ptr) __gf_free(free_ptr) + +static inline char * +gf_strndup(const char *src, size_t len) +{ + char *dup_str = NULL; + + if (!src) { + goto out; + } + + dup_str = GF_MALLOC(len + 1, gf_common_mt_strdup); + if (!dup_str) { + goto out; + } + + memcpy(dup_str, src, len); + dup_str[len] = '\0'; +out: + return dup_str; +} + +static inline char * +gf_strdup(const char *src) +{ + if (!src) + return NULL; + + return gf_strndup(src, strlen(src)); +} + +static inline void * +gf_memdup(const void *src, size_t size) +{ + void *dup_mem = NULL; + + dup_mem = GF_MALLOC(size, gf_common_mt_memdup); + if (!dup_mem) + goto out; + + memcpy(dup_mem, src, size); + +out: + return dup_mem; +} + +#ifdef GF_DISABLE_MEMPOOL + +/* No-op memory pool enough to fit current API without massive redesign. */ + +struct mem_pool { + unsigned long sizeof_type; +}; + +#define mem_pools_init() \ + do { \ + } while (0) +#define mem_pools_fini() \ + do { \ + } while (0) +#define mem_pool_thread_destructor(pool_list) (void)pool_list + +#else /* !GF_DISABLE_MEMPOOL */ + +/* kind of 'header' for the actual mem_pool_shared structure, this might make + * it possible to dump some more details in a statedump */ +struct mem_pool { + /* object size, without pooled_obj_hdr_t */ + unsigned long sizeof_type; + unsigned long count; /* requested pool size (unused) */ + char *name; + char *xl_name; + gf_atomic_t active; /* current allocations */ +#ifdef DEBUG + gf_atomic_t hit; /* number of allocations served from pt_pool */ + gf_atomic_t miss; /* number of std allocs due to miss */ +#endif + struct list_head owner; /* glusterfs_ctx_t->mempool_list */ + glusterfs_ctx_t *ctx; /* take ctx->lock when updating owner */ + + struct mem_pool_shared *pool; /* the initial pool that was returned */ +}; + +typedef struct pooled_obj_hdr { + unsigned long magic; + struct pooled_obj_hdr *next; + struct per_thread_pool_list *pool_list; + unsigned int power_of_two; + + /* track the pool that was used to request this object */ + struct mem_pool *pool; +} pooled_obj_hdr_t; + +/* Each memory block inside a pool has a fixed size that is a power of two. + * However each object will have a header that will reduce the available + * space. */ +#define AVAILABLE_SIZE(p2) ((1UL << (p2)) - sizeof(pooled_obj_hdr_t)) + +typedef struct per_thread_pool { + /* the pool that was used to request this allocation */ + struct mem_pool_shared *parent; + /* Everything else is protected by our own lock. */ + pooled_obj_hdr_t *hot_list; + pooled_obj_hdr_t *cold_list; +} per_thread_pool_t; + +typedef struct per_thread_pool_list { + /* thr_list is used to place the TLS pool_list into the active global list + * (pool_threads) or the inactive global list (pool_free_threads). It's + * protected by the global pool_lock. */ + struct list_head thr_list; + + /* This lock is used to update poison and the hot/cold lists of members + * of 'pools' array. */ + pthread_spinlock_t lock; + + /* This field is used to mark a pool_list as not being owned by any thread. + * This means that the sweeper thread won't be cleaning objects stored in + * its pools. mem_put() uses it to decide if the object being released is + * placed into its original pool_list or directly destroyed. */ + bool poison; + + /* + * There's really more than one pool, but the actual number is hidden + * in the implementation code so we just make it a single-element array + * here. + */ + per_thread_pool_t pools[1]; +} per_thread_pool_list_t; + +/* actual pool structure, shared between different mem_pools */ +struct mem_pool_shared { + unsigned int power_of_two; + /* + * Updates to these are *not* protected by a global lock, so races + * could occur and the numbers might be slightly off. Don't expect + * them to line up exactly. It's the general trends that matter, and + * it's not worth the locked-bus-cycle overhead to make these precise. + */ + gf_atomic_t allocs_hot; + gf_atomic_t allocs_cold; + gf_atomic_t allocs_stdc; + gf_atomic_t frees_to_list; +}; + +void +mem_pools_init(void); /* start the pool_sweeper thread */ +void +mem_pools_fini(void); /* cleanup memory pools */ +void +mem_pool_thread_destructor(per_thread_pool_list_t *pool_list); + +#endif /* GF_DISABLE_MEMPOOL */ + +struct mem_pool * +mem_pool_new_fn(glusterfs_ctx_t *ctx, unsigned long sizeof_type, + unsigned long count, char *name); + +#define mem_pool_new(type, count) \ + mem_pool_new_fn(THIS->ctx, sizeof(type), count, #type) + +#define mem_pool_new_ctx(ctx, type, count) \ + mem_pool_new_fn(ctx, sizeof(type), count, #type) + +void +mem_put(void *ptr); +void * +mem_get(struct mem_pool *pool); +void * +mem_get0(struct mem_pool *pool); + +void +mem_pool_destroy(struct mem_pool *pool); + +void +gf_mem_acct_enable_set(void *ctx); + +#endif /* _MEM_POOL_H */ diff --git a/libglusterfs/src/glusterfs/mem-types.h b/libglusterfs/src/glusterfs/mem-types.h new file mode 100644 index 00000000000..d45d5b68c91 --- /dev/null +++ b/libglusterfs/src/glusterfs/mem-types.h @@ -0,0 +1,139 @@ +/* + Copyright (c) 2008-2016 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef __MEM_TYPES_H__ +#define __MEM_TYPES_H__ + +enum gf_common_mem_types_ { + gf_common_mt_dnscache6, /* used only in one location */ + gf_common_mt_event_pool, + gf_common_mt_reg, + gf_common_mt_pollfd, /* used only in one location */ + gf_common_mt_fdentry_t, /* used only in one location */ + gf_common_mt_fdtable_t, /* used only in one location */ + gf_common_mt_fd_ctx, /* used only in one location */ + gf_common_mt_gf_dirent_t, + gf_common_mt_inode_t, /* used only in one location */ + gf_common_mt_inode_ctx, /* used only in one location */ + gf_common_mt_list_head, + gf_common_mt_inode_table_t, /* used only in one location */ + gf_common_mt_xlator_t, + gf_common_mt_xlator_list_t, /* used only in one location */ + gf_common_mt_volume_opt_list_t, + gf_common_mt_gf_timer_t, /* used only in one location */ + gf_common_mt_gf_timer_registry_t, /* used only in one location */ + gf_common_mt_auth_handle_t, /* used only in one location */ + gf_common_mt_iobuf, /* used only in one location */ + gf_common_mt_iobuf_arena, /* used only in one location */ + gf_common_mt_iobref, /* used only in one location */ + gf_common_mt_iobuf_pool, /* used only in one location */ + gf_common_mt_iovec, + gf_common_mt_memdup, /* used only in one location */ + gf_common_mt_asprintf, /* used only in one location */ + gf_common_mt_strdup, + gf_common_mt_socket_private_t, /* used only in one location */ + gf_common_mt_ioq, /* used only in one location */ + gf_common_mt_char, + gf_common_mt_rbthash_table_t, /* used only in one location */ + gf_common_mt_rbthash_bucket, /* used only in one location */ + gf_common_mt_mem_pool, /* used only in one location */ + gf_common_mt_rpcsvc_auth_list, /* used only in one location */ + gf_common_mt_rpcsvc_t, /* used only in one location */ + gf_common_mt_rpcsvc_program_t, /* used only in one location */ + gf_common_mt_rpcsvc_listener_t, /* used only in one location */ + gf_common_mt_rpcsvc_wrapper_t, /* used only in one location */ + gf_common_mt_rpcclnt_t, /* used only in one location */ + gf_common_mt_rpcclnt_savedframe_t, /* used only in one location */ + gf_common_mt_rpc_trans_t, + gf_common_mt_rpc_trans_pollin_t, /* used only in one location */ + gf_common_mt_rpc_trans_reqinfo_t, /* used only in one location */ + gf_common_mt_glusterfs_graph_t, + gf_common_mt_rdma_private_t, /* used only in one location */ + gf_common_mt_rpc_transport_t, /* used only in one location */ + gf_common_mt_rdma_post_t, /* used only in one location */ + gf_common_mt_qpent, /* used only in one location */ + gf_common_mt_rdma_device_t, /* used only in one location */ + gf_common_mt_rdma_arena_mr, /* used only in one location */ + gf_common_mt_sge, /* used only in one location */ + gf_common_mt_rpcclnt_cb_program_t, /* used only in one location */ + gf_common_mt_libxl_marker_local, /* used only in one location */ + gf_common_mt_graph_buf, /* used only in one location */ + gf_common_mt_trie_trie, /* used only in one location */ + gf_common_mt_trie_data, /* used only in one location */ + gf_common_mt_trie_node, /* used only in one location */ + gf_common_mt_trie_buf, /* used only in one location */ + gf_common_mt_run_argv, /* used only in one location */ + gf_common_mt_run_logbuf, /* used only in one location */ + gf_common_mt_fd_lk_ctx_t, /* used only in one location */ + gf_common_mt_fd_lk_ctx_node_t, /* used only in one location */ + gf_common_mt_buffer_t, /* used only in one location */ + gf_common_mt_circular_buffer_t, /* used only in one location */ + gf_common_mt_eh_t, + gf_common_mt_store_handle_t, /* used only in one location */ + gf_common_mt_store_iter_t, /* used only in one location */ + gf_common_mt_drc_client_t, /* used only in one location */ + gf_common_mt_drc_globals_t, /* used only in one location */ + gf_common_mt_groups_t, + gf_common_mt_cliententry_t, /* used only in one location */ + gf_common_mt_clienttable_t, /* used only in one location */ + gf_common_mt_client_t, /* used only in one location */ + gf_common_mt_client_ctx, /* used only in one location */ + gf_common_mt_auxgids, /* used only in one location */ + gf_common_mt_syncopctx, /* used only in one location */ + gf_common_mt_iobrefs, /* used only in one location */ + gf_common_mt_gsync_status_t, + gf_common_mt_uuid_t, + gf_common_mt_mgmt_v3_lock_obj_t, /* used only in one location */ + gf_common_mt_txn_opinfo_obj_t, /* used only in one location */ + gf_common_mt_strfd_t, /* used only in one location */ + gf_common_mt_strfd_data_t, /* used only in one location */ + gf_common_mt_regex_t, /* used only in one location */ + gf_common_mt_ereg, /* used only in one location */ + gf_common_mt_wr, /* used only in one location */ + gf_common_mt_dnscache, /* used only in one location */ + gf_common_mt_dnscache_entry, /* used only in one location */ + gf_common_mt_parser_t, /* used only in one location */ + gf_common_quota_meta_t, + gf_common_mt_rbuf_t, /* used only in one location */ + gf_common_mt_rlist_t, /* used only in one location */ + gf_common_mt_rvec_t, /* used only in one location */ + /* glusterd can load the nfs-xlator dynamically and needs these two */ + gf_common_mt_nfs_netgroups, /* used only in one location */ + gf_common_mt_nfs_exports, /* used only in one location */ + gf_common_mt_gf_brick_spec_t, /* used only in one location */ + gf_common_mt_int, + gf_common_mt_pointer, + gf_common_mt_synctask, /* used only in one location */ + gf_common_mt_syncstack, /* used only in one location */ + gf_common_mt_syncenv, /* used only in one location */ + gf_common_mt_scan_data, /* used only in one location */ + gf_common_list_node, + gf_mt_default_args_t, /* used only in one location */ + gf_mt_default_args_cbk_t, /* used only in one location */ + /*used for compound fops*/ + gf_mt_compound_req_t, /* used only in one location */ + gf_mt_compound_rsp_t, /* used only in one location */ + gf_common_mt_tw_ctx, /* used only in one location */ + gf_common_mt_tw_timer_list, + /*lock migration*/ + gf_common_mt_lock_mig, + /* throttle */ + gf_common_mt_tbf_t, /* used only in one location */ + gf_common_mt_tbf_bucket_t, /* used only in one location */ + gf_common_mt_tbf_throttle_t, /* used only in one location */ + gf_common_mt_pthread_t, /* used only in one location */ + gf_common_ping_local_t, /* used only in one location */ + gf_common_volfile_t, + gf_common_mt_mgmt_v3_lock_timer_t, /* used only in one location */ + gf_common_mt_server_cmdline_t, /* used only in one location */ + gf_common_mt_latency_t, + gf_common_mt_end +}; +#endif diff --git a/libglusterfs/src/glusterfs/monitoring.h b/libglusterfs/src/glusterfs/monitoring.h new file mode 100644 index 00000000000..09d9f54e734 --- /dev/null +++ b/libglusterfs/src/glusterfs/monitoring.h @@ -0,0 +1,21 @@ +/* + Copyright (c) 2017 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 __MONITORING_H__ +#define __MONITORING_H__ + +#include "glusterfs/glusterfs.h" + +#define GLUSTER_METRICS_DIR "/var/run/gluster/metrics" + +char * +gf_monitor_metrics(glusterfs_ctx_t *ctx); + +#endif /* __MONITORING_H__ */ diff --git a/libglusterfs/src/glusterfs/options.h b/libglusterfs/src/glusterfs/options.h new file mode 100644 index 00000000000..747b13ba375 --- /dev/null +++ b/libglusterfs/src/glusterfs/options.h @@ -0,0 +1,327 @@ +/* + 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 _OPTIONS_H +#define _OPTIONS_H + +#include <stdio.h> +#include <stdint.h> +#include <inttypes.h> + +#include "glusterfs/xlator.h" +#include "glusterfs/libglusterfs-messages.h" +/* Add possible new type of option you may need */ +typedef enum { + GF_OPTION_TYPE_ANY = 0, + GF_OPTION_TYPE_STR, + GF_OPTION_TYPE_INT, + GF_OPTION_TYPE_SIZET, + GF_OPTION_TYPE_PERCENT, + GF_OPTION_TYPE_PERCENT_OR_SIZET, + GF_OPTION_TYPE_BOOL, + GF_OPTION_TYPE_XLATOR, + GF_OPTION_TYPE_PATH, + GF_OPTION_TYPE_TIME, + GF_OPTION_TYPE_DOUBLE, + GF_OPTION_TYPE_INTERNET_ADDRESS, + GF_OPTION_TYPE_INTERNET_ADDRESS_LIST, + GF_OPTION_TYPE_PRIORITY_LIST, + GF_OPTION_TYPE_SIZE_LIST, + GF_OPTION_TYPE_CLIENT_AUTH_ADDR, + GF_OPTION_TYPE_MAX, +} volume_option_type_t; + +typedef enum { + GF_OPT_VALIDATE_BOTH = 0, + GF_OPT_VALIDATE_MIN, + GF_OPT_VALIDATE_MAX, +} opt_validate_type_t; + +typedef enum { + OPT_FLAG_NONE = 0, + OPT_FLAG_SETTABLE = 1 << 0, /* can be set using volume set */ + OPT_FLAG_CLIENT_OPT = 1 << 1, /* affects clients */ + OPT_FLAG_GLOBAL = 1 + << 2, /* affects all instances of the particular xlator */ + OPT_FLAG_FORCE = 1 << 3, /* needs force to be reset */ + OPT_FLAG_NEVER_RESET = 1 << 4, /* which should not be reset */ + OPT_FLAG_DOC = 1 << 5, /* can be shown in volume set help */ +} opt_flags_t; + +typedef enum { + OPT_STATUS_ADVANCED = 0, + OPT_STATUS_BASIC = 1, + OPT_STATUS_EXPERIMENTAL = 2, + OPT_STATUS_DEPRECATED = 3, +} opt_level_t; + +#define ZR_VOLUME_MAX_NUM_KEY 4 +#define ZR_OPTION_MAX_ARRAY_SIZE 64 +/* The maximum number of releases that an option could be backported to + * based on the release schedule as in August 2017 (3), plus one more + * Refer comment on volume_options.op_version for more information. + */ +#define GF_MAX_RELEASES 4 + +/* Custom validation functoins for options + * TODO: Need to check what sorts of validation is being done, and decide if + * passing the volinfo is actually required. If it is, then we should possibly + * try a solution in GD2 for this. + */ +/* typedef int (*option_validation_fn) (glusterd_volinfo_t *volinfo, dict_t + *dict, char *key, char *value, char **op_errstr); + */ + +/* Each translator should define this structure */ +/* XXX: This structure is in use by GD2, and SHOULD NOT be modified. + * If there is a need to add new members, add them to the end of the structure. + * If the struct must be modified, GD2 MUST be updated as well + */ +typedef struct volume_options { + char *key[ZR_VOLUME_MAX_NUM_KEY]; + /* different key, same meaning */ + volume_option_type_t type; + double min; /* 0 means no range */ + double max; /* 0 means no range */ + char *value[ZR_OPTION_MAX_ARRAY_SIZE]; + /* If specified, will check for one of + the value from this array */ + char *default_value; + char *description; /* about the key */ + /* Required for int options where only the min value + * is given and is 0. This will cause validation not to + * happen + */ + opt_validate_type_t validate; + + /* The op-version at which this option was introduced. + * This is an array to support options that get backported to supported + * releases. + * Normally, an option introduced for a major release just has a single + * entry in the array, with op-version of the major release + * For an option that is backported, the op-versions of the all the + * releases it was ported to should be added, starting from the newest, + * to the oldest. + */ + uint32_t op_version[GF_MAX_RELEASES]; + /* The op-version at which this option was deprecated. + * Follows the same rules as above. + */ + uint32_t deprecated[GF_MAX_RELEASES]; + /* Additional flags for an option + * Check the OPT_FLAG_* enums for available flags + */ + uint32_t flags; + /* Tags applicable to this option, which can be used to group similar + * options + */ + char *tags[ZR_OPTION_MAX_ARRAY_SIZE]; + /* A custom validation function if required + * TODO: See todo above for option_validation_fn + */ + /* option_validation_fn validate_fn; */ + /* This is actual key that should be set in the options dict. Can + * contain varstrings + */ + char *setkey; + + /* A 'level' is about the technical depth / understanding one + needs to handle the option. 'category' is based on + quality (ie, tests, people behind it, documentation available) */ + + /* The level at which the option is classified */ + opt_level_t level; + + /* Flag to understand how this option is categorized */ + gf_category_t category; +} volume_option_t; + +typedef struct vol_opt_list { + struct list_head list; + volume_option_t *given_opt; +} volume_opt_list_t; + +int +xlator_tree_reconfigure(xlator_t *old_xl, xlator_t *new_xl); +int +xlator_validate_rec(xlator_t *xlator, char **op_errstr); +int +graph_reconf_validateopt(glusterfs_graph_t *graph, char **op_errstr); +int +xlator_option_info_list(volume_opt_list_t *list, char *key, char **def_val, + char **descr); +/* +int validate_xlator_volume_options (xlator_t *xl, dict_t *options, + volume_option_t *opt, char **op_errstr); +*/ +int +xlator_options_validate_list(xlator_t *xl, dict_t *options, + volume_opt_list_t *list, char **op_errstr); +int +xlator_option_validate(xlator_t *xl, char *key, char *value, + volume_option_t *opt, char **op_errstr); +int +xlator_options_validate(xlator_t *xl, dict_t *options, char **errstr); + +int +xlator_option_validate_addr_list(xlator_t *xl, const char *key, + const char *value, volume_option_t *opt, + char **op_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 xlator_option_init_##type(xlator_t *this, dict_t *options, char *key, \ + type_t *val_p); + +DECLARE_INIT_OPT(char *, str); +DECLARE_INIT_OPT(uint64_t, uint64); +DECLARE_INIT_OPT(int64_t, int64); +DECLARE_INIT_OPT(uint32_t, uint32); +DECLARE_INIT_OPT(int32_t, int32); +DECLARE_INIT_OPT(uint64_t, size); +DECLARE_INIT_OPT(uint64_t, size_uint64); +DECLARE_INIT_OPT(double, percent); +DECLARE_INIT_OPT(double, percent_or_size); +DECLARE_INIT_OPT(gf_boolean_t, bool); +DECLARE_INIT_OPT(xlator_t *, xlator); +DECLARE_INIT_OPT(char *, path); +DECLARE_INIT_OPT(double, double); +DECLARE_INIT_OPT(uint32_t, time); + +#define DEFINE_INIT_OPT(type_t, type, conv) \ + int xlator_option_init_##type(xlator_t *this, dict_t *options, char *key, \ + type_t *val_p) \ + { \ + int ret = 0; \ + volume_option_t *opt = NULL; \ + char *def_value = NULL; \ + char *set_value = NULL; \ + char *value = NULL; \ + xlator_t *old_THIS = NULL; \ + \ + opt = xlator_volume_option_get(this, key); \ + if (!opt) { \ + gf_msg(this->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ENTRY, \ + "unknown option: %s", key); \ + ret = -1; \ + return ret; \ + } \ + def_value = opt->default_value; \ + ret = dict_get_str(options, key, &set_value); \ + \ + if (def_value) \ + value = def_value; \ + if (set_value) \ + value = set_value; \ + if (!value) { \ + gf_msg_trace(this->name, 0, "option %s not set", key); \ + *val_p = (type_t)0; \ + return 0; \ + } \ + if (value == def_value) { \ + gf_msg_trace(this->name, 0, \ + "option %s using default" \ + " value %s", \ + key, value); \ + } else { \ + gf_msg_debug(this->name, 0, \ + "option %s using set" \ + " value %s", \ + key, value); \ + } \ + old_THIS = THIS; \ + THIS = this; \ + ret = conv(value, val_p); \ + THIS = old_THIS; \ + if (ret) { \ + gf_msg(this->name, GF_LOG_INFO, 0, LG_MSG_CONVERSION_FAILED, \ + "option %s conversion failed value %s", key, value); \ + return ret; \ + } \ + ret = xlator_option_validate(this, key, value, opt, NULL); \ + return ret; \ + } + +#define GF_OPTION_INIT(key, val, type, err_label) \ + do { \ + int val_ret = 0; \ + val_ret = xlator_option_init_##type(THIS, THIS->options, key, &(val)); \ + if (val_ret) \ + goto err_label; \ + } while (0) + +#define DECLARE_RECONF_OPT(type_t, type) \ + int xlator_option_reconf_##type(xlator_t *this, dict_t *options, \ + char *key, int keylen, type_t *val_p); + +DECLARE_RECONF_OPT(char *, str); +DECLARE_RECONF_OPT(uint64_t, uint64); +DECLARE_RECONF_OPT(int64_t, int64); +DECLARE_RECONF_OPT(uint32_t, uint32); +DECLARE_RECONF_OPT(int32_t, int32); +DECLARE_RECONF_OPT(uint64_t, size); +DECLARE_RECONF_OPT(uint64_t, size_uint64); +DECLARE_RECONF_OPT(double, percent); +DECLARE_RECONF_OPT(double, percent_or_size); +DECLARE_RECONF_OPT(gf_boolean_t, bool); +DECLARE_RECONF_OPT(xlator_t *, xlator); +DECLARE_RECONF_OPT(char *, path); +DECLARE_RECONF_OPT(double, double); +DECLARE_RECONF_OPT(uint32_t, time); + +#define DEFINE_RECONF_OPT(type_t, type, conv) \ + int xlator_option_reconf_##type(xlator_t *this, dict_t *options, \ + char *key, int keylen, type_t *val_p) \ + { \ + int ret = 0; \ + char *value = NULL; \ + xlator_t *old_THIS = NULL; \ + \ + volume_option_t *opt = xlator_volume_option_get(this, key); \ + if (!opt) { \ + gf_msg(this->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ENTRY, \ + "unknown option: %s", key); \ + return -1; \ + } \ + ret = dict_get_strn(options, key, keylen, &value); \ + if (ret == 0 && value) { \ + gf_msg(this->name, GF_LOG_INFO, 0, 0, \ + "option %s using set value %s", key, value); \ + } else if (opt->default_value) { \ + value = opt->default_value; \ + gf_msg_trace(this->name, 0, "option %s using default value %s", \ + key, value); \ + } else { \ + gf_msg_trace(this->name, 0, "option %s not set", key); \ + *val_p = (type_t)0; \ + return 0; \ + } \ + \ + old_THIS = THIS; \ + THIS = this; \ + ret = conv(value, val_p); \ + THIS = old_THIS; \ + if (ret) \ + return ret; \ + return xlator_option_validate(this, key, value, opt, NULL); \ + } + +#define GF_OPTION_RECONF(key, val, opt, type, err_label) \ + do { \ + if (xlator_option_reconf_##type(THIS, opt, key, SLEN(key), &(val))) \ + goto err_label; \ + } while (0) + +#endif /* !_OPTIONS_H */ diff --git a/libglusterfs/src/glusterfs/parse-utils.h b/libglusterfs/src/glusterfs/parse-utils.h new file mode 100644 index 00000000000..8653b9dd180 --- /dev/null +++ b/libglusterfs/src/glusterfs/parse-utils.h @@ -0,0 +1,50 @@ +/* + Copyright 2014-present Facebook. All Rights Reserved + + This file is part of GlusterFS. + + Author : + Shreyas Siravara <shreyas.siravara@gmail.com> + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _PARSE_UTILS_H +#define _PARSE_UTILS_H + +#include <regex.h> + +#define GF_PARSE "parse-utils" + +struct parser { + regex_t preg; /* Compiled regex */ + regmatch_t pmatch[1]; /* The match */ + char *complete_str; /* The string we are parsing */ + char *regex; /* Regex used to parse the string */ + char *_rstr; /* Temp string to hold offsets */ +}; + +/* Initializes some of the parsers variables */ +struct parser * +parser_init(const char *regex); + +/* Sets the string to parse */ +int +parser_set_string(struct parser *parser, const char *complete_str); + +/* Frees memory used by the string after all matches are found */ +int +parser_unset_string(struct parser *parser); + +/* Free memory used by the parser */ +void +parser_deinit(struct parser *ptr); + +/* Get the next matching string */ +char * +parser_get_next_match(struct parser *parser); + +#endif /* _PARSE_UTILS_H */ diff --git a/libglusterfs/src/glusterfs/quota-common-utils.h b/libglusterfs/src/glusterfs/quota-common-utils.h new file mode 100644 index 00000000000..0096e340756 --- /dev/null +++ b/libglusterfs/src/glusterfs/quota-common-utils.h @@ -0,0 +1,68 @@ +/* + Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _QUOTA_COMMON_UTILS_H +#define _QUOTA_COMMON_UTILS_H + +#include "glusterfs/iatt.h" + +#define GF_QUOTA_CONF_VERSION 1.2 +#define QUOTA_CONF_HEADER "GlusterFS Quota conf | version: v1.2\n" +#define QUOTA_CONF_HEADER_1_1 "GlusterFS Quota conf | version: v1.1\n" + +typedef enum { + GF_QUOTA_CONF_TYPE_USAGE = 1, + GF_QUOTA_CONF_TYPE_OBJECTS +} gf_quota_conf_type_t; + +struct _quota_limits { + int64_t hl; + int64_t sl; +} __attribute__((__packed__)); +typedef struct _quota_limits quota_limits_t; + +struct _quota_meta { + int64_t size; + int64_t file_count; + int64_t dir_count; +} __attribute__((__packed__)); +typedef struct _quota_meta quota_meta_t; + +gf_boolean_t +quota_meta_is_null(const quota_meta_t *meta); + +int32_t +quota_data_to_meta(data_t *data, quota_meta_t *meta); + +int32_t +quota_dict_get_inode_meta(dict_t *dict, char *key, const int keylen, + quota_meta_t *meta); + +int32_t +quota_dict_get_meta(dict_t *dict, char *key, const int keylen, + quota_meta_t *meta); + +int32_t +quota_dict_set_meta(dict_t *dict, char *key, const quota_meta_t *meta, + ia_type_t ia_type); + +int32_t +quota_conf_read_header(int fd, char *buf); + +int32_t +quota_conf_read_version(int fd, float *version); + +int32_t +quota_conf_read_gfid(int fd, void *buf, char *type, float version); + +int32_t +quota_conf_skip_header(int fd); + +#endif /* _QUOTA_COMMON_UTILS_H */ diff --git a/libglusterfs/src/glusterfs/rbthash.h b/libglusterfs/src/glusterfs/rbthash.h new file mode 100644 index 00000000000..4c731de69c2 --- /dev/null +++ b/libglusterfs/src/glusterfs/rbthash.h @@ -0,0 +1,75 @@ +/* + 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 __RBTHASH_TABLE_H_ +#define __RBTHASH_TABLE_H_ + +#include <stdint.h> // for uint32_t +#include "glusterfs/glusterfs.h" // for gf_boolean_t, glusterfs_ctx_t +#include "glusterfs/list.h" // for list_head +#include "glusterfs/locking.h" // for gf_lock_t +struct mem_pool; + +#define GF_RBTHASH_MEMPOOL 16384 // 1048576 +#define GF_RBTHASH "rbthash" + +struct rbthash_bucket { + struct rb_table *bucket; + gf_lock_t bucketlock; +}; + +typedef struct rbthash_entry { + void *data; + void *key; + int keylen; + uint32_t keyhash; + struct list_head list; +} rbthash_entry_t; + +typedef uint32_t (*rbt_hasher_t)(void *data, int len); +typedef void (*rbt_data_destroyer_t)(void *data); +typedef void (*rbt_traverse_t)(void *data, void *mydata); + +typedef struct rbthash_table { + int size; + int numbuckets; + struct mem_pool *entrypool; + gf_lock_t tablelock; + struct rbthash_bucket *buckets; + rbt_hasher_t hashfunc; + rbt_data_destroyer_t dfunc; + gf_boolean_t pool_alloced; + struct list_head list; +} rbthash_table_t; + +extern rbthash_table_t * +rbthash_table_init(glusterfs_ctx_t *ctx, int buckets, rbt_hasher_t hfunc, + rbt_data_destroyer_t dfunc, unsigned long expected_entries, + struct mem_pool *entrypool); + +extern int +rbthash_insert(rbthash_table_t *tbl, void *data, void *key, int keylen); + +extern void * +rbthash_get(rbthash_table_t *tbl, void *key, int keylen); + +extern void * +rbthash_remove(rbthash_table_t *tbl, void *key, int keylen); + +extern void * +rbthash_replace(rbthash_table_t *tbl, void *key, int keylen, void *newdata); + +extern void +rbthash_table_destroy(rbthash_table_t *tbl); + +extern void +rbthash_table_traverse(rbthash_table_t *tbl, rbt_traverse_t traverse, + void *mydata); +#endif diff --git a/libglusterfs/src/glusterfs/refcount.h b/libglusterfs/src/glusterfs/refcount.h new file mode 100644 index 00000000000..cf922dabb05 --- /dev/null +++ b/libglusterfs/src/glusterfs/refcount.h @@ -0,0 +1,101 @@ +/* + Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _REFCOUNT_H +#define _REFCOUNT_H + +/* check for compiler support for __sync_*_and_fetch() + * + * a more comprehensive feature test is shown at + * http://lists.iptel.org/pipermail/semsdev/2010-October/005075.html + * this is sufficient for RHEL5 i386 builds + */ +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) && \ + !defined(__i386__) +#undef REFCOUNT_NEEDS_LOCK +#else +#define REFCOUNT_NEEDS_LOCK +#include "glusterfs/locking.h" +#endif /* compiler support for __sync_*_and_fetch() */ + +typedef void (*gf_ref_release_t)(void *data); + +struct _gf_ref { +#ifdef REFCOUNT_NEEDS_LOCK + gf_lock_t lk; /* lock for atomically adjust cnt */ +#endif + unsigned int cnt; /* number of users, free on 0 */ + + gf_ref_release_t release; /* cleanup when cnt == 0 */ + void *data; /* parameter passed to release() */ +}; +typedef struct _gf_ref gf_ref_t; + +/* _gf_ref_get -- increase the refcount + * + * @return: greater then 0 when a reference was taken, 0 when not + */ +void * +_gf_ref_get(gf_ref_t *ref); + +/* _gf_ref_put -- decrease the refcount + * + * @return: greater then 0 when there are still references, 0 when cleanup + * should be done, gf_ref_release_t is called on cleanup + */ +unsigned int +_gf_ref_put(gf_ref_t *ref); + +/* _gf_ref_init -- initialize an embedded refcount object + * + * @release: function to call when the refcount == 0 + * @data: parameter to be passed to @release + */ +void +_gf_ref_init(gf_ref_t *ref, gf_ref_release_t release, void *data); + +/* + * Strong suggestion to use the simplified GF_REF_* API. + */ + +/* GF_REF_DECL -- declaration to put inside your structure + * + * Example: + * struct my_struct { + * GF_REF_DECL; + * + * ... // additional members + * }; + */ +#define GF_REF_DECL gf_ref_t _ref + +/* GF_REF_INIT -- initialize a GF_REF_DECL structure + * + * @p: allocated structure with GF_REF_DECL + * @d: destructor to call once refcounting reaches 0 + * + * Sets the refcount to 1. + */ +#define GF_REF_INIT(p, d) _gf_ref_init(&(p)->_ref, (gf_ref_release_t)d, p) + +/* GF_REF_GET -- increase the refcount of a GF_REF_DECL structure + * + * @return: greater then 0 when a reference was taken, 0 when not + */ +#define GF_REF_GET(p) _gf_ref_get(&(p)->_ref) + +/* GF_REF_PUT -- decrease the refcount of a GF_REF_DECL structure + * + * @return: greater then 0 when there are still references, 0 when cleanup + * should be done, gf_ref_release_t is called on cleanup + */ +#define GF_REF_PUT(p) _gf_ref_put(&(p)->_ref) + +#endif /* _REFCOUNT_H */ diff --git a/libglusterfs/src/glusterfs/revision.h b/libglusterfs/src/glusterfs/revision.h new file mode 100644 index 00000000000..3c404d30e78 --- /dev/null +++ b/libglusterfs/src/glusterfs/revision.h @@ -0,0 +1 @@ +#define GLUSTERFS_REPOSITORY_REVISION "git://git.gluster.org/glusterfs.git" diff --git a/libglusterfs/src/glusterfs/rot-buffs.h b/libglusterfs/src/glusterfs/rot-buffs.h new file mode 100644 index 00000000000..9dc227d58b8 --- /dev/null +++ b/libglusterfs/src/glusterfs/rot-buffs.h @@ -0,0 +1,125 @@ +/* + Copyright (c) 2008-2015 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef __ROT_BUFFS_H +#define __ROT_BUFFS_H + +#include "glusterfs/list.h" +#include "glusterfs/locking.h" +#include "glusterfs/common-utils.h" + +typedef struct rbuf_iovec { + struct iovec iov; + + struct list_head list; +} rbuf_iovec_t; + +#define RBUF_IOVEC_SIZE (sizeof(rbuf_iovec_t)) + +typedef struct rbuf_list { + gf_lock_t c_lock; + + pthread_mutex_t b_lock; /* protects this structure */ + pthread_cond_t b_cond; /* signal for writer completion */ + + gf_boolean_t awaiting; + + unsigned long long pending; /* pending writers */ + unsigned long long completed; /* completed writers */ + + rbuf_iovec_t *rvec; /* currently used IO vector */ + + struct list_head veclist; /* list of attached rbuf_iov */ + + unsigned long long used; /* consumable entries + attached in ->veclist */ + unsigned long long total; /* total entries in ->veclist (used + during deallocation) */ + + unsigned long seq[2]; /* if interested, this whould store + the start sequence number and the + range */ + + struct list_head list; /* attachment to rbuf_t */ +} rbuf_list_t; + +struct rlist_iter { + struct list_head veclist; + + unsigned long long iter; +}; + +#define RLIST_ENTRY_COUNT(rlist) rlist->used + +#define rlist_iter_init(riter, rlist) \ + do { \ + (riter)->iter = rlist->used; \ + (riter)->veclist = rlist->veclist; \ + } while (0) + +#define rvec_for_each_entry(pos, riter) \ + for (pos = list_entry((riter)->veclist.next, typeof(*pos), list); \ + (riter)->iter > 0; \ + pos = list_entry(pos->list.next, typeof(*pos), list), \ + --((riter)->iter)) + +/** + * Sequence number assignment routine is called during buffer + * switch under rbuff ->lock. + */ +typedef void(sequence_fn)(rbuf_list_t *, void *); + +#define RLIST_STORE_SEQ(rlist, start, range) \ + do { \ + rlist->seq[0] = start; \ + rlist->seq[1] = range; \ + } while (0) + +#define RLIST_GET_SEQ(rlist, start, range) \ + do { \ + start = rlist->seq[0]; \ + range = rlist->seq[1]; \ + } while (0) + +typedef struct rbuf { + gf_lock_t lock; /* protects "current" rlist */ + + rbuf_list_t *current; /* cached pointer to first free rlist */ + + struct list_head freelist; +} rbuf_t; + +typedef enum { + RBUF_CONSUMABLE = 1, + RBUF_BUSY, + RBUF_EMPTY, + RBUF_WOULD_STARVE, +} rlist_retval_t; + +/* Initialization/Destruction */ +rbuf_t * +rbuf_init(int); +void +rbuf_dtor(rbuf_t *); + +/* Producer API */ +char * +rbuf_reserve_write_area(rbuf_t *, size_t, void **); +int +rbuf_write_complete(void *); + +/* Consumer API */ +int +rbuf_get_buffer(rbuf_t *, void **, sequence_fn *, void *); +int +rbuf_wait_for_completion(rbuf_t *, void *, void (*)(rbuf_list_t *, void *), + void *); + +#endif diff --git a/libglusterfs/src/glusterfs/run.h b/libglusterfs/src/glusterfs/run.h new file mode 100644 index 00000000000..76af95fd27f --- /dev/null +++ b/libglusterfs/src/glusterfs/run.h @@ -0,0 +1,207 @@ +/* + 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 __RUN_H__ +#define __RUN_H__ + +#define RUN_PIPE -1 + +struct runner { + char **argv; + unsigned argvlen; + int runerr; + pid_t chpid; + int chfd[3]; + FILE *chio[3]; +}; + +typedef struct runner runner_t; + +/** + * initialize runner_t instance. + * + * @param runner pointer to runner_t instance + */ +void +runinit(runner_t *runner); + +/** + * get FILE pointer to which child's stdio is redirected. + * + * @param runner pointer to runner_t instance + * @param fd specifies which standard file descriptor is + * is asked for + * + * @see runner_redir() + */ +FILE * +runner_chio(runner_t *runner, int fd); + +/** + * add an argument. + * + * 'arg' is duplicated. + * + * Errors are deferred, no error handling is necessary. + * + * @param runner pointer to runner_t instance + * @param arg command line argument + */ +void +runner_add_arg(runner_t *runner, const char *arg); + +/** + * add a sequence of arguments. + * + * Variadic function, calls runner_add_arg() on each vararg. + * Argument sequence MUST be NULL terminated. + * + * Errors are deferred, no error handling is necessary. + * + * @param runner pointer to runner_t instance + * + * @see runner_add_arg() + */ +void +runner_add_args(runner_t *runner, ...); + +/** + * add an argument with printf style formatting. + * + * Errors are deferred, no error handling is necessary. + * + * @param runner pointer to runner_t instance + * @param format printf style format specifier + */ +void +runner_argprintf(runner_t *runner, const char *format, ...) + __attribute__((__format__(__printf__, 2, 3))); +/** + * log a message about the command to be run. + * + * @param runner pointer to runner_t instance + * + * @param dom log domain + * @param lvl log level + * @param msg message with which the command is prefixed in log + * + * @see gf_log() + */ +void +runner_log(runner_t *runner, const char *dom, gf_loglevel_t lvl, + const char *msg); + +/** + * set up redirection for child. + * + * @param runner pointer to runner_t instance + * + * @param fd fd of child to redirect (0, 1, or 2) + * @param tgt_fd fd on parent side to redirect to. + * Note that runner_end() will close tgt_fd, + * if user needs it in another context it should + * be dup'd beforehand. + * RUN_PIPE can be used for requiring a + * pipe from child to parent. The FILE + * created for this purpose will be + * accessible via runner_chio() (after + * runner_start() has been invoked). + * + * @see runner_start(), dup(2), runner_chio(), runner_start() + */ +void +runner_redir(runner_t *runner, int fd, int tgt_fd); + +/** + * spawn child with accumulated arg list. + * + * @param runner pointer to runner_t instance + * + * @return 0 on successful spawn + * -1 on failure (either due to earlier errors or execve(2) failing) + * + * @see runner_cout() + */ +int +runner_start(runner_t *runner); + +/** + * complete operation and free resources. + * + * If child exists, waits for it. Redirections will be closed. + * Dynamically allocated memory shall be freed. + * + * @param runner pointer to runner_t instance + * + * @return 0 if child terminated successfully + * -1 if there is no running child + * n > 0 if child failed; value to be interpreted as status + * in waitpid(2) + * + * @see waitpid(2) + */ +int +runner_end(runner_t *runner); + +/** + * variant of runner_end() which does not free internal data + * so that the runner instance can be run again. + * + * @see runner_end() + */ +int +runner_end_reuse(runner_t *runner); + +/** + * spawn and child, take it to completion and free resources. + * + * Essentially it's a concatenation of runner_start() and runner_end() + * with simplified return semantics. + * + * @param runner pointer to runner_t instance + * + * @return 0 on success + * -1 on failuire + * + * @see runner_start(), runner_end() + */ +int +runner_run(runner_t *runner); + +/** + * variant for runner_run() which does not wait for acknowledgement + * from child, and always assumes it succeeds. + */ +int +runner_run_nowait(runner_t *runner); + +/** + * variant of runner_run() which does not free internal data + * so that the runner instance can be run again. + * + * @see runner_run() + */ +int +runner_run_reuse(runner_t *runner); + +/** + * run a command with args. + * + * Variadic function, child process is spawned with + * the given sequence of args and waited for. + * Argument sequence MUST be NULL terminated. + * + * @return 0 on success + * -1 on failure + */ +int +runcmd(const char *arg, ...); + +#endif diff --git a/libglusterfs/src/glusterfs/stack.h b/libglusterfs/src/glusterfs/stack.h new file mode 100644 index 00000000000..536a330d38b --- /dev/null +++ b/libglusterfs/src/glusterfs/stack.h @@ -0,0 +1,555 @@ +/* + 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. +*/ + +/* + This file defines MACROS and static inlines used to emulate a function + call over asynchronous communication with remote server +*/ + +#ifndef _STACK_H +#define _STACK_H + +struct _call_stack; +typedef struct _call_stack call_stack_t; +struct _call_frame; +typedef struct _call_frame call_frame_t; +struct call_pool; +typedef struct call_pool call_pool_t; + +#include <sys/time.h> + +#include "glusterfs/xlator.h" +#include "glusterfs/dict.h" +#include "glusterfs/list.h" +#include "glusterfs/common-utils.h" +#include "glusterfs/lkowner.h" +#include "glusterfs/client_t.h" +#include "glusterfs/libglusterfs-messages.h" +#include "glusterfs/timespec.h" + +#define NFS_PID 1 +#define LOW_PRIO_PROC_PID -1 + +#define STACK_ERR_XL_NAME(stack) (stack->err_xl ? stack->err_xl->name : "-") +#define STACK_CLIENT_NAME(stack) \ + (stack->client ? stack->client->client_uid : "-") + +typedef int32_t (*ret_fn_t)(call_frame_t *frame, call_frame_t *prev_frame, + xlator_t *this, int32_t op_ret, int32_t op_errno, + ...); + +void +gf_frame_latency_update(call_frame_t *frame); + +struct call_pool { + union { + struct list_head all_frames; + struct { + call_stack_t *next_call; + call_stack_t *prev_call; + } all_stacks; + }; + int64_t cnt; + gf_atomic_t total_count; + gf_lock_t lock; + struct mem_pool *frame_mem_pool; + struct mem_pool *stack_mem_pool; +}; + +struct _call_frame { + call_stack_t *root; /* stack root */ + call_frame_t *parent; /* previous BP */ + struct list_head frames; + void *local; /* local variables */ + xlator_t *this; /* implicit object */ + ret_fn_t ret; /* op_return address */ + int32_t ref_count; + gf_lock_t lock; + void *cookie; /* unique cookie */ + gf_boolean_t complete; + + glusterfs_fop_t op; + struct timespec begin; /* when this frame was created */ + struct timespec end; /* when this frame completed */ + const char *wind_from; + const char *wind_to; + const char *unwind_from; + const char *unwind_to; +}; + +struct _ns_info { + uint32_t hash; /* Hash of the namespace from SuperFastHash */ + gf_boolean_t found; /* Set to true if we found a namespace */ +}; + +typedef struct _ns_info ns_info_t; + +#define SMALL_GROUP_COUNT 128 + +struct _call_stack { + union { + struct list_head all_frames; + struct { + call_stack_t *next_call; + call_stack_t *prev_call; + }; + }; + call_pool_t *pool; + gf_lock_t stack_lock; + client_t *client; + uint64_t unique; + void *state; /* pointer to request state */ + uid_t uid; + gid_t gid; + pid_t pid; + char identifier[UNIX_PATH_MAX]; + uint16_t ngrps; + uint32_t groups_small[SMALL_GROUP_COUNT]; + uint32_t *groups_large; + uint32_t *groups; + gf_lkowner_t lk_owner; + glusterfs_ctx_t *ctx; + + struct list_head myframes; /* List of call_frame_t that go + to make the call stack */ + + int32_t op; + int8_t type; + struct timespec tv; + xlator_t *err_xl; + int32_t error; + + uint32_t flags; /* use it wisely, think of it as a mechanism to + send information over the wire too */ + struct timespec ctime; /* timestamp, most probably set at + creation of stack. */ + + ns_info_t ns_info; +}; + +/* call_stack flags field users */ +#define MDATA_CTIME (1 << 0) +#define MDATA_MTIME (1 << 1) +#define MDATA_ATIME (1 << 2) +#define MDATA_PAR_CTIME (1 << 3) +#define MDATA_PAR_MTIME (1 << 4) +#define MDATA_PAR_ATIME (1 << 5) + +#define frame_set_uid_gid(frm, u, g) \ + do { \ + if (frm) { \ + (frm)->root->uid = u; \ + (frm)->root->gid = g; \ + (frm)->root->ngrps = 0; \ + } \ + } while (0); + +struct xlator_fops; + +static inline void +FRAME_DESTROY(call_frame_t *frame) +{ + void *local = NULL; + + if (frame->root->ctx->measure_latency) + gf_frame_latency_update(frame); + + list_del_init(&frame->frames); + if (frame->local) { + local = frame->local; + frame->local = NULL; + } + + LOCK_DESTROY(&frame->lock); + mem_put(frame); + + if (local) + mem_put(local); +} + +static inline void +STACK_DESTROY(call_stack_t *stack) +{ + call_frame_t *frame = NULL; + call_frame_t *tmp = NULL; + + LOCK(&stack->pool->lock); + { + list_del_init(&stack->all_frames); + stack->pool->cnt--; + } + UNLOCK(&stack->pool->lock); + + LOCK_DESTROY(&stack->stack_lock); + + list_for_each_entry_safe(frame, tmp, &stack->myframes, frames) + { + FRAME_DESTROY(frame); + } + + GF_FREE(stack->groups_large); + + mem_put(stack); +} + +static inline void +STACK_RESET(call_stack_t *stack) +{ + call_frame_t *frame = NULL; + call_frame_t *tmp = NULL; + call_frame_t *last = NULL; + struct list_head toreset = {0}; + + INIT_LIST_HEAD(&toreset); + + /* We acquire call_pool->lock only to remove the frames from this stack + * to preserve atomicity. This synchronizes across concurrent requests + * like statedump, STACK_DESTROY etc. */ + + LOCK(&stack->pool->lock); + { + last = list_last_entry(&stack->myframes, call_frame_t, frames); + list_del_init(&last->frames); + list_splice_init(&stack->myframes, &toreset); + list_add(&last->frames, &stack->myframes); + } + UNLOCK(&stack->pool->lock); + + list_for_each_entry_safe(frame, tmp, &toreset, frames) + { + FRAME_DESTROY(frame); + } +} + +#define FRAME_SU_DO(frm, local_type) \ + do { \ + local_type *__local = (frm)->local; \ + __local->uid = frm->root->uid; \ + __local->gid = frm->root->gid; \ + __local->pid = frm->root->pid; \ + frm->root->uid = 0; \ + frm->root->gid = 0; \ + frm->root->pid = GF_CLIENT_PID_NO_ROOT_SQUASH; \ + } while (0); + +#define FRAME_SU_UNDO(frm, local_type) \ + do { \ + local_type *__local = (frm)->local; \ + frm->root->uid = __local->uid; \ + frm->root->gid = __local->gid; \ + frm->root->pid = __local->pid; \ + } while (0); + +/* NOTE: make sure to keep this as an macro, mainly because, we need 'fn' + field here to be the proper fn ptr, so its address is valid entry in + 'xlator_fops' struct. + To understand this, check the `xlator.h:struct xlator_fops`, and then + see a STACK_WIND call, which generally calls `subvol->fops->fop`, so + the address offset should give the index */ + +/* +1 is required as 0 means NULL fop, and we don't have a variable for it */ +#define get_fop_index_from_fn(xl, fn) \ + (1 + (((long)&(fn) - (long)&((xl)->fops->stat)) / sizeof(void *))) + +/* NOTE: the above reason holds good here too. But notice that we are getting + the base address of the 'stat' fop, which is the first entry in the fop + structure. All we need to do is move as much as 'idx' fields, and get the + actual pointer from that field. */ + +static inline void * +get_the_pt_fop(void *base_fop, int fop_idx) +{ + void *target_addr = (base_fop + ((fop_idx - 1) * sizeof(void *))); + /* all below type casting is for not getting warning. */ + return (void *)*(unsigned long *)target_addr; +} + +/* make a call without switching frames */ +#define STACK_WIND_TAIL(frame, obj, fn, params...) \ + do { \ + xlator_t *old_THIS = NULL; \ + xlator_t *next_xl = obj; \ + typeof(fn) next_xl_fn = fn; \ + int opn = get_fop_index_from_fn((next_xl), (fn)); \ + \ + frame->this = next_xl; \ + frame->wind_to = #fn; \ + old_THIS = THIS; \ + THIS = next_xl; \ + gf_msg_trace("stack-trace", 0, \ + "stack-address: %p, " \ + "winding from %s to %s", \ + frame->root, old_THIS->name, THIS->name); \ + /* Need to capture counts at leaf node */ \ + if (!next_xl->pass_through && !next_xl->children) { \ + GF_ATOMIC_INC(next_xl->stats.total.metrics[opn].fop); \ + GF_ATOMIC_INC(next_xl->stats.interval.metrics[opn].fop); \ + GF_ATOMIC_INC(next_xl->stats.total.count); \ + GF_ATOMIC_INC(next_xl->stats.interval.count); \ + } \ + \ + if (next_xl->pass_through) { \ + next_xl_fn = get_the_pt_fop(&next_xl->pass_through_fops->stat, \ + opn); \ + } \ + next_xl_fn(frame, next_xl, params); \ + THIS = old_THIS; \ + } while (0) + +/* make a call */ +#define STACK_WIND(frame, rfn, obj, fn, params...) \ + STACK_WIND_COMMON(frame, rfn, 0, NULL, obj, fn, params) + +/* make a call with a cookie */ +#define STACK_WIND_COOKIE(frame, rfn, cky, obj, fn, params...) \ + STACK_WIND_COMMON(frame, rfn, 1, cky, obj, fn, params) + +/* Cookie passed as the argument can be NULL (ptr) or 0 (int). Hence we + have to have a mechanism to separate out the two STACK_WIND formats. + Needed a common macro, as other than for cookie, all the other code + is common across. + */ +#define STACK_WIND_COMMON(frame, rfn, has_cookie, cky, obj, fn, params...) \ + do { \ + call_frame_t *_new = NULL; \ + xlator_t *old_THIS = NULL; \ + typeof(fn) next_xl_fn = fn; \ + \ + _new = mem_get0(frame->root->pool->frame_mem_pool); \ + if (!_new) { \ + break; \ + } \ + typeof(fn##_cbk) tmp_cbk = rfn; \ + _new->root = frame->root; \ + _new->this = obj; \ + _new->ret = (ret_fn_t)tmp_cbk; \ + _new->parent = frame; \ + /* (void *) is required for avoiding gcc warning */ \ + _new->cookie = ((has_cookie == 1) ? (void *)(cky) : (void *)_new); \ + _new->wind_from = __FUNCTION__; \ + _new->wind_to = #fn; \ + _new->unwind_to = #rfn; \ + LOCK_INIT(&_new->lock); \ + LOCK(&frame->root->stack_lock); \ + { \ + list_add(&_new->frames, &frame->root->myframes); \ + frame->ref_count++; \ + } \ + UNLOCK(&frame->root->stack_lock); \ + fn##_cbk = rfn; \ + old_THIS = THIS; \ + THIS = obj; \ + gf_msg_trace("stack-trace", 0, \ + "stack-address: %p, " \ + "winding from %s to %s", \ + frame->root, old_THIS->name, THIS->name); \ + if (obj->ctx->measure_latency) \ + timespec_now(&_new->begin); \ + _new->op = get_fop_index_from_fn((_new->this), (fn)); \ + if (!obj->pass_through) { \ + GF_ATOMIC_INC(obj->stats.total.metrics[_new->op].fop); \ + GF_ATOMIC_INC(obj->stats.interval.metrics[_new->op].fop); \ + GF_ATOMIC_INC(obj->stats.total.count); \ + GF_ATOMIC_INC(obj->stats.interval.count); \ + } else { \ + /* we want to get to the actual fop to call */ \ + next_xl_fn = get_the_pt_fop(&obj->pass_through_fops->stat, \ + _new->op); \ + } \ + next_xl_fn(_new, obj, params); \ + THIS = old_THIS; \ + } while (0) + +#define STACK_UNWIND STACK_UNWIND_STRICT + +/* return from function in type-safe way */ +#define STACK_UNWIND_STRICT(fop, frame, op_ret, op_errno, params...) \ + do { \ + fop_##fop##_cbk_t fn = NULL; \ + call_frame_t *_parent = NULL; \ + xlator_t *old_THIS = NULL; \ + \ + if (!frame) { \ + gf_msg("stack", GF_LOG_CRITICAL, 0, LG_MSG_FRAME_ERROR, "!frame"); \ + break; \ + } \ + if ((op_ret) < 0) { \ + gf_msg_debug("stack-trace", op_errno, \ + "stack-address: %p, " \ + "%s returned %d error: %s", \ + frame->root, THIS->name, (int32_t)(op_ret), \ + strerror(op_errno)); \ + } else { \ + gf_msg_trace("stack-trace", 0, \ + "stack-address: %p, " \ + "%s returned %d", \ + frame->root, THIS->name, (int32_t)(op_ret)); \ + } \ + fn = (fop_##fop##_cbk_t)frame->ret; \ + _parent = frame->parent; \ + LOCK(&frame->root->stack_lock); \ + { \ + _parent->ref_count--; \ + if ((op_ret) < 0 && (op_errno) != frame->root->error) { \ + frame->root->err_xl = frame->this; \ + frame->root->error = (op_errno); \ + } else if ((op_ret) == 0) { \ + frame->root->err_xl = NULL; \ + frame->root->error = 0; \ + } \ + } \ + UNLOCK(&frame->root->stack_lock); \ + old_THIS = THIS; \ + THIS = _parent->this; \ + frame->complete = _gf_true; \ + frame->unwind_from = __FUNCTION__; \ + if (frame->this->ctx->measure_latency) { \ + timespec_now(&frame->end); \ + /* required for top most xlator */ \ + if (_parent->ret == NULL) \ + timespec_now(&_parent->end); \ + } \ + if (op_ret < 0) { \ + GF_ATOMIC_INC(THIS->stats.total.metrics[frame->op].cbk); \ + GF_ATOMIC_INC(THIS->stats.interval.metrics[frame->op].cbk); \ + } \ + fn(_parent, frame->cookie, _parent->this, op_ret, op_errno, params); \ + THIS = old_THIS; \ + } 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 { + GF_FREE(stack->groups_large); + stack->groups_large = GF_CALLOC(ngrps, sizeof(gid_t), + gf_common_mt_groups_t); + if (!stack->groups_large) + return -1; + stack->groups = stack->groups_large; + } + + stack->ngrps = ngrps; + + return 0; +} + +static inline int +call_stack_groups_capacity(call_stack_t *stack) +{ + return max(stack->ngrps, SMALL_GROUP_COUNT); +} + +static inline int +call_frames_count(call_stack_t *call_stack) +{ + call_frame_t *pos; + int32_t count = 0; + + if (!call_stack) + return count; + + list_for_each_entry(pos, &call_stack->myframes, frames) count++; + + return count; +} + +static inline call_frame_t * +copy_frame(call_frame_t *frame) +{ + call_stack_t *newstack = NULL; + call_stack_t *oldstack = NULL; + call_frame_t *newframe = NULL; + + if (!frame) { + return NULL; + } + + newstack = mem_get0(frame->root->pool->stack_mem_pool); + if (newstack == NULL) { + return NULL; + } + + INIT_LIST_HEAD(&newstack->myframes); + + newframe = mem_get0(frame->root->pool->frame_mem_pool); + if (!newframe) { + mem_put(newstack); + return NULL; + } + + newframe->this = frame->this; + newframe->root = newstack; + INIT_LIST_HEAD(&newframe->frames); + list_add(&newframe->frames, &newstack->myframes); + + oldstack = frame->root; + + newstack->uid = oldstack->uid; + newstack->gid = oldstack->gid; + newstack->pid = oldstack->pid; + newstack->op = oldstack->op; + newstack->type = oldstack->type; + newstack->ctime = oldstack->ctime; + newstack->flags = oldstack->flags; + if (call_stack_alloc_groups(newstack, oldstack->ngrps) != 0) { + mem_put(newstack); + return NULL; + } + if (!oldstack->groups) { + gf_msg_debug("stack", EINVAL, "groups is null (ngrps: %d)", + oldstack->ngrps); + /* Considering 'groups' is NULL, set ngrps to 0 */ + oldstack->ngrps = 0; + + if (oldstack->groups_large) + oldstack->groups = oldstack->groups_large; + else + oldstack->groups = oldstack->groups_small; + } + newstack->ngrps = oldstack->ngrps; + memcpy(newstack->groups, oldstack->groups, sizeof(gid_t) * oldstack->ngrps); + newstack->unique = oldstack->unique; + newstack->pool = oldstack->pool; + newstack->lk_owner = oldstack->lk_owner; + newstack->ctx = oldstack->ctx; + + if (newstack->ctx->measure_latency) { + timespec_now(&newstack->tv); + memcpy(&newframe->begin, &newstack->tv, sizeof(newstack->tv)); + } + + LOCK_INIT(&newframe->lock); + LOCK_INIT(&newstack->stack_lock); + + LOCK(&oldstack->pool->lock); + { + list_add(&newstack->all_frames, &oldstack->all_frames); + newstack->pool->cnt++; + } + UNLOCK(&oldstack->pool->lock); + GF_ATOMIC_INC(newstack->pool->total_count); + + return newframe; +} + +void +call_stack_set_groups(call_stack_t *stack, int ngrps, gid_t **groupbuf_p); +void +gf_proc_dump_pending_frames(call_pool_t *call_pool); +void +gf_proc_dump_pending_frames_to_dict(call_pool_t *call_pool, dict_t *dict); +call_frame_t * +create_frame(xlator_t *xl, call_pool_t *pool); +gf_boolean_t +__is_fuse_call(call_frame_t *frame); +#endif /* _STACK_H */ diff --git a/libglusterfs/src/glusterfs/statedump.h b/libglusterfs/src/glusterfs/statedump.h new file mode 100644 index 00000000000..ce082706bdf --- /dev/null +++ b/libglusterfs/src/glusterfs/statedump.h @@ -0,0 +1,132 @@ +/* + 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 STATEDUMP_H +#define STATEDUMP_H + +#include <stdarg.h> +#include "glusterfs/inode.h" +#include "glusterfs/strfd.h" + +#define GF_DUMP_MAX_BUF_LEN 4096 + +typedef struct gf_dump_xl_options_ { + gf_boolean_t dump_priv; + gf_boolean_t dump_inode; + gf_boolean_t dump_fd; + gf_boolean_t dump_inodectx; + gf_boolean_t dump_fdctx; + gf_boolean_t dump_history; +} gf_dump_xl_options_t; + +typedef struct gf_dump_options_ { + gf_boolean_t dump_mem; + gf_boolean_t dump_iobuf; + gf_boolean_t dump_callpool; + gf_dump_xl_options_t xl_options; // options for all xlators + char *dump_path; +} gf_dump_options_t; + +extern gf_dump_options_t dump_options; + +__attribute__((__format__(__printf__, 3, 4))) static inline void +_gf_proc_dump_build_key(char *key, const char *prefix, const char *fmt, ...) +{ + va_list ap; + int32_t len; + + len = snprintf(key, GF_DUMP_MAX_BUF_LEN, "%s.", prefix); + if (len >= 0) { + va_start(ap, fmt); + len = vsnprintf(key + len, GF_DUMP_MAX_BUF_LEN - len, fmt, ap); + va_end(ap); + } + if (len < 0) { + *key = 0; + } +} + +#define gf_proc_dump_build_key(key, key_prefix, fmt...) \ + { \ + _gf_proc_dump_build_key(key, key_prefix, ##fmt); \ + } + +#define GF_PROC_DUMP_SET_OPTION(opt, val) opt = val + +#define GF_CHECK_DUMP_OPTION_ENABLED(option_dump, var, label) \ + do { \ + if (option_dump == _gf_true) { \ + var = _gf_false; \ + goto label; \ + } \ + } while (0); + +void +gf_proc_dump_init(); + +void +gf_proc_dump_fini(void); + +void +gf_proc_dump_cleanup(void); + +void +gf_proc_dump_info(int signum, glusterfs_ctx_t *ctx); + +int +gf_proc_dump_add_section(char *key, ...) + __attribute__((__format__(__printf__, 1, 2))); + +int +gf_proc_dump_write(char *key, char *value, ...) + __attribute__((__format__(__printf__, 2, 3))); + +void +inode_table_dump(inode_table_t *itable, char *prefix); + +void +inode_table_dump_to_dict(inode_table_t *itable, char *prefix, dict_t *dict); + +void +fdtable_dump(fdtable_t *fdtable, char *prefix); + +void +fdtable_dump_to_dict(fdtable_t *fdtable, char *prefix, dict_t *dict); + +void +inode_dump(inode_t *inode, char *prefix); + +void +gf_proc_dump_mem_info_to_dict(dict_t *dict); + +void +gf_proc_dump_mempool_info_to_dict(glusterfs_ctx_t *ctx, dict_t *dict); + +void +glusterd_init(int sig); + +void +gf_proc_dump_xlator_private(xlator_t *this, strfd_t *strfd); + +void +gf_proc_dump_mallinfo(strfd_t *strfd); + +void +gf_proc_dump_xlator_history(xlator_t *this, strfd_t *strfd); + +void +gf_proc_dump_xlator_meminfo(xlator_t *this, strfd_t *strfd); + +void +gf_proc_dump_xlator_profile(xlator_t *this, strfd_t *strfd); + +void +gf_latency_statedump_and_reset(char *key, gf_latency_t *lat); +#endif /* STATEDUMP_H */ diff --git a/libglusterfs/src/glusterfs/store.h b/libglusterfs/src/glusterfs/store.h new file mode 100644 index 00000000000..a1f70c7b840 --- /dev/null +++ b/libglusterfs/src/glusterfs/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_ + +#include "glusterfs/compat.h" +#include "glusterfs/glusterfs.h" + +struct gf_store_handle_ { + char *path; + int fd; + int tmp_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 **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_save_items(int fd, char *items); + +int32_t +gf_store_handle_new(const 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/glusterfs/strfd.h b/libglusterfs/src/glusterfs/strfd.h new file mode 100644 index 00000000000..861cd02e005 --- /dev/null +++ b/libglusterfs/src/glusterfs/strfd.h @@ -0,0 +1,34 @@ +/* + Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _STRFD_H +#define _STRFD_H + +typedef struct { + void *data; + size_t alloc_size; + size_t size; + off_t pos; +} strfd_t; + +strfd_t * +strfd_open(); + +int +strprintf(strfd_t *strfd, const char *fmt, ...) + __attribute__((__format__(__printf__, 2, 3))); + +int +strvprintf(strfd_t *strfd, const char *fmt, va_list ap); + +int +strfd_close(strfd_t *strfd); + +#endif diff --git a/libglusterfs/src/glusterfs/syncop-utils.h b/libglusterfs/src/glusterfs/syncop-utils.h new file mode 100644 index 00000000000..1f3ee403edc --- /dev/null +++ b/libglusterfs/src/glusterfs/syncop-utils.h @@ -0,0 +1,54 @@ +/* + Copyright (c) 2015, Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _SYNCOP_UTILS_H +#define _SYNCOP_UTILS_H + +typedef int (*syncop_dir_scan_fn_t)(xlator_t *subvol, gf_dirent_t *entry, + loc_t *parent, void *data); +int +syncop_ftw(xlator_t *subvol, loc_t *loc, int pid, void *data, + int (*fn)(xlator_t *subvol, gf_dirent_t *entry, loc_t *parent, + void *data)); + +int +syncop_mt_dir_scan(call_frame_t *frame, xlator_t *subvol, loc_t *loc, int pid, + void *data, syncop_dir_scan_fn_t fn, dict_t *xdata, + uint32_t max_jobs, uint32_t max_qlen); + +int +syncop_dir_scan(xlator_t *subvol, loc_t *loc, int pid, void *data, + int (*fn)(xlator_t *subvol, gf_dirent_t *entry, loc_t *parent, + void *data)); + +int +syncop_dirfd(xlator_t *subvol, loc_t *loc, fd_t **fd, int pid); + +int +syncop_is_subvol_local(xlator_t *this, loc_t *loc, gf_boolean_t *is_local); + +int +syncop_gfid_to_path(inode_table_t *itable, xlator_t *subvol, uuid_t gfid, + char **path_p); + +int +syncop_ftw_throttle(xlator_t *subvol, loc_t *loc, int pid, void *data, + int (*fn)(xlator_t *subvol, gf_dirent_t *entry, + loc_t *parent, void *data), + int count, int sleep_time); +int +syncop_inode_find(xlator_t *this, xlator_t *subvol, uuid_t gfid, + inode_t **inode, dict_t *xdata, dict_t **rsp_dict); + +int +syncop_gfid_to_path_hard(inode_table_t *itable, xlator_t *subvol, uuid_t gfid, + inode_t *inode, char **path_p, + gf_boolean_t hard_resolve); +#endif /* _SYNCOP_H */ diff --git a/libglusterfs/src/glusterfs/syncop.h b/libglusterfs/src/glusterfs/syncop.h new file mode 100644 index 00000000000..4e9241a32fc --- /dev/null +++ b/libglusterfs/src/glusterfs/syncop.h @@ -0,0 +1,718 @@ +/* + 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 _SYNCOP_H +#define _SYNCOP_H + +#include <sys/time.h> +#include <pthread.h> +#include <ucontext.h> +#include "glusterfs/dict.h" // for dict_t +#include "glusterfs/stack.h" // for call_frame_t, STACK_DESTROY, STACK_... +#include "glusterfs/timer.h" + +#define SYNCENV_PROC_MAX 16 +#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 +#define SYNCOPCTX_PID 0x00000008 +#define SYNCOPCTX_LKOWNER 0x00000010 + +#ifdef HAVE_TSAN_API +/* Currently hardcoded within thread context maintained by the sanitizer. */ +#define TSAN_THREAD_NAMELEN 64 +#endif + +struct synctask; +struct syncproc; +struct syncenv; +struct synccond; + +typedef int (*synctask_cbk_t)(int ret, call_frame_t *frame, void *opaque); + +typedef int (*synctask_fn_t)(void *opaque); + +typedef enum { + SYNCTASK_INIT = 0, + SYNCTASK_RUN, + SYNCTASK_SUSPEND, + SYNCTASK_WAIT, + SYNCTASK_DONE, + SYNCTASK_ZOMBIE, +} synctask_state_t; + +/* for one sequential execution of @syncfn */ +struct synctask { + struct list_head all_tasks; + struct syncenv *env; + xlator_t *xl; + call_frame_t *frame; + call_frame_t *opframe; + synctask_cbk_t synccbk; + synctask_fn_t syncfn; + struct timespec *delta; + gf_timer_t *timer; + struct synccond *synccond; + void *opaque; + void *stack; + synctask_state_t state; + int woken; + int slept; + int ret; + + uid_t uid; + gid_t gid; + +#ifdef HAVE_TSAN_API + struct { + void *fiber; + char name[TSAN_THREAD_NAMELEN]; + } tsan; +#endif + + ucontext_t ctx; + struct syncproc *proc; + + pthread_mutex_t mutex; /* for synchronous spawning of synctask */ + pthread_cond_t cond; + int done; + + struct list_head waitq; /* can wait only "once" at a time */ +}; + +struct syncproc { + pthread_t processor; + +#ifdef HAVE_TSAN_API + struct { + void *fiber; + char name[TSAN_THREAD_NAMELEN]; + } tsan; +#endif + + ucontext_t sched; + struct syncenv *env; + struct synctask *current; +}; + +/* hosts the scheduler thread and framework for executing synctasks */ +struct syncenv { + struct syncproc proc[SYNCENV_PROC_MAX]; + + pthread_mutex_t mutex; + pthread_cond_t cond; + + struct list_head runq; + struct list_head waitq; + + int procs; + int procs_idle; + + int runcount; + + int procmin; + int procmax; + + size_t stacksize; + + int destroy; /* FLAG to mark syncenv is in destroy mode + so that no more synctasks are accepted*/ +}; + +typedef enum { LOCK_NULL = 0, LOCK_TASK, LOCK_THREAD } lock_type_t; + +typedef enum { + SYNC_LOCK_DEFAULT = 0, + SYNC_LOCK_RECURSIVE, /*it allows recursive locking*/ +} lock_attr_t; + +struct synclock { + pthread_mutex_t guard; /* guard the remaining members, pair @cond */ + pthread_cond_t cond; /* waiting non-synctasks */ + struct list_head waitq; /* waiting synctasks */ + volatile int lock; /* true(non zero) or false(zero), lock status */ + lock_attr_t attr; + struct synctask *owner; /* NULL if current owner is not a synctask */ + pthread_t owner_tid; + lock_type_t type; +}; +typedef struct synclock synclock_t; + +struct synccond { + pthread_mutex_t pmutex; + pthread_cond_t pcond; + struct list_head waitq; +}; +typedef struct synccond synccond_t; + +struct syncbarrier { + gf_boolean_t initialized; /*Set on successful initialization*/ + pthread_mutex_t guard; /* guard the remaining members, pair @cond */ + pthread_cond_t cond; /* waiting non-synctasks */ + struct list_head waitq; /* waiting synctasks */ + int count; /* count the number of wakes */ + int waitfor; /* no. of wakes until which task can be in + waitq before being woken up. */ +}; +typedef struct syncbarrier syncbarrier_t; + +struct syncargs { + int op_ret; + int op_errno; + + /* + * The below 3 iatt structures are used in the fops + * whose callbacks get struct iatt as one of the + * a return arguments. Currently, the maximum number + * of iatt structures returned is 3 for some fops + * such as mknod, copy_file_range, mkdir etc. So + * all the following 3 iatt structures would be used + * for those fops. + */ + struct iatt iatt1; + struct iatt iatt2; + struct iatt iatt3; + dict_t *xattr; + struct statvfs statvfs_buf; + struct iovec *vector; + int count; + struct iobref *iobref; + char *buffer; + dict_t *xdata; + struct gf_flock flock; + struct gf_lease lease; + dict_t *dict_out; + + /* some more _cbk needs */ + uuid_t uuid; + char *errstr; + dict_t *dict; + pthread_mutex_t lock_dict; + + syncbarrier_t barrier; + + /* do not touch */ + struct synctask *task; + pthread_mutex_t mutex; + pthread_cond_t cond; + int done; + + gf_dirent_t entries; + off_t offset; + + lock_migration_info_t locklist; +}; + +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; + pid_t pid; + gf_lkowner_t lk_owner; +}; + +#define __yawn(args) \ + do { \ + args->task = synctask_get(); \ + if (args->task) \ + break; \ + pthread_mutex_init(&args->mutex, NULL); \ + pthread_cond_init(&args->cond, NULL); \ + args->done = 0; \ + } while (0) + +#define __wake(args) \ + do { \ + if (args->task) { \ + synctask_wake(args->task); \ + } else { \ + pthread_mutex_lock(&args->mutex); \ + { \ + args->done = 1; \ + pthread_cond_signal(&args->cond); \ + } \ + pthread_mutex_unlock(&args->mutex); \ + } \ + } while (0) + +#define __yield(args) \ + do { \ + if (args->task) { \ + synctask_yield(args->task, NULL); \ + } else { \ + pthread_mutex_lock(&args->mutex); \ + { \ + while (!args->done) \ + pthread_cond_wait(&args->cond, &args->mutex); \ + } \ + pthread_mutex_unlock(&args->mutex); \ + pthread_mutex_destroy(&args->mutex); \ + pthread_cond_destroy(&args->cond); \ + } \ + } while (0) + +#define SYNCOP(subvol, stb, cbk, fn_op, params...) \ + do { \ + struct synctask *task = NULL; \ + call_frame_t *frame = NULL; \ + \ + task = synctask_get(); \ + stb->task = task; \ + if (task) \ + frame = copy_frame(task->opframe); \ + else \ + frame = syncop_create_frame(THIS); \ + \ + if (!frame) { \ + stb->op_ret = -1; \ + stb->op_errno = errno; \ + break; \ + } \ + \ + if (task) { \ + frame->root->uid = task->uid; \ + frame->root->gid = task->gid; \ + } \ + \ + __yawn(stb); \ + \ + frame->op = get_fop_index_from_fn(subvol, fn_op); \ + STACK_WIND_COOKIE(frame, cbk, (void *)stb, subvol, fn_op, params); \ + \ + __yield(stb); \ + STACK_DESTROY(frame->root); \ + } while (0) + +/* + * syncop_xxx() calls are executed in two ways, one is inside a synctask where + * the executing function will do 'swapcontext' and the other is without + * synctask where the executing thread is made to wait using pthread_cond_wait. + * Executing thread may change when syncop_xxx() is executed inside a synctask. + * This leads to errno_location change i.e. errno may give errno of + * non-executing thread. So errno is not touched inside a synctask execution. + * All gfapi calls are executed using the second way of executing syncop_xxx() + * where the executing thread waits using pthread_cond_wait so it is ok to set + * errno in these cases. The following macro makes syncop_xxx() behave just + * like a system call, where -1 is returned and errno is set when a failure + * occurs. + */ +#define DECODE_SYNCOP_ERR(ret) \ + do { \ + if (ret < 0) { \ + errno = -ret; \ + ret = -1; \ + } else { \ + errno = 0; \ + } \ + } while (0) + +#define SYNCENV_DEFAULT_STACKSIZE (2 * 1024 * 1024) + +struct syncenv * +syncenv_new(size_t stacksize, int procmin, int procmax); +void +syncenv_destroy(struct syncenv *); +void +syncenv_scale(struct syncenv *env); + +int +synctask_new1(struct syncenv *, size_t stacksize, synctask_fn_t, synctask_cbk_t, + call_frame_t *frame, void *); +int +synctask_new(struct syncenv *, synctask_fn_t, synctask_cbk_t, + call_frame_t *frame, void *); +struct synctask * +synctask_create(struct syncenv *, size_t stacksize, 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, struct timespec *delta); +void +synctask_sleep(int32_t secs); +void +synctask_waitfor(struct synctask *task, int count); + +#define synctask_barrier_init(args) syncbarrier_init(&args->barrier) +#define synctask_barrier_wait(args, n) syncbarrier_wait(&args->barrier, n) +#define synctask_barrier_wake(args) syncbarrier_wake(&args->barrier) + +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); +int +syncopctx_setfspid(void *pid); +int +syncopctx_setfslkowner(gf_lkowner_t *lk_owner); + +static inline call_frame_t * +syncop_create_frame(xlator_t *this) +{ + 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->type = GF_OP_TYPE_FOP; + opctx = syncopctx_getctx(); + + if (opctx && (opctx->valid & SYNCOPCTX_PID)) + frame->root->pid = opctx->pid; + else + frame->root->pid = getpid(); + + 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; + } + } + + if (opctx && (opctx->valid & SYNCOPCTX_LKOWNER)) + frame->root->lk_owner = opctx->lk_owner; + + return frame; +} + +int +synclock_init(synclock_t *lock, lock_attr_t attr); +int +synclock_destroy(synclock_t *lock); +int +synclock_lock(synclock_t *lock); +int +synclock_trylock(synclock_t *lock); +int +synclock_unlock(synclock_t *lock); + +int32_t +synccond_init(synccond_t *cond); + +void +synccond_destroy(synccond_t *cond); + +int +synccond_wait(synccond_t *cond, synclock_t *lock); + +int +synccond_timedwait(synccond_t *cond, synclock_t *lock, struct timespec *delta); + +void +synccond_signal(synccond_t *cond); + +void +synccond_broadcast(synccond_t *cond); + +int +syncbarrier_init(syncbarrier_t *barrier); +int +syncbarrier_wait(syncbarrier_t *barrier, int waitfor); +int +syncbarrier_wake(syncbarrier_t *barrier); +int +syncbarrier_destroy(syncbarrier_t *barrier); + +int +syncop_lookup(xlator_t *subvol, loc_t *loc, + /* out */ + struct iatt *iatt, struct iatt *parent, + /* xdata */ + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_readdirp(xlator_t *subvol, fd_t *fd, size_t size, off_t off, + /* out */ + gf_dirent_t *entries, dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_readdir(xlator_t *subvol, fd_t *fd, size_t size, off_t off, + gf_dirent_t *entries, dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_opendir(xlator_t *subvol, loc_t *loc, fd_t *fd, dict_t *xdata_in, + dict_t **xdata_out); + +int +syncop_setattr(xlator_t *subvol, loc_t *loc, struct iatt *iatt, int valid, + /* out */ + struct iatt *preop, struct iatt *postop, dict_t *xdata_in, + dict_t **xdata_out); + +int +syncop_fsetattr(xlator_t *subvol, fd_t *fd, struct iatt *iatt, int valid, + /* out */ + struct iatt *preop, struct iatt *postop, dict_t *xdata_in, + dict_t **xdata_out); + +int +syncop_statfs(xlator_t *subvol, loc_t *loc, + /* out */ + struct statvfs *buf, dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_setxattr(xlator_t *subvol, loc_t *loc, dict_t *dict, int32_t flags, + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_fsetxattr(xlator_t *subvol, fd_t *fd, dict_t *dict, int32_t flags, + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_listxattr(xlator_t *subvol, loc_t *loc, dict_t **dict, dict_t *xdata_in, + dict_t **xdata_out); + +int +syncop_getxattr(xlator_t *xl, loc_t *loc, dict_t **dict, const char *key, + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_fgetxattr(xlator_t *xl, fd_t *fd, dict_t **dict, const char *key, + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_removexattr(xlator_t *subvol, loc_t *loc, const char *name, + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_fremovexattr(xlator_t *subvol, fd_t *fd, const char *name, + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_create(xlator_t *subvol, loc_t *loc, int32_t flags, mode_t mode, + fd_t *fd, struct iatt *iatt, dict_t *xdata_in, + dict_t **xdata_out); + +int +syncop_open(xlator_t *subvol, loc_t *loc, int32_t flags, fd_t *fd, + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_close(fd_t *fd); + +int +syncop_write(xlator_t *subvol, fd_t *fd, const char *buf, int size, + off_t offset, struct iobref *iobref, uint32_t flags, + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_writev(xlator_t *subvol, fd_t *fd, const struct iovec *vector, + int32_t count, off_t offset, struct iobref *iobref, + uint32_t flags, struct iatt *preiatt, struct iatt *postiatt, + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_readv(xlator_t *subvol, fd_t *fd, size_t size, off_t off, uint32_t flags, + /* out */ + struct iovec **vector, int *count, struct iobref **iobref, + struct iatt *iatt, dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_ftruncate(xlator_t *subvol, fd_t *fd, off_t offset, struct iatt *preiatt, + struct iatt *postiatt, dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_truncate(xlator_t *subvol, loc_t *loc, off_t offset, dict_t *xdata_in, + dict_t **xdata_out); + +int +syncop_unlink(xlator_t *subvol, loc_t *loc, dict_t *xdata_in, + dict_t **xdata_out); + +int +syncop_rmdir(xlator_t *subvol, loc_t *loc, int flags, dict_t *xdata_in, + dict_t **xdata_out); + +int +syncop_fsync(xlator_t *subvol, fd_t *fd, int dataonly, struct iatt *preiatt, + struct iatt *postiatt, dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_flush(xlator_t *subvol, fd_t *fd, dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_fstat(xlator_t *subvol, fd_t *fd, struct iatt *stbuf, dict_t *xdata_in, + dict_t **xdata_out); + +int +syncop_stat(xlator_t *subvol, loc_t *loc, struct iatt *stbuf, dict_t *xdata_in, + dict_t **xdata_out); + +int +syncop_symlink(xlator_t *subvol, loc_t *loc, const char *newpath, + struct iatt *iatt, dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_readlink(xlator_t *subvol, loc_t *loc, char **buffer, size_t size, + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_mknod(xlator_t *subvol, loc_t *loc, mode_t mode, dev_t rdev, + struct iatt *iatt, dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_mkdir(xlator_t *subvol, loc_t *loc, mode_t mode, struct iatt *iatt, + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_link(xlator_t *subvol, loc_t *oldloc, loc_t *newloc, struct iatt *iatt, + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_fsyncdir(xlator_t *subvol, fd_t *fd, int datasync, dict_t *xdata_in, + dict_t **xdata_out); + +int +syncop_access(xlator_t *subvol, loc_t *loc, int32_t mask, dict_t *xdata_in, + dict_t **xdata_out); + +int +syncop_fallocate(xlator_t *subvol, fd_t *fd, int32_t keep_size, off_t offset, + size_t len, dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_discard(xlator_t *subvol, fd_t *fd, off_t offset, size_t len, + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_zerofill(xlator_t *subvol, fd_t *fd, off_t offset, off_t len, + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_rename(xlator_t *subvol, loc_t *oldloc, loc_t *newloc, dict_t *xdata_in, + dict_t **xdata_out); + +int +syncop_lk(xlator_t *subvol, fd_t *fd, int cmd, struct gf_flock *flock, + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_inodelk(xlator_t *subvol, const char *volume, loc_t *loc, int32_t cmd, + struct gf_flock *lock, dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_lease(xlator_t *subvol, loc_t *loc, struct gf_lease *lease, + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_ipc(xlator_t *subvol, int op, dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_xattrop(xlator_t *subvol, loc_t *loc, gf_xattrop_flags_t flags, + dict_t *dict, dict_t *xdata_in, dict_t **dict_out, + dict_t **xdata_out); + +int +syncop_fxattrop(xlator_t *subvol, fd_t *fd, gf_xattrop_flags_t flags, + dict_t *dict, dict_t *xdata_in, dict_t **dict_out, + dict_t **xdata_out); + +int +syncop_seek(xlator_t *subvol, fd_t *fd, off_t offset, gf_seek_what_t what, + dict_t *xdata_in, off_t *off); + +int +syncop_getactivelk(xlator_t *subvol, loc_t *loc, + lock_migration_info_t *locklist, dict_t *xdata_in, + dict_t **xdata_out); + +int +syncop_setactivelk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int +syncop_setactivelk(xlator_t *subvol, loc_t *loc, + lock_migration_info_t *locklist, dict_t *xdata_in, + dict_t **xdata_out); + +int +syncop_put(xlator_t *subvol, loc_t *loc, mode_t mode, mode_t umask, + uint32_t flags, struct iovec *vector, int32_t count, off_t offset, + struct iobref *iobref, dict_t *xattr, struct iatt *iatt, + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_setactivelk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata); + +int +syncop_icreate(xlator_t *subvol, loc_t *loc, mode_t mode, dict_t *xdata_out); + +int +syncop_entrylk(xlator_t *subvol, const char *volume, loc_t *loc, + const char *basename, entrylk_cmd cmd, entrylk_type type, + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_copy_file_range(xlator_t *subvol, fd_t *fd_in, off64_t off_in, + fd_t *fd_out, off64_t off_out, size_t len, + uint32_t flags, struct iatt *stbuf, + struct iatt *preiatt_dst, struct iatt *postiatt_dst, + dict_t *xdata_in, dict_t **xdata_out); + +int +syncop_copy_file_range_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, struct iatt *stbuf, + struct iatt *prebuf_dst, struct iatt *postbuf_dst, + dict_t *xdata); + +#endif /* _SYNCOP_H */ diff --git a/libglusterfs/src/glusterfs/syscall.h b/libglusterfs/src/glusterfs/syscall.h new file mode 100644 index 00000000000..b6d3ab4f2ad --- /dev/null +++ b/libglusterfs/src/glusterfs/syscall.h @@ -0,0 +1,278 @@ +/* + 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 __SYSCALL_H__ +#define __SYSCALL_H__ + +#include <dirent.h> +#include <sys/uio.h> +#include <sys/statvfs.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <stdio.h> + +/* GF follows the Linux XATTR definition, which differs in Darwin. */ +#define GF_XATTR_CREATE 0x1 /* set value, fail if attr already exists */ +#define GF_XATTR_REPLACE 0x2 /* set value, fail if attr does not exist */ + +/* Linux kernel version 2.6.x don't have these defined + define if not defined */ + +#ifndef XATTR_SECURITY_PREFIX +#define XATTR_SECURITY_PREFIX "security." +#define XATTR_SECURITY_PREFIX_LEN (sizeof(XATTR_SECURITY_PREFIX) - 1) +#endif + +#ifndef XATTR_SYSTEM_PREFIX +#define XATTR_SYSTEM_PREFIX "system." +#define XATTR_SYSTEM_PREFIX_LEN (sizeof(XATTR_SYSTEM_PREFIX) - 1) +#endif + +#ifndef XATTR_TRUSTED_PREFIX +#define XATTR_TRUSTED_PREFIX "trusted." +#define XATTR_TRUSTED_PREFIX_LEN (sizeof(XATTR_TRUSTED_PREFIX) - 1) +#endif + +#ifndef XATTR_USER_PREFIX +#define XATTR_USER_PREFIX "user." +#define XATTR_USER_PREFIX_LEN (sizeof(XATTR_USER_PREFIX) - 1) +#endif + +#if defined(GF_DARWIN_HOST_OS) +#include <sys/xattr.h> +#define XATTR_DARWIN_NOSECURITY XATTR_NOSECURITY +#define XATTR_DARWIN_NODEFAULT XATTR_NODEFAULT +#define XATTR_DARWIN_SHOWCOMPRESSION XATTR_SHOWCOMPRESSION +#endif + +int +sys_lstat(const char *path, struct stat *buf); + +int +sys_stat(const char *path, struct stat *buf); + +int +sys_fstat(int fd, struct stat *buf); + +int +sys_fstatat(int dirfd, const char *pathname, struct stat *buf, int flags); + +int +sys_open(const char *pathname, int flags, int mode); + +int +sys_openat(int dirfd, const char *pathname, int flags, int mode); + +DIR * +sys_opendir(const char *name); + +struct dirent * +sys_readdir(DIR *dir, struct dirent *de); + +ssize_t +sys_readlink(const char *path, char *buf, size_t bufsiz); + +int +sys_closedir(DIR *dir); + +int +sys_mknod(const char *pathname, mode_t mode, dev_t dev); + +int +sys_mkdir(const char *pathname, mode_t mode); + +int +sys_mkdirat(int dirfd, const char *pathname, mode_t mode); + +int +sys_unlink(const char *pathname); + +int +sys_unlinkat(int dfd, const char *pathname); + +int +sys_rmdir(const char *pathname); + +int +sys_symlink(const char *oldpath, const char *newpath); + +int +sys_symlinkat(const char *oldpath, int dirfd, const char *newpath); + +int +sys_rename(const char *oldpath, const char *newpath); + +int +sys_link(const char *oldpath, const char *newpath); + +int +sys_linkat(int oldfd, const char *oldpath, int newfd, const char *newpath); + +int +sys_chmod(const char *path, mode_t mode); + +int +sys_fchmod(int fd, mode_t mode); + +int +sys_chown(const char *path, uid_t owner, gid_t group); + +int +sys_fchown(int fd, uid_t owner, gid_t group); + +int +sys_lchown(const char *path, uid_t owner, gid_t group); + +int +sys_truncate(const char *path, off_t length); + +int +sys_ftruncate(int fd, off_t length); + +int +sys_utimes(const char *filename, const struct timeval times[2]); + +#if defined(HAVE_UTIMENSAT) +int +sys_utimensat(int dirfd, const char *filename, const struct timespec times[2], + int flags); +#endif + +int +sys_futimes(int fd, const struct timeval times[2]); + +int +sys_creat(const char *pathname, mode_t mode); + +ssize_t +sys_readv(int fd, const struct iovec *iov, int iovcnt); + +ssize_t +sys_writev(int fd, const struct iovec *iov, int iovcnt); + +ssize_t +sys_read(int fd, void *buf, size_t count); + +ssize_t +sys_write(int fd, const void *buf, size_t count); + +off_t +sys_lseek(int fd, off_t offset, int whence); + +int +sys_statvfs(const char *path, struct statvfs *buf); + +int +sys_fstatvfs(int fd, struct statvfs *buf); + +int +sys_close(int fd); + +int +sys_fsync(int fd); + +int +sys_fdatasync(int fd); + +void +gf_add_prefix(const char *ns, const char *key, char **newkey); + +void +gf_remove_prefix(const char *ns, const char *key, char **newkey); + +int +sys_lsetxattr(const char *path, const char *name, const void *value, + size_t size, int flags); + +ssize_t +sys_llistxattr(const char *path, char *list, size_t size); + +ssize_t +sys_lgetxattr(const char *path, const char *name, void *value, size_t size); + +ssize_t +sys_fgetxattr(int filedes, const char *name, void *value, size_t size); + +int +sys_fsetxattr(int filedes, const char *name, const void *value, size_t size, + int flags); + +ssize_t +sys_flistxattr(int filedes, char *list, size_t size); + +int +sys_lremovexattr(const char *path, const char *name); + +int +sys_fremovexattr(int filedes, const char *name); + +int +sys_access(const char *pathname, int mode); + +int +sys_fallocate(int fd, int mode, off_t offset, off_t len); + +ssize_t +sys_preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset); + +ssize_t +sys_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset); + +ssize_t +sys_pread(int fd, void *buf, size_t count, off_t offset); + +ssize_t +sys_pwrite(int fd, const void *buf, size_t count, off_t offset); + +int +sys_socket(int domain, int type, int protocol); + +int +sys_accept(int sock, struct sockaddr *sockaddr, socklen_t *socklen, int flags); + +#ifdef GF_BSD_HOST_OS +#ifndef _OFF64_T_DECLARED +/* + * Including <stdio.h> (done above) should actually define + * _OFF64_T_DECLARED with off64_t data type being available + * for consumption. But, off64_t data type is not recognizable + * for FreeBSD versions less than 11. Hence, int64_t is typedefed + * to off64_t. + */ +#define _OFF64_T_DECLARED +typedef int64_t off64_t; +#endif /* _OFF64_T_DECLARED */ +#endif /* GF_BSD_HOST_OS */ + +/* + * According to the man page of copy_file_range, both off_in and off_out are + * pointers to the data type loff_t (i.e. loff_t *). But, freebsd does not + * have (and recognize) loff_t. Since loff_t is 64 bits, use off64_t + * instead. Since it's a pointer type it should be okay. It just needs + * to be a pointer-to-64-bit pointer for both 32- and 64-bit platforms. + * off64_t is recognized by freebsd. + * TODO: In future, when freebsd can recognize loff_t, probably revisit this + * and change the off_in and off_out to (loff_t *). + */ +ssize_t +sys_copy_file_range(int fd_in, off64_t *off_in, int fd_out, off64_t *off_out, + size_t len, unsigned int flags); + +int +sys_kill(pid_t pid, int sig); + +#ifdef __FreeBSD__ +int +sys_sysctl(const int *name, u_int namelen, void *oldp, size_t *oldlenp, + const void *newp, size_t newlen); +#endif + +#endif /* __SYSCALL_H__ */ diff --git a/libglusterfs/src/glusterfs/template-component-messages.h b/libglusterfs/src/glusterfs/template-component-messages.h new file mode 100644 index 00000000000..aa7ad3d1baa --- /dev/null +++ b/libglusterfs/src/glusterfs/template-component-messages.h @@ -0,0 +1,28 @@ +/* + 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 _component_MESSAGES_H_ +#define _component_MESSAGES_H_ + +#include "glusterfs/glfs-message-id.h" + +/* To add new message IDs, append new identifiers at the end of the list. + * + * Never remove a message ID. If it's not used anymore, you can rename it or + * leave it as it is, but not delete it. This is to prevent reutilization of + * IDs by other messages. + * + * The component name must match one of the entries defined in + * glfs-message-id.h. + */ + +GLFS_MSGID(component, message id, message id, ...); + +#endif /* !_component_MESSAGES_H_ */ diff --git a/libglusterfs/src/glusterfs/throttle-tbf.h b/libglusterfs/src/glusterfs/throttle-tbf.h new file mode 100644 index 00000000000..cccb13c83d9 --- /dev/null +++ b/libglusterfs/src/glusterfs/throttle-tbf.h @@ -0,0 +1,74 @@ +/* + Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include "glusterfs/list.h" +#include "glusterfs/xlator.h" +#include "glusterfs/locking.h" + +#ifndef THROTTLE_TBF_H__ +#define THROTTLE_TBF_H__ + +typedef enum tbf_ops { + TBF_OP_MIN = -1, + TBF_OP_HASH = 0, /* checksum calculation */ + TBF_OP_READ = 1, /* inode read(s) */ + TBF_OP_READDIR = 2, /* dentry read(s) */ + TBF_OP_MAX = 3, +} tbf_ops_t; + +/** + * Operation rate specification + */ +typedef struct tbf_opspec { + tbf_ops_t op; + + unsigned long rate; + + unsigned long maxlimit; + + unsigned long token_gen_interval; /* Token generation interval in usec */ +} tbf_opspec_t; + +/** + * Token bucket for each operation type + */ +typedef struct tbf_bucket { + gf_lock_t lock; + + pthread_t tokener; /* token generator thread */ + + unsigned long tokenrate; /* token generation rate */ + + unsigned long tokens; /* number of current tokens */ + + unsigned long maxtokens; /* maximum token in the bucket */ + + struct list_head queued; /* list of non-conformant requests */ + + unsigned long token_gen_interval; /* Token generation interval in usec */ +} tbf_bucket_t; + +typedef struct tbf { + tbf_bucket_t **bucket; +} tbf_t; + +tbf_t * +tbf_init(tbf_opspec_t *, unsigned int); + +int +tbf_mod(tbf_t *, tbf_opspec_t *); + +void +tbf_throttle(tbf_t *, tbf_ops_t, unsigned long); + +#define TBF_THROTTLE_BEGIN(tbf, op, tokens) (tbf_throttle(tbf, op, tokens)) +#define TBF_THROTTLE_END(tbf, op, tokens) + +#endif /** THROTTLE_TBF_H__ */ diff --git a/libglusterfs/src/glusterfs/timer.h b/libglusterfs/src/glusterfs/timer.h new file mode 100644 index 00000000000..ae5b2edf451 --- /dev/null +++ b/libglusterfs/src/glusterfs/timer.h @@ -0,0 +1,56 @@ +/* + 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 _TIMER_H +#define _TIMER_H + +#include "glusterfs/glusterfs.h" +#include "glusterfs/xlator.h" +#include <sys/time.h> +#include <pthread.h> + +typedef void (*gf_timer_cbk_t)(void *); + +struct _gf_timer { + union { + struct list_head list; + struct { + struct _gf_timer *next; + struct _gf_timer *prev; + }; + }; + struct timespec at; + gf_timer_cbk_t callbk; + void *data; + xlator_t *xl; + gf_boolean_t fired; +}; + +struct _gf_timer_registry { + struct list_head active; + pthread_mutex_t lock; + pthread_cond_t cond; + pthread_t th; + char fin; +}; + +typedef struct _gf_timer gf_timer_t; +typedef struct _gf_timer_registry gf_timer_registry_t; + +gf_timer_t * +gf_timer_call_after(glusterfs_ctx_t *ctx, struct timespec delta, + gf_timer_cbk_t cbk, void *data); + +int32_t +gf_timer_call_cancel(glusterfs_ctx_t *ctx, gf_timer_t *event); + +void +gf_timer_registry_destroy(glusterfs_ctx_t *ctx); +#endif /* _TIMER_H */ diff --git a/libglusterfs/src/glusterfs/timespec.h b/libglusterfs/src/glusterfs/timespec.h new file mode 100644 index 00000000000..bb9ab446a5f --- /dev/null +++ b/libglusterfs/src/glusterfs/timespec.h @@ -0,0 +1,33 @@ +/* + 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> +#include <sys/time.h> + +#define TS(ts) ((ts.tv_sec * 1000000000LL) + ts.tv_nsec) +#define NANO (+1.0E-9) +#define GIGA UINT64_C(1000000000) + +void +timespec_now(struct timespec *ts); +void +timespec_now_realtime(struct timespec *ts); +void +timespec_adjust_delta(struct timespec *ts, struct timespec delta); +void +timespec_sub(const struct timespec *begin, const struct timespec *end, + struct timespec *res); +int +timespec_cmp(const struct timespec *lhs_ts, const struct timespec *rhs_ts); + +#endif /* __INCLUDE_TIMESPEC_H__ */ diff --git a/libglusterfs/src/glusterfs/trie.h b/libglusterfs/src/glusterfs/trie.h new file mode 100644 index 00000000000..6d2d8015964 --- /dev/null +++ b/libglusterfs/src/glusterfs/trie.h @@ -0,0 +1,52 @@ +/* + 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 _TRIE_H_ +#define _TRIE_H_ + +struct trienode; +typedef struct trienode trienode_t; + +struct trie; +typedef struct trie trie_t; + +struct trienodevec { + trienode_t **nodes; + unsigned cnt; +}; + +trie_t * +trie_new(); + +int +trie_add(trie_t *trie, const char *word); + +void +trie_destroy(trie_t *trie); + +void +trie_destroy_bynode(trienode_t *node); + +int +trie_measure(trie_t *trie, const char *word, trienode_t **nodes, int nodecnt); + +int +trie_measure_vec(trie_t *trie, const char *word, struct trienodevec *nodevec); + +void +trie_reset_search(trie_t *trie); + +int +trienode_get_dist(trienode_t *node); + +int +trienode_get_word(trienode_t *node, char **buf); + +#endif diff --git a/libglusterfs/src/glusterfs/upcall-utils.h b/libglusterfs/src/glusterfs/upcall-utils.h new file mode 100644 index 00000000000..0de8428c5fc --- /dev/null +++ b/libglusterfs/src/glusterfs/upcall-utils.h @@ -0,0 +1,110 @@ +/* + Copyright (c) 2015, Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _UPCALL_UTILS_H +#define _UPCALL_UTILS_H + +#include "glusterfs/iatt.h" +#include "glusterfs/compat-uuid.h" +#include "glusterfs/compat.h" + +/* Flags sent for cache_invalidation */ +#define UP_NLINK 0x00000001 /* update nlink */ +#define UP_MODE 0x00000002 /* update mode and ctime */ +#define UP_OWN 0x00000004 /* update mode,uid,gid and ctime */ +#define UP_SIZE 0x00000008 /* update fsize */ +#define UP_TIMES 0x00000010 /* update all times */ +#define UP_ATIME 0x00000020 /* update atime only */ +#define UP_PERM \ + 0x00000040 /* update fields needed for permission \ + checking */ +#define UP_RENAME \ + 0x00000080 /* this is a rename op - delete the cache \ + entry */ +#define UP_FORGET \ + 0x00000100 /* inode_forget on server side - \ + invalidate the cache entry */ +#define UP_PARENT_TIMES 0x00000200 /* update parent dir times */ + +#define UP_XATTR 0x00000400 /* update the xattrs and ctime */ +#define UP_XATTR_RM 0x00000800 /* Remove the xattrs and update ctime */ + +#define UP_EXPLICIT_LOOKUP 0x00001000 /* Request an explicit lookup */ + +#define UP_INVAL_ATTR 0x00002000 /* Request to invalidate iatt and xatt */ + +/* for fops - open, read, lk, */ +#define UP_UPDATE_CLIENT (UP_ATIME) + +/* for fop - write, truncate */ +#define UP_WRITE_FLAGS (UP_SIZE | UP_TIMES) + +/* for fop - setattr */ +#define UP_ATTR_FLAGS (UP_SIZE | UP_TIMES | UP_OWN | UP_MODE | UP_PERM) +/* for fop - rename */ +#define UP_RENAME_FLAGS (UP_RENAME) + +/* to invalidate parent directory entries for fops -rename, unlink, rmdir, + * mkdir, create */ +#define UP_PARENT_DENTRY_FLAGS (UP_PARENT_TIMES) + +/* for fop - unlink, link, rmdir, mkdir */ +#define UP_NLINK_FLAGS (UP_NLINK | UP_TIMES) + +#define IATT_UPDATE_FLAGS \ + (UP_NLINK | UP_MODE | UP_OWN | UP_SIZE | UP_TIMES | UP_ATIME | UP_PERM) + +typedef enum { + GF_UPCALL_EVENT_NULL, + GF_UPCALL_CACHE_INVALIDATION, + GF_UPCALL_RECALL_LEASE, + GF_UPCALL_INODELK_CONTENTION, + GF_UPCALL_ENTRYLK_CONTENTION, +} gf_upcall_event_t; + +struct gf_upcall { + char *client_uid; + uuid_t gfid; + uint32_t event_type; + void *data; +}; + +struct gf_upcall_cache_invalidation { + uint32_t flags; + uint32_t expire_time_attr; + struct iatt stat; + struct iatt p_stat; /* parent dir stat */ + struct iatt oldp_stat; /* oldparent dir stat */ + dict_t *dict; /* For xattrs */ +}; + +struct gf_upcall_recall_lease { + uint32_t lease_type; /* Lease type to which client can downgrade to*/ + uuid_t tid; /* transaction id of the fop that caused + the recall */ + dict_t *dict; +}; + +struct gf_upcall_inodelk_contention { + struct gf_flock flock; + pid_t pid; + const char *domain; + dict_t *xdata; +}; + +struct gf_upcall_entrylk_contention { + uint32_t type; + pid_t pid; + const char *name; + const char *domain; + dict_t *xdata; +}; + +#endif /* _UPCALL_UTILS_H */ diff --git a/libglusterfs/src/glusterfs/xlator.h b/libglusterfs/src/glusterfs/xlator.h new file mode 100644 index 00000000000..4fd3abdaeff --- /dev/null +++ b/libglusterfs/src/glusterfs/xlator.h @@ -0,0 +1,1106 @@ +/* + 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 _XLATOR_H +#define _XLATOR_H + +#include <stdint.h> // for int32_t +#include <sys/types.h> // for off_t, mode_t, off64_t, dev_t +#include "glusterfs/glusterfs-fops.h" // for GF_FOP_MAXVALUE, entrylk_cmd +#include "glusterfs/atomic.h" // for gf_atomic_t +#include "glusterfs/glusterfs.h" // for gf_boolean_t, glusterfs_ctx_t +#include "glusterfs/compat-uuid.h" // for uuid_t +#include "glusterfs/compat.h" +#include "glusterfs/event-history.h" +#include "glusterfs/dict.h" +#include "glusterfs/latency.h" + +#define FIRST_CHILD(xl) (xl->children->xlator) +#define SECOND_CHILD(xl) (xl->children->next->xlator) + +#define GF_SET_ATTR_MODE 0x1 +#define GF_SET_ATTR_UID 0x2 +#define GF_SET_ATTR_GID 0x4 +#define GF_SET_ATTR_SIZE 0x8 +#define GF_SET_ATTR_ATIME 0x10 +#define GF_SET_ATTR_MTIME 0x20 +#define GF_SET_ATTR_CTIME 0x40 +#define GF_ATTR_ATIME_NOW 0x80 +#define GF_ATTR_MTIME_NOW 0x100 + +#define gf_attr_mode_set(mode) ((mode)&GF_SET_ATTR_MODE) +#define gf_attr_uid_set(mode) ((mode)&GF_SET_ATTR_UID) +#define gf_attr_gid_set(mode) ((mode)&GF_SET_ATTR_GID) +#define gf_attr_size_set(mode) ((mode)&GF_SET_ATTR_SIZE) +#define gf_attr_atime_set(mode) ((mode)&GF_SET_ATTR_ATIME) +#define gf_attr_mtime_set(mode) ((mode)&GF_SET_ATTR_MTIME) + +struct _xlator; +typedef struct _xlator xlator_t; +struct _dir_entry; +typedef struct _dir_entry dir_entry_t; +struct _gf_dirent; +typedef struct _gf_dirent gf_dirent_t; +struct _loc; +typedef struct _loc loc_t; + +typedef int32_t (*event_notify_fn_t)(xlator_t *this, int32_t event, void *data, + ...); + +#include "glusterfs/list.h" +#include "glusterfs/gf-dirent.h" +#include "glusterfs/stack.h" +#include "glusterfs/iobuf.h" +#include "glusterfs/globals.h" +#include "glusterfs/iatt.h" +#include "glusterfs/options.h" +#include "glusterfs/client_t.h" + +struct _loc { + const char *path; + const char *name; + inode_t *inode; + inode_t *parent; + /* Currently all location based operations are through 'gfid' of inode. + * But the 'inode->gfid' only gets set in higher most layer (as in, + * 'fuse', 'protocol/server', or 'nfs/server'). So if translators want + * to send fops on a inode before the 'inode->gfid' is set, they have to + * make use of below 'gfid' fields + */ + uuid_t gfid; + uuid_t pargfid; +}; + +typedef int32_t (*fop_getspec_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, char *spec_data); + +typedef int32_t (*fop_rchecksum_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, uint32_t weak_checksum, + uint8_t *strong_checksum, dict_t *xdata); + +typedef int32_t (*fop_getspec_t)(call_frame_t *frame, xlator_t *this, + const char *key, int32_t flag); + +typedef int32_t (*fop_rchecksum_t)(call_frame_t *frame, xlator_t *this, + fd_t *fd, off_t offset, int32_t len, + dict_t *xdata); + +typedef int32_t (*fop_lookup_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, inode_t *inode, + struct iatt *buf, dict_t *xdata, + struct iatt *postparent); + +typedef int32_t (*fop_stat_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, struct iatt *buf, + dict_t *xdata); + +typedef int32_t (*fop_fstat_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, struct iatt *buf, + dict_t *xdata); + +typedef int32_t (*fop_truncate_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata); + +typedef int32_t (*fop_ftruncate_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata); + +typedef int32_t (*fop_access_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +typedef int32_t (*fop_readlink_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, const char *path, + struct iatt *buf, dict_t *xdata); + +typedef int32_t (*fop_mknod_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +typedef int32_t (*fop_mkdir_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +typedef int32_t (*fop_unlink_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +typedef int32_t (*fop_rmdir_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +typedef int32_t (*fop_symlink_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +typedef int32_t (*fop_rename_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, struct iatt *buf, + struct iatt *preoldparent, + struct iatt *postoldparent, + struct iatt *prenewparent, + struct iatt *postnewparent, dict_t *xdata); + +typedef int32_t (*fop_link_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +typedef int32_t (*fop_create_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, fd_t *fd, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +typedef int32_t (*fop_open_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, fd_t *fd, dict_t *xdata); + +typedef int32_t (*fop_readv_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, struct iovec *vector, + int32_t count, struct iatt *stbuf, + struct iobref *iobref, dict_t *xdata); + +typedef int32_t (*fop_writev_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata); + +typedef int32_t (*fop_flush_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +typedef int32_t (*fop_fsync_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata); + +typedef int32_t (*fop_opendir_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, fd_t *fd, dict_t *xdata); + +typedef int32_t (*fop_fsyncdir_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +typedef int32_t (*fop_statfs_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, struct statvfs *buf, + dict_t *xdata); + +typedef int32_t (*fop_setxattr_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +typedef int32_t (*fop_getxattr_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *dict, + dict_t *xdata); + +typedef int32_t (*fop_fsetxattr_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +typedef int32_t (*fop_fgetxattr_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *dict, + dict_t *xdata); + +typedef int32_t (*fop_removexattr_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +typedef int32_t (*fop_fremovexattr_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +typedef int32_t (*fop_lk_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, struct gf_flock *flock, + dict_t *xdata); + +typedef int32_t (*fop_inodelk_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +typedef int32_t (*fop_finodelk_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +typedef int32_t (*fop_entrylk_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +typedef int32_t (*fop_fentrylk_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +typedef int32_t (*fop_readdir_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, gf_dirent_t *entries, + dict_t *xdata); + +typedef int32_t (*fop_readdirp_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, gf_dirent_t *entries, + dict_t *xdata); + +typedef int32_t (*fop_xattrop_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *xattr, + dict_t *xdata); + +typedef int32_t (*fop_fxattrop_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *xattr, + dict_t *xdata); + +typedef int32_t (*fop_setattr_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_fsetattr_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_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_ipc_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +typedef int32_t (*fop_seek_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, off_t offset, + dict_t *xdata); + +typedef int32_t (*fop_lease_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, struct gf_lease *lease, + dict_t *xdata); +typedef int32_t (*fop_compound_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, void *data, + dict_t *xdata); + +typedef int32_t (*fop_getactivelk_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, + lock_migration_info_t *locklist, + dict_t *xdata); + +typedef int32_t (*fop_setactivelk_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, dict_t *xdata); + +typedef int32_t (*fop_put_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata); + +typedef int32_t (*fop_icreate_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, inode_t *inode, + struct iatt *buf, dict_t *xdata); + +typedef int32_t (*fop_namelink_cbk_t)(call_frame_t *frame, void *cookie, + xlator_t *this, int32_t op_ret, + int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata); + +typedef int32_t (*fop_copy_file_range_cbk_t)( + call_frame_t *frame, void *cookie, xlator_t *this, int32_t op_ret, + int32_t op_errno, struct iatt *stbuf, struct iatt *prebuf_dst, + struct iatt *postbuf_dst, dict_t *xdata); + +typedef int32_t (*fop_lookup_t)(call_frame_t *frame, xlator_t *this, loc_t *loc, + dict_t *xdata); + +typedef int32_t (*fop_stat_t)(call_frame_t *frame, xlator_t *this, loc_t *loc, + dict_t *xdata); + +typedef int32_t (*fop_fstat_t)(call_frame_t *frame, xlator_t *this, fd_t *fd, + dict_t *xdata); + +typedef int32_t (*fop_truncate_t)(call_frame_t *frame, xlator_t *this, + loc_t *loc, off_t offset, dict_t *xdata); + +typedef int32_t (*fop_ftruncate_t)(call_frame_t *frame, xlator_t *this, + fd_t *fd, off_t offset, dict_t *xdata); + +typedef int32_t (*fop_access_t)(call_frame_t *frame, xlator_t *this, loc_t *loc, + int32_t mask, dict_t *xdata); + +typedef int32_t (*fop_readlink_t)(call_frame_t *frame, xlator_t *this, + loc_t *loc, size_t size, dict_t *xdata); + +typedef int32_t (*fop_mknod_t)(call_frame_t *frame, xlator_t *this, loc_t *loc, + mode_t mode, dev_t rdev, mode_t umask, + dict_t *xdata); + +typedef int32_t (*fop_mkdir_t)(call_frame_t *frame, xlator_t *this, loc_t *loc, + mode_t mode, mode_t umask, dict_t *xdata); + +typedef int32_t (*fop_unlink_t)(call_frame_t *frame, xlator_t *this, loc_t *loc, + int xflags, dict_t *xdata); + +typedef int32_t (*fop_rmdir_t)(call_frame_t *frame, xlator_t *this, loc_t *loc, + int xflags, dict_t *xdata); + +typedef int32_t (*fop_symlink_t)(call_frame_t *frame, xlator_t *this, + const char *linkname, loc_t *loc, mode_t umask, + dict_t *xdata); + +typedef int32_t (*fop_rename_t)(call_frame_t *frame, xlator_t *this, + loc_t *oldloc, loc_t *newloc, dict_t *xdata); + +typedef int32_t (*fop_link_t)(call_frame_t *frame, xlator_t *this, + loc_t *oldloc, loc_t *newloc, dict_t *xdata); + +typedef int32_t (*fop_create_t)(call_frame_t *frame, xlator_t *this, loc_t *loc, + int32_t flags, mode_t mode, mode_t umask, + fd_t *fd, dict_t *xdata); + +/* Tell subsequent writes on the fd_t to fsync after every writev fop without + * requiring a fsync fop. + */ +#define GF_OPEN_FSYNC 0x01 + +/* Tell write-behind to disable writing behind despite O_SYNC not being set. + */ +#define GF_OPEN_NOWB 0x02 + +typedef int32_t (*fop_open_t)(call_frame_t *frame, xlator_t *this, loc_t *loc, + int32_t flags, fd_t *fd, dict_t *xdata); + +typedef int32_t (*fop_readv_t)(call_frame_t *frame, xlator_t *this, fd_t *fd, + size_t size, off_t offset, uint32_t flags, + dict_t *xdata); + +typedef int32_t (*fop_writev_t)(call_frame_t *frame, xlator_t *this, fd_t *fd, + struct iovec *vector, int32_t count, + off_t offset, uint32_t flags, + struct iobref *iobref, dict_t *xdata); + +typedef int32_t (*fop_flush_t)(call_frame_t *frame, xlator_t *this, fd_t *fd, + dict_t *xdata); + +typedef int32_t (*fop_fsync_t)(call_frame_t *frame, xlator_t *this, fd_t *fd, + int32_t datasync, dict_t *xdata); + +typedef int32_t (*fop_opendir_t)(call_frame_t *frame, xlator_t *this, + loc_t *loc, fd_t *fd, dict_t *xdata); + +typedef int32_t (*fop_fsyncdir_t)(call_frame_t *frame, xlator_t *this, fd_t *fd, + int32_t datasync, dict_t *xdata); + +typedef int32_t (*fop_statfs_t)(call_frame_t *frame, xlator_t *this, loc_t *loc, + dict_t *xdata); + +typedef int32_t (*fop_setxattr_t)(call_frame_t *frame, xlator_t *this, + loc_t *loc, dict_t *dict, int32_t flags, + dict_t *xdata); + +typedef int32_t (*fop_getxattr_t)(call_frame_t *frame, xlator_t *this, + loc_t *loc, const char *name, dict_t *xdata); + +typedef int32_t (*fop_fsetxattr_t)(call_frame_t *frame, xlator_t *this, + fd_t *fd, dict_t *dict, int32_t flags, + dict_t *xdata); + +typedef int32_t (*fop_fgetxattr_t)(call_frame_t *frame, xlator_t *this, + fd_t *fd, const char *name, dict_t *xdata); + +typedef int32_t (*fop_removexattr_t)(call_frame_t *frame, xlator_t *this, + loc_t *loc, const char *name, + dict_t *xdata); + +typedef int32_t (*fop_fremovexattr_t)(call_frame_t *frame, xlator_t *this, + fd_t *fd, const char *name, + dict_t *xdata); + +typedef int32_t (*fop_lk_t)(call_frame_t *frame, xlator_t *this, fd_t *fd, + int32_t cmd, struct gf_flock *flock, dict_t *xdata); + +typedef int32_t (*fop_inodelk_t)(call_frame_t *frame, xlator_t *this, + const char *volume, loc_t *loc, int32_t cmd, + struct gf_flock *flock, dict_t *xdata); + +typedef int32_t (*fop_finodelk_t)(call_frame_t *frame, xlator_t *this, + const char *volume, fd_t *fd, int32_t cmd, + struct gf_flock *flock, dict_t *xdata); + +typedef int32_t (*fop_entrylk_t)(call_frame_t *frame, xlator_t *this, + const char *volume, loc_t *loc, + const char *basename, entrylk_cmd cmd, + entrylk_type type, dict_t *xdata); + +typedef int32_t (*fop_fentrylk_t)(call_frame_t *frame, xlator_t *this, + const char *volume, fd_t *fd, + const char *basename, entrylk_cmd cmd, + entrylk_type type, dict_t *xdata); + +typedef int32_t (*fop_readdir_t)(call_frame_t *frame, xlator_t *this, fd_t *fd, + size_t size, off_t offset, dict_t *xdata); + +typedef int32_t (*fop_readdirp_t)(call_frame_t *frame, xlator_t *this, fd_t *fd, + size_t size, off_t offset, dict_t *xdata); + +typedef int32_t (*fop_xattrop_t)(call_frame_t *frame, xlator_t *this, + loc_t *loc, gf_xattrop_flags_t optype, + dict_t *xattr, dict_t *xdata); + +typedef int32_t (*fop_fxattrop_t)(call_frame_t *frame, xlator_t *this, fd_t *fd, + gf_xattrop_flags_t optype, dict_t *xattr, + dict_t *xdata); + +typedef int32_t (*fop_setattr_t)(call_frame_t *frame, xlator_t *this, + loc_t *loc, struct iatt *stbuf, int32_t valid, + dict_t *xdata); + +typedef int32_t (*fop_fsetattr_t)(call_frame_t *frame, xlator_t *this, fd_t *fd, + 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, off_t len, dict_t *xdata); + +typedef int32_t (*fop_ipc_t)(call_frame_t *frame, xlator_t *this, int32_t op, + dict_t *xdata); + +typedef int32_t (*fop_seek_t)(call_frame_t *frame, xlator_t *this, fd_t *fd, + off_t offset, gf_seek_what_t what, dict_t *xdata); + +typedef int32_t (*fop_lease_t)(call_frame_t *frame, xlator_t *this, loc_t *loc, + struct gf_lease *lease, dict_t *xdata); + +typedef int32_t (*fop_compound_t)(call_frame_t *frame, xlator_t *this, + void *args, dict_t *xdata); + +typedef int32_t (*fop_getactivelk_t)(call_frame_t *frame, xlator_t *this, + loc_t *loc, dict_t *xdata); + +typedef int32_t (*fop_setactivelk_t)(call_frame_t *frame, xlator_t *this, + loc_t *loc, + lock_migration_info_t *locklist, + dict_t *xdata); + +typedef int32_t (*fop_put_t)(call_frame_t *frame, xlator_t *this, loc_t *loc, + mode_t mode, mode_t umask, uint32_t flags, + struct iovec *vector, int32_t count, off_t offset, + struct iobref *iobref, dict_t *xattr, + dict_t *xdata); + +typedef int32_t (*fop_icreate_t)(call_frame_t *frame, xlator_t *this, + loc_t *loc, mode_t mode, dict_t *xdata); + +typedef int32_t (*fop_namelink_t)(call_frame_t *frame, xlator_t *this, + loc_t *loc, dict_t *xdata); +typedef int32_t (*fop_copy_file_range_t)(call_frame_t *frame, xlator_t *this, + fd_t *fd_in, off64_t off_in, + fd_t *fd_out, off64_t off_out, + size_t len, uint32_t flags, + dict_t *xdata); + +/* WARNING: make sure the list is in order with FOP definition in + `rpc/xdr/src/glusterfs-fops.x`. + If it is not in order, mainly the metrics related feature would be broken */ +struct xlator_fops { + fop_stat_t stat; + fop_readlink_t readlink; + fop_mknod_t mknod; + fop_mkdir_t mkdir; + fop_unlink_t unlink; + fop_rmdir_t rmdir; + fop_symlink_t symlink; + fop_rename_t rename; + fop_link_t link; + fop_truncate_t truncate; + fop_open_t open; + fop_readv_t readv; + fop_writev_t writev; + fop_statfs_t statfs; + fop_flush_t flush; + fop_fsync_t fsync; + fop_setxattr_t setxattr; + fop_getxattr_t getxattr; + fop_removexattr_t removexattr; + fop_opendir_t opendir; + fop_fsyncdir_t fsyncdir; + fop_access_t access; + fop_create_t create; + fop_ftruncate_t ftruncate; + fop_fstat_t fstat; + fop_lk_t lk; + fop_lookup_t lookup; + fop_readdir_t readdir; + fop_inodelk_t inodelk; + fop_finodelk_t finodelk; + fop_entrylk_t entrylk; + fop_fentrylk_t fentrylk; + fop_xattrop_t xattrop; + fop_fxattrop_t fxattrop; + fop_fgetxattr_t fgetxattr; + fop_fsetxattr_t fsetxattr; + fop_rchecksum_t rchecksum; + fop_setattr_t setattr; + fop_fsetattr_t fsetattr; + fop_readdirp_t readdirp; + + /* These 3 are required to keep the index same as GF_FOP_##FOP */ + void *forget_placeholder; + void *release_placeholder; + void *releasedir_placeholder; + + fop_getspec_t getspec; + fop_fremovexattr_t fremovexattr; + fop_fallocate_t fallocate; + fop_discard_t discard; + fop_zerofill_t zerofill; + fop_ipc_t ipc; + fop_seek_t seek; + fop_lease_t lease; + fop_compound_t compound; + fop_getactivelk_t getactivelk; + fop_setactivelk_t setactivelk; + fop_put_t put; + fop_icreate_t icreate; + fop_namelink_t namelink; + fop_copy_file_range_t copy_file_range; + + /* these entries are used for a typechecking hack in STACK_WIND _only_ */ + /* make sure to add _cbk variables only after defining regular fops as + its relative position is used to get the index */ + fop_stat_cbk_t stat_cbk; + fop_readlink_cbk_t readlink_cbk; + fop_mknod_cbk_t mknod_cbk; + fop_mkdir_cbk_t mkdir_cbk; + fop_unlink_cbk_t unlink_cbk; + fop_rmdir_cbk_t rmdir_cbk; + fop_symlink_cbk_t symlink_cbk; + fop_rename_cbk_t rename_cbk; + fop_link_cbk_t link_cbk; + fop_truncate_cbk_t truncate_cbk; + fop_open_cbk_t open_cbk; + fop_readv_cbk_t readv_cbk; + fop_writev_cbk_t writev_cbk; + fop_statfs_cbk_t statfs_cbk; + fop_flush_cbk_t flush_cbk; + fop_fsync_cbk_t fsync_cbk; + fop_setxattr_cbk_t setxattr_cbk; + fop_getxattr_cbk_t getxattr_cbk; + fop_removexattr_cbk_t removexattr_cbk; + fop_opendir_cbk_t opendir_cbk; + fop_fsyncdir_cbk_t fsyncdir_cbk; + fop_access_cbk_t access_cbk; + fop_create_cbk_t create_cbk; + fop_ftruncate_cbk_t ftruncate_cbk; + fop_fstat_cbk_t fstat_cbk; + fop_lk_cbk_t lk_cbk; + fop_lookup_cbk_t lookup_cbk; + fop_readdir_cbk_t readdir_cbk; + fop_inodelk_cbk_t inodelk_cbk; + fop_finodelk_cbk_t finodelk_cbk; + fop_entrylk_cbk_t entrylk_cbk; + fop_fentrylk_cbk_t fentrylk_cbk; + fop_xattrop_cbk_t xattrop_cbk; + fop_fxattrop_cbk_t fxattrop_cbk; + fop_fgetxattr_cbk_t fgetxattr_cbk; + fop_fsetxattr_cbk_t fsetxattr_cbk; + fop_rchecksum_cbk_t rchecksum_cbk; + fop_setattr_cbk_t setattr_cbk; + fop_fsetattr_cbk_t fsetattr_cbk; + fop_readdirp_cbk_t readdirp_cbk; + + /* These 3 are required to keep the index same as GF_FOP_##FOP */ + void *forget_placeholder_cbk; + void *release_placeholder_cbk; + void *releasedir_placeholder_cbk; + + fop_getspec_cbk_t getspec_cbk; + fop_fremovexattr_cbk_t fremovexattr_cbk; + fop_fallocate_cbk_t fallocate_cbk; + fop_discard_cbk_t discard_cbk; + fop_zerofill_cbk_t zerofill_cbk; + fop_ipc_cbk_t ipc_cbk; + fop_seek_cbk_t seek_cbk; + fop_lease_cbk_t lease_cbk; + fop_compound_cbk_t compound_cbk; + fop_getactivelk_cbk_t getactivelk_cbk; + fop_setactivelk_cbk_t setactivelk_cbk; + fop_put_cbk_t put_cbk; + fop_icreate_cbk_t icreate_cbk; + fop_namelink_cbk_t namelink_cbk; + fop_copy_file_range_cbk_t copy_file_range_cbk; +}; + +typedef int32_t (*cbk_forget_t)(xlator_t *this, inode_t *inode); + +typedef int32_t (*cbk_release_t)(xlator_t *this, fd_t *fd); + +typedef int32_t (*cbk_invalidate_t)(xlator_t *this, inode_t *inode); + +typedef int32_t (*cbk_client_t)(xlator_t *this, client_t *client); + +typedef void (*cbk_ictxmerge_t)(xlator_t *this, fd_t *fd, inode_t *inode, + inode_t *linked_inode); + +typedef size_t (*cbk_inodectx_size_t)(xlator_t *this, inode_t *inode); + +typedef size_t (*cbk_fdctx_size_t)(xlator_t *this, fd_t *fd); + +typedef void (*cbk_fdclose_t)(xlator_t *this, fd_t *fd); + +struct xlator_cbks { + 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; + cbk_ictxmerge_t ictxmerge; + cbk_inodectx_size_t ictxsize; + cbk_fdctx_size_t fdctxsize; + cbk_fdclose_t fdclose; + cbk_fdclose_t fdclosedir; +}; + +typedef int32_t (*dumpop_priv_t)(xlator_t *this); + +typedef int32_t (*dumpop_inode_t)(xlator_t *this); + +typedef int32_t (*dumpop_fd_t)(xlator_t *this); + +typedef int32_t (*dumpop_inodectx_t)(xlator_t *this, inode_t *ino); + +typedef int32_t (*dumpop_fdctx_t)(xlator_t *this, fd_t *fd); + +typedef int32_t (*dumpop_priv_to_dict_t)(xlator_t *this, dict_t *dict, + char *brickname); + +typedef int32_t (*dumpop_inode_to_dict_t)(xlator_t *this, dict_t *dict); + +typedef int32_t (*dumpop_fd_to_dict_t)(xlator_t *this, dict_t *dict); + +typedef int32_t (*dumpop_inodectx_to_dict_t)(xlator_t *this, inode_t *ino, + dict_t *dict); + +typedef int32_t (*dumpop_fdctx_to_dict_t)(xlator_t *this, fd_t *fd, + dict_t *dict); + +typedef int32_t (*dumpop_eh_t)(xlator_t *this); + +struct xlator_dumpops { + dumpop_priv_t priv; + dumpop_inode_t inode; + dumpop_fd_t fd; + dumpop_inodectx_t inodectx; + dumpop_fdctx_t fdctx; + dumpop_priv_to_dict_t priv_to_dict; + dumpop_inode_to_dict_t inode_to_dict; + dumpop_fd_to_dict_t fd_to_dict; + dumpop_inodectx_to_dict_t inodectx_to_dict; + dumpop_fdctx_to_dict_t fdctx_to_dict; + dumpop_eh_t history; +}; + +typedef struct xlator_list { + xlator_t *xlator; + struct xlator_list *next; +} xlator_list_t; + +typedef struct fop_metrics { + gf_atomic_t fop; + gf_atomic_t cbk; /* only updaed when there is failure */ +} fop_metrics_t; + +struct _xlator { + /* Built during parsing */ + char *name; + char *type; + char *instance_name; /* Used for multi NFSd */ + xlator_t *next; + xlator_t *prev; + xlator_list_t *parents; + xlator_list_t *children; + dict_t *options; + + /* Set after doing dlopen() */ + void *dlhandle; + struct xlator_fops *fops; + struct xlator_cbks *cbks; + struct xlator_dumpops *dumpops; + struct list_head volume_options; /* list of volume_option_t */ + + void (*fini)(xlator_t *this); + int32_t (*init)(xlator_t *this); + int32_t (*reconfigure)(xlator_t *this, dict_t *options); + int32_t (*mem_acct_init)(xlator_t *this); + int32_t (*dump_metrics)(xlator_t *this, int fd); + + event_notify_fn_t notify; + + gf_loglevel_t loglevel; /* Log level for translator */ + + struct { + struct { + /* for latency measurement */ + fop_metrics_t metrics[GF_FOP_MAXVALUE]; + + gf_atomic_t count; + } total; + + struct { + /* for latency measurement */ + gf_latency_t latencies[GF_FOP_MAXVALUE]; + /* for latency measurement */ + fop_metrics_t metrics[GF_FOP_MAXVALUE]; + + gf_atomic_t count; + } interval; + } stats; + + /* Misc */ + eh_t *history; /* event history context */ + glusterfs_ctx_t *ctx; + glusterfs_graph_t *graph; /* not set for fuse */ + inode_table_t *itable; + char init_succeeded; + void *private; + struct mem_acct *mem_acct; + uint64_t winds; + char switched; + + /* for the memory pool of 'frame->local' */ + struct mem_pool *local_pool; + gf_boolean_t is_autoloaded; + + /* Saved volfile ID (used for multiplexing) */ + char *volfile_id; + + /* Its used as an index to inode_ctx*/ + uint32_t xl_id; + + /* op_version: initialized in xlator code itself */ + uint32_t op_version[GF_MAX_RELEASES]; + + /* flags: initialized in xlator code itself */ + uint32_t flags; + + /* id: unique, initialized in xlator code itself */ + uint32_t id; + + /* identifier: a full string which can unique identify the xlator */ + char *identifier; + + /* Is this pass_through? */ + gf_boolean_t pass_through; + struct xlator_fops *pass_through_fops; + + /* cleanup flag to avoid races during xlator cleanup */ + uint32_t cleanup_starting; + + /* flag to avoid recall of xlator_mem_cleanup for xame xlator */ + uint32_t call_cleanup; + + /* Flag to understand how this xlator is categorized */ + gf_category_t category; + + /* Variable to save xprt associated for detach brick */ + gf_atomic_t xprtrefcnt; + + /* Flag to notify got CHILD_DOWN event for detach brick */ + uint32_t notify_down; + + /* Flag to avoid throw duplicate PARENT_DOWN event */ + uint32_t parent_down; +}; + +/* This would be the only structure which needs to be exported by + the translators. For the backward compatibility, in 4.x series + even the old exported fields will be supported */ +/* XXX: This struct is in use by GD2, and hence SHOULD NOT be modified. + * If the struct must be modified, see instructions at the comment with + * GD2MARKER below. + */ +typedef struct { + /* op_version: will be used by volume generation logic to figure + out whether to insert it in graph or no, based on cluster's + operating version. + default value: 0, which means good to insert always */ + uint32_t op_version[GF_MAX_RELEASES]; + + /* flags: will be used by volume generation logic to optimize the + placements etc. + default value: 0, which means don't treat it specially */ + uint32_t flags; + + /* xlator_id: unique per xlator. make sure to have no collission + in this ID */ + uint32_t xlator_id; + + /* identifier: a string constant */ + char *identifier; + + /* struct options: if the translator takes any 'options' from the + volume file, then that should be defined here. optional. */ + volume_option_t *options; + + /* Flag to understand how this xlator is categorized */ + gf_category_t category; + + /* XXX: GD2MARKER + * If a new member that needs to be visible to GD2 is introduced, + * add it above this comment. + * Any other new members need to be added below this comment, or at the + * end of the struct + */ + + /* init(): mandatory method, will be called during the + graph initialization */ + int32_t (*init)(xlator_t *this); + + /* fini(): optional method, will be initialized to default + method which would just free the 'xlator->private' variable. + This method is called when the graph is no more in use, and + is being destroyed. Also when SIGTERM is received */ + void (*fini)(xlator_t *this); + + /* reconfigure(): optional method, will be initialized to default + method in case not provided by xlator. This method is called + when there are only option changes in xlator, and no graph change. + eg., a 'gluster volume set' command */ + int32_t (*reconfigure)(xlator_t *this, dict_t *options); + + /* mem_acct_init(): used for memory accounting inside of the xlator. + optional. called during translator initialization */ + int32_t (*mem_acct_init)(xlator_t *this); + + /* dump_metrics(): used for providing internal metrics. optional */ + int32_t (*dump_metrics)(xlator_t *this, int fd); + + /* notify(): used for handling the notification of events from either + the parent or child in the graph. optional. */ + event_notify_fn_t notify; + + /* struct fops: mandatory. provides all the filesystem operations + methods of the xlator */ + struct xlator_fops *fops; + /* struct cbks: optional. provides methods to handle + inode forgets, and fd releases */ + struct xlator_cbks *cbks; + + /* dumpops: a structure again, with methods to dump the details. + optional. */ + struct xlator_dumpops *dumpops; + + /* struct pass_through_fops: optional. provides all the filesystem + operations which should be used if the xlator is marked as pass_through + */ + /* by default, the default_fops would be used */ + struct xlator_fops *pass_through_fops; +} xlator_api_t; + +#define xlator_has_parent(xl) (xl->parents != NULL) + +#define XLATOR_NOTIFY(ret, _xl, params...) \ + do { \ + xlator_t *_old_THIS = NULL; \ + \ + _old_THIS = THIS; \ + THIS = _xl; \ + \ + ret = _xl->notify(_xl, params); \ + \ + THIS = _old_THIS; \ + } while (0); + +int32_t +xlator_set_type_virtual(xlator_t *xl, const char *type); + +int32_t +xlator_set_type(xlator_t *xl, const char *type); + +int32_t +xlator_dynload(xlator_t *xl); + +xlator_t * +file_to_xlator_tree(glusterfs_ctx_t *ctx, FILE *fp); + +int +xlator_notify(xlator_t *this, int32_t event, void *data, ...); +int +xlator_init(xlator_t *this); +int +xlator_destroy(xlator_t *xl); + +int32_t +xlator_tree_init(xlator_t *xl); +int32_t +xlator_tree_free_members(xlator_t *xl); +int32_t +xlator_tree_free_memacct(xlator_t *xl); + +void +xlator_tree_fini(xlator_t *xl); + +void +xlator_foreach(xlator_t *this, void (*fn)(xlator_t *each, void *data), + void *data); + +void +xlator_foreach_depth_first(xlator_t *this, + void (*fn)(xlator_t *each, void *data), void *data); + +xlator_t * +xlator_search_by_name(xlator_t *any, const char *name); +xlator_t * +get_xlator_by_name(xlator_t *this, char *target); +xlator_t * +get_xlator_by_type(xlator_t *this, char *target); + +void +xlator_set_inode_lru_limit(xlator_t *this, void *data); + +void +inode_destroy_notify(inode_t *inode, const char *xlname); + +int +loc_copy(loc_t *dst, loc_t *src); +int +loc_copy_overload_parent(loc_t *dst, loc_t *src, inode_t *parent); +#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); +void +loc_pargfid(loc_t *loc, uuid_t pargfid); +char * +loc_gfid_utoa(loc_t *loc); +gf_boolean_t +loc_is_root(loc_t *loc); +int32_t +loc_build_child(loc_t *child, loc_t *parent, char *name); +gf_boolean_t +loc_is_nameless(loc_t *loc); +int +xlator_mem_acct_init(xlator_t *xl, int num_types); +void +xlator_mem_acct_unref(struct mem_acct *mem_acct); +int +is_gf_log_command(xlator_t *trans, const char *name, char *value, size_t size); +int +glusterd_check_log_level(const char *value); +int +xlator_volopt_dynload(char *xlator_type, void **dl_handle, + volume_opt_list_t *vol_opt_handle); +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(FILE *newvolfile_fp, glusterfs_ctx_t *ctx); + +int +gf_volfile_reconfigure(int oldvollen, FILE *newvolfile_fp, glusterfs_ctx_t *ctx, + const char *oldvolfile); + +int +loc_touchup(loc_t *loc, const char *name); + +int +glusterfs_leaf_position(xlator_t *tgt); + +int +glusterfs_reachable_leaves(xlator_t *base, dict_t *leaves); + +int +xlator_subvolume_count(xlator_t *this); + +void +xlator_init_lock(void); +void +xlator_init_unlock(void); +int +copy_opts_to_child(xlator_t *src, xlator_t *dst, char *glob); + +int +glusterfs_delete_volfile_checksum(glusterfs_ctx_t *ctx, const char *volfile_id); +int +xlator_memrec_free(xlator_t *xl); + +void +xlator_mem_cleanup(xlator_t *this); + +void +handle_default_options(xlator_t *xl, dict_t *options); + +void +gluster_graph_take_reference(xlator_t *tree); + +gf_boolean_t +mgmt_is_multiplexed_daemon(char *name); + +gf_boolean_t +xlator_is_cleanup_starting(xlator_t *this); +int +graph_total_client_xlator(glusterfs_graph_t *graph); +#endif /* _XLATOR_H */ diff --git a/libglusterfs/src/graph-print.c b/libglusterfs/src/graph-print.c new file mode 100644 index 00000000000..595d74330a1 --- /dev/null +++ b/libglusterfs/src/graph-print.c @@ -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. +*/ + +#include <sys/uio.h> + +#include "glusterfs/common-utils.h" +#include "glusterfs/xlator.h" +#include "glusterfs/graph-utils.h" +#include "glusterfs/libglusterfs-messages.h" + +struct gf_printer { + ssize_t (*write)(struct gf_printer *gp, char *buf, size_t len); + void *priv; + int len; +}; + +static ssize_t +gp_write_file(struct gf_printer *gp, char *buf, size_t len) +{ + FILE *f = gp->priv; + + if (fwrite(buf, len, 1, f) != 1) { + gf_msg("graph-print", GF_LOG_ERROR, errno, LG_MSG_FWRITE_FAILED, + "fwrite failed"); + + return -1; + } + + return len; +} + +static int +gpprintf(struct gf_printer *gp, const char *format, ...) +{ + va_list arg; + char *str = NULL; + int ret = 0; + + va_start(arg, format); + ret = gf_vasprintf(&str, format, arg); + va_end(arg); + + if (ret < 0) + return ret; + + ret = gp->write(gp, str, ret); + + GF_FREE(str); + + return ret; +} + +#define GPPRINTF(gp, fmt, ...) \ + do { \ + ret = gpprintf(gp, fmt, ##__VA_ARGS__); \ + if (ret == -1) \ + goto out; \ + else \ + gp->len += ret; \ + } while (0) + +static int +_print_volume_options(dict_t *d, char *k, data_t *v, void *tmp) +{ + struct gf_printer *gp = tmp; + int ret = 0; + GPPRINTF(gp, " option %s %s\n", k, v->data); + return 0; +out: + /* means, it is a failure */ + return -1; +} + +static int +glusterfs_graph_print(struct gf_printer *gp, glusterfs_graph_t *graph) +{ + xlator_t *trav = NULL; + xlator_list_t *xch = NULL; + int ret = 0; + ssize_t len = 0; + + if (!graph->first) + return 0; + + for (trav = graph->first; trav->next; trav = trav->next) + ; + for (; trav; trav = trav->prev) { + GPPRINTF(gp, "volume %s\n type %s\n", trav->name, trav->type); + + ret = dict_foreach(trav->options, _print_volume_options, gp); + if (ret) + goto out; + + if (trav->children) { + GPPRINTF(gp, " subvolumes"); + + for (xch = trav->children; xch; xch = xch->next) + GPPRINTF(gp, " %s", xch->xlator->name); + + GPPRINTF(gp, "\n"); + } + + GPPRINTF(gp, "end-volume\n"); + if (trav != graph->first) + GPPRINTF(gp, "\n"); + } + +out: + len = gp->len; + if (ret == -1) { + gf_msg("graph-print", GF_LOG_ERROR, 0, LG_MSG_PRINT_FAILED, + "printing failed"); + + return -1; + } + + return len; + +#undef GPPRINTF +} + +int +glusterfs_graph_print_file(FILE *file, glusterfs_graph_t *graph) +{ + struct gf_printer gp = {.write = gp_write_file, .priv = file}; + + return glusterfs_graph_print(&gp, graph); +} diff --git a/libglusterfs/src/graph.c b/libglusterfs/src/graph.c index 4adb04a39c3..13f298eb3bd 100644 --- a/libglusterfs/src/graph.c +++ b/libglusterfs/src/graph.c @@ -1,35 +1,39 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 "xlator.h" -#include <dlfcn.h> -#include <netdb.h> -#include <fnmatch.h> -#include "defaults.h" - - - +#include <stdint.h> // for uint32_t +#include <sys/time.h> // for timeval +#include <errno.h> // for EIO, errno, EINVAL, ENOMEM +#include <fnmatch.h> // for fnmatch, FNM_NOESCAPE +#include <openssl/sha.h> // for SHA256_DIGEST_LENGTH +#include <regex.h> // for regmatch_t, regcomp +#include <stdio.h> // for fclose, fopen, snprintf +#include <stdlib.h> // for NULL, atoi, mkstemp +#include <string.h> // for strcmp, strerror, memcpy +#include <strings.h> // for rindex +#include <sys/stat.h> // for stat +#include <sys/time.h> // for gettimeofday +#include <unistd.h> // for gethostname, getpid +#include "glusterfs/common-utils.h" // for gf_strncpy, gf_time_fmt +#include "glusterfs/defaults.h" +#include "glusterfs/dict.h" // for dict_foreach, dict_set_... +#include "glusterfs/globals.h" // for xlator_t, xlator_list_t +#include "glusterfs/glusterfs.h" // for glusterfs_graph_t, glus... +#include "glusterfs/glusterfs-fops.h" // for GF_EVENT_GRAPH_NEW, GF_... +#include "glusterfs/libglusterfs-messages.h" // for LG_MSG_GRAPH_ERROR, LG_... +#include "glusterfs/list.h" // for list_add, list_del_init +#include "glusterfs/logging.h" // for gf_msg, GF_LOG_ERROR +#include "glusterfs/mem-pool.h" // for GF_FREE, gf_strdup, GF_... +#include "glusterfs/mem-types.h" // for gf_common_mt_xlator_list_t +#include "glusterfs/options.h" // for xlator_tree_reconfigure +#include "glusterfs/syscall.h" // for sys_close, sys_stat #if 0 static void @@ -37,20 +41,17 @@ _gf_dump_details (int argc, char **argv) { extern FILE *gf_log_logfile; int i = 0; - char timestr[256]; + char timestr[GF_TIMESTR_SIZE]; time_t utime = 0; - struct tm *tm = NULL; pid_t mypid = 0; struct utsname uname_buf = {{0, }, }; int uname_ret = -1; - utime = time (NULL); - tm = localtime (&utime); mypid = getpid (); uname_ret = uname (&uname_buf); - /* Which git? What time? */ - strftime (timestr, 256, "%Y-%m-%d %H:%M:%S", tm); + utime = time (NULL); + gf_time_fmt (timestr, sizeof timestr, utime, gf_timefmt_FT); fprintf (gf_log_logfile, "========================================" "========================================\n"); @@ -83,423 +84,1797 @@ _gf_dump_details (int argc, char **argv) } #endif - -static int -_log_if_option_is_invalid (xlator_t *xl, data_pair_t *pair) -{ - volume_opt_list_t *vol_opt = NULL; - volume_option_t *opt = NULL; - int i = 0; - int index = 0; - int found = 0; - - /* Get the first volume_option */ - list_for_each_entry (vol_opt, &xl->volume_options, list) { - /* Warn for extra option */ - if (!vol_opt->given_opt) - break; - - opt = vol_opt->given_opt; - for (index = 0; - ((index < ZR_OPTION_MAX_ARRAY_SIZE) && - (opt[index].key && opt[index].key[0])); index++) - for (i = 0; (i < ZR_VOLUME_MAX_NUM_KEY) && - opt[index].key[i]; i++) { - if (fnmatch (opt[index].key[i], - pair->key, - FNM_NOESCAPE) == 0) { - found = 1; - break; - } - } +int +glusterfs_read_secure_access_file(void) +{ + FILE *fp = NULL; + char line[100] = { + 0, + }; + int cert_depth = 1; /* Default SSL CERT DEPTH */ + regex_t regcmpl; + char *key = {"^option transport.socket.ssl-cert-depth"}; + char keyval[50] = { + 0, + }; + int start = 0, end = 0, copy_len = 0; + regmatch_t result[1] = {{0}}; + + fp = fopen(SECURE_ACCESS_FILE, "r"); + if (!fp) + goto out; + + /* Check if any line matches with key */ + while (fgets(line, sizeof(line), fp) != NULL) { + if (regcomp(®cmpl, key, REG_EXTENDED)) { + goto out; } - - if (!found) { - gf_log (xl->name, GF_LOG_WARNING, - "option '%s' is not recognized", - pair->key); + if (!regexec(®cmpl, line, 1, result, 0)) { + start = result[0].rm_so; + end = result[0].rm_eo; + copy_len = end - start; + gf_strncpy(keyval, line + copy_len, sizeof(keyval)); + if (keyval[0]) { + cert_depth = atoi(keyval); + if (cert_depth == 0) + cert_depth = 1; /* Default SSL CERT DEPTH */ + break; + } } - return 0; + regfree(®cmpl); + } + +out: + if (fp) + fclose(fp); + return cert_depth; } +xlator_t * +glusterfs_get_last_xlator(glusterfs_graph_t *graph) +{ + xlator_t *trav = graph->first; + if (!trav) + return NULL; + + while (trav->next) + trav = trav->next; + + return trav; +} + +xlator_t * +glusterfs_mux_xlator_unlink(xlator_t *pxl, xlator_t *cxl) +{ + xlator_list_t *unlink = NULL; + xlator_list_t *prev = NULL; + xlator_list_t **tmp = NULL; + xlator_t *next_child = NULL; + xlator_t *xl = NULL; + + for (tmp = &pxl->children; *tmp; tmp = &(*tmp)->next) { + if ((*tmp)->xlator == cxl) { + unlink = *tmp; + *tmp = (*tmp)->next; + if (*tmp) + next_child = (*tmp)->xlator; + break; + } + prev = *tmp; + } + + if (!prev) + xl = pxl; + else if (prev->xlator) + xl = prev->xlator->graph->last_xl; + + if (xl) + xl->next = next_child; + if (next_child) + next_child->prev = xl; + + GF_FREE(unlink); + return next_child; +} int -glusterfs_graph_insert (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx, - const char *type, const char *name) +glusterfs_xlator_link(xlator_t *pxl, xlator_t *cxl) { - xlator_t *ixl = NULL; - xlator_list_t *xlchild = NULL; - xlator_list_t *xlparent = NULL; + xlator_list_t *xlchild = NULL; + xlator_list_t *xlparent = NULL; + xlator_list_t **tmp = NULL; - if (!ctx->master) { - gf_log ("glusterfs", GF_LOG_ERROR, - "volume \"%s\" can be added from command line only " - "on client side", type); + xlparent = (void *)GF_CALLOC(1, sizeof(*xlparent), + gf_common_mt_xlator_list_t); + if (!xlparent) + return -1; - return -1; - } + xlchild = (void *)GF_CALLOC(1, sizeof(*xlchild), + gf_common_mt_xlator_list_t); + if (!xlchild) { + GF_FREE(xlparent); - ixl = GF_CALLOC (1, sizeof (*ixl), gf_common_mt_xlator_t); - if (!ixl) - return -1; - - ixl->ctx = ctx; - ixl->graph = graph; - ixl->options = get_new_dict (); - if (!ixl->options) - goto err; - - ixl->name = gf_strdup (name); - if (!ixl->name) - goto err; - - if (xlator_set_type (ixl, type) == -1) { - gf_log ("glusterfs", GF_LOG_ERROR, - "%s (%s) initialization failed", - name, type); - return -1; - } + return -1; + } + xlparent->xlator = pxl; + for (tmp = &cxl->parents; *tmp; tmp = &(*tmp)->next) + ; + *tmp = xlparent; - /* children */ - xlchild = GF_CALLOC (sizeof (*xlchild), 1, gf_common_mt_xlator_list_t); - if (!xlchild) - goto err; - xlchild->xlator = graph->top; - ixl->children = xlchild; xlchild = NULL; + xlchild->xlator = cxl; + for (tmp = &pxl->children; *tmp; tmp = &(*tmp)->next) + ; + *tmp = xlchild; + return 0; +} - /* parent */ - xlparent = GF_CALLOC (sizeof (*xlparent), 1, - gf_common_mt_xlator_list_t); - if (!xlparent) - goto err; - xlparent->xlator = ixl; +void +glusterfs_graph_set_first(glusterfs_graph_t *graph, xlator_t *xl) +{ + xl->next = graph->first; + if (graph->first) + ((xlator_t *)graph->first)->prev = xl; + graph->first = xl; - ixl->next = graph->first; - graph->first = ixl; + graph->xl_count++; + xl->xl_id = graph->xl_count; +} - xlparent->next = ((xlator_t *)graph->top)->parents; - ((xlator_t *)graph->top)->parents = xlparent; +int +glusterfs_graph_insert(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx, + const char *type, const char *name, + gf_boolean_t autoload) +{ + xlator_t *ixl = NULL; - graph->top = ixl; + if (!ctx->master) { + gf_msg("glusterfs", GF_LOG_ERROR, 0, LG_MSG_VOLUME_ERROR, + "volume \"%s\" can be added from command line only " + "on client side", + type); - graph->xl_count++; + return -1; + } - return 0; -err: - xlator_destroy (ixl); + ixl = GF_CALLOC(1, sizeof(*ixl), gf_common_mt_xlator_t); + if (!ixl) return -1; + + ixl->ctx = ctx; + ixl->graph = graph; + ixl->options = dict_new(); + if (!ixl->options) + goto err; + + ixl->name = gf_strdup(name); + if (!ixl->name) + goto err; + + ixl->is_autoloaded = autoload; + + if (xlator_set_type(ixl, type) == -1) { + gf_msg("glusterfs", GF_LOG_ERROR, 0, LG_MSG_INIT_FAILED, + "%s (%s) initialization failed", name, type); + return -1; + } + + if (glusterfs_xlator_link(ixl, graph->top) == -1) + goto err; + glusterfs_graph_set_first(graph, ixl); + graph->top = ixl; + + return 0; +err: + xlator_destroy(ixl); + return -1; } +int +glusterfs_graph_acl(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->acl) + return 0; + + ret = glusterfs_graph_insert(graph, ctx, "system/posix-acl", + "posix-acl-autoload", 1); + return ret; +} int -glusterfs_graph_readonly (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx) +glusterfs_graph_worm(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx) { - int ret = 0; - cmd_args_t *cmd_args = NULL; + int ret = 0; + cmd_args_t *cmd_args = NULL; - cmd_args = &ctx->cmd_args; + cmd_args = &ctx->cmd_args; - if (!cmd_args->read_only) - return 0; + if (!cmd_args->worm) + return 0; - ret = glusterfs_graph_insert (graph, ctx, "features/read-only", - "readonly-autoload"); - return ret; + ret = glusterfs_graph_insert(graph, ctx, "features/worm", "worm-autoload", + 1); + return ret; } +int +glusterfs_graph_meta(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx) +{ + int ret = 0; + + if (!ctx->master) + return 0; + + ret = glusterfs_graph_insert(graph, ctx, "meta", "meta-autoload", 1); + return ret; +} int -glusterfs_graph_mac_compat (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx) +glusterfs_graph_mac_compat(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx) { - int ret = 0; - cmd_args_t *cmd_args = NULL; + int ret = 0; + cmd_args_t *cmd_args = NULL; - cmd_args = &ctx->cmd_args; + cmd_args = &ctx->cmd_args; - if (cmd_args->mac_compat == GF_OPTION_DISABLE) - return 0; + if (cmd_args->mac_compat == GF_OPTION_DISABLE) + return 0; - ret = glusterfs_graph_insert (graph, ctx, "features/mac-compat", - "mac-compat-autoload"); + ret = glusterfs_graph_insert(graph, ctx, "features/mac-compat", + "mac-compat-autoload", 1); - return ret; + 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) -{ - int ret = 0; - xlator_t *trav = NULL; - xlator_cmdline_option_t *cmd_option = NULL; - - trav = graph->first; - - while (trav) { - list_for_each_entry (cmd_option, - &cmd_args->xlator_options, cmd_args) { - if (!fnmatch (cmd_option->volume, - trav->name, FNM_NOESCAPE)) { - ret = dict_set_str (trav->options, - cmd_option->key, - cmd_option->value); - if (ret == 0) { - gf_log (trav->name, GF_LOG_WARNING, - "adding option '%s' for " - "volume '%s' with value '%s'", - cmd_option->key, trav->name, - cmd_option->value); - } else { - gf_log (trav->name, GF_LOG_WARNING, - "adding option '%s' for " - "volume '%s' failed: %s", - cmd_option->key, trav->name, - strerror (-ret)); - } - } +gf_add_cmdline_options(glusterfs_graph_t *graph, cmd_args_t *cmd_args) +{ + int ret = 0; + xlator_t *trav = NULL; + xlator_cmdline_option_t *cmd_option = NULL; + + trav = graph->first; + + while (trav) { + list_for_each_entry(cmd_option, &cmd_args->xlator_options, cmd_args) + { + if (!fnmatch(cmd_option->volume, trav->name, FNM_NOESCAPE)) { + ret = dict_set_str(trav->options, cmd_option->key, + cmd_option->value); + if (ret == 0) { + gf_msg(trav->name, GF_LOG_TRACE, 0, LG_MSG_VOL_OPTION_ADD, + "adding option '%s' for " + "volume '%s' with value '%s'", + cmd_option->key, trav->name, cmd_option->value); + } else { + gf_msg(trav->name, GF_LOG_WARNING, -ret, + LG_MSG_VOL_OPTION_ADD, + "adding option '%s' for " + "volume '%s' failed", + cmd_option->key, trav->name); } - trav = trav->next; + } } + trav = trav->next; + } } - int -glusterfs_graph_validate_options (glusterfs_graph_t *graph) +glusterfs_graph_validate_options(glusterfs_graph_t *graph) { - volume_opt_list_t *vol_opt = NULL; - xlator_t *trav = NULL; - int ret = -1; + xlator_t *trav = NULL; + int ret = -1; + char *errstr = NULL; - trav = graph->first; + trav = graph->first; - while (trav) { - if (list_empty (&trav->volume_options)) - continue; - - vol_opt = list_entry (trav->volume_options.next, - volume_opt_list_t, list); + while (trav) { + if (list_empty(&trav->volume_options)) { + trav = trav->next; + continue; + } - ret = validate_xlator_volume_options (trav, - vol_opt->given_opt); - if (ret) { - gf_log (trav->name, GF_LOG_ERROR, - "validating translator failed"); - return ret; - } - trav = trav->next; + ret = xlator_options_validate(trav, trav->options, &errstr); + if (ret) { + gf_msg(trav->name, GF_LOG_ERROR, 0, LG_MSG_VALIDATION_FAILED, + "validation failed: " + "%s", + errstr); + return ret; } + trav = trav->next; + } - return 0; + return 0; } - int -glusterfs_graph_init (glusterfs_graph_t *graph) +glusterfs_graph_init(glusterfs_graph_t *graph) { - xlator_t *trav = NULL; - int ret = -1; + xlator_t *trav = NULL; + int ret = -1; - trav = graph->first; + trav = graph->first; - while (trav) { - ret = xlator_init (trav); - if (ret) { - gf_log (trav->name, GF_LOG_ERROR, - "initializing translator failed"); - return ret; - } - trav = trav->next; + while (trav) { + ret = xlator_init(trav); + if (ret) { + gf_msg(trav->name, GF_LOG_ERROR, 0, LG_MSG_TRANSLATOR_INIT_FAILED, + "initializing translator failed"); + return ret; } + trav = trav->next; + } - return 0; + return 0; } - int -glusterfs_graph_unknown_options (glusterfs_graph_t *graph) +glusterfs_graph_deactivate(glusterfs_graph_t *graph) { - data_pair_t *pair = NULL; - xlator_t *trav = NULL; + xlator_t *top = NULL; - trav = graph->first; + if (graph == NULL) + goto out; - /* Validate again phase */ - while (trav) { - pair = trav->options->members_list; - while (pair) { - _log_if_option_is_invalid (trav, pair); - pair = pair->next; - } - trav = trav->next; - } + top = graph->top; + xlator_tree_fini(top); +out: + return 0; +} - return 0; +static int +_log_if_unknown_option(dict_t *dict, char *key, data_t *value, void *data) +{ + volume_option_t *found = NULL; + xlator_t *xl = NULL; + + xl = data; + + found = xlator_volume_option_get(xl, key); + + if (!found) { + gf_msg(xl->name, GF_LOG_DEBUG, 0, LG_MSG_XLATOR_OPTION_INVALID, + "option '%s' is not recognized", key); + } + + return 0; } +static void +_xlator_check_unknown_options(xlator_t *xl, void *data) +{ + dict_foreach(xl->options, _log_if_unknown_option, xl); +} -void -fill_uuid (char *uuid, int size) +static int +glusterfs_graph_unknown_options(glusterfs_graph_t *graph) { - char hostname[256] = {0,}; - struct timeval tv = {0,}; - struct tm now = {0, }; - char now_str[32]; + xlator_foreach(graph->first, _xlator_check_unknown_options, NULL); + return 0; +} - if (gettimeofday (&tv, NULL) == -1) { - gf_log ("graph", GF_LOG_ERROR, - "gettimeofday: failed %s", - strerror (errno)); - } +static void +fill_uuid(char *uuid, int size, struct timeval tv) +{ + char hostname[50] = { + 0, + }; + char now_str[GF_TIMESTR_SIZE]; - if (gethostname (hostname, 256) == -1) { - gf_log ("graph", GF_LOG_ERROR, - "gethostname: failed %s", - strerror (errno)); - } + if (gethostname(hostname, sizeof(hostname) - 1) != 0) { + gf_msg("graph", GF_LOG_ERROR, errno, LG_MSG_GETHOSTNAME_FAILED, + "gethostname failed"); + hostname[sizeof(hostname) - 1] = '\0'; + } - localtime_r (&tv.tv_sec, &now); - strftime (now_str, 32, "%Y/%m/%d-%H:%M:%S", &now); - snprintf (uuid, size, "%s-%d-%s:%"GF_PRI_SUSECONDS, - hostname, getpid(), now_str, tv.tv_usec); + gf_time_fmt_tv(now_str, sizeof now_str, &tv, gf_timefmt_dirent); + snprintf(uuid, size, "%s-%d-%s", hostname, getpid(), now_str); - return; + return; } +static int +glusterfs_graph_settop(glusterfs_graph_t *graph, char *volume_name, + gf_boolean_t exact_match) +{ + int ret = -1; + xlator_t *trav = NULL; + + if (!volume_name || !exact_match) { + graph->top = graph->first; + ret = 0; + } else { + for (trav = graph->first; trav; trav = trav->next) { + if (strcmp(trav->name, volume_name) == 0) { + graph->top = trav; + ret = 0; + break; + } + } + } + + return ret; +} int -glusterfs_graph_settop (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx) +glusterfs_graph_parent_up(glusterfs_graph_t *graph) { - const char *volume_name = NULL; - xlator_t *trav = NULL; + xlator_t *trav = NULL; + int ret = -1; - volume_name = ctx->cmd_args.volume_name; + trav = graph->first; - if (!volume_name) { - graph->top = graph->first; - return 0; + while (trav) { + if (!xlator_has_parent(trav)) { + ret = xlator_notify(trav, GF_EVENT_PARENT_UP, trav); } - for (trav = graph->first; trav; trav = trav->next) { - if (strcmp (trav->name, volume_name) == 0) { - graph->top = trav; - return 0; - } - } + if (ret) + break; + + trav = trav->next; + } + + return ret; +} + +int +glusterfs_graph_prepare(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx, + char *volume_name) +{ + xlator_t *trav = NULL; + int ret = 0; + + /* XXX: CHECKSUM */ + + /* XXX: attach to -n volname */ + /* A '/' in the volume name suggests brick multiplexing is used, find + * the top of the (sub)graph. The volname MUST match the subvol in this + * case. In other cases (like for gfapi) the default top for the + * (sub)graph is ok. */ + if (!volume_name) { + /* GlusterD does not pass a volume_name */ + ret = glusterfs_graph_settop(graph, volume_name, _gf_false); + } else if (strncmp(volume_name, "/snaps/", 7) == 0) { + /* snap shots have their top xlator named like "/snaps/..." */ + ret = glusterfs_graph_settop(graph, volume_name, _gf_false); + } else if (volume_name[0] == '/') { + /* brick multiplexing passes the brick path */ + ret = glusterfs_graph_settop(graph, volume_name, _gf_true); + } else { + ret = glusterfs_graph_settop(graph, volume_name, _gf_false); + } + + if (ret) { + gf_msg("graph", GF_LOG_ERROR, EINVAL, LG_MSG_GRAPH_ERROR, + "glusterfs graph settop failed"); + errno = EINVAL; + return -1; + } + + /* XXX: WORM VOLUME */ + ret = glusterfs_graph_worm(graph, ctx); + if (ret) { + gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_GRAPH_ERROR, + "glusterfs graph worm failed"); + return -1; + } + ret = glusterfs_graph_acl(graph, ctx); + if (ret) { + gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_GRAPH_ERROR, + "glusterfs graph ACL failed"); + return -1; + } + /* XXX: MAC COMPAT */ + ret = glusterfs_graph_mac_compat(graph, ctx); + if (ret) { + gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_GRAPH_ERROR, + "glusterfs graph mac compat failed"); return -1; + } + + /* XXX: gfid-access */ + ret = glusterfs_graph_gfid_access(graph, ctx); + if (ret) { + gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_GRAPH_ERROR, + "glusterfs graph 'gfid-access' failed"); + return -1; + } + + /* XXX: topmost xlator */ + ret = glusterfs_graph_meta(graph, ctx); + if (ret) { + gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_GRAPH_ERROR, + "glusterfs graph meta failed"); + return -1; + } + + /* XXX: this->ctx setting */ + for (trav = graph->first; trav; trav = trav->next) { + trav->ctx = ctx; + } + + /* XXX: DOB setting */ + gettimeofday(&graph->dob, NULL); + + fill_uuid(graph->graph_uuid, sizeof(graph->graph_uuid), graph->dob); + + graph->id = ctx->graph_id++; + + /* XXX: --xlator-option additions */ + gf_add_cmdline_options(graph, &ctx->cmd_args); + + return 0; +} + +static xlator_t * +glusterfs_root(glusterfs_graph_t *graph) +{ + return graph->first; +} + +static int +glusterfs_is_leaf(xlator_t *xl) +{ + int ret = 0; + + if (!xl->children) + ret = 1; + + return ret; +} + +static uint32_t +glusterfs_count_leaves(xlator_t *xl) +{ + int n = 0; + xlator_list_t *list = NULL; + + if (glusterfs_is_leaf(xl)) + n = 1; + else + for (list = xl->children; list; list = list->next) + n += glusterfs_count_leaves(list->xlator); + + return n; } +int +glusterfs_get_leaf_count(glusterfs_graph_t *graph) +{ + return graph->leaf_count; +} + +static int +_glusterfs_leaf_position(xlator_t *tgt, int *id, xlator_t *xl) +{ + xlator_list_t *list = NULL; + int found = 0; + + if (xl == tgt) + found = 1; + else if (glusterfs_is_leaf(xl)) + *id += 1; + else + for (list = xl->children; !found && list; list = list->next) + found = _glusterfs_leaf_position(tgt, id, list->xlator); + + return found; +} int -glusterfs_graph_parent_up (glusterfs_graph_t *graph) +glusterfs_leaf_position(xlator_t *tgt) { - xlator_t *trav = NULL; - int ret = -1; + xlator_t *root = NULL; + int pos = 0; - trav = graph->first; + root = glusterfs_root(tgt->graph); - while (trav) { - if (!xlator_has_parent (trav)) { - ret = xlator_notify (trav, GF_EVENT_PARENT_UP, trav); - } + if (!_glusterfs_leaf_position(tgt, &pos, root)) + pos = -1; - if (ret) - break; + return pos; +} - trav = trav->next; +static int +_glusterfs_reachable_leaves(xlator_t *base, xlator_t *xl, dict_t *leaves) +{ + xlator_list_t *list = NULL; + int err = 1; + int pos = 0; + char *strpos = NULL; + + if (glusterfs_is_leaf(xl)) { + pos = glusterfs_leaf_position(xl); + if (pos < 0) + goto out; + + err = gf_asprintf(&strpos, "%d", pos); + + if (err >= 0) { + err = dict_set_static_ptr(leaves, strpos, base); + GF_FREE(strpos); } + } else { + for (err = 0, list = xl->children; !err && list; list = list->next) + err = _glusterfs_reachable_leaves(base, list->xlator, leaves); + } - return ret; +out: + return err; } +/* + * This function determines which leaves are children (or grandchildren) + * of the given base. The base may have multiple sub volumes. Each sub + * volumes in turn may have sub volumes.. until the leaves are reached. + * Each leaf is numbered 1,2,3,...etc. + * + * The base translator calls this function to see which of *its* subvolumes + * it would forward an FOP to, to *get to* a particular leaf. + * That information is built into the "leaves" dictionary. + * key:destination leaf# -> value:base subvolume xlator. + */ int -glusterfs_graph_prepare (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx) +glusterfs_reachable_leaves(xlator_t *base, dict_t *leaves) { - xlator_t *trav = NULL; - int ret = 0; + xlator_list_t *list = NULL; + int err = 0; - /* XXX: CHECKSUM */ + for (list = base->children; !err && list; list = list->next) + err = _glusterfs_reachable_leaves(list->xlator, list->xlator, leaves); - /* XXX: attach to -n volname */ - ret = glusterfs_graph_settop (graph, ctx); - if (ret) - return -1; + return err; +} - /* XXX: RO VOLUME */ - ret = glusterfs_graph_readonly (graph, ctx); - if (ret) - return -1; +int +glusterfs_graph_activate(glusterfs_graph_t *graph, glusterfs_ctx_t *ctx) +{ + int ret = 0; + xlator_t *root = NULL; - /* XXX: MAC COMPAT */ - ret = glusterfs_graph_mac_compat (graph, ctx); - if (ret) - return -1; + root = glusterfs_root(graph); - /* XXX: this->ctx setting */ - for (trav = graph->first; trav; trav = trav->next) { - trav->ctx = ctx; + graph->leaf_count = glusterfs_count_leaves(root); + + /* XXX: all xlator options validation */ + ret = glusterfs_graph_validate_options(graph); + if (ret) { + gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_VALIDATION_FAILED, + "validate options failed"); + return ret; + } + + /* XXX: perform init () */ + ret = glusterfs_graph_init(graph); + if (ret) { + gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_GRAPH_INIT_FAILED, + "init failed"); + return ret; + } + + ret = glusterfs_graph_unknown_options(graph); + if (ret) { + gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_UNKNOWN_OPTIONS_FAILED, + "unknown options " + "failed"); + return ret; + } + + /* XXX: log full graph (_gf_dump_details) */ + + list_add(&graph->list, &ctx->graphs); + ctx->active = graph; + + /* XXX: attach to master and set active pointer */ + if (ctx->master) { + ret = xlator_notify(ctx->master, GF_EVENT_GRAPH_NEW, graph); + if (ret) { + gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_EVENT_NOTIFY_FAILED, + "graph new notification failed"); + return ret; } + ((xlator_t *)ctx->master)->next = graph->top; + } + + /* XXX: perform parent up */ + ret = glusterfs_graph_parent_up(graph); + if (ret) { + gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_EVENT_NOTIFY_FAILED, + "parent up notification failed"); + return ret; + } - /* XXX: DOB setting */ - gettimeofday (&graph->dob, NULL); + return 0; +} - fill_uuid (graph->graph_uuid, 128); +int +xlator_equal_rec(xlator_t *xl1, xlator_t *xl2) +{ + xlator_list_t *trav1 = NULL; + xlator_list_t *trav2 = NULL; + int ret = 0; - /* XXX: --xlator-option additions */ - gf_add_cmdline_options (graph, &ctx->cmd_args); + if (xl1 == NULL || xl2 == NULL) { + gf_msg_debug("xlator", 0, "invalid argument"); + return -1; + } + + trav1 = xl1->children; + trav2 = xl2->children; + + while (trav1 && trav2) { + ret = xlator_equal_rec(trav1->xlator, trav2->xlator); + if (ret) { + gf_msg_debug("glusterfsd-mgmt", 0, + "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/distribute and cluster/nufa share the same + xlator name + */ + if (strcmp(xl1->type, xl2->type)) { + ret = -1; + goto out; + } +out: + return ret; +} - return 0; +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; + xlator_list_t *ltrav; + + trav1 = graph1->first; + trav2 = graph2->first; + + if (strcmp(trav2->type, "protocol/server") == 0) { + trav2 = trav2->children->xlator; + for (ltrav = trav1->children; ltrav; ltrav = ltrav->next) { + trav1 = ltrav->xlator; + if (!trav1->cleanup_starting && !strcmp(trav1->name, trav2->name)) { + break; + } + } + if (!ltrav) { + return _gf_false; + } + } + + ret = xlator_equal_rec(trav1, trav2); + + if (ret) { + gf_msg_debug("glusterfsd-mgmt", 0, "graphs are not equal"); + ret = _gf_false; + goto out; + } + + ret = _gf_true; + gf_msg_debug("glusterfsd-mgmt", 0, "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(FILE *newvolfile_fp, glusterfs_ctx_t *ctx) +{ + glusterfs_graph_t *oldvolfile_graph = NULL; + glusterfs_graph_t *newvolfile_graph = NULL; + + int ret = -1; + + if (!ctx) { + gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, 0, LG_MSG_CTX_NULL, + "ctx is NULL"); + goto out; + } + + oldvolfile_graph = ctx->active; + if (!oldvolfile_graph) { + ret = 1; + goto out; + } + + newvolfile_graph = glusterfs_graph_construct(newvolfile_fp); + + if (!newvolfile_graph) { + goto out; + } + + glusterfs_graph_prepare(newvolfile_graph, ctx, ctx->cmd_args.volume_name); + + if (!is_graph_topology_equal(oldvolfile_graph, newvolfile_graph)) { + ret = 1; + gf_msg_debug("glusterfsd-mgmt", 0, + "Graph topology not " + "equal(should call INIT)"); + goto out; + } + + gf_msg_debug("glusterfsd-mgmt", 0, + "Only options have changed in the" + " new graph"); + + ret = glusterfs_graph_reconfigure(oldvolfile_graph, newvolfile_graph); + if (ret) { + gf_msg_debug("glusterfsd-mgmt", 0, + "Could not reconfigure " + "new options in old graph"); + goto out; + } + + ret = 0; +out: + + if (newvolfile_graph) + glusterfs_graph_destroy(newvolfile_graph); + + return ret; +} + +/* This function need to remove. This added to support gfapi volfile + * reconfigure. + */ int -glusterfs_graph_activate (glusterfs_graph_t *graph, glusterfs_ctx_t *ctx) +gf_volfile_reconfigure(int oldvollen, FILE *newvolfile_fp, glusterfs_ctx_t *ctx, + const char *oldvolfile) { - int ret = 0; + glusterfs_graph_t *oldvolfile_graph = NULL; + glusterfs_graph_t *newvolfile_graph = NULL; + FILE *oldvolfile_fp = NULL; + /*Since the function mkstemp() replaces XXXXXX, + * assigning it to a variable + */ + char temp_file[] = "/tmp/temp_vol_file_XXXXXX"; + gf_boolean_t active_graph_found = _gf_true; + + int ret = -1; + int u_ret = -1; + int file_desc = -1; + + if (!oldvollen) { + ret = 1; // Has to call INIT for the whole graph + goto out; + } + + if (!ctx) { + gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, 0, LG_MSG_CTX_NULL, + "ctx is NULL"); + goto out; + } + + oldvolfile_graph = ctx->active; + if (!oldvolfile_graph) { + active_graph_found = _gf_false; + gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, 0, LG_MSG_ACTIVE_GRAPH_NULL, + "glusterfs_ctx->active is NULL"); + + /* coverity[secure_temp] mkstemp uses 0600 as the mode and is safe */ + file_desc = mkstemp(temp_file); + if (file_desc < 0) { + gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, errno, + LG_MSG_TMPFILE_CREATE_FAILED, + "Unable to " + "create temporary volfile"); + goto out; + } - /* XXX: all xlator options validation */ - ret = glusterfs_graph_validate_options (graph); - if (ret) - return ret; + /*Calling unlink so that when the file is closed or program + *terminates the tempfile is deleted. + */ + u_ret = sys_unlink(temp_file); + + if (u_ret < 0) { + gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, errno, + LG_MSG_TMPFILE_DELETE_FAILED, + "Temporary file" + " delete failed."); + sys_close(file_desc); + goto out; + } - /* XXX: perform init () */ - ret = glusterfs_graph_init (graph); - if (ret) - return ret; + oldvolfile_fp = fdopen(file_desc, "w+b"); + if (!oldvolfile_fp) + goto out; - ret = glusterfs_graph_unknown_options (graph); - if (ret) - return ret; + 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; + } + + glusterfs_graph_prepare(newvolfile_graph, ctx, ctx->cmd_args.volume_name); + + if (!is_graph_topology_equal(oldvolfile_graph, newvolfile_graph)) { + ret = 1; + gf_msg_debug("glusterfsd-mgmt", 0, + "Graph topology not " + "equal(should call INIT)"); + goto out; + } + + gf_msg_debug("glusterfsd-mgmt", 0, + "Only options have changed in the" + " new graph"); + + /* */ + ret = glusterfs_graph_reconfigure(oldvolfile_graph, newvolfile_graph); + if (ret) { + gf_msg_debug("glusterfsd-mgmt", 0, + "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) +{ + xlator_t *old_xl = NULL; + xlator_t *new_xl = NULL; + xlator_list_t *trav; + + GF_ASSERT(oldgraph); + GF_ASSERT(newgraph); + + old_xl = oldgraph->first; + while (old_xl->is_autoloaded) { + old_xl = old_xl->children->xlator; + } + + new_xl = newgraph->first; + while (new_xl->is_autoloaded) { + new_xl = new_xl->children->xlator; + } + + if (strcmp(old_xl->type, "protocol/server") != 0) { + return xlator_tree_reconfigure(old_xl, new_xl); + } + + /* Some options still need to be handled by the server translator. */ + if (old_xl->reconfigure) { + old_xl->reconfigure(old_xl, new_xl->options); + } + + (void)copy_opts_to_child(new_xl, FIRST_CHILD(new_xl), "*auth*"); + new_xl = FIRST_CHILD(new_xl); + + for (trav = old_xl->children; trav; trav = trav->next) { + if (!trav->xlator->cleanup_starting && + !strcmp(trav->xlator->name, new_xl->name)) { + return xlator_tree_reconfigure(trav->xlator, new_xl); + } + } - /* XXX: log full graph (_gf_dump_details) */ + return -1; +} - list_add (&graph->list, &ctx->graphs); - ctx->active = graph; +int +glusterfs_graph_destroy_residual(glusterfs_graph_t *graph) +{ + int ret = -1; - /* XXX: attach to master and set active pointer */ - if (ctx->master) - ret = xlator_notify (ctx->master, GF_EVENT_GRAPH_NEW, graph); - if (ret) - return ret; + if (graph == NULL) + return ret; - /* XXX: perform parent up */ - ret = glusterfs_graph_parent_up (graph); - if (ret) - return ret; + ret = xlator_tree_free_memacct(graph->first); + list_del_init(&graph->list); + pthread_mutex_destroy(&graph->mutex); + pthread_cond_destroy(&graph->child_down_cond); + GF_FREE(graph); - return 0; + return ret; } +/* This function destroys all the xlator members except for the + * xlator strcuture and its mem accounting field. + * + * If otherwise, it would destroy the master xlator object as well + * its mem accounting, which would mean after calling glusterfs_graph_destroy() + * there cannot be any reference to GF_FREE() from the master xlator, this is + * not possible because of the following dependencies: + * - glusterfs_ctx_t will have mem pools allocated by the master xlators + * - xlator objects will have references to those mem pools(g: dict) + * + * Ordering the freeing in any of the order will also not solve the dependency: + * - Freeing xlator objects(including memory accounting) before mem pools + * destruction will mean not use GF_FREE while destroying mem pools. + * - Freeing mem pools and then destroying xlator objects would lead to crashes + * when xlator tries to unref dict or other mem pool objects. + * + * Hence the way chosen out of this interdependency is to split xlator object + * free into two stages: + * - Free all the xlator members excpet for its mem accounting structure + * - Free all the mem accouting structures of xlator along with the xlator + * object itself. + */ +int +glusterfs_graph_destroy(glusterfs_graph_t *graph) +{ + int ret = 0; + + GF_VALIDATE_OR_GOTO("graph", graph, out); + + ret = xlator_tree_free_members(graph->first); + + ret = glusterfs_graph_destroy_residual(graph); +out: + return ret; +} int -glusterfs_graph_destroy (glusterfs_graph_t *graph) +glusterfs_graph_fini(glusterfs_graph_t *graph) { + xlator_t *trav = NULL; + + trav = graph->first; + + while (trav) { + if (trav->init_succeeded) { + trav->cleanup_starting = 1; + trav->fini(trav); + if (trav->local_pool) { + mem_pool_destroy(trav->local_pool); + trav->local_pool = NULL; + } + if (trav->itable) { + inode_table_destroy(trav->itable); + trav->itable = NULL; + } + trav->init_succeeded = 0; + } + trav = trav->next; + } + + return 0; +} + +int +glusterfs_graph_attach(glusterfs_graph_t *orig_graph, char *path, + glusterfs_graph_t **newgraph) +{ + xlator_t *this = THIS; + FILE *fp; + glusterfs_graph_t *graph; + xlator_t *xl; + char *volfile_id = NULL; + char *volfile_content = NULL; + struct stat stbuf = { + 0, + }; + size_t file_len = -1; + gf_volfile_t *volfile_obj = NULL; + int ret = -1; + char sha256_hash[SHA256_DIGEST_LENGTH] = { + 0, + }; + + if (!orig_graph) { + return -EINVAL; + } + + ret = sys_stat(path, &stbuf); + if (ret < 0) { + gf_log(THIS->name, GF_LOG_ERROR, "Unable to stat %s (%s)", path, + strerror(errno)); + return -EINVAL; + } + + file_len = stbuf.st_size; + volfile_content = GF_MALLOC(file_len + 1, gf_common_mt_char); + if (!volfile_content) + return -ENOMEM; + + fp = fopen(path, "r"); + if (!fp) { + gf_log(THIS->name, GF_LOG_WARNING, "oops, %s disappeared on us", path); + GF_FREE(volfile_content); + return -EIO; + } + + ret = fread(volfile_content, sizeof(char), file_len, fp); + if (ret == file_len) { + glusterfs_compute_sha256((const unsigned char *)volfile_content, + file_len, sha256_hash); + } else { + gf_log(THIS->name, GF_LOG_ERROR, + "read failed on path %s. File size=%" GF_PRI_SIZET + "read size=%d", + path, file_len, ret); + GF_FREE(volfile_content); + fclose(fp); + return -EIO; + } + + GF_FREE(volfile_content); + + graph = glusterfs_graph_construct(fp); + fclose(fp); + if (!graph) { + gf_log(this->name, GF_LOG_WARNING, "could not create graph from %s", + path); + return -EIO; + } + + /* + * If there's a server translator on top, we want whatever's below + * that. + */ + xl = graph->first; + if (strcmp(xl->type, "protocol/server") == 0) { + (void)copy_opts_to_child(xl, FIRST_CHILD(xl), "*auth*"); + xl = FIRST_CHILD(xl); + } + graph->first = xl; + *newgraph = graph; + + volfile_id = strstr(path, "/snaps/"); + if (!volfile_id) { + volfile_id = rindex(path, '/'); + if (volfile_id) { + ++volfile_id; + } + } + if (volfile_id) { + xl->volfile_id = gf_strdup(volfile_id); + /* There's a stray ".vol" at the end. */ + xl->volfile_id[strlen(xl->volfile_id) - 4] = '\0'; + } + + /* TODO memory leaks everywhere need to free graph in case of error */ + if (glusterfs_graph_prepare(graph, this->ctx, xl->name)) { + gf_log(this->name, GF_LOG_WARNING, + "failed to prepare graph for xlator %s", xl->name); + return -EIO; + } else if (glusterfs_graph_init(graph)) { + gf_log(this->name, GF_LOG_WARNING, + "failed to initialize graph for xlator %s", xl->name); + return -EIO; + } else if (glusterfs_xlator_link(orig_graph->top, graph->top)) { + gf_log(this->name, GF_LOG_WARNING, + "failed to link the graphs for xlator %s ", xl->name); + return -EIO; + } + + if (!volfile_obj) { + volfile_obj = GF_CALLOC(1, sizeof(gf_volfile_t), gf_common_volfile_t); + if (!volfile_obj) { + return -EIO; + } + } + + INIT_LIST_HEAD(&volfile_obj->volfile_list); + snprintf(volfile_obj->vol_id, sizeof(volfile_obj->vol_id), "%s", + xl->volfile_id); + memcpy(volfile_obj->volfile_checksum, sha256_hash, + sizeof(volfile_obj->volfile_checksum)); + list_add(&volfile_obj->volfile_list, &this->ctx->volfile_list); + + return 0; +} +int +glusterfs_muxsvc_cleanup_parent(glusterfs_ctx_t *ctx, + glusterfs_graph_t *parent_graph) +{ + if (parent_graph) { + if (parent_graph->first) { + xlator_destroy(parent_graph->first); + } + ctx->active = NULL; + GF_FREE(parent_graph); + parent_graph = NULL; + } + return 0; +} + +void * +glusterfs_graph_cleanup(void *arg) +{ + glusterfs_graph_t *graph = NULL; + glusterfs_ctx_t *ctx = THIS->ctx; + int ret = -1; + graph = arg; + + if (!graph) + return NULL; + + /* To destroy the graph, fitst sent a GF_EVENT_PARENT_DOWN + * Then wait for GF_EVENT_CHILD_DOWN to get on the top + * xl. Once we have GF_EVENT_CHILD_DOWN event, then proceed + * to fini. + * + * During fini call, this will take a last unref on rpc and + * rpc_transport_object. + */ + if (graph->first) + default_notify(graph->first, GF_EVENT_PARENT_DOWN, graph->first); + + ret = pthread_mutex_lock(&graph->mutex); + if (ret != 0) { + gf_msg("glusterfs", GF_LOG_ERROR, EAGAIN, LG_MSG_GRAPH_CLEANUP_FAILED, + "Failed to acquire a lock"); + goto out; + } + /* check and wait for CHILD_DOWN for top xlator*/ + while (graph->used) { + ret = pthread_cond_wait(&graph->child_down_cond, &graph->mutex); + if (ret != 0) + gf_msg("glusterfs", GF_LOG_INFO, 0, LG_MSG_GRAPH_CLEANUP_FAILED, + "cond wait failed "); + } + + ret = pthread_mutex_unlock(&graph->mutex); + if (ret != 0) { + gf_msg("glusterfs", GF_LOG_ERROR, EAGAIN, LG_MSG_GRAPH_CLEANUP_FAILED, + "Failed to release a lock"); + } + + /* Though we got a child down on top xlator, we have to wait until + * all the notifier to exit. Because there should not be any threads + * that access xl variables. + */ + pthread_mutex_lock(&ctx->notify_lock); + { + while (ctx->notifying) + pthread_cond_wait(&ctx->notify_cond, &ctx->notify_lock); + } + pthread_mutex_unlock(&ctx->notify_lock); + + pthread_mutex_lock(&ctx->cleanup_lock); + { + glusterfs_graph_fini(graph); + glusterfs_graph_destroy(graph); + } + pthread_mutex_unlock(&ctx->cleanup_lock); +out: + return NULL; +} + +glusterfs_graph_t * +glusterfs_muxsvc_setup_parent_graph(glusterfs_ctx_t *ctx, char *name, + char *type) +{ + glusterfs_graph_t *parent_graph = NULL; + xlator_t *ixl = NULL; + int ret = -1; + parent_graph = GF_CALLOC(1, sizeof(*parent_graph), + gf_common_mt_glusterfs_graph_t); + if (!parent_graph) + goto out; + + INIT_LIST_HEAD(&parent_graph->list); + + ctx->active = parent_graph; + ixl = GF_CALLOC(1, sizeof(*ixl), gf_common_mt_xlator_t); + if (!ixl) + goto out; + + ixl->ctx = ctx; + ixl->graph = parent_graph; + ixl->options = dict_new(); + if (!ixl->options) + goto out; + + ixl->name = gf_strdup(name); + if (!ixl->name) + goto out; + + ixl->is_autoloaded = 1; + + if (xlator_set_type(ixl, type) == -1) { + gf_msg("glusterfs", GF_LOG_ERROR, EINVAL, LG_MSG_GRAPH_SETUP_FAILED, + "%s (%s) set type failed", name, type); + goto out; + } + + glusterfs_graph_set_first(parent_graph, ixl); + parent_graph->top = ixl; + ixl = NULL; + + gettimeofday(&parent_graph->dob, NULL); + fill_uuid(parent_graph->graph_uuid, 128, parent_graph->dob); + parent_graph->id = ctx->graph_id++; + ret = 0; +out: + if (ixl) + xlator_destroy(ixl); + + if (ret) { + glusterfs_muxsvc_cleanup_parent(ctx, parent_graph); + parent_graph = NULL; + } + return parent_graph; +} + +int +glusterfs_svc_mux_pidfile_cleanup(gf_volfile_t *volfile_obj) +{ + if (!volfile_obj || !volfile_obj->pidfp) return 0; + + gf_msg_trace("glusterfsd", 0, "pidfile %s cleanup", volfile_obj->vol_id); + + lockf(fileno(volfile_obj->pidfp), F_ULOCK, 0); + fclose(volfile_obj->pidfp); + volfile_obj->pidfp = NULL; + + return 0; +} + +int +glusterfs_process_svc_detach(glusterfs_ctx_t *ctx, gf_volfile_t *volfile_obj) +{ + xlator_t *last_xl = NULL; + glusterfs_graph_t *graph = NULL; + glusterfs_graph_t *parent_graph = NULL; + pthread_t clean_graph = { + 0, + }; + int ret = -1; + xlator_t *xl = NULL; + + if (!ctx || !ctx->active || !volfile_obj) + goto out; + + pthread_mutex_lock(&ctx->cleanup_lock); + { + parent_graph = ctx->active; + graph = volfile_obj->graph; + if (!graph) + goto unlock; + if (graph->first) + xl = graph->first; + + last_xl = graph->last_xl; + if (last_xl) + last_xl->next = NULL; + if (!xl || xl->cleanup_starting) + goto unlock; + + xl->cleanup_starting = 1; + gf_msg("mgmt", GF_LOG_INFO, 0, LG_MSG_GRAPH_DETACH_STARTED, + "detaching child %s", volfile_obj->vol_id); + + list_del_init(&volfile_obj->volfile_list); + glusterfs_mux_xlator_unlink(parent_graph->top, xl); + glusterfs_svc_mux_pidfile_cleanup(volfile_obj); + parent_graph->last_xl = glusterfs_get_last_xlator(parent_graph); + parent_graph->xl_count -= graph->xl_count; + parent_graph->leaf_count -= graph->leaf_count; + parent_graph->id++; + ret = 0; + } +unlock: + pthread_mutex_unlock(&ctx->cleanup_lock); +out: + if (!ret) { + list_del_init(&volfile_obj->volfile_list); + if (graph) { + ret = gf_thread_create_detached( + &clean_graph, glusterfs_graph_cleanup, graph, "graph_clean"); + if (ret) { + gf_msg("glusterfs", GF_LOG_ERROR, EINVAL, + LG_MSG_GRAPH_CLEANUP_FAILED, + "%s failed to create clean " + "up thread", + volfile_obj->vol_id); + ret = 0; + } + } + GF_FREE(volfile_obj); + } + return ret; +} + +int +glusterfs_svc_mux_pidfile_setup(gf_volfile_t *volfile_obj, const char *pid_file) +{ + int ret = -1; + FILE *pidfp = NULL; + + if (!pid_file || !volfile_obj) + goto out; + + if (volfile_obj->pidfp) { + ret = 0; + goto out; + } + pidfp = fopen(pid_file, "a+"); + if (!pidfp) { + goto out; + } + volfile_obj->pidfp = pidfp; + + ret = lockf(fileno(pidfp), F_TLOCK, 0); + if (ret) { + ret = 0; + goto out; + } +out: + return ret; } +int +glusterfs_svc_mux_pidfile_update(gf_volfile_t *volfile_obj, + const char *pid_file, pid_t pid) +{ + int ret = 0; + FILE *pidfp = NULL; + int old_pid; + + if (!volfile_obj->pidfp) { + ret = glusterfs_svc_mux_pidfile_setup(volfile_obj, pid_file); + if (ret == -1) + goto out; + } + pidfp = volfile_obj->pidfp; + ret = fscanf(pidfp, "%d", &old_pid); + if (ret <= 0) { + goto update; + } + if (old_pid == pid) { + ret = 0; + goto out; + } else { + gf_msg("mgmt", GF_LOG_INFO, 0, LG_MSG_GRAPH_ATTACH_PID_FILE_UPDATED, + "Old pid=%d found in pidfile %s. Cleaning the old pid and " + "Updating new pid=%d", + old_pid, pid_file, pid); + } +update: + ret = sys_ftruncate(fileno(pidfp), 0); + if (ret) { + gf_msg("glusterfsd", GF_LOG_ERROR, errno, + LG_MSG_GRAPH_ATTACH_PID_FILE_UPDATED, + "pidfile %s truncation failed", pid_file); + goto out; + } + + ret = fprintf(pidfp, "%d\n", pid); + if (ret <= 0) { + gf_msg("glusterfsd", GF_LOG_ERROR, errno, + LG_MSG_GRAPH_ATTACH_PID_FILE_UPDATED, "pidfile %s write failed", + pid_file); + goto out; + } + + ret = fflush(pidfp); + if (ret) { + gf_msg("glusterfsd", GF_LOG_ERROR, errno, + LG_MSG_GRAPH_ATTACH_PID_FILE_UPDATED, "pidfile %s write failed", + pid_file); + goto out; + } +out: + return ret; +} +int +glusterfs_update_mux_pid(dict_t *dict, gf_volfile_t *volfile_obj) +{ + char *file = NULL; + int ret = -1; + + GF_VALIDATE_OR_GOTO("graph", dict, out); + GF_VALIDATE_OR_GOTO("graph", volfile_obj, out); + + ret = dict_get_str(dict, "pidfile", &file); + if (ret < 0) { + gf_msg("mgmt", GF_LOG_ERROR, EINVAL, LG_MSG_GRAPH_SETUP_FAILED, + "Failed to get pidfile from dict for volfile_id=%s", + volfile_obj->vol_id); + } + + ret = glusterfs_svc_mux_pidfile_update(volfile_obj, file, getpid()); + if (ret < 0) { + ret = -1; + gf_msg("mgmt", GF_LOG_ERROR, EINVAL, LG_MSG_GRAPH_SETUP_FAILED, + "Failed to update " + "the pidfile for volfile_id=%s", + volfile_obj->vol_id); + + goto out; + } + + if (ret == 1) + gf_msg("mgmt", GF_LOG_INFO, 0, LG_MSG_GRAPH_ATTACH_PID_FILE_UPDATED, + "PID %d updated in pidfile=%s", getpid(), file); + ret = 0; +out: + return ret; +} +int +glusterfs_process_svc_attach_volfp(glusterfs_ctx_t *ctx, FILE *fp, + char *volfile_id, char *checksum, + dict_t *dict) +{ + glusterfs_graph_t *graph = NULL; + glusterfs_graph_t *parent_graph = NULL; + glusterfs_graph_t *clean_graph = NULL; + int ret = -1; + xlator_t *xl = NULL; + xlator_t *last_xl = NULL; + gf_volfile_t *volfile_obj = NULL; + pthread_t thread_id = { + 0, + }; + + if (!ctx) + goto out; + parent_graph = ctx->active; + graph = glusterfs_graph_construct(fp); + if (!graph) { + gf_msg("glusterfsd", GF_LOG_ERROR, EINVAL, LG_MSG_GRAPH_ATTACH_FAILED, + "failed to construct the graph"); + goto out; + } + graph->parent_down = 0; + graph->last_xl = glusterfs_get_last_xlator(graph); + + for (xl = graph->first; xl; xl = xl->next) { + if (strcmp(xl->type, "mount/fuse") == 0) { + gf_msg("glusterfsd", GF_LOG_ERROR, EINVAL, + LG_MSG_GRAPH_ATTACH_FAILED, + "fuse xlator cannot be specified in volume file"); + goto out; + } + } + + graph->leaf_count = glusterfs_count_leaves(glusterfs_root(graph)); + xl = graph->first; + /* TODO memory leaks everywhere need to free graph in case of error */ + if (glusterfs_graph_prepare(graph, ctx, xl->name)) { + gf_msg("glusterfsd", GF_LOG_WARNING, EINVAL, LG_MSG_GRAPH_ATTACH_FAILED, + "failed to prepare graph for xlator %s", xl->name); + ret = -1; + goto out; + } else if (glusterfs_graph_init(graph)) { + gf_msg("glusterfsd", GF_LOG_WARNING, EINVAL, LG_MSG_GRAPH_ATTACH_FAILED, + "failed to initialize graph for xlator %s", xl->name); + ret = -1; + goto out; + } else if (glusterfs_graph_parent_up(graph)) { + gf_msg("glusterfsd", GF_LOG_WARNING, EINVAL, LG_MSG_GRAPH_ATTACH_FAILED, + "failed to link the graphs for xlator %s ", xl->name); + ret = -1; + goto out; + } + + if (!parent_graph) { + parent_graph = glusterfs_muxsvc_setup_parent_graph(ctx, "glustershd", + "debug/io-stats"); + if (!parent_graph) + goto out; + ((xlator_t *)parent_graph->top)->next = xl; + clean_graph = parent_graph; + } else { + last_xl = parent_graph->last_xl; + if (last_xl) + last_xl->next = xl; + xl->prev = last_xl; + } + parent_graph->last_xl = graph->last_xl; + + ret = glusterfs_xlator_link(parent_graph->top, xl); + if (ret) { + gf_msg("graph", GF_LOG_ERROR, 0, LG_MSG_EVENT_NOTIFY_FAILED, + "parent up notification failed"); + goto out; + } + parent_graph->xl_count += graph->xl_count; + parent_graph->leaf_count += graph->leaf_count; + parent_graph->id++; + + volfile_obj = GF_CALLOC(1, sizeof(gf_volfile_t), gf_common_volfile_t); + if (!volfile_obj) { + ret = -1; + goto out; + } + volfile_obj->pidfp = NULL; + snprintf(volfile_obj->vol_id, sizeof(volfile_obj->vol_id), "%s", + volfile_id); + + if (strcmp(ctx->cmd_args.process_name, "glustershd") == 0) { + ret = glusterfs_update_mux_pid(dict, volfile_obj); + if (ret == -1) { + GF_FREE(volfile_obj); + goto out; + } + } + + graph->used = 1; + parent_graph->id++; + list_add(&graph->list, &ctx->graphs); + INIT_LIST_HEAD(&volfile_obj->volfile_list); + volfile_obj->graph = graph; + memcpy(volfile_obj->volfile_checksum, checksum, + sizeof(volfile_obj->volfile_checksum)); + list_add_tail(&volfile_obj->volfile_list, &ctx->volfile_list); + gf_log_dump_graph(fp, graph); + graph = NULL; + + ret = 0; +out: + if (ret) { + if (graph) { + gluster_graph_take_reference(graph->first); + ret = gf_thread_create_detached(&thread_id, glusterfs_graph_cleanup, + graph, "graph_clean"); + if (ret) { + gf_msg("glusterfs", GF_LOG_ERROR, EINVAL, + LG_MSG_GRAPH_CLEANUP_FAILED, + "%s failed to create clean " + "up thread", + volfile_id); + ret = 0; + } + } + if (clean_graph) + glusterfs_muxsvc_cleanup_parent(ctx, clean_graph); + } + return ret; +} + +int +glusterfs_mux_volfile_reconfigure(FILE *newvolfile_fp, glusterfs_ctx_t *ctx, + gf_volfile_t *volfile_obj, char *checksum, + dict_t *dict) +{ + glusterfs_graph_t *oldvolfile_graph = NULL; + glusterfs_graph_t *newvolfile_graph = NULL; + char vol_id[NAME_MAX + 1]; + + int ret = -1; + + if (!ctx) { + gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, 0, LG_MSG_CTX_NULL, + "ctx is NULL"); + goto out; + } + + /* Change the message id */ + if (!volfile_obj) { + gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, 0, LG_MSG_CTX_NULL, + "failed to get volfile object"); + goto out; + } + + oldvolfile_graph = volfile_obj->graph; + if (!oldvolfile_graph) { + goto out; + } + + newvolfile_graph = glusterfs_graph_construct(newvolfile_fp); + + if (!newvolfile_graph) { + goto out; + } + newvolfile_graph->last_xl = glusterfs_get_last_xlator(newvolfile_graph); + + glusterfs_graph_prepare(newvolfile_graph, ctx, newvolfile_graph->first); + + if (!is_graph_topology_equal(oldvolfile_graph, newvolfile_graph)) { + ret = snprintf(vol_id, sizeof(vol_id), "%s", volfile_obj->vol_id); + if (ret < 0) + goto out; + ret = glusterfs_process_svc_detach(ctx, volfile_obj); + if (ret) { + gf_msg("glusterfsd-mgmt", GF_LOG_ERROR, EINVAL, + LG_MSG_GRAPH_CLEANUP_FAILED, + "Could not detach " + "old graph. Aborting the reconfiguration operation"); + goto out; + } + volfile_obj = NULL; + ret = glusterfs_process_svc_attach_volfp(ctx, newvolfile_fp, vol_id, + checksum, dict); + goto out; + } + + gf_msg_debug("glusterfsd-mgmt", 0, + "Only options have changed in the" + " new graph"); + + ret = glusterfs_graph_reconfigure(oldvolfile_graph, newvolfile_graph); + if (ret) { + gf_msg_debug("glusterfsd-mgmt", 0, + "Could not reconfigure " + "new options in old graph"); + goto out; + } + memcpy(volfile_obj->volfile_checksum, checksum, + sizeof(volfile_obj->volfile_checksum)); + + ret = 0; +out: + + if (newvolfile_graph) + glusterfs_graph_destroy(newvolfile_graph); + + return ret; +} diff --git a/libglusterfs/src/graph.l b/libglusterfs/src/graph.l index f7a02e48107..b9d4b2b6828 100644 --- a/libglusterfs/src/graph.l +++ b/libglusterfs/src/graph.l @@ -1,60 +1,40 @@ /* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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. */ - %x STRING %option yylineno %option noinput %{ #define YYSTYPE char * -#include "xlator.h" +#include "glusterfs/xlator.h" #include "y.tab.h" #include <string.h> -#define START_STRSIZE 32 static char *text; -static int text_asize; static int text_size; void append_string(const char *str, int size) { - int new_size = text_size + size + 1; - if (new_size > text_asize) { - new_size += START_STRSIZE - 1; - new_size &= -START_STRSIZE; - if (!text) { - text = GF_CALLOC (1, new_size, - gf_common_mt_char); - } else { - text = GF_REALLOC (text, new_size); - } - if (!text) { - gf_log ("parser", GF_LOG_ERROR, - "out of memory"); - return; - } - text_asize = new_size; - } - memcpy(text + text_size, str, size); - text_size += size; - text[text_size] = 0; + int new_size = text_size + size + 1; + if (!text) { + text = GF_CALLOC (1, new_size, gf_common_mt_char); + } else { + text = GF_REALLOC (text, new_size); + } + if (!text) { + return; + } + memcpy(text + text_size, str, size); + text_size += size; + text[text_size] = 0; } %} @@ -77,13 +57,15 @@ TYPE [t][y][p][e] \\. { append_string (yytext + 1, yyleng - 1); } \" { if (0) { - yyunput (0, NULL); + yyunput (0, NULL); } BEGIN (INITIAL); - yylval = text; + graphyylval = text; + text = NULL; + text_size = 0; 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 14afaae6475..e63febdc08b 100644 --- a/libglusterfs/src/graph.y +++ b/libglusterfs/src/graph.y @@ -1,23 +1,13 @@ /* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2006-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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. */ - %token VOLUME_BEGIN VOLUME_END OPTION NEWLINE SUBVOLUME ID WHITESPACE COMMENT TYPE STRING_TOK %{ @@ -28,9 +18,15 @@ #include <sys/mman.h> #include <sys/types.h> #include <sys/wait.h> +#include <pthread.h> -#include "xlator.h" -#include "logging.h" +#define RELAX_POISONING + +#include "glusterfs/xlator.h" +#include "glusterfs/graph-utils.h" +#include "glusterfs/logging.h" +#include "glusterfs/syscall.h" +#include "glusterfs/libglusterfs-messages.h" static int new_volume (char *name); static int volume_type (char *type); @@ -44,8 +40,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 (); %} @@ -85,11 +81,11 @@ glusterfs_graph_t *construct; static void type_error (void) { - extern int yylineno; + extern int graphyylineno; - gf_log ("parser", GF_LOG_ERROR, + gf_msg ("parser", GF_LOG_ERROR, 0, LG_MSG_VOLFILE_PARSE_ERROR, "Volume %s, before line %d: Please specify volume type", - curr->name, yylineno); + curr->name, graphyylineno); return; } @@ -97,11 +93,11 @@ type_error (void) static void sub_error (void) { - extern int yylineno; + extern int graphyylineno; - gf_log ("parser", GF_LOG_ERROR, + gf_msg ("parser", GF_LOG_ERROR, 0, LG_MSG_VOLFILE_PARSE_ERROR, "Volume %s, before line %d: Please specify subvolumes", - curr->name, yylineno); + curr->name, graphyylineno); return; } @@ -109,12 +105,12 @@ sub_error (void) static void option_error (void) { - extern int yylineno; + extern int graphyylineno; - gf_log ("parser", GF_LOG_ERROR, + gf_msg ("parser", GF_LOG_ERROR, 0, LG_MSG_VOLFILE_PARSE_ERROR, "Volume %s, before line %d: Please specify " "option <key> <value>", - curr->name, yylineno); + curr->name, graphyylineno); return; } @@ -122,21 +118,20 @@ option_error (void) static int new_volume (char *name) { - extern int yylineno; + extern int graphyylineno; xlator_t *trav = NULL; int ret = 0; if (!name) { - gf_log ("parser", GF_LOG_DEBUG, - "Invalid argument name: '%s'", name); + gf_msg_debug ("parser", 0,"Invalid argument name"); ret = -1; goto out; } if (curr) { - gf_log ("parser", GF_LOG_ERROR, - "new volume (%s) defintion in line %d unexpected", - name, yylineno); + gf_msg ("parser", GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, + "new volume (%s) definition in line %d unexpected", + name, graphyylineno); ret = -1; goto out; } @@ -145,7 +140,6 @@ new_volume (char *name) gf_common_mt_xlator_t); if (!curr) { - gf_log ("parser", GF_LOG_ERROR, "Out of memory"); ret = -1; goto out; } @@ -154,9 +148,9 @@ new_volume (char *name) while (trav) { if (!strcmp (name, trav->name)) { - gf_log ("parser", GF_LOG_ERROR, - "Line %d: volume '%s' defined again", - yylineno, name); + gf_msg ("parser", GF_LOG_ERROR, 0, + LG_MSG_VOLFILE_PARSE_ERROR, "Line %d: volume " + "'%s' defined again", graphyylineno, name); ret = -1; goto out; } @@ -170,7 +164,8 @@ new_volume (char *name) goto out; } - curr->options = get_new_dict (); + INIT_LIST_HEAD(&curr->volume_options); + curr->options = dict_new (); if (!curr->options) { GF_FREE (curr->name); @@ -188,8 +183,9 @@ new_volume (char *name) construct->first = curr; construct->xl_count++; + curr->xl_id = construct->xl_count; - gf_log ("parser", GF_LOG_TRACE, "New node for '%s'", name); + gf_msg_trace ("parser", 0, "New node for '%s'", name); out: GF_FREE (name); @@ -201,26 +197,26 @@ out: static int volume_type (char *type) { - extern int yylineno; + extern int graphyylineno; int32_t ret = 0; if (!type) { - gf_log ("parser", GF_LOG_DEBUG, "Invalid argument type"); + gf_msg_debug ("parser", 0, "Invalid argument type"); ret = -1; goto out; } ret = xlator_set_type (curr, type); if (ret) { - gf_log ("parser", GF_LOG_ERROR, + gf_msg ("parser", GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "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; } - gf_log ("parser", GF_LOG_TRACE, "Type:%s:%s", curr->name, type); + gf_msg_trace ("parser", 0, "Type:%s:%s", curr->name, type); out: GF_FREE (type); @@ -232,30 +228,30 @@ out: static int volume_option (char *key, char *value) { - extern int yylineno; + extern int graphyylineno; int ret = 0; char *set_value = NULL; if (!key || !value){ - gf_log ("parser", GF_LOG_ERROR, "Invalid argument"); + gf_msg ("parser", GF_LOG_ERROR, 0, + LG_MSG_INVALID_VOLFILE_ENTRY, "Invalid argument"); ret = -1; goto out; } set_value = gf_strdup (value); - ret = dict_set_dynstr (curr->options, key, set_value); + ret = dict_set_option (curr->options, key, set_value); if (ret == 1) { - gf_log ("parser", GF_LOG_ERROR, - "Volume '%s', line %d: duplicate entry " - "('option %s') present", - curr->name, yylineno, key); + gf_msg ("parser", GF_LOG_ERROR, 0, + LG_MSG_INVALID_VOLFILE_ENTRY, "Volume '%s', line %d: " + "duplicate entry ('option %s') present", + curr->name, graphyylineno, key); ret = -1; goto out; } - gf_log ("parser", GF_LOG_TRACE, "Option:%s:%s:%s", - curr->name, key, value); + gf_msg_trace ("parser", 0, "Option:%s:%s:%s", curr->name, key, value); out: GF_FREE (key); @@ -268,15 +264,13 @@ out: static int volume_sub (char *sub) { - extern int yylineno; + extern int graphyylineno; xlator_t *trav = NULL; - xlator_list_t *xlchild = NULL; - xlator_list_t *tmp = NULL; - xlator_list_t *xlparent = NULL; int ret = 0; if (!sub) { - gf_log ("parser", GF_LOG_ERROR, "Invalid subvolumes argument"); + gf_msg ("parser", GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, + "Invalid subvolumes argument"); ret = -1; goto out; } @@ -290,62 +284,28 @@ volume_sub (char *sub) } if (!trav) { - gf_log ("parser", GF_LOG_ERROR, + gf_msg ("parser", GF_LOG_ERROR, 0, LG_MSG_SUB_VOLUME_ERROR, "Volume '%s', line %d: subvolume '%s' is not defined " - "prior to usage", - curr->name, yylineno, sub); + "prior to usage",curr->name, graphyylineno, sub); ret = -1; goto out; } if (trav == curr) { - gf_log ("parser", GF_LOG_ERROR, + gf_msg ("parser", GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "Volume '%s', line %d: has '%s' itself as subvolume", - curr->name, yylineno, sub); + curr->name, graphyylineno, sub); ret = -1; goto out; } - xlparent = (void *) GF_CALLOC (1, sizeof (*xlparent), - gf_common_mt_xlator_list_t); - - if (!xlparent) { - gf_log ("parser", GF_LOG_ERROR, "Out of memory"); + ret = glusterfs_xlator_link (curr, trav); + if (ret) { ret = -1; goto out; } - xlparent->xlator = curr; - - tmp = trav->parents; - if (tmp == NULL) { - trav->parents = xlparent; - } else { - while (tmp->next) - tmp = tmp->next; - tmp->next = xlparent; - } - - xlchild = (void *) GF_CALLOC (1, sizeof(*xlchild), - gf_common_mt_xlator_list_t); - if (!xlchild) { - gf_log ("parser", GF_LOG_ERROR, "Out of memory"); - ret = -1; - goto out; - } - - xlchild->xlator = trav; - - tmp = curr->children; - if (tmp == NULL) { - curr->children = xlchild; - } else { - while (tmp->next) - tmp = tmp->next; - tmp->next = xlchild; - } - - gf_log ("parser", GF_LOG_TRACE, "child:%s->%s", curr->name, sub); + gf_msg_trace ("parser", 0, "child:%s->%s", curr->name, sub); out: GF_FREE (sub); @@ -358,11 +318,11 @@ static int volume_end (void) { if (!curr->fops) { - gf_log ("parser", GF_LOG_ERROR, + gf_msg ("parser", GF_LOG_ERROR, 0, LG_MSG_VOLUME_ERROR, "\"type\" not specified for volume %s", curr->name); return -1; } - gf_log ("parser", GF_LOG_TRACE, "end:%s", curr->name); + gf_msg_trace ("parser", 0, "end:%s", curr->name); curr = NULL; return 0; @@ -370,55 +330,52 @@ volume_end (void) int -yywrap () +graphyywrap () { return 1; } int -yyerror (const char *str) +graphyyerror (const char *str) { - extern char *yytext; - extern int yylineno; - - if (curr && curr->name && yytext) { - if (!strcmp (yytext, "volume")) { - gf_log ("parser", GF_LOG_ERROR, - "'end-volume' not defined for volume '%s'", - curr->name); - } else if (!strcmp (yytext, "type")) { - gf_log ("parser", GF_LOG_ERROR, + extern char *graphyytext; + extern int graphyylineno; + + if (curr && curr->name && graphyytext) { + if (!strcmp (graphyytext, "volume")) { + gf_msg ("parser", GF_LOG_ERROR, 0, + LG_MSG_VOLUME_ERROR, "'end-volume' not" + " defined for volume '%s'", curr->name); + } else if (!strcmp (graphyytext, "type")) { + gf_msg ("parser", GF_LOG_ERROR, 0, LG_MSG_VOLUME_ERROR, "line %d: duplicate 'type' defined for " - "volume '%s'", - yylineno, curr->name); - } else if (!strcmp (yytext, "subvolumes")) { - gf_log ("parser", GF_LOG_ERROR, - "line %d: duplicate 'subvolumes' defined for " - "volume '%s'", - yylineno, curr->name); + "volume '%s'", graphyylineno, curr->name); + } else if (!strcmp (graphyytext, "subvolumes")) { + gf_msg ("parser", GF_LOG_ERROR, 0, + LG_MSG_SUB_VOLUME_ERROR, "line %d: duplicate " + "'subvolumes' defined for volume '%s'", + graphyylineno, curr->name); } else if (curr) { - gf_log ("parser", GF_LOG_ERROR, + gf_msg ("parser", GF_LOG_ERROR, 0, LG_MSG_SYNTAX_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, + gf_msg ("parser", GF_LOG_ERROR, 0, LG_MSG_SYNTAX_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'"); } } else { - gf_log ("parser", GF_LOG_ERROR, - "syntax error in line %d: \"%s\" \n" + gf_msg ("parser", GF_LOG_ERROR, 0, LG_MSG_SYNTAX_ERROR, + "syntax error in line %d: \"%s\"\n" "(allowed tokens are 'volume', 'type', " "'subvolumes', 'option', 'end-volume')\n", - yylineno, yytext); + graphyylineno, graphyytext); } return -1; @@ -436,7 +393,8 @@ execute_cmd (char *cmd, char **result, size_t size) fpp = popen (cmd, "r"); if (!fpp) { - gf_log ("parser", GF_LOG_ERROR, "%s: failed to popen", cmd); + gf_msg ("parser", GF_LOG_ERROR, 0, LG_MSG_FILE_OP_FAILED, + "%s: failed to popen", cmd); return -1; } @@ -477,8 +435,6 @@ preprocess (FILE *srcfp, FILE *dstfp) char in_backtick = 0; int line = 1; int column = 0; - int backtick_line = 0; - int backtick_column = 0; int character = 0; @@ -488,7 +444,6 @@ preprocess (FILE *srcfp, FILE *dstfp) cmd = GF_CALLOC (cmd_buf_size, 1, gf_common_mt_char); if (cmd == NULL) { - gf_log ("parser", GF_LOG_ERROR, "Out of memory"); return -1; } @@ -496,7 +451,6 @@ preprocess (FILE *srcfp, FILE *dstfp) gf_common_mt_char); if (result == NULL) { GF_FREE (cmd); - gf_log ("parser", GF_LOG_ERROR, "Out of memory"); return -1; } @@ -516,9 +470,6 @@ preprocess (FILE *srcfp, FILE *dstfp) } else { i = 0; cmd[i] = '\0'; - - backtick_column = column; - backtick_line = line; } in_backtick = !in_backtick; @@ -528,6 +479,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; } @@ -560,15 +512,16 @@ preprocess (FILE *srcfp, FILE *dstfp) } if (in_backtick) { - gf_log ("parser", GF_LOG_ERROR, - "Unterminated backtick in volume specfication file at line (%d), column (%d).", - line, column); + gf_msg ("parser", GF_LOG_ERROR, 0, LG_MSG_VOLUME_ERROR, + "Unterminated backtick in volume specification file at " + "line (%d), column (%d).", line, column); ret = -1; } out: fseek (srcfp, 0L, SEEK_SET); fseek (dstfp, 0L, SEEK_SET); + GF_FREE (cmd); GF_FREE (result); @@ -576,7 +529,7 @@ out: } -extern FILE *yyin; +extern FILE *graphyyin; glusterfs_graph_t * glusterfs_graph_new () @@ -590,6 +543,9 @@ glusterfs_graph_new () INIT_LIST_HEAD (&graph->list); + pthread_mutex_init(&graph->mutex, NULL); + pthread_cond_init(&graph->child_down_cond, NULL); + gettimeofday (&graph->dob, NULL); return graph; @@ -600,52 +556,66 @@ glusterfs_graph_t * glusterfs_graph_construct (FILE *fp) { int ret = 0; + int tmp_fd = -1; glusterfs_graph_t *graph = NULL; - FILE *tmp_file = NULL; + FILE *tmp_file = NULL; + char template[] = "/tmp/tmp.XXXXXX"; + static pthread_mutex_t graph_mutex = PTHREAD_MUTEX_INITIALIZER; graph = glusterfs_graph_new (); if (!graph) - return NULL; + goto err; - tmp_file = tmpfile (); + /* coverity[secure_temp] mkstemp uses 0600 as the mode and is safe */ + tmp_fd = mkstemp (template); + if (-1 == tmp_fd) + goto err; - if (tmp_file == NULL) { - gf_log ("parser", GF_LOG_ERROR, - "cannot create temparory file"); + ret = sys_unlink (template); + if (ret < 0) { + gf_msg ("parser", GF_LOG_WARNING, 0, LG_MSG_FILE_OP_FAILED, + "Unable to delete file: %s", template); + } - glusterfs_graph_destroy (graph); - return NULL; - } + tmp_file = fdopen (tmp_fd, "w+b"); + if (!tmp_file) + goto err; - ret = preprocess (fp, tmp_file); - if (ret < 0) { - gf_log ("parser", GF_LOG_ERROR, - "parsing of backticks failed"); + ret = preprocess (fp, tmp_file); + if (ret < 0) { + gf_msg ("parser", GF_LOG_ERROR, 0, LG_MSG_BACKTICK_PARSE_FAILED, + "parsing of backticks failed"); + goto err; + } - glusterfs_graph_destroy (graph); - fclose (tmp_file); - return NULL; + pthread_mutex_lock (&graph_mutex); + { + graphyyin = tmp_file; + construct = graph; + ret = yyparse (); + construct = NULL; } - - yyin = tmp_file; - - construct = graph; - - ret = yyparse (); - - construct = NULL; - - fclose (tmp_file); + pthread_mutex_unlock (&graph_mutex); if (ret == 1) { - gf_log ("parser", GF_LOG_DEBUG, - "parsing of volfile failed, please review it " - "once more"); - - glusterfs_graph_destroy (graph); - return NULL; + gf_msg_debug ("parser", 0, "parsing of volfile failed, please " + "review it once more"); + goto err; } + fclose (tmp_file); return graph; +err: + if (tmp_file) { + fclose (tmp_file); + } else { + gf_msg ("parser", GF_LOG_ERROR, 0, LG_MSG_FILE_OP_FAILED, + "cannot create temporary file"); + if (-1 != tmp_fd) + sys_close (tmp_fd); + } + + glusterfs_graph_destroy (graph); + return NULL; } diff --git a/libglusterfs/src/hashfn.c b/libglusterfs/src/hashfn.c index 134e729e80a..d2237e99f83 100644 --- a/libglusterfs/src/hashfn.c +++ b/libglusterfs/src/hashfn.c @@ -1,48 +1,21 @@ /* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ #include <stdint.h> #include <stdlib.h> -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include "hashfn.h" - -#define get16bits(d) (*((const uint16_t *) (d))) +#define get16bits(d) (*((const uint16_t *)(d))) #define DM_DELTA 0x9E3779B9 -#define DM_FULLROUNDS 10 /* 32 is overkill, 16 is strong crypto */ -#define DM_PARTROUNDS 6 /* 6 gets complete mixing */ - - -uint32_t -ReallySimpleHash (char *path, int len) -{ - uint32_t hash = 0; - for (;len > 0; len--) - hash ^= (char)path[len]; - - return hash; -} +#define DM_FULLROUNDS 10 /* 32 is overkill, 16 is strong crypto */ +#define DM_PARTROUNDS 6 /* 6 gets complete mixing */ /* This is apparently the "fastest hash function for strings". @@ -51,146 +24,145 @@ ReallySimpleHash (char *path, int len) /* In any case make sure, you return 1 */ -uint32_t SuperFastHash (const char * data, int32_t len) { - uint32_t hash = len, tmp; - int32_t rem; - - if (len <= 1 || data == NULL) return 1; - - rem = len & 3; - len >>= 2; - - /* Main loop */ - for (;len > 0; len--) { - hash += get16bits (data); - tmp = (get16bits (data+2) << 11) ^ hash; - hash = (hash << 16) ^ tmp; - data += 2*sizeof (uint16_t); - hash += hash >> 11; - } - - /* Handle end cases */ - switch (rem) { - case 3: hash += get16bits (data); - hash ^= hash << 16; - hash ^= data[sizeof (uint16_t)] << 18; - hash += hash >> 11; - break; - case 2: hash += get16bits (data); - hash ^= hash << 11; +uint32_t +SuperFastHash(const char *data, int32_t len) +{ + uint32_t hash = len, tmp; + int32_t rem; + + if (len <= 1 || data == NULL) + return 1; + + rem = len & 3; + len >>= 2; + + /* Main loop */ + for (; len > 0; len--) { + hash += get16bits(data); + tmp = (get16bits(data + 2) << 11) ^ hash; + hash = (hash << 16) ^ tmp; + data += 2 * sizeof(uint16_t); + hash += hash >> 11; + } + + /* Handle end cases */ + switch (rem) { + case 3: + hash += get16bits(data); + hash ^= hash << 16; + hash ^= data[sizeof(uint16_t)] << 18; + hash += hash >> 11; + break; + case 2: + hash += get16bits(data); + hash ^= hash << 11; + hash += hash >> 17; + break; + case 1: + hash += *data; + hash ^= hash << 10; + hash += hash >> 1; + } + + /* Force "avalanching" of final 127 bits */ + hash ^= hash << 3; + hash += hash >> 5; + hash ^= hash << 4; hash += hash >> 17; - break; - case 1: hash += *data; - hash ^= hash << 10; - hash += hash >> 1; - } - - /* Force "avalanching" of final 127 bits */ - hash ^= hash << 3; - hash += hash >> 5; - hash ^= hash << 4; - hash += hash >> 17; - hash ^= hash << 25; - hash += hash >> 6; - - return hash; -} + hash ^= hash << 25; + hash += hash >> 6; + return hash; +} /* Davies-Meyer hashing function implementation */ static int -dm_round (int rounds, uint32_t *array, uint32_t *h0, uint32_t *h1) +dm_round(int rounds, uint32_t *array, uint32_t *h0, uint32_t *h1) { - uint32_t sum = 0; - int n = 0; - uint32_t b0 = 0; - uint32_t b1 = 0; - - b0 = *h0; - b1 = *h1; - - n = rounds; - - do { - sum += DM_DELTA; - b0 += ((b1 << 4) + array[0]) - ^ (b1 + sum) - ^ ((b1 >> 5) + array[1]); - b1 += ((b0 << 4) + array[2]) - ^ (b0 + sum) - ^ ((b0 >> 5) + array[3]); - } while (--n); - - *h0 += b0; - *h1 += b1; - - return 0; -} + uint32_t sum = 0; + int n = 0; + uint32_t b0 = 0; + uint32_t b1 = 0; + + b0 = *h0; + b1 = *h1; + n = rounds; + + do { + sum += DM_DELTA; + b0 += ((b1 << 4) + array[0]) ^ (b1 + sum) ^ ((b1 >> 5) + array[1]); + b1 += ((b0 << 4) + array[2]) ^ (b0 + sum) ^ ((b0 >> 5) + array[3]); + } while (--n); + + *h0 += b0; + *h1 += b1; + + return 0; +} uint32_t -__pad (int len) +__pad(int len) { - uint32_t pad = 0; + uint32_t pad = 0; - pad = (uint32_t) len | ((uint32_t) len << 8); - pad |= pad << 16; + pad = (uint32_t)len | ((uint32_t)len << 8); + pad |= pad << 16; - return pad; + return pad; } uint32_t -gf_dm_hashfn (const char *msg, int len) +gf_dm_hashfn(const char *msg, int len) { - uint32_t h0 = 0x9464a485; - uint32_t h1 = 0x542e1a94; - uint32_t array[4]; - uint32_t pad = 0; - int i = 0; - int j = 0; - int full_quads = 0; - int full_words = 0; - int full_bytes = 0; - uint32_t *intmsg = NULL; - int word = 0; - - - intmsg = (uint32_t *) msg; - pad = __pad (len); - - full_bytes = len; - full_words = len / 4; - full_quads = len / 16; - - for (i = 0; i < full_quads; i++) { - for (j = 0; j < 4; j++) { - word = *intmsg; - array[j] = word; - intmsg++; - full_words--; - full_bytes -= 4; - } - dm_round (DM_PARTROUNDS, &array[0], &h0, &h1); - } - - for (j = 0; j < 4; j++) { - if (full_words) { - word = *intmsg; - array[j] = word; - intmsg++; - full_words--; - full_bytes -= 4; - } else { - array[j] = pad; - while (full_bytes) { - array[j] <<= 8; - array[j] |= msg[len - full_bytes]; - full_bytes--; - } - } - } - dm_round (DM_FULLROUNDS, &array[0], &h0, &h1); - - return h0 ^ h1; + uint32_t h0 = 0x9464a485; + uint32_t h1 = 0x542e1a94; + uint32_t array[4]; + uint32_t pad = 0; + int i = 0; + int j = 0; + int full_quads = 0; + int full_words = 0; + int full_bytes = 0; + uint32_t *intmsg = NULL; + int word = 0; + + intmsg = (uint32_t *)msg; + pad = __pad(len); + + full_bytes = len; + full_words = len / 4; + full_quads = len / 16; + + for (i = 0; i < full_quads; i++) { + for (j = 0; j < 4; j++) { + word = *intmsg; + array[j] = word; + intmsg++; + full_words--; + full_bytes -= 4; + } + dm_round(DM_PARTROUNDS, &array[0], &h0, &h1); + } + + for (j = 0; j < 4; j++) { + if (full_words) { + word = *intmsg; + array[j] = word; + intmsg++; + full_words--; + full_bytes -= 4; + } else { + array[j] = pad; + while (full_bytes) { + array[j] <<= 8; + array[j] |= msg[len - full_bytes]; + full_bytes--; + } + } + } + dm_round(DM_FULLROUNDS, &array[0], &h0, &h1); + + return h0 ^ h1; } diff --git a/libglusterfs/src/hashfn.h b/libglusterfs/src/hashfn.h deleted file mode 100644 index 4cda48a092e..00000000000 --- a/libglusterfs/src/hashfn.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef __HASHFN_H__ -#define __HASHFN_H__ - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include <sys/types.h> -#include <stdint.h> - -uint32_t SuperFastHash (const char * data, int32_t len); - -uint32_t gf_dm_hashfn (const char *msg, int len); - -uint32_t -ReallySimpleHash (char *path, int len); -#endif /* __HASHFN_H__ */ diff --git a/libglusterfs/src/iatt.h b/libglusterfs/src/iatt.h deleted file mode 100644 index e67d714c2a7..00000000000 --- a/libglusterfs/src/iatt.h +++ /dev/null @@ -1,325 +0,0 @@ -/* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - - -#ifndef _IATT_H -#define _IATT_H - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include <sys/types.h> -#include <sys/stat.h> /* for iatt <--> stat conversions */ -#include <unistd.h> - -#include "compat.h" -#include "uuid.h" - -typedef enum { - IA_INVAL = 0, - IA_IFREG, - IA_IFDIR, - IA_IFLNK, - IA_IFBLK, - IA_IFCHR, - IA_IFIFO, - IA_IFSOCK -} ia_type_t; - - -typedef struct { - uint8_t suid:1; - uint8_t sgid:1; - uint8_t sticky:1; - struct { - uint8_t read:1; - uint8_t write:1; - uint8_t exec:1; - } owner, group, other; -} ia_prot_t; - - -struct iatt { - uint64_t ia_ino; /* inode number */ - uint64_t ia_gen; /* generation number */ - uuid_t ia_gfid; - uint64_t ia_dev; /* backing device ID */ - ia_type_t ia_type; /* type of file */ - ia_prot_t ia_prot; /* protection */ - uint32_t ia_nlink; /* Link count */ - uint32_t ia_uid; /* user ID of owner */ - uint32_t ia_gid; /* group ID of owner */ - uint64_t ia_rdev; /* device ID (if special file) */ - uint64_t ia_size; /* file size in bytes */ - uint32_t ia_blksize; /* blocksize for filesystem I/O */ - uint64_t ia_blocks; /* number of 512B blocks allocated */ - uint32_t ia_atime; /* last access time */ - uint32_t ia_atime_nsec; - uint32_t ia_mtime; /* last modification time */ - uint32_t ia_mtime_nsec; - uint32_t ia_ctime; /* last status change time */ - uint32_t ia_ctime_nsec; -}; - - -#define IA_ISREG(t) (t == IA_IFREG) -#define IA_ISDIR(t) (t == IA_IFDIR) -#define IA_ISLNK(t) (t == IA_IFLNK) -#define IA_ISBLK(t) (t == IA_IFBLK) -#define IA_ISCHR(t) (t == IA_IFCHR) -#define IA_ISFIFO(t) (t == IA_IFIFO) -#define IA_ISSOCK(t) (t == IA_IFSOCK) - -#define IA_PROT_RUSR(prot) ((prot).owner.read == 1) -#define IA_PROT_WUSR(prot) ((prot).owner.write == 1) -#define IA_PROT_XUSR(prot) ((prot).owner.exec == 1) - -#define IA_PROT_RGRP(prot) ((prot).group.read == 1) -#define IA_PROT_WGRP(prot) ((prot).group.write == 1) -#define IA_PROT_XGRP(prot) ((prot).group.exec == 1) - -#define IA_PROT_ROTH(prot) ((prot).other.read == 1) -#define IA_PROT_WOTH(prot) ((prot).other.write == 1) -#define IA_PROT_XOTH(prot) ((prot).other.exec == 1) - -#define IA_PROT_SUID(prot) ((prot).suid == 1) -#define IA_PROT_SGID(prot) ((prot).sgid == 1) -#define IA_PROT_STCKY(prot) ((prot).sticky == 1) - -static inline uint32_t -ia_major (uint64_t ia_dev) -{ - return (uint32_t) (ia_dev >> 32); -} - - -static inline uint32_t -ia_minor (uint64_t ia_dev) -{ - return (uint32_t) (ia_dev & 0xffffffff); -} - - -static inline uint64_t -ia_makedev (uint32_t ia_maj, uint32_t ia_min) -{ - return ((((uint64_t) ia_maj) << 32) & ia_min); -} - - -static inline ia_prot_t -ia_prot_from_st_mode (mode_t mode) -{ - ia_prot_t ia_prot = {0, }; - - if (mode & S_ISUID) - ia_prot.suid = 1; - if (mode & S_ISGID) - ia_prot.sgid = 1; - if (mode & S_ISVTX) - ia_prot.sticky = 1; - - if (mode & S_IRUSR) - ia_prot.owner.read = 1; - if (mode & S_IWUSR) - ia_prot.owner.write = 1; - if (mode & S_IXUSR) - ia_prot.owner.exec = 1; - - if (mode & S_IRGRP) - ia_prot.group.read = 1; - if (mode & S_IWGRP) - ia_prot.group.write = 1; - if (mode & S_IXGRP) - ia_prot.group.exec = 1; - - if (mode & S_IROTH) - ia_prot.other.read = 1; - if (mode & S_IWOTH) - ia_prot.other.write = 1; - if (mode & S_IXOTH) - ia_prot.other.exec = 1; - - return ia_prot; -} - - -static inline ia_type_t -ia_type_from_st_mode (mode_t mode) -{ - ia_type_t type = IA_INVAL; - - if (S_ISREG (mode)) - type = IA_IFREG; - if (S_ISDIR (mode)) - type = IA_IFDIR; - if (S_ISLNK (mode)) - type = IA_IFLNK; - if (S_ISBLK (mode)) - type = IA_IFBLK; - if (S_ISCHR (mode)) - type = IA_IFCHR; - if (S_ISFIFO (mode)) - type = IA_IFIFO; - if (S_ISSOCK (mode)) - type = IA_IFSOCK; - - return type; -} - - -static inline mode_t -st_mode_from_ia (ia_prot_t prot, ia_type_t type) -{ - mode_t st_mode = 0; - uint32_t type_bit = 0; - uint32_t prot_bit = 0; - - switch (type) { - case IA_IFREG: - type_bit = S_IFREG; - break; - case IA_IFDIR: - type_bit = S_IFDIR; - break; - case IA_IFLNK: - type_bit = S_IFLNK; - break; - case IA_IFBLK: - type_bit = S_IFBLK; - break; - case IA_IFCHR: - type_bit = S_IFCHR; - break; - case IA_IFIFO: - type_bit = S_IFIFO; - break; - case IA_IFSOCK: - type_bit = S_IFSOCK; - break; - case IA_INVAL: - break; - } - - if (prot.suid) - prot_bit |= S_ISUID; - if (prot.sgid) - prot_bit |= S_ISGID; - if (prot.sticky) - prot_bit |= S_ISVTX; - - if (prot.owner.read) - prot_bit |= S_IRUSR; - if (prot.owner.write) - prot_bit |= S_IWUSR; - if (prot.owner.exec) - prot_bit |= S_IXUSR; - - if (prot.group.read) - prot_bit |= S_IRGRP; - if (prot.group.write) - prot_bit |= S_IWGRP; - if (prot.group.exec) - prot_bit |= S_IXGRP; - - if (prot.other.read) - prot_bit |= S_IROTH; - if (prot.other.write) - prot_bit |= S_IWOTH; - if (prot.other.exec) - prot_bit |= S_IXOTH; - - st_mode = (type_bit | prot_bit); - - return st_mode; -} - - -static inline int -iatt_from_stat (struct iatt *iatt, struct stat *stat) -{ - iatt->ia_dev = stat->st_dev; - iatt->ia_ino = stat->st_ino; - - (void) iatt->ia_gen; - - iatt->ia_type = ia_type_from_st_mode (stat->st_mode); - iatt->ia_prot = ia_prot_from_st_mode (stat->st_mode); - - iatt->ia_nlink = stat->st_nlink; - iatt->ia_uid = stat->st_uid; - iatt->ia_gid = stat->st_gid; - - iatt->ia_rdev = ia_makedev (major (stat->st_rdev), - minor (stat->st_rdev)); - - iatt->ia_size = stat->st_size; - iatt->ia_blksize = stat->st_blksize; - iatt->ia_blocks = stat->st_blocks; - - iatt->ia_atime = stat->st_atime; - iatt->ia_atime_nsec = ST_ATIM_NSEC (stat); - - iatt->ia_mtime = stat->st_mtime; - iatt->ia_mtime_nsec = ST_MTIM_NSEC (stat); - - iatt->ia_ctime = stat->st_ctime; - iatt->ia_ctime_nsec = ST_CTIM_NSEC (stat); - - return 0; -} - - -static inline int -iatt_to_stat (struct iatt *iatt, struct stat *stat) -{ - stat->st_dev = iatt->ia_dev; - stat->st_ino = iatt->ia_ino; - - (void) iatt->ia_gen; - - stat->st_mode = st_mode_from_ia (iatt->ia_prot, iatt->ia_type); - - stat->st_nlink = iatt->ia_nlink; - stat->st_uid = iatt->ia_uid; - stat->st_gid = iatt->ia_gid; - - stat->st_rdev = makedev (ia_major (iatt->ia_rdev), - ia_minor (iatt->ia_rdev)); - - stat->st_size = iatt->ia_size; - stat->st_blksize = iatt->ia_blksize; - stat->st_blocks = iatt->ia_blocks; - - stat->st_atime = iatt->ia_atime; - ST_ATIM_NSEC_SET (stat, iatt->ia_atime_nsec); - - stat->st_mtime = iatt->ia_mtime; - ST_MTIM_NSEC_SET (stat, iatt->ia_mtime_nsec); - - stat->st_ctime = iatt->ia_ctime; - ST_CTIM_NSEC_SET (stat, iatt->ia_ctime_nsec); - - return 0; -} - - -#endif /* _IATT_H */ diff --git a/libglusterfs/src/inode.c b/libglusterfs/src/inode.c index 45d151ef04b..dbadf77442d 100644 --- a/libglusterfs/src/inode.c +++ b/libglusterfs/src/inode.c @@ -1,1436 +1,2677 @@ /* - Copyright (c) 2007-2009 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 "inode.h" -#include "common-utils.h" -#include "statedump.h" +#include "glusterfs/inode.h" +#include "glusterfs/common-utils.h" +#include "glusterfs/statedump.h" #include <pthread.h> #include <sys/types.h> #include <stdint.h> -#include "list.h" -#include <time.h> +#include "glusterfs/list.h" #include <assert.h> +#include "glusterfs/libglusterfs-messages.h" /* TODO: move latest accessed dentry to list_head of inode */ -#define INODE_DUMP_LIST(head, key_buf, key_prefix, list_type) \ - { \ - int i = 1; \ - inode_t *inode = NULL; \ - list_for_each_entry (inode, head, list) { \ - gf_proc_dump_build_key(key_buf, key_prefix, "%s.%d",list_type, \ - i++); \ - gf_proc_dump_add_section(key_buf); \ - inode_dump(inode, key); \ - } \ +// clang-format off +/* + +Details as per Xavi: + + I think we should have 3 lists: active, lru and invalidate. + +We'll need 3 things: refs, nlookups and invalidate_sent flag. Any change of +refs, invalidate_sent flag and moving from one list to another must be done +atomically. + +With this information, these are the states that cause a transition: + + refs nlookups inv_sent op + 1 0 0 unref -> refs = 0, active--->destroy + 1 1 0 unref -> refs = 0, active--->lru + 1 1 0 forget -> nlookups = 0, active--->active + *0 1 0 forget -> nlookups = 0, lru--->destroy + *0 1 1 forget -> nlookups = 0, invalidate--->destroy + 0 1 0 ref -> refs = 1, lru--->active + 0 1 1 ref -> refs = 1, inv_sent = 0, invalidate--->active + 0 1 0 overflow -> refs = 1, inv_sent = 1, lru--->invalidate + 1 1 1 unref -> refs = 0, invalidate--->invalidate + 1 1 1 forget -> nlookups = 0, inv_sent = 0, invalidate--->active + +(*) technically these combinations cannot happen because a forget sent by the +kernel first calls ref() and then unref(). However it's equivalent. + +overflow means that lru list has grown beyond the limit and the inode needs to +be invalidated. All other combinations do not cause a change in state or are not +possible. + +Based on this, the code could be similar to this: + + ref(inode, inv) + { + if (refs == 0) { + if (inv_sent) { + invalidate_count--; + inv_sent = 0; + } else { + lru_count--; + } + if (inv) { + inv_sent = 1; + invalidate_count++; + list_move(inode, invalidate); + } else { + active_count++; + list_move(inode, active); + } + } + refs++; + } + + unref(inode, clear) + { + if (clear && inv_sent) { + // there is a case of fuse itself sending forget, without + // invalidate, after entry delete, like unlink(), rmdir(). + inv_sent = 0; + invalidate_count--; + active_count++; + list_move(inode, active); + } + refs--; + if ((refs == 0) && !inv_sent) { + active_count--; + if (nlookups == 0) { + destroy(inode); + } else { + lru_count++; + list_move(inode, lru); + } } + } + + forget(inode) + { + ref(inode, false); + nlookups--; + unref(inode, true); + } + + overflow(inode) + { + ref(inode, true); + invalidator(inode); + unref(inode, false); + } + +*/ +// clang-format on + +#define INODE_DUMP_LIST(head, key_buf, key_prefix, list_type) \ + { \ + int i = 1; \ + inode_t *inode = NULL; \ + list_for_each_entry(inode, head, list) \ + { \ + gf_proc_dump_build_key(key_buf, key_prefix, "%s.%d", list_type, \ + i++); \ + gf_proc_dump_add_section("%s", key_buf); \ + inode_dump(inode, key); \ + } \ + } static inode_t * -__inode_unref (inode_t *inode); +__inode_unref(inode_t *inode, bool clear); static int -inode_table_prune (inode_table_t *table); +inode_table_prune(inode_table_t *table); + +void +fd_dump(struct list_head *head, char *prefix); static int -hash_dentry (inode_t *parent, const char *name, int mod) +hash_dentry(inode_t *parent, const char *name, int mod) { - int hash = 0; - int ret = 0; + int hash = 0; + int ret = 0; - hash = *name; - if (hash) { - for (name += 1; *name != '\0'; name++) { - hash = (hash << 5) - hash + *name; - } + hash = *name; + if (hash) { + for (name += 1; *name != '\0'; name++) { + hash = (hash << 5) - hash + *name; } - ret = (hash + (unsigned long)parent) % mod; + } + ret = (hash + (unsigned long)parent) % mod; - return ret; + return ret; } - static int -hash_gfid (uuid_t uuid, int mod) +hash_gfid(uuid_t uuid, int mod) { - int ret = 0; - - ret = uuid[15] + (uuid[14] << 8); - - return ret; + return ((uuid[15] + (uuid[14] << 8)) % mod); } - static void -__dentry_hash (dentry_t *dentry) +__dentry_hash(dentry_t *dentry, const int hash) { - inode_table_t *table = NULL; - int hash = 0; - - if (!dentry) - return; + inode_table_t *table = NULL; - table = dentry->inode->table; - hash = hash_dentry (dentry->parent, dentry->name, - table->hashsize); + table = dentry->inode->table; - list_del_init (&dentry->hash); - list_add (&dentry->hash, &table->name_hash[hash]); + list_del_init(&dentry->hash); + list_add(&dentry->hash, &table->name_hash[hash]); } - static int -__is_dentry_hashed (dentry_t *dentry) +__is_dentry_hashed(dentry_t *dentry) { - if (!dentry) - return 0; - - return !list_empty (&dentry->hash); + return !list_empty(&dentry->hash); } - static void -__dentry_unhash (dentry_t *dentry) +__dentry_unhash(dentry_t *dentry) { - if (!dentry) - return; - - list_del_init (&dentry->hash); + list_del_init(&dentry->hash); } - static void -__dentry_unset (dentry_t *dentry) +dentry_destroy(dentry_t *dentry) { - struct mem_pool *tmp_pool = NULL; + if (!dentry) + return; - if (!dentry) - return; + GF_FREE(dentry->name); + dentry->name = NULL; + mem_put(dentry); - tmp_pool = dentry->inode->table->dentry_pool; - __dentry_unhash (dentry); + return; +} - list_del_init (&dentry->inode_list); +static dentry_t * +__dentry_unset(dentry_t *dentry) +{ + if (!dentry) + return NULL; - if (dentry->name) - GF_FREE (dentry->name); + __dentry_unhash(dentry); - if (dentry->parent) { - __inode_unref (dentry->parent); - dentry->parent = NULL; - } + list_del_init(&dentry->inode_list); - mem_put (tmp_pool, dentry); - tmp_pool = NULL; + if (dentry->parent) { + __inode_unref(dentry->parent, false); + dentry->parent = NULL; + } + return dentry; } +static int +__foreach_ancestor_dentry(dentry_t *dentry, + int(per_dentry_fn)(dentry_t *dentry, void *data), + void *data) +{ + inode_t *parent = NULL; + dentry_t *each = NULL; + int ret = 0; + if (!dentry) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, 0, LG_MSG_DENTRY_NOT_FOUND, + "dentry not found"); + return 0; + } + + ret = per_dentry_fn(dentry, data); + if (ret) { + gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_PER_DENTRY_FAILED, + "ret=%d", ret, NULL); + goto out; + } + + parent = dentry->parent; + if (!parent) { + gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_PARENT_DENTRY_NOT_FOUND, + NULL); + goto out; + } + + list_for_each_entry(each, &parent->dentry_list, inode_list) + { + ret = __foreach_ancestor_dentry(each, per_dentry_fn, data); + if (ret) + goto out; + } +out: + return ret; +} -static void -__inode_unhash (inode_t *inode) +static int +__check_cycle(dentry_t *a_dentry, void *data) { - if (!inode) - return; + inode_t *link_inode = NULL; - list_del_init (&inode->hash); -} + link_inode = data; + + if (a_dentry->parent == link_inode) + return 1; + return 0; +} static int -__is_inode_hashed (inode_t *inode) +__is_dentry_cyclic(dentry_t *dentry) { - if (!inode) - return 0; + int ret = 0; - return !list_empty (&inode->hash); -} + ret = __foreach_ancestor_dentry(dentry, __check_cycle, dentry->inode); + if (ret) { + gf_smsg(dentry->inode->table->name, GF_LOG_CRITICAL, 0, + LG_MSG_DENTRY_CYCLIC_LOOP, "gfid=%s name=-%s", + uuid_utoa(dentry->inode->gfid), dentry->name, NULL); + } + return ret; +} static void -__inode_hash (inode_t *inode) +__inode_unhash(inode_t *inode) { - inode_table_t *table = NULL; - int hash = 0; + list_del_init(&inode->hash); +} - if (!inode) - return; +static int +__is_inode_hashed(inode_t *inode) +{ + return !list_empty(&inode->hash); +} - table = inode->table; - hash = hash_gfid (inode->gfid, 65536); +static void +__inode_hash(inode_t *inode, const int hash) +{ + inode_table_t *table = inode->table; - list_del_init (&inode->hash); - list_add (&inode->hash, &table->inode_hash[hash]); + list_del_init(&inode->hash); + list_add(&inode->hash, &table->inode_hash[hash]); } - static dentry_t * -__dentry_search_for_inode (inode_t *inode, ino_t par, const char *name) +__dentry_search_for_inode(inode_t *inode, uuid_t pargfid, const char *name) { - dentry_t *dentry = NULL; - dentry_t *tmp = NULL; + dentry_t *dentry = NULL; + dentry_t *tmp = NULL; - if (!inode || !name) - return NULL; + /* earlier, just the ino was sent, which could have been 0, now + we deal with gfid, and if sent gfid is null or 0, no need to + continue with the check */ + if (!pargfid || gf_uuid_is_null(pargfid)) + return NULL; - list_for_each_entry (tmp, &inode->dentry_list, inode_list) { - if (tmp->parent->ino == par && !strcmp (tmp->name, name)) { - dentry = tmp; - break; - } + list_for_each_entry(tmp, &inode->dentry_list, inode_list) + { + if ((gf_uuid_compare(tmp->parent->gfid, pargfid) == 0) && + !strcmp(tmp->name, name)) { + dentry = tmp; + break; } + } - return dentry; + return dentry; } - static void -__inode_destroy (inode_t *inode) +__inode_ctx_free(inode_t *inode) { - int index = 0; - xlator_t *xl = NULL; - xlator_t *old_THIS = NULL; - struct mem_pool *tmp_pool = NULL; - - if (!inode) - return; - - if (!inode->_ctx) - goto noctx; - - tmp_pool = inode->table->inode_pool; - - for (index = 0; index < inode->table->xl->graph->xl_count; index++) { - if (inode->_ctx[index].xl_key) { - xl = (xlator_t *)(long)inode->_ctx[index].xl_key; - old_THIS = THIS; - THIS = xl; - if (xl->cbks->forget) - xl->cbks->forget (xl, inode); - THIS = old_THIS; - } + int index = 0; + xlator_t *xl = NULL; + xlator_t *old_THIS = NULL; + + if (!inode->_ctx) { + gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_CTX_NULL, NULL); + goto noctx; + } + + for (index = 0; index < inode->table->ctxcount; index++) { + if (inode->_ctx[index].value1 || inode->_ctx[index].value2) { + xl = (xlator_t *)(long)inode->_ctx[index].xl_key; + if (xl && !xl->call_cleanup && xl->cbks->forget) { + old_THIS = THIS; + THIS = xl; + xl->cbks->forget(xl, inode); + THIS = old_THIS; + } } + } - GF_FREE (inode->_ctx); -noctx: - LOCK_DESTROY (&inode->lock); - // memset (inode, 0xb, sizeof (*inode)); - mem_put (tmp_pool, inode); - tmp_pool = NULL; + GF_FREE(inode->_ctx); + inode->_ctx = NULL; +noctx: + return; } - static void -__inode_activate (inode_t *inode) +__inode_destroy(inode_t *inode) { - if (!inode) - return; + __inode_ctx_free(inode); - list_move (&inode->list, &inode->table->active); - inode->table->active_size++; + LOCK_DESTROY(&inode->lock); + // memset (inode, 0xb, sizeof (*inode)); + mem_put(inode); } - -static void -__inode_passivate (inode_t *inode) +void +inode_ctx_merge(fd_t *fd, inode_t *inode, inode_t *linked_inode) { - dentry_t *dentry = NULL; - dentry_t *t = NULL; + int index = 0; + xlator_t *xl = NULL; + xlator_t *old_THIS = NULL; - if (!inode) - return; + if (!fd || !inode || !linked_inode) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "invalid inode"); + return; + } + + if (!inode->_ctx || !linked_inode->_ctx) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "invalid inode context"); + return; + } - list_move_tail (&inode->list, &inode->table->lru); - inode->table->lru_size++; + for (; index < inode->table->ctxcount; index++) { + if (inode->_ctx[index].xl_key) { + xl = (xlator_t *)(long)inode->_ctx[index].xl_key; - list_for_each_entry_safe (dentry, t, &inode->dentry_list, inode_list) { - if (!__is_dentry_hashed (dentry)) - __dentry_unset (dentry); + old_THIS = THIS; + THIS = xl; + if (xl->cbks->ictxmerge) + xl->cbks->ictxmerge(xl, fd, inode, linked_inode); + THIS = old_THIS; } + } } +static void +__inode_activate(inode_t *inode) +{ + list_move(&inode->list, &inode->table->active); + inode->table->active_size++; +} static void -__inode_retire (inode_t *inode) +__inode_passivate(inode_t *inode) { - dentry_t *dentry = NULL; - dentry_t *t = NULL; + dentry_t *dentry = NULL; + dentry_t *t = NULL; + + list_move_tail(&inode->list, &inode->table->lru); + inode->table->lru_size++; + + list_for_each_entry_safe(dentry, t, &inode->dentry_list, inode_list) + { + if (!__is_dentry_hashed(dentry)) + dentry_destroy(__dentry_unset(dentry)); + } +} - if (!inode) - return; +static void +__inode_retire(inode_t *inode) +{ + dentry_t *dentry = NULL; + dentry_t *t = NULL; - list_move_tail (&inode->list, &inode->table->purge); - inode->table->purge_size++; + list_move_tail(&inode->list, &inode->table->purge); + inode->table->purge_size++; - __inode_unhash (inode); + __inode_unhash(inode); - list_for_each_entry_safe (dentry, t, &inode->dentry_list, inode_list) { - __dentry_unset (dentry); - } + list_for_each_entry_safe(dentry, t, &inode->dentry_list, inode_list) + { + dentry_destroy(__dentry_unset(dentry)); + } } +static int +__inode_get_xl_index(inode_t *inode, xlator_t *xlator) +{ + int set_idx = -1; + + if ((inode->_ctx[xlator->xl_id].xl_key != NULL) && + (inode->_ctx[xlator->xl_id].xl_key != xlator)) + goto out; + + set_idx = xlator->xl_id; + inode->_ctx[set_idx].xl_key = xlator; + +out: + return set_idx; +} static inode_t * -__inode_unref (inode_t *inode) +__inode_unref(inode_t *inode, bool clear) { - if (!inode) - return NULL; + int index = 0; + xlator_t *this = NULL; + uint64_t nlookup = 0; + + /* + * Root inode should always be in active list of inode table. So unrefs + * on root inode are no-ops. + */ + if (__is_root_gfid(inode->gfid)) + return inode; - if (inode->ino == 1) - return inode; + /* + * No need to acquire inode table's lock + * as __inode_unref is called after acquiding + * the inode table's lock. + */ + if (inode->table->cleanup_started && !inode->ref) + /* + * There is a good chance that, the inode + * on which unref came has already been + * zero refed and added to the purge list. + * This can happen when inode table is + * being destroyed (glfs_fini is something + * which destroys the inode table). + * + * Consider a directory 'a' which has a file + * 'b'. Now as part of inode table destruction + * zero refing of inodes does not happen from + * leaf to the root. It happens in the order + * inodes are present in the list. So, in this + * example, the dentry of 'b' would have its + * parent set to the inode of 'a'. So if + * 'a' gets zero refed first (as part of + * inode table cleanup) and then 'b' has to + * zero refed, then dentry_unset is called on + * the dentry of 'b' and it further goes on to + * call inode_unref on b's parent which is 'a'. + * In this situation, GF_ASSERT would be called + * below as the refcount of 'a' has been already set + * to zero. + * + * So return the inode if the inode table cleanup + * has already started and inode refcount is 0. + */ + return inode; - assert (inode->ref); + this = THIS; - --inode->ref; + if (clear && inode->in_invalidate_list) { + inode->in_invalidate_list = false; + inode->table->invalidate_size--; + __inode_activate(inode); + } + GF_ASSERT(inode->ref); - if (!inode->ref) { - inode->table->active_size--; + --inode->ref; - if (inode->nlookup) - __inode_passivate (inode); - else - __inode_retire (inode); - } + index = __inode_get_xl_index(inode, this); + if (index >= 0) { + inode->_ctx[index].xl_key = this; + inode->_ctx[index].ref--; + } - return inode; -} + if (!inode->ref && !inode->in_invalidate_list) { + inode->table->active_size--; + + nlookup = GF_ATOMIC_GET(inode->nlookup); + if (nlookup) + __inode_passivate(inode); + else + __inode_retire(inode); + } + return inode; +} static inode_t * -__inode_ref (inode_t *inode) +__inode_ref(inode_t *inode, bool is_invalidate) { - if (!inode) - return NULL; + int index = 0; + xlator_t *this = NULL; - if (!inode->ref) { - inode->table->lru_size--; - __inode_activate (inode); - } - inode->ref++; + if (!inode) + return NULL; + this = THIS; + + /* + * Root inode should always be in active list of inode table. So unrefs + * on root inode are no-ops. If we do not allow unrefs but allow refs, + * it leads to refcount overflows and deleting and adding the inode + * to active-list, which is ugly. active_size (check __inode_activate) + * in inode table increases which is wrong. So just keep the ref + * count as 1 always + */ + if (__is_root_gfid(inode->gfid) && inode->ref) return inode; -} + if (!inode->ref) { + if (inode->in_invalidate_list) { + inode->in_invalidate_list = false; + inode->table->invalidate_size--; + } else { + inode->table->lru_size--; + } + if (is_invalidate) { + inode->in_invalidate_list = true; + inode->table->invalidate_size++; + list_move_tail(&inode->list, &inode->table->invalidate); + } else { + __inode_activate(inode); + } + } + + inode->ref++; + + index = __inode_get_xl_index(inode, this); + if (index >= 0) { + inode->_ctx[index].xl_key = this; + inode->_ctx[index].ref++; + } + + return inode; +} inode_t * -inode_unref (inode_t *inode) +inode_unref(inode_t *inode) { - inode_table_t *table = NULL; + inode_table_t *table = NULL; - if (!inode) - return NULL; + if (!inode) + return NULL; - table = inode->table; + table = inode->table; - pthread_mutex_lock (&table->lock); - { - inode = __inode_unref (inode); - } - pthread_mutex_unlock (&table->lock); + pthread_mutex_lock(&table->lock); + { + inode = __inode_unref(inode, false); + } + pthread_mutex_unlock(&table->lock); - inode_table_prune (table); + inode_table_prune(table); - return inode; + return inode; } - inode_t * -inode_ref (inode_t *inode) +inode_ref(inode_t *inode) { - inode_table_t *table = NULL; + inode_table_t *table = NULL; - if (!inode) - return NULL; + if (!inode) + return NULL; - table = inode->table; + table = inode->table; - pthread_mutex_lock (&table->lock); - { - inode = __inode_ref (inode); - } - pthread_mutex_unlock (&table->lock); + pthread_mutex_lock(&table->lock); + { + inode = __inode_ref(inode, false); + } + pthread_mutex_unlock(&table->lock); - return inode; + return inode; } - static dentry_t * -__dentry_create (inode_t *inode, inode_t *parent, const char *name) +dentry_create(inode_t *inode, inode_t *parent, const char *name) { - dentry_t *newd = NULL; - - if (!inode || !parent || !name) - return NULL; - - newd = mem_get0 (parent->table->dentry_pool); + dentry_t *newd = NULL; - if (newd == NULL) { - gf_log ("inode", GF_LOG_ERROR, "out of memory"); - goto out; - } - - INIT_LIST_HEAD (&newd->inode_list); - INIT_LIST_HEAD (&newd->hash); + newd = mem_get0(parent->table->dentry_pool); + if (newd == NULL) { + goto out; + } - newd->name = gf_strdup (name); - if (newd->name == NULL) { - gf_log ("inode", GF_LOG_ERROR, "out of memory"); - mem_put (parent->table->dentry_pool, newd); - newd = NULL; - goto out; - } + INIT_LIST_HEAD(&newd->inode_list); + INIT_LIST_HEAD(&newd->hash); - if (parent) - newd->parent = __inode_ref (parent); + newd->name = gf_strdup(name); + if (newd->name == NULL) { + mem_put(newd); + newd = NULL; + goto out; + } - list_add (&newd->inode_list, &inode->dentry_list); - newd->inode = inode; + newd->inode = inode; out: - return newd; + return newd; } - static inode_t * -__inode_create (inode_table_t *table) +inode_create(inode_table_t *table) { - inode_t *newi = NULL; - - if (!table) - return NULL; + inode_t *newi = NULL; - newi = mem_get0 (table->inode_pool); - if (!newi) { - gf_log ("inode", GF_LOG_ERROR, "out of memory"); - goto out; - } + newi = mem_get0(table->inode_pool); + if (!newi) { + goto out; + } - newi->table = table; + newi->table = table; - LOCK_INIT (&newi->lock); + LOCK_INIT(&newi->lock); - INIT_LIST_HEAD (&newi->fd_list); - INIT_LIST_HEAD (&newi->list); - 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), - gf_common_mt_inode_ctx); - - if (newi->_ctx == NULL) { - gf_log ("inode", GF_LOG_ERROR, "out of memory"); - LOCK_DESTROY (&newi->lock); - mem_put (table->inode_pool, newi); - newi = NULL; - goto out; - } + INIT_LIST_HEAD(&newi->fd_list); + INIT_LIST_HEAD(&newi->list); + INIT_LIST_HEAD(&newi->hash); + INIT_LIST_HEAD(&newi->dentry_list); - list_add (&newi->list, &table->lru); - table->lru_size++; + 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); + newi = NULL; + goto out; + } out: - - return newi; + return newi; } - inode_t * -inode_new (inode_table_t *table) +inode_new(inode_table_t *table) { - inode_t *inode = NULL; + inode_t *inode = NULL; - if (!table) - return NULL; + if (!table) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, 0, + LG_MSG_INODE_TABLE_NOT_FOUND, + "inode not " + "found"); + return NULL; + } - pthread_mutex_lock (&table->lock); + inode = inode_create(table); + if (inode) { + pthread_mutex_lock(&table->lock); { - inode = __inode_create (table); - if (inode != NULL) { - __inode_ref (inode); - } + list_add(&inode->list, &table->lru); + table->lru_size++; + __inode_ref(inode, false); } - pthread_mutex_unlock (&table->lock); + pthread_mutex_unlock(&table->lock); + } - return inode; + return inode; } - +/* Reduce the ref count by value 'nref' + * Args: + * inode - address of the inode to operate on + * nref - number to subtracted from inode->ref + * if nref is 0, then the ref count is overwritten 0 + * + * This function may cause the purging of the inode, + * hence to be used only in destructor functions and not otherwise. + */ static inode_t * -__inode_lookup (inode_t *inode) +__inode_ref_reduce_by_n(inode_t *inode, uint64_t nref) { - if (!inode) - return NULL; + uint64_t nlookup = 0; - inode->nlookup++; + GF_ASSERT(inode->ref >= nref); - return inode; -} + inode->ref -= nref; + + if (!nref) + inode->ref = 0; + + if (!inode->ref) { + inode->table->active_size--; + nlookup = GF_ATOMIC_GET(inode->nlookup); + if (nlookup) + __inode_passivate(inode); + else + __inode_retire(inode); + } + + return inode; +} static inode_t * -__inode_forget (inode_t *inode, uint64_t nlookup) +inode_forget_atomic(inode_t *inode, uint64_t nlookup) { - if (!inode) - return NULL; - - assert (inode->nlookup >= nlookup); + uint64_t inode_lookup = 0; - inode->nlookup -= nlookup; + if (!inode) + return NULL; - if (!nlookup) - inode->nlookup = 0; + if (nlookup == 0) { + GF_ATOMIC_INIT(inode->nlookup, 0); + } else { + inode_lookup = GF_ATOMIC_FETCH_SUB(inode->nlookup, nlookup); + GF_ASSERT(inode_lookup >= nlookup); + } - return inode; + return inode; } - dentry_t * -__dentry_grep (inode_table_t *table, inode_t *parent, const char *name) +__dentry_grep(inode_table_t *table, inode_t *parent, const char *name, + const int hash) { - int hash = 0; - dentry_t *dentry = NULL; - dentry_t *tmp = NULL; - - if (!table || !name || !parent) - return NULL; - - hash = hash_dentry (parent, name, table->hashsize); - - list_for_each_entry (tmp, &table->name_hash[hash], hash) { - if (tmp->parent == parent && !strcmp (tmp->name, name)) { - dentry = tmp; - break; - } + dentry_t *dentry = NULL; + dentry_t *tmp = NULL; + + list_for_each_entry(tmp, &table->name_hash[hash], hash) + { + if (tmp->parent == parent && !strcmp(tmp->name, name)) { + dentry = tmp; + break; } + } - return dentry; + return dentry; } - inode_t * -inode_grep (inode_table_t *table, inode_t *parent, const char *name) +inode_grep(inode_table_t *table, inode_t *parent, const char *name) { - inode_t *inode = NULL; - dentry_t *dentry = NULL; - - if (!table || !parent || !name) - return NULL; + inode_t *inode = NULL; + dentry_t *dentry = NULL; - pthread_mutex_lock (&table->lock); - { - dentry = __dentry_grep (table, parent, name); + if (!table || !parent || !name) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "table || parent || name" + " not found"); + return NULL; + } - if (dentry) - inode = dentry->inode; + int hash = hash_dentry(parent, name, table->hashsize); - if (inode) - __inode_ref (inode); + pthread_mutex_lock(&table->lock); + { + dentry = __dentry_grep(table, parent, name, hash); + if (dentry) { + inode = dentry->inode; + if (inode) + __inode_ref(inode, false); } - pthread_mutex_unlock (&table->lock); + } + pthread_mutex_unlock(&table->lock); - return inode; + return inode; } - inode_t * -inode_get (inode_table_t *table, ino_t ino, uint64_t gen) +inode_resolve(inode_table_t *table, char *path) { - return NULL; -} + char *tmp = NULL, *bname = NULL, *str = NULL, *saveptr = NULL; + inode_t *inode = NULL, *parent = NULL; + + if ((path == NULL) || (table == NULL)) { + goto out; + } + + parent = inode_ref(table->root); + str = tmp = gf_strdup(path); + if (str == NULL) { + goto out; + } + + while (1) { + bname = strtok_r(str, "/", &saveptr); + if (bname == NULL) { + break; + } + if (inode != NULL) { + inode_unref(inode); + } -static int -__is_root_gfid (uuid_t gfid) -{ - uuid_t root; - int ret; + inode = inode_grep(table, parent, bname); + if (inode == NULL) { + break; + } - memset (root, 0, 16); - root[15] = 1; + if (parent != NULL) { + inode_unref(parent); + } - ret = uuid_compare (gfid, root); + parent = inode_ref(inode); + str = NULL; + } - return ret; + inode_unref(parent); + GF_FREE(tmp); +out: + return inode; } +int +inode_grep_for_gfid(inode_table_t *table, inode_t *parent, const char *name, + uuid_t gfid, ia_type_t *type) +{ + inode_t *inode = NULL; + dentry_t *dentry = NULL; + int ret = -1; + + if (!table || !parent || !name) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "table || parent || name" + " not found"); + return ret; + } + + int hash = hash_dentry(parent, name, table->hashsize); + + pthread_mutex_lock(&table->lock); + { + dentry = __dentry_grep(table, parent, name, hash); + if (dentry) { + inode = dentry->inode; + if (inode) { + gf_uuid_copy(gfid, inode->gfid); + *type = inode->ia_type; + ret = 0; + } + } + } + pthread_mutex_unlock(&table->lock); + + return ret; +} -inode_t * -__inode_find (inode_table_t *table, uuid_t gfid) +/* return 1 if gfid is of root, 0 if not */ +gf_boolean_t +__is_root_gfid(uuid_t gfid) { - inode_t *inode = NULL; - inode_t *tmp = NULL; - int hash = 0; + static uuid_t root = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; - if (!table) - goto out; + if (gf_uuid_compare(gfid, root) == 0) + return _gf_true; - if (__is_root_gfid (gfid) == 0) - return table->root; + return _gf_false; +} - hash = hash_gfid (gfid, 65536); +inode_t * +__inode_find(inode_table_t *table, uuid_t gfid, const int hash) +{ + inode_t *inode = NULL; + inode_t *tmp = NULL; - list_for_each_entry (tmp, &table->inode_hash[hash], hash) { - if (uuid_compare (tmp->gfid, gfid) == 0) { - inode = tmp; - break; - } + if (__is_root_gfid(gfid)) + return table->root; + + list_for_each_entry(tmp, &table->inode_hash[hash], hash) + { + if (gf_uuid_compare(tmp->gfid, gfid) == 0) { + inode = tmp; + break; } + } -out: - return inode; + return inode; } - inode_t * -inode_find (inode_table_t *table, uuid_t gfid) +inode_find(inode_table_t *table, uuid_t gfid) { - inode_t *inode = NULL; + inode_t *inode = NULL; - if (!table) - return NULL; + if (!table) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, 0, + LG_MSG_INODE_TABLE_NOT_FOUND, + "table not " + "found"); + return NULL; + } - pthread_mutex_lock (&table->lock); - { - inode = __inode_find (table, gfid); - if (inode) - __inode_ref (inode); - } - pthread_mutex_unlock (&table->lock); + int hash = hash_gfid(gfid, 65536); - return inode; -} + pthread_mutex_lock(&table->lock); + { + inode = __inode_find(table, gfid, hash); + if (inode) + __inode_ref(inode, false); + } + pthread_mutex_unlock(&table->lock); + return inode; +} static inode_t * -__inode_link (inode_t *inode, inode_t *parent, const char *name, - struct iatt *iatt) +__inode_link(inode_t *inode, inode_t *parent, const char *name, + struct iatt *iatt, const int dhash) { - dentry_t *dentry = NULL; - dentry_t *old_dentry = NULL; - inode_t *old_inode = NULL; - inode_table_t *table = NULL; - inode_t *link_inode = NULL; + dentry_t *dentry = NULL; + dentry_t *old_dentry = NULL; + inode_t *old_inode = NULL; + inode_table_t *table = NULL; + inode_t *link_inode = NULL; + char link_uuid_str[64] = {0}, parent_uuid_str[64] = {0}; + + table = inode->table; + + if (parent) { + /* We should prevent inode linking between different + inode tables. This can cause errors which is very + hard to catch/debug. */ + if (inode->table != parent->table) { + errno = EINVAL; + GF_ASSERT(!"link attempted b/w inodes of diff table"); + } - if (!inode) - return NULL; + if (parent->ia_type != IA_IFDIR) { + errno = EINVAL; + GF_ASSERT(!"link attempted on non-directory parent"); + return NULL; + } - table = inode->table; - if (!table) - return NULL; + if (!name || strlen(name) == 0) { + errno = EINVAL; + GF_ASSERT (!"link attempted with no basename on " + "parent"); + return NULL; + } + } - link_inode = inode; + link_inode = inode; - if (!__is_inode_hashed (inode)) { - if (!iatt) - return NULL; + if (!__is_inode_hashed(inode)) { + if (!iatt) { + errno = EINVAL; + return NULL; + } - if (uuid_is_null (iatt->ia_gfid)) - return NULL; + if (gf_uuid_is_null(iatt->ia_gfid)) { + errno = EINVAL; + return NULL; + } - uuid_copy (inode->gfid, iatt->ia_gfid); - inode->ino = iatt->ia_ino; - inode->ia_type = iatt->ia_type; + int ihash = hash_gfid(iatt->ia_gfid, 65536); - old_inode = __inode_find (table, inode->gfid); + old_inode = __inode_find(table, iatt->ia_gfid, ihash); - if (old_inode) { - link_inode = old_inode; - } else { - __inode_hash (inode); - } + if (old_inode) { + link_inode = old_inode; + } else { + gf_uuid_copy(inode->gfid, iatt->ia_gfid); + inode->ia_type = iatt->ia_type; + __inode_hash(inode, ihash); } + } else { + /* @old_inode serves another important purpose - it indicates + to the code further below whether a dentry cycle check is + required or not (a new inode linkage can never result in + creation of a loop.) + + if the given @inode is already hashed, it actually means + it is an "old" inode and deserves to undergo the cyclic + check. + */ + old_inode = inode; + } + + if (name && (!strcmp(name, ".") || !strcmp(name, ".."))) { + return link_inode; + } + + /* use only link_inode beyond this point */ + if (parent) { + old_dentry = __dentry_grep(table, parent, name, dhash); + + if (!old_dentry || old_dentry->inode != link_inode) { + dentry = dentry_create(link_inode, parent, name); + if (!dentry) { + gf_msg_callingfn(THIS->name, GF_LOG_ERROR, 0, + LG_MSG_DENTRY_CREATE_FAILED, + "dentry create failed on " + "inode %s with parent %s", + uuid_utoa_r(link_inode->gfid, link_uuid_str), + uuid_utoa_r(parent->gfid, parent_uuid_str)); + errno = ENOMEM; + return NULL; + } - /* use only link_inode beyond this point */ - if (parent) { - old_dentry = __dentry_grep (table, parent, name); + /* dentry linking needs to happen inside lock */ + dentry->parent = __inode_ref(parent, false); + list_add(&dentry->inode_list, &link_inode->dentry_list); - if (!old_dentry || old_dentry->inode != link_inode) { - dentry = __dentry_create (link_inode, parent, name); - __dentry_hash (dentry); + if (old_inode && __is_dentry_cyclic(dentry)) { + errno = ELOOP; + dentry_destroy(__dentry_unset(dentry)); + return NULL; + } + __dentry_hash(dentry, dhash); - if (old_dentry) - __dentry_unset (old_dentry); - } + if (old_dentry) + dentry_destroy(__dentry_unset(old_dentry)); } + } - return link_inode; + return link_inode; } - inode_t * -inode_link (inode_t *inode, inode_t *parent, const char *name, - struct iatt *iatt) +inode_link(inode_t *inode, inode_t *parent, const char *name, struct iatt *iatt) { - inode_table_t *table = NULL; - inode_t *linked_inode = NULL; + int hash = 0; + inode_table_t *table = NULL; + inode_t *linked_inode = NULL; - if (!inode) - return NULL; + if (!inode) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, 0, LG_MSG_INODE_NOT_FOUND, + "inode not found"); + return NULL; + } - table = inode->table; + table = inode->table; - pthread_mutex_lock (&table->lock); - { - linked_inode = __inode_link (inode, parent, name, iatt); + if (parent && name) { + hash = hash_dentry(parent, name, table->hashsize); + } - if (linked_inode) - __inode_ref (linked_inode); - } - pthread_mutex_unlock (&table->lock); + if (name && strchr(name, '/')) { + GF_ASSERT(!"inode link attempted with '/' in name"); + return NULL; + } + + pthread_mutex_lock(&table->lock); + { + linked_inode = __inode_link(inode, parent, name, iatt, hash); + if (linked_inode) + __inode_ref(linked_inode, false); + } + pthread_mutex_unlock(&table->lock); - inode_table_prune (table); + inode_table_prune(table); - return linked_inode; + return linked_inode; } +int +inode_lookup(inode_t *inode) +{ + if (!inode) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, 0, LG_MSG_INODE_NOT_FOUND, + "inode not found"); + return -1; + } + + GF_ATOMIC_INC(inode->nlookup); + + return 0; +} int -inode_lookup (inode_t *inode) +inode_ref_reduce_by_n(inode_t *inode, uint64_t nref) { - inode_table_t *table = NULL; + inode_table_t *table = NULL; - if (!inode) - return -1; + if (!inode) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, 0, LG_MSG_INODE_NOT_FOUND, + "inode not found"); + return -1; + } - table = inode->table; + table = inode->table; - pthread_mutex_lock (&table->lock); - { - __inode_lookup (inode); - } - pthread_mutex_unlock (&table->lock); + pthread_mutex_lock(&table->lock); + { + __inode_ref_reduce_by_n(inode, nref); + } + pthread_mutex_unlock(&table->lock); - return 0; -} + inode_table_prune(table); + return 0; +} int -inode_forget (inode_t *inode, uint64_t nlookup) +inode_forget(inode_t *inode, uint64_t nlookup) { - inode_table_t *table = NULL; + inode_table_t *table = NULL; - if (!inode) - return -1; + if (!inode) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, 0, LG_MSG_INODE_NOT_FOUND, + "inode not found"); + return -1; + } - table = inode->table; + table = inode->table; - pthread_mutex_lock (&table->lock); - { - __inode_forget (inode, nlookup); - } - pthread_mutex_unlock (&table->lock); + inode_forget_atomic(inode, nlookup); - inode_table_prune (table); + inode_table_prune(table); - return 0; + return 0; } - -static void -__inode_unlink (inode_t *inode, inode_t *parent, const char *name) +int +inode_forget_with_unref(inode_t *inode, uint64_t nlookup) { - dentry_t *dentry = NULL; + inode_table_t *table = NULL; - if (!inode || !parent || !name) - return; + if (!inode) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, 0, LG_MSG_INODE_NOT_FOUND, + "inode not found"); + return -1; + } - dentry = __dentry_search_for_inode (inode, parent->ino, name); + table = inode->table; - /* dentry NULL for corrupted backend */ - if (dentry) - __dentry_unset (dentry); + pthread_mutex_lock(&table->lock); + { + inode_forget_atomic(inode, nlookup); + __inode_unref(inode, true); + } + pthread_mutex_unlock(&table->lock); + + inode_table_prune(table); + + return 0; +} + +/* + * Invalidate an inode. This is invoked when a translator decides that an + * inode's cache is no longer valid. Any translator interested in taking action + * in this situation can define the invalidate callback. + */ +int +inode_invalidate(inode_t *inode) +{ + int ret = 0; + xlator_t *xl = NULL; + xlator_t *old_THIS = NULL; + + if (!inode) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, 0, LG_MSG_INODE_NOT_FOUND, + "inode not found"); + return -1; + } + + /* + * The master xlator is not in the graph but it can define an invalidate + * handler. + */ + xl = inode->table->xl->ctx->master; + if (xl && xl->cbks->invalidate) { + old_THIS = THIS; + THIS = xl; + ret = xl->cbks->invalidate(xl, inode); + THIS = old_THIS; + if (ret) + return ret; + } + + xl = inode->table->xl->graph->first; + while (xl) { + old_THIS = THIS; + THIS = xl; + if (xl->cbks->invalidate) + ret = xl->cbks->invalidate(xl, inode); + THIS = old_THIS; + + if (ret) + break; + + xl = xl->next; + } + + return ret; } +static dentry_t * +__inode_unlink(inode_t *inode, inode_t *parent, const char *name) +{ + dentry_t *dentry = NULL; + char pgfid[64] = {0}; + char gfid[64] = {0}; + + dentry = __dentry_search_for_inode(inode, parent->gfid, name); + + /* dentry NULL for corrupted backend */ + if (dentry) { + dentry = __dentry_unset(dentry); + } else { + gf_smsg("inode", GF_LOG_WARNING, 0, LG_MSG_DENTRY_NOT_FOUND, + "parent-gfid=%s name=%s gfid%s", + uuid_utoa_r(parent->gfid, pgfid), name, + uuid_utoa_r(inode->gfid, gfid), NULL); + } + + return dentry; +} void -inode_unlink (inode_t *inode, inode_t *parent, const char *name) +inode_unlink(inode_t *inode, inode_t *parent, const char *name) { - inode_table_t *table = NULL; + inode_table_t *table; + dentry_t *dentry; - if (!inode) - return; + if (!inode || !parent || !name) + return; - table = inode->table; + table = inode->table; - pthread_mutex_lock (&table->lock); - { - __inode_unlink (inode, parent, name); - } - pthread_mutex_unlock (&table->lock); + pthread_mutex_lock(&table->lock); + { + dentry = __inode_unlink(inode, parent, name); + } + pthread_mutex_unlock(&table->lock); - inode_table_prune (table); -} + dentry_destroy(dentry); + inode_table_prune(table); +} int -inode_rename (inode_table_t *table, inode_t *srcdir, const char *srcname, - inode_t *dstdir, const char *dstname, inode_t *inode, - struct iatt *iatt) +inode_rename(inode_table_t *table, inode_t *srcdir, const char *srcname, + inode_t *dstdir, const char *dstname, inode_t *inode, + struct iatt *iatt) { - if (!inode) - return -1; + int hash = 0; + dentry_t *dentry = NULL; - table = inode->table; + if (!inode) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, 0, LG_MSG_INODE_NOT_FOUND, + "inode not found"); + return -1; + } - pthread_mutex_lock (&table->lock); - { - __inode_link (inode, dstdir, dstname, iatt); - __inode_unlink (inode, srcdir, srcname); - } - pthread_mutex_unlock (&table->lock); + table = inode->table; - inode_table_prune (table); + if (dstname && strchr(dstname, '/')) { + GF_ASSERT(!"inode link attempted with '/' in name"); + return -1; + } - return 0; -} + if (dstdir && dstname) { + hash = hash_dentry(dstdir, dstname, table->hashsize); + } + pthread_mutex_lock(&table->lock); + { + __inode_link(inode, dstdir, dstname, iatt, hash); + /* pick the old dentry */ + dentry = __inode_unlink(inode, srcdir, srcname); + } + pthread_mutex_unlock(&table->lock); + + /* free the old dentry */ + dentry_destroy(dentry); + + inode_table_prune(table); + + return 0; +} static dentry_t * -__dentry_search_arbit (inode_t *inode) +__dentry_search_arbit(inode_t *inode) { - dentry_t *dentry = NULL; - dentry_t *trav = NULL; + dentry_t *dentry = NULL; + dentry_t *trav = NULL; - if (!inode) - return NULL; + if (!inode) + return NULL; - list_for_each_entry (trav, &inode->dentry_list, inode_list) { - if (__is_dentry_hashed (trav)) { - dentry = trav; - break; - } + list_for_each_entry(trav, &inode->dentry_list, inode_list) + { + if (__is_dentry_hashed(trav)) { + dentry = trav; + break; } + } - if (!dentry) { - list_for_each_entry (trav, &inode->dentry_list, inode_list) { - dentry = trav; - break; - } + if (!dentry) { + list_for_each_entry(trav, &inode->dentry_list, inode_list) + { + dentry = trav; + break; } + } - return dentry; + return dentry; } - inode_t * -inode_parent (inode_t *inode, ino_t par, const char *name) +inode_parent(inode_t *inode, uuid_t pargfid, const char *name) { - inode_t *parent = NULL; - inode_table_t *table = NULL; - dentry_t *dentry = NULL; + inode_t *parent = NULL; + inode_table_t *table = NULL; + dentry_t *dentry = NULL; - if (!inode) - return NULL; + if (!inode) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, 0, LG_MSG_INODE_NOT_FOUND, + "inode not found"); + return NULL; + } - table = inode->table; + table = inode->table; - pthread_mutex_lock (&table->lock); - { - if (par && name) { - dentry = __dentry_search_for_inode (inode, par, name); - } else { - dentry = __dentry_search_arbit (inode); - } + pthread_mutex_lock(&table->lock); + { + if (pargfid && !gf_uuid_is_null(pargfid) && name) { + dentry = __dentry_search_for_inode(inode, pargfid, name); + } else { + dentry = __dentry_search_arbit(inode); + } - if (dentry) - parent = dentry->parent; + if (dentry) + parent = dentry->parent; - if (parent) - __inode_ref (parent); - } - pthread_mutex_unlock (&table->lock); + if (parent) + __inode_ref(parent, false); + } + pthread_mutex_unlock(&table->lock); - return parent; + return parent; } +static int +__inode_has_dentry(inode_t *inode) +{ + return !list_empty(&inode->dentry_list); +} int -inode_path (inode_t *inode, const char *name, char **bufp) +inode_has_dentry(inode_t *inode) { - inode_table_t *table = NULL; - dentry_t *trav = NULL; - size_t i = 0, size = 0; - int64_t ret = 0; - int len = 0; - char *buf = NULL; + int dentry_present = 0; - if (!inode) - return -1; + if (!inode) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, 0, LG_MSG_INODE_NOT_FOUND, + "inode not found"); + return 0; + } - table = inode->table; + LOCK(&inode->lock); + { + dentry_present = __inode_has_dentry(inode); + } + UNLOCK(&inode->lock); - pthread_mutex_lock (&table->lock); - { - for (trav = __dentry_search_arbit (inode); trav; - trav = __dentry_search_arbit (trav->parent)) { - i ++; /* "/" */ - i += strlen (trav->name); - if (i > PATH_MAX) { - gf_log (table->name, GF_LOG_CRITICAL, - "possible infinite loop detected, " - "forcing break. name=(%s)", name); - ret = -ENOENT; - goto unlock; - } - } + return dentry_present; +} - if ((inode->ino != 1) && - (i == 0)) { - gf_log (table->name, GF_LOG_DEBUG, - "no dentry for non-root inode %"PRId64, - inode->ino); - ret = -ENOENT; - goto unlock; - } +int +__inode_path(inode_t *inode, const char *name, char **bufp) +{ + inode_table_t *table = NULL; + inode_t *itrav = NULL; + dentry_t *trav = NULL; + size_t i = 0, size = 0; + int64_t ret = 0; + int len = 0; + char *buf = NULL; + + if (!inode || gf_uuid_is_null(inode->gfid)) { + GF_ASSERT(0); + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "invalid inode"); + return -EINVAL; + } + + table = inode->table; + + itrav = inode; + for (trav = __dentry_search_arbit(itrav); trav; + trav = __dentry_search_arbit(itrav)) { + itrav = trav->parent; + i++; /* "/" */ + i += strlen(trav->name); + if (i > PATH_MAX) { + gf_smsg(table->name, GF_LOG_CRITICAL, 0, LG_MSG_DENTRY_CYCLIC_LOOP, + "name=%s", name, NULL); + ret = -ENOENT; + goto out; + } + } + + if (!__is_root_gfid(itrav->gfid)) { + /* "<gfid:00000000-0000-0000-0000-000000000000>"/path */ + i += GFID_STR_PFX_LEN; + } + + if (name) { + i++; + i += strlen(name); + } + + ret = i; + size = i + 1; + buf = GF_CALLOC(size, sizeof(char), gf_common_mt_char); + if (buf) { + buf[size - 1] = 0; + + if (name) { + len = strlen(name); + memcpy(buf + (i - len), name, len); + buf[i - len - 1] = '/'; + i -= (len + 1); + } - if (name) { - i++; - i += strlen (name); - } + itrav = inode; + for (trav = __dentry_search_arbit(itrav); trav; + trav = __dentry_search_arbit(itrav)) { + itrav = trav->parent; + len = strlen(trav->name); + memcpy(buf + (i - len), trav->name, len); + buf[i - len - 1] = '/'; + i -= (len + 1); + } - ret = i; - size = i + 1; - buf = GF_CALLOC (size, sizeof (char), gf_common_mt_char); - if (buf) { - - buf[size - 1] = 0; - - if (name) { - len = strlen (name); - strncpy (buf + (i - len), name, len); - buf[i-len-1] = '/'; - i -= (len + 1); - } - - for (trav = __dentry_search_arbit (inode); trav; - trav = __dentry_search_arbit (trav->parent)) { - len = strlen (trav->name); - strncpy (buf + (i - len), trav->name, len); - buf[i-len-1] = '/'; - i -= (len + 1); - } - *bufp = buf; - } else { - gf_log (table->name, GF_LOG_ERROR, - "out of memory"); - ret = -ENOMEM; - } + if (!__is_root_gfid(itrav->gfid)) { + snprintf(&buf[i - GFID_STR_PFX_LEN], GFID_STR_PFX_LEN, + INODE_PATH_FMT, uuid_utoa(itrav->gfid)); + buf[i - 1] = '>'; } -unlock: - pthread_mutex_unlock (&table->lock); - if (inode->ino == 1 && !name) { - ret = 1; - if (buf) { - GF_FREE (buf); - } - buf = GF_CALLOC (ret + 1, sizeof (char), gf_common_mt_char); - if (buf) { - strcpy (buf, "/"); - *bufp = buf; - } else { - gf_log (table->name, GF_LOG_ERROR, - "out of memory"); - ret = -ENOMEM; - } + *bufp = buf; + } else { + ret = -ENOMEM; + } + +out: + if (__is_root_gfid(inode->gfid) && !name) { + ret = 1; + GF_FREE(buf); + buf = GF_CALLOC(ret + 1, sizeof(char), gf_common_mt_char); + if (buf) { + strcpy(buf, "/"); + *bufp = buf; + } else { + ret = -ENOMEM; } + } - return ret; + if (ret < 0) + *bufp = NULL; + return ret; } -static int -inode_table_prune (inode_table_t *table) +int +inode_path(inode_t *inode, const char *name, char **bufp) { - int ret = 0; - struct list_head purge = {0, }; - inode_t *del = NULL; - inode_t *tmp = NULL; - inode_t *entry = NULL; + inode_table_t *table = NULL; + int ret = -1; - if (!table) - return -1; + if (!inode) + return -EINVAL; - INIT_LIST_HEAD (&purge); + table = inode->table; - pthread_mutex_lock (&table->lock); - { - while (table->lru_limit - && table->lru_size > (table->lru_limit)) { + pthread_mutex_lock(&table->lock); + { + ret = __inode_path(inode, name, bufp); + } + pthread_mutex_unlock(&table->lock); + + return ret; +} + +void +__inode_table_set_lru_limit(inode_table_t *table, uint32_t lru_limit) +{ + table->lru_limit = lru_limit; + return; +} + +void +inode_table_set_lru_limit(inode_table_t *table, uint32_t lru_limit) +{ + pthread_mutex_lock(&table->lock); + { + __inode_table_set_lru_limit(table, lru_limit); + } + pthread_mutex_unlock(&table->lock); - entry = list_entry (table->lru.next, inode_t, list); + inode_table_prune(table); - table->lru_size--; - __inode_retire (entry); + return; +} - ret++; +static int +inode_table_prune(inode_table_t *table) +{ + int ret = 0; + int ret1 = 0; + struct list_head purge = { + 0, + }; + inode_t *del = NULL; + inode_t *tmp = NULL; + inode_t *entry = NULL; + uint64_t nlookup = 0; + int64_t lru_size = 0; + + if (!table) + return -1; + + INIT_LIST_HEAD(&purge); + + pthread_mutex_lock(&table->lock); + { + if (!table->lru_limit) + goto purge_list; + + lru_size = table->lru_size; + while (lru_size > (table->lru_limit)) { + if (list_empty(&table->lru)) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, 0, + LG_MSG_INVALID_INODE_LIST, + "Empty inode lru list found" + " but with (%d) lru_size", + table->lru_size); + break; + } + + lru_size--; + entry = list_entry(table->lru.next, inode_t, list); + /* The logic of invalidation is required only if invalidator_fn + is present */ + if (table->invalidator_fn) { + /* check for valid inode with 'nlookup' */ + nlookup = GF_ATOMIC_GET(entry->nlookup); + if (nlookup) { + if (entry->invalidate_sent) { + list_move_tail(&entry->list, &table->lru); + continue; + } + __inode_ref(entry, true); + tmp = entry; + break; } + } - list_splice_init (&table->purge, &purge); - table->purge_size = 0; + table->lru_size--; + __inode_retire(entry); + ret++; } - pthread_mutex_unlock (&table->lock); + purge_list: + list_splice_init(&table->purge, &purge); + table->purge_size = 0; + } + pthread_mutex_unlock(&table->lock); + + /* Pick 1 inode for invalidation */ + if (tmp) { + xlator_t *old_THIS = THIS; + THIS = table->invalidator_xl; + ret1 = table->invalidator_fn(table->invalidator_xl, tmp); + THIS = old_THIS; + pthread_mutex_lock(&table->lock); { - list_for_each_entry_safe (del, tmp, &purge, list) { - list_del_init (&del->list); - __inode_forget (del, 0); - __inode_destroy (del); - } + if (!ret1) { + tmp->invalidate_sent = true; + __inode_unref(tmp, false); + } else { + /* Move this back to the lru list*/ + __inode_unref(tmp, true); + } } - - return ret; + pthread_mutex_unlock(&table->lock); + } + + /* Just so that if purge list is handled too, then clear it off */ + list_for_each_entry_safe(del, tmp, &purge, list) + { + list_del_init(&del->list); + inode_forget_atomic(del, 0); + __inode_destroy(del); + } + + return ret; } - static void -__inode_table_init_root (inode_table_t *table) +__inode_table_init_root(inode_table_t *table) { - inode_t *root = NULL; - struct iatt iatt = {0, }; + inode_t *root = NULL; + struct iatt iatt = { + 0, + }; + + if (!table) + return; - if (!table) - return; + root = inode_create(table); - root = __inode_create (table); + list_add(&root->list, &table->lru); + table->lru_size++; - iatt.ia_gfid[15] = 1; - iatt.ia_ino = 1; - iatt.ia_type = IA_IFDIR; + iatt.ia_gfid[15] = 1; + iatt.ia_ino = 1; + iatt.ia_type = IA_IFDIR; - table->root = root; - __inode_link (root, NULL, NULL, &iatt); + __inode_link(root, NULL, NULL, &iatt, 0); + table->root = root; } - inode_table_t * -inode_table_new (size_t lru_limit, xlator_t *xl) +inode_table_with_invalidator(uint32_t lru_limit, xlator_t *xl, + int32_t (*invalidator_fn)(xlator_t *, inode_t *), + xlator_t *invalidator_xl) { - inode_table_t *new = NULL; - int ret = 0; - int i = 0; + inode_table_t *new = NULL; + uint32_t mem_pool_size = lru_limit; + int ret = -1; + int i = 0; - new = (void *)GF_CALLOC(1, sizeof (*new), gf_common_mt_inode_table_t); - if (!new) - return NULL; + new = (void *)GF_CALLOC(1, sizeof(*new), gf_common_mt_inode_table_t); + if (!new) + return NULL; - new->xl = xl; + new->xl = xl; + new->ctxcount = xl->graph->xl_count + 1; - new->lru_limit = lru_limit; + new->lru_limit = lru_limit; + new->invalidator_fn = invalidator_fn; + new->invalidator_xl = invalidator_xl; - new->hashsize = 14057; /* TODO: Random Number?? */ + new->hashsize = 14057; /* TODO: Random Number?? */ - new->inode_pool = mem_pool_new (inode_t, 204654); + /* In case FUSE is initing the inode table. */ + if (!mem_pool_size || (mem_pool_size > DEFAULT_INODE_MEMPOOL_ENTRIES)) + mem_pool_size = DEFAULT_INODE_MEMPOOL_ENTRIES; - if (!new->inode_pool) { - GF_FREE (new); - return NULL; + new->inode_pool = mem_pool_new(inode_t, mem_pool_size); + if (!new->inode_pool) + goto out; + + new->dentry_pool = mem_pool_new(dentry_t, mem_pool_size); + if (!new->dentry_pool) + goto out; + + new->inode_hash = (void *)GF_CALLOC(65536, sizeof(struct list_head), + gf_common_mt_list_head); + if (!new->inode_hash) + goto out; + + new->name_hash = (void *)GF_CALLOC(new->hashsize, sizeof(struct list_head), + gf_common_mt_list_head); + if (!new->name_hash) + goto out; + + /* if number of fd open in one process is more than this, + we may hit perf issues */ + new->fd_mem_pool = mem_pool_new(fd_t, 1024); + + if (!new->fd_mem_pool) + goto out; + + for (i = 0; i < 65536; i++) { + INIT_LIST_HEAD(&new->inode_hash[i]); + } + + for (i = 0; i < new->hashsize; i++) { + INIT_LIST_HEAD(&new->name_hash[i]); + } + + INIT_LIST_HEAD(&new->active); + INIT_LIST_HEAD(&new->lru); + INIT_LIST_HEAD(&new->purge); + INIT_LIST_HEAD(&new->invalidate); + + ret = gf_asprintf(&new->name, "%s/inode", xl->name); + if (-1 == ret) { + /* TODO: This should be ok to continue, check with avati */ + ; + } + + new->cleanup_started = _gf_false; + + __inode_table_init_root(new); + + pthread_mutex_init(&new->lock, NULL); + + ret = 0; +out: + if (ret) { + if (new) { + GF_FREE(new->inode_hash); + GF_FREE(new->name_hash); + if (new->dentry_pool) + mem_pool_destroy(new->dentry_pool); + if (new->inode_pool) + mem_pool_destroy(new->inode_pool); + GF_FREE(new); + new = NULL; } + } + + return new; +} - new->dentry_pool = mem_pool_new (dentry_t, 204654); +inode_table_t * +inode_table_new(uint32_t lru_limit, xlator_t *xl) +{ + /* Only fuse for now requires the inode table with invalidator */ + return inode_table_with_invalidator(lru_limit, xl, NULL, NULL); +} - if (!new->dentry_pool) { - GF_FREE (new); - return NULL; +int +inode_table_ctx_free(inode_table_t *table) +{ + int ret = 0; + inode_t *del = NULL; + inode_t *tmp = NULL; + int purge_count = 0; + int lru_count = 0; + int active_count = 0; + xlator_t *this = NULL; + int itable_size = 0; + + if (!table) + return -1; + + this = THIS; + + pthread_mutex_lock(&table->lock); + { + list_for_each_entry_safe(del, tmp, &table->purge, list) + { + if (del->_ctx) { + __inode_ctx_free(del); + purge_count++; + } } - new->inode_hash = (void *)GF_CALLOC (65536, - sizeof (struct list_head), - gf_common_mt_list_head); - if (!new->inode_hash) { - GF_FREE (new); - return NULL; + list_for_each_entry_safe(del, tmp, &table->lru, list) + { + if (del->_ctx) { + __inode_ctx_free(del); + lru_count++; + } } - new->name_hash = (void *)GF_CALLOC (new->hashsize, - sizeof (struct list_head), - gf_common_mt_list_head); - if (!new->name_hash) { - GF_FREE (new->inode_hash); - GF_FREE (new); - return NULL; + /* should the contexts of active inodes be freed? + * Since before this function being called fds would have + * been migrated and would have held the ref on the new + * inode from the new inode table, the older inode would not + * be used. + */ + list_for_each_entry_safe(del, tmp, &table->active, list) + { + if (del->_ctx) { + __inode_ctx_free(del); + active_count++; + } } + } + pthread_mutex_unlock(&table->lock); + + ret = purge_count + lru_count + active_count; + itable_size = table->active_size + table->lru_size + table->purge_size; + gf_msg_callingfn(this->name, GF_LOG_INFO, 0, LG_MSG_INODE_CONTEXT_FREED, + "total %d (itable size: " + "%d) inode contexts have been freed (active: %d, (" + "active size: %d), lru: %d, (lru size: %d), purge: " + "%d, (purge size: %d))", + ret, itable_size, active_count, table->active_size, + lru_count, table->lru_size, purge_count, + table->purge_size); + return ret; +} + +void +inode_table_destroy_all(glusterfs_ctx_t *ctx) +{ + glusterfs_graph_t *trav_graph = NULL, *tmp = NULL; + xlator_t *tree = NULL; + inode_table_t *inode_table = NULL; + + if (ctx == NULL) + goto out; + + /* TODO: Traverse ctx->graphs with in ctx->lock and also the other + * graph additions and traversals in ctx->lock. + */ + list_for_each_entry_safe(trav_graph, tmp, &ctx->graphs, list) + { + tree = trav_graph->first; + inode_table = tree->itable; + tree->itable = NULL; + if (inode_table) + inode_table_destroy(inode_table); + } +out: + return; +} - new->fd_mem_pool = mem_pool_new (fd_t, 16384); +void +inode_table_destroy(inode_table_t *inode_table) +{ + inode_t *trav = NULL; - if (!new->fd_mem_pool) { - GF_FREE (new->inode_hash); - GF_FREE (new); - } + if (inode_table == NULL) + return; - for (i = 0; i < 65536; i++) { - INIT_LIST_HEAD (&new->inode_hash[i]); + /* Ideally at this point in time, there should be no inodes with + * refs remaining. But there are quite a few chances where the inodes + * leak. So we can take three approaches for cleaning up the inode table: + * 1. Assume there are no leaks and then send a forget on all the inodes + * in lru list.(If no leaks there should be no inodes in active list) + * 2. Knowing there could be leaks and not freeing those inodes will + * also not free its inode context and this could leak a lot of + * memory, force free the inodes by changing the ref to 0. + * The problem with this is that any reference to inode after this + * calling this function will lead to a crash. + * 3. Knowing there could be leakes, just free the inode contexts of + * all the inodes. and let the inodes be alive. This way the major + * memory consumed by the inode contexts are freed, but there can + * be errors when any inode contexts are accessed after destroying + * this table. + * + * Not sure which is the approach to be taken, going by approach 2. + */ + + /* Approach 3: + * ret = inode_table_ctx_free (inode_table); + */ + pthread_mutex_lock(&inode_table->lock); + { + inode_table->cleanup_started = _gf_true; + /* Process lru list first as we need to unset their dentry + * entries (the ones which may not be unset during + * '__inode_passivate' as they were hashed) which in turn + * shall unref their parent + * + * These parent inodes when unref'ed may well again fall + * into lru list and if we are at the end of traversing + * the list, we may miss to delete/retire that entry. Hence + * traverse the lru list till it gets empty. + */ + while (!list_empty(&inode_table->lru)) { + trav = list_first_entry(&inode_table->lru, inode_t, list); + inode_forget_atomic(trav, 0); + __inode_retire(trav); + inode_table->lru_size--; } + /* Same logic for invalidate list */ + while (!list_empty(&inode_table->invalidate)) { + trav = list_first_entry(&inode_table->invalidate, inode_t, list); + inode_forget_atomic(trav, 0); + __inode_retire(trav); + inode_table->invalidate_size--; + } - for (i = 0; i < new->hashsize; i++) { - INIT_LIST_HEAD (&new->name_hash[i]); + while (!list_empty(&inode_table->active)) { + trav = list_first_entry(&inode_table->active, inode_t, list); + /* forget and unref the inode to retire and add it to + * purge list. By this time there should not be any + * inodes present in the active list except for root + * inode. Its a ref_leak otherwise. */ + if (trav && (trav != inode_table->root)) + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, 0, + LG_MSG_REF_COUNT, + "Active inode(%p) with refcount" + "(%d) found during cleanup", + trav, trav->ref); + inode_forget_atomic(trav, 0); + __inode_ref_reduce_by_n(trav, 0); } + } + pthread_mutex_unlock(&inode_table->lock); - INIT_LIST_HEAD (&new->active); - INIT_LIST_HEAD (&new->lru); - INIT_LIST_HEAD (&new->purge); + inode_table_prune(inode_table); - ret = gf_asprintf (&new->name, "%s/inode", xl->name); - if (-1 == ret) { - /* TODO: This should be ok to continue, check with avati */ - ; - } + GF_FREE(inode_table->inode_hash); + GF_FREE(inode_table->name_hash); + if (inode_table->dentry_pool) + mem_pool_destroy(inode_table->dentry_pool); + if (inode_table->inode_pool) + mem_pool_destroy(inode_table->inode_pool); + if (inode_table->fd_mem_pool) + mem_pool_destroy(inode_table->fd_mem_pool); - __inode_table_init_root (new); + pthread_mutex_destroy(&inode_table->lock); - pthread_mutex_init (&new->lock, NULL); + GF_FREE(inode_table->name); + GF_FREE(inode_table); - return new; + return; } - inode_t * -inode_from_path (inode_table_t *itable, const char *path) +inode_from_path(inode_table_t *itable, const char *path) { - inode_t *inode = NULL; - inode_t *parent = NULL; - inode_t *root = NULL; - inode_t *curr = NULL; - char *pathname = NULL; - char *component = NULL, *next_component = NULL; - char *strtokptr = NULL; + inode_t *inode = NULL; + inode_t *parent = NULL; + inode_t *root = NULL; + inode_t *curr = NULL; + char *pathname = NULL; + char *component = NULL, *next_component = NULL; + char *strtokptr = NULL; + + if (!itable || !path) + return NULL; - if (!itable || !path) - return NULL; + /* top-down approach */ + pathname = gf_strdup(path); + if (pathname == NULL) { + goto out; + } + + root = itable->root; + parent = inode_ref(root); + component = strtok_r(pathname, "/", &strtokptr); + + if (component == NULL) + /* root inode */ + inode = inode_ref(parent); - /* top-down approach */ - pathname = gf_strdup (path); - if (pathname == NULL) { - gf_log ("inode", GF_LOG_ERROR, "out of memory"); - goto out; + while (component) { + curr = inode_grep(itable, parent, component); + + if (curr == NULL) { + strtok_r(NULL, "/", &strtokptr); + break; } - root = itable->root; - parent = inode_ref (root); - component = strtok_r (pathname, "/", &strtokptr); + next_component = strtok_r(NULL, "/", &strtokptr); - if (component == NULL) - /* root inode */ - inode = inode_ref (parent); + if (next_component) { + inode_unref(parent); + parent = curr; + curr = NULL; + } else { + inode = curr; + } - while (component) { - curr = inode_grep (itable, parent, component); + component = next_component; + } - if (curr == NULL) { - strtok_r (NULL, "/", &strtokptr); - break; - } + if (parent) + inode_unref(parent); - next_component = strtok_r (NULL, "/", &strtokptr); + GF_FREE(pathname); - if (next_component) { - inode_unref (parent); - parent = curr; - curr = NULL; - } else { - inode = curr; - } +out: + return inode; +} - component = next_component; - } +void +inode_set_need_lookup(inode_t *inode, xlator_t *this) +{ + uint64_t need_lookup = LOOKUP_NEEDED; - if (parent) - inode_unref (parent); + if (!inode || !this) + return; - if (pathname) - GF_FREE (pathname); + inode_ctx_set(inode, this, &need_lookup); -out: - return inode; + return; } +/* Function behaviour: + * Function return true if inode_ctx is not present, + * or value stored in inode_ctx is LOOKUP_NEEDED. + * If inode_ctx value is LOOKUP_NOT_NEEDED, which means + * inode_ctx is present for xlator this, but no lookup + * needed. + */ +gf_boolean_t +inode_needs_lookup(inode_t *inode, xlator_t *this) +{ + uint64_t need_lookup = 0; + gf_boolean_t ret = _gf_false; + int op_ret = -1; -int -__inode_ctx_put2 (inode_t *inode, xlator_t *xlator, uint64_t value1, - uint64_t value2) -{ - int ret = 0; - int index = 0; - int put_idx = -1; - - if (!inode || !xlator) - return -1; - - for (index = 0; index < xlator->graph->xl_count; index++) { - if (!inode->_ctx[index].xl_key) { - if (put_idx == -1) - put_idx = index; - /* dont break, to check if key already exists - further on */ - } - if (inode->_ctx[index].xl_key == xlator) { - put_idx = index; - break; - } - } + if (!inode || !this) + return ret; - if (put_idx == -1) { - ret = -1; - goto out;; - } + op_ret = inode_ctx_get(inode, this, &need_lookup); + if (op_ret == -1) { + ret = _gf_true; + } else if (need_lookup == LOOKUP_NEEDED) { + ret = _gf_true; + need_lookup = LOOKUP_NOT_NEEDED; + inode_ctx_set(inode, this, &need_lookup); + } - inode->_ctx[put_idx].xl_key = xlator; - inode->_ctx[put_idx].value1 = value1; - inode->_ctx[put_idx].value2 = value2; + return ret; +} + +int +__inode_ctx_set2(inode_t *inode, xlator_t *xlator, uint64_t *value1_p, + uint64_t *value2_p) +{ + int ret = 0; + int set_idx = -1; + + if (!inode || !xlator || !inode->_ctx) + return -1; + + set_idx = __inode_get_xl_index(inode, xlator); + if (set_idx == -1) { + ret = -1; + goto out; + ; + } + + inode->_ctx[set_idx].xl_key = xlator; + if (value1_p) + inode->_ctx[set_idx].value1 = *value1_p; + if (value2_p) + inode->_ctx[set_idx].value2 = *value2_p; out: - return ret; + 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_put2 (inode_t *inode, xlator_t *xlator, uint64_t value1, - uint64_t value2) +inode_ctx_set2(inode_t *inode, xlator_t *xlator, uint64_t *value1_p, + uint64_t *value2_p) { - int ret = 0; + int ret = 0; - if (!inode || !xlator) - return -1; + if (!inode || !xlator) + return -1; - LOCK (&inode->lock); - { - ret = __inode_ctx_put2 (inode, xlator, value1, value2); - } - UNLOCK (&inode->lock); + LOCK(&inode->lock); + { + ret = __inode_ctx_set2(inode, xlator, value1_p, value2_p); + } + UNLOCK(&inode->lock); - return ret; + 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_get2 (inode_t *inode, xlator_t *xlator, uint64_t *value1, - uint64_t *value2) +inode_ctx_set0(inode_t *inode, xlator_t *xlator, uint64_t *value1_p) { - int index = 0; - int ret = 0; + int ret = 0; - if (!inode || !xlator) - return -1; + if (!inode || !xlator) + return -1; - for (index = 0; index < xlator->graph->xl_count; index++) { - if (inode->_ctx[index].xl_key == xlator) - break; - } + LOCK(&inode->lock); + { + ret = __inode_ctx_set0(inode, xlator, value1_p); + } + UNLOCK(&inode->lock); - if (index == xlator->graph->xl_count) { - ret = -1; - goto out; - } + return ret; +} - if (value1) - *value1 = inode->_ctx[index].value1; +int +__inode_ctx_get2(inode_t *inode, xlator_t *xlator, uint64_t *value1, + uint64_t *value2) +{ + int index = 0; + int ret = -1; - if (value2) - *value2 = inode->_ctx[index].value2; + if (!inode || !xlator || !inode->_ctx) + goto out; + index = xlator->xl_id; + if (inode->_ctx[index].xl_key != xlator) + 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; + return ret; } +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) + *value1 = tmp_value; + + return ret; +} int -inode_ctx_get2 (inode_t *inode, xlator_t *xlator, uint64_t *value1, - uint64_t *value2) +__inode_ctx_get1(inode_t *inode, xlator_t *xlator, uint64_t *value2) { - int ret = 0; + uint64_t tmp_value = 0; + int ret = 0; - if (!inode || !xlator) - return -1; + ret = __inode_ctx_get2(inode, xlator, NULL, &tmp_value); + if (!ret && value2) + *value2 = tmp_value; - LOCK (&inode->lock); - { - ret = __inode_ctx_get2 (inode, xlator, value1, value2); - } - UNLOCK (&inode->lock); + return ret; +} - return ret; +int +inode_ctx_get2(inode_t *inode, xlator_t *xlator, uint64_t *value1, + uint64_t *value2) +{ + int ret = 0; + + if (!inode || !xlator) + return -1; + + LOCK(&inode->lock); + { + ret = __inode_ctx_get2(inode, xlator, value1, value2); + } + UNLOCK(&inode->lock); + + 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_del2 (inode_t *inode, xlator_t *xlator, uint64_t *value1, - uint64_t *value2) +inode_ctx_get0(inode_t *inode, xlator_t *xlator, uint64_t *value1) { - int index = 0; - int ret = 0; + int ret = 0; - if (!inode || !xlator) - return -1; + if (!inode || !xlator) + return -1; - LOCK (&inode->lock); - { - for (index = 0; index < xlator->graph->xl_count; index++) { - if (inode->_ctx[index].xl_key == xlator) - break; - } + LOCK(&inode->lock); + { + ret = __inode_ctx_get0(inode, xlator, value1); + } + UNLOCK(&inode->lock); - if (index == xlator->graph->xl_count) { - ret = -1; - goto unlock; - } + return ret; +} - if (value1) - *value1 = inode->_ctx[index].value1; - if (value2) - *value2 = inode->_ctx[index].value2; +int +inode_ctx_del2(inode_t *inode, xlator_t *xlator, uint64_t *value1, + uint64_t *value2) +{ + int index = 0; + int ret = 0; - inode->_ctx[index].key = 0; - inode->_ctx[index].value1 = 0; - inode->_ctx[index].value2 = 0; + if (!inode || !xlator) + return -1; + + LOCK(&inode->lock); + { + if (!inode->_ctx) + goto unlock; + + index = xlator->xl_id; + if (inode->_ctx[index].xl_key != xlator) { + ret = -1; + goto unlock; } + + if (inode->_ctx[index].value1 && value1) + *value1 = inode->_ctx[index].value1; + if (inode->_ctx[index].value2 && value2) + *value2 = inode->_ctx[index].value2; + + inode->_ctx[index].key = 0; + inode->_ctx[index].xl_key = NULL; + inode->_ctx[index].value1 = 0; + inode->_ctx[index].value2 = 0; + } unlock: - UNLOCK (&inode->lock); + UNLOCK(&inode->lock); - return ret; + return ret; } - -int -__inode_ctx_put (inode_t *inode, xlator_t *key, uint64_t value) +/* 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) { - return __inode_ctx_put2 (inode, key, value, 0); -} + int index = 0; + int ret = 0; + + if (!inode || !xlator) + return -1; + + LOCK(&inode->lock); + { + index = xlator->xl_id; + if (inode->_ctx[index].xl_key != xlator) { + 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_put (inode_t *inode, xlator_t *key, uint64_t value) +inode_ctx_reset2(inode_t *inode, xlator_t *xlator, uint64_t *value1_p, + uint64_t *value2_p) { - return inode_ctx_put2 (inode, key, value, 0); + 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_get (inode_t *inode, xlator_t *key, uint64_t *value) +inode_ctx_reset1(inode_t *inode, xlator_t *xlator, uint64_t *value2_p) { - return __inode_ctx_get2 (inode, key, value, 0); -} + 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_get (inode_t *inode, xlator_t *key, uint64_t *value) +inode_ctx_reset0(inode_t *inode, xlator_t *xlator, uint64_t *value1_p) { - return inode_ctx_get2 (inode, key, value, 0); -} + 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; +} int -inode_ctx_del (inode_t *inode, xlator_t *key, uint64_t *value) +inode_is_linked(inode_t *inode) { - return inode_ctx_del2 (inode, key, value, 0); -} + int ret = 0; + inode_table_t *table = NULL; + + if (!inode) { + gf_msg_callingfn(THIS->name, GF_LOG_WARNING, 0, LG_MSG_INODE_NOT_FOUND, + "inode not found"); + return 0; + } + + table = inode->table; + pthread_mutex_lock(&table->lock); + { + ret = __is_inode_hashed(inode); + } + pthread_mutex_unlock(&table->lock); + + return ret; +} void -inode_dump (inode_t *inode, char *prefix) +inode_dump(inode_t *inode, char *prefix) { - char key[GF_DUMP_MAX_BUF_LEN]; - int ret = -1; - xlator_t *xl = NULL; - int i = 0; - char uuidbuf[256]; - - if (!inode) - return; + int ret = -1; + xlator_t *xl = NULL; + int i = 0; + fd_t *fd = NULL; + struct _inode_ctx *inode_ctx = NULL; + struct list_head fd_list; + int ref = 0; + char key[GF_DUMP_MAX_BUF_LEN]; + uint64_t nlookup = 0; + + if (!inode) + return; - ret = TRY_LOCK(&inode->lock); + INIT_LIST_HEAD(&fd_list); - if (ret != 0) { - gf_log("", GF_LOG_WARNING, "Unable to dump inode" - " errno: %d", errno); - return; + ret = TRY_LOCK(&inode->lock); + if (ret != 0) { + return; + } + + { + nlookup = GF_ATOMIC_GET(inode->nlookup); + gf_proc_dump_write("gfid", "%s", uuid_utoa(inode->gfid)); + gf_proc_dump_write("nlookup", "%" PRIu64, nlookup); + gf_proc_dump_write("fd-count", "%u", inode->fd_count); + gf_proc_dump_write("active-fd-count", "%u", inode->active_fd_count); + gf_proc_dump_write("ref", "%u", inode->ref); + gf_proc_dump_write("invalidate-sent", "%d", inode->invalidate_sent); + gf_proc_dump_write("ia_type", "%d", inode->ia_type); + if (inode->_ctx) { + 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->ctxcount; i++) { + inode_ctx[i] = inode->_ctx[i]; + xl = inode_ctx[i].xl_key; + ref = inode_ctx[i].ref; + if (ref != 0 && xl) { + gf_proc_dump_build_key(key, "ref_by_xl:", "%s", xl->name); + gf_proc_dump_write(key, "%d", ref); + } + } } - uuid_unparse (inode->gfid, uuidbuf); - gf_proc_dump_build_key(key, prefix, "gfid"); - gf_proc_dump_write(key, "%s", uuidbuf); - gf_proc_dump_build_key(key, prefix, "nlookup"); - gf_proc_dump_write(key, "%ld", inode->nlookup); - gf_proc_dump_build_key(key, prefix, "ref"); - gf_proc_dump_write(key, "%u", inode->ref); - gf_proc_dump_build_key(key, prefix, "ino"); - gf_proc_dump_write(key, "%ld", inode->ino); - gf_proc_dump_build_key(key, prefix, "ia_type"); - gf_proc_dump_write(key, "%d", inode->ia_type); - UNLOCK(&inode->lock); - if (!inode->_ctx) - goto out; + if (dump_options.xl_options.dump_fdctx != _gf_true) + goto unlock; - for (i = 0; i < inode->table->xl->graph->xl_count; i++) { - if (inode->_ctx[i].xl_key) { - xl = (xlator_t *)(long)inode->_ctx[i].xl_key; - if (xl->dumpops && xl->dumpops->inodectx) - xl->dumpops->inodectx (xl, inode); - } + list_for_each_entry(fd, &inode->fd_list, inode_list) + { + fd_ctx_dump(fd, prefix); + } + } +unlock: + UNLOCK(&inode->lock); + + if (inode_ctx && (dump_options.xl_options.dump_inodectx == _gf_true)) { + 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) + xl->dumpops->inodectx(xl, inode); + } } + } -out: + GF_FREE(inode_ctx); + + return; +} + +void +inode_table_dump(inode_table_t *itable, char *prefix) +{ + char key[GF_DUMP_MAX_BUF_LEN]; + int ret = 0; + + if (!itable) return; + + ret = pthread_mutex_trylock(&itable->lock); + + if (ret != 0) { + return; + } + + gf_proc_dump_build_key(key, prefix, "hashsize"); + gf_proc_dump_write(key, "%" GF_PRI_SIZET, itable->hashsize); + gf_proc_dump_build_key(key, prefix, "name"); + gf_proc_dump_write(key, "%s", itable->name); + + gf_proc_dump_build_key(key, prefix, "lru_limit"); + gf_proc_dump_write(key, "%d", itable->lru_limit); + gf_proc_dump_build_key(key, prefix, "active_size"); + gf_proc_dump_write(key, "%d", itable->active_size); + gf_proc_dump_build_key(key, prefix, "lru_size"); + gf_proc_dump_write(key, "%d", itable->lru_size); + gf_proc_dump_build_key(key, prefix, "purge_size"); + gf_proc_dump_write(key, "%d", itable->purge_size); + gf_proc_dump_build_key(key, prefix, "invalidate_size"); + gf_proc_dump_write(key, "%d", itable->invalidate_size); + + INODE_DUMP_LIST(&itable->active, key, prefix, "active"); + INODE_DUMP_LIST(&itable->lru, key, prefix, "lru"); + INODE_DUMP_LIST(&itable->purge, key, prefix, "purge"); + INODE_DUMP_LIST(&itable->invalidate, key, prefix, "invalidate"); + + pthread_mutex_unlock(&itable->lock); } void -inode_table_dump (inode_table_t *itable, char *prefix) +inode_dump_to_dict(inode_t *inode, char *prefix, dict_t *dict) { + int ret = -1; + char key[GF_DUMP_MAX_BUF_LEN] = { + 0, + }; + uint64_t nlookup = 0; + + ret = TRY_LOCK(&inode->lock); + if (ret) + return; + + snprintf(key, sizeof(key), "%s.gfid", prefix); + ret = dict_set_dynstr(dict, key, gf_strdup(uuid_utoa(inode->gfid))); + if (ret) + goto out; + + snprintf(key, sizeof(key), "%s.nlookup", prefix); + nlookup = GF_ATOMIC_GET(inode->nlookup); + ret = dict_set_uint64(dict, key, nlookup); + if (ret) + goto out; + + snprintf(key, sizeof(key), "%s.ref", prefix); + ret = dict_set_uint32(dict, key, inode->ref); + if (ret) + goto out; + + snprintf(key, sizeof(key), "%s.ia_type", prefix); + ret = dict_set_int32(dict, key, inode->ia_type); + if (ret) + goto out; - char key[GF_DUMP_MAX_BUF_LEN]; - int ret = 0; +out: + UNLOCK(&inode->lock); + return; +} - if (!itable) - return; +void +inode_table_dump_to_dict(inode_table_t *itable, char *prefix, dict_t *dict) +{ + char key[GF_DUMP_MAX_BUF_LEN] = { + 0, + }; + int ret = 0; +#ifdef DEBUG + inode_t *inode = NULL; + int count = 0; +#endif + ret = pthread_mutex_trylock(&itable->lock); + if (ret) + return; - memset(key, 0, sizeof(key)); - ret = pthread_mutex_trylock(&itable->lock); + snprintf(key, sizeof(key), "%s.itable.lru_limit", prefix); + ret = dict_set_uint32(dict, key, itable->lru_limit); + if (ret) + goto out; + + snprintf(key, sizeof(key), "%s.itable.active_size", prefix); + ret = dict_set_uint32(dict, key, itable->active_size); + if (ret) + goto out; + + snprintf(key, sizeof(key), "%s.itable.lru_size", prefix); + ret = dict_set_uint32(dict, key, itable->lru_size); + if (ret) + goto out; + + snprintf(key, sizeof(key), "%s.itable.purge_size", prefix); + ret = dict_set_uint32(dict, key, itable->purge_size); + if (ret) + goto out; + +#ifdef DEBUG + /* Dumping inode details in dictionary and sending it to CLI is not + required as when a developer (or support team) asks for this command + output, they just want to get top level detail of inode table. + If one wants to debug, let them take statedump and debug, this + wouldn't be available in CLI during production setup. + */ + list_for_each_entry(inode, &itable->active, list) + { + snprintf(key, sizeof(key), "%s.itable.active%d", prefix, count++); + inode_dump_to_dict(inode, key, dict); + } + count = 0; + + list_for_each_entry(inode, &itable->lru, list) + { + snprintf(key, sizeof(key), "%s.itable.lru%d", prefix, count++); + inode_dump_to_dict(inode, key, dict); + } + count = 0; + + list_for_each_entry(inode, &itable->purge, list) + { + snprintf(key, sizeof(key), "%s.itable.purge%d", prefix, count++); + inode_dump_to_dict(inode, key, dict); + } +#endif - if (ret != 0) { - gf_log("", GF_LOG_WARNING, "Unable to dump inode table" - " errno: %d", errno); - return; +out: + pthread_mutex_unlock(&itable->lock); + + return; +} + +size_t +inode_ctx_size(inode_t *inode) +{ + int i = 0; + size_t size = 0; + xlator_t *xl = NULL, *old_THIS = NULL; + + if (!inode) + goto out; + + LOCK(&inode->lock); + { + for (i = 0; i < inode->table->ctxcount; i++) { + if (!inode->_ctx[i].xl_key) + continue; + + xl = (xlator_t *)(long)inode->_ctx[i].xl_key; + old_THIS = THIS; + THIS = xl; + + /* If inode ref is taken when THIS is global xlator, + * the ctx xl_key is set, but the value is NULL. + * For global xlator the cbks can be NULL, hence check + * for the same */ + if (!xl->cbks) { + THIS = old_THIS; + continue; + } + + if (xl->cbks->ictxsize) + size += xl->cbks->ictxsize(xl, inode); + + THIS = old_THIS; } + } + UNLOCK(&inode->lock); - gf_proc_dump_build_key(key, prefix, "hashsize"); - gf_proc_dump_write(key, "%d", itable->hashsize); - gf_proc_dump_build_key(key, prefix, "name"); - gf_proc_dump_write(key, "%s", itable->name); - - gf_proc_dump_build_key(key, prefix, "lru_limit"); - gf_proc_dump_write(key, "%d", itable->lru_limit); - gf_proc_dump_build_key(key, prefix, "active_size"); - gf_proc_dump_write(key, "%d", itable->active_size); - gf_proc_dump_build_key(key, prefix, "lru_size"); - gf_proc_dump_write(key, "%d", itable->lru_size); - gf_proc_dump_build_key(key, prefix, "purge_size"); - gf_proc_dump_write(key, "%d", itable->purge_size); - - INODE_DUMP_LIST(&itable->active, key, prefix, "active"); - INODE_DUMP_LIST(&itable->lru, key, prefix, "lru"); - INODE_DUMP_LIST(&itable->purge, key, prefix, "purge"); - - pthread_mutex_unlock(&itable->lock); +out: + return size; +} + +/* * + * This function finds name of the inode, if it has dentry. The dentry will be + * created only if inode_link happens with valid parent and name. And this + * function is only applicable for directories because multiple dentries are + * not possible(no hardlinks) + * */ +void +inode_find_directory_name(inode_t *inode, const char **name) +{ + dentry_t *dentry = NULL; + + GF_VALIDATE_OR_GOTO("inode", inode, out); + GF_VALIDATE_OR_GOTO("inode", name, out); + + if (!IA_ISDIR(inode->ia_type)) + return; + + pthread_mutex_lock(&inode->table->lock); + { + dentry = __dentry_search_arbit(inode); + if (dentry) { + *name = dentry->name; + } + } + pthread_mutex_unlock(&inode->table->lock); +out: + return; } diff --git a/libglusterfs/src/inode.h b/libglusterfs/src/inode.h deleted file mode 100644 index 71d53366946..00000000000 --- a/libglusterfs/src/inode.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - Copyright (c) 2007-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _INODE_H -#define _INODE_H - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include <stdint.h> -#include <sys/types.h> - -struct _inode_table; -typedef struct _inode_table inode_table_t; - -struct _inode; -typedef struct _inode inode_t; - -struct _dentry; -typedef struct _dentry dentry_t; - -#include "list.h" -#include "xlator.h" -#include "iatt.h" -#include "uuid.h" - - -struct _inode_table { - pthread_mutex_t lock; - size_t hashsize; /* bucket size of inode hash and dentry hash */ - char *name; /* name of the inode table, just for gf_log() */ - inode_t *root; /* root directory inode, with number 1 */ - xlator_t *xl; /* xlator to be called to do purge */ - uint32_t lru_limit; /* maximum LRU cache size */ - struct list_head *inode_hash; /* buckets for inode hash table */ - struct list_head *name_hash; /* buckets for dentry hash table */ - struct list_head active; /* list of inodes currently active (in an fop) */ - uint32_t active_size; /* count of inodes in active list */ - struct list_head lru; /* list of inodes recently used. - lru.next most recent */ - uint32_t lru_size; /* count of inodes in lru list */ - struct list_head purge; /* list of inodes to be purged soon */ - uint32_t purge_size; /* count of inodes in purge list */ - - 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 */ -}; - - -struct _dentry { - struct list_head inode_list; /* list of dentries of inode */ - struct list_head hash; /* hash table pointers */ - inode_t *inode; /* inode of this directory entry */ - char *name; /* name of the directory entry */ - inode_t *parent; /* directory of the entry */ -}; - -struct _inode_ctx { - union { - uint64_t key; - xlator_t *xl_key; - }; - union { - uint64_t value1; - void *ptr1; - }; - union { - uint64_t value2; - void *ptr2; - }; -}; - -struct _inode { - inode_table_t *table; /* the table this inode belongs to */ - uuid_t gfid; - gf_lock_t lock; - uint64_t nlookup; - uint32_t ref; /* reference count on this inode */ - ino_t ino; /* inode number in the storage (persistent) */ - ia_type_t ia_type; /* what kind of file */ - struct list_head fd_list; /* list of open files on this inode */ - struct list_head dentry_list; /* list of directory entries for this inode */ - struct list_head hash; /* hash table pointers */ - struct list_head list; /* active/lru/purge */ - - struct _inode_ctx *_ctx; /* replacement for dict_t *(inode->ctx) */ -}; - - -inode_table_t * -inode_table_new (size_t lru_limit, xlator_t *xl); - -inode_t * -inode_new (inode_table_t *table); - -inode_t * -inode_link (inode_t *inode, inode_t *parent, - const char *name, struct iatt *stbuf); - -void -inode_unlink (inode_t *inode, inode_t *parent, const char *name); - -inode_t * -inode_parent (inode_t *inode, ino_t par, const char *name); - -inode_t * -inode_ref (inode_t *inode); - -inode_t * -inode_unref (inode_t *inode); - -int -inode_lookup (inode_t *inode); - -int -inode_forget (inode_t *inode, uint64_t nlookup); - -int -inode_rename (inode_table_t *table, inode_t *olddir, const char *oldname, - inode_t *newdir, const char *newname, - inode_t *inode, struct iatt *stbuf); - -inode_t * -inode_grep (inode_table_t *table, inode_t *parent, const char *name); - -inode_t * -inode_get (inode_table_t *table, ino_t ino, uint64_t gen); - -inode_t * -inode_find (inode_table_t *table, uuid_t gfid); - -int -inode_path (inode_t *inode, const char *name, char **bufp); - -inode_t * -inode_from_path (inode_table_t *table, const char *path); - -int -__inode_ctx_put (inode_t *inode, xlator_t *xlator, uint64_t value); - -int -inode_ctx_put (inode_t *inode, xlator_t *xlator, uint64_t value); - -int -__inode_ctx_get (inode_t *inode, xlator_t *xlator, uint64_t *value); - -int -inode_ctx_get (inode_t *inode, xlator_t *xlator, uint64_t *value); - -int -inode_ctx_del (inode_t *inode, xlator_t *xlator, uint64_t *value); - -int -inode_ctx_put2 (inode_t *inode, xlator_t *xlator, uint64_t value1, - uint64_t value2); - -int -inode_ctx_get2 (inode_t *inode, xlator_t *xlator, uint64_t *value1, - uint64_t *value2); - -int -inode_ctx_del2 (inode_t *inode, xlator_t *xlator, uint64_t *value1, - uint64_t *value2); - -#endif /* _INODE_H */ diff --git a/libglusterfs/src/iobuf.c b/libglusterfs/src/iobuf.c index b25a94e7f1e..4e7d2958764 100644 --- a/libglusterfs/src/iobuf.c +++ b/libglusterfs/src/iobuf.c @@ -1,747 +1,1146 @@ /* - Copyright (c) 2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ -#include "iobuf.h" -#include "statedump.h" +#include "glusterfs/iobuf.h" +#include "glusterfs/statedump.h" #include <stdio.h> - +#include "glusterfs/libglusterfs-messages.h" /* TODO: implement destroy margins and prefetching of arenas */ -void -__iobuf_arena_init_iobufs (struct iobuf_arena *iobuf_arena) -{ - size_t arena_size = 0; - size_t page_size = 0; - int iobuf_cnt = 0; - struct iobuf *iobuf = NULL; - int offset = 0; - int i = 0; - - arena_size = iobuf_arena->iobuf_pool->arena_size; - page_size = iobuf_arena->iobuf_pool->page_size; - iobuf_cnt = arena_size / page_size; - - iobuf_arena->iobufs = GF_CALLOC (sizeof (*iobuf), iobuf_cnt, - gf_common_mt_iobuf); - if (!iobuf_arena->iobufs) - return; +#define IOBUF_ARENA_MAX_INDEX \ + (sizeof(gf_iobuf_init_config) / (sizeof(struct iobuf_init_config))) - iobuf = iobuf_arena->iobufs; - for (i = 0; i < iobuf_cnt; i++) { - INIT_LIST_HEAD (&iobuf->list); - LOCK_INIT (&iobuf->lock); +/* Make sure this array is sorted based on pagesize */ +static const struct iobuf_init_config gf_iobuf_init_config[] = { + /* { pagesize, num_pages }, */ + {128, 1024}, {512, 512}, {2 * 1024, 512}, {8 * 1024, 128}, + {32 * 1024, 64}, {128 * 1024, 32}, {256 * 1024, 8}, {1 * 1024 * 1024, 2}, +}; - iobuf->iobuf_arena = iobuf_arena; +static int +gf_iobuf_get_arena_index(const size_t page_size) +{ + int i; - iobuf->ptr = iobuf_arena->mem_base + offset; + for (i = 0; i < IOBUF_ARENA_MAX_INDEX; i++) { + if (page_size <= gf_iobuf_init_config[i].pagesize) + return i; + } - list_add (&iobuf->list, &iobuf_arena->passive.list); - iobuf_arena->passive_cnt++; + return -1; +} - offset += page_size; - iobuf++; +static size_t +gf_iobuf_get_pagesize(const size_t page_size, int *index) +{ + int i; + size_t size = 0; + + for (i = 0; i < IOBUF_ARENA_MAX_INDEX; i++) { + size = gf_iobuf_init_config[i].pagesize; + if (page_size <= size) { + if (index != NULL) + *index = i; + return size; } -} + } + return -1; +} -void -__iobuf_arena_destroy_iobufs (struct iobuf_arena *iobuf_arena) +static void +__iobuf_arena_init_iobufs(struct iobuf_arena *iobuf_arena) { - size_t arena_size = 0; - size_t page_size = 0; - int iobuf_cnt = 0; - struct iobuf *iobuf = NULL; - int i = 0; + const int iobuf_cnt = iobuf_arena->page_count; + struct iobuf *iobuf = NULL; + int offset = 0; + int i = 0; + + iobuf_arena->iobufs = GF_CALLOC(sizeof(*iobuf), iobuf_cnt, + gf_common_mt_iobuf); + if (!iobuf_arena->iobufs) + return; - arena_size = iobuf_arena->iobuf_pool->arena_size; - page_size = iobuf_arena->iobuf_pool->page_size; - iobuf_cnt = arena_size / page_size; + iobuf = iobuf_arena->iobufs; + for (i = 0; i < iobuf_cnt; i++) { + INIT_LIST_HEAD(&iobuf->list); + LOCK_INIT(&iobuf->lock); - if (!iobuf_arena->iobufs) - return; + iobuf->iobuf_arena = iobuf_arena; - iobuf = iobuf_arena->iobufs; - for (i = 0; i < iobuf_cnt; i++) { - assert (iobuf->ref == 0); + iobuf->ptr = iobuf_arena->mem_base + offset; - list_del_init (&iobuf->list); - iobuf++; - } + list_add(&iobuf->list, &iobuf_arena->passive.list); + iobuf_arena->passive_cnt++; - GF_FREE (iobuf_arena->iobufs); -} + offset += iobuf_arena->page_size; + iobuf++; + } + return; +} -void -__iobuf_arena_destroy (struct iobuf_arena *iobuf_arena) +static void +__iobuf_arena_destroy_iobufs(struct iobuf_arena *iobuf_arena) { - struct iobuf_pool *iobuf_pool = NULL; + int iobuf_cnt = 0; + struct iobuf *iobuf = NULL; + int i = 0; - if (!iobuf_arena) - return; + if (!iobuf_arena->iobufs) { + gf_msg_callingfn(THIS->name, GF_LOG_ERROR, 0, LG_MSG_IOBUFS_NOT_FOUND, + "iobufs not found"); + return; + } - iobuf_pool = iobuf_arena->iobuf_pool; + iobuf_cnt = iobuf_arena->page_count; + iobuf = iobuf_arena->iobufs; + for (i = 0; i < iobuf_cnt; i++) { + GF_ASSERT(GF_ATOMIC_GET(iobuf->ref) == 0); - __iobuf_arena_destroy_iobufs (iobuf_arena); + LOCK_DESTROY(&iobuf->lock); + list_del_init(&iobuf->list); + iobuf++; + } - if (iobuf_arena->mem_base - && iobuf_arena->mem_base != MAP_FAILED) - munmap (iobuf_arena->mem_base, iobuf_pool->arena_size); + GF_FREE(iobuf_arena->iobufs); - GF_FREE (iobuf_arena); + return; } - -struct iobuf_arena * -__iobuf_arena_alloc (struct iobuf_pool *iobuf_pool) +static void +__iobuf_arena_destroy(struct iobuf_pool *iobuf_pool, + struct iobuf_arena *iobuf_arena) { - struct iobuf_arena *iobuf_arena = NULL; - size_t arena_size = 0; + GF_VALIDATE_OR_GOTO("iobuf", iobuf_arena, out); - iobuf_arena = GF_CALLOC (sizeof (*iobuf_arena), 1, - gf_common_mt_iobuf_arena); - if (!iobuf_arena) - goto err; + if (iobuf_pool->rdma_deregistration) + iobuf_pool->rdma_deregistration(iobuf_pool->mr_list, iobuf_arena); - INIT_LIST_HEAD (&iobuf_arena->list); - INIT_LIST_HEAD (&iobuf_arena->active.list); - INIT_LIST_HEAD (&iobuf_arena->passive.list); - iobuf_arena->iobuf_pool = iobuf_pool; + __iobuf_arena_destroy_iobufs(iobuf_arena); - arena_size = iobuf_pool->arena_size; - iobuf_arena->mem_base = mmap (NULL, arena_size, PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); - if (iobuf_arena->mem_base == MAP_FAILED) - goto err; + if (iobuf_arena->mem_base && iobuf_arena->mem_base != MAP_FAILED) + munmap(iobuf_arena->mem_base, iobuf_arena->arena_size); - __iobuf_arena_init_iobufs (iobuf_arena); - if (!iobuf_arena->iobufs) - goto err; + GF_FREE(iobuf_arena); +out: + return; +} - iobuf_pool->arena_cnt++; +static struct iobuf_arena * +__iobuf_arena_alloc(struct iobuf_pool *iobuf_pool, size_t page_size, + int32_t num_iobufs) +{ + struct iobuf_arena *iobuf_arena = NULL; + size_t rounded_size = 0; + int index = 0; /* unused */ - return iobuf_arena; + GF_VALIDATE_OR_GOTO("iobuf", iobuf_pool, out); -err: - __iobuf_arena_destroy (iobuf_arena); - return NULL; -} + iobuf_arena = GF_CALLOC(sizeof(*iobuf_arena), 1, gf_common_mt_iobuf_arena); + if (!iobuf_arena) + goto err; + INIT_LIST_HEAD(&iobuf_arena->list); + INIT_LIST_HEAD(&iobuf_arena->all_list); + INIT_LIST_HEAD(&iobuf_arena->active.list); + INIT_LIST_HEAD(&iobuf_arena->passive.list); + iobuf_arena->iobuf_pool = iobuf_pool; -struct iobuf_arena * -__iobuf_arena_unprune (struct iobuf_pool *iobuf_pool) -{ - struct iobuf_arena *iobuf_arena = NULL; - struct iobuf_arena *tmp = NULL; + rounded_size = gf_iobuf_get_pagesize(page_size, &index); - list_for_each_entry (tmp, &iobuf_pool->purge.list, list) { - list_del_init (&tmp->list); - iobuf_arena = tmp; - break; - } + iobuf_arena->page_size = rounded_size; + iobuf_arena->page_count = num_iobufs; - return iobuf_arena; -} + iobuf_arena->arena_size = rounded_size * num_iobufs; + iobuf_arena->mem_base = mmap(NULL, iobuf_arena->arena_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (iobuf_arena->mem_base == MAP_FAILED) { + gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_MAPPING_FAILED, NULL); + goto err; + } -struct iobuf_arena * -__iobuf_pool_add_arena (struct iobuf_pool *iobuf_pool) -{ - struct iobuf_arena *iobuf_arena = NULL; + if (iobuf_pool->rdma_registration) { + iobuf_pool->rdma_registration(iobuf_pool->device, iobuf_arena); + } - iobuf_arena = __iobuf_arena_unprune (iobuf_pool); + list_add_tail(&iobuf_arena->all_list, &iobuf_pool->all_arenas); - if (!iobuf_arena) - iobuf_arena = __iobuf_arena_alloc (iobuf_pool); + __iobuf_arena_init_iobufs(iobuf_arena); + if (!iobuf_arena->iobufs) { + gf_smsg(THIS->name, GF_LOG_ERROR, 0, LG_MSG_INIT_IOBUF_FAILED, NULL); + goto err; + } - if (!iobuf_arena) - return NULL; + iobuf_pool->arena_cnt++; - list_add_tail (&iobuf_arena->list, &iobuf_pool->arenas.list); + return iobuf_arena; - return iobuf_arena; +err: + __iobuf_arena_destroy(iobuf_pool, iobuf_arena); + +out: + return NULL; } +static struct iobuf_arena * +__iobuf_arena_unprune(struct iobuf_pool *iobuf_pool, const size_t page_size, + const int index) +{ + struct iobuf_arena *iobuf_arena = NULL; + struct iobuf_arena *tmp = NULL; + + GF_VALIDATE_OR_GOTO("iobuf", iobuf_pool, out); -struct iobuf_arena * -iobuf_pool_add_arena (struct iobuf_pool *iobuf_pool) + list_for_each_entry(tmp, &iobuf_pool->purge[index], list) + { + list_del_init(&tmp->list); + iobuf_arena = tmp; + break; + } +out: + return iobuf_arena; +} + +static struct iobuf_arena * +__iobuf_pool_add_arena(struct iobuf_pool *iobuf_pool, const size_t page_size, + const int32_t num_pages, const int index) { - struct iobuf_arena *iobuf_arena = NULL; + struct iobuf_arena *iobuf_arena = NULL; - pthread_mutex_lock (&iobuf_pool->mutex); - { - iobuf_arena = __iobuf_pool_add_arena (iobuf_pool); + iobuf_arena = __iobuf_arena_unprune(iobuf_pool, page_size, index); + + if (!iobuf_arena) { + iobuf_arena = __iobuf_arena_alloc(iobuf_pool, page_size, num_pages); + if (!iobuf_arena) { + gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_ARENA_NOT_FOUND, + NULL); + return NULL; } - pthread_mutex_unlock (&iobuf_pool->mutex); + } + list_add(&iobuf_arena->list, &iobuf_pool->arenas[index]); - return iobuf_arena; + return iobuf_arena; } - +/* This function destroys all the iobufs and the iobuf_pool */ void -iobuf_pool_destroy (struct iobuf_pool *iobuf_pool) +iobuf_pool_destroy(struct iobuf_pool *iobuf_pool) { - struct iobuf_arena *iobuf_arena = NULL; - struct iobuf_arena *tmp = NULL; + struct iobuf_arena *iobuf_arena = NULL; + struct iobuf_arena *tmp = NULL; + int i = 0; + + GF_VALIDATE_OR_GOTO("iobuf", iobuf_pool, out); + + pthread_mutex_lock(&iobuf_pool->mutex); + { + for (i = 0; i < IOBUF_ARENA_MAX_INDEX; i++) { + list_for_each_entry_safe(iobuf_arena, tmp, &iobuf_pool->arenas[i], + list) + { + list_del_init(&iobuf_arena->list); + iobuf_pool->arena_cnt--; - if (!iobuf_pool) - return; + __iobuf_arena_destroy(iobuf_pool, iobuf_arena); + } + list_for_each_entry_safe(iobuf_arena, tmp, &iobuf_pool->purge[i], + list) + { + list_del_init(&iobuf_arena->list); + iobuf_pool->arena_cnt--; + __iobuf_arena_destroy(iobuf_pool, iobuf_arena); + } + /* If there are no iobuf leaks, there should be no + * arenas in the filled list. If at all there are any + * arenas in the filled list, the below function will + * assert. + */ + list_for_each_entry_safe(iobuf_arena, tmp, &iobuf_pool->filled[i], + list) + { + list_del_init(&iobuf_arena->list); + iobuf_pool->arena_cnt--; + __iobuf_arena_destroy(iobuf_pool, iobuf_arena); + } + /* If there are no iobuf leaks, there shoould be + * no standard allocated arenas, iobuf_put will free + * such arenas. + * TODO: Free the stdalloc arenas forcefully if present? + */ + } + } + pthread_mutex_unlock(&iobuf_pool->mutex); - list_for_each_entry_safe (iobuf_arena, tmp, &iobuf_pool->arenas.list, - list) { + pthread_mutex_destroy(&iobuf_pool->mutex); - list_del_init (&iobuf_arena->list); - iobuf_pool->arena_cnt--; + GF_FREE(iobuf_pool); - __iobuf_arena_destroy (iobuf_arena); - } +out: + return; } - -struct iobuf_pool * -iobuf_pool_new (size_t arena_size, size_t page_size) +static void +iobuf_create_stdalloc_arena(struct iobuf_pool *iobuf_pool) { - struct iobuf_pool *iobuf_pool = NULL; + struct iobuf_arena *iobuf_arena = NULL; - if (arena_size < page_size) - return NULL; + /* No locking required here as its called only once during init */ + iobuf_arena = GF_CALLOC(sizeof(*iobuf_arena), 1, gf_common_mt_iobuf_arena); + if (!iobuf_arena) + goto err; - iobuf_pool = GF_CALLOC (sizeof (*iobuf_pool), 1, - gf_common_mt_iobuf_pool); - if (!iobuf_pool) - return NULL; + INIT_LIST_HEAD(&iobuf_arena->list); + INIT_LIST_HEAD(&iobuf_arena->active.list); + INIT_LIST_HEAD(&iobuf_arena->passive.list); - pthread_mutex_init (&iobuf_pool->mutex, NULL); - INIT_LIST_HEAD (&iobuf_pool->arenas.list); - INIT_LIST_HEAD (&iobuf_pool->filled.list); - INIT_LIST_HEAD (&iobuf_pool->purge.list); + iobuf_arena->iobuf_pool = iobuf_pool; - iobuf_pool->arena_size = arena_size; - iobuf_pool->page_size = page_size; + iobuf_arena->page_size = 0x7fffffff; - iobuf_pool_add_arena (iobuf_pool); + list_add_tail(&iobuf_arena->list, + &iobuf_pool->arenas[IOBUF_ARENA_MAX_INDEX]); - return iobuf_pool; +err: + return; } - -void -__iobuf_pool_prune (struct iobuf_pool *iobuf_pool) +struct iobuf_pool * +iobuf_pool_new(void) { - struct iobuf_arena *iobuf_arena = NULL; - struct iobuf_arena *tmp = NULL; + struct iobuf_pool *iobuf_pool = NULL; + int i = 0; + size_t page_size = 0; + size_t arena_size = 0; + int32_t num_pages = 0; + + iobuf_pool = GF_CALLOC(sizeof(*iobuf_pool), 1, gf_common_mt_iobuf_pool); + if (!iobuf_pool) + goto out; + INIT_LIST_HEAD(&iobuf_pool->all_arenas); + pthread_mutex_init(&iobuf_pool->mutex, NULL); + for (i = 0; i <= IOBUF_ARENA_MAX_INDEX; i++) { + INIT_LIST_HEAD(&iobuf_pool->arenas[i]); + INIT_LIST_HEAD(&iobuf_pool->filled[i]); + INIT_LIST_HEAD(&iobuf_pool->purge[i]); + } + + iobuf_pool->default_page_size = 128 * GF_UNIT_KB; + + iobuf_pool->rdma_registration = NULL; + iobuf_pool->rdma_deregistration = NULL; + + for (i = 0; i < GF_RDMA_DEVICE_COUNT; i++) { + iobuf_pool->device[i] = NULL; + iobuf_pool->mr_list[i] = NULL; + } + + /* No locking required here + * as no one else can use this pool yet + */ + for (i = 0; i < IOBUF_ARENA_MAX_INDEX; i++) { + page_size = gf_iobuf_init_config[i].pagesize; + num_pages = gf_iobuf_init_config[i].num_pages; + + if (__iobuf_pool_add_arena(iobuf_pool, page_size, num_pages, i) != NULL) + arena_size += page_size * num_pages; + } + + /* Need an arena to handle all the bigger iobuf requests */ + iobuf_create_stdalloc_arena(iobuf_pool); + + iobuf_pool->arena_size = arena_size; +out: - if (list_empty (&iobuf_pool->arenas.list)) - /* buffering - preserve this one arena (if at all) - for __iobuf_arena_unprune */ - return; + return iobuf_pool; +} - list_for_each_entry_safe (iobuf_arena, tmp, &iobuf_pool->purge.list, - list) { - if (iobuf_arena->active_cnt) - continue; +static void +__iobuf_arena_prune(struct iobuf_pool *iobuf_pool, + struct iobuf_arena *iobuf_arena, const int index) +{ + /* code flow comes here only if the arena is in purge list and we can + * free the arena only if we have at least one arena in 'arenas' list + * (ie, at least few iobufs free in arena), that way, there won't + * be spurious mmap/unmap of buffers + */ + if (list_empty(&iobuf_pool->arenas[index])) + goto out; - list_del_init (&iobuf_arena->list); - iobuf_pool->arena_cnt--; + /* All cases matched, destroy */ + list_del_init(&iobuf_arena->list); + list_del_init(&iobuf_arena->all_list); + iobuf_pool->arena_cnt--; - __iobuf_arena_destroy (iobuf_arena); - } -} + __iobuf_arena_destroy(iobuf_pool, iobuf_arena); +out: + return; +} void -iobuf_pool_prune (struct iobuf_pool *iobuf_pool) +iobuf_pool_prune(struct iobuf_pool *iobuf_pool) { - pthread_mutex_lock (&iobuf_pool->mutex); - { - __iobuf_pool_prune (iobuf_pool); + struct iobuf_arena *iobuf_arena = NULL; + struct iobuf_arena *tmp = NULL; + int i = 0; + + GF_VALIDATE_OR_GOTO("iobuf", iobuf_pool, out); + + pthread_mutex_lock(&iobuf_pool->mutex); + { + for (i = 0; i < IOBUF_ARENA_MAX_INDEX; i++) { + if (list_empty(&iobuf_pool->arenas[i])) { + continue; + } + + list_for_each_entry_safe(iobuf_arena, tmp, &iobuf_pool->purge[i], + list) + { + __iobuf_arena_prune(iobuf_pool, iobuf_arena, i); + } } - pthread_mutex_unlock (&iobuf_pool->mutex); -} + } + pthread_mutex_unlock(&iobuf_pool->mutex); +out: + return; +} -struct iobuf_arena * -__iobuf_select_arena (struct iobuf_pool *iobuf_pool) +/* Always called under the iobuf_pool mutex lock */ +static struct iobuf_arena * +__iobuf_select_arena(struct iobuf_pool *iobuf_pool, const size_t page_size, + const int index) { - struct iobuf_arena *iobuf_arena = NULL; - struct iobuf_arena *trav = NULL; - - /* look for unused iobuf from the head-most arena */ - list_for_each_entry (trav, &iobuf_pool->arenas.list, list) { - if (trav->passive_cnt) { - iobuf_arena = trav; - break; - } + struct iobuf_arena *iobuf_arena = NULL; + struct iobuf_arena *trav = NULL; + + /* look for unused iobuf from the head-most arena */ + list_for_each_entry(trav, &iobuf_pool->arenas[index], list) + { + if (trav->passive_cnt) { + iobuf_arena = trav; + break; } + } - if (!iobuf_arena) { - /* all arenas were full */ - iobuf_arena = __iobuf_pool_add_arena (iobuf_pool); - } + if (!iobuf_arena) { + /* all arenas were full, find the right count to add */ + iobuf_arena = __iobuf_pool_add_arena( + iobuf_pool, page_size, gf_iobuf_init_config[index].num_pages, + index); + } - return iobuf_arena; + return iobuf_arena; } - -struct iobuf * -__iobuf_ref (struct iobuf *iobuf) +/* Always called under the iobuf_pool mutex lock */ +static struct iobuf * +__iobuf_get(struct iobuf_pool *iobuf_pool, const size_t page_size, + const int index) { - iobuf->ref++; + struct iobuf *iobuf = NULL; + struct iobuf_arena *iobuf_arena = NULL; - return iobuf; -} + /* most eligible arena for picking an iobuf */ + iobuf_arena = __iobuf_select_arena(iobuf_pool, page_size, index); + if (!iobuf_arena) + return NULL; + list_for_each_entry(iobuf, &iobuf_arena->passive.list, list) break; -struct iobuf * -__iobuf_unref (struct iobuf *iobuf) -{ - iobuf->ref--; + list_del(&iobuf->list); + iobuf_arena->passive_cnt--; - return iobuf; -} + list_add(&iobuf->list, &iobuf_arena->active.list); + iobuf_arena->active_cnt++; + /* no resetting requied for this element */ + iobuf_arena->alloc_cnt++; -struct iobuf * -__iobuf_get (struct iobuf_arena *iobuf_arena) -{ - struct iobuf *iobuf = NULL; - struct iobuf_pool *iobuf_pool = NULL; + if (iobuf_arena->max_active < iobuf_arena->active_cnt) + iobuf_arena->max_active = iobuf_arena->active_cnt; - iobuf_pool = iobuf_arena->iobuf_pool; + if (iobuf_arena->passive_cnt == 0) { + list_del(&iobuf_arena->list); + list_add(&iobuf_arena->list, &iobuf_pool->filled[index]); + } - list_for_each_entry (iobuf, &iobuf_arena->passive.list, list) - break; + return iobuf; +} - list_del (&iobuf->list); - iobuf_arena->passive_cnt--; +static struct iobuf * +iobuf_get_from_stdalloc(struct iobuf_pool *iobuf_pool, const size_t page_size) +{ + struct iobuf *iobuf = NULL; + struct iobuf_arena *iobuf_arena = NULL; + struct iobuf_arena *trav = NULL; + int ret = -1; + + /* The first arena in the 'MAX-INDEX' will always be used for misc */ + list_for_each_entry(trav, &iobuf_pool->arenas[IOBUF_ARENA_MAX_INDEX], list) + { + iobuf_arena = trav; + break; + } + + iobuf = GF_CALLOC(1, sizeof(*iobuf), gf_common_mt_iobuf); + if (!iobuf) + goto out; + + /* 4096 is the alignment */ + iobuf->free_ptr = GF_CALLOC(1, ((page_size + GF_IOBUF_ALIGN_SIZE) - 1), + gf_common_mt_char); + if (!iobuf->free_ptr) + goto out; + + iobuf->ptr = GF_ALIGN_BUF(iobuf->free_ptr, GF_IOBUF_ALIGN_SIZE); + iobuf->iobuf_arena = iobuf_arena; + LOCK_INIT(&iobuf->lock); + + /* Hold a ref because you are allocating and using it */ + GF_ATOMIC_INIT(iobuf->ref, 1); + + ret = 0; +out: + if (ret && iobuf) { + GF_FREE(iobuf->free_ptr); + GF_FREE(iobuf); + iobuf = NULL; + } - list_add (&iobuf->list, &iobuf_arena->active.list); - iobuf_arena->active_cnt++; + return iobuf; +} - if (iobuf_arena->passive_cnt == 0) { - list_del (&iobuf_arena->list); - list_add (&iobuf_arena->list, &iobuf_pool->filled.list); +struct iobuf * +iobuf_get2(struct iobuf_pool *iobuf_pool, size_t page_size) +{ + struct iobuf *iobuf = NULL; + size_t rounded_size = 0; + int index = 0; + + if (page_size == 0) { + page_size = iobuf_pool->default_page_size; + } + + rounded_size = gf_iobuf_get_pagesize(page_size, &index); + if (rounded_size == -1) { + /* make sure to provide the requested buffer with standard + memory allocations */ + iobuf = iobuf_get_from_stdalloc(iobuf_pool, page_size); + + gf_msg_debug("iobuf", 0, + "request for iobuf of size %zu " + "is serviced using standard calloc() (%p) as it " + "exceeds the maximum available buffer size", + page_size, iobuf); + + iobuf_pool->request_misses++; + return iobuf; + } else if (index == -1) { + gf_smsg("iobuf", GF_LOG_ERROR, 0, LG_MSG_PAGE_SIZE_EXCEEDED, + "page_size=%zu", page_size, NULL); + return NULL; + } + + pthread_mutex_lock(&iobuf_pool->mutex); + { + iobuf = __iobuf_get(iobuf_pool, rounded_size, index); + if (!iobuf) { + pthread_mutex_unlock(&iobuf_pool->mutex); + gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_IOBUF_NOT_FOUND, + NULL); + goto post_unlock; } - return iobuf; + iobuf_ref(iobuf); + } + pthread_mutex_unlock(&iobuf_pool->mutex); +post_unlock: + return iobuf; } - struct iobuf * -iobuf_get (struct iobuf_pool *iobuf_pool) +iobuf_get_page_aligned(struct iobuf_pool *iobuf_pool, size_t page_size, + size_t align_size) { - struct iobuf *iobuf = NULL; - struct iobuf_arena *iobuf_arena = NULL; - - pthread_mutex_lock (&iobuf_pool->mutex); - { - /* most eligible arena for picking an iobuf */ - iobuf_arena = __iobuf_select_arena (iobuf_pool); - if (!iobuf_arena) - goto unlock; + size_t req_size = 0; + struct iobuf *iobuf = NULL; - iobuf = __iobuf_get (iobuf_arena); - if (!iobuf) - goto unlock; + req_size = page_size; - __iobuf_ref (iobuf); - } -unlock: - pthread_mutex_unlock (&iobuf_pool->mutex); + if (req_size == 0) { + req_size = iobuf_pool->default_page_size; + } - return iobuf; + iobuf = iobuf_get2(iobuf_pool, req_size + align_size); + if (!iobuf) + return NULL; + /* If std allocation was used, then free_ptr will be non-NULL. In this + * case, we do not want to modify the original free_ptr. + * On the other hand, if the buf was gotten through the available + * arenas, then we use iobuf->free_ptr to store the original + * pointer to the offset into the mmap'd block of memory and in turn + * reuse iobuf->ptr to hold the page-aligned address. And finally, in + * iobuf_put(), we copy iobuf->free_ptr into iobuf->ptr - back to where + * it was originally when __iobuf_get() returned this iobuf. + */ + if (!iobuf->free_ptr) + iobuf->free_ptr = iobuf->ptr; + iobuf->ptr = GF_ALIGN_BUF(iobuf->ptr, align_size); + + return iobuf; } - -void -__iobuf_put (struct iobuf *iobuf, struct iobuf_arena *iobuf_arena) +struct iobuf * +iobuf_get(struct iobuf_pool *iobuf_pool) { - struct iobuf_pool *iobuf_pool = NULL; + struct iobuf *iobuf = NULL; + int index = 0; - iobuf_pool = iobuf_arena->iobuf_pool; + GF_VALIDATE_OR_GOTO("iobuf", iobuf_pool, out); - if (iobuf_arena->passive_cnt == 0) { - list_del (&iobuf_arena->list); - list_add_tail (&iobuf_arena->list, &iobuf_pool->arenas.list); + index = gf_iobuf_get_arena_index(iobuf_pool->default_page_size); + if (index == -1) { + gf_smsg("iobuf", GF_LOG_ERROR, 0, LG_MSG_PAGE_SIZE_EXCEEDED, + "page_size=%zu", iobuf_pool->default_page_size, NULL); + return NULL; + } + + pthread_mutex_lock(&iobuf_pool->mutex); + { + iobuf = __iobuf_get(iobuf_pool, iobuf_pool->default_page_size, index); + if (!iobuf) { + pthread_mutex_unlock(&iobuf_pool->mutex); + gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_IOBUF_NOT_FOUND, + NULL); + goto out; } - list_del_init (&iobuf->list); - iobuf_arena->active_cnt--; + iobuf_ref(iobuf); + } + pthread_mutex_unlock(&iobuf_pool->mutex); - list_add (&iobuf->list, &iobuf_arena->passive.list); - iobuf_arena->passive_cnt++; - - if (iobuf_arena->active_cnt == 0) { - list_del (&iobuf_arena->list); - list_add_tail (&iobuf_arena->list, &iobuf_pool->purge.list); - } +out: + return iobuf; } +static void +__iobuf_put(struct iobuf *iobuf, struct iobuf_arena *iobuf_arena) +{ + struct iobuf_pool *iobuf_pool = NULL; + int index = 0; + + iobuf_pool = iobuf_arena->iobuf_pool; + + index = gf_iobuf_get_arena_index(iobuf_arena->page_size); + if (index == -1) { + gf_msg_debug("iobuf", 0, + "freeing the iobuf (%p) " + "allocated with standard calloc()", + iobuf); + + /* free up properly without bothering about lists and all */ + LOCK_DESTROY(&iobuf->lock); + GF_FREE(iobuf->free_ptr); + GF_FREE(iobuf); + return; + } + + if (iobuf_arena->passive_cnt == 0) { + list_del(&iobuf_arena->list); + list_add_tail(&iobuf_arena->list, &iobuf_pool->arenas[index]); + } + + list_del_init(&iobuf->list); + iobuf_arena->active_cnt--; + + if (iobuf->free_ptr) { + iobuf->ptr = iobuf->free_ptr; + iobuf->free_ptr = NULL; + } + + list_add(&iobuf->list, &iobuf_arena->passive.list); + iobuf_arena->passive_cnt++; + + if (iobuf_arena->active_cnt == 0) { + list_del(&iobuf_arena->list); + list_add_tail(&iobuf_arena->list, &iobuf_pool->purge[index]); + GF_VALIDATE_OR_GOTO("iobuf", iobuf_pool, out); + __iobuf_arena_prune(iobuf_pool, iobuf_arena, index); + } +out: + return; +} void -iobuf_put (struct iobuf *iobuf) +iobuf_put(struct iobuf *iobuf) { - struct iobuf_arena *iobuf_arena = NULL; - struct iobuf_pool *iobuf_pool = NULL; + struct iobuf_arena *iobuf_arena = NULL; + struct iobuf_pool *iobuf_pool = NULL; - if (!iobuf) - return; + GF_VALIDATE_OR_GOTO("iobuf", iobuf, out); - iobuf_arena = iobuf->iobuf_arena; - if (!iobuf_arena) - return; + iobuf_arena = iobuf->iobuf_arena; + if (!iobuf_arena) { + gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_ARENA_NOT_FOUND, NULL); + return; + } - iobuf_pool = iobuf_arena->iobuf_pool; - if (!iobuf_pool) - return; + iobuf_pool = iobuf_arena->iobuf_pool; + if (!iobuf_pool) { + gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_POOL_NOT_FOUND, "iobuf", + NULL); + return; + } - pthread_mutex_lock (&iobuf_pool->mutex); - { - __iobuf_put (iobuf, iobuf_arena); - } - pthread_mutex_unlock (&iobuf_pool->mutex); + pthread_mutex_lock(&iobuf_pool->mutex); + { + __iobuf_put(iobuf, iobuf_arena); + } + pthread_mutex_unlock(&iobuf_pool->mutex); - iobuf_pool_prune (iobuf_pool); +out: + return; } - void -iobuf_unref (struct iobuf *iobuf) +iobuf_unref(struct iobuf *iobuf) { - int ref = 0; + int ref = 0; - if (!iobuf) - return; + GF_VALIDATE_OR_GOTO("iobuf", iobuf, out); - LOCK (&iobuf->lock); - { - __iobuf_unref (iobuf); - ref = iobuf->ref; - } - UNLOCK (&iobuf->lock); + ref = GF_ATOMIC_DEC(iobuf->ref); - if (!ref) - iobuf_put (iobuf); -} + if (!ref) + iobuf_put(iobuf); +out: + return; +} struct iobuf * -iobuf_ref (struct iobuf *iobuf) +iobuf_ref(struct iobuf *iobuf) { - if (!iobuf) - return NULL; - - LOCK (&iobuf->lock); - { - __iobuf_ref (iobuf); - } - UNLOCK (&iobuf->lock); + GF_VALIDATE_OR_GOTO("iobuf", iobuf, out); + GF_ATOMIC_INC(iobuf->ref); - return iobuf; +out: + return iobuf; } - struct iobref * -iobref_new () +iobref_new() { - struct iobref *iobref = NULL; + struct iobref *iobref = NULL; - iobref = GF_CALLOC (sizeof (*iobref), 1, - gf_common_mt_iobref); - if (!iobref) - return NULL; + iobref = GF_MALLOC(sizeof(*iobref), gf_common_mt_iobref); + if (!iobref) + return NULL; - LOCK_INIT (&iobref->lock); + iobref->iobrefs = GF_CALLOC(sizeof(*iobref->iobrefs), 16, + gf_common_mt_iobrefs); + if (!iobref->iobrefs) { + GF_FREE(iobref); + return NULL; + } - iobref->ref++; + iobref->allocated = 16; + iobref->used = 0; - return iobref; -} + LOCK_INIT(&iobref->lock); + GF_ATOMIC_INIT(iobref->ref, 1); + return iobref; +} struct iobref * -iobref_ref (struct iobref *iobref) +iobref_ref(struct iobref *iobref) { - if (!iobref) - return NULL; - - LOCK (&iobref->lock); - { - iobref->ref++; - } - UNLOCK (&iobref->lock); + GF_VALIDATE_OR_GOTO("iobuf", iobref, out); + GF_ATOMIC_INC(iobref->ref); - return iobref; +out: + return iobref; } - void -iobref_destroy (struct iobref *iobref) +iobref_destroy(struct iobref *iobref) { - int i = 0; - struct iobuf *iobuf = NULL; + int i = 0; + struct iobuf *iobuf = NULL; - if (!iobref) - return; + GF_VALIDATE_OR_GOTO("iobuf", iobref, out); - for (i = 0; i < 8; i++) { - iobuf = iobref->iobrefs[i]; + for (i = 0; i < iobref->allocated; i++) { + iobuf = iobref->iobrefs[i]; - iobref->iobrefs[i] = NULL; - if (iobuf) - iobuf_unref (iobuf); - } + iobref->iobrefs[i] = NULL; + if (iobuf) + iobuf_unref(iobuf); + } - GF_FREE (iobref); -} + GF_FREE(iobref->iobrefs); + GF_FREE(iobref); +out: + return; +} void -iobref_unref (struct iobref *iobref) +iobref_unref(struct iobref *iobref) { - int ref = 0; + int ref = 0; - if (!iobref) - return; + GF_VALIDATE_OR_GOTO("iobuf", iobref, out); + ref = GF_ATOMIC_DEC(iobref->ref); - LOCK (&iobref->lock); - { - ref = (--iobref->ref); - } - UNLOCK (&iobref->lock); + if (!ref) + iobref_destroy(iobref); - if (!ref) - iobref_destroy (iobref); +out: + return; } - -int -__iobref_add (struct iobref *iobref, struct iobuf *iobuf) +void +iobref_clear(struct iobref *iobref) { - int i = 0; - int ret = -ENOMEM; + int i = 0; + + GF_VALIDATE_OR_GOTO("iobuf", iobref, out); - for (i = 0; i < 8; i++) { - if (iobref->iobrefs[i] == NULL) { - iobref->iobrefs[i] = iobuf_ref (iobuf); - ret = 0; - break; - } + for (; i < iobref->allocated; i++) { + if (iobref->iobrefs[i] != NULL) { + iobuf_unref(iobref->iobrefs[i]); + } else { + /** iobuf's are attached serially */ + break; } + } + + iobref_unref(iobref); - return ret; +out: + return; } +static void +__iobref_grow(struct iobref *iobref) +{ + void *newptr = NULL; + int i = 0; + + newptr = GF_REALLOC(iobref->iobrefs, + iobref->allocated * 2 * (sizeof(*iobref->iobrefs))); + if (newptr) { + iobref->iobrefs = newptr; + iobref->allocated *= 2; + + for (i = iobref->used; i < iobref->allocated; i++) + iobref->iobrefs[i] = NULL; + } +} int -iobref_add (struct iobref *iobref, struct iobuf *iobuf) +__iobref_add(struct iobref *iobref, struct iobuf *iobuf) { - int ret = 0; + int i = 0; + int ret = -ENOMEM; - if (!iobref) - return -EINVAL; + GF_VALIDATE_OR_GOTO("iobuf", iobref, out); + GF_VALIDATE_OR_GOTO("iobuf", iobuf, out); - if (!iobuf) - return -EINVAL; + if (iobref->used == iobref->allocated) { + __iobref_grow(iobref); - LOCK (&iobref->lock); - { - ret = __iobref_add (iobref, iobuf); + if (iobref->used == iobref->allocated) { + ret = -ENOMEM; + goto out; } - UNLOCK (&iobref->lock); + } + + for (i = 0; i < iobref->allocated; i++) { + if (iobref->iobrefs[i] == NULL) { + iobref->iobrefs[i] = iobuf_ref(iobuf); + iobref->used++; + ret = 0; + break; + } + } - return ret; +out: + return ret; } +int +iobref_add(struct iobref *iobref, struct iobuf *iobuf) +{ + int ret = -EINVAL; + + GF_VALIDATE_OR_GOTO("iobuf", iobref, out); + GF_VALIDATE_OR_GOTO("iobuf", iobuf, out); + + LOCK(&iobref->lock); + { + ret = __iobref_add(iobref, iobuf); + } + UNLOCK(&iobref->lock); + +out: + return ret; +} int -iobref_merge (struct iobref *to, struct iobref *from) +iobref_merge(struct iobref *to, struct iobref *from) { - int i = 0; - int ret = 0; - struct iobuf *iobuf = NULL; + int i = 0; + int ret = 0; + struct iobuf *iobuf = NULL; - LOCK (&from->lock); - { - for (i = 0; i < 8; i++) { - iobuf = from->iobrefs[i]; + GF_VALIDATE_OR_GOTO("iobuf", to, out); + GF_VALIDATE_OR_GOTO("iobuf", from, out); + + LOCK(&from->lock); + { + for (i = 0; i < from->allocated; i++) { + iobuf = from->iobrefs[i]; - if (!iobuf) - break; + if (!iobuf) + break; - ret = iobref_add (to, iobuf); + ret = iobref_add(to, iobuf); - if (ret < 0) - break; - } + if (ret < 0) + break; } - UNLOCK (&from->lock); + } + UNLOCK(&from->lock); - return ret; +out: + return ret; } - size_t -iobuf_size (struct iobuf *iobuf) +iobuf_size(struct iobuf *iobuf) { - size_t size = 0; + size_t size = 0; - if (!iobuf) - goto out; + GF_VALIDATE_OR_GOTO("iobuf", iobuf, out); - if (!iobuf->iobuf_arena) - goto out; + if (!iobuf->iobuf_arena) { + gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_ARENA_NOT_FOUND, NULL); + goto out; + } - if (!iobuf->iobuf_arena->iobuf_pool) - goto out; + if (!iobuf->iobuf_arena->iobuf_pool) { + gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_POOL_NOT_FOUND, NULL); + goto out; + } - size = iobuf->iobuf_arena->iobuf_pool->page_size; + size = iobuf->iobuf_arena->page_size; out: - return size; + return size; } - size_t -iobref_size (struct iobref *iobref) +iobref_size(struct iobref *iobref) { - size_t size = 0; - int i = 0; + size_t size = 0; + int i = 0; - if (!iobref) - goto out; + GF_VALIDATE_OR_GOTO("iobuf", iobref, out); - LOCK (&iobref->lock); - { - for (i = 0; i < 8; i++) { - if (iobref->iobrefs[i]) - size += iobuf_size (iobref->iobrefs[i]); - } + LOCK(&iobref->lock); + { + for (i = 0; i < iobref->allocated; i++) { + if (iobref->iobrefs[i]) + size += iobuf_size(iobref->iobrefs[i]); } - UNLOCK (&iobref->lock); + } + UNLOCK(&iobref->lock); + out: - return size; + return size; } -void -iobuf_info_dump (struct iobuf *iobuf, const char *key_prefix) +void +iobuf_info_dump(struct iobuf *iobuf, const char *key_prefix) { - char key[GF_DUMP_MAX_BUF_LEN]; - struct iobuf my_iobuf; - int ret = 0; + char key[GF_DUMP_MAX_BUF_LEN]; + struct iobuf my_iobuf; + int ret = 0; - if (!iobuf) - return; + GF_VALIDATE_OR_GOTO("iobuf", iobuf, out); - memset(&my_iobuf, 0, sizeof(my_iobuf)); - - ret = TRY_LOCK(&iobuf->lock); - if (ret) { - gf_log("", GF_LOG_WARNING, "Unable to dump iobuf" - " errno: %d", errno); - return; - } - memcpy(&my_iobuf, iobuf, sizeof(my_iobuf)); - UNLOCK(&iobuf->lock); + ret = TRY_LOCK(&iobuf->lock); + if (ret) { + return; + } + memcpy(&my_iobuf, iobuf, sizeof(my_iobuf)); + UNLOCK(&iobuf->lock); - gf_proc_dump_build_key(key, key_prefix,"ref"); - gf_proc_dump_write(key, "%d", my_iobuf.ref); - gf_proc_dump_build_key(key, key_prefix,"ptr"); - gf_proc_dump_write(key, "%p", my_iobuf.ptr); + gf_proc_dump_build_key(key, key_prefix, "ref"); + gf_proc_dump_write(key, "%" GF_PRI_ATOMIC, GF_ATOMIC_GET(my_iobuf.ref)); + gf_proc_dump_build_key(key, key_prefix, "ptr"); + gf_proc_dump_write(key, "%p", my_iobuf.ptr); +out: + return; } -void -iobuf_arena_info_dump (struct iobuf_arena *iobuf_arena, const char *key_prefix) +void +iobuf_arena_info_dump(struct iobuf_arena *iobuf_arena, const char *key_prefix) { - char key[GF_DUMP_MAX_BUF_LEN]; - int i = 1; - struct iobuf *trav; - - if (!iobuf_arena) - return; - - gf_proc_dump_build_key(key, key_prefix,"mem_base"); - gf_proc_dump_write(key, "%p", iobuf_arena->mem_base); - gf_proc_dump_build_key(key, key_prefix, "active_cnt"); - gf_proc_dump_write(key, "%d", iobuf_arena->active_cnt); - gf_proc_dump_build_key(key, key_prefix, "passive_cnt"); - gf_proc_dump_write(key, "%d", iobuf_arena->passive_cnt); - list_for_each_entry (trav, &iobuf_arena->active.list, list) { - gf_proc_dump_build_key(key, key_prefix,"active_iobuf.%d", i++); - gf_proc_dump_add_section(key); - iobuf_info_dump(trav, key); - } + char key[GF_DUMP_MAX_BUF_LEN]; + int i = 1; + struct iobuf *trav; + + GF_VALIDATE_OR_GOTO("iobuf", iobuf_arena, out); + + gf_proc_dump_build_key(key, key_prefix, "mem_base"); + gf_proc_dump_write(key, "%p", iobuf_arena->mem_base); + gf_proc_dump_build_key(key, key_prefix, "active_cnt"); + gf_proc_dump_write(key, "%d", iobuf_arena->active_cnt); + gf_proc_dump_build_key(key, key_prefix, "passive_cnt"); + gf_proc_dump_write(key, "%d", iobuf_arena->passive_cnt); + gf_proc_dump_build_key(key, key_prefix, "alloc_cnt"); + gf_proc_dump_write(key, "%" PRIu64, iobuf_arena->alloc_cnt); + gf_proc_dump_build_key(key, key_prefix, "max_active"); + gf_proc_dump_write(key, "%d", iobuf_arena->max_active); + gf_proc_dump_build_key(key, key_prefix, "page_size"); + gf_proc_dump_write(key, "%" GF_PRI_SIZET, iobuf_arena->page_size); + list_for_each_entry(trav, &iobuf_arena->active.list, list) + { + gf_proc_dump_build_key(key, key_prefix, "active_iobuf.%d", i++); + gf_proc_dump_add_section("%s", key); + iobuf_info_dump(trav, key); + } +out: + return; } void -iobuf_stats_dump (struct iobuf_pool *iobuf_pool) +iobuf_stats_dump(struct iobuf_pool *iobuf_pool) { - - char msg[1024]; - struct iobuf_arena *trav = NULL; - int i = 1; - int ret = -1; + char msg[1024]; + struct iobuf_arena *trav = NULL; + int i = 1; + int j = 0; + int ret = -1; - if (!iobuf_pool) - return; + GF_VALIDATE_OR_GOTO("iobuf", iobuf_pool, out); - memset(msg, 0, sizeof(msg)); + ret = pthread_mutex_trylock(&iobuf_pool->mutex); - ret = pthread_mutex_trylock(&iobuf_pool->mutex); - - if (ret) { - gf_log("", GF_LOG_WARNING, "Unable to dump iobuf pool" - " errno: %d", errno); - return; + if (ret) { + return; + } + gf_proc_dump_add_section("iobuf.global"); + gf_proc_dump_write("iobuf_pool", "%p", iobuf_pool); + gf_proc_dump_write("iobuf_pool.default_page_size", "%" GF_PRI_SIZET, + iobuf_pool->default_page_size); + gf_proc_dump_write("iobuf_pool.arena_size", "%" GF_PRI_SIZET, + iobuf_pool->arena_size); + gf_proc_dump_write("iobuf_pool.arena_cnt", "%d", iobuf_pool->arena_cnt); + gf_proc_dump_write("iobuf_pool.request_misses", "%" PRId64, + iobuf_pool->request_misses); + + for (j = 0; j < IOBUF_ARENA_MAX_INDEX; j++) { + list_for_each_entry(trav, &iobuf_pool->arenas[j], list) + { + snprintf(msg, sizeof(msg), "arena.%d", i); + gf_proc_dump_add_section("%s", msg); + iobuf_arena_info_dump(trav, msg); + i++; } - gf_proc_dump_add_section("iobuf.global"); - gf_proc_dump_write("iobuf.global.iobuf_pool","%p", iobuf_pool); - gf_proc_dump_write("iobuf.global.iobuf_pool.page_size", "%d", - iobuf_pool->page_size); - gf_proc_dump_write("iobuf.global.iobuf_pool.arena_size", "%d", - iobuf_pool->arena_size); - gf_proc_dump_write("iobuf.global.iobuf_pool.arena_cnt", "%d", - iobuf_pool->arena_cnt); - - list_for_each_entry (trav, &iobuf_pool->arenas.list, list) { - snprintf(msg, sizeof(msg), "iobuf.global.iobuf_pool.arena.%d", - i); - gf_proc_dump_add_section(msg); - iobuf_arena_info_dump(trav,msg); - i++; + list_for_each_entry(trav, &iobuf_pool->purge[j], list) + { + snprintf(msg, sizeof(msg), "purge.%d", i); + gf_proc_dump_add_section("%s", msg); + iobuf_arena_info_dump(trav, msg); + i++; + } + list_for_each_entry(trav, &iobuf_pool->filled[j], list) + { + snprintf(msg, sizeof(msg), "filled.%d", i); + gf_proc_dump_add_section("%s", msg); + iobuf_arena_info_dump(trav, msg); + i++; } - - pthread_mutex_unlock(&iobuf_pool->mutex); + } - return; -} + pthread_mutex_unlock(&iobuf_pool->mutex); +out: + return; +} void iobuf_to_iovec(struct iobuf *iob, struct iovec *iov) { - iov->iov_base = iobuf_ptr (iob); - iov->iov_len = iobuf_pagesize (iob); + GF_VALIDATE_OR_GOTO("iobuf", iob, out); + GF_VALIDATE_OR_GOTO("iobuf", iov, out); + + iov->iov_base = iobuf_ptr(iob); + iov->iov_len = iobuf_pagesize(iob); + +out: + return; } +int +iobuf_copy(struct iobuf_pool *iobuf_pool, const struct iovec *iovec_src, + int iovcnt, struct iobref **iobref, struct iobuf **iobuf, + struct iovec *iov_dst) +{ + size_t size = -1; + int ret = 0; + + size = iov_length(iovec_src, iovcnt); + + *iobuf = iobuf_get2(iobuf_pool, size); + if (!(*iobuf)) { + ret = -1; + errno = ENOMEM; + goto out; + } + + *iobref = iobref_new(); + if (!(*iobref)) { + iobuf_unref(*iobuf); + errno = ENOMEM; + ret = -1; + goto out; + } + + ret = iobref_add(*iobref, *iobuf); + if (ret) { + iobuf_unref(*iobuf); + iobref_unref(*iobref); + errno = ENOMEM; + ret = -1; + goto out; + } + + iov_unload(iobuf_ptr(*iobuf), iovec_src, iovcnt); + + iov_dst->iov_base = iobuf_ptr(*iobuf); + iov_dst->iov_len = size; + +out: + return ret; +} diff --git a/libglusterfs/src/iobuf.h b/libglusterfs/src/iobuf.h deleted file mode 100644 index bc2209958cf..00000000000 --- a/libglusterfs/src/iobuf.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - Copyright (c) 2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _IOBUF_H_ -#define _IOBUF_H_ - -#include "list.h" -#include "common-utils.h" -#include <pthread.h> -#include <sys/mman.h> -#include <sys/uio.h> - -/* Lets try to define the new anonymous mapping - * flag, in case the system is still using the - * now deprecated MAP_ANON flag. - * - * Also, this should ideally be in a centralized/common - * header which can be used by other source files also. - */ -#ifndef MAP_ANONYMOUS -#define MAP_ANONYMOUS MAP_ANON -#endif - -/* one allocatable unit for the consumers of the IOBUF API */ -/* each unit hosts @page_size bytes of memory */ -struct iobuf; - -/* one region of memory MMAPed from the operating system */ -/* each region MMAPs @arena_size bytes of memory */ -/* each arena hosts @arena_size / @page_size IOBUFs */ -struct iobuf_arena; - -/* expandable and contractable pool of memory, internally broken into arenas */ -struct iobuf_pool; - - -struct iobuf { - union { - struct list_head list; - struct { - struct iobuf *next; - struct iobuf *prev; - }; - }; - struct iobuf_arena *iobuf_arena; - - gf_lock_t lock; /* for ->ptr and ->ref */ - int ref; /* 0 == passive, >0 == active */ - - void *ptr; /* usable memory region by the consumer */ -}; - - -struct iobuf_arena { - union { - struct list_head list; - struct { - struct iobuf_arena *next; - struct iobuf_arena *prev; - }; - }; - struct iobuf_pool *iobuf_pool; - - void *mem_base; - struct iobuf *iobufs; /* allocated iobufs list */ - - int active_cnt; - struct iobuf active; /* head node iobuf - (unused by itself) */ - int passive_cnt; - struct iobuf passive; /* head node iobuf - (unused by itself) */ -}; - - -struct iobuf_pool { - pthread_mutex_t mutex; - size_t page_size; /* size of all iobufs in this pool */ - size_t arena_size; /* size of memory region in arena */ - - int arena_cnt; - struct iobuf_arena arenas; /* head node arena - (unused by itself) */ - struct iobuf_arena filled; /* arenas without free iobufs */ - struct iobuf_arena purge; /* arenas which can be purged */ -}; - - - - -struct iobuf_pool *iobuf_pool_new (size_t arena_size, size_t page_size); -void iobuf_pool_destroy (struct iobuf_pool *iobuf_pool); -struct iobuf *iobuf_get (struct iobuf_pool *iobuf_pool); -void iobuf_unref (struct iobuf *iobuf); -struct iobuf *iobuf_ref (struct iobuf *iobuf); -void iobuf_pool_destroy (struct iobuf_pool *iobuf_pool); -void iobuf_to_iovec(struct iobuf *iob, struct iovec *iov); - -#define iobuf_ptr(iob) ((iob)->ptr) -#define iobpool_pagesize(iobpool) ((iobpool)->page_size) -#define iobuf_pagesize(iob) (iobpool_pagesize((iob)->iobuf_arena->iobuf_pool)) - - -struct iobref { - gf_lock_t lock; - int ref; - struct iobuf *iobrefs[8]; -}; - -struct iobref *iobref_new (); -struct iobref *iobref_ref (struct iobref *iobref); -void iobref_unref (struct iobref *iobref); -int iobref_add (struct iobref *iobref, struct iobuf *iobuf); -int iobref_merge (struct iobref *to, struct iobref *from); - - -size_t iobuf_size (struct iobuf *iobuf); -size_t iobref_size (struct iobref *iobref); -void iobuf_stats_dump (struct iobuf_pool *iobuf_pool); - -#endif /* !_IOBUF_H_ */ diff --git a/libglusterfs/src/latency.c b/libglusterfs/src/latency.c index d8f405148a3..ce4b0e8255d 100644 --- a/libglusterfs/src/latency.c +++ b/libglusterfs/src/latency.c @@ -1,183 +1,84 @@ /* - Copyright (c) 2009 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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. */ - /* * This file contains functions to support dumping of * latencies of FOPs broken down by subvolumes. */ -#include "glusterfs.h" -#include "stack.h" -#include "xlator.h" -#include "common-utils.h" -#include "statedump.h" - +#include "glusterfs/glusterfs.h" +#include "glusterfs/statedump.h" -void -gf_set_fop_from_fn_pointer (call_frame_t *frame, struct xlator_fops *fops, void *fn) +gf_latency_t * +gf_latency_new(size_t n) { - glusterfs_fop_t fop = -1; + int i = 0; + gf_latency_t *lat = NULL; - if (fops->stat == fn) - fop = GF_FOP_STAT; - else if (fops->readlink == fn) - fop = GF_FOP_READLINK; - else if (fops->mknod == fn) - fop = GF_FOP_MKNOD; - else if (fops->mkdir == fn) - fop = GF_FOP_MKDIR; - else if (fops->unlink == fn) - fop = GF_FOP_UNLINK; - else if (fops->rmdir == fn) - fop = GF_FOP_RMDIR; - else if (fops->symlink == fn) - fop = GF_FOP_SYMLINK; - else if (fops->rename == fn) - fop = GF_FOP_RENAME; - else if (fops->link == fn) - fop = GF_FOP_LINK; - else if (fops->truncate == fn) - fop = GF_FOP_TRUNCATE; - else if (fops->open == fn) - fop = GF_FOP_OPEN; - else if (fops->readv == fn) - fop = GF_FOP_READ; - else if (fops->writev == fn) - fop = GF_FOP_WRITE; - else if (fops->statfs == fn) - fop = GF_FOP_STATFS; - else if (fops->flush == fn) - fop = GF_FOP_FLUSH; - else if (fops->fsync == fn) - fop = GF_FOP_FSYNC; - else if (fops->setxattr == fn) - fop = GF_FOP_SETXATTR; - else if (fops->getxattr == fn) - fop = GF_FOP_GETXATTR; - else if (fops->removexattr == fn) - fop = GF_FOP_REMOVEXATTR; - else if (fops->opendir == fn) - fop = GF_FOP_OPENDIR; - else if (fops->fsyncdir == fn) - fop = GF_FOP_FSYNCDIR; - else if (fops->access == fn) - fop = GF_FOP_ACCESS; - else if (fops->create == fn) - fop = GF_FOP_CREATE; - else if (fops->ftruncate == fn) - fop = GF_FOP_FTRUNCATE; - else if (fops->fstat == fn) - fop = GF_FOP_FSTAT; - else if (fops->lk == fn) - fop = GF_FOP_LK; - else if (fops->lookup == fn) - fop = GF_FOP_LOOKUP; - else if (fops->readdir == fn) - fop = GF_FOP_READDIR; - else if (fops->inodelk == fn) - fop = GF_FOP_INODELK; - else if (fops->finodelk == fn) - fop = GF_FOP_FINODELK; - else if (fops->entrylk == fn) - fop = GF_FOP_ENTRYLK; - else if (fops->fentrylk == fn) - fop = GF_FOP_FENTRYLK; - else if (fops->xattrop == fn) - fop = GF_FOP_XATTROP; - else if (fops->fxattrop == fn) - fop = GF_FOP_FXATTROP; - else if (fops->fgetxattr == fn) - fop = GF_FOP_FGETXATTR; - else if (fops->fsetxattr == fn) - fop = GF_FOP_FSETXATTR; - else if (fops->rchecksum == fn) - fop = GF_FOP_RCHECKSUM; - else if (fops->setattr == fn) - fop = GF_FOP_SETATTR; - else if (fops->fsetattr == fn) - fop = GF_FOP_FSETATTR; - else if (fops->readdirp == fn) - fop = GF_FOP_READDIRP; - else if (fops->getspec == fn) - fop = GF_FOP_GETSPEC; - else - fop = -1; + lat = GF_MALLOC(n * sizeof(*lat), gf_common_mt_latency_t); + if (!lat) + return NULL; - frame->op = fop; + for (i = 0; i < n; i++) { + gf_latency_reset(lat + i); + } + return lat; } - void -gf_update_latency (call_frame_t *frame) +gf_latency_update(gf_latency_t *lat, struct timespec *begin, + struct timespec *end) { - double elapsed; - struct timeval *begin, *end; - - fop_latency_t *lat; + if (!(begin->tv_sec && end->tv_sec)) { + /*Measure latency might have been enabled/disabled during the op*/ + return; + } - begin = &frame->begin; - end = &frame->end; + double elapsed = gf_tsdiff(begin, end); - elapsed = (end->tv_sec - begin->tv_sec) * 1e6 - + (end->tv_usec - begin->tv_usec); + if (lat->max < elapsed) + lat->max = elapsed; - lat = &frame->this->latencies[frame->op]; + if (lat->min > elapsed) + lat->min = elapsed; - lat->total += elapsed; - lat->count++; - lat->mean = lat->mean + (elapsed - lat->mean) / lat->count; + lat->total += elapsed; + lat->count++; } - void -gf_proc_dump_latency_info (xlator_t *xl) +gf_latency_reset(gf_latency_t *lat) { - char key_prefix[GF_DUMP_MAX_BUF_LEN]; - char key[GF_DUMP_MAX_BUF_LEN]; - int i; - - snprintf (key_prefix, GF_DUMP_MAX_BUF_LEN, "%s.latency", xl->name); - gf_proc_dump_add_section (key_prefix); - - for (i = 0; i < GF_FOP_MAXVALUE; i++) { - gf_proc_dump_build_key (key, key_prefix, gf_fop_list[i]); - - gf_proc_dump_write (key, "%.03f,%"PRId64",%.03f", - xl->latencies[i].mean, - xl->latencies[i].count, - xl->latencies[i].total); - } + if (!lat) + return; + memset(lat, 0, sizeof(*lat)); + lat->min = ULLONG_MAX; + /* make sure 'min' is set to high value, so it would be + properly set later */ } - void -gf_latency_toggle (int signum) +gf_frame_latency_update(call_frame_t *frame) { - glusterfs_ctx_t *ctx = NULL; - - ctx = glusterfs_ctx_get (); - - if (ctx) { - ctx->measure_latency = !ctx->measure_latency; - gf_log ("[core]", GF_LOG_NORMAL, - "Latency measurement turned %s", - ctx->measure_latency ? "on" : "off"); - } + gf_latency_t *lat; + /* Can happen mostly at initiator xlator, as STACK_WIND/UNWIND macros + set it right anyways for those frames */ + if (!frame->op) + frame->op = frame->root->op; + + if (frame->op < 0 || frame->op >= GF_FOP_MAXVALUE) { + gf_log("[core]", GF_LOG_WARNING, "Invalid frame op value: %d", + frame->op); + return; + } + + lat = &frame->this->stats.interval.latencies[frame->op]; + gf_latency_update(lat, &frame->begin, &frame->end); } diff --git a/libglusterfs/src/latency.h b/libglusterfs/src/latency.h deleted file mode 100644 index ba7d76cddca..00000000000 --- a/libglusterfs/src/latency.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - Copyright (c) 2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef __LATENCY_H__ -#define __LATENCY_H__ - - -typedef struct fop_latency { - uint64_t min; /* min time for the call (microseconds) */ - uint64_t max; /* max time for the call (microseconds) */ - double total; /* total time (microseconds) */ - double std; /* standard deviation */ - double mean; /* mean (microseconds) */ - uint64_t count; -} fop_latency_t; - -void -gf_latency_toggle (int signum); - -#endif /* __LATENCY_H__ */ diff --git a/libglusterfs/src/libglusterfs.sym b/libglusterfs/src/libglusterfs.sym new file mode 100644 index 00000000000..5f18cd56cbe --- /dev/null +++ b/libglusterfs/src/libglusterfs.sym @@ -0,0 +1,1193 @@ +are_dicts_equal +args_access_cbk_store +args_access_store +args_create_cbk_store +args_create_store +args_discard_cbk_store +args_discard_store +args_entrylk_cbk_store +args_entrylk_store +args_fallocate_cbk_store +args_fallocate_store +args_fentrylk_cbk_store +args_fentrylk_store +args_fgetxattr_cbk_store +args_fgetxattr_store +args_finodelk_cbk_store +args_finodelk_store +args_flush_cbk_store +args_flush_store +args_fremovexattr_cbk_store +args_fremovexattr_store +args_fsetattr_cbk_store +args_fsetattr_store +args_fsetxattr_cbk_store +args_fsetxattr_store +args_fstat_cbk_store +args_fstat_store +args_fsync_cbk_store +args_fsyncdir_cbk_store +args_fsyncdir_store +args_fsync_store +args_ftruncate_cbk_store +args_ftruncate_store +args_fxattrop_cbk_store +args_fxattrop_store +args_getxattr_cbk_store +args_getxattr_store +args_inodelk_cbk_store +args_inodelk_store +args_ipc_cbk_store +args_lease_cbk_store +args_lease_store +args_link_cbk_store +args_link_store +args_lk_cbk_store +args_lk_store +args_lookup_cbk_store +args_lookup_store +args_mkdir_cbk_store +args_mkdir_store +args_mknod_cbk_store +args_mknod_store +args_open_cbk_store +args_opendir_cbk_store +args_opendir_store +args_open_store +args_rchecksum_cbk_store +args_rchecksum_store +args_readdir_cbk_store +args_readdirp_cbk_store +args_readdirp_store +args_readdir_store +args_readlink_cbk_store +args_readlink_store +args_readv_cbk_store +args_readv_store +args_removexattr_cbk_store +args_removexattr_store +args_rename_cbk_store +args_rename_store +args_rmdir_cbk_store +args_rmdir_store +args_seek_cbk_store +args_seek_store +args_setattr_cbk_store +args_setattr_store +args_setxattr_cbk_store +args_setxattr_store +args_stat_cbk_store +args_statfs_cbk_store +args_statfs_store +args_stat_store +args_symlink_cbk_store +args_symlink_store +args_truncate_cbk_store +args_truncate_store +args_unlink_cbk_store +args_unlink_store +args_writev_cbk_store +args_writev_store +args_xattrop_cbk_store +args_xattrop_store +args_zerofill_cbk_store +args_zerofill_store +args_copy_file_range_cbk_store +args_copy_file_range_store +bin_to_data +call_resume +call_resume_keep_stub +call_resume_wind +call_stack_set_groups +call_stub_destroy +call_unwind_error +call_unwind_error_keep_stub +client_ctx_del +client_ctx_get +client_ctx_set +client_dump +close_fds_except +cluster_fop_success_fill +cluster_fstat +cluster_ftruncate +cluster_fxattrop +cluster_getxattr +cluster_inodelk +cluster_link +cluster_lookup +cluster_mkdir +cluster_mknod +cluster_open +cluster_readlink +cluster_replies_wipe +cluster_rmdir +cluster_setattr +cluster_setxattr +cluster_symlink +cluster_tiebreaker_inodelk +cluster_uninodelk +cluster_unlink +cluster_xattrop +cluster_xattrop_cbk +copy_opts_to_child +create_frame +data_copy +data_destroy +data_from_dynptr +data_from_uint64 +data_ref +data_to_bin +data_to_int32 +data_to_int64 +data_to_ptr +data_to_str +data_to_uint16 +data_to_uint32 +data_to_uint64 +data_to_uint8 +data_to_iatt +data_unref +default_access +default_access_cbk +default_access_failure_cbk +default_access_resume +default_create +default_create_cbk +default_create_failure_cbk +default_create_resume +default_discard +default_discard_cbk +default_discard_failure_cbk +default_discard_resume +default_entrylk +default_entrylk_cbk +default_entrylk_failure_cbk +default_entrylk_resume +default_fallocate +default_fallocate_cbk +default_fallocate_failure_cbk +default_fallocate_resume +default_fentrylk +default_fentrylk_cbk +default_fentrylk_failure_cbk +default_fentrylk_resume +default_fgetxattr +default_fgetxattr_cbk +default_fgetxattr_failure_cbk +default_fgetxattr_resume +default_finodelk +default_finodelk_cbk +default_finodelk_failure_cbk +default_finodelk_resume +default_flush +default_flush_cbk +default_flush_failure_cbk +default_flush_resume +default_forget +default_fremovexattr +default_fremovexattr_cbk +default_fremovexattr_failure_cbk +default_fremovexattr_resume +default_fsetattr +default_fsetattr_cbk +default_fsetattr_failure_cbk +default_fsetattr_resume +default_fsetxattr +default_fsetxattr_cbk +default_fsetxattr_failure_cbk +default_fsetxattr_resume +default_fstat +default_fstat_cbk +default_fstat_failure_cbk +default_fstat_resume +default_fsync +default_fsync_cbk +default_fsyncdir +default_fsyncdir_cbk +default_fsyncdir_failure_cbk +default_fsyncdir_resume +default_fsync_failure_cbk +default_fsync_resume +default_ftruncate +default_ftruncate_cbk +default_ftruncate_failure_cbk +default_ftruncate_resume +default_fxattrop +default_fxattrop_cbk +default_fxattrop_failure_cbk +default_fxattrop_resume +default_getactivelk +default_getactivelk_failure_cbk +default_getactivelk_resume +default_getspec +default_getspec_cbk +default_getxattr +default_getxattr_cbk +default_getxattr_failure_cbk +default_getxattr_resume +default_inodelk +default_inodelk_cbk +default_inodelk_failure_cbk +default_inodelk_resume +default_ipc +default_ipc_cbk +default_lease +default_lease_failure_cbk +default_lease_resume +default_link +default_link_cbk +default_link_failure_cbk +default_link_resume +default_lk +default_lk_cbk +default_lk_failure_cbk +default_lk_resume +default_lookup +default_lookup_cbk +default_lookup_failure_cbk +default_lookup_resume +default_mem_acct_init +default_mkdir +default_mkdir_cbk +default_mkdir_failure_cbk +default_mkdir_resume +default_mknod +default_mknod_cbk +default_mknod_failure_cbk +default_mknod_resume +default_notify +default_open +default_open_cbk +default_opendir +default_opendir_cbk +default_opendir_failure_cbk +default_opendir_resume +default_open_failure_cbk +default_open_resume +default_rchecksum +default_rchecksum_cbk +default_rchecksum_failure_cbk +default_rchecksum_resume +default_readdir +default_readdir_cbk +default_readdir_failure_cbk +default_readdirp +default_readdirp_cbk +default_readdirp_failure_cbk +default_readdirp_resume +default_readdir_resume +default_readlink +default_readlink_cbk +default_readlink_failure_cbk +default_readlink_resume +default_readv +default_readv_cbk +default_readv_failure_cbk +default_readv_resume +default_release +default_releasedir +default_removexattr +default_removexattr_cbk +default_removexattr_failure_cbk +default_removexattr_resume +default_rename +default_rename_cbk +default_rename_failure_cbk +default_rename_resume +default_rmdir +default_rmdir_cbk +default_rmdir_failure_cbk +default_rmdir_resume +default_seek +default_seek_cbk +default_seek_failure_cbk +default_seek_resume +default_setactivelk +default_setactivelk_failure_cbk +default_setactivelk_resume +default_setattr +default_setattr_cbk +default_setattr_failure_cbk +default_setattr_resume +default_setxattr +default_setxattr_cbk +default_setxattr_failure_cbk +default_setxattr_resume +default_stat +default_stat_cbk +default_stat_failure_cbk +default_statfs +default_statfs_cbk +default_statfs_failure_cbk +default_statfs_resume +default_stat_resume +default_symlink +default_symlink_cbk +default_symlink_failure_cbk +default_symlink_resume +default_truncate +default_truncate_cbk +default_truncate_failure_cbk +default_truncate_resume +default_unlink +default_unlink_cbk +default_unlink_failure_cbk +default_unlink_resume +default_writev +default_writev_cbk +default_writev_failure_cbk +default_writev_resume +default_xattrop +default_xattrop_cbk +default_xattrop_failure_cbk +default_xattrop_resume +default_zerofill +default_zerofill_cbk +default_zerofill_failure_cbk +default_zerofill_resume +default_put +default_put_cbk +default_put_failure_cbk +default_put_resume +default_copy_file_range +default_copy_file_range_cbk +default_copy_file_range_failure_cbk +default_copy_file_range_resume +dht_is_linkfile +dict_add +dict_addn +dict_add_dynstr_with_alloc +dict_allocate_and_serialize +dict_copy +dict_copy_with_ref +dict_del +dict_deln +dict_dump_to_statedump +dict_dump_to_str +dict_dump_to_log +dict_foreach +dict_foreach_fnmatch +dict_foreach_match +dict_for_key_value +dict_get +dict_getn +dict_get_bin +dict_get_double +dict_get_gfuuid +dict_get_iatt +dict_get_mdata +dict_get_int16 +dict_get_int32 +dict_get_int32n +dict_get_int64 +dict_get_int8 +dict_get_ptr +dict_get_ptr_and_len +dict_get_str +dict_get_strn +dict_get_str_boolean +dict_get_uint32 +dict_get_uint64 +dict_get_with_ref +dict_has_key_from_array +dict_key_count +dict_keys_join +dict_lookup +dict_new +dict_null_foreach_fn +dict_ref +dict_remove_foreach_fn +dict_rename_key +dict_reset +dict_serialize +dict_serialized_length +dict_serialized_length_lk +dict_serialize_value_with_delim +dict_set +dict_setn +dict_set_bin +dict_set_double +dict_set_dynptr +dict_set_dynstr +dict_set_dynstrn +dict_set_dynstr_with_alloc +dict_set_gfuuid +dict_set_iatt +dict_set_mdata +dict_set_int16 +dict_set_int32 +dict_set_int32n +dict_set_int64 +dict_set_int8 +dict_set_static_bin +dict_set_static_ptr +dict_set_str +dict_set_strn +dict_setn_nstrn +dict_set_nstrn +dict_set_uint32 +dict_set_uint64 +dict_set_flag +dict_clear_flag +dict_check_flag +dict_unref +dict_unserialize +drop_token +eh_destroy +eh_dump +eh_new +eh_save_history +entry_copy +gf_event_dispatch +gf_event_dispatch_destroy +gf_event_handled +gf_event_pool_destroy +gf_event_pool_new +gf_event_reconfigure_threads +gf_event_register +gf_event_select_on +gf_event_unregister +gf_event_unregister_close +fd_anonymous +fd_anonymous_with_flags +fd_bind +fd_close +fd_create +fd_create_uint64 +__fd_ctx_del +fd_ctx_del +fd_ctx_dump +__fd_ctx_get +fd_ctx_get +__fd_ctx_set +fd_ctx_set +fd_is_anonymous +fd_list_empty +fd_lk_ctx_empty +fd_lk_ctx_ref +fd_lk_ctx_unref +fd_lk_insert_and_merge +fd_lookup +fd_lookup_anonymous +fd_lookup_uint64 +__fd_ref +fd_ref +fd_unref +_fini +fop_access_stub +fop_create_stub +fop_copy_file_range_stub +fop_copy_file_range_cbk_stub +fop_discard_stub +fop_entrylk_stub +fop_enum_to_pri_string +fop_fallocate_stub +fop_fentrylk_stub +fop_fgetxattr_stub +fop_finodelk_stub +fop_flush_stub +fop_fremovexattr_cbk_stub +fop_fremovexattr_stub +fop_fsetattr_stub +fop_fsetxattr_cbk_stub +fop_fsetxattr_stub +fop_fstat_stub +fop_fsync_cbk_stub +fop_fsyncdir_stub +fop_fsync_stub +fop_ftruncate_cbk_stub +fop_ftruncate_stub +fop_fxattrop_stub +fop_getactivelk_stub +fop_getxattr_stub +fop_icreate_stub +fop_inodelk_stub +fop_ipc_stub +fop_lease_stub +fop_link_stub +fop_lk_stub +fop_log_level +fop_lookup_cbk_stub +fop_lookup_stub +fop_mkdir_stub +fop_mknod_stub +fop_namelink_stub +fop_opendir_stub +fop_open_stub +fop_put_stub +fop_rchecksum_stub +fop_readdirp_stub +fop_readdir_stub +fop_readlink_stub +fop_readv_stub +fop_removexattr_cbk_stub +fop_removexattr_stub +fop_rename_cbk_stub +fop_rename_stub +fop_rmdir_cbk_stub +fop_rmdir_stub +fop_seek_stub +fop_setactivelk_stub +fop_setattr_stub +fop_setxattr_stub +fop_statfs_stub +fop_stat_stub +fop_symlink_stub +fop_truncate_cbk_stub +fop_truncate_stub +fop_unlink_cbk_stub +fop_unlink_stub +fop_writev_cbk_stub +fop_writev_stub +fop_xattrop_stub +fop_zerofill_stub +generate_glusterfs_ctx_id +get_checksum_for_file +get_checksum_for_path +get_file_mtime +get_host_name +get_mem_size +get_path_name +get_xlator_by_name +get_xlator_by_type +gf_array_insertionsort +gf_asprintf +gf_async +gf_async_adjust_threads +gf_async_ctrl +gf_async_init +gf_async_fini +gf_backtrace_save +gf_bits_count +gf_bits_index +gf_build_absolute_path +__gf_calloc +gf_canonicalize_path +gf_check_log_format +gf_check_logger +gf_client_disconnect +gf_client_dump_fdtables +gf_client_dump_fdtables_to_dict +gf_client_dump_inodes +gf_client_dump_inodes_to_dict +gf_client_get +gf_client_put +gf_client_ref +gf_clienttable_alloc +gf_client_unref +gf_cmd_log +gf_cmd_log_init +gf_compare_sockaddr +gf_deitransform +gf_dirent_entry_free +gf_dirent_for_name +gf_dirent_free +gf_dirent_orig_offset +gf_dm_hashfn +gf_dnscache_init +gf_dnscache_deinit +gf_errno_to_error +gf_error_to_errno +_gf_event +gf_fd_fdptr_get +gf_fd_fdtable_alloc +gf_fd_fdtable_copy_all_fds +gf_fd_fdtable_destroy +gf_fd_fdtable_get_all_fds +gf_fdptr_put +gf_fd_put +gf_fd_unused_get +gf_fill_iatt_for_dirent +gf_fop_int +gf_fop_string +__gf_free +gf_free_mig_locks +gf_getgrouplist +gf_get_hostname_from_ip +gf_get_index_by_elem +gf_global_mem_acct_enable_set +gfid_to_ino +gf_inode_type_to_str +gf_is_ip_in_net +gf_is_local_addr +gf_is_same_address +gf_is_service_running +gf_is_str_int +gf_is_valid_xattr_namespace +gf_is_zero_filled_stat +gf_itransform +gf_link_inodes_from_dirent +_gf_log +_gf_log_callingfn +gf_log_disable_suppression_before_exit +gf_log_dump_graph +_gf_log_eh +gf_log_fini +gf_log_get_localtime +gf_log_get_loglevel +gf_log_globals_init +gf_log_init +gf_log_inject_timer_event +gf_log_logrotate +gf_log_set_localtime +gf_log_set_log_buf_size +gf_log_set_log_flush_timeout +gf_log_set_logformat +gf_log_set_logger +gf_log_set_loglevel +gf_lstat_dir +__gf_malloc +gf_mem_acct_enable_set +gf_monitor_metrics +_gf_msg +_gf_msg_nomem +gf_nwrite +gf_path_strip_trailing_slashes +gf_print_trace +gf_proc_dump_add_section +gf_proc_dump_info +gf_proc_dump_init +gf_proc_dump_mallinfo +gf_proc_dump_mem_info +gf_proc_dump_mem_info_to_dict +gf_proc_dump_mempool_info +gf_proc_dump_mempool_info_to_dict +gf_proc_dump_pending_frames +gf_proc_dump_pending_frames_to_dict +gf_proc_dump_write +gf_proc_dump_xlator_history +gf_proc_dump_xlator_meminfo +gf_proc_dump_xlator_private +gf_proc_dump_xlator_profile +gf_process_getspec_servers_list +gf_process_reserved_ports +__gf_realloc +_gf_ref_get +_gf_ref_init +_gf_ref_put +gf_resolve_ip6 +gf_resolve_path_parent +gf_rev_dns_lookup +gf_rev_dns_lookup_cached +gf_rsync_strong_checksum +gf_rsync_md5_checksum +gf_rsync_weak_checksum +gf_set_log_file_path +gf_set_log_ident +gf_set_timestamp +gf_set_volfile_server_common +_gf_smsg +gf_sock_union_equal_addr +gf_store_handle_create_on_absence +gf_store_handle_destroy +gf_store_handle_new +gf_store_handle_retrieve +gf_store_iter_destroy +gf_store_iter_get_matching +gf_store_iter_get_next +gf_store_iter_new +gf_store_lock +gf_store_locked_local +gf_store_mkdir +gf_store_mkstemp +gf_store_read_and_tokenize +gf_store_rename_tmppath +gf_store_retrieve_value +gf_store_save_value +gf_store_save_items +gf_store_unlink_tmppath +gf_store_unlock +gf_string2boolean +gf_string2bytesize_int64 +gf_string2bytesize_uint64 +gf_string2double +gf_string2int +gf_string2int32 +gf_string2percent +gf_string2time +gf_string2uint +gf_string2uint32 +gf_string2uint64 +gf_string2uint_base10 +gf_strip_whitespace +gf_strncpy +gf_strTrim +gf_strstr +gf_thread_cleanup_xint +gf_thread_create +gf_thread_vcreate +gf_thread_create_detached +gf_thread_set_name +gf_thread_set_vname +gf_timer_call_after +gf_timer_call_cancel +gf_timer_registry_destroy +_gf_timestuff +gf_trim +gf_tw_add_timer +gf_tw_del_timer +gf_tw_mod_timer +gf_tw_mod_timer_pending +gf_uint64_2human_readable +gf_umount_lazy +gf_update_latency +gf_uuid_clear +gf_uuid_compare +gf_uuid_copy +gf_uuid_is_null +gf_uuid_generate +gf_uuid_parse +gf_uuid_unparse +gf_valid_pid +gf_vasprintf +gf_volfile_reconfigure +gf_xxh64_wrapper +gf_zero_fill_stat +gid_cache_add +gid_cache_init +gid_cache_lookup +gid_cache_reconf +gid_cache_release +glusterd_check_log_level +glusterfs_compute_sha256 +glusterfs_ctx_new +glusterfs_ctx_tw_get +glusterfs_ctx_tw_put +glusterfs_delete_volfile_checksum +glusterfs_globals_init +glusterfs_graph_activate +glusterfs_graph_attach +glusterfs_graph_construct +glusterfs_graph_deactivate +glusterfs_graph_destroy +glusterfs_graph_destroy_residual +glusterfs_graph_prepare +glusterfs_read_secure_access_file +glusterfs_graph_print_file +glusterfs_graph_set_first +glusterfs_is_local_pathinfo +glusterfs_leaf_position +glusterfs_reachable_leaves +__glusterfs_this_location +glusterfs_this_set +glusterfs_volfile_reconfigure +glusterfs_xlator_link +graph_reconf_validateopt +_init +inode_ctx_del2 +__inode_ctx_get0 +inode_ctx_get0 +__inode_ctx_get1 +inode_ctx_get1 +__inode_ctx_get2 +inode_ctx_get2 +inode_ctx_merge +inode_ctx_reset0 +inode_ctx_reset1 +inode_ctx_reset2 +__inode_ctx_set0 +inode_ctx_set0 +__inode_ctx_set1 +inode_ctx_set1 +__inode_ctx_set2 +inode_ctx_set2 +inode_ctx_size +inode_dump +inode_dump_to_dict +__inode_find +inode_find +inode_find_directory_name +inode_forget +inode_forget_with_unref +inode_from_path +inode_grep +inode_grep_for_gfid +inode_has_dentry +inode_invalidate +inode_is_linked +inode_link +inode_lookup +inode_needs_lookup +inode_new +inode_parent +__inode_path +inode_path +inode_ref +inode_ref_reduce_by_n +inode_rename +inode_resolve +inode_set_need_lookup +inode_table_ctx_free +inode_table_destroy +inode_table_destroy_all +inode_table_dump +inode_table_dump_to_dict +inode_table_new +inode_table_with_invalidator +__inode_table_set_lru_limit +inode_table_set_lru_limit +inode_unlink +inode_unref +int_to_data +iobref_add +iobref_clear +iobref_merge +iobref_new +iobref_ref +iobref_size +iobref_unref +iobuf_get +iobuf_get2 +iobuf_get_page_aligned +iobuf_pool_destroy +iobuf_pool_new +iobuf_size +iobuf_to_iovec +iobuf_unref +iobuf_copy +is_data_equal +__is_fuse_call +is_gf_log_command +is_graph_topology_equal +__is_root_gfid +is_valid_lease_id +leaseid_utoa +gf_existing_leaseid +gf_leaseid_get +list_node_add +list_node_add_order +list_node_del +lkowner_utoa +loc_copy +loc_copy_overload_parent +loc_gfid +loc_gfid_utoa +loc_is_nameless +loc_is_root +loc_pargfid +loc_path +loc_touchup +loc_wipe +log_base2 +_mask_cancellation +mask_match +mem_get +mem_get0 +mem_pool_destroy +mem_pool_new_fn +mem_pools_fini +mem_pools_init +mem_put +mkdir_p +next_token +nwstrtail +os_daemon +os_daemon_return +parser_deinit +parser_get_next_match +parser_init +parser_set_string +parser_unset_string +quota_conf_read_gfid +quota_conf_read_version +quota_conf_skip_header +quota_data_to_meta +quota_dict_get_inode_meta +quota_dict_get_meta +quota_dict_set_meta +quota_meta_is_null +rb_create +rb_delete +rb_destroy +rb_find +rb_probe +rbthash_get +rbthash_insert +rbthash_remove +rbthash_table_destroy +rbthash_table_init +rbuf_dtor +rbuf_get_buffer +rbuf_init +rbuf_reserve_write_area +rbuf_wait_for_completion +rbuf_write_complete +recursive_rmdir +runcmd +runinit +runner +runner_add_arg +runner_add_args +runner_argprintf +runner_chio +runner_end +runner_log +runner_redir +runner_run +runner_run_nowait +runner_run_reuse +runner_start +set_sys_log_level +skipwhite +strfd_close +strfd_open +strprintf +strtail +str_to_data +SuperFastHash +syncbarrier_destroy +syncbarrier_init +syncbarrier_wait +syncbarrier_wake +synccond_init +synccond_destroy +synccond_wait +synccond_timedwait +synccond_signal +synccond_broadcast +syncenv_destroy +syncenv_new +synclock_destroy +synclock_init +synclock_lock +synclock_trylock +synclock_unlock +syncop_access +syncop_close +syncop_create +syncop_copy_file_range +syncopctx_getctx +syncopctx_setfsgid +syncopctx_setfsgroups +syncopctx_setfslkowner +syncopctx_setfspid +syncopctx_setfsuid +syncop_dirfd +syncop_dir_scan +syncop_discard +syncop_fallocate +syncop_flush +syncop_fgetxattr +syncop_fremovexattr +syncop_fsetattr +syncop_fsetxattr +syncop_fstat +syncop_fsync +syncop_fsyncdir +syncop_ftruncate +syncop_ftw +syncop_ftw_throttle +syncop_fxattrop +syncop_getactivelk +syncop_getxattr +syncop_gfid_to_path +syncop_gfid_to_path_hard +syncop_inode_find +syncop_inodelk +syncop_entrylk +syncop_ipc +syncop_is_subvol_local +syncop_link +syncop_listxattr +syncop_lk +syncop_lookup +syncop_mkdir +syncop_mknod +syncop_mt_dir_scan +syncop_open +syncop_opendir +syncop_readdir +syncop_readdirp +syncop_readlink +syncop_readv +syncop_removexattr +syncop_rename +syncop_rmdir +syncop_seek +syncop_setactivelk +syncop_setattr +syncop_setxattr +syncop_stat +syncop_statfs +syncop_symlink +syncop_truncate +syncop_unlink +syncop_write +syncop_writev +syncop_xattrop +syncop_zerofill +syncop_lease +synctask_get +synctask_new +synctask_new1 +synctask_set +synctask_setid +synctask_sleep +synctask_wake +synctask_yield +sys_access +sys_chmod +sys_chown +sys_close +sys_closedir +sys_copy_file_range +sys_creat +sys_fallocate +sys_fchmod +sys_fchown +sys_fdatasync +sys_fgetxattr +sys_flistxattr +sys_fremovexattr +sys_fsetxattr +sys_fstat +sys_fstatat +sys_fsync +sys_ftruncate +sys_futimes +sys_lchown +sys_lgetxattr +sys_link +sys_linkat +sys_llistxattr +sys_lremovexattr +sys_lseek +sys_lsetxattr +sys_lstat +sys_mkdir +sys_mkdirat +sys_mknod +sys_open +sys_openat +sys_opendir +sys_pread +sys_pwrite +sys_pwritev +sys_read +sys_readdir +sys_readlink +sys_readv +sys_rename +sys_rmdir +sys_stat +sys_statvfs +sys_symlink +sys_symlinkat +sys_truncate +sys_unlink +sys_unlinkat +sys_utimensat +sys_write +sys_writev +sys_socket +sys_accept +sys_kill +sys_sysctl +tbf_init +tbf_throttle +timespec_now +timespec_now_realtime +timespec_sub +timespec_adjust_delta +timespec_cmp +token_iter_init +trap +trie_add +trie_destroy +trie_measure +trie_measure_vec +trie_new +trienode_get_word +_unmask_cancellation +uuid_utoa +uuid_utoa_r +validate_brick_name +valid_host_name +valid_ipv4_address +valid_internet_address +xlator_destroy +xlator_foreach +xlator_foreach_depth_first +xlator_init +xlator_mem_acct_init +xlator_mem_acct_unref +xlator_notify +xlator_option_info_list +xlator_option_init_bool +xlator_option_init_double +xlator_option_init_int32 +xlator_option_init_path +xlator_option_init_percent +xlator_option_init_percent_or_size +xlator_option_init_size +xlator_option_init_size_uint64 +xlator_option_init_size_int64 +xlator_option_init_str +xlator_option_init_time +xlator_option_init_uint32 +xlator_option_init_uint64 +xlator_option_init_int64 +xlator_option_init_xlator +xlator_option_reconf_bool +xlator_option_reconf_int32 +xlator_option_reconf_path +xlator_option_reconf_percent +xlator_option_reconf_percent_or_size +xlator_option_reconf_size +xlator_option_reconf_size_uint64 +xlator_option_reconf_size_int64 +xlator_option_reconf_str +xlator_option_reconf_time +xlator_option_reconf_uint32 +xlator_option_reconf_uint64 +xlator_option_reconf_int64 +xlator_option_reconf_xlator +xlator_options_validate +xlator_options_validate_list +xlator_option_validate +xlator_option_validate_addr_list +xlator_search_by_name +xlator_set_inode_lru_limit +xlator_set_type +xlator_set_type_virtual +xlator_subvolume_count +xlator_tree_free_members +xlator_volopt_dynload +xlator_volume_option_get +xlator_volume_option_get_list +xlator_memrec_free +xlator_mem_cleanup +gluster_graph_take_reference +default_fops +gf_fop_list +gf_upcall_list +vol_type_str +global_ctx +global_ctx_mutex +global_xlator +use_spinlocks +dump_options +glusterfs_leaseid_buf_get +glusterfs_leaseid_exist +gf_replace_old_iatt_in_dict +gf_replace_new_iatt_in_dict +gf_changelog_init +gf_changelog_register_generic +gf_gfid_generate_from_xxh64 +find_xlator_option_in_cmd_args_t +gf_d_type_from_ia_type +glusterfs_graph_fini +glusterfs_process_svc_attach_volfp +glusterfs_mux_volfile_reconfigure +glusterfs_process_svc_detach +mgmt_is_multiplexed_daemon +xlator_is_cleanup_starting +gf_nanosleep +gf_syncfs +graph_total_client_xlator +get_xattrs_to_heal +gf_latency_statedump_and_reset +gf_latency_new +gf_latency_reset +gf_latency_update +gf_frame_latency_update diff --git a/libglusterfs/src/list.h b/libglusterfs/src/list.h deleted file mode 100644 index 6e0f048bd5f..00000000000 --- a/libglusterfs/src/list.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - Copyright (c) 2008-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _LLIST_H -#define _LLIST_H - - -struct list_head { - struct list_head *next; - struct list_head *prev; -}; - - -#define INIT_LIST_HEAD(head) do { \ - (head)->next = (head)->prev = head; \ - } while (0) - - -static inline void -list_add (struct list_head *new, struct list_head *head) -{ - new->prev = head; - new->next = head->next; - - new->prev->next = new; - new->next->prev = new; -} - - -static inline void -list_add_tail (struct list_head *new, struct list_head *head) -{ - new->next = head; - new->prev = head->prev; - - new->prev->next = new; - new->next->prev = new; -} - - -static inline void -list_del (struct list_head *old) -{ - old->prev->next = old->next; - old->next->prev = old->prev; - - old->next = (void *)0xbabebabe; - old->prev = (void *)0xcafecafe; -} - - -static inline void -list_del_init (struct list_head *old) -{ - old->prev->next = old->next; - old->next->prev = old->prev; - - old->next = old; - old->prev = old; -} - - -static inline void -list_move (struct list_head *list, struct list_head *head) -{ - list_del (list); - list_add (list, head); -} - - -static inline void -list_move_tail (struct list_head *list, struct list_head *head) -{ - list_del (list); - list_add_tail (list, head); -} - - -static inline int -list_empty (struct list_head *head) -{ - return (head->next == head); -} - - -static inline void -__list_splice (struct list_head *list, struct list_head *head) -{ - (list->prev)->next = (head->next); - (head->next)->prev = (list->prev); - - (head)->next = (list->next); - (list->next)->prev = (head); -} - - -static inline void -list_splice (struct list_head *list, struct list_head *head) -{ - if (list_empty (list)) - return; - - __list_splice (list, head); -} - - -static inline void -list_splice_init (struct list_head *list, struct list_head *head) -{ - if (list_empty (list)) - return; - - __list_splice (list, head); - INIT_LIST_HEAD (list); -} - - -#define list_entry(ptr, type, member) \ - ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) - - -#define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - - -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - - -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -#endif /* _LLIST_H */ diff --git a/libglusterfs/src/locking.c b/libglusterfs/src/locking.c new file mode 100644 index 00000000000..7577054e33a --- /dev/null +++ b/libglusterfs/src/locking.c @@ -0,0 +1,27 @@ +/* + Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#if defined(HAVE_SPINLOCK) +/* None of this matters otherwise. */ + +#include <pthread.h> +#include <unistd.h> + +#define LOCKING_IMPL +#include "glusterfs/locking.h" + +int use_spinlocks = 0; + +static void __attribute__((constructor)) gf_lock_setup(void) +{ + // use_spinlocks = (sysconf(_SC_NPROCESSORS_ONLN) > 1); +} + +#endif diff --git a/libglusterfs/src/locking.h b/libglusterfs/src/locking.h deleted file mode 100644 index 4b1ac164c39..00000000000 --- a/libglusterfs/src/locking.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - Copyright (c) 2008-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _LOCKING_H -#define _LOCKING_H - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include <pthread.h> - -#if HAVE_SPINLOCK -#define LOCK_INIT(x) pthread_spin_init (x, 0) -#define LOCK(x) pthread_spin_lock (x) -#define TRY_LOCK(x) pthread_spin_trylock (x) -#define UNLOCK(x) pthread_spin_unlock (x) -#define LOCK_DESTROY(x) pthread_spin_destroy (x) - -typedef pthread_spinlock_t gf_lock_t; -#else -#define LOCK_INIT(x) pthread_mutex_init (x, 0) -#define LOCK(x) pthread_mutex_lock (x) -#define TRY_LOCK(x) pthread_mutex_trylock (x) -#define UNLOCK(x) pthread_mutex_unlock (x) -#define LOCK_DESTROY(x) pthread_mutex_destroy (x) - -typedef pthread_mutex_t gf_lock_t; -#endif /* HAVE_SPINLOCK */ - - -#endif /* _LOCKING_H */ diff --git a/libglusterfs/src/logging.c b/libglusterfs/src/logging.c index 4493b05c7cd..a930d3e3b63 100644 --- a/libglusterfs/src/logging.c +++ b/libglusterfs/src/logging.c @@ -1,27 +1,13 @@ /* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 <errno.h> #include <pthread.h> #include <stdio.h> @@ -30,481 +16,2431 @@ #include <locale.h> #include <string.h> #include <stdlib.h> - -#include "xlator.h" -#include "logging.h" -#include "defaults.h" - -#ifdef GF_LINUX_HOST_OS #include <syslog.h> +#include <sys/resource.h> + +#ifdef HAVE_BACKTRACE +#include <execinfo.h> +#else +#include "execinfo_compat.h" #endif +#include <sys/stat.h> + +#include "glusterfs/syscall.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" +#define GF_LOG_BACKTRACE_DEPTH 5 +#define GF_LOG_BACKTRACE_SIZE 4096 +#define GF_MAX_SLOG_PAIR_COUNT 100 + +#include "glusterfs/logging.h" +#include "glusterfs/glusterfs.h" +#include "glusterfs/timer.h" +#include "glusterfs/libglusterfs-messages.h" -static pthread_mutex_t logfile_mutex; -static char *filename = NULL; -static uint8_t logrotate = 0; -static FILE *logfile = NULL; -static gf_loglevel_t loglevel = GF_LOG_MAX; -static int gf_log_syslog = 0; +/* Do not replace gf_log in TEST_LOG with gf_msg, as there is a slight chance + * that it could lead to an infinite recursion.*/ +#define TEST_LOG(__msg, __args...) \ + gf_log("logging-infra", GF_LOG_DEBUG, __msg, ##__args); -char gf_log_xl_log_set; -gf_loglevel_t gf_log_loglevel; /* extern'd */ -FILE *gf_log_logfile; +static void +gf_log_flush_timeout_cbk(void *data); + +int +gf_log_inject_timer_event(glusterfs_ctx_t *ctx); -static char *cmd_log_filename = NULL; -static FILE *cmdlogfile = NULL; +static void +gf_log_flush_extra_msgs(glusterfs_ctx_t *ctx, uint32_t new); + +static int +log_buf_init(log_buf_t *buf, const char *domain, const char *file, + const char *function, int32_t line, gf_loglevel_t level, + int errnum, uint64_t msgid, char **appmsgstr, int graph_id); +static void +gf_log_rotate(glusterfs_ctx_t *ctx); + +static char gf_level_strings[] = { + ' ', /* NONE */ + 'M', /* EMERGENCY */ + 'A', /* ALERT */ + 'C', /* CRITICAL */ + 'E', /* ERROR */ + 'W', /* WARNING */ + 'N', /* NOTICE */ + 'I', /* INFO */ + 'D', /* DEBUG */ + 'T', /* TRACE */ +}; void -gf_log_logrotate (int signum) +gf_log_logrotate(int signum) { - logrotate = 1; + if (THIS->ctx) { + THIS->ctx->log.logrotate = 1; + THIS->ctx->log.cmd_history_logrotate = 1; + } } void -gf_log_enable_syslog (void) +gf_log_enable_syslog(void) { - gf_log_syslog = 1; + if (THIS->ctx) + THIS->ctx->log.gf_log_syslog = 1; } void -gf_log_disable_syslog (void) +gf_log_disable_syslog(void) { - gf_log_syslog = 0; + if (THIS->ctx) + THIS->ctx->log.gf_log_syslog = 0; } gf_loglevel_t -gf_log_get_loglevel (void) +gf_log_get_loglevel(void) { - return loglevel; + if (THIS->ctx) + return THIS->ctx->log.loglevel; + else + /* return global defaults (see gf_log_globals_init) */ + return GF_LOG_INFO; } void -gf_log_set_loglevel (gf_loglevel_t level) +gf_log_set_loglevel(glusterfs_ctx_t *ctx, gf_loglevel_t level) { - gf_log_loglevel = loglevel = level; + if (ctx) + ctx->log.loglevel = level; } +int +gf_log_get_localtime(void) +{ + if (THIS->ctx) + return THIS->ctx->log.localtime; + else + /* return global defaults (see gf_log_globals_init) */ + return 0; +} -gf_loglevel_t -gf_log_get_xl_loglevel (void *this) +void +gf_log_set_localtime(int on_off) { - xlator_t *xl = this; - if (!xl) - return 0; - return xl->loglevel; + if (THIS->ctx) + THIS->ctx->log.localtime = on_off; } void -gf_log_set_xl_loglevel (void *this, gf_loglevel_t level) +gf_log_flush(void) { - xlator_t *xl = this; - if (!xl) - return; - gf_log_xl_log_set = 1; - xl->loglevel = level; + xlator_t *this = THIS; + glusterfs_ctx_t *ctx = this->ctx; + + if (ctx && ctx->log.logger == gf_logger_glusterlog) { + pthread_mutex_lock(&ctx->log.logfile_mutex); + fflush(ctx->log.gf_log_logfile); + pthread_mutex_unlock(&ctx->log.logfile_mutex); + } + + return; } void -gf_log_fini (void) +gf_log_set_xl_loglevel(void *this, gf_loglevel_t level) { - pthread_mutex_destroy (&logfile_mutex); + xlator_t *xl = this; + if (!xl) + return; + xl->loglevel = level; } +/* TODO: The following get/set functions are yet not invoked from anywhere + * in the code. The _intention_ is to pass CLI arguments to various daemons + * that are started, which would then invoke these set APIs as required. + * + * glusterd would read the defaults from its .vol file configuration shipped + * as a part of the packages distributed. + * + * For any gluster* daemon that is started the shipped configuration becomes the + * default, if a volume has to change its logging format or logger, then a + * gluster CLI is invoked to set this property for the volume in question. + * + * The property is maintained by glusterd, and passed to the daemon as a CLI + * option, IOW persistence of the option is maintained by glusterd persistent + * storage (i.e .vol file) only + * + * care needs to be taken to configure and start daemons based on the versions + * that supports these features */ -int -gf_log_init (const char *file) -{ - if (!file){ - fprintf (stderr, "gf_log_init: no filename specified\n"); - return -1; - } - - pthread_mutex_init (&logfile_mutex, NULL); - - filename = gf_strdup (file); - if (!filename) { - fprintf (stderr, "gf_log_init: strdup error\n"); - return -1; - } - - logfile = fopen (file, "a"); - if (!logfile){ - fprintf (stderr, - "gf_log_init: failed to open logfile \"%s\" (%s)\n", - file, - strerror (errno)); - return -1; - } +void +gf_log_set_logformat(gf_log_format_t format) +{ + if (THIS->ctx) + THIS->ctx->log.logformat = format; +} -#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 +void +gf_log_set_logger(gf_log_logger_t logger) +{ + if (THIS->ctx) + THIS->ctx->log.logger = logger; +} - gf_log_logfile = logfile; +gf_loglevel_t +gf_log_get_xl_loglevel(void *this) +{ + xlator_t *xl = this; + if (!xl) + return 0; + return xl->loglevel; +} - return 0; +void +gf_log_set_log_buf_size(uint32_t buf_size) +{ + uint32_t old = 0; + glusterfs_ctx_t *ctx = THIS->ctx; + + pthread_mutex_lock(&ctx->log.log_buf_lock); + { + old = ctx->log.lru_size; + ctx->log.lru_size = buf_size; + } + pthread_mutex_unlock(&ctx->log.log_buf_lock); + + /* If the old size is less than/equal to the new size, then do nothing. + * + * But if the new size is less than the old size, then + * a. If the cur size of the buf is less than or equal the new size, + * then do nothing. + * b. But if the current size of the buf is greater than the new size, + * then flush the least recently used (cur size - new_size) msgs + * to disk. + */ + if (buf_size < old) + gf_log_flush_extra_msgs(ctx, buf_size); } +void +gf_log_set_log_flush_timeout(uint32_t timeout) +{ + THIS->ctx->log.timeout = timeout; +} -/* - * Initialize logging to a central server. - * If successful, log messages will be written both to - * the local file and to the remote server. +/* If log_buf_init() fails (indicated by a return value of -1), + * call log_buf_destroy() to clean up memory allocated in heap and to return + * the log_buf_t object back to its memory pool. */ +static int +log_buf_init(log_buf_t *buf, const char *domain, const char *file, + const char *function, int32_t line, gf_loglevel_t level, + int errnum, uint64_t msgid, char **appmsgstr, int graph_id) +{ + int ret = -1; -static int __central_log_enabled = 0; + if (!buf || !domain || !file || !function || !appmsgstr || !*appmsgstr) + goto out; -struct _msg_queue { - struct list_head msgs; -}; + buf->msg = gf_strdup(*appmsgstr); + if (!buf->msg) + goto out; -struct _log_msg { - const char *msg; - struct list_head queue; -}; + buf->msg_id = msgid; + buf->errnum = errnum; + buf->domain = gf_strdup(domain); + if (!buf->domain) + goto out; + buf->file = gf_strdup(file); + if (!buf->file) + goto out; + buf->function = gf_strdup(function); + if (!buf->function) + goto out; + buf->line = line; + buf->level = level; + buf->refcount = 0; + buf->graph_id = graph_id; + INIT_LIST_HEAD(&buf->msg_list); -void -gf_log_lock (void) -{ - pthread_mutex_lock (&logfile_mutex); + ret = 0; +out: + return ret; } - -void -gf_log_unlock (void) +static int +log_buf_destroy(log_buf_t *buf) { - pthread_mutex_unlock (&logfile_mutex); + if (!buf) + return -1; + + GF_FREE(buf->msg); + GF_FREE(buf->domain); + GF_FREE(buf->file); + GF_FREE(buf->function); + + mem_put(buf); + return 0; } +static void +gf_log_rotate(glusterfs_ctx_t *ctx) +{ + int fd = -1; + FILE *new_logfile = NULL; + FILE *old_logfile = NULL; + + /* not involving locks on initial check to speed it up */ + if (ctx->log.logrotate) { + /* let only one winner through on races */ + pthread_mutex_lock(&ctx->log.logfile_mutex); + + if (!ctx->log.logrotate) { + pthread_mutex_unlock(&ctx->log.logfile_mutex); + return; + } else { + ctx->log.logrotate = 0; + pthread_mutex_unlock(&ctx->log.logfile_mutex); + } + + fd = sys_open(ctx->log.filename, O_CREAT | O_WRONLY | O_APPEND, + S_IRUSR | S_IWUSR); + if (fd < 0) { + gf_smsg("logrotate", GF_LOG_ERROR, errno, + LG_MSG_OPEN_LOGFILE_FAILED, NULL); + return; + } + + new_logfile = fdopen(fd, "a"); + if (!new_logfile) { + gf_smsg("logrotate", GF_LOG_CRITICAL, errno, + LG_MSG_OPEN_LOGFILE_FAILED, "filename=%s", + ctx->log.filename, NULL); + sys_close(fd); + return; + } + + pthread_mutex_lock(&ctx->log.logfile_mutex); + { + if (ctx->log.logfile) + old_logfile = ctx->log.logfile; + + ctx->log.gf_log_logfile = ctx->log.logfile = new_logfile; + } + pthread_mutex_unlock(&ctx->log.logfile_mutex); + + if (old_logfile != NULL) + fclose(old_logfile); + } + + return; +} void -gf_log_cleanup (void) +gf_log_globals_fini(void) { - pthread_mutex_destroy (&logfile_mutex); + /* TODO: Nobody is invoking the fini, but cleanup needs to happen here, + * needs cleanup for, log.ident, log.filename, closelog, log file close + * rotate state, possibly under a lock */ + pthread_mutex_destroy(&THIS->ctx->log.logfile_mutex); + pthread_mutex_destroy(&THIS->ctx->log.log_buf_lock); } +void +gf_log_disable_suppression_before_exit(glusterfs_ctx_t *ctx) +{ + /* + * First set log buf size to 0. This would ensure two things: + * i. that all outstanding log messages are flushed to disk, and + * ii. all subsequent calls to gf_msg will result in the logs getting + * directly flushed to disk without being buffered. + * + * Then, cancel the current log timer event. + */ + + gf_log_set_log_buf_size(0); + pthread_mutex_lock(&ctx->log.log_buf_lock); + { + if (ctx->log.log_flush_timer) { + gf_timer_call_cancel(ctx, ctx->log.log_flush_timer); + ctx->log.log_flush_timer = NULL; + } + } + pthread_mutex_unlock(&ctx->log.log_buf_lock); +} +/** gf_log_fini - function to perform the cleanup of the log information + * @data - glusterfs context + * @return: success: 0 + * failure: -1 + */ int -_gf_log (const char *domain, const char *file, const char *function, int line, - gf_loglevel_t level, const char *fmt, ...) -{ - const char *basename = NULL; - FILE *new_logfile = NULL; - va_list ap; - struct tm *tm = NULL; - char timestr[256]; - struct timeval tv = {0,}; - - char *str1 = NULL; - char *str2 = NULL; - char *msg = NULL; - size_t len = 0; - int ret = 0; - xlator_t *this = NULL; - gf_loglevel_t xlator_loglevel = 0; - - if (!logfile) - return -1; - - this = THIS; - - xlator_loglevel = this->loglevel; - if (xlator_loglevel == 0) - xlator_loglevel = loglevel; - - if (level > xlator_loglevel) - goto out; +gf_log_fini(void *data) +{ + glusterfs_ctx_t *ctx = data; + int ret = 0; + FILE *old_logfile = NULL; + + if (ctx == NULL) { + ret = -1; + goto out; + } + + gf_log_disable_suppression_before_exit(ctx); + + pthread_mutex_lock(&ctx->log.logfile_mutex); + { + if (ctx->log.logfile) { + old_logfile = ctx->log.logfile; + + /* Logfile needs to be set to NULL, so that any + call to gf_log after calling gf_log_fini, will + log the message to stderr. + */ + ctx->log.loglevel = GF_LOG_NONE; + ctx->log.logfile = NULL; + } + } + pthread_mutex_unlock(&ctx->log.logfile_mutex); - static char *level_strings[] = {"", /* NONE */ - "M", /* EMERGENCY */ - "A", /* ALERT */ - "C", /* CRITICAL */ - "E", /* ERROR */ - "W", /* WARNING */ - "N", /* NOTICE */ - "I", /* INFO/NORMAL */ - "D", /* DEBUG */ - "T", /* TRACE */ - ""}; - - if (!domain || !file || !function || !fmt) { - fprintf (stderr, - "logging: %s:%s():%d: invalid argument\n", - __FILE__, __PRETTY_FUNCTION__, __LINE__); - return -1; - } - - - if (logrotate) { - logrotate = 0; - - new_logfile = fopen (filename, "a"); - if (!new_logfile) { - gf_log ("logrotate", GF_LOG_CRITICAL, - "failed to open logfile %s (%s)", - filename, strerror (errno)); - goto log; - } - - fclose (logfile); - gf_log_logfile = logfile = new_logfile; - } + if (old_logfile && (fclose(old_logfile) != 0)) + ret = -1; -log: - ret = gettimeofday (&tv, NULL); - if (-1 == ret) - goto out; + GF_FREE(ctx->log.ident); + GF_FREE(ctx->log.filename); - tm = localtime (&tv.tv_sec); +out: + return ret; +} - pthread_mutex_lock (&logfile_mutex); - { - va_start (ap, fmt); +/** + * 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 + */ +static 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; + } + + /* TODO: Should check for errors here and return appropriately */ + setlocale(LC_ALL, ""); + setlocale(LC_NUMERIC, "C"); /* C-locale for strtod, ... */ + /* close the previous syslog if open as we are changing settings */ + closelog(); + openlog(ident, _option, _facility); +} - strftime (timestr, 256, "%Y-%m-%d %H:%M:%S", tm); - snprintf (timestr + strlen (timestr), 256 - strlen (timestr), - ".%"GF_PRI_SUSECONDS, tv.tv_usec); +/** + * _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" + * + */ +static 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; + } - basename = strrchr (file, '/'); - if (basename) - basename++; - else - basename = file; + if ((pos + 2) >= len) { + break; + } - ret = gf_asprintf (&str1, "[%s] %s [%s:%d:%s] %s: ", - timestr, level_strings[level], - basename, line, function, - domain); - if (-1 == ret) { - goto unlock; + 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; + } + } - ret = vasprintf (&str2, fmt, ap); - if (-1 == ret) { - goto unlock; - } + buf[pos] = '\0'; + return (char *)p; +} + +/** + * gf_syslog -function to submit message to syslog specific to gluster + * @facility_priority: facility_priority of syslog() + * @format: optional format string to syslog() + * + * @return: void + */ +static void +gf_syslog(int facility_priority, char *format, ...) +{ + char *msg = NULL; + char json_msg[GF_JSON_MSG_LENGTH]; + GF_UNUSED char *p = NULL; + va_list ap; + + GF_ASSERT(format); + + va_start(ap, format); + if (vasprintf(&msg, format, ap) != -1) { + p = _json_escape(msg, json_msg, GF_JSON_MSG_LENGTH); + syslog(facility_priority, "%s", msg); + free(msg); + } else + syslog(GF_LOG_CRITICAL, "vasprintf() failed, out of memory?"); + va_end(ap); +} + +void +gf_log_globals_init(void *data, gf_loglevel_t level) +{ + glusterfs_ctx_t *ctx = data; - va_end (ap); + pthread_mutex_init(&ctx->log.logfile_mutex, NULL); - len = strlen (str1); - msg = GF_MALLOC (len + strlen (str2) + 1, gf_common_mt_char); + ctx->log.loglevel = level; + ctx->log.gf_log_syslog = 1; + ctx->log.sys_log_level = GF_LOG_CRITICAL; + ctx->log.logger = gf_logger_glusterlog; + ctx->log.logformat = gf_logformat_withmsgid; + ctx->log.lru_size = GF_LOG_LRU_BUFSIZE_DEFAULT; + ctx->log.timeout = GF_LOG_FLUSH_TIMEOUT_DEFAULT; + ctx->log.localtime = GF_LOG_LOCALTIME_DEFAULT; - strcpy (msg, str1); - strcpy (msg + len, str2); + pthread_mutex_init(&ctx->log.log_buf_lock, NULL); - fprintf (logfile, "%s\n", msg); - fflush (logfile); + INIT_LIST_HEAD(&ctx->log.lru_queue); #ifdef GF_LINUX_HOST_OS - /* We want only serious log in 'syslog', not our debug - and trace logs */ - if (gf_log_syslog && level && (level <= GF_LOG_ERROR)) - syslog ((level-1), "%s\n", msg); + /* For the 'syslog' output. one can grep 'GlusterFS' in syslog + for serious logs */ + openlog("GlusterFS", LOG_PID, LOG_DAEMON); #endif - } +} -unlock: - pthread_mutex_unlock (&logfile_mutex); +int +gf_log_init(void *data, const char *file, const char *ident) +{ + glusterfs_ctx_t *ctx = data; + int fd = -1; + struct stat buf; + + if (ctx == NULL) { + fprintf(stderr, "ERROR: ctx is NULL\n"); + return -1; + } + if (ident) { + GF_FREE(ctx->log.ident); + ctx->log.ident = gf_strdup(ident); + } + + /* we keep the files and the syslog open, so that on logger change, we + * are ready to log anywhere, that the new value specifies */ + if (ctx->log.ident) { + gf_openlog(ctx->log.ident, -1, LOG_DAEMON); + } else { + gf_openlog(NULL, -1, LOG_DAEMON); + } + /* TODO: make FACILITY configurable than LOG_DAEMON */ + if (sys_stat(GF_LOG_CONTROL_FILE, &buf) == 0) { + /* use syslog logging */ + ctx->log.log_control_file_found = 1; + } else { + /* use old style logging */ + ctx->log.log_control_file_found = 0; + } + + if (!file) { + fprintf(stderr, "ERROR: no filename specified\n"); + return -1; + } + + /* free the (possible) previous filename */ + GF_FREE(ctx->log.filename); + ctx->log.filename = NULL; + + /* close and reopen logfile for log rotate */ + if (ctx->log.logfile) { + fclose(ctx->log.logfile); + ctx->log.logfile = NULL; + ctx->log.gf_log_logfile = NULL; + } + + if (strcmp(file, "-") == 0) { + int dupfd = -1; + + ctx->log.filename = gf_strdup("/dev/stderr"); + if (!ctx->log.filename) { + fprintf(stderr, "ERROR: strdup failed\n"); + return -1; + } - if (msg) { - if ((ret != -1) && __central_log_enabled && - ((glusterfs_central_log_flag_get ()) == 0)) { + dupfd = dup(fileno(stderr)); + if (dupfd == -1) { + fprintf(stderr, "ERROR: could not dup %d (%s)\n", fileno(stderr), + strerror(errno)); + return -1; + } - glusterfs_central_log_flag_set (); - { - //gf_log_central (msg); - } - glusterfs_central_log_flag_unset (); - } - GF_FREE (msg); + ctx->log.logfile = fdopen(dupfd, "a"); + if (!ctx->log.logfile) { + fprintf(stderr, "ERROR: could not fdopen on %d (%s)\n", dupfd, + strerror(errno)); + sys_close(dupfd); + return -1; + } + } else { + /* Also create parent dir */ + char *logdir = gf_strdup(file); + if (!logdir) { + return -1; + } + char *tmp_index = rindex(logdir, '/'); + if (tmp_index) { + tmp_index[0] = '\0'; + } + if (mkdir_p(logdir, 0755, true)) { + /* EEXIST is handled in mkdir_p() itself */ + gf_smsg("logging", GF_LOG_ERROR, 0, LG_MSG_STRDUP_ERROR, + "logdir=%s", logdir, "errno=%s", strerror(errno), NULL); + GF_FREE(logdir); + return -1; + } + /* no need of this variable */ + GF_FREE(logdir); + + ctx->log.filename = gf_strdup(file); + if (!ctx->log.filename) { + fprintf(stderr, + "ERROR: updating log-filename failed: " + "%s\n", + strerror(errno)); + return -1; + } + + fd = sys_open(file, O_CREAT | O_WRONLY | O_APPEND, S_IRUSR | S_IWUSR); + if (fd < 0) { + fprintf(stderr, + "ERROR: failed to create logfile" + " \"%s\" (%s)\n", + file, strerror(errno)); + return -1; + } + + ctx->log.logfile = fdopen(fd, "a"); + if (!ctx->log.logfile) { + fprintf(stderr, + "ERROR: failed to open logfile \"%s\" " + "(%s)\n", + file, strerror(errno)); + sys_close(fd); + return -1; + } + } + + ctx->log.gf_log_logfile = ctx->log.logfile; + + return 0; +} + +void +set_sys_log_level(gf_loglevel_t level) +{ + if (THIS->ctx) + THIS->ctx->log.sys_log_level = level; +} + +/* Check if we should be logging + * Return value: _gf_false : Print the log + * _gf_true : Do not Print the log + */ +static gf_boolean_t +skip_logging(xlator_t *this, gf_loglevel_t level) +{ + gf_loglevel_t existing_level = this->loglevel ? this->loglevel + : this->ctx->log.loglevel; + if (level > existing_level) { + return _gf_true; + } + + if (level == GF_LOG_NONE) { + return _gf_true; + } + + return _gf_false; +} + +int +_gf_log_callingfn(const char *domain, const char *file, const char *function, + int line, gf_loglevel_t level, const char *fmt, ...) +{ + const char *basename = NULL; + xlator_t *this = THIS; + char *logline = NULL; + char *msg = NULL; + char timestr[GF_TIMESTR_SIZE] = { + 0, + }; + char *callstr = NULL; + struct timeval tv = { + 0, + }; + int ret = 0; + va_list ap; + glusterfs_ctx_t *ctx = this->ctx; + + if (!ctx) + goto out; + + if (skip_logging(this, level)) + goto out; + + if (!domain || !file || !function || !fmt) { + fprintf(stderr, "logging: %s:%s():%d: invalid argument\n", __FILE__, + __PRETTY_FUNCTION__, __LINE__); + return -1; + } + + basename = strrchr(file, '/'); + if (basename) + basename++; + else + basename = file; + + /*Saving the backtrace to pre-allocated ctx->btbuf + * to avoid allocating memory from the heap*/ + callstr = gf_backtrace_save(NULL); + + va_start(ap, fmt); + ret = vasprintf(&msg, fmt, ap); + va_end(ap); + if (-1 == ret) { + goto out; + } + + 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(priority, "[%s:%d:%s] %s %d-%s: %s", basename, line, function, + callstr, ((this->graph) ? this->graph->id : 0), domain, msg); + + goto out; + } + + ret = gettimeofday(&tv, NULL); + if (-1 == ret) + goto out; + + gf_time_fmt_tv(timestr, sizeof timestr, &tv, gf_timefmt_FT); + + ret = gf_asprintf(&logline, "[%s] %c [%s:%d:%s] %s %d-%s: %s\n", timestr, + gf_level_strings[level], basename, line, function, + callstr, ((this->graph) ? this->graph->id : 0), domain, + msg); + if (-1 == ret) { + goto out; + } + + pthread_mutex_lock(&ctx->log.logfile_mutex); + { + if (ctx->log.logfile) { + fputs(logline, ctx->log.logfile); + fflush(ctx->log.logfile); + } else if (ctx->log.loglevel >= level) { + fputs(logline, stderr); + fflush(stderr); } - if (str1) - GF_FREE (str1); +#ifdef GF_LINUX_HOST_OS + /* We want only serious log in 'syslog', not our debug + and trace logs */ + if (ctx->log.gf_log_syslog && level && + (level <= ctx->log.sys_log_level)) + syslog((level - 1), "%s", logline); +#endif + } - if (str2) - FREE (str2); + pthread_mutex_unlock(&ctx->log.logfile_mutex); out: - return (0); + + GF_FREE(logline); + + FREE(msg); + + return ret; } +static int +_gf_msg_plain_internal(gf_loglevel_t level, const char *msg) +{ + xlator_t *this = NULL; + glusterfs_ctx_t *ctx = NULL; + int priority; + + this = THIS; + ctx = this->ctx; + + /* log to the configured logging service */ + switch (ctx->log.logger) { + case gf_logger_syslog: + if (ctx->log.log_control_file_found && ctx->log.gf_log_syslog) { + SET_LOG_PRIO(level, priority); + + syslog(priority, "%s", msg); + break; + } + /* NOTE: If syslog control file is absent, which is another + * way to control logging to syslog, then we will fall through + * to the gluster log. The ideal way to do things would be to + * not have the extra control file check */ + case gf_logger_glusterlog: + pthread_mutex_lock(&ctx->log.logfile_mutex); + { + if (ctx->log.logfile) { + fprintf(ctx->log.logfile, "%s\n", msg); + fflush(ctx->log.logfile); + } else { + fprintf(stderr, "%s\n", msg); + fflush(stderr); + } -struct _client_log { - char *identifier; - FILE *file; - struct list_head list; -}; +#ifdef GF_LINUX_HOST_OS + /* We want only serious logs in 'syslog', not our debug + * and trace logs */ + if (ctx->log.gf_log_syslog && level && + (level <= ctx->log.sys_log_level)) + syslog((level - 1), "%s\n", msg); +#endif + } + pthread_mutex_unlock(&ctx->log.logfile_mutex); -struct _client_log *client_logs = NULL; + break; + } + return 0; +} -static void -client_log_init (struct _client_log *cl, char *identifier) +int +_gf_msg_plain(gf_loglevel_t level, const char *fmt, ...) { - int ret = 0; - char *path = NULL; + xlator_t *this = NULL; + int ret = 0; + va_list ap; + char *msg = NULL; + glusterfs_ctx_t *ctx = NULL; + + this = THIS; + ctx = this->ctx; - cl->identifier = identifier; + if (!ctx) + goto out; - ret = gf_asprintf (&path, "%s.client-%s", filename, identifier); - if (-1 == ret) { - return; + if (skip_logging(this, level)) + goto out; + + va_start(ap, fmt); + ret = vasprintf(&msg, fmt, ap); + va_end(ap); + if (-1 == ret) { + goto out; + } + + ret = _gf_msg_plain_internal(level, msg); + + FREE(msg); + +out: + return ret; +} + +int +_gf_msg_vplain(gf_loglevel_t level, const char *fmt, va_list ap) +{ + xlator_t *this = NULL; + int ret = 0; + char *msg = NULL; + glusterfs_ctx_t *ctx = NULL; + + this = THIS; + ctx = this->ctx; + + if (!ctx) + goto out; + + if (skip_logging(this, level)) + goto out; + + ret = vasprintf(&msg, fmt, ap); + if (-1 == ret) { + goto out; + } + + ret = _gf_msg_plain_internal(level, msg); + + FREE(msg); +out: + return ret; +} + +int +_gf_msg_plain_nomem(gf_loglevel_t level, const char *msg) +{ + xlator_t *this = NULL; + int ret = 0; + glusterfs_ctx_t *ctx = NULL; + + this = THIS; + ctx = this->ctx; + + if (!ctx) + goto out; + + if (skip_logging(this, level)) + goto out; + + ret = _gf_msg_plain_internal(level, msg); + +out: + return ret; +} + +void +_gf_msg_backtrace_nomem(gf_loglevel_t level, int stacksize) +{ + xlator_t *this = NULL; + glusterfs_ctx_t *ctx = NULL; + void *array[200]; + size_t bt_size = 0; + int fd = -1; + + this = THIS; + ctx = this->ctx; + + if (!ctx) + goto out; + + /* syslog does not have fd support, hence no no-mem variant */ + if (ctx->log.logger != gf_logger_glusterlog) + goto out; + + if (skip_logging(this, level)) + goto out; + + bt_size = backtrace(array, ((stacksize <= 200) ? stacksize : 200)); + if (!bt_size) + goto out; + pthread_mutex_lock(&ctx->log.logfile_mutex); + { + fd = ctx->log.logfile ? fileno(ctx->log.logfile) : fileno(stderr); + if (fd != -1) { + /* print to the file fd, to prevent any + allocations from backtrace_symbols + */ + backtrace_symbols_fd(&array[0], bt_size, fd); } - cl->file = fopen (path, "a"); - GF_FREE (path); - - INIT_LIST_HEAD (&cl->list); + } + pthread_mutex_unlock(&ctx->log.logfile_mutex); + +out: + return; } +int +_gf_msg_backtrace(int stacksize, char *callstr, size_t strsize) +{ + int ret = -1; + int i = 0; + int size = 0; + int savstrsize = strsize; + void *array[200]; + char **callingfn = NULL; + + /* We chop off last 2 anyway, so if request is less than tolerance + * nothing to do */ + if (stacksize < 3) + goto out; + + size = backtrace(array, ((stacksize <= 200) ? stacksize : 200)); + if ((size - 3) < 0) + goto out; + if (size) + callingfn = backtrace_symbols(&array[2], size - 2); + if (!callingfn) + goto out; + + ret = snprintf(callstr, strsize, "("); + PRINT_SIZE_CHECK(ret, out, strsize); + + for ((i = size - 3); i >= 0; i--) { + ret = snprintf(callstr + savstrsize - strsize, strsize, "-->%s ", + callingfn[i]); + PRINT_SIZE_CHECK(ret, out, strsize); + } + + ret = snprintf(callstr + savstrsize - strsize, strsize, ")"); + PRINT_SIZE_CHECK(ret, out, strsize); +out: + FREE(callingfn); + return ret; +} -static FILE * -__logfile_for_client (char *identifier) +int +_gf_msg_nomem(const char *domain, const char *file, const char *function, + int line, gf_loglevel_t level, size_t size) { - struct _client_log *client = NULL; + const char *basename = NULL; + xlator_t *this = NULL; + struct timeval tv = { + 0, + }; + int ret = 0; + int fd = -1; + char msg[2048] = { + 0, + }; + char timestr[GF_TIMESTR_SIZE] = { + 0, + }; + glusterfs_ctx_t *ctx = NULL; + int wlen = 0; + int priority; + struct rusage r_usage; + + this = THIS; + ctx = this->ctx; + + if (!ctx) + goto out; + + if (skip_logging(this, level)) + goto out; + + if (!domain || !file || !function) { + fprintf(stderr, "logging: %s:%s():%d: invalid argument\n", __FILE__, + __PRETTY_FUNCTION__, __LINE__); + return -1; + } + + GET_FILE_NAME_TO_LOG(file, basename); + + ret = gettimeofday(&tv, NULL); + if (-1 == ret) + goto out; + gf_time_fmt_tv(timestr, sizeof timestr, &tv, gf_timefmt_FT); + + /* TODO: Currently we print in the enhanced format, with a message ID + * of 0. Need to enhance this to support format as configured */ + wlen = snprintf( + msg, sizeof msg, + "[%s] %c [MSGID: %" PRIu64 + "]" + " [%s:%d:%s] %s: no memory " + "available for size (%" GF_PRI_SIZET + ") current memory usage in kilobytes %ld" + " [call stack follows]\n", + timestr, gf_level_strings[level], (uint64_t)0, basename, line, function, + domain, size, + (!getrusage(RUSAGE_SELF, &r_usage) ? r_usage.ru_maxrss : 0)); + if (-1 == wlen) { + ret = -1; + goto out; + } + + /* log to the configured logging service */ + switch (ctx->log.logger) { + case gf_logger_syslog: + if (ctx->log.log_control_file_found && ctx->log.gf_log_syslog) { + SET_LOG_PRIO(level, priority); + + /* if syslog allocates, then this may fail, but we + * cannot do much about it at the moment */ + /* There is no fd for syslog, hence no stack printed */ + syslog(priority, "%s", msg); + break; + } + /* NOTE: If syslog control file is absent, which is another + * way to control logging to syslog, then we will fall through + * to the gluster log. The ideal way to do things would be to + * not have the extra control file check */ + case gf_logger_glusterlog: + pthread_mutex_lock(&ctx->log.logfile_mutex); + { + fd = ctx->log.logfile ? fileno(ctx->log.logfile) + : fileno(stderr); + if (fd == -1) { + pthread_mutex_unlock(&ctx->log.logfile_mutex); + goto out; + } + + /* write directly to the fd to prevent out of order + * message and stack */ + ret = sys_write(fd, msg, wlen); + if (ret == -1) { + pthread_mutex_unlock(&ctx->log.logfile_mutex); + goto out; + } +#ifdef GF_LINUX_HOST_OS + /* We want only serious log in 'syslog', not our debug + * and trace logs */ + if (ctx->log.gf_log_syslog && level && + (level <= ctx->log.sys_log_level)) + syslog((level - 1), "%s\n", msg); +#endif + } + pthread_mutex_unlock(&ctx->log.logfile_mutex); - if (!client_logs) { - client = GF_CALLOC (1, sizeof (*client), - gf_common_mt_client_log); - if (!client) - return NULL; + _gf_msg_backtrace_nomem(level, GF_LOG_BACKTRACE_DEPTH); - client_log_init (client, identifier); + break; + } - client_logs = client; +out: + return ret; +} + +static int +gf_log_syslog(glusterfs_ctx_t *ctx, const char *domain, const char *file, + const char *function, int32_t line, gf_loglevel_t level, + int errnum, uint64_t msgid, char **appmsgstr, char *callstr, + int graph_id, gf_log_format_t fmt) +{ + int priority; + + SET_LOG_PRIO(level, priority); + + /* log with appropriate format */ + switch (fmt) { + case gf_logformat_traditional: + if (!callstr) { + if (errnum) + syslog(priority, "[%s:%d:%s] %d-%s: %s [%s]", file, line, + function, graph_id, domain, *appmsgstr, + strerror(errnum)); + else + syslog(priority, "[%s:%d:%s] %d-%s: %s", file, line, + function, graph_id, domain, *appmsgstr); + } else { + if (errnum) + syslog(priority, + "[%s:%d:%s] %s %d-%s:" + " %s [%s]", + file, line, function, callstr, graph_id, domain, + *appmsgstr, strerror(errnum)); + else + syslog(priority, "[%s:%d:%s] %s %d-%s: %s", file, line, + function, callstr, graph_id, domain, *appmsgstr); + } + break; + case gf_logformat_withmsgid: + if (!callstr) { + if (errnum) + syslog(priority, + "[MSGID: %" PRIu64 + "]" + " [%s:%d:%s] %d-%s: %s [%s]", + msgid, file, line, function, graph_id, domain, + *appmsgstr, strerror(errnum)); + else + syslog(priority, + "[MSGID: %" PRIu64 + "]" + " [%s:%d:%s] %d-%s: %s", + msgid, file, line, function, graph_id, domain, + *appmsgstr); + } else { + if (errnum) + syslog(priority, + "[MSGID: %" PRIu64 + "]" + " [%s:%d:%s] %s %d-%s: %s [%s]", + msgid, file, line, function, callstr, graph_id, + domain, *appmsgstr, strerror(errnum)); + else + syslog(priority, + "[MSGID: %" PRIu64 + "]" + " [%s:%d:%s] %s %d-%s: %s", + msgid, file, line, function, callstr, graph_id, + domain, *appmsgstr); + } + break; + case gf_logformat_cee: + /* TODO: Enhance CEE with additional parameters */ + gf_syslog(priority, "[%s:%d:%s] %d-%s: %s", file, line, function, + graph_id, domain, *appmsgstr); + break; + + default: + /* NOTE: should not get here without logging */ + break; + } + + /* TODO: There can be no errors from gf_syslog? */ + return 0; +} + +static int +gf_log_glusterlog(glusterfs_ctx_t *ctx, const char *domain, const char *file, + const char *function, int32_t line, gf_loglevel_t level, + int errnum, uint64_t msgid, char **appmsgstr, char *callstr, + struct timeval tv, int graph_id, gf_log_format_t fmt) +{ + char timestr[GF_TIMESTR_SIZE] = { + 0, + }; + char *header = NULL; + char *footer = NULL; + int ret = 0; + + /* rotate if required */ + gf_log_rotate(ctx); + + /* format the time stamp */ + gf_time_fmt_tv(timestr, sizeof timestr, &tv, gf_timefmt_FT); + + /* generate footer */ + if (errnum) { + ret = gf_asprintf(&footer, " [%s]\n", strerror(errnum)); + } else { + ret = gf_asprintf(&footer, " \n"); + } + if (-1 == ret) { + goto err; + } + + /* generate message, inc. the header */ + if (fmt == gf_logformat_traditional) { + if (!callstr) { + ret = gf_asprintf(&header, + "[%s] %c [%s:%d:%s]" + " %d-%s: %s", + timestr, gf_level_strings[level], file, line, + function, graph_id, domain, *appmsgstr); + } else { + ret = gf_asprintf(&header, + "[%s] %c [%s:%d:%s] %s" + " %d-%s: %s", + timestr, gf_level_strings[level], file, line, + function, callstr, graph_id, domain, *appmsgstr); + } + } else { /* gf_logformat_withmsgid */ + /* CEE log format unsupported in logger_glusterlog, so just + * print enhanced log format */ + if (!callstr) { + ret = gf_asprintf(&header, + "[%s] %c [MSGID: %" PRIu64 + "]" + " [%s:%d:%s] %d-%s: %s", + timestr, gf_level_strings[level], msgid, file, + line, function, graph_id, domain, *appmsgstr); + } else { + ret = gf_asprintf(&header, + "[%s] %c [MSGID: %" PRIu64 + "]" + " [%s:%d:%s] %s %d-%s: %s", + timestr, gf_level_strings[level], msgid, file, + line, function, callstr, graph_id, domain, + *appmsgstr); + } + } + if (-1 == ret) { + goto err; + } + + /* send the full message to log */ + + pthread_mutex_lock(&ctx->log.logfile_mutex); + { + if (ctx->log.logfile) { + fprintf(ctx->log.logfile, "%s%s", header, footer); + fflush(ctx->log.logfile); + } else if (ctx->log.loglevel >= level) { + fprintf(stderr, "%s%s", header, footer); + fflush(stderr); } - list_for_each_entry (client, &client_logs->list, list) { - if (!strcmp (client->identifier, identifier)) - break; +#ifdef GF_LINUX_HOST_OS + /* We want only serious logs in 'syslog', not our debug + * and trace logs */ + if (ctx->log.gf_log_syslog && level && + (level <= ctx->log.sys_log_level)) { + syslog((level - 1), "%s%s", header, footer); } +#endif + } - if (!client) { - client = GF_CALLOC (1, sizeof (*client), - gf_common_mt_client_log); - if (!client) - return NULL; + /* TODO: Plugin in memory log buffer retention here. For logs not + * flushed during cores, it would be useful to retain some of the last + * few messages in memory */ + pthread_mutex_unlock(&ctx->log.logfile_mutex); + ret = 0; - client_log_init (client, identifier); +err: + GF_FREE(header); + GF_FREE(footer); + + return ret; +} + +static int +gf_syslog_log_repetitions(const char *domain, const char *file, + const char *function, int32_t line, + gf_loglevel_t level, int errnum, uint64_t msgid, + char **appmsgstr, char *callstr, int refcount, + struct timeval oldest, struct timeval latest, + int graph_id) +{ + int priority; + char timestr_latest[GF_TIMESTR_SIZE] = { + 0, + }; + char timestr_oldest[GF_TIMESTR_SIZE] = { + 0, + }; + + SET_LOG_PRIO(level, priority); + + gf_time_fmt_tv(timestr_latest, sizeof timestr_latest, &latest, + gf_timefmt_FT); + gf_time_fmt_tv(timestr_oldest, sizeof timestr_oldest, &oldest, + gf_timefmt_FT); + + if (errnum) { + syslog(priority, + "The message \"[MSGID: %" PRIu64 + "] [%s:%d:%s] " + "%d-%s: %s [%s] \" repeated %d times between %s" + " and %s", + msgid, file, line, function, graph_id, domain, *appmsgstr, + strerror(errnum), refcount, timestr_oldest, timestr_latest); + } else { + syslog(priority, + "The message \"[MSGID: %" PRIu64 + "] [%s:%d:%s] " + "%d-%s: %s \" repeated %d times between %s" + " and %s", + msgid, file, line, function, graph_id, domain, *appmsgstr, + refcount, timestr_oldest, timestr_latest); + } + return 0; +} - list_add_tail (&client->list, &client_logs->list); +static int +gf_glusterlog_log_repetitions(glusterfs_ctx_t *ctx, const char *domain, + const char *file, const char *function, + int32_t line, gf_loglevel_t level, int errnum, + uint64_t msgid, char **appmsgstr, char *callstr, + int refcount, struct timeval oldest, + struct timeval latest, int graph_id) +{ + int ret = 0; + char timestr_latest[GF_TIMESTR_SIZE] = { + 0, + }; + char timestr_oldest[GF_TIMESTR_SIZE] = { + 0, + }; + char errstr[256] = { + 0, + }; + char *header = NULL; + char *footer = NULL; + + if (!ctx) + goto err; + + gf_log_rotate(ctx); + + ret = gf_asprintf(&header, + "The message \"%c [MSGID: %" PRIu64 + "]" + " [%s:%d:%s] %d-%s: %s", + gf_level_strings[level], msgid, file, line, function, + graph_id, domain, *appmsgstr); + if (-1 == ret) { + goto err; + } + + gf_time_fmt_tv(timestr_latest, sizeof timestr_latest, &latest, + gf_timefmt_FT); + + gf_time_fmt_tv(timestr_oldest, sizeof timestr_oldest, &oldest, + gf_timefmt_FT); + + if (errnum) + snprintf(errstr, sizeof(errstr) - 1, " [%s]", strerror(errnum)); + + ret = gf_asprintf(&footer, "%s\" repeated %d times between [%s] and [%s]", + errstr, refcount, timestr_oldest, timestr_latest); + if (-1 == ret) { + ret = -1; + goto err; + } + + pthread_mutex_lock(&ctx->log.logfile_mutex); + { + if (ctx->log.logfile) { + fprintf(ctx->log.logfile, "%s%s\n", header, footer); + fflush(ctx->log.logfile); + } else if (ctx->log.loglevel >= level) { + fprintf(stderr, "%s%s\n", header, footer); + fflush(stderr); } - return client->file; +#ifdef GF_LINUX_HOST_OS + /* We want only serious logs in 'syslog', not our debug + * and trace logs */ + if (ctx->log.gf_log_syslog && level && + (level <= ctx->log.sys_log_level)) + syslog((level - 1), "%s%s\n", header, footer); +#endif + } + + /* TODO: Plugin in memory log buffer retention here. For logs not + * flushed during cores, it would be useful to retain some of the last + * few messages in memory */ + pthread_mutex_unlock(&ctx->log.logfile_mutex); + ret = 0; + +err: + GF_FREE(header); + GF_FREE(footer); + + return ret; +} + +static int +gf_log_print_with_repetitions(glusterfs_ctx_t *ctx, const char *domain, + const char *file, const char *function, + int32_t line, gf_loglevel_t level, int errnum, + uint64_t msgid, char **appmsgstr, char *callstr, + int refcount, struct timeval oldest, + struct timeval latest, int graph_id) +{ + int ret = -1; + gf_log_logger_t logger = ctx->log.logger; + + switch (logger) { + case gf_logger_syslog: + if (ctx->log.log_control_file_found && ctx->log.gf_log_syslog) { + ret = gf_syslog_log_repetitions( + domain, file, function, line, level, errnum, msgid, + appmsgstr, callstr, refcount, oldest, latest, graph_id); + break; + } + /* NOTE: If syslog control file is absent, which is another + * way to control logging to syslog, then we will fall through + * to the gluster log. The ideal way to do things would be to + * not have the extra control file check */ + + case gf_logger_glusterlog: + ret = gf_glusterlog_log_repetitions( + ctx, domain, file, function, line, level, errnum, msgid, + appmsgstr, callstr, refcount, oldest, latest, graph_id); + break; + } + + return ret; +} + +static int +gf_log_print_plain_fmt(glusterfs_ctx_t *ctx, const char *domain, + const char *file, const char *function, int32_t line, + gf_loglevel_t level, int errnum, uint64_t msgid, + char **appmsgstr, char *callstr, struct timeval tv, + int graph_id, gf_log_format_t fmt) +{ + int ret = -1; + gf_log_logger_t logger = 0; + + logger = ctx->log.logger; + + /* log to the configured logging service */ + switch (logger) { + case gf_logger_syslog: + if (ctx->log.log_control_file_found && ctx->log.gf_log_syslog) { + ret = gf_log_syslog(ctx, domain, file, function, line, level, + errnum, msgid, appmsgstr, callstr, graph_id, + fmt); + break; + } + /* NOTE: If syslog control file is absent, which is another + * way to control logging to syslog, then we will fall through + * to the gluster log. The ideal way to do things would be to + * not have the extra control file check */ + case gf_logger_glusterlog: + ret = gf_log_glusterlog(ctx, domain, file, function, line, level, + errnum, msgid, appmsgstr, callstr, tv, + graph_id, fmt); + break; + } + + return ret; +} + +void +gf_log_flush_message(log_buf_t *buf, glusterfs_ctx_t *ctx) +{ + if (buf->refcount == 1) { + (void)gf_log_print_plain_fmt(ctx, buf->domain, buf->file, buf->function, + buf->line, buf->level, buf->errnum, + buf->msg_id, &buf->msg, NULL, buf->latest, + buf->graph_id, gf_logformat_withmsgid); + } + + if (buf->refcount > 1) { + gf_log_print_with_repetitions( + ctx, buf->domain, buf->file, buf->function, buf->line, buf->level, + buf->errnum, buf->msg_id, &buf->msg, NULL, buf->refcount, + buf->oldest, buf->latest, buf->graph_id); + } + return; } +static void +gf_log_flush_list(struct list_head *copy, glusterfs_ctx_t *ctx) +{ + log_buf_t *iter = NULL; + log_buf_t *tmp = NULL; + + list_for_each_entry_safe(iter, tmp, copy, msg_list) + { + gf_log_flush_message(iter, ctx); + list_del_init(&iter->msg_list); + log_buf_destroy(iter); + } +} + +void +gf_log_flush_msgs(glusterfs_ctx_t *ctx) +{ + struct list_head copy; + + INIT_LIST_HEAD(©); + + pthread_mutex_lock(&ctx->log.log_buf_lock); + { + list_splice_init(&ctx->log.lru_queue, ©); + ctx->log.lru_cur_size = 0; + } + pthread_mutex_unlock(&ctx->log.log_buf_lock); + + gf_log_flush_list(©, ctx); + + return; +} + +static void +gf_log_flush_extra_msgs(glusterfs_ctx_t *ctx, uint32_t new) +{ + int count = 0; + int i = 0; + log_buf_t *iter = NULL; + log_buf_t *tmp = NULL; + struct list_head copy; + + INIT_LIST_HEAD(©); + + /* If the number of outstanding log messages does not cause list + * overflow even after reducing the size of the list, then do nothing. + * Otherwise (that is if there are more items in the list than there + * need to be after reducing its size), move the least recently used + * 'diff' elements to be flushed into a separate list... + */ + + pthread_mutex_lock(&ctx->log.log_buf_lock); + { + if (ctx->log.lru_cur_size <= new) + goto unlock; + count = ctx->log.lru_cur_size - new; + list_for_each_entry_safe(iter, tmp, &ctx->log.lru_queue, msg_list) + { + if (i == count) + break; + + list_del_init(&iter->msg_list); + list_add_tail(&iter->msg_list, ©); + i++; + } + ctx->log.lru_cur_size = ctx->log.lru_cur_size - count; + } + // ... quickly unlock ... +unlock: + pthread_mutex_unlock(&ctx->log.log_buf_lock); + if (list_empty(©)) + return; + + TEST_LOG( + "Log buffer size reduced. About to flush %d extra log " + "messages", + count); + // ... and then flush them outside the lock. + gf_log_flush_list(©, ctx); + TEST_LOG("Just flushed %d extra log messages", count); + + return; +} + +static int +__gf_log_inject_timer_event(glusterfs_ctx_t *ctx) +{ + int ret = -1; + struct timespec timeout = { + 0, + }; + + if (!ctx) + goto out; + + if (ctx->log.log_flush_timer) { + gf_timer_call_cancel(ctx, ctx->log.log_flush_timer); + ctx->log.log_flush_timer = NULL; + } + + timeout.tv_sec = ctx->log.timeout; + timeout.tv_nsec = 0; + + TEST_LOG("Starting timer now. Timeout = %u, current buf size = %d", + ctx->log.timeout, ctx->log.lru_size); + ctx->log.log_flush_timer = gf_timer_call_after( + ctx, timeout, gf_log_flush_timeout_cbk, (void *)ctx); + if (!ctx->log.log_flush_timer) + goto out; + + ret = 0; + +out: + return ret; +} int -gf_log_from_client (const char *msg, char *identifier) +gf_log_inject_timer_event(glusterfs_ctx_t *ctx) { - FILE *client_log = NULL; + int ret = -1; - client_log = __logfile_for_client (identifier); + if (!ctx) + return -1; - fprintf (client_log, "%s\n", msg); - fflush (client_log); + pthread_mutex_lock(&ctx->log.log_buf_lock); + { + ret = __gf_log_inject_timer_event(ctx); + } + pthread_mutex_unlock(&ctx->log.log_buf_lock); - return 0; + return ret; +} + +void +gf_log_flush_timeout_cbk(void *data) +{ + glusterfs_ctx_t *ctx = NULL; + + ctx = (glusterfs_ctx_t *)data; + + TEST_LOG( + "Log timer timed out. About to flush outstanding messages if " + "present"); + gf_log_flush_msgs(ctx); + + (void)gf_log_inject_timer_event(ctx); + + return; +} + +static int +_gf_msg_internal(const char *domain, const char *file, const char *function, + int32_t line, gf_loglevel_t level, int errnum, uint64_t msgid, + char **appmsgstr, char *callstr, int graph_id) +{ + int ret = -1; + uint32_t size = 0; + const char *basename = NULL; + xlator_t *this = NULL; + glusterfs_ctx_t *ctx = NULL; + log_buf_t *iter = NULL; + log_buf_t *buf_tmp = NULL; + log_buf_t *buf_new = NULL; + log_buf_t *first = NULL; + struct timeval tv = { + 0, + }; + gf_boolean_t found = _gf_false; + gf_boolean_t flush_lru = _gf_false; + gf_boolean_t flush_logged_msg = _gf_false; + + this = THIS; + ctx = this->ctx; + + if (!ctx) + goto out; + + GET_FILE_NAME_TO_LOG(file, basename); + + ret = gettimeofday(&tv, NULL); + if (ret) + goto out; + + /* If this function is called via _gf_msg_callingfn () (indicated by a + * non-NULL callstr), or if the logformat is traditional, flush the + * message directly to disk. + */ + + if ((callstr) || (ctx->log.logformat == gf_logformat_traditional)) { + ret = gf_log_print_plain_fmt(ctx, domain, basename, function, line, + level, errnum, msgid, appmsgstr, callstr, + tv, graph_id, gf_logformat_traditional); + goto out; + } + + pthread_mutex_lock(&ctx->log.log_buf_lock); + { + /* Check if the msg being logged is already part of the list */ + list_for_each_entry_safe_reverse(iter, buf_tmp, &ctx->log.lru_queue, + msg_list) + { + if (first == NULL) + // Remember the first (lru) element in first ptr + first = iter; + + /* Try to fail the search early on by doing the less + * expensive integer comparisons and continue to string + * parameter comparisons only after all int parameters + * are found to be matching. + */ + if (line != iter->line) + continue; + + if (errnum != iter->errnum) + continue; + + if (msgid != iter->msg_id) + continue; + + if (level != iter->level) + continue; + + if (graph_id != iter->graph_id) + continue; + + if (strcmp(domain, iter->domain)) + continue; + + if (strcmp(basename, iter->file)) + continue; + + if (strcmp(function, iter->function)) + continue; + + if (strcmp(*appmsgstr, iter->msg)) + continue; + + // Ah! Found a match! + list_move_tail(&iter->msg_list, &ctx->log.lru_queue); + iter->refcount++; + found = _gf_true; + // Update the 'latest' timestamp. + memcpy((void *)&(iter->latest), (void *)&tv, + sizeof(struct timeval)); + break; + } + if (found) { + ret = 0; + goto unlock; + } + // else ... + + size = ctx->log.lru_size; + /* If the upper limit on the log buf size is 0, flush the msg to + * disk directly after unlock. There's no need to buffer the + * msg here. + */ + if (size == 0) { + flush_logged_msg = _gf_true; + goto unlock; + } else if (((ctx->log.lru_cur_size + 1) > size) && (first)) { + /* If the list is full, flush the lru msg to disk and also + * release it after unlock, and ... + * */ + if (first->refcount >= 1) + TEST_LOG( + "Buffer overflow of a buffer whose size limit " + "is %d. About to flush least recently used log" + " message to disk", + size); + list_del_init(&first->msg_list); + ctx->log.lru_cur_size--; + flush_lru = _gf_true; + } + /* create a new list element, initialise and enqueue it. + * Additionally, this being the first occurrence of the msg, + * log it directly to disk after unlock. */ + buf_new = mem_get0(THIS->ctx->logbuf_pool); + if (!buf_new) { + ret = -1; + goto unlock; + } + ret = log_buf_init(buf_new, domain, basename, function, line, level, + errnum, msgid, appmsgstr, graph_id); + if (ret) { + log_buf_destroy(buf_new); + goto unlock; + } + + memcpy((void *)&(buf_new->latest), (void *)&tv, sizeof(struct timeval)); + memcpy((void *)&(buf_new->oldest), (void *)&tv, sizeof(struct timeval)); + + list_add_tail(&buf_new->msg_list, &ctx->log.lru_queue); + ctx->log.lru_cur_size++; + flush_logged_msg = _gf_true; + ret = 0; + } +unlock: + pthread_mutex_unlock(&ctx->log.log_buf_lock); + + /* Value of @ret is a don't-care below since irrespective of success or + * failure post setting of @flush_lru, @first must be flushed and freed. + */ + if (flush_lru) { + gf_log_flush_message(first, ctx); + log_buf_destroy(first); + } + /* Similarly, irrespective of whether all operations since setting of + * @flush_logged_msg were successful or not, flush the message being + * logged to disk in the plain format. + */ + if (flush_logged_msg) { + ret = gf_log_print_plain_fmt(ctx, domain, basename, function, line, + level, errnum, msgid, appmsgstr, callstr, + tv, graph_id, gf_logformat_withmsgid); + } + +out: + return ret; } int -gf_cmd_log_init (const char *filename) +_gf_msg(const char *domain, const char *file, const char *function, + int32_t line, gf_loglevel_t level, int errnum, int trace, + uint64_t msgid, const char *fmt, ...) { - if (!filename){ - gf_log ("glusterd",GF_LOG_CRITICAL, "gf_cmd_log_init: no " - "filename specified\n"); + int ret = 0; + char *msgstr = NULL; + va_list ap; + xlator_t *this = THIS; + glusterfs_ctx_t *ctx = NULL; + char *callstr = NULL; + int log_inited = 0; + + if (this == NULL) + return -1; + + ctx = this->ctx; + if (ctx == NULL) { + /* messages before context initialization are ignored */ + return -1; + } + + /* check if we should be logging */ + if (skip_logging(this, level)) + goto out; + + /* in args check */ + if (!domain || !file || !function || !fmt) { + fprintf(stderr, "logging: %s:%s():%d: invalid argument\n", __FILE__, + __PRETTY_FUNCTION__, __LINE__); + return -1; + } + + /* form the message */ + va_start(ap, fmt); + ret = vasprintf(&msgstr, fmt, ap); + va_end(ap); + + /* log */ + if (ret != -1) { + if (trace) { + callstr = GF_MALLOC(GF_LOG_BACKTRACE_SIZE, gf_common_mt_char); + if (callstr == NULL) return -1; + + ret = _gf_msg_backtrace(GF_LOG_BACKTRACE_DEPTH, callstr, + GF_LOG_BACKTRACE_SIZE); + if (ret < 0) { + GF_FREE(callstr); + callstr = NULL; + } } - cmd_log_filename = gf_strdup (filename); - if (!filename) { - gf_log ("glusterd",GF_LOG_CRITICAL, "gf_cmd_log_init: strdup" - " error\n"); - return -1; + pthread_mutex_lock(&ctx->log.logfile_mutex); + { + if (ctx->log.logfile) { + log_inited = 1; + } } + pthread_mutex_unlock(&ctx->log.logfile_mutex); + + if (!log_inited && ctx->log.gf_log_syslog) { + ret = gf_log_syslog( + ctx, domain, file, function, line, level, errnum, msgid, + &msgstr, (callstr ? callstr : NULL), + (this->graph) ? this->graph->id : 0, gf_logformat_traditional); + } else { + ret = _gf_msg_internal(domain, file, function, line, level, errnum, + msgid, &msgstr, (callstr ? callstr : NULL), + (this->graph) ? this->graph->id : 0); + } + } else { + /* man (3) vasprintf states on error strp contents + * are undefined, be safe */ + msgstr = NULL; + } + if (callstr) + GF_FREE(callstr); + FREE(msgstr); - cmdlogfile = fopen (cmd_log_filename, "a"); - if (!cmdlogfile){ - gf_log ("glusterd", GF_LOG_CRITICAL, - "gf_cmd_log_init: failed to open logfile \"%s\" " - "(%s)\n", cmd_log_filename, strerror (errno)); - return -1; +out: + return ret; +} + +/* TODO: Deprecate (delete) _gf_log, _gf_log_callingfn, + * once messages are changed to use _gf_msgXXX APIs for logging */ +int +_gf_log(const char *domain, const char *file, const char *function, int line, + gf_loglevel_t level, const char *fmt, ...) +{ + const char *basename = NULL; + FILE *new_logfile = NULL; + va_list ap; + char timestr[GF_TIMESTR_SIZE] = { + 0, + }; + struct timeval tv = { + 0, + }; + char *logline = NULL; + char *msg = NULL; + int ret = 0; + int fd = -1; + xlator_t *this = THIS; + glusterfs_ctx_t *ctx = this->ctx; + + if (!ctx) + goto out; + + if (skip_logging(this, level)) + goto out; + + if (!domain || !file || !function || !fmt) { + fprintf(stderr, "logging: %s:%s():%d: invalid argument\n", __FILE__, + __PRETTY_FUNCTION__, __LINE__); + return -1; + } + + basename = strrchr(file, '/'); + if (basename) + basename++; + else + basename = file; + + va_start(ap, fmt); + ret = vasprintf(&msg, fmt, ap); + va_end(ap); + if (-1 == ret) { + goto err; + } + + 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; } - return 0; + + gf_syslog(priority, "[%s:%d:%s] %d-%s: %s", basename, line, function, + ((this->graph) ? this->graph->id : 0), domain, msg); + goto err; + } + + if (ctx->log.logrotate) { + ctx->log.logrotate = 0; + + fd = sys_open(ctx->log.filename, O_CREAT | O_RDONLY, S_IRUSR | S_IWUSR); + if (fd < 0) { + gf_smsg("logrotate", GF_LOG_ERROR, errno, + LG_MSG_OPEN_LOGFILE_FAILED, NULL); + return -1; + } + sys_close(fd); + + new_logfile = fopen(ctx->log.filename, "a"); + if (!new_logfile) { + gf_smsg("logrotate", GF_LOG_CRITICAL, errno, + LG_MSG_OPEN_LOGFILE_FAILED, "filename=%s", + ctx->log.filename, NULL); + goto log; + } + + pthread_mutex_lock(&ctx->log.logfile_mutex); + { + if (ctx->log.logfile) + fclose(ctx->log.logfile); + + ctx->log.gf_log_logfile = ctx->log.logfile = new_logfile; + } + pthread_mutex_unlock(&ctx->log.logfile_mutex); + } + +log: + ret = gettimeofday(&tv, NULL); + if (-1 == ret) + goto out; + + gf_time_fmt_tv(timestr, sizeof timestr, &tv, gf_timefmt_FT); + + ret = gf_asprintf(&logline, "[%s] %c [%s:%d:%s] %d-%s: %s\n", timestr, + gf_level_strings[level], basename, line, function, + ((this->graph) ? this->graph->id : 0), domain, msg); + if (-1 == ret) { + goto err; + } + + pthread_mutex_lock(&ctx->log.logfile_mutex); + { + if (ctx->log.logfile) { + fputs(logline, ctx->log.logfile); + fflush(ctx->log.logfile); + } else if (ctx->log.loglevel >= level) { + fputs(logline, stderr); + fflush(stderr); + } + +#ifdef GF_LINUX_HOST_OS + /* We want only serious log in 'syslog', not our debug + and trace logs */ + if (ctx->log.gf_log_syslog && level && + (level <= ctx->log.sys_log_level)) + syslog((level - 1), "%s", logline); +#endif + } + + pthread_mutex_unlock(&ctx->log.logfile_mutex); + +err: + GF_FREE(logline); + + FREE(msg); + +out: + return (0); } int -gf_cmd_log (const char *domain, const char *fmt, ...) -{ - va_list ap; - struct tm *tm = NULL; - char timestr[256]; - struct timeval tv = {0,}; - char *str1 = NULL; - char *str2 = NULL; - char *msg = NULL; - size_t len = 0; - int ret = 0; - - if (!cmdlogfile) - return -1; +_gf_log_eh(const char *function, const char *fmt, ...) +{ + int ret = -1; + va_list ap; + char *logline = NULL; + char *msg = NULL; + xlator_t *this = NULL; + this = THIS; - if (!domain || !fmt) { - gf_log ("glusterd", GF_LOG_TRACE, - "logging: invalid argument\n"); - return -1; + va_start(ap, fmt); + ret = vasprintf(&msg, fmt, ap); + va_end(ap); + if (-1 == ret) { + goto out; + } + + ret = gf_asprintf(&logline, "[%d] %s: %s", + ((this->graph) ? this->graph->id : 0), function, msg); + if (-1 == ret) { + goto out; + } + + ret = eh_save_history(this->history, logline); + +out: + GF_FREE(logline); + + FREE(msg); + + return ret; +} + +int +gf_cmd_log_init(const char *filename) +{ + int fd = -1; + xlator_t *this = NULL; + glusterfs_ctx_t *ctx = NULL; + + this = THIS; + ctx = this->ctx; + + if (!ctx) + return -1; + + if (!filename) { + gf_smsg(this->name, GF_LOG_CRITICAL, 0, LG_MSG_FILENAME_NOT_SPECIFIED, + "gf_cmd_log_init", NULL); + return -1; + } + + ctx->log.cmd_log_filename = gf_strdup(filename); + if (!ctx->log.cmd_log_filename) { + return -1; + } + /* close and reopen cmdlogfile for log rotate*/ + if (ctx->log.cmdlogfile) { + fclose(ctx->log.cmdlogfile); + ctx->log.cmdlogfile = NULL; + } + + fd = sys_open(ctx->log.cmd_log_filename, O_CREAT | O_WRONLY | O_APPEND, + S_IRUSR | S_IWUSR); + if (fd < 0) { + gf_smsg(this->name, GF_LOG_CRITICAL, errno, LG_MSG_OPEN_LOGFILE_FAILED, + "cmd_log_file", NULL); + return -1; + } + + ctx->log.cmdlogfile = fdopen(fd, "a"); + if (!ctx->log.cmdlogfile) { + gf_smsg(this->name, GF_LOG_CRITICAL, errno, LG_MSG_OPEN_LOGFILE_FAILED, + "gf_cmd_log_init: %s", ctx->log.cmd_log_filename, NULL); + sys_close(fd); + return -1; + } + return 0; +} + +int +gf_cmd_log(const char *domain, const char *fmt, ...) +{ + va_list ap; + char timestr[GF_TIMESTR_SIZE]; + struct timeval tv = { + 0, + }; + char *logline = NULL; + char *msg = NULL; + int ret = 0; + int fd = -1; + glusterfs_ctx_t *ctx = NULL; + + ctx = THIS->ctx; + + if (!ctx) + return -1; + + if (!ctx->log.cmdlogfile) + return -1; + + if (!domain || !fmt) { + gf_msg_trace("glusterd", 0, "logging: invalid argument\n"); + return -1; + } + + ret = gettimeofday(&tv, NULL); + if (ret == -1) + goto out; + va_start(ap, fmt); + ret = vasprintf(&msg, fmt, ap); + va_end(ap); + if (ret == -1) { + goto out; + } + + gf_time_fmt_tv(timestr, sizeof timestr, &tv, gf_timefmt_FT); + + ret = gf_asprintf(&logline, "[%s] %s : %s\n", timestr, domain, msg); + if (ret == -1) { + goto out; + } + + /* close and reopen cmdlogfile fd for in case of log rotate*/ + if (ctx->log.cmd_history_logrotate) { + ctx->log.cmd_history_logrotate = 0; + + if (ctx->log.cmdlogfile) { + fclose(ctx->log.cmdlogfile); + ctx->log.cmdlogfile = NULL; } - ret = gettimeofday (&tv, NULL); - if (ret == -1) - goto out; + fd = sys_open(ctx->log.cmd_log_filename, O_CREAT | O_WRONLY | O_APPEND, + S_IRUSR | S_IWUSR); + if (fd < 0) { + gf_smsg(THIS->name, GF_LOG_CRITICAL, errno, + LG_MSG_OPEN_LOGFILE_FAILED, "name=%s", + ctx->log.cmd_log_filename, NULL); + ret = -1; + goto out; + } + + ctx->log.cmdlogfile = fdopen(fd, "a"); + if (!ctx->log.cmdlogfile) { + gf_smsg(THIS->name, GF_LOG_CRITICAL, errno, + LG_MSG_OPEN_LOGFILE_FAILED, "name=%s", + ctx->log.cmd_log_filename, NULL); + ret = -1; + sys_close(fd); + goto out; + } + } + + fputs(logline, ctx->log.cmdlogfile); + fflush(ctx->log.cmdlogfile); + +out: + GF_FREE(logline); - tm = localtime (&tv.tv_sec); + FREE(msg); - va_start (ap, fmt); - strftime (timestr, 256, "%Y-%m-%d %H:%M:%S", tm); - snprintf (timestr + strlen (timestr), 256 - strlen (timestr), - ".%"GF_PRI_SUSECONDS, tv.tv_usec); + return ret; +} - ret = gf_asprintf (&str1, "[%s] %s : ", - timestr, domain); - if (ret == -1) { - goto out; +static int +_do_slog_format(int errnum, const char *event, va_list inp, char **msg) +{ + va_list valist_tmp; + int i = 0; + int j = 0; + int k = 0; + int ret = 0; + char *fmt = NULL; + char *buffer = NULL; + int num_format_chars = 0; + char format_char = '%'; + char *tmp1 = NULL; + char *tmp2 = NULL; + char temp_sep[3] = ""; + + tmp2 = gf_strdup(""); + if (!tmp2) { + ret = -1; + goto out; + } + + /* Hardcoded value for max key value pairs, exits early */ + /* from loop if found NULL */ + for (i = 0; i < GF_MAX_SLOG_PAIR_COUNT; i++) { + fmt = va_arg(inp, char *); + if (fmt == NULL) { + break; } - ret = vasprintf (&str2, fmt, ap); - if (ret == -1) { - goto out; + /* Get number of times % is used in input for formatting, */ + /* this count will be used to skip those many args from the */ + /* main list and will be used to format inner format */ + num_format_chars = 0; + for (k = 0; fmt[k] != '\0'; k++) { + /* If %% is used then that is escaped */ + if (fmt[k] == format_char && fmt[k + 1] == format_char) { + k++; + } else if (fmt[k] == format_char) { + num_format_chars++; + } } - va_end (ap); + tmp1 = gf_strdup(tmp2); + if (!tmp1) { + ret = -1; + goto out; + } - len = strlen (str1); - msg = GF_MALLOC (len + strlen (str2) + 1, gf_common_mt_char); + GF_FREE(tmp2); + tmp2 = NULL; - strcpy (msg, str1); - strcpy (msg + len, str2); + if (num_format_chars > 0) { + /* Make separate valist and format the string */ + va_copy(valist_tmp, inp); + ret = gf_vasprintf(&buffer, fmt, valist_tmp); + if (ret < 0) { + va_end(valist_tmp); + goto out; + } + va_end(valist_tmp); - fprintf (cmdlogfile, "%s\n", msg); - fflush (cmdlogfile); + for (j = 0; j < num_format_chars; j++) { + /* Skip the va_arg value since these values + are already used for internal formatting */ + (void)va_arg(inp, void *); + } -out: - if (msg) { - GF_FREE (msg); + ret = gf_asprintf(&tmp2, "%s%s{%s}", tmp1, temp_sep, buffer); + if (ret < 0) + goto out; + + GF_FREE(buffer); + buffer = NULL; + } else { + ret = gf_asprintf(&tmp2, "%s%s{%s}", tmp1, temp_sep, fmt); + if (ret < 0) + goto out; } - if (str1) - GF_FREE (str1); + /* Set seperator for next iteration */ + temp_sep[0] = ','; + temp_sep[1] = ' '; + temp_sep[2] = 0; + + GF_FREE(tmp1); + tmp1 = NULL; + } + + tmp1 = gf_strdup(tmp2); + if (!tmp1) { + ret = -1; + goto out; + } + GF_FREE(tmp2); + tmp2 = NULL; + + if (errnum) { + ret = gf_asprintf(&tmp2, "%s [%s%s{errno=%d}, {error=%s}]", event, tmp1, + temp_sep, errnum, strerror(errnum)); + } else { + ret = gf_asprintf(&tmp2, "%s [%s]", event, tmp1); + } + + if (ret == -1) + goto out; + + *msg = gf_strdup(tmp2); + if (!*msg) + ret = -1; + +out: + if (buffer) + GF_FREE(buffer); - if (str2) - FREE (str2); + if (tmp1) + GF_FREE(tmp1); - return (0); - + if (tmp2) + GF_FREE(tmp2); + + return ret; +} + +int +_gf_smsg(const char *domain, const char *file, const char *function, + int32_t line, gf_loglevel_t level, int errnum, int trace, + uint64_t msgid, const char *event, ...) +{ + va_list valist; + char *msg = NULL; + int ret = 0; + xlator_t *this = THIS; + + if (skip_logging(this, level)) + return ret; + + va_start(valist, event); + ret = _do_slog_format(errnum, event, valist, &msg); + if (ret == -1) + goto out; + + /* Pass errnum as zero since it is already formated as required */ + ret = _gf_msg(domain, file, function, line, level, 0, trace, msgid, "%s", + msg); + +out: + va_end(valist); + if (msg) + GF_FREE(msg); + return ret; } diff --git a/libglusterfs/src/logging.h b/libglusterfs/src/logging.h deleted file mode 100644 index e440d597549..00000000000 --- a/libglusterfs/src/logging.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - Copyright (c) 2006-2010 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - - -#ifndef __LOGGING_H__ -#define __LOGGING_H__ - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include <stdint.h> -#include <stdio.h> -#include <stdarg.h> - -#ifdef GF_DARWIN_HOST_OS -#define GF_PRI_FSBLK "u" -#define GF_PRI_DEV PRId32 -#define GF_PRI_NLINK PRIu16 -#define GF_PRI_SUSECONDS PRId32 -#else -#define GF_PRI_FSBLK PRIu64 -#define GF_PRI_DEV PRIu64 -#define GF_PRI_NLINK PRIu32 -#define GF_PRI_SUSECONDS "ld" -#endif -#define GF_PRI_BLKSIZE PRId32 -#define GF_PRI_SIZET "zu" - -#if 0 -/* Syslog definitions :-) */ -#define LOG_EMERG 0 /* system is unusable */ -#define LOG_ALERT 1 /* action must be taken immediately */ -#define LOG_CRIT 2 /* critical conditions */ -#define LOG_ERR 3 /* error conditions */ -#define LOG_WARNING 4 /* warning conditions */ -#define LOG_NOTICE 5 /* normal but significant condition */ -#define LOG_INFO 6 /* informational */ -#define LOG_DEBUG 7 /* debug-level messages */ -#endif - -typedef enum { - GF_LOG_NONE, - GF_LOG_EMERG, - GF_LOG_ALERT, - GF_LOG_CRITICAL, /* fatal errors */ - GF_LOG_ERROR, /* major failures (not necessarily fatal) */ - GF_LOG_WARNING, /* info about normal operation */ - GF_LOG_NOTICE, - GF_LOG_INFO, /* Normal information */ -#define GF_LOG_NORMAL GF_LOG_INFO - GF_LOG_DEBUG, /* internal errors */ - GF_LOG_TRACE, /* full trace of operation */ -} gf_loglevel_t; - -#define GF_LOG_MAX GF_LOG_DEBUG - -extern gf_loglevel_t gf_log_loglevel; -extern char gf_log_xl_log_set; - -#define gf_log(dom, levl, fmt...) do { \ - if ((levl > gf_log_loglevel) && !gf_log_xl_log_set) \ - break; \ - _gf_log (dom, __FILE__, __FUNCTION__, __LINE__, \ - levl, ##fmt); \ - } while (0) - -/* Log once in GF_UNIVERSAL_ANSWER times */ -#define GF_LOG_OCCASIONALLY(var, args...) if (!(var++%GF_UNIVERSAL_ANSWER)) { \ - gf_log (args); \ - } - - -void -gf_log_logrotate (int signum); - -int gf_log_init (const char *filename); -void gf_log_cleanup (void); - -int -_gf_log (const char *domain, const char *file, const char *function, - int32_t line, gf_loglevel_t level, const char *fmt, ...); - -int -gf_log_from_client (const char *msg, char *identifier); - -void gf_log_lock (void); -void gf_log_unlock (void); - -void gf_log_disable_syslog (void); -void gf_log_enable_syslog (void); -gf_loglevel_t gf_log_get_loglevel (void); -void gf_log_set_loglevel (gf_loglevel_t level); -gf_loglevel_t gf_log_get_xl_loglevel (void *xl); -void gf_log_set_xl_loglevel (void *xl, gf_loglevel_t level); - -#define GF_DEBUG(xl, format, args...) \ - gf_log ((xl)->name, GF_LOG_DEBUG, format, ##args) -#define GF_INFO(xl, format, args...) \ - gf_log ((xl)->name, GF_LOG_INFO, format, ##args) -#define GF_WARNING(xl, format, args...) \ - gf_log ((xl)->name, GF_LOG_WARNING, format, ##args) -#define GF_ERROR(xl, format, args...) \ - gf_log ((xl)->name, GF_LOG_ERROR, format, ##args) - -int -gf_cmd_log (const char *domain, const char *fmt, ...); - -int -gf_cmd_log_init (const char *filename); -#endif /* __LOGGING_H__ */ diff --git a/libglusterfs/src/mem-pool.c b/libglusterfs/src/mem-pool.c index aec1d909dde..2d5a12b0a00 100644 --- a/libglusterfs/src/mem-pool.c +++ b/libglusterfs/src/mem-pool.c @@ -1,517 +1,932 @@ /* - Copyright (c) 2008-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. */ -#include "mem-pool.h" -#include "logging.h" -#include "xlator.h" +#include "glusterfs/mem-pool.h" +#include "glusterfs/common-utils.h" // for GF_ASSERT, gf_thread_cr... +#include "glusterfs/globals.h" // for xlator_t, THIS #include <stdlib.h> #include <stdarg.h> +#include "unittest/unittest.h" +#include "glusterfs/libglusterfs-messages.h" -#define GF_MEM_POOL_PAD_BOUNDARY (sizeof(struct list_head)) -#define mem_pool_chunkhead2ptr(head) ((head) + GF_MEM_POOL_PAD_BOUNDARY) -#define mem_pool_ptr2chunkhead(ptr) ((ptr) - GF_MEM_POOL_PAD_BOUNDARY) +void +gf_mem_acct_enable_set(void *data) +{ + glusterfs_ctx_t *ctx = NULL; -#define GF_MEM_HEADER_SIZE (4 + sizeof (size_t) + sizeof (xlator_t *) + 4) -#define GF_MEM_TRAILER_SIZE 4 + REQUIRE(data != NULL); -#define GF_MEM_HEADER_MAGIC 0xCAFEBABE -#define GF_MEM_TRAILER_MAGIC 0xBAADF00D + ctx = data; -#define GLUSTERFS_ENV_MEM_ACCT_STR "GLUSTERFS_DISABLE_MEM_ACCT" + GF_ASSERT(ctx != NULL); -static int gf_mem_acct_enable = 1; + ctx->mem_acct_enable = 1; -int -gf_mem_acct_is_enabled () -{ - return gf_mem_acct_enable; + ENSURE(1 == ctx->mem_acct_enable); + + return; } -void -gf_mem_acct_enable_set () +static void * +gf_mem_header_prepare(struct mem_header *header, size_t size) { - char *opt = NULL; - long val = -1; + void *ptr; - opt = getenv (GLUSTERFS_ENV_MEM_ACCT_STR); + header->size = size; - if (!opt) - return; + ptr = header + 1; - val = strtol (opt, NULL, 0); - - if (val) - gf_mem_acct_enable = 0; - else - gf_mem_acct_enable = 1; + /* data follows in this gap of 'size' bytes */ + *(uint32_t *)(ptr + size) = GF_MEM_TRAILER_MAGIC; + return ptr; } -void -gf_mem_set_acct_info (xlator_t *xl, char **alloc_ptr, - size_t size, uint32_t type) +static void * +gf_mem_set_acct_info(struct mem_acct *mem_acct, struct mem_header *header, + size_t size, uint32_t type, const char *typestr) { + struct mem_acct_rec *rec = NULL; + bool new_ref = false; - char *ptr = NULL; - - if (!alloc_ptr) - return; + if (mem_acct != NULL) { + GF_ASSERT(type <= mem_acct->num_types); - ptr = (char *) (*alloc_ptr); - - if (!xl) { - assert (0); + rec = &mem_acct->rec[type]; + LOCK(&rec->lock); + { + if (!rec->typestr) { + rec->typestr = typestr; + } + rec->size += size; + new_ref = (rec->num_allocs == 0); + rec->num_allocs++; + rec->total_allocs++; + rec->max_size = max(rec->max_size, rec->size); + rec->max_num_allocs = max(rec->max_num_allocs, rec->num_allocs); + +#ifdef DEBUG + list_add(&header->acct_list, &rec->obj_list); +#endif } + UNLOCK(&rec->lock); - if (!(xl->mem_acct.rec)) { - assert (0); + /* We only take a reference for each memory type used, not for each + * allocation. This minimizes the use of atomic operations. */ + if (new_ref) { + GF_ATOMIC_INC(mem_acct->refcnt); } + } - if (type > xl->mem_acct.num_types) { - assert (0); - } + header->type = type; + header->mem_acct = mem_acct; + header->magic = GF_MEM_HEADER_MAGIC; - LOCK(&xl->mem_acct.rec[type].lock); + return gf_mem_header_prepare(header, size); +} + +static void * +gf_mem_update_acct_info(struct mem_acct *mem_acct, struct mem_header *header, + size_t size) +{ + struct mem_acct_rec *rec = NULL; + + if (mem_acct != NULL) { + rec = &mem_acct->rec[header->type]; + LOCK(&rec->lock); { - xl->mem_acct.rec[type].size += size; - xl->mem_acct.rec[type].num_allocs++; - xl->mem_acct.rec[type].max_size = - max (xl->mem_acct.rec[type].max_size, - xl->mem_acct.rec[type].size); - xl->mem_acct.rec[type].max_num_allocs = - max (xl->mem_acct.rec[type].max_num_allocs, - xl->mem_acct.rec[type].num_allocs); + rec->size += size - header->size; + rec->total_allocs++; + rec->max_size = max(rec->max_size, rec->size); + +#ifdef DEBUG + /* The old 'header' already was present in 'obj_list', but + * realloc() could have changed its address. We need to remove + * the old item from the list and add the new one. This can be + * done this way because list_move() doesn't use the pointers + * to the old location (which are not valid anymore) already + * present in the list, it simply overwrites them. */ + list_move(&header->acct_list, &rec->obj_list); +#endif } - UNLOCK(&xl->mem_acct.rec[type].lock); - - *(uint32_t *)(ptr) = type; - ptr = ptr + 4; - memcpy (ptr, &size, sizeof(size_t)); - ptr += sizeof (size_t); - memcpy (ptr, &xl, sizeof(xlator_t *)); - ptr += sizeof (xlator_t *); - *(uint32_t *)(ptr) = GF_MEM_HEADER_MAGIC; - ptr = ptr + 4; - *(uint32_t *) (ptr + size) = GF_MEM_TRAILER_MAGIC; - - *alloc_ptr = (void *)ptr; - return; + UNLOCK(&rec->lock); + } + + return gf_mem_header_prepare(header, size); } +static bool +gf_mem_acct_enabled(void) +{ + xlator_t *x = THIS; + /* Low-level __gf_xxx() may be called + before ctx is initialized. */ + return x->ctx && x->ctx->mem_acct_enable; +} void * -__gf_calloc (size_t nmemb, size_t size, uint32_t type) +__gf_calloc(size_t nmemb, size_t size, uint32_t type, const char *typestr) { - size_t tot_size = 0; - size_t req_size = 0; - char *ptr = NULL; - xlator_t *xl = NULL; - - if (!gf_mem_acct_enable) - return CALLOC (nmemb, size); + size_t tot_size = 0; + size_t req_size = 0; + void *ptr = NULL; + xlator_t *xl = NULL; - xl = THIS; + if (!gf_mem_acct_enabled()) + return CALLOC(nmemb, size); - req_size = nmemb * size; - tot_size = req_size + GF_MEM_HEADER_SIZE + GF_MEM_TRAILER_SIZE; + xl = THIS; - ptr = calloc (1, tot_size); + req_size = nmemb * size; + tot_size = req_size + GF_MEM_HEADER_SIZE + GF_MEM_TRAILER_SIZE; - if (!ptr) - return NULL; + ptr = calloc(1, tot_size); - gf_mem_set_acct_info (xl, &ptr, req_size, type); + if (!ptr) { + gf_msg_nomem("", GF_LOG_ALERT, tot_size); + return NULL; + } - return (void *)ptr; + return gf_mem_set_acct_info(xl->mem_acct, ptr, req_size, type, typestr); } void * -__gf_malloc (size_t size, uint32_t type) +__gf_malloc(size_t size, uint32_t type, const char *typestr) { - size_t tot_size = 0; - char *ptr = NULL; - xlator_t *xl = NULL; + size_t tot_size = 0; + void *ptr = NULL; + xlator_t *xl = NULL; - if (!gf_mem_acct_enable) - return MALLOC (size); + if (!gf_mem_acct_enabled()) + return MALLOC(size); - xl = THIS; + xl = THIS; - tot_size = size + GF_MEM_HEADER_SIZE + GF_MEM_TRAILER_SIZE; + tot_size = size + GF_MEM_HEADER_SIZE + GF_MEM_TRAILER_SIZE; - ptr = malloc (tot_size); - if (!ptr) - return NULL; + ptr = malloc(tot_size); + if (!ptr) { + gf_msg_nomem("", GF_LOG_ALERT, tot_size); + return NULL; + } - gf_mem_set_acct_info (xl, &ptr, size, type); - - return (void *)ptr; + return gf_mem_set_acct_info(xl->mem_acct, ptr, size, type, typestr); } void * -__gf_realloc (void *ptr, size_t size) +__gf_realloc(void *ptr, size_t size) { - size_t tot_size = 0; - char *orig_ptr = NULL; - xlator_t *xl = NULL; - uint32_t type = 0; + size_t tot_size = 0; + struct mem_header *header = NULL; + if (!gf_mem_acct_enabled()) + return REALLOC(ptr, size); - tot_size = size + GF_MEM_HEADER_SIZE + GF_MEM_TRAILER_SIZE; + REQUIRE(NULL != ptr); - orig_ptr = (char *)ptr - 4; + header = (struct mem_header *)(ptr - GF_MEM_HEADER_SIZE); + GF_ASSERT(header->magic == GF_MEM_HEADER_MAGIC); - assert (*(uint32_t *)orig_ptr == GF_MEM_HEADER_MAGIC); + tot_size = size + GF_MEM_HEADER_SIZE + GF_MEM_TRAILER_SIZE; + header = realloc(header, tot_size); + if (!header) { + gf_msg_nomem("", GF_LOG_ALERT, tot_size); + return NULL; + } - orig_ptr = orig_ptr - sizeof(xlator_t *); - xl = *((xlator_t **)orig_ptr); + return gf_mem_update_acct_info(header->mem_acct, header, size); +} - orig_ptr = (char *)ptr - GF_MEM_HEADER_SIZE; - type = *(uint32_t *)orig_ptr; +int +gf_vasprintf(char **string_ptr, const char *format, va_list arg) +{ + va_list arg_save; + char *str = NULL; + int size = 0; + int rv = 0; + + if (!string_ptr || !format) + return -1; + + va_copy(arg_save, arg); + + size = vsnprintf(NULL, 0, format, arg); + size++; + str = GF_MALLOC(size, gf_common_mt_asprintf); + if (str == NULL) { + /* log is done in GF_MALLOC itself */ + va_end(arg_save); + return -1; + } + rv = vsnprintf(str, size, format, arg_save); + + *string_ptr = str; + va_end(arg_save); + return (rv); +} - ptr = realloc (orig_ptr, tot_size); - if (!ptr) - return NULL; +int +gf_asprintf(char **string_ptr, const char *format, ...) +{ + va_list arg; + int rv = 0; - gf_mem_set_acct_info (xl, (char **)&ptr, size, type); + va_start(arg, format); + rv = gf_vasprintf(string_ptr, format, arg); + va_end(arg); - return (void *)ptr; + return rv; } -int -gf_asprintf (char **string_ptr, const char *format, ...) +#ifdef DEBUG +void +__gf_mem_invalidate(void *ptr) +{ + struct mem_header *header = ptr; + void *end = NULL; + + struct mem_invalid inval = { + .magic = GF_MEM_INVALID_MAGIC, + .mem_acct = header->mem_acct, + .type = header->type, + .size = header->size, + .baseaddr = ptr + GF_MEM_HEADER_SIZE, + }; + + /* calculate the last byte of the allocated area */ + end = ptr + GF_MEM_HEADER_SIZE + inval.size + GF_MEM_TRAILER_SIZE; + + /* overwrite the old mem_header */ + memcpy(ptr, &inval, sizeof(inval)); + ptr += sizeof(inval); + + /* zero out remaining (old) mem_header bytes) */ + memset(ptr, 0x00, sizeof(*header) - sizeof(inval)); + ptr += sizeof(*header) - sizeof(inval); + + /* zero out the first byte of data */ + *(uint32_t *)(ptr) = 0x00; + ptr += 1; + + /* repeated writes of invalid structurein data area */ + while ((ptr + (sizeof(inval))) < (end - 1)) { + memcpy(ptr, &inval, sizeof(inval)); + ptr += sizeof(inval); + } + + /* fill out remaining data area with 0xff */ + memset(ptr, 0xff, end - ptr); +} +#endif /* DEBUG */ + +/* Coverity taint NOTE: pointers passed to free, would operate on +pointer-GF_MEM_HEADER_SIZE content and if the pointer was used for any IO +related purpose, the pointer stands tainted, and hence coverity would consider +access to the said region as tainted. The following directive to coverity hence +sanitizes the pointer, thus removing any taint to the same within this function. +If the pointer is accessed outside the scope of this function without any +checks on content read from an IO operation, taints will still be reported, and +needs appropriate addressing. */ + +/* coverity[ +tainted_data_sanitize : arg-0 ] */ +static void +gf_free_sanitize(void *s) { - va_list arg; - char *str = NULL; - int size = 0; - int rv = 0; - - if (!string_ptr || !format) - return -1; - - va_start (arg, format); - size = vsnprintf (NULL, 0, format, arg); - size++; - va_start (arg, format); - str = GF_MALLOC (size, gf_common_mt_asprintf); - if (str == NULL) { - va_end (arg); - /* - * Strictly speaking, GNU asprintf doesn't do this, - * but the caller isn't checking the return value. - */ - gf_log ("libglusterfs", GF_LOG_CRITICAL, - "failed to allocate memory"); - return -1; - } - rv = vsnprintf( str, size, format, arg); - va_end (arg); - - *string_ptr = str; - return (rv); } void -__gf_free (void *free_ptr) +__gf_free(void *free_ptr) { - size_t req_size = 0; - char *ptr = NULL; - uint32_t type = 0; - xlator_t *xl = NULL; - - if (!gf_mem_acct_enable) { - FREE (free_ptr); - return; + void *ptr = NULL; + struct mem_acct *mem_acct; + struct mem_header *header = NULL; + bool last_ref = false; + + if (!gf_mem_acct_enabled()) { + FREE(free_ptr); + return; + } + + if (!free_ptr) + return; + + gf_free_sanitize(free_ptr); + ptr = free_ptr - GF_MEM_HEADER_SIZE; + header = (struct mem_header *)ptr; + + // Possible corruption, assert here + GF_ASSERT(GF_MEM_HEADER_MAGIC == header->magic); + + mem_acct = header->mem_acct; + if (!mem_acct) { + goto free; + } + + // This points to a memory overrun + GF_ASSERT(GF_MEM_TRAILER_MAGIC == + *(uint32_t *)((char *)free_ptr + header->size)); + + LOCK(&mem_acct->rec[header->type].lock); + { + mem_acct->rec[header->type].size -= header->size; + mem_acct->rec[header->type].num_allocs--; + /* If all the instances are freed up then ensure typestr is set + * to NULL */ + if (!mem_acct->rec[header->type].num_allocs) { + last_ref = true; + mem_acct->rec[header->type].typestr = NULL; } +#ifdef DEBUG + list_del(&header->acct_list); +#endif + } + UNLOCK(&mem_acct->rec[header->type].lock); - if (!free_ptr) - return; + if (last_ref) { + xlator_mem_acct_unref(mem_acct); + } +free: +#ifdef DEBUG + __gf_mem_invalidate(ptr); +#endif - ptr = (char *)free_ptr - 4; + FREE(ptr); +} - if (GF_MEM_HEADER_MAGIC != *(uint32_t *)ptr) { - //Possible corruption, assert here - assert (0); - } +#if defined(GF_DISABLE_MEMPOOL) - *(uint32_t *)ptr = 0; +struct mem_pool * +mem_pool_new_fn(glusterfs_ctx_t *ctx, unsigned long sizeof_type, + unsigned long count, char *name) +{ + struct mem_pool *new; - ptr = ptr - sizeof(xlator_t *); - memcpy (&xl, ptr, sizeof(xlator_t *)); + new = GF_MALLOC(sizeof(struct mem_pool), gf_common_mt_mem_pool); + if (!new) + return NULL; - if (!xl) { - //gf_free expects xl to be available - assert (0); - } + new->sizeof_type = sizeof_type; + return new; +} - if (!xl->mem_acct.rec) { - ptr = (char *)free_ptr - GF_MEM_HEADER_SIZE; - goto free; - } +void +mem_pool_destroy(struct mem_pool *pool) +{ + GF_FREE(pool); +} + +#else /* !GF_DISABLE_MEMPOOL */ + +static pthread_mutex_t pool_lock = PTHREAD_MUTEX_INITIALIZER; +static struct list_head pool_threads; +static pthread_mutex_t pool_free_lock = PTHREAD_MUTEX_INITIALIZER; +static struct list_head pool_free_threads; +static struct mem_pool_shared pools[NPOOLS]; +static size_t pool_list_size; + +static __thread per_thread_pool_list_t *thread_pool_list = NULL; + +#define N_COLD_LISTS 1024 +#define POOL_SWEEP_SECS 30 + +typedef struct { + pooled_obj_hdr_t *cold_lists[N_COLD_LISTS]; + unsigned int n_cold_lists; +} sweep_state_t; +enum init_state { + GF_MEMPOOL_INIT_NONE = 0, + GF_MEMPOOL_INIT_EARLY, + GF_MEMPOOL_INIT_LATE, + GF_MEMPOOL_INIT_DESTROY +}; - ptr = ptr - sizeof(size_t); - memcpy (&req_size, ptr, sizeof (size_t)); - ptr = ptr - 4; - type = *(uint32_t *)ptr; +static enum init_state init_done = GF_MEMPOOL_INIT_NONE; +static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER; +static unsigned int init_count = 0; +static pthread_t sweeper_tid; - if (GF_MEM_TRAILER_MAGIC != *(uint32_t *) - ((char *)free_ptr + req_size)) { - // This points to a memory overrun - assert (0); +static bool +collect_garbage(sweep_state_t *state, per_thread_pool_list_t *pool_list) +{ + unsigned int i; + per_thread_pool_t *pt_pool; + + (void)pthread_spin_lock(&pool_list->lock); + + for (i = 0; i < NPOOLS; ++i) { + pt_pool = &pool_list->pools[i]; + if (pt_pool->cold_list) { + if (state->n_cold_lists >= N_COLD_LISTS) { + (void)pthread_spin_unlock(&pool_list->lock); + return true; + } + state->cold_lists[state->n_cold_lists++] = pt_pool->cold_list; } - *(uint32_t *) ((char *)free_ptr + req_size) = 0; + pt_pool->cold_list = pt_pool->hot_list; + pt_pool->hot_list = NULL; + } + + (void)pthread_spin_unlock(&pool_list->lock); + + return false; +} + +static void +free_obj_list(pooled_obj_hdr_t *victim) +{ + pooled_obj_hdr_t *next; + + while (victim) { + next = victim->next; + free(victim); + victim = next; + } +} - LOCK (&xl->mem_acct.rec[type].lock); +static void * +pool_sweeper(void *arg) +{ + sweep_state_t state; + per_thread_pool_list_t *pool_list; + uint32_t i; + bool pending; + + /* + * This is all a bit inelegant, but the point is to avoid doing + * expensive things (like freeing thousands of objects) while holding a + * global lock. Thus, we split each iteration into two passes, with + * only the first and fastest holding the lock. + */ + + pending = true; + + for (;;) { + /* If we know there's pending work to do (or it's the first run), we + * do collect garbage more often. */ + sleep(pending ? POOL_SWEEP_SECS / 5 : POOL_SWEEP_SECS); + + (void)pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + state.n_cold_lists = 0; + pending = false; + + /* First pass: collect stuff that needs our attention. */ + (void)pthread_mutex_lock(&pool_lock); + list_for_each_entry(pool_list, &pool_threads, thr_list) { - xl->mem_acct.rec[type].size -= req_size; - xl->mem_acct.rec[type].num_allocs--; + if (collect_garbage(&state, pool_list)) { + pending = true; + } } - UNLOCK (&xl->mem_acct.rec[type].lock); -free: - FREE (ptr); -} + (void)pthread_mutex_unlock(&pool_lock); + /* Second pass: free cold objects from live pools. */ + for (i = 0; i < state.n_cold_lists; ++i) { + free_obj_list(state.cold_lists[i]); + } + (void)pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + } + return NULL; +} -struct mem_pool * -mem_pool_new_fn (unsigned long sizeof_type, - unsigned long count) +void +mem_pool_thread_destructor(per_thread_pool_list_t *pool_list) { - struct mem_pool *mem_pool = NULL; - unsigned long padded_sizeof_type = 0; - void *pool = NULL; - int i = 0; - struct list_head *list = NULL; - - if (!sizeof_type || !count) { - gf_log ("mem-pool", GF_LOG_ERROR, "invalid argument"); - return NULL; - } - padded_sizeof_type = sizeof_type + GF_MEM_POOL_PAD_BOUNDARY; - - mem_pool = GF_CALLOC (sizeof (*mem_pool), 1, gf_common_mt_mem_pool); - if (!mem_pool) - return NULL; - - LOCK_INIT (&mem_pool->lock); - INIT_LIST_HEAD (&mem_pool->list); - - mem_pool->padded_sizeof_type = padded_sizeof_type; - mem_pool->cold_count = count; - mem_pool->real_sizeof_type = sizeof_type; - - pool = GF_CALLOC (count, padded_sizeof_type, gf_common_mt_long); - if (!pool) { - GF_FREE (mem_pool); - return NULL; + per_thread_pool_t *pt_pool; + uint32_t i; + + if (pool_list == NULL) { + pool_list = thread_pool_list; + } + + /* The current thread is terminating. None of the allocated objects will + * be used again. We can directly destroy them here instead of delaying + * it until the next sweeper loop. */ + if (pool_list != NULL) { + /* Remove pool_list from the global list to avoid that sweeper + * could touch it. */ + pthread_mutex_lock(&pool_lock); + list_del(&pool_list->thr_list); + pthread_mutex_unlock(&pool_lock); + + /* We need to protect hot/cold changes from potential mem_put() calls + * that reference this pool_list. Once poison is set to true, we are + * sure that no one else will touch hot/cold lists. The only possible + * race is when at the same moment a mem_put() is adding a new item + * to the hot list. We protect from that by taking pool_list->lock. + * After that we don't need the lock to destroy the hot/cold lists. */ + pthread_spin_lock(&pool_list->lock); + pool_list->poison = true; + pthread_spin_unlock(&pool_list->lock); + + for (i = 0; i < NPOOLS; i++) { + pt_pool = &pool_list->pools[i]; + + free_obj_list(pt_pool->hot_list); + pt_pool->hot_list = NULL; + + free_obj_list(pt_pool->cold_list); + pt_pool->cold_list = NULL; } - for (i = 0; i < count; i++) { - list = pool + (i * (padded_sizeof_type)); - INIT_LIST_HEAD (list); - list_add_tail (list, &mem_pool->list); - } + pthread_mutex_lock(&pool_free_lock); + list_add(&pool_list->thr_list, &pool_free_threads); + pthread_mutex_unlock(&pool_free_lock); + + thread_pool_list = NULL; + } +} + +static __attribute__((constructor)) void +mem_pools_preinit(void) +{ + unsigned int i; + + INIT_LIST_HEAD(&pool_threads); + INIT_LIST_HEAD(&pool_free_threads); + + for (i = 0; i < NPOOLS; ++i) { + pools[i].power_of_two = POOL_SMALLEST + i; - mem_pool->pool = pool; - mem_pool->pool_end = pool + (count * (padded_sizeof_type)); + GF_ATOMIC_INIT(pools[i].allocs_hot, 0); + GF_ATOMIC_INIT(pools[i].allocs_cold, 0); + GF_ATOMIC_INIT(pools[i].allocs_stdc, 0); + GF_ATOMIC_INIT(pools[i].frees_to_list, 0); + } - return mem_pool; + pool_list_size = sizeof(per_thread_pool_list_t) + + sizeof(per_thread_pool_t) * (NPOOLS - 1); + + init_done = GF_MEMPOOL_INIT_EARLY; } -void* -mem_get0 (struct mem_pool *mem_pool) +static __attribute__((destructor)) void +mem_pools_postfini(void) { - struct list_head *list = NULL; - void *ptr = NULL; + /* TODO: This function should destroy all per thread memory pools that + * are still alive, but this is not possible right now because glibc + * starts calling destructors as soon as exit() is called, and + * gluster doesn't ensure that all threads have been stopped before + * calling exit(). Existing threads would crash when they try to use + * memory or they terminate if we destroy things here. + * + * When we propertly terminate all threads, we can add the needed + * code here. Till then we need to leave the memory allocated. Most + * probably this function will be executed on process termination, + * so the memory will be released anyway by the system. */ +} - if (!mem_pool) { - gf_log ("mem-pool", GF_LOG_ERROR, "invalid argument"); - return NULL; - } +/* Call mem_pools_init() once threading has been configured completely. This + * prevent the pool_sweeper thread from getting killed once the main() thread + * exits during deamonizing. */ +void +mem_pools_init(void) +{ + pthread_mutex_lock(&init_mutex); + if ((init_count++) == 0) { + (void)gf_thread_create(&sweeper_tid, NULL, pool_sweeper, NULL, + "memsweep"); + + init_done = GF_MEMPOOL_INIT_LATE; + } + pthread_mutex_unlock(&init_mutex); +} - LOCK (&mem_pool->lock); - { - if (mem_pool->cold_count) { - list = mem_pool->list.next; - list_del (list); - - mem_pool->hot_count++; - mem_pool->cold_count--; - - ptr = list; - goto fwd_addr_out; - } - ptr = MALLOC (mem_pool->real_sizeof_type); - goto unlocked_out; +void +mem_pools_fini(void) +{ + pthread_mutex_lock(&init_mutex); + switch (init_count) { + case 0: + /* + * If init_count is already zero (as e.g. if somebody called this + * before mem_pools_init) then the sweeper was probably never even + * started so we don't need to stop it. Even if there's some crazy + * circumstance where there is a sweeper but init_count is still + * zero, that just means we'll leave it running. Not perfect, but + * far better than any known alternative. + */ + break; + case 1: { + /* if mem_pools_init() was not called, sweeper_tid will be invalid + * and the functions will error out. That is not critical. In all + * other cases, the sweeper_tid will be valid and the thread gets + * stopped. */ + (void)pthread_cancel(sweeper_tid); + (void)pthread_join(sweeper_tid, NULL); + + /* There could be threads still running in some cases, so we can't + * destroy pool_lists in use. We can also not destroy unused + * pool_lists because some allocated objects may still be pointing + * to them. */ + mem_pool_thread_destructor(NULL); + + init_done = GF_MEMPOOL_INIT_DESTROY; + /* Fall through. */ } -fwd_addr_out: - ptr = mem_pool_chunkhead2ptr (ptr); -unlocked_out: + default: + --init_count; + } + pthread_mutex_unlock(&init_mutex); +} - memset(ptr, 0, mem_pool->real_sizeof_type); - UNLOCK (&mem_pool->lock); +void +mem_pool_destroy(struct mem_pool *pool) +{ + if (!pool) + return; - return ptr; + /* remove this pool from the owner (glusterfs_ctx_t) */ + LOCK(&pool->ctx->lock); + { + list_del(&pool->owner); + } + UNLOCK(&pool->ctx->lock); + + /* free this pool, but keep the mem_pool_shared */ + GF_FREE(pool); + + /* + * Pools are now permanent, so the mem_pool->pool is kept around. All + * of the objects *in* the pool will eventually be freed via the + * pool-sweeper thread, and this way we don't have to add a lot of + * reference-counting complexity. + */ } -void * -mem_get (struct mem_pool *mem_pool) +struct mem_pool * +mem_pool_new_fn(glusterfs_ctx_t *ctx, unsigned long sizeof_type, + unsigned long count, char *name) { - struct list_head *list = NULL; - void *ptr = NULL; - - if (!mem_pool) { - gf_log ("mem-pool", GF_LOG_ERROR, "invalid argument"); - return NULL; - } - - LOCK (&mem_pool->lock); - { - if (mem_pool->cold_count) { - list = mem_pool->list.next; - list_del (list); - - mem_pool->hot_count++; - mem_pool->cold_count--; - - ptr = list; - goto fwd_addr_out; - } - - /* This is a problem area. If we've run out of - * chunks in our slab above, we need to allocate - * enough memory to service this request. - * The problem is, these indvidual chunks will fail - * the first address range check in __is_member. Now, since - * we're not allocating a full second slab, we wont have - * enough info perform the range check in __is_member. - * - * I am working around this by performing a regular allocation - * , just the way the caller would've done when not using the - * mem-pool. That also means, we're not padding the size with - * the list_head structure because, this will not be added to - * the list of chunks that belong to the mem-pool allocated - * initially. - * - * This is the best we can do without adding functionality for - * managing multiple slabs. That does not interest us at present - * because it is too much work knowing that a better slab - * allocator is coming RSN. - */ - ptr = MALLOC (mem_pool->real_sizeof_type); - - /* Memory coming from the heap need not be transformed from a - * chunkhead to a usable pointer since it is not coming from - * the pool. - */ - goto unlocked_out; - } -fwd_addr_out: - ptr = mem_pool_chunkhead2ptr (ptr); -unlocked_out: - UNLOCK (&mem_pool->lock); - - return ptr; + unsigned long extra_size, size; + unsigned int power; + struct mem_pool *new = NULL; + struct mem_pool_shared *pool = NULL; + + if (!sizeof_type) { + gf_msg_callingfn("mem-pool", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + return NULL; + } + + /* This is the overhead we'll have because of memory accounting for each + * memory block. */ + extra_size = sizeof(pooled_obj_hdr_t); + + /* We need to compute the total space needed to hold the data type and + * the header. Given that the smallest block size we have in the pools + * is 2^POOL_SMALLEST, we need to take the MAX(size, 2^POOL_SMALLEST). + * However, since this value is only needed to compute its rounded + * logarithm in base 2, and this only depends on the highest bit set, + * we can simply do a bitwise or with the minimum size. We need to + * subtract 1 for correct handling of sizes that are exactly a power + * of 2. */ + size = (sizeof_type + extra_size - 1UL) | ((1UL << POOL_SMALLEST) - 1UL); + + /* We compute the logarithm in base 2 rounded up of the resulting size. + * This value will identify which pool we need to use from the pools of + * powers of 2. This is equivalent to finding the position of the highest + * bit set. */ + power = sizeof(size) * 8 - __builtin_clzl(size); + if (power > POOL_LARGEST) { + gf_msg_callingfn("mem-pool", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + return NULL; + } + pool = &pools[power - POOL_SMALLEST]; + + new = GF_MALLOC(sizeof(struct mem_pool), gf_common_mt_mem_pool); + if (!new) + return NULL; + + new->ctx = ctx; + new->sizeof_type = sizeof_type; + new->count = count; + new->name = name; + new->xl_name = THIS->name; + new->pool = pool; + GF_ATOMIC_INIT(new->active, 0); +#ifdef DEBUG + GF_ATOMIC_INIT(new->hit, 0); + GF_ATOMIC_INIT(new->miss, 0); +#endif + INIT_LIST_HEAD(&new->owner); + + LOCK(&ctx->lock); + { + list_add(&new->owner, &ctx->mempool_list); + } + UNLOCK(&ctx->lock); + + return new; } - -static int -__is_member (struct mem_pool *pool, void *ptr) +per_thread_pool_list_t * +mem_get_pool_list(void) { - if (!pool || !ptr) { - gf_log ("mem-pool", GF_LOG_ERROR, "invalid argument"); - return -1; - } + per_thread_pool_list_t *pool_list; + unsigned int i; + + pool_list = thread_pool_list; + if (pool_list) { + return pool_list; + } + + (void)pthread_mutex_lock(&pool_free_lock); + if (!list_empty(&pool_free_threads)) { + pool_list = list_entry(pool_free_threads.next, per_thread_pool_list_t, + thr_list); + list_del(&pool_list->thr_list); + } + (void)pthread_mutex_unlock(&pool_free_lock); + + if (!pool_list) { + pool_list = MALLOC(pool_list_size); + if (!pool_list) { + return NULL; + } + + INIT_LIST_HEAD(&pool_list->thr_list); + (void)pthread_spin_init(&pool_list->lock, PTHREAD_PROCESS_PRIVATE); + for (i = 0; i < NPOOLS; ++i) { + pool_list->pools[i].parent = &pools[i]; + pool_list->pools[i].hot_list = NULL; + pool_list->pools[i].cold_list = NULL; + } + } + + /* There's no need to take pool_list->lock, because this is already an + * atomic operation and we don't need to synchronize it with any change + * in hot/cold lists. */ + pool_list->poison = false; + + (void)pthread_mutex_lock(&pool_lock); + list_add(&pool_list->thr_list, &pool_threads); + (void)pthread_mutex_unlock(&pool_lock); - if (ptr < pool->pool || ptr >= pool->pool_end) - return 0; + thread_pool_list = pool_list; - if ((mem_pool_ptr2chunkhead (ptr) - pool->pool) - % pool->padded_sizeof_type) - return -1; + /* Ensure that all memory objects associated to the new pool_list are + * destroyed when the thread terminates. */ + gf_thread_needs_cleanup(); - return 1; + return pool_list; } +static pooled_obj_hdr_t * +mem_get_from_pool(struct mem_pool *mem_pool) +{ + per_thread_pool_list_t *pool_list; + per_thread_pool_t *pt_pool; + pooled_obj_hdr_t *retval; +#ifdef DEBUG + gf_boolean_t hit = _gf_true; +#endif + + pool_list = mem_get_pool_list(); + if (!pool_list || pool_list->poison) { + return NULL; + } + + pt_pool = &pool_list->pools[mem_pool->pool->power_of_two - POOL_SMALLEST]; + + (void)pthread_spin_lock(&pool_list->lock); + + retval = pt_pool->hot_list; + if (retval) { + pt_pool->hot_list = retval->next; + (void)pthread_spin_unlock(&pool_list->lock); + GF_ATOMIC_INC(pt_pool->parent->allocs_hot); + } else { + retval = pt_pool->cold_list; + if (retval) { + pt_pool->cold_list = retval->next; + (void)pthread_spin_unlock(&pool_list->lock); + GF_ATOMIC_INC(pt_pool->parent->allocs_cold); + } else { + (void)pthread_spin_unlock(&pool_list->lock); + GF_ATOMIC_INC(pt_pool->parent->allocs_stdc); + retval = malloc(1 << pt_pool->parent->power_of_two); +#ifdef DEBUG + hit = _gf_false; +#endif + } + } + + if (retval != NULL) { + retval->pool = mem_pool; + retval->power_of_two = mem_pool->pool->power_of_two; +#ifdef DEBUG + if (hit == _gf_true) + GF_ATOMIC_INC(mem_pool->hit); + else + GF_ATOMIC_INC(mem_pool->miss); +#endif + retval->magic = GF_MEM_HEADER_MAGIC; + retval->pool_list = pool_list; + } -void -mem_put (struct mem_pool *pool, void *ptr) + return retval; +} + +#endif /* GF_DISABLE_MEMPOOL */ + +void * +mem_get0(struct mem_pool *mem_pool) { - struct list_head *list = NULL; - - if (!pool || !ptr) { - gf_log ("mem-pool", GF_LOG_ERROR, "invalid argument"); - return; - } - - LOCK (&pool->lock); - { - - switch (__is_member (pool, ptr)) - { - case 1: - list = mem_pool_ptr2chunkhead (ptr); - pool->hot_count--; - pool->cold_count++; - list_add (list, &pool->list); - break; - case -1: - /* For some reason, the address given is within - * the address range of the mem-pool but does not align - * with the expected start of a chunk that includes - * the list headers also. Sounds like a problem in - * layers of clouds up above us. ;) - */ - abort (); - break; - case 0: - /* The address is outside the range of the mem-pool. We - * assume here that this address was allocated at a - * point when the mem-pool was out of chunks in mem_get - * or the programmer has made a mistake by calling the - * wrong de-allocation interface. We do - * not have enough info to distinguish between the two - * situations. - */ - FREE (ptr); - break; - default: - /* log error */ - break; - } - } - UNLOCK (&pool->lock); + void *ptr = mem_get(mem_pool); + if (ptr) { +#if defined(GF_DISABLE_MEMPOOL) + memset(ptr, 0, mem_pool->sizeof_type); +#else + memset(ptr, 0, AVAILABLE_SIZE(mem_pool->pool->power_of_two)); +#endif + } + + return ptr; } +void * +mem_get(struct mem_pool *mem_pool) +{ + if (!mem_pool) { + gf_msg_callingfn("mem-pool", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + return NULL; + } + +#if defined(GF_DISABLE_MEMPOOL) + return GF_MALLOC(mem_pool->sizeof_type, gf_common_mt_mem_pool); +#else + pooled_obj_hdr_t *retval = mem_get_from_pool(mem_pool); + if (!retval) { + return NULL; + } + + GF_ATOMIC_INC(mem_pool->active); + + return retval + 1; +#endif /* GF_DISABLE_MEMPOOL */ +} void -mem_pool_destroy (struct mem_pool *pool) +mem_put(void *ptr) { - if (!pool) - return; +#if defined(GF_DISABLE_MEMPOOL) + GF_FREE(ptr); +#else + pooled_obj_hdr_t *hdr; + per_thread_pool_list_t *pool_list; + per_thread_pool_t *pt_pool; + + if (!ptr) { + gf_msg_callingfn("mem-pool", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + return; + } - LOCK_DESTROY (&pool->lock); - GF_FREE (pool->pool); - GF_FREE (pool); + hdr = ((pooled_obj_hdr_t *)ptr) - 1; + if (hdr->magic != GF_MEM_HEADER_MAGIC) { + /* Not one of ours; don't touch it. */ + return; + } + if (!hdr->pool_list) { + gf_msg_callingfn("mem-pool", GF_LOG_CRITICAL, EINVAL, + LG_MSG_INVALID_ARG, + "invalid argument hdr->pool_list NULL"); return; + } + + pool_list = hdr->pool_list; + pt_pool = &pool_list->pools[hdr->power_of_two - POOL_SMALLEST]; + + if (hdr->pool) + GF_ATOMIC_DEC(hdr->pool->active); + + hdr->magic = GF_MEM_INVALID_MAGIC; + + (void)pthread_spin_lock(&pool_list->lock); + if (!pool_list->poison) { + hdr->next = pt_pool->hot_list; + pt_pool->hot_list = hdr; + (void)pthread_spin_unlock(&pool_list->lock); + GF_ATOMIC_INC(pt_pool->parent->frees_to_list); + } else { + /* If the owner thread of this element has terminated, we simply + * release its memory. */ + (void)pthread_spin_unlock(&pool_list->lock); + free(hdr); + } +#endif /* GF_DISABLE_MEMPOOL */ } diff --git a/libglusterfs/src/mem-pool.h b/libglusterfs/src/mem-pool.h deleted file mode 100644 index 0b467bb2cdb..00000000000 --- a/libglusterfs/src/mem-pool.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - Copyright (c) 2008-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _MEM_POOL_H_ -#define _MEM_POOL_H_ - -#include "list.h" -#include "locking.h" -#include "mem-types.h" -#include <stdlib.h> -#include <inttypes.h> -#include <string.h> - - -#define MALLOC(size) malloc(size) -#define CALLOC(cnt,size) calloc(cnt,size) - -#define FREE(ptr) \ - if (ptr != NULL) { \ - free ((void *)ptr); \ - ptr = (void *)0xeeeeeeee; \ - } - -struct mem_acct { - uint32_t num_types; - struct mem_acct_rec *rec; -}; - -struct mem_acct_rec { - size_t size; - size_t max_size; - uint32_t num_allocs; - uint32_t max_num_allocs; - gf_lock_t lock; -}; - - -void * -__gf_calloc (size_t cnt, size_t size, uint32_t type); - -void * -__gf_malloc (size_t size, uint32_t type); - -void * -__gf_realloc (void *ptr, size_t size); - -int -gf_asprintf (char **string_ptr, const char *format, ...); - -#define GF_CALLOC(nmemb, size, type) __gf_calloc (nmemb, size, type) - -#define GF_MALLOC(size, type) __gf_malloc (size, type) - -#define GF_REALLOC(ptr, size) __gf_realloc (ptr, size) - -void -__gf_free (void *ptr); - - -#define GF_FREE(free_ptr) __gf_free (free_ptr); - -static inline -char * gf_strdup (const char *src) -{ - - char *dup_str = NULL; - size_t len = 0; - - len = strlen (src) + 1; - - dup_str = GF_CALLOC(1, len, gf_common_mt_strdup); - - if (!dup_str) - return NULL; - - memcpy (dup_str, src, len); - - return dup_str; -} - - - -struct mem_pool { - struct list_head list; - int hot_count; - int cold_count; - gf_lock_t lock; - unsigned long padded_sizeof_type; - void *pool; - void *pool_end; - int real_sizeof_type; -}; - -struct mem_pool * -mem_pool_new_fn (unsigned long sizeof_type, unsigned long count); - -#define mem_pool_new(type,count) mem_pool_new_fn (sizeof(type), count) - -void mem_put (struct mem_pool *pool, void *ptr); -void *mem_get (struct mem_pool *pool); -void *mem_get0 (struct mem_pool *pool); - -void mem_pool_destroy (struct mem_pool *pool); - -int gf_mem_acct_is_enabled (); -void gf_mem_acct_enable_set (); - -#endif /* _MEM_POOL_H */ diff --git a/libglusterfs/src/mem-types.h b/libglusterfs/src/mem-types.h deleted file mode 100644 index ace869d708a..00000000000 --- a/libglusterfs/src/mem-types.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef __MEM_TYPES_H__ -#define __MEM_TYPES_H__ - - -enum gf_common_mem_types_ { - gf_common_mt_call_stub_t = 0, - gf_common_mt_dnscache6 = 1, - gf_common_mt_data_pair_t = 2, - gf_common_mt_data_t = 3, - gf_common_mt_dict_t = 4, - gf_common_mt_event_pool = 5, - gf_common_mt_reg = 6, - gf_common_mt_pollfd = 7, - gf_common_mt_epoll_event = 8, - gf_common_mt_fdentry_t = 9, - gf_common_mt_fdtable_t = 10, - gf_common_mt_fd_t = 11, - gf_common_mt_fd_ctx = 12, - gf_common_mt_gf_dirent_t = 13, - gf_common_mt_glusterfs_ctx_t = 14, - gf_common_mt_dentry_t = 15, - gf_common_mt_inode_t = 16, - gf_common_mt_inode_ctx = 17, - gf_common_mt_list_head = 18, - gf_common_mt_inode_table_t = 19, - gf_common_mt_xlator_t = 20, - gf_common_mt_xlator_list_t = 21, - gf_common_mt_log_msg = 22, - gf_common_mt_client_log = 23, - gf_common_mt_volume_opt_list_t = 24, - gf_common_mt_gf_hdr_common_t = 25, - gf_common_mt_call_frame_t = 26, - gf_common_mt_call_stack_t = 27, - gf_common_mt_gf_timer_t = 28, - gf_common_mt_gf_timer_registry_t= 29, - gf_common_mt_transport = 30, - gf_common_mt_transport_msg = 31, - gf_common_mt_auth_handle_t = 32, - gf_common_mt_iobuf = 33, - gf_common_mt_iobuf_arena = 34, - gf_common_mt_iobref = 35, - gf_common_mt_iobuf_pool = 36, - gf_common_mt_iovec = 37, - gf_common_mt_memdup = 38, - gf_common_mt_asprintf = 39, - gf_common_mt_strdup = 40, - gf_common_mt_socket_private_t = 41, - gf_common_mt_ioq = 42, - gf_common_mt_transport_t = 43, - gf_common_mt_socket_local_t = 44, - gf_common_mt_char = 45, - gf_common_mt_rbthash_table_t = 46, - gf_common_mt_rbthash_bucket = 47, - gf_common_mt_mem_pool = 48, - gf_common_mt_long = 49, - gf_common_mt_rpcsvc_auth_list = 50, - gf_common_mt_rpcsvc_t = 51, - gf_common_mt_rpcsvc_conn_t = 52, - gf_common_mt_rpcsvc_program_t = 53, - gf_common_mt_rpcsvc_listener_t = 54, - gf_common_mt_rpcsvc_wrapper_t = 55, - gf_common_mt_rpcsvc_stage_t = 56, - gf_common_mt_rpcclnt_t = 57, - gf_common_mt_rpcclnt_savedframe_t = 58, - gf_common_mt_rpc_trans_t = 59, - gf_common_mt_rpc_trans_pollin_t = 60, - gf_common_mt_rpc_trans_handover_t = 61, - gf_common_mt_rpc_trans_reqinfo_t= 62, - gf_common_mt_rpc_trans_rsp_t = 63, - gf_common_mt_glusterfs_graph_t = 64, - gf_common_mt_rdma_private_t = 65, - gf_common_mt_rdma_ioq_t = 66, - gf_common_mt_rpc_transport_t = 67, - gf_common_mt_rdma_local_t = 68, - gf_common_mt_rdma_post_t = 69, - gf_common_mt_qpent = 70, - gf_common_mt_rdma_device_t = 71, - gf_common_mt_rdma_context_t = 72, - gf_common_mt_sge = 73, - gf_common_mt_end = 74 -}; -#endif diff --git a/libglusterfs/src/monitoring.c b/libglusterfs/src/monitoring.c new file mode 100644 index 00000000000..fbb68dc8622 --- /dev/null +++ b/libglusterfs/src/monitoring.c @@ -0,0 +1,282 @@ +/* + Copyright (c) 2017 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/monitoring.h" +#include "glusterfs/xlator.h" +#include "glusterfs/syscall.h" + +#include <stdlib.h> + +static void +dump_mem_acct_details(xlator_t *xl, int fd) +{ + struct mem_acct_rec *mem_rec; + int i = 0; + + if (!xl || !xl->mem_acct || (xl->ctx->active != xl->graph)) + return; + + dprintf(fd, "# %s.%s.total.num_types %d\n", xl->type, xl->name, + xl->mem_acct->num_types); + + dprintf(fd, + "# type, in-use-size, in-use-units, max-size, " + "max-units, total-allocs\n"); + + for (i = 0; i < xl->mem_acct->num_types; i++) { + mem_rec = &xl->mem_acct->rec[i]; + if (mem_rec->num_allocs == 0) + continue; + dprintf(fd, "# %s, %" PRIu64 ", %u, %" PRIu64 ", %u, %" PRIu64 "\n", + mem_rec->typestr, mem_rec->size, mem_rec->num_allocs, + mem_rec->max_size, mem_rec->max_num_allocs, + mem_rec->total_allocs); + } +} + +static void +dump_global_memory_accounting(int fd) +{ +#if MEMORY_ACCOUNTING_STATS + int i = 0; + uint64_t count = 0; + + uint64_t tcalloc = GF_ATOMIC_GET(gf_memory_stat_counts.total_calloc); + uint64_t tmalloc = GF_ATOMIC_GET(gf_memory_stat_counts.total_malloc); + uint64_t tfree = GF_ATOMIC_GET(gf_memory_stat_counts.total_free); + + dprintf(fd, "memory.total.calloc %lu\n", tcalloc); + dprintf(fd, "memory.total.malloc %lu\n", tmalloc); + dprintf(fd, "memory.total.realloc %lu\n", + GF_ATOMIC_GET(gf_memory_stat_counts.total_realloc)); + dprintf(fd, "memory.total.free %lu\n", tfree); + dprintf(fd, "memory.total.in-use %lu\n", ((tcalloc + tmalloc) - tfree)); + + for (i = 0; i < GF_BLK_MAX_VALUE; i++) { + count = GF_ATOMIC_GET(gf_memory_stat_counts.blk_size[i]); + dprintf(fd, "memory.total.blk_size.%s %lu\n", + gf_mem_stats_blk[i].blk_size_str, count); + } + + dprintf(fd, "#----\n"); +#endif + + /* This is not a metric to be watched in admin guide, + but keeping it here till we resolve all leak-issues + would be great */ +} + +static void +dump_latency_and_count(xlator_t *xl, int fd) +{ + int32_t index = 0; + uint64_t fop; + uint64_t cbk; + uint64_t count; + + if (xl->winds) { + dprintf(fd, "%s.total.pending-winds.count %" PRIu64 "\n", xl->name, + xl->winds); + } + + /* Need 'fuse' data, and don't need all the old graph info */ + if ((xl != xl->ctx->master) && (xl->ctx->active != xl->graph)) + return; + + count = GF_ATOMIC_GET(xl->stats.total.count); + dprintf(fd, "%s.total.fop-count %" PRIu64 "\n", xl->name, count); + + count = GF_ATOMIC_GET(xl->stats.interval.count); + dprintf(fd, "%s.interval.fop-count %" PRIu64 "\n", xl->name, count); + GF_ATOMIC_INIT(xl->stats.interval.count, 0); + + for (index = 0; index < GF_FOP_MAXVALUE; index++) { + fop = GF_ATOMIC_GET(xl->stats.total.metrics[index].fop); + if (fop) { + dprintf(fd, "%s.total.%s.count %" PRIu64 "\n", xl->name, + gf_fop_list[index], fop); + } + fop = GF_ATOMIC_GET(xl->stats.interval.metrics[index].fop); + if (fop) { + dprintf(fd, "%s.interval.%s.count %" PRIu64 "\n", xl->name, + gf_fop_list[index], fop); + } + cbk = GF_ATOMIC_GET(xl->stats.interval.metrics[index].cbk); + if (cbk) { + dprintf(fd, "%s.interval.%s.fail_count %" PRIu64 "\n", xl->name, + gf_fop_list[index], cbk); + } + if (xl->stats.interval.latencies[index].count != 0) { + dprintf(fd, "%s.interval.%s.latency %lf\n", xl->name, + gf_fop_list[index], + (((double)xl->stats.interval.latencies[index].total) / + xl->stats.interval.latencies[index].count)); + dprintf(fd, "%s.interval.%s.max %" PRIu64 "\n", xl->name, + gf_fop_list[index], + xl->stats.interval.latencies[index].max); + dprintf(fd, "%s.interval.%s.min %" PRIu64 "\n", xl->name, + gf_fop_list[index], + xl->stats.interval.latencies[index].min); + } + GF_ATOMIC_INIT(xl->stats.interval.metrics[index].cbk, 0); + GF_ATOMIC_INIT(xl->stats.interval.metrics[index].fop, 0); + } + memset(xl->stats.interval.latencies, 0, + sizeof(xl->stats.interval.latencies)); +} + +static inline void +dump_call_stack_details(glusterfs_ctx_t *ctx, int fd) +{ + dprintf(fd, "total.stack.count %" PRIu64 "\n", + GF_ATOMIC_GET(ctx->pool->total_count)); + dprintf(fd, "total.stack.in-flight %" PRIu64 "\n", ctx->pool->cnt); +} + +static inline void +dump_dict_details(glusterfs_ctx_t *ctx, int fd) +{ + uint64_t total_dicts = 0; + uint64_t total_pairs = 0; + + total_dicts = GF_ATOMIC_GET(ctx->stats.total_dicts_used); + total_pairs = GF_ATOMIC_GET(ctx->stats.total_pairs_used); + + dprintf(fd, "total.dict.max-pairs-per %" PRIu64 "\n", + GF_ATOMIC_GET(ctx->stats.max_dict_pairs)); + dprintf(fd, "total.dict.pairs-used %" PRIu64 "\n", total_pairs); + dprintf(fd, "total.dict.used %" PRIu64 "\n", total_dicts); + dprintf(fd, "total.dict.average-pairs %" PRIu64 "\n", + (total_pairs / total_dicts)); +} + +static void +dump_inode_stats(glusterfs_ctx_t *ctx, int fd) +{ +} + +static void +dump_global_metrics(glusterfs_ctx_t *ctx, int fd) +{ + struct timeval tv; + time_t nowtime; + struct tm *nowtm; + char tmbuf[64] = { + 0, + }; + + gettimeofday(&tv, NULL); + nowtime = tv.tv_sec; + nowtm = localtime(&nowtime); + strftime(tmbuf, sizeof tmbuf, "%Y-%m-%d %H:%M:%S", nowtm); + + /* Let every file have information on which process dumped info */ + dprintf(fd, "## %s\n", ctx->cmdlinestr); + dprintf(fd, "### %s\n", tmbuf); + dprintf(fd, "### BrickName: %s\n", ctx->cmd_args.brick_name); + dprintf(fd, "### MountName: %s\n", ctx->cmd_args.mount_point); + dprintf(fd, "### VolumeName: %s\n", ctx->cmd_args.volume_name); + + /* Dump memory accounting */ + dump_global_memory_accounting(fd); + dprintf(fd, "# -----\n"); + + dump_call_stack_details(ctx, fd); + dump_dict_details(ctx, fd); + dprintf(fd, "# -----\n"); + + dump_inode_stats(ctx, fd); + dprintf(fd, "# -----\n"); +} + +static void +dump_xl_metrics(glusterfs_ctx_t *ctx, int fd) +{ + xlator_t *xl; + + xl = ctx->active->top; + + while (xl) { + dump_latency_and_count(xl, fd); + dump_mem_acct_details(xl, fd); + if (xl->dump_metrics) + xl->dump_metrics(xl, fd); + xl = xl->next; + } + + if (ctx->master) { + xl = ctx->master; + + dump_latency_and_count(xl, fd); + dump_mem_acct_details(xl, fd); + if (xl->dump_metrics) + xl->dump_metrics(xl, fd); + } + + return; +} + +char * +gf_monitor_metrics(glusterfs_ctx_t *ctx) +{ + int ret = -1; + int fd = 0; + char *filepath = NULL, *dumppath = NULL; + + gf_msg_trace("monitoring", 0, "received monitoring request (sig:USR2)"); + + dumppath = ctx->config.metrics_dumppath; + if (dumppath == NULL) { + dumppath = GLUSTER_METRICS_DIR; + } + ret = mkdir_p(dumppath, 0755, true); + if (ret) { + /* EEXIST is handled in mkdir_p() itself */ + gf_msg("monitoring", GF_LOG_ERROR, 0, LG_MSG_STRDUP_ERROR, + "failed to create metrics dir %s (%s)", dumppath, + strerror(errno)); + return NULL; + } + + ret = gf_asprintf(&filepath, "%s/gmetrics.XXXXXX", dumppath); + if (ret < 0) { + return NULL; + } + + /* coverity[secure_temp] mkstemp uses 0600 as the mode and is safe */ + fd = mkstemp(filepath); + if (fd < 0) { + gf_msg("monitoring", GF_LOG_ERROR, 0, LG_MSG_STRDUP_ERROR, + "failed to open tmp file %s (%s)", filepath, strerror(errno)); + GF_FREE(filepath); + return NULL; + } + + dump_global_metrics(ctx, fd); + + dump_xl_metrics(ctx, fd); + + /* This below line is used just to capture any errors with dprintf() */ + ret = dprintf(fd, "\n# End of metrics\n"); + if (ret < 0) { + gf_msg("monitoring", GF_LOG_WARNING, 0, LG_MSG_STRDUP_ERROR, + "dprintf() failed: %s", strerror(errno)); + } + + ret = sys_fsync(fd); + if (ret < 0) { + gf_msg("monitoring", GF_LOG_WARNING, 0, LG_MSG_STRDUP_ERROR, + "fsync() failed: %s", strerror(errno)); + } + sys_close(fd); + + /* Figure this out, not happy with returning this string */ + return filepath; +} diff --git a/libglusterfs/src/options.c b/libglusterfs/src/options.c new file mode 100644 index 00000000000..f6b5aa0ea23 --- /dev/null +++ b/libglusterfs/src/options.c @@ -0,0 +1,1249 @@ +/* + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include <fnmatch.h> + +#include "glusterfs/xlator.h" +#include "glusterfs/defaults.h" +#include "glusterfs/libglusterfs-messages.h" + +#define GF_OPTION_LIST_EMPTY(_opt) (_opt->value[0] == NULL) + +static int +xlator_option_validate_path(xlator_t *xl, const char *key, const char *value, + volume_option_t *opt, char **op_errstr) +{ + int ret = -1; + char errstr[256]; + + if (strstr(value, "../")) { + snprintf(errstr, 256, "invalid path given '%s'", value); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", + errstr, NULL); + goto out; + } + + /* Make sure the given path is valid */ + if (value[0] != '/') { + snprintf(errstr, 256, + "option %s %s: '%s' is not an " + "absolute path name", + key, value, value); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", + errstr, NULL); + goto out; + } + + ret = 0; +out: + if (ret && op_errstr) + *op_errstr = gf_strdup(errstr); + return ret; +} + +static int +xlator_option_validate_int(xlator_t *xl, const char *key, const char *value, + volume_option_t *opt, char **op_errstr) +{ + long long inputll = 0; + unsigned long long uinputll = 0; + int ret = -1; + char errstr[256]; + + /* Check the range */ + if (gf_string2longlong(value, &inputll) != 0) { + snprintf(errstr, 256, "invalid number format \"%s\" in option \"%s\"", + value, key); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", + errstr, NULL); + goto out; + } + + /* Handle '-0' */ + if ((inputll == 0) && (gf_string2ulonglong(value, &uinputll) != 0)) { + snprintf(errstr, 256, "invalid number format \"%s\" in option \"%s\"", + value, key); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", + errstr, NULL); + goto out; + } + + if ((opt->min == 0) && (opt->max == 0) && + (opt->validate == GF_OPT_VALIDATE_BOTH)) { + gf_msg_trace(xl->name, 0, + "no range check required for " + "'option %s %s'", + key, value); + ret = 0; + goto out; + } + + if (opt->validate == GF_OPT_VALIDATE_MIN) { + if (inputll < opt->min) { + snprintf(errstr, 256, + "'%lld' in 'option %s %s' is smaller than " + "minimum value '%.0f'", + inputll, key, value, opt->min); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", + errstr, NULL); + goto out; + } + } else if (opt->validate == GF_OPT_VALIDATE_MAX) { + if (inputll > opt->max) { + snprintf(errstr, 256, + "'%lld' in 'option %s %s' is greater than " + "maximum value '%.0f'", + inputll, key, value, opt->max); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", + errstr, NULL); + goto out; + } + } else if ((inputll < opt->min) || (inputll > opt->max)) { + snprintf(errstr, 256, + "'%lld' in 'option %s %s' is out of range " + "[%.0f - %.0f]", + inputll, key, value, opt->min, opt->max); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_OUT_OF_RANGE, "error=%s", + errstr, NULL); + goto out; + } + + ret = 0; +out: + if (ret && op_errstr) + *op_errstr = gf_strdup(errstr); + return ret; +} + +static int +xlator_option_validate_sizet(xlator_t *xl, const char *key, const char *value, + volume_option_t *opt, char **op_errstr) +{ + uint64_t size = 0; + int ret = 0; + char errstr[256]; + + /* Check the range */ + if (gf_string2bytesize_uint64(value, &size) != 0) { + snprintf(errstr, 256, "invalid number format \"%s\" in option \"%s\"", + value, key); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", + errstr, NULL); + ret = -1; + goto out; + } + + if ((opt->min == 0) && (opt->max == 0)) { + gf_msg_trace(xl->name, 0, + "no range check required for " + "'option %s %s'", + key, value); + goto out; + } + + if ((size < opt->min) || (size > opt->max)) { + snprintf(errstr, 256, + "'%" PRIu64 + "' in 'option %s %s' is out of range [%.0f - %.0f]", + size, key, value, opt->min, opt->max); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_OUT_OF_RANGE, "error=%s", + errstr, NULL); + ret = -1; + } + +out: + if (ret && op_errstr) + *op_errstr = gf_strdup(errstr); + return ret; +} + +static int +xlator_option_validate_bool(xlator_t *xl, const char *key, const char *value, + volume_option_t *opt, char **op_errstr) +{ + int ret = -1; + char errstr[256]; + gf_boolean_t is_valid; + + /* Check if the value is one of + '0|1|on|off|no|yes|true|false|enable|disable' */ + + if (gf_string2boolean(value, &is_valid) != 0) { + snprintf(errstr, 256, "option %s %s: '%s' is not a valid boolean value", + key, value, value); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", + errstr, NULL); + goto out; + } + + ret = 0; +out: + if (ret && op_errstr) + *op_errstr = gf_strdup(errstr); + return ret; +} + +static int +xlator_option_validate_xlator(xlator_t *xl, const char *key, const char *value, + volume_option_t *opt, char **op_errstr) +{ + int ret = -1; + char errstr[256]; + xlator_t *xlopt = NULL; + + /* Check if the value is one of the xlators */ + xlopt = xl; + while (xlopt->prev) + xlopt = xlopt->prev; + + while (xlopt) { + if (strcmp(value, xlopt->name) == 0) { + ret = 0; + break; + } + xlopt = xlopt->next; + } + + if (!xlopt) { + snprintf(errstr, 256, "option %s %s: '%s' is not a valid volume name", + key, value, value); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", + errstr, NULL); + goto out; + } + + ret = 0; +out: + if (ret && op_errstr) + *op_errstr = gf_strdup(errstr); + return ret; +} + +static void +set_error_str(char *errstr, size_t len, volume_option_t *opt, const char *key, + const char *value) +{ + int i = 0; + int ret = 0; + + ret = snprintf(errstr, len, + "option %s %s: '%s' is not valid " + "(possible options are ", + key, value, value); + + for (i = 0; (i < ZR_OPTION_MAX_ARRAY_SIZE) && opt->value[i];) { + ret += snprintf(errstr + ret, len - ret, "%s", opt->value[i]); + if (((++i) < ZR_OPTION_MAX_ARRAY_SIZE) && (opt->value[i])) + ret += snprintf(errstr + ret, len - ret, ", "); + else + ret += snprintf(errstr + ret, len - ret, ".)"); + } + return; +} + +static int +is_all_whitespaces(const char *value) +{ + int i = 0; + + if (value == NULL) + return -1; + + for (i = 0; value[i] != '\0'; i++) { + if (value[i] == ' ') + continue; + else + return 0; + } + + return 1; +} + +static int +xlator_option_validate_str(xlator_t *xl, const char *key, const char *value, + volume_option_t *opt, char **op_errstr) +{ + int ret = -1; + int i = 0; + + /* Check if the '*str' is valid */ + if (GF_OPTION_LIST_EMPTY(opt)) { + ret = 0; + goto out; + } + + if (is_all_whitespaces(value) == 1) + goto out; + + for (i = 0; (i < ZR_OPTION_MAX_ARRAY_SIZE) && opt->value[i]; i++) { +#ifdef GF_DARWIN_HOST_OS + if (fnmatch(opt->value[i], value, 0) == 0) { + ret = 0; + break; + } +#else + if (fnmatch(opt->value[i], value, FNM_EXTMATCH) == 0) { + ret = 0; + break; + } +#endif + } + + if ((i == ZR_OPTION_MAX_ARRAY_SIZE) || (!opt->value[i])) + goto out; + /* enter here only if + * 1. reached end of opt->value array and haven't + * validated input + * OR + * 2. valid input list is less than + * ZR_OPTION_MAX_ARRAY_SIZE and input has not + * matched all possible input values. + */ + + ret = 0; + +out: + if (ret) { + char errstr[4096]; + set_error_str(errstr, sizeof(errstr), opt, key, value); + + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", + errstr, NULL); + if (op_errstr) + *op_errstr = gf_strdup(errstr); + } + return ret; +} + +static int +xlator_option_validate_percent(xlator_t *xl, const char *key, const char *value, + volume_option_t *opt, char **op_errstr) +{ + double percent = 0; + int ret = -1; + char errstr[256]; + + /* Check if the value is valid percentage */ + if (gf_string2percent(value, &percent) != 0) { + snprintf(errstr, 256, "invalid percent format \"%s\" in \"option %s\"", + value, key); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", + errstr, NULL); + goto out; + } + + if ((percent < 0.0) || (percent > 100.0)) { + snprintf(errstr, 256, + "'%lf' in 'option %s %s' is out of range [0 - 100]", percent, + key, value); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_OUT_OF_RANGE, "error=%s", + errstr, NULL); + goto out; + } + + ret = 0; +out: + if (ret && op_errstr) + *op_errstr = gf_strdup(errstr); + return ret; +} + +static int +xlator_option_validate_fractional_value(const char *value) +{ + const char *s = NULL; + int ret = 0; + + s = strchr(value, '.'); + if (s) { + for (s = s + 1; *s != '\0'; s++) { + if (*s != '0') { + return -1; + } + } + } + + return ret; +} + +static int +xlator_option_validate_percent_or_sizet(xlator_t *xl, const char *key, + const char *value, volume_option_t *opt, + char **op_errstr) +{ + int ret = -1; + char errstr[256]; + double size = 0; + gf_boolean_t is_percent = _gf_false; + + if (gf_string2percent_or_bytesize(value, &size, &is_percent) == 0) { + if (is_percent) { + if ((size < 0.0) || (size > 100.0)) { + snprintf(errstr, sizeof(errstr), + "'%lf' in 'option %s %s' is out" + " of range [0 - 100]", + size, key, value); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_OUT_OF_RANGE, + "error=%s", errstr, NULL); + goto out; + } + ret = 0; + goto out; + } + + /*Input value of size(in byte) should not be fractional*/ + ret = xlator_option_validate_fractional_value(value); + if (ret) { + snprintf(errstr, sizeof(errstr), + "'%lf' in 'option %s" + " %s' should not be fractional value. Use " + "valid unsigned integer value.", + size, key, value); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", + errstr, NULL); + goto out; + } + + /* Check the range */ + if ((opt->min == 0) && (opt->max == 0)) { + gf_msg_trace(xl->name, 0, + "no range check required " + "for 'option %s %s'", + key, value); + ret = 0; + goto out; + } + if ((size < opt->min) || (size > opt->max)) { + snprintf(errstr, 256, + "'%lf' in 'option %s %s'" + " is out of range [%.0f - %.0f]", + size, key, value, opt->min, opt->max); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_OUT_OF_RANGE, "error=%s", + errstr, NULL); + goto out; + } + ret = 0; + goto out; + } + + /* If control reaches here, invalid argument */ + + snprintf(errstr, 256, "invalid number format \"%s\" in \"option %s\"", + value, key); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", errstr, + NULL); + +out: + if (ret && op_errstr) + *op_errstr = gf_strdup(errstr); + return ret; +} + +static int +xlator_option_validate_time(xlator_t *xl, const char *key, const char *value, + volume_option_t *opt, char **op_errstr) +{ + int ret = -1; + char errstr[256]; + uint32_t input_time = 0; + + /* Check if the value is valid time */ + if (gf_string2time(value, &input_time) != 0) { + snprintf(errstr, 256, + "invalid time format \"%s\" in " + "\"option %s\"", + value, key); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", + errstr, NULL); + goto out; + } + + if ((opt->min == 0) && (opt->max == 0)) { + gf_msg_trace(xl->name, 0, + "no range check required for " + "'option %s %s'", + key, value); + ret = 0; + goto out; + } + + if ((input_time < opt->min) || (input_time > opt->max)) { + snprintf(errstr, 256, + "'%" PRIu32 + "' in 'option %s %s' is " + "out of range [%.0f - %.0f]", + input_time, key, value, opt->min, opt->max); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_OUT_OF_RANGE, "error=%s", + errstr, NULL); + goto out; + } + + ret = 0; +out: + if (ret && op_errstr) + *op_errstr = gf_strdup(errstr); + return ret; +} + +static int +xlator_option_validate_double(xlator_t *xl, const char *key, const char *value, + volume_option_t *opt, char **op_errstr) +{ + double input = 0.0; + int ret = -1; + char errstr[256]; + + /* Check the range */ + if (gf_string2double(value, &input) != 0) { + snprintf(errstr, 256, "invalid number format \"%s\" in option \"%s\"", + value, key); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", + errstr, NULL); + goto out; + } + + if ((opt->min == 0) && (opt->max == 0) && + (opt->validate == GF_OPT_VALIDATE_BOTH)) { + gf_msg_trace(xl->name, 0, + "no range check required for " + "'option %s %s'", + key, value); + ret = 0; + goto out; + } + + if (opt->validate == GF_OPT_VALIDATE_MIN) { + if (input < opt->min) { + snprintf(errstr, 256, + "'%f' in 'option %s %s' is smaller than " + "minimum value '%f'", + input, key, value, opt->min); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", + errstr, NULL); + goto out; + } + } else if (opt->validate == GF_OPT_VALIDATE_MAX) { + if (input > opt->max) { + snprintf(errstr, 256, + "'%f' in 'option %s %s' is greater than " + "maximum value '%f'", + input, key, value, opt->max); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", + errstr, NULL); + goto out; + } + } else if ((input < opt->min) || (input > opt->max)) { + snprintf(errstr, 256, + "'%f' in 'option %s %s' is out of range " + "[%f - %f]", + input, key, value, opt->min, opt->max); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_OUT_OF_RANGE, "error=%s", + errstr, NULL); + goto out; + } + + ret = 0; +out: + if (ret && op_errstr) + *op_errstr = gf_strdup(errstr); + return ret; +} + +static int +xlator_option_validate_addr(xlator_t *xl, const char *key, const char *value, + volume_option_t *opt, char **op_errstr) +{ + int ret = -1; + char errstr[256]; + + if (!valid_internet_address((char *)value, _gf_false, _gf_false)) { + snprintf(errstr, 256, "option %s %s: Can not parse %s address", key, + value, value); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", + errstr, NULL); + if (op_errstr) + *op_errstr = gf_strdup(errstr); + } + + ret = 0; + + return ret; +} + +int +xlator_option_validate_addr_list(xlator_t *xl, const char *key, + const char *value, volume_option_t *opt, + char **op_errstr) +{ + int ret = -1; + char *dup_val = NULL; + char *addr_tok = NULL; + char *save_ptr = NULL; + char *entry = NULL; + char *entry_ptr = NULL; + char *dir_and_addr = NULL; + char *addr_ptr = NULL; + char *addr_list = NULL; + char *addr = NULL; + char *dir = NULL; + + dup_val = gf_strdup(value); + if (!dup_val) + goto out; + + if (dup_val[0] != '/' && !strchr(dup_val, '(')) { + /* Possible old format, handle it for back-ward compatibility */ + addr_tok = strtok_r(dup_val, ",", &save_ptr); + while (addr_tok) { + if (!valid_internet_address(addr_tok, _gf_true, _gf_true)) + goto out; + + addr_tok = strtok_r(NULL, ",", &save_ptr); + } + ret = 0; + goto out; + } + + /* Lets handle the value with new format */ + entry = strtok_r(dup_val, ",", &entry_ptr); + while (entry) { + dir_and_addr = gf_strdup(entry); + if (!dir_and_addr) + goto out; + + dir = strtok_r(dir_and_addr, "(", &addr_ptr); + if (dir[0] != '/') { + /* Valid format should be starting from '/' */ + goto out; + } + /* dir = strtok_r (NULL, " =", &addr_tmp); */ + addr = strtok_r(NULL, ")", &addr_ptr); + if (!addr) + goto out; + + addr_list = gf_strdup(addr); + if (!addr_list) + goto out; + + /* This format be separated by '|' */ + addr_tok = strtok_r(addr_list, "|", &save_ptr); + if (addr_tok == NULL) + goto out; + while (addr_tok) { + if (!valid_internet_address(addr_tok, _gf_true, _gf_true)) + goto out; + + addr_tok = strtok_r(NULL, "|", &save_ptr); + } + entry = strtok_r(NULL, ",", &entry_ptr); + GF_FREE(dir_and_addr); + GF_FREE(addr_list); + addr_list = NULL; + dir_and_addr = NULL; + } + + ret = 0; + +out: + if (ret) { + char errstr[4096]; + snprintf(errstr, sizeof(errstr), + "option %s %s: '%s' is not " + "a valid internet-address-list", + key, value, value); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", + errstr, NULL); + if (op_errstr) + *op_errstr = gf_strdup(errstr); + } + GF_FREE(dup_val); + GF_FREE(dir_and_addr); + GF_FREE(addr_list); + return ret; +} + +static int +xlator_option_validate_mntauth(xlator_t *xl, const char *key, const char *value, + volume_option_t *opt, char **op_errstr) +{ + int ret = -1; + char *dup_val = NULL; + char *addr_tok = NULL; + char *save_ptr = NULL; + + dup_val = gf_strdup(value); + if (!dup_val) + goto out; + + addr_tok = strtok_r(dup_val, ",", &save_ptr); + if (addr_tok == NULL) + goto out; + while (addr_tok) { + if (!valid_mount_auth_address(addr_tok)) + goto out; + + addr_tok = strtok_r(NULL, ",", &save_ptr); + } + ret = 0; + +out: + if (ret) { + char errstr[4096]; + snprintf(errstr, sizeof(errstr), + "option %s %s: '%s' is not " + "a valid mount-auth-address", + key, value, value); + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, "error=%s", + errstr, NULL); + if (op_errstr) + *op_errstr = gf_strdup(errstr); + } + GF_FREE(dup_val); + + return ret; +} + +/*XXX: the rules to validate are as per block-size required for stripe xlator */ +static int +gf_validate_size(const char *sizestr, volume_option_t *opt) +{ + uint64_t value = 0; + int ret = 0; + + GF_ASSERT(opt); + + if (gf_string2bytesize_uint64(sizestr, &value) != 0 || value < opt->min || + value % 512) { + ret = -1; + goto out; + } + +out: + gf_msg_debug(THIS->name, 0, "Returning %d", ret); + return ret; +} + +static int +gf_validate_number(const char *numstr, volume_option_t *opt) +{ + int32_t value; + return gf_string2int32(numstr, &value); +} + +/* Parses the string to be of the form <key1>:<value1>,<key2>:<value2>... * + * takes two optional validaters key_validator and value_validator */ +static int +validate_list_elements(const char *string, volume_option_t *opt, + int(key_validator)(const char *), + int(value_validator)(const char *, volume_option_t *)) +{ + char *dup_string = NULL; + char *str_sav = NULL; + char *substr_sav = NULL; + char *str_ptr = NULL; + char *key = NULL; + char *value = NULL; + int ret = 0; + + GF_ASSERT(string); + + dup_string = gf_strdup(string); + if (NULL == dup_string) + goto out; + + str_ptr = strtok_r(dup_string, ",", &str_sav); + if (str_ptr == NULL) { + ret = -1; + goto out; + } + while (str_ptr) { + key = strtok_r(str_ptr, ":", &substr_sav); + if (!key || (key_validator && key_validator(key))) { + ret = -1; + gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_INVALID_ENTRY, + "list=%s", string, "key=%s", key ? key : "", NULL); + goto out; + } + + value = strtok_r(NULL, ":", &substr_sav); + if (!value || (value_validator && value_validator(value, opt))) { + ret = -1; + gf_smsg(THIS->name, GF_LOG_WARNING, 0, LG_MSG_INVALID_ENTRY, + "list=%s", string, "value=%s", key, NULL); + goto out; + } + + str_ptr = strtok_r(NULL, ",", &str_sav); + substr_sav = NULL; + } + +out: + GF_FREE(dup_string); + gf_msg_debug(THIS->name, 0, "Returning %d", ret); + return ret; +} + +static int +xlator_option_validate_priority_list(xlator_t *xl, const char *key, + const char *value, volume_option_t *opt, + char **op_errstr) +{ + int ret = 0; + char errstr[1024] = { + 0, + }; + + GF_ASSERT(value); + + ret = validate_list_elements(value, opt, NULL, &gf_validate_number); + if (ret) { + snprintf(errstr, 1024, + "option %s %s: '%s' is not a valid " + "priority-list", + key, value, value); + *op_errstr = gf_strdup(errstr); + } + + return ret; +} + +static int +xlator_option_validate_size_list(xlator_t *xl, const char *key, + const char *value, volume_option_t *opt, + char **op_errstr) +{ + int ret = 0; + char errstr[1024] = { + 0, + }; + + GF_ASSERT(value); + + ret = gf_validate_size(value, opt); + if (ret) + ret = validate_list_elements(value, opt, NULL, &gf_validate_size); + + if (ret) { + snprintf(errstr, 1024, + "option %s %s: '%s' is not a valid " + "size-list", + key, value, value); + *op_errstr = gf_strdup(errstr); + } + + return ret; +} + +static int +xlator_option_validate_any(xlator_t *xl, const char *key, const char *value, + volume_option_t *opt, char **op_errstr) +{ + return 0; +} + +typedef int(xlator_option_validator_t)(xlator_t *xl, const char *key, + const char *value, volume_option_t *opt, + char **operrstr); + +int +xlator_option_validate(xlator_t *xl, char *key, char *value, + volume_option_t *opt, char **op_errstr) +{ + int ret = -1; + xlator_option_validator_t *validate; + xlator_option_validator_t *validators[] = { + [GF_OPTION_TYPE_PATH] = xlator_option_validate_path, + [GF_OPTION_TYPE_INT] = xlator_option_validate_int, + [GF_OPTION_TYPE_SIZET] = xlator_option_validate_sizet, + [GF_OPTION_TYPE_BOOL] = xlator_option_validate_bool, + [GF_OPTION_TYPE_XLATOR] = xlator_option_validate_xlator, + [GF_OPTION_TYPE_STR] = xlator_option_validate_str, + [GF_OPTION_TYPE_PERCENT] = xlator_option_validate_percent, + [GF_OPTION_TYPE_PERCENT_OR_SIZET] = + xlator_option_validate_percent_or_sizet, + [GF_OPTION_TYPE_TIME] = xlator_option_validate_time, + [GF_OPTION_TYPE_DOUBLE] = xlator_option_validate_double, + [GF_OPTION_TYPE_INTERNET_ADDRESS] = xlator_option_validate_addr, + [GF_OPTION_TYPE_INTERNET_ADDRESS_LIST] = + xlator_option_validate_addr_list, + [GF_OPTION_TYPE_PRIORITY_LIST] = xlator_option_validate_priority_list, + [GF_OPTION_TYPE_SIZE_LIST] = xlator_option_validate_size_list, + [GF_OPTION_TYPE_ANY] = xlator_option_validate_any, + [GF_OPTION_TYPE_CLIENT_AUTH_ADDR] = xlator_option_validate_mntauth, + [GF_OPTION_TYPE_MAX] = NULL, + }; + + if (opt->type > GF_OPTION_TYPE_MAX) { + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_UNKNOWN_OPTION_TYPE, + "type=%d", opt->type, NULL); + goto out; + } + + validate = validators[opt->type]; + + ret = validate(xl, key, value, opt, op_errstr); +out: + return ret; +} + +volume_option_t * +xlator_volume_option_get_list(volume_opt_list_t *vol_list, const char *key) +{ + volume_option_t *opt = NULL; + volume_opt_list_t *opt_list = NULL; + int index = 0; + int i = 0; + char *cmp_key = NULL; + + if (!vol_list->given_opt) { + opt_list = list_entry(vol_list->list.next, volume_opt_list_t, list); + opt = opt_list->given_opt; + } else + opt = vol_list->given_opt; + + for (index = 0; opt[index].key[0]; index++) { + for (i = 0; i < ZR_VOLUME_MAX_NUM_KEY; i++) { + cmp_key = opt[index].key[i]; + if (!cmp_key) + break; + if (fnmatch(cmp_key, key, FNM_NOESCAPE) == 0) { + return &opt[index]; + } + } + } + + return NULL; +} + +volume_option_t * +xlator_volume_option_get(xlator_t *xl, const char *key) +{ + volume_opt_list_t *vol_list = NULL; + volume_option_t *found = NULL; + + list_for_each_entry(vol_list, &xl->volume_options, list) + { + found = xlator_volume_option_get_list(vol_list, key); + if (found) + break; + } + + return found; +} + +static int +xl_opt_validate(dict_t *dict, char *key, data_t *value, void *data) +{ + xlator_t *xl = NULL; + volume_opt_list_t *vol_opt = NULL; + volume_option_t *opt = NULL; + int ret = 0; + char *errstr = NULL; + + struct { + xlator_t *this; + volume_opt_list_t *vol_opt; + char *errstr; + } * stub; + + stub = data; + xl = stub->this; + vol_opt = stub->vol_opt; + + opt = xlator_volume_option_get_list(vol_opt, key); + if (!opt) + return 0; + + ret = xlator_option_validate(xl, key, value->data, opt, &errstr); + if (ret) + gf_smsg(xl->name, GF_LOG_WARNING, 0, LG_MSG_VALIDATE_RETURNS, "key=%s", + key, "ret=%d", ret, NULL); + + if (errstr) + /* possible small leak of previously set stub->errstr */ + stub->errstr = errstr; + + if (fnmatch(opt->key[0], key, FNM_NOESCAPE) != 0) { + gf_smsg(xl->name, GF_LOG_DEBUG, 0, LG_MSG_OPTION_DEPRECATED, "key=%s", + key, "preferred=%s", opt->key[0], NULL); + dict_set(dict, opt->key[0], value); + dict_del(dict, key); + } + return 0; +} + +int +xlator_options_validate_list(xlator_t *xl, dict_t *options, + volume_opt_list_t *vol_opt, char **op_errstr) +{ + int ret = 0; + struct { + xlator_t *this; + volume_opt_list_t *vol_opt; + char *errstr; + } stub; + + stub.this = xl; + stub.vol_opt = vol_opt; + stub.errstr = NULL; + + dict_foreach(options, xl_opt_validate, &stub); + if (stub.errstr) { + ret = -1; + if (op_errstr) + *op_errstr = stub.errstr; + } + + return ret; +} + +int +xlator_options_validate(xlator_t *xl, dict_t *options, char **op_errstr) +{ + int ret = 0; + volume_opt_list_t *vol_opt = NULL; + + if (!xl) { + gf_msg_debug(THIS->name, 0, "'this' not a valid ptr"); + ret = -1; + goto out; + } + + if (list_empty(&xl->volume_options)) + goto out; + + list_for_each_entry(vol_opt, &xl->volume_options, list) + { + ret = xlator_options_validate_list(xl, options, vol_opt, op_errstr); + } +out: + return ret; +} + +int +xlator_validate_rec(xlator_t *xlator, char **op_errstr) +{ + int ret = -1; + xlator_list_t *trav = NULL; + xlator_t *old_THIS = NULL; + + GF_VALIDATE_OR_GOTO("xlator", xlator, out); + + trav = xlator->children; + + while (trav) { + if (xlator_validate_rec(trav->xlator, op_errstr)) { + gf_smsg("xlator", GF_LOG_WARNING, 0, LG_MSG_VALIDATE_REC_FAILED, + NULL); + goto out; + } + + trav = trav->next; + } + + if (xlator_dynload(xlator)) + gf_msg_debug(xlator->name, 0, "Did not load the symbols"); + + old_THIS = THIS; + THIS = xlator; + + /* Need this here, as this graph has not yet called init() */ + if (!xlator->mem_acct) { + if (!xlator->mem_acct_init) + xlator->mem_acct_init = default_mem_acct_init; + xlator->mem_acct_init(xlator); + } + + ret = xlator_options_validate(xlator, xlator->options, op_errstr); + THIS = old_THIS; + + if (ret) { + gf_smsg(xlator->name, GF_LOG_INFO, 0, LG_MSG_INVALID_ENTRY, "%s", + *op_errstr, NULL); + goto out; + } + + gf_msg_debug(xlator->name, 0, "Validated options"); + + ret = 0; +out: + return ret; +} + +int +graph_reconf_validateopt(glusterfs_graph_t *graph, char **op_errstr) +{ + xlator_t *xlator = NULL; + int ret = -1; + + GF_ASSERT(graph); + + xlator = graph->first; + + ret = xlator_validate_rec(xlator, op_errstr); + + return ret; +} + +static int +xlator_reconfigure_rec(xlator_t *old_xl, xlator_t *new_xl) +{ + xlator_list_t *trav1 = NULL; + xlator_list_t *trav2 = NULL; + int32_t ret = -1; + xlator_t *old_THIS = NULL; + + GF_VALIDATE_OR_GOTO("xlator", old_xl, out); + GF_VALIDATE_OR_GOTO("xlator", new_xl, out); + + trav1 = old_xl->children; + trav2 = new_xl->children; + + while (trav1 && trav2) { + ret = xlator_reconfigure_rec(trav1->xlator, trav2->xlator); + if (ret) + goto out; + + gf_msg_debug(trav1->xlator->name, 0, "reconfigured"); + + trav1 = trav1->next; + trav2 = trav2->next; + } + + if (old_xl->reconfigure) { + old_THIS = THIS; + THIS = old_xl; + + xlator_init_lock(); + handle_default_options(old_xl, new_xl->options); + ret = old_xl->reconfigure(old_xl, new_xl->options); + xlator_init_unlock(); + + THIS = old_THIS; + + if (ret) + goto out; + } else { + gf_msg_debug(old_xl->name, 0, "No reconfigure() found"); + } + + ret = 0; +out: + return ret; +} + +int +xlator_tree_reconfigure(xlator_t *old_xl, xlator_t *new_xl) +{ + xlator_t *new_top = NULL; + xlator_t *old_top = NULL; + + GF_ASSERT(old_xl); + GF_ASSERT(new_xl); + + old_top = old_xl; + new_top = new_xl; + + return xlator_reconfigure_rec(old_top, new_top); +} + +int +xlator_option_info_list(volume_opt_list_t *list, char *key, char **def_val, + char **descr) +{ + int ret = -1; + volume_option_t *opt = NULL; + + opt = xlator_volume_option_get_list(list, key); + if (!opt) + goto out; + + if (def_val) + *def_val = opt->default_value; + if (descr) + *descr = opt->description; + + ret = 0; +out: + return ret; +} + +static int +pass(char *in, char **out) +{ + *out = in; + return 0; +} + +static int +xl_by_name(char *in, xlator_t **out) +{ + xlator_t *xl = NULL; + + xl = xlator_search_by_name(THIS, in); + + if (!xl) + return -1; + *out = xl; + return 0; +} + +static int +pc_or_size(char *in, double *out) +{ + double pc = 0; + int ret = 0; + uint64_t size = 0; + + if (gf_string2percent(in, &pc) == 0) { + if (pc > 100.0) { + ret = gf_string2bytesize_uint64(in, &size); + if (!ret) + *out = size; + } else { + *out = pc; + } + } else { + ret = gf_string2bytesize_uint64(in, &size); + if (!ret) + *out = size; + } + return ret; +} + +DEFINE_INIT_OPT(char *, str, pass); +DEFINE_INIT_OPT(uint64_t, uint64, gf_string2uint64); +DEFINE_INIT_OPT(int64_t, int64, gf_string2int64); +DEFINE_INIT_OPT(uint32_t, uint32, gf_string2uint32); +DEFINE_INIT_OPT(int32_t, int32, gf_string2int32); +DEFINE_INIT_OPT(uint64_t, size, gf_string2bytesize_uint64); +DEFINE_INIT_OPT(uint64_t, size_uint64, gf_string2bytesize_uint64); +DEFINE_INIT_OPT(double, percent, gf_string2percent); +DEFINE_INIT_OPT(double, percent_or_size, pc_or_size); +DEFINE_INIT_OPT(gf_boolean_t, bool, gf_string2boolean); +DEFINE_INIT_OPT(xlator_t *, xlator, xl_by_name); +DEFINE_INIT_OPT(char *, path, pass); +DEFINE_INIT_OPT(double, double, gf_string2double); +DEFINE_INIT_OPT(uint32_t, time, gf_string2time); + +DEFINE_RECONF_OPT(char *, str, pass); +DEFINE_RECONF_OPT(uint64_t, uint64, gf_string2uint64); +DEFINE_RECONF_OPT(int64_t, int64, gf_string2int64); +DEFINE_RECONF_OPT(uint32_t, uint32, gf_string2uint32); +DEFINE_RECONF_OPT(int32_t, int32, gf_string2int32); +DEFINE_RECONF_OPT(uint64_t, size, gf_string2bytesize_uint64); +DEFINE_RECONF_OPT(uint64_t, size_uint64, gf_string2bytesize_uint64); +DEFINE_RECONF_OPT(double, percent, gf_string2percent); +DEFINE_RECONF_OPT(double, percent_or_size, pc_or_size); +DEFINE_RECONF_OPT(gf_boolean_t, bool, gf_string2boolean); +DEFINE_RECONF_OPT(xlator_t *, xlator, xl_by_name); +DEFINE_RECONF_OPT(char *, path, pass); +DEFINE_RECONF_OPT(double, double, gf_string2double); +DEFINE_RECONF_OPT(uint32_t, time, gf_string2time); diff --git a/libglusterfs/src/parse-utils.c b/libglusterfs/src/parse-utils.c new file mode 100644 index 00000000000..4531d5f0170 --- /dev/null +++ b/libglusterfs/src/parse-utils.c @@ -0,0 +1,174 @@ +/* + Copyright 2014-present Facebook. All Rights Reserved + + This file is part of GlusterFS. + + Author : + Shreyas Siravara <shreyas.siravara@gmail.com> + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include <regex.h> +#include <stdio.h> + +#include "glusterfs/parse-utils.h" +#include "glusterfs/mem-pool.h" +#include "glusterfs/common-utils.h" +#include "glusterfs/libglusterfs-messages.h" + +/** + * parser_init: Initialize a parser with the a string to parse and + * the regex we want to use to parse it. + * + * @complete_str: the string to parse + * @regex : the regex to use + * + * Notes : It is up to the caller to call the parser_deinit () function + * to free the allocated parser. + * + * @return : success: parser ptr (on successful compilation and allocation) + * : failure: NULL (on failure to compile regex or allocate memory) + */ +struct parser * +parser_init(const char *regex) +{ + int rc = 0; + struct parser *parser = NULL; + + parser = GF_MALLOC(sizeof(*parser), gf_common_mt_parser_t); + if (!parser) + goto out; + + parser->regex = gf_strdup(regex); + if (!parser->regex) { + GF_FREE(parser); + parser = NULL; + goto out; + } + + rc = regcomp(&parser->preg, parser->regex, REG_EXTENDED); + if (rc != 0) { + gf_msg(GF_PARSE, GF_LOG_INFO, 0, LG_MSG_REGEX_OP_FAILED, + "Failed to compile regex pattern."); + parser_deinit(parser); + parser = NULL; + goto out; + } + parser->complete_str = NULL; +out: + return parser; +} + +/** + * parser_set_string -- Set the string in the parser that we want to parse. + * Subsequent calls to get_next_match () will use this + * string along with the regex that the parser was + * initialized with. + * + * @parser : The parser to use + * @complete_str: The string to set in the parser (what we are going parse) + * + * @return: success: 0 + * failure: -EINVAL for NULL args, -ENOMEM for allocation errors + */ +int +parser_set_string(struct parser *parser, const char *complete_str) +{ + int ret = -EINVAL; + + GF_VALIDATE_OR_GOTO(GF_PARSE, parser, out); + GF_VALIDATE_OR_GOTO(GF_PARSE, complete_str, out); + + parser->complete_str = gf_strdup(complete_str); + GF_CHECK_ALLOC_AND_LOG(GF_PARSE, parser, ret, "Failed to duplicate string!", + out); + + /* Point the temp internal string to what we just dup'ed */ + parser->_rstr = (char *)parser->complete_str; + ret = 0; +out: + return ret; +} + +/** + * parser_unset_string -- Free the string that was set to be parsed. + * This function needs to be called after + * parser_set_string and parser_get_next_match + * in order to free memory used by the string. + * + * @parser : The parser to free memory in + * @return : success: 0 + * : failure: -EINVAL on NULL args + */ +int +parser_unset_string(struct parser *parser) +{ + int ret = -EINVAL; + + GF_VALIDATE_OR_GOTO(GF_PARSE, parser, out); + + GF_FREE(parser->complete_str); + parser->complete_str = NULL; /* Avoid double frees in parser_deinit */ + ret = 0; +out: + return ret; +} + +/** + * parser_deinit: Free the parser and all the memory allocated by it + * + * @parser : Parser to free + * + * @return : nothing + */ +void +parser_deinit(struct parser *ptr) +{ + if (!ptr) + return; + + regfree(&ptr->preg); + GF_FREE(ptr->complete_str); + GF_FREE(ptr->regex); + GF_FREE(ptr); +} + +/** + * parser_get_match: Given the parser that is configured with a compiled regex, + * return the next match in the string. + * + * @parser : Parser to use + * + * @return : success: Pointer to matched character + * : failure: NULL + */ +char * +parser_get_next_match(struct parser *parser) +{ + int rc = -EINVAL; + size_t copy_len = 0; + char *match = NULL; + + GF_VALIDATE_OR_GOTO(GF_PARSE, parser, out); + + rc = regexec(&parser->preg, parser->_rstr, 1, parser->pmatch, 0); + if (rc != 0) { + gf_msg_debug(GF_PARSE, 0, "Could not match %s with regex %s", + parser->_rstr, parser->regex); + goto out; + } + + copy_len = parser->pmatch[0].rm_eo - parser->pmatch[0].rm_so; + + match = gf_strndup(parser->_rstr + parser->pmatch[0].rm_so, copy_len); + GF_CHECK_ALLOC_AND_LOG(GF_PARSE, match, rc, "Duplicating match failed!", + out); + + parser->_rstr = &parser->_rstr[parser->pmatch[0].rm_eo]; +out: + return match; +} diff --git a/libglusterfs/src/quota-common-utils.c b/libglusterfs/src/quota-common-utils.c new file mode 100644 index 00000000000..804e2f0ad4b --- /dev/null +++ b/libglusterfs/src/quota-common-utils.c @@ -0,0 +1,241 @@ +/* + Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include "glusterfs/dict.h" +#include "glusterfs/logging.h" +#include "glusterfs/byte-order.h" +#include "glusterfs/quota-common-utils.h" +#include "glusterfs/common-utils.h" +#include "glusterfs/libglusterfs-messages.h" + +gf_boolean_t +quota_meta_is_null(const quota_meta_t *meta) +{ + if (meta->size == 0 && meta->file_count == 0 && meta->dir_count == 0) + return _gf_true; + + return _gf_false; +} + +int32_t +quota_data_to_meta(data_t *data, quota_meta_t *meta) +{ + int32_t ret = -1; + quota_meta_t *value = NULL; + int64_t *size = NULL; + + if (!data || !meta) + goto out; + + if (data->len > sizeof(int64_t)) { + value = (quota_meta_t *)data->data; + meta->size = ntoh64(value->size); + meta->file_count = ntoh64(value->file_count); + if (data->len > (sizeof(int64_t)) * 2) + meta->dir_count = ntoh64(value->dir_count); + else + meta->dir_count = 0; + } else { + size = (int64_t *)data->data; + meta->size = ntoh64(*size); + meta->file_count = 0; + meta->dir_count = 0; + /* This can happen during software upgrade. + * Older version of glusterfs will not have inode count. + * Return failure, this will be healed as part of lookup + */ + gf_msg_callingfn("quota", GF_LOG_DEBUG, 0, LG_MSG_QUOTA_XATTRS_MISSING, + "Object quota " + "xattrs missing: len = %d", + data->len); + ret = -2; + goto out; + } + + ret = 0; +out: + + return ret; +} + +int32_t +quota_dict_get_inode_meta(dict_t *dict, char *key, const int keylen, + quota_meta_t *meta) +{ + int32_t ret = -1; + data_t *data = NULL; + + if (!dict || !key || !meta) + goto out; + + data = dict_getn(dict, key, keylen); + if (!data || !data->data) + goto out; + + ret = quota_data_to_meta(data, meta); + +out: + + return ret; +} + +int32_t +quota_dict_get_meta(dict_t *dict, char *key, const int keylen, + quota_meta_t *meta) +{ + int32_t ret = -1; + + ret = quota_dict_get_inode_meta(dict, key, keylen, meta); + if (ret == -2) + ret = 0; + + return ret; +} + +int32_t +quota_dict_set_meta(dict_t *dict, char *key, const quota_meta_t *meta, + ia_type_t ia_type) +{ + int32_t ret = -ENOMEM; + quota_meta_t *value = NULL; + + value = GF_MALLOC(sizeof(quota_meta_t), gf_common_quota_meta_t); + if (value == NULL) { + goto out; + } + + value->size = hton64(meta->size); + value->file_count = hton64(meta->file_count); + value->dir_count = hton64(meta->dir_count); + + if (ia_type == IA_IFDIR) { + ret = dict_set_bin(dict, key, value, sizeof(*value)); + } else { + /* For a file we don't need to store dir_count in the + * quota size xattr, so we set the len of the data in the dict + * as 128bits, so when the posix xattrop reads the dict, it only + * performs operations on size and file_count + */ + ret = dict_set_bin(dict, key, value, sizeof(*value) - sizeof(int64_t)); + } + + if (ret < 0) { + gf_msg_callingfn("quota", GF_LOG_ERROR, 0, LG_MSG_DICT_SET_FAILED, + "dict set failed"); + GF_FREE(value); + } + +out: + return ret; +} + +int32_t +quota_conf_read_header(int fd, char *buf) +{ + int ret = 0; + const int header_len = SLEN(QUOTA_CONF_HEADER); + + ret = gf_nread(fd, buf, header_len); + if (ret <= 0) { + goto out; + } else if (ret > 0 && ret != header_len) { + ret = -1; + goto out; + } + + buf[header_len - 1] = 0; + +out: + if (ret < 0) + gf_msg_callingfn("quota", GF_LOG_ERROR, 0, LG_MSG_QUOTA_CONF_ERROR, + "failed to read " + "header from a quota conf"); + + return ret; +} + +int32_t +quota_conf_read_version(int fd, float *version) +{ + int ret = 0; + char buf[PATH_MAX] = ""; + char *tail = NULL; + float value = 0.0f; + + ret = quota_conf_read_header(fd, buf); + if (ret == 0) { + /* quota.conf is empty */ + value = GF_QUOTA_CONF_VERSION; + goto out; + } else if (ret < 0) { + goto out; + } + + value = strtof((buf + strlen(buf) - 3), &tail); + if (tail[0] != '\0') { + ret = -1; + gf_msg_callingfn("quota", GF_LOG_ERROR, 0, LG_MSG_QUOTA_CONF_ERROR, + "invalid quota conf" + " version"); + goto out; + } + + ret = 0; + +out: + if (ret >= 0) + *version = value; + else + gf_msg_callingfn("quota", GF_LOG_ERROR, 0, LG_MSG_QUOTA_CONF_ERROR, + "failed to " + "read version from a quota conf header"); + + return ret; +} + +int32_t +quota_conf_read_gfid(int fd, void *buf, char *type, float version) +{ + int ret = 0; + + ret = gf_nread(fd, buf, 16); + if (ret <= 0) + goto out; + + if (ret != 16) { + ret = -1; + goto out; + } + + if (version >= 1.2f) { + ret = gf_nread(fd, type, 1); + if (ret != 1) { + ret = -1; + goto out; + } + ret = 17; + } else { + *type = GF_QUOTA_CONF_TYPE_USAGE; + } + +out: + if (ret < 0) + gf_msg_callingfn("quota", GF_LOG_ERROR, 0, LG_MSG_QUOTA_CONF_ERROR, + "failed to " + "read gfid from a quota conf"); + + return ret; +} + +int32_t +quota_conf_skip_header(int fd) +{ + return gf_skip_header_section(fd, strlen(QUOTA_CONF_HEADER)); +} diff --git a/libglusterfs/src/rbthash.c b/libglusterfs/src/rbthash.c index b5e684def18..c90b5a21f44 100644 --- a/libglusterfs/src/rbthash.c +++ b/libglusterfs/src/rbthash.c @@ -1,84 +1,73 @@ /* - Copyright (c) 2008-2009 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 "rbthash.h" +#include "glusterfs/rbthash.h" #include "rb.h" -#include "locking.h" -#include "mem-pool.h" -#include "logging.h" +#include "glusterfs/locking.h" +#include "glusterfs/mem-pool.h" +#include "glusterfs/logging.h" +#include "glusterfs/libglusterfs-messages.h" #include <pthread.h> #include <string.h> - int -rbthash_comparator (void *entry1, void *entry2, void *param) +rbthash_comparator(void *entry1, void *entry2, void *param) { - int ret = 0; - rbthash_entry_t *e1 = NULL; - rbthash_entry_t *e2 = NULL; + int ret = 0; + rbthash_entry_t *e1 = NULL; + rbthash_entry_t *e2 = NULL; - if ((!entry1) || (!entry2) || (!param)) - return -1; + if ((!entry1) || (!entry2) || (!param)) + return -1; - e1 = (rbthash_entry_t *)entry1; - e2 = (rbthash_entry_t *)entry2; + e1 = (rbthash_entry_t *)entry1; + e2 = (rbthash_entry_t *)entry2; - if (e1->keylen != e2->keylen) { - if (e1->keylen < e2->keylen) - ret = -1; - else if (e1->keylen > e2->keylen) - ret = 1; - } else - ret = memcmp (e1->key, e2->key, e1->keylen); + if (e1->keylen != e2->keylen) { + if (e1->keylen < e2->keylen) + ret = -1; + else if (e1->keylen > e2->keylen) + ret = 1; + } else + ret = memcmp(e1->key, e2->key, e1->keylen); - return ret; + return ret; } - int -__rbthash_init_buckets (rbthash_table_t *tbl, int buckets) +__rbthash_init_buckets(rbthash_table_t *tbl, int buckets) { - int i = 0; - int ret = -1; - - if (!tbl) - return -1; - - for (; i < buckets; i++) { - LOCK_INIT (&tbl->buckets[i].bucketlock); - tbl->buckets[i].bucket = rb_create ((rb_comparison_func *)rbthash_comparator, tbl, NULL); - if (!tbl->buckets[i].bucket) { - gf_log (GF_RBTHASH, GF_LOG_ERROR, "Failed to create rb" - " table bucket"); - ret = -1; - goto err; - } + int i = 0; + int ret = -1; + + if (!tbl) + return -1; + + for (; i < buckets; i++) { + LOCK_INIT(&tbl->buckets[i].bucketlock); + tbl->buckets[i].bucket = rb_create( + (rb_comparison_func *)rbthash_comparator, tbl, NULL); + if (!tbl->buckets[i].bucket) { + gf_smsg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_RB_TABLE_CREATE_FAILED, + NULL); + ret = -1; + goto err; } + } - ret = 0; + ret = 0; err: - return ret; + return ret; } - /* * rbthash_table_init - Initialize a RBT based hash table * @buckets - Number of buckets in the hash table @@ -90,337 +79,376 @@ err: */ rbthash_table_t * -rbthash_table_init (int buckets, rbt_hasher_t hfunc, - rbt_data_destroyer_t dfunc, - unsigned long expected_entries, - struct mem_pool *entrypool) +rbthash_table_init(glusterfs_ctx_t *ctx, int buckets, rbt_hasher_t hfunc, + rbt_data_destroyer_t dfunc, unsigned long expected_entries, + struct mem_pool *entrypool) { - rbthash_table_t *newtab = NULL; - int ret = -1; - - if (!hfunc) { - gf_log (GF_RBTHASH, GF_LOG_ERROR, "Hash function not given"); - return NULL; - } - - if (!entrypool && !expected_entries) { - gf_log (GF_RBTHASH, GF_LOG_ERROR, - "Both mem-pool and expected entries not provided"); - return NULL; - } - - if (entrypool && expected_entries) { - gf_log (GF_RBTHASH, GF_LOG_ERROR, - "Both mem-pool and expected entries are provided"); - return NULL; - } - - - newtab = GF_CALLOC (1, sizeof (*newtab), - gf_common_mt_rbthash_table_t); - if (!newtab) - return NULL; - - newtab->buckets = GF_CALLOC (buckets, sizeof (struct rbthash_bucket), - gf_common_mt_rbthash_bucket); - if (!newtab->buckets) { - gf_log (GF_RBTHASH, GF_LOG_ERROR, "Failed to allocate memory"); - goto free_newtab; + rbthash_table_t *newtab = NULL; + int ret = -1; + + if (!hfunc) { + gf_smsg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_HASH_FUNC_ERROR, NULL); + return NULL; + } + + if (!entrypool && !expected_entries) { + gf_smsg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_ENTRIES_NOT_PROVIDED, NULL); + return NULL; + } + + if (entrypool && expected_entries) { + gf_smsg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_ENTRIES_PROVIDED, NULL); + return NULL; + } + + newtab = GF_CALLOC(1, sizeof(*newtab), gf_common_mt_rbthash_table_t); + if (!newtab) + return NULL; + + newtab->buckets = GF_CALLOC(buckets, sizeof(struct rbthash_bucket), + gf_common_mt_rbthash_bucket); + if (!newtab->buckets) { + goto free_newtab; + } + + if (expected_entries) { + newtab->entrypool = mem_pool_new_ctx(ctx, rbthash_entry_t, + expected_entries); + if (!newtab->entrypool) { + goto free_buckets; } - - if (expected_entries) { - newtab->entrypool = - mem_pool_new (rbthash_entry_t, expected_entries); - if (!newtab->entrypool) { - gf_log (GF_RBTHASH, GF_LOG_ERROR, - "Failed to allocate mem-pool"); - goto free_buckets; - } - newtab->pool_alloced = _gf_true; - } else { - newtab->entrypool = entrypool; - } - - LOCK_INIT (&newtab->tablelock); - newtab->numbuckets = buckets; - ret = __rbthash_init_buckets (newtab, buckets); - - if (ret == -1) { - gf_log (GF_RBTHASH, GF_LOG_ERROR, "Failed to init buckets"); - if (newtab->pool_alloced) - mem_pool_destroy (newtab->entrypool); - } else { - gf_log (GF_RBTHASH, GF_LOG_TRACE, "Inited hash table: buckets:" - " %d", buckets); - } - - newtab->hashfunc = hfunc; - newtab->dfunc = dfunc; + newtab->pool_alloced = _gf_true; + } else { + newtab->entrypool = entrypool; + } + + LOCK_INIT(&newtab->tablelock); + INIT_LIST_HEAD(&newtab->list); + newtab->numbuckets = buckets; + ret = __rbthash_init_buckets(newtab, buckets); + + if (ret == -1) { + gf_smsg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_RBTHASH_INIT_BUCKET_FAILED, + NULL); + if (newtab->pool_alloced) + mem_pool_destroy(newtab->entrypool); + } else { + gf_msg_trace(GF_RBTHASH, 0, + "Inited hash table: buckets:" + " %d", + buckets); + } + + newtab->hashfunc = hfunc; + newtab->dfunc = dfunc; free_buckets: - if (ret == -1) - GF_FREE (newtab->buckets); + if (ret == -1) + GF_FREE(newtab->buckets); free_newtab: - if (ret == -1) { - GF_FREE (newtab); - newtab = NULL; - } + if (ret == -1) { + GF_FREE(newtab); + newtab = NULL; + } - return newtab; + return newtab; } rbthash_entry_t * -rbthash_init_entry (rbthash_table_t *tbl, void *data, void *key, int keylen) +rbthash_init_entry(rbthash_table_t *tbl, void *data, void *key, int keylen) { - int ret = -1; - rbthash_entry_t *entry = NULL; - - if ((!tbl) || (!data) || (!key)) - return NULL; - - entry = mem_get (tbl->entrypool); - if (!entry) { - gf_log (GF_RBTHASH, GF_LOG_ERROR, "Failed to get entry from" - " mem-pool"); - goto ret; - } - - entry->data = data; - entry->key = GF_CALLOC (keylen, sizeof (char), gf_common_mt_char); - if (!entry->key) { - gf_log (GF_RBTHASH, GF_LOG_ERROR, "Memory allocation failed"); - goto free_entry; - } - - memcpy (entry->key, key, keylen); - entry->keylen = keylen; - entry->keyhash = tbl->hashfunc (entry->key, entry->keylen); - gf_log (GF_RBTHASH, GF_LOG_TRACE, "HASH: %u", entry->keyhash); - - ret = 0; + int ret = -1; + rbthash_entry_t *entry = NULL; + + if ((!tbl) || (!data) || (!key)) + return NULL; + + entry = mem_get(tbl->entrypool); + if (!entry) { + gf_smsg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_RBTHASH_GET_ENTRY_FAILED, + NULL); + goto ret; + } + + entry->data = data; + entry->key = GF_MALLOC(keylen, gf_common_mt_char); + if (!entry->key) { + goto free_entry; + } + + INIT_LIST_HEAD(&entry->list); + memcpy(entry->key, key, keylen); + entry->keylen = keylen; + entry->keyhash = tbl->hashfunc(entry->key, entry->keylen); + gf_msg_trace(GF_RBTHASH, 0, "HASH: %u", entry->keyhash); + + ret = 0; free_entry: - if (ret == -1) { - mem_put (tbl->entrypool, entry); - entry = NULL; - } + if (ret == -1) { + mem_put(entry); + entry = NULL; + } ret: - return entry; + return entry; } - void -rbthash_deinit_entry (rbthash_table_t *tbl, rbthash_entry_t *entry) +rbthash_deinit_entry(rbthash_table_t *tbl, rbthash_entry_t *entry) { + if (!entry) + return; - if (!entry) - return; + GF_FREE(entry->key); - if (entry->key) - GF_FREE (entry->key); + if (tbl) { + if ((entry->data) && (tbl->dfunc)) + tbl->dfunc(entry->data); - if (tbl) { - if ((entry->data) && (tbl->dfunc)) - tbl->dfunc (entry->data); - mem_put (tbl->entrypool, entry); + LOCK(&tbl->tablelock); + { + list_del_init(&entry->list); } + UNLOCK(&tbl->tablelock); - return; -} + mem_put(entry); + } + return; +} -inline struct rbthash_bucket * -rbthash_entry_bucket (rbthash_table_t *tbl, rbthash_entry_t * entry) +static struct rbthash_bucket * +rbthash_entry_bucket(rbthash_table_t *tbl, rbthash_entry_t *entry) { - int nbucket = 0; + int nbucket = 0; - nbucket = (entry->keyhash % tbl->numbuckets); - gf_log (GF_RBTHASH, GF_LOG_TRACE, "BUCKET: %d", nbucket); - return &tbl->buckets[nbucket]; + nbucket = (entry->keyhash % tbl->numbuckets); + gf_msg_trace(GF_RBTHASH, 0, "BUCKET: %d", nbucket); + return &tbl->buckets[nbucket]; } - int -rbthash_insert_entry (rbthash_table_t *tbl, rbthash_entry_t *entry) +rbthash_insert_entry(rbthash_table_t *tbl, rbthash_entry_t *entry) { - struct rbthash_bucket *bucket = NULL; - int ret = -1; - - if ((!tbl) || (!entry)) - return -1; - - bucket = rbthash_entry_bucket (tbl, entry); - if (!bucket) { - gf_log (GF_RBTHASH, GF_LOG_ERROR, "Failed to get bucket"); - goto err; - } - - ret = 0; - LOCK (&bucket->bucketlock); - { - if (!rb_probe (bucket->bucket, (void *)entry)) { - gf_log (GF_RBTHASH, GF_LOG_ERROR, "Failed to insert" - " entry"); - ret = -1; - } + struct rbthash_bucket *bucket = NULL; + int ret = -1; + + if ((!tbl) || (!entry)) + return -1; + + bucket = rbthash_entry_bucket(tbl, entry); + if (!bucket) { + gf_smsg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_RBTHASH_GET_BUCKET_FAILED, + NULL); + goto err; + } + + ret = 0; + LOCK(&bucket->bucketlock); + { + if (!rb_probe(bucket->bucket, (void *)entry)) { + UNLOCK(&bucket->bucketlock); + gf_smsg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_RBTHASH_INSERT_FAILED, + NULL); + ret = -1; + goto err; } - UNLOCK (&bucket->bucketlock); + } + UNLOCK(&bucket->bucketlock); err: - return ret; + return ret; } - int -rbthash_insert (rbthash_table_t *tbl, void *data, void *key, int keylen) +rbthash_insert(rbthash_table_t *tbl, void *data, void *key, int keylen) { - rbthash_entry_t *entry = NULL; - int ret = -1; - - if ((!tbl) || (!data) || (!key)) - return -1; - - entry = rbthash_init_entry (tbl, data, key, keylen); - if (!entry) { - gf_log (GF_RBTHASH, GF_LOG_ERROR, "Failed to init entry"); - goto err; - } - - ret = rbthash_insert_entry (tbl, entry); - - if (ret == -1) { - gf_log (GF_RBTHASH, GF_LOG_ERROR, "Failed to insert entry"); - rbthash_deinit_entry (tbl, entry); - } + rbthash_entry_t *entry = NULL; + int ret = -1; + + if ((!tbl) || (!data) || (!key)) + return -1; + + entry = rbthash_init_entry(tbl, data, key, keylen); + if (!entry) { + gf_smsg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_RBTHASH_INIT_ENTRY_FAILED, + NULL); + goto err; + } + + ret = rbthash_insert_entry(tbl, entry); + + if (ret == -1) { + gf_smsg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_RBTHASH_INSERT_FAILED, + NULL); + rbthash_deinit_entry(tbl, entry); + goto err; + } + + LOCK(&tbl->tablelock); + { + list_add_tail(&entry->list, &tbl->list); + } + UNLOCK(&tbl->tablelock); err: - return ret; + return ret; } -inline struct rbthash_bucket * -rbthash_key_bucket (rbthash_table_t *tbl, void *key, int keylen) +static struct rbthash_bucket * +rbthash_key_bucket(rbthash_table_t *tbl, void *key, int keylen) { - uint32_t keyhash = 0; - int nbucket = 0; + uint32_t keyhash = 0; + int nbucket = 0; - if ((!tbl) || (!key)) - return NULL; + if ((!tbl) || (!key)) + return NULL; - keyhash = tbl->hashfunc (key, keylen); - gf_log (GF_RBTHASH, GF_LOG_TRACE, "HASH: %u", keyhash); - nbucket = (keyhash % tbl->numbuckets); - gf_log (GF_RBTHASH, GF_LOG_TRACE, "BUCKET: %u", nbucket); + keyhash = tbl->hashfunc(key, keylen); + gf_msg_trace(GF_RBTHASH, 0, "HASH: %u", keyhash); + nbucket = (keyhash % tbl->numbuckets); + gf_msg_trace(GF_RBTHASH, 0, "BUCKET: %u", nbucket); - return &tbl->buckets[nbucket]; + return &tbl->buckets[nbucket]; } - void * -rbthash_get (rbthash_table_t *tbl, void *key, int keylen) +rbthash_get(rbthash_table_t *tbl, void *key, int keylen) { - struct rbthash_bucket *bucket = NULL; - rbthash_entry_t *entry = NULL; - rbthash_entry_t searchentry = {0, }; - - if ((!tbl) || (!key)) - return NULL; - - bucket = rbthash_key_bucket (tbl, key, keylen); - if (!bucket) { - gf_log (GF_RBTHASH, GF_LOG_ERROR, "Failed to get bucket"); - return NULL; - } - - searchentry.key = key; - searchentry.keylen = keylen; - LOCK (&bucket->bucketlock); - { - entry = rb_find (bucket->bucket, &searchentry); - } - UNLOCK (&bucket->bucketlock); - - if (!entry) - return NULL; - - return entry->data; + struct rbthash_bucket *bucket = NULL; + rbthash_entry_t *entry = NULL; + rbthash_entry_t searchentry = { + 0, + }; + + if ((!tbl) || (!key)) + return NULL; + + bucket = rbthash_key_bucket(tbl, key, keylen); + if (!bucket) { + gf_smsg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_RBTHASH_GET_BUCKET_FAILED, + NULL); + return NULL; + } + + searchentry.key = key; + searchentry.keylen = keylen; + LOCK(&bucket->bucketlock); + { + entry = rb_find(bucket->bucket, &searchentry); + } + UNLOCK(&bucket->bucketlock); + + if (!entry) + return NULL; + + return entry->data; } - void * -rbthash_remove (rbthash_table_t *tbl, void *key, int keylen) +rbthash_remove(rbthash_table_t *tbl, void *key, int keylen) { - struct rbthash_bucket *bucket = NULL; - rbthash_entry_t *entry = NULL; - rbthash_entry_t searchentry = {0, }; - void *dataref = NULL; - - if ((!tbl) || (!key)) - return NULL; - - bucket = rbthash_key_bucket (tbl, key, keylen); - if (!bucket) { - gf_log (GF_RBTHASH, GF_LOG_ERROR, "Failed to get bucket"); - return NULL; - } - - searchentry.key = key; - searchentry.keylen = keylen; - - LOCK (&bucket->bucketlock); - { - entry = rb_delete (bucket->bucket, &searchentry); - } - UNLOCK (&bucket->bucketlock); - - if (!entry) - return NULL; + struct rbthash_bucket *bucket = NULL; + rbthash_entry_t *entry = NULL; + rbthash_entry_t searchentry = { + 0, + }; + void *dataref = NULL; + + if ((!tbl) || (!key)) + return NULL; + + bucket = rbthash_key_bucket(tbl, key, keylen); + if (!bucket) { + gf_smsg(GF_RBTHASH, GF_LOG_ERROR, 0, LG_MSG_RBTHASH_GET_BUCKET_FAILED, + NULL); + return NULL; + } + + searchentry.key = key; + searchentry.keylen = keylen; + + LOCK(&bucket->bucketlock); + { + entry = rb_delete(bucket->bucket, &searchentry); + } + UNLOCK(&bucket->bucketlock); + + if (!entry) + return NULL; + + GF_FREE(entry->key); + dataref = entry->data; + + LOCK(&tbl->tablelock); + { + list_del_init(&entry->list); + } + UNLOCK(&tbl->tablelock); + + mem_put(entry); + + return dataref; +} - GF_FREE (entry->key); - dataref = entry->data; - mem_put (tbl->entrypool, entry); +void +rbthash_entry_deiniter(void *entry, void *rbparam) +{ + if (!entry) + return; - return dataref; + rbthash_deinit_entry(rbparam, entry); } - void -rbthash_entry_deiniter (void *entry, void *rbparam) +rbthash_table_destroy_buckets(rbthash_table_t *tbl) { - if (!entry) - return; + int x = 0; + if (!tbl) + return; - rbthash_deinit_entry (rbparam, entry); -} + for (; x < tbl->numbuckets; x++) { + LOCK_DESTROY(&tbl->buckets[x].bucketlock); + rb_destroy(tbl->buckets[x].bucket, rbthash_entry_deiniter); + } + return; +} void -rbthash_table_destroy_buckets (rbthash_table_t *tbl) +rbthash_table_destroy(rbthash_table_t *tbl) { - int x = 0; - if (!tbl) - return; + if (!tbl) + return; - for (;x < tbl->numbuckets; x++) { - LOCK_DESTROY (&tbl->buckets[x].bucketlock); - rb_destroy (tbl->buckets[x].bucket, rbthash_entry_deiniter); - } + rbthash_table_destroy_buckets(tbl); + if (tbl->pool_alloced) + mem_pool_destroy(tbl->entrypool); - return; + GF_FREE(tbl->buckets); + GF_FREE(tbl); } - void -rbthash_table_destroy (rbthash_table_t *tbl) +rbthash_table_traverse(rbthash_table_t *tbl, rbt_traverse_t traverse, + void *mydata) { - if (!tbl) - return; + rbthash_entry_t *entry = NULL; - rbthash_table_destroy_buckets (tbl); - if (tbl->pool_alloced) - mem_pool_destroy (tbl->entrypool); + if ((tbl == NULL) || (traverse == NULL)) { + goto out; + } - GF_FREE (tbl->buckets); - GF_FREE (tbl); -} + LOCK(&tbl->tablelock); + { + list_for_each_entry(entry, &tbl->list, list) + { + traverse(entry->data, mydata); + } + } + UNLOCK(&tbl->tablelock); +out: + return; +} diff --git a/libglusterfs/src/rbthash.h b/libglusterfs/src/rbthash.h deleted file mode 100644 index e4c11e51cee..00000000000 --- a/libglusterfs/src/rbthash.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - Copyright (c) 2008-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef __RBTHASH_TABLE_H_ -#define __RBTHASH_TABLE_H_ -#include "rb.h" -#include "locking.h" -#include "mem-pool.h" -#include "logging.h" -#include "common-utils.h" - -#include <pthread.h> - -#define GF_RBTHASH_MEMPOOL 16384 //1048576 -#define GF_RBTHASH "rbthash" - -struct rbthash_bucket { - struct rb_table *bucket; - gf_lock_t bucketlock; -}; - -typedef struct rbthash_entry { - void *data; - void *key; - int keylen; - uint32_t keyhash; -} rbthash_entry_t; - -typedef uint32_t (*rbt_hasher_t) (void *data, int len); -typedef void (*rbt_data_destroyer_t) (void *data); - -typedef struct rbthash_table { - int size; - int numbuckets; - struct mem_pool *entrypool; - gf_lock_t tablelock; - struct rbthash_bucket *buckets; - rbt_hasher_t hashfunc; - rbt_data_destroyer_t dfunc; - gf_boolean_t pool_alloced; -} rbthash_table_t; - -extern rbthash_table_t * -rbthash_table_init (int buckets, rbt_hasher_t hfunc, - rbt_data_destroyer_t dfunc, unsigned long expected_entries, - struct mem_pool *entrypool); - -extern int -rbthash_insert (rbthash_table_t *tbl, void *data, void *key, int keylen); - -extern void * -rbthash_get (rbthash_table_t *tbl, void *key, int keylen); - -extern void * -rbthash_remove (rbthash_table_t *tbl, void *key, int keylen); - -extern void * -rbthash_replace (rbthash_table_t *tbl, void *key, int keylen, void *newdata); - -extern void -rbthash_table_destroy (rbthash_table_t *tbl); -#endif diff --git a/libglusterfs/src/refcount.c b/libglusterfs/src/refcount.c new file mode 100644 index 00000000000..d5a5a82fa0f --- /dev/null +++ b/libglusterfs/src/refcount.c @@ -0,0 +1,108 @@ +/* + Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include "glusterfs/common-utils.h" +#include "glusterfs/refcount.h" + +#ifndef REFCOUNT_NEEDS_LOCK + +void * +_gf_ref_get(gf_ref_t *ref) +{ + unsigned int cnt = __sync_fetch_and_add(&ref->cnt, 1); + + /* if cnt == 0, we're in a fatal position, the object will be free'd + * + * There is a race when two threads do a _gf_ref_get(). Only one of + * them may get a 0 returned. That is acceptable, because one + * _gf_ref_get() returning 0 should be handled as a fatal problem and + * when correct usage/locking is used, it should never happen. + */ + GF_ASSERT(cnt != 0); + + return cnt ? ref->data : NULL; +} + +unsigned int +_gf_ref_put(gf_ref_t *ref) +{ + unsigned int cnt = __sync_fetch_and_sub(&ref->cnt, 1); + + /* if cnt == 1, the last user just did a _gf_ref_put() + * + * When cnt == 0, one _gf_ref_put() was done too much and there has + * been a thread using the refcounted structure when it was not + * supposed to. + */ + GF_ASSERT(cnt != 0); + + if (cnt == 1 && ref->release) + ref->release(ref->data); + + return (cnt != 1); +} + +#else + +void * +_gf_ref_get(gf_ref_t *ref) +{ + unsigned int cnt = 0; + + LOCK(&ref->lk); + { + /* never can be 0, should have been free'd */ + if (ref->cnt > 0) + cnt = ++ref->cnt; + else + GF_ASSERT(ref->cnt > 0); + } + UNLOCK(&ref->lk); + + return cnt ? ref->data : NULL; +} + +unsigned int +_gf_ref_put(gf_ref_t *ref) +{ + unsigned int cnt = 0; + int release = 0; + + LOCK(&ref->lk); + { + if (ref->cnt != 0) { + cnt = --ref->cnt; + /* call release() only when cnt == 0 */ + release = (cnt == 0); + } else + GF_ASSERT(ref->cnt != 0); + } + UNLOCK(&ref->lk); + + if (release && ref->release) + ref->release(ref->data); + + return !release; +} + +#endif /* REFCOUNT_NEEDS_LOCK */ + +void +_gf_ref_init(gf_ref_t *ref, gf_ref_release_t release, void *data) +{ + GF_ASSERT(ref); + +#ifdef REFCOUNT_NEEDS_LOCK + LOCK_INIT(&ref->lk); +#endif + ref->cnt = 1; + ref->release = release; + ref->data = data; +} diff --git a/libglusterfs/src/revision.h b/libglusterfs/src/revision.h deleted file mode 100644 index 03c887fc078..00000000000 --- a/libglusterfs/src/revision.h +++ /dev/null @@ -1 +0,0 @@ -#define GLUSTERFS_REPOSITORY_REVISION "git://git.sv.gnu.org/gluster.git" diff --git a/libglusterfs/src/rot-buffs.c b/libglusterfs/src/rot-buffs.c new file mode 100644 index 00000000000..260bf16ecea --- /dev/null +++ b/libglusterfs/src/rot-buffs.c @@ -0,0 +1,490 @@ +/* + Copyright (c) 2008-2015 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include <math.h> + +#include "glusterfs/mem-types.h" +#include "glusterfs/mem-pool.h" + +#include "glusterfs/rot-buffs.h" + +/** + * Producer-Consumer based on top of rotational buffers. + * + * This favours writers (producer) and keeps the critical section + * light weight. Buffer switch happens when a consumer wants to + * consume data. This is the slow path and waits for pending + * writes to finish. + * + * TODO: do away with opaques (use arrays with indexing). + */ + +#define ROT_BUFF_DEFAULT_COUNT 2 +#define ROT_BUFF_ALLOC_SIZE (1 * 1024 * 1024) /* 1MB per iovec */ + +#define RLIST_IOV_MELDED_ALLOC_SIZE (RBUF_IOVEC_SIZE + ROT_BUFF_ALLOC_SIZE) + +/** + * iovec list is not shrunk (deallocated) if usage/total count + * falls in this range. this is the fast path and should satisfy + * most of the workloads. for the rest shrinking iovec list is + * generous. + */ +#define RVEC_LOW_WATERMARK_COUNT 1 +#define RVEC_HIGH_WATERMARK_COUNT (1 << 4) + +static inline rbuf_list_t * +rbuf_current_buffer(rbuf_t *rbuf) +{ + return rbuf->current; +} + +static void +rlist_mark_waiting(rbuf_list_t *rlist) +{ + LOCK(&rlist->c_lock); + { + rlist->awaiting = _gf_true; + } + UNLOCK(&rlist->c_lock); +} + +static int +__rlist_has_waiter(rbuf_list_t *rlist) +{ + return (rlist->awaiting == _gf_true); +} + +static void * +rbuf_alloc_rvec() +{ + return GF_CALLOC(1, RLIST_IOV_MELDED_ALLOC_SIZE, gf_common_mt_rvec_t); +} + +static void +rlist_reset_vector_usage(rbuf_list_t *rlist) +{ + rlist->used = 1; +} + +static void +rlist_increment_vector_usage(rbuf_list_t *rlist) +{ + rlist->used++; +} + +static void +rlist_increment_total_usage(rbuf_list_t *rlist) +{ + rlist->total++; +} + +static int +rvec_in_watermark_range(rbuf_list_t *rlist) +{ + return ((rlist->total >= RVEC_LOW_WATERMARK_COUNT) && + (rlist->total <= RVEC_HIGH_WATERMARK_COUNT)); +} + +static void +rbuf_reset_rvec(rbuf_iovec_t *rvec) +{ + GF_VALIDATE_OR_GOTO("libglusterfs", rvec, err); + /* iov_base is _never_ modified */ + rvec->iov.iov_len = 0; +err: + return; +} + +/* TODO: alloc multiple rbuf_iovec_t */ +static int +rlist_add_new_vec(rbuf_list_t *rlist) +{ + rbuf_iovec_t *rvec = NULL; + + rvec = (rbuf_iovec_t *)rbuf_alloc_rvec(); + if (!rvec) + return -1; + INIT_LIST_HEAD(&rvec->list); + rvec->iov.iov_base = ((char *)rvec) + RBUF_IOVEC_SIZE; + rvec->iov.iov_len = 0; + + list_add_tail(&rvec->list, &rlist->veclist); + + rlist->rvec = rvec; /* cache the latest */ + + rlist_increment_vector_usage(rlist); + rlist_increment_total_usage(rlist); + + return 0; +} + +static void +rlist_free_rvec(rbuf_iovec_t *rvec) +{ + if (!rvec) + return; + list_del(&rvec->list); + GF_FREE(rvec); +} + +static void +rlist_purge_all_rvec(rbuf_list_t *rlist) +{ + rbuf_iovec_t *rvec = NULL; + + if (!rlist) + return; + while (!list_empty(&rlist->veclist)) { + rvec = list_first_entry(&rlist->veclist, rbuf_iovec_t, list); + rlist_free_rvec(rvec); + } +} + +static void +rlist_shrink_rvec(rbuf_list_t *rlist, unsigned long long shrink) +{ + rbuf_iovec_t *rvec = NULL; + + while (!list_empty(&rlist->veclist) && (shrink-- > 0)) { + rvec = list_first_entry(&rlist->veclist, rbuf_iovec_t, list); + rlist_free_rvec(rvec); + } +} + +static void +rbuf_purge_rlist(rbuf_t *rbuf) +{ + rbuf_list_t *rlist = NULL; + + while (!list_empty(&rbuf->freelist)) { + rlist = list_first_entry(&rbuf->freelist, rbuf_list_t, list); + list_del(&rlist->list); + + rlist_purge_all_rvec(rlist); + + LOCK_DESTROY(&rlist->c_lock); + + (void)pthread_mutex_destroy(&rlist->b_lock); + (void)pthread_cond_destroy(&rlist->b_cond); + + GF_FREE(rlist); + } +} + +rbuf_t * +rbuf_init(int bufcount) +{ + int j = 0; + int ret = 0; + rbuf_t *rbuf = NULL; + rbuf_list_t *rlist = NULL; + + if (bufcount <= 0) + bufcount = ROT_BUFF_DEFAULT_COUNT; + + rbuf = GF_CALLOC(1, sizeof(rbuf_t), gf_common_mt_rbuf_t); + if (!rbuf) + goto error_return; + + LOCK_INIT(&rbuf->lock); + INIT_LIST_HEAD(&rbuf->freelist); + + /* it could have been one big calloc() but this is just once.. */ + for (j = 0; j < bufcount; j++) { + rlist = GF_CALLOC(1, sizeof(rbuf_list_t), gf_common_mt_rlist_t); + if (!rlist) { + ret = -1; + break; + } + + INIT_LIST_HEAD(&rlist->list); + INIT_LIST_HEAD(&rlist->veclist); + + rlist->pending = rlist->completed = 0; + + ret = rlist_add_new_vec(rlist); + if (ret) + break; + + LOCK_INIT(&rlist->c_lock); + + rlist->awaiting = _gf_false; + ret = pthread_mutex_init(&rlist->b_lock, 0); + if (ret != 0) { + GF_FREE(rlist); + break; + } + + ret = pthread_cond_init(&rlist->b_cond, 0); + if (ret != 0) { + GF_FREE(rlist); + break; + } + + list_add_tail(&rlist->list, &rbuf->freelist); + } + + if (ret != 0) + goto dealloc_rlist; + + /* cache currently used buffer: first in the list */ + rbuf->current = list_first_entry(&rbuf->freelist, rbuf_list_t, list); + return rbuf; + +dealloc_rlist: + rbuf_purge_rlist(rbuf); + LOCK_DESTROY(&rbuf->lock); + GF_FREE(rbuf); +error_return: + return NULL; +} + +void +rbuf_dtor(rbuf_t *rbuf) +{ + if (!rbuf) + return; + rbuf->current = NULL; + rbuf_purge_rlist(rbuf); + LOCK_DESTROY(&rbuf->lock); + + GF_FREE(rbuf); +} + +static char * +rbuf_adjust_write_area(struct iovec *iov, size_t bytes) +{ + char *wbuf = NULL; + + wbuf = iov->iov_base + iov->iov_len; + iov->iov_len += bytes; + return wbuf; +} + +static char * +rbuf_alloc_write_area(rbuf_list_t *rlist, size_t bytes) +{ + int ret = 0; + struct iovec *iov = NULL; + + /* check for available space in _current_ IO buffer */ + iov = &rlist->rvec->iov; + if (iov->iov_len + bytes <= ROT_BUFF_ALLOC_SIZE) + return rbuf_adjust_write_area(iov, bytes); /* fast path */ + + /* not enough bytes, try next available buffers */ + if (list_is_last(&rlist->rvec->list, &rlist->veclist)) { + /* OH! consumed all vector buffers */ + GF_ASSERT(rlist->used == rlist->total); + ret = rlist_add_new_vec(rlist); + if (ret) + goto error_return; + } else { + /* not the end, have available rbuf_iovec's */ + rlist->rvec = list_next_entry(rlist->rvec, list); + rlist->used++; + rbuf_reset_rvec(rlist->rvec); + } + + iov = &rlist->rvec->iov; + return rbuf_adjust_write_area(iov, bytes); + +error_return: + return NULL; +} + +char * +rbuf_reserve_write_area(rbuf_t *rbuf, size_t bytes, void **opaque) +{ + char *wbuf = NULL; + rbuf_list_t *rlist = NULL; + + if (!rbuf || (bytes <= 0) || (bytes > ROT_BUFF_ALLOC_SIZE) || !opaque) + return NULL; + + LOCK(&rbuf->lock); + { + rlist = rbuf_current_buffer(rbuf); + wbuf = rbuf_alloc_write_area(rlist, bytes); + if (!wbuf) + goto unblock; + rlist->pending++; + } +unblock: + UNLOCK(&rbuf->lock); + + if (wbuf) + *opaque = rlist; + return wbuf; +} + +static void +rbuf_notify_waiter(rbuf_list_t *rlist) +{ + pthread_mutex_lock(&rlist->b_lock); + { + pthread_cond_signal(&rlist->b_cond); + } + pthread_mutex_unlock(&rlist->b_lock); +} + +int +rbuf_write_complete(void *opaque) +{ + rbuf_list_t *rlist = NULL; + gf_boolean_t notify = _gf_false; + + if (!opaque) + return -1; + + rlist = opaque; + + LOCK(&rlist->c_lock); + { + rlist->completed++; + /** + * it's safe to test ->pending without rbuf->lock *only* if + * there's a waiter as there can be no new incoming writes. + */ + if (__rlist_has_waiter(rlist) && (rlist->completed == rlist->pending)) + notify = _gf_true; + } + UNLOCK(&rlist->c_lock); + + if (notify) + rbuf_notify_waiter(rlist); + + return 0; +} + +int +rbuf_get_buffer(rbuf_t *rbuf, void **opaque, sequence_fn *seqfn, void *mydata) +{ + int retval = RBUF_CONSUMABLE; + rbuf_list_t *rlist = NULL; + + if (!rbuf || !opaque) + return -1; + + LOCK(&rbuf->lock); + { + rlist = rbuf_current_buffer(rbuf); + if (!rlist->pending) { + retval = RBUF_EMPTY; + goto unblock; + } + + if (list_is_singular(&rbuf->freelist)) { + /** + * removal would lead to writer starvation, disallow + * switching. + */ + retval = RBUF_WOULD_STARVE; + goto unblock; + } + + list_del_init(&rlist->list); + if (seqfn) + seqfn(rlist, mydata); + rbuf->current = list_first_entry(&rbuf->freelist, rbuf_list_t, list); + } +unblock: + UNLOCK(&rbuf->lock); + + if (retval == RBUF_CONSUMABLE) + *opaque = rlist; /* caller _owns_ the buffer */ + + return retval; +} + +/** + * Wait for completion of pending writers and invoke dispatcher + * routine (for buffer consumption). + */ + +static void +__rbuf_wait_for_writers(rbuf_list_t *rlist) +{ + while (rlist->completed != rlist->pending) + pthread_cond_wait(&rlist->b_cond, &rlist->b_lock); +} + +#ifndef M_E +#define M_E 2.7 +#endif + +static void +rlist_shrink_vector(rbuf_list_t *rlist) +{ + unsigned long long shrink = 0; + + /** + * fast path: don't bother to deallocate if vectors are hardly + * used. + */ + if (rvec_in_watermark_range(rlist)) + return; + + /** + * Calculate the shrink count based on total allocated vectors. + * Note that the calculation sticks to rlist->total irrespective + * of the actual usage count (rlist->used). Later, ->used could + * be used to apply slack to the calculation based on how much + * it lags from ->total. For now, let's stick to slow decay. + */ + shrink = rlist->total - (rlist->total * pow(M_E, -0.2)); + + rlist_shrink_rvec(rlist, shrink); + rlist->total -= shrink; +} + +int +rbuf_wait_for_completion(rbuf_t *rbuf, void *opaque, + void (*fn)(rbuf_list_t *, void *), void *arg) +{ + rbuf_list_t *rlist = NULL; + + if (!rbuf || !opaque) + return -1; + + rlist = opaque; + + pthread_mutex_lock(&rlist->b_lock); + { + rlist_mark_waiting(rlist); + __rbuf_wait_for_writers(rlist); + } + pthread_mutex_unlock(&rlist->b_lock); + + /** + * from here on, no need of locking until the rlist is put + * back into rotation. + */ + + fn(rlist, arg); /* invoke dispatcher */ + + rlist->awaiting = _gf_false; + rlist->pending = rlist->completed = 0; + + rlist_shrink_vector(rlist); + rlist_reset_vector_usage(rlist); + + rlist->rvec = list_first_entry(&rlist->veclist, rbuf_iovec_t, list); + rbuf_reset_rvec(rlist->rvec); + + LOCK(&rbuf->lock); + { + list_add_tail(&rlist->list, &rbuf->freelist); + } + UNLOCK(&rbuf->lock); + + return 0; +} diff --git a/libglusterfs/src/run.c b/libglusterfs/src/run.c new file mode 100644 index 00000000000..58f95a7e610 --- /dev/null +++ b/libglusterfs/src/run.c @@ -0,0 +1,570 @@ +/* + 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 _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <dirent.h> +#include <assert.h> +#include <signal.h> +#include <sys/wait.h> +#include "glusterfs/syscall.h" + +/* + * Following defines are available for helping development: + * RUN_STANDALONE and RUN_DO_DEMO. + * + * Compiling a standalone object file with no dependencies + * on glusterfs: + * $ cc -DRUN_STANDALONE -c run.c + * + * Compiling a demo program that exercises bits of run.c + * functionality (linking to glusterfs): + * $ cc -DRUN_DO_DEMO -orun run.c `pkg-config --libs --cflags glusterfs-api` + * + * Compiling a demo program that exercises bits of run.c + * functionality (with no dependence on glusterfs): + * + * $ cc -DRUN_DO_DEMO -DRUN_STANDALONE -orun run.c + */ +#if defined(RUN_STANDALONE) || defined(RUN_DO_DEMO) +int +close_fds_except(int *fdv, size_t count); +#define sys_read(f, b, c) read(f, b, c) +#define sys_write(f, b, c) write(f, b, c) +#define sys_close(f) close(f) +#define GF_CALLOC(n, s, t) calloc(n, s) +#define GF_ASSERT(cond) assert(cond) +#define GF_REALLOC(p, s) realloc(p, s) +#define GF_FREE(p) free(p) +#define gf_strdup(s) strdup(s) +#define gf_vasprintf(p, f, va) vasprintf(p, f, va) +#define gf_loglevel_t int +#define gf_msg_callingfn(dom, level, errnum, msgid, fmt, args...) \ + printf("LOG: " fmt "\n", ##args) +#define LOG_DEBUG 0 +#ifdef RUN_STANDALONE +#include <stdbool.h> +#include <sys/resource.h> +int +close_fds_except(int *fdv, size_t count) +{ + int i = 0; + size_t j = 0; + bool should_close = true; + struct rlimit rl; + int ret = -1; + + ret = getrlimit(RLIMIT_NOFILE, &rl); + if (ret) + return ret; + + for (i = 0; i < rl.rlim_cur; i++) { + should_close = true; + for (j = 0; j < count; j++) { + if (i == fdv[j]) { + should_close = false; + break; + } + } + if (should_close) + sys_close(i); + } + return 0; +} +#endif +#ifdef __linux__ +#define GF_LINUX_HOST_OS +#endif +#else /* ! RUN_STANDALONE || RUN_DO_DEMO */ +#include "glusterfs/glusterfs.h" +#include "glusterfs/common-utils.h" +#include "glusterfs/libglusterfs-messages.h" +#endif + +#include "glusterfs/run.h" +void +runinit(runner_t *runner) +{ + int i = 0; + + runner->argvlen = 64; + runner->argv = GF_CALLOC(runner->argvlen, sizeof(*runner->argv), + gf_common_mt_run_argv); + runner->runerr = runner->argv ? 0 : errno; + runner->chpid = -1; + for (i = 0; i < 3; i++) { + runner->chfd[i] = -1; + runner->chio[i] = NULL; + } +} + +FILE * +runner_chio(runner_t *runner, int fd) +{ + GF_ASSERT(fd > 0 && fd < 3); + + if ((fd > 0) && (fd < 3)) + return runner->chio[fd]; + + return NULL; +} + +static void +runner_insert_arg(runner_t *runner, char *arg) +{ + int i = 0; + + GF_ASSERT(arg); + + if (runner->runerr || !runner->argv) + return; + + for (i = 0; i < runner->argvlen; i++) { + if (runner->argv[i] == NULL) + break; + } + GF_ASSERT(i < runner->argvlen); + + if (i == runner->argvlen - 1) { + runner->argv = GF_REALLOC(runner->argv, + runner->argvlen * 2 * sizeof(*runner->argv)); + if (!runner->argv) { + runner->runerr = errno; + return; + } + memset(/* "+" is aware of the type of its left side, + * no need to multiply with type-size */ + runner->argv + runner->argvlen, 0, + runner->argvlen * sizeof(*runner->argv)); + runner->argvlen *= 2; + } + + runner->argv[i] = arg; +} + +void +runner_add_arg(runner_t *runner, const char *arg) +{ + arg = gf_strdup(arg); + if (!arg) { + runner->runerr = errno; + return; + } + + runner_insert_arg(runner, (char *)arg); +} + +static void +runner_va_add_args(runner_t *runner, va_list argp) +{ + const char *arg; + + while ((arg = va_arg(argp, const char *))) + runner_add_arg(runner, arg); +} + +void +runner_add_args(runner_t *runner, ...) +{ + va_list argp; + + va_start(argp, runner); + runner_va_add_args(runner, argp); + va_end(argp); +} + +void +runner_argprintf(runner_t *runner, const char *format, ...) +{ + va_list argva; + char *arg = NULL; + int ret = 0; + + va_start(argva, format); + ret = gf_vasprintf(&arg, format, argva); + va_end(argva); + + if (ret < 0) { + runner->runerr = errno; + return; + } + + runner_insert_arg(runner, arg); +} + +void +runner_log(runner_t *runner, const char *dom, gf_loglevel_t lvl, + const char *msg) +{ + char *buf = NULL; + size_t len = 0; + int i = 0; + + if (runner->runerr) + return; + + for (i = 0;; i++) { + if (runner->argv[i] == NULL) + break; + len += (strlen(runner->argv[i]) + 1); + } + + buf = GF_CALLOC(1, len + 1, gf_common_mt_run_logbuf); + if (!buf) { + runner->runerr = errno; + return; + } + for (i = 0;; i++) { + if (runner->argv[i] == NULL) + break; + strcat(buf, runner->argv[i]); + strcat(buf, " "); + } + if (len > 0) + buf[len - 1] = '\0'; + + gf_msg_callingfn(dom, lvl, 0, LG_MSG_RUNNER_LOG, "%s: %s", msg, buf); + + GF_FREE(buf); +} + +void +runner_redir(runner_t *runner, int fd, int tgt_fd) +{ + GF_ASSERT(fd > 0 && fd < 3); + + if ((fd > 0) && (fd < 3)) + runner->chfd[fd] = (tgt_fd >= 0) ? tgt_fd : -2; +} + +int +runner_start(runner_t *runner) +{ + int pi[3][2] = {{-1, -1}, {-1, -1}, {-1, -1}}; + int xpi[2]; + int ret = 0; + int errno_priv = 0; + int i = 0; + sigset_t set; + + if (runner->runerr || !runner->argv) { + errno = (runner->runerr) ? runner->runerr : EINVAL; + return -1; + } + + GF_ASSERT(runner->argv[0]); + + /* set up a channel to child to communicate back + * possible execve(2) failures + */ + ret = pipe(xpi); + if (ret != -1) + ret = fcntl(xpi[1], F_SETFD, FD_CLOEXEC); + + for (i = 0; i < 3; i++) { + if (runner->chfd[i] != -2) + continue; + ret = pipe(pi[i]); + if (ret != -1) { + runner->chio[i] = fdopen(pi[i][i ? 0 : 1], i ? "r" : "w"); + if (!runner->chio[i]) + ret = -1; + } + } + + if (ret != -1) + runner->chpid = fork(); + switch (runner->chpid) { + case -1: + errno_priv = errno; + sys_close(xpi[0]); + sys_close(xpi[1]); + for (i = 0; i < 3; i++) { + sys_close(pi[i][0]); + sys_close(pi[i][1]); + } + errno = errno_priv; + return -1; + case 0: + for (i = 0; i < 3; i++) + sys_close(pi[i][i ? 0 : 1]); + sys_close(xpi[0]); + ret = 0; + + for (i = 0; i < 3; i++) { + if (ret == -1) + break; + switch (runner->chfd[i]) { + case -1: + /* no redir */ + break; + case -2: + /* redir to pipe */ + ret = dup2(pi[i][i ? 1 : 0], i); + break; + default: + /* redir to file */ + ret = dup2(runner->chfd[i], i); + } + } + + if (ret != -1) { + int fdv[4] = {0, 1, 2, xpi[1]}; + + ret = close_fds_except(fdv, sizeof(fdv) / sizeof(*fdv)); + } + + if (ret != -1) { + /* save child from inheriting our signal handling */ + sigemptyset(&set); + sigprocmask(SIG_SETMASK, &set, NULL); + + execvp(runner->argv[0], runner->argv); + } + ret = sys_write(xpi[1], &errno, sizeof(errno)); + _exit(1); + } + + errno_priv = errno; + for (i = 0; i < 3; i++) + sys_close(pi[i][i ? 1 : 0]); + sys_close(xpi[1]); + if (ret == -1) { + for (i = 0; i < 3; i++) { + if (runner->chio[i]) { + fclose(runner->chio[i]); + runner->chio[i] = NULL; + } + } + } else { + ret = sys_read(xpi[0], (char *)&errno_priv, sizeof(errno_priv)); + sys_close(xpi[0]); + if (ret <= 0) + return 0; + GF_ASSERT(ret == sizeof(errno_priv)); + } + errno = errno_priv; + return -1; +} + +int +runner_end_reuse(runner_t *runner) +{ + int i = 0; + int ret = 1; + int chstat = 0; + + if (runner->chpid > 0) { + if (waitpid(runner->chpid, &chstat, 0) == runner->chpid) { + if (WIFEXITED(chstat)) { + ret = WEXITSTATUS(chstat); + } else { + ret = chstat; + } + } + } + + for (i = 0; i < 3; i++) { + if (runner->chio[i]) { + fclose(runner->chio[i]); + runner->chio[i] = NULL; + } + } + + return -ret; +} + +int +runner_end(runner_t *runner) +{ + int i = 0; + int ret = -1; + char **p = NULL; + + ret = runner_end_reuse(runner); + + if (runner->argv) { + for (p = runner->argv; *p; p++) + GF_FREE(*p); + GF_FREE(runner->argv); + } + for (i = 0; i < 3; i++) + sys_close(runner->chfd[i]); + + return ret; +} + +static int +runner_run_generic(runner_t *runner, int (*rfin)(runner_t *runner)) +{ + int ret = 0; + + ret = runner_start(runner); + if (ret) + goto out; + ret = rfin(runner); + +out: + return ret; +} + +int +runner_run(runner_t *runner) +{ + return runner_run_generic(runner, runner_end); +} + +int +runner_run_nowait(runner_t *runner) +{ + int pid; + + pid = fork(); + + if (!pid) { + setsid(); + _exit(runner_start(runner)); + } + + if (pid > 0) + runner->chpid = pid; + return runner_end(runner); +} + +int +runner_run_reuse(runner_t *runner) +{ + return runner_run_generic(runner, runner_end_reuse); +} + +int +runcmd(const char *arg, ...) +{ + runner_t runner; + va_list argp; + + runinit(&runner); + /* ISO C requires a named argument before '...' */ + runner_add_arg(&runner, arg); + + va_start(argp, arg); + runner_va_add_args(&runner, argp); + va_end(argp); + + return runner_run(&runner); +} + +#ifdef RUN_DO_DEMO +static void +TBANNER(const char *txt) +{ + printf("######\n### demoing %s\n", txt); +} + +int +main(int argc, char **argv) +{ + runner_t runner; + char buf[80]; + char *wdbuf; + ; + int ret; + int fd; + long pathmax = pathconf("/", _PC_PATH_MAX); + struct timeval tv = { + 0, + }; + struct timeval *tvp = NULL; + char *tfile; + + wdbuf = malloc(pathmax); + assert(wdbuf); + getcwd(wdbuf, pathmax); + + TBANNER("basic functionality: running \"echo a b\""); + runcmd("echo", "a", "b", NULL); + + TBANNER("argv extension: running \"echo 1 2 ... 100\""); + runcmd("echo", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", + "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", + "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", + "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", + "45", "46", "47", "48", "49", "50", "51", "52", "53", "54", "55", + "56", "57", "58", "59", "60", "61", "62", "63", "64", "65", "66", + "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", + "78", "79", "80", "81", "82", "83", "84", "85", "86", "87", "88", + "89", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", + "100", NULL); + + TBANNER( + "add_args, argprintf, log, and popen-style functionality:\n" + " running a multiline echo command, emit a log about it,\n" + " redirect it to a pipe, read output lines\n" + " and print them prefixed with \"got: \""); + runinit(&runner); + runner_add_args(&runner, "echo", "pid:", NULL); + runner_argprintf(&runner, "%d\n", getpid()); + runner_add_arg(&runner, "wd:"); + runner_add_arg(&runner, wdbuf); + runner_redir(&runner, 1, RUN_PIPE); + runner_start(&runner); + runner_log(&runner, "(x)", LOG_DEBUG, "starting program"); + while (fgets(buf, sizeof(buf), runner_chio(&runner, 1))) + printf("got: %s", buf); + runner_end(&runner); + + TBANNER("execve error reporting: running a non-existent command"); + ret = runcmd("bafflavvitty", NULL); + printf("%d %d [%s]\n", ret, errno, strerror(errno)); + + TBANNER( + "output redirection: running \"echo foo\" redirected " + "to a temp file"); + tfile = strdup("/tmp/foofXXXXXX"); + assert(tfile); + fd = mkstemp(tfile); + assert(fd != -1); + printf("redirecting to %s\n", tfile); + runinit(&runner); + runner_add_args(&runner, "echo", "foo", NULL); + runner_redir(&runner, 1, fd); + ret = runner_run(&runner); + printf("runner_run returned: %d", ret); + if (ret != 0) + printf(", with errno %d [%s]", errno, strerror(errno)); + putchar('\n'); + + /* sleep for seconds given as argument (0 means forever) + * to allow investigation of post-execution state to + * cbeck for resource leaks (eg. zombies). + */ + if (argc > 1) { + tv.tv_sec = strtoul(argv[1], NULL, 10); + printf("### %s", "sleeping for"); + if (tv.tv_sec > 0) { + printf(" %d seconds\n", tv.tv_sec); + tvp = &tv; + } else + printf("%s\n", "ever"); + select(0, 0, 0, 0, tvp); + } + + return 0; +} +#endif diff --git a/libglusterfs/src/scheduler.c b/libglusterfs/src/scheduler.c deleted file mode 100644 index 3fcaef73b57..00000000000 --- a/libglusterfs/src/scheduler.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include <dlfcn.h> -#include <netdb.h> -#include "xlator.h" -#include "scheduler.h" -#include "list.h" - -struct sched_ops * -get_scheduler (xlator_t *xl, const char *name) -{ - struct sched_ops *tmp_sched = NULL; - volume_opt_list_t *vol_opt = NULL; - char *sched_file = NULL; - void *handle = NULL; - int ret = 0; - - if (name == NULL) { - gf_log ("scheduler", GF_LOG_ERROR, - "'name' not specified, EINVAL"); - return NULL; - } - - ret = gf_asprintf (&sched_file, "%s/%s.so", SCHEDULERDIR, name); - if (-1 == ret) { - gf_log ("scheduler", GF_LOG_ERROR, "asprintf failed"); - return NULL; - } - - gf_log ("scheduler", GF_LOG_DEBUG, - "attempt to load file %s.so", name); - - handle = dlopen (sched_file, RTLD_LAZY); - if (!handle) { - gf_log ("scheduler", GF_LOG_ERROR, - "dlopen(%s): %s", sched_file, dlerror ()); - GF_FREE(sched_file); - return NULL; - } - - tmp_sched = dlsym (handle, "sched"); - if (!tmp_sched) { - gf_log ("scheduler", GF_LOG_ERROR, - "dlsym(sched) on %s", dlerror ()); - GF_FREE(sched_file); - return NULL; - } - - vol_opt = GF_CALLOC (1, sizeof (volume_opt_list_t), - gf_common_mt_volume_opt_list_t); - vol_opt->given_opt = dlsym (handle, "options"); - if (vol_opt->given_opt == NULL) { - gf_log ("scheduler", GF_LOG_DEBUG, - "volume option validation not specified"); - } else { - list_add_tail (&vol_opt->list, &xl->volume_options); - if (validate_xlator_volume_options (xl, vol_opt->given_opt) - == -1) { - gf_log ("scheduler", GF_LOG_ERROR, - "volume option validation failed"); - GF_FREE(sched_file); - return NULL; - } - } - GF_FREE(sched_file); - GF_FREE (vol_opt); - - return tmp_sched; -} diff --git a/libglusterfs/src/scheduler.h b/libglusterfs/src/scheduler.h deleted file mode 100644 index 3e4acaaddcc..00000000000 --- a/libglusterfs/src/scheduler.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _SCHEDULER_H -#define _SCHEDULER_H - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include "xlator.h" - -struct sched_ops { - int32_t (*init) (xlator_t *this); - void (*fini) (xlator_t *this); - void (*update) (xlator_t *this); - xlator_t *(*schedule) (xlator_t *this, const void *path); - void (*notify) (xlator_t *xl, int32_t event, void *data); - int32_t (*mem_acct_init) (xlator_t *this); -}; - -extern struct sched_ops *get_scheduler (xlator_t *xl, const char *name); - -#endif /* _SCHEDULER_H */ diff --git a/libglusterfs/src/stack.c b/libglusterfs/src/stack.c index 0723557b36d..1531f0da43f 100644 --- a/libglusterfs/src/stack.c +++ b/libglusterfs/src/stack.c @@ -1,165 +1,452 @@ /* - Copyright (c) 2009 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 "statedump.h" -#include "stack.h" +#include "glusterfs/statedump.h" +#include "glusterfs/stack.h" +#include "glusterfs/libglusterfs-messages.h" -static inline -int call_frames_count (call_frame_t *call_frame) +call_frame_t * +create_frame(xlator_t *xl, call_pool_t *pool) { - call_frame_t *pos; - int32_t count = 0; + call_stack_t *stack = NULL; + call_frame_t *frame = NULL; + static uint64_t unique = 0; + + if (!xl || !pool) { + return NULL; + } + + stack = mem_get0(pool->stack_mem_pool); + if (!stack) + return NULL; + + INIT_LIST_HEAD(&stack->myframes); + + frame = mem_get0(pool->frame_mem_pool); + if (!frame) { + mem_put(stack); + return NULL; + } + + frame->root = stack; + frame->this = xl; + LOCK_INIT(&frame->lock); + INIT_LIST_HEAD(&frame->frames); + list_add(&frame->frames, &stack->myframes); + + stack->pool = pool; + stack->ctx = xl->ctx; + + if (frame->root->ctx->measure_latency) { + timespec_now(&stack->tv); + memcpy(&frame->begin, &stack->tv, sizeof(stack->tv)); + } + + LOCK(&pool->lock); + { + list_add(&stack->all_frames, &pool->all_frames); + pool->cnt++; + stack->unique = unique++; + } + UNLOCK(&pool->lock); + GF_ATOMIC_INC(pool->total_count); + + LOCK_INIT(&stack->stack_lock); + + return frame; +} - if (!call_frame) - return count; +void +call_stack_set_groups(call_stack_t *stack, int ngrps, gid_t **groupbuf_p) +{ + /* We take the ownership of the passed group buffer. */ + + if (ngrps <= SMALL_GROUP_COUNT) { + memcpy(stack->groups_small, *groupbuf_p, sizeof(gid_t) * ngrps); + stack->groups = stack->groups_small; + GF_FREE(*groupbuf_p); + } else { + stack->groups_large = *groupbuf_p; + stack->groups = stack->groups_large; + } + + stack->ngrps = ngrps; + /* Set a canary. */ + *groupbuf_p = (void *)0xdeadf00d; +} - for (pos = call_frame; pos != NULL; pos = pos->next) - count++; +void +gf_proc_dump_call_frame(call_frame_t *call_frame, const char *key_buf, ...) +{ + char prefix[GF_DUMP_MAX_BUF_LEN]; + va_list ap; + call_frame_t my_frame = { + 0, + }; + + int ret = -1; + char timestr[GF_TIMESTR_SIZE] = { + 0, + }; + int len; + + if (!call_frame) + return; + + GF_ASSERT(key_buf); + + va_start(ap, key_buf); + vsnprintf(prefix, GF_DUMP_MAX_BUF_LEN, key_buf, ap); + va_end(ap); + + ret = TRY_LOCK(&call_frame->lock); + if (ret) + goto out; + + memcpy(&my_frame, call_frame, sizeof(my_frame)); + UNLOCK(&call_frame->lock); + + if (my_frame.root->ctx->measure_latency) { + gf_time_fmt(timestr, sizeof(timestr), my_frame.begin.tv_sec, + gf_timefmt_FT); + len = strlen(timestr); + snprintf(timestr + len, sizeof(timestr) - len, ".%" GF_PRI_SNSECONDS, + my_frame.begin.tv_nsec); + gf_proc_dump_write("frame-creation-time", "%s", timestr); + gf_proc_dump_write( + "timings", "%ld.%" GF_PRI_SNSECONDS " -> %ld.%" GF_PRI_SNSECONDS, + my_frame.begin.tv_sec, my_frame.begin.tv_nsec, my_frame.end.tv_sec, + my_frame.end.tv_nsec); + } + + gf_proc_dump_write("frame", "%p", call_frame); + gf_proc_dump_write("ref_count", "%d", my_frame.ref_count); + gf_proc_dump_write("translator", "%s", my_frame.this->name); + gf_proc_dump_write("complete", "%d", my_frame.complete); + + if (my_frame.parent) + gf_proc_dump_write("parent", "%s", my_frame.parent->this->name); + + if (my_frame.wind_from) + gf_proc_dump_write("wind_from", "%s", my_frame.wind_from); + + if (my_frame.wind_to) + gf_proc_dump_write("wind_to", "%s", my_frame.wind_to); + + if (my_frame.unwind_from) + gf_proc_dump_write("unwind_from", "%s", my_frame.unwind_from); + + if (my_frame.unwind_to) + gf_proc_dump_write("unwind_to", "%s", my_frame.unwind_to); + + ret = 0; +out: + if (ret) { + gf_proc_dump_write("Unable to dump the frame information", + "(Lock acquisition failed)"); + return; + } +} - return count; +void +gf_proc_dump_call_stack(call_stack_t *call_stack, const char *key_buf, ...) +{ + char prefix[GF_DUMP_MAX_BUF_LEN]; + va_list ap; + call_frame_t *trav; + int32_t i = 1, cnt = 0; + char timestr[GF_TIMESTR_SIZE] = { + 0, + }; + int len; + + if (!call_stack) + return; + + GF_ASSERT(key_buf); + + va_start(ap, key_buf); + vsnprintf(prefix, GF_DUMP_MAX_BUF_LEN, key_buf, ap); + va_end(ap); + + cnt = call_frames_count(call_stack); + gf_time_fmt(timestr, sizeof(timestr), call_stack->tv.tv_sec, gf_timefmt_FT); + len = strlen(timestr); + snprintf(timestr + len, sizeof(timestr) - len, ".%" GF_PRI_SNSECONDS, + call_stack->tv.tv_nsec); + gf_proc_dump_write("callstack-creation-time", "%s", timestr); + + gf_proc_dump_write("stack", "%p", call_stack); + gf_proc_dump_write("uid", "%d", call_stack->uid); + gf_proc_dump_write("gid", "%d", call_stack->gid); + gf_proc_dump_write("pid", "%d", call_stack->pid); + gf_proc_dump_write("unique", "%" PRIu64, call_stack->unique); + gf_proc_dump_write("lk-owner", "%s", lkowner_utoa(&call_stack->lk_owner)); + gf_proc_dump_write("ctime", "%" GF_PRI_SECOND ".%" GF_PRI_SNSECONDS, + call_stack->tv.tv_sec, call_stack->tv.tv_nsec); + + if (call_stack->type == GF_OP_TYPE_FOP) + gf_proc_dump_write("op", "%s", (char *)gf_fop_list[call_stack->op]); + else + gf_proc_dump_write("op", "stack"); + + gf_proc_dump_write("type", "%d", call_stack->type); + gf_proc_dump_write("cnt", "%d", cnt); + + list_for_each_entry(trav, &call_stack->myframes, frames) + { + gf_proc_dump_add_section("%s.frame.%d", prefix, i); + gf_proc_dump_call_frame(trav, "%s.frame.%d", prefix, i); + i++; + } } void -gf_proc_dump_call_frame (call_frame_t *call_frame, const char *key_buf,...) +gf_proc_dump_pending_frames(call_pool_t *call_pool) { - - char prefix[GF_DUMP_MAX_BUF_LEN]; - va_list ap; - char key[GF_DUMP_MAX_BUF_LEN]; - call_frame_t my_frame; - int ret = -1; - - if (!call_frame) - return; - - assert(key_buf); - - memset(prefix, 0, sizeof(prefix)); - memset(&my_frame, 0, sizeof(my_frame)); - va_start(ap, key_buf); - vsnprintf(prefix, GF_DUMP_MAX_BUF_LEN, key_buf, ap); - va_end(ap); - - ret = TRY_LOCK(&call_frame->lock); - if (ret) { - gf_log("", GF_LOG_WARNING, "Unable to dump call frame" - " errno: %d", errno); - return; - } - - memcpy(&my_frame, call_frame, sizeof(my_frame)); - UNLOCK(&call_frame->lock); - - gf_proc_dump_build_key(key, prefix,"ref_count"); - gf_proc_dump_write(key, "%d", my_frame.ref_count); - gf_proc_dump_build_key(key, prefix,"translator"); - gf_proc_dump_write(key, "%s", my_frame.this->name); - gf_proc_dump_build_key(key, prefix,"complete"); - gf_proc_dump_write(key, "%d", my_frame.complete); - if (my_frame.parent) { - gf_proc_dump_build_key(key, prefix,"parent"); - gf_proc_dump_write(key, "%s", my_frame.parent->this->name); - } + call_stack_t *trav = NULL; + int i = 1; + int ret = -1; + gf_boolean_t section_added = _gf_false; + + if (!call_pool) + return; + + ret = TRY_LOCK(&(call_pool->lock)); + if (ret) + goto out; + + gf_proc_dump_add_section("global.callpool"); + section_added = _gf_true; + gf_proc_dump_write("callpool_address", "%p", call_pool); + gf_proc_dump_write("callpool.cnt", "%" PRId64, call_pool->cnt); + + list_for_each_entry(trav, &call_pool->all_frames, all_frames) + { + gf_proc_dump_add_section("global.callpool.stack.%d", i); + gf_proc_dump_call_stack(trav, "global.callpool.stack.%d", i); + i++; + } + UNLOCK(&(call_pool->lock)); + + ret = 0; +out: + if (ret) { + if (_gf_false == section_added) + gf_proc_dump_add_section("global.callpool"); + gf_proc_dump_write("Unable to dump the callpool", + "(Lock acquisition failed) %p", call_pool); + } + return; } +void +gf_proc_dump_call_frame_to_dict(call_frame_t *call_frame, char *prefix, + dict_t *dict) +{ + int ret = -1; + char key[GF_DUMP_MAX_BUF_LEN] = { + 0, + }; + char msg[GF_DUMP_MAX_BUF_LEN] = { + 0, + }; + call_frame_t tmp_frame = { + 0, + }; + + if (!call_frame || !dict) + return; + + ret = TRY_LOCK(&call_frame->lock); + if (ret) + return; + memcpy(&tmp_frame, call_frame, sizeof(tmp_frame)); + UNLOCK(&call_frame->lock); + + snprintf(key, sizeof(key), "%s.refcount", prefix); + ret = dict_set_int32(dict, key, tmp_frame.ref_count); + if (ret) + return; + + snprintf(key, sizeof(key), "%s.translator", prefix); + ret = dict_set_dynstr(dict, key, gf_strdup(tmp_frame.this->name)); + if (ret) + return; + + snprintf(key, sizeof(key), "%s.complete", prefix); + ret = dict_set_int32(dict, key, tmp_frame.complete); + if (ret) + return; + + if (tmp_frame.root->ctx->measure_latency) { + snprintf(key, sizeof(key), "%s.timings", prefix); + snprintf(msg, sizeof(msg), + "%ld.%" GF_PRI_SNSECONDS " -> %ld.%" GF_PRI_SNSECONDS, + tmp_frame.begin.tv_sec, tmp_frame.begin.tv_nsec, + tmp_frame.end.tv_sec, tmp_frame.end.tv_nsec); + ret = dict_set_str(dict, key, msg); + if (ret) + return; + } + + if (tmp_frame.parent) { + snprintf(key, sizeof(key), "%s.parent", prefix); + ret = dict_set_dynstr(dict, key, + gf_strdup(tmp_frame.parent->this->name)); + if (ret) + return; + } + + if (tmp_frame.wind_from) { + snprintf(key, sizeof(key), "%s.windfrom", prefix); + ret = dict_set_dynstr(dict, key, gf_strdup(tmp_frame.wind_from)); + if (ret) + return; + } + + if (tmp_frame.wind_to) { + snprintf(key, sizeof(key), "%s.windto", prefix); + ret = dict_set_dynstr(dict, key, gf_strdup(tmp_frame.wind_to)); + if (ret) + return; + } + + if (tmp_frame.unwind_from) { + snprintf(key, sizeof(key), "%s.unwindfrom", prefix); + ret = dict_set_dynstr(dict, key, gf_strdup(tmp_frame.unwind_from)); + if (ret) + return; + } + + if (tmp_frame.unwind_to) { + snprintf(key, sizeof(key), "%s.unwind_to", prefix); + ret = dict_set_dynstr(dict, key, gf_strdup(tmp_frame.unwind_to)); + if (ret) + return; + } + + return; +} void -gf_proc_dump_call_stack (call_stack_t *call_stack, const char *key_buf,...) +gf_proc_dump_call_stack_to_dict(call_stack_t *call_stack, char *prefix, + dict_t *dict) { - char prefix[GF_DUMP_MAX_BUF_LEN]; - va_list ap; - call_frame_t *trav; - int32_t cnt, i; - char key[GF_DUMP_MAX_BUF_LEN]; - - if (!call_stack) - return; - - assert(key_buf); - - cnt = call_frames_count(&call_stack->frames); - - memset(prefix, 0, sizeof(prefix)); - va_start(ap, key_buf); - vsnprintf(prefix, GF_DUMP_MAX_BUF_LEN, key_buf, ap); - va_end(ap); - - gf_proc_dump_build_key(key, prefix,"uid"); - gf_proc_dump_write(key, "%d", call_stack->uid); - gf_proc_dump_build_key(key, prefix,"gid"); - gf_proc_dump_write(key, "%d", call_stack->gid); - gf_proc_dump_build_key(key, prefix,"pid"); - gf_proc_dump_write(key, "%d", call_stack->pid); - gf_proc_dump_build_key(key, prefix,"unique"); - gf_proc_dump_write(key, "%Ld", call_stack->unique); - - gf_proc_dump_build_key(key, prefix,"op"); - if (call_stack->type == GF_OP_TYPE_FOP) - gf_proc_dump_write(key, "%s", gf_fop_list[call_stack->op]); - else if (call_stack->type == GF_OP_TYPE_MGMT) - gf_proc_dump_write(key, "%s", gf_mgmt_list[call_stack->op]); - - gf_proc_dump_build_key(key, prefix,"type"); - gf_proc_dump_write(key, "%d", call_stack->type); - gf_proc_dump_build_key(key, prefix,"cnt"); - gf_proc_dump_write(key, "%d", cnt); - - trav = &call_stack->frames; - - for (i = 1; i <= cnt; i++) { - if (trav) { - gf_proc_dump_add_section("%s.frame.%d", prefix, i); - gf_proc_dump_call_frame(trav, "%s.frame.%d", prefix, i); - trav = trav->next; - } - } + int ret = -1; + char key[GF_DUMP_MAX_BUF_LEN] = { + 0, + }; + call_frame_t *trav = NULL; + int i = 0; + int count = 0; + + if (!call_stack || !dict) + return; + + count = call_frames_count(call_stack); + snprintf(key, sizeof(key), "%s.uid", prefix); + ret = dict_set_int32(dict, key, call_stack->uid); + if (ret) + return; + + snprintf(key, sizeof(key), "%s.gid", prefix); + ret = dict_set_int32(dict, key, call_stack->gid); + if (ret) + return; + + snprintf(key, sizeof(key), "%s.pid", prefix); + ret = dict_set_int32(dict, key, call_stack->pid); + if (ret) + return; + + snprintf(key, sizeof(key), "%s.unique", prefix); + ret = dict_set_uint64(dict, key, call_stack->unique); + if (ret) + return; + + snprintf(key, sizeof(key), "%s.op", prefix); + if (call_stack->type == GF_OP_TYPE_FOP) + ret = dict_set_str(dict, key, (char *)gf_fop_list[call_stack->op]); + else + ret = dict_set_str(dict, key, "other"); + + if (ret) + return; + + snprintf(key, sizeof(key), "%s.type", prefix); + ret = dict_set_int32(dict, key, call_stack->type); + if (ret) + return; + + snprintf(key, sizeof(key), "%s.count", prefix); + ret = dict_set_int32(dict, key, count); + if (ret) + return; + + list_for_each_entry(trav, &call_stack->myframes, frames) + { + snprintf(key, sizeof(key), "%s.frame%d", prefix, i); + gf_proc_dump_call_frame_to_dict(trav, key, dict); + i++; + } + + return; } void -gf_proc_dump_pending_frames (call_pool_t *call_pool) +gf_proc_dump_pending_frames_to_dict(call_pool_t *call_pool, dict_t *dict) { - - call_stack_t *trav = NULL; - int i = 1; - int ret = -1; - - if (!call_pool) - return; - - ret = TRY_LOCK (&(call_pool->lock)); - if (ret) { - gf_log("", GF_LOG_WARNING, "Unable to dump call pool" - " errno: %d", errno); - return; - } - - - gf_proc_dump_add_section("global.callpool"); - gf_proc_dump_write("global.callpool","%p", call_pool); - gf_proc_dump_write("global.callpool.cnt","%d", call_pool->cnt); - - - list_for_each_entry (trav, &call_pool->all_frames, all_frames) { - gf_proc_dump_add_section("global.callpool.stack.%d",i); - gf_proc_dump_call_stack(trav, "global.callpool.stack.%d", i); - i++; - } - UNLOCK (&(call_pool->lock)); + int ret = -1; + call_stack_t *trav = NULL; + char key[GF_DUMP_MAX_BUF_LEN] = { + 0, + }; + int i = 0; + + if (!call_pool || !dict) + return; + + ret = TRY_LOCK(&call_pool->lock); + if (ret) { + gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_LOCK_FAILURE, + "Unable to dump call " + "pool to dict."); + return; + } + + ret = dict_set_int32(dict, "callpool.count", call_pool->cnt); + if (ret) + goto out; + + list_for_each_entry(trav, &call_pool->all_frames, all_frames) + { + snprintf(key, sizeof(key), "callpool.stack%d", i); + gf_proc_dump_call_stack_to_dict(trav, key, dict); + i++; + } + +out: + UNLOCK(&call_pool->lock); + + return; } +gf_boolean_t +__is_fuse_call(call_frame_t *frame) +{ + gf_boolean_t is_fuse_call = _gf_false; + GF_ASSERT(frame); + GF_ASSERT(frame->root); + + if (NFS_PID != frame->root->pid) + is_fuse_call = _gf_true; + return is_fuse_call; +} diff --git a/libglusterfs/src/stack.h b/libglusterfs/src/stack.h deleted file mode 100644 index 55bcecc4b80..00000000000 --- a/libglusterfs/src/stack.h +++ /dev/null @@ -1,403 +0,0 @@ -/* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -/* - This file defines MACROS and static inlines used to emulate a function - call over asynchronous communication with remote server -*/ - -#ifndef _STACK_H -#define _STACK_H - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -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; - -#include <sys/time.h> - -#include "xlator.h" -#include "dict.h" -#include "list.h" -#include "common-utils.h" -#include "globals.h" - -typedef int32_t (*ret_fn_t) (call_frame_t *frame, - call_frame_t *prev_frame, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - ...); - -struct _call_pool_t { - union { - struct list_head all_frames; - struct { - call_stack_t *next_call; - call_stack_t *prev_call; - } all_stacks; - }; - int64_t cnt; - gf_lock_t lock; - struct mem_pool *frame_mem_pool; - struct mem_pool *stack_mem_pool; -}; - -struct _call_frame_t { - call_stack_t *root; /* stack root */ - call_frame_t *parent; /* previous BP */ - call_frame_t *next; - call_frame_t *prev; /* maintainence list */ - void *local; /* local variables */ - xlator_t *this; /* implicit object */ - ret_fn_t ret; /* op_return address */ - int32_t ref_count; - gf_lock_t lock; - void *cookie; /* unique cookie */ - gf_boolean_t complete; - - glusterfs_fop_t op; - struct timeval begin; /* when this frame was created */ - struct timeval end; /* when this frame completed */ -}; - -struct _call_stack_t { - union { - struct list_head all_frames; - struct { - call_stack_t *next_call; - call_stack_t *prev_call; - }; - }; - call_pool_t *pool; - void *trans; - uint64_t unique; - void *state; /* pointer to request state */ - uid_t uid; - gid_t gid; - pid_t pid; - uint32_t ngrps; - uint32_t groups[GF_REQUEST_MAXGROUPS]; - uint64_t lk_owner; - - call_frame_t frames; - - int32_t op; - int8_t type; -}; - - -#define frame_set_uid_gid(frm, u, g) \ - do { \ - if (frm) { \ - (frm)->root->uid = u; \ - (frm)->root->gid = g; \ - (frm)->root->ngrps = 0; \ - } \ - } while (0); \ - -struct xlator_fops; - -void -gf_set_fop_from_fn_pointer (call_frame_t *frame, struct xlator_fops *fops, - void *fn); - -void -gf_update_latency (call_frame_t *frame); - -static inline void -FRAME_DESTROY (call_frame_t *frame) -{ - void *local = NULL; - if (frame->next) - frame->next->prev = frame->prev; - if (frame->prev) - frame->prev->next = frame->next; - if (frame->local) { - local = frame->local; - frame->local = NULL; - - } - - LOCK_DESTROY (&frame->lock); - mem_put (frame->root->pool->frame_mem_pool, frame); - - if (local) - GF_FREE (local); -} - - -static inline void -STACK_DESTROY (call_stack_t *stack) -{ - glusterfs_ctx_t *ctx = glusterfs_ctx_get (); - void *local = NULL; - - if (ctx && ctx->measure_latency) { - gettimeofday (&stack->frames.end, NULL); - gf_update_latency (&stack->frames); - } - - LOCK (&stack->pool->lock); - { - list_del_init (&stack->all_frames); - stack->pool->cnt--; - } - UNLOCK (&stack->pool->lock); - - if (stack->frames.local) { - local = stack->frames.local; - stack->frames.local = NULL; - } - - LOCK_DESTROY (&stack->frames.lock); - - while (stack->frames.next) { - if (ctx && ctx->measure_latency) { - gf_update_latency (stack->frames.next); - } - - FRAME_DESTROY (stack->frames.next); - } - mem_put (stack->pool->stack_mem_pool, stack); - - if (local) - GF_FREE (local); -} - - -#define cbk(x) cbk_##x - - -/* make a call */ -#define STACK_WIND(frame, rfn, obj, fn, params ...) \ - do { \ - call_frame_t *_new = NULL; \ - xlator_t *old_THIS = NULL; \ - \ - _new = mem_get0 (frame->root->pool->frame_mem_pool); \ - if (!_new) { \ - gf_log ("stack", GF_LOG_ERROR, "alloc failed"); \ - break; \ - } \ - typeof(fn##_cbk) tmp_cbk = rfn; \ - _new->root = frame->root; \ - _new->next = frame->root->frames.next; \ - _new->prev = &frame->root->frames; \ - if (frame->root->frames.next) \ - frame->root->frames.next->prev = _new; \ - frame->root->frames.next = _new; \ - _new->this = obj; \ - _new->ret = (ret_fn_t) tmp_cbk; \ - _new->parent = frame; \ - _new->cookie = _new; \ - LOCK_INIT (&_new->lock); \ - frame->ref_count++; \ - \ - if (((xlator_t *) obj)->ctx->measure_latency) { \ - gettimeofday (&_new->begin, NULL); \ - gf_set_fop_from_fn_pointer (_new, ((xlator_t *)obj)->fops, fn); \ - } \ - \ - old_THIS = THIS; \ - THIS = obj; \ - fn (_new, obj, params); \ - THIS = old_THIS; \ - } while (0) - - -/* make a call with a cookie */ -#define STACK_WIND_COOKIE(frame, rfn, cky, obj, fn, params ...) \ - do { \ - call_frame_t *_new = NULL; \ - xlator_t *old_THIS = NULL; \ - \ - _new = mem_get0 (frame->root->pool->frame_mem_pool); \ - if (!_new) { \ - gf_log ("stack", GF_LOG_ERROR, "alloc failed"); \ - break; \ - } \ - typeof(fn##_cbk) tmp_cbk = rfn; \ - _new->root = frame->root; \ - _new->next = frame->root->frames.next; \ - _new->prev = &frame->root->frames; \ - if (frame->root->frames.next) \ - frame->root->frames.next->prev = _new; \ - frame->root->frames.next = _new; \ - _new->this = obj; \ - _new->ret = (ret_fn_t) tmp_cbk; \ - _new->parent = frame; \ - _new->cookie = cky; \ - LOCK_INIT (&_new->lock); \ - frame->ref_count++; \ - fn##_cbk = rfn; \ - \ - if (((xlator_t *) obj)->ctx->measure_latency) { \ - gettimeofday (&_new->begin, NULL); \ - gf_set_fop_from_fn_pointer (_new, ((xlator_t *)obj)->fops, fn); \ - } \ - \ - old_THIS = THIS; \ - THIS = obj; \ - fn (_new, obj, params); \ - THIS = old_THIS; \ - } while (0) - - -/* return from function */ -#define STACK_UNWIND(frame, params ...) \ - do { \ - ret_fn_t fn = NULL; \ - call_frame_t *_parent = NULL; \ - xlator_t *old_THIS = NULL; \ - if (!frame) { \ - gf_log ("stack", GF_LOG_CRITICAL, "!frame"); \ - break; \ - } \ - fn = frame->ret; \ - _parent = frame->parent; \ - _parent->ref_count--; \ - old_THIS = THIS; \ - THIS = _parent->this; \ - frame->complete = _gf_true; \ - \ - if (((xlator_t *) old_THIS)->ctx->measure_latency) { \ - gettimeofday (&frame->end, NULL); \ - } \ - \ - fn (_parent, frame->cookie, _parent->this, params); \ - THIS = old_THIS; \ - } while (0) - - -/* return from function in type-safe way */ -#define STACK_UNWIND_STRICT(op, frame, params ...) \ - do { \ - fop_##op##_cbk_t fn = NULL; \ - call_frame_t *_parent = NULL; \ - xlator_t *old_THIS = NULL; \ - \ - if (!frame) { \ - gf_log ("stack", GF_LOG_CRITICAL, "!frame"); \ - break; \ - } \ - fn = (fop_##op##_cbk_t )frame->ret; \ - _parent = frame->parent; \ - _parent->ref_count--; \ - old_THIS = THIS; \ - THIS = _parent->this; \ - frame->complete = _gf_true; \ - \ - if (((xlator_t *) old_THIS)->ctx->measure_latency) { \ - gettimeofday (&frame->end, NULL); \ - } \ - \ - fn (_parent, frame->cookie, _parent->this, params); \ - THIS = old_THIS; \ - } while (0) - - -static inline call_frame_t * -copy_frame (call_frame_t *frame) -{ - call_stack_t *newstack = NULL; - call_stack_t *oldstack = NULL; - - if (!frame) { - return NULL; - } - - newstack = mem_get0 (frame->root->pool->stack_mem_pool); - if (newstack == NULL) { - return NULL; - } - - oldstack = frame->root; - - newstack->uid = oldstack->uid; - newstack->gid = oldstack->gid; - newstack->pid = oldstack->pid; - newstack->ngrps = oldstack->ngrps; - memcpy (newstack->groups, oldstack->groups, - sizeof (uint32_t) * GF_REQUEST_MAXGROUPS); - newstack->unique = oldstack->unique; - - newstack->frames.this = frame->this; - newstack->frames.root = newstack; - newstack->pool = oldstack->pool; - newstack->lk_owner = oldstack->lk_owner; - - LOCK_INIT (&newstack->frames.lock); - - LOCK (&oldstack->pool->lock); - { - list_add (&newstack->all_frames, &oldstack->all_frames); - newstack->pool->cnt++; - } - UNLOCK (&oldstack->pool->lock); - - return &newstack->frames; -} - - -static inline call_frame_t * -create_frame (xlator_t *xl, call_pool_t *pool) -{ - call_stack_t *stack = NULL; - glusterfs_ctx_t *ctx = glusterfs_ctx_get (); - - if (!xl || !pool) { - return NULL; - } - - stack = mem_get0 (pool->stack_mem_pool); - if (!stack) - return NULL; - - stack->pool = pool; - stack->frames.root = stack; - stack->frames.this = xl; - - LOCK (&pool->lock); - { - list_add (&stack->all_frames, &pool->all_frames); - pool->cnt++; - } - UNLOCK (&pool->lock); - - LOCK_INIT (&stack->frames.lock); - - if (ctx && ctx->measure_latency) { - gettimeofday (&stack->frames.begin, NULL); - } - - return &stack->frames; -} - -void -gf_proc_dump_pending_frames(call_pool_t *call_pool); - -#endif /* _STACK_H */ diff --git a/libglusterfs/src/statedump.c b/libglusterfs/src/statedump.c index 05f1a777fad..65f0eb5c7f3 100644 --- a/libglusterfs/src/statedump.c +++ b/libglusterfs/src/statedump.c @@ -1,458 +1,1053 @@ /* - Copyright (c) 2009 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 <stdarg.h> -#include "glusterfs.h" -#include "logging.h" -#include "iobuf.h" -#include "statedump.h" -#include "stack.h" +#include "glusterfs/glusterfs.h" +#include "glusterfs/logging.h" +#include "glusterfs/statedump.h" +#include "glusterfs/stack.h" +#include "glusterfs/syscall.h" #ifdef HAVE_MALLOC_H #include <malloc.h> #endif /* MALLOC_H */ +/* We don't want gf_log in this function because it may cause + 'deadlock' with statedump. This is because statedump happens + inside a signal handler and cannot afford to block on a lock.*/ +#ifdef gf_log +#undef gf_log +#endif -#define GF_PROC_DUMP_IS_OPTION_ENABLED(opt) \ - (dump_options.dump_##opt == _gf_true) +#define GF_PROC_DUMP_IS_OPTION_ENABLED(opt) \ + (dump_options.dump_##opt == _gf_true) -#define GF_PROC_DUMP_IS_XL_OPTION_ENABLED(opt)\ - (dump_options.xl_options.dump_##opt == _gf_true) +#define GF_PROC_DUMP_IS_XL_OPTION_ENABLED(opt) \ + (dump_options.xl_options.dump_##opt == _gf_true) extern xlator_t global_xlator; -static pthread_mutex_t gf_proc_dump_mutex; +static pthread_mutex_t gf_proc_dump_mutex; static int gf_dump_fd = -1; -static gf_dump_options_t dump_options; +gf_dump_options_t dump_options; +static strfd_t *gf_dump_strfd = NULL; static void -gf_proc_dump_lock (void) +gf_proc_dump_lock(void) { - pthread_mutex_lock (&gf_proc_dump_mutex); + pthread_mutex_lock(&gf_proc_dump_mutex); } - static void -gf_proc_dump_unlock (void) +gf_proc_dump_unlock(void) +{ + pthread_mutex_unlock(&gf_proc_dump_mutex); +} + +static int +gf_proc_dump_open(char *tmpname) { - pthread_mutex_unlock (&gf_proc_dump_mutex); + int dump_fd = -1; + + mode_t mask = umask(S_IRWXG | S_IRWXO); + dump_fd = mkstemp(tmpname); + umask(mask); + if (dump_fd < 0) + return -1; + + gf_dump_fd = dump_fd; + return 0; } +static void +gf_proc_dump_close(void) +{ + sys_close(gf_dump_fd); + gf_dump_fd = -1; +} static int -gf_proc_dump_open (void) +gf_proc_dump_set_path(char *dump_options_file) { - char path[256]; - int dump_fd = -1; + int ret = -1; + FILE *fp = NULL; + char buf[256]; + char *key = NULL, *value = NULL; + char *saveptr = NULL; + + fp = fopen(dump_options_file, "r"); + if (!fp) + goto out; + + ret = fscanf(fp, "%255s", buf); + + while (ret != EOF) { + key = strtok_r(buf, "=", &saveptr); + if (!key) { + ret = fscanf(fp, "%255s", buf); + continue; + } - memset (path, 0, sizeof (path)); - snprintf (path, sizeof (path), "%s.%d", GF_DUMP_LOGFILE_ROOT, getpid ()); + value = strtok_r(NULL, "=", &saveptr); - dump_fd = open (path, O_CREAT|O_RDWR|O_TRUNC|O_APPEND, 0600); - if (dump_fd < 0) { - gf_log("", GF_LOG_ERROR, "Unable to open file: %s" - " errno: %d", path, errno); - return -1; + if (!value) { + ret = fscanf(fp, "%255s", buf); + continue; } + if (!strcmp(key, "path")) { + dump_options.dump_path = gf_strdup(value); + break; + } + } - gf_dump_fd = dump_fd; - return 0; +out: + if (fp) + fclose(fp); + return ret; } +static int +gf_proc_dump_add_section_fd(char *key, va_list ap) +{ + char buf[GF_DUMP_MAX_BUF_LEN]; + int len; -static void -gf_proc_dump_close (void) + GF_ASSERT(key); + + len = snprintf(buf, GF_DUMP_MAX_BUF_LEN, "\n["); + len += vsnprintf(buf + len, GF_DUMP_MAX_BUF_LEN - len, key, ap); + len += snprintf(buf + len, GF_DUMP_MAX_BUF_LEN - len, "]\n"); + return sys_write(gf_dump_fd, buf, len); +} + +static int +gf_proc_dump_add_section_strfd(char *key, va_list ap) { - close (gf_dump_fd); - gf_dump_fd = -1; + int ret = 0; + + ret += strprintf(gf_dump_strfd, "["); + ret += strvprintf(gf_dump_strfd, key, ap); + ret += strprintf(gf_dump_strfd, "]\n"); + + return ret; } +int +gf_proc_dump_add_section(char *key, ...) +{ + va_list ap; + int ret = 0; -void -gf_proc_dump_add_section (char *key, ...) + va_start(ap, key); + if (gf_dump_strfd) + ret = gf_proc_dump_add_section_strfd(key, ap); + else + ret = gf_proc_dump_add_section_fd(key, ap); + va_end(ap); + + return ret; +} + +static int +gf_proc_dump_write_fd(char *key, char *value, va_list ap) { + char buf[GF_DUMP_MAX_BUF_LEN]; + int len = 0; - char buf[GF_DUMP_MAX_BUF_LEN]; - va_list ap; - int ret; + GF_ASSERT(key); - GF_ASSERT(key); + len = snprintf(buf, GF_DUMP_MAX_BUF_LEN, "%s=", key); + len += vsnprintf(buf + len, GF_DUMP_MAX_BUF_LEN - len, value, ap); - memset (buf, 0, sizeof(buf)); - snprintf (buf, GF_DUMP_MAX_BUF_LEN, "\n["); - va_start (ap, key); - vsnprintf (buf + strlen(buf), - GF_DUMP_MAX_BUF_LEN - strlen (buf), key, ap); - va_end (ap); - snprintf (buf + strlen(buf), - GF_DUMP_MAX_BUF_LEN - strlen (buf), "]\n"); - ret = write (gf_dump_fd, buf, strlen (buf)); - if (ret < 0) - gf_log("", GF_LOG_ERROR, "write error: %s", strerror(errno)); + len += snprintf(buf + len, GF_DUMP_MAX_BUF_LEN - len, "\n"); + return sys_write(gf_dump_fd, buf, len); } +static int +gf_proc_dump_write_strfd(char *key, char *value, va_list ap) +{ + int ret = 0; + + ret += strprintf(gf_dump_strfd, "%s = ", key); + ret += strvprintf(gf_dump_strfd, value, ap); + ret += strprintf(gf_dump_strfd, "\n"); + + return ret; +} + +int +gf_proc_dump_write(char *key, char *value, ...) +{ + int ret = 0; + va_list ap; + + va_start(ap, value); + if (gf_dump_strfd) + ret = gf_proc_dump_write_strfd(key, value, ap); + else + ret = gf_proc_dump_write_fd(key, value, ap); + va_end(ap); + + return ret; +} void -gf_proc_dump_write (char *key, char *value,...) +gf_latency_statedump_and_reset(char *key, gf_latency_t *lat) { + /* Doesn't make sense to continue if there are no fops + came in the given interval */ + if (!lat || !lat->count) + return; + gf_proc_dump_write(key, + "AVG:%lf CNT:%" PRIu64 " TOTAL:%" PRIu64 " MIN:%" PRIu64 + " MAX:%" PRIu64, + (((double)lat->total) / lat->count), lat->count, + lat->total, lat->min, lat->max); + gf_latency_reset(lat); +} - char buf[GF_DUMP_MAX_BUF_LEN]; - int offset = 0; - va_list ap; - int ret; +void +gf_proc_dump_xl_latency_info(xlator_t *xl) +{ + char key_prefix[GF_DUMP_MAX_BUF_LEN]; + char key[GF_DUMP_MAX_BUF_LEN]; + int i; - GF_ASSERT (key); + snprintf(key_prefix, GF_DUMP_MAX_BUF_LEN, "%s.latency", xl->name); + gf_proc_dump_add_section("%s", key_prefix); - offset = strlen (key); + for (i = 0; i < GF_FOP_MAXVALUE; i++) { + gf_proc_dump_build_key(key, key_prefix, "%s", (char *)gf_fop_list[i]); - memset (buf, 0, GF_DUMP_MAX_BUF_LEN); - snprintf (buf, GF_DUMP_MAX_BUF_LEN, "%s", key); - snprintf (buf + offset, GF_DUMP_MAX_BUF_LEN - offset, "="); - offset += 1; - va_start (ap, value); - vsnprintf (buf + offset, GF_DUMP_MAX_BUF_LEN - offset, value, ap); - va_end (ap); + gf_latency_t *lat = &xl->stats.interval.latencies[i]; - offset = strlen (buf); - snprintf (buf + offset, GF_DUMP_MAX_BUF_LEN - offset, "\n"); - ret = write (gf_dump_fd, buf, strlen (buf)); - if (ret < 0) - gf_log("", GF_LOG_ERROR, "write error: %s", strerror(errno)); + gf_latency_statedump_and_reset(key, lat); + } } static void -gf_proc_dump_xlator_mem_info (xlator_t *xl) -{ - char key[GF_DUMP_MAX_BUF_LEN]; - char prefix[GF_DUMP_MAX_BUF_LEN]; - int i = 0; - struct mem_acct rec = {0,}; - - if (!xl) - return; - - if (!xl->mem_acct.rec) - return; - - gf_proc_dump_add_section ("%s.%s - Memory usage", xl->type,xl->name); - gf_proc_dump_write ("num_types", "%d", xl->mem_acct.num_types); - - for (i = 0; i < xl->mem_acct.num_types; i++) { - if (!(memcmp (&xl->mem_acct.rec[i], &rec, - sizeof (struct mem_acct)))) - continue; - - gf_proc_dump_add_section ("%s.%s - usage-type %d", xl->type, - xl->name,i); - gf_proc_dump_build_key (prefix, "memusage", "%s.%s.type.%d", - xl->type, xl->name, i); - gf_proc_dump_build_key (key, prefix, "size"); - gf_proc_dump_write (key, "%u", xl->mem_acct.rec[i].size); - gf_proc_dump_build_key (key, prefix, "num_allocs"); - gf_proc_dump_write (key, "%u", xl->mem_acct.rec[i].num_allocs); - gf_proc_dump_build_key (key, prefix, "max_size"); - gf_proc_dump_write (key, "%u", xl->mem_acct.rec[i].max_size); - gf_proc_dump_build_key (key, prefix, "max_num_allocs"); - gf_proc_dump_write (key, "%u", xl->mem_acct.rec[i].max_num_allocs); - } +gf_proc_dump_xlator_mem_info(xlator_t *xl) +{ + int i = 0; + + if (!xl) + return; + if (!xl->mem_acct) return; + + gf_proc_dump_add_section("%s.%s - Memory usage", xl->type, xl->name); + gf_proc_dump_write("num_types", "%d", xl->mem_acct->num_types); + + for (i = 0; i < xl->mem_acct->num_types; i++) { + if (xl->mem_acct->rec[i].num_allocs == 0) + continue; + + gf_proc_dump_add_section("%s.%s - usage-type %s memusage", xl->type, + xl->name, xl->mem_acct->rec[i].typestr); + gf_proc_dump_write("size", "%" PRIu64, xl->mem_acct->rec[i].size); + gf_proc_dump_write("num_allocs", "%u", xl->mem_acct->rec[i].num_allocs); + gf_proc_dump_write("max_size", "%" PRIu64, + xl->mem_acct->rec[i].max_size); + gf_proc_dump_write("max_num_allocs", "%u", + xl->mem_acct->rec[i].max_num_allocs); + gf_proc_dump_write("total_allocs", "%" PRIu64, + xl->mem_acct->rec[i].total_allocs); + } + + return; } +static void +gf_proc_dump_xlator_mem_info_only_in_use(xlator_t *xl) +{ + int i = 0; + if (!xl) + return; + + if (!xl->mem_acct) + return; + + gf_proc_dump_add_section("%s.%s - Memory usage", xl->type, xl->name); + gf_proc_dump_write("num_types", "%d", xl->mem_acct->num_types); + + for (i = 0; i < xl->mem_acct->num_types; i++) { + if (!xl->mem_acct->rec[i].size) + continue; + + gf_proc_dump_add_section("%s.%s - usage-type %d", xl->type, xl->name, + i); + + gf_proc_dump_write("size", "%" PRIu64, xl->mem_acct->rec[i].size); + gf_proc_dump_write("max_size", "%" PRIu64, + xl->mem_acct->rec[i].max_size); + gf_proc_dump_write("num_allocs", "%u", xl->mem_acct->rec[i].num_allocs); + gf_proc_dump_write("max_num_allocs", "%u", + xl->mem_acct->rec[i].max_num_allocs); + gf_proc_dump_write("total_allocs", "%" PRIu64, + xl->mem_acct->rec[i].total_allocs); + } + + return; +} /* Currently this dumps only mallinfo. More can be built on here */ void -gf_proc_dump_mem_info () -{ -#ifdef HAVE_MALLOC_STATS - struct mallinfo info; - - memset (&info, 0, sizeof (struct mallinfo)); - info = mallinfo (); - - gf_proc_dump_add_section ("mallinfo"); - gf_proc_dump_write ("mallinfo_arena", "%d", info.arena); - gf_proc_dump_write ("mallinfo_ordblks", "%d", info.ordblks); - gf_proc_dump_write ("mallinfo_smblks", "%d", info.smblks); - gf_proc_dump_write ("mallinfo_hblks", "%d", info.hblks); - gf_proc_dump_write ("mallinfo_hblkhd", "%d", info.hblkhd); - gf_proc_dump_write ("mallinfo_usmblks", "%d", info.usmblks); - gf_proc_dump_write ("mallinfo_fsmblks", "%d", info.fsmblks); - gf_proc_dump_write ("mallinfo_uordblks", "%d", info.uordblks); - gf_proc_dump_write ("mallinfo_fordblks", "%d", info.fordblks); - gf_proc_dump_write ("mallinfo_keepcost", "%d", info.keepcost); +gf_proc_dump_mem_info() +{ +#ifdef HAVE_MALLINFO + struct mallinfo info; + + memset(&info, 0, sizeof(struct mallinfo)); + info = mallinfo(); + + gf_proc_dump_add_section("mallinfo"); + gf_proc_dump_write("mallinfo_arena", "%d", info.arena); + gf_proc_dump_write("mallinfo_ordblks", "%d", info.ordblks); + gf_proc_dump_write("mallinfo_smblks", "%d", info.smblks); + gf_proc_dump_write("mallinfo_hblks", "%d", info.hblks); + gf_proc_dump_write("mallinfo_hblkhd", "%d", info.hblkhd); + gf_proc_dump_write("mallinfo_usmblks", "%d", info.usmblks); + gf_proc_dump_write("mallinfo_fsmblks", "%d", info.fsmblks); + gf_proc_dump_write("mallinfo_uordblks", "%d", info.uordblks); + gf_proc_dump_write("mallinfo_fordblks", "%d", info.fordblks); + gf_proc_dump_write("mallinfo_keepcost", "%d", info.keepcost); #endif - gf_proc_dump_xlator_mem_info(&global_xlator); + gf_proc_dump_xlator_mem_info(&global_xlator); +} + +void +gf_proc_dump_mem_info_to_dict(dict_t *dict) +{ + if (!dict) + return; +#ifdef HAVE_MALLINFO + struct mallinfo info; + int ret = -1; + + memset(&info, 0, sizeof(struct mallinfo)); + info = mallinfo(); + + ret = dict_set_int32(dict, "mallinfo.arena", info.arena); + if (ret) + return; + + ret = dict_set_int32(dict, "mallinfo.ordblks", info.ordblks); + if (ret) + return; + + ret = dict_set_int32(dict, "mallinfo.smblks", info.smblks); + if (ret) + return; + + ret = dict_set_int32(dict, "mallinfo.hblks", info.hblks); + if (ret) + return; + + ret = dict_set_int32(dict, "mallinfo.hblkhd", info.hblkhd); + if (ret) + return; + ret = dict_set_int32(dict, "mallinfo.usmblks", info.usmblks); + if (ret) + return; + + ret = dict_set_int32(dict, "mallinfo.fsmblks", info.fsmblks); + if (ret) + return; + + ret = dict_set_int32(dict, "mallinfo.uordblks", info.uordblks); + if (ret) + return; + + ret = dict_set_int32(dict, "mallinfo.fordblks", info.fordblks); + if (ret) + return; + + ret = dict_set_int32(dict, "mallinfo.keepcost", info.keepcost); + if (ret) + return; +#endif + return; } -void gf_proc_dump_latency_info (xlator_t *xl); +void +gf_proc_dump_mempool_info(glusterfs_ctx_t *ctx) +{ +#ifdef GF_DISABLE_MEMPOOL + gf_proc_dump_write("built with --disable-mempool", " so no memory pools"); +#else + struct mem_pool *pool = NULL; + + gf_proc_dump_add_section("mempool"); + + LOCK(&ctx->lock); + { + list_for_each_entry(pool, &ctx->mempool_list, owner) + { + int64_t active = GF_ATOMIC_GET(pool->active); + + gf_proc_dump_write("-----", "-----"); + gf_proc_dump_write("pool-name", "%s", pool->name); + gf_proc_dump_write("xlator-name", "%s", pool->xl_name); + gf_proc_dump_write("active-count", "%" GF_PRI_ATOMIC, active); + gf_proc_dump_write("sizeof-type", "%lu", pool->sizeof_type); + gf_proc_dump_write("padded-sizeof", "%d", + 1 << pool->pool->power_of_two); + gf_proc_dump_write("size", "%" PRId64, + (1 << pool->pool->power_of_two) * active); + gf_proc_dump_write("shared-pool", "%p", pool->pool); + } + } + UNLOCK(&ctx->lock); +#endif /* GF_DISABLE_MEMPOOL */ +} void -gf_proc_dump_xlator_info (xlator_t *this_xl) -{ - glusterfs_ctx_t *ctx = NULL; - xlator_t *fuse_xlator, *this_xlator; - - if (!this_xl) - return; - - ctx = glusterfs_ctx_get (); - if (!ctx) - return; - - if (ctx->master){ - - gf_log ("", GF_LOG_DEBUG, "Dumping Proc for fuse Xlator"); - fuse_xlator = (xlator_t *) ctx->master; - - if (!fuse_xlator->dumpops) - return; - - if (fuse_xlator->dumpops->priv && - GF_PROC_DUMP_IS_XL_OPTION_ENABLED (priv)) - fuse_xlator->dumpops->priv (fuse_xlator); - - if (fuse_xlator->dumpops->inode && - GF_PROC_DUMP_IS_XL_OPTION_ENABLED (inode)) { - - if (!ctx->active) - return; - this_xlator = (xlator_t *) ctx->active->top; - - if (this_xlator && this_xlator->itable) - inode_table_dump (this_xlator->itable, - "xlator.mount.fuse.itable"); - else - return; - } - - if (fuse_xlator->dumpops->fd && - GF_PROC_DUMP_IS_XL_OPTION_ENABLED (fd)) - fuse_xlator->dumpops->fd (fuse_xlator); - } - - - while (this_xl) { - - if (ctx->measure_latency) - gf_proc_dump_latency_info (this_xl); - - gf_proc_dump_xlator_mem_info(this_xl); - - if (!this_xl->dumpops) { - this_xl = this_xl->next; - continue; - } - - if (this_xl->dumpops->priv && - GF_PROC_DUMP_IS_XL_OPTION_ENABLED (priv)) - this_xl->dumpops->priv (this_xl); - - if (this_xl->dumpops->inode && - GF_PROC_DUMP_IS_XL_OPTION_ENABLED (inode)) - this_xl->dumpops->inode (this_xl); - - - if (this_xl->dumpops->fd && - GF_PROC_DUMP_IS_XL_OPTION_ENABLED (fd)) - this_xl->dumpops->fd (this_xl); - - this_xl = this_xl->next; +gf_proc_dump_mempool_info_to_dict(glusterfs_ctx_t *ctx, dict_t *dict) +{ +#ifndef GF_DISABLE_MEMPOOL + struct mem_pool *pool = NULL; + char key[GF_DUMP_MAX_BUF_LEN] = { + 0, + }; + int count = 0; + int ret = -1; + + if (!ctx || !dict) + return; + + LOCK(&ctx->lock); + { + list_for_each_entry(pool, &ctx->mempool_list, owner) + { + int64_t active = GF_ATOMIC_GET(pool->active); + + snprintf(key, sizeof(key), "pool%d.name", count); + ret = dict_set_str(dict, key, pool->name); + if (ret) + goto out; + + snprintf(key, sizeof(key), "pool%d.active-count", count); + ret = dict_set_uint64(dict, key, active); + if (ret) + goto out; + + snprintf(key, sizeof(key), "pool%d.sizeof-type", count); + ret = dict_set_uint64(dict, key, pool->sizeof_type); + if (ret) + goto out; + + snprintf(key, sizeof(key), "pool%d.padded-sizeof", count); + ret = dict_set_uint64(dict, key, 1 << pool->pool->power_of_two); + if (ret) + goto out; + + snprintf(key, sizeof(key), "pool%d.size", count); + ret = dict_set_uint64(dict, key, + (1 << pool->pool->power_of_two) * active); + if (ret) + goto out; + + snprintf(key, sizeof(key), "pool%d.shared-pool", count); + ret = dict_set_static_ptr(dict, key, pool->pool); + if (ret) + goto out; } + } +out: + UNLOCK(&ctx->lock); +#endif /* !GF_DISABLE_MEMPOOL */ +} + +void +gf_proc_dump_latency_info(xlator_t *xl); + +void +gf_proc_dump_dict_info(glusterfs_ctx_t *ctx) +{ + int64_t total_dicts = 0; + int64_t total_pairs = 0; + + total_dicts = GF_ATOMIC_GET(ctx->stats.total_dicts_used); + total_pairs = GF_ATOMIC_GET(ctx->stats.total_pairs_used); + + gf_proc_dump_write("max-pairs-per-dict", "%" GF_PRI_ATOMIC, + GF_ATOMIC_GET(ctx->stats.max_dict_pairs)); + gf_proc_dump_write("total-pairs-used", "%" PRId64, total_pairs); + gf_proc_dump_write("total-dicts-used", "%" PRId64, total_dicts); + gf_proc_dump_write("average-pairs-per-dict", "%" PRId64, + (total_pairs / total_dicts)); +} + +static void +gf_proc_dump_single_xlator_info(xlator_t *trav) +{ + glusterfs_ctx_t *ctx = trav->ctx; + char itable_key[1024] = { + 0, + }; + if (trav->cleanup_starting) return; + + if (ctx->measure_latency) + gf_proc_dump_xl_latency_info(trav); + + gf_proc_dump_xlator_mem_info(trav); + + if (GF_PROC_DUMP_IS_XL_OPTION_ENABLED(inode) && (trav->itable)) { + snprintf(itable_key, sizeof(itable_key), "%d.%s.itable", ctx->graph_id, + trav->name); + } + + if (!trav->dumpops) { + return; + } + + if (trav->dumpops->priv && GF_PROC_DUMP_IS_XL_OPTION_ENABLED(priv)) + trav->dumpops->priv(trav); + + if (GF_PROC_DUMP_IS_XL_OPTION_ENABLED(inode) && (trav->dumpops->inode)) + trav->dumpops->inode(trav); + if (trav->dumpops->fd && GF_PROC_DUMP_IS_XL_OPTION_ENABLED(fd)) + trav->dumpops->fd(trav); + + if (trav->dumpops->history && GF_PROC_DUMP_IS_XL_OPTION_ENABLED(history)) + trav->dumpops->history(trav); } -static int -gf_proc_dump_parse_set_option (char *key, char *value) -{ - gf_boolean_t *opt_key = NULL; - gf_boolean_t opt_value = _gf_false; - - - if (!strncasecmp (key, "mem", 3)) { - opt_key = &dump_options.dump_mem; - } else if (!strncasecmp (key, "iobuf", 5)) { - opt_key = &dump_options.dump_iobuf; - } else if (!strncasecmp (key, "callpool", 8)) { - opt_key = &dump_options.dump_callpool; - } else if (!strncasecmp (key, "priv", 4)) { - opt_key = &dump_options.xl_options.dump_priv; - } else if (!strncasecmp (key, "fd", 2)) { - opt_key = &dump_options.xl_options.dump_fd; - } else if (!strncasecmp (key, "inode", 5)) { - opt_key = &dump_options.xl_options.dump_inode; + +static void +gf_proc_dump_per_xlator_info(xlator_t *top) +{ + xlator_t *trav = top; + + while (trav && !trav->cleanup_starting) { + gf_proc_dump_single_xlator_info(trav); + trav = trav->next; + } +} + +void +gf_proc_dump_xlator_info(xlator_t *top, gf_boolean_t brick_mux) +{ + xlator_t *trav = NULL; + xlator_list_t **trav_p = NULL; + + if (!top) + return; + + trav = top; + gf_proc_dump_per_xlator_info(trav); + + if (brick_mux) { + trav_p = &top->children; + while (*trav_p) { + trav = (*trav_p)->xlator; + gf_proc_dump_per_xlator_info(trav); + trav_p = &(*trav_p)->next; + } + } + + return; +} + +static void +gf_proc_dump_oldgraph_xlator_info(xlator_t *top) +{ + xlator_t *trav = NULL; + + if (!top) + return; + + trav = top; + while (trav) { + gf_proc_dump_xlator_mem_info_only_in_use(trav); + + if (GF_PROC_DUMP_IS_XL_OPTION_ENABLED(inode) && (trav->itable)) { + /*TODO: dump inode table info if necessary by + printing the graph id (taken by glusterfs_cbtx_t) + in the key + */ } - if (!opt_key) { - //None of dump options match the key, return back - gf_log ("", GF_LOG_WARNING, "None of the options matched key" - ": %s", key); - return -1; + if (!trav->dumpops) { + trav = trav->next; + continue; } - opt_value = (strncasecmp (value, "yes", 3) ? - _gf_false: _gf_true); + if (GF_PROC_DUMP_IS_XL_OPTION_ENABLED(inode) && (trav->dumpops->inode)) + trav->dumpops->inode(trav); - GF_PROC_DUMP_SET_OPTION (*opt_key, opt_value); + if (trav->dumpops->fd && GF_PROC_DUMP_IS_XL_OPTION_ENABLED(fd)) + trav->dumpops->fd(trav); - return 0; -} + trav = trav->next; + } + return; +} static int -gf_proc_dump_enable_all_options () +gf_proc_dump_enable_all_options() { + GF_PROC_DUMP_SET_OPTION(dump_options.dump_mem, _gf_true); + GF_PROC_DUMP_SET_OPTION(dump_options.dump_iobuf, _gf_true); + GF_PROC_DUMP_SET_OPTION(dump_options.dump_callpool, _gf_true); + GF_PROC_DUMP_SET_OPTION(dump_options.xl_options.dump_priv, _gf_true); + GF_PROC_DUMP_SET_OPTION(dump_options.xl_options.dump_inode, _gf_true); + GF_PROC_DUMP_SET_OPTION(dump_options.xl_options.dump_fd, _gf_true); + GF_PROC_DUMP_SET_OPTION(dump_options.xl_options.dump_inodectx, _gf_true); + GF_PROC_DUMP_SET_OPTION(dump_options.xl_options.dump_fdctx, _gf_true); + GF_PROC_DUMP_SET_OPTION(dump_options.xl_options.dump_history, _gf_true); + + return 0; +} - GF_PROC_DUMP_SET_OPTION (dump_options.dump_mem, _gf_true); - GF_PROC_DUMP_SET_OPTION (dump_options.dump_iobuf, _gf_true); - GF_PROC_DUMP_SET_OPTION (dump_options.dump_callpool, _gf_true); - GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_priv, _gf_true); - GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_inode, _gf_true); - GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_fd, _gf_true); +gf_boolean_t +is_gf_proc_dump_all_disabled() +{ + gf_boolean_t all_disabled = _gf_true; + + GF_CHECK_DUMP_OPTION_ENABLED(dump_options.dump_mem, all_disabled, out); + GF_CHECK_DUMP_OPTION_ENABLED(dump_options.dump_iobuf, all_disabled, out); + GF_CHECK_DUMP_OPTION_ENABLED(dump_options.dump_callpool, all_disabled, out); + GF_CHECK_DUMP_OPTION_ENABLED(dump_options.xl_options.dump_priv, + all_disabled, out); + GF_CHECK_DUMP_OPTION_ENABLED(dump_options.xl_options.dump_inode, + all_disabled, out); + GF_CHECK_DUMP_OPTION_ENABLED(dump_options.xl_options.dump_fd, all_disabled, + out); + GF_CHECK_DUMP_OPTION_ENABLED(dump_options.xl_options.dump_inodectx, + all_disabled, out); + GF_CHECK_DUMP_OPTION_ENABLED(dump_options.xl_options.dump_fdctx, + all_disabled, out); + GF_CHECK_DUMP_OPTION_ENABLED(dump_options.xl_options.dump_history, + all_disabled, out); - return 0; +out: + return all_disabled; } +/* These options are dumped by default if glusterdump.options + file exists and it is emtpty +*/ static int -gf_proc_dump_disable_all_options () +gf_proc_dump_enable_default_options() { + GF_PROC_DUMP_SET_OPTION(dump_options.dump_mem, _gf_true); + GF_PROC_DUMP_SET_OPTION(dump_options.dump_callpool, _gf_true); - GF_PROC_DUMP_SET_OPTION (dump_options.dump_mem, _gf_false); - GF_PROC_DUMP_SET_OPTION (dump_options.dump_iobuf, _gf_false); - GF_PROC_DUMP_SET_OPTION (dump_options.dump_callpool, _gf_false); - GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_priv, _gf_false); - GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_inode, - _gf_false); - GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_fd, _gf_false); + return 0; +} +static int +gf_proc_dump_disable_all_options() +{ + GF_PROC_DUMP_SET_OPTION(dump_options.dump_mem, _gf_false); + GF_PROC_DUMP_SET_OPTION(dump_options.dump_iobuf, _gf_false); + GF_PROC_DUMP_SET_OPTION(dump_options.dump_callpool, _gf_false); + GF_PROC_DUMP_SET_OPTION(dump_options.xl_options.dump_priv, _gf_false); + GF_PROC_DUMP_SET_OPTION(dump_options.xl_options.dump_inode, _gf_false); + GF_PROC_DUMP_SET_OPTION(dump_options.xl_options.dump_fd, _gf_false); + GF_PROC_DUMP_SET_OPTION(dump_options.xl_options.dump_inodectx, _gf_false); + GF_PROC_DUMP_SET_OPTION(dump_options.xl_options.dump_fdctx, _gf_false); + GF_PROC_DUMP_SET_OPTION(dump_options.xl_options.dump_history, _gf_false); + return 0; +} + +static int +gf_proc_dump_parse_set_option(char *key, char *value) +{ + gf_boolean_t *opt_key = NULL; + gf_boolean_t opt_value = _gf_false; + char buf[GF_DUMP_MAX_BUF_LEN]; + int ret = -1; + int len; + + if (!strcasecmp(key, "all")) { + (void)gf_proc_dump_enable_all_options(); return 0; + } else if (!strcasecmp(key, "mem")) { + opt_key = &dump_options.dump_mem; + } else if (!strcasecmp(key, "iobuf")) { + opt_key = &dump_options.dump_iobuf; + } else if (!strcasecmp(key, "callpool")) { + opt_key = &dump_options.dump_callpool; + } else if (!strcasecmp(key, "priv")) { + opt_key = &dump_options.xl_options.dump_priv; + } else if (!strcasecmp(key, "fd")) { + opt_key = &dump_options.xl_options.dump_fd; + } else if (!strcasecmp(key, "inode")) { + opt_key = &dump_options.xl_options.dump_inode; + } else if (!strcasecmp(key, "inodectx")) { + opt_key = &dump_options.xl_options.dump_inodectx; + } else if (!strcasecmp(key, "fdctx")) { + opt_key = &dump_options.xl_options.dump_fdctx; + } else if (!strcasecmp(key, "history")) { + opt_key = &dump_options.xl_options.dump_history; + } + + if (!opt_key) { + // None of dump options match the key, return back + len = snprintf(buf, sizeof(buf), + "[Warning]:None of the options " + "matched key : %s\n", + key); + if (len < 0) + ret = -1; + else { + ret = sys_write(gf_dump_fd, buf, len); + if (ret >= 0) + ret = -1; + } + goto out; + } + + opt_value = (strncasecmp(value, "yes", 3) ? _gf_false : _gf_true); + + GF_PROC_DUMP_SET_OPTION(*opt_key, opt_value); + + ret = 0; +out: + return ret; } static int -gf_proc_dump_options_init () +gf_proc_dump_options_init() { - int ret = -1; - FILE *fp = NULL; - char buf[256]; - char *key = NULL, *value = NULL; - char *saveptr = NULL; - - - fp = fopen (GF_DUMP_OPTIONFILE, "r"); + int ret = -1; + FILE *fp = NULL; + char buf[256]; + char *key = NULL, *value = NULL; + char *saveptr = NULL; + char dump_option_file[PATH_MAX]; + + /* glusterd will create a file glusterdump.<pid>.options and + sets the statedump options for the process and the file is removed + after the statedump is taken. Direct issue of SIGUSR1 does not have + mechanism for considering the statedump options. So to have a way + of configuring the statedump of all the glusterfs processes through + both cli command and SIGUSR1, glusterdump.options file is searched + and the options mentioned in it are given the higher priority. + */ + snprintf(dump_option_file, sizeof(dump_option_file), + DEFAULT_VAR_RUN_DIRECTORY "/glusterdump.options"); + fp = fopen(dump_option_file, "r"); + if (!fp) { + snprintf(dump_option_file, sizeof(dump_option_file), + DEFAULT_VAR_RUN_DIRECTORY "/glusterdump.%d.options", getpid()); + + fp = fopen(dump_option_file, "r"); if (!fp) { - //ENOENT, return success - (void) gf_proc_dump_enable_all_options (); - return 0; + // ENOENT, return success + (void)gf_proc_dump_enable_all_options(); + return 0; } + } - (void) gf_proc_dump_disable_all_options (); + (void)gf_proc_dump_disable_all_options(); - ret = fscanf (fp, "%s", buf); + // swallow the errors if setting statedump file path is failed. + (void)gf_proc_dump_set_path(dump_option_file); - while (ret != EOF) { + ret = fscanf(fp, "%255s", buf); - key = strtok_r (buf, "=", &saveptr); - if (!key) { - ret = fscanf (fp, "%s", buf); - continue; - } + while (ret != EOF) { + key = strtok_r(buf, "=", &saveptr); + if (!key) { + ret = fscanf(fp, "%255s", buf); + continue; + } - value = strtok_r (NULL, "=", &saveptr); + value = strtok_r(NULL, "=", &saveptr); - if (!value) { - ret = fscanf (fp, "%s", buf); - continue; - } + if (!value) { + ret = fscanf(fp, "%255s", buf); + continue; + } - gf_log ("", GF_LOG_DEBUG, "key = %s, value = %s", - key, value); + gf_proc_dump_parse_set_option(key, value); + } - gf_proc_dump_parse_set_option (key, value); + if (is_gf_proc_dump_all_disabled()) + (void)gf_proc_dump_enable_default_options(); - } + if (fp) + fclose(fp); - return 0; + return 0; } void -gf_proc_dump_info (int signum) +gf_proc_dump_info(int signum, glusterfs_ctx_t *ctx) { - int ret = -1; - glusterfs_ctx_t *ctx = NULL; + int i = 0; + int ret = -1; + glusterfs_graph_t *trav = NULL; + char brick_name[PATH_MAX] = { + 0, + }; + char timestr[GF_TIMESTR_SIZE] = { + 0, + }; + char sign_string[512] = { + 0, + }; + char tmp_dump_name[PATH_MAX] = { + 0, + }; + char path[PATH_MAX] = { + 0, + }; + struct timeval tv = { + 0, + }; + gf_boolean_t is_brick_mux = _gf_false; + xlator_t *top = NULL; + xlator_list_t **trav_p = NULL; + int brick_count = 0; + int len = 0; + + gf_msg_trace("dump", 0, "received statedump request (sig:USR1)"); + + if (!ctx) + goto out; + + /* + * Multiplexed daemons can change the active graph when attach/detach + * is called. So this has to be protected with the cleanup lock. + */ + if (mgmt_is_multiplexed_daemon(ctx->cmd_args.process_name)) + pthread_mutex_lock(&ctx->cleanup_lock); + gf_proc_dump_lock(); + + if (!mgmt_is_multiplexed_daemon(ctx->cmd_args.process_name) && + (ctx && ctx->active)) { + top = ctx->active->first; + for (trav_p = &top->children; *trav_p; trav_p = &(*trav_p)->next) { + brick_count++; + } - - gf_proc_dump_lock (); - ret = gf_proc_dump_open (); - if (ret < 0) - goto out; + if (brick_count > 1) + is_brick_mux = _gf_true; + } + + if (ctx->cmd_args.brick_name) { + GF_REMOVE_SLASH_FROM_PATH(ctx->cmd_args.brick_name, brick_name); + } else + snprintf(brick_name, sizeof(brick_name), "glusterdump"); + + ret = gf_proc_dump_options_init(); + if (ret < 0) + goto out; + + ret = snprintf( + path, sizeof(path), "%s/%s.%d.dump.%" PRIu64, + ((dump_options.dump_path != NULL) + ? dump_options.dump_path + : ((ctx->statedump_path != NULL) ? ctx->statedump_path + : DEFAULT_VAR_RUN_DIRECTORY)), + brick_name, getpid(), (uint64_t)gf_time()); + if ((ret < 0) || (ret >= sizeof(path))) { + goto out; + } + + snprintf( + tmp_dump_name, PATH_MAX, "%s/dumpXXXXXX", + ((dump_options.dump_path != NULL) + ? dump_options.dump_path + : ((ctx->statedump_path != NULL) ? ctx->statedump_path + : DEFAULT_VAR_RUN_DIRECTORY))); + + ret = gf_proc_dump_open(tmp_dump_name); + if (ret < 0) + goto out; + + // continue even though gettimeofday() has failed + ret = gettimeofday(&tv, NULL); + if (0 == ret) { + gf_time_fmt_tv(timestr, sizeof timestr, &tv, gf_timefmt_FT); + } + + len = snprintf(sign_string, sizeof(sign_string), "DUMP-START-TIME: %s\n", + timestr); + + // swallow the errors of write for start and end marker + (void)sys_write(gf_dump_fd, sign_string, len); + + memset(timestr, 0, sizeof(timestr)); + + if (GF_PROC_DUMP_IS_OPTION_ENABLED(mem)) { + gf_proc_dump_mem_info(); + gf_proc_dump_mempool_info(ctx); + } + + if (GF_PROC_DUMP_IS_OPTION_ENABLED(iobuf)) + iobuf_stats_dump(ctx->iobuf_pool); + if (GF_PROC_DUMP_IS_OPTION_ENABLED(callpool)) + gf_proc_dump_pending_frames(ctx->pool); + + /* dictionary stats */ + gf_proc_dump_add_section("dict"); + gf_proc_dump_dict_info(ctx); + + if (ctx->master) { + gf_proc_dump_add_section("fuse"); + gf_proc_dump_single_xlator_info(ctx->master); + } + + if (ctx->active) { + gf_proc_dump_add_section("active graph - %d", ctx->graph_id); + gf_proc_dump_xlator_info(ctx->active->top, is_brick_mux); + } + + i = 0; + list_for_each_entry(trav, &ctx->graphs, list) + { + if (trav == ctx->active) + continue; + + gf_proc_dump_add_section("oldgraph[%d]", i); + + gf_proc_dump_oldgraph_xlator_info(trav->top); + i++; + } + + ret = gettimeofday(&tv, NULL); + if (0 == ret) { + gf_time_fmt_tv(timestr, sizeof timestr, &tv, gf_timefmt_FT); + } + + len = snprintf(sign_string, sizeof(sign_string), "\nDUMP-END-TIME: %s", + timestr); + (void)sys_write(gf_dump_fd, sign_string, len); + + if (gf_dump_fd != -1) + gf_proc_dump_close(); + sys_rename(tmp_dump_name, path); +out: + GF_FREE(dump_options.dump_path); + dump_options.dump_path = NULL; + if (ctx) { + gf_proc_dump_unlock(); + if (mgmt_is_multiplexed_daemon(ctx->cmd_args.process_name)) + pthread_mutex_unlock(&ctx->cleanup_lock); + } + + return; +} - ret = gf_proc_dump_options_init (); - - if (ret < 0) - goto out; +void +gf_proc_dump_fini(void) +{ + pthread_mutex_destroy(&gf_proc_dump_mutex); +} + +void +gf_proc_dump_init() +{ + pthread_mutex_init(&gf_proc_dump_mutex, NULL); - if (GF_PROC_DUMP_IS_OPTION_ENABLED (mem)) - gf_proc_dump_mem_info (); + return; +} - ctx = glusterfs_ctx_get (); - - if (ctx) { - if (GF_PROC_DUMP_IS_OPTION_ENABLED (iobuf)) - iobuf_stats_dump (ctx->iobuf_pool); - if (GF_PROC_DUMP_IS_OPTION_ENABLED (callpool)) - gf_proc_dump_pending_frames (ctx->pool); - gf_proc_dump_xlator_info (ctx->active->top); +void +gf_proc_dump_cleanup(void) +{ + pthread_mutex_destroy(&gf_proc_dump_mutex); +} - } +void +gf_proc_dump_xlator_private(xlator_t *this, strfd_t *strfd) +{ + gf_proc_dump_lock(); + { + gf_dump_strfd = strfd; - gf_proc_dump_close (); -out: - gf_proc_dump_unlock (); + if (this->dumpops && this->dumpops->priv) + this->dumpops->priv(this); - return; + gf_dump_strfd = NULL; + } + gf_proc_dump_unlock(); } - void -gf_proc_dump_fini (void) +gf_proc_dump_mallinfo(strfd_t *strfd) { - pthread_mutex_destroy (&gf_proc_dump_mutex); -} + gf_proc_dump_lock(); + { + gf_dump_strfd = strfd; + gf_proc_dump_mem_info(); + + gf_dump_strfd = NULL; + } + gf_proc_dump_unlock(); +} void -gf_proc_dump_init () +gf_proc_dump_xlator_history(xlator_t *this, strfd_t *strfd) { - pthread_mutex_init (&gf_proc_dump_mutex, NULL); + gf_proc_dump_lock(); + { + gf_dump_strfd = strfd; - return; + if (this->dumpops && this->dumpops->history) + this->dumpops->history(this); + + gf_dump_strfd = NULL; + } + gf_proc_dump_unlock(); } +void +gf_proc_dump_xlator_itable(xlator_t *this, strfd_t *strfd) +{ + gf_proc_dump_lock(); + { + gf_dump_strfd = strfd; + + gf_dump_strfd = NULL; + } + gf_proc_dump_unlock(); +} void -gf_proc_dump_cleanup (void) +gf_proc_dump_xlator_meminfo(xlator_t *this, strfd_t *strfd) { - pthread_mutex_destroy (&gf_proc_dump_mutex); + gf_proc_dump_lock(); + { + gf_dump_strfd = strfd; + + gf_proc_dump_xlator_mem_info(this); + + gf_dump_strfd = NULL; + } + gf_proc_dump_unlock(); } +void +gf_proc_dump_xlator_profile(xlator_t *this, strfd_t *strfd) +{ + gf_proc_dump_lock(); + { + gf_dump_strfd = strfd; + + gf_proc_dump_xl_latency_info(this); + gf_dump_strfd = NULL; + } + gf_proc_dump_unlock(); +} diff --git a/libglusterfs/src/statedump.h b/libglusterfs/src/statedump.h deleted file mode 100644 index 02cba5bac51..00000000000 --- a/libglusterfs/src/statedump.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - Copyright (c) 2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - - -#ifndef STATEDUMP_H -#define STATEDUMP_H - -#include <stdarg.h> -#include "inode.h" - -#define GF_DUMP_MAX_BUF_LEN 4096 - -#define GF_DUMP_LOGFILE_ROOT "/tmp/glusterdump" -#define GF_DUMP_LOGFILE_ROOT_LEN 256 - -#define GF_DUMP_OPTIONFILE "/tmp/glusterdump.input" - -typedef struct gf_dump_xl_options_ { - gf_boolean_t dump_priv; - gf_boolean_t dump_inode; - gf_boolean_t dump_fd; -} gf_dump_xl_options_t; - -typedef struct gf_dump_options_ { - gf_boolean_t dump_mem; - gf_boolean_t dump_iobuf; - gf_boolean_t dump_callpool; - gf_dump_xl_options_t xl_options; //options for all xlators -} gf_dump_options_t; - -static inline -void _gf_proc_dump_build_key (char *key, const char *prefix, char *fmt,...) -{ - char buf[GF_DUMP_MAX_BUF_LEN]; - va_list ap; - - memset(buf, 0, sizeof(buf)); - va_start(ap, fmt); - vsnprintf(buf, GF_DUMP_MAX_BUF_LEN, fmt, ap); - va_end(ap); - snprintf(key, GF_DUMP_MAX_BUF_LEN, "%s.%s", prefix, buf); -} - -#define gf_proc_dump_build_key(key, key_prefix, fmt...) \ -{\ - _gf_proc_dump_build_key(key, key_prefix, ##fmt);\ -} - -#define GF_PROC_DUMP_SET_OPTION(opt,val) opt = val - -void -gf_proc_dump_init(); - -void -gf_proc_dump_fini(void); - -void -gf_proc_dump_cleanup(void); - -void -gf_proc_dump_info(int signum); - -void -gf_proc_dump_add_section(char *key,...); - -void -gf_proc_dump_write(char *key, char *value,...); - -void -inode_table_dump(inode_table_t *itable, char *prefix); - -void -fdtable_dump(fdtable_t *fdtable, char *prefix); - -void -inode_dump(inode_t *inode, char *prefix); - -void -glusterd_init (int sig); -#endif /* STATEDUMP_H */ diff --git a/libglusterfs/src/store.c b/libglusterfs/src/store.c new file mode 100644 index 00000000000..5c316b9291a --- /dev/null +++ b/libglusterfs/src/store.c @@ -0,0 +1,744 @@ +/* + 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 <inttypes.h> +#include <libgen.h> + +#include "glusterfs/glusterfs.h" +#include "glusterfs/store.h" +#include "glusterfs/xlator.h" +#include "glusterfs/syscall.h" +#include "glusterfs/libglusterfs-messages.h" + +int32_t +gf_store_mkdir(char *path) +{ + int32_t ret = -1; + + ret = mkdir_p(path, 0755, _gf_true); + + if ((-1 == ret) && (EEXIST != errno)) { + gf_msg("", GF_LOG_ERROR, errno, LG_MSG_DIR_OP_FAILED, + "mkdir()" + " failed on path %s.", + path); + } 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_msg("", GF_LOG_ERROR, 0, LG_MSG_STORE_HANDLE_CREATE_FAILED, + "Unable to" + " create store handle for path: %s", + path); + } + } + return ret; +} + +int32_t +gf_store_mkstemp(gf_store_handle_t *shandle) +{ + char tmppath[PATH_MAX] = { + 0, + }; + + GF_VALIDATE_OR_GOTO("store", shandle, out); + GF_VALIDATE_OR_GOTO("store", shandle->path, out); + + snprintf(tmppath, sizeof(tmppath), "%s.tmp", shandle->path); + shandle->tmp_fd = open(tmppath, O_RDWR | O_CREAT | O_TRUNC, 0600); + if (shandle->tmp_fd < 0) { + gf_msg("", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED, + "Failed to open %s.", tmppath); + } +out: + return shandle->tmp_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_msg(this->name, GF_LOG_ERROR, errno, LG_MSG_DIR_OP_FAILED, + "Failed to open directory %s.", pdir); + goto out; + } + + ret = sys_fsync(dirfd); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, errno, LG_MSG_DIR_OP_FAILED, + "Failed to fsync %s.", pdir); + goto out; + } + + ret = 0; +out: + if (dirfd >= 0) { + ret = sys_close(dirfd); + if (ret) { + gf_msg(this->name, GF_LOG_ERROR, errno, LG_MSG_DIR_OP_FAILED, + "Failed to close %s", pdir); + } + } + + 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_VALIDATE_OR_GOTO("store", shandle, out); + GF_VALIDATE_OR_GOTO("store", shandle->path, out); + + ret = sys_fsync(shandle->tmp_fd); + if (ret) { + gf_msg(THIS->name, GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED, + "Failed to fsync %s", shandle->path); + goto out; + } + snprintf(tmppath, sizeof(tmppath), "%s.tmp", shandle->path); + ret = sys_rename(tmppath, shandle->path); + if (ret) { + gf_msg(THIS->name, GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED, + "Failed to rename %s to %s", tmppath, shandle->path); + goto out; + } + + ret = gf_store_sync_direntry(tmppath); +out: + if (shandle && shandle->tmp_fd >= 0) { + sys_close(shandle->tmp_fd); + shandle->tmp_fd = -1; + } + return ret; +} + +int32_t +gf_store_unlink_tmppath(gf_store_handle_t *shandle) +{ + int32_t ret = -1; + char tmppath[PATH_MAX] = { + 0, + }; + + GF_VALIDATE_OR_GOTO("store", shandle, out); + GF_VALIDATE_OR_GOTO("store", shandle->path, out); + + snprintf(tmppath, sizeof(tmppath), "%s.tmp", shandle->path); + ret = sys_unlink(tmppath); + if (ret && (errno != ENOENT)) { + gf_msg("", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED, + "Failed to mv %s to %s", tmppath, shandle->path); + } else { + ret = 0; + } +out: + if (shandle && shandle->tmp_fd >= 0) { + sys_close(shandle->tmp_fd); + shandle->tmp_fd = -1; + } + return ret; +} + +int +gf_store_read_and_tokenize(FILE *file, 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; + char str[8192]; + + GF_ASSERT(file); + GF_ASSERT(iter_key); + GF_ASSERT(iter_val); + GF_ASSERT(store_errno); + +retry: + temp = fgets(str, 8192, file); + if (temp == NULL || feof(file)) { + ret = -1; + *store_errno = GD_STORE_EOF; + goto out; + } + + if (strcmp(str, "\n") == 0) + goto retry; + + 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 *iter_key = NULL; + char *iter_val = NULL; + 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() */ + sys_lseek(handle->fd, 0, SEEK_SET); + + if (handle->fd == -1) { + gf_msg("", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED, + "Unable to open file %s", handle->path); + goto out; + } + if (!handle->read) { + int duped_fd = dup(handle->fd); + + if (duped_fd >= 0) + handle->read = fdopen(duped_fd, "r"); + if (!handle->read) { + if (duped_fd != -1) + sys_close(duped_fd); + gf_msg("", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED, + "Unable to open file %s", handle->path); + goto out; + } + } else { + fseek(handle->read, 0, SEEK_SET); + } + do { + ret = gf_store_read_and_tokenize(handle->read, &iter_key, &iter_val, + &store_errno); + if (ret < 0) { + gf_msg_trace("", 0, + "error while reading key '%s': " + "%s", + key, gf_store_strerror(store_errno)); + goto out; + } + + gf_msg_trace("", 0, "key %s read", iter_key); + + if (!strcmp(key, iter_key)) { + gf_msg_debug("", 0, "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 */ + sys_close(handle->fd); + } + + 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_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED, + "fdopen failed."); + ret = -1; + goto out; + } + + ret = fprintf(fp, "%s=%s\n", key, value); + if (ret < 0) { + gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED, + "Unable to store key: %s, value: %s.", key, value); + ret = -1; + goto out; + } + + ret = fflush(fp); + if (ret) { + gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED, + "fflush failed."); + ret = -1; + goto out; + } + + ret = 0; +out: + if (fp) + fclose(fp); + + gf_msg_debug(THIS->name, 0, "returning: %d", ret); + return ret; +} + +int32_t +gf_store_save_items(int fd, char *items) +{ + int32_t ret = -1; + int dup_fd = -1; + FILE *fp = NULL; + + GF_ASSERT(fd > 0); + GF_ASSERT(items); + + dup_fd = dup(fd); + if (dup_fd == -1) + goto out; + + fp = fdopen(dup_fd, "a+"); + if (fp == NULL) { + gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED, + "fdopen failed."); + ret = -1; + goto out; + } + + ret = fputs(items, fp); + if (ret < 0) { + gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED, + "Unable to store items: %s", items); + ret = -1; + goto out; + } + + ret = fflush(fp); + if (ret) { + gf_msg(THIS->name, GF_LOG_WARNING, errno, LG_MSG_FILE_OP_FAILED, + "fflush failed."); + ret = -1; + goto out; + } + + ret = 0; +out: + if (fp) + fclose(fp); + + gf_msg_debug(THIS->name, 0, "returning: %d", ret); + return ret; +} + +int32_t +gf_store_handle_new(const 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_msg("", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED, + "Failed to open file: %s.", path); + goto out; + } + + ret = gf_store_sync_direntry(spath); + if (ret) + goto out; + + shandle->path = spath; + shandle->locked = F_ULOCK; + *handle = shandle; + shandle->tmp_fd = -1; + + ret = 0; +out: + if (fd >= 0) + sys_close(fd); + + if (ret) { + GF_FREE(spath); + GF_FREE(shandle); + } + + gf_msg_debug("", 0, "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 = sys_stat(path, &statbuf); + if (ret) { + gf_msg("", GF_LOG_ERROR, errno, LG_MSG_PATH_NOT_FOUND, + "Path " + "corresponding to %s.", + path); + goto out; + } + ret = gf_store_handle_new(path, handle); +out: + gf_msg_debug("", 0, "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_msg_debug("", 0, "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_msg("", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED, + "Unable to open file %s", shandle->path); + goto out; + } + + tmp_iter = GF_CALLOC(1, sizeof(*tmp_iter), gf_common_mt_store_iter_t); + if (!tmp_iter) + goto out; + + if (snprintf(tmp_iter->filepath, sizeof(tmp_iter->filepath), "%s", + shandle->path) >= sizeof(tmp_iter->filepath)) + goto out; + + tmp_iter->file = fp; + + *iter = tmp_iter; + tmp_iter = NULL; + ret = 0; + +out: + if (ret && fp) + fclose(fp); + + GF_FREE(tmp_iter); + + gf_msg_debug("", 0, "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_msg("", GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, + "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_msg("", GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, + "Glusterd " + "store may be corrupted, Invalid key (null) in %s", + storepath); + *op_errno = GD_STORE_KEY_NULL; + } else if (val == NULL) { + ret = -1; + gf_msg("", GF_LOG_ERROR, 0, LG_MSG_INVALID_ENTRY, + "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 *iter_key = NULL; + char *iter_val = NULL; + gf_store_op_errno_t store_errno = GD_STORE_SUCCESS; + + GF_ASSERT(iter); + GF_ASSERT(key); + GF_ASSERT(value); + + ret = gf_store_read_and_tokenize(iter->file, &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: + if (ret) { + GF_FREE(*key); + GF_FREE(*value); + *key = NULL; + *value = NULL; + } + if (op_errno) + *op_errno = store_errno; + + gf_msg_debug("", 0, "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_msg("", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED, + "Unable" + " to close file: %s, ret: %d", + (*iter)->filepath, ret); + + GF_FREE(*iter); + *iter = NULL; + + 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"; + } +} + +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_msg("", GF_LOG_ERROR, errno, LG_MSG_FILE_OP_FAILED, + "Failed to open '%s'", sh->path); + return -1; + } + + ret = lockf(sh->fd, F_LOCK, 0); + if (ret) + gf_msg("", GF_LOG_ERROR, errno, LG_MSG_LOCK_FAILED, + "Failed to gain lock on '%s'", sh->path); + 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; + + /* does not matter if this fails, locks are released on close anyway */ + if (lockf(sh->fd, F_ULOCK, 0) == -1) + gf_msg("", GF_LOG_ERROR, errno, LG_MSG_UNLOCK_FAILED, + "Failed to release lock on '%s'", sh->path); + + sys_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/strfd.c b/libglusterfs/src/strfd.c new file mode 100644 index 00000000000..8a2580edc85 --- /dev/null +++ b/libglusterfs/src/strfd.c @@ -0,0 +1,93 @@ +/* + Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include <stdarg.h> + +#include "glusterfs/mem-types.h" +#include "glusterfs/mem-pool.h" +#include "glusterfs/strfd.h" +#include "glusterfs/common-utils.h" + +strfd_t * +strfd_open() +{ + strfd_t *strfd = NULL; + + strfd = GF_CALLOC(1, sizeof(*strfd), gf_common_mt_strfd_t); + + return strfd; +} + +int +strvprintf(strfd_t *strfd, const char *fmt, va_list ap) +{ + char *str = NULL; + int size = 0; + + size = vasprintf(&str, fmt, ap); + + if (size < 0) + return size; + + if (!strfd->alloc_size) { + strfd->data = GF_CALLOC(max(size + 1, 4096), 1, + gf_common_mt_strfd_data_t); + if (!strfd->data) { + free(str); /* NOT GF_FREE */ + return -1; + } + strfd->alloc_size = max(size + 1, 4096); + } + + if (strfd->alloc_size <= (strfd->size + size)) { + char *tmp_ptr = NULL; + int new_size = max( + (strfd->alloc_size * 2), + gf_roundup_next_power_of_two(strfd->size + size + 1)); + tmp_ptr = GF_REALLOC(strfd->data, new_size); + if (!tmp_ptr) { + free(str); /* NOT GF_FREE */ + return -1; + } + strfd->alloc_size = new_size; + strfd->data = tmp_ptr; + } + + /* Copy the trailing '\0', but do not account for it in ->size. + This allows safe use of strfd->data as a string. */ + memcpy(strfd->data + strfd->size, str, size + 1); + strfd->size += size; + + free(str); /* NOT GF_FREE */ + + return size; +} + +int +strprintf(strfd_t *strfd, const char *fmt, ...) +{ + int ret = 0; + va_list ap; + + va_start(ap, fmt); + ret = strvprintf(strfd, fmt, ap); + va_end(ap); + + return ret; +} + +int +strfd_close(strfd_t *strfd) +{ + GF_FREE(strfd->data); + GF_FREE(strfd); + + return 0; +} diff --git a/libglusterfs/src/syncop-utils.c b/libglusterfs/src/syncop-utils.c new file mode 100644 index 00000000000..d9f1723856d --- /dev/null +++ b/libglusterfs/src/syncop-utils.c @@ -0,0 +1,669 @@ +/* + Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include "glusterfs/syncop.h" +#include "glusterfs/syncop-utils.h" +#include "glusterfs/common-utils.h" +#include "glusterfs/libglusterfs-messages.h" + +struct syncop_dir_scan_data { + xlator_t *subvol; + loc_t *parent; + void *data; + gf_dirent_t *q; + gf_dirent_t *entry; + pthread_cond_t *cond; + pthread_mutex_t *mut; + syncop_dir_scan_fn_t fn; + uint32_t *jobs_running; + uint32_t *qlen; + int32_t *retval; +}; + +int +syncop_dirfd(xlator_t *subvol, loc_t *loc, fd_t **fd, int pid) +{ + int ret = 0; + fd_t *dirfd = NULL; + + if (!fd) + return -EINVAL; + + dirfd = fd_create(loc->inode, pid); + if (!dirfd) { + gf_msg(subvol->name, GF_LOG_ERROR, errno, LG_MSG_FD_CREATE_FAILED, + "fd_create of %s", uuid_utoa(loc->gfid)); + ret = -errno; + goto out; + } + + ret = syncop_opendir(subvol, loc, dirfd, NULL, NULL); + if (ret) { + /* + * On Linux, if the brick was not updated, opendir will + * fail. We therefore use backward compatible code + * that violate the standards by reusing offsets + * in seekdir() from different DIR *, but it works on Linux. + * + * On other systems it never worked, hence we do not need + * to provide backward-compatibility. + */ +#ifdef GF_LINUX_HOST_OS + fd_unref(dirfd); + dirfd = fd_anonymous(loc->inode); + if (!dirfd) { + gf_msg(subvol->name, GF_LOG_ERROR, errno, + LG_MSG_FD_ANONYMOUS_FAILED, + "fd_anonymous of " + "%s", + uuid_utoa(loc->gfid)); + ret = -errno; + goto out; + } + ret = 0; +#else /* GF_LINUX_HOST_OS */ + fd_unref(dirfd); + gf_msg(subvol->name, GF_LOG_ERROR, errno, LG_MSG_DIR_OP_FAILED, + "opendir of %s", uuid_utoa(loc->gfid)); + goto out; +#endif /* GF_LINUX_HOST_OS */ + } else { + fd_bind(dirfd); + } +out: + if (ret == 0) + *fd = dirfd; + return ret; +} + +int +syncop_ftw(xlator_t *subvol, loc_t *loc, int pid, void *data, + int (*fn)(xlator_t *subvol, gf_dirent_t *entry, loc_t *parent, + void *data)) +{ + loc_t child_loc = { + 0, + }; + fd_t *fd = NULL; + uint64_t offset = 0; + gf_dirent_t *entry = NULL; + int ret = 0; + gf_dirent_t entries; + + ret = syncop_dirfd(subvol, loc, &fd, pid); + if (ret) + goto out; + + INIT_LIST_HEAD(&entries.list); + + while ((ret = syncop_readdirp(subvol, fd, 131072, offset, &entries, NULL, + NULL))) { + if (ret < 0) + break; + + if (ret > 0) { + /* If the entries are only '.', and '..' then ret + * value will be non-zero. so set it to zero here. */ + ret = 0; + } + list_for_each_entry(entry, &entries.list, list) + { + offset = entry->d_off; + + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) + continue; + + gf_link_inode_from_dirent(NULL, fd->inode, entry); + + ret = fn(subvol, entry, loc, data); + if (ret) + break; + + if (entry->d_stat.ia_type == IA_IFDIR) { + child_loc.inode = inode_ref(entry->inode); + gf_uuid_copy(child_loc.gfid, entry->inode->gfid); + ret = syncop_ftw(subvol, &child_loc, pid, data, fn); + loc_wipe(&child_loc); + if (ret) + break; + } + } + + gf_dirent_free(&entries); + if (ret) + break; + } + +out: + if (fd) + fd_unref(fd); + return ret; +} + +/** + * Syncop_ftw_throttle can be used in a configurable way to control + * the speed at which crawling is done. It takes 2 more arguments + * compared to syncop_ftw. + * After @count entries are finished in a directory (to be + * precise, @count files) sleep for @sleep_time seconds. + * If either @count or @sleep_time is <=0, then it behaves similar to + * syncop_ftw. + */ +int +syncop_ftw_throttle(xlator_t *subvol, loc_t *loc, int pid, void *data, + int (*fn)(xlator_t *subvol, gf_dirent_t *entry, + loc_t *parent, void *data), + int count, int sleep_time) +{ + loc_t child_loc = { + 0, + }; + fd_t *fd = NULL; + uint64_t offset = 0; + gf_dirent_t *entry = NULL; + int ret = 0; + gf_dirent_t entries; + int tmp = 0; + + if (sleep_time <= 0) { + ret = syncop_ftw(subvol, loc, pid, data, fn); + goto out; + } + + ret = syncop_dirfd(subvol, loc, &fd, pid); + if (ret) + goto out; + + INIT_LIST_HEAD(&entries.list); + + while ((ret = syncop_readdirp(subvol, fd, 131072, offset, &entries, NULL, + NULL))) { + if (ret < 0) + break; + + if (ret > 0) { + /* If the entries are only '.', and '..' then ret + * value will be non-zero. so set it to zero here. */ + ret = 0; + } + + tmp = 0; + + list_for_each_entry(entry, &entries.list, list) + { + offset = entry->d_off; + + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) + continue; + + if (++tmp >= count) { + tmp = 0; + sleep(sleep_time); + } + + gf_link_inode_from_dirent(NULL, fd->inode, entry); + + ret = fn(subvol, entry, loc, data); + if (ret) + continue; + + if (entry->d_stat.ia_type == IA_IFDIR) { + child_loc.inode = inode_ref(entry->inode); + gf_uuid_copy(child_loc.gfid, entry->inode->gfid); + ret = syncop_ftw_throttle(subvol, &child_loc, pid, data, fn, + count, sleep_time); + loc_wipe(&child_loc); + if (ret) + continue; + } + } + + gf_dirent_free(&entries); + if (ret) + break; + } + +out: + if (fd) + fd_unref(fd); + return ret; +} + +static void +_scan_data_destroy(struct syncop_dir_scan_data *data) +{ + GF_FREE(data); +} + +static int +_dir_scan_job_fn_cbk(int ret, call_frame_t *frame, void *opaque) +{ + struct syncop_dir_scan_data *scan_data = opaque; + + _scan_data_destroy(scan_data); + return 0; +} + +static int +_dir_scan_job_fn(void *data) +{ + struct syncop_dir_scan_data *scan_data = data; + gf_dirent_t *entry = NULL; + int ret = 0; + + entry = scan_data->entry; + scan_data->entry = NULL; + do { + ret = scan_data->fn(scan_data->subvol, entry, scan_data->parent, + scan_data->data); + gf_dirent_entry_free(entry); + entry = NULL; + pthread_mutex_lock(scan_data->mut); + { + if (ret) + *scan_data->retval |= ret; + if (list_empty(&scan_data->q->list)) { + (*scan_data->jobs_running)--; + pthread_cond_broadcast(scan_data->cond); + } else { + entry = list_first_entry(&scan_data->q->list, + typeof(*scan_data->q), list); + list_del_init(&entry->list); + (*scan_data->qlen)--; + } + } + pthread_mutex_unlock(scan_data->mut); + } while (entry); + + return ret; +} + +static int +_run_dir_scan_task(call_frame_t *frame, xlator_t *subvol, loc_t *parent, + gf_dirent_t *q, gf_dirent_t *entry, int *retval, + pthread_mutex_t *mut, pthread_cond_t *cond, + uint32_t *jobs_running, uint32_t *qlen, + syncop_dir_scan_fn_t fn, void *data) +{ + int ret = 0; + struct syncop_dir_scan_data *scan_data = NULL; + + scan_data = GF_CALLOC(1, sizeof(struct syncop_dir_scan_data), + gf_common_mt_scan_data); + if (!scan_data) { + ret = -ENOMEM; + goto out; + } + + scan_data->subvol = subvol; + scan_data->parent = parent; + scan_data->data = data; + scan_data->mut = mut; + scan_data->cond = cond; + scan_data->fn = fn; + scan_data->jobs_running = jobs_running; + scan_data->entry = entry; + scan_data->q = q; + scan_data->qlen = qlen; + scan_data->retval = retval; + + ret = synctask_new(subvol->ctx->env, _dir_scan_job_fn, _dir_scan_job_fn_cbk, + frame, scan_data); +out: + if (ret < 0) { + gf_dirent_entry_free(entry); + _scan_data_destroy(scan_data); + pthread_mutex_lock(mut); + { + *jobs_running = *jobs_running - 1; + } + pthread_mutex_unlock(mut); + /*No need to cond-broadcast*/ + } + return ret; +} + +int +syncop_mt_dir_scan(call_frame_t *frame, xlator_t *subvol, loc_t *loc, int pid, + void *data, syncop_dir_scan_fn_t fn, dict_t *xdata, + uint32_t max_jobs, uint32_t max_qlen) +{ + fd_t *fd = NULL; + uint64_t offset = 0; + gf_dirent_t *last = NULL; + int ret = 0; + int retval = 0; + gf_dirent_t q; + gf_dirent_t *entry = NULL; + gf_dirent_t *tmp = NULL; + uint32_t jobs_running = 0; + uint32_t qlen = 0; + pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + gf_dirent_t entries; + xlator_t *this = NULL; + + if (frame) { + this = frame->this; + } else { + this = THIS; + } + + /*For this functionality to be implemented in general, we need + * synccond_t infra which doesn't block the executing thread. Until then + * return failures inside synctask if they use this.*/ + if (synctask_get()) + return -ENOTSUP; + + if (max_jobs == 0) + return -EINVAL; + + /*Code becomes simpler this way. cond_wait just on qlength. + * Little bit of cheating*/ + if (max_qlen == 0) + max_qlen = 1; + + ret = syncop_dirfd(subvol, loc, &fd, pid); + if (ret) + goto out; + + INIT_LIST_HEAD(&entries.list); + INIT_LIST_HEAD(&q.list); + + while ((ret = syncop_readdir(subvol, fd, 131072, offset, &entries, xdata, + NULL))) { + if (ret < 0) + break; + + if (ret > 0) { + /* If the entries are only '.', and '..' then ret + * value will be non-zero. so set it to zero here. */ + ret = 0; + } + + last = list_last_entry(&entries.list, typeof(*last), list); + offset = last->d_off; + + list_for_each_entry_safe(entry, tmp, &entries.list, list) + { + if (this && this->cleanup_starting) + goto out; + + list_del_init(&entry->list); + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) { + gf_dirent_entry_free(entry); + continue; + } + + if (entry->d_stat.ia_type == IA_IFDIR) { + ret = fn(subvol, entry, loc, data); + gf_dirent_entry_free(entry); + if (ret) + goto out; + continue; + } + + if (retval) /*Any jobs failed?*/ + goto out; + + pthread_mutex_lock(&mut); + { + while (qlen == max_qlen) + pthread_cond_wait(&cond, &mut); + if (max_jobs == jobs_running) { + list_add_tail(&entry->list, &q.list); + qlen++; + entry = NULL; + } else { + jobs_running++; + } + } + pthread_mutex_unlock(&mut); + + if (!entry) + continue; + + ret = _run_dir_scan_task(frame, subvol, loc, &q, entry, &retval, + &mut, &cond, &jobs_running, &qlen, fn, + data); + if (ret) + goto out; + } + } + +out: + if (fd) + fd_unref(fd); + + pthread_mutex_lock(&mut); + { + while (jobs_running) + pthread_cond_wait(&cond, &mut); + } + pthread_mutex_unlock(&mut); + + gf_dirent_free(&q); + gf_dirent_free(&entries); + + return ret | retval; +} + +int +syncop_dir_scan(xlator_t *subvol, loc_t *loc, int pid, void *data, + int (*fn)(xlator_t *subvol, gf_dirent_t *entry, loc_t *parent, + void *data)) +{ + fd_t *fd = NULL; + uint64_t offset = 0; + gf_dirent_t *entry = NULL; + int ret = 0; + gf_dirent_t entries; + + ret = syncop_dirfd(subvol, loc, &fd, pid); + if (ret) + goto out; + + INIT_LIST_HEAD(&entries.list); + + while ((ret = syncop_readdir(subvol, fd, 131072, offset, &entries, NULL, + NULL))) { + if (ret < 0) + break; + + if (ret > 0) { + /* If the entries are only '.', and '..' then ret + * value will be non-zero. so set it to zero here. */ + ret = 0; + } + + list_for_each_entry(entry, &entries.list, list) + { + offset = entry->d_off; + + if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) + continue; + + ret = fn(subvol, entry, loc, data); + if (ret) + break; + } + gf_dirent_free(&entries); + if (ret) + break; + } + +out: + if (fd) + fd_unref(fd); + return ret; +} + +int +syncop_is_subvol_local(xlator_t *this, loc_t *loc, gf_boolean_t *is_local) +{ + char *pathinfo = NULL; + dict_t *xattr = NULL; + int ret = 0; + + if (!this || !this->type || !is_local) + return -EINVAL; + + if (strcmp(this->type, "protocol/client") != 0) + return -EINVAL; + + *is_local = _gf_false; + + ret = syncop_getxattr(this, loc, &xattr, GF_XATTR_PATHINFO_KEY, NULL, NULL); + if (ret < 0) { + ret = -1; + goto out; + } + + if (!xattr) { + ret = -EINVAL; + goto out; + } + + ret = dict_get_str(xattr, GF_XATTR_PATHINFO_KEY, &pathinfo); + if (ret) + goto out; + + ret = glusterfs_is_local_pathinfo(pathinfo, is_local); + + gf_msg_debug(this->name, 0, "subvol %s is %slocal", this->name, + *is_local ? "" : "not "); + +out: + if (xattr) + dict_unref(xattr); + + return ret; +} + +/** + * For hard resove, it it telling posix to make use of the + * gfid2path extended attribute stored on disk. Otherwise + * posix xlator (with GFID_TO_PATH_KEY as the key) will just + * do a in memory inode_path to get the path. Depending upon + * the consumer of this function, they can choose how they want + * to proceed. If doing a xattr operation sounds costly, then + * use GFID_TO_PATH_KEY as the key for getxattr. + **/ + +int +syncop_gfid_to_path_hard(inode_table_t *itable, xlator_t *subvol, uuid_t gfid, + inode_t *inode, char **path_p, + gf_boolean_t hard_resolve) +{ + int ret = 0; + char *path = NULL; + loc_t loc = { + 0, + }; + dict_t *xattr = NULL; + + gf_uuid_copy(loc.gfid, gfid); + + if (!inode) + loc.inode = inode_new(itable); + else + loc.inode = inode_ref(inode); + + if (!hard_resolve) + ret = syncop_getxattr(subvol, &loc, &xattr, GFID_TO_PATH_KEY, NULL, + NULL); + else + ret = syncop_getxattr(subvol, &loc, &xattr, GFID2PATH_VIRT_XATTR_KEY, + NULL, NULL); + + if (ret < 0) + goto out; + + /* + * posix will do dict_set_dynstr for GFID_TO_PATH_KEY i.e. + * for in memory search for the path. And for on disk xattr + * fetching of the path for the key GFID2PATH_VIRT_XATTR_KEY + * it uses dict_set_dynptr. So, for GFID2PATH_VIRT_XATTR_KEY + * use dict_get_ptr to avoid dict complaining about type + * mismatch (i.e. str vs ptr) + */ + if (!hard_resolve) + ret = dict_get_str(xattr, GFID_TO_PATH_KEY, &path); + else + ret = dict_get_ptr(xattr, GFID2PATH_VIRT_XATTR_KEY, (void **)&path); + + if (ret || !path) { + ret = -EINVAL; + goto out; + } + + if (path_p) { + *path_p = gf_strdup(path); + if (!*path_p) { + ret = -ENOMEM; + goto out; + } + } + + ret = 0; + +out: + if (xattr) + dict_unref(xattr); + loc_wipe(&loc); + + return ret; +} + +int +syncop_gfid_to_path(inode_table_t *itable, xlator_t *subvol, uuid_t gfid, + char **path_p) +{ + return syncop_gfid_to_path_hard(itable, subvol, gfid, NULL, path_p, + _gf_false); +} + +int +syncop_inode_find(xlator_t *this, xlator_t *subvol, uuid_t gfid, + inode_t **inode, dict_t *xdata, dict_t **rsp_dict) +{ + int ret = 0; + loc_t loc = { + 0, + }; + struct iatt iatt = { + 0, + }; + *inode = NULL; + + *inode = inode_find(this->itable, gfid); + if (*inode) + goto out; + + loc.inode = inode_new(this->itable); + if (!loc.inode) { + ret = -ENOMEM; + goto out; + } + gf_uuid_copy(loc.gfid, gfid); + + ret = syncop_lookup(subvol, &loc, &iatt, NULL, xdata, rsp_dict); + if (ret < 0) + goto out; + + *inode = inode_link(loc.inode, NULL, NULL, &iatt); + if (!*inode) { + ret = -ENOMEM; + goto out; + } +out: + loc_wipe(&loc); + return ret; +} diff --git a/libglusterfs/src/syncop.c b/libglusterfs/src/syncop.c index cfece659171..df20cec559f 100644 --- a/libglusterfs/src/syncop.c +++ b/libglusterfs/src/syncop.c @@ -1,540 +1,3572 @@ /* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 _CONFIG_H -#define _CONFIG_H -#include "config.h" +#include "glusterfs/syncop.h" +#include "glusterfs/libglusterfs-messages.h" + +#ifdef HAVE_TSAN_API +#include <sanitizer/tsan_interface.h> #endif -#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(); -call_frame_t * -syncop_create_frame () + opctx->uid = *(uid_t *)uid; + opctx->valid |= SYNCOPCTX_UID; + +out: + return ret; +} + +int +syncopctx_setfsgid(void *gid) { - struct synctask *task = NULL; - struct call_frame_t *frame = NULL; + struct syncopctx *opctx = NULL; + int ret = 0; - task = synctask_get (); + /* In args check */ + if (!gid) { + ret = -1; + errno = EINVAL; + goto out; + } - if (task) { - frame = task->opaque; + opctx = syncopctx_getctx(); + + opctx->gid = *(gid_t *)gid; + opctx->valid |= SYNCOPCTX_GID; + +out: + 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(); + + /* resize internal groups as required */ + if (count && opctx->grpsize < count) { + if (opctx->groups) { + /* Group list will be updated later, so no need to keep current + * data and waste time copying it. It's better to free the current + * allocation and then allocate a fresh new memory block. */ + GF_FREE(opctx->groups); + opctx->groups = NULL; + opctx->grpsize = 0; } + tmpgroups = GF_MALLOC(count * sizeof(gid_t), gf_common_mt_syncopctx); + if (tmpgroups == NULL) { + 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; + + if ((opctx->valid & SYNCOPCTX_GROUPS) == 0) { + /* This is the first time we are storing groups into the TLS structure + * so we mark the current thread so that it will be properly cleaned + * up when the thread terminates. */ + gf_thread_needs_cleanup(); + } + opctx->valid |= SYNCOPCTX_GROUPS; - return (call_frame_t *)frame; +out: + return ret; } -void -synctask_yield (struct synctask *task) +int +syncopctx_setfspid(void *pid) +{ + struct syncopctx *opctx = NULL; + int ret = 0; + + /* In args check */ + if (!pid) { + ret = -1; + errno = EINVAL; + goto out; + } + + opctx = syncopctx_getctx(); + + opctx->pid = *(pid_t *)pid; + opctx->valid |= SYNCOPCTX_PID; + +out: + return ret; +} + +int +syncopctx_setfslkowner(gf_lkowner_t *lk_owner) { - struct syncenv *env = NULL; + struct syncopctx *opctx = NULL; + int ret = 0; + + /* In args check */ + if (!lk_owner) { + ret = -1; + errno = EINVAL; + goto out; + } - env = task->env; + opctx = syncopctx_getctx(); - if (swapcontext (&task->ctx, &env->sched) < 0) { - gf_log ("syncop", GF_LOG_ERROR, - "swapcontext failed (%s)", strerror (errno)); + opctx->lk_owner = *lk_owner; + opctx->valid |= SYNCOPCTX_LKOWNER; + +out: + return ret; +} + +void * +syncenv_processor(void *thdata); + +static void +__run(struct synctask *task) +{ + struct syncenv *env = NULL; + int32_t total, ret, i; + + env = task->env; + + list_del_init(&task->all_tasks); + switch (task->state) { + case SYNCTASK_INIT: + case SYNCTASK_SUSPEND: + break; + case SYNCTASK_RUN: + gf_msg_debug(task->xl->name, 0, + "re-running already running" + " task"); + env->runcount--; + break; + case SYNCTASK_WAIT: + break; + case SYNCTASK_DONE: + gf_msg(task->xl->name, GF_LOG_WARNING, 0, LG_MSG_COMPLETED_TASK, + "running completed task"); + return; + case SYNCTASK_ZOMBIE: + gf_msg(task->xl->name, GF_LOG_WARNING, 0, LG_MSG_WAKE_UP_ZOMBIE, + "attempted to wake up " + "zombie!!"); + return; + } + + list_add_tail(&task->all_tasks, &env->runq); + task->state = SYNCTASK_RUN; + + env->runcount++; + + total = env->procs + env->runcount - env->procs_idle; + if (total > env->procmax) { + total = env->procmax; + } + if (total > env->procs) { + for (i = 0; i < env->procmax; i++) { + if (env->proc[i].env == NULL) { + env->proc[i].env = env; + ret = gf_thread_create(&env->proc[i].processor, NULL, + syncenv_processor, &env->proc[i], + "sproc%d", i); + if ((ret < 0) || (++env->procs >= total)) { + break; + } + } } + } } +static void +__wait(struct synctask *task) +{ + struct syncenv *env = NULL; + + env = task->env; + + list_del_init(&task->all_tasks); + switch (task->state) { + case SYNCTASK_INIT: + case SYNCTASK_SUSPEND: + break; + case SYNCTASK_RUN: + env->runcount--; + break; + case SYNCTASK_WAIT: + gf_msg(task->xl->name, GF_LOG_WARNING, 0, LG_MSG_REWAITING_TASK, + "re-waiting already waiting " + "task"); + break; + case SYNCTASK_DONE: + gf_msg(task->xl->name, GF_LOG_WARNING, 0, LG_MSG_COMPLETED_TASK, + "running completed task"); + return; + case SYNCTASK_ZOMBIE: + gf_msg(task->xl->name, GF_LOG_WARNING, 0, LG_MSG_SLEEP_ZOMBIE, + "attempted to sleep a zombie!!"); + return; + } + + list_add_tail(&task->all_tasks, &env->waitq); + task->state = SYNCTASK_WAIT; +} void -synctask_yawn (struct synctask *task) +synctask_yield(struct synctask *task, struct timespec *delta) { - struct syncenv *env = NULL; + xlator_t *oldTHIS = THIS; - env = task->env; +#if defined(__NetBSD__) && defined(_UC_TLSBASE) + /* Preserve pthread private pointer through swapcontex() */ + task->proc->sched.uc_flags &= ~_UC_TLSBASE; +#endif - pthread_mutex_lock (&env->mutex); - { - list_del_init (&task->all_tasks); - list_add (&task->all_tasks, &env->waitq); - } - pthread_mutex_unlock (&env->mutex); -} + task->delta = delta; + if (task->state != SYNCTASK_DONE) { + task->state = SYNCTASK_SUSPEND; + } + +#ifdef HAVE_TSAN_API + __tsan_switch_to_fiber(task->proc->tsan.fiber, 0); +#endif + + if (swapcontext(&task->ctx, &task->proc->sched) < 0) { + gf_msg("syncop", GF_LOG_ERROR, errno, LG_MSG_SWAPCONTEXT_FAILED, + "swapcontext failed"); + } + + THIS = oldTHIS; +} void -synctask_zzzz (struct synctask *task) +synctask_sleep(int32_t secs) { - synctask_yawn (task); + struct timespec delta; + struct synctask *task; - synctask_yield (task); + task = synctask_get(); + + if (task == NULL) { + sleep(secs); + } else { + delta.tv_sec = secs; + delta.tv_nsec = 0; + + synctask_yield(task, &delta); + } } +static void +__synctask_wake(struct synctask *task) +{ + task->woken = 1; + + if (task->slept) + __run(task); + + pthread_cond_broadcast(&task->env->cond); +} void -synctask_wake (struct synctask *task) +synctask_wake(struct synctask *task) { - struct syncenv *env = NULL; + struct syncenv *env = NULL; - env = task->env; + env = task->env; - pthread_mutex_lock (&env->mutex); - { - list_del_init (&task->all_tasks); - list_add_tail (&task->all_tasks, &env->runq); + pthread_mutex_lock(&env->mutex); + { + if (task->timer != NULL) { + if (gf_timer_call_cancel(task->xl->ctx, task->timer) != 0) { + goto unlock; + } + + task->timer = NULL; + task->synccond = NULL; } - pthread_mutex_unlock (&env->mutex); - pthread_cond_broadcast (&env->cond); + __synctask_wake(task); + } +unlock: + pthread_mutex_unlock(&env->mutex); } - void -synctask_wrap (struct synctask *task) +synctask_wrap(void) { - int ret; + struct synctask *task = NULL; - ret = task->syncfn (task->opaque); - task->synccbk (ret, task->opaque); + /* Do not trust the pointer received. It may be + wrong and can lead to crashes. */ - /* cannot destroy @task right here as we are - in the execution stack of @task itself - */ - task->complete = 1; - synctask_wake (task); + task = synctask_get(); + task->ret = task->syncfn(task->opaque); + if (task->synccbk) + task->synccbk(task->ret, task->frame, task->opaque); - synctask_yield (task); -} + task->state = SYNCTASK_DONE; + synctask_yield(task, NULL); +} void -synctask_destroy (struct synctask *task) +synctask_destroy(struct synctask *task) { - if (!task) - return; + if (!task) + return; - if (task->stack) - FREE (task->stack); - FREE (task); + GF_FREE(task->stack); + + if (task->opframe) + STACK_DESTROY(task->opframe->root); + + if (task->synccbk == NULL) { + pthread_mutex_destroy(&task->mutex); + pthread_cond_destroy(&task->cond); + } + +#ifdef HAVE_TSAN_API + __tsan_destroy_fiber(task->tsan.fiber); +#endif + + GF_FREE(task); } +void +synctask_done(struct synctask *task) +{ + if (task->synccbk) { + synctask_destroy(task); + return; + } + + pthread_mutex_lock(&task->mutex); + { + task->state = SYNCTASK_ZOMBIE; + task->done = 1; + pthread_cond_broadcast(&task->cond); + } + pthread_mutex_unlock(&task->mutex); +} int -synctask_new (struct syncenv *env, synctask_fn_t fn, synctask_cbk_t cbk, - void *opaque) +synctask_setid(struct synctask *task, uid_t uid, gid_t gid) { - struct synctask *newtask = NULL; + if (!task) + return -1; - newtask = CALLOC (1, sizeof (*newtask)); - if (!newtask) - return -ENOMEM; + if (uid != -1) + task->uid = uid; - newtask->env = env; - newtask->xl = THIS; - newtask->syncfn = fn; - newtask->synccbk = cbk; - newtask->opaque = opaque; + if (gid != -1) + task->gid = gid; - INIT_LIST_HEAD (&newtask->all_tasks); + return 0; +} - if (getcontext (&newtask->ctx) < 0) { - gf_log ("syncop", GF_LOG_ERROR, - "getcontext failed (%s)", - strerror (errno)); - goto err; - } +struct synctask * +synctask_create(struct syncenv *env, size_t stacksize, synctask_fn_t fn, + synctask_cbk_t cbk, call_frame_t *frame, void *opaque) +{ + struct synctask *newtask = NULL; + xlator_t *this = THIS; + int destroymode = 0; + + VALIDATE_OR_GOTO(env, err); + VALIDATE_OR_GOTO(fn, err); + + /* Check if the syncenv is in destroymode i.e. destroy is SET. + * If YES, then don't allow any new synctasks on it. Return NULL. + */ + pthread_mutex_lock(&env->mutex); + { + destroymode = env->destroy; + } + pthread_mutex_unlock(&env->mutex); + + /* syncenv is in DESTROY mode, return from here */ + if (destroymode) + return NULL; - newtask->stack = CALLOC (1, env->stacksize); - if (!newtask->stack) { - gf_log ("syncop", GF_LOG_ERROR, - "out of memory for stack"); - goto err; - } + newtask = GF_CALLOC(1, sizeof(*newtask), gf_common_mt_synctask); + if (!newtask) + return NULL; - newtask->ctx.uc_stack.ss_sp = newtask->stack; + newtask->frame = frame; + if (!frame) { + newtask->opframe = create_frame(this, this->ctx->pool); + if (!newtask->opframe) + goto err; + set_lk_owner_from_ptr(&newtask->opframe->root->lk_owner, + newtask->opframe->root); + } else { + newtask->opframe = copy_frame(frame); + } + if (!newtask->opframe) + goto err; + newtask->env = env; + newtask->xl = this; + newtask->syncfn = fn; + newtask->synccbk = cbk; + newtask->opaque = opaque; + + /* default to the uid/gid of the passed frame */ + newtask->uid = newtask->opframe->root->uid; + newtask->gid = newtask->opframe->root->gid; + + INIT_LIST_HEAD(&newtask->all_tasks); + INIT_LIST_HEAD(&newtask->waitq); + + if (getcontext(&newtask->ctx) < 0) { + gf_msg("syncop", GF_LOG_ERROR, errno, LG_MSG_GETCONTEXT_FAILED, + "getcontext failed"); + goto err; + } + + if (stacksize <= 0) { + newtask->stack = GF_CALLOC(1, env->stacksize, gf_common_mt_syncstack); newtask->ctx.uc_stack.ss_size = env->stacksize; + } else { + newtask->stack = GF_CALLOC(1, stacksize, gf_common_mt_syncstack); + newtask->ctx.uc_stack.ss_size = stacksize; + } - makecontext (&newtask->ctx, (void *) synctask_wrap, 2, newtask); + if (!newtask->stack) { + goto err; + } - synctask_wake (newtask); + newtask->ctx.uc_stack.ss_sp = newtask->stack; - return 0; + makecontext(&newtask->ctx, (void (*)(void))synctask_wrap, 0); + +#ifdef HAVE_TSAN_API + newtask->tsan.fiber = __tsan_create_fiber(0); + snprintf(newtask->tsan.name, TSAN_THREAD_NAMELEN, "<synctask of %s>", + this->name); + __tsan_set_fiber_name(newtask->tsan.fiber, newtask->tsan.name); +#endif + + newtask->state = SYNCTASK_INIT; + + newtask->slept = 1; + + if (!cbk) { + pthread_mutex_init(&newtask->mutex, NULL); + pthread_cond_init(&newtask->cond, NULL); + newtask->done = 0; + } + + synctask_wake(newtask); + + return newtask; err: - if (newtask) { - if (newtask->stack) - FREE (newtask->stack); - FREE (newtask); - } + if (newtask) { + GF_FREE(newtask->stack); + if (newtask->opframe) + STACK_DESTROY(newtask->opframe->root); + GF_FREE(newtask); + } + + 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_new1(struct syncenv *env, size_t stacksize, 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, stacksize, fn, cbk, frame, opaque); + if (!newtask) return -1; + + if (!cbk) + ret = synctask_join(newtask); + + return ret; } +int +synctask_new(struct syncenv *env, synctask_fn_t fn, synctask_cbk_t cbk, + call_frame_t *frame, void *opaque) +{ + return synctask_new1(env, 0, fn, cbk, frame, opaque); +} struct synctask * -syncenv_task (struct syncenv *env) +syncenv_task(struct syncproc *proc) { - struct synctask *task = NULL; + struct syncenv *env = NULL; + struct synctask *task = NULL; + struct timespec sleep_till = { + 0, + }; + int ret = 0; + + env = proc->env; + + pthread_mutex_lock(&env->mutex); + { + while (list_empty(&env->runq)) { + /* If either of the conditions are met then exit + * the current thread: + * 1. syncenv has to scale down(procs > procmin) + * 2. syncenv is in destroy mode and no tasks in + * either waitq or runq. + * + * At any point in time, a task can be either in runq, + * or in executing state or in the waitq. Once the + * destroy mode is set, no new synctask creates will + * be allowed, but whatever in waitq or runq should be + * allowed to finish before exiting any of the syncenv + * processor threads. + */ + if (((ret == ETIMEDOUT) && (env->procs > env->procmin)) || + (env->destroy && list_empty(&env->waitq))) { + task = NULL; + env->procs--; + memset(proc, 0, sizeof(*proc)); + pthread_cond_broadcast(&env->cond); + goto unlock; + } + + env->procs_idle++; + + sleep_till.tv_sec = gf_time() + SYNCPROC_IDLE_TIME; + ret = pthread_cond_timedwait(&env->cond, &env->mutex, &sleep_till); + + env->procs_idle--; + } - pthread_mutex_lock (&env->mutex); - { - while (list_empty (&env->runq)) - pthread_cond_wait (&env->cond, &env->mutex); + task = list_entry(env->runq.next, struct synctask, all_tasks); - task = list_entry (env->runq.next, struct synctask, all_tasks); + list_del_init(&task->all_tasks); + env->runcount--; - list_del_init (&task->all_tasks); - } - pthread_mutex_unlock (&env->mutex); + task->woken = 0; + task->slept = 0; - return task; + task->proc = proc; + } +unlock: + pthread_mutex_unlock(&env->mutex); + + return task; } +static void +synctask_timer(void *data) +{ + struct synctask *task = data; + struct synccond *cond; + + cond = task->synccond; + if (cond != NULL) { + pthread_mutex_lock(&cond->pmutex); + + list_del_init(&task->waitq); + task->synccond = NULL; + + pthread_mutex_unlock(&cond->pmutex); + + task->ret = -ETIMEDOUT; + } + + pthread_mutex_lock(&task->env->mutex); + + gf_timer_call_cancel(task->xl->ctx, task->timer); + task->timer = NULL; + + __synctask_wake(task); + + pthread_mutex_unlock(&task->env->mutex); +} void -synctask_switchto (struct synctask *task) +synctask_switchto(struct synctask *task) { - struct syncenv *env = NULL; + struct syncenv *env = NULL; - env = task->env; + env = task->env; - synctask_set (task); - THIS = task->xl; + synctask_set(task); + THIS = task->xl; + +#if defined(__NetBSD__) && defined(_UC_TLSBASE) + /* Preserve pthread private pointer through swapcontex() */ + task->ctx.uc_flags &= ~_UC_TLSBASE; +#endif + +#ifdef HAVE_TSAN_API + __tsan_switch_to_fiber(task->tsan.fiber, 0); +#endif - if (swapcontext (&env->sched, &task->ctx) < 0) { - gf_log ("syncop", GF_LOG_ERROR, - "swapcontext failed (%s)", strerror (errno)); + if (swapcontext(&task->proc->sched, &task->ctx) < 0) { + gf_msg("syncop", GF_LOG_ERROR, errno, LG_MSG_SWAPCONTEXT_FAILED, + "swapcontext failed"); + } + + if (task->state == SYNCTASK_DONE) { + synctask_done(task); + return; + } + + pthread_mutex_lock(&env->mutex); + { + if (task->woken) { + __run(task); + } else { + task->slept = 1; + __wait(task); + + if (task->delta != NULL) { + task->timer = gf_timer_call_after(task->xl->ctx, *task->delta, + synctask_timer, task); + } } -} + task->delta = NULL; + } + pthread_mutex_unlock(&env->mutex); +} void * -syncenv_processor (void *thdata) +syncenv_processor(void *thdata) { - struct syncenv *env = NULL; - struct synctask *task = NULL; + struct syncproc *proc = NULL; + struct synctask *task = NULL; - env = thdata; + proc = thdata; - for (;;) { - task = syncenv_task (env); +#ifdef HAVE_TSAN_API + proc->tsan.fiber = __tsan_create_fiber(0); + snprintf(proc->tsan.name, TSAN_THREAD_NAMELEN, "<sched of syncenv@%p>", + proc); + __tsan_set_fiber_name(proc->tsan.fiber, proc->tsan.name); +#endif - if (task->complete) { - synctask_destroy (task); - continue; - } + while ((task = syncenv_task(proc)) != NULL) { + synctask_switchto(task); + } - synctask_switchto (task); +#ifdef HAVE_TSAN_API + __tsan_destroy_fiber(proc->tsan.fiber); +#endif + + return NULL; +} + +/* The syncenv threads are cleaned up in this routine. + */ +void +syncenv_destroy(struct syncenv *env) +{ + if (env == NULL) + return; + + /* SET the 'destroy' in syncenv structure to prohibit any + * further synctask(s) on this syncenv which is in destroy mode. + * + * If syncenv threads are in pthread cond wait with no tasks in + * their run or wait queue, then the threads are woken up by + * broadcasting the cond variable and if destroy field is set, + * the infinite loop in syncenv_processor is broken and the + * threads return. + * + * If syncenv threads have tasks in runq or waitq, the tasks are + * completed and only then the thread returns. + */ + pthread_mutex_lock(&env->mutex); + { + env->destroy = 1; + /* This broadcast will wake threads in pthread_cond_wait + * in syncenv_task + */ + pthread_cond_broadcast(&env->cond); + + /* when the syncenv_task() thread is exiting, it broadcasts to + * wake the below wait. + */ + while (env->procs != 0) { + pthread_cond_wait(&env->cond, &env->mutex); } + } + pthread_mutex_unlock(&env->mutex); + + pthread_mutex_destroy(&env->mutex); + pthread_cond_destroy(&env->cond); + + GF_FREE(env); + + return; +} + +struct syncenv * +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 = GF_CALLOC(1, sizeof(*newenv), gf_common_mt_syncenv); + if (!newenv) return NULL; + + pthread_mutex_init(&newenv->mutex, NULL); + pthread_cond_init(&newenv->cond, NULL); + + INIT_LIST_HEAD(&newenv->runq); + INIT_LIST_HEAD(&newenv->waitq); + + newenv->stacksize = SYNCENV_DEFAULT_STACKSIZE; + if (stacksize) + newenv->stacksize = stacksize; + newenv->procmin = procmin; + newenv->procmax = procmax; + newenv->procs_idle = 0; + + for (i = 0; i < newenv->procmin; i++) { + newenv->proc[i].env = newenv; + ret = gf_thread_create(&newenv->proc[i].processor, NULL, + syncenv_processor, &newenv->proc[i], "sproc%d", + i); + if (ret) + break; + newenv->procs++; + } + + if (ret != 0) { + syncenv_destroy(newenv); + newenv = NULL; + } + + return newenv; +} + +int +synclock_init(synclock_t *lock, lock_attr_t attr) +{ + if (!lock) + return -1; + + pthread_cond_init(&lock->cond, 0); + lock->type = LOCK_NULL; + lock->owner = NULL; + lock->owner_tid = 0; + lock->lock = 0; + lock->attr = attr; + INIT_LIST_HEAD(&lock->waitq); + + return pthread_mutex_init(&lock->guard, 0); +} + +int +synclock_destroy(synclock_t *lock) +{ + if (!lock) + return -1; + + pthread_cond_destroy(&lock->cond); + return pthread_mutex_destroy(&lock->guard); +} + +static int +__synclock_lock(struct synclock *lock) +{ + struct synctask *task = NULL; + + if (!lock) + return -1; + + task = synctask_get(); + + if (lock->lock && (lock->attr == SYNC_LOCK_RECURSIVE)) { + /*Recursive lock (if same owner requested for lock again then + *increment lock count and return success). + *Note:same number of unlocks required. + */ + switch (lock->type) { + case LOCK_TASK: + if (task == lock->owner) { + lock->lock++; + gf_msg_trace("", 0, + "Recursive lock called by" + " sync task.owner= %p,lock=%d", + lock->owner, lock->lock); + return 0; + } + break; + case LOCK_THREAD: + if (pthread_equal(pthread_self(), lock->owner_tid)) { + lock->lock++; + gf_msg_trace("", 0, + "Recursive lock called by" + " thread ,owner=%u lock=%d", + (unsigned int)lock->owner_tid, lock->lock); + return 0; + } + break; + default: + gf_msg("", GF_LOG_CRITICAL, 0, LG_MSG_UNKNOWN_LOCK_TYPE, + "unknown lock type"); + break; + } + } + + while (lock->lock) { + if (task) { + /* called within a synctask */ + task->woken = 0; + list_add_tail(&task->waitq, &lock->waitq); + pthread_mutex_unlock(&lock->guard); + synctask_yield(task, NULL); + /* task is removed from waitq in unlock, + * under lock->guard.*/ + pthread_mutex_lock(&lock->guard); + } else { + /* called by a non-synctask */ + pthread_cond_wait(&lock->cond, &lock->guard); + } + } + + if (task) { + lock->type = LOCK_TASK; + lock->owner = task; /* for synctask*/ + + } else { + lock->type = LOCK_THREAD; + lock->owner_tid = pthread_self(); /* for non-synctask */ + } + lock->lock = 1; + + return 0; +} + +int +synclock_lock(synclock_t *lock) +{ + int ret = 0; + + pthread_mutex_lock(&lock->guard); + { + ret = __synclock_lock(lock); + } + pthread_mutex_unlock(&lock->guard); + + return ret; } +int +synclock_trylock(synclock_t *lock) +{ + int ret = 0; + + errno = 0; + + pthread_mutex_lock(&lock->guard); + { + if (lock->lock) { + errno = EBUSY; + ret = -1; + goto unlock; + } + + ret = __synclock_lock(lock); + } +unlock: + pthread_mutex_unlock(&lock->guard); + + return ret; +} + +static int +__synclock_unlock(synclock_t *lock) +{ + struct synctask *task = NULL; + struct synctask *curr = NULL; + + if (!lock) + return -1; + + if (lock->lock == 0) { + gf_msg("", GF_LOG_CRITICAL, 0, LG_MSG_UNLOCK_BEFORE_LOCK, + "Unlock called before lock "); + return -1; + } + curr = synctask_get(); + /*unlock should be called by lock owner + *i.e this will not allow the lock in nonsync task and unlock + * in sync task and vice-versa + */ + switch (lock->type) { + case LOCK_TASK: + if (curr == lock->owner) { + lock->lock--; + gf_msg_trace("", 0, + "Unlock success %p, remaining" + " locks=%d", + lock->owner, lock->lock); + } else { + gf_msg("", GF_LOG_WARNING, 0, LG_MSG_LOCK_OWNER_ERROR, + "Unlock called by %p, but lock held by %p", curr, + lock->owner); + } + + break; + case LOCK_THREAD: + if (pthread_equal(pthread_self(), lock->owner_tid)) { + lock->lock--; + gf_msg_trace("", 0, + "Unlock success %u, remaining " + "locks=%d", + (unsigned int)lock->owner_tid, lock->lock); + } else { + gf_msg("", GF_LOG_WARNING, 0, LG_MSG_LOCK_OWNER_ERROR, + "Unlock called by %u, but lock held by %u", + (unsigned int)pthread_self(), + (unsigned int)lock->owner_tid); + } + + break; + default: + break; + } + + if (lock->lock > 0) { + return 0; + } + lock->type = LOCK_NULL; + lock->owner = NULL; + lock->owner_tid = 0; + lock->lock = 0; + /* There could be both synctasks and non synctasks + waiting (or none, or either). As a mid-approach + between maintaining too many waiting counters + at one extreme and a thundering herd on unlock + at the other, call a cond_signal (which wakes + one waiter) and first synctask waiter. So at + most we have two threads waking up to grab the + just released lock. + */ + pthread_cond_signal(&lock->cond); + if (!list_empty(&lock->waitq)) { + task = list_entry(lock->waitq.next, struct synctask, waitq); + list_del_init(&task->waitq); + synctask_wake(task); + } + + return 0; +} + +int +synclock_unlock(synclock_t *lock) +{ + int ret = 0; + + pthread_mutex_lock(&lock->guard); + { + ret = __synclock_unlock(lock); + } + pthread_mutex_unlock(&lock->guard); + + return ret; +} + +/* Condition variables */ + +int32_t +synccond_init(synccond_t *cond) +{ + int32_t ret; + + INIT_LIST_HEAD(&cond->waitq); + + ret = pthread_mutex_init(&cond->pmutex, NULL); + if (ret != 0) { + return -ret; + } + + ret = pthread_cond_init(&cond->pcond, NULL); + if (ret != 0) { + pthread_mutex_destroy(&cond->pmutex); + } + + return -ret; +} void -syncenv_destroy (struct syncenv *env) +synccond_destroy(synccond_t *cond) { + pthread_cond_destroy(&cond->pcond); + pthread_mutex_destroy(&cond->pmutex); +} + +int +synccond_timedwait(synccond_t *cond, synclock_t *lock, struct timespec *delta) +{ + struct timespec now; + struct synctask *task = NULL; + int ret; + + task = synctask_get(); + if (task == NULL) { + if (delta != NULL) { + timespec_now_realtime(&now); + timespec_adjust_delta(&now, *delta); + } + + pthread_mutex_lock(&cond->pmutex); + + if (delta == NULL) { + ret = -pthread_cond_wait(&cond->pcond, &cond->pmutex); + } else { + ret = -pthread_cond_timedwait(&cond->pcond, &cond->pmutex, &now); + } + } else { + pthread_mutex_lock(&cond->pmutex); + + list_add_tail(&task->waitq, &cond->waitq); + task->synccond = cond; + + ret = synclock_unlock(lock); + if (ret == 0) { + pthread_mutex_unlock(&cond->pmutex); + + synctask_yield(task, delta); + + ret = synclock_lock(lock); + if (ret == 0) { + ret = task->ret; + } + task->ret = 0; + + return ret; + } + + list_del_init(&task->waitq); + } + + pthread_mutex_unlock(&cond->pmutex); + + return ret; } +int +synccond_wait(synccond_t *cond, synclock_t *lock) +{ + return synccond_timedwait(cond, lock, NULL); +} -struct syncenv * -syncenv_new (size_t stacksize) +void +synccond_signal(synccond_t *cond) { - struct syncenv *newenv = NULL; - int ret = 0; + struct synctask *task; - newenv = CALLOC (1, sizeof (*newenv)); + pthread_mutex_lock(&cond->pmutex); - if (!newenv) - return NULL; + if (!list_empty(&cond->waitq)) { + task = list_first_entry(&cond->waitq, struct synctask, waitq); + list_del_init(&task->waitq); - pthread_mutex_init (&newenv->mutex, NULL); - pthread_cond_init (&newenv->cond, NULL); + pthread_mutex_unlock(&cond->pmutex); - INIT_LIST_HEAD (&newenv->runq); - INIT_LIST_HEAD (&newenv->waitq); + synctask_wake(task); + } else { + pthread_cond_signal(&cond->pcond); - newenv->stacksize = SYNCENV_DEFAULT_STACKSIZE; - if (stacksize) - newenv->stacksize = stacksize; + pthread_mutex_unlock(&cond->pmutex); + } +} + +void +synccond_broadcast(synccond_t *cond) +{ + struct list_head list; + struct synctask *task; - ret = pthread_create (&newenv->processor, NULL, - syncenv_processor, newenv); + INIT_LIST_HEAD(&list); - if (ret != 0) - syncenv_destroy (newenv); + pthread_mutex_lock(&cond->pmutex); - return newenv; + list_splice_init(&cond->waitq, &list); + pthread_cond_broadcast(&cond->pcond); + + pthread_mutex_unlock(&cond->pmutex); + + while (!list_empty(&list)) { + task = list_first_entry(&list, struct synctask, waitq); + list_del_init(&task->waitq); + + synctask_wake(task); + } } +/* Barriers */ -/* FOPS */ +int +syncbarrier_init(struct syncbarrier *barrier) +{ + int ret = 0; + if (!barrier) { + errno = EINVAL; + return -1; + } + ret = pthread_cond_init(&barrier->cond, 0); + if (ret) { + errno = ret; + return -1; + } + barrier->count = 0; + barrier->waitfor = 0; + INIT_LIST_HEAD(&barrier->waitq); + + ret = pthread_mutex_init(&barrier->guard, 0); + if (ret) { + (void)pthread_cond_destroy(&barrier->cond); + errno = ret; + return -1; + } + barrier->initialized = _gf_true; + return 0; +} int -syncop_lookup_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int op_ret, int op_errno, inode_t *inode, - struct iatt *iatt, dict_t *xattr, struct iatt *parent) +syncbarrier_destroy(struct syncbarrier *barrier) +{ + int ret = 0; + int ret1 = 0; + if (!barrier) { + errno = EINVAL; + return -1; + } + + if (barrier->initialized) { + ret = pthread_cond_destroy(&barrier->cond); + ret1 = pthread_mutex_destroy(&barrier->guard); + barrier->initialized = _gf_false; + } + if (ret || ret1) { + errno = ret ? ret : ret1; + return -1; + } + return 0; +} + +static int +__syncbarrier_wait(struct syncbarrier *barrier, int waitfor) { - struct syncargs *args = NULL; + struct synctask *task = NULL; - args = cookie; + if (!barrier) { + errno = EINVAL; + return -1; + } - args->op_ret = op_ret; - args->op_errno = op_errno; + task = synctask_get(); - if (op_ret == 0) { - args->iatt1 = *iatt; - args->xattr = xattr; - args->iatt2 = *parent; + while (barrier->count < waitfor) { + if (task) { + /* called within a synctask */ + list_add_tail(&task->waitq, &barrier->waitq); + pthread_mutex_unlock(&barrier->guard); + synctask_yield(task, NULL); + pthread_mutex_lock(&barrier->guard); + } else { + /* called by a non-synctask */ + pthread_cond_wait(&barrier->cond, &barrier->guard); } + } - __wake (args); + barrier->count = 0; + return 0; +} + +int +syncbarrier_wait(struct syncbarrier *barrier, int waitfor) +{ + int ret = 0; + + pthread_mutex_lock(&barrier->guard); + { + ret = __syncbarrier_wait(barrier, waitfor); + } + pthread_mutex_unlock(&barrier->guard); + + return ret; +} + +static int +__syncbarrier_wake(struct syncbarrier *barrier) +{ + struct synctask *task = NULL; + + if (!barrier) { + errno = EINVAL; + return -1; + } + + barrier->count++; + if (barrier->waitfor && (barrier->count < barrier->waitfor)) return 0; + + pthread_cond_signal(&barrier->cond); + if (!list_empty(&barrier->waitq)) { + task = list_entry(barrier->waitq.next, struct synctask, waitq); + list_del_init(&task->waitq); + synctask_wake(task); + } + barrier->waitfor = 0; + + return 0; +} + +int +syncbarrier_wake(struct syncbarrier *barrier) +{ + int ret = 0; + + pthread_mutex_lock(&barrier->guard); + { + ret = __syncbarrier_wake(barrier); + } + pthread_mutex_unlock(&barrier->guard); + + return ret; } +/* FOPS */ int -syncop_lookup (xlator_t *subvol, loc_t *loc, dict_t *xattr_req, - struct iatt *iatt, dict_t **xattr_rsp, struct iatt *parent) +syncop_lookup_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, + int op_errno, inode_t *inode, struct iatt *iatt, + dict_t *xdata, struct iatt *parent) { - struct syncargs args = {0, }; + struct syncargs *args = NULL; - SYNCOP (subvol, (&args), syncop_lookup_cbk, subvol->fops->lookup, - loc, xattr_req); + args = cookie; - if (iatt) - *iatt = args.iatt1; - if (xattr_rsp) - *xattr_rsp = args.xattr; - if (parent) - *parent = args.iatt2; + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); - errno = args.op_errno; - return args.op_ret; + if (op_ret == 0) { + args->iatt1 = *iatt; + args->iatt2 = *parent; + } + + __wake(args); + + return 0; +} + +int +syncop_lookup(xlator_t *subvol, loc_t *loc, struct iatt *iatt, + struct iatt *parent, dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_lookup_cbk, subvol->fops->lookup, loc, + xdata_in); + + if (iatt) + *iatt = args.iatt1; + if (parent) + *parent = args.iatt2; + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; } -static gf_dirent_t * -entry_copy (gf_dirent_t *source) +int32_t +syncop_readdirp_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, gf_dirent_t *entries, + dict_t *xdata) { - gf_dirent_t *sink = NULL; + struct syncargs *args = NULL; + gf_dirent_t *entry = NULL; + gf_dirent_t *tmp = NULL; + + int count = 0; + + args = cookie; + + INIT_LIST_HEAD(&args->entries.list); - sink = gf_dirent_for_name (source->d_name); + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); - sink->d_off = source->d_off; - sink->d_ino = source->d_ino; - sink->d_type = source->d_type; + if (op_ret >= 0) { + list_for_each_entry(entry, &entries->list, list) + { + tmp = entry_copy(entry); + if (!tmp) { + args->op_ret = -1; + args->op_errno = ENOMEM; + gf_dirent_free(&(args->entries)); + break; + } + gf_msg_trace(this->name, 0, + "adding entry=%s, " + "count=%d", + tmp->d_name, count); + list_add_tail(&tmp->list, &(args->entries.list)); + count++; + } + } + + __wake(args); + + return 0; +} - return sink; +int +syncop_readdirp(xlator_t *subvol, fd_t *fd, size_t size, off_t off, + gf_dirent_t *entries, dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_readdirp_cbk, subvol->fops->readdirp, fd, + size, off, xdata_in); + + if (entries) + list_splice_init(&args.entries.list, &entries->list); + else + gf_dirent_free(&args.entries); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; } int32_t -syncop_readdirp_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - gf_dirent_t *entries) -{ - struct syncargs *args = NULL; - gf_dirent_t *entry = NULL; - gf_dirent_t *tmp = NULL; - - int count = 0; - - args = cookie; - - INIT_LIST_HEAD (&args->entries.list); - - args->op_ret = op_ret; - args->op_errno = op_errno; - - if (op_ret >= 0) { - list_for_each_entry (entry, &entries->list, list) { - tmp = entry_copy (entry); - gf_log (this->name, GF_LOG_TRACE, - "adding entry=%s, count=%d", - tmp->d_name, count); - list_add_tail (&tmp->list, &(args->entries.list)); - count++; - } +syncop_readdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, gf_dirent_t *entries, + dict_t *xdata) +{ + struct syncargs *args = NULL; + gf_dirent_t *entry = NULL; + gf_dirent_t *tmp = NULL; + + int count = 0; + + args = cookie; + + INIT_LIST_HEAD(&args->entries.list); + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + if (op_ret >= 0) { + list_for_each_entry(entry, &entries->list, list) + { + tmp = entry_copy(entry); + if (!tmp) { + args->op_ret = -1; + args->op_errno = ENOMEM; + gf_dirent_free(&(args->entries)); + break; + } + gf_msg_trace(this->name, 0, + "adding " + "entry=%s, count=%d", + tmp->d_name, count); + list_add_tail(&tmp->list, &(args->entries.list)); + count++; } + } - __wake (args); + __wake(args); - return 0; + return 0; +} + +int +syncop_readdir(xlator_t *subvol, fd_t *fd, size_t size, off_t off, + gf_dirent_t *entries, dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_readdir_cbk, subvol->fops->readdir, fd, size, + off, xdata_in); + + if (entries) + list_splice_init(&args.entries.list, &entries->list); + else + gf_dirent_free(&args.entries); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int32_t +syncop_opendir_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + __wake(args); + + return 0; } int -syncop_readdirp (xlator_t *subvol, - fd_t *fd, - size_t size, - off_t off, - gf_dirent_t *entries) +syncop_opendir(xlator_t *subvol, loc_t *loc, fd_t *fd, dict_t *xdata_in, + dict_t **xdata_out) { - struct syncargs args = {0, }; + struct syncargs args = { + 0, + }; - SYNCOP (subvol, (&args), syncop_readdirp_cbk, subvol->fops->readdirp, - fd, size, off); + SYNCOP(subvol, (&args), syncop_opendir_cbk, subvol->fops->opendir, loc, fd, + xdata_in); - if (entries) - list_splice_init (&args.entries.list, &entries->list); + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); - errno = args.op_errno; - return args.op_ret; + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_fsyncdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + __wake(args); + + return 0; +} + +int +syncop_fsyncdir(xlator_t *subvol, fd_t *fd, int datasync, dict_t *xdata_in, + dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_fsyncdir_cbk, subvol->fops->fsyncdir, fd, + datasync, xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_removexattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + __wake(args); + + return 0; +} + +int +syncop_removexattr(xlator_t *subvol, loc_t *loc, const char *name, + dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_removexattr_cbk, subvol->fops->removexattr, + loc, name, xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_fremovexattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + __wake(args); + + return 0; +} + +int +syncop_fremovexattr(xlator_t *subvol, fd_t *fd, const char *name, + dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_fremovexattr_cbk, subvol->fops->fremovexattr, + fd, name, xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_setxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + __wake(args); + + return 0; +} + +int +syncop_setxattr(xlator_t *subvol, loc_t *loc, dict_t *dict, int32_t flags, + dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_setxattr_cbk, subvol->fops->setxattr, loc, + dict, flags, xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_fsetxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + __wake(args); + + return 0; +} + +int +syncop_fsetxattr(xlator_t *subvol, fd_t *fd, dict_t *dict, int32_t flags, + dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_fsetxattr_cbk, subvol->fops->fsetxattr, fd, + dict, flags, xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_getxattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, dict_t *dict, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + if (op_ret >= 0) + args->xattr = dict_ref(dict); + + __wake(args); + + return 0; +} + +int +syncop_listxattr(xlator_t *subvol, loc_t *loc, dict_t **dict, dict_t *xdata_in, + dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_getxattr_cbk, subvol->fops->getxattr, loc, + NULL, xdata_in); + + if (dict) + *dict = args.xattr; + else if (args.xattr) + dict_unref(args.xattr); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_getxattr(xlator_t *subvol, loc_t *loc, dict_t **dict, const char *key, + dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_getxattr_cbk, subvol->fops->getxattr, loc, + key, xdata_in); + + if (dict) + *dict = args.xattr; + else if (args.xattr) + dict_unref(args.xattr); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_fgetxattr(xlator_t *subvol, fd_t *fd, dict_t **dict, const char *key, + dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_getxattr_cbk, subvol->fops->fgetxattr, fd, + key, xdata_in); + + if (dict) + *dict = args.xattr; + else if (args.xattr) + dict_unref(args.xattr); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_statfs_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct statvfs *buf, + dict_t *xdata) + +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + if (op_ret == 0) { + args->statvfs_buf = *buf; + } + + __wake(args); + + return 0; +} + +int +syncop_statfs(xlator_t *subvol, loc_t *loc, struct statvfs *buf, + dict_t *xdata_in, dict_t **xdata_out) + +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_statfs_cbk, subvol->fops->statfs, loc, + xdata_in); + + if (buf) + *buf = args.statvfs_buf; + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_setattr_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, struct iatt *preop, + struct iatt *postop, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + if (op_ret == 0) { + args->iatt1 = *preop; + args->iatt2 = *postop; + } + + __wake(args); + + return 0; +} + +int +syncop_setattr(xlator_t *subvol, loc_t *loc, struct iatt *iatt, int valid, + struct iatt *preop, struct iatt *postop, dict_t *xdata_in, + dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_setattr_cbk, subvol->fops->setattr, loc, + iatt, valid, xdata_in); + + if (preop) + *preop = args.iatt1; + if (postop) + *postop = args.iatt2; + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_fsetattr(xlator_t *subvol, fd_t *fd, struct iatt *iatt, int valid, + struct iatt *preop, struct iatt *postop, dict_t *xdata_in, + dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_setattr_cbk, subvol->fops->fsetattr, fd, + iatt, valid, xdata_in); + + if (preop) + *preop = args.iatt1; + if (postop) + *postop = args.iatt2; + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; } int32_t -syncop_opendir_cbk (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - fd_t *fd) +syncop_open_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd, dict_t *xdata) { - struct syncargs *args = NULL; + struct syncargs *args = NULL; - args = cookie; + args = cookie; - args->op_ret = op_ret; - args->op_errno = op_errno; + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); - __wake (args); + __wake(args); - return 0; + return 0; } int -syncop_opendir (xlator_t *subvol, - loc_t *loc, - fd_t *fd) +syncop_open(xlator_t *subvol, loc_t *loc, int32_t flags, fd_t *fd, + dict_t *xdata_in, dict_t **xdata_out) { - struct syncargs args = {0, }; + struct syncargs args = { + 0, + }; - SYNCOP (subvol, (&args), syncop_opendir_cbk, subvol->fops->opendir, - loc, fd); + SYNCOP(subvol, (&args), syncop_open_cbk, subvol->fops->open, loc, flags, fd, + xdata_in); - errno = args.op_errno; - return args.op_ret; + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; } +int32_t +syncop_readv_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iovec *vector, + int32_t count, struct iatt *stbuf, struct iobref *iobref, + dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + INIT_LIST_HEAD(&args->entries.list); + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + if (args->op_ret >= 0) { + if (iobref) + args->iobref = iobref_ref(iobref); + args->vector = iov_dup(vector, count); + args->count = count; + args->iatt1 = *stbuf; + } + + __wake(args); + + return 0; +} int -syncop_setxattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int op_ret, int op_errno) +syncop_readv(xlator_t *subvol, fd_t *fd, size_t size, off_t off, uint32_t flags, + struct iovec **vector, int *count, struct iobref **iobref, + struct iatt *iatt, dict_t *xdata_in, dict_t **xdata_out) { - struct syncargs *args = NULL; + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_readv_cbk, subvol->fops->readv, fd, size, + off, flags, xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (iatt) + *iatt = args.iatt1; + + if (args.op_ret < 0) + goto out; + + if (vector) + *vector = args.vector; + else + GF_FREE(args.vector); + + if (count) + *count = args.count; + + /* Do we need a 'ref' here? */ + if (iobref) + *iobref = args.iobref; + else if (args.iobref) + iobref_unref(args.iobref); + +out: + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} - args = cookie; +int +syncop_writev_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->op_ret = op_ret; - args->op_errno = op_errno; + args = cookie; - __wake (args); + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); - return 0; + if (op_ret >= 0) { + args->iatt1 = *prebuf; + args->iatt2 = *postbuf; + } + + __wake(args); + + return 0; } +int +syncop_writev(xlator_t *subvol, fd_t *fd, const struct iovec *vector, + int32_t count, off_t offset, struct iobref *iobref, + uint32_t flags, struct iatt *preiatt, struct iatt *postiatt, + dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_writev_cbk, subvol->fops->writev, fd, + (struct iovec *)vector, count, offset, flags, iobref, xdata_in); + + if (preiatt) + *preiatt = args.iatt1; + if (postiatt) + *postiatt = args.iatt2; + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} int -syncop_setxattr (xlator_t *subvol, loc_t *loc, dict_t *dict, int32_t flags) +syncop_write(xlator_t *subvol, fd_t *fd, const char *buf, int size, + off_t offset, struct iobref *iobref, uint32_t flags, + dict_t *xdata_in, dict_t **xdata_out) { - struct syncargs args = {0, }; + struct syncargs args = { + 0, + }; + struct iovec vec = { + 0, + }; + + vec.iov_len = size; + vec.iov_base = (void *)buf; + + SYNCOP(subvol, (&args), syncop_writev_cbk, subvol->fops->writev, fd, &vec, + 1, offset, flags, iobref, xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} - SYNCOP (subvol, (&args), syncop_setxattr_cbk, subvol->fops->setxattr, - loc, dict, flags); +int +syncop_close(fd_t *fd) +{ + if (fd) + fd_unref(fd); + return 0; +} - errno = args.op_errno; - return args.op_ret; +int32_t +syncop_create_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, fd_t *fd, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + if (buf) + args->iatt1 = *buf; + + __wake(args); + + return 0; } int -syncop_statfs_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int32_t op_ret, int32_t op_errno, - struct statvfs *buf) +syncop_create(xlator_t *subvol, loc_t *loc, int32_t flags, mode_t mode, + fd_t *fd, struct iatt *iatt, dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_create_cbk, subvol->fops->create, loc, flags, + mode, 0, fd, xdata_in); + + if (iatt) + *iatt = args.iatt1; + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} +int32_t +syncop_put_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) { - struct syncargs *args = NULL; + struct syncargs *args = NULL; - args = cookie; + args = cookie; - args->op_ret = op_ret; - args->op_errno = op_errno; + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); - if (op_ret == 0) { - args->statvfs_buf = *buf; - } + if (buf) + args->iatt1 = *buf; - __wake (args); + __wake(args); - return 0; + return 0; +} + +int +syncop_put(xlator_t *subvol, loc_t *loc, mode_t mode, mode_t umask, + uint32_t flags, struct iovec *vector, int32_t count, off_t offset, + struct iobref *iobref, dict_t *xattr, struct iatt *iatt, + dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_put_cbk, subvol->fops->put, loc, mode, umask, + flags, (struct iovec *)vector, count, offset, iobref, xattr, + xdata_in); + + if (iatt) + *iatt = args.iatt1; + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; } +int +syncop_unlink_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, + int op_errno, struct iatt *preparent, struct iatt *postparent, + dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + __wake(args); + + return 0; +} int -syncop_statfs (xlator_t *subvol, loc_t *loc, struct statvfs *buf) +syncop_unlink(xlator_t *subvol, loc_t *loc, dict_t *xdata_in, + dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_unlink_cbk, subvol->fops->unlink, loc, 0, + xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_rmdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, + int op_errno, struct iatt *preparent, struct iatt *postparent, + dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + __wake(args); + + return 0; +} + +int +syncop_rmdir(xlator_t *subvol, loc_t *loc, int flags, dict_t *xdata_in, + dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_rmdir_cbk, subvol->fops->rmdir, loc, flags, + xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_link_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + if (buf) + args->iatt1 = *buf; + + __wake(args); + + return 0; +} + +int +syncop_link(xlator_t *subvol, loc_t *oldloc, loc_t *newloc, struct iatt *iatt, + dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_link_cbk, subvol->fops->link, oldloc, newloc, + xdata_in); + + if (iatt) + *iatt = args.iatt1; + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + + return args.op_ret; +} + +int +syncop_rename_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *buf, + struct iatt *preoldparent, struct iatt *postoldparent, + struct iatt *prenewparent, struct iatt *postnewparent, + dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + __wake(args); + + return 0; +} + +int +syncop_rename(xlator_t *subvol, loc_t *oldloc, loc_t *newloc, dict_t *xdata_in, + dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_rename_cbk, subvol->fops->rename, oldloc, + newloc, xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + + return args.op_ret; +} + +int +syncop_ftruncate_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; + if (xdata) + args->xdata = dict_ref(xdata); + + if (op_ret >= 0) { + args->iatt1 = *prebuf; + args->iatt2 = *postbuf; + } + + __wake(args); + + return 0; +} + +int +syncop_ftruncate(xlator_t *subvol, fd_t *fd, off_t offset, struct iatt *preiatt, + struct iatt *postiatt, dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_ftruncate_cbk, subvol->fops->ftruncate, fd, + offset, xdata_in); + + if (preiatt) + *preiatt = args.iatt1; + if (postiatt) + *postiatt = args.iatt2; + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_truncate(xlator_t *subvol, loc_t *loc, off_t offset, dict_t *xdata_in, + dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_ftruncate_cbk, subvol->fops->truncate, loc, + offset, xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_fsync_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) { - struct syncargs args = {0, }; + struct syncargs *args = NULL; - SYNCOP (subvol, (&args), syncop_statfs_cbk, subvol->fops->statfs, - loc); + args = cookie; - if (buf) - *buf = args.statvfs_buf; + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); - errno = args.op_errno; + if (op_ret >= 0) { + args->iatt1 = *prebuf; + args->iatt2 = *postbuf; + } + + __wake(args); + + return 0; +} + +int +syncop_fsync(xlator_t *subvol, fd_t *fd, int dataonly, struct iatt *preiatt, + struct iatt *postiatt, dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_fsync_cbk, subvol->fops->fsync, fd, dataonly, + xdata_in); + + if (preiatt) + *preiatt = args.iatt1; + if (postiatt) + *postiatt = args.iatt2; + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_flush_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + __wake(args); + + return 0; +} + +int +syncop_flush(xlator_t *subvol, fd_t *fd, dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = {0}; + + SYNCOP(subvol, (&args), syncop_flush_cbk, subvol->fops->flush, fd, + xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_fstat_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *stbuf, + dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + if (op_ret == 0) + args->iatt1 = *stbuf; + + __wake(args); + + return 0; +} + +int +syncop_fstat(xlator_t *subvol, fd_t *fd, struct iatt *stbuf, dict_t *xdata_in, + dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_fstat_cbk, subvol->fops->fstat, fd, + xdata_in); + + if (stbuf) + *stbuf = args.iatt1; + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_stat(xlator_t *subvol, loc_t *loc, struct iatt *stbuf, dict_t *xdata_in, + dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_fstat_cbk, subvol->fops->stat, loc, + xdata_in); + + if (stbuf) + *stbuf = args.iatt1; + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int32_t +syncop_symlink_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + if (buf) + args->iatt1 = *buf; + + __wake(args); + + return 0; +} + +int +syncop_symlink(xlator_t *subvol, loc_t *loc, const char *newpath, + struct iatt *iatt, dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_symlink_cbk, subvol->fops->symlink, newpath, + loc, 0, xdata_in); + + if (iatt) + *iatt = args.iatt1; + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_readlink_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, const char *path, + struct iatt *stbuf, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + if ((op_ret != -1) && path) + args->buffer = gf_strdup(path); + + __wake(args); + + return 0; +} + +int +syncop_readlink(xlator_t *subvol, loc_t *loc, char **buffer, size_t size, + dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_readlink_cbk, subvol->fops->readlink, loc, + size, xdata_in); + + if (buffer) + *buffer = args.buffer; + else + GF_FREE(args.buffer); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_mknod_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + if (buf) + args->iatt1 = *buf; + + __wake(args); + + return 0; +} + +int +syncop_mknod(xlator_t *subvol, loc_t *loc, mode_t mode, dev_t rdev, + struct iatt *iatt, dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_mknod_cbk, subvol->fops->mknod, loc, mode, + rdev, 0, xdata_in); + + if (iatt) + *iatt = args.iatt1; + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_mkdir_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, struct iatt *preparent, + struct iatt *postparent, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + if (buf) + args->iatt1 = *buf; + + __wake(args); + + return 0; +} + +int +syncop_mkdir(xlator_t *subvol, loc_t *loc, mode_t mode, struct iatt *iatt, + dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_mkdir_cbk, subvol->fops->mkdir, loc, mode, 0, + xdata_in); + + if (iatt) + *iatt = args.iatt1; + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_access_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + __wake(args); + + return 0; +} + +/* posix_acl xlator will respond in different ways for access calls from + fuse and access calls from nfs. For fuse, checking op_ret is sufficient + to check whether the access call is successful or not. But for nfs the + mode of the access that is permitted is put into op_errno before unwind. + With syncop, the caller of syncop_access will not be able to get the + mode of the access despite call being successul (since syncop_access + returns only the op_ret collected in args). + Now, if access call is failed, then args.op_ret is returned to recognise + the failure. But if op_ret is zero, then the mode of access which is + set in args.op_errno is returned. Thus the caller of syncop_access + has to check whether the return value is less than zero or not. If the + return value it got is less than zero, then access call is failed. + If it is not, then the access call is successful and the value the caller + got is the mode of the access. +*/ +int +syncop_access(xlator_t *subvol, loc_t *loc, int32_t mask, dict_t *xdata_in, + dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_access_cbk, subvol->fops->access, loc, mask, + xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_errno; +} + +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; + if (xdata) + args->xdata = dict_ref(xdata); + + __wake(args); + + return 0; +} + +int +syncop_fallocate(xlator_t *subvol, fd_t *fd, int32_t keep_size, off_t offset, + size_t len, dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_fallocate_cbk, subvol->fops->fallocate, fd, + keep_size, offset, len, xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -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; + if (xdata) + args->xdata = dict_ref(xdata); + + __wake(args); + + return 0; +} + +int +syncop_discard(xlator_t *subvol, fd_t *fd, off_t offset, size_t len, + dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_discard_cbk, subvol->fops->discard, fd, + offset, len, xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -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; + if (xdata) + args->xdata = dict_ref(xdata); + + __wake(args); + + return 0; +} + +int +syncop_zerofill(xlator_t *subvol, fd_t *fd, off_t offset, off_t len, + dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_zerofill_cbk, subvol->fops->zerofill, fd, + offset, len, xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_ipc_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, + int op_errno, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + __wake(args); + + return 0; +} + +int +syncop_ipc(xlator_t *subvol, int32_t op, dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_ipc_cbk, subvol->fops->ipc, op, xdata_in); + + if (args.xdata) { + if (xdata_out) { + /* + * We're passing this reference to the caller, along + * with the pointer itself. That means they're + * responsible for calling dict_unref at some point. + */ + *xdata_out = args.xdata; + } else { + dict_unref(args.xdata); + } + } + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} + +int +syncop_seek_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, + int op_errno, off_t offset, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + args->offset = offset; + if (xdata) + args->xdata = dict_ref(xdata); + + __wake(args); + + return 0; +} + +int +syncop_seek(xlator_t *subvol, fd_t *fd, off_t offset, gf_seek_what_t what, + dict_t *xdata_in, off_t *off) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_seek_cbk, subvol->fops->seek, fd, offset, + what, xdata_in); + + if (args.op_ret < 0) { + return -args.op_errno; + } else { + if (off) + *off = args.offset; return args.op_ret; + } } int -syncop_setattr_cbk (call_frame_t *frame, void *cookie, xlator_t *this, - int op_ret, int op_errno, - struct iatt *preop, struct iatt *postop) +syncop_lease_cbk(call_frame_t *frame, void *cookie, xlator_t *this, int op_ret, + int op_errno, struct gf_lease *lease, dict_t *xdata) { - struct syncargs *args = NULL; + struct syncargs *args = NULL; - args = cookie; + args = cookie; - args->op_ret = op_ret; - args->op_errno = op_errno; + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + if (lease) + args->lease = *lease; + + __wake(args); + + return 0; +} - if (op_ret == 0) { - args->iatt1 = *preop; - args->iatt2 = *postop; +int +syncop_lease(xlator_t *subvol, loc_t *loc, struct gf_lease *lease, + dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_lease_cbk, subvol->fops->lease, loc, lease, + xdata_in); + + *lease = args.lease; + + if (args.xdata) { + if (xdata_out) { + /* + * We're passing this reference to the caller, along + * with the pointer itself. That means they're + * responsible for calling dict_unref at some point. + */ + *xdata_out = args.xdata; + } else { + dict_unref(args.xdata); } + } - __wake (args); + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; +} - return 0; +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) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + if (flock) + args->flock = *flock; + __wake(args); + + return 0; +} + +int +syncop_lk(xlator_t *subvol, fd_t *fd, int cmd, struct gf_flock *flock, + dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_lk_cbk, subvol->fops->lk, fd, cmd, flock, + xdata_in); + + *flock = args.flock; + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + return args.op_ret; } +int32_t +syncop_inodelk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + __wake(args); + + return 0; +} int -syncop_setattr (xlator_t *subvol, loc_t *loc, struct iatt *iatt, int valid, - struct iatt *preop, struct iatt *postop) +syncop_inodelk(xlator_t *subvol, const char *volume, loc_t *loc, int32_t cmd, + struct gf_flock *lock, dict_t *xdata_in, dict_t **xdata_out) { - struct syncargs args = {0, }; + struct syncargs args = { + 0, + }; - SYNCOP (subvol, (&args), syncop_setattr_cbk, subvol->fops->setattr, - loc, iatt, valid); + SYNCOP(subvol, (&args), syncop_inodelk_cbk, subvol->fops->inodelk, volume, + loc, cmd, lock, xdata_in); - if (preop) - *preop = args.iatt1; - if (postop) - *postop = args.iatt2; + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); - errno = args.op_errno; - return args.op_ret; + if (args.op_ret < 0) + return -args.op_errno; + + return args.op_ret; +} + +int32_t +syncop_entrylk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + __wake(args); + return 0; +} + +int +syncop_entrylk(xlator_t *subvol, const char *volume, loc_t *loc, + const char *basename, entrylk_cmd cmd, entrylk_type type, + dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_entrylk_cbk, subvol->fops->entrylk, volume, + loc, basename, cmd, type, xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + + return args.op_ret; +} + +int32_t +syncop_xattrop_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *dict, + dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + if (dict) + args->dict_out = dict_ref(dict); + + __wake(args); + + return 0; +} + +int +syncop_xattrop(xlator_t *subvol, loc_t *loc, gf_xattrop_flags_t flags, + dict_t *dict, dict_t *xdata_in, dict_t **dict_out, + dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_xattrop_cbk, subvol->fops->xattrop, loc, + flags, dict, xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (dict_out) + *dict_out = args.dict_out; + else if (args.dict_out) + dict_unref(args.dict_out); + + if (args.op_ret < 0) + return -args.op_errno; + + return args.op_ret; +} + +int +syncop_fxattrop(xlator_t *subvol, fd_t *fd, gf_xattrop_flags_t flags, + dict_t *dict, dict_t *xdata_in, dict_t **dict_out, + dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_xattrop_cbk, subvol->fops->fxattrop, fd, + flags, dict, xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (dict_out) + *dict_out = args.dict_out; + else if (args.dict_out) + dict_unref(args.dict_out); + + if (args.op_ret < 0) + return -args.op_errno; + + return args.op_ret; +} + +int32_t +syncop_getactivelk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, + lock_migration_info_t *locklist, dict_t *xdata) +{ + struct syncargs *args = NULL; + lock_migration_info_t *tmp = NULL; + lock_migration_info_t *entry = NULL; + + args = cookie; + + INIT_LIST_HEAD(&args->locklist.list); + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + if (op_ret > 0) { + list_for_each_entry(tmp, &locklist->list, list) + { + entry = GF_CALLOC(1, sizeof(lock_migration_info_t), + gf_common_mt_char); + + if (!entry) { + gf_msg(THIS->name, GF_LOG_ERROR, 0, 0, + "lock mem allocation failed"); + gf_free_mig_locks(&args->locklist); + + break; + } + + INIT_LIST_HEAD(&entry->list); + + entry->flock = tmp->flock; + + entry->lk_flags = tmp->lk_flags; + + entry->client_uid = gf_strdup(tmp->client_uid); + + list_add_tail(&entry->list, &args->locklist.list); + } + } + + __wake(args); + + return 0; } +int +syncop_getactivelk(xlator_t *subvol, loc_t *loc, + lock_migration_info_t *locklist, dict_t *xdata_in, + dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_getactivelk_cbk, subvol->fops->getactivelk, + loc, xdata_in); + + if (locklist) + list_splice_init(&args.locklist.list, &locklist->list); + else + gf_free_mig_locks(&args.locklist); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + + return args.op_ret; +} + +int +syncop_setactivelk_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + + if (xdata) + args->xdata = dict_ref(xdata); + + __wake(args); + + return 0; +} + +int +syncop_setactivelk(xlator_t *subvol, loc_t *loc, + lock_migration_info_t *locklist, dict_t *xdata_in, + dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_setactivelk_cbk, subvol->fops->setactivelk, + loc, locklist, xdata_in); + + if (xdata_out) + *xdata_out = args.xdata; + else if (args.xdata) + dict_unref(args.xdata); + + if (args.op_ret < 0) + return -args.op_errno; + + return args.op_ret; +} + +int +syncop_icreate_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, inode_t *inode, + struct iatt *buf, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + if (buf) + args->iatt1 = *buf; + + __wake(args); + + return 0; +} + +int +syncop_namelink_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int32_t op_ret, int32_t op_errno, struct iatt *prebuf, + struct iatt *postbuf, dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + + if (xdata) + args->xdata = dict_ref(xdata); + + __wake(args); + + return 0; +} + +int +syncop_copy_file_range(xlator_t *subvol, fd_t *fd_in, off64_t off_in, + fd_t *fd_out, off64_t off_out, size_t len, + uint32_t flags, struct iatt *stbuf, + struct iatt *preiatt_dst, struct iatt *postiatt_dst, + dict_t *xdata_in, dict_t **xdata_out) +{ + struct syncargs args = { + 0, + }; + + SYNCOP(subvol, (&args), syncop_copy_file_range_cbk, + subvol->fops->copy_file_range, fd_in, off_in, fd_out, off_out, len, + flags, xdata_in); + + if (stbuf) { + *stbuf = args.iatt1; + } + if (preiatt_dst) { + *preiatt_dst = args.iatt2; + } + if (postiatt_dst) { + *postiatt_dst = args.iatt3; + } + + if (xdata_out) { + *xdata_out = args.xdata; + } else if (args.xdata) { + dict_unref(args.xdata); + } + + errno = args.op_errno; + return args.op_ret; +} + +int +syncop_copy_file_range_cbk(call_frame_t *frame, void *cookie, xlator_t *this, + int op_ret, int op_errno, struct iatt *stbuf, + struct iatt *prebuf_dst, struct iatt *postbuf_dst, + dict_t *xdata) +{ + struct syncargs *args = NULL; + + args = cookie; + + args->op_ret = op_ret; + args->op_errno = op_errno; + if (xdata) + args->xdata = dict_ref(xdata); + + if (op_ret >= 0) { + args->iatt1 = *stbuf; + args->iatt2 = *prebuf_dst; + args->iatt3 = *postbuf_dst; + } + + __wake(args); + + return 0; +} diff --git a/libglusterfs/src/syncop.h b/libglusterfs/src/syncop.h deleted file mode 100644 index 13b07ed31fd..00000000000 --- a/libglusterfs/src/syncop.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _SYNCOP_H -#define _SYNCOP_H - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include "xlator.h" -#include <sys/time.h> -#include <pthread.h> -#include <ucontext.h> - - -struct synctask; -struct syncenv; - - -typedef int (*synctask_cbk_t) (int ret, void *opaque); - -typedef int (*synctask_fn_t) (void *opaque); - - -/* for one sequential execution of @syncfn */ -struct synctask { - struct list_head all_tasks; - struct syncenv *env; - xlator_t *xl; - synctask_cbk_t synccbk; - synctask_fn_t syncfn; - void *opaque; - void *stack; - int complete; - - ucontext_t ctx; -}; - -/* hosts the scheduler thread and framework for executing synctasks */ -struct syncenv { - pthread_t processor; - struct synctask *current; - - struct list_head runq; - struct list_head waitq; - - pthread_mutex_t mutex; - pthread_cond_t cond; - - ucontext_t sched; - size_t stacksize; -}; - - -struct syncargs { - int op_ret; - int op_errno; - struct iatt iatt1; - struct iatt iatt2; - dict_t *xattr; - gf_dirent_t entries; - struct statvfs statvfs_buf; - - /* do not touch */ - pthread_mutex_t mutex; - char complete; - pthread_cond_t cond; - struct synctask *task; -}; - - -#define __yawn(args) do { \ - struct synctask *task = NULL; \ - \ - task = synctask_get (); \ - if (task) { \ - args->task = task; \ - synctask_yawn (task); \ - } else { \ - pthread_mutex_init (&args->mutex, NULL); \ - pthread_cond_init (&args->cond, NULL); \ - } \ -} while (0) - - -#define __yield(args) do { \ - if (args->task) { \ - synctask_yield (args->task); \ - } else { \ - pthread_mutex_lock (&args->mutex); \ - { \ - while (!args->complete) \ - pthread_cond_wait (&args->cond, \ - &args->mutex); \ - } \ - pthread_mutex_unlock (&args->mutex); \ - \ - pthread_mutex_destroy (&args->mutex); \ - pthread_cond_destroy (&args->cond); \ - } \ -} while (0) - - -#define __wake(args) do { \ - if (args->task) { \ - synctask_wake (args->task); \ - } else { \ - pthread_mutex_lock (&args->mutex); \ - { \ - args->complete = 1; \ - pthread_cond_broadcast (&args->cond); \ - } \ - pthread_mutex_unlock (&args->mutex); \ - } \ -} while (0) - - -#define SYNCOP(subvol, stb, cbk, op, params ...) do { \ - call_frame_t *frame = NULL; \ - \ - frame = syncop_create_frame (); \ - \ - __yawn (stb); \ - STACK_WIND_COOKIE (frame, cbk, (void *)stb, subvol, op, params);\ - __yield (stb); \ -} while (0) - - -#define SYNCENV_DEFAULT_STACKSIZE (16 * 1024) - -struct syncenv * syncenv_new (); -void syncenv_destroy (struct syncenv *); - -int synctask_new (struct syncenv *, synctask_fn_t, synctask_cbk_t, void *); -void synctask_zzzz (struct synctask *task); -void synctask_yawn (struct synctask *task); -void synctask_wake (struct synctask *task); -void synctask_yield (struct synctask *task); - -int syncop_lookup (xlator_t *subvol, loc_t *loc, dict_t *xattr_req, - /* out */ - struct iatt *iatt, dict_t **xattr_rsp, struct iatt *parent); - -int syncop_readdirp (xlator_t *subvol, fd_t *fd, size_t size, off_t off, - /* out */ - gf_dirent_t *entries); - -int -syncop_opendir (xlator_t *subvol, - loc_t *loc, - fd_t *fd); - -int syncop_setattr (xlator_t *subvol, loc_t *loc, struct iatt *iatt, int valid, - /* out */ - struct iatt *preop, struct iatt *postop); - -int -syncop_statfs (xlator_t *subvol, loc_t *loc, struct statvfs *buf); - -int -syncop_setxattr (xlator_t *subvol, loc_t *loc, dict_t *dict, int32_t flags); - -#endif /* _SYNCOP_H */ diff --git a/libglusterfs/src/syscall.c b/libglusterfs/src/syscall.c index e0d0b13fa3a..04400f98b6c 100644 --- a/libglusterfs/src/syscall.c +++ b/libglusterfs/src/syscall.c @@ -1,432 +1,876 @@ /* - Copyright (c) 2009 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 "compat.h" -#include "syscall.h" +#include "glusterfs/compat.h" +#include "glusterfs/syscall.h" +#include "glusterfs/mem-pool.h" +#include "glusterfs/libglusterfs-messages.h" +#ifdef __FreeBSD__ +#include <sys/sysctl.h> +#include <signal.h> +#endif #include <sys/types.h> #include <utime.h> #include <sys/time.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdarg.h> +#ifdef HAVE_COPY_FILE_RANGE_SYS +#include <sys/syscall.h> +#endif + +#define FS_ERROR_LOG(result) \ + do { \ + gf_msg_callingfn("FS", GF_LOG_CRITICAL, EIO, \ + LG_MSG_SYSCALL_RETURNS_WRONG, \ + "returned %zd for the syscall", (ssize_t)result); \ + } while (0) + +/* + * Input to these macros is generally a function call, so capture the result + * i.e. (_ret) in another variable and use that instead of using _ret again + */ +#define FS_RET_CHECK(_ret, err) \ + ({ \ + typeof(_ret) _result = (_ret); \ + if (_result < -1) { \ + FS_ERROR_LOG(_result); \ + _result = -1; \ + err = EIO; \ + } \ + _result; \ + }) + +#define FS_RET_CHECK0(_ret, err) \ + ({ \ + typeof(_ret) _result0 = (_ret); \ + if (_result0 < -1 || _result0 > 0) { \ + FS_ERROR_LOG(_result0); \ + _result0 = -1; \ + err = EIO; \ + } \ + _result0; \ + }) + +#define FS_RET_CHECK_ERRNO(_ret, err) \ + ({ \ + typeof(_ret) _result1 = (_ret); \ + if (_result1 < 0) { \ + FS_ERROR_LOG(_result1); \ + _result1 = -1; \ + err = EIO; \ + } else if (_result1 > 0) { \ + err = _result1; \ + _result1 = -1; \ + } \ + _result1; \ + }) int -sys_lstat (const char *path, struct stat *buf) +sys_lstat(const char *path, struct stat *buf) { - return lstat (path, buf); + return FS_RET_CHECK0(lstat(path, buf), errno); } +int +sys_stat(const char *path, struct stat *buf) +{ + return FS_RET_CHECK0(stat(path, buf), errno); +} int -sys_stat (const char *path, struct stat *buf) +sys_fstat(int fd, struct stat *buf) { - return stat (path, buf); + return FS_RET_CHECK0(fstat(fd, buf), errno); } +int +sys_fstatat(int dirfd, const char *pathname, struct stat *buf, int flags) +{ +#ifdef GF_DARWIN_HOST_OS + if (fchdir(dirfd) < 0) + return -1; + if (flags & AT_SYMLINK_NOFOLLOW) + return FS_RET_CHECK0(lstat(pathname, buf), errno); + else + return FS_RET_CHECK0(stat(pathname, buf), errno); +#else + return FS_RET_CHECK0(fstatat(dirfd, pathname, buf, flags), errno); +#endif +} int -sys_fstat (int fd, struct stat *buf) +sys_openat(int dirfd, const char *pathname, int flags, int mode) { - return fstat (fd, buf); + int fd; + +#ifdef GF_DARWIN_HOST_OS + if (fchdir(dirfd) < 0) + return -1; + fd = open(pathname, flags, mode); + /* TODO: Shouldn't we restore the old current directory */ +#else /* GF_DARWIN_HOST_OS */ + fd = openat(dirfd, pathname, flags, mode); +#ifdef __FreeBSD__ + /* On FreeBSD S_ISVTX flag is ignored for an open() with O_CREAT set. + * We need to force the flag using fchmod(). */ + if ((fd >= 0) && ((flags & O_CREAT) != 0) && ((mode & S_ISVTX) != 0)) { + sys_fchmod(fd, mode); + /* TODO: It's unlikely that fchmod could fail here. However, + if it fails we cannot always restore the old state + (if the file existed, we cannot recover it). We would + need many more system calls to correctly handle all + possible cases and it doesn't worth it. For now we + simply ignore the error. */ + } +#endif /* __FreeBSD__ */ +#endif /* !GF_DARWIN_HOST_OS */ + + return FS_RET_CHECK(fd, errno); } +int +sys_open(const char *pathname, int flags, int mode) +{ + return FS_RET_CHECK(sys_openat(AT_FDCWD, pathname, flags, mode), errno); +} DIR * -sys_opendir (const char *name) +sys_opendir(const char *name) { - return opendir (name); + return opendir(name); } - -struct dirent * -sys_readdir (DIR *dir) +int +sys_mkdirat(int dirfd, const char *pathname, mode_t mode) { - return readdir (dir); +#ifdef GF_DARWIN_HOST_OS + if (fchdir(dirfd) < 0) + return -1; + return FS_RET_CHECK0(mkdir(pathname, mode), errno); +#else + return FS_RET_CHECK0(mkdirat(dirfd, pathname, mode), errno); +#endif } +struct dirent * +sys_readdir(DIR *dir, struct dirent *de) +{ +#if !defined(__GLIBC__) + /* + * World+Dog says glibc's readdir(3) is MT-SAFE as long as + * two threads are not accessing the same DIR; there's a + * potential buffer overflow in glibc's readdir_r(3); and + * glibc's readdir_r(3) is deprecated after version 2.22 + * with presumed eventual removal. + * Given all that, World+Dog says everyone should just use + * readdir(3). But it's unknown, unclear whether the same + * is also true for *BSD, MacOS, and, etc. + */ + struct dirent *entry = NULL; + + (void)readdir_r(dir, de, &entry); + return entry; +#else + return readdir(dir); +#endif +} -ssize_t -sys_readlink (const char *path, char *buf, size_t bufsiz) +ssize_t +sys_readlink(const char *path, char *buf, size_t bufsiz) { - return readlink (path, buf, bufsiz); + return FS_RET_CHECK(readlink(path, buf, bufsiz), errno); } - -int -sys_closedir (DIR *dir) +int +sys_closedir(DIR *dir) { - return closedir (dir); + return FS_RET_CHECK0(closedir(dir), errno); } - int -sys_mknod (const char *pathname, mode_t mode, dev_t dev) +sys_mknod(const char *pathname, mode_t mode, dev_t dev) { - return mknod (pathname, mode, dev); + return FS_RET_CHECK0(mknod(pathname, mode, dev), errno); } - -int -sys_mkdir (const char *pathname, mode_t mode) +int +sys_mkdir(const char *pathname, mode_t mode) { - return mkdir (pathname, mode); + return FS_RET_CHECK0(mkdir(pathname, mode), errno); } - -int -sys_unlink (const char *pathname) +int +sys_unlink(const char *pathname) { - return unlink (pathname); +#ifdef GF_SOLARIS_HOST_OS + return FS_RET_CHECK0(solaris_unlink(pathname), errno); +#endif + return FS_RET_CHECK0(unlink(pathname), errno); } - -int -sys_rmdir (const char *pathname) +int +sys_unlinkat(int dfd, const char *pathname) { - return rmdir (pathname); +#ifdef GF_SOLARIS_HOST_OS + return FS_RET_CHECK0(solaris_unlinkat(dfd, pathname, 0), errno); +#endif + return FS_RET_CHECK0(unlinkat(dfd, pathname, 0), errno); } - -int -sys_symlink (const char *oldpath, const char *newpath) +int +sys_rmdir(const char *pathname) { - return symlink (oldpath, newpath); + return FS_RET_CHECK0(rmdir(pathname), errno); } - int -sys_rename (const char *oldpath, const char *newpath) +sys_symlink(const char *oldpath, const char *newpath) { - return rename (oldpath, newpath); + return FS_RET_CHECK0(symlink(oldpath, newpath), errno); } - -int -sys_link (const char *oldpath, const char *newpath) +int +sys_symlinkat(const char *oldpath, int dirfd, const char *newpath) { - return link (oldpath, newpath); + return FS_RET_CHECK0(symlinkat(oldpath, dirfd, newpath), errno); } - int -sys_chmod (const char *path, mode_t mode) +sys_rename(const char *oldpath, const char *newpath) { - return chmod (path, mode); +#ifdef GF_SOLARIS_HOST_OS + return FS_RET_CHECK0(solaris_rename(oldpath, newpath), errno); +#endif + return FS_RET_CHECK0(rename(oldpath, newpath), errno); } +int +sys_link(const char *oldpath, const char *newpath) +{ +#ifdef HAVE_LINKAT + /* + * On most systems (Linux being the notable exception), link(2) + * first resolves symlinks. If the target is a directory or + * is nonexistent, it will fail. linkat(2) operates on the + * symlink instead of its target when the AT_SYMLINK_FOLLOW + * flag is not supplied. + */ + return FS_RET_CHECK0(linkat(AT_FDCWD, oldpath, AT_FDCWD, newpath, 0), + errno); +#else + return FS_RET_CHECK0(link(oldpath, newpath), errno); +#endif +} int -sys_fchmod (int fd, mode_t mode) +sys_linkat(int oldfd, const char *oldpath, int newfd, const char *newpath) { - return fchmod (fd, mode); + return FS_RET_CHECK0(linkat(oldfd, oldpath, newfd, newpath, 0), errno); } - -int -sys_chown (const char *path, uid_t owner, gid_t group) +int +sys_chmod(const char *path, mode_t mode) { - return chown (path, owner, group); + return FS_RET_CHECK0(chmod(path, mode), errno); } - int -sys_fchown (int fd, uid_t owner, gid_t group) +sys_fchmod(int fd, mode_t mode) { - return fchown (fd, owner, group); + return FS_RET_CHECK0(fchmod(fd, mode), errno); } - int -sys_lchown (const char *path, uid_t owner, gid_t group) +sys_chown(const char *path, uid_t owner, gid_t group) { - return lchown (path, owner, group); + return FS_RET_CHECK0(chown(path, owner, group), errno); } - -int -sys_truncate (const char *path, off_t length) +int +sys_fchown(int fd, uid_t owner, gid_t group) { - return truncate (path, length); + return FS_RET_CHECK0(fchown(fd, owner, group), errno); } +int +sys_lchown(const char *path, uid_t owner, gid_t group) +{ + return FS_RET_CHECK0(lchown(path, owner, group), errno); +} -int -sys_ftruncate (int fd, off_t length) +int +sys_truncate(const char *path, off_t length) { - return ftruncate (fd, length); + return FS_RET_CHECK0(truncate(path, length), errno); } +int +sys_ftruncate(int fd, off_t length) +{ + return FS_RET_CHECK0(ftruncate(fd, length), errno); +} -int -sys_utimes (const char *filename, const struct timeval times[2]) +int +sys_utimes(const char *filename, const struct timeval times[2]) { - return utimes (filename, times); + return FS_RET_CHECK0(utimes(filename, times), errno); } +#if defined(HAVE_UTIMENSAT) +int +sys_utimensat(int dirfd, const char *filename, const struct timespec times[2], + int flags) +{ + return FS_RET_CHECK0(utimensat(dirfd, filename, times, flags), errno); +} +#endif int -sys_creat (const char *pathname, mode_t mode) +sys_futimes(int fd, const struct timeval times[2]) { - return creat (pathname, mode); + return futimes(fd, times); } +int +sys_creat(const char *pathname, mode_t mode) +{ + return FS_RET_CHECK(sys_open(pathname, O_CREAT | O_TRUNC | O_WRONLY, mode), + errno); +} ssize_t -sys_readv (int fd, const struct iovec *iov, int iovcnt) +sys_readv(int fd, const struct iovec *iov, int iovcnt) { - return readv (fd, iov, iovcnt); + return FS_RET_CHECK(readv(fd, iov, iovcnt), errno); } +ssize_t +sys_writev(int fd, const struct iovec *iov, int iovcnt) +{ + return FS_RET_CHECK(writev(fd, iov, iovcnt), errno); +} ssize_t -sys_writev (int fd, const struct iovec *iov, int iovcnt) +sys_read(int fd, void *buf, size_t count) { - return writev (fd, iov, iovcnt); + return FS_RET_CHECK(read(fd, buf, count), errno); } +ssize_t +sys_write(int fd, const void *buf, size_t count) +{ + return FS_RET_CHECK(write(fd, buf, count), errno); +} ssize_t -sys_read (int fd, void *buf, size_t count) +sys_preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) { - return read (fd, buf, count); + return FS_RET_CHECK(preadv(fd, iov, iovcnt, offset), errno); } +ssize_t +sys_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) +{ + return FS_RET_CHECK(pwritev(fd, iov, iovcnt, offset), errno); +} -ssize_t -sys_write (int fd, const void *buf, size_t count) +ssize_t +sys_pread(int fd, void *buf, size_t count, off_t offset) { - return write (fd, buf, count); + return FS_RET_CHECK(pread(fd, buf, count, offset), errno); } +ssize_t +sys_pwrite(int fd, const void *buf, size_t count, off_t offset) +{ + return FS_RET_CHECK(pwrite(fd, buf, count, offset), errno); +} off_t -sys_lseek (int fd, off_t offset, int whence) +sys_lseek(int fd, off_t offset, int whence) { - return lseek (fd, offset, whence); + return FS_RET_CHECK(lseek(fd, offset, whence), errno); } - int -sys_statvfs (const char *path, struct statvfs *buf) +sys_statvfs(const char *path, struct statvfs *buf) { - return statvfs (path, buf); -} + int ret; + ret = statvfs(path, buf); +#ifdef __FreeBSD__ + /* FreeBSD doesn't return the expected value in buf->f_bsize. It + * contains the optimal I/O size instead of the file system block + * size. Gluster expects that this field contains the block size. + */ + if (ret == 0) { + buf->f_bsize = buf->f_frsize; + } +#endif /* __FreeBSD__ */ -int -sys_close (int fd) -{ - return close (fd); + return FS_RET_CHECK0(ret, errno); } +int +sys_fstatvfs(int fd, struct statvfs *buf) +{ + int ret; -int -sys_fsync (int fd) + ret = fstatvfs(fd, buf); +#ifdef __FreeBSD__ + /* FreeBSD doesn't return the expected value in buf->f_bsize. It + * contains the optimal I/O size instead of the file system block + * size. Gluster expects this field to contain the block size. + */ + if (ret == 0) { + buf->f_bsize = buf->f_frsize; + } +#endif /* __FreeBSD__ */ + + return FS_RET_CHECK0(ret, errno); +} + +int +sys_close(int fd) { - return fsync (fd); + int ret = -1; + + if (fd >= 0) + ret = close(fd); + + return FS_RET_CHECK0(ret, errno); } +int +sys_fsync(int fd) +{ + return FS_RET_CHECK0(fsync(fd), errno); +} -int -sys_fdatasync (int fd) +int +sys_fdatasync(int fd) { -#ifdef HAVE_FDATASYNC - return fdatasync (fd); +#ifdef GF_DARWIN_HOST_OS + return FS_RET_CHECK0(fcntl(fd, F_FULLFSYNC), errno); +#elif __FreeBSD__ + return FS_RET_CHECK0(fsync(fd), errno); #else - return 0; + return FS_RET_CHECK0(fdatasync(fd), errno); #endif } +void +gf_add_prefix(const char *ns, const char *key, char **newkey) +{ + /* if we don't have any namespace, append USER NS */ + if (strncmp(key, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) && + strncmp(key, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) && + strncmp(key, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && + strncmp(key, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) { + int ns_length = strlen(ns); + *newkey = GF_MALLOC(ns_length + strlen(key) + 10, gf_common_mt_char); + if (!*newkey) + return; + strcpy(*newkey, ns); + strcat(*newkey, key); + } else { + *newkey = gf_strdup(key); + } +} -int -sys_lsetxattr (const char *path, const char *name, const void *value, - size_t size, int flags) +void +gf_remove_prefix(const char *ns, const char *key, char **newkey) { - -#ifdef GF_LINUX_HOST_OS - return lsetxattr (path, name, value, size, flags); + int ns_length = strlen(ns); + if (strncmp(key, ns, ns_length) == 0) { + *newkey = GF_MALLOC(-ns_length + strlen(key) + 10, gf_common_mt_char); + if (!*newkey) + return; + strcpy(*newkey, key + ns_length); + } else { + *newkey = gf_strdup(key); + } +} + +int +sys_lsetxattr(const char *path, const char *name, const void *value, + size_t size, int flags) +{ +#if defined(GF_LINUX_HOST_OS) || defined(__NetBSD__) + return FS_RET_CHECK0(lsetxattr(path, name, value, size, flags), errno); #endif #ifdef GF_BSD_HOST_OS - return extattr_set_link (path, EXTATTR_NAMESPACE_USER, - name, value, size); + return FS_RET_CHECK( + extattr_set_link(path, EXTATTR_NAMESPACE_USER, name, value, size), + errno); #endif - + #ifdef GF_SOLARIS_HOST_OS - return solaris_setxattr (path, name, value, size, flags); + return FS_RET_CHECK0(solaris_setxattr(path, name, value, size, flags), + errno); #endif #ifdef GF_DARWIN_HOST_OS - return setxattr (path, name, value, size, 0, - flags|XATTR_NOFOLLOW); + /* OS X clients will carry other flags, which will be used on a + OS X host, but masked out on others. GF assume NOFOLLOW on Linux, + enforcing */ + return FS_RET_CHECK0(setxattr(path, name, value, size, 0, + (flags & ~XATTR_NOSECURITY) | XATTR_NOFOLLOW), + errno); #endif - } - ssize_t -sys_llistxattr (const char *path, char *list, size_t size) +sys_llistxattr(const char *path, char *list, size_t size) { - -#ifdef GF_LINUX_HOST_OS - return llistxattr (path, list, size); +#if defined(GF_LINUX_HOST_OS) || defined(__NetBSD__) + return FS_RET_CHECK(llistxattr(path, list, size), errno); #endif #ifdef GF_BSD_HOST_OS - return extattr_list_link (path, EXTATTR_NAMESPACE_USER, list, size); + ssize_t ret = FS_RET_CHECK( + extattr_list_link(path, EXTATTR_NAMESPACE_USER, list, size), errno); + gf_extattr_list_reshape(list, ret); + return ret; #endif - + #ifdef GF_SOLARIS_HOST_OS - return solaris_listxattr (path, list, size); + return FS_RET_CHECK(solaris_listxattr(path, list, size), errno); #endif #ifdef GF_DARWIN_HOST_OS - return listxattr (path, list, size, XATTR_NOFOLLOW); + return FS_RET_CHECK(listxattr(path, list, size, XATTR_NOFOLLOW), errno); #endif - } - ssize_t -sys_lgetxattr (const char *path, const char *name, void *value, size_t size) +sys_lgetxattr(const char *path, const char *name, void *value, size_t size) { - -#ifdef GF_LINUX_HOST_OS - return lgetxattr (path, name, value, size); +#if defined(GF_LINUX_HOST_OS) || defined(__NetBSD__) + return FS_RET_CHECK(lgetxattr(path, name, value, size), errno); #endif #ifdef GF_BSD_HOST_OS - return extattr_get_link (path, EXTATTR_NAMESPACE_USER, name, value, - size); + return FS_RET_CHECK( + extattr_get_link(path, EXTATTR_NAMESPACE_USER, name, value, size), + errno); #endif - + #ifdef GF_SOLARIS_HOST_OS - return solaris_getxattr (path, name, value, size); + return FS_RET_CHECK(solaris_getxattr(path, name, value, size), errno); #endif #ifdef GF_DARWIN_HOST_OS - return getxattr (path, name, value, size, 0, XATTR_NOFOLLOW); + return FS_RET_CHECK(getxattr(path, name, value, size, 0, XATTR_NOFOLLOW), + errno); #endif - } - -ssize_t -sys_fgetxattr (int filedes, const char *name, void *value, size_t size) +ssize_t +sys_fgetxattr(int filedes, const char *name, void *value, size_t size) { - -#ifdef GF_LINUX_HOST_OS - return fgetxattr (filedes, name, value, size); +#if defined(GF_LINUX_HOST_OS) || defined(__NetBSD__) + return FS_RET_CHECK(fgetxattr(filedes, name, value, size), errno); #endif #ifdef GF_BSD_HOST_OS - return extattr_get_fd (filedes, EXTATTR_NAMESPACE_USER, name, - value, size); + return FS_RET_CHECK( + extattr_get_fd(filedes, EXTATTR_NAMESPACE_USER, name, value, size), + errno); #endif - + #ifdef GF_SOLARIS_HOST_OS - return solaris_fgetxattr (filedes, name, value, size); + return FS_RET_CHECK(solaris_fgetxattr(filedes, name, value, size), errno); #endif #ifdef GF_DARWIN_HOST_OS - return fgetxattr (filedes, name, value, size, 0, 0); + return FS_RET_CHECK(fgetxattr(filedes, name, value, size, 0, 0), errno); #endif - } - -int -sys_fsetxattr (int filedes, const char *name, const void *value, - size_t size, int flags) +int +sys_fremovexattr(int filedes, const char *name) { - -#ifdef GF_LINUX_HOST_OS - return fsetxattr (filedes, name, value, size, flags); +#if defined(GF_LINUX_HOST_OS) || defined(__NetBSD__) + return FS_RET_CHECK0(fremovexattr(filedes, name), errno); #endif #ifdef GF_BSD_HOST_OS - return extattr_set_fd (filedes, EXTATTR_NAMESPACE_USER, name, - value, size); + return FS_RET_CHECK0( + extattr_delete_fd(filedes, EXTATTR_NAMESPACE_USER, name), errno); #endif - + #ifdef GF_SOLARIS_HOST_OS - return solaris_fsetxattr (filedes, name, value, size, flags); + return FS_RET_CHECK0(solaris_fremovexattr(filedes, name), errno); #endif #ifdef GF_DARWIN_HOST_OS - return fsetxattr (filedes, name, value, size, 0, flags); + return FS_RET_CHECK0(fremovexattr(filedes, name, 0), errno); #endif - } - -ssize_t -sys_flistxattr (int filedes, char *list, size_t size) +int +sys_fsetxattr(int filedes, const char *name, const void *value, size_t size, + int flags) { - -#ifdef GF_LINUX_HOST_OS - return flistxattr (filedes, list, size); +#if defined(GF_LINUX_HOST_OS) || defined(__NetBSD__) + return FS_RET_CHECK0(fsetxattr(filedes, name, value, size, flags), errno); #endif #ifdef GF_BSD_HOST_OS - return extattr_list_fd (filedes, EXTATTR_NAMESPACE_USER, list, size); + return FS_RET_CHECK( + extattr_set_fd(filedes, EXTATTR_NAMESPACE_USER, name, value, size), + errno); #endif #ifdef GF_SOLARIS_HOST_OS - return solaris_flistxattr (filedes, list, size); + return FS_RET_CHECK0(solaris_fsetxattr(filedes, name, value, size, flags), + errno); #endif #ifdef GF_DARWIN_HOST_OS - return flistxattr (filedes, list, size, XATTR_NOFOLLOW); + return FS_RET_CHECK0( + fsetxattr(filedes, name, value, size, 0, flags & ~XATTR_NOSECURITY), + errno); #endif - } +ssize_t +sys_flistxattr(int filedes, char *list, size_t size) +{ +#if defined(GF_LINUX_HOST_OS) || defined(__NetBSD__) + return FS_RET_CHECK(flistxattr(filedes, list, size), errno); +#endif + +#ifdef GF_BSD_HOST_OS + ssize_t ret = FS_RET_CHECK( + extattr_list_fd(filedes, EXTATTR_NAMESPACE_USER, list, size), errno); + gf_extattr_list_reshape(list, ret); + return ret; +#endif + +#ifdef GF_SOLARIS_HOST_OS + return FS_RET_CHECK(solaris_flistxattr(filedes, list, size), errno); +#endif + +#ifdef GF_DARWIN_HOST_OS + return FS_RET_CHECK(flistxattr(filedes, list, size, XATTR_NOFOLLOW), errno); +#endif +} -int -sys_lremovexattr (const char *path, const char *name) +int +sys_lremovexattr(const char *path, const char *name) { - -#ifdef GF_LINUX_HOST_OS - return lremovexattr (path, name); +#if defined(GF_LINUX_HOST_OS) || defined(__NetBSD__) + return FS_RET_CHECK0(lremovexattr(path, name), errno); #endif #ifdef GF_BSD_HOST_OS - return extattr_delete_link (path, EXTATTR_NAMESPACE_USER, name); + return FS_RET_CHECK0( + extattr_delete_link(path, EXTATTR_NAMESPACE_USER, name), errno); #endif - + #ifdef GF_SOLARIS_HOST_OS - return solaris_removexattr (path, name); + return FS_RET_CHECK0(solaris_removexattr(path, name), errno); #endif #ifdef GF_DARWIN_HOST_OS - return removexattr (path, name, XATTR_NOFOLLOW); + return FS_RET_CHECK0(removexattr(path, name, XATTR_NOFOLLOW), errno); +#endif +} + +int +sys_access(const char *pathname, int mode) +{ + return FS_RET_CHECK0(access(pathname, mode), errno); +} + +int +sys_fallocate(int fd, int mode, off_t offset, off_t len) +{ +#ifdef HAVE_FALLOCATE + return FS_RET_CHECK0(fallocate(fd, mode, offset, len), errno); +#endif + +#ifdef HAVE_POSIX_FALLOCATE + if (mode) { + /* keep size not supported */ + errno = EOPNOTSUPP; + return -1; + } + + return FS_RET_CHECK_ERRNO(posix_fallocate(fd, offset, len), errno); +#endif + +#if defined(F_ALLOCATECONTIG) && defined(GF_DARWIN_HOST_OS) + /* C conversion from C++ implementation for OSX by Mozilla Foundation */ + if (mode) { + /* keep size not supported */ + errno = EOPNOTSUPP; + return -1; + } + /* + * The F_PREALLOCATE command operates on the following structure: + * + * typedef struct fstore { + * u_int32_t fst_flags; // IN: flags word + * int fst_posmode; // IN: indicates offset field + * off_t fst_offset; // IN: start of the region + * off_t fst_length; // IN: size of the region + * off_t fst_bytesalloc; // OUT: number of bytes allocated + * } fstore_t; + * + * The flags (fst_flags) for the F_PREALLOCATE command are as follows: + * F_ALLOCATECONTIG Allocate contiguous space. + * F_ALLOCATEALL Allocate all requested space or no space at all. + * + * The position modes (fst_posmode) for the F_PREALLOCATE command + * indicate how to use the offset field. The modes are as follows: + * F_PEOFPOSMODE Allocate from the physical end of file. + * F_VOLPOSMODE Allocate from the volume offset. + * + */ + + int ret; + fstore_t store = {F_ALLOCATECONTIG, F_PEOFPOSMODE, offset, len, 0}; + ret = fcntl(fd, F_PREALLOCATE, &store); + if (ret == -1) { + store.fst_flags = F_ALLOCATEALL; + ret = fcntl(fd, F_PREALLOCATE, &store); + } + if (ret == -1) + return ret; + return FS_RET_CHECK0(ftruncate(fd, offset + len), errno); +#endif + errno = ENOSYS; + return -1; +} + +int +sys_socket(int domain, int type, int protocol) +{ +#ifdef SOCK_CLOEXEC + return socket(domain, type | SOCK_CLOEXEC, protocol); +#else + int fd = -1; + + fd = socket(domain, type, protocol); + if (fd >= 0) + fcntl(fd, F_SETFD, FD_CLOEXEC); + return fd; +#endif +} + +#if (defined(HAVE_ACCEPT4) || defined(HAVE_PACCEPT)) +static inline int +prep_accept_flags(int flags) +{ + if (flags & O_NONBLOCK) { + flags &= ~O_NONBLOCK; + flags |= SOCK_NONBLOCK; + } + + flags |= SOCK_CLOEXEC; + + return flags; +} +#endif + +int +sys_accept(int sock, struct sockaddr *sockaddr, socklen_t *socklen, int flags) +{ + int newsock = -1; + +#ifdef HAVE_ACCEPT4 + + flags = prep_accept_flags(flags); + newsock = accept4(sock, sockaddr, socklen, flags); + +#elif HAVE_PACCEPT + flags = prep_accept_flags(flags); + newsock = paccept(sock, sockaddr, socklen, NULL, flags); + +#else + int op_errno = 0; + int curflag = 0; + int ret = 0; + + newsock = accept(sock, sockaddr, socklen); + if (newsock != -1) { + curflag = fcntl(newsock, F_GETFL); + if (fcntl(newsock, F_SETFL, curflag | flags) == -1) { + op_errno = errno; + goto err; + } + + curflag = fcntl(newsock, F_GETFD); + if (fcntl(newsock, F_SETFD, curflag | FD_CLOEXEC) == -1) { + op_errno = errno; + goto err; + } + } + +err: + if (op_errno) { + close(newsock); + errno = op_errno; + return -1; + } + #endif + return newsock; +} +ssize_t +sys_copy_file_range(int fd_in, off64_t *off_in, int fd_out, off64_t *off_out, + size_t len, unsigned int flags) +{ + /* + * TODO: Add check for other platofrms like freebsd etc if this syscall is + * not generic. + * This is what the function does. + * 1) Check whether copy_file_range API is present. If so call it. + * 2) If copy_file_range API is not present, then check whether + * the system call is there. If so, then use syscall to invoke + * SYS_copy_file_range system call. + * 3) If neither of the above is present, then return ENOSYS. + */ +#ifdef HAVE_COPY_FILE_RANGE + return FS_RET_CHECK( + copy_file_range(fd_in, off_in, fd_out, off_out, len, flags), errno); +#else +#ifdef HAVE_COPY_FILE_RANGE_SYS + return syscall(SYS_copy_file_range, fd_in, off_in, fd_out, off_out, len, + flags); +#else + errno = ENOSYS; + return -1; +#endif /* HAVE_COPY_FILE_RANGE_SYS */ +#endif /* HAVE_COPY_FILE_RANGE */ } +#ifdef __FreeBSD__ +int +sys_kill(pid_t pid, int sig) +{ + return FS_RET_CHECK0(kill(pid, sig), errno); +} -int -sys_access (const char *pathname, int mode) +int +sys_sysctl(const int *name, u_int namelen, void *oldp, size_t *oldlenp, + const void *newp, size_t newlen) { - return access (pathname, mode); + return FS_RET_CHECK0(sysctl(name, namelen, oldp, oldlenp, newp, newlen), + errno); } +#endif diff --git a/libglusterfs/src/syscall.h b/libglusterfs/src/syscall.h deleted file mode 100644 index 2bc29508b37..00000000000 --- a/libglusterfs/src/syscall.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - Copyright (c) 2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef __SYSCALL_H__ -#define __SYSCALL_H__ - -int -sys_lstat (const char *path, struct stat *buf); - -int -sys_stat (const char *path, struct stat *buf); - -int -sys_fstat (int fd, struct stat *buf); - -DIR * -sys_opendir (const char *name); - -struct dirent * -sys_readdir (DIR *dir); - -ssize_t -sys_readlink (const char *path, char *buf, size_t bufsiz); - -int -sys_closedir (DIR *dir); - -int -sys_mknod (const char *pathname, mode_t mode, dev_t dev); - -int -sys_mkdir (const char *pathname, mode_t mode); - -int -sys_unlink (const char *pathname); - -int -sys_rmdir (const char *pathname); - -int -sys_symlink (const char *oldpath, const char *newpath); - -int -sys_rename (const char *oldpath, const char *newpath); - -int -sys_link (const char *oldpath, const char *newpath); - -int -sys_chmod (const char *path, mode_t mode); - -int -sys_fchmod (int fd, mode_t mode); - -int -sys_chown (const char *path, uid_t owner, gid_t group); - -int -sys_fchown (int fd, uid_t owner, gid_t group); - -int -sys_lchown (const char *path, uid_t owner, gid_t group); - -int -sys_truncate (const char *path, off_t length); - -int -sys_ftruncate (int fd, off_t length); - -int -sys_utimes (const char *filename, const struct timeval times[2]); - -int -sys_creat (const char *pathname, mode_t mode); - -ssize_t -sys_readv (int fd, const struct iovec *iov, int iovcnt); - -ssize_t -sys_writev (int fd, const struct iovec *iov, int iovcnt); - -ssize_t -sys_read (int fd, void *buf, size_t count); - -ssize_t -sys_write (int fd, const void *buf, size_t count); - -off_t -sys_lseek (int fd, off_t offset, int whence); - -int -sys_statvfs (const char *path, struct statvfs *buf); - -int -sys_close (int fd); - -int -sys_fsync (int fd); - -int -sys_fdatasync (int fd); - -int -sys_lsetxattr (const char *path, const char *name, const void *value, - size_t size, int flags); - -ssize_t -sys_llistxattr (const char *path, char *list, size_t size); - -ssize_t -sys_lgetxattr (const char *path, const char *name, void *value, size_t size); - -ssize_t -sys_fgetxattr (int filedes, const char *name, void *value, size_t size); - -int -sys_fsetxattr (int filedes, const char *name, const void *value, - size_t size, int flags); - -ssize_t -sys_flistxattr (int filedes, char *list, size_t size); - -int -sys_lremovexattr (const char *path, const char *name); - -int -sys_access (const char *pathname, int mode); - -int -sys_ftruncate (int fd, off_t length); - -#endif /* __SYSCALL_H__ */ diff --git a/libglusterfs/src/throttle-tbf.c b/libglusterfs/src/throttle-tbf.c new file mode 100644 index 00000000000..e11ca4f9d35 --- /dev/null +++ b/libglusterfs/src/throttle-tbf.c @@ -0,0 +1,290 @@ +/* + Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +/** + * + * Basic token bucket implementation for rate limiting. As of now interfaces + * to throttle disk read request, directory entry scan and hash calculation + * are available. To throttle a particular request (operation), the call needs + * to be wrapped in-between throttling APIs, for e.g. + * + * TBF_THROTTLE_BEGIN (...); <-- induces "delays" if required + * { + * call (...); + * } + * TBF_THROTTLE_END (...); <-- not used atm, maybe needed later + * + */ + +#include "glusterfs/mem-pool.h" +#include "glusterfs/throttle-tbf.h" + +typedef struct tbf_throttle { + char done; + + pthread_mutex_t mutex; + pthread_cond_t cond; + + unsigned long tokens; + + struct list_head list; +} tbf_throttle_t; + +static tbf_throttle_t * +tbf_init_throttle(unsigned long tokens_required) +{ + tbf_throttle_t *throttle = NULL; + + throttle = GF_CALLOC(1, sizeof(*throttle), gf_common_mt_tbf_throttle_t); + if (!throttle) + return NULL; + + throttle->done = 0; + throttle->tokens = tokens_required; + INIT_LIST_HEAD(&throttle->list); + + (void)pthread_mutex_init(&throttle->mutex, NULL); + (void)pthread_cond_init(&throttle->cond, NULL); + + return throttle; +} + +void +_tbf_dispatch_queued(tbf_bucket_t *bucket) +{ + gf_boolean_t xcont = _gf_false; + tbf_throttle_t *tmp = NULL; + tbf_throttle_t *throttle = NULL; + + list_for_each_entry_safe(throttle, tmp, &bucket->queued, list) + { + pthread_mutex_lock(&throttle->mutex); + { + if (bucket->tokens < throttle->tokens) { + xcont = _gf_true; + goto unblock; + } + + /* this request can now be serviced */ + throttle->done = 1; + list_del_init(&throttle->list); + + bucket->tokens -= throttle->tokens; + pthread_cond_signal(&throttle->cond); + } + unblock: + pthread_mutex_unlock(&throttle->mutex); + if (xcont) + break; + } +} + +void * +tbf_tokengenerator(void *arg) +{ + unsigned long tokenrate = 0; + unsigned long maxtokens = 0; + unsigned long token_gen_interval = 0; + tbf_bucket_t *bucket = arg; + + tokenrate = bucket->tokenrate; + maxtokens = bucket->maxtokens; + token_gen_interval = bucket->token_gen_interval; + + while (1) { + gf_nanosleep(token_gen_interval * GF_US_IN_NS); + + LOCK(&bucket->lock); + { + bucket->tokens += tokenrate; + if (bucket->tokens > maxtokens) + bucket->tokens = maxtokens; + + if (!list_empty(&bucket->queued)) + _tbf_dispatch_queued(bucket); + } + UNLOCK(&bucket->lock); + } + + return NULL; +} + +/** + * There is lazy synchronization between this routine (when invoked + * under tbf_mod() context) and tbf_throttle(). *bucket is + * updated _after_ all the required variables are initialized. + */ +static int32_t +tbf_init_bucket(tbf_t *tbf, tbf_opspec_t *spec) +{ + int ret = 0; + tbf_bucket_t *curr = NULL; + tbf_bucket_t **bucket = NULL; + + GF_ASSERT(spec->op >= TBF_OP_MIN); + GF_ASSERT(spec->op <= TBF_OP_MAX); + + /* no rate? no throttling. */ + if (!spec->rate) + return 0; + + bucket = tbf->bucket + spec->op; + + curr = GF_CALLOC(1, sizeof(*curr), gf_common_mt_tbf_bucket_t); + if (!curr) + goto error_return; + + LOCK_INIT(&curr->lock); + INIT_LIST_HEAD(&curr->queued); + + curr->tokens = 0; + curr->tokenrate = spec->rate; + curr->maxtokens = spec->maxlimit; + curr->token_gen_interval = spec->token_gen_interval; + + ret = gf_thread_create(&curr->tokener, NULL, tbf_tokengenerator, curr, + "tbfclock"); + if (ret != 0) + goto freemem; + + *bucket = curr; + return 0; + +freemem: + LOCK_DESTROY(&curr->lock); + GF_FREE(curr); +error_return: + return -1; +} + +#define TBF_ALLOC_SIZE (sizeof(tbf_t) + (TBF_OP_MAX * sizeof(tbf_bucket_t))) + +tbf_t * +tbf_init(tbf_opspec_t *tbfspec, unsigned int count) +{ + int32_t i = 0; + int32_t ret = 0; + tbf_t *tbf = NULL; + tbf_opspec_t *opspec = NULL; + + tbf = GF_CALLOC(1, TBF_ALLOC_SIZE, gf_common_mt_tbf_t); + if (!tbf) + goto error_return; + + tbf->bucket = (tbf_bucket_t **)((char *)tbf + sizeof(*tbf)); + for (i = 0; i < TBF_OP_MAX; i++) { + *(tbf->bucket + i) = NULL; + } + + for (i = 0; i < count; i++) { + opspec = tbfspec + i; + + ret = tbf_init_bucket(tbf, opspec); + if (ret) + break; + } + + if (ret) + goto error_return; + + return tbf; + +error_return: + return NULL; +} + +static void +tbf_mod_bucket(tbf_bucket_t *bucket, tbf_opspec_t *spec) +{ + LOCK(&bucket->lock); + { + bucket->tokens = 0; + bucket->tokenrate = spec->rate; + bucket->maxtokens = spec->maxlimit; + } + UNLOCK(&bucket->lock); + + /* next token tick would unqueue pending operations */ +} + +int +tbf_mod(tbf_t *tbf, tbf_opspec_t *tbfspec) +{ + int ret = 0; + tbf_bucket_t *bucket = NULL; + tbf_ops_t op = TBF_OP_MIN; + + if (!tbf || !tbfspec) + return -1; + + op = tbfspec->op; + + GF_ASSERT(op >= TBF_OP_MIN); + GF_ASSERT(op <= TBF_OP_MAX); + + bucket = *(tbf->bucket + op); + if (bucket) { + tbf_mod_bucket(bucket, tbfspec); + } else { + ret = tbf_init_bucket(tbf, tbfspec); + } + + return ret; +} + +void +tbf_throttle(tbf_t *tbf, tbf_ops_t op, unsigned long tokens_requested) +{ + char waitq = 0; + tbf_bucket_t *bucket = NULL; + tbf_throttle_t *throttle = NULL; + + GF_ASSERT(op >= TBF_OP_MIN); + GF_ASSERT(op <= TBF_OP_MAX); + + bucket = *(tbf->bucket + op); + if (!bucket) + return; + + LOCK(&bucket->lock); + { + /** + * if there are enough tokens in the bucket there is no need + * to throttle the request: therefore, consume the required + * number of tokens and continue. + */ + if (tokens_requested <= bucket->tokens) { + bucket->tokens -= tokens_requested; + } else { + throttle = tbf_init_throttle(tokens_requested); + if (!throttle) /* let it slip through for now.. */ + goto unblock; + + waitq = 1; + pthread_mutex_lock(&throttle->mutex); + list_add_tail(&throttle->list, &bucket->queued); + } + } +unblock: + UNLOCK(&bucket->lock); + + if (waitq) { + while (!throttle->done) { + pthread_cond_wait(&throttle->cond, &throttle->mutex); + } + + pthread_mutex_unlock(&throttle->mutex); + + pthread_mutex_destroy(&throttle->mutex); + pthread_cond_destroy(&throttle->cond); + + GF_FREE(throttle); + } +} diff --git a/libglusterfs/src/timer.c b/libglusterfs/src/timer.c index 0ef1190c324..66c861b04cd 100644 --- a/libglusterfs/src/timer.c +++ b/libglusterfs/src/timer.c @@ -1,229 +1,256 @@ /* - Copyright (c) 2007-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif + 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 "timer.h" -#include "logging.h" -#include "common-utils.h" -#include "globals.h" +#include "glusterfs/timer.h" +#include "glusterfs/logging.h" +#include "glusterfs/common-utils.h" +#include "glusterfs/globals.h" +#include "glusterfs/timespec.h" +#include "glusterfs/libglusterfs-messages.h" -#define TS(tv) ((((unsigned long long) tv.tv_sec) * 1000000) + (tv.tv_usec)) +/* fwd decl */ +static gf_timer_registry_t * +gf_timer_registry_init(glusterfs_ctx_t *); gf_timer_t * -gf_timer_call_after (glusterfs_ctx_t *ctx, - struct timeval delta, - gf_timer_cbk_t callbk, - void *data) +gf_timer_call_after(glusterfs_ctx_t *ctx, 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; - - if (ctx == NULL) - { - gf_log ("timer", GF_LOG_ERROR, "invalid argument"); - return NULL; - } + gf_timer_registry_t *reg = NULL; + gf_timer_t *event = NULL; + gf_timer_t *trav = NULL; + uint64_t at = 0; - reg = gf_timer_registry_init (ctx); + if ((ctx == NULL) || (ctx->cleanup_started)) { + gf_msg_callingfn("timer", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "Either ctx is NULL or" + " ctx cleanup started"); + return NULL; + } - if (!reg) { - gf_log ("timer", GF_LOG_ERROR, "!reg"); - return NULL; - } + reg = gf_timer_registry_init(ctx); - event = GF_CALLOC (1, sizeof (*event), gf_common_mt_gf_timer_t); - if (!event) { - gf_log ("timer", GF_LOG_CRITICAL, "Not enough memory"); - 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; - at = TS (event->at); - event->callbk = callbk; - event->data = data; - event->xl = THIS; - pthread_mutex_lock (®->lock); + if (!reg) { + gf_msg_callingfn("timer", GF_LOG_ERROR, 0, LG_MSG_TIMER_REGISTER_ERROR, + "!reg"); + return NULL; + } + + event = GF_CALLOC(1, sizeof(*event), gf_common_mt_gf_timer_t); + if (!event) { + return NULL; + } + timespec_now(&event->at); + timespec_adjust_delta(&event->at, delta); + at = TS(event->at); + event->callbk = callbk; + event->data = data; + event->xl = THIS; + pthread_mutex_lock(®->lock); + { + list_for_each_entry_reverse(trav, ®->active, list) { - trav = reg->active.prev; - while (trav != ®->active) { - if (TS (trav->at) < at) - break; - trav = trav->prev; - } - event->prev = trav; - event->next = event->prev->next; - event->prev->next = event; - event->next->prev = event; + if (TS(trav->at) < at) + break; + } + list_add(&event->list, &trav->list); + if (&trav->list == ®->active) { + pthread_cond_signal(®->cond); } - pthread_mutex_unlock (®->lock); - return event; + } + pthread_mutex_unlock(®->lock); + return event; } int32_t -gf_timer_call_stale (gf_timer_registry_t *reg, - gf_timer_t *event) +gf_timer_call_cancel(glusterfs_ctx_t *ctx, gf_timer_t *event) { - if (reg == NULL || event == NULL) - { - gf_log ("timer", GF_LOG_ERROR, "invalid argument"); - return 0; - } - - event->next->prev = event->prev; - event->prev->next = event->next; - event->next = ®->stale; - event->prev = event->next->prev; - event->next->prev = event; - event->prev->next = event; + gf_timer_registry_t *reg = NULL; + gf_boolean_t fired = _gf_false; + + if (ctx == NULL || event == NULL) { + gf_msg_callingfn("timer", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + return -1; + } + + if (ctx->cleanup_started) { + gf_msg_callingfn("timer", GF_LOG_INFO, 0, LG_MSG_CTX_CLEANUP_STARTED, + "ctx cleanup started"); + return -1; + } + + LOCK(&ctx->lock); + { + reg = ctx->timer; + } + UNLOCK(&ctx->lock); + if (!reg) { + /* This can happen when cleanup may have just started and + * gf_timer_registry_destroy() sets ctx->timer to NULL. + * gf_timer_proc() takes care of cleaning up the events. + */ + return -1; + } + + pthread_mutex_lock(®->lock); + { + fired = event->fired; + if (fired) + goto unlock; + list_del(&event->list); + } +unlock: + pthread_mutex_unlock(®->lock); + + if (!fired) { + GF_FREE(event); return 0; + } + return -1; } -int32_t -gf_timer_call_cancel (glusterfs_ctx_t *ctx, - gf_timer_t *event) +static void * +gf_timer_proc(void *data) { - gf_timer_registry_t *reg = NULL; - - if (ctx == NULL || event == NULL) - { - gf_log ("timer", GF_LOG_ERROR, "invalid argument"); - return 0; - } - - reg = gf_timer_registry_init (ctx); - if (!reg) { - gf_log ("timer", GF_LOG_ERROR, "!reg"); - GF_FREE (event); - return 0; - } + gf_timer_registry_t *reg = data; + gf_timer_t *event = NULL; + gf_timer_t *tmp = NULL; + xlator_t *old_THIS = NULL; - pthread_mutex_lock (®->lock); - { - event->next->prev = event->prev; - event->prev->next = event->next; + pthread_mutex_lock(®->lock); + + while (!reg->fin) { + if (list_empty(®->active)) { + pthread_cond_wait(®->cond, ®->lock); + } else { + struct timespec now; + + timespec_now(&now); + event = list_first_entry(®->active, gf_timer_t, list); + if (TS(now) < TS(event->at)) { + now = event->at; + pthread_cond_timedwait(®->cond, ®->lock, &now); + } else { + event->fired = _gf_true; + list_del_init(&event->list); + + pthread_mutex_unlock(®->lock); + + old_THIS = NULL; + if (event->xl) { + old_THIS = THIS; + THIS = event->xl; + } + event->callbk(event->data); + GF_FREE(event); + if (old_THIS) { + THIS = old_THIS; + } + + pthread_mutex_lock(®->lock); + } } - pthread_mutex_unlock (®->lock); + } - GF_FREE (event); - return 0; + /* Do not call gf_timer_call_cancel(), + * it will lead to deadlock + */ + list_for_each_entry_safe(event, tmp, ®->active, list) + { + list_del(&event->list); + /* TODO Possible resource leak + * Before freeing the event, we need to call the respective + * event functions and free any resources. + * For example, In case of rpc_clnt_reconnect, we need to + * unref rpc object which was taken when added to timer + * wheel. + */ + GF_FREE(event); + } + + pthread_mutex_unlock(®->lock); + + return NULL; } -void * -gf_timer_proc (void *ctx) +static gf_timer_registry_t * +gf_timer_registry_init(glusterfs_ctx_t *ctx) { - gf_timer_registry_t *reg = NULL; - - if (ctx == NULL) - { - gf_log ("timer", GF_LOG_ERROR, "invalid argument"); - return NULL; + gf_timer_registry_t *reg = NULL; + int ret = -1; + pthread_condattr_t attr; + + LOCK(&ctx->lock); + { + reg = ctx->timer; + if (reg) { + UNLOCK(&ctx->lock); + goto out; } - - reg = gf_timer_registry_init (ctx); + reg = GF_CALLOC(1, sizeof(*reg), gf_common_mt_gf_timer_registry_t); if (!reg) { - gf_log ("timer", GF_LOG_ERROR, "!reg"); - return NULL; + UNLOCK(&ctx->lock); + goto out; } + ctx->timer = reg; + pthread_mutex_init(®->lock, NULL); + pthread_condattr_init(&attr); + pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + pthread_cond_init(®->cond, &attr); + INIT_LIST_HEAD(®->active); + } + UNLOCK(&ctx->lock); + ret = gf_thread_create(®->th, NULL, gf_timer_proc, reg, "timer"); + if (ret) { + gf_msg(THIS->name, GF_LOG_ERROR, ret, LG_MSG_PTHREAD_FAILED, + "Thread creation failed"); + } - while (!reg->fin) { - unsigned long long now; - struct timeval now_tv; - gf_timer_t *event = NULL; - - gettimeofday (&now_tv, NULL); - now = TS (now_tv); - while (1) { - unsigned long long at; - char need_cbk = 0; - - pthread_mutex_lock (®->lock); - { - event = reg->active.next; - at = TS (event->at); - if (event != ®->active && now >= at) { - need_cbk = 1; - gf_timer_call_stale (reg, event); - } - } - pthread_mutex_unlock (®->lock); - if (event->xl) - THIS = event->xl; - if (need_cbk) - event->callbk (event->data); - - else - break; - } - usleep (1000000); - } +out: + return reg; +} - pthread_mutex_lock (®->lock); - { - while (reg->active.next != ®->active) { - gf_timer_call_cancel (ctx, reg->active.next); - } +void +gf_timer_registry_destroy(glusterfs_ctx_t *ctx) +{ + pthread_t thr_id; + gf_timer_registry_t *reg = NULL; - while (reg->stale.next != ®->stale) { - gf_timer_call_cancel (ctx, reg->stale.next); - } - } - pthread_mutex_unlock (®->lock); - pthread_mutex_destroy (®->lock); - GF_FREE (((glusterfs_ctx_t *)ctx)->timer); + if (ctx == NULL) + return; - return NULL; -} + LOCK(&ctx->lock); + { + reg = ctx->timer; + ctx->timer = NULL; + } + UNLOCK(&ctx->lock); -gf_timer_registry_t * -gf_timer_registry_init (glusterfs_ctx_t *ctx) -{ - if (ctx == NULL) { - gf_log ("timer", GF_LOG_ERROR, "invalid argument"); - return NULL; - } + if (!reg) + return; - if (!ctx->timer) { - gf_timer_registry_t *reg = NULL; + thr_id = reg->th; - reg = GF_CALLOC (1, sizeof (*reg), - gf_common_mt_gf_timer_registry_t); - if (!reg) - goto out; + pthread_mutex_lock(®->lock); - pthread_mutex_init (®->lock, NULL); - reg->active.next = ®->active; - reg->active.prev = ®->active; - reg->stale.next = ®->stale; - reg->stale.prev = ®->stale; + reg->fin = 1; + pthread_cond_signal(®->cond); - ctx->timer = reg; - pthread_create (®->th, NULL, gf_timer_proc, ctx); - } -out: - return ctx->timer; + pthread_mutex_unlock(®->lock); + + pthread_join(thr_id, NULL); + + pthread_cond_destroy(®->cond); + pthread_mutex_destroy(®->lock); + + GF_FREE(reg); } diff --git a/libglusterfs/src/timer.h b/libglusterfs/src/timer.h deleted file mode 100644 index e5fa5e2c679..00000000000 --- a/libglusterfs/src/timer.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - Copyright (c) 2007-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _TIMER_H -#define _TIMER_H - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include "glusterfs.h" -#include "xlator.h" -#include <sys/time.h> -#include <pthread.h> - -typedef void (*gf_timer_cbk_t) (void *); - -struct _gf_timer { - struct _gf_timer *next, *prev; - struct timeval at; - gf_timer_cbk_t callbk; - void *data; - xlator_t *xl; -}; - -struct _gf_timer_registry { - pthread_t th; - char fin; - struct _gf_timer stale; - struct _gf_timer active; - pthread_mutex_t lock; -}; - -typedef struct _gf_timer gf_timer_t; -typedef struct _gf_timer_registry gf_timer_registry_t; - -gf_timer_t * -gf_timer_call_after (glusterfs_ctx_t *ctx, - struct timeval delta, - gf_timer_cbk_t cbk, - void *data); - -int32_t -gf_timer_call_cancel (glusterfs_ctx_t *ctx, - gf_timer_t *event); - -void * -gf_timer_proc (void *data); - -gf_timer_registry_t * -gf_timer_registry_init (glusterfs_ctx_t *ctx); - -#endif /* _TIMER_H */ diff --git a/libglusterfs/src/timespec.c b/libglusterfs/src/timespec.c new file mode 100644 index 00000000000..96cef5c6f07 --- /dev/null +++ b/libglusterfs/src/timespec.c @@ -0,0 +1,129 @@ +/* + 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> +#include <time.h> +#include <sys/time.h> +#include <string.h> + +#if defined GF_DARWIN_HOST_OS +#include <mach/mach_time.h> +static mach_timebase_info_data_t gf_timebase; +#endif + +#include "glusterfs/timespec.h" +#include "glusterfs/libglusterfs-messages.h" +#include "glusterfs/common-utils.h" + +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)) { + /* All good */ + return; + } + + /* Fall back, but there is hope in gettimeofday() syscall */ + struct timeval tv; + if (0 == gettimeofday(&tv, NULL)) { + /* Again, all good */ + TIMEVAL_TO_TIMESPEC(&tv, ts); + return; + } + + /* If control hits here, there is surely a problem, + mainly because, as per man page too, these syscalls + shouldn't fail. Best way is to ABORT, because it is + not right */ + GF_ABORT("gettimeofday() failed!!"); + +#elif defined GF_DARWIN_HOST_OS + uint64_t time = mach_absolute_time(); + static double scaling = 0.0; + + if (mach_timebase_info(&gf_timebase) != KERN_SUCCESS) { + gf_timebase.numer = 1; + gf_timebase.denom = 1; + } + if (gf_timebase.denom == 0) { + gf_timebase.numer = 1; + gf_timebase.denom = 1; + } + + scaling = (double)gf_timebase.numer / (double)gf_timebase.denom; + time *= scaling; + + ts->tv_sec = (time * NANO); + ts->tv_nsec = (time - (ts->tv_sec * GIGA)); + +#endif /* Platform verification */ +} + +void +timespec_now_realtime(struct timespec *ts) +{ +#if defined GF_LINUX_HOST_OS || defined GF_SOLARIS_HOST_OS || \ + defined GF_BSD_HOST_OS + if (0 == clock_gettime(CLOCK_REALTIME, ts)) { + return; + } +#endif + + /* Fall back to gettimeofday()*/ + struct timeval tv = { + 0, + }; + if (0 == gettimeofday(&tv, NULL)) { + TIMEVAL_TO_TIMESPEC(&tv, ts); + return; + } + + return; +} + +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; +} + +void +timespec_sub(const struct timespec *begin, const struct timespec *end, + struct timespec *res) +{ + if (end->tv_nsec < begin->tv_nsec) { + res->tv_sec = end->tv_sec - begin->tv_sec - 1; + res->tv_nsec = end->tv_nsec + 1000000000 - begin->tv_nsec; + } else { + res->tv_sec = end->tv_sec - begin->tv_sec; + res->tv_nsec = end->tv_nsec - begin->tv_nsec; + } +} + +int +timespec_cmp(const struct timespec *lhs_ts, const struct timespec *rhs_ts) +{ + if (lhs_ts->tv_sec < rhs_ts->tv_sec) { + return -1; + } else if (lhs_ts->tv_sec > rhs_ts->tv_sec) { + return 1; + } else if (lhs_ts->tv_nsec < rhs_ts->tv_nsec) { + return -1; + } else if (lhs_ts->tv_nsec > rhs_ts->tv_nsec) { + return 1; + } + + return 0; +} diff --git a/libglusterfs/src/trie.c b/libglusterfs/src/trie.c new file mode 100644 index 00000000000..809550b864c --- /dev/null +++ b/libglusterfs/src/trie.c @@ -0,0 +1,366 @@ +/* + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include <stdio.h> +#include <string.h> + +#include "glusterfs/common-utils.h" +#include "glusterfs/trie.h" + +#define DISTANCE_EDIT 1 +#define DISTANCE_INS 1 +#define DISTANCE_DEL 1 + +struct trienode { + char id; + char eow; + int depth; + void *data; + struct trie *trie; + struct trienode *parent; + struct trienode *subnodes[255]; +}; + +struct trie { + struct trienode root; + int nodecnt; + size_t len; +}; + +trie_t * +trie_new() +{ + trie_t *trie = NULL; + + trie = GF_CALLOC(1, sizeof(*trie), gf_common_mt_trie_trie); + if (!trie) + return NULL; + + trie->root.trie = trie; + + return trie; +} + +static trienode_t * +trie_subnode(trienode_t *node, int id) +{ + trienode_t *subnode = NULL; + + subnode = node->subnodes[id]; + if (!subnode) { + subnode = GF_CALLOC(1, sizeof(*subnode), gf_common_mt_trie_node); + if (!subnode) + return NULL; + + subnode->id = id; + subnode->depth = node->depth + 1; + node->subnodes[id] = subnode; + subnode->parent = node; + subnode->trie = node->trie; + node->trie->nodecnt++; + } + + return subnode; +} + +int +trie_add(trie_t *trie, const char *dword) +{ + trienode_t *node = NULL; + int i = 0; + char id = 0; + trienode_t *subnode = NULL; + + node = &trie->root; + + for (i = 0; i < strlen(dword); i++) { + id = dword[i]; + + subnode = trie_subnode(node, id); + if (!subnode) + return -1; + node = subnode; + } + + node->eow = 1; + + return 0; +} + +static void +trienode_free(trienode_t *node) +{ + trienode_t *trav = NULL; + int i = 0; + + for (i = 0; i < 255; i++) { + trav = node->subnodes[i]; + + if (trav) + trienode_free(trav); + } + + GF_FREE(node->data); + GF_FREE(node); +} + +void +trie_destroy(trie_t *trie) +{ + trienode_free((trienode_t *)trie); +} + +void +trie_destroy_bynode(trienode_t *node) +{ + trie_destroy(node->trie); +} + +static int +trienode_walk(trienode_t *node, int (*fn)(trienode_t *node, void *data), + void *data, int eowonly) +{ + trienode_t *trav = NULL; + int i = 0; + int cret = 0; + int ret = 0; + + if (!eowonly || node->eow) + ret = fn(node, data); + + if (ret) + goto out; + + for (i = 0; i < 255; i++) { + trav = node->subnodes[i]; + if (!trav) + continue; + + cret = trienode_walk(trav, fn, data, eowonly); + if (cret < 0) { + ret = cret; + goto out; + } + ret += cret; + } + +out: + return ret; +} + +static int +trie_walk(trie_t *trie, int (*fn)(trienode_t *node, void *data), void *data, + int eowonly) +{ + return trienode_walk(&trie->root, fn, data, eowonly); +} + +static void +print_node(trienode_t *node, char **buf) +{ + if (!node->parent) + return; + + if (node->parent) { + print_node(node->parent, buf); + *(*buf)++ = node->id; + } +} + +int +trienode_get_word(trienode_t *node, char **bufp) +{ + char *buf = NULL; + + buf = GF_CALLOC(1, node->depth + 1, gf_common_mt_trie_buf); + if (!buf) + return -1; + *bufp = buf; + + print_node(node, &buf); + + return 0; +} + +static int +calc_dist(trienode_t *node, void *data) +{ + const char *word = NULL; + int i = 0; + int *row = NULL; + int *uprow = NULL; + int distu = 0; + int distl = 0; + int distul = 0; + + word = data; + + node->data = GF_CALLOC(node->trie->len, sizeof(int), + gf_common_mt_trie_data); + if (!node->data) + return -1; + row = node->data; + + if (!node->parent) { + for (i = 0; i < node->trie->len; i++) + row[i] = i + 1; + + return 0; + } + + uprow = node->parent->data; + + distu = node->depth; /* up node */ + distul = node->parent->depth; /* up-left node */ + + for (i = 0; i < node->trie->len; i++) { + distl = uprow[i]; /* left node */ + + if (word[i] == node->id) + row[i] = distul; + else + row[i] = min((distul + DISTANCE_EDIT), + min((distu + DISTANCE_DEL), (distl + DISTANCE_INS))); + + distu = row[i]; + distul = distl; + } + + return 0; +} + +int +trienode_get_dist(trienode_t *node) +{ + int *row = NULL; + + row = node->data; + + return row[node->trie->len - 1]; +} + +struct trienodevec_w { + struct trienodevec *vec; + const char *word; +}; + +static void +trienodevec_clear(struct trienodevec *nodevec) +{ + memset(nodevec->nodes, 0, sizeof(*nodevec->nodes) * nodevec->cnt); +} + +static int +collect_closest(trienode_t *node, void *data) +{ + struct trienodevec_w *nodevec_w = NULL; + struct trienodevec *nodevec = NULL; + int dist = 0; + int i = 0; + + nodevec_w = data; + nodevec = nodevec_w->vec; + + if (calc_dist(node, (void *)nodevec_w->word)) + return -1; + + if (!node->eow || !nodevec->cnt) + return 0; + + dist = trienode_get_dist(node); + + /* + * I thought that when descending further after some dictionary word dw, + * if we see that child's distance is bigger than it was for dw, then we + * can prune this branch, as it can contain only worse nodes. + * + * This conjecture fails, see eg: + * + * d("AB", "B") = 1; + * d("AB", "BA") = 2; + * d("AB", "BAB") = 1; + * + * -- if both "B" and "BAB" are in dict., then pruning at "BA" * would + * miss "BAB". + * + * (example courtesy of Richard Bann <richardbann at gmail.com>) + + if (node->parent->eow && dist > trienode_get_dist (node->parent)) + return 1; + + */ + + if (nodevec->nodes[0] && dist < trienode_get_dist(nodevec->nodes[0])) { + /* improving over the findings so far */ + trienodevec_clear(nodevec); + nodevec->nodes[0] = node; + } else if (!nodevec->nodes[0] || + dist == trienode_get_dist(nodevec->nodes[0])) { + /* as good as the best so far, add if there is free space */ + for (i = 0; i < nodevec->cnt; i++) { + if (!nodevec->nodes[i]) { + nodevec->nodes[i] = node; + break; + } + } + } + + return 0; +} + +int +trie_measure(trie_t *trie, const char *word, trienode_t **nodes, int nodecnt) +{ + struct trienodevec nodevec = { + 0, + }; + + nodevec.nodes = nodes; + nodevec.cnt = nodecnt; + + return trie_measure_vec(trie, word, &nodevec); +} + +int +trie_measure_vec(trie_t *trie, const char *word, struct trienodevec *nodevec) +{ + struct trienodevec_w nodevec_w = { + 0, + }; + int ret = 0; + + trie->len = strlen(word); + + trienodevec_clear(nodevec); + nodevec_w.vec = nodevec; + nodevec_w.word = word; + + ret = trie_walk(trie, collect_closest, &nodevec_w, 0); + if (ret > 0) + ret = 0; + + return ret; +} + +static int +trienode_reset(trienode_t *node, void *data) +{ + GF_FREE(node->data); + + return 0; +} + +void +trie_reset_search(trie_t *trie) +{ + trie->len = 0; + + trie_walk(trie, trienode_reset, NULL, 0); +} diff --git a/libglusterfs/src/unittest/global_mock.c b/libglusterfs/src/unittest/global_mock.c new file mode 100644 index 00000000000..2fcf96dbad8 --- /dev/null +++ b/libglusterfs/src/unittest/global_mock.c @@ -0,0 +1,25 @@ +/* + Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include "glusterfs/logging.h" +#include "glusterfs/xlator.h" + +#include <stdarg.h> +#include <stddef.h> +#include <setjmp.h> +#include <inttypes.h> + +#include <cmocka.h> + +xlator_t ** +__glusterfs_this_location() +{ + return ((xlator_t **)(uintptr_t)mock()); +} diff --git a/libglusterfs/src/unittest/log_mock.c b/libglusterfs/src/unittest/log_mock.c new file mode 100644 index 00000000000..60f6530726b --- /dev/null +++ b/libglusterfs/src/unittest/log_mock.c @@ -0,0 +1,52 @@ +/* + Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include "glusterfs/logging.h" +#include "glusterfs/xlator.h" + +#include <stdarg.h> +#include <stddef.h> +#include <setjmp.h> +#include <inttypes.h> + +#include <cmocka.h> + +int +_gf_log(const char *domain, const char *file, const char *function, + int32_t line, gf_loglevel_t level, const char *fmt, ...) +{ + return 0; +} + +int +_gf_log_callingfn(const char *domain, const char *file, const char *function, + int32_t line, gf_loglevel_t level, const char *fmt, ...) +{ + return 0; +} + +int +_gf_log_nomem(const char *domain, const char *file, const char *function, + int line, gf_loglevel_t level, size_t size) +{ + return 0; +} + +int +_gf_msg_nomem(const char *domain, const char *file, const char *function, + int line, gf_loglevel_t level, size_t size) +{ + return 0; +} + +void +gf_log_globals_init(void *data, gf_loglevel_t level) +{ +} diff --git a/libglusterfs/src/unittest/mem_pool_unittest.c b/libglusterfs/src/unittest/mem_pool_unittest.c new file mode 100644 index 00000000000..9ca324329ba --- /dev/null +++ b/libglusterfs/src/unittest/mem_pool_unittest.c @@ -0,0 +1,483 @@ +/* + Copyright (c) 2014 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include "glusterfs/mem-pool.h" +#include "glusterfs/logging.h" +#include "glusterfs/xlator.h" + +#include <stdarg.h> +#include <stddef.h> +#include <setjmp.h> +#include <inttypes.h> +#include <string.h> +#include <cmocka_pbc.h> +#include <cmocka.h> + +#ifndef assert_ptr_equal +#define assert_ptr_equal(a, b) \ + _assert_int_equal(cast_ptr_to_largest_integral_type(a), \ + cast_ptr_to_largest_integral_type(b), __FILE__, \ + __LINE__) +#endif + +/* + * memory header for gf_mem_set_acct_info + */ +typedef struct __attribute__((packed)) { + uint32_t type; + size_t size; + xlator_t *xl; + uint32_t header_magic; + uint8_t pad[8]; +} mem_header_t; + +/* + * Prototypes to private functions + */ +int +gf_mem_set_acct_info(xlator_t *xl, char **alloc_ptr, size_t size, uint32_t type, + const char *typestr); + +/* + * Helper functions + */ +static xlator_t * +helper_xlator_init(uint32_t num_types) +{ + xlator_t *xl; + int i, ret; + + REQUIRE(num_types > 0); + + xl = test_calloc(1, sizeof(xlator_t)); + assert_non_null(xl); + xl->mem_acct->num_types = num_types; + xl->mem_acct = test_calloc(sizeof(struct mem_acct) + + sizeof(struct mem_acct_rec) * num_types); + assert_non_null(xl->mem_acct); + + xl->ctx = test_calloc(1, sizeof(glusterfs_ctx_t)); + assert_non_null(xl->ctx); + + for (i = 0; i < num_types; i++) { + ret = LOCK_INIT(&(xl->mem_acct->rec[i].lock)); + assert_int_equal(ret, 0); + } + + ENSURE(num_types == xl->mem_acct->num_types); + ENSURE(NULL != xl); + + return xl; +} + +static int +helper_xlator_destroy(xlator_t *xl) +{ + int i, ret; + + for (i = 0; i < xl->mem_acct->num_types; i++) { + ret = LOCK_DESTROY(&(xl->mem_acct->rec[i].lock)); + assert_int_equal(ret, 0); + } + + free(xl->mem_acct->rec); + free(xl->ctx); + free(xl); + return 0; +} + +static void +helper_check_memory_headers(char *mem, xlator_t *xl, size_t size, uint32_t type) +{ + mem_header_t *p; + + p = (mem_header_t *)mem, assert_int_equal(p->type, type); + assert_int_equal(p->size, size); + assert_true(p->xl == xl); + assert_int_equal(p->header_magic, GF_MEM_HEADER_MAGIC); + assert_true(*(uint32_t *)(mem + sizeof(mem_header_t) + size) == + GF_MEM_TRAILER_MAGIC); +} + +/* + * Tests + */ +static void +test_gf_mem_acct_enable_set(void **state) +{ + (void)state; + glusterfs_ctx_t test_ctx; + + expect_assert_failure(gf_mem_acct_enable_set(NULL)); + + memset(&test_ctx, 0, sizeof(test_ctx)); + assert_true(NULL == test_ctx.process_uuid); + gf_mem_acct_enable_set((void *)&test_ctx); + assert_true(1 == test_ctx.mem_acct_enable); + assert_true(NULL == test_ctx.process_uuid); +} + +static void +test_gf_mem_set_acct_info_asserts(void **state) +{ + xlator_t *xl; + xlator_t xltest; + char *alloc_ptr; + size_t size; + uint32_t type; + + memset(&xltest, 0, sizeof(xlator_t)); + xl = (xlator_t *)0xBADD; + alloc_ptr = (char *)0xBADD; + size = 8196; + type = 0; + + // Check xl is NULL + expect_assert_failure( + gf_mem_set_acct_info(NULL, &alloc_ptr, size, type, "")); + // Check xl->mem_acct = NULL + expect_assert_failure( + gf_mem_set_acct_info(&xltest, &alloc_ptr, 0, type, "")); + // Check type <= xl->mem_acct->num_types + type = 100; + expect_assert_failure( + gf_mem_set_acct_info(&xltest, &alloc_ptr, 0, type, "")); + // Check alloc is NULL + assert_int_equal(-1, gf_mem_set_acct_info(&xltest, NULL, size, type, "")); + + // Initialize xl + xl = helper_xlator_init(10); + + // Test number of types + type = 100; + assert_true(NULL != xl->mem_acct); + assert_true(type > xl->mem_acct->num_types); + expect_assert_failure(gf_mem_set_acct_info(xl, &alloc_ptr, size, type, "")); + + helper_xlator_destroy(xl); +} + +static void +test_gf_mem_set_acct_info_memory(void **state) +{ + xlator_t *xl; + char *alloc_ptr; + char *temp_ptr; + size_t size; + uint32_t type; + const char *typestr = "TEST"; + + size = 8196; + type = 9; + + // Initialize xl + xl = helper_xlator_init(10); + assert_null(xl->mem_acct->rec[type].typestr); + + // Test allocation + temp_ptr = test_calloc(1, size + GF_MEM_HEADER_SIZE + GF_MEM_TRAILER_SIZE); + assert_non_null(temp_ptr); + alloc_ptr = temp_ptr; + gf_mem_set_acct_info(xl, &alloc_ptr, size, type, typestr); + + // Check values + assert_ptr_equal(typestr, xl->mem_acct->rec[type].typestr); + assert_int_equal(xl->mem_acct->rec[type].size, size); + assert_int_equal(xl->mem_acct->rec[type].num_allocs, 1); + assert_int_equal(xl->mem_acct->rec[type].total_allocs, 1); + assert_int_equal(xl->mem_acct->rec[type].max_size, size); + assert_int_equal(xl->mem_acct->rec[type].max_num_allocs, 1); + + // Check memory + helper_check_memory_headers(temp_ptr, xl, size, type); + + // Check that alloc_ptr has been moved correctly + // by gf_mem_set_acct_info + { + mem_header_t *p; + + p = (mem_header_t *)temp_ptr; + p++; + p->type = 1234; + assert_int_equal(*(uint32_t *)alloc_ptr, p->type); + } + + free(temp_ptr); + helper_xlator_destroy(xl); +} + +static void +test_gf_calloc_default_calloc(void **state) +{ + xlator_t *xl; + void *mem; + size_t size; + uint32_t type; + + // Initialize xl + xl = helper_xlator_init(10); + assert_int_equal(xl->ctx->mem_acct_enable, 0); + will_return(__glusterfs_this_location, &xl); + + // Call __gf_calloc + size = 1024; + type = 3; + mem = __gf_calloc(1, size, type, "3"); + assert_non_null(mem); + memset(mem, 0x5A, size); + + // Check xl did not change + assert_int_equal(xl->mem_acct->rec[type].size, 0); + assert_int_equal(xl->mem_acct->rec[type].num_allocs, 0); + assert_int_equal(xl->mem_acct->rec[type].total_allocs, 0); + assert_int_equal(xl->mem_acct->rec[type].max_size, 0); + assert_int_equal(xl->mem_acct->rec[type].max_num_allocs, 0); + + free(mem); + helper_xlator_destroy(xl); +} + +static void +test_gf_calloc_mem_acct_enabled(void **state) +{ + xlator_t *xl; + void *mem; + size_t size; + uint32_t type; + + // Initialize xl + xl = helper_xlator_init(10); + assert_int_equal(xl->ctx->mem_acct_enable, 0); + xl->ctx->mem_acct_enable = 1; + + // For line mem-pool.c:115 and mem-pool:118 + will_return_always(__glusterfs_this_location, &xl); + + // Call __gf_calloc + size = 1024; + type = 3; + mem = __gf_calloc(1, size, type, "3"); + assert_non_null(mem); + memset(mem, 0x5A, size); + + // Check xl values + assert_int_equal(xl->mem_acct->rec[type].size, size); + assert_int_equal(xl->mem_acct->rec[type].num_allocs, 1); + assert_int_equal(xl->mem_acct->rec[type].total_allocs, 1); + assert_int_equal(xl->mem_acct->rec[type].max_size, size); + assert_int_equal(xl->mem_acct->rec[type].max_num_allocs, 1); + + // Check memory + helper_check_memory_headers(mem - sizeof(mem_header_t), xl, size, type); + free(mem - sizeof(mem_header_t)); + helper_xlator_destroy(xl); +} + +static void +test_gf_malloc_default_malloc(void **state) +{ + xlator_t *xl; + void *mem; + size_t size; + uint32_t type; + + // Initialize xl + xl = helper_xlator_init(10); + assert_int_equal(xl->ctx->mem_acct_enable, 0); + will_return(__glusterfs_this_location, &xl); + + // Call __gf_malloc + size = 1024; + type = 3; + mem = __gf_malloc(size, type, "3"); + assert_non_null(mem); + memset(mem, 0x5A, size); + + // Check xl did not change + assert_int_equal(xl->mem_acct->rec[type].size, 0); + assert_int_equal(xl->mem_acct->rec[type].num_allocs, 0); + assert_int_equal(xl->mem_acct->rec[type].total_allocs, 0); + assert_int_equal(xl->mem_acct->rec[type].max_size, 0); + assert_int_equal(xl->mem_acct->rec[type].max_num_allocs, 0); + + free(mem); + helper_xlator_destroy(xl); +} + +static void +test_gf_malloc_mem_acct_enabled(void **state) +{ + xlator_t *xl; + void *mem; + size_t size; + uint32_t type; + + // Initialize xl + xl = helper_xlator_init(10); + assert_int_equal(xl->ctx->mem_acct_enable, 0); + xl->ctx->mem_acct_enable = 1; + + // For line mem-pool.c:115 and mem-pool:118 + will_return_always(__glusterfs_this_location, &xl); + + // Call __gf_malloc + size = 1024; + type = 3; + mem = __gf_malloc(size, type, "3"); + assert_non_null(mem); + memset(mem, 0x5A, size); + + // Check xl values + assert_int_equal(xl->mem_acct->rec[type].size, size); + assert_int_equal(xl->mem_acct->rec[type].num_allocs, 1); + assert_int_equal(xl->mem_acct->rec[type].total_allocs, 1); + assert_int_equal(xl->mem_acct->rec[type].max_size, size); + assert_int_equal(xl->mem_acct->rec[type].max_num_allocs, 1); + + // Check memory + helper_check_memory_headers(mem - sizeof(mem_header_t), xl, size, type); + free(mem - sizeof(mem_header_t)); + helper_xlator_destroy(xl); +} + +static void +test_gf_realloc_default_realloc(void **state) +{ + xlator_t *xl; + void *mem; + size_t size; + uint32_t type; + + // Initialize xl + xl = helper_xlator_init(10); + assert_int_equal(xl->ctx->mem_acct_enable, 0); + will_return_always(__glusterfs_this_location, &xl); + + // Call __gf_malloc then realloc + size = 10; + type = 3; + mem = __gf_malloc(size, type, "3"); + assert_non_null(mem); + memset(mem, 0xA5, size); + + size = 1024; + mem = __gf_realloc(mem, size); + assert_non_null(mem); + memset(mem, 0x5A, size); + + // Check xl did not change + assert_int_equal(xl->mem_acct->rec[type].size, 0); + assert_int_equal(xl->mem_acct->rec[type].num_allocs, 0); + assert_int_equal(xl->mem_acct->rec[type].total_allocs, 0); + assert_int_equal(xl->mem_acct->rec[type].max_size, 0); + assert_int_equal(xl->mem_acct->rec[type].max_num_allocs, 0); + + free(mem); + helper_xlator_destroy(xl); +} + +static void +test_gf_realloc_mem_acct_enabled(void **state) +{ + xlator_t *xl; + void *mem; + size_t size; + uint32_t type; + + // Initialize xl + xl = helper_xlator_init(10); + assert_int_equal(xl->ctx->mem_acct_enable, 0); + xl->ctx->mem_acct_enable = 1; + + // For line mem-pool.c:115 and mem-pool:118 + will_return_always(__glusterfs_this_location, &xl); + + // Call __gf_malloc then realloc + size = 1024; + type = 3; + mem = __gf_malloc(size, type, "3"); + assert_non_null(mem); + memset(mem, 0xA5, size); + + size = 2048; + mem = __gf_realloc(mem, size); + assert_non_null(mem); + memset(mem, 0x5A, size); + + // Check xl values + // + // :TODO: This is really weird. I would have expected + // xl to only have a size equal to that of the realloc + // not to the realloc + the malloc. + // Is this a bug? + // + assert_int_equal(xl->mem_acct->rec[type].size, size + 1024); + assert_int_equal(xl->mem_acct->rec[type].num_allocs, 2); + assert_int_equal(xl->mem_acct->rec[type].total_allocs, 2); + assert_int_equal(xl->mem_acct->rec[type].max_size, size + 1024); + assert_int_equal(xl->mem_acct->rec[type].max_num_allocs, 2); + + // Check memory + helper_check_memory_headers(mem - sizeof(mem_header_t), xl, size, type); + free(mem - sizeof(mem_header_t)); + helper_xlator_destroy(xl); +} + +static void +test_gf_realloc_ptr(void **state) +{ + xlator_t *xl; + void *mem; + size_t size; + + // Initialize xl + xl = helper_xlator_init(10); + assert_int_equal(xl->ctx->mem_acct_enable, 0); + + // For line mem-pool.c:115 and mem-pool:118 + will_return_always(__glusterfs_this_location, &xl); + + // Tests according to the manpage for realloc + + // Like a malloc + size = 1024; + mem = __gf_realloc(NULL, size); + assert_non_null(mem); + memset(mem, 0xA5, size); + + // Like a free + mem = __gf_realloc(mem, 0); + assert_null(mem); + + // Now enable xl context + xl->ctx->mem_acct_enable = 1; + expect_assert_failure(__gf_realloc(NULL, size)); + + helper_xlator_destroy(xl); +} + +int +main(void) +{ + const struct CMUnitTest libglusterfs_mem_pool_tests[] = { + cmocka_unit_test(test_gf_mem_acct_enable_set), + cmocka_unit_test(test_gf_mem_set_acct_info_asserts), + cmocka_unit_test(test_gf_mem_set_acct_info_memory), + cmocka_unit_test(test_gf_calloc_default_calloc), + cmocka_unit_test(test_gf_calloc_mem_acct_enabled), + cmocka_unit_test(test_gf_malloc_default_malloc), + cmocka_unit_test(test_gf_malloc_mem_acct_enabled), + cmocka_unit_test(test_gf_realloc_default_realloc), + cmocka_unit_test(test_gf_realloc_mem_acct_enabled), + cmocka_unit_test(test_gf_realloc_ptr), + }; + + return cmocka_run_group_tests(libglusterfs_mem_pool_tests, NULL, NULL); +} diff --git a/libglusterfs/src/unittest/unittest.h b/libglusterfs/src/unittest/unittest.h new file mode 100644 index 00000000000..58b3e28bb6e --- /dev/null +++ b/libglusterfs/src/unittest/unittest.h @@ -0,0 +1,47 @@ +/* + Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#ifndef _GF_UNITTEST_H_ +#define _GF_UNITTEST_H_ + +#ifdef UNIT_TESTING +#include <stdarg.h> +#include <stddef.h> +#include <setjmp.h> +#include <cmocka_pbc.h> +#include <cmocka.h> + +extern void +mock_assert(const int result, const char *const expression, + const char *const file, const int line); + +// Change GF_CALLOC and GF_FREE to use +// cmocka memory allocation versions +#ifdef UNIT_TESTING +#undef GF_CALLOC +#define GF_CALLOC(n, s, t) test_calloc(n, s) +#undef GF_FREE +#define GF_FREE test_free + +/* Catch intended assert()'s while unit-testing */ +extern void +mock_assert(const int result, const char *const expression, + const char *const file, const int line); + +#undef assert +#define assert(expression) \ + mock_assert((int)(expression), #expression, __FILE__, __LINE__); +#endif +#else +#define REQUIRE(p) /**/ +#define ENSURE(p) /**/ +#endif + +#endif /* _GF_UNITTEST */ diff --git a/libglusterfs/src/xlator.c b/libglusterfs/src/xlator.c index 2074c143c8c..9a2582d45d5 100644 --- a/libglusterfs/src/xlator.c +++ b/libglusterfs/src/xlator.c @@ -1,1087 +1,1593 @@ /* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> + Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com> This file is part of GlusterFS. - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. + 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 "xlator.h" +#include "glusterfs/xlator.h" #include <dlfcn.h> #include <netdb.h> #include <fnmatch.h> -#include "defaults.h" +#include "glusterfs/defaults.h" +#include "glusterfs/libglusterfs-messages.h" +#define SET_DEFAULT_FOP(fn) \ + do { \ + if (!xl->fops->fn) \ + xl->fops->fn = default_##fn; \ + if (!xl->pass_through_fops->fn) \ + xl->pass_through_fops->fn = default_##fn; \ + } while (0) -#define SET_DEFAULT_FOP(fn) do { \ - if (!xl->fops->fn) \ - xl->fops->fn = default_##fn; \ - } while (0) +#define SET_DEFAULT_CBK(fn) \ + do { \ + if (!xl->cbks->fn) \ + xl->cbks->fn = default_##fn; \ + } while (0) -#define SET_DEFAULT_CBK(fn) do { \ - if (!xl->cbks->fn) \ - xl->cbks->fn = default_##fn; \ - } while (0) +pthread_mutex_t xlator_init_mutex = PTHREAD_MUTEX_INITIALIZER; +void +xlator_init_lock(void) +{ + (void)pthread_mutex_lock(&xlator_init_mutex); +} -#define GF_OPTION_LIST_EMPTY(_opt) (_opt->value[0] == NULL) +void +xlator_init_unlock(void) +{ + (void)pthread_mutex_unlock(&xlator_init_mutex); +} + +static struct xlator_cbks default_cbks = {}; +struct volume_options default_options[] = { + { + .key = {"log-level"}, + .type = GF_OPTION_TYPE_STR, + .op_version = {GD_OP_VERSION_6_0}, + .flags = OPT_FLAG_SETTABLE, + .tags = {"generic"}, + .value = {"DEBUG", "WARNING", "ERROR", "INFO", "CRITICAL", "NONE", + "TRACE"}, + .description = "Option to set log-level of given translator", + }, + { + .key = {NULL}, + }, +}; + +/* Handle the common options in each translator */ +void +handle_default_options(xlator_t *xl, dict_t *options) +{ + int ret; + char *value; + + /* log-level */ + ret = dict_get_str(options, "log-level", &value); + if (!ret) { + int log_level = glusterd_check_log_level(value); + if (log_level != -1) { + xl->loglevel = log_level; + } + } +} static void -fill_defaults (xlator_t *xl) +fill_defaults(xlator_t *xl) { - if (xl == NULL) { - gf_log ("xlator", GF_LOG_DEBUG, "invalid argument"); - return; - } - - SET_DEFAULT_FOP (create); - SET_DEFAULT_FOP (open); - SET_DEFAULT_FOP (stat); - SET_DEFAULT_FOP (readlink); - SET_DEFAULT_FOP (mknod); - SET_DEFAULT_FOP (mkdir); - SET_DEFAULT_FOP (unlink); - SET_DEFAULT_FOP (rmdir); - SET_DEFAULT_FOP (symlink); - SET_DEFAULT_FOP (rename); - SET_DEFAULT_FOP (link); - SET_DEFAULT_FOP (truncate); - SET_DEFAULT_FOP (readv); - SET_DEFAULT_FOP (writev); - SET_DEFAULT_FOP (statfs); - SET_DEFAULT_FOP (flush); - SET_DEFAULT_FOP (fsync); - SET_DEFAULT_FOP (setxattr); - SET_DEFAULT_FOP (getxattr); - SET_DEFAULT_FOP (fsetxattr); - SET_DEFAULT_FOP (fgetxattr); - SET_DEFAULT_FOP (removexattr); - SET_DEFAULT_FOP (opendir); - SET_DEFAULT_FOP (readdir); - SET_DEFAULT_FOP (readdirp); - SET_DEFAULT_FOP (fsyncdir); - SET_DEFAULT_FOP (access); - SET_DEFAULT_FOP (ftruncate); - SET_DEFAULT_FOP (fstat); - SET_DEFAULT_FOP (lk); - SET_DEFAULT_FOP (inodelk); - SET_DEFAULT_FOP (finodelk); - SET_DEFAULT_FOP (entrylk); - SET_DEFAULT_FOP (fentrylk); - SET_DEFAULT_FOP (lookup); - SET_DEFAULT_FOP (rchecksum); - SET_DEFAULT_FOP (xattrop); - SET_DEFAULT_FOP (fxattrop); - SET_DEFAULT_FOP (setattr); - SET_DEFAULT_FOP (fsetattr); - - SET_DEFAULT_FOP (getspec); - - SET_DEFAULT_CBK (release); - SET_DEFAULT_CBK (releasedir); - SET_DEFAULT_CBK (forget); - - if (!xl->notify) - xl->notify = default_notify; - - if (!xl->mem_acct_init) - xl->mem_acct_init = default_mem_acct_init; - - return; + if (xl == NULL) { + gf_msg_callingfn("xlator", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG, + "invalid argument"); + return; + } + + if (!xl->pass_through_fops) + xl->pass_through_fops = default_fops; + + SET_DEFAULT_FOP(create); + SET_DEFAULT_FOP(open); + SET_DEFAULT_FOP(stat); + SET_DEFAULT_FOP(readlink); + SET_DEFAULT_FOP(mknod); + SET_DEFAULT_FOP(mkdir); + SET_DEFAULT_FOP(unlink); + SET_DEFAULT_FOP(rmdir); + SET_DEFAULT_FOP(symlink); + SET_DEFAULT_FOP(rename); + SET_DEFAULT_FOP(link); + SET_DEFAULT_FOP(truncate); + SET_DEFAULT_FOP(readv); + SET_DEFAULT_FOP(writev); + SET_DEFAULT_FOP(statfs); + SET_DEFAULT_FOP(flush); + SET_DEFAULT_FOP(fsync); + SET_DEFAULT_FOP(setxattr); + SET_DEFAULT_FOP(getxattr); + SET_DEFAULT_FOP(fsetxattr); + SET_DEFAULT_FOP(fgetxattr); + SET_DEFAULT_FOP(removexattr); + SET_DEFAULT_FOP(fremovexattr); + SET_DEFAULT_FOP(opendir); + SET_DEFAULT_FOP(readdir); + SET_DEFAULT_FOP(readdirp); + SET_DEFAULT_FOP(fsyncdir); + SET_DEFAULT_FOP(access); + SET_DEFAULT_FOP(ftruncate); + SET_DEFAULT_FOP(fstat); + SET_DEFAULT_FOP(lk); + SET_DEFAULT_FOP(inodelk); + SET_DEFAULT_FOP(finodelk); + SET_DEFAULT_FOP(entrylk); + SET_DEFAULT_FOP(fentrylk); + SET_DEFAULT_FOP(lookup); + SET_DEFAULT_FOP(rchecksum); + SET_DEFAULT_FOP(xattrop); + 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(ipc); + SET_DEFAULT_FOP(seek); + SET_DEFAULT_FOP(lease); + SET_DEFAULT_FOP(getactivelk); + SET_DEFAULT_FOP(setactivelk); + SET_DEFAULT_FOP(put); + + SET_DEFAULT_FOP(getspec); + SET_DEFAULT_FOP(icreate); + SET_DEFAULT_FOP(namelink); + SET_DEFAULT_FOP(copy_file_range); + + if (!xl->cbks) + xl->cbks = &default_cbks; + + SET_DEFAULT_CBK(release); + SET_DEFAULT_CBK(releasedir); + SET_DEFAULT_CBK(forget); + + if (!xl->fini) + xl->fini = default_fini; + + if (!xl->notify) + xl->notify = default_notify; + + if (!xl->mem_acct_init) + xl->mem_acct_init = default_mem_acct_init; + + return; } -/* RFC 1123 & 952 */ -static char -valid_host_name (char *address, int length) +int +xlator_set_type_virtual(xlator_t *xl, const char *type) { - int i = 0; - char ret = 1; + GF_VALIDATE_OR_GOTO("xlator", xl, out); + GF_VALIDATE_OR_GOTO("xlator", type, out); - if ((length > 75) || (length == 1)) { - ret = 0; - goto out; - } + xl->type = gf_strdup(type); + + if (xl->type) + return 0; - if (!isalnum (address[length - 1])) { - ret = 0; - goto out; +out: + return -1; +} + +int +xlator_volopt_dynload(char *xlator_type, void **dl_handle, + volume_opt_list_t *opt_list) +{ + int ret = -1; + int flag = 0; + char *name = NULL; + void *handle = NULL; + xlator_api_t *xlapi = NULL; + volume_option_t *opt = NULL; + + GF_VALIDATE_OR_GOTO("xlator", xlator_type, out); + + /* socket.so doesn't fall under the default xlator directory, hence we + * need this check */ + if (!strstr(xlator_type, "rpc-transport")) + ret = gf_asprintf(&name, "%s/%s.so", XLATORDIR, xlator_type); + else { + flag = 1; + ret = gf_asprintf(&name, "%s/%s.so", XLATORPARENTDIR, xlator_type); + } + if (-1 == ret) { + goto out; + } + + ret = -1; + + gf_msg_trace("xlator", 0, "attempt to load file %s", name); + + handle = dlopen(name, RTLD_NOW); + if (!handle) { + gf_smsg("xlator", GF_LOG_WARNING, 0, LG_MSG_DLOPEN_FAILED, "error=%s", + dlerror(), NULL); + goto out; + } + + if (flag == 0) { + /* check new struct first, and then check this */ + xlapi = dlsym(handle, "xlator_api"); + if (!xlapi) { + gf_smsg("xlator", GF_LOG_ERROR, 0, LG_MSG_DLSYM_ERROR, "error=%s", + dlerror(), NULL); + goto out; } - for (i = 0; i < length; i++) { - if (!isalnum (address[i]) && (address[i] != '.') - && (address[i] != '-')) { - ret = 0; - goto out; - } + opt_list->given_opt = xlapi->options; + if (!opt_list->given_opt) { + gf_smsg("xlator", GF_LOG_ERROR, 0, LG_MSG_LOAD_FAILED, NULL); + goto out; + } + } else { + opt = dlsym(handle, "options"); + if (!opt) { + gf_smsg("xlator", GF_LOG_ERROR, 0, LG_MSG_DLSYM_ERROR, "error=%s", + dlerror(), NULL); + goto out; } + opt_list->given_opt = opt; + } + + *dl_handle = handle; + handle = NULL; + + ret = 0; out: - return ret; + GF_FREE(name); + if (handle) + dlclose(handle); + + gf_msg_debug("xlator", 0, "Returning %d", ret); + return ret; } -static char -valid_ipv4_address (char *address, int length) +static int +xlator_dynload_apis(xlator_t *xl) { - int octets = 0; - int value = 0; - char *tmp = NULL, *ptr = NULL, *prev = NULL, *endptr = NULL; - char ret = 1; - - tmp = gf_strdup (address); - prev = tmp; - prev = strtok_r (tmp, ".", &ptr); - - while (prev != NULL) - { - octets++; - value = strtol (prev, &endptr, 10); - if ((value > 255) || (value < 0) || (endptr != NULL)) { - ret = 0; - goto out; - } - - prev = strtok_r (NULL, ".", &ptr); + int ret = -1; + void *handle = NULL; + volume_opt_list_t *vol_opt = NULL; + xlator_api_t *xlapi = NULL; + int i = 0; + + handle = xl->dlhandle; + + xlapi = dlsym(handle, "xlator_api"); + if (!xlapi) { + gf_smsg("xlator", GF_LOG_ERROR, 0, LG_MSG_DLSYM_ERROR, "dlsym=%s", + dlerror(), NULL); + ret = -1; + goto out; + } + + xl->fops = xlapi->fops; + if (!xl->fops) { + gf_smsg("xlator", GF_LOG_WARNING, 0, LG_MSG_STRUCT_MISS, "name=%s", + xl->name, NULL); + goto out; + } + + xl->cbks = xlapi->cbks; + if (!xl->cbks) { + gf_msg_trace("xlator", 0, "%s: struct missing (cbks)", xl->name); + } + + xl->init = xlapi->init; + if (!xl->init) { + gf_smsg("xlator", GF_LOG_WARNING, 0, LG_MSG_METHOD_MISS, "name=%s", + xl->name, NULL); + goto out; + } + + xl->fini = xlapi->fini; + if (!xl->fini) { + gf_msg_trace("xlator", 0, "%s: method missing (fini)", xl->name); + } + + xl->reconfigure = xlapi->reconfigure; + if (!xl->reconfigure) { + gf_msg_trace("xlator", 0, "%s: method missing (reconfigure)", xl->name); + } + xl->notify = xlapi->notify; + if (!xl->notify) { + gf_msg_trace("xlator", 0, "%s: method missing (notify)", xl->name); + } + xl->dumpops = xlapi->dumpops; + if (!xl->dumpops) { + gf_msg_trace("xlator", 0, "%s: method missing (dumpops)", xl->name); + } + xl->mem_acct_init = xlapi->mem_acct_init; + if (!xl->mem_acct_init) { + gf_msg_trace("xlator", 0, "%s: method missing (mem_acct_init)", + xl->name); + } + + xl->dump_metrics = xlapi->dump_metrics; + if (!xl->dump_metrics) { + gf_msg_trace("xlator", 0, "%s: method missing (dump_metrics)", + xl->name); + } + + xl->pass_through_fops = xlapi->pass_through_fops; + if (!xl->pass_through_fops) { + gf_msg_trace("xlator", 0, + "%s: method missing (pass_through_fops), " + "falling back to default", + xl->name); + } + + vol_opt = GF_CALLOC(1, sizeof(volume_opt_list_t), + gf_common_mt_volume_opt_list_t); + if (!vol_opt) { + goto out; + } + INIT_LIST_HEAD(&vol_opt->list); + + vol_opt->given_opt = default_options; + list_add_tail(&vol_opt->list, &xl->volume_options); + + if (xlapi->options) { + vol_opt = GF_CALLOC(1, sizeof(volume_opt_list_t), + gf_common_mt_volume_opt_list_t); + if (!vol_opt) { + goto out; } + INIT_LIST_HEAD(&vol_opt->list); - if (octets != 4) { - ret = 0; - } + vol_opt->given_opt = xlapi->options; + list_add_tail(&vol_opt->list, &xl->volume_options); + } + + xl->id = xlapi->xlator_id; + xl->flags = xlapi->flags; + xl->identifier = xlapi->identifier; + xl->category = xlapi->category; + memcpy(xl->op_version, xlapi->op_version, + sizeof(uint32_t) * GF_MAX_RELEASES); + + for (i = 0; i < GF_FOP_MAXVALUE; i++) { + gf_latency_reset(&xl->stats.interval.latencies[i]); + } + + ret = 0; out: - GF_FREE (tmp); - return ret; + return ret; } -static char -valid_ipv6_address (char *address, int length) +int +xlator_dynload(xlator_t *xl) { - int hex_numbers = 0; - int value = 0; - char *tmp = NULL, *ptr = NULL, *prev = NULL, *endptr = NULL; - char ret = 1; - - tmp = gf_strdup (address); - prev = strtok_r (tmp, ":", &ptr); - - while (prev != NULL) - { - hex_numbers++; - value = strtol (prev, &endptr, 16); - if ((value > 0xffff) || (value < 0) - || (endptr != NULL && *endptr != '\0')) { - ret = 0; - goto out; - } - - prev = strtok_r (NULL, ":", &ptr); - } - - if (hex_numbers > 8) { - ret = 0; + int ret = -1; + char *name = NULL; + void *handle = NULL; + + GF_VALIDATE_OR_GOTO("xlator", xl, out); + + INIT_LIST_HEAD(&xl->volume_options); + + ret = gf_asprintf(&name, "%s/%s.so", XLATORDIR, xl->type); + if (-1 == ret) { + goto out; + } + + ret = -1; + + gf_msg_trace("xlator", 0, "attempt to load file %s", name); + + handle = dlopen(name, RTLD_NOW); + if (!handle) { + gf_smsg("xlator", GF_LOG_WARNING, 0, LG_MSG_DLOPEN_FAILED, "error=%s", + dlerror(), NULL); + goto out; + } + xl->dlhandle = handle; + + ret = xlator_dynload_apis(xl); + if (-1 == ret) + goto out; + + fill_defaults(xl); + + ret = 0; + +out: + GF_FREE(name); + return ret; +} + +int +xlator_set_type(xlator_t *xl, const char *type) +{ + int ret = 0; + + /* Handle 'global' translator differently */ + if (!strncmp(GF_GLOBAL_XLATOR_NAME, type, SLEN(GF_GLOBAL_XLATOR_NAME))) { + volume_opt_list_t *vol_opt = NULL; + + /* set the required values from Global xlator */ + xl->type = gf_strdup(GF_GLOBAL_XLATOR_NAME); + xl->cbks = global_xlator.cbks; + xl->fops = global_xlator.fops; + xl->init = global_xlator.init; + xl->fini = global_xlator.fini; + xl->reconfigure = global_xlator.reconfigure; + + vol_opt = GF_CALLOC(1, sizeof(volume_opt_list_t), + gf_common_mt_volume_opt_list_t); + if (!vol_opt) { + ret = -1; + goto out; } + vol_opt->given_opt = global_xl_options; + + INIT_LIST_HEAD(&xl->volume_options); + INIT_LIST_HEAD(&vol_opt->list); + list_add_tail(&vol_opt->list, &xl->volume_options); + + fill_defaults(xl); + ret = 0; + goto out; + } + + ret = xlator_set_type_virtual(xl, type); + if (!ret) + ret = xlator_dynload(xl); out: - GF_FREE (tmp); - return ret; + return ret; } -static char -valid_internet_address (char *address) +void +xlator_set_inode_lru_limit(xlator_t *this, void *data) { - char ret = 0; - int length = 0; + int inode_lru_limit = 0; - if (address == NULL) { - goto out; + if (this->itable) { + if (!data) { + gf_smsg(this->name, GF_LOG_WARNING, 0, LG_MSG_INPUT_DATA_NULL, + NULL); + goto out; } + inode_lru_limit = *(int *)data; + inode_table_set_lru_limit(this->itable, inode_lru_limit); + } - length = strlen (address); - if (length == 0) { - goto out; - } +out: + return; +} - if (valid_ipv4_address (address, length) - || valid_ipv6_address (address, length) - || valid_host_name (address, length)) { - ret = 1; - } +void +xlator_foreach(xlator_t *this, void (*fn)(xlator_t *each, void *data), + void *data) +{ + xlator_t *first = NULL; + xlator_t *old_THIS = NULL; + + GF_VALIDATE_OR_GOTO("xlator", this, out); + GF_VALIDATE_OR_GOTO("xlator", fn, out); -out: - return ret; + first = this; + + while (first->prev) + first = first->prev; + + while (first) { + old_THIS = THIS; + THIS = first; + + fn(first, data); + + THIS = old_THIS; + first = first->next; + } + +out: + return; } -int -_volume_option_value_validate (xlator_t *xl, - data_pair_t *pair, - volume_option_t *opt) +void +xlator_foreach_depth_first(xlator_t *this, + void (*fn)(xlator_t *each, void *data), void *data) { - int i = 0; - int ret = -1; - uint64_t input_size = 0; - long long inputll = 0; - - /* Key is valid, validate the option */ - switch (opt->type) { - case GF_OPTION_TYPE_PATH: - { - if (strstr (pair->value->data, "../")) { - gf_log (xl->name, GF_LOG_ERROR, - "invalid path given '%s'", - pair->value->data); - ret = -1; - goto out; - } - - /* Make sure the given path is valid */ - if (pair->value->data[0] != '/') { - gf_log (xl->name, GF_LOG_WARNING, - "option %s %s: '%s' is not an " - "absolute path name", - pair->key, pair->value->data, - pair->value->data); - } - ret = 0; - } - break; - case GF_OPTION_TYPE_INT: - { - /* Check the range */ - if (gf_string2longlong (pair->value->data, - &inputll) != 0) { - gf_log (xl->name, GF_LOG_ERROR, - "invalid number format \"%s\" in " - "\"option %s\"", - pair->value->data, pair->key); - goto out; - } - - if ((opt->min == 0) && (opt->max == 0)) { - gf_log (xl->name, GF_LOG_DEBUG, - "no range check required for " - "'option %s %s'", - pair->key, pair->value->data); - ret = 0; - break; - } - if ((inputll < opt->min) || - (inputll > opt->max)) { - gf_log (xl->name, GF_LOG_WARNING, - "'%lld' in 'option %s %s' is out of " - "range [%"PRId64" - %"PRId64"]", - inputll, pair->key, - pair->value->data, - opt->min, opt->max); - } - ret = 0; - } - break; - case GF_OPTION_TYPE_SIZET: - { - /* Check the range */ - if (gf_string2bytesize (pair->value->data, - &input_size) != 0) { - gf_log (xl->name, GF_LOG_ERROR, - "invalid size format \"%s\" in " - "\"option %s\"", - pair->value->data, pair->key); - goto out; - } - - if ((opt->min == 0) && (opt->max == 0)) { - gf_log (xl->name, GF_LOG_DEBUG, - "no range check required for " - "'option %s %s'", - pair->key, pair->value->data); - ret = 0; - break; - } - if ((input_size < opt->min) || - (input_size > opt->max)) { - gf_log (xl->name, GF_LOG_ERROR, - "'%"PRId64"' in 'option %s %s' is " - "out of range [%"PRId64" - %"PRId64"]", - input_size, pair->key, - pair->value->data, - opt->min, opt->max); - } - ret = 0; - } - break; - case GF_OPTION_TYPE_BOOL: - { - /* Check if the value is one of - '0|1|on|off|no|yes|true|false|enable|disable' */ - gf_boolean_t bool_value; - if (gf_string2boolean (pair->value->data, - &bool_value) != 0) { - gf_log (xl->name, GF_LOG_ERROR, - "option %s %s: '%s' is not a valid " - "boolean value", - pair->key, pair->value->data, - pair->value->data); - goto out; - } - ret = 0; - } - break; - case GF_OPTION_TYPE_XLATOR: - { - /* Check if the value is one of the xlators */ - xlator_t *xlopt = xl; - while (xlopt->prev) - xlopt = xlopt->prev; - - while (xlopt) { - if (strcmp (pair->value->data, - xlopt->name) == 0) { - ret = 0; - break; - } - xlopt = xlopt->next; - } - if (!xlopt) { - gf_log (xl->name, GF_LOG_ERROR, - "option %s %s: '%s' is not a " - "valid volume name", - pair->key, pair->value->data, - pair->value->data); - } - ret = 0; - } - break; - case GF_OPTION_TYPE_STR: - { - /* Check if the '*str' is valid */ - if (GF_OPTION_LIST_EMPTY(opt)) { - ret = 0; - goto out; - } - - for (i = 0; (i < ZR_OPTION_MAX_ARRAY_SIZE) && - opt->value[i]; i++) { - if (fnmatch (opt->value[i], pair->value->data, - FNM_EXTMATCH) == 0) { - ret = 0; - break; - } - } - - if ((i == ZR_OPTION_MAX_ARRAY_SIZE) - || ((i < ZR_OPTION_MAX_ARRAY_SIZE) - && (!opt->value[i]))) { - /* enter here only if - * 1. reached end of opt->value array and haven't - * validated input - * OR - * 2. valid input list is less than - * ZR_OPTION_MAX_ARRAY_SIZE and input has not - * matched all possible input values. - */ - char given_array[4096] = {0,}; - for (i = 0; (i < ZR_OPTION_MAX_ARRAY_SIZE) && - opt->value[i]; i++) { - strcat (given_array, opt->value[i]); - strcat (given_array, ", "); - } - - gf_log (xl->name, GF_LOG_ERROR, - "option %s %s: '%s' is not valid " - "(possible options are %s)", - pair->key, pair->value->data, - pair->value->data, given_array); - - goto out; - } - } - break; - case GF_OPTION_TYPE_PERCENT: - { - uint32_t percent = 0; - - - /* Check if the value is valid percentage */ - if (gf_string2percent (pair->value->data, - &percent) != 0) { - gf_log (xl->name, GF_LOG_ERROR, - "invalid percent format \"%s\" " - "in \"option %s\"", - pair->value->data, pair->key); - goto out; - } - - if ((percent < 0) || (percent > 100)) { - gf_log (xl->name, GF_LOG_ERROR, - "'%d' in 'option %s %s' is out of " - "range [0 - 100]", - percent, pair->key, - pair->value->data); - } - ret = 0; - } - break; - case GF_OPTION_TYPE_PERCENT_OR_SIZET: - { - uint32_t percent = 0; - uint64_t input_size = 0; - - /* Check if the value is valid percentage */ - if (gf_string2percent (pair->value->data, - &percent) == 0) { - if (percent > 100) { - gf_log (xl->name, GF_LOG_DEBUG, - "value given was greater than 100, " - "assuming this is actually a size"); - if (gf_string2bytesize (pair->value->data, - &input_size) == 0) { - /* Check the range */ - if ((opt->min == 0) && - (opt->max == 0)) { - gf_log (xl->name, GF_LOG_DEBUG, - "no range check " - "required for " - "'option %s %s'", - pair->key, - pair->value->data); - // It is a size - ret = 0; - goto out; - } - if ((input_size < opt->min) || - (input_size > opt->max)) { - gf_log (xl->name, GF_LOG_ERROR, - "'%"PRId64"' in " - "'option %s %s' is out" - " of range [%"PRId64"" - "- %"PRId64"]", - input_size, pair->key, - pair->value->data, - opt->min, opt->max); - } - // It is a size - ret = 0; - goto out; - } else { - // It's not a percent or size - gf_log (xl->name, GF_LOG_ERROR, - "invalid number format \"%s\" " - "in \"option %s\"", - pair->value->data, pair->key); - } - - } - // It is a percent - ret = 0; - goto out; - } else { - if (gf_string2bytesize (pair->value->data, - &input_size) == 0) { - /* Check the range */ - if ((opt->min == 0) && (opt->max == 0)) { - gf_log (xl->name, GF_LOG_DEBUG, - "no range check required for " - "'option %s %s'", - pair->key, pair->value->data); - // It is a size - ret = 0; - goto out; - } - if ((input_size < opt->min) || - (input_size > opt->max)) { - gf_log (xl->name, GF_LOG_ERROR, - "'%"PRId64"' in 'option %s %s'" - " is out of range [%"PRId64" -" - " %"PRId64"]", - input_size, pair->key, - pair->value->data, - opt->min, opt->max); - } - } else { - // It's not a percent or size - gf_log (xl->name, GF_LOG_ERROR, - "invalid number format \"%s\" " - "in \"option %s\"", - pair->value->data, pair->key); - } - //It is a size - ret = 0; - goto out; - } - - } - break; - case GF_OPTION_TYPE_TIME: - { - uint32_t input_time = 0; - - /* Check if the value is valid percentage */ - if (gf_string2time (pair->value->data, - &input_time) != 0) { - gf_log (xl->name, - GF_LOG_ERROR, - "invalid time format \"%s\" in " - "\"option %s\"", - pair->value->data, pair->key); - goto out; - } - - if ((opt->min == 0) && (opt->max == 0)) { - gf_log (xl->name, GF_LOG_DEBUG, - "no range check required for " - "'option %s %s'", - pair->key, pair->value->data); - ret = 0; - goto out; - } - if ((input_time < opt->min) || - (input_time > opt->max)) { - gf_log (xl->name, GF_LOG_ERROR, - "'%"PRIu32"' in 'option %s %s' is " - "out of range [%"PRId64" - %"PRId64"]", - input_time, pair->key, - pair->value->data, - opt->min, opt->max); - } - ret = 0; - } - break; - case GF_OPTION_TYPE_DOUBLE: - { - double input_time = 0.0; - - /* Check if the value is valid double */ - if (gf_string2double (pair->value->data, - &input_time) != 0) { - gf_log (xl->name, - GF_LOG_ERROR, - "invalid time format \"%s\" in \"option %s\"", - pair->value->data, pair->key); - goto out; - } - - if (input_time < 0.0) { - gf_log (xl->name, - GF_LOG_ERROR, - "invalid time format \"%s\" in \"option %s\"", - pair->value->data, pair->key); - goto out; - } - - if ((opt->min == 0) && (opt->max == 0)) { - gf_log (xl->name, GF_LOG_DEBUG, - "no range check required for 'option %s %s'", - pair->key, pair->value->data); - ret = 0; - goto out; - } - ret = 0; - } - break; - case GF_OPTION_TYPE_INTERNET_ADDRESS: - { - if (valid_internet_address (pair->value->data)) { - ret = 0; - } else { - gf_log (xl->name, GF_LOG_ERROR, "internet address '%s'" - " does not conform to standards.", - pair->value->data); - goto out; - } - } - break; - case GF_OPTION_TYPE_ANY: - /* NO CHECK */ - ret = 0; - break; - } - + xlator_list_t *subv = NULL; + + subv = this->children; + + while (subv) { + xlator_foreach_depth_first(subv->xlator, fn, data); + subv = subv->next; + } + + fn(this, data); +} + +xlator_t * +xlator_search_by_name(xlator_t *any, const char *name) +{ + xlator_t *search = NULL; + + GF_VALIDATE_OR_GOTO("xlator", any, out); + GF_VALIDATE_OR_GOTO("xlator", name, out); + + search = any; + + while (search->prev) + search = search->prev; + + while (search) { + if (!strcmp(search->name, name)) + break; + search = search->next; + } + out: - return ret; + return search; +} + +/* + * With brick multiplexing, we sort of have multiple graphs, so + * xlator_search_by_name might not find what we want. Also, the translator + * we're looking for might not be a direct child if something else was put in + * between (as already happened with decompounder before that was fixed) and + * it's hard to debug why our translator wasn't found. Using a recursive tree + * search instead of a linear search works around both problems. + */ +static xlator_t * +get_xlator_by_name_or_type(xlator_t *this, char *target, int is_name) +{ + xlator_list_t *trav; + xlator_t *child_xl; + char *value; + + for (trav = this->children; trav; trav = trav->next) { + value = is_name ? trav->xlator->name : trav->xlator->type; + if (!strcmp(value, target) && !trav->xlator->cleanup_starting) { + return trav->xlator; + } + child_xl = get_xlator_by_name_or_type(trav->xlator, target, is_name); + if (child_xl) { + /* + * If the xlator we're looking for is somewhere down + * the stack, get_xlator_by_name expects to get a + * pointer to the top of its subtree (child of "this") + * while get_xlator_by_type expects a pointer to what + * we actually found. Handle both cases here. + * + * TBD: rename the functions and fix callers to better + * reflect the difference in semantics. + */ + return is_name ? trav->xlator : child_xl; + } + } + + return NULL; +} + +xlator_t * +get_xlator_by_name(xlator_t *this, char *target) +{ + return get_xlator_by_name_or_type(this, target, 1); +} + +xlator_t * +get_xlator_by_type(xlator_t *this, char *target) +{ + return get_xlator_by_name_or_type(this, target, 0); +} + +static int +__xlator_init(xlator_t *xl) +{ + xlator_t *old_THIS = NULL; + int ret = 0; + int fop_idx = 0; + + old_THIS = THIS; + THIS = xl; + + /* initialize the metrics related locks */ + for (fop_idx = 0; fop_idx < GF_FOP_MAXVALUE; fop_idx++) { + GF_ATOMIC_INIT(xl->stats.total.metrics[fop_idx].fop, 0); + GF_ATOMIC_INIT(xl->stats.total.metrics[fop_idx].cbk, 0); + + GF_ATOMIC_INIT(xl->stats.interval.metrics[fop_idx].fop, 0); + GF_ATOMIC_INIT(xl->stats.interval.metrics[fop_idx].cbk, 0); + } + GF_ATOMIC_INIT(xl->stats.total.count, 0); + GF_ATOMIC_INIT(xl->stats.interval.count, 0); + + xlator_init_lock(); + handle_default_options(xl, xl->options); + ret = xl->init(xl); + xlator_init_unlock(); + + THIS = old_THIS; + + return ret; } int -validate_xlator_volume_options (xlator_t *xl, volume_option_t *opt) +xlator_init(xlator_t *xl) { - int i = 0; - int ret = -1; - int index = 0; - volume_option_t *trav = NULL; - data_pair_t *pairs = NULL; - - if (!opt) { - ret = 0; - goto out; - } - - /* First search for not supported options, if any report error */ - pairs = xl->options->members_list; - while (pairs) { - ret = -1; - for (index = 0; - opt[index].key && opt[index].key[0] ; index++) { - trav = &(opt[index]); - for (i = 0 ; - (i < ZR_VOLUME_MAX_NUM_KEY) && - trav->key[i]; i++) { - /* Check if the key is valid */ - if (fnmatch (trav->key[i], - pairs->key, FNM_NOESCAPE) == 0) { - ret = 0; - break; - } - } - if (!ret) { - if (i) { - gf_log (xl->name, GF_LOG_WARNING, - "option '%s' is deprecated, " - "preferred is '%s', continuing" - " with correction", - trav->key[i], trav->key[0]); - /* TODO: some bytes lost */ - pairs->key = gf_strdup (trav->key[0]); - } - break; - } - } - if (!ret) { - ret = _volume_option_value_validate (xl, pairs, trav); - if (-1 == ret) { - goto out; - } - } - - pairs = pairs->next; - } - - ret = 0; - out: - return ret; + int32_t ret = -1; + + GF_VALIDATE_OR_GOTO("xlator", xl, out); + + if (xl->mem_acct_init) + xl->mem_acct_init(xl); + + xl->instance_name = NULL; + GF_ATOMIC_INIT(xl->xprtrefcnt, 0); + if (!xl->init) { + gf_smsg(xl->name, GF_LOG_WARNING, 0, LG_MSG_INIT_FAILED, NULL); + goto out; + } + + ret = __xlator_init(xl); + + if (ret) { + gf_smsg(xl->name, GF_LOG_ERROR, 0, LG_MSG_VOLUME_ERROR, "name=%s", + xl->name, NULL); + goto out; + } + + xl->init_succeeded = 1; + /*xl->cleanup_starting = 0; + xl->call_cleanup = 0; + */ + ret = 0; +out: + return ret; } -int32_t -xlator_set_type (xlator_t *xl, - const char *type) +static void +xlator_fini_rec(xlator_t *xl) { - int ret = 0; - char *name = NULL; - void *handle = NULL; - volume_opt_list_t *vol_opt = NULL; - - if (xl == NULL || type == NULL) { - gf_log ("xlator", GF_LOG_DEBUG, "invalid argument"); - return -1; - } - - xl->type = gf_strdup (type); - - ret = gf_asprintf (&name, "%s/%s.so", XLATORDIR, type); - if (-1 == ret) { - gf_log ("xlator", GF_LOG_ERROR, "asprintf failed"); - return -1; + xlator_list_t *trav = NULL; + xlator_t *old_THIS = NULL; + + GF_VALIDATE_OR_GOTO("xlator", xl, out); + + trav = xl->children; + + while (trav) { + if (!trav->xlator->init_succeeded) { + break; } - gf_log ("xlator", GF_LOG_TRACE, "attempt to load file %s", name); - - handle = dlopen (name, RTLD_NOW|RTLD_GLOBAL); - if (!handle) { - gf_log ("xlator", GF_LOG_DEBUG, "%s", dlerror ()); - GF_FREE (name); - return -1; - } - xl->dlhandle = handle; - - if (!(xl->fops = dlsym (handle, "fops"))) { - gf_log ("xlator", GF_LOG_DEBUG, "dlsym(fops) on %s", - dlerror ()); - GF_FREE (name); - return -1; - } - - if (!(xl->cbks = dlsym (handle, "cbks"))) { - gf_log ("xlator", GF_LOG_DEBUG, "dlsym(cbks) on %s", - dlerror ()); - GF_FREE (name); - return -1; - } - - if (!(xl->init = dlsym (handle, "init"))) { - gf_log ("xlator", GF_LOG_DEBUG, "dlsym(init) on %s", - dlerror ()); - GF_FREE (name); - return -1; - } - - if (!(xl->fini = dlsym (handle, "fini"))) { - gf_log ("xlator", GF_LOG_DEBUG, "dlsym(fini) on %s", - dlerror ()); - GF_FREE (name); - return -1; - } - - if (!(xl->notify = dlsym (handle, "notify"))) { - gf_log ("xlator", GF_LOG_DEBUG, - "dlsym(notify) on %s -- neglecting", dlerror ()); - } - - if (!(xl->dumpops = dlsym (handle, "dumpops"))) { - gf_log ("xlator", GF_LOG_DEBUG, - "dlsym(dumpops) on %s -- neglecting", dlerror ()); - } - - if (!(xl->mem_acct_init = dlsym (handle, "mem_acct_init"))) { - gf_log (xl->name, GF_LOG_DEBUG, - "dlsym(mem_acct_init) on %s -- neglecting", - dlerror ()); + xlator_fini_rec(trav->xlator); + gf_msg_debug(trav->xlator->name, 0, "fini done"); + trav = trav->next; + } + + xl->cleanup_starting = 1; + if (xl->init_succeeded) { + if (xl->fini) { + old_THIS = THIS; + THIS = xl; + + xl->fini(xl); + + if (xl->local_pool) { + mem_pool_destroy(xl->local_pool); + xl->local_pool = NULL; + } + if (xl->itable) { + inode_table_destroy(xl->itable); + xl->itable = NULL; + } + + THIS = old_THIS; + } else { + gf_msg_debug(xl->name, 0, "No fini() found"); } + xl->init_succeeded = 0; + } - INIT_LIST_HEAD (&xl->volume_options); +out: + return; +} - vol_opt = GF_CALLOC (1, sizeof (volume_opt_list_t), - gf_common_mt_volume_opt_list_t); +int +xlator_notify(xlator_t *xl, int event, void *data, ...) +{ + xlator_t *old_THIS = NULL; + int ret = 0; - if (!vol_opt) { - GF_FREE (name); - return -1; - } + old_THIS = THIS; + THIS = xl; - if (!(vol_opt->given_opt = dlsym (handle, "options"))) { - dlerror (); - gf_log (xl->name, GF_LOG_DEBUG, - "Strict option validation not enforced -- neglecting"); - } - list_add_tail (&vol_opt->list, &xl->volume_options); + ret = xl->notify(xl, event, data); - fill_defaults (xl); + THIS = old_THIS; - GF_FREE (name); - return 0; + return ret; } +int +xlator_mem_acct_init(xlator_t *xl, int num_types) +{ + int i = 0; + int ret = 0; + + if (!xl) + return -1; + + if (!xl->ctx) + return -1; + + if (!xl->ctx->mem_acct_enable) + return 0; + + xl->mem_acct = MALLOC(sizeof(struct mem_acct) + + sizeof(struct mem_acct_rec) * num_types); + + if (!xl->mem_acct) { + return -1; + } + + xl->mem_acct->num_types = num_types; + GF_ATOMIC_INIT(xl->mem_acct->refcnt, 1); + + for (i = 0; i < num_types; i++) { + memset(&xl->mem_acct->rec[i], 0, sizeof(struct mem_acct_rec)); + ret = LOCK_INIT(&(xl->mem_acct->rec[i].lock)); + if (ret) { + fprintf(stderr, "Unable to lock..errno : %d", errno); + } +#ifdef DEBUG + INIT_LIST_HEAD(&(xl->mem_acct->rec[i].obj_list)); +#endif + } + + return 0; +} + +void +xlator_mem_acct_unref(struct mem_acct *mem_acct) +{ + uint32_t i; + + if (GF_ATOMIC_DEC(mem_acct->refcnt) == 0) { + for (i = 0; i < mem_acct->num_types; i++) { + LOCK_DESTROY(&(mem_acct->rec[i].lock)); + } + FREE(mem_acct); + } +} void -xlator_foreach (xlator_t *this, - void (*fn)(xlator_t *each, - void *data), - void *data) +xlator_tree_fini(xlator_t *xl) { - xlator_t *first = NULL; + xlator_t *top = NULL; + + GF_VALIDATE_OR_GOTO("xlator", xl, out); + + top = xl; + xlator_fini_rec(top); - if (this == NULL || fn == NULL || data == NULL) { - gf_log ("xlator", GF_LOG_DEBUG, "invalid argument"); - return; - } +out: + return; +} - first = this; +int +xlator_list_destroy(xlator_list_t *list) +{ + xlator_list_t *next = NULL; - while (first->prev) - first = first->prev; + while (list) { + next = list->next; + GF_FREE(list); + list = next; + } - while (first) { - fn (first, data); - first = first->next; - } + return 0; } +int +xlator_memrec_free(xlator_t *xl) +{ + struct mem_acct *mem_acct = NULL; -xlator_t * -xlator_search_by_name (xlator_t *any, const char *name) + if (!xl) { + return 0; + } + mem_acct = xl->mem_acct; + + if (mem_acct) { + xlator_mem_acct_unref(mem_acct); + xl->mem_acct = NULL; + } + + return 0; +} + +static int +xlator_members_free(xlator_t *xl) { - xlator_t *search = NULL; + volume_opt_list_t *vol_opt = NULL; + volume_opt_list_t *tmp = NULL; + + if (!xl) + return 0; - if (any == NULL || name == NULL) { - gf_log ("xlator", GF_LOG_DEBUG, "invalid argument"); - return NULL; - } + GF_FREE(xl->name); + GF_FREE(xl->type); + if (!(xl->ctx && xl->ctx->cmd_args.vgtool != _gf_none) && xl->dlhandle) + dlclose(xl->dlhandle); + if (xl->options) + dict_unref(xl->options); - search = any; + xlator_list_destroy(xl->children); - while (search->prev) - search = search->prev; + xlator_list_destroy(xl->parents); - while (search) { - if (!strcmp (search->name, name)) - break; - search = search->next; - } + list_for_each_entry_safe(vol_opt, tmp, &xl->volume_options, list) + { + list_del_init(&vol_opt->list); + GF_FREE(vol_opt); + } - return search; + return 0; } +/* This function destroys all the xlator members except for the + * xlator strcuture and its mem accounting field. + * + * If otherwise, it would destroy the master xlator object as well + * its mem accounting, which would mean after calling glusterfs_graph_destroy() + * there cannot be any reference to GF_FREE() from the master xlator, this is + * not possible because of the following dependencies: + * - glusterfs_ctx_t will have mem pools allocated by the master xlators + * - xlator objects will have references to those mem pools(g: dict) + * + * Ordering the freeing in any of the order will also not solve the dependency: + * - Freeing xlator objects(including memory accounting) before mem pools + * destruction will mean not use GF_FREE while destroying mem pools. + * - Freeing mem pools and then destroying xlator objects would lead to crashes + * when xlator tries to unref dict or other mem pool objects. + * + * Hence the way chosen out of this interdependency is to split xlator object + * free into two stages: + * - Free all the xlator members excpet for its mem accounting structure + * - Free all the mem accouting structures of xlator along with the xlator + * object itself. + * + * This two stages of destruction, is mainly required for glfs_fini(). + */ + +int +xlator_tree_free_members(xlator_t *tree) +{ + xlator_t *trav = tree; + xlator_t *prev = tree; + + if (!tree) { + gf_smsg("parser", GF_LOG_ERROR, 0, LG_MSG_TREE_NOT_FOUND, NULL); + return -1; + } + + while (prev) { + trav = prev->next; + xlator_members_free(prev); + prev = trav; + } + + return 0; +} + +int +xlator_tree_free_memacct(xlator_t *tree) +{ + xlator_t *trav = tree; + xlator_t *prev = tree; + + if (!tree) { + gf_smsg("parser", GF_LOG_ERROR, 0, LG_MSG_TREE_NOT_FOUND, NULL); + return -1; + } + + while (prev) { + trav = prev->next; + xlator_memrec_free(prev); + GF_FREE(prev); + prev = trav; + } + + return 0; +} static int -__xlator_init(xlator_t *xl) +xlator_mem_free(xlator_t *xl) { - xlator_t *old_THIS = NULL; - int ret = 0; + volume_opt_list_t *vol_opt = NULL; + volume_opt_list_t *tmp = NULL; - old_THIS = THIS; - THIS = xl; + if (!xl) + return 0; - ret = xl->init (xl); + if (xl->options) { + dict_unref(xl->options); + xl->options = NULL; + } - THIS = old_THIS; + list_for_each_entry_safe(vol_opt, tmp, &xl->volume_options, list) + { + list_del_init(&vol_opt->list); + GF_FREE(vol_opt); + } + + xlator_memrec_free(xl); - return ret; + return 0; } +static void +xlator_call_fini(xlator_t *this) +{ + if (!this || this->call_cleanup) + return; + this->cleanup_starting = 1; + this->call_cleanup = 1; + xlator_call_fini(this->next); + this->fini(this); +} + +void +xlator_mem_cleanup(xlator_t *this) +{ + xlator_list_t *list = this->children; + xlator_t *trav = list->xlator; + inode_table_t *inode_table = NULL; + xlator_t *prev = trav; + glusterfs_ctx_t *ctx = NULL; + xlator_list_t **trav_p = NULL; + xlator_t *top = NULL; + xlator_t *victim = NULL; + glusterfs_graph_t *graph = NULL; + gf_boolean_t graph_cleanup = _gf_false; + + if (this->call_cleanup || !this->ctx) + return; + + this->call_cleanup = 1; + ctx = this->ctx; + + inode_table = this->itable; + if (inode_table) { + inode_table_destroy(inode_table); + this->itable = NULL; + } + + xlator_call_fini(trav); + + while (prev) { + trav = prev->next; + xlator_mem_free(prev); + prev = trav; + } + + if (this->fini) { + this->fini(this); + } + + xlator_mem_free(this); + + if (ctx->active) { + top = ctx->active->first; + LOCK(&ctx->volfile_lock); + for (trav_p = &top->children; *trav_p; trav_p = &(*trav_p)->next) { + victim = (*trav_p)->xlator; + if (victim->call_cleanup && !strcmp(victim->name, this->name)) { + graph_cleanup = _gf_true; + (*trav_p) = (*trav_p)->next; + break; + } + } + UNLOCK(&ctx->volfile_lock); + } + + if (graph_cleanup) { + prev = this; + graph = ctx->active; + pthread_mutex_lock(&graph->mutex); + while (prev) { + trav = prev->next; + GF_FREE(prev); + prev = trav; + } + pthread_mutex_unlock(&graph->mutex); + } +} + +void +loc_wipe(loc_t *loc) +{ + if (loc->inode) { + inode_unref(loc->inode); + loc->inode = NULL; + } + if (loc->path) { + GF_FREE((char *)loc->path); + loc->path = NULL; + } + + if (loc->parent) { + inode_unref(loc->parent); + loc->parent = NULL; + } + + memset(loc, 0, sizeof(*loc)); +} int -xlator_init (xlator_t *xl) +loc_path(loc_t *loc, const char *bname) { - int32_t ret = 0; + int ret = 0; - if (xl == NULL) { - gf_log ("xlator", GF_LOG_DEBUG, "invalid argument"); - return 0; - } + if (loc->path) + goto out; - ret = -1; + ret = -1; - if (xl->mem_acct_init) - xl->mem_acct_init (xl); + if (bname && !strlen(bname)) + bname = NULL; - if (!xl->init) { - gf_log (xl->name, GF_LOG_DEBUG, "No init() found"); - goto out; - } + if (!bname) + goto inode_path; - ret = __xlator_init (xl); + if (loc->parent && !gf_uuid_is_null(loc->parent->gfid)) { + ret = inode_path(loc->parent, bname, (char **)&loc->path); + } else if (!gf_uuid_is_null(loc->pargfid)) { + ret = gf_asprintf((char **)&loc->path, INODE_PATH_FMT "/%s", + uuid_utoa(loc->pargfid), bname); + } - if (ret) { - gf_log (xl->name, GF_LOG_ERROR, - "Initialization of volume '%s' failed," - " review your volfile again", - xl->name); - goto out; - } + if (loc->path) + goto out; - xl->init_succeeded = 1; +inode_path: + if (loc->inode && !gf_uuid_is_null(loc->inode->gfid)) { + ret = inode_path(loc->inode, NULL, (char **)&loc->path); + } else if (!gf_uuid_is_null(loc->gfid)) { + ret = gf_asprintf((char **)&loc->path, INODE_PATH_FMT, + uuid_utoa(loc->gfid)); + } +out: + return ret; +} - ret = 0; +void +loc_gfid(loc_t *loc, uuid_t gfid) +{ + if (!gfid) + goto out; + gf_uuid_clear(gfid); + + if (!loc) + goto out; + else if (!gf_uuid_is_null(loc->gfid)) + gf_uuid_copy(gfid, loc->gfid); + else if (loc->inode && (!gf_uuid_is_null(loc->inode->gfid))) + gf_uuid_copy(gfid, loc->inode->gfid); out: - return ret; + return; } +void +loc_pargfid(loc_t *loc, uuid_t gfid) +{ + if (!gfid) + goto out; + gf_uuid_clear(gfid); + + if (!loc) + goto out; + else if (!gf_uuid_is_null(loc->pargfid)) + gf_uuid_copy(gfid, loc->pargfid); + else if (loc->parent && (!gf_uuid_is_null(loc->parent->gfid))) + gf_uuid_copy(gfid, loc->parent->gfid); +out: + return; +} -static void -xlator_fini_rec (xlator_t *xl) +char * +loc_gfid_utoa(loc_t *loc) { - xlator_list_t *trav = NULL; - - if (xl == NULL) { - gf_log ("xlator", GF_LOG_DEBUG, "invalid argument"); - return; - } - - trav = xl->children; - - while (trav) { - if (!trav->xlator->init_succeeded) { - break; - } - - xlator_fini_rec (trav->xlator); - gf_log (trav->xlator->name, GF_LOG_DEBUG, "fini done"); - trav = trav->next; - } - - if (xl->init_succeeded) { - if (xl->fini) { - xl->fini (xl); - } else { - gf_log (xl->name, GF_LOG_DEBUG, "No fini() found"); - } - xl->init_succeeded = 0; - } + uuid_t gfid = { + 0, + }; + loc_gfid(loc, gfid); + return uuid_utoa(gfid); } +int +loc_touchup(loc_t *loc, const char *name) +{ + char *path = NULL; + int ret = 0; + + if (loc->path) + goto out; + + if (loc->parent && name && strlen(name)) { + ret = inode_path(loc->parent, name, &path); + if (path) /*Guaranteed to have trailing '/' */ + loc->name = strrchr(path, '/') + 1; + + if (gf_uuid_is_null(loc->pargfid)) + gf_uuid_copy(loc->pargfid, loc->parent->gfid); + } else if (loc->inode) { + ret = inode_path(loc->inode, 0, &path); + if (gf_uuid_is_null(loc->gfid)) + gf_uuid_copy(loc->gfid, loc->inode->gfid); + } + + if (ret < 0 || !path) { + ret = -ENOMEM; + goto out; + } + + loc->path = path; + ret = 0; +out: + return ret; +} int -xlator_notify (xlator_t *xl, int event, void *data, ...) +loc_copy_overload_parent(loc_t *dst, loc_t *src, inode_t *parent) { - xlator_t *old_THIS = NULL; - int ret = 0; + int ret = -1; - old_THIS = THIS; - THIS = xl; + GF_VALIDATE_OR_GOTO("xlator", dst, err); + GF_VALIDATE_OR_GOTO("xlator", src, err); + GF_VALIDATE_OR_GOTO("xlator", parent, err); - ret = xl->notify (xl, event, data); + gf_uuid_copy(dst->gfid, src->gfid); + gf_uuid_copy(dst->pargfid, parent->gfid); - THIS = old_THIS; + if (src->inode) + dst->inode = inode_ref(src->inode); - return ret; -} + if (parent) + dst->parent = inode_ref(parent); + + if (src->path) { + dst->path = gf_strdup(src->path); + if (!dst->path) + goto out; + + if (src->name) + dst->name = strrchr(dst->path, '/'); + if (dst->name) + dst->name++; + } else if (src->name) { + dst->name = src->name; + } + + ret = 0; +out: + if (ret == -1) + loc_wipe(dst); + +err: + return ret; +} int -xlator_mem_acct_init (xlator_t *xl, int num_types) +loc_copy(loc_t *dst, loc_t *src) { - int i = 0; - int ret = 0; + int ret = -1; - if (!gf_mem_acct_is_enabled()) - return 0; + GF_VALIDATE_OR_GOTO("xlator", dst, err); + GF_VALIDATE_OR_GOTO("xlator", src, err); - if (!xl) - return -1; + if (!gf_uuid_is_null(src->gfid)) + gf_uuid_copy(dst->gfid, src->gfid); + else if (src->inode && !gf_uuid_is_null(src->inode->gfid)) + gf_uuid_copy(dst->gfid, src->inode->gfid); - xl->mem_acct.num_types = num_types; + gf_uuid_copy(dst->pargfid, src->pargfid); - xl->mem_acct.rec = calloc(num_types, sizeof(struct mem_acct_rec)); + if (src->inode) + dst->inode = inode_ref(src->inode); - if (!xl->mem_acct.rec) { - gf_log("xlator", GF_LOG_ERROR, "Out of Memory"); - return -1; - } + if (src->parent) + dst->parent = inode_ref(src->parent); - for (i = 0; i < num_types; i++) { - ret = LOCK_INIT(&(xl->mem_acct.rec[i].lock)); - if (ret) { - fprintf(stderr, "Unable to lock..errno : %d",errno); - } - } + if (src->path) { + dst->path = gf_strdup(src->path); - gf_log(xl->name, GF_LOG_DEBUG, "Allocated mem_acct_rec for %d types", - num_types); + if (!dst->path) + goto out; - return 0; + if (src->name) + dst->name = strrchr(dst->path, '/'); + if (dst->name) + dst->name++; + } else if (src->name) { + dst->name = src->name; + } + + ret = 0; +out: + if (ret == -1) + loc_wipe(dst); + +err: + return ret; } -void -xlator_tree_fini (xlator_t *xl) +gf_boolean_t +loc_is_root(loc_t *loc) { - xlator_t *top = NULL; + 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 _gf_false; +} + +int32_t +loc_build_child(loc_t *child, loc_t *parent, char *name) +{ + int32_t ret = -1; + + GF_VALIDATE_OR_GOTO("xlator", child, out); + GF_VALIDATE_OR_GOTO("xlator", parent, out); + GF_VALIDATE_OR_GOTO("xlator", name, out); + + loc_gfid(parent, child->pargfid); + + if (strcmp(parent->path, "/") == 0) + ret = gf_asprintf((char **)&child->path, "/%s", name); + else + ret = gf_asprintf((char **)&child->path, "%s/%s", parent->path, name); + + if (ret < 0 || !child->path) { + ret = -1; + goto out; + } + + child->name = strrchr(child->path, '/') + 1; - if (xl == NULL) { - gf_log ("xlator", GF_LOG_DEBUG, "invalid argument"); - return; - } + child->parent = inode_ref(parent->inode); + child->inode = inode_new(parent->inode->table); - top = xl; - xlator_fini_rec (top); + if (!child->inode) { + ret = -1; + goto out; + } + + ret = 0; + +out: + if ((ret < 0) && child) + loc_wipe(child); + + return ret; } +gf_boolean_t +loc_is_nameless(loc_t *loc) +{ + gf_boolean_t ret = _gf_false; + + GF_VALIDATE_OR_GOTO("xlator", loc, out); + + if ((!loc->parent && gf_uuid_is_null(loc->pargfid)) || !loc->name) + ret = _gf_true; +out: + return ret; +} int -xlator_tree_free (xlator_t *tree) +xlator_destroy(xlator_t *xl) { - xlator_t *trav = tree, *prev = tree; + if (!xl) + return 0; - if (!tree) { - gf_log ("parser", GF_LOG_ERROR, "Translator tree not found"); - return -1; - } - - while (prev) { - trav = prev->next; - dict_destroy (prev->options); - GF_FREE (prev->name); - GF_FREE (prev->type); - GF_FREE (prev); - prev = trav; - } - - return 0; + xlator_members_free(xl); + xlator_memrec_free(xl); + GF_FREE(xl); + + return 0; } +static int32_t +gf_bin_to_string(char *dst, size_t size, void *src, size_t len) +{ + if (len >= size) { + return EINVAL; + } -void -loc_wipe (loc_t *loc) + memcpy(dst, src, len); + dst[len] = 0; + + return 0; +} + +int +is_gf_log_command(xlator_t *this, const char *name, char *value, size_t size) { - if (loc->inode) { - inode_unref (loc->inode); - loc->inode = NULL; + xlator_t *trav = NULL; + char key[1024] = { + 0, + }; + int ret = -1; + int log_level = -1; + gf_boolean_t syslog_flag = 0; + glusterfs_ctx_t *ctx = NULL; + + if (!strcmp("trusted.glusterfs.syslog", name)) { + ret = gf_bin_to_string(key, sizeof(key), value, size); + if (ret != 0) { + goto out; } - if (loc->path) { - GF_FREE ((char *)loc->path); - loc->path = NULL; + ret = gf_string2boolean(key, &syslog_flag); + if (ret) { + ret = EOPNOTSUPP; + goto out; } - - if (loc->parent) { - inode_unref (loc->parent); - loc->parent = NULL; + if (syslog_flag) + gf_log_enable_syslog(); + else + gf_log_disable_syslog(); + + goto out; + } + + if (fnmatch("trusted.glusterfs*set-log-level", name, FNM_NOESCAPE)) + goto out; + + ret = gf_bin_to_string(key, sizeof(key), value, size); + if (ret != 0) { + goto out; + } + + log_level = glusterd_check_log_level(key); + if (log_level == -1) { + ret = EOPNOTSUPP; + goto out; + } + + /* Some crude way to change the log-level of process */ + if (!strcmp(name, "trusted.glusterfs.set-log-level")) { + gf_smsg("glusterfs", gf_log_get_loglevel(), 0, LG_MSG_SET_LOG_LEVEL, + "new-value=%d", log_level, "old-value=%d", + gf_log_get_loglevel(), NULL); + gf_log_set_loglevel(this->ctx, log_level); + ret = 0; + goto out; + } + + if (!strcmp(name, "trusted.glusterfs.fuse.set-log-level")) { + /* */ + gf_smsg(this->name, gf_log_get_xl_loglevel(this), 0, + LG_MSG_SET_LOG_LEVEL, "new-value=%d", log_level, "old-value=%d", + gf_log_get_xl_loglevel(this), NULL); + gf_log_set_xl_loglevel(this, log_level); + ret = 0; + goto out; + } + + ctx = this->ctx; + if (!ctx) + goto out; + if (!ctx->active) + goto out; + trav = ctx->active->top; + + while (trav) { + snprintf(key, 1024, "trusted.glusterfs.%s.set-log-level", trav->name); + if (fnmatch(name, key, FNM_NOESCAPE) == 0) { + gf_smsg(trav->name, gf_log_get_xl_loglevel(trav), 0, + LG_MSG_SET_LOG_LEVEL, "new-value%d", log_level, + "old-value=%d", gf_log_get_xl_loglevel(trav), NULL); + gf_log_set_xl_loglevel(trav, log_level); + ret = 0; } + trav = trav->next; + } +out: + return ret; } - int -loc_copy (loc_t *dst, loc_t *src) +glusterd_check_log_level(const char *value) { - int ret = -1; - - dst->ino = src->ino; - - if (src->inode) - dst->inode = inode_ref (src->inode); + int log_level = -1; + + if (!strcasecmp(value, "CRITICAL")) { + log_level = GF_LOG_CRITICAL; + } else if (!strcasecmp(value, "ERROR")) { + log_level = GF_LOG_ERROR; + } else if (!strcasecmp(value, "WARNING")) { + log_level = GF_LOG_WARNING; + } else if (!strcasecmp(value, "INFO")) { + log_level = GF_LOG_INFO; + } else if (!strcasecmp(value, "DEBUG")) { + log_level = GF_LOG_DEBUG; + } else if (!strcasecmp(value, "TRACE")) { + log_level = GF_LOG_TRACE; + } else if (!strcasecmp(value, "NONE")) { + log_level = GF_LOG_NONE; + } + + if (log_level == -1) + gf_smsg(THIS->name, GF_LOG_ERROR, 0, LG_MSG_INVALID_INIT, NULL); + + return log_level; +} - if (src->parent) - dst->parent = inode_ref (src->parent); +int +xlator_subvolume_count(xlator_t *this) +{ + int i = 0; + xlator_list_t *list = NULL; - dst->path = gf_strdup (src->path); + for (list = this->children; list; list = list->next) + i++; + return i; +} - if (!dst->path) - goto out; +static int +_copy_opt_to_child(dict_t *options, char *key, data_t *value, void *data) +{ + xlator_t *child = data; - dst->name = strrchr (dst->path, '/'); - if (dst->name) - dst->name++; + gf_log(__func__, GF_LOG_DEBUG, "copying %s to child %s", key, child->name); + dict_set(child->options, key, value); - ret = 0; -out: - return ret; + return 0; } - int -xlator_list_destroy (xlator_list_t *list) +copy_opts_to_child(xlator_t *src, xlator_t *dst, char *glob) { - xlator_list_t *next = NULL; + return dict_foreach_fnmatch(src->options, glob, _copy_opt_to_child, dst); +} - while (list) { - next = list->next; - GF_FREE (list); - list = next; +int +glusterfs_delete_volfile_checksum(glusterfs_ctx_t *ctx, const char *volfile_id) +{ + gf_volfile_t *volfile_tmp = NULL; + gf_volfile_t *volfile_obj = NULL; + + list_for_each_entry(volfile_tmp, &ctx->volfile_list, volfile_list) + { + if (!strcmp(volfile_id, volfile_tmp->vol_id)) { + list_del_init(&volfile_tmp->volfile_list); + volfile_obj = volfile_tmp; + break; } - - return 0; + } + + if (volfile_obj) { + GF_FREE(volfile_obj); + } else { + gf_log(THIS->name, GF_LOG_ERROR, + "failed to get volfile " + "checksum for volfile id %s.", + volfile_id); + } + + return 0; } +/* + The function is required to take dict ref for every xlator at graph. + At the time of compare graph topology create a graph and populate + key values in the dictionary, after finished graph comparison we do destroy + the new graph.At the time of construct graph we don't take any reference + so to avoid dict leak at the of destroying graph due to ref counter underflow + we need to call dict_ref here. -int -xlator_destroy (xlator_t *xl) +*/ + +void +gluster_graph_take_reference(xlator_t *tree) { - if (!xl) - return 0; + xlator_t *trav = tree; + xlator_t *prev = tree; + + if (!tree) { + gf_smsg("parser", GF_LOG_ERROR, 0, LG_MSG_TREE_NOT_FOUND, NULL); + return; + } + + while (prev) { + trav = prev->next; + if (prev->options) + dict_ref(prev->options); + prev = trav; + } + return; +} - if (xl->name) - GF_FREE (xl->name); - if (xl->type) - GF_FREE (xl->type); - if (xl->dlhandle) - dlclose (xl->dlhandle); - if (xl->options) - dict_destroy (xl->options); +gf_boolean_t +mgmt_is_multiplexed_daemon(char *name) +{ + const char *mux_daemons[] = {"glustershd", NULL}; + int i; - xlator_list_destroy (xl->children); + if (!name) + return _gf_false; - xlator_list_destroy (xl->parents); + for (i = 0; mux_daemons[i]; i++) { + if (!strcmp(name, mux_daemons[i])) + return _gf_true; + } + return _gf_false; +} - GF_FREE (xl); +gf_boolean_t +xlator_is_cleanup_starting(xlator_t *this) +{ + gf_boolean_t cleanup = _gf_false; + glusterfs_graph_t *graph = NULL; + xlator_t *xl = NULL; + + if (!this) { + gf_smsg("xlator", GF_LOG_WARNING, EINVAL, LG_MSG_OBJECT_NULL, "xlator", + NULL); + goto out; + } + + graph = this->graph; + if (!graph) { + gf_smsg("xlator", GF_LOG_WARNING, EINVAL, LG_MSG_GRAPH_NOT_SET, + "name=%s", this->name, NULL); + goto out; + } + + xl = graph->first; + if (xl && xl->cleanup_starting) + cleanup = _gf_true; +out: + return cleanup; +} +int +graph_total_client_xlator(glusterfs_graph_t *graph) +{ + xlator_t *xl = NULL; + int count = 0; + + if (!graph) { + gf_smsg("xlator", GF_LOG_WARNING, EINVAL, LG_MSG_OBJECT_NULL, "graph", + NULL); + goto out; + } + + xl = graph->first; + if (!strcmp(xl->type, "protocol/server")) { + gf_msg_debug(xl->name, 0, "Return because it is a server graph"); return 0; + } + + while (xl) { + if (strcmp(xl->type, "protocol/client") == 0) { + count++; + } + xl = xl->next; + } +out: + return count; } diff --git a/libglusterfs/src/xlator.h b/libglusterfs/src/xlator.h deleted file mode 100644 index c71aa7bb3cc..00000000000 --- a/libglusterfs/src/xlator.h +++ /dev/null @@ -1,864 +0,0 @@ -/* - Copyright (c) 2006-2009 Gluster, Inc. <http://www.gluster.com> - This file is part of GlusterFS. - - GlusterFS is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 3 of the License, - or (at your option) any later version. - - GlusterFS is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see - <http://www.gnu.org/licenses/>. -*/ - -#ifndef _XLATOR_H -#define _XLATOR_H - -#ifndef _CONFIG_H -#define _CONFIG_H -#include "config.h" -#endif - -#include <stdio.h> -#include <stdint.h> -#include <inttypes.h> - - -#include "logging.h" -#include "common-utils.h" -#include "dict.h" -#include "compat.h" -#include "list.h" -#include "latency.h" - -#define FIRST_CHILD(xl) (xl->children->xlator) - -#define GF_SET_ATTR_MODE 0x1 -#define GF_SET_ATTR_UID 0x2 -#define GF_SET_ATTR_GID 0x4 -#define GF_SET_ATTR_SIZE 0x8 -#define GF_SET_ATTR_ATIME 0x10 -#define GF_SET_ATTR_MTIME 0x20 - -#define gf_attr_mode_set(mode) ((mode) & GF_SET_ATTR_MODE) -#define gf_attr_uid_set(mode) ((mode) & GF_SET_ATTR_UID) -#define gf_attr_gid_set(mode) ((mode) & GF_SET_ATTR_GID) -#define gf_attr_size_set(mode) ((mode) & GF_SET_ATTR_SIZE) -#define gf_attr_atime_set(mode) ((mode) & GF_SET_ATTR_ATIME) -#define gf_attr_mtime_set(mode) ((mode) & GF_SET_ATTR_MTIME) - -struct _xlator; -typedef struct _xlator xlator_t; -struct _dir_entry_t; -typedef struct _dir_entry_t dir_entry_t; -struct _gf_dirent_t; -typedef struct _gf_dirent_t gf_dirent_t; -struct _loc; -typedef struct _loc loc_t; - - -typedef int32_t (*event_notify_fn_t) (xlator_t *this, int32_t event, void *data, - ...); - -#include "list.h" -#include "gf-dirent.h" -#include "stack.h" -#include "iobuf.h" -#include "inode.h" -#include "fd.h" -#include "globals.h" -#include "iatt.h" - -struct _loc { - const char *path; - const char *name; - ino_t ino; - inode_t *inode; - inode_t *parent; -}; - - -typedef int32_t (*fop_getspec_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - char *spec_data); - -typedef int32_t (*fop_rchecksum_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - uint32_t weak_checksum, - uint8_t *strong_checksum); - - -typedef int32_t (*fop_getspec_t) (call_frame_t *frame, - xlator_t *this, - const char *key, - int32_t flag); - -typedef int32_t (*fop_rchecksum_t) (call_frame_t *frame, - xlator_t *this, - fd_t *fd, off_t offset, - int32_t len); - - -typedef int32_t (*fop_lookup_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - dict_t *xattr, - struct iatt *postparent); - -typedef int32_t (*fop_stat_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *buf); - -typedef int32_t (*fop_fstat_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *buf); - -typedef int32_t (*fop_truncate_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *prebuf, - struct iatt *postbuf); - -typedef int32_t (*fop_ftruncate_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *prebuf, - struct iatt *postbuf); - -typedef int32_t (*fop_access_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno); - -typedef int32_t (*fop_readlink_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - const char *path, - struct iatt *buf); - -typedef int32_t (*fop_mknod_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent); - -typedef int32_t (*fop_mkdir_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent); - -typedef int32_t (*fop_unlink_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *preparent, - struct iatt *postparent); - -typedef int32_t (*fop_rmdir_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *preparent, - struct iatt *postparent); - -typedef int32_t (*fop_symlink_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent); - -typedef int32_t (*fop_rename_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *buf, - struct iatt *preoldparent, - struct iatt *postoldparent, - struct iatt *prenewparent, - struct iatt *postnewparent); - -typedef int32_t (*fop_link_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent); - -typedef int32_t (*fop_create_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - fd_t *fd, - inode_t *inode, - struct iatt *buf, - struct iatt *preparent, - struct iatt *postparent); - -typedef int32_t (*fop_open_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - fd_t *fd); - -typedef int32_t (*fop_readv_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iovec *vector, - int32_t count, - struct iatt *stbuf, - struct iobref *iobref); - -typedef int32_t (*fop_writev_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *prebuf, - struct iatt *postbuf); - -typedef int32_t (*fop_flush_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno); - -typedef int32_t (*fop_fsync_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct iatt *prebuf, - struct iatt *postbuf); - -typedef int32_t (*fop_opendir_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - fd_t *fd); - -typedef int32_t (*fop_fsyncdir_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno); - -typedef int32_t (*fop_statfs_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct statvfs *buf); - -typedef int32_t (*fop_setxattr_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno); - -typedef int32_t (*fop_getxattr_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - dict_t *dict); - -typedef int32_t (*fop_fsetxattr_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno); - -typedef int32_t (*fop_fgetxattr_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - dict_t *dict); - -typedef int32_t (*fop_removexattr_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno); - -typedef int32_t (*fop_lk_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - struct flock *flock); - -typedef int32_t (*fop_inodelk_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno); - -typedef int32_t (*fop_finodelk_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno); - -typedef int32_t (*fop_entrylk_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno); - -typedef int32_t (*fop_fentrylk_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno); - -typedef int32_t (*fop_readdir_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - gf_dirent_t *entries); - -typedef int32_t (*fop_readdirp_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - gf_dirent_t *entries); - -typedef int32_t (*fop_xattrop_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - dict_t *xattr); - -typedef int32_t (*fop_fxattrop_cbk_t) (call_frame_t *frame, - void *cookie, - xlator_t *this, - int32_t op_ret, - int32_t op_errno, - dict_t *xattr); - - -typedef int32_t (*fop_setattr_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); - -typedef int32_t (*fop_fsetattr_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); - -typedef int32_t (*fop_lookup_t) (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - dict_t *xattr_req); - -typedef int32_t (*fop_stat_t) (call_frame_t *frame, - xlator_t *this, - loc_t *loc); - -typedef int32_t (*fop_fstat_t) (call_frame_t *frame, - xlator_t *this, - fd_t *fd); - -typedef int32_t (*fop_truncate_t) (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - off_t offset); - -typedef int32_t (*fop_ftruncate_t) (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - off_t offset); - -typedef int32_t (*fop_access_t) (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - int32_t mask); - -typedef int32_t (*fop_readlink_t) (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - size_t size); - -typedef int32_t (*fop_mknod_t) (call_frame_t *frame, xlator_t *this, - loc_t *loc, mode_t mode, dev_t rdev, - dict_t *params); - -typedef int32_t (*fop_mkdir_t) (call_frame_t *frame, xlator_t *this, - loc_t *loc, mode_t mode, dict_t *params); - -typedef int32_t (*fop_unlink_t) (call_frame_t *frame, - xlator_t *this, - loc_t *loc); - -typedef int32_t (*fop_rmdir_t) (call_frame_t *frame, - xlator_t *this, - loc_t *loc); - -typedef int32_t (*fop_symlink_t) (call_frame_t *frame, xlator_t *this, - const char *linkname, loc_t *loc, - dict_t *params); - -typedef int32_t (*fop_rename_t) (call_frame_t *frame, - xlator_t *this, - loc_t *oldloc, - loc_t *newloc); - -typedef int32_t (*fop_link_t) (call_frame_t *frame, - xlator_t *this, - loc_t *oldloc, - loc_t *newloc); - -typedef int32_t (*fop_create_t) (call_frame_t *frame, xlator_t *this, - loc_t *loc, int32_t flags, mode_t mode, - fd_t *fd, dict_t *params); - -/* Tell subsequent writes on the fd_t to fsync after every writev fop without - * requiring a fsync fop. - */ -#define GF_OPEN_FSYNC 0x01 - -/* Tell write-behind to disable writing behind despite O_SYNC not being set. - */ -#define GF_OPEN_NOWB 0x02 - -typedef int32_t (*fop_open_t) (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - int32_t flags, - fd_t *fd, - int32_t wbflags); - -typedef int32_t (*fop_readv_t) (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - size_t size, - off_t offset); - -typedef int32_t (*fop_writev_t) (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - struct iovec *vector, - int32_t count, - off_t offset, - struct iobref *iobref); - -typedef int32_t (*fop_flush_t) (call_frame_t *frame, - xlator_t *this, - fd_t *fd); - -typedef int32_t (*fop_fsync_t) (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - int32_t datasync); - -typedef int32_t (*fop_opendir_t) (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - fd_t *fd); - -typedef int32_t (*fop_fsyncdir_t) (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - int32_t datasync); - -typedef int32_t (*fop_statfs_t) (call_frame_t *frame, - xlator_t *this, - loc_t *loc); - -typedef int32_t (*fop_setxattr_t) (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - dict_t *dict, - int32_t flags); - -typedef int32_t (*fop_getxattr_t) (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - const char *name); - -typedef int32_t (*fop_fsetxattr_t) (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - dict_t *dict, - int32_t flags); - -typedef int32_t (*fop_fgetxattr_t) (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - const char *name); - -typedef int32_t (*fop_removexattr_t) (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - const char *name); - -typedef int32_t (*fop_lk_t) (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - int32_t cmd, - struct flock *flock); - -typedef int32_t (*fop_inodelk_t) (call_frame_t *frame, - xlator_t *this, - const char *volume, - loc_t *loc, - int32_t cmd, - struct flock *flock); - -typedef int32_t (*fop_finodelk_t) (call_frame_t *frame, - xlator_t *this, - const char *volume, - fd_t *fd, - int32_t cmd, - struct flock *flock); - -typedef int32_t (*fop_entrylk_t) (call_frame_t *frame, - xlator_t *this, - const char *volume, loc_t *loc, - const char *basename, entrylk_cmd cmd, - entrylk_type type); - -typedef int32_t (*fop_fentrylk_t) (call_frame_t *frame, - xlator_t *this, - const char *volume, fd_t *fd, - const char *basename, entrylk_cmd cmd, - entrylk_type type); - -typedef int32_t (*fop_readdir_t) (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - size_t size, - off_t offset); - -typedef int32_t (*fop_readdirp_t) (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - size_t size, - off_t offset); - -typedef int32_t (*fop_xattrop_t) (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - gf_xattrop_flags_t optype, - dict_t *xattr); - -typedef int32_t (*fop_fxattrop_t) (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - gf_xattrop_flags_t optype, - dict_t *xattr); - -typedef int32_t (*fop_setattr_t) (call_frame_t *frame, - xlator_t *this, - loc_t *loc, - struct iatt *stbuf, - int32_t valid); - -typedef int32_t (*fop_fsetattr_t) (call_frame_t *frame, - xlator_t *this, - fd_t *fd, - struct iatt *stbuf, - int32_t valid); - - -struct xlator_fops { - fop_lookup_t lookup; - fop_stat_t stat; - fop_fstat_t fstat; - fop_truncate_t truncate; - fop_ftruncate_t ftruncate; - fop_access_t access; - fop_readlink_t readlink; - fop_mknod_t mknod; - fop_mkdir_t mkdir; - fop_unlink_t unlink; - fop_rmdir_t rmdir; - fop_symlink_t symlink; - fop_rename_t rename; - fop_link_t link; - fop_create_t create; - fop_open_t open; - fop_readv_t readv; - fop_writev_t writev; - fop_flush_t flush; - fop_fsync_t fsync; - fop_opendir_t opendir; - fop_readdir_t readdir; - fop_readdirp_t readdirp; - fop_fsyncdir_t fsyncdir; - fop_statfs_t statfs; - fop_setxattr_t setxattr; - fop_getxattr_t getxattr; - fop_fsetxattr_t fsetxattr; - fop_fgetxattr_t fgetxattr; - fop_removexattr_t removexattr; - fop_lk_t lk; - fop_inodelk_t inodelk; - fop_finodelk_t finodelk; - fop_entrylk_t entrylk; - fop_fentrylk_t fentrylk; - fop_rchecksum_t rchecksum; - fop_xattrop_t xattrop; - fop_fxattrop_t fxattrop; - fop_setattr_t setattr; - fop_fsetattr_t fsetattr; - fop_getspec_t getspec; - - /* these entries are used for a typechecking hack in STACK_WIND _only_ */ - fop_lookup_cbk_t lookup_cbk; - fop_stat_cbk_t stat_cbk; - fop_fstat_cbk_t fstat_cbk; - fop_truncate_cbk_t truncate_cbk; - fop_ftruncate_cbk_t ftruncate_cbk; - fop_access_cbk_t access_cbk; - fop_readlink_cbk_t readlink_cbk; - fop_mknod_cbk_t mknod_cbk; - fop_mkdir_cbk_t mkdir_cbk; - fop_unlink_cbk_t unlink_cbk; - fop_rmdir_cbk_t rmdir_cbk; - fop_symlink_cbk_t symlink_cbk; - fop_rename_cbk_t rename_cbk; - fop_link_cbk_t link_cbk; - fop_create_cbk_t create_cbk; - fop_open_cbk_t open_cbk; - fop_readv_cbk_t readv_cbk; - fop_writev_cbk_t writev_cbk; - fop_flush_cbk_t flush_cbk; - fop_fsync_cbk_t fsync_cbk; - fop_opendir_cbk_t opendir_cbk; - fop_readdir_cbk_t readdir_cbk; - fop_readdirp_cbk_t readdirp_cbk; - fop_fsyncdir_cbk_t fsyncdir_cbk; - fop_statfs_cbk_t statfs_cbk; - fop_setxattr_cbk_t setxattr_cbk; - fop_getxattr_cbk_t getxattr_cbk; - fop_fsetxattr_cbk_t fsetxattr_cbk; - fop_fgetxattr_cbk_t fgetxattr_cbk; - fop_removexattr_cbk_t removexattr_cbk; - fop_lk_cbk_t lk_cbk; - fop_inodelk_cbk_t inodelk_cbk; - fop_finodelk_cbk_t finodelk_cbk; - fop_entrylk_cbk_t entrylk_cbk; - fop_fentrylk_cbk_t fentrylk_cbk; - fop_rchecksum_cbk_t rchecksum_cbk; - fop_xattrop_cbk_t xattrop_cbk; - fop_fxattrop_cbk_t fxattrop_cbk; - fop_setattr_cbk_t setattr_cbk; - fop_fsetattr_cbk_t fsetattr_cbk; - fop_getspec_cbk_t getspec_cbk; -}; - -typedef int32_t (*cbk_forget_t) (xlator_t *this, - inode_t *inode); - -typedef int32_t (*cbk_release_t) (xlator_t *this, - fd_t *fd); - -struct xlator_cbks { - cbk_forget_t forget; - cbk_release_t release; - cbk_release_t releasedir; -}; - -typedef int32_t (*dumpop_priv_t) (xlator_t *this); - -typedef int32_t (*dumpop_inode_t) (xlator_t *this); - -typedef int32_t (*dumpop_fd_t) (xlator_t *this); - -typedef int32_t (*dumpop_inodectx_t) (xlator_t *this, inode_t *ino); - - -struct xlator_dumpops { - dumpop_priv_t priv; - dumpop_inode_t inode; - dumpop_fd_t fd; - dumpop_inodectx_t inodectx; -}; - -typedef struct xlator_list { - xlator_t *xlator; - struct xlator_list *next; -} xlator_list_t; - -/* Add possible new type of option you may need */ -typedef enum { - GF_OPTION_TYPE_ANY = 0, - GF_OPTION_TYPE_STR, - GF_OPTION_TYPE_INT, - GF_OPTION_TYPE_SIZET, - GF_OPTION_TYPE_PERCENT, - GF_OPTION_TYPE_PERCENT_OR_SIZET, - GF_OPTION_TYPE_BOOL, - GF_OPTION_TYPE_XLATOR, - GF_OPTION_TYPE_PATH, - GF_OPTION_TYPE_TIME, - GF_OPTION_TYPE_DOUBLE, - GF_OPTION_TYPE_INTERNET_ADDRESS, -} volume_option_type_t; - - -#define ZR_VOLUME_MAX_NUM_KEY 4 -#define ZR_OPTION_MAX_ARRAY_SIZE 64 - -/* Each translator should define this structure */ -typedef struct volume_options { - char *key[ZR_VOLUME_MAX_NUM_KEY]; - /* different key, same meaning */ - volume_option_type_t type; - int64_t min; /* -1 means no range */ - int64_t max; /* -1 means no range */ - char *value[ZR_OPTION_MAX_ARRAY_SIZE]; - /* If specified, will check for one of - the value from this array */ - char *description; /* about the key */ -} volume_option_t; - - -typedef struct vol_opt_list { - struct list_head list; - volume_option_t *given_opt; -} volume_opt_list_t; - - -struct _xlator { - /* Built during parsing */ - char *name; - char *type; - xlator_t *next; - xlator_t *prev; - xlator_list_t *parents; - xlator_list_t *children; - dict_t *options; - - /* Set after doing dlopen() */ - void *dlhandle; - struct xlator_fops *fops; - struct xlator_cbks *cbks; - struct xlator_dumpops *dumpops; - struct list_head volume_options; /* list of volume_option_t */ - - void (*fini) (xlator_t *this); - int32_t (*init) (xlator_t *this); - int32_t (*mem_acct_init) (xlator_t *this); - event_notify_fn_t notify; - - gf_loglevel_t loglevel; /* Log level for translator */ - - /* for latency measurement */ - fop_latency_t latencies[GF_FOP_MAXVALUE]; - - /* Misc */ - glusterfs_ctx_t *ctx; - glusterfs_graph_t *graph; /* not set for fuse */ - inode_table_t *itable; - char init_succeeded; - void *private; - struct mem_acct mem_acct; -}; - -#define xlator_has_parent(xl) (xl->parents != NULL) - -int validate_xlator_volume_options (xlator_t *xl, volume_option_t *opt); - -int32_t xlator_set_type (xlator_t *xl, const char *type); - -xlator_t *file_to_xlator_tree (glusterfs_ctx_t *ctx, - FILE *fp); - -int xlator_notify (xlator_t *this, int32_t event, void *data, ...); -int xlator_init (xlator_t *this); -int xlator_destroy (xlator_t *xl); - -int32_t xlator_tree_init (xlator_t *xl); -int32_t xlator_tree_free (xlator_t *xl); - -void xlator_tree_fini (xlator_t *xl); - -void xlator_foreach (xlator_t *this, - void (*fn) (xlator_t *each, - void *data), - void *data); - -xlator_t *xlator_search_by_name (xlator_t *any, const char *name); - -void inode_destroy_notify (inode_t *inode, const char *xlname); - -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 xlator_mem_acct_init (xlator_t *xl, int num_types); - -#define GF_STAT_PRINT_FMT_STR "%"PRIx64",%"PRIx64",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx64",%"PRIx64",%"PRIx32",%"PRIx64",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32"\n" - -#define GF_STAT_SCAN_FMT_STR "%"SCNx64",%"SCNx64",%"SCNx32",%"SCNx32",%"SCNx32",%"SCNx32",%"SCNx64",%"SCNx64",%"SCNx32",%"SCNx64",%"SCNx32",%"SCNx32",%"SCNx32",%"SCNx32",%"SCNx32",%"SCNx32"\n" - -#define GF_STATFS_PRINT_FMT_STR "%"PRIx32",%"PRIx32",%"PRIx64",%"PRIx64",%"PRIx64",%"PRIx64",%"PRIx64",%"PRIx64",%"PRIx32",%"PRIx32",%"PRIx32"\n" - -#define GF_STATFS_SCAN_FMT_STR "%"SCNx32",%"SCNx32",%"SCNx64",%"SCNx64",%"SCNx64",%"SCNx64",%"SCNx64",%"SCNx64",%"SCNx32",%"SCNx32",%"SCNx32"\n" - -#endif /* _XLATOR_H */ |
